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 memory;
12mod view;
13
14use std::any::type_name;
15
16pub use context::{EventCx, MeasureCx, PaintCx};
17pub use id::WidgetId;
18pub use view::{NodeMut, View};
19
20pub(crate) use context::{Effects, FocusRequest, Frame, Interaction, LayerRecord};
21pub(crate) use flex::{Axis, Flex};
22pub(crate) use id::{IdMap, Key};
23pub(crate) use memory::Memory;
24
25use crate::event::Event;
26use crate::geometry::{Padding, Rect, Size};
27
28/// Something that can be laid out, painted and interacted with.
29///
30/// Widgets are plain values created in `view` every frame. Anything that must survive between
31/// frames and is not application data (a cursor position, a scroll offset) is kept in runtime
32/// memory through [`PaintCx::memory`] and [`EventCx::memory`].
33pub trait Widget<Msg>: 'static {
34    /// The size the widget wants when it may use up to `available`.
35    fn measure(&self, cx: &mut MeasureCx<'_>, available: Size) -> Size;
36
37    /// Draws the widget into `area`.
38    fn paint(&self, cx: &mut PaintCx<'_>, area: Rect);
39
40    /// Draws the widget's overlay after the whole view was painted, when it asked for one with
41    /// [`PaintCx::request_overlay`]. `anchor` is the area the widget was painted in.
42    fn paint_overlay(&self, _cx: &mut PaintCx<'_>, _anchor: Rect) {}
43
44    /// Handles input. Returns `true` when the event was used; unused key and scroll events
45    /// bubble to the parent widget.
46    fn event(&self, _cx: &mut EventCx<'_, Msg>, _event: &Event) -> bool {
47        false
48    }
49
50    /// Whether the widget can take keyboard focus.
51    fn focusable(&self) -> bool {
52        false
53    }
54
55    /// Child nodes, for widgets that contain other widgets.
56    fn children(&self) -> &[Node<Msg>] {
57        &[]
58    }
59
60    /// Mutable child nodes, used to assign ids.
61    fn children_mut(&mut self) -> &mut [Node<Msg>] {
62        &mut []
63    }
64}
65
66/// A widget whose children are built with a closure, see [`View::add_with`].
67pub trait Container<Msg>: Widget<Msg> {
68    /// Receives the children built for this widget.
69    fn set_children(&mut self, children: Vec<Node<Msg>>);
70}
71
72/// How much space a node takes along one axis.
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
74pub enum Length {
75    /// As much as the widget measures.
76    #[default]
77    Auto,
78    /// Exactly this many cells.
79    Cells(u16),
80    /// A share of the space left after `Auto` and `Cells` siblings, by weight.
81    Fill(u16),
82}
83
84/// Where children sit along an axis when there is room left.
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
86pub enum Align {
87    /// At the start.
88    #[default]
89    Start,
90    /// In the middle.
91    Center,
92    /// At the end.
93    End,
94}
95
96/// Layout properties of a node.
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
98pub struct LayoutProps {
99    /// Width.
100    pub width: Length,
101    /// Height.
102    pub height: Length,
103    /// Space kept free inside the node.
104    pub padding: Padding,
105    /// Cells between children of a row or column.
106    pub gap: u16,
107    /// Placement of children along the main axis of a row or column, or both axes of a stack.
108    pub justify: Align,
109    /// Placement of children across the main axis.
110    pub align: Align,
111}
112
113/// One widget in the view tree with its layout properties.
114pub struct Node<Msg> {
115    pub(crate) key: Key,
116    pub(crate) id: WidgetId,
117    pub(crate) type_name: &'static str,
118    pub(crate) layout: LayoutProps,
119    pub(crate) persistent: bool,
120    /// `Some(true)` makes the node a text selection region, `Some(false)` keeps selection out.
121    pub(crate) selectable: Option<bool>,
122    pub(crate) widget: Box<dyn Widget<Msg>>,
123}
124
125impl<Msg: 'static> Node<Msg> {
126    pub(crate) fn new<W: Widget<Msg>>(widget: W, index: usize) -> Self {
127        Self {
128            key: Key::Index(index),
129            id: WidgetId::ROOT,
130            type_name: type_name::<W>(),
131            layout: LayoutProps::default(),
132            persistent: false,
133            selectable: None,
134            widget: Box::new(widget),
135        }
136    }
137
138    /// The node's id; valid once the view has been built.
139    #[must_use]
140    pub fn id(&self) -> WidgetId {
141        self.id
142    }
143
144    /// The node's layout properties.
145    #[must_use]
146    pub fn layout(&self) -> LayoutProps {
147        self.layout
148    }
149
150    /// Gives this node and its descendants their ids.
151    pub(crate) fn assign_ids(&mut self, parent: WidgetId) {
152        self.id = parent.child(&self.key, self.type_name);
153        let id = self.id;
154        for child in self.widget.children_mut() {
155            child.assign_ids(id);
156        }
157    }
158
159    /// Finds the node with `id` in this subtree.
160    pub(crate) fn find(&self, id: WidgetId) -> Option<&Self> {
161        if self.id == id {
162            return Some(self);
163        }
164        self.widget.children().iter().find_map(|child| child.find(id))
165    }
166}