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}