1mod context;
9mod flex;
10mod id;
11mod idle;
12mod mapped;
13#[cfg(test)]
14mod mapped_rules;
15mod memory;
16mod place;
17mod pointer_shape;
18#[cfg(test)]
19mod sized_rules;
20mod view;
21mod wrap;
22#[cfg(test)]
23mod wrap_rules;
24
25use std::any::{Any, type_name};
26
27pub use context::{EventCx, MeasureCx, PaintCx};
28pub use id::WidgetId;
29pub use pointer_shape::PointerShape;
30pub use view::{NodeMut, View};
31
32pub(crate) use context::{Effects, FocusRequest, Frame, Grounds, Interaction, LayerRecord};
33pub(crate) use flex::{Axis, Flex};
34pub(crate) use id::{IdMap, Key};
35pub(crate) use idle::{IdleScope, IdleWatch};
36pub(crate) use mapped::Reached;
37pub(crate) use memory::Memory;
38
39use mapped::Mapped;
40
41use crate::event::Event;
42use crate::geometry::{Padding, Rect, Size};
43use crate::keymap::Scope;
44
45pub trait Widget<Msg>: 'static {
51 fn measure(&self, cx: &mut MeasureCx<'_>, available: Size) -> Size;
53
54 fn paint(&self, cx: &mut PaintCx<'_>, area: Rect);
56
57 fn paint_overlay(&self, _cx: &mut PaintCx<'_>, _anchor: Rect) {}
60
61 fn event(&self, _cx: &mut EventCx<'_, Msg>, _event: &Event) -> bool {
64 false
65 }
66
67 fn focusable(&self) -> bool {
69 false
70 }
71
72 fn children(&self) -> &[Node<Msg>] {
74 &[]
75 }
76
77 fn children_mut(&mut self) -> &mut [Node<Msg>] {
79 &mut []
80 }
81}
82
83pub(crate) trait StoredWidget<Msg>: Widget<Msg> + Any {}
86
87impl<Msg, W: Widget<Msg>> StoredWidget<Msg> for W {}
88
89pub trait Container<Msg>: Widget<Msg> {
91 fn set_children(&mut self, children: Vec<Node<Msg>>);
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
97pub enum Length {
98 #[default]
100 Auto,
101 Cells(u16),
103 Fill(u16),
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
109pub enum Align {
110 #[default]
112 Start,
113 Center,
115 End,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
121pub struct LayoutProps {
122 pub width: Length,
124 pub height: Length,
126 pub padding: Padding,
128 pub gap: u16,
130 pub justify: Align,
132 pub align: Align,
134}
135
136pub struct Node<Msg> {
138 pub(crate) key: Key,
139 pub(crate) id: WidgetId,
140 pub(crate) type_name: &'static str,
141 pub(crate) layout: LayoutProps,
142 pub(crate) persistent: bool,
143 pub(crate) selectable: Option<bool>,
145 pub(crate) actions: Vec<FocusAction<Msg>>,
147 pub(crate) widget: Box<dyn StoredWidget<Msg>>,
148}
149
150pub(crate) struct FocusAction<Msg> {
152 pub(crate) asked: Asked,
153 pub(crate) message: Box<dyn Fn() -> Msg>,
154}
155
156#[derive(Debug, Clone, PartialEq, Eq)]
158pub(crate) enum Asked {
159 Action(Scope, String),
161 Clipboard(ClipboardKey),
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
171#[non_exhaustive]
172pub enum ClipboardKey {
173 Cut,
175 Copy,
177 Paste,
179}
180
181impl<Msg: 'static> Node<Msg> {
182 pub(crate) fn new<W: Widget<Msg>>(widget: W, index: usize) -> Self {
183 Self {
184 key: Key::Index(index),
185 id: WidgetId::ROOT,
186 type_name: type_name::<W>(),
187 layout: LayoutProps::default(),
188 persistent: false,
189 selectable: None,
190 actions: Vec::new(),
191 widget: Box::new(widget),
192 }
193 }
194
195 #[must_use]
197 pub fn id(&self) -> WidgetId {
198 self.id
199 }
200
201 #[must_use]
203 pub fn layout(&self) -> LayoutProps {
204 self.layout
205 }
206
207 pub(crate) fn answer_action(&self, scope: Scope, action: &str) -> Option<Msg> {
210 self.answer(|asked| matches!(asked, Asked::Action(s, a) if *s == scope && a == action))
211 }
212
213 pub(crate) fn answer_clipboard(&self, key: ClipboardKey) -> Option<Msg> {
216 self.answer(|asked| *asked == Asked::Clipboard(key))
217 }
218
219 fn answer(&self, wanted: impl Fn(&Asked) -> bool) -> Option<Msg> {
220 self.actions.iter().find(|answer| wanted(&answer.asked)).map(|answer| (answer.message)())
221 }
222
223 pub(crate) fn assign_ids(&mut self, parent: WidgetId) {
225 self.id = parent.child(&self.key, self.type_name);
226 let id = self.id;
227 if let Some(mapped) = (&mut *self.widget as &mut dyn Any).downcast_mut::<Mapped<Msg>>() {
228 mapped.assign_ids(id);
229 return;
230 }
231 for child in self.widget.children_mut() {
232 child.assign_ids(id);
233 }
234 }
235
236 pub(crate) fn find(&self, id: WidgetId) -> Option<Box<dyn Reached<Msg> + '_>> {
239 if self.id == id {
240 return Some(Box::new(self));
241 }
242 if let Some(mapped) = self.mapped() {
243 return mapped.find(id);
244 }
245 self.widget.children().iter().find_map(|child| child.find(id))
246 }
247
248 pub(crate) fn count_focusable(&self) -> usize {
251 let own = usize::from(self.widget.focusable());
252 match self.mapped() {
253 Some(mapped) => own + mapped.count_focusable(),
254 None => own + self.widget.children().iter().map(Self::count_focusable).sum::<usize>(),
255 }
256 }
257
258 fn mapped(&self) -> Option<&Mapped<Msg>> {
260 (&*self.widget as &dyn Any).downcast_ref::<Mapped<Msg>>()
261 }
262}