denise-ui
The scene graph, widgets and compositor for Denise, a direct-rendering UI toolkit in Rust for embedded Linux and systems without a desktop environment.
A retained tree of widgets in a generational arena, stacked into scenes, drawn
through denise-render into a
denise::Surface. This is the layer that turns "a rasteriser and a display" into
a user interface.
use ;
use ;
use Ui;
#
No callbacks
A widget holds a value of your message type and emits it when something happens,
so every state change lands in one match you wrote — no closures holding
Rc<RefCell<_>>, no widget referencing another widget, no M: Clone bound.
The widgets
Fourteen of them, deliberately few:
Panel |
A surface with an optional border |
Label |
Static text, aligned in its box |
Button |
Emits a message of your type |
TextInput |
Editing, a caret, and the only widget that animates by default |
Checkbox · Toggle |
A boolean, as a box or as a switch |
RadioGroup |
One choice from a few. One node, so one tab stop |
Progress · Slider |
A value in a range, as output and as input |
Divider · Badge · Alert |
A rule, a pill, a banner |
Tabs · List |
One selected from many, horizontally or vertically |
The bar a widget has to clear is being something several panels would otherwise
each get subtly wrong — focus handling, keyboard semantics, hit areas, disabled
states — not saving a caller three fill_rect calls. More are being added one at
a time against issue #6.
Every one names theme roles rather than colours, and every surface/foreground pair is contrast-checked by a test in all three built-in themes.
Damage is the toolkit's job
There are no dirty flags to set. Ui::widget_mut invalidates on access; hover,
press, focus and enabled are tracked by the tree; moving, resizing, showing or
removing a node damages both the old rectangle and the new. Ui::render returns
false and draws nothing when nothing changed, which is the state a kiosk should
be in almost all the time.
What is not here
No layout engine. Nodes take explicit rectangles relative to their parent,
which is what a fixed-resolution panel wants; a constraint solver can be added over
this without changing anything below it. Widgets with a natural size offer
preferred_width/preferred_height as queries the application makes — the tree
never calls them, and that is the line.
Nothing scrolls (#21).
Features
| Feature | Default | What it does |
|---|---|---|
std |
✅ | Off gives no_std + alloc |
truetype |
Real TrueType fonts, via denise-text |
|
shaping |
Ligatures, bidi and font fallback, via denise-text |
#![forbid(unsafe_code)].
Status
M5 complete, M6 in progress. cargo run -p denise-ui --example showcase -- dark showcase.ppm renders every widget in every state to a file, which is how a
theme or font change gets reviewed without a display.
MIT licensed. Part of Denise — see the repository README for the whole picture.