1use std::fmt::Debug;
9
10use iced::{
11 Alignment::Center,
12 Element,
13 widget::{button, column, container, row, text},
14};
15
16use snora_core::{Menu, MenuAction};
17
18use crate::icon::icon_element;
19use crate::style::menu_button_style;
20
21pub(crate) struct MenuGeometry {
25 pub(crate) gap: f32,
27}
28
29impl MenuGeometry {
30 pub(crate) const fn unstyled() -> Self {
32 Self { gap: 6.0 }
33 }
34}
35
36pub fn render_menu<'a, Message, MenuId, MenuItemId, F>(
43 menu: Menu<MenuId, MenuItemId>,
44 on_action: &'a F,
45 is_active: bool,
46) -> Element<'a, Message>
47where
48 Message: Clone + 'a,
49 MenuId: Clone + Debug + PartialEq + 'a,
50 MenuItemId: Clone + Debug + 'a,
51 F: Fn(MenuAction<MenuId, MenuItemId>) -> Message + 'a,
52{
53 build_menu(menu, on_action, is_active, MenuGeometry::unstyled())
54}
55
56pub(crate) fn build_menu<'a, Message, MenuId, MenuItemId, F>(
57 menu: Menu<MenuId, MenuItemId>,
58 on_action: &'a F,
59 is_active: bool,
60 geometry: MenuGeometry,
61) -> Element<'a, Message>
62where
63 Message: Clone + 'a,
64 MenuId: Clone + Debug + PartialEq + 'a,
65 MenuItemId: Clone + Debug + 'a,
66 F: Fn(MenuAction<MenuId, MenuItemId>) -> Message + 'a,
67{
68 let mut header_content = row![].spacing(geometry.gap).align_y(Center);
70 if let Some(ref ic) = menu.icon {
71 header_content = header_content.push(icon_element(ic));
72 }
73 header_content = header_content.push(text(menu.label).size(14));
74
75 let trigger_msg = on_action(MenuAction::MenuPressed(menu.id.clone()));
76
77 let mut stack = column![];
78 stack = stack.push(
79 button(header_content)
80 .style(menu_button_style)
81 .on_press(trigger_msg),
82 );
83
84 if !is_active {
85 return container(stack).into();
86 }
87
88 for item in menu.items {
90 let mut btn_content = row![].spacing(geometry.gap).align_y(Center);
91 if let Some(ref ic) = item.icon {
92 btn_content = btn_content.push(icon_element(ic));
93 }
94 btn_content = btn_content.push(text(item.label).size(14));
95
96 let msg = on_action(MenuAction::MenuItemPressed {
97 menu_id: item.menu_id.clone(),
98 menu_item_id: item.id.clone(),
99 });
100
101 stack = stack.push(button(btn_content).style(menu_button_style).on_press(msg));
102 }
103
104 container(stack).into()
105}