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