From 1242f5e90e37a4162ff2c17e62c2eb2b2aa896aa Mon Sep 17 00:00:00 2001 From: genusistimelord Date: Wed, 24 Jul 2024 09:31:23 -0400 Subject: [PATCH] Add operation to menu and partial overlay support --- src/widgets/menu/menu_bar.rs | 20 ++++++- src/widgets/menu/menu_bar_overlay.rs | 60 +++++++++++++++++++- src/widgets/menu/menu_tree.rs | 85 +++++++++++++++++++++++++++- 3 files changed, 162 insertions(+), 3 deletions(-) diff --git a/src/widgets/menu/menu_bar.rs b/src/widgets/menu/menu_bar.rs index 5b13931a..0e06505c 100644 --- a/src/widgets/menu/menu_bar.rs +++ b/src/widgets/menu/menu_bar.rs @@ -9,7 +9,7 @@ use iced::{ advanced::{ layout::{Limits, Node}, mouse, overlay, renderer, - widget::{tree, Tree}, + widget::{tree, Operation, Tree}, Clipboard, Layout, Shell, Widget, }, alignment, event, Element, Event, Length, Padding, Rectangle, Size, @@ -258,6 +258,24 @@ where .merge(status) } + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation<()>, + ) { + operation.container(None, layout.bounds(), &mut |operation| { + self.roots + .iter() // [Item...] + .zip(tree.children.iter_mut()) // [item_tree...] + .zip(layout.children()) // [widget_node...] + .for_each(|((child, state), layout)| { + child.operate(state, layout, renderer, operation); + }); + }); + } + fn mouse_interaction( &self, tree: &Tree, diff --git a/src/widgets/menu/menu_bar_overlay.rs b/src/widgets/menu/menu_bar_overlay.rs index a4a569e3..2622666e 100644 --- a/src/widgets/menu/menu_bar_overlay.rs +++ b/src/widgets/menu/menu_bar_overlay.rs @@ -10,7 +10,7 @@ use iced::{ advanced::{ layout::{Limits, Node}, mouse, overlay, renderer, - widget::Tree, + widget::{Operation, Tree}, Clipboard, Layout, Shell, }, event, Event, Point, Rectangle, Size, Vector, @@ -404,6 +404,64 @@ where ) } + fn operate( + &mut self, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation<()>, + ) { + let bar = self.tree.state.downcast_ref::(); + let Some(active) = bar.active_root else { + return; + }; + + // let viewport = layout.bounds(); + let mut lc = layout.children(); + let _bar_bounds = lc.next().unwrap().bounds(); + let _roots_layout = lc.next().unwrap(); + + // let parent_bounds = roots_layout.children().nth(active).unwrap().bounds(); + let menu_layouts_layout = lc.next().unwrap(); // Node{0, [menu_node...]} + let mut menu_layouts = menu_layouts_layout.children(); // [menu_node...] + + let active_root = &self.roots[active]; + let active_tree = &mut self.tree.children[active]; + + fn rec<'a, 'b, Message, Theme: Catalog, Renderer: renderer::Renderer>( + tree: &mut Tree, + item: &Item<'a, Message, Theme, Renderer>, + layout_iter: &mut impl Iterator>, + renderer: &Renderer, + operation: &mut dyn Operation<()>, + ) { + let menu = item.menu.as_ref().expect("No menu defined in this item"); + let menu_tree = &mut tree.children[1]; + + let Some(menu_layout) = layout_iter.next() else { + return; + }; + + menu.operate(menu_tree, menu_layout, renderer, operation); + + operation.container(None, menu_layout.bounds(), &mut |operation| { + menu.items + .iter() // [Item...] + .zip(menu_tree.children.iter_mut()) // [item_tree...] // [widget_node...] + .for_each(|(child, state)| { + rec(state, child, layout_iter, renderer, operation); + }); + }); + } + + rec( + active_tree, + active_root, + &mut menu_layouts, + renderer, + operation, + ); + } + fn draw( &self, renderer: &mut Renderer, diff --git a/src/widgets/menu/menu_tree.rs b/src/widgets/menu/menu_tree.rs index 794afb10..2dfe819c 100644 --- a/src/widgets/menu/menu_tree.rs +++ b/src/widgets/menu/menu_tree.rs @@ -12,10 +12,12 @@ use super::common::*; use super::flex; +use iced::advanced::overlay::Group; +use iced::advanced::widget::Operation; use iced::{ advanced::{ layout::{Layout, Limits, Node}, - mouse, renderer, + mouse, overlay, renderer, widget::tree::{self, Tree}, Clipboard, Shell, }, @@ -374,6 +376,62 @@ where .merge(status) } + pub(super) fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation<()>, + ) { + let mut lc = layout.children(); + let slice_layout = lc.next().unwrap(); + let _prescroll = lc.next().unwrap().bounds(); + let _offset_bounds = lc.next().unwrap().bounds(); + let _check_bounds = lc.next().unwrap().bounds(); + + let menu_state = tree.state.downcast_mut::(); + let slice = &menu_state.slice; + + operation.container(None, layout.bounds(), &mut |operation| { + self.items[slice.start_index..=slice.end_index] // [item...] + .iter() + .zip(tree.children[slice.start_index..=slice.end_index].iter_mut()) // [item_tree...] + .zip(slice_layout.children()) + .for_each(|((child, state), layout)| { + child.operate(state, layout, renderer, operation); + }); + }); + } + + #[allow(dead_code)] + pub(super) fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + translation: Vector, + ) -> Option> { + let mut lc = layout.children(); + let slice_layout = lc.next()?; + let _prescroll = lc.next()?.bounds(); + let _offset_bounds = lc.next()?.bounds(); + let _check_bounds = lc.next()?.bounds(); + + let menu_state = tree.state.downcast_mut::(); + let slice = &menu_state.slice; + + let children = self.items[slice.start_index..=slice.end_index] // [item...] + .iter_mut() + .zip(tree.children[slice.start_index..=slice.end_index].iter_mut()) // [item_tree...] + .zip(slice_layout.children()) + .filter_map(|((child, state), layout)| { + child.overlay(state, layout, renderer, translation) + }) + .collect::>(); + + (!children.is_empty()).then(|| Group::with_children(children).overlay()) + } + /// tree: Tree{ menu_state, \[item_tree...] } /// /// layout: Node{inf, \[ slice_node, prescroll, offset_bounds, check_bounds ]} @@ -774,6 +832,31 @@ where viewport, ); } + + pub(super) fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation<()>, + ) { + self.item + .as_widget() + .operate(&mut tree.children[0], layout, renderer, operation); + } + + #[allow(dead_code)] + pub(super) fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + translation: Vector, + ) -> Option> { + self.item + .as_widget_mut() + .overlay(&mut tree.children[0], layout, renderer, translation) + } } /// Adaptive open direction