refactor: menu bar buttons

This commit is contained in:
Ashley Wulber 2025-02-18 01:20:30 -05:00
parent ad65f45f5b
commit 5ef18de61f
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
4 changed files with 174 additions and 36 deletions

View file

@ -3,6 +3,10 @@ name = "application"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[features]
default = ["wayland"]
wayland = ["libcosmic/wayland"]
[dependencies] [dependencies]
tracing = "0.1.37" tracing = "0.1.37"
tracing-subscriber = "0.3.17" tracing-subscriber = "0.3.17"
@ -18,7 +22,6 @@ features = [
"xdg-portal", "xdg-portal",
"dbus-config", "dbus-config",
"a11y", "a11y",
"wayland",
"wgpu", "wgpu",
"single-instance", "single-instance",
"multi-window", "multi-window",

View file

@ -12,6 +12,7 @@ use cosmic::iced::widget::column;
use cosmic::iced::Length; use cosmic::iced::Length;
use cosmic::iced_core::Size; use cosmic::iced_core::Size;
use cosmic::surface_message::{MessageWrapper, SurfaceMessage, SurfaceMessageHandler}; use cosmic::surface_message::{MessageWrapper, SurfaceMessage, SurfaceMessageHandler};
use cosmic::widget::button;
use cosmic::widget::icon::{from_name, Handle}; use cosmic::widget::icon::{from_name, Handle};
use cosmic::widget::menu::KeyBind; use cosmic::widget::menu::KeyBind;
use cosmic::widget::{ use cosmic::widget::{
@ -87,6 +88,7 @@ pub enum Message {
Hi, Hi,
} }
#[cfg(feature = "wayland")]
impl SurfaceMessageHandler for Message { impl SurfaceMessageHandler for Message {
fn to_surface_message(self) -> MessageWrapper<Self> { fn to_surface_message(self) -> MessageWrapper<Self> {
match self { match self {
@ -96,6 +98,7 @@ impl SurfaceMessageHandler for Message {
} }
} }
#[cfg(feature = "wayland")]
impl From<SurfaceMessage> for Message { impl From<SurfaceMessage> for Message {
fn from(value: SurfaceMessage) -> Self { fn from(value: SurfaceMessage) -> Self {
Message::Surface(value) Message::Surface(value)
@ -232,46 +235,146 @@ impl cosmic::Application for App {
} }
fn header_start(&self) -> Vec<Element<Self::Message>> { fn header_start(&self) -> Vec<Element<Self::Message>> {
vec![self.core.responsive_menu_bar( use cosmic::widget::menu::Tree;
MENU_ID.clone(), #[cfg(not(feature = "wayland"))]
vec![ {
menu::Tree::with_children( vec![cosmic::widget::menu::bar(vec![
menu::root("hiiiiiiiiiiiiiiiiiii 1"), Tree::with_children(
Element::from(button::text("hiiiiiiiiiiiiiiiiiii 1")),
menu::items( menu::items(
&self.keybinds, &self.keybinds,
vec![menu::Item::Button("hi", None, Action::Hi)], vec![menu::Item::Button("hi", None, Action::Hi)],
), ),
), ),
menu::Tree::with_children( Tree::with_children(
menu::root("hiiiiiiiiiiiiiiiiii 2"), Element::from(button::text("hiiiiiiiiiiiiiiiiii 2")),
menu::items( menu::items(
&self.keybinds, &self.keybinds,
vec![menu::Item::Button("hi 2", None, Action::Hi)], vec![menu::Item::Button("hi 2", None, Action::Hi)],
), ),
), ),
menu::Tree::with_children( Tree::with_children(
menu::root("hiiiiiiiiiiiiiiiiiiiii 3"), Element::from(button::text("hiiiiiiiiiiiiiiiiiiiii 3")),
menu::items( menu::items(
&self.keybinds, &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( Tree::with_children(
menu::root("hi 3"), Element::from(button::text("hi 3")),
menu::items( menu::items(
&self.keybinds, &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( Tree::with_children(Element::from(button::text("hi 4")), {
menu::root("hi 4"), let mut root_items = vec![menu::Tree::with_children(
menu::items( 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, &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
}),
],
)]
}
} }
} }

View file

@ -388,32 +388,65 @@ impl Core {
id id
} }
pub fn responsive_menu_bar<'a, Message: Clone + From<SurfaceMessage> + '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::SurfaceMessage>
+ crate::surface_message::SurfaceMessageHandler
+ 'static,
>(
&self, &self,
id: crate::widget::Id, id: crate::widget::Id,
roots: Vec<Tree<'a, Message>>, trees: Vec<(
crate::widget::Button<'a, Message>,
Vec<impl Into<Tree<'a, Message>>>,
)>,
) -> crate::Element<'a, Message> { ) -> crate::Element<'a, Message> {
use iced::Length;
use crate::widget::id_container;
let menu_bar_size = self.menu_bars.get(&id); let menu_bar_size = self.menu_bars.get(&id);
#[allow(clippy::if_not_else)]
if !menu_bar_size.is_some_and(|(limits, size)| { if !menu_bar_size.is_some_and(|(limits, size)| {
let max_size = limits.max(); let max_size = limits.max();
max_size.width < size.width max_size.width < size.width
}) { }) {
crate::Element::from(responsive_container::responsive_container( 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, id,
)) ))
} else { } else {
crate::Element::from( crate::Element::from(
responsive_container::responsive_container( responsive_container::responsive_container(
menu::bar(vec![menu::Tree::<_>::with_children( id_container(
Element::from( menu::bar(vec![menu::Tree::<_>::with_children(
button::icon(icon::from_name("open-menu-symbolic")) Element::from(
.padding([4, 12]) button::icon(icon::from_name("open-menu-symbolic"))
.class(crate::theme::Button::MenuRoot), .padding([4, 12])
), .class(crate::theme::Button::MenuRoot),
roots, ),
)]), 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, id,
) )
.size(menu_bar_size.unwrap().1), .size(menu_bar_size.unwrap().1),

View file

@ -9,9 +9,9 @@ use std::rc::Rc;
use iced_widget::core::{renderer, Element}; use iced_widget::core::{renderer, Element};
use crate::iced_core::{Alignment, Length}; use crate::iced_core::{Alignment, Length};
use crate::widget::icon;
use crate::widget::menu::action::MenuAction; use crate::widget::menu::action::MenuAction;
use crate::widget::menu::key_bind::KeyBind; use crate::widget::menu::key_bind::KeyBind;
use crate::widget::{icon, Button};
use crate::{theme, widget}; use crate::{theme, widget};
/// Nested menu is essentially a tree of items, a menu is a collection of items /// Nested menu is essentially a tree of items, a menu is a collection of items
@ -192,14 +192,13 @@ pub enum MenuItem<A: MenuAction, L: Into<Cow<'static, str>>> {
/// - A button for the root menu item. /// - A button for the root menu item.
pub fn menu_root<'a, Message, Renderer: renderer::Renderer>( pub fn menu_root<'a, Message, Renderer: renderer::Renderer>(
label: impl Into<Cow<'a, str>> + 'a, label: impl Into<Cow<'a, str>> + 'a,
) -> iced::Element<'a, Message, crate::Theme, Renderer> ) -> Button<'a, Message>
where where
Element<'a, Message, crate::Theme, Renderer>: From<widget::Button<'a, Message>>, Element<'a, Message, crate::Theme, Renderer>: From<widget::Button<'a, Message>>,
{ {
widget::button::custom(widget::text(label)) widget::button::custom(widget::text(label))
.padding([4, 12]) .padding([4, 12])
.class(theme::Button::MenuRoot) .class(theme::Button::MenuRoot)
.into()
} }
/// Create a list of menu items from a vector of `MenuItem`. /// Create a list of menu items from a vector of `MenuItem`.