Skip to main content

qframe/widget/
mod.rs

1//! The widget model: the [`Widget`] trait, view nodes, layout properties and the contexts
2//! widgets measure, paint and handle events with.
3//!
4//! An application's `view` builds a fresh tree of [`Node`]s every frame through [`View`].
5//! The runtime assigns every node a [`WidgetId`], lays the tree out while painting it, and
6//! keeps the tree until the next frame so input can reach the widgets that were on screen.
7
8mod context;
9mod flex;
10mod id;
11mod idle;
12mod mapped;
13#[cfg(test)]
14mod mapped_rules;
15mod memory;
16mod place;
17#[cfg(test)]
18mod sized_rules;
19mod view;
20mod wrap;
21#[cfg(test)]
22mod wrap_rules;
23
24use std::any::{Any, type_name};
25
26pub use context::{EventCx, MeasureCx, PaintCx};
27pub use id::WidgetId;
28pub use view::{NodeMut, View};
29
30pub(crate) use context::{Effects, FocusRequest, Frame, Grounds, Interaction, LayerRecord};
31pub(crate) use flex::{Axis, Flex};
32pub(crate) use id::{IdMap, Key};
33pub(crate) use idle::{IdleScope, IdleWatch};
34pub(crate) use mapped::Reached;
35pub(crate) use memory::Memory;
36
37use mapped::Mapped;
38
39use crate::event::Event;
40use crate::geometry::{Padding, Rect, Size};
41use crate::keymap::Scope;
42
43/// Something that can be laid out, painted and interacted with.
44///
45/// Widgets are plain values created in `view` every frame. Anything that must survive between
46/// frames and is not application data (a cursor position, a scroll offset) is kept in runtime
47/// memory through [`PaintCx::memory`] and [`EventCx::memory`].
48pub trait Widget<Msg>: 'static {
49    /// The size the widget wants when it may use up to `available`.
50    fn measure(&self, cx: &mut MeasureCx<'_>, available: Size) -> Size;
51
52    /// Draws the widget into `area`.
53    fn paint(&self, cx: &mut PaintCx<'_>, area: Rect);
54
55    /// Draws the widget's overlay after the whole view was painted, when it asked for one with
56    /// [`PaintCx::request_overlay`]. `anchor` is the area the widget was painted in.
57    fn paint_overlay(&self, _cx: &mut PaintCx<'_>, _anchor: Rect) {}
58
59    /// Handles input. Returns `true` when the event was used; unused key and scroll events
60    /// bubble to the parent widget.
61    fn event(&self, _cx: &mut EventCx<'_, Msg>, _event: &Event) -> bool {
62        false
63    }
64
65    /// Whether the widget can take keyboard focus.
66    fn focusable(&self) -> bool {
67        false
68    }
69
70    /// Child nodes, for widgets that contain other widgets.
71    fn children(&self) -> &[Node<Msg>] {
72        &[]
73    }
74
75    /// Mutable child nodes, used to assign ids.
76    fn children_mut(&mut self) -> &mut [Node<Msg>] {
77        &mut []
78    }
79}
80
81/// A widget as a node stores it: one that can also be told apart by its type, so the tree walks
82/// recognise the node of a part built with another message type.
83pub(crate) trait StoredWidget<Msg>: Widget<Msg> + Any {}
84
85impl<Msg, W: Widget<Msg>> StoredWidget<Msg> for W {}
86
87/// A widget whose children are built with a closure, see [`View::add_with`].
88pub trait Container<Msg>: Widget<Msg> {
89    /// Receives the children built for this widget.
90    fn set_children(&mut self, children: Vec<Node<Msg>>);
91}
92
93/// How much space a node takes along one axis.
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
95pub enum Length {
96    /// As much as the widget measures.
97    #[default]
98    Auto,
99    /// Exactly this many cells.
100    Cells(u16),
101    /// A share of the space left after `Auto` and `Cells` siblings, by weight.
102    Fill(u16),
103}
104
105/// Where children sit along an axis when there is room left.
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
107pub enum Align {
108    /// At the start.
109    #[default]
110    Start,
111    /// In the middle.
112    Center,
113    /// At the end.
114    End,
115}
116
117/// Layout properties of a node.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
119pub struct LayoutProps {
120    /// Width.
121    pub width: Length,
122    /// Height.
123    pub height: Length,
124    /// Space kept free inside the node.
125    pub padding: Padding,
126    /// Cells between children of a row or column.
127    pub gap: u16,
128    /// Placement of children along the main axis of a row or column, or both axes of a stack.
129    pub justify: Align,
130    /// Placement of children across the main axis.
131    pub align: Align,
132}
133
134/// One widget in the view tree with its layout properties.
135pub struct Node<Msg> {
136    pub(crate) key: Key,
137    pub(crate) id: WidgetId,
138    pub(crate) type_name: &'static str,
139    pub(crate) layout: LayoutProps,
140    pub(crate) persistent: bool,
141    /// `Some(true)` makes the node a text selection region, `Some(false)` keeps selection out.
142    pub(crate) selectable: Option<bool>,
143    /// Keymap actions the node answers while focus is inside it, see [`NodeMut::on_action`].
144    pub(crate) actions: Vec<FocusAction<Msg>>,
145    pub(crate) widget: Box<dyn StoredWidget<Msg>>,
146}
147
148/// A keymap action a node answers with its own message while focus is inside it.
149pub(crate) struct FocusAction<Msg> {
150    pub(crate) scope: Scope,
151    pub(crate) action: String,
152    pub(crate) message: Box<dyn Fn() -> Msg>,
153}
154
155impl<Msg: 'static> Node<Msg> {
156    pub(crate) fn new<W: Widget<Msg>>(widget: W, index: usize) -> Self {
157        Self {
158            key: Key::Index(index),
159            id: WidgetId::ROOT,
160            type_name: type_name::<W>(),
161            layout: LayoutProps::default(),
162            persistent: false,
163            selectable: None,
164            actions: Vec::new(),
165            widget: Box::new(widget),
166        }
167    }
168
169    /// The node's id; valid once the view has been built.
170    #[must_use]
171    pub fn id(&self) -> WidgetId {
172        self.id
173    }
174
175    /// The node's layout properties.
176    #[must_use]
177    pub fn layout(&self) -> LayoutProps {
178        self.layout
179    }
180
181    /// The message this node sends for the keymap action `action` of `scope` while focus is
182    /// inside it; see [`NodeMut::on_action`].
183    pub(crate) fn answer_action(&self, scope: Scope, action: &str) -> Option<Msg> {
184        self.actions
185            .iter()
186            .find(|answer| answer.scope == scope && answer.action == action)
187            .map(|answer| (answer.message)())
188    }
189
190    /// Gives this node and its descendants their ids.
191    pub(crate) fn assign_ids(&mut self, parent: WidgetId) {
192        self.id = parent.child(&self.key, self.type_name);
193        let id = self.id;
194        if let Some(mapped) = (&mut *self.widget as &mut dyn Any).downcast_mut::<Mapped<Msg>>() {
195            mapped.assign_ids(id);
196            return;
197        }
198        for child in self.widget.children_mut() {
199            child.assign_ids(id);
200        }
201    }
202
203    /// Finds the node with `id` in this subtree, also inside parts built with another message
204    /// type.
205    pub(crate) fn find(&self, id: WidgetId) -> Option<Box<dyn Reached<Msg> + '_>> {
206        if self.id == id {
207            return Some(Box::new(self));
208        }
209        if let Some(mapped) = self.mapped() {
210            return mapped.find(id);
211        }
212        self.widget.children().iter().find_map(|child| child.find(id))
213    }
214
215    /// How many focusable widgets this subtree holds, also inside parts built with another
216    /// message type.
217    pub(crate) fn count_focusable(&self) -> usize {
218        let own = usize::from(self.widget.focusable());
219        match self.mapped() {
220            Some(mapped) => own + mapped.count_focusable(),
221            None => own + self.widget.children().iter().map(Self::count_focusable).sum::<usize>(),
222        }
223    }
224
225    /// The part built with another message type this node holds, if it is one.
226    fn mapped(&self) -> Option<&Mapped<Msg>> {
227        (&*self.widget as &dyn Any).downcast_ref::<Mapped<Msg>>()
228    }
229}