1use std::collections::HashMap;
5use std::sync::Arc;
6
7use super::menu_inner::{
8 CloseCondition, Direction, ItemHeight, ItemWidth, Menu, MenuState, PathHighlight,
9};
10use super::menu_tree::MenuTree;
11use crate::Renderer;
12#[cfg(all(
13 feature = "multi-window",
14 feature = "wayland",
15 target_os = "linux",
16 feature = "winit",
17 feature = "surface-message"
18))]
19use crate::app::cosmic::{WINDOWING_SYSTEM, WindowingSystem};
20use crate::style::menu_bar::StyleSheet;
21use crate::widget::RcWrapper;
22use crate::widget::dropdown::menu::{self, State};
23use crate::widget::menu::menu_inner::init_root_menu;
24
25use iced::event::Status;
26use iced::{Point, Shadow, Vector, window};
27use iced_core::Border;
28use iced_widget::core::layout::{Limits, Node};
29use iced_widget::core::mouse::{self, Cursor};
30use iced_widget::core::renderer::{self, Renderer as IcedRenderer};
31use iced_widget::core::widget::{Tree, tree};
32use iced_widget::core::{
33 Alignment, Clipboard, Element, Layout, Length, Padding, Rectangle, Shell, Widget, event,
34 overlay, touch,
35};
36
37pub fn menu_bar<Message>(menu_roots: Vec<MenuTree<Message>>) -> MenuBar<Message>
39where
40 Message: Clone + 'static,
41{
42 MenuBar::new(menu_roots)
43}
44
45#[derive(Clone, Default)]
46pub(crate) struct MenuBarState {
47 pub(crate) inner: RcWrapper<MenuBarStateInner>,
48}
49
50pub(crate) struct MenuBarStateInner {
51 pub(crate) tree: Tree,
52 pub(crate) popup_id: HashMap<window::Id, window::Id>,
53 pub(crate) pressed: bool,
54 pub(crate) bar_pressed: bool,
55 pub(crate) view_cursor: Cursor,
56 pub(crate) open: bool,
57 pub(crate) active_root: Vec<usize>,
58 pub(crate) horizontal_direction: Direction,
59 pub(crate) vertical_direction: Direction,
60 pub(crate) menu_states: Vec<MenuState>,
62}
63impl MenuBarStateInner {
64 pub(super) fn get_trimmed_indices(&self, index: usize) -> impl Iterator<Item = usize> + '_ {
66 self.menu_states
67 .iter()
68 .skip(index)
69 .take_while(|ms| ms.index.is_some())
70 .map(|ms| ms.index.expect("No indices were found in the menu state."))
71 }
72
73 pub(crate) fn reset(&mut self) {
74 self.open = false;
75 self.active_root = Vec::new();
76 self.menu_states.clear();
77 }
78}
79impl Default for MenuBarStateInner {
80 fn default() -> Self {
81 Self {
82 tree: Tree::empty(),
83 pressed: false,
84 view_cursor: Cursor::Available([-0.5, -0.5].into()),
85 open: false,
86 active_root: Vec::new(),
87 horizontal_direction: Direction::Positive,
88 vertical_direction: Direction::Positive,
89 menu_states: Vec::new(),
90 popup_id: HashMap::new(),
91 bar_pressed: false,
92 }
93 }
94}
95
96pub(crate) fn menu_roots_children<Message>(menu_roots: &[MenuTree<Message>]) -> Vec<Tree>
97where
98 Message: Clone + 'static,
99{
100 menu_roots
110 .iter()
111 .map(|root| {
112 let mut tree = Tree::empty();
113 let flat = root
114 .flattern()
115 .iter()
116 .map(|mt| Tree::new(mt.item.clone()))
117 .collect();
118 tree.children = flat;
119 tree
120 })
121 .collect()
122}
123
124#[allow(invalid_reference_casting)]
125pub(crate) fn menu_roots_diff<Message>(menu_roots: &mut [MenuTree<Message>], tree: &mut Tree)
126where
127 Message: Clone + 'static,
128{
129 if tree.children.len() > menu_roots.len() {
130 tree.children.truncate(menu_roots.len());
131 }
132
133 tree.children
134 .iter_mut()
135 .zip(menu_roots.iter())
136 .for_each(|(t, root)| {
137 let mut flat = root
138 .flattern()
139 .iter()
140 .map(|mt| {
141 let widget = &mt.item;
142 let widget_ptr = widget as *const dyn Widget<Message, crate::Theme, Renderer>;
143 let widget_ptr_mut =
144 widget_ptr as *mut dyn Widget<Message, crate::Theme, Renderer>;
145 unsafe { &mut *widget_ptr_mut }
147 })
148 .collect::<Vec<_>>();
149
150 t.diff_children(flat.as_mut_slice());
151 });
152
153 if tree.children.len() < menu_roots.len() {
154 let extended = menu_roots[tree.children.len()..].iter().map(|root| {
155 let mut tree = Tree::empty();
156 let flat = root
157 .flattern()
158 .iter()
159 .map(|mt| Tree::new(mt.item.clone()))
160 .collect();
161 tree.children = flat;
162 tree
163 });
164 tree.children.extend(extended);
165 }
166}
167
168pub fn get_mut_or_default<T: Default>(vec: &mut Vec<T>, index: usize) -> &mut T {
169 if index < vec.len() {
170 &mut vec[index]
171 } else {
172 vec.resize_with(index + 1, T::default);
173 &mut vec[index]
174 }
175}
176
177#[allow(missing_debug_implementations)]
179pub struct MenuBar<Message> {
180 width: Length,
181 height: Length,
182 spacing: f32,
183 padding: Padding,
184 bounds_expand: u16,
185 main_offset: i32,
186 cross_offset: i32,
187 close_condition: CloseCondition,
188 item_width: ItemWidth,
189 item_height: ItemHeight,
190 path_highlight: Option<PathHighlight>,
191 menu_roots: Vec<MenuTree<Message>>,
192 style: <crate::Theme as StyleSheet>::Style,
193 window_id: window::Id,
194 #[cfg(all(
195 feature = "multi-window",
196 feature = "wayland",
197 feature = "winit",
198 target_os = "linux"
199 ))]
200 positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner,
201 pub(crate) on_surface_action:
202 Option<Arc<dyn Fn(crate::surface::Action) -> Message + Send + Sync + 'static>>,
203}
204
205impl<Message> MenuBar<Message>
206where
207 Message: Clone + 'static,
208{
209 #[must_use]
211 pub fn new(menu_roots: Vec<MenuTree<Message>>) -> Self {
212 let mut menu_roots = menu_roots;
213 menu_roots.iter_mut().for_each(MenuTree::set_index);
214
215 Self {
216 width: Length::Shrink,
217 height: Length::Shrink,
218 spacing: 0.0,
219 padding: Padding::ZERO,
220 bounds_expand: 16,
221 main_offset: 0,
222 cross_offset: 0,
223 close_condition: CloseCondition {
224 leave: false,
225 click_outside: true,
226 click_inside: true,
227 },
228 item_width: ItemWidth::Uniform(150),
229 item_height: ItemHeight::Uniform(30),
230 path_highlight: Some(PathHighlight::MenuActive),
231 menu_roots,
232 style: <crate::Theme as StyleSheet>::Style::default(),
233 window_id: window::Id::NONE,
234 #[cfg(all(
235 feature = "multi-window",
236 feature = "wayland",
237 feature = "winit",
238 target_os = "linux"
239 ))]
240 positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner::default(),
241 on_surface_action: None,
242 }
243 }
244
245 #[must_use]
251 pub fn bounds_expand(mut self, value: u16) -> Self {
252 self.bounds_expand = value;
253 self
254 }
255
256 #[must_use]
258 pub fn close_condition(mut self, close_condition: CloseCondition) -> Self {
259 self.close_condition = close_condition;
260 self
261 }
262
263 #[must_use]
265 pub fn cross_offset(mut self, value: i32) -> Self {
266 self.cross_offset = value;
267 self
268 }
269
270 #[must_use]
272 pub fn height(mut self, height: Length) -> Self {
273 self.height = height;
274 self
275 }
276
277 #[must_use]
279 pub fn item_height(mut self, item_height: ItemHeight) -> Self {
280 self.item_height = item_height;
281 self
282 }
283
284 #[must_use]
286 pub fn item_width(mut self, item_width: ItemWidth) -> Self {
287 self.item_width = item_width;
288 self
289 }
290
291 #[must_use]
293 pub fn main_offset(mut self, value: i32) -> Self {
294 self.main_offset = value;
295 self
296 }
297
298 #[must_use]
300 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
301 self.padding = padding.into();
302 self
303 }
304
305 #[must_use]
307 pub fn path_highlight(mut self, path_highlight: Option<PathHighlight>) -> Self {
308 self.path_highlight = path_highlight;
309 self
310 }
311
312 #[must_use]
314 pub fn spacing(mut self, units: f32) -> Self {
315 self.spacing = units;
316 self
317 }
318
319 #[must_use]
321 pub fn style(mut self, style: impl Into<<crate::Theme as StyleSheet>::Style>) -> Self {
322 self.style = style.into();
323 self
324 }
325
326 #[must_use]
328 pub fn width(mut self, width: Length) -> Self {
329 self.width = width;
330 self
331 }
332
333 #[cfg(all(
334 feature = "multi-window",
335 feature = "wayland",
336 feature = "winit",
337 target_os = "linux"
338 ))]
339 pub fn with_positioner(
340 mut self,
341 positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner,
342 ) -> Self {
343 self.positioner = positioner;
344 self
345 }
346
347 #[must_use]
348 pub fn window_id(mut self, id: window::Id) -> Self {
349 self.window_id = id;
350 self
351 }
352
353 #[must_use]
354 pub fn window_id_maybe(mut self, id: Option<window::Id>) -> Self {
355 if let Some(id) = id {
356 self.window_id = id;
357 }
358 self
359 }
360
361 #[must_use]
362 pub fn on_surface_action(
363 mut self,
364 handler: impl Fn(crate::surface::Action) -> Message + Send + Sync + 'static,
365 ) -> Self {
366 self.on_surface_action = Some(Arc::new(handler));
367 self
368 }
369
370 #[cfg(all(
371 feature = "multi-window",
372 feature = "wayland",
373 target_os = "linux",
374 feature = "winit",
375 feature = "surface-message"
376 ))]
377 #[allow(clippy::too_many_lines)]
378 fn create_popup(
379 &mut self,
380 layout: Layout<'_>,
381 view_cursor: Cursor,
382 renderer: &Renderer,
383 shell: &mut Shell<'_, Message>,
384 viewport: &Rectangle,
385 my_state: &mut MenuBarState,
386 ) {
387 if self.window_id != window::Id::NONE && self.on_surface_action.is_some() {
388 use crate::surface::action::destroy_popup;
389 use iced_runtime::platform_specific::wayland::popup::{
390 SctkPopupSettings, SctkPositioner,
391 };
392
393 let surface_action = self.on_surface_action.as_ref().unwrap();
394 let old_active_root = my_state
395 .inner
396 .with_data(|state| state.active_root.first().copied());
397
398 let hovered_root = layout
400 .children()
401 .position(|lo| view_cursor.is_over(lo.bounds()));
402 if hovered_root.is_none()
403 || old_active_root
404 .zip(hovered_root)
405 .is_some_and(|r| r.0 == r.1)
406 {
407 return;
408 }
409
410 let (id, root_list) = my_state.inner.with_data_mut(|state| {
411 if let Some(id) = state.popup_id.get(&self.window_id).copied() {
412 state.menu_states.clear();
414 state.active_root.clear();
415 shell.publish(surface_action(destroy_popup(id)));
416 state.view_cursor = view_cursor;
417 (id, layout.children().map(|lo| lo.bounds()).collect())
418 } else {
419 (
420 window::Id::unique(),
421 layout.children().map(|lo| lo.bounds()).collect(),
422 )
423 }
424 });
425
426 let mut popup_menu: Menu<'static, _> = Menu {
427 tree: my_state.clone(),
428 menu_roots: std::borrow::Cow::Owned(self.menu_roots.clone()),
429 bounds_expand: self.bounds_expand,
430 menu_overlays_parent: false,
431 close_condition: self.close_condition,
432 item_width: self.item_width,
433 item_height: self.item_height,
434 bar_bounds: layout.bounds(),
435 main_offset: self.main_offset,
436 cross_offset: self.cross_offset,
437 root_bounds_list: root_list,
438 path_highlight: self.path_highlight,
439 style: std::borrow::Cow::Owned(self.style.clone()),
440 position: Point::new(0., 0.),
441 is_overlay: false,
442 window_id: id,
443 depth: 0,
444 on_surface_action: self.on_surface_action.clone(),
445 };
446
447 init_root_menu(
448 &mut popup_menu,
449 renderer,
450 shell,
451 view_cursor.position().unwrap(),
452 viewport.size(),
453 Vector::new(0., 0.),
454 layout.bounds(),
455 self.main_offset as f32,
456 );
457 let (anchor_rect, gravity) = my_state.inner.with_data_mut(|state| {
458 state.popup_id.insert(self.window_id, id);
459 (state
460 .menu_states
461 .iter()
462 .find(|s| s.index.is_none())
463 .map(|s| s.menu_bounds.parent_bounds)
464 .map_or_else(
465 || {
466 let bounds = layout.bounds();
467 Rectangle {
468 x: bounds.x as i32,
469 y: bounds.y as i32,
470 width: bounds.width as i32,
471 height: bounds.height as i32,
472 }
473 },
474 |r| Rectangle {
475 x: r.x as i32,
476 y: r.y as i32,
477 width: r.width as i32,
478 height: r.height as i32,
479 },
480 ), match (state.horizontal_direction, state.vertical_direction) {
481 (Direction::Positive, Direction::Positive) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomRight,
482 (Direction::Positive, Direction::Negative) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::TopRight,
483 (Direction::Negative, Direction::Positive) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomLeft,
484 (Direction::Negative, Direction::Negative) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::TopLeft,
485 })
486 });
487
488 let menu_node = popup_menu.layout(renderer, Limits::NONE.min_width(1.).min_height(1.));
489 let popup_size = menu_node.size();
490 let positioner = SctkPositioner {
491 size: Some((
492 popup_size.width.ceil() as u32 + 2,
493 popup_size.height.ceil() as u32 + 2,
494 )),
495 anchor_rect,
496 anchor:
497 cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Anchor::BottomLeft,
498 gravity,
499 reactive: true,
500 ..Default::default()
501 };
502 let parent = self.window_id;
503 shell.publish((surface_action)(crate::surface::action::simple_popup(
504 move || SctkPopupSettings {
505 parent,
506 id,
507 positioner: positioner.clone(),
508 parent_size: None,
509 grab: true,
510 close_with_children: false,
511 input_zone: None,
512 },
513 Some(move || {
514 Element::from(crate::widget::container(popup_menu.clone()).center(Length::Fill))
515 .map(crate::action::app)
516 }),
517 )));
518 }
519 }
520}
521impl<Message> Widget<Message, crate::Theme, Renderer> for MenuBar<Message>
522where
523 Message: Clone + 'static,
524{
525 fn size(&self) -> iced_core::Size<Length> {
526 iced_core::Size::new(self.width, self.height)
527 }
528
529 fn diff(&mut self, tree: &mut Tree) {
530 let state = tree.state.downcast_mut::<MenuBarState>();
531 state
532 .inner
533 .with_data_mut(|inner| menu_roots_diff(&mut self.menu_roots, &mut inner.tree));
534 }
535
536 fn tag(&self) -> tree::Tag {
537 tree::Tag::of::<MenuBarState>()
538 }
539
540 fn state(&self) -> tree::State {
541 tree::State::new(MenuBarState::default())
542 }
543
544 fn children(&self) -> Vec<Tree> {
545 menu_roots_children(&self.menu_roots)
546 }
547
548 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &Limits) -> Node {
549 use super::flex;
550
551 let limits = limits.width(self.width).height(self.height);
552 let mut children = self
553 .menu_roots
554 .iter_mut()
555 .map(|root| &mut root.item)
556 .collect::<Vec<_>>();
557 let mut tree_children = tree
559 .children
560 .iter_mut()
561 .map(|t| &mut t.children[0])
562 .collect::<Vec<_>>();
563 flex::resolve_wrapper(
564 &flex::Axis::Horizontal,
565 renderer,
566 &limits,
567 self.padding,
568 self.spacing,
569 Alignment::Center,
570 &mut children,
571 &mut tree_children,
572 )
573 }
574
575 #[allow(clippy::too_many_lines)]
576 fn update(
577 &mut self,
578 tree: &mut Tree,
579 event: &event::Event,
580 layout: Layout<'_>,
581 view_cursor: Cursor,
582 renderer: &Renderer,
583 clipboard: &mut dyn Clipboard,
584 shell: &mut Shell<'_, Message>,
585 viewport: &Rectangle,
586 ) {
587 use event::Event::{Mouse, Touch};
588 use mouse::Button::Left;
589 use mouse::Event::ButtonReleased;
590 use touch::Event::{FingerLifted, FingerLost};
591
592 process_root_events(
593 &mut self.menu_roots,
594 view_cursor,
595 tree,
596 event,
597 layout,
598 renderer,
599 clipboard,
600 shell,
601 viewport,
602 );
603
604 let my_state = tree.state.downcast_mut::<MenuBarState>();
605
606 let reset = self.window_id != window::Id::NONE
608 && my_state
609 .inner
610 .with_data(|d| !d.open && !d.active_root.is_empty());
611
612 let open = my_state.inner.with_data_mut(|state| {
613 if reset {
614 if let Some(popup_id) = state.popup_id.get(&self.window_id).copied() {
615 if let Some(handler) = self.on_surface_action.as_ref() {
616 shell.publish((handler)(crate::surface::Action::DestroyPopup(popup_id)));
617 state.reset();
618 }
619 }
620 }
621 state.open
622 });
623
624 match event {
625 Mouse(mouse::Event::ButtonPressed(Left))
626 | Touch(touch::Event::FingerPressed { .. })
627 if view_cursor.is_over(layout.bounds()) =>
628 {
629 shell.capture_event();
631 }
632 Mouse(ButtonReleased(Left)) | Touch(FingerLifted { .. } | FingerLost { .. }) => {
633 let create_popup = my_state.inner.with_data_mut(|state| {
634 let mut create_popup = false;
635 if state.menu_states.is_empty() && view_cursor.is_over(layout.bounds()) {
636 state.view_cursor = view_cursor;
637 state.open = true;
638 create_popup = true;
639 } else if let Some(_id) = state.popup_id.remove(&self.window_id) {
640 state.menu_states.clear();
641 state.active_root.clear();
642 state.open = false;
643 #[cfg(all(
644 feature = "wayland",
645 target_os = "linux",
646 feature = "winit",
647 feature = "surface-message"
648 ))]
649 {
650 let surface_action = self.on_surface_action.as_ref().unwrap();
651 shell.capture_event();
652
653 shell.publish(surface_action(crate::surface::action::destroy_popup(
654 _id,
655 )));
656 }
657 state.view_cursor = view_cursor;
658 }
659 create_popup
660 });
661
662 if !create_popup {
663 return;
664 }
665 shell.capture_event();
666 #[cfg(all(
667 feature = "multi-window",
668 feature = "wayland",
669 target_os = "linux",
670 feature = "winit",
671 feature = "surface-message"
672 ))]
673 if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
674 self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
675 }
676 }
677 Mouse(mouse::Event::CursorMoved { .. } | mouse::Event::CursorEntered)
678 if open && view_cursor.is_over(layout.bounds()) =>
679 {
680 shell.capture_event();
681 #[cfg(all(
682 feature = "multi-window",
683 feature = "wayland",
684 target_os = "linux",
685 feature = "winit",
686 feature = "surface-message"
687 ))]
688 if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
689 self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
690 }
691 }
692 _ => (),
693 }
694 }
695
696 fn draw(
697 &self,
698 tree: &Tree,
699 renderer: &mut Renderer,
700 theme: &crate::Theme,
701 style: &renderer::Style,
702 layout: Layout<'_>,
703 view_cursor: Cursor,
704 viewport: &Rectangle,
705 ) {
706 let state = tree.state.downcast_ref::<MenuBarState>();
707 let cursor_pos = view_cursor.position().unwrap_or_default();
708 state.inner.with_data_mut(|state| {
709 let position = if state.open && (cursor_pos.x < 0.0 || cursor_pos.y < 0.0) {
710 state.view_cursor
711 } else {
712 view_cursor
713 };
714
715 if self.path_highlight.is_some() {
717 let styling = theme.appearance(&self.style);
718 if let Some(active) = state.active_root.first() {
719 let active_bounds = layout
720 .children()
721 .nth(*active)
722 .expect("Active child not found in menu?")
723 .bounds();
724 let path_quad = renderer::Quad {
725 bounds: active_bounds,
726 border: Border {
727 radius: styling.bar_border_radius.into(),
728 ..Default::default()
729 },
730 shadow: Shadow::default(),
731 snap: true,
732 };
733
734 renderer.fill_quad(path_quad, styling.path);
735 }
736 }
737
738 self.menu_roots
739 .iter()
740 .zip(&tree.children)
741 .zip(layout.children())
742 .for_each(|((root, t), lo)| {
743 root.item.draw(
744 &t.children[root.index],
745 renderer,
746 theme,
747 style,
748 lo,
749 position,
750 viewport,
751 );
752 });
753 });
754 }
755
756 fn overlay<'b>(
757 &'b mut self,
758 tree: &'b mut Tree,
759 layout: Layout<'b>,
760 _renderer: &Renderer,
761 viewport: &Rectangle,
762 translation: Vector,
763 ) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> {
764 #[cfg(all(
765 feature = "multi-window",
766 feature = "wayland",
767 target_os = "linux",
768 feature = "winit",
769 feature = "surface-message"
770 ))]
771 if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland))
772 && self.on_surface_action.is_some()
773 && self.window_id != window::Id::NONE
774 {
775 return None;
776 }
777
778 let state = tree.state.downcast_ref::<MenuBarState>();
779 if state.inner.with_data(|state| !state.open) {
780 return None;
781 }
782
783 Some(
784 Menu {
785 tree: state.clone(),
786 menu_roots: std::borrow::Cow::Owned(self.menu_roots.clone()),
787 bounds_expand: self.bounds_expand,
788 menu_overlays_parent: false,
789 close_condition: self.close_condition,
790 item_width: self.item_width,
791 item_height: self.item_height,
792 bar_bounds: layout.bounds(),
793 main_offset: self.main_offset,
794 cross_offset: self.cross_offset,
795 root_bounds_list: layout.children().map(|lo| lo.bounds()).collect(),
796 path_highlight: self.path_highlight,
797 style: std::borrow::Cow::Borrowed(&self.style),
798 position: Point::new(translation.x, translation.y),
799 is_overlay: true,
800 window_id: window::Id::NONE,
801 depth: 0,
802 on_surface_action: self.on_surface_action.clone(),
803 }
804 .overlay(),
805 )
806 }
807}
808
809impl<Message> From<MenuBar<Message>> for Element<'_, Message, crate::Theme, Renderer>
810where
811 Message: Clone + 'static,
812{
813 fn from(value: MenuBar<Message>) -> Self {
814 Self::new(value)
815 }
816}
817
818#[allow(unused_results, clippy::too_many_arguments)]
819fn process_root_events<Message>(
820 menu_roots: &mut [MenuTree<Message>],
821 view_cursor: Cursor,
822 tree: &mut Tree,
823 event: &event::Event,
824 layout: Layout<'_>,
825 renderer: &Renderer,
826 clipboard: &mut dyn Clipboard,
827 shell: &mut Shell<'_, Message>,
828 viewport: &Rectangle,
829) {
830 for ((root, t), lo) in menu_roots
831 .iter_mut()
832 .zip(&mut tree.children)
833 .zip(layout.children())
834 {
835 root.item.update(
837 &mut t.children[root.index],
838 event,
839 lo,
840 view_cursor,
841 renderer,
842 clipboard,
843 shell,
844 viewport,
845 );
846 }
847}