1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! The widget layer of densa: a retained tree of widgets, laid out with flexbox, painted
//! onto a `densa_draw::Canvas`, and driven by pointer, keyboard and input method events.
//!
//! A [`Ui`] owns the widgets. The application adds them under the [root](Ui::root) with a
//! [`Style`], then a window layer (such as `densa-window`) calls [`Ui::paint`] each frame and
//! hands it input with [`Ui::pointer`], [`Ui::key`] and [`Ui::ime`]. Widgets report what
//! the user did as [`Action`]s, read with [`Ui::actions`]. Nothing here depends on a window
//! system or a GPU, so an interface runs, and is tested, headless.
//!
//! Layout runs only when a style, a widget's content or the viewport changes; painting,
//! hit-testing and delivering events run every frame and do not allocate.
//!
//! Widgets also describe themselves to assistive technology ([`Widget::accessibility`]):
//! [`Ui::access_tree`] is what a screen reader reads, and [`Ui::access_action`] does what it
//! asks. Both are platform-neutral; `densa-window` connects them to the operating system.
//!
//! ```
//! use densa_core::{Point, Size};
//! use densa_paragraph::TextSystem;
//! use densa_ui::{
//! ActionKind, Event, EventCx, Handled, PointerButton, PointerEvent, PointerKind, Style, Ui,
//! Widget,
//! };
//!
//! /// Reports a click when pressed.
//! struct Clickable;
//!
//! impl Widget for Clickable {
//! fn event(&mut self, cx: &mut EventCx<'_>, event: &Event<'_>) -> Handled {
//! match event {
//! Event::Pointer(p) if matches!(p.kind, PointerKind::Down(_)) => {
//! cx.emit(ActionKind::Clicked);
//! Handled::Yes
//! }
//! _ => Handled::No,
//! }
//! }
//! }
//!
//! let mut ui = Ui::new(TextSystem::new()?);
//! ui.resize(Size::new(400.0, 300.0));
//! let button = ui.add(ui.root(), Clickable, Style::row().size(120.0, 32.0))?;
//!
//! let press = PointerKind::Down(PointerButton::Primary);
//! ui.pointer(PointerEvent::new(press, Point::new(10.0, 10.0)));
//! let clicked: Vec<_> = ui.actions().map(|action| action.source).collect();
//! assert_eq!(clicked, [button]);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
pub use ;
pub use ;
pub use ;
pub use WidgetId;
pub use ;
pub use Theme;
pub use ;
pub use ;