From dc10c77b411e05772bd423e1777e7c0199517848 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 18 Feb 2025 01:20:30 -0500 Subject: [PATCH] refactor: menu bar buttons --- examples/application/Cargo.toml | 5 +- examples/application/src/main.rs | 143 ++++++++++++++++++++++++++----- src/app/core.rs | 57 +++++++++--- src/widget/menu/menu_tree.rs | 5 +- 4 files changed, 174 insertions(+), 36 deletions(-) diff --git a/examples/application/Cargo.toml b/examples/application/Cargo.toml index 695f9897..23413086 100644 --- a/examples/application/Cargo.toml +++ b/examples/application/Cargo.toml @@ -3,6 +3,10 @@ name = "application" version = "0.1.0" edition = "2021" +[features] +default = ["wayland"] +wayland = ["libcosmic/wayland"] + [dependencies] tracing = "0.1.37" tracing-subscriber = "0.3.17" @@ -18,7 +22,6 @@ features = [ "xdg-portal", "dbus-config", "a11y", - "wayland", "wgpu", "single-instance", "multi-window", diff --git a/examples/application/src/main.rs b/examples/application/src/main.rs index cb709b5f..6b1cbf7f 100644 --- a/examples/application/src/main.rs +++ b/examples/application/src/main.rs @@ -12,6 +12,7 @@ use cosmic::iced::widget::column; use cosmic::iced::Length; use cosmic::iced_core::Size; use cosmic::surface_message::{MessageWrapper, SurfaceMessage, SurfaceMessageHandler}; +use cosmic::widget::button; use cosmic::widget::icon::{from_name, Handle}; use cosmic::widget::menu::KeyBind; use cosmic::widget::{ @@ -87,6 +88,7 @@ pub enum Message { Hi, } +#[cfg(feature = "wayland")] impl SurfaceMessageHandler for Message { fn to_surface_message(self) -> MessageWrapper { match self { @@ -96,6 +98,7 @@ impl SurfaceMessageHandler for Message { } } +#[cfg(feature = "wayland")] impl From for Message { fn from(value: SurfaceMessage) -> Self { Message::Surface(value) @@ -232,46 +235,146 @@ impl cosmic::Application for App { } fn header_start(&self) -> Vec> { - vec![self.core.responsive_menu_bar( - MENU_ID.clone(), - vec![ - menu::Tree::with_children( - menu::root("hiiiiiiiiiiiiiiiiiii 1"), + use cosmic::widget::menu::Tree; + #[cfg(not(feature = "wayland"))] + { + vec![cosmic::widget::menu::bar(vec![ + Tree::with_children( + Element::from(button::text("hiiiiiiiiiiiiiiiiiii 1")), menu::items( &self.keybinds, vec![menu::Item::Button("hi", None, Action::Hi)], ), ), - menu::Tree::with_children( - menu::root("hiiiiiiiiiiiiiiiiii 2"), + Tree::with_children( + Element::from(button::text("hiiiiiiiiiiiiiiiiii 2")), menu::items( &self.keybinds, vec![menu::Item::Button("hi 2", None, Action::Hi)], ), ), - menu::Tree::with_children( - menu::root("hiiiiiiiiiiiiiiiiiiiii 3"), + Tree::with_children( + Element::from(button::text("hiiiiiiiiiiiiiiiiiiiii 3")), menu::items( &self.keybinds, - vec![menu::Item::Button("hi 3", None, Action::Hi)], + vec![ + menu::Item::Button("hi 3", None, Action::Hi), + menu::Item::Button("hi 3 #2", None, Action::Hi), + ], ), ), - menu::Tree::with_children( - menu::root("hi 3"), + Tree::with_children( + Element::from(button::text("hi 3")), menu::items( &self.keybinds, - vec![menu::Item::Button("hi 3", None, Action::Hi)], + vec![ + menu::Item::Button("hi 3", None, Action::Hi), + menu::Item::Button("hi 3 #2", None, Action::Hi), + menu::Item::Button("hi 3 #3", None, Action::Hi), + ], ), ), - menu::Tree::with_children( - menu::root("hi 4"), - menu::items( + Tree::with_children(Element::from(button::text("hi 4")), { + let mut root_items = vec![menu::Tree::with_children( + menu::root("hi 41 extra root"), + menu::items( + &self.keybinds, + vec![menu::Item::Button("hi 3", None, Action::Hi)], + ), + )]; + let mut items = menu::items( &self.keybinds, - vec![menu::Item::Button("hi 3", None, Action::Hi)], + vec![ + menu::Item::Button("hi 42", None, Action::Hi), + menu::Item::Button("hi 43", None, Action::Hi), + menu::Item::Button("hi 44", None, Action::Hi), + menu::Item::Button("hi 45", None, Action::Hi), + menu::Item::Button("hi 46", None, Action::Hi), + ], + ); + root_items.append(&mut items); + root_items + }), + ]) + .into()] + } + #[cfg(feature = "wayland")] + { + vec![self.core.responsive_menu_bar( + MENU_ID.clone(), + vec![ + ( + menu::root("hiiiiiiiiiiiiiiiiiii 1"), + menu::items( + &self.keybinds, + vec![menu::Item::Button("hi", None, Action::Hi)], + ), ), - ), - ], - )] + ( + menu::root("hiiiiiiiiiiiiiiiiiiiii 2"), + menu::items( + &self.keybinds, + vec![ + menu::Item::Button("hi 21", None, Action::Hi), + menu::Item::Button("hi 22", None, Action::Hi), + ], + ), + ), + ( + menu::root("hi 3"), + menu::items( + &self.keybinds, + vec![menu::Item::Button("hi 33", None, Action::Hi)], + ), + ), + (menu::root("hi 4"), { + let mut root_items = vec![menu::Tree::with_children( + menu::root("hi 41 extra root"), + vec![menu::Tree::with_children(menu::root("hi 41 extra 2"), { + let mut root_items = vec![menu::Tree::with_children( + menu::root("hi 41 extra root"), + vec![menu::Tree::with_children( + menu::root("hi 41 extra 2"), + menu::items( + &self.keybinds, + vec![menu::Item::Button( + "hi 41 extra root item", + None, + Action::Hi, + )], + ), + )], + )]; + let mut items = menu::items( + &self.keybinds, + vec![ + menu::Item::Button("hi 42", None, Action::Hi), + menu::Item::Button("hi 43", None, Action::Hi), + menu::Item::Button("hi 44", None, Action::Hi), + menu::Item::Button("hi 45", None, Action::Hi), + menu::Item::Button("hi 46", None, Action::Hi), + ], + ); + root_items.append(&mut items); + root_items + })], + )]; + let mut items = menu::items( + &self.keybinds, + vec![ + menu::Item::Button("hi 42", None, Action::Hi), + menu::Item::Button("hi 43", None, Action::Hi), + menu::Item::Button("hi 44", None, Action::Hi), + menu::Item::Button("hi 45", None, Action::Hi), + menu::Item::Button("hi 46", None, Action::Hi), + ], + ); + root_items.append(&mut items); + root_items + }), + ], + )] + } } } diff --git a/src/app/core.rs b/src/app/core.rs index 151e94fe..50c6fb05 100644 --- a/src/app/core.rs +++ b/src/app/core.rs @@ -388,32 +388,65 @@ impl Core { id } - pub fn responsive_menu_bar<'a, Message: Clone + From + 'static>( + #[cfg(feature = "wayland")] + /// # Panics + /// + /// Will panic if the menu bar collapses without tracking the size + pub fn responsive_menu_bar< + 'a, + Message: Clone + + From + + crate::surface_message::SurfaceMessageHandler + + 'static, + >( &self, id: crate::widget::Id, - roots: Vec>, + trees: Vec<( + crate::widget::Button<'a, Message>, + Vec>>, + )>, ) -> crate::Element<'a, Message> { + use iced::Length; + + use crate::widget::id_container; + let menu_bar_size = self.menu_bars.get(&id); + #[allow(clippy::if_not_else)] if !menu_bar_size.is_some_and(|(limits, size)| { let max_size = limits.max(); - max_size.width < size.width }) { crate::Element::from(responsive_container::responsive_container( - menu::bar(roots), + id_container( + menu::bar( + trees + .into_iter() + .map(|mt| menu::Tree::<_>::with_children(mt.0, mt.1)) + .collect(), + ), + crate::widget::Id::new(format!("menu_bar_expanded_{id}")), + ), id, )) } else { crate::Element::from( responsive_container::responsive_container( - menu::bar(vec![menu::Tree::<_>::with_children( - Element::from( - button::icon(icon::from_name("open-menu-symbolic")) - .padding([4, 12]) - .class(crate::theme::Button::MenuRoot), - ), - roots, - )]), + id_container( + menu::bar(vec![menu::Tree::<_>::with_children( + Element::from( + button::icon(icon::from_name("open-menu-symbolic")) + .padding([4, 12]) + .class(crate::theme::Button::MenuRoot), + ), + trees + .into_iter() + .map(|mt| { + menu::Tree::<_>::with_children(mt.0.width(Length::Fill), mt.1) + }) + .collect(), + )]), + crate::widget::Id::new(format!("menu_bar_collapsed_{id}")), + ), id, ) .size(menu_bar_size.unwrap().1), diff --git a/src/widget/menu/menu_tree.rs b/src/widget/menu/menu_tree.rs index 01ca3076..86ed0dfb 100644 --- a/src/widget/menu/menu_tree.rs +++ b/src/widget/menu/menu_tree.rs @@ -9,9 +9,9 @@ use std::rc::Rc; use iced_widget::core::{renderer, Element}; use crate::iced_core::{Alignment, Length}; -use crate::widget::icon; use crate::widget::menu::action::MenuAction; use crate::widget::menu::key_bind::KeyBind; +use crate::widget::{icon, Button}; use crate::{theme, widget}; /// Nested menu is essentially a tree of items, a menu is a collection of items @@ -192,14 +192,13 @@ pub enum MenuItem>> { /// - A button for the root menu item. pub fn menu_root<'a, Message, Renderer: renderer::Renderer>( label: impl Into> + 'a, -) -> iced::Element<'a, Message, crate::Theme, Renderer> +) -> Button<'a, Message> where Element<'a, Message, crate::Theme, Renderer>: From>, { widget::button::custom(widget::text(label)) .padding([4, 12]) .class(theme::Button::MenuRoot) - .into() } /// Create a list of menu items from a vector of `MenuItem`.