menu.rs

 1use crate::{platform::ForegroundPlatform, Action, App, AppContext};
 2
 3pub struct Menu<'a> {
 4    pub name: &'a str,
 5    pub items: Vec<MenuItem<'a>>,
 6}
 7
 8pub enum MenuItem<'a> {
 9    Separator,
10    Submenu(Menu<'a>),
11    Action {
12        name: &'a str,
13        action: Box<dyn Action>,
14        os_action: Option<OsAction>,
15    },
16}
17
18impl<'a> MenuItem<'a> {
19    pub fn separator() -> Self {
20        Self::Separator
21    }
22
23    pub fn submenu(menu: Menu<'a>) -> Self {
24        Self::Submenu(menu)
25    }
26
27    pub fn action(name: &'a str, action: impl Action) -> Self {
28        Self::Action {
29            name,
30            action: Box::new(action),
31            os_action: None,
32        }
33    }
34
35    pub fn os_action(name: &'a str, action: impl Action, os_action: OsAction) -> Self {
36        Self::Action {
37            name,
38            action: Box::new(action),
39            os_action: Some(os_action),
40        }
41    }
42}
43
44#[derive(Copy, Clone, Eq, PartialEq)]
45pub enum OsAction {
46    Cut,
47    Copy,
48    Paste,
49    SelectAll,
50    Undo,
51    Redo,
52}
53
54impl AppContext {
55    pub fn set_menus(&mut self, menus: Vec<Menu>) {
56        self.foreground_platform
57            .set_menus(menus, &self.keystroke_matcher);
58    }
59}
60
61pub(crate) fn setup_menu_handlers(foreground_platform: &dyn ForegroundPlatform, app: &App) {
62    foreground_platform.on_will_open_menu(Box::new({
63        let cx = app.0.clone();
64        move || {
65            let mut cx = cx.borrow_mut();
66            cx.keystroke_matcher.clear_pending();
67        }
68    }));
69    foreground_platform.on_validate_menu_command(Box::new({
70        let cx = app.0.clone();
71        move |action| {
72            let cx = cx.borrow_mut();
73            !cx.keystroke_matcher.has_pending_keystrokes() && cx.is_action_available(action)
74        }
75    }));
76    foreground_platform.on_menu_command(Box::new({
77        let cx = app.0.clone();
78        move |action| {
79            let mut cx = cx.borrow_mut();
80            if let Some(main_window) = cx.active_window() {
81                let dispatched = main_window
82                    .update(&mut *cx, |cx| {
83                        if let Some(view_id) = cx.focused_view_id() {
84                            cx.dispatch_action(Some(view_id), action);
85                            true
86                        } else {
87                            false
88                        }
89                    })
90                    .unwrap_or(false);
91
92                if dispatched {
93                    return;
94                }
95            }
96            cx.dispatch_global_action_any(action);
97        }
98    }));
99}