cosmic/widget/
responsive_menu_bar.rs1use std::collections::HashMap;
2
3use apply::Apply;
4
5use crate::widget::{button, icon, responsive_container};
6use crate::{Core, Element};
7
8use super::menu::{self, ItemHeight, ItemWidth};
9
10#[must_use]
11pub fn responsive_menu_bar() -> ResponsiveMenuBar {
12 ResponsiveMenuBar::default()
13}
14
15pub struct ResponsiveMenuBar {
16 collapsed_item_width: ItemWidth,
17 item_width: ItemWidth,
18 item_height: ItemHeight,
19 spacing: f32,
20}
21
22impl Default for ResponsiveMenuBar {
23 fn default() -> ResponsiveMenuBar {
24 ResponsiveMenuBar {
25 collapsed_item_width: {
26 #[cfg(wayland_platform)]
27 if matches!(
28 crate::app::cosmic::WINDOWING_SYSTEM.get(),
29 Some(crate::app::cosmic::WindowingSystem::Wayland)
30 ) {
31 ItemWidth::Static(150)
32 } else {
33 ItemWidth::Static(84)
34 }
35 #[cfg(not(wayland_platform))]
36 {
37 ItemWidth::Static(84)
38 }
39 },
40 item_width: ItemWidth::Uniform(150),
41 item_height: ItemHeight::Uniform(30),
42 spacing: 0.,
43 }
44 }
45}
46
47impl ResponsiveMenuBar {
48 #[must_use]
50 pub fn item_width(mut self, item_width: ItemWidth) -> Self {
51 self.item_width = item_width;
52 self
53 }
54
55 #[must_use]
57 pub fn item_height(mut self, item_height: ItemHeight) -> Self {
58 self.item_height = item_height;
59 self
60 }
61
62 #[must_use]
64 pub fn spacing(mut self, spacing: f32) -> Self {
65 self.spacing = spacing;
66 self
67 }
68
69 pub fn into_element<
73 'a,
74 Message: Clone + 'static,
75 A: menu::Action<Message = Message> + Clone,
76 S: Into<std::borrow::Cow<'static, str>> + 'static,
77 >(
78 self,
79 core: &Core,
80 key_binds: &HashMap<menu::KeyBind, A>,
81 id: crate::widget::Id,
82 action_message: impl Fn(crate::surface::Action<Message>) -> Message
83 + Send
84 + Sync
85 + Clone
86 + 'static,
87 trees: Vec<(S, Vec<menu::Item<A, S>>)>,
88 ) -> Element<'a, Message> {
89 use crate::widget::id_container;
90
91 let menu_bar_size = core.menu_bars.get(&id);
92
93 #[allow(clippy::if_not_else)]
94 if !menu_bar_size.is_some_and(|(limits, size)| {
95 let max_size = limits.max();
96 max_size.width < size.width
97 }) {
98 responsive_container::responsive_container(
99 id_container(
100 menu::bar(
101 trees
102 .into_iter()
103 .map(|mt: (S, Vec<menu::Item<A, S>>)| {
104 menu::Tree::<_>::with_children(
105 crate::widget::RcElementWrapper::new(Element::from(
106 menu::root(mt.0),
107 )),
108 menu::items(key_binds, mt.1),
109 )
110 })
111 .collect(),
112 )
113 .item_width(self.item_width)
114 .item_height(self.item_height)
115 .spacing(self.spacing)
116 .on_surface_action(action_message.clone())
117 .window_id_maybe(core.main_window_id()),
118 crate::widget::Id::new(format!("menu_bar_expanded_{id}")),
119 ),
120 id,
121 action_message,
122 )
123 .apply(Element::from)
124 } else {
125 responsive_container::responsive_container(
126 id_container(
127 menu::bar(vec![menu::Tree::<_>::with_children(
128 Element::from(
129 button::icon(icon::from_name("open-menu-symbolic"))
130 .padding([4, 12])
131 .class(crate::theme::Button::MenuRoot),
132 ),
133 menu::items(
134 key_binds,
135 trees
136 .into_iter()
137 .map(|mt| menu::Item::Folder(mt.0, mt.1))
138 .collect(),
139 )
140 .into_iter()
141 .map(|t| {
142 t.width(match self.item_width {
143 ItemWidth::Uniform(w) | ItemWidth::Static(w) => w,
144 })
145 })
146 .collect(),
147 )])
148 .item_height(self.item_height)
149 .item_width(self.collapsed_item_width)
150 .spacing(self.spacing)
151 .on_surface_action(action_message.clone())
152 .window_id_maybe(core.main_window_id()),
153 crate::widget::Id::new(format!("menu_bar_collapsed_{id}")),
154 ),
155 id,
156 action_message,
157 )
158 .size(menu_bar_size.unwrap().1)
159 .apply(Element::from)
160 }
161 }
162}