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(all(feature = "winit", feature = "wayland", target_os = "linux"))]
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(all(feature = "winit", feature = "wayland", target_os = "linux")))]
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 + Send + Sync + Clone + 'static,
83 trees: Vec<(S, Vec<menu::Item<A, S>>)>,
84 ) -> Element<'a, Message> {
85 use crate::widget::id_container;
86
87 let menu_bar_size = core.menu_bars.get(&id);
88
89 #[allow(clippy::if_not_else)]
90 if !menu_bar_size.is_some_and(|(limits, size)| {
91 let max_size = limits.max();
92 max_size.width < size.width
93 }) {
94 responsive_container::responsive_container(
95 id_container(
96 menu::bar(
97 trees
98 .into_iter()
99 .map(|mt: (S, Vec<menu::Item<A, S>>)| {
100 menu::Tree::<_>::with_children(
101 crate::widget::RcElementWrapper::new(Element::from(
102 menu::root(mt.0),
103 )),
104 menu::items(key_binds, mt.1),
105 )
106 })
107 .collect(),
108 )
109 .item_width(self.item_width)
110 .item_height(self.item_height)
111 .spacing(self.spacing)
112 .on_surface_action(action_message.clone())
113 .window_id_maybe(core.main_window_id()),
114 crate::widget::Id::new(format!("menu_bar_expanded_{id}")),
115 ),
116 id,
117 action_message,
118 )
119 .apply(Element::from)
120 } else {
121 responsive_container::responsive_container(
122 id_container(
123 menu::bar(vec![menu::Tree::<_>::with_children(
124 Element::from(
125 button::icon(icon::from_name("open-menu-symbolic"))
126 .padding([4, 12])
127 .class(crate::theme::Button::MenuRoot),
128 ),
129 menu::items(
130 key_binds,
131 trees
132 .into_iter()
133 .map(|mt| menu::Item::Folder(mt.0, mt.1))
134 .collect(),
135 )
136 .into_iter()
137 .map(|t| {
138 t.width(match self.item_width {
139 ItemWidth::Uniform(w) | ItemWidth::Static(w) => w,
140 })
141 })
142 .collect(),
143 )])
144 .item_height(self.item_height)
145 .item_width(self.collapsed_item_width)
146 .spacing(self.spacing)
147 .on_surface_action(action_message.clone())
148 .window_id_maybe(core.main_window_id()),
149 crate::widget::Id::new(format!("menu_bar_collapsed_{id}")),
150 ),
151 id,
152 action_message,
153 )
154 .size(menu_bar_size.unwrap().1)
155 .apply(Element::from)
156 }
157 }
158}