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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! element API and built-in elements like `Container`, `Button`, `Text`, etc.
use crate::{
draw::{atlas::ImageCtx, UiDrawCommandList},
input::InputCtx,
layout::{LayoutInfo, Size2d},
measure::Response,
rect::Rect,
signal::SignalStore,
state::StateRepo,
text::{FontHandle, TextMeasure},
UiInstance,
};
mod builtin;
pub use builtin::*;
/// Context for the `Element::measure` function
pub struct MeasureContext<'a> {
pub layout: &'a LayoutInfo,
pub state: &'a StateRepo,
pub text_measure: TextMeasure<'a>,
pub current_font: FontHandle,
pub images: ImageCtx<'a>,
//XXX: should measure have a reference to input?
//pub input: InputCtx<'a>,
}
/// Context for the `Element::process` function
pub struct ProcessContext<'a> {
pub measure: &'a Response,
pub layout: &'a LayoutInfo,
pub draw: &'a mut UiDrawCommandList,
pub state: &'a mut StateRepo,
pub text_measure: TextMeasure<'a>,
pub current_font: FontHandle,
pub images: ImageCtx<'a>,
pub input: InputCtx<'a>,
pub signal: &'a mut SignalStore,
}
pub trait UiElement {
/// Get the name of the element (in lower case)
///
/// For example, "button" or "progress_bar"
fn name(&self) -> &'static str;
/// Get the requested UiElement size
///
/// You should implement this function whenever possible, otherwise some features may not work at all, such as the `Remaining` size
fn size(&self) -> Option<Size2d> { None }
/// Measure step, guaranteed to be called before the `process` step\
/// May be called multiple times per single frame, so it should not contain any expensive calls\
/// This function may not mutate any state.\
///
/// This function should return the size of the element along with any hints or layout metadata
fn measure(&self, ctx: MeasureContext) -> Response;
/// Process step, guaranteed to be called after the `measure` step\
/// You should process the user inputs and render the element here.
fn process(&self, ctx: ProcessContext);
}
/// A list of elements\
/// Use the [`add`](`ElementList::add`) method to add elements to the list
pub struct ElementList(pub Vec<Box<dyn UiElement>>);
impl ElementList {
/// Add an element to the list
pub fn add(&mut self, element: impl UiElement + 'static) {
self.0.push(Box::new(element))
}
/// Create a new `ElementList` from a callback\
/// The callback will be called with a reference to the newly list
pub(crate) fn from_callback(cb: impl FnOnce(&mut ElementList)) -> Self {
let mut list = ElementList(Vec::new());
cb(&mut list);
list
}
}
/// Extension trait for [`UiElement`] that adds the [`add_child`] and [`add_root`] methods
pub trait UiElementExt: UiElement {
/// Add element as a child/nested element.
fn add_child(self, ui: &mut ElementList);
/// Add element as a ui root.
fn add_root(self, ui: &mut UiInstance, max_size: impl Into<Rect>);
}
impl<T: UiElement + 'static> UiElementExt for T {
fn add_child(self, ui: &mut ElementList) {
ui.add(self)
}
fn add_root(self, ui: &mut UiInstance, rect: impl Into<Rect>) {
ui.add(self, rect);
}
}