makepad_widgets/
window_menu.rs

1// a window menu implementation
2use crate::{
3    makepad_derive_widget::*,
4    makepad_draw::*,
5    widget::*,
6};
7use std::collections::HashMap;
8
9live_design!{
10    WindowMenuBase = {{WindowMenu}}{
11    }
12}
13
14#[derive(Clone, Debug, Live, LiveHook)]
15#[live_ignore]
16pub enum WindowMenuItem {
17    #[pick {items: vec![]}]
18    Main{items:Vec<LiveId>},
19    #[live {name:"Unknown".to_string(), shift: false, key:KeyCode::Unknown, enabled:true }]
20    Item{
21        name: String,
22        shift: bool,
23        key: KeyCode,
24        enabled: bool
25    },
26    #[live {name:"Unknown".to_string(), items:vec![] }]
27    Sub{
28        name:String,
29        items:Vec<LiveId>
30    },
31    #[live]
32    Line
33}
34
35#[derive(Live)]
36pub struct WindowMenu{
37    #[walk] walk: Walk,
38    #[layout] layout: Layout,
39    #[rust] menu_items: HashMap<LiveId, WindowMenuItem>,
40}
41
42#[derive(Clone, WidgetAction)]
43pub enum WindowMenuAction {
44    Command(LiveId),
45    None
46}
47
48impl LiveHook for WindowMenu {
49    fn apply_value_instance(&mut self, cx: &mut Cx, from: ApplyFrom, index: usize, nodes: &[LiveNode]) -> usize {
50        let id = nodes[index].id;
51        match from {
52            ApplyFrom::NewFromDoc {..} | ApplyFrom::UpdateFromDoc {..} => {
53                if nodes[index].origin.has_prop_type(LivePropType::Instance) {
54                    if nodes[index].value.is_enum() {
55                        let mut dock_item = WindowMenuItem::new(cx);
56                        let index = dock_item.apply(cx, from, index, nodes);
57                        self.menu_items.insert(id, dock_item);
58                        return index;
59                    }
60                }
61                else {
62                    cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
63                }
64            }
65            _ => ()
66        }
67        nodes.skip_node(index)
68    }
69    
70    fn after_new_from_doc(&mut self, _cx: &mut Cx) {
71        // lets translate the menu into a macos menu
72        #[cfg(target_os="macos")]{
73            // alright lets fetch this thing
74            fn recur_menu(command:LiveId,menu_items:&HashMap<LiveId, WindowMenuItem>)->MacosMenu{
75                
76                if let Some(item) = menu_items.get(&command){
77                    match item.clone(){
78                        WindowMenuItem::Main{items}=>{
79                            let mut out = Vec::new();
80                            for item in items{
81                                out.push(recur_menu(item, menu_items));
82                            }
83                            return MacosMenu::Main{items:out}
84                        }
85                        WindowMenuItem::Item{name, shift, key, enabled}=>{
86                            return MacosMenu::Item{
87                                command,
88                                name,
89                                shift,
90                                key,
91                                enabled
92                            }
93                        }
94                        WindowMenuItem::Sub{name, items}=>{
95                            let mut out = Vec::new();
96                            for item in items{
97                                out.push(recur_menu(item, menu_items));
98                            }
99                            return MacosMenu::Sub{name, items:out}
100                        }
101                        WindowMenuItem::Line=>{
102                            return MacosMenu::Line
103                        }
104                    }
105                }
106                else{
107                    log!("Menu cannot find item {}", command);
108                    MacosMenu::Line
109                }
110            }
111            let menu = recur_menu(live_id!(main), &self.menu_items);
112            _cx.update_macos_menu(menu)
113        }
114    }
115    
116    fn before_live_design(cx: &mut Cx) {
117        register_widget!(cx, WindowMenu);
118    }
119}
120
121
122impl Widget for WindowMenu {
123    fn redraw(&mut self, _cx: &mut Cx) {
124    }
125    
126    fn handle_widget_event_with(&mut self, cx: &mut Cx, event: &Event, _dispatch_action: &mut dyn FnMut(&mut Cx, WidgetActionItem)) {
127        match event{
128            Event::MacosMenuCommand(item)=>{
129                if *item == live_id!(quit){
130                    cx.quit();
131                }
132            }
133            _=>()
134        }
135    }
136    
137    fn walk(&mut self, _cx: &mut Cx) -> Walk {
138        return Walk::fixed(0.0,0.0);
139    }
140    
141    fn draw_walk_widget(&mut self, _cx: &mut Cx2d, _walk: Walk) -> WidgetDraw {
142        WidgetDraw::done()
143    }
144}
145
146
147#[derive(Clone, Debug, PartialEq, WidgetRef)]
148pub struct WindowMenuRef(WidgetRef);
149
150impl WindowMenuRef {
151    pub fn command(&self) -> Option<LiveId> {
152        if let Some(mut _dock) = self.borrow_mut() {
153          
154        }
155        None
156    }
157}
158