b3_core/
menu.rs

1//! This module contains a platform independent application menu implementation.
2
3use crate::{
4    platform::{MenuApi, MenuItemApi, Wrapper},
5    platform_impl::{MenuImpl, MenuItemImpl},
6    ContextOwner,
7    Icon,
8};
9
10/// Menu item action.
11#[derive(Debug)]
12pub enum Action {
13    /// This variant will send an event with the specified action name into the
14    /// event loop.
15    ///
16    /// Use this variant when you want to capture menu event by an event
17    /// handler.
18    Event(String),
19
20    /// An action callback for a menu item.
21    Callback(fn()),
22}
23
24impl Action {
25    /// Creates a new action of the event type.
26    ///
27    /// # Parameters:
28    /// * `name` - Action name.
29    pub fn new_event<S>(name: S) -> Self
30    where
31        S: Into<String>,
32    {
33        Self::Event(name.into())
34    }
35
36    /// Creates a new action callback.
37    ///
38    /// # Parameters:
39    /// * `callback` - Action callback.
40    pub fn new_callback(callback: fn()) -> Self { Self::Callback(callback) }
41}
42
43/// This structure represents short codes (menu hotkeys) for different
44/// platforms.
45#[derive(Debug, Default)]
46pub struct ShortCode {
47    pub(crate) macos: Option<String>,
48}
49
50impl ShortCode {
51    /// Returns a short code for macOS platform or `None`.
52    pub fn macos_code(&self) -> Option<&String> { self.macos.as_ref() }
53}
54
55/// Application menu item.
56#[derive(Debug)]
57pub struct MenuItem(MenuItemImpl);
58
59impl MenuItem {
60    /// Returns a new builder instance.
61    pub fn builder() -> MenuItemBuilder { MenuItemBuilder::new() }
62
63    fn new(ctx: &impl ContextOwner) -> Self { Self(MenuItemImpl::new(ctx, false)) }
64
65    /// Creates a new menu separator.
66    ///
67    /// # Parameters:
68    /// * `ctx` - ContextOnwer
69    pub fn separator(ctx: &impl ContextOwner) -> Self { Self(MenuItemImpl::new(ctx, true)) }
70}
71
72impl MenuItem {
73    /// Sets a new menu item title.
74    ///
75    /// # Parameters:
76    /// * `title` - Title.
77    pub fn set_title<S>(&mut self, title: S)
78    where
79        S: Into<String>,
80    {
81        self.0.set_title(title.into());
82    }
83
84    /// Returns a menu item title.
85    pub fn title(&self) -> String { self.0.title() }
86
87    /// Sets a menu item action.
88    ///
89    /// # Parameters:
90    /// * `action` - Menu item action.
91    pub fn set_action(&mut self, action: Option<Action>) { self.0.set_action(action); }
92
93    /// Sets a submenu.
94    ///
95    /// # Parameters:
96    /// * `submenu` - Submenu of the current menu item.
97    pub fn set_submenu(&mut self, submenu: Option<Menu>) { self.0.set_submenu(submenu); }
98
99    /// Returns a submenu.
100    pub fn submenu(&self) -> Option<&Menu> { self.0.submenu() }
101
102    /// Returns a mutable submenu.
103    pub fn submenu_mut(&mut self) -> Option<&mut Menu> { self.0.submenu_mut() }
104
105    /// Checks if a menu item has a submenu.
106    pub fn has_submenu(&self) -> bool { self.0.has_submenu() }
107
108    /// Sets short codes for different platforms.
109    ///
110    /// # Parameters:
111    /// * `short_code` - Short codes.
112    pub fn set_short_code(&mut self, short_code: ShortCode) { self.0.set_short_code(short_code); }
113
114    /// Returns short codes for different platforms.
115    pub fn short_code(&self) -> &ShortCode { self.0.short_code() }
116
117    /// Turns on/off a menu item.
118    ///
119    /// # Parameters:
120    /// * `enabled` - Enable flag.
121    pub fn set_enabled(&mut self, enabled: bool) { self.0.set_enabled(enabled); }
122
123    /// Returns if a menu item is turned on/off.
124    pub fn enabled(&self) -> bool { self.0.enabled() }
125
126    /// Sets a tooltip for the menu item.
127    ///
128    /// # Parameters:
129    /// * `tooltip` - Tooltip message.
130    pub fn set_tooltip(&mut self, tooltip: Option<String>) { self.0.set_tooltip(tooltip); }
131
132    /// Returns a tooltip of the menu item.
133    pub fn tooltip(&self) -> Option<String> { self.0.tooltip() }
134
135    /// Sets a menu item icon.
136    ///
137    /// # Parameters:
138    /// * `icon` - Menu item icon.
139    pub fn set_icon(&mut self, icon: Option<Icon>) { self.0.set_icon(icon); }
140
141    /// Returns a menu item icon.
142    pub fn icon(&self) -> Option<&Icon> { self.0.icon() }
143}
144
145impl Wrapper<MenuItemImpl> for MenuItem {
146    #[inline]
147    fn get_impl(&self) -> &MenuItemImpl { &self.0 }
148
149    #[inline]
150    fn get_impl_mut(&mut self) -> &mut MenuItemImpl { &mut self.0 }
151}
152
153/// Menu item builder.
154#[derive(Debug, Default)]
155pub struct MenuItemBuilder {
156    title:      Option<String>,
157    action:     Option<Action>,
158    submenu:    Option<Menu>,
159    short_code: ShortCode,
160    enabled:    Option<bool>,
161    icon:       Option<Icon>,
162}
163
164impl MenuItemBuilder {
165    fn new() -> Self {
166        Self {
167            ..Default::default()
168        }
169    }
170
171    /// Sets a title for the item under building.
172    ///
173    /// # Parameters:
174    /// * `title` - Title.
175    pub fn with_title<S>(mut self, title: S) -> MenuItemBuilder
176    where
177        S: Into<String>,
178    {
179        self.title = Some(title.into());
180        self
181    }
182
183    /// Sets an action for the item under building.
184    ///
185    /// # Parameters:
186    /// * `action` - Action.
187    pub fn with_action(mut self, action: Action) -> MenuItemBuilder {
188        self.action = Some(action);
189        self
190    }
191
192    /// Sets a submenu for the item under building.
193    ///
194    /// # Parameters:
195    /// * `submenu` - Menu item's submenu.
196    pub fn with_submenu(mut self, submenu: Menu) -> MenuItemBuilder {
197        self.submenu = Some(submenu);
198        self
199    }
200
201    /// Sets short codes for the item under building.
202    ///
203    /// # Parameters:
204    /// * `short_code` - Short codes.
205    pub fn with_macos_short_code<S>(mut self, short_code: S) -> MenuItemBuilder
206    where
207        S: Into<String>,
208    {
209        self.short_code.macos = Some(short_code.into());
210        self
211    }
212
213    /// Turns on/off the item under building.
214    ///
215    /// # Parameters:
216    /// * `enabled` -  Enable flag.
217    pub fn with_enabled(mut self, enabled: bool) -> MenuItemBuilder {
218        self.enabled = Some(enabled);
219        self
220    }
221
222    /// Sets an icon for the item under building.
223    ///
224    /// # Parameters:
225    /// * `icon` - Menu item icon.
226    pub fn with_icon(mut self, icon: Icon) -> MenuItemBuilder {
227        self.icon = Some(icon);
228        self
229    }
230
231    /// Build a new menu item with specified options.
232    ///
233    /// # Parameters:
234    /// * `ctx` - Context owner.
235    pub fn build(self, ctx: &impl ContextOwner) -> MenuItem {
236        let mut item = MenuItem::new(ctx);
237
238        if let Some(title) = self.title {
239            item.set_title(title);
240        }
241
242        if self.action.is_some() {
243            item.set_action(self.action);
244        }
245
246        if self.submenu.is_some() {
247            item.set_submenu(self.submenu);
248        }
249
250        item.set_short_code(self.short_code);
251
252        if let Some(enabled) = self.enabled {
253            item.set_enabled(enabled);
254        }
255
256        if self.icon.is_some() {
257            item.set_icon(self.icon);
258        }
259
260        item
261    }
262}
263
264/// Application menu/submenu.
265#[derive(Debug)]
266pub struct Menu(MenuImpl);
267
268impl Menu {
269    /// Returns a new builder instance.
270    pub fn builder() -> MenuBuilder { MenuBuilder::new() }
271
272    fn new(ctx: &impl ContextOwner, items: Vec<MenuItem>) -> Self {
273        Self(MenuImpl::new(ctx, items))
274    }
275}
276
277impl Wrapper<MenuImpl> for Menu {
278    #[inline]
279    fn get_impl(&self) -> &MenuImpl { &self.0 }
280
281    #[inline]
282    fn get_impl_mut(&mut self) -> &mut MenuImpl { &mut self.0 }
283}
284
285/// Menu item builder.
286#[derive(Debug)]
287pub struct MenuBuilder {
288    items: Vec<MenuItem>,
289}
290
291impl MenuBuilder {
292    #[inline]
293    fn new() -> Self {
294        Self {
295            items: Vec::new()
296        }
297    }
298
299    /// Add a new item to the menu under building.
300    ///
301    /// # Parameters:
302    /// * `item` - Menu item.
303    pub fn with_item(mut self, item: MenuItem) -> MenuBuilder {
304        self.items.push(item);
305        self
306    }
307
308    /// Build a new menu with registered items.
309    ///
310    /// # Parameters:
311    /// * `ctx` - Context owner.
312    pub fn build(self, ctx: &impl ContextOwner) -> Menu { Menu::new(ctx, self.items) }
313}