denise_ui/lib.rs
1//! Denise's scene graph, widgets and compositor.
2//!
3//! A retained tree of widgets in a generational arena, stacked into scenes, drawn
4//! through [`denise_render`] into a [`denise::Surface`]. This is the layer that
5//! turns "a rasteriser and a display" into "a user interface".
6//!
7//! ```no_run
8//! # use denise::{Rect, Size, theme};
9//! # use denise_ui::{Ui, widgets::Panel};
10//! # fn demo(surface: &mut impl denise::Surface) -> Result<(), denise::SurfaceError> {
11//! #[derive(Clone, Debug)]
12//! enum Msg { Ok }
13//!
14//! let mut ui: Ui<Msg> = Ui::new(Size::new(1920, 1080), theme::DARK);
15//! let root = ui.root();
16//! ui.add(root, Panel::default(), Rect::new(40, 40, 400, 240));
17//!
18//! loop {
19//! // ui.handle(&events);
20//! ui.render(surface)?; // draws nothing at all when nothing changed
21//! for message in ui.drain_messages() {
22//! match message { Msg::Ok => {} }
23//! }
24//! # break;
25//! }
26//! # Ok(())
27//! # }
28//! ```
29//!
30//! # Why a separate crate
31//!
32//! [`denise`] is the platform-agnostic contract — geometry, colour, the pixel
33//! buffer, input, damage, theming — and [`denise_render`] is the rasteriser that
34//! depends on it. Widgets need both, so they cannot live in either without a
35//! dependency cycle. Keeping them here also means a signage application that draws
36//! its own scene links no arena, no tree and no widget code at all.
37//!
38//! # What is not here
39//!
40//! No layout engine. Nodes are positioned with explicit rectangles relative to
41//! their parent, which is what a fixed-resolution panel actually wants; a
42//! constraint solver can be added over this without changing anything below it.
43
44#![cfg_attr(not(feature = "std"), no_std)]
45
46extern crate alloc;
47
48pub mod anchor;
49mod arena;
50pub mod cursor;
51pub mod motion;
52mod node;
53pub mod overlay;
54mod toast;
55mod tooltip;
56mod ui;
57pub mod widget;
58pub mod widgets;
59
60pub use anchor::{Anchors, Dock};
61pub use arena::NodeId;
62pub use cursor::{ARROW, CROSSHAIR, Cursor, CursorImage};
63pub use motion::{Motion, Wake};
64pub use overlay::{Side, anchored};
65pub use ui::Ui;
66pub use widget::{
67 Animation, Event, EventCtx, Handled, MeasureCtx, Measured, Offer, PaintCtx, VisualState, Void,
68 Widget,
69};
70pub use widgets::{
71 Alert, Align, Badge, Button, Checkbox, Describe, Divider, DynDescribe, Label, List, ListItem,
72 Mismatch, Orientation, Panel, Progress, Property, PropertyError, PropertyKind, RadialProgress,
73 RadioGroup, Select, Slider, Spinner, TabEvent, Tabs, TextArea, TextBuffer, TextDocument,
74 TextInput, Toggle, Tree, TreeItem, Value, open_select,
75};
76
77// Re-exported so an application names one crate rather than three to style a
78// label, and so `FontId(0)` means the same thing everywhere.
79pub use denise_text::{FontId, GlyphSource, TextEngine, TextStyle};
80
81/// Compiles the examples in this crate's README, so they cannot drift from the API
82/// they claim to demonstrate. Never built except under `cargo test --doc`.
83#[cfg(doctest)]
84#[doc = include_str!("../README.md")]
85struct Readme;