app_menu.rs

 1use crate::{Action, AppContext, Platform};
 2use util::ResultExt;
 3
 4pub struct Menu<'a> {
 5    pub name: &'a str,
 6    pub items: Vec<MenuItem<'a>>,
 7}
 8
 9pub enum MenuItem<'a> {
10    Separator,
11    Submenu(Menu<'a>),
12    Action {
13        name: &'a str,
14        action: Box<dyn Action>,
15        os_action: Option<OsAction>,
16    },
17}
18
19impl<'a> MenuItem<'a> {
20    pub fn separator() -> Self {
21        Self::Separator
22    }
23
24    pub fn submenu(menu: Menu<'a>) -> Self {
25        Self::Submenu(menu)
26    }
27
28    pub fn action(name: &'a str, action: impl Action) -> Self {
29        Self::Action {
30            name,
31            action: Box::new(action),
32            os_action: None,
33        }
34    }
35
36    pub fn os_action(name: &'a str, action: impl Action, os_action: OsAction) -> Self {
37        Self::Action {
38            name,
39            action: Box::new(action),
40            os_action: Some(os_action),
41        }
42    }
43}
44
45#[derive(Copy, Clone, Eq, PartialEq)]
46pub enum OsAction {
47    Cut,
48    Copy,
49    Paste,
50    SelectAll,
51    Undo,
52    Redo,
53}
54
55pub(crate) fn init_app_menus(platform: &dyn Platform, cx: &mut AppContext) {
56    platform.on_will_open_app_menu(Box::new({
57        let cx = cx.to_async();
58        move || {
59            cx.update(|cx| cx.clear_pending_keystrokes()).ok();
60        }
61    }));
62
63    platform.on_validate_app_menu_command(Box::new({
64        let cx = cx.to_async();
65        move |action| {
66            cx.update(|cx| cx.is_action_available(action))
67                .unwrap_or(false)
68        }
69    }));
70
71    platform.on_app_menu_action(Box::new({
72        let cx = cx.to_async();
73        move |action| {
74            cx.update(|cx| cx.dispatch_action(action)).log_err();
75        }
76    }));
77}