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::clipboard::{Clipboard, Held};
13use crate::popup::{Incoming, Popup};
14use crate::{
15 Action, Available, Constraints, Cursor, EventCx, LayoutCx, Overflow, PaintCx, PointerButton,
16 Style, Theme, Widget, WidgetId,
17};
18
19const ACTION_CAPACITY: usize = 64;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[non_exhaustive]
25pub enum UiError {
26 NoSuchWidget(WidgetId),
28 TooManyWidgets,
30}
31
32impl fmt::Display for UiError {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 match self {
35 Self::NoSuchWidget(id) => write!(
36 f,
37 "there is no widget {id:?}: it was removed (or belongs to another Ui)"
38 ),
39 Self::TooManyWidgets => f.write_str("more than 2^32 widgets"),
40 }
41 }
42}
43
44impl std::error::Error for UiError {}
45
46#[derive(Debug)]
48pub(crate) struct Node {
49 pub(crate) generation: u32,
50 pub(crate) access: u64,
52 pub(crate) live: bool,
53 pub(crate) parent: Option<WidgetId>,
54 pub(crate) children: Vec<WidgetId>,
55 pub(crate) taffy: taffy::NodeId,
56 pub(crate) style: Style,
57 pub(crate) rect: Rect,
59 pub(crate) content: Rect,
61 pub(crate) content_size: Size,
63 pub(crate) scroll: Point,
65 pub(crate) hovered: bool,
67 pub(crate) cursor: Option<Cursor>,
68 pub(crate) extent: Rect,
70 pub(crate) dirty: bool,
72 pub(crate) notified: Option<Size>,
74}
75
76#[derive(Debug, Clone, Copy)]
78pub(crate) struct Press {
79 pub(crate) time: Duration,
80 pub(crate) position: Point,
81 pub(crate) button: PointerButton,
82 pub(crate) clicks: u8,
83}
84
85#[derive(Debug)]
87pub(crate) struct State {
88 pub(crate) nodes: Vec<Node>,
89 free: Vec<u32>,
90 pub(crate) next_access: u64,
92 taffy: TaffyTree<WidgetId>,
93 pub(crate) root: WidgetId,
94 pub(crate) layer: WidgetId,
96 pub(crate) popups: Vec<Popup>,
98 pub(crate) incoming: Incoming,
100 pub(crate) closing: Vec<WidgetId>,
102 pub(crate) theme: Theme,
103 pub(crate) scale: f32,
104 viewport: Size,
105 pub(crate) text: TextSystem,
106 pub(crate) focus: Option<WidgetId>,
107 pub(crate) hover: Option<WidgetId>,
108 pub(crate) capture: Option<WidgetId>,
109 pub(crate) requested_focus: Option<Option<WidgetId>>,
111 pub(crate) actions: VecDeque<Action>,
112 pub(crate) needs_layout: bool,
113 pub(crate) needs_paint: bool,
114 pub(crate) needs_place: bool,
116 pub(crate) ime_area: Option<(WidgetId, Rect)>,
117 pub(crate) last_press: Option<Press>,
118 pub(crate) pointer: Option<Point>,
120 pub(crate) clipboard: Held,
121}
122
123fn sync<T>(result: TaffyResult<T>) -> T {
126 match result {
127 Ok(value) => value,
128 Err(error) => unreachable!("the layout tree is out of step with the widgets: {error}"),
129 }
130}
131
132impl State {
133 pub(crate) fn is_live(&self, id: WidgetId) -> bool {
134 self.nodes
135 .get(id.slot())
136 .is_some_and(|node| node.live && node.generation == id.generation)
137 }
138
139 pub(crate) fn node(&self, id: WidgetId) -> Option<&Node> {
140 self.is_live(id).then(|| &self.nodes[id.slot()])
141 }
142
143 pub(crate) fn viewport(&self) -> Size {
144 self.viewport
145 }
146
147 fn taffy_style(&self, id: WidgetId) -> taffy::Style {
149 let mut style = self.nodes[id.slot()].style.to_taffy(self.scale);
150 if id == self.root || id == self.layer {
151 style.size = taffy::Size {
152 width: taffy::style::Dimension::length(self.viewport.width),
153 height: taffy::style::Dimension::length(self.viewport.height),
154 };
155 }
156 style
157 }
158
159 fn renew_layout_node(&mut self, id: WidgetId) {
165 let old = self.nodes[id.slot()].taffy;
166 let fresh = sync(self.taffy.new_leaf_with_context(self.taffy_style(id), id));
167 if let Some(parent) = self.taffy.parent(old) {
168 let index = sync(self.taffy.children(parent))
169 .iter()
170 .position(|child| *child == old);
171 if let Some(index) = index {
172 sync(self.taffy.replace_child_at_index(parent, index, fresh));
173 }
174 }
175 sync(self.taffy.remove(old));
176 self.nodes[id.slot()].taffy = fresh;
177 self.nodes[id.slot()].dirty = true;
178 }
179
180 pub(crate) fn new_node(
183 &mut self,
184 parent: WidgetId,
185 position: usize,
186 style: Style,
187 ) -> Result<WidgetId, UiError> {
188 if !self.is_live(parent) {
189 return Err(UiError::NoSuchWidget(parent));
190 }
191 let position = position.min(self.nodes[parent.slot()].children.len());
192 let index = match self.free.pop() {
193 Some(index) => index,
194 None => u32::try_from(self.nodes.len()).map_err(|_| UiError::TooManyWidgets)?,
195 };
196 let slot = index as usize;
197 let generation = self.nodes.get(slot).map_or(0, |node| node.generation);
198 let id = WidgetId { index, generation };
199 let taffy = sync(
200 self.taffy
201 .new_leaf_with_context(style.to_taffy(self.scale), id),
202 );
203 sync(
204 self.taffy
205 .insert_child_at_index(self.nodes[parent.slot()].taffy, position, taffy),
206 );
207 self.next_access += 1;
208 let node = Node {
209 generation,
210 access: self.next_access,
211 live: true,
212 parent: Some(parent),
213 children: Vec::new(),
214 taffy,
215 style,
216 rect: Rect::default(),
217 content: Rect::default(),
218 content_size: Size::ZERO,
219 scroll: Point::ORIGIN,
220 hovered: false,
221 cursor: None,
222 extent: Rect::default(),
223 dirty: true,
224 notified: None,
225 };
226 if slot == self.nodes.len() {
227 self.nodes.push(node);
228 } else {
229 self.nodes[slot] = node;
230 }
231 self.nodes[parent.slot()].children.insert(position, id);
232 self.needs_layout = true;
233 self.needs_paint = true;
234 Ok(id)
235 }
236
237 pub(crate) fn set_style(&mut self, id: WidgetId, style: Style) -> bool {
238 if !self.is_live(id) {
239 return false;
240 }
241 self.nodes[id.slot()].style = style;
242 self.nodes[id.slot()].dirty = true;
243 let taffy_style = self.taffy_style(id);
244 sync(
245 self.taffy
246 .set_style(self.nodes[id.slot()].taffy, taffy_style),
247 );
248 self.needs_layout = true;
249 self.needs_paint = true;
250 true
251 }
252
253 pub(crate) fn is_shown(&self, id: WidgetId) -> bool {
255 let mut at = Some(id);
256 while let Some(current) = at.filter(|w| self.is_live(*w)) {
257 let node = &self.nodes[current.slot()];
258 if node.style.hidden {
259 return false;
260 }
261 at = node.parent;
262 }
263 self.is_live(id)
264 }
265
266 pub(crate) fn is_within(&self, id: WidgetId, ancestor: WidgetId) -> bool {
268 let mut at = Some(id);
269 while let Some(current) = at.filter(|w| self.is_live(*w)) {
270 if current == ancestor {
271 return true;
272 }
273 at = self.nodes[current.slot()].parent;
274 }
275 false
276 }
277
278 pub(crate) fn mark_dirty(&mut self, id: WidgetId) {
279 if self.is_live(id) {
280 sync(self.taffy.mark_dirty(self.nodes[id.slot()].taffy));
281 self.nodes[id.slot()].dirty = true;
282 self.needs_layout = true;
283 self.needs_paint = true;
284 }
285 }
286
287 pub(crate) fn scroll_to(&mut self, id: WidgetId, offset: Point) -> Point {
288 let node = &mut self.nodes[id.slot()];
289 let room = |content: f32, shown: f32| (content - shown).max(0.0);
290 let max_x = room(node.content_size.width, node.rect.width());
291 let max_y = room(node.content_size.height, node.rect.height());
292 let clamped = Point::new(offset.x.clamp(0.0, max_x), offset.y.clamp(0.0, max_y));
293 if clamped != node.scroll {
294 node.scroll = clamped;
295 self.needs_place = true;
296 self.needs_paint = true;
297 }
298 clamped
299 }
300}
301
302pub struct Ui {
311 pub(crate) widgets: Vec<Option<Box<dyn Widget>>>,
312 pub(crate) state: State,
313}
314
315impl fmt::Debug for Ui {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 f.debug_struct("Ui")
318 .field("widgets", &self.widgets.len())
319 .field("viewport", &self.state.viewport)
320 .field("focus", &self.state.focus)
321 .finish_non_exhaustive()
322 }
323}
324
325struct Root;
327
328struct Layer;
330
331impl Widget for Layer {}
332
333impl Widget for Root {
334 fn paint(&mut self, cx: &PaintCx<'_>, canvas: &mut Canvas<'_>) {
335 canvas.fill_rect(cx.rect(), cx.theme().background);
336 }
337}
338
339impl Ui {
340 pub fn new(text: TextSystem) -> Self {
343 let root = WidgetId {
344 index: 0,
345 generation: 0,
346 };
347 let layer = WidgetId {
348 index: 1,
349 generation: 0,
350 };
351 let style = Style::column();
352 let mut taffy = TaffyTree::new();
353 let node = sync(taffy.new_leaf_with_context(style.to_taffy(1.0), root));
354 let layer_node = sync(taffy.new_leaf_with_context(style.to_taffy(1.0), layer));
355 let top = |taffy: taffy::NodeId| Node {
356 generation: 0,
357 access: 0,
359 live: true,
360 parent: None,
361 children: Vec::new(),
362 taffy,
363 style: style.clone(),
364 rect: Rect::default(),
365 content: Rect::default(),
366 content_size: Size::ZERO,
367 scroll: Point::ORIGIN,
368 hovered: false,
369 cursor: None,
370 extent: Rect::default(),
371 dirty: true,
372 notified: None,
373 };
374 let mut state = State {
375 nodes: vec![top(node), top(layer_node)],
376 free: Vec::new(),
377 next_access: 0,
378 taffy,
379 root,
380 layer,
381 popups: Vec::new(),
382 incoming: Incoming::default(),
383 closing: Vec::new(),
384 theme: Theme::default(),
385 scale: 1.0,
386 viewport: Size::ZERO,
387 text,
388 focus: None,
389 hover: None,
390 capture: None,
391 requested_focus: None,
392 actions: VecDeque::with_capacity(ACTION_CAPACITY),
393 needs_layout: true,
394 needs_paint: true,
395 needs_place: false,
396 ime_area: None,
397 last_press: None,
398 pointer: None,
399 clipboard: Held::default(),
400 };
401 for (id, taffy) in [(root, node), (layer, layer_node)] {
402 let style = state.taffy_style(id);
403 sync(state.taffy.set_style(taffy, style));
404 }
405 Self {
406 widgets: vec![Some(Box::new(Root)), Some(Box::new(Layer))],
407 state,
408 }
409 }
410
411 pub fn root(&self) -> WidgetId {
413 self.state.root
414 }
415
416 pub fn add(
421 &mut self,
422 parent: WidgetId,
423 widget: impl Widget,
424 style: Style,
425 ) -> Result<WidgetId, UiError> {
426 let index = self.children(parent).len();
427 self.insert(parent, index, widget, style)
428 }
429
430 pub fn insert(
436 &mut self,
437 parent: WidgetId,
438 index: usize,
439 widget: impl Widget,
440 style: Style,
441 ) -> Result<WidgetId, UiError> {
442 let id = self.state.new_node(parent, index, style)?;
443 let slot = id.slot();
444 if slot >= self.widgets.len() {
445 self.widgets.resize_with(slot + 1, || None);
446 }
447 self.widgets[slot] = Some(Box::new(widget));
448 Ok(id)
449 }
450
451 pub fn remove(&mut self, id: WidgetId) -> bool {
455 if self.state.close_popup(id) {
456 self.settle();
457 return true;
458 }
459 self.remove_widget(id)
460 }
461
462 pub(crate) fn remove_widget(&mut self, id: WidgetId) -> bool {
464 if !self.state.is_live(id) || id == self.state.root || id == self.state.layer {
465 return false;
466 }
467 if let Some(hover) = self.state.hover.filter(|h| self.state.is_within(*h, id)) {
468 self.mark_hovered(Some(hover), false);
469 self.state.hover = None;
470 }
471 let parent = self.state.nodes[id.slot()].parent;
472 if let Some(parent) = parent {
473 self.state.nodes[parent.slot()]
474 .children
475 .retain(|child| *child != id);
476 }
477 let mut doomed = vec![id];
478 while let Some(gone) = doomed.pop() {
479 let node = &mut self.state.nodes[gone.slot()];
480 doomed.append(&mut node.children);
481 node.live = false;
482 node.generation = node.generation.wrapping_add(1);
483 node.cursor = None;
484 let taffy = node.taffy;
485 sync(self.state.taffy.remove(taffy));
486 self.widgets[gone.slot()] = None;
487 self.state.free.push(gone.index);
488 }
489 if let Some(parent) = parent.filter(|p| self.state.nodes[p.slot()].children.is_empty()) {
490 self.state.renew_layout_node(parent);
491 }
492 let state = &mut self.state;
493 let live = |slot: &mut Option<WidgetId>, nodes: &[Node]| {
494 if slot.is_some_and(|w| {
495 !(nodes[w.slot()].live && nodes[w.slot()].generation == w.generation)
496 }) {
497 *slot = None;
498 }
499 };
500 live(&mut state.focus, &state.nodes);
501 live(&mut state.hover, &state.nodes);
502 live(&mut state.capture, &state.nodes);
503 let nodes = &state.nodes;
504 state.popups.retain(|popup| {
505 nodes[popup.id.slot()].live && nodes[popup.id.slot()].generation == popup.id.generation
506 });
507 if state.ime_area.is_some_and(|(w, _)| !state.is_live(w)) {
508 state.ime_area = None;
509 }
510 state.needs_layout = true;
511 state.needs_paint = true;
512 true
513 }
514
515 pub fn set_style(&mut self, id: WidgetId, style: Style) -> bool {
517 self.state.set_style(id, style)
518 }
519
520 pub fn style(&self, id: WidgetId) -> Option<&Style> {
522 self.state.node(id).map(|node| &node.style)
523 }
524
525 pub fn parent(&self, id: WidgetId) -> Option<WidgetId> {
527 self.state.node(id).and_then(|node| node.parent)
528 }
529
530 pub fn children(&self, id: WidgetId) -> &[WidgetId] {
532 self.state.node(id).map_or(&[], |node| &node.children)
533 }
534
535 pub fn rect(&self, id: WidgetId) -> Option<Rect> {
538 self.state.node(id).map(|node| node.rect)
539 }
540
541 pub fn widget<T: Widget>(&self, id: WidgetId) -> Option<&T> {
543 if !self.state.is_live(id) {
544 return None;
545 }
546 let widget: &dyn Widget = self.widgets.get(id.slot())?.as_deref()?;
547 (widget as &dyn Any).downcast_ref::<T>()
548 }
549
550 pub fn update<T: Widget, R>(
553 &mut self,
554 id: WidgetId,
555 update: impl FnOnce(&mut T, &mut EventCx<'_>) -> R,
556 ) -> Option<R> {
557 if !self.state.is_live(id) {
558 return None;
559 }
560 let widget: &mut dyn Widget = self.widgets.get_mut(id.slot())?.as_deref_mut()?;
561 let widget = (widget as &mut dyn Any).downcast_mut::<T>()?;
562 let mut cx = EventCx {
563 state: &mut self.state,
564 id,
565 };
566 let result = update(widget, &mut cx);
567 self.settle();
568 Some(result)
569 }
570
571 pub fn theme(&self) -> &Theme {
573 &self.state.theme
574 }
575
576 pub fn set_theme(&mut self, theme: Theme) {
578 self.state.theme = theme;
579 self.restyle();
580 }
581
582 pub fn clipboard(&mut self) -> &mut dyn Clipboard {
584 self.state.clipboard.0.as_mut()
585 }
586
587 pub fn set_clipboard(&mut self, clipboard: impl Clipboard + 'static) {
590 self.state.clipboard = Held(Box::new(clipboard));
591 }
592
593 pub fn scale(&self) -> f32 {
595 self.state.scale
596 }
597
598 pub fn set_scale(&mut self, scale: f32) {
600 if scale.is_finite() && scale > 0.0 && scale != self.state.scale {
601 self.state.scale = scale;
602 self.restyle();
603 }
604 }
605
606 pub fn viewport(&self) -> Size {
608 self.state.viewport
609 }
610
611 pub fn resize(&mut self, viewport: Size) {
613 if viewport != self.state.viewport {
614 self.state.viewport = viewport;
615 let root = self.state.root;
616 let style = self.state.taffy_style(root);
617 sync(
618 self.state
619 .taffy
620 .set_style(self.state.nodes[root.slot()].taffy, style),
621 );
622 self.state.needs_layout = true;
623 self.state.needs_paint = true;
624 }
625 }
626
627 pub fn text_system(&mut self) -> &mut TextSystem {
629 &mut self.state.text
630 }
631
632 pub fn needs_paint(&self) -> bool {
634 self.state.needs_paint || self.state.needs_layout || self.state.needs_place
635 }
636
637 pub fn cursor(&self) -> Cursor {
640 let mut at = self.state.capture.or(self.state.hover);
641 while let Some(id) = at.filter(|id| self.state.is_live(*id)) {
642 let node = &self.state.nodes[id.slot()];
643 if let Some(cursor) = node.cursor {
644 return cursor;
645 }
646 at = node.parent;
647 }
648 Cursor::Default
649 }
650
651 pub fn ime_area(&self) -> Option<Rect> {
653 self.state
654 .ime_area
655 .filter(|(id, _)| self.state.focus == Some(*id))
656 .map(|(_, area)| area)
657 }
658
659 pub fn actions(&mut self) -> impl Iterator<Item = Action> + '_ {
661 self.state.actions.drain(..)
662 }
663
664 pub fn next_action(&mut self) -> Option<Action> {
667 self.state.actions.pop_front()
668 }
669
670 pub fn layout(&mut self) {
673 if self.state.needs_layout {
674 self.compute(self.state.root);
675 if !self.state.nodes[self.state.layer.slot()]
676 .children
677 .is_empty()
678 {
679 self.compute(self.state.layer);
680 }
681 self.state.needs_layout = false;
682 self.place(self.state.root, Point::ORIGIN, true, true);
683 self.place(self.state.layer, Point::ORIGIN, true, true);
684 self.state.needs_place = false;
685 self.after_moves();
686 }
687 if self.state.needs_place {
688 self.place(self.state.root, Point::ORIGIN, false, true);
689 self.place(self.state.layer, Point::ORIGIN, false, true);
690 self.state.needs_place = false;
691 self.after_moves();
692 }
693 }
694
695 fn compute(&mut self, top: WidgetId) {
697 {
698 let Self { widgets, state } = self;
699 let root = state.nodes[top.slot()].taffy;
700 let available = taffy::Size {
701 width: AvailableSpace::Definite(state.viewport.width),
702 height: AvailableSpace::Definite(state.viewport.height),
703 };
704 let scale = state.scale;
705 let (text, theme) = (&mut state.text, &state.theme);
706 let computed = state.taffy.compute_layout_with_measure(
707 root,
708 available,
709 |inputs, _, context, style| {
710 taffy::compute_leaf_layout(
711 inputs,
712 style,
713 |_, _| 0.0,
714 |known, room| {
715 let widget =
716 context.and_then(|id| widgets.get_mut(id.slot())?.as_mut());
717 let Some(widget) = widget else {
718 return taffy::Size::ZERO;
719 };
720 let mut cx = LayoutCx {
721 text: &mut *text,
722 theme,
723 scale,
724 };
725 let size = widget.measure(&mut cx, constraints(known, room));
726 taffy::Size {
727 width: known.width.unwrap_or(size.width),
728 height: known.height.unwrap_or(size.height),
729 }
730 },
731 )
732 },
733 );
734 sync(computed);
735 }
736 }
737
738 fn after_moves(&mut self) {
741 if self.state.focus.is_some_and(|f| !self.state.is_shown(f)) {
742 self.set_focus(None);
743 }
744 if let (Some(at), None) = (self.state.pointer, self.state.capture) {
745 let (hit, _) = self.hit_top(at);
746 self.set_hover(hit, at);
747 }
748 }
749
750 fn place(&mut self, id: WidgetId, origin: Point, notify: bool, shown: bool) {
753 let state = &mut self.state;
754 let (taffy, parent) = (state.nodes[id.slot()].taffy, state.nodes[id.slot()].parent);
755 let layout = *sync(state.taffy.layout(taffy));
756 let size = Size::new(layout.size.width, layout.size.height);
757 let corner = match parent.filter(|parent| *parent == state.layer) {
758 Some(_) => state
760 .popup_origin(id, size)
761 .map(|at| Point::new(at.x.round(), at.y.round())),
762 None => None,
763 }
764 .unwrap_or(Point::new(
765 origin.x + layout.location.x,
766 origin.y + layout.location.y,
767 ));
768 let node = &mut state.nodes[id.slot()];
769 let rect = Rect::new(corner.x, corner.y, size.width, size.height);
770 node.rect = rect;
771 node.content = Rect::from_edges(
772 rect.left() + layout.border.left + layout.padding.left,
773 rect.top() + layout.border.top + layout.padding.top,
774 rect.right() - layout.border.right - layout.padding.right,
775 rect.bottom() - layout.border.bottom - layout.padding.bottom,
776 );
777 let overflow = layout.scrollable_overflow_rect;
779 node.content_size = Size::new(overflow.right, overflow.bottom);
780 let shown = shown && !node.style.hidden;
784 let room = |content: f32, view: f32| (content - view).max(0.0);
785 let clamped = if !shown {
786 node.scroll
787 } else {
788 Point::new(
789 node.scroll.x.clamp(0.0, room(overflow.right, rect.width())),
790 node.scroll
791 .y
792 .clamp(0.0, room(overflow.bottom, rect.height())),
793 )
794 };
795 if clamped != node.scroll {
796 node.scroll = clamped;
797 state.needs_paint = true;
798 }
799 node.extent = if node.style.overflow == Overflow::Visible {
800 Rect::from_edges(
801 rect.left() + overflow.left.min(0.0),
802 rect.top() + overflow.top.min(0.0),
803 rect.right().max(rect.left() + overflow.right),
804 rect.bottom().max(rect.top() + overflow.bottom),
805 )
806 } else {
807 rect
808 };
809 let inner = Point::new(rect.left() - node.scroll.x, rect.top() - node.scroll.y);
810 let changed = node.dirty || node.notified != Some(rect.size());
811 if notify && changed {
812 node.dirty = false;
813 node.notified = Some(rect.size());
814 if let Some(widget) = self.widgets.get_mut(id.slot()).and_then(Option::as_mut) {
815 let mut cx = LayoutCx {
816 text: &mut state.text,
817 theme: &state.theme,
818 scale: state.scale,
819 };
820 widget.layout(&mut cx, rect.size());
821 }
822 }
823 for index in 0..self.state.nodes[id.slot()].children.len() {
824 let child = self.state.nodes[id.slot()].children[index];
825 self.place(child, inner, notify, shown);
826 }
827 }
828
829 pub fn paint(&mut self, canvas: &mut Canvas<'_>) {
831 self.layout();
832 self.paint_node(self.state.root, canvas);
833 self.paint_node(self.state.layer, canvas);
834 self.state.needs_paint = false;
835 }
836
837 fn paint_node(&mut self, id: WidgetId, canvas: &mut Canvas<'_>) {
838 let node = &self.state.nodes[id.slot()];
839 if node.style.hidden {
840 return;
841 }
842 let rect = node.rect;
843 let clips = node.style.overflow != Overflow::Visible;
844 if canvas.clip_rect().intersect(node.extent).is_empty() {
846 return;
847 }
848 let saved = canvas.state();
849 if let Some(widget) = self.widgets.get_mut(id.slot()).and_then(Option::as_mut) {
850 widget.paint(
851 &PaintCx {
852 state: &self.state,
853 id,
854 },
855 canvas,
856 );
857 }
858 if clips {
859 canvas.clip(rect);
860 }
861 for index in 0..self.state.nodes[id.slot()].children.len() {
862 let child = self.state.nodes[id.slot()].children[index];
863 self.paint_node(child, canvas);
864 }
865 canvas.restore(saved);
866 if let Some(widget) = self.widgets.get_mut(id.slot()).and_then(Option::as_mut) {
867 widget.paint_over(
868 &PaintCx {
869 state: &self.state,
870 id,
871 },
872 canvas,
873 );
874 }
875 }
876
877 fn restyle(&mut self) {
879 for slot in 0..self.state.nodes.len() {
880 let node = &self.state.nodes[slot];
881 if node.live {
882 let id = WidgetId {
883 index: slot as u32,
884 generation: node.generation,
885 };
886 let style = self.state.taffy_style(id);
887 sync(self.state.taffy.set_style(node.taffy, style));
888 self.state.nodes[slot].dirty = true;
889 }
890 }
891 self.state.needs_layout = true;
892 self.state.needs_paint = true;
893 }
894
895 pub(crate) fn settle(&mut self) {
897 for _ in 0..4 {
900 self.adopt();
901 match self.state.requested_focus.take() {
902 Some(focus) => self.give_focus(focus),
903 None => break,
904 }
905 }
906 self.adopt();
908 self.state.requested_focus = None;
909 }
910}
911
912fn constraints(known: taffy::Size<Option<f32>>, room: taffy::Size<AvailableSpace>) -> Constraints {
914 let available = |space: AvailableSpace| match space {
915 AvailableSpace::Definite(room) => Available::Definite(room),
916 AvailableSpace::MinContent => Available::MinContent,
917 AvailableSpace::MaxContent => Available::MaxContent,
918 };
919 Constraints {
920 width: known.width,
921 height: known.height,
922 available_width: available(room.width),
923 available_height: available(room.height),
924 }
925}