Skip to main content

densa_ui/
ui.rs

1use std::any::Any;
2use std::collections::VecDeque;
3use std::fmt;
4use std::time::Duration;
5
6use densa_core::{Point, Rect, Size};
7use densa_draw::Canvas;
8use densa_paragraph::TextSystem;
9use taffy::style::AvailableSpace;
10use taffy::{TaffyResult, TaffyTree};
11
12use crate::{
13    Action, Available, Constraints, Cursor, EventCx, LayoutCx, Overflow, PaintCx, PointerButton,
14    Style, Theme, Widget, WidgetId,
15};
16
17/// Actions held without allocating between reads.
18const ACTION_CAPACITY: usize = 64;
19
20/// Why a [`Ui`] refused a change.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22#[non_exhaustive]
23pub enum UiError {
24    /// The widget was removed, or belongs to another `Ui`.
25    NoSuchWidget(WidgetId),
26    /// More than 2^32 widgets.
27    TooManyWidgets,
28}
29
30impl fmt::Display for UiError {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        match self {
33            Self::NoSuchWidget(id) => write!(f, "there is no widget {id:?}"),
34            Self::TooManyWidgets => f.write_str("more than 2^32 widgets"),
35        }
36    }
37}
38
39impl std::error::Error for UiError {}
40
41/// A widget's place in the tree and its layout.
42#[derive(Debug)]
43pub(crate) struct Node {
44    pub(crate) generation: u32,
45    /// Its number for assistive technology: never reused, unlike its slot.
46    pub(crate) access: u64,
47    pub(crate) live: bool,
48    pub(crate) parent: Option<WidgetId>,
49    pub(crate) children: Vec<WidgetId>,
50    pub(crate) taffy: taffy::NodeId,
51    pub(crate) style: Style,
52    /// Where it is, in physical pixels from the window's top-left corner.
53    pub(crate) rect: Rect,
54    /// `rect` inside the padding.
55    pub(crate) content: Rect,
56    /// What its children cover.
57    pub(crate) content_size: Size,
58    /// How far its children are scrolled.
59    pub(crate) scroll: Point,
60    /// Whether the pointer is over it or one of its children.
61    pub(crate) hovered: bool,
62    pub(crate) cursor: Option<Cursor>,
63    /// `rect` grown to cover children that overflow it: what painting it can touch.
64    pub(crate) extent: Rect,
65    /// Its style or content changed since `Widget::layout` was last called.
66    pub(crate) dirty: bool,
67    /// The size `Widget::layout` was last called with.
68    pub(crate) notified: Option<Size>,
69}
70
71/// A press remembered to count multi-clicks.
72#[derive(Debug, Clone, Copy)]
73pub(crate) struct Press {
74    pub(crate) time: Duration,
75    pub(crate) position: Point,
76    pub(crate) button: PointerButton,
77    pub(crate) clicks: u8,
78}
79
80/// Everything but the widgets: what contexts borrow while a widget runs.
81#[derive(Debug)]
82pub(crate) struct State {
83    pub(crate) nodes: Vec<Node>,
84    free: Vec<u32>,
85    /// The last widget serial given out (the root has 0).
86    pub(crate) next_access: u64,
87    taffy: TaffyTree<WidgetId>,
88    pub(crate) root: WidgetId,
89    pub(crate) theme: Theme,
90    pub(crate) scale: f32,
91    viewport: Size,
92    pub(crate) text: TextSystem,
93    pub(crate) focus: Option<WidgetId>,
94    pub(crate) hover: Option<WidgetId>,
95    pub(crate) capture: Option<WidgetId>,
96    /// Focus asked for by a widget, given once its event is handled.
97    pub(crate) requested_focus: Option<Option<WidgetId>>,
98    pub(crate) actions: VecDeque<Action>,
99    pub(crate) needs_layout: bool,
100    pub(crate) needs_paint: bool,
101    /// Scrolling moved widgets: their rectangles need computing again, not their layout.
102    pub(crate) needs_place: bool,
103    pub(crate) ime_area: Option<(WidgetId, Rect)>,
104    pub(crate) last_press: Option<Press>,
105    /// Where the pointer is, if over the window: hover follows layout changes under it.
106    pub(crate) pointer: Option<Point>,
107}
108
109/// The layout tree mirrors the widget tree, so its operations only fail on ids this crate
110/// never hands it.
111fn sync<T>(result: TaffyResult<T>) -> T {
112    match result {
113        Ok(value) => value,
114        Err(error) => unreachable!("the layout tree is out of step with the widgets: {error}"),
115    }
116}
117
118impl State {
119    pub(crate) fn is_live(&self, id: WidgetId) -> bool {
120        self.nodes
121            .get(id.slot())
122            .is_some_and(|node| node.live && node.generation == id.generation)
123    }
124
125    pub(crate) fn node(&self, id: WidgetId) -> Option<&Node> {
126        self.is_live(id).then(|| &self.nodes[id.slot()])
127    }
128
129    /// `id`'s layout engine style: the root fills the viewport.
130    fn taffy_style(&self, id: WidgetId) -> taffy::Style {
131        let mut style = self.nodes[id.slot()].style.to_taffy(self.scale);
132        if id == self.root {
133            style.size = taffy::Size {
134                width: taffy::style::Dimension::length(self.viewport.width),
135                height: taffy::style::Dimension::length(self.viewport.height),
136            };
137        }
138        style
139    }
140
141    /// Gives `id` a new, childless layout node in its old one's place. taffy keeps the
142    /// absolutely positioned descendants it lays out on their container ("hoisted children")
143    /// and clears that list only when it lays the container out as one: a container whose
144    /// last child is removed is laid out as a leaf from then on, and rounding the layout
145    /// panicked on the removed child's id.
146    fn renew_layout_node(&mut self, id: WidgetId) {
147        let old = self.nodes[id.slot()].taffy;
148        let fresh = sync(self.taffy.new_leaf_with_context(self.taffy_style(id), id));
149        if let Some(parent) = self.taffy.parent(old) {
150            let index = sync(self.taffy.children(parent))
151                .iter()
152                .position(|child| *child == old);
153            if let Some(index) = index {
154                sync(self.taffy.replace_child_at_index(parent, index, fresh));
155            }
156        }
157        sync(self.taffy.remove(old));
158        self.nodes[id.slot()].taffy = fresh;
159        self.nodes[id.slot()].dirty = true;
160    }
161
162    pub(crate) fn set_style(&mut self, id: WidgetId, style: Style) -> bool {
163        if !self.is_live(id) {
164            return false;
165        }
166        self.nodes[id.slot()].style = style;
167        self.nodes[id.slot()].dirty = true;
168        let taffy_style = self.taffy_style(id);
169        sync(
170            self.taffy
171                .set_style(self.nodes[id.slot()].taffy, taffy_style),
172        );
173        self.needs_layout = true;
174        self.needs_paint = true;
175        true
176    }
177
178    /// Whether `id` and every widget around it are shown (none hidden).
179    pub(crate) fn is_shown(&self, id: WidgetId) -> bool {
180        let mut at = Some(id);
181        while let Some(current) = at.filter(|w| self.is_live(*w)) {
182            let node = &self.nodes[current.slot()];
183            if node.style.hidden {
184                return false;
185            }
186            at = node.parent;
187        }
188        self.is_live(id)
189    }
190
191    /// Whether `id` is `ancestor` or inside it.
192    pub(crate) fn is_within(&self, id: WidgetId, ancestor: WidgetId) -> bool {
193        let mut at = Some(id);
194        while let Some(current) = at.filter(|w| self.is_live(*w)) {
195            if current == ancestor {
196                return true;
197            }
198            at = self.nodes[current.slot()].parent;
199        }
200        false
201    }
202
203    pub(crate) fn mark_dirty(&mut self, id: WidgetId) {
204        if self.is_live(id) {
205            sync(self.taffy.mark_dirty(self.nodes[id.slot()].taffy));
206            self.nodes[id.slot()].dirty = true;
207            self.needs_layout = true;
208            self.needs_paint = true;
209        }
210    }
211
212    pub(crate) fn scroll_to(&mut self, id: WidgetId, offset: Point) -> Point {
213        let node = &mut self.nodes[id.slot()];
214        let room = |content: f32, shown: f32| (content - shown).max(0.0);
215        let max_x = room(node.content_size.width, node.rect.width());
216        let max_y = room(node.content_size.height, node.rect.height());
217        let clamped = Point::new(offset.x.clamp(0.0, max_x), offset.y.clamp(0.0, max_y));
218        if clamped != node.scroll {
219            node.scroll = clamped;
220            self.needs_place = true;
221            self.needs_paint = true;
222        }
223        clamped
224    }
225}
226
227/// A tree of widgets: their layout, painting and events.
228///
229/// The `Ui` owns its widgets and lays them out with flexbox when their styles, contents or
230/// the viewport change. Every frame, [`paint`](Self::paint) draws them onto a
231/// [`Canvas`], and the window layer feeds input through [`pointer`](Self::pointer),
232/// [`key`](Self::key) and [`ime`](Self::ime). Painting, hit-testing and delivering events
233/// do not allocate. Coordinates are physical pixels; [`Style`] lengths are logical pixels,
234/// multiplied by [`scale`](Self::scale).
235pub struct Ui {
236    pub(crate) widgets: Vec<Option<Box<dyn Widget>>>,
237    pub(crate) state: State,
238}
239
240impl fmt::Debug for Ui {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        f.debug_struct("Ui")
243            .field("widgets", &self.widgets.len())
244            .field("viewport", &self.state.viewport)
245            .field("focus", &self.state.focus)
246            .finish_non_exhaustive()
247    }
248}
249
250/// The widget at the root: the window's background.
251struct Root;
252
253impl Widget for Root {
254    fn paint(&mut self, cx: &PaintCx<'_>, canvas: &mut Canvas<'_>) {
255        canvas.fill_rect(cx.rect(), cx.theme().background);
256    }
257}
258
259impl Ui {
260    /// An empty interface with the dark theme at scale 1, its root a column filling the
261    /// viewport. `text` shapes every widget's text.
262    pub fn new(text: TextSystem) -> Self {
263        let root = WidgetId {
264            index: 0,
265            generation: 0,
266        };
267        let style = Style::column();
268        let mut taffy = TaffyTree::new();
269        let node = sync(taffy.new_leaf_with_context(style.to_taffy(1.0), root));
270        let mut state = State {
271            nodes: vec![Node {
272                generation: 0,
273                access: 0,
274                live: true,
275                parent: None,
276                children: Vec::new(),
277                taffy: node,
278                style,
279                rect: Rect::default(),
280                content: Rect::default(),
281                content_size: Size::ZERO,
282                scroll: Point::ORIGIN,
283                hovered: false,
284                cursor: None,
285                extent: Rect::default(),
286                dirty: true,
287                notified: None,
288            }],
289            free: Vec::new(),
290            next_access: 0,
291            taffy,
292            root,
293            theme: Theme::default(),
294            scale: 1.0,
295            viewport: Size::ZERO,
296            text,
297            focus: None,
298            hover: None,
299            capture: None,
300            requested_focus: None,
301            actions: VecDeque::with_capacity(ACTION_CAPACITY),
302            needs_layout: true,
303            needs_paint: true,
304            needs_place: false,
305            ime_area: None,
306            last_press: None,
307            pointer: None,
308        };
309        let style = state.taffy_style(root);
310        sync(state.taffy.set_style(node, style));
311        Self {
312            widgets: vec![Some(Box::new(Root))],
313            state,
314        }
315    }
316
317    /// The root: a column filling the viewport, painted with the theme's background.
318    pub fn root(&self) -> WidgetId {
319        self.state.root
320    }
321
322    /// Adds `widget` as the last child of `parent`, laid out by `style`.
323    ///
324    /// # Errors
325    /// [`UiError::NoSuchWidget`] if `parent` was removed, [`UiError::TooManyWidgets`].
326    pub fn add(
327        &mut self,
328        parent: WidgetId,
329        widget: impl Widget,
330        style: Style,
331    ) -> Result<WidgetId, UiError> {
332        let index = self.children(parent).len();
333        self.insert(parent, index, widget, style)
334    }
335
336    /// Adds `widget` as child number `index` of `parent` (past the end: the last), laid out
337    /// by `style`.
338    ///
339    /// # Errors
340    /// [`UiError::NoSuchWidget`] if `parent` was removed, [`UiError::TooManyWidgets`].
341    pub fn insert(
342        &mut self,
343        parent: WidgetId,
344        index: usize,
345        widget: impl Widget,
346        style: Style,
347    ) -> Result<WidgetId, UiError> {
348        if !self.state.is_live(parent) {
349            return Err(UiError::NoSuchWidget(parent));
350        }
351        let position = index.min(self.state.nodes[parent.slot()].children.len());
352        let index = match self.state.free.pop() {
353            Some(index) => index,
354            None => u32::try_from(self.state.nodes.len()).map_err(|_| UiError::TooManyWidgets)?,
355        };
356        let slot = index as usize;
357        let generation = self.state.nodes.get(slot).map_or(0, |node| node.generation);
358        let id = WidgetId { index, generation };
359        let taffy = sync(
360            self.state
361                .taffy
362                .new_leaf_with_context(style.to_taffy(self.state.scale), id),
363        );
364        sync(self.state.taffy.insert_child_at_index(
365            self.state.nodes[parent.slot()].taffy,
366            position,
367            taffy,
368        ));
369        self.state.next_access += 1;
370        let node = Node {
371            generation,
372            access: self.state.next_access,
373            live: true,
374            parent: Some(parent),
375            children: Vec::new(),
376            taffy,
377            style,
378            rect: Rect::default(),
379            content: Rect::default(),
380            content_size: Size::ZERO,
381            scroll: Point::ORIGIN,
382            hovered: false,
383            cursor: None,
384            extent: Rect::default(),
385            dirty: true,
386            notified: None,
387        };
388        if slot == self.state.nodes.len() {
389            self.state.nodes.push(node);
390            self.widgets.push(Some(Box::new(widget)));
391        } else {
392            self.state.nodes[slot] = node;
393            self.widgets[slot] = Some(Box::new(widget));
394        }
395        self.state.nodes[parent.slot()]
396            .children
397            .insert(position, id);
398        self.state.needs_layout = true;
399        self.state.needs_paint = true;
400        Ok(id)
401    }
402
403    /// Removes `id` and everything inside it; `false` if it was already gone, or is the
404    /// root.
405    pub fn remove(&mut self, id: WidgetId) -> bool {
406        if !self.state.is_live(id) || id == self.state.root {
407            return false;
408        }
409        if let Some(hover) = self.state.hover.filter(|h| self.state.is_within(*h, id)) {
410            self.mark_hovered(Some(hover), false);
411            self.state.hover = None;
412        }
413        let parent = self.state.nodes[id.slot()].parent;
414        if let Some(parent) = parent {
415            self.state.nodes[parent.slot()]
416                .children
417                .retain(|child| *child != id);
418        }
419        let mut doomed = vec![id];
420        while let Some(gone) = doomed.pop() {
421            let node = &mut self.state.nodes[gone.slot()];
422            doomed.append(&mut node.children);
423            node.live = false;
424            node.generation = node.generation.wrapping_add(1);
425            node.cursor = None;
426            let taffy = node.taffy;
427            sync(self.state.taffy.remove(taffy));
428            self.widgets[gone.slot()] = None;
429            self.state.free.push(gone.index);
430        }
431        if let Some(parent) = parent.filter(|p| self.state.nodes[p.slot()].children.is_empty()) {
432            self.state.renew_layout_node(parent);
433        }
434        let state = &mut self.state;
435        let live = |slot: &mut Option<WidgetId>, nodes: &[Node]| {
436            if slot.is_some_and(|w| {
437                !(nodes[w.slot()].live && nodes[w.slot()].generation == w.generation)
438            }) {
439                *slot = None;
440            }
441        };
442        live(&mut state.focus, &state.nodes);
443        live(&mut state.hover, &state.nodes);
444        live(&mut state.capture, &state.nodes);
445        if state.ime_area.is_some_and(|(w, _)| !state.is_live(w)) {
446            state.ime_area = None;
447        }
448        state.needs_layout = true;
449        state.needs_paint = true;
450        true
451    }
452
453    /// Changes `id`'s style; `false` if it was removed.
454    pub fn set_style(&mut self, id: WidgetId, style: Style) -> bool {
455        self.state.set_style(id, style)
456    }
457
458    /// `id`'s style.
459    pub fn style(&self, id: WidgetId) -> Option<&Style> {
460        self.state.node(id).map(|node| &node.style)
461    }
462
463    /// `id`'s parent; `None` for the root or a removed widget.
464    pub fn parent(&self, id: WidgetId) -> Option<WidgetId> {
465        self.state.node(id).and_then(|node| node.parent)
466    }
467
468    /// `id`'s children, first painted first; empty for a removed widget.
469    pub fn children(&self, id: WidgetId) -> &[WidgetId] {
470        self.state.node(id).map_or(&[], |node| &node.children)
471    }
472
473    /// Where `id` is, in physical pixels from the window's top-left corner, as of the last
474    /// layout.
475    pub fn rect(&self, id: WidgetId) -> Option<Rect> {
476        self.state.node(id).map(|node| node.rect)
477    }
478
479    /// The widget `id`, if it is a `T`.
480    pub fn widget<T: Widget>(&self, id: WidgetId) -> Option<&T> {
481        if !self.state.is_live(id) {
482            return None;
483        }
484        let widget: &dyn Widget = self.widgets[id.slot()].as_deref()?;
485        (widget as &dyn Any).downcast_ref::<T>()
486    }
487
488    /// Runs `update` on the widget `id`, if it is a `T`, with a context to request layout,
489    /// paint or focus as an event handler would.
490    pub fn update<T: Widget, R>(
491        &mut self,
492        id: WidgetId,
493        update: impl FnOnce(&mut T, &mut EventCx<'_>) -> R,
494    ) -> Option<R> {
495        if !self.state.is_live(id) {
496            return None;
497        }
498        let widget: &mut dyn Widget = self.widgets[id.slot()].as_deref_mut()?;
499        let widget = (widget as &mut dyn Any).downcast_mut::<T>()?;
500        let mut cx = EventCx {
501            state: &mut self.state,
502            id,
503        };
504        let result = update(widget, &mut cx);
505        self.settle();
506        Some(result)
507    }
508
509    /// The theme.
510    pub fn theme(&self) -> &Theme {
511        &self.state.theme
512    }
513
514    /// Changes the theme; widgets are measured again (sizes may differ).
515    pub fn set_theme(&mut self, theme: Theme) {
516        self.state.theme = theme;
517        self.restyle();
518    }
519
520    /// Physical pixels per logical pixel.
521    pub fn scale(&self) -> f32 {
522        self.state.scale
523    }
524
525    /// Changes the scale factor (the window moved to a screen of another density).
526    pub fn set_scale(&mut self, scale: f32) {
527        if scale.is_finite() && scale > 0.0 && scale != self.state.scale {
528            self.state.scale = scale;
529            self.restyle();
530        }
531    }
532
533    /// The area the root fills, in physical pixels.
534    pub fn viewport(&self) -> Size {
535        self.state.viewport
536    }
537
538    /// Changes the area the root fills (the window was resized).
539    pub fn resize(&mut self, viewport: Size) {
540        if viewport != self.state.viewport {
541            self.state.viewport = viewport;
542            let root = self.state.root;
543            let style = self.state.taffy_style(root);
544            sync(
545                self.state
546                    .taffy
547                    .set_style(self.state.nodes[root.slot()].taffy, style),
548            );
549            self.state.needs_layout = true;
550            self.state.needs_paint = true;
551        }
552    }
553
554    /// The text system widgets shape their text with.
555    pub fn text_system(&mut self) -> &mut TextSystem {
556        &mut self.state.text
557    }
558
559    /// Whether something changed since the last [`paint`](Self::paint).
560    pub fn needs_paint(&self) -> bool {
561        self.state.needs_paint || self.state.needs_layout || self.state.needs_place
562    }
563
564    /// The cursor to show: the one set by the widget under the pointer (or holding it), or
565    /// its nearest parent that set one.
566    pub fn cursor(&self) -> Cursor {
567        let mut at = self.state.capture.or(self.state.hover);
568        while let Some(id) = at.filter(|id| self.state.is_live(*id)) {
569            let node = &self.state.nodes[id.slot()];
570            if let Some(cursor) = node.cursor {
571                return cursor;
572            }
573            at = node.parent;
574        }
575        Cursor::Default
576    }
577
578    /// Where the focused widget wants input method candidates, if it does.
579    pub fn ime_area(&self) -> Option<Rect> {
580        self.state
581            .ime_area
582            .filter(|(id, _)| self.state.focus == Some(*id))
583            .map(|(_, area)| area)
584    }
585
586    /// The actions widgets reported and not yet read, oldest first, taken out.
587    pub fn actions(&mut self) -> impl Iterator<Item = Action> + '_ {
588        self.state.actions.drain(..)
589    }
590
591    /// The oldest action not yet read, taken out: lets the application act on each with the
592    /// `Ui` at hand.
593    pub fn next_action(&mut self) -> Option<Action> {
594        self.state.actions.pop_front()
595    }
596
597    /// Lays the widgets out if anything changed. [`paint`](Self::paint) and the event
598    /// methods call it first; call it to read [`rect`](Self::rect)s before painting.
599    pub fn layout(&mut self) {
600        if self.state.needs_layout {
601            let Self { widgets, state } = self;
602            let root = state.nodes[state.root.slot()].taffy;
603            let available = taffy::Size {
604                width: AvailableSpace::Definite(state.viewport.width),
605                height: AvailableSpace::Definite(state.viewport.height),
606            };
607            let scale = state.scale;
608            let (text, theme) = (&mut state.text, &state.theme);
609            let computed = state.taffy.compute_layout_with_measure(
610                root,
611                available,
612                |inputs, _, context, style| {
613                    taffy::compute_leaf_layout(
614                        inputs,
615                        style,
616                        |_, _| 0.0,
617                        |known, room| {
618                            let widget =
619                                context.and_then(|id| widgets.get_mut(id.slot())?.as_mut());
620                            let Some(widget) = widget else {
621                                return taffy::Size::ZERO;
622                            };
623                            let mut cx = LayoutCx {
624                                text: &mut *text,
625                                theme,
626                                scale,
627                            };
628                            let size = widget.measure(&mut cx, constraints(known, room));
629                            taffy::Size {
630                                width: known.width.unwrap_or(size.width),
631                                height: known.height.unwrap_or(size.height),
632                            }
633                        },
634                    )
635                },
636            );
637            sync(computed);
638            self.state.needs_layout = false;
639            self.place(self.state.root, Point::ORIGIN, true, true);
640            self.state.needs_place = false;
641            self.after_moves();
642        }
643        if self.state.needs_place {
644            self.place(self.state.root, Point::ORIGIN, false, true);
645            self.state.needs_place = false;
646            self.after_moves();
647        }
648    }
649
650    /// After widgets moved, resized or were hidden: a hidden widget loses focus, and hover
651    /// follows the widgets that are now under a pointer that did not move.
652    fn after_moves(&mut self) {
653        if self.state.focus.is_some_and(|f| !self.state.is_shown(f)) {
654            self.set_focus(None);
655        }
656        if let (Some(at), None) = (self.state.pointer, self.state.capture) {
657            let hit = self.hit(self.state.root, at);
658            self.set_hover(hit, at);
659        }
660    }
661
662    /// Computes `id`'s rectangle (and its children's) from the last layout, its parent's
663    /// content starting at `origin`; `notify` tells widgets their sizes.
664    fn place(&mut self, id: WidgetId, origin: Point, notify: bool, shown: bool) {
665        let state = &mut self.state;
666        let node = &mut state.nodes[id.slot()];
667        let layout = *sync(state.taffy.layout(node.taffy));
668        let rect = Rect::new(
669            origin.x + layout.location.x,
670            origin.y + layout.location.y,
671            layout.size.width,
672            layout.size.height,
673        );
674        node.rect = rect;
675        node.content = Rect::from_edges(
676            rect.left() + layout.border.left + layout.padding.left,
677            rect.top() + layout.border.top + layout.padding.top,
678            rect.right() - layout.border.right - layout.padding.right,
679            rect.bottom() - layout.border.bottom - layout.padding.bottom,
680        );
681        // Measured from the padding box's corner: how far the content reaches.
682        let overflow = layout.scrollable_overflow_rect;
683        node.content_size = Size::new(overflow.right, overflow.bottom);
684        // Content that shrank, or a view that grew, leaves less to scroll. A hidden widget
685        // has no size, so it keeps its scroll for when it is shown again (a tab switched
686        // away and back).
687        let shown = shown && !node.style.hidden;
688        let room = |content: f32, view: f32| (content - view).max(0.0);
689        let clamped = if !shown {
690            node.scroll
691        } else {
692            Point::new(
693                node.scroll.x.clamp(0.0, room(overflow.right, rect.width())),
694                node.scroll
695                    .y
696                    .clamp(0.0, room(overflow.bottom, rect.height())),
697            )
698        };
699        if clamped != node.scroll {
700            node.scroll = clamped;
701            state.needs_paint = true;
702        }
703        node.extent = if node.style.overflow == Overflow::Visible {
704            Rect::from_edges(
705                rect.left() + overflow.left.min(0.0),
706                rect.top() + overflow.top.min(0.0),
707                rect.right().max(rect.left() + overflow.right),
708                rect.bottom().max(rect.top() + overflow.bottom),
709            )
710        } else {
711            rect
712        };
713        let inner = Point::new(rect.left() - node.scroll.x, rect.top() - node.scroll.y);
714        let changed = node.dirty || node.notified != Some(rect.size());
715        if notify && changed {
716            node.dirty = false;
717            node.notified = Some(rect.size());
718            if let Some(widget) = self.widgets[id.slot()].as_mut() {
719                let mut cx = LayoutCx {
720                    text: &mut state.text,
721                    theme: &state.theme,
722                    scale: state.scale,
723                };
724                widget.layout(&mut cx, rect.size());
725            }
726        }
727        for index in 0..self.state.nodes[id.slot()].children.len() {
728            let child = self.state.nodes[id.slot()].children[index];
729            self.place(child, inner, notify, shown);
730        }
731    }
732
733    /// Paints every visible widget onto `canvas`, laying them out first if needed.
734    pub fn paint(&mut self, canvas: &mut Canvas<'_>) {
735        self.layout();
736        self.paint_node(self.state.root, canvas);
737        self.state.needs_paint = false;
738    }
739
740    fn paint_node(&mut self, id: WidgetId, canvas: &mut Canvas<'_>) {
741        let node = &self.state.nodes[id.slot()];
742        if node.style.hidden {
743            return;
744        }
745        let rect = node.rect;
746        let clips = node.style.overflow != Overflow::Visible;
747        // Nothing it or its children paint would show.
748        if canvas.clip_rect().intersect(node.extent).is_empty() {
749            return;
750        }
751        let saved = canvas.state();
752        if let Some(widget) = self.widgets[id.slot()].as_mut() {
753            widget.paint(
754                &PaintCx {
755                    state: &self.state,
756                    id,
757                },
758                canvas,
759            );
760        }
761        if clips {
762            canvas.clip(rect);
763        }
764        for index in 0..self.state.nodes[id.slot()].children.len() {
765            let child = self.state.nodes[id.slot()].children[index];
766            self.paint_node(child, canvas);
767        }
768        canvas.restore(saved);
769        if let Some(widget) = self.widgets[id.slot()].as_mut() {
770            widget.paint_over(
771                &PaintCx {
772                    state: &self.state,
773                    id,
774                },
775                canvas,
776            );
777        }
778    }
779
780    /// Re-styles every widget (scale or theme changed), so all are measured again.
781    fn restyle(&mut self) {
782        for slot in 0..self.state.nodes.len() {
783            let node = &self.state.nodes[slot];
784            if node.live {
785                let id = WidgetId {
786                    index: slot as u32,
787                    generation: node.generation,
788                };
789                let style = self.state.taffy_style(id);
790                sync(self.state.taffy.set_style(node.taffy, style));
791                self.state.nodes[slot].dirty = true;
792            }
793        }
794        self.state.needs_layout = true;
795        self.state.needs_paint = true;
796    }
797
798    /// Gives focus a widget asked for while handling an event, and re-places scrolled widgets.
799    pub(crate) fn settle(&mut self) {
800        // Focus events can ask for focus again: give up after a few rounds.
801        for _ in 0..4 {
802            match self.state.requested_focus.take() {
803                Some(focus) => self.give_focus(focus),
804                None => break,
805            }
806        }
807        self.state.requested_focus = None;
808    }
809}
810
811/// Layout's question in densa's terms.
812fn constraints(known: taffy::Size<Option<f32>>, room: taffy::Size<AvailableSpace>) -> Constraints {
813    let available = |space: AvailableSpace| match space {
814        AvailableSpace::Definite(room) => Available::Definite(room),
815        AvailableSpace::MinContent => Available::MinContent,
816        AvailableSpace::MaxContent => Available::MaxContent,
817    };
818    Constraints {
819        width: known.width,
820        height: known.height,
821        available_width: available(room.width),
822        available_height: available(room.height),
823    }
824}