1 unstable release
new 0.1.0 | Jan 19, 2025 |
---|
#442 in GUI
250KB
4.5K
SLoC
Keru is a Graphical User Interface library.
It is in active development and it's not ready to be used. Many features are missing or half-baked.
It offers a declarative API similar to immediate mode GUI libraries, but it is not immediate mode.
See the docs.rs page for more information.
Code Example
// Define an unique identity for this button
#[node_key] const INCREASE: NodeKey;
// Add nodes to the UI and set their parameters
ui.add(INCREASE)
.params(BUTTON)
.color(Color::RED)
.text("Increase");
// Place the nodes into the tree and define the layout
ui.v_stack().nest(|| {
if self.show {
ui.place(INCREASE);
ui.label(self.count); // This one doesn't need a key.
}
});
// Run code in response to events
if ui.is_clicked(INCREASE) {
self.count += 1;
}
lib.rs
:
Keru is an experimental Graphical User Interface library.
It is in active development and it's not ready to be used. Many features are missing or half-baked.
Keru offers a declarative API similar to immediate mode GUI libraries, but it is not immediate mode.
Example
// Define an unique identity for a node. You can also create keys dynamically.
#[node_key] const INCREASE: NodeKey;
// Add the node to the UI and set its parameters
self.ui.add(INCREASE)
.params(BUTTON)
.color(Color::RED)
.text("Increase");
// Place nodes into the tree and define the layout
self.ui.v_stack().nest(|| {
if self.show {
self.ui.place(INCREASE);
self.ui.label(self.count);
}
});
// Run code in response to events
if self.ui.is_clicked(INCREASE) {
self.count += 1;
}
Using NodeKeys
gives more flexibility when organizing the code, but they are not required. See the "no_keys" example to see a similar counter written without NodeKeys
.
Window Loop
If you just want to try out some GUI building code, you can use the one-line loop in example_window_loop
. The Counter example uses this method.
However, Keru is intended to be used as part of a regular winit
/wgpu
window loop managed by the library user. This makes it very simple to combine it with any kind of custom rendering (as long as it uses wgpu
).
Once you have a window loop, you can create a [Ui
] struct and store it in your main program state.
To integrate it with the window loop, you only need to do two things:
- When you receive a
winit
WindowEvent
, pass it to [Ui::window_event()
]. - When you receive a
WindowEvent::RedrawRequested
, redeclare your GUI, then call [Ui::render()
].
You can use the [Ui::needs_rerender()
] to decide whether to render the GUI or skip it.
For a full integration example, see the Painter example. Another simpler integration example will be added in the future.
Declaring the GUI
To redeclare your GUI, you have to start a new GUI "tree", rerun all your GUI declaration code, then finish the tree.
#
#
self.ui.begin_tree();
self.ui.text("Hello World");
self.ui.finish_tree();
#
Note that even if you do this every frame, it doesn't mean that the GUI is re-rendering every frame, doing a full relayout on every frame, or anything of that sort. See the "About" page for more information on this point.
To see how the GUI declaration code works, you can check the basic example above, the Counter example, or the paint_ui.rs
file in the painter example.
To summarize, for each element in the GUI, you have to perform some of these conceptual steps:
- optionally, define a
NodeKey
for the node - add the node to the [
Ui
] - set its parameters (color, size, text, ...)
- place it in the tree
- optionally, start a nested block
- optionally, check for input on the nodes and run code as a consequence
You can do these things by either calling methods directly on the main [Ui
] struct, or by calling chained methods on the result of a previous method.
Methods on the [Ui
] struct usually take a NodeKey
argument to refer to a specific node.
Creating complex GUIs
-
In dynamic GUIs, you can't identify every node with a static
NodeKey
in the way the examples do it.Instead, you can use the [
NodeKey::sibling()
] function to create keys dynamically at runtime. -
To create reusable "widgets", you can just wrap the GUI code in a function. However, it's very likely that you'll need to create a
subtree
for it to make it work correctly.
These building blocks should be enough to create complex GUIs. But only time will tell.
More information
See the "About" page for more information about how Keru works internally, how it compares to other libraries, and more.
Dependencies
~33–67MB
~1M SLoC