Skip to main content

smudge_core/
element.rs

1//! Elements: the builder that describes one node, and the bindings that keep
2//! its properties current.
3//!
4//! An element holds a widget, a style, the bindings that update parts of that
5//! style, and its children. Building one touches no tree: mounting creates the
6//! nodes and installs one render effect per binding inside the node's owner.
7//!
8//! A binding never writes to the tree itself. Its effect reads the value and
9//! pushes an update onto the shared update queue, and the frame applies the
10//! queued updates before it lays anything out. That is what keeps every write
11//! to the tree in one place and in one order.
12//!
13//! Every builder takes either a plain value or a closure. A plain value is
14//! written when the element is built and costs nothing afterwards. A closure
15//! becomes a binding: it is read when the node mounts and again whenever a
16//! signal it reads changes, and it updates that one property without rebuilding
17//! the element or its children.
18//!
19//! ```
20//! use smudge_core::geometry::Color;
21//! use smudge_core::reactive::{self, prelude::*};
22//! use smudge_core::style::px;
23//! use smudge_core::widget::panel;
24//!
25//! let (on, _set_on) = reactive::signal_local(false);
26//! let card = panel()
27//!     .width(px(120.0))
28//!     .height(px(40.0))
29//!     .corner_radius(6.0)
30//!     .background(move || {
31//!         if on.get() {
32//!             Color::rgb(220, 60, 60).into()
33//!         } else {
34//!             Color::rgb(60, 60, 220).into()
35//!         }
36//!     })
37//!     .child(panel().width(px(20.0)).height(px(20.0)).background(Color::WHITE));
38//! ```
39
40use std::any::TypeId;
41use std::cell::RefCell;
42use std::collections::{HashMap, VecDeque};
43use std::hash::Hash;
44use std::rc::Rc;
45
46use crate::geometry::{Color, Point, Size};
47use crate::input::{Handled, KeyEvent};
48use crate::paint::PaintOp;
49use crate::reactive::{Owner, RenderEffect, RwSignal};
50use crate::semantics::Role;
51use crate::style::{
52    Align, Direction, Edges, Justify, LayoutProps, Length, Overflow, PaintProps, Position, Style,
53};
54use crate::theme::{ColorToken, ColorValue, RadiusToken, RadiusValue};
55use crate::tree::interaction::Handlers;
56use crate::tree::{Dirty, WidgetId, WidgetTree};
57use crate::variants::{PatchBuilder, StylePatch, Variants};
58use crate::widget::{PaintCx, Widget};
59
60/// One change to the widget tree, applied by the frame's apply step.
61pub(crate) type Update = Box<dyn FnOnce(&mut WidgetTree)>;
62
63/// The style that an element applies to every child as it is added.
64type ChildStyling = Rc<dyn Fn(&mut Style)>;
65
66/// The updates that are waiting to be applied.
67///
68/// Every binding shares one queue, so a frame applies the effects of all of
69/// them in the order the effects were queued.
70#[derive(Clone, Default)]
71pub(crate) struct UpdateQueue(Rc<RefCell<VecDeque<Update>>>);
72
73impl UpdateQueue {
74    /// Queues `update` to run in the next apply step.
75    pub(crate) fn push(&self, update: Update) {
76        self.0.borrow_mut().push_back(update);
77    }
78
79    /// Applies every queued update to `tree`, in the order they were queued,
80    /// and returns whether any ran.
81    ///
82    /// An update may queue another update, as mounting a child does when its
83    /// bindings run. Those run after the updates that were already waiting, in
84    /// the same call, so one call settles everything the queue holds.
85    pub(crate) fn apply(&self, tree: &mut WidgetTree) -> bool {
86        let mut applied = false;
87        loop {
88            let next = self.0.borrow_mut().pop_front();
89            let Some(update) = next else {
90                return applied;
91            };
92            applied = true;
93            update(tree);
94        }
95    }
96}
97
98/// A property that is either fixed or computed from signals.
99///
100/// [`Value::Static`] is written once, when the element is built. [`Value::Dynamic`]
101/// becomes a binding: the closure is read when the node mounts and again
102/// whenever a signal it reads changes.
103///
104/// A value converts into this type, so a builder method can take either one.
105#[derive(Clone)]
106pub enum Value<T> {
107    /// A value that never changes.
108    Static(T),
109    /// A closure that reads the value from signals.
110    Dynamic(Rc<dyn Fn() -> T>),
111}
112
113/// Implements the conversion from a plain value for every property type.
114macro_rules! static_values {
115    ($($property:ty),* $(,)?) => {
116        $(
117            impl From<$property> for Value<$property> {
118                fn from(value: $property) -> Value<$property> {
119                    Value::Static(value)
120                }
121            }
122        )*
123    };
124}
125
126static_values!(
127    ColorValue,
128    RadiusValue,
129    Length,
130    Size,
131    Edges<Length>,
132    f32,
133    bool,
134    Direction,
135    Align,
136    Justify,
137    Overflow,
138    Point,
139);
140
141impl From<crate::window::Cursor> for Value<Option<crate::window::Cursor>> {
142    fn from(cursor: crate::window::Cursor) -> Value<Option<crate::window::Cursor>> {
143        Value::Static(Some(cursor))
144    }
145}
146
147impl From<Option<crate::window::Cursor>> for Value<Option<crate::window::Cursor>> {
148    fn from(cursor: Option<crate::window::Cursor>) -> Value<Option<crate::window::Cursor>> {
149        Value::Static(cursor)
150    }
151}
152
153impl From<Option<u32>> for Value<Option<u32>> {
154    fn from(value: Option<u32>) -> Value<Option<u32>> {
155        Value::Static(value)
156    }
157}
158
159impl From<u32> for Value<u32> {
160    fn from(value: u32) -> Value<u32> {
161        Value::Static(value)
162    }
163}
164
165impl From<String> for Value<String> {
166    fn from(text: String) -> Value<String> {
167        Value::Static(text)
168    }
169}
170
171impl From<&str> for Value<String> {
172    fn from(text: &str) -> Value<String> {
173        Value::Static(text.to_owned())
174    }
175}
176
177impl From<Color> for Value<ColorValue> {
178    fn from(color: Color) -> Value<ColorValue> {
179        Value::Static(color.into())
180    }
181}
182
183impl From<ColorToken> for Value<ColorValue> {
184    fn from(token: ColorToken) -> Value<ColorValue> {
185        Value::Static(token.into())
186    }
187}
188
189impl From<f32> for Value<RadiusValue> {
190    fn from(radius: f32) -> Value<RadiusValue> {
191        Value::Static(radius.into())
192    }
193}
194
195impl From<RadiusToken> for Value<RadiusValue> {
196    fn from(token: RadiusToken) -> Value<RadiusValue> {
197        Value::Static(token.into())
198    }
199}
200
201impl<F: Fn() -> T + 'static, T: 'static> From<F> for Value<T> {
202    fn from(get: F) -> Value<T> {
203        Value::Dynamic(Rc::new(get))
204    }
205}
206
207/// Installs a binding's effect inside a node's owner and returns its handle.
208type Install = Box<dyn FnOnce(WidgetId, &UpdateQueue) -> RenderEffect>;
209
210/// One property of one node that a render effect keeps up to date.
211struct Binding {
212    /// Creates the effect inside the node's owner and returns its handle.
213    ///
214    /// The effect runs once immediately and queues an update every time it
215    /// runs.
216    install: Install,
217    /// The property the binding writes, when it writes one the element's
218    /// builders can set again.
219    key: Option<Key>,
220}
221
222/// What a binding writes, so a later write of the same thing can replace an
223/// earlier binding of it.
224#[derive(Copy, Clone, Debug, PartialEq, Eq)]
225enum Key {
226    /// A property of the node's style or state.
227    Style(Prop),
228    /// A property of the node's widget, named by the marker type given to
229    /// [`Element::bind`].
230    Widget(TypeId),
231}
232
233/// A property an element's builders write, so a later write of the same
234/// property can replace an earlier binding of it.
235#[derive(Copy, Clone, Debug, PartialEq, Eq)]
236enum Prop {
237    Width,
238    Height,
239    MinWidth,
240    MinHeight,
241    MaxWidth,
242    MaxHeight,
243    Padding,
244    Margin,
245    Gap,
246    Direction,
247    Wrap,
248    Grow,
249    Shrink,
250    Basis,
251    AlignItems,
252    JustifyContent,
253    Inset,
254    BorderWidth,
255    Overflow,
256    Hidden,
257    Background,
258    BorderColor,
259    TextColor,
260    Radius,
261    ScrollOffset,
262    Disabled,
263    Cursor,
264    Pin,
265}
266
267impl Binding {
268    /// A binding that writes one layout property.
269    fn layout<T: 'static>(
270        prop: Prop,
271        get: Rc<dyn Fn() -> T>,
272        write: fn(&mut LayoutProps, T),
273    ) -> Binding {
274        Binding {
275            key: Some(Key::Style(prop)),
276            install: Box::new(move |id, queue| {
277                let queue = queue.clone();
278                RenderEffect::new(move || {
279                    let value = get();
280                    let queue = queue.clone();
281                    queue.push(Box::new(move |tree| {
282                        tree.apply_layout(id, move |layout| write(layout, value));
283                    }));
284                })
285            }),
286        }
287    }
288
289    /// A binding that writes one paint property.
290    fn paint<T: 'static>(
291        prop: Prop,
292        get: Rc<dyn Fn() -> T>,
293        write: fn(&mut PaintProps, T),
294    ) -> Binding {
295        Binding {
296            key: Some(Key::Style(prop)),
297            install: Box::new(move |id, queue| {
298                let queue = queue.clone();
299                RenderEffect::new(move || {
300                    let value = get();
301                    let queue = queue.clone();
302                    queue.push(Box::new(move |tree| {
303                        tree.apply_paint(id, move |paint| write(paint, value));
304                    }));
305                })
306            }),
307        }
308    }
309
310    /// A binding that writes the node's disabled bit.
311    fn disabled(get: Rc<dyn Fn() -> bool>) -> Binding {
312        Binding {
313            key: Some(Key::Style(Prop::Disabled)),
314            install: Box::new(move |id, queue| {
315                let queue = queue.clone();
316                RenderEffect::new(move || {
317                    let value = get();
318                    let queue = queue.clone();
319                    queue.push(Box::new(move |tree| {
320                        tree.set_disabled(id, value);
321                    }));
322                })
323            }),
324        }
325    }
326
327    /// A binding that writes the node's accessible label.
328    fn a11y_label(get: Rc<dyn Fn() -> String>) -> Binding {
329        Binding {
330            key: None,
331            install: Box::new(move |id, queue| {
332                let queue = queue.clone();
333                RenderEffect::new(move || {
334                    let value = get();
335                    let queue = queue.clone();
336                    queue.push(Box::new(move |tree| {
337                        tree.set_a11y_label(id, Some(value));
338                    }));
339                })
340            }),
341        }
342    }
343
344    /// A binding that writes the node's scroll offset.
345    ///
346    /// The write moves the node's flowing descendants without running the
347    /// layout engine, which is what a scroll view does on every wheel tick.
348    fn scroll_offset(get: Rc<dyn Fn() -> Point>) -> Binding {
349        Binding {
350            key: Some(Key::Style(Prop::ScrollOffset)),
351            install: Box::new(move |id, queue| {
352                let queue = queue.clone();
353                RenderEffect::new(move || {
354                    let value = get();
355                    let queue = queue.clone();
356                    queue.push(Box::new(move |tree| {
357                        tree.set_scroll_offset(id, value);
358                    }));
359                })
360            }),
361        }
362    }
363
364    /// A binding that writes which flowing child the node pins, and where.
365    fn pin_child(get: Rc<dyn Fn() -> Option<(usize, f32)>>) -> Binding {
366        Binding {
367            key: Some(Key::Style(Prop::Pin)),
368            install: Box::new(move |id, queue| {
369                let queue = queue.clone();
370                RenderEffect::new(move || {
371                    let value = get();
372                    let queue = queue.clone();
373                    queue.push(Box::new(move |tree| {
374                        tree.set_pin(id, value);
375                    }));
376                })
377            }),
378        }
379    }
380
381    /// A binding that writes the node's cursor.
382    fn cursor(get: Rc<dyn Fn() -> Option<crate::window::Cursor>>) -> Binding {
383        Binding {
384            key: Some(Key::Style(Prop::Cursor)),
385            install: Box::new(move |id, queue| {
386                let queue = queue.clone();
387                RenderEffect::new(move || {
388                    let value = get();
389                    let queue = queue.clone();
390                    queue.push(Box::new(move |tree| {
391                        tree.set_cursor(id, value);
392                    }));
393                })
394            }),
395        }
396    }
397
398    /// A binding that writes one property of the node's widget.
399    ///
400    /// The apply function reports how much of the node its write invalidated,
401    /// and the node is marked with that. A write that changes what the widget
402    /// measures returns [`Dirty::Layout`], which also invalidates the size the
403    /// layout engine cached for the node.
404    fn widget<W: Widget, T: 'static>(
405        key: Key,
406        get: Rc<dyn Fn() -> T>,
407        apply: fn(&mut W, T) -> Dirty,
408    ) -> Binding {
409        Binding {
410            key: Some(key),
411            install: Box::new(move |id, queue| {
412                let queue = queue.clone();
413                RenderEffect::new(move || {
414                    let value = get();
415                    let queue = queue.clone();
416                    queue.push(Box::new(move |tree| {
417                        let dirty = match tree.widget_mut::<W>(id) {
418                            Some(widget) => apply(widget, value),
419                            None => return,
420                        };
421                        tree.mark(id, dirty);
422                    }));
423                })
424            }),
425        }
426    }
427}
428
429/// A node under construction: its widget, its style, its pending bindings and
430/// its children.
431///
432/// Build one with a widget constructor such as [`panel`](crate::widget::panel),
433/// chain the builder methods, and hand it to a parent with [`Element::child`]
434/// or to [`show`].
435///
436/// A builder takes either a plain value, which is written into the style
437/// immediately, or a closure, which becomes a binding that is read at mount and
438/// again whenever a signal it reads changes.
439pub struct Element<W: Widget> {
440    /// The widget the node will own.
441    widget: W,
442    /// The style the node starts with.
443    style: Style,
444    /// Bindings installed when the node mounts.
445    bindings: Vec<Binding>,
446    /// The style patches per interaction state, when a variant builder ran.
447    variants: Option<Variants>,
448    /// The input handlers the node will own.
449    handlers: Handlers,
450    /// Whether the node starts disabled.
451    disabled: bool,
452    /// The cursor the node sets for the pointer over it, when its element
453    /// set a static one.
454    cursor: Option<crate::window::Cursor>,
455    /// Whether the node can take the keyboard focus.
456    focusable: bool,
457    /// Whether the node requests the focus on the first frame after it is
458    /// laid out.
459    autofocus: bool,
460    /// Whether the node keeps Tab movement inside its subtree while it is
461    /// mounted.
462    trap_focus: bool,
463    /// The signal that pins the node's scroll offset to the end of its
464    /// content while it reads `true`.
465    follow_end: Option<RwSignal<bool>>,
466    /// The role the accessibility projection reports, when an element set
467    /// one.
468    a11y_role: Option<Role>,
469    /// The accessible label an element set, when it set one.
470    a11y_label: Option<Value<String>>,
471    /// The scroll offset written to the node when it mounts.
472    scroll_offset: Point,
473    /// Applied to the style of every child as it is added.
474    child_styling: Option<ChildStyling>,
475    /// The children, in paint order.
476    children: Vec<AnyElement>,
477}
478
479impl<W: Widget> Element<W> {
480    /// Creates an element for `widget` with the default style.
481    ///
482    /// ```
483    /// use smudge_core::element::Element;
484    /// use smudge_core::widget::Panel;
485    ///
486    /// let element = Element::new(Panel);
487    /// ```
488    pub fn new(widget: W) -> Element<W> {
489        Element {
490            widget,
491            style: Style::default(),
492            bindings: Vec::new(),
493            variants: None,
494            handlers: Handlers::default(),
495            disabled: false,
496            cursor: None,
497            focusable: false,
498            autofocus: false,
499            trap_focus: false,
500            follow_end: None,
501            a11y_role: None,
502            a11y_label: None,
503            scroll_offset: Point::default(),
504            child_styling: None,
505            children: Vec::new(),
506        }
507    }
508
509    /// Appends `child` after the children the element already has.
510    ///
511    /// When [`Element::style_children`] set a style for the children, it is
512    /// applied to this one.
513    pub fn child(mut self, child: impl IntoElement) -> Self {
514        let mut child = child.into_any();
515        if let Some(style) = &self.child_styling {
516            style(&mut child.style);
517        }
518        self.children.push(child);
519        self
520    }
521
522    /// Appends every child of `children`, in order.
523    ///
524    /// When [`Element::style_children`] set a style for the children, it is
525    /// applied to each one.
526    pub fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self {
527        self.children.extend(children.into_iter().map(|child| {
528            let mut child = child.into_any();
529            if let Some(style) = &self.child_styling {
530                style(&mut child.style);
531            }
532            child
533        }));
534        self
535    }
536
537    /// Applies `style` to every direct child of this element: to the children
538    /// added so far, at once, and to every child added afterwards as it is
539    /// added.
540    ///
541    /// The children of a child keep their own style, and a child that mounts
542    /// later through [`show`] mounts under a slot, so it is styled only
543    /// through that slot. A binding on the same field of a child applies when
544    /// the child mounts, after this style, so the binding wins.
545    ///
546    /// This is how a container decides how its children sit: a stack applies
547    /// the absolute position that makes children overlap, for example.
548    ///
549    /// ```
550    /// use smudge_core::element::Element;
551    /// use smudge_core::widget::Panel;
552    ///
553    /// let layers = Element::new(Panel).style_children(|style| {
554    ///     style.paint.corner_radius = 4.0.into();
555    /// });
556    /// ```
557    pub fn style_children(mut self, style: impl Fn(&mut Style) + 'static) -> Self {
558        let style = Rc::new(style);
559        for child in &mut self.children {
560            style(&mut child.style);
561        }
562        self.child_styling = Some(style);
563        self
564    }
565
566    /// Writes one layout property, or records a binding for it.
567    fn layout_value<T: 'static>(
568        mut self,
569        prop: Prop,
570        value: impl Into<Value<T>>,
571        write: fn(&mut LayoutProps, T),
572    ) -> Self {
573        self.replace_binding(prop);
574        match value.into() {
575            Value::Static(value) => write(&mut self.style.layout, value),
576            Value::Dynamic(get) => self.bindings.push(Binding::layout(prop, get, write)),
577        }
578        self
579    }
580
581    /// Drops the bindings recorded for `prop` so far, because a later write
582    /// of the same property, fixed or bound, replaces them: the last builder
583    /// call for a property wins, as it does between two fixed values.
584    fn replace_binding(&mut self, prop: Prop) {
585        self.drop_bindings(Key::Style(prop));
586    }
587
588    /// Drops the bindings recorded for `key` so far.
589    fn drop_bindings(&mut self, key: Key) {
590        self.bindings.retain(|binding| binding.key != Some(key));
591    }
592
593    /// Writes one paint property, or records a binding for it.
594    fn paint_value<T: 'static>(
595        mut self,
596        prop: Prop,
597        value: impl Into<Value<T>>,
598        write: fn(&mut PaintProps, T),
599    ) -> Self {
600        self.replace_binding(prop);
601        match value.into() {
602            Value::Static(value) => write(&mut self.style.paint, value),
603            Value::Dynamic(get) => self.bindings.push(Binding::paint(prop, get, write)),
604        }
605        self
606    }
607
608    /// Sets the width. This takes part in layout.
609    pub fn width(self, width: impl Into<Value<Length>>) -> Self {
610        self.layout_value(Prop::Width, width, |layout, width| layout.width = width)
611    }
612
613    /// Sets the height. This takes part in layout.
614    pub fn height(self, height: impl Into<Value<Length>>) -> Self {
615        self.layout_value(Prop::Height, height, |layout, height| {
616            layout.height = height
617        })
618    }
619
620    /// Sets the width and the height, in logical pixels. This takes part in
621    /// layout.
622    pub fn size(self, size: impl Into<Value<Size>>) -> Self {
623        let (width, height): (Value<Length>, Value<Length>) = match size.into() {
624            Value::Static(size) => (
625                Value::Static(Length::px(size.width)),
626                Value::Static(Length::px(size.height)),
627            ),
628            Value::Dynamic(get) => {
629                let get_height = Rc::clone(&get);
630                (
631                    Value::Dynamic(Rc::new(move || Length::px(get().width))),
632                    Value::Dynamic(Rc::new(move || Length::px(get_height().height))),
633                )
634            }
635        };
636        self.width(width).height(height)
637    }
638
639    /// Sets the lower bound of the width. This takes part in layout.
640    pub fn min_width(self, width: impl Into<Value<Length>>) -> Self {
641        self.layout_value(Prop::MinWidth, width, |layout, width| {
642            layout.min_width = width
643        })
644    }
645
646    /// Sets the lower bound of the height. This takes part in layout.
647    pub fn min_height(self, height: impl Into<Value<Length>>) -> Self {
648        self.layout_value(Prop::MinHeight, height, |layout, height| {
649            layout.min_height = height
650        })
651    }
652
653    /// Sets the upper bound of the width. This takes part in layout.
654    pub fn max_width(self, width: impl Into<Value<Length>>) -> Self {
655        self.layout_value(Prop::MaxWidth, width, |layout, width| {
656            layout.max_width = width
657        })
658    }
659
660    /// Sets the upper bound of the height. This takes part in layout.
661    pub fn max_height(self, height: impl Into<Value<Length>>) -> Self {
662        self.layout_value(Prop::MaxHeight, height, |layout, height| {
663            layout.max_height = height
664        })
665    }
666
667    /// Sets the same padding on all four sides. This takes part in layout.
668    pub fn padding(self, padding: impl Into<Value<Length>>) -> Self {
669        self.layout_value(Prop::Padding, padding, |layout, padding| {
670            layout.padding = Edges::all(padding);
671        })
672    }
673
674    /// Sets the horizontal padding from `width` and the vertical padding from
675    /// `height`. This takes part in layout.
676    pub fn padding_xy(self, padding: impl Into<Value<Size>>) -> Self {
677        self.layout_value(Prop::Padding, padding, |layout, padding| {
678            layout.padding = Edges::xy(Length::px(padding.width), Length::px(padding.height));
679        })
680    }
681
682    /// Sets the same margin on all four sides. This takes part in layout.
683    pub fn margin(self, margin: impl Into<Value<Length>>) -> Self {
684        self.layout_value(Prop::Margin, margin, |layout, margin| {
685            layout.margin = Edges::all(margin);
686        })
687    }
688
689    /// Sets the space between adjacent children. This takes part in layout.
690    pub fn gap(self, gap: impl Into<Value<Size>>) -> Self {
691        self.layout_value(Prop::Gap, gap, |layout, gap| layout.gap = gap)
692    }
693
694    /// Sets the main axis of the children's flex layout. This takes part in
695    /// layout.
696    pub fn direction(self, direction: impl Into<Value<Direction>>) -> Self {
697        self.layout_value(Prop::Direction, direction, |layout, direction| {
698            layout.direction = direction;
699        })
700    }
701
702    /// Lays the children out left to right. This takes part in layout.
703    pub fn row(mut self) -> Self {
704        self.replace_binding(Prop::Direction);
705        self.style.layout.direction = Direction::Row;
706        self
707    }
708
709    /// Lays the children out top to bottom. This takes part in layout.
710    pub fn column(mut self) -> Self {
711        self.replace_binding(Prop::Direction);
712        self.style.layout.direction = Direction::Column;
713        self
714    }
715
716    /// Lets children that do not fit move to a new line instead of shrinking.
717    /// This takes part in layout.
718    pub fn wrap(self, wrap: impl Into<Value<bool>>) -> Self {
719        self.layout_value(Prop::Wrap, wrap, |layout, wrap| layout.wrap = wrap)
720    }
721
722    /// Sets the share of the leftover space on the main axis this node takes.
723    /// This takes part in layout.
724    pub fn grow(self, grow: impl Into<Value<f32>>) -> Self {
725        self.layout_value(Prop::Grow, grow, |layout, grow| layout.grow = grow)
726    }
727
728    /// Sets how readily this node gives up space when its siblings overflow.
729    /// This takes part in layout.
730    pub fn shrink(self, shrink: impl Into<Value<f32>>) -> Self {
731        self.layout_value(Prop::Shrink, shrink, |layout, shrink| {
732            layout.shrink = shrink
733        })
734    }
735
736    /// Sets the main axis size the node starts from before growing or
737    /// shrinking. This takes part in layout.
738    pub fn basis(self, basis: impl Into<Value<Length>>) -> Self {
739        self.layout_value(Prop::Basis, basis, |layout, basis| layout.basis = basis)
740    }
741
742    /// Sets how the children line up across the main axis. This takes part in
743    /// layout.
744    pub fn align_items(self, align: impl Into<Value<Align>>) -> Self {
745        self.layout_value(Prop::AlignItems, align, |layout, align| {
746            layout.align_items = Some(align)
747        })
748    }
749
750    /// Sets how the children are spread along the main axis. This takes part in
751    /// layout.
752    pub fn justify_content(self, justify: impl Into<Value<Justify>>) -> Self {
753        self.layout_value(Prop::JustifyContent, justify, |layout, justify| {
754            layout.justify_content = Some(justify);
755        })
756    }
757
758    /// Takes the node out of normal flow, so its insets place it against its
759    /// containing block and its siblings are laid out as if it were not there.
760    /// This takes part in layout.
761    pub fn absolute(mut self) -> Self {
762        self.style.layout.position = Position::Absolute;
763        self
764    }
765
766    /// Sets the offsets from the containing block's edges. This takes part in
767    /// layout.
768    pub fn inset(self, inset: impl Into<Value<Edges<Length>>>) -> Self {
769        self.layout_value(Prop::Inset, inset, |layout, inset| layout.inset = inset)
770    }
771
772    /// Sets the border width, the same on all four sides. This takes part in
773    /// layout, because the border takes space away from the content. The border
774    /// is painted in the color set by [`Element::border_color`].
775    pub fn border(self, width: impl Into<Value<f32>>) -> Self {
776        self.layout_value(Prop::BorderWidth, width, |layout, width| {
777            layout.border_width = Edges::all(width);
778        })
779    }
780
781    /// Clips the children to the node's bounds. This takes part in layout,
782    /// because clipping also changes the automatic minimum size of a flex item.
783    pub fn clip(self, clip: impl Into<Value<bool>>) -> Self {
784        self.layout_value(Prop::Overflow, clip, |layout, clip| {
785            layout.overflow = if clip {
786                Overflow::Clip
787            } else {
788                Overflow::Visible
789            };
790        })
791    }
792
793    /// Sets what happens to children that do not fit inside the node. This
794    /// takes part in layout: [`Overflow::Scroll`] makes the node a scroll
795    /// container, whose automatic minimum size as a flex item is zero, and
796    /// [`Element::clip`] is the shorthand for [`Overflow::Clip`].
797    pub fn overflow(self, overflow: impl Into<Value<Overflow>>) -> Self {
798        self.layout_value(Prop::Overflow, overflow, |layout, overflow| {
799            layout.overflow = overflow;
800        })
801    }
802
803    /// Hides the node and its subtree, or shows them again. This takes part in
804    /// layout, because a hidden node is not laid out and paints nothing.
805    pub fn hidden(self, hidden: impl Into<Value<bool>>) -> Self {
806        self.layout_value(Prop::Hidden, hidden, |layout, hidden| {
807            layout.hidden = hidden
808        })
809    }
810
811    /// Translates the node's flowing children by this offset after layout,
812    /// outside the layout engine.
813    ///
814    /// This is what a scroll view changes when it scrolls: every child that
815    /// stays in the flow moves by minus the offset in the window, without
816    /// running the layout engine again. The frame damages the areas the
817    /// children moved out of and into and wraps them in an offset display
818    /// item, so a child that only moved does not paint again. An absolutely
819    /// positioned child is left where its insets place it, so chrome drawn
820    /// over the content does not scroll away with it.
821    ///
822    /// The offset can be bound to a signal, like the style builders. It is a
823    /// position, not a style: it takes part in no layout comparison, and an
824    /// equal offset changes nothing.
825    pub fn scroll_offset(mut self, offset: impl Into<Value<Point>>) -> Self {
826        self.replace_binding(Prop::ScrollOffset);
827        match offset.into() {
828            Value::Static(offset) => self.scroll_offset = offset,
829            Value::Dynamic(get) => self.bindings.push(Binding::scroll_offset(get)),
830        }
831        self
832    }
833
834    /// Keeps one flowing child at a fixed place inside the node, whatever
835    /// the heights of the children before it.
836    ///
837    /// While `pin` returns `Some((index, y))`, every layout pass ends with
838    /// the top of the flowing child at `index` sitting `y` logical pixels
839    /// below the top of the node's content box. The children keep their
840    /// order and the sizes the pass gave them, so the ones before the pinned
841    /// child stack upward from it and the ones after it stack downward,
842    /// edge to edge. A child that grows therefore pushes its neighbours away
843    /// from the pinned child in the frame it grows, and never overlaps them.
844    ///
845    /// The pin moves the children the way [`Element::scroll_offset`] does,
846    /// outside the layout engine, so do not give the node a scroll offset
847    /// too. `None`, an index past the last child, or a pinned child that is
848    /// hidden or absolutely positioned leaves the children where they are. A change of the pin alone moves them without a
849    /// layout pass.
850    ///
851    /// ```
852    /// use smudge_core::element::Element;
853    /// use smudge_core::style::px;
854    /// use smudge_core::widget::{Panel, panel};
855    ///
856    /// // The second row stays 100 pixels down, however tall the first is.
857    /// let rows = Element::new(Panel)
858    ///     .column()
859    ///     .pin_child(|| Some((1, 100.0)))
860    ///     .child(panel().height(px(30.0)))
861    ///     .child(panel().height(px(30.0)));
862    /// ```
863    pub fn pin_child(mut self, pin: impl Fn() -> Option<(usize, f32)> + 'static) -> Self {
864        self.replace_binding(Prop::Pin);
865        self.bindings.push(Binding::pin_child(Rc::new(pin)));
866        self
867    }
868
869    /// Sets the fill painted behind the node. This repaints the node without
870    /// laying it out again.
871    ///
872    /// The color can be a [`Color`] or a
873    /// [`ColorToken`]. A token resolves against the
874    /// theme that is current when the node paints.
875    pub fn background(self, color: impl Into<Value<ColorValue>>) -> Self {
876        self.paint_value(Prop::Background, color, |paint, color| {
877            paint.background = Some(color)
878        })
879    }
880
881    /// Sets the color of the border whose width [`Element::border`] sets. This
882    /// repaints the node without laying it out again.
883    ///
884    /// The color can be a [`Color`] or a
885    /// [`ColorToken`]. A token resolves against the
886    /// theme that is current when the node paints.
887    pub fn border_color(self, color: impl Into<Value<ColorValue>>) -> Self {
888        self.paint_value(Prop::BorderColor, color, |paint, color| {
889            paint.border_color = Some(color)
890        })
891    }
892
893    /// Sets the color a widget's text paints with. This repaints the node
894    /// without laying it out again.
895    ///
896    /// Widgets that show text read it; widgets without text ignore it. The
897    /// color can be a [`Color`] or a
898    /// [`ColorToken`]. A token resolves against the
899    /// theme that is current when the node paints.
900    pub fn text_color(self, color: impl Into<Value<ColorValue>>) -> Self {
901        self.paint_value(Prop::TextColor, color, |paint, color| {
902            paint.text_color = Some(color)
903        })
904    }
905
906    /// Sets the corner radius of the background and the border, the same on all
907    /// four corners. An image widget rounds the pixels it paints by the same
908    /// radius. This repaints the node without laying it out again.
909    ///
910    /// The radius can be an [`f32`] or a
911    /// [`RadiusToken`]. A token resolves against
912    /// the theme that is current when the node paints.
913    pub fn corner_radius(self, radius: impl Into<Value<RadiusValue>>) -> Self {
914        self.paint_value(Prop::Radius, radius, |paint, radius| {
915            paint.corner_radius = radius;
916        })
917    }
918
919    /// Records a patch built by `build` into one slot of the element's
920    /// variants.
921    fn variant(
922        mut self,
923        select: impl FnOnce(&mut Variants) -> &mut Option<StylePatch>,
924        build: impl FnOnce(PatchBuilder) -> PatchBuilder,
925    ) -> Self {
926        let builder = build(PatchBuilder::default());
927        let variants = self.variants.get_or_insert_with(Variants::default);
928        *select(variants) = Some(builder.patch());
929        self
930    }
931
932    /// Applies a patch while the node is in the hovered chain, which is the
933    /// node under the pointer that can respond and its ancestors.
934    ///
935    /// The closure records static values into a [`PatchBuilder`]; a reactive
936    /// value has no place in a patch, so the patch methods take plain values.
937    /// While the pointer is over the node the patch overrides the fields it
938    /// sets, and when the pointer leaves, the base style stands again. A node
939    /// with a variant is a target for hover and presses even without
940    /// handlers, so a styled card reacts to the pointer on its own.
941    ///
942    /// A change of hover re-resolves the style: a patch that touches only
943    /// paint properties repaints the node, one that touches layout
944    /// properties lays it out again. Hover also follows a layout that moves
945    /// nodes under a resting pointer, except that a layout never takes the
946    /// hover away from a node whose hover patch changes its layout: such a
947    /// patch can move the node off the pointer, and the node then stays
948    /// hovered until the pointer moves, instead of flickering.
949    ///
950    /// ```
951    /// use smudge_core::geometry::Color;
952    /// use smudge_core::widget::panel;
953    ///
954    /// let card = panel()
955    ///     .background(Color::rgb(50, 50, 50))
956    ///     .hover(|p| p.background(Color::rgb(70, 70, 70)));
957    /// ```
958    pub fn hover(self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder) -> Self {
959        self.variant(|variants| &mut variants.hovered, patch)
960    }
961
962    /// Applies a patch while the node holds the keyboard focus and the focus
963    /// last moved by keyboard navigation.
964    ///
965    /// The focus a press moved draws no focus style, so a ring follows Tab and
966    /// not a mouse click. Everything else works as
967    /// [`hover`](Element::hover) does.
968    ///
969    /// ```
970    /// use smudge_core::geometry::Color;
971    /// use smudge_core::style::px;
972    /// use smudge_core::widget::panel;
973    ///
974    /// let field = panel()
975    ///     .width(px(120.0))
976    ///     .height(px(24.0))
977    ///     .focusable()
978    ///     .focused(|p| p.border(1.0).border_color(Color::rgb(0, 120, 215)));
979    /// ```
980    pub fn focused(self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder) -> Self {
981        self.variant(|variants| &mut variants.focused, patch)
982    }
983
984    /// Applies a patch while a primary press is held on the node.
985    ///
986    /// Everything works as [`hover`](Element::hover) does; the pressed state
987    /// starts when the button goes down on the node and ends when it is
988    /// released.
989    ///
990    /// ```
991    /// use smudge_core::geometry::Color;
992    /// use smudge_core::widget::panel;
993    ///
994    /// let button = panel()
995    ///     .background(Color::rgb(50, 50, 50))
996    ///     .pressed(|p| p.background(Color::rgb(30, 30, 30)));
997    /// ```
998    pub fn pressed(self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder) -> Self {
999        self.variant(|variants| &mut variants.pressed, patch)
1000    }
1001
1002    /// Applies a patch while the node is disabled.
1003    ///
1004    /// The patch wins over every other state, so a disabled control keeps its
1005    /// switched-off look while it is hovered or pressed. Everything else
1006    /// works as [`hover`](Element::hover) does.
1007    ///
1008    /// ```
1009    /// use smudge_core::geometry::Color;
1010    /// use smudge_core::widget::panel;
1011    ///
1012    /// let button = panel()
1013    ///     .background(Color::rgb(50, 50, 50))
1014    ///     .disabled_style(|p| p.background(Color::rgb(35, 35, 35)));
1015    /// ```
1016    pub fn disabled_style(self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder) -> Self {
1017        self.variant(|variants| &mut variants.disabled, patch)
1018    }
1019
1020    /// Runs `handler` when the primary button is released over the node after
1021    /// a press that started on it.
1022    ///
1023    /// The press is captured: between the press and the release the node keeps
1024    /// the pointer even when it moves away, and the handler runs only when the
1025    /// release happens over the node again. A press released elsewhere runs
1026    /// nothing.
1027    ///
1028    /// ```
1029    /// use std::cell::Cell;
1030    /// use std::rc::Rc;
1031    ///
1032    /// use smudge_core::app::{App, AppConfig, RepaintMode};
1033    /// use smudge_core::geometry::{Color, Point, Size};
1034    /// use smudge_core::input::{InputEvent, PointerButton};
1035    /// use smudge_core::style::px;
1036    /// use smudge_core::widget::panel;
1037    ///
1038    /// let presses = Rc::new(Cell::new(0u32));
1039    /// let counted = Rc::clone(&presses);
1040    /// let mut app = App::new(
1041    ///     AppConfig {
1042    ///         viewport: Size {
1043    ///             width: 100.0,
1044    ///             height: 60.0,
1045    ///         },
1046    ///         scale: 1.0,
1047    ///         clear_color: Color::WHITE,
1048    ///         repaint: RepaintMode::Damage,
1049    ///     },
1050    ///     move || {
1051    ///         panel().width(px(40.0)).height(px(20.0)).on_press(move || {
1052    ///             counted.set(counted.get() + 1);
1053    ///         })
1054    ///     },
1055    /// );
1056    /// app.frame();
1057    ///
1058    /// let corner = Point { x: 10.0, y: 5.0 };
1059    /// app.handle_event(InputEvent::PointerMoved { position: corner });
1060    /// app.handle_event(InputEvent::PointerDown {
1061    ///     position: corner,
1062    ///     button: PointerButton::Primary,
1063    /// });
1064    /// app.handle_event(InputEvent::PointerUp {
1065    ///     position: corner,
1066    ///     button: PointerButton::Primary,
1067    /// });
1068    /// assert_eq!(presses.get(), 1);
1069    /// ```
1070    pub fn on_press(mut self, handler: impl FnMut() + 'static) -> Self {
1071        self.handlers.on_press = Some(Box::new(handler));
1072        self
1073    }
1074
1075    /// Runs `handler` when the node enters (`true`) or leaves (`false`) the
1076    /// hovered chain.
1077    ///
1078    /// The hovered chain is the nearest enabled node under the pointer that can
1079    /// respond and its enabled ancestors, so a container stays hovered while
1080    /// the pointer is over one of its children, and a disabled node never
1081    /// hears it. While a press is held, hover does not change until the
1082    /// button is released. The handler runs inside the node's owner, so it can
1083    /// write the signals the element's bindings read.
1084    pub fn on_hover(mut self, handler: impl FnMut(bool) + 'static) -> Self {
1085        self.handlers.on_hover = Some(Box::new(handler));
1086        self
1087    }
1088
1089    /// Runs `handler` when the primary pointer button is pressed on the node.
1090    ///
1091    /// The position is in logical pixels, relative to the top left of the
1092    /// node's rectangle, so it does not depend on where layout or a scroll
1093    /// view put the node. Other buttons do not run it.
1094    pub fn on_pointer_down(mut self, handler: impl FnMut(Point) + 'static) -> Self {
1095        self.handlers.on_pointer_down = Some(Box::new(handler));
1096        self
1097    }
1098
1099    /// Runs `handler` when a primary press targets a node that is neither this
1100    /// node nor one of its descendants.
1101    ///
1102    /// A press on the node itself, on a child, or on a deeper descendant does
1103    /// not run it, so a popup asks for presses outside itself and closes on
1104    /// the ones it gets. A press that reaches no node at all is outside every
1105    /// node.
1106    pub fn on_press_outside(mut self, handler: impl FnMut() + 'static) -> Self {
1107        self.handlers.on_press_outside = Some(Box::new(handler));
1108        self
1109    }
1110
1111    /// Runs `handler` when the wheel scrolls while the node is in the hovered
1112    /// chain, which is the case when the pointer is over the node or over one
1113    /// of its descendants.
1114    ///
1115    /// The delta is in logical pixels, positive for scrolling right and down.
1116    /// The handlers run from the deepest node in the hovered chain outward,
1117    /// and the first that returns [`Handled::Yes`] takes the whole event, so
1118    /// of two nested scroll views the one under the pointer scrolls and the
1119    /// one around it does not. A handler that cannot use the event, such as
1120    /// a view already scrolled to its end in the wheel's direction, returns
1121    /// [`Handled::No`] and the event bubbles to the next one. The handler
1122    /// runs inside the node's owner, so it can write the signals the
1123    /// element's bindings read.
1124    pub fn on_wheel(mut self, handler: impl FnMut(Point) -> Handled + 'static) -> Self {
1125        self.handlers.on_wheel = Some(Box::new(handler));
1126        self
1127    }
1128
1129    /// Runs `handler` when the pointer moves while a press that started on
1130    /// the node is held, which is how a drag reaches the node it started on.
1131    ///
1132    /// With no press held, the handler runs when the node is the hover target
1133    /// and the pointer moves, so a node can follow the pointer without being
1134    /// pressed. While a press is held, hover does not change, and the moves
1135    /// go to the captured node alone. The position is in logical pixels,
1136    /// relative to the top left of the node's rectangle. The handler runs
1137    /// inside the node's owner, so it can write the signals the element's
1138    /// bindings read.
1139    pub fn on_pointer_move(mut self, handler: impl FnMut(Point) + 'static) -> Self {
1140        self.handlers.on_pointer_move = Some(Box::new(handler));
1141        self
1142    }
1143
1144    /// Runs `handler` when the primary button is released.
1145    ///
1146    /// After a press on the node, the handler runs when the button comes up
1147    /// wherever that happens, which is how a drag ends even when the pointer
1148    /// is no longer over the node. With no press held, the handler runs when
1149    /// the release happens over the node as the hover target. The position is
1150    /// in logical pixels, relative to the top left of the node's rectangle.
1151    /// The handler runs inside the node's owner, so it can write the signals the
1152    /// element's bindings read.
1153    pub fn on_pointer_up(mut self, handler: impl FnMut(Point) + 'static) -> Self {
1154        self.handlers.on_pointer_up = Some(Box::new(handler));
1155        self
1156    }
1157
1158    /// Runs `handler` when the input method commits text while the node or
1159    /// one of its descendants holds the keyboard focus.
1160    ///
1161    /// A commit can arrive with no key event at all, because composing text
1162    /// with an input method ends in a commit rather than a key press, so an
1163    /// editor that takes text needs this handler. The commit goes to the
1164    /// deepest handler in the focused chain and does not bubble past it.
1165    /// While a focus trap is active and the focus is outside it, the commit
1166    /// starts at the trap instead, as a key does. The handler runs inside
1167    /// the node's owner, so it can write the signals the element's bindings
1168    /// read.
1169    pub fn on_ime_commit(mut self, handler: impl FnMut(&str) + 'static) -> Self {
1170        self.handlers.on_ime_commit = Some(Box::new(handler));
1171        self
1172    }
1173
1174    /// Runs `handler` when the input method changes its composing text while
1175    /// the node or one of its descendants holds the keyboard focus.
1176    ///
1177    /// The handler receives the composing text and the byte range of the
1178    /// cursor inside it, or `None` when the input method shows no cursor. An
1179    /// empty text means the composition was canceled or committed, and the
1180    /// preedit must go. An editor draws the composing text itself, usually
1181    /// underlined, and does not write it into its value until the commit
1182    /// arrives. Like [`Element::on_ime_commit`], the event goes to the
1183    /// deepest handler in the focused chain and does not bubble past it, and
1184    /// the handler runs inside the node's owner.
1185    pub fn on_ime_preedit(
1186        mut self,
1187        handler: impl FnMut(&str, Option<(usize, usize)>) + 'static,
1188    ) -> Self {
1189        self.handlers.on_ime_preedit = Some(Box::new(handler));
1190        self
1191    }
1192
1193    /// Disables the node, which takes it out of hit testing, or enables it
1194    /// again.
1195    ///
1196    /// A disabled node receives no pointer events of its own: its handlers
1197    /// never run, and a press over it passes to whatever enabled node is hit
1198    /// instead. Its children are still hit. This can be bound to a signal,
1199    /// like the style builders.
1200    pub fn disabled(mut self, disabled: impl Into<Value<bool>>) -> Self {
1201        self.replace_binding(Prop::Disabled);
1202        match disabled.into() {
1203            Value::Static(disabled) => self.disabled = disabled,
1204            Value::Dynamic(get) => self.bindings.push(Binding::disabled(get)),
1205        }
1206        self
1207    }
1208
1209    /// Sets the cursor the pointer shows while it is over the node, or over
1210    /// a descendant that sets none of its own.
1211    ///
1212    /// The window shows the cursor of the deepest enabled node under the
1213    /// pointer that sets one, so a nested setter wins over an ancestor's.
1214    /// Setting a cursor does not make the node a target: a press over a node
1215    /// that sets only a cursor still lands on the nearest ancestor that
1216    /// responds, and so does hover. This takes a [`Cursor`], or an
1217    /// `Option<Cursor>` where `None` leaves the choice to the ancestors, and
1218    /// it can be bound to a signal, like the style builders: a binding that
1219    /// returns `None` hands the choice back to the ancestors.
1220    ///
1221    /// [`Cursor`]: crate::window::Cursor
1222    ///
1223    /// ```
1224    /// use smudge_core::geometry::Color;
1225    /// use smudge_core::widget::panel;
1226    /// use smudge_core::window::Cursor;
1227    ///
1228    /// let link = panel()
1229    ///     .width(smudge_core::style::px(80.0))
1230    ///     .height(smudge_core::style::px(24.0))
1231    ///     .background(Color::rgb(40, 40, 48))
1232    ///     .cursor(Cursor::Pointer);
1233    /// ```
1234    pub fn cursor(mut self, cursor: impl Into<Value<Option<crate::window::Cursor>>>) -> Self {
1235        self.replace_binding(Prop::Cursor);
1236        match cursor.into() {
1237            Value::Static(cursor) => self.cursor = cursor,
1238            Value::Dynamic(get) => self.bindings.push(Binding::cursor(get)),
1239        }
1240        self
1241    }
1242
1243    /// Sets the role the accessibility projection reports for the node.
1244    ///
1245    /// A widget that reports no role of its own stays out of the projection
1246    /// and its children attach to the nearest projected ancestor, so this
1247    /// builder places a plain container on the accessibility tree. The role
1248    /// is fixed for the node's lifetime, and it overrides the role the
1249    /// widget itself reports.
1250    pub fn role(mut self, role: Role) -> Self {
1251        self.a11y_role = Some(role);
1252        self
1253    }
1254
1255    /// Sets the accessible name a screen reader announces for the node.
1256    ///
1257    /// This can be bound to a signal, like the style builders. It overrides
1258    /// the name the widget itself reports.
1259    pub fn accessible_label(mut self, label: impl Into<Value<String>>) -> Self {
1260        self.a11y_label = Some(label.into());
1261        self
1262    }
1263
1264    /// Makes the node able to take the keyboard focus, by a press on it or by
1265    /// Tab navigation.
1266    ///
1267    /// While a node holds the focus, key events reach it before they bubble to
1268    /// its ancestors, which is what [`Element::on_key`] hears.
1269    /// [`Element::on_key`] implies this, so a key handler never needs a
1270    /// separate `focusable` call.
1271    pub fn focusable(mut self) -> Self {
1272        self.focusable = true;
1273        self
1274    }
1275
1276    /// Takes the keyboard focus on the first frame the node is laid out
1277    /// after it mounts.
1278    ///
1279    /// The request resolves after the layout pass that lays the node out, so
1280    /// the focus is set before the frame paints and a node a [`show`] mounts
1281    /// takes the focus in the frame it appears in. The request runs once per
1282    /// mount: when the focus moves away later, the node does not ask again,
1283    /// and a node unmounted and mounted again by a fresh [`show`] run does.
1284    /// A node that is hidden, or sits under a hidden ancestor, keeps its
1285    /// request until it is first laid out visible, so a dialog that mounts
1286    /// hidden and shows later takes the focus in the frame it shows in. A
1287    /// request whose node is disabled when it resolves is dropped and never
1288    /// asked again. When several nodes show in one frame, the node painted
1289    /// last wins.
1290    ///
1291    /// While a focus trap is mounted, only a node inside the trap can take
1292    /// the focus this way; a request for a node outside it is dropped, like
1293    /// any other request that cannot take the focus.
1294    ///
1295    /// This makes the node focusable, like [`Element::on_key`] does.
1296    ///
1297    /// ```
1298    /// use std::cell::Cell;
1299    /// use std::rc::Rc;
1300    ///
1301    /// use smudge_core::app::{App, AppConfig, RepaintMode};
1302    /// use smudge_core::geometry::{Color, Size};
1303    /// use smudge_core::widget::panel;
1304    ///
1305    /// let focused = Rc::new(Cell::new(false));
1306    /// let count = Rc::clone(&focused);
1307    /// let mut app = App::new(
1308    ///     AppConfig {
1309    ///         viewport: Size {
1310    ///             width: 100.0,
1311    ///             height: 60.0,
1312    ///         },
1313    ///         scale: 1.0,
1314    ///         clear_color: Color::WHITE,
1315    ///         repaint: RepaintMode::Damage,
1316    ///     },
1317    ///     move || panel().autofocus().on_focus(move |on| count.set(on)),
1318    /// );
1319    /// app.frame();
1320    ///
1321    /// assert!(focused.get(), "the node took the focus on its first frame");
1322    /// ```
1323    pub fn autofocus(mut self) -> Self {
1324        self.focusable = true;
1325        self.autofocus = true;
1326        self
1327    }
1328
1329    /// Keeps Tab and Shift+Tab cycling among the focusable nodes inside the
1330    /// node's subtree, for as long as the node is mounted and not hidden.
1331    ///
1332    /// A node the user Tabs to inside the trap never lands outside it: the
1333    /// cycle wraps within the subtree, and a Tab pressed with nothing
1334    /// focused enters the trap at its first focusable node. While the trap
1335    /// holds no focusable node, a Tab press leaves the focus where it is. A
1336    /// pointer press that lands on no node that can respond, or on a node
1337    /// outside the trap, leaves the focus where it is, and a press on a node
1338    /// inside the trap moves the focus as usual: to that node when it can
1339    /// take the focus, and away when it cannot. This is how a modal dialog
1340    /// keeps the keyboard inside itself instead of wandering into the view
1341    /// behind it.
1342    ///
1343    /// While the trap is active, a key that would start outside it, because
1344    /// the focus is outside the trap or nothing holds the focus, starts at
1345    /// the trap node and bubbles from there to the root, so the trap's own
1346    /// key handlers hear it and a control behind it does not.
1347    ///
1348    /// When several traps are mounted, the last one wins, and a nested trap
1349    /// therefore takes over from the one around it. Removing a trap, which
1350    /// is what unmounting a [`show`] child does, restores the trap mounted
1351    /// before it, and returns the focus to the node that held it when the
1352    /// trap became active, when that node is still mounted and can take it.
1353    /// A trap becomes active when it mounts visible or shows again. A trap
1354    /// that cannot hold the focus, because it became disabled or hidden or
1355    /// sits under a hidden ancestor, yields to an earlier one while it stays
1356    /// mounted, and a trap that hides gives the focus back the way removing
1357    /// it does, when the focus was inside it or nowhere. A hidden or
1358    /// disabled state counts once a layout pass has run, which every frame
1359    /// that changes the hidden state does.
1360    pub fn trap_focus(mut self) -> Self {
1361        self.trap_focus = true;
1362        self
1363    }
1364
1365    /// Pins the node's scroll offset to the end of its flowing content while
1366    /// `signal` reads `true`.
1367    ///
1368    /// Every layout pass that runs while the signal reads `true` ends with
1369    /// the node's offset at the furthest its flowing content reaches, minus
1370    /// the height of its content box, floored at zero. The pin uses the
1371    /// rectangles that pass just computed, so a frame that grows the content
1372    /// shows the end in view in the same frame. A signal that reads `false`
1373    /// leaves the offset where it is, and a write of `true` from anywhere
1374    /// pins the node in the next frame.
1375    ///
1376    /// What turns the signal is the caller's decision, not the core's: the
1377    /// scroll view widget pairs this builder with its wheel handling, so a
1378    /// step that leaves the end releases the pin and a step back to it
1379    /// engages it again.
1380    ///
1381    /// ```
1382    /// use smudge_core::element::Element;
1383    /// use smudge_core::reactive::RwSignal;
1384    /// use smudge_core::widget::Panel;
1385    ///
1386    /// let following = RwSignal::new(true);
1387    /// let view = Element::new(Panel).follow(following);
1388    /// ```
1389    pub fn follow(mut self, signal: RwSignal<bool>) -> Self {
1390        self.follow_end = Some(signal);
1391        self
1392    }
1393
1394    /// Runs `handler` when a key event reaches the node while the node or one
1395    /// of its descendants holds the keyboard focus.
1396    ///
1397    /// The event walks up from the focused node, and the first handler that
1398    /// returns [`Handled::Yes`] stops it, so a handler that takes a key hides
1399    /// it from its ancestors. Tab moves the focus away only when no handler
1400    /// took the Tab key. This makes the node focusable, so a press on it or a
1401    /// Tab puts the focus on it.
1402    ///
1403    /// The handler runs inside the node's owner, so it can write the signals
1404    /// the element's bindings read.
1405    ///
1406    /// ```
1407    /// use std::cell::Cell;
1408    /// use std::rc::Rc;
1409    ///
1410    /// use smudge_core::app::{App, AppConfig, RepaintMode};
1411    /// use smudge_core::geometry::{Color, Size};
1412    /// use smudge_core::input::{Handled, InputEvent, Key, KeyEvent};
1413    /// use smudge_core::style::px;
1414    /// use smudge_core::widget::panel;
1415    ///
1416    /// let enters = Rc::new(Cell::new(0u32));
1417    /// let counted = Rc::clone(&enters);
1418    /// let mut app = App::new(
1419    ///     AppConfig {
1420    ///         viewport: Size {
1421    ///             width: 100.0,
1422    ///             height: 60.0,
1423    ///         },
1424    ///         scale: 1.0,
1425    ///         clear_color: Color::WHITE,
1426    ///         repaint: RepaintMode::Damage,
1427    ///     },
1428    ///     move || {
1429    ///         panel().child(
1430    ///             panel()
1431    ///                 .width(px(40.0))
1432    ///                 .height(px(20.0))
1433    ///                 .on_key(move |event: &KeyEvent| {
1434    ///                     if event.pressed && event.key == Key::Enter {
1435    ///                         counted.set(counted.get() + 1);
1436    ///                         Handled::Yes
1437    ///                     } else {
1438    ///                         Handled::No
1439    ///                     }
1440    ///                 }),
1441    ///         )
1442    ///     },
1443    /// );
1444    /// app.frame();
1445    ///
1446    /// // Tab moves the focus to the panel, which then hears the Enter key.
1447    /// app.handle_event(InputEvent::Key(KeyEvent {
1448    ///     key: Key::Tab,
1449    ///     pressed: true,
1450    ///     repeat: false,
1451    ///     modifiers: Default::default(),
1452    ///     text: None,
1453    /// }));
1454    /// app.handle_event(InputEvent::Key(KeyEvent {
1455    ///     key: Key::Enter,
1456    ///     pressed: true,
1457    ///     repeat: false,
1458    ///     modifiers: Default::default(),
1459    ///     text: None,
1460    /// }));
1461    /// assert_eq!(enters.get(), 1);
1462    /// ```
1463    pub fn on_key(mut self, handler: impl FnMut(&KeyEvent) -> Handled + 'static) -> Self {
1464        self.handlers.on_key = Some(Box::new(handler));
1465        self.focusable = true;
1466        self
1467    }
1468
1469    /// Runs the handler set with [`Element::on_press`] when the node holds
1470    /// the keyboard focus and a fresh press of Enter or Space arrives.
1471    ///
1472    /// This is how a button fires from the keyboard with the same handler its
1473    /// pointer press uses. The activation runs before any
1474    /// [`Element::on_key`] handler on the same node, and a key repeat fires
1475    /// nothing. A press handler that ran takes the key, so it does not reach
1476    /// an ancestor; without a press handler the key bubbles as usual.
1477    ///
1478    /// This makes the node focusable, like [`Element::on_key`] does.
1479    pub fn activate_on_keys(mut self) -> Self {
1480        self.handlers.activate_on_keys = true;
1481        self.focusable = true;
1482        self
1483    }
1484
1485    /// Runs `handler` when the node gains (`true`) or loses (`false`) the
1486    /// keyboard focus.
1487    ///
1488    /// The handler does not make the node focusable; pair it with
1489    /// [`Element::focusable`] for that. It runs inside the node's owner, so it
1490    /// can write the signals the element's bindings read. A node that is
1491    /// removed while focused clears the focus without hearing `on_focus` again,
1492    /// because its handlers are being torn down with it.
1493    pub fn on_focus(mut self, handler: impl FnMut(bool) + 'static) -> Self {
1494        self.handlers.on_focus = Some(Box::new(handler));
1495        self
1496    }
1497
1498    /// Binds one property of the element's own widget.
1499    ///
1500    /// The first argument names the property: pass a value of a marker type, usually a
1501    /// unit struct, that stands for it and for nothing else. The last call
1502    /// for a key wins, fixed or bound, the way it does for the style
1503    /// builders: a later call drops the binding an earlier call with a key
1504    /// of the same type recorded. Bindings with different key types all
1505    /// stay, and they apply in the order they were made.
1506    ///
1507    /// `apply` writes the value into the widget and returns how much of the
1508    /// node the write invalidated. A write that changes what the widget
1509    /// measures returns [`Dirty::Layout`], and the node is laid out and painted
1510    /// again. Any other write returns [`Dirty::Paint`] and only repaints the
1511    /// node.
1512    ///
1513    /// ```
1514    /// use smudge_core::element::Element;
1515    /// use smudge_core::paint::PaintOp;
1516    /// use smudge_core::tree::Dirty;
1517    /// use smudge_core::widget::{PaintCx, Widget};
1518    ///
1519    /// struct Dot(f32);
1520    ///
1521    /// impl Widget for Dot {
1522    ///     fn paint(&self, _cx: &PaintCx<'_>, _out: &mut Vec<PaintOp>) {}
1523    /// }
1524    ///
1525    /// /// The key of the dot's radius.
1526    /// struct Radius;
1527    ///
1528    /// let element = Element::new(Dot(0.0)).bind(Radius, 3.0, |dot, value| {
1529    ///     dot.0 = value;
1530    ///     Dirty::Paint
1531    /// });
1532    /// ```
1533    pub fn bind<K: 'static, T: 'static>(
1534        mut self,
1535        _key: K,
1536        value: impl Into<Value<T>>,
1537        apply: fn(&mut W, T) -> Dirty,
1538    ) -> Self {
1539        let key = Key::Widget(TypeId::of::<K>());
1540        self.drop_bindings(key);
1541        match value.into() {
1542            Value::Static(value) => {
1543                apply(&mut self.widget, value);
1544            }
1545            Value::Dynamic(get) => self.bindings.push(Binding::widget(key, get, apply)),
1546        }
1547        self
1548    }
1549}
1550
1551/// An element with its widget type erased, so that a parent can hold children
1552/// of different widget types.
1553///
1554/// Build one with [`IntoElement::into_any`]. Its contents are private: only
1555/// mounting reads them.
1556pub struct AnyElement {
1557    /// The node's widget.
1558    widget: Box<dyn Widget>,
1559    /// The style the node starts with.
1560    style: Style,
1561    /// Bindings installed when the node mounts.
1562    bindings: Vec<Binding>,
1563    /// The style patches per interaction state, when a variant builder ran.
1564    variants: Option<Variants>,
1565    /// The input handlers the node will own.
1566    handlers: Handlers,
1567    /// Whether the node starts disabled.
1568    disabled: bool,
1569    /// The cursor the node sets for the pointer over it, when its element
1570    /// set a static one.
1571    cursor: Option<crate::window::Cursor>,
1572    /// Whether the node can take the keyboard focus.
1573    focusable: bool,
1574    /// Whether the node requests the focus on the first frame after it is
1575    /// laid out.
1576    autofocus: bool,
1577    /// Whether the node keeps Tab movement inside its subtree while it is
1578    /// mounted.
1579    trap_focus: bool,
1580    /// The signal that pins the node's scroll offset to the end of its
1581    /// content while it reads `true`.
1582    follow_end: Option<RwSignal<bool>>,
1583    /// The role the accessibility projection reports, when an element set
1584    /// one.
1585    a11y_role: Option<Role>,
1586    /// The accessible label an element set, when it set one.
1587    a11y_label: Option<Value<String>>,
1588    /// The scroll offset written to the node when it mounts.
1589    scroll_offset: Point,
1590    /// The children, in paint order.
1591    children: Vec<AnyElement>,
1592}
1593
1594impl AnyElement {
1595    /// Erases the widget type of `element`.
1596    fn new<W: Widget>(element: Element<W>) -> AnyElement {
1597        AnyElement {
1598            widget: Box::new(element.widget),
1599            style: element.style,
1600            bindings: element.bindings,
1601            variants: element.variants,
1602            handlers: element.handlers,
1603            disabled: element.disabled,
1604            cursor: element.cursor,
1605            focusable: element.focusable,
1606            autofocus: element.autofocus,
1607            trap_focus: element.trap_focus,
1608            follow_end: element.follow_end,
1609            a11y_role: element.a11y_role,
1610            a11y_label: element.a11y_label,
1611            scroll_offset: element.scroll_offset,
1612            children: element.children,
1613        }
1614    }
1615}
1616
1617/// Converts an element into the erased form a parent stores.
1618pub trait IntoElement {
1619    /// Erases the widget type of this element.
1620    fn into_any(self) -> AnyElement;
1621}
1622
1623impl<W: Widget> IntoElement for Element<W> {
1624    fn into_any(self) -> AnyElement {
1625        AnyElement::new(self)
1626    }
1627}
1628
1629impl IntoElement for AnyElement {
1630    fn into_any(self) -> AnyElement {
1631        self
1632    }
1633}
1634
1635/// Mounts `element` as a child of `parent`, or as the root when `parent` is
1636/// `None`, and returns the id of the node it created.
1637///
1638/// The node starts at [`Dirty::Layout`]. Bindings are installed inside the
1639/// node's owner and run once immediately, so the updates they queue are applied
1640/// before the first layout.
1641pub(crate) fn mount(
1642    element: AnyElement,
1643    tree: &mut WidgetTree,
1644    queue: &UpdateQueue,
1645    parent: Option<WidgetId>,
1646) -> WidgetId {
1647    let AnyElement {
1648        widget,
1649        style,
1650        mut bindings,
1651        variants,
1652        handlers,
1653        disabled,
1654        cursor,
1655        focusable,
1656        autofocus,
1657        trap_focus,
1658        follow_end,
1659        a11y_role,
1660        a11y_label,
1661        scroll_offset,
1662        children,
1663    } = element;
1664    let id = tree.insert(parent, widget, style);
1665    tree.set_variants(id, variants.map(Rc::new));
1666    tree.set_disabled(id, disabled);
1667    tree.set_cursor(id, cursor);
1668    tree.set_focusable(id, focusable);
1669    if autofocus {
1670        tree.queue_autofocus(id);
1671    }
1672    if trap_focus {
1673        tree.push_focus_trap(id);
1674    }
1675    if let Some(signal) = follow_end {
1676        tree.set_follow(id, signal);
1677    }
1678    tree.set_a11y_role(id, a11y_role);
1679    tree.set_handlers(id, handlers);
1680    let bindings = match a11y_label {
1681        Some(Value::Static(text)) => {
1682            tree.set_a11y_label(id, Some(text));
1683            bindings
1684        }
1685        Some(Value::Dynamic(get)) => {
1686            bindings.push(Binding::a11y_label(get));
1687            bindings
1688        }
1689        None => bindings,
1690    };
1691    if scroll_offset != Point::default() {
1692        tree.set_scroll_offset(id, scroll_offset);
1693    }
1694    let owner = tree.owner(id).expect("the node was just inserted").clone();
1695    for binding in bindings {
1696        owner.with(|| (binding.install)(id, queue));
1697    }
1698    for child in children {
1699        mount(child, tree, queue, Some(id));
1700    }
1701    id
1702}
1703
1704/// A node that paints nothing and leaves its children to a binding.
1705///
1706/// [`show`] mounts its child under a slot, and [`for_each`] keeps one child
1707/// per key of a list under one.
1708pub struct Slot;
1709
1710impl Widget for Slot {
1711    fn paint(&self, _cx: &PaintCx<'_>, _out: &mut Vec<PaintOp>) {}
1712}
1713
1714/// Mounts the element that `build` returns as a child of `slot`, inside an
1715/// owner of its own.
1716///
1717/// The owner keeps the values the build creates alive for as long as the
1718/// child stays mounted, and [`unmount_child`] disposes them. Returns `None`
1719/// when `slot` is a stale id, which happens when the slot was removed while
1720/// an update that mounts into it was still queued.
1721fn mount_under_slot(
1722    slot: WidgetId,
1723    tree: &mut WidgetTree,
1724    queue: &UpdateQueue,
1725    build: impl FnOnce() -> AnyElement,
1726) -> Option<(WidgetId, Owner)> {
1727    let owner = tree.owner(slot)?.child();
1728    let element = owner.with(build);
1729    let child = mount(element, tree, queue, Some(slot));
1730    Some((child, owner))
1731}
1732
1733/// Removes a child that [`mount_under_slot`] mounted and disposes the owner
1734/// its build ran in.
1735///
1736/// The tree removal runs first, so the child's bindings stop before the
1737/// values the build created are disposed.
1738fn unmount_child(child: WidgetId, owner: &Owner, tree: &mut WidgetTree) {
1739    tree.remove(child);
1740    owner.cleanup();
1741}
1742
1743/// Mounts the element `build` returns while `when` is true, and removes it
1744/// while `when` is false.
1745///
1746/// Only `when` runs inside a binding, so only the signals it reads make the
1747/// slot check again. `build` runs untracked, once each time the child mounts,
1748/// under an owner of its own. Signals that `build` creates therefore live
1749/// exactly as long as the child: they survive every check that leaves the
1750/// child mounted, and they are disposed when the child is removed, after the
1751/// child's bindings have stopped.
1752///
1753/// ```
1754/// use smudge_core::element::show;
1755/// use smudge_core::reactive::{self, prelude::*};
1756/// use smudge_core::widget::panel;
1757///
1758/// let (visible, _set_visible) = reactive::signal_local(true);
1759/// let root = show(move || visible.get(), panel);
1760/// ```
1761pub fn show<E: IntoElement>(
1762    when: impl Fn() -> bool + 'static,
1763    build: impl Fn() -> E + 'static,
1764) -> Element<Slot> {
1765    let build: Rc<dyn Fn() -> AnyElement> = Rc::new(move || build().into_any());
1766    let mut element = Element::new(Slot);
1767    element.bindings.push(Binding {
1768        key: None,
1769        install: Box::new(move |id, queue| {
1770            let queue = queue.clone();
1771            let mounted: Rc<RefCell<Option<(WidgetId, Owner)>>> = Rc::new(RefCell::new(None));
1772            RenderEffect::new(move || {
1773                let visible = when();
1774                let child_queue = queue.clone();
1775                let mounted = Rc::clone(&mounted);
1776                let build = Rc::clone(&build);
1777                queue.push(Box::new(move |tree| {
1778                    let mut mounted = mounted.borrow_mut();
1779                    match (visible, mounted.take()) {
1780                        (true, None) => {
1781                            if let Some(child) =
1782                                mount_under_slot(id, tree, &child_queue, || build())
1783                            {
1784                                *mounted = Some(child);
1785                            }
1786                        }
1787                        (false, Some((child, owner))) => unmount_child(child, &owner, tree),
1788                        (_, unchanged) => *mounted = unchanged,
1789                    }
1790                }));
1791            })
1792        }),
1793    });
1794    element
1795}
1796
1797/// Mounts one child per key of the list that `items` returns, keeping the
1798/// children that survive a change mounted and in place.
1799///
1800/// The returned element is a slot whose children follow the list. A key the
1801/// list gains mounts a new child, a key it loses removes that child's whole
1802/// tree, and a key that moves keeps its child, which is reordered rather than
1803/// rebuilt. A child keeps its reactive state across a reorder, and the frame
1804/// repaints only what changed position or stacking.
1805///
1806/// A row is built once per key, by `row`, the first time the key appears in
1807/// the list. Content that changes while a row stays mounted must come from
1808/// the signals that row reads: a new value for a key the list already had
1809/// reaches no mounted child.
1810///
1811/// The keys of a list must be unique. In a debug build a duplicate key trips
1812/// a debug assertion. In a release build the last duplicate wins: the row
1813/// mounted for that key takes the position of its last occurrence, and the
1814/// earlier occurrences contribute nothing.
1815///
1816/// `items` runs inside a binding, so only the signals it reads make the slot
1817/// diff the list again. `key` should depend on its item alone, because a key
1818/// that changes makes the slot remove one child and mount another. `row` runs
1819/// once per new key inside an owner of its own, so the signals a row creates
1820/// live exactly as long as the row.
1821///
1822/// The slot manages its own children; do not add children to the returned
1823/// element beside it.
1824///
1825/// ```
1826/// use smudge_core::element::for_each;
1827/// use smudge_core::reactive::{self, prelude::*};
1828/// use smudge_core::style::px;
1829/// use smudge_core::widget::panel;
1830///
1831/// let (items, _set_items) = reactive::signal_local(vec![1u32, 2, 3]);
1832/// let list = for_each(
1833///     move || items.get(),
1834///     |item| *item,
1835///     |item| panel().width(px(40.0)).height(px(10.0)),
1836/// );
1837/// ```
1838pub fn for_each<T, K, E>(
1839    items: impl Fn() -> Vec<T> + 'static,
1840    key: impl Fn(&T) -> K + 'static,
1841    row: impl Fn(T) -> E + 'static,
1842) -> Element<Slot>
1843where
1844    T: 'static,
1845    K: Eq + Hash + Clone + 'static,
1846    E: IntoElement,
1847{
1848    let items = Rc::new(items);
1849    let key = Rc::new(key);
1850    let row: Rc<dyn Fn(T) -> AnyElement> = Rc::new(move |item| row(item).into_any());
1851    let mut element = Element::new(Slot);
1852    element.bindings.push(Binding {
1853        key: None,
1854        install: Box::new(move |slot, queue| {
1855            let queue = queue.clone();
1856            let mounted: Rc<RefCell<HashMap<K, (WidgetId, Owner)>>> =
1857                Rc::new(RefCell::new(HashMap::new()));
1858            let order: Rc<RefCell<Vec<K>>> = Rc::new(RefCell::new(Vec::new()));
1859            RenderEffect::new(move || {
1860                let items = items();
1861                let keys: Vec<K> = items.iter().map(|item| key(item)).collect();
1862                // The last occurrence of a key decides where its row goes, so
1863                // a duplicate keeps one row and the earlier ones are skipped.
1864                let mut last: HashMap<K, usize> = HashMap::with_capacity(keys.len());
1865                for (at, item_key) in keys.iter().enumerate() {
1866                    last.insert(item_key.clone(), at);
1867                }
1868                debug_assert!(
1869                    last.len() == keys.len(),
1870                    "for_each found a duplicate key, but the keys of a list must be unique"
1871                );
1872                let child_queue = queue.clone();
1873                let mounted = Rc::clone(&mounted);
1874                let order = Rc::clone(&order);
1875                let row = Rc::clone(&row);
1876                queue.push(Box::new(move |tree| {
1877                    let mut mounted = mounted.borrow_mut();
1878                    let mut order = order.borrow_mut();
1879
1880                    mounted.retain(|key, (child, owner)| {
1881                        let kept = last.contains_key(key);
1882                        if !kept {
1883                            unmount_child(*child, owner, tree);
1884                        }
1885                        kept
1886                    });
1887
1888                    let mut new_order = Vec::with_capacity(last.len());
1889                    let mut children = Vec::with_capacity(last.len());
1890                    for (at, (item, item_key)) in items.into_iter().zip(keys).enumerate() {
1891                        if last[&item_key] != at {
1892                            continue;
1893                        }
1894                        let child = match mounted.get(&item_key) {
1895                            Some((child, _)) => *child,
1896                            None => {
1897                                let row = Rc::clone(&row);
1898                                let Some((child, owner)) =
1899                                    mount_under_slot(slot, tree, &child_queue, move || row(item))
1900                                else {
1901                                    continue;
1902                                };
1903                                mounted.insert(item_key.clone(), (child, owner));
1904                                child
1905                            }
1906                        };
1907                        children.push(child);
1908                        new_order.push(item_key);
1909                    }
1910
1911                    if *order != new_order {
1912                        tree.set_children(slot, children);
1913                        *order = new_order;
1914                    }
1915                }));
1916            })
1917        }),
1918    });
1919    element
1920}
1921
1922#[cfg(test)]
1923#[path = "element_tests.rs"]
1924mod tests;