This commit is contained in:
Ashley Wulber 2025-06-02 13:25:05 -04:00
parent 89700a2ed5
commit 4c03483e25
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
5 changed files with 210 additions and 154 deletions

View file

@ -260,6 +260,7 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
is_overlay: true, is_overlay: true,
window_id: window::Id::NONE, window_id: window::Id::NONE,
depth: 0, depth: 0,
on_surface_action: None,
} }
.overlay(), .overlay(),
) )

View file

@ -1,7 +1,7 @@
// From iced_aw, license MIT // From iced_aw, license MIT
//! A widget that handles menu trees //! A widget that handles menu trees
use std::collections::HashMap; use std::{collections::HashMap, sync::Arc};
use super::{ use super::{
menu_inner::{ menu_inner::{
@ -12,6 +12,7 @@ use super::{
use crate::{ use crate::{
Renderer, Renderer,
style::menu_bar::StyleSheet, style::menu_bar::StyleSheet,
surface::action::destroy_popup,
widget::{ widget::{
RcWrapper, RcWrapper,
dropdown::menu::{self, State}, dropdown::menu::{self, State},
@ -70,6 +71,7 @@ impl MenuBarStateInner {
} }
pub(super) fn reset(&mut self) { pub(super) fn reset(&mut self) {
dbg!("reset");
self.open = false; self.open = false;
self.active_root = Vec::new(); self.active_root = Vec::new();
self.menu_states.clear(); self.menu_states.clear();
@ -192,7 +194,8 @@ pub struct MenuBar<Message> {
window_id: window::Id, window_id: window::Id,
#[cfg(all(feature = "wayland", feature = "winit"))] #[cfg(all(feature = "wayland", feature = "winit"))]
positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner, positioner: iced_runtime::platform_specific::wayland::popup::SctkPositioner,
pub(crate) on_surface_action: Option<Box<dyn Fn(crate::surface::Action) -> Message>>, pub(crate) on_surface_action:
Option<Arc<dyn Fn(crate::surface::Action) -> Message + Send + Sync + 'static>>,
} }
impl<Message> MenuBar<Message> impl<Message> MenuBar<Message>
@ -348,9 +351,9 @@ where
pub fn on_surface_action( pub fn on_surface_action(
mut self, mut self,
handler: impl Fn(crate::surface::Action) -> Message + 'static, handler: impl Fn(crate::surface::Action) -> Message + Send + Sync + 'static,
) -> Self { ) -> Self {
self.on_surface_action = Some(Box::new(handler)); self.on_surface_action = Some(Arc::new(handler));
self self
} }
} }
@ -420,9 +423,10 @@ where
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
viewport: &Rectangle, viewport: &Rectangle,
) -> event::Status { ) -> event::Status {
use event::Event::{Mouse, Touch}; use event::Event::{Mouse, Touch, Window};
use mouse::{Button::Left, Event::ButtonReleased}; use mouse::{Button::Left, Event::ButtonReleased};
use touch::Event::{FingerLifted, FingerLost}; use touch::Event::{FingerLifted, FingerLost};
use window::Event::Focused;
let root_status = process_root_events( let root_status = process_root_events(
&mut self.menu_roots, &mut self.menu_roots,
@ -439,12 +443,16 @@ where
let my_state = tree.state.downcast_mut::<MenuBarState>(); let my_state = tree.state.downcast_mut::<MenuBarState>();
// XXX this should reset the state if there are no other copies of the state, which implies no dropdown menus open. // XXX this should reset the state if there are no other copies of the state, which implies no dropdown menus open.
let reset = self.window_id != window::Id::NONE && my_state.inner.with_data(|d| d.open); let reset = self.window_id != window::Id::NONE
&& my_state
.inner
.with_data(|d| !d.open && !d.active_root.is_empty());
my_state.inner.with_data_mut(|state| { my_state.inner.with_data_mut(|state| {
if reset { if reset {
if let Some(popup_id) = state.popup_id.get(&self.window_id).copied() { if let Some(popup_id) = state.popup_id.get(&self.window_id).copied() {
dbg!("reset destroy"); dbg!("reset destroy");
if let Some(handler) = self.on_surface_action.as_ref() { if let Some(handler) = self.on_surface_action.as_ref() {
shell.publish((handler)(crate::surface::Action::DestroyPopup(popup_id))); shell.publish((handler)(crate::surface::Action::DestroyPopup(popup_id)));
state.reset(); state.reset();
@ -457,13 +465,29 @@ where
match event { match event {
Mouse(ButtonReleased(Left)) | Touch(FingerLifted { .. } | FingerLost { .. }) => { Mouse(ButtonReleased(Left)) | Touch(FingerLifted { .. } | FingerLost { .. }) => {
my_state.inner.with_data_mut(|state| { let create_popup = my_state.inner.with_data_mut(|state| {
let mut create_popup = false;
if state.menu_states.is_empty() && view_cursor.is_over(layout.bounds()) { if state.menu_states.is_empty() && view_cursor.is_over(layout.bounds()) {
state.view_cursor = view_cursor; state.view_cursor = view_cursor;
dbg!(view_cursor.is_over(layout.bounds()));
state.open = true; state.open = true;
create_popup = true;
} else if let Some(id) = state.popup_id.remove(&self.window_id) {
dbg!("destroy popup...");
state.menu_states.clear();
state.active_root.clear();
let surface_action = self.on_surface_action.as_ref().unwrap();
state.open = false;
shell.publish(surface_action(destroy_popup(id)));
state.view_cursor = view_cursor;
} }
create_popup
}); });
#[cfg(all(feature = "wayland", feature = "winit"))] dbg!(create_popup);
if !create_popup {
return root_status;
}
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
dbg!( dbg!(
self.window_id != window::Id::NONE, self.window_id != window::Id::NONE,
@ -533,6 +557,7 @@ where
is_overlay: false, is_overlay: false,
window_id: id, window_id: id,
depth: 0, depth: 0,
on_surface_action: self.on_surface_action.clone(),
}; };
init_root_menu( init_root_menu(
@ -545,7 +570,8 @@ where
layout.bounds(), layout.bounds(),
self.main_offset as f32, self.main_offset as f32,
); );
let anchor_rect = my_state.inner.with_data(|state| { let anchor_rect = my_state.inner.with_data_mut(|state| {
state.popup_id.insert(self.window_id, id);
state.menu_states[0] state.menu_states[0]
.iter() .iter()
.find(|s| s.index.is_none()) .find(|s| s.index.is_none())
@ -601,11 +627,15 @@ where
} }
} }
// Window(Focused) => { // Window(Focused) => {
// if let Some(popup_id) = state.popup_id.get(&self.window_id).copied() { // my_state.inner.with_data_mut(|state| {
// dbg!("window focused"); // if let Some(popup_id) = state.popup_id.get(&self.window_id).copied() {
// shell.publish(Message::from(SurfaceMessage::DestroyPopup(popup_id))); // dbg!("window focused");
// } // if let Some(handler) = self.on_surface_action.as_ref() {
// state.reset(); // shell.publish((handler)(destroy_popup(popup_id)));
// state.reset();
// }
// }
// });
// } // }
_ => (), _ => (),
} }
@ -635,7 +665,11 @@ where
// draw path highlight // draw path highlight
if self.path_highlight.is_some() { if self.path_highlight.is_some() {
let styling = theme.appearance(&self.style); let styling = theme.appearance(&self.style);
if let Some(active) = get_mut_or_default(&mut state.active_root, 0).get(0) { if let Some(active) = state
.active_root
.get(0)
.and_then(|active_root| active_root.get(0))
{
let active_bounds = layout let active_bounds = layout
.children() .children()
.nth(*active) .nth(*active)
@ -679,13 +713,13 @@ where
_renderer: &Renderer, _renderer: &Renderer,
translation: Vector, translation: Vector,
) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> { ) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> {
#[cfg(all(feature = "wayland", feature = "winit"))] // #[cfg(all(feature = "wayland", feature = "winit"))]
return None; return None;
let state = tree.state.downcast_ref::<MenuBarState>(); let state = tree.state.downcast_ref::<MenuBarState>();
if state if state
.inner .inner
.with_data_mut(|state| !state.open || state.active_root.is_empty()) .with_data(|state| !state.open || state.active_root.is_empty())
{ {
return None; return None;
}; };
@ -709,6 +743,7 @@ where
is_overlay: true, is_overlay: true,
window_id: window::Id::NONE, window_id: window::Id::NONE,
depth: 0, depth: 0,
on_surface_action: self.on_surface_action.clone(),
} }
.overlay(), .overlay(),
) )

View file

@ -1,7 +1,7 @@
// From iced_aw, license MIT // From iced_aw, license MIT
//! Menu tree overlay //! Menu tree overlay
use std::borrow::Cow; use std::{borrow::Cow, sync::Arc};
use super::{menu_bar::MenuBarState, menu_tree::MenuTree}; use super::{menu_bar::MenuBarState, menu_tree::MenuTree};
use crate::style::menu_bar::StyleSheet; use crate::style::menu_bar::StyleSheet;
@ -466,6 +466,8 @@ pub(crate) struct Menu<'b, Message: std::clone::Clone> {
/// window id for this popup /// window id for this popup
pub(crate) window_id: window::Id, pub(crate) window_id: window::Id,
pub(crate) depth: usize, pub(crate) depth: usize,
pub(crate) on_surface_action:
Option<Arc<dyn Fn(crate::surface::Action) -> Message + Send + Sync + 'static>>,
} }
impl<'b, Message: Clone + 'static> Menu<'b, Message> { impl<'b, Message: Clone + 'static> Menu<'b, Message> {
pub(crate) fn overlay(self) -> overlay::Element<'b, Message, crate::Theme, crate::Renderer> { pub(crate) fn overlay(self) -> overlay::Element<'b, Message, crate::Theme, crate::Renderer> {
@ -473,6 +475,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
} }
pub(crate) fn layout(&self, renderer: &crate::Renderer, limits: Limits) -> Node { pub(crate) fn layout(&self, renderer: &crate::Renderer, limits: Limits) -> Node {
dbg!("layout");
// layout children; // layout children;
let position = self.position; let position = self.position;
let mut intrinsic_size = Size::ZERO; let mut intrinsic_size = Size::ZERO;
@ -480,6 +483,8 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
dbg!(self.depth); dbg!(self.depth);
let empty = Vec::new(); let empty = Vec::new();
self.tree.inner.with_data_mut(|data| { self.tree.inner.with_data_mut(|data| {
dbg!(data.active_root.len());
let overlay_offset = Point::ORIGIN - position; let overlay_offset = Point::ORIGIN - position;
let tree_children = &mut data.tree.children; let tree_children = &mut data.tree.children;
dbg!(&data.active_root,); dbg!(&data.active_root,);
@ -557,11 +562,12 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
.unwrap_or_default(); .unwrap_or_default();
// dbg!(intrinsic_size); // dbg!(intrinsic_size);
// overlay space viewport rectangle // overlay space viewport rectangle
Node::with_children( let node = Node::with_children(
limits.resolve(Length::Shrink, Length::Shrink, intrinsic_size), limits.resolve(Length::Shrink, Length::Shrink, intrinsic_size),
children, children,
) )
.translate(Point::ORIGIN - position) .translate(Point::ORIGIN - position);
node
}) })
} }
@ -574,6 +580,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
) -> (Option<(usize, MenuState)>, event::Status) { ) -> (Option<(usize, MenuState)>, event::Status) {
// dbg!("on event");
use event::{ use event::{
Event::{Mouse, Touch}, Event::{Mouse, Touch},
Status::{Captured, Ignored}, Status::{Captured, Ignored},
@ -606,7 +613,6 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
overlay_offset, overlay_offset,
); );
dbg!("init_root_menu");
init_root_menu( init_root_menu(
self, self,
renderer, renderer,
@ -650,6 +656,8 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
self.cross_offset as f32, self.cross_offset as f32,
self.is_overlay, self.is_overlay,
); );
dbg!(new_root.as_ref().map(|r| r.0));
return (new_root, status.merge(menu_status)); return (new_root, status.merge(menu_status));
} }
@ -668,19 +676,24 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
let is_inside = state.menu_states[self.depth] let is_inside = state.menu_states[self.depth]
.iter() .iter()
.any(|ms| ms.menu_bounds.check_bounds.contains(overlay_cursor)); .any(|ms| ms.menu_bounds.check_bounds.contains(overlay_cursor));
let mut needs_reset = false;
if self.close_condition.click_inside needs_reset |= self.close_condition.click_inside
&& is_inside && is_inside
&& matches!( && matches!(
event, event,
Mouse(ButtonReleased(Left)) | Touch(FingerLifted { .. }) Mouse(ButtonReleased(Left)) | Touch(FingerLifted { .. })
) );
{
state.reset(); needs_reset |= self.close_condition.click_outside && !is_inside;
return Captured;
} if needs_reset {
dbg!("reset");
if let Some(handler) = self.on_surface_action.as_ref() {
shell.publish((handler)(crate::surface::Action::DestroyPopup(
self.window_id,
)));
}
if self.close_condition.click_outside && !is_inside {
state.reset(); state.reset();
return Captured; return Captured;
} }
@ -711,11 +724,12 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
view_cursor: Cursor, view_cursor: Cursor,
) { ) {
self.tree.inner.with_data(|state| { self.tree.inner.with_data(|state| {
if !state.open {
return;
}
let Some(active_root) = state.active_root.get(self.depth) else { let Some(active_root) = state.active_root.get(self.depth) else {
// dbg!(self.window_id);
return; return;
}; };
dbg!(active_root);
let viewport = layout.bounds(); let viewport = layout.bounds();
let viewport_size = viewport.size(); let viewport_size = viewport.size();
let overlay_offset = Point::ORIGIN - viewport.position(); let overlay_offset = Point::ORIGIN - viewport.position();
@ -725,7 +739,6 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
} else { } else {
Rectangle::new(Point::ORIGIN, Size::INFINITY) Rectangle::new(Point::ORIGIN, Size::INFINITY)
}; };
// dbg!(self.window_id, &active_root);
let styling = theme.appearance(&self.style); let styling = theme.appearance(&self.style);
let (active_tree, roots) = active_root.iter().take(self.depth).fold( let (active_tree, roots) = active_root.iter().take(self.depth).fold(
@ -736,24 +749,8 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|(tree, mt), next_active_root| (tree, &mt[*next_active_root].children), |(tree, mt), next_active_root| (tree, &mt[*next_active_root].children),
); );
dbg!(
state.tree.children.len(),
state.tree.children[active_root[0]].children.len()
);
// let tree = &state.tree.children[active_root].children;
// let root = &self.menu_roots[active_root];
dbg!(&active_root.len());
let indices = state.get_trimmed_indices(self.depth).collect::<Vec<_>>(); let indices = state.get_trimmed_indices(self.depth).collect::<Vec<_>>();
dbg!(self.depth);
dbg!(
self.window_id,
state.menu_states.len(),
state.menu_states[self.depth].len(),
layout.children().count(),
layout.bounds()
);
state.menu_states[self.depth] state.menu_states[self.depth]
.iter() .iter()
.zip(layout.children()) .zip(layout.children())
@ -822,7 +819,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
} }
} }
if start_index < menu_roots.len() { if start_index < menu_roots.len() {
dbg!(start_index, end_index, menu_roots.len()); // dbg!(start_index, end_index, menu_roots.len());
// draw item // draw item
menu_roots[start_index..=end_index] menu_roots[start_index..=end_index]
.iter() .iter()
@ -906,7 +903,7 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
renderer: &crate::Renderer, renderer: &crate::Renderer,
limits: &iced_core::layout::Limits, limits: &iced_core::layout::Limits,
) -> iced_core::layout::Node { ) -> iced_core::layout::Node {
// dbg!(self.window_id, limits); // dbg!("layout", self.window_id, limits);
Menu::layout(self, renderer, *limits) Menu::layout(self, renderer, *limits)
} }
@ -935,70 +932,84 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
_viewport: &Rectangle, _viewport: &Rectangle,
) -> event::Status { ) -> event::Status {
let (new_root, status) = self.on_event(event, layout, cursor, renderer, clipboard, shell); let (new_root, status) = self.on_event(event, layout, cursor, renderer, clipboard, shell);
// #[cfg(feature = "wayland")] dbg!(new_root.as_ref().map(|r| r.0));
// #[cfg(all(feature = "wayland", feature = "surface-message"))]
// if let Some((new_root, new_ms)) = new_root { // if let Some((new_root, new_ms)) = new_root {
// use iced_runtime::platform_specific::wayland::popup::{ // use iced_runtime::platform_specific::wayland::popup::{
// SctkPopupSettings, SctkPositioner, // SctkPopupSettings, SctkPositioner,
// }; // };
// let mut guard = self.tree.inner.lock().unwrap(); // dbg!(new_root);
// let popup_id = *guard // let Some((mut menu, popup_id)) = self.tree.inner.with_data_mut(|state| {
// .popup_id // let popup_id = *state
// .entry(self.window_id) // .popup_id
// .or_insert_with(window::Id::unique); // .entry(self.window_id)
// let active_roots = &guard.active_root[&self.window_id]; // .or_insert_with(window::Id::unique);
// // dbg!(active_roots); // let active_roots = state
// let root_bounds_list = active_roots // .active_root
// .into_iter() // .get(self.depth)
// .fold(layout, |l, active_root| { // .cloned()
// // dbg!(active_root); // .unwrap_or_default(); // dbg!(active_roots);
// l.children().nth(*active_root).unwrap() // // let root_bounds_list = active_roots
// }) // // .into_iter()
// .children() // // .fold(layout, |l, active_root| {
// .map(|c| c.bounds()) // // // dbg!(active_root);
// .collect(); // // l.children().nth(active_root).unwrap()
// drop(guard); // // })
// // .children()
// // .map(|c| c.bounds())
// // .collect();
// let root_bounds_list = layout.children().map(|lo| lo.bounds()).collect();
// // drop(state);
// // dbg!(&root_bounds_list); // // dbg!(&root_bounds_list);
// // dbg!(self.menu_roots.clone().len()); // // dbg!(self.menu_roots.clone().len());
// // dbg!(self // // dbg!(self
// // .menu_roots // // .menu_roots
// // .clone() // // .clone()
// // .iter() // // .iter()
// // .map(|r| r.index) // // .map(|r| r.index)
// // .collect::<Vec<_>>()); // // .collect::<Vec<_>>());
// let mut popup_menu = Menu { // let mut popup_menu = Menu {
// tree: self.tree.clone(), // tree: self.tree.clone(),
// menu_roots: Cow::Owned(Cow::into_owned(self.menu_roots.clone())), // menu_roots: Cow::Owned(Cow::into_owned(self.menu_roots.clone())),
// bounds_expand: self.bounds_expand, // bounds_expand: self.bounds_expand,
// menu_overlays_parent: false, // menu_overlays_parent: false,
// close_condition: self.close_condition, // close_condition: self.close_condition,
// item_width: self.item_width, // item_width: self.item_width,
// item_height: self.item_height, // item_height: self.item_height,
// bar_bounds: layout.bounds(), // bar_bounds: layout.bounds(),
// main_offset: self.main_offset, // main_offset: self.main_offset,
// cross_offset: self.cross_offset, // cross_offset: self.cross_offset,
// root_bounds_list, // root_bounds_list,
// path_highlight: self.path_highlight, // path_highlight: self.path_highlight,
// style: Cow::Owned(Cow::into_owned(self.style.clone())), // style: Cow::Owned(Cow::into_owned(self.style.clone())),
// position: Point::new(0., 0.), // position: Point::new(0., 0.),
// is_overlay: false, // is_overlay: false,
// window_id: popup_id, // window_id: popup_id,
// depth: self.depth + 1, // depth: self.depth + 1,
// }; // on_surface_action: self.on_surface_action.clone(),
// let mut guard = self.tree.inner.lock().unwrap(); // };
// // dbg!(guard.menu_states.keys()); // // let mut state = self.tree.inner.lock().unwrap();
// let Some(parent_root) = guard.active_root.get(&self.window_id) else { // // dbg!(state.menu_states.keys());
// // TODO log warning // // let Some(parent_root) = state.active_root.get(&self.window_id) else {
// // // TODO log warning
// // return status;
// // };
// let Some(parent_root) = state.active_root.get(self.depth).cloned() else {
// return None;
// };
// let mut roots = parent_root.clone();
// roots.push(new_root);
// // dbg!(&roots);
// state.active_root.push(roots);
// // _ = state.menu_states.remove(&popup_id);
// // drop(state);
// Some((popup_menu, popup_id))
// }) else {
// return status; // return status;
// }; // };
// let mut roots = parent_root.clone();
// roots.push(new_root);
// // dbg!(&roots);
// guard.active_root.insert(popup_id, roots);
// _ = guard.menu_states.remove(&popup_id);
// drop(guard);
// init_root_popup_menu( // init_root_popup_menu(
// &mut popup_menu, // &mut menu,
// renderer, // renderer,
// shell, // shell,
// cursor.position().unwrap(), // cursor.position().unwrap(),
@ -1007,40 +1018,38 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
// layout.bounds(), // layout.bounds(),
// self.main_offset as f32, // self.main_offset as f32,
// ); // );
// let mut guard = self.tree.inner.lock().unwrap(); // let anchor_rect = self.tree.inner.with_data_mut(|state| {
// // let mut state = self.tree.inner.lock().unwrap();
// state.menu_states.get_mut(self.depth).unwrap().push(new_ms);
// guard // state.menu_states[self.depth]
// .menu_states // .iter()
// .get_mut(&self.window_id) // .find(|s| s.index.is_none())
// .unwrap() // .map(|s| s.menu_bounds.parent_bounds)
// .push(new_ms); // .map_or_else(
// || {
// let bounds = layout.bounds();
// Rectangle {
// x: bounds.x as i32,
// y: bounds.y as i32,
// width: bounds.width as i32,
// height: bounds.height as i32,
// }
// },
// |r| Rectangle {
// x: r.x as i32,
// y: r.y as i32,
// width: r.width as i32,
// height: r.height as i32,
// },
// )
// });
// let anchor_rect = guard.menu_states[&self.window_id]
// .iter()
// .find(|s| s.index.is_none())
// .map(|s| s.menu_bounds.parent_bounds)
// .map_or_else(
// || {
// let bounds = layout.bounds();
// Rectangle {
// x: bounds.x as i32,
// y: bounds.y as i32,
// width: bounds.width as i32,
// height: bounds.height as i32,
// }
// },
// |r| Rectangle {
// x: r.x as i32,
// y: r.y as i32,
// width: r.width as i32,
// height: r.height as i32,
// },
// );
// // dbg!(&anchor_rect); // // dbg!(&anchor_rect);
// drop(guard); // // drop(state);
// let menu_node = Widget::layout( // let menu_node = Widget::layout(
// &popup_menu, // &menu,
// &mut Tree::empty(), // &mut Tree::empty(),
// renderer, // renderer,
// &Limits::NONE.min_width(1.).min_height(1.), // &Limits::NONE.min_width(1.).min_height(1.),
@ -1051,16 +1060,16 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
// let popup_size = menu_node.size(); // let popup_size = menu_node.size();
// let positioner = SctkPositioner { // let positioner = SctkPositioner {
// size: Some((popup_size.width.ceil() as u32 + 2, popup_size.height.ceil() as u32 + 2)), // size: Some((popup_size.width.ceil() as u32 + 2, popup_size.height.ceil() as u32 + 2)),
// anchor_rect, // anchor_rect,
// anchor: cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Anchor::TopRight, // anchor: cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Anchor::TopRight,
// gravity:cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomRight, // gravity:cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomRight,
// reactive: true, // reactive: true,
// ..Default::default() // ..Default::default()
// }; // };
// let parent = self.window_id; // let parent = self.window_id;
// // dbg!(&positioner); // // dbg!(&positioner);
// shell.publish(crate::app::message::simple_popup( // (self.on_surface_action.as_ref().unwrap())(crate::surface::action::simple_popup(
// move || SctkPopupSettings { // move || SctkPopupSettings {
// parent, // parent,
// id: popup_id, // id: popup_id,
@ -1068,14 +1077,17 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
// parent_size: None, // parent_size: None,
// grab: true, // grab: true,
// close_with_children: true, // close_with_children: true,
// input_zone: todo!(),
// }, // },
// Some(move || { // Some(move || {
// crate::Element::from( // crate::Element::from(
// crate::widget::container(popup_menu.clone()).center(Length::Fill), // crate::widget::container(menu.clone()).center(Length::Fill),
// ) // )
// .map(crate::app::Message::App) // .map(crate::action::app)
// }), // }),
// )); // ));
// return status;
// } // }
status status
} }
@ -1259,6 +1271,7 @@ pub(super) fn init_root_popup_menu<Message>(
) where ) where
Message: std::clone::Clone, Message: std::clone::Clone,
{ {
dbg!("init");
menu.tree.inner.with_data_mut(|state| { menu.tree.inner.with_data_mut(|state| {
if !(state if !(state
.menu_states .menu_states
@ -1396,11 +1409,9 @@ fn process_menu_events<'b, Message: std::clone::Clone>(
Cow::Owned(o) => o.as_mut_slice(), Cow::Owned(o) => o.as_mut_slice(),
}; };
my_state.inner.with_data_mut(|state| { my_state.inner.with_data_mut(|state| {
dbg!(&state.active_root);
let Some(active_root) = state.active_root.get(menu.depth).cloned() else { let Some(active_root) = state.active_root.get(menu.depth).cloned() else {
return Status::Ignored; return Status::Ignored;
}; };
dbg!("got the active root");
let indices = state.get_trimmed_indices(menu.depth); let indices = state.get_trimmed_indices(menu.depth);
@ -1414,7 +1425,6 @@ fn process_menu_events<'b, Message: std::clone::Clone>(
if indices.is_empty() { if indices.is_empty() {
return Status::Ignored; return Status::Ignored;
} }
dbg!(&active_root, &indices);
// get active item // get active item
// let mt = indices.iter().fold(root | mt, &i | &mut mt.children[i]); // let mt = indices.iter().fold(root | mt, &i | &mut mt.children[i]);
@ -1425,7 +1435,6 @@ fn process_menu_events<'b, Message: std::clone::Clone>(
), ),
|(tree, mt), next_active_root| (tree, &mut mt.children[*next_active_root]), |(tree, mt), next_active_root| (tree, &mut mt.children[*next_active_root]),
); );
dbg!(mt.children.len(), mt.index,);
// let Some(i) = state.menu_states[menu.depth].iter().position(|ms| { // let Some(i) = state.menu_states[menu.depth].iter().position(|ms| {
// ms.menu_bounds // ms.menu_bounds
// .check_bounds // .check_bounds
@ -1437,7 +1446,6 @@ fn process_menu_events<'b, Message: std::clone::Clone>(
// widget tree // widget tree
let tree = &mut tree[mt.index]; let tree = &mut tree[mt.index];
dbg!(tree.children.len());
// get layout // get layout
let last_ms = &state.menu_states[menu.depth][indices.len() - 1]; let last_ms = &state.menu_states[menu.depth][indices.len() - 1];
@ -1450,9 +1458,7 @@ fn process_menu_events<'b, Message: std::clone::Clone>(
); );
let child_layout = Layout::new(&child_node); let child_layout = Layout::new(&child_node);
dbg!("item on event handler...");
// process only the last widget // process only the last widget
dbg!(&event);
mt.item.on_event( mt.item.on_event(
tree, tree,
event, event,
@ -1495,12 +1501,14 @@ where
menu.tree.inner.with_data_mut(|state| { menu.tree.inner.with_data_mut(|state| {
let Some(active_root) = state.active_root.get(menu.depth).clone() else { let Some(active_root) = state.active_root.get(menu.depth).clone() else {
if is_overlay && !menu.bar_bounds.contains(overlay_cursor) { if is_overlay && !menu.bar_bounds.contains(overlay_cursor) {
dbg!("overlay");
state.reset(); state.reset();
} }
return (new_menu_root, Ignored); return (new_menu_root, Ignored);
}; };
if state.pressed { if state.pressed {
dbg!("pressed");
return (new_menu_root, Ignored); return (new_menu_root, Ignored);
} }
@ -1543,7 +1551,6 @@ where
{ {
break; break;
} }
// dbg!(menu_states.len());
prev_bounds.pop(); prev_bounds.pop();
menu_states.pop(); menu_states.pop();
} }
@ -1562,6 +1569,7 @@ where
// keep state.open when the cursor is still inside the menu bar // keep state.open when the cursor is still inside the menu bar
// this allows the overlay to keep drawing when the cursor is // this allows the overlay to keep drawing when the cursor is
// moving aroung the menu bar // moving aroung the menu bar
dbg!("oops menu bar shouldn't disable popup");
if !menu.bar_bounds.contains(overlay_cursor) { if !menu.bar_bounds.contains(overlay_cursor) {
state.open = false; state.open = false;
} }
@ -1621,6 +1629,15 @@ where
) )
} }
}; };
// if last_menu_state
// .index
// .as_ref()
// .is_some_and(|old_index| *old_index == new_index)
// {
// dbg!("skipping duplicate", last_menu_state.index);
// return (None, Captured);
// }
dbg!(&last_menu_state.index, new_index);
let item = &active_menu[new_index]; let item = &active_menu[new_index];
// dbg!(new_index); // dbg!(new_index);
@ -1707,6 +1724,8 @@ where
use mouse::ScrollDelta; use mouse::ScrollDelta;
menu.tree.inner.with_data_mut(|state| { menu.tree.inner.with_data_mut(|state| {
dbg!(state.active_root.len());
let delta_y = match delta { let delta_y = match delta {
ScrollDelta::Lines { y, .. } => y * 60.0, ScrollDelta::Lines { y, .. } => y * 60.0,
ScrollDelta::Pixels { y, .. } => y, ScrollDelta::Pixels { y, .. } => y,

View file

@ -64,7 +64,7 @@ impl ResponsiveMenuBar {
core: &Core, core: &Core,
key_binds: &HashMap<menu::KeyBind, A>, key_binds: &HashMap<menu::KeyBind, A>,
id: crate::widget::Id, id: crate::widget::Id,
action_message: impl Fn(crate::surface::Action) -> Message + Clone + 'static, action_message: impl Fn(crate::surface::Action) -> Message + Send + Sync + Clone + 'static,
trees: Vec<(S, Vec<menu::Item<A, S>>)>, trees: Vec<(S, Vec<menu::Item<A, S>>)>,
) -> Element<'a, Message> { ) -> Element<'a, Message> {
use crate::widget::id_container; use crate::widget::id_container;

View file

@ -1618,6 +1618,7 @@ where
is_overlay: true, is_overlay: true,
window_id: window::Id::NONE, window_id: window::Id::NONE,
depth: 0, depth: 0,
on_surface_action: None,
} }
.overlay(), .overlay(),
) )