Skip to main content

egui_desktop/menu/
items.rs

1use crate::menu::shortcuts::KeyboardShortcut;
2use std::fmt::{Debug, Formatter, Result};
3
4/// A single submenu item with customization options.
5///
6/// Represents an entry inside a dropdown menu, with optional keyboard shortcut,
7/// enabled/disabled state, separator, callback, and nested children.
8pub struct SubMenuItem {
9    /// The visible label for this submenu item.
10    pub label: String,
11    /// Optional keyboard shortcut that triggers this item.
12    pub shortcut: Option<KeyboardShortcut>,
13    /// Whether the item can be interacted with.
14    pub enabled: bool,
15    /// If true, draws a separator line after this item.
16    pub separator_after: bool,
17    /// Optional callback executed when the item is activated.
18    pub callback: Option<Box<dyn Fn() + Send + Sync>>,
19    /// Optional nested submenu items.
20    pub children: Vec<SubMenuItem>,
21}
22
23impl Debug for SubMenuItem {
24    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
25        f.debug_struct("SubMenuItem")
26            .field("label", &self.label)
27            .field("shortcut", &self.shortcut)
28            .field("enabled", &self.enabled)
29            .field("separator_after", &self.separator_after)
30            .field("callback", &"<function>")
31            .finish()
32    }
33}
34
35impl Clone for SubMenuItem {
36    fn clone(&self) -> Self {
37        Self {
38            label: self.label.clone(),
39            shortcut: self.shortcut.clone(),
40            enabled: self.enabled,
41            separator_after: self.separator_after,
42            callback: None, // Can't clone callbacks, set to None
43            children: self.children.clone(),
44        }
45    }
46}
47
48impl SubMenuItem {
49    /// Create a new submenu item with a text label.
50    pub fn new(label: &str) -> Self {
51        Self {
52            label: label.to_string(),
53            shortcut: None,
54            enabled: true,
55            separator_after: false,
56            callback: None,
57            children: Vec::new(),
58        }
59    }
60
61    /// Assign a keyboard shortcut to this item.
62    pub fn with_shortcut(mut self, shortcut: KeyboardShortcut) -> Self {
63        self.shortcut = Some(shortcut);
64        self
65    }
66
67    /// Set the callback executed when this item is activated.
68    pub fn with_callback(mut self, callback: Box<dyn Fn() + Send + Sync>) -> Self {
69        self.callback = Some(callback);
70        self
71    }
72
73    /// Disable this item (non-interactive, rendered as disabled).
74    pub fn disabled(mut self) -> Self {
75        self.enabled = false;
76        self
77    }
78
79    /// Draw a separator line after this item.
80    pub fn with_separator(mut self) -> Self {
81        self.separator_after = true;
82        self
83    }
84
85    /// Append a child item to this submenu.
86    pub fn add_child(mut self, child: SubMenuItem) -> Self {
87        self.children.push(child);
88        self
89    }
90
91    /// Replace the children of this submenu.
92    pub fn with_children(mut self, children: Vec<SubMenuItem>) -> Self {
93        self.children = children;
94        self
95    }
96}
97
98/// A menu item with submenu support.
99#[derive(Debug, Clone)]
100pub struct MenuItem {
101    /// Top-level menu label.
102    pub label: String,
103    /// Submenu entries displayed when this menu is opened.
104    pub subitems: Vec<SubMenuItem>,
105    /// Whether the top-level menu is enabled.
106    pub enabled: bool,
107}
108
109impl MenuItem {
110    /// Create a new top-level menu.
111    pub fn new(label: &str) -> Self {
112        Self {
113            label: label.to_string(),
114            subitems: Vec::new(),
115            enabled: true,
116        }
117    }
118
119    /// Append a submenu item to this menu.
120    pub fn add_subitem(mut self, subitem: SubMenuItem) -> Self {
121        self.subitems.push(subitem);
122        self
123    }
124
125    /// Disable this top-level menu.
126    pub fn disabled(mut self) -> Self {
127        self.enabled = false;
128        self
129    }
130}