makepad_widget/
desktopwindow.rs

1use makepad_render::*;
2use crate::buttonlogic::*;
3use crate::desktopbutton::*;
4use crate::windowmenu::*;
5use crate::widgetstyle::*;
6
7#[derive(Clone)]
8pub struct DesktopWindow {
9    pub window: Window,
10    pub pass: Pass,
11    pub color_texture: Texture,
12    pub depth_texture: Texture,
13    pub caption_view: View, // we have a root view otherwise is_overlay subviews can't attach topmost
14    pub main_view: View, // we have a root view otherwise is_overlay subviews can't attach topmost
15    pub inner_view: View,
16    //pub caption_bg_color: ColorId,
17    pub min_btn: DesktopButton,
18    pub max_btn: DesktopButton,
19    pub close_btn: DesktopButton,
20    pub vr_btn: DesktopButton,
21    pub caption_text: Text,
22    pub caption_bg: Quad,
23    pub caption_size: Vec2,
24    pub caption: String,
25    
26    pub window_menu: WindowMenu,
27    pub default_menu: Menu,
28    
29    pub _last_menu: Option<Menu>,
30    
31    // testing
32    pub inner_over_chrome: bool,
33}
34
35#[derive(Clone, PartialEq)]
36pub enum DesktopWindowEvent {
37    EventForOtherWindow,
38    WindowClosed,
39    WindowGeomChange(WindowGeomChangeEvent),
40    None
41}
42
43impl DesktopWindow {
44    pub fn proto(cx: &mut Cx) -> Self {
45        Self {
46            window: Window::proto(cx),
47            pass: Pass::default(),
48            color_texture: Texture::default(),
49            depth_texture: Texture::default(),
50            main_view: View::proto(cx),
51            caption_view: View::proto(cx),
52            inner_view: View::proto(cx),
53            
54            min_btn: DesktopButton::proto(cx),
55            max_btn: DesktopButton::proto(cx),
56            close_btn: DesktopButton::proto(cx),
57            vr_btn: DesktopButton::proto(cx),
58            
59            window_menu: WindowMenu::proto(cx),
60            default_menu: Menu::main(vec![
61                Menu::sub("App", vec![
62                    Menu::item("Quit App",  Cx::command_quit()),
63                ]),
64            ]),
65            caption_text: Text::proto(cx),
66            //caption_bg_color: Color_bg_selected_over::id(cx),
67            caption_bg: Quad::proto(cx),
68            caption_size: Vec2::default(),
69            caption: "Makepad".to_string(),
70            inner_over_chrome: false,
71            _last_menu: None
72        }
73    }
74    
75    pub fn text_style_window_caption() ->TextStyleId{uid!()}
76    
77    pub fn style(cx:&mut Cx, _opt:&StyleOptions){
78        Self::text_style_window_caption().set(cx, Theme::text_style_unscaled().get(cx));
79    }
80    
81    pub fn handle_desktop_window(&mut self, cx: &mut Cx, event: &mut Event) -> DesktopWindowEvent {
82        //self.main_view.handle_scroll_bars(cx, event);
83        //self.inner_view.handle_scroll_bars(cx, event);
84        if let ButtonEvent::Clicked = self.vr_btn.handle_button(cx, event) {
85            if self.window.vr_is_presenting(cx) {
86                self.window.vr_stop_presenting(cx);
87            }
88            else {
89                self.window.vr_start_presenting(cx);
90            }
91        }
92        if let ButtonEvent::Clicked = self.min_btn.handle_button(cx, event) {
93            self.window.minimize_window(cx);
94        }
95        if let ButtonEvent::Clicked = self.max_btn.handle_button(cx, event) {
96            if self.window.is_fullscreen(cx) {
97                self.window.restore_window(cx);
98            }
99            else {
100                self.window.maximize_window(cx);
101            }
102        }
103        if let ButtonEvent::Clicked = self.close_btn.handle_button(cx, event) {
104            self.window.close_window(cx);
105        }
106        if let Some(window_id) = self.window.window_id {
107            let is_for_other_window = match event {
108                Event::WindowCloseRequested(ev) => ev.window_id != window_id,
109                Event::WindowClosed(ev) => {
110                    if ev.window_id == window_id {
111                        return DesktopWindowEvent::WindowClosed
112                    }
113                    true
114                }
115                Event::WindowGeomChange(ev) => {
116                    if ev.window_id == window_id {
117                        return DesktopWindowEvent::WindowGeomChange(ev.clone())
118                    }
119                    true
120                },
121                Event::WindowDragQuery(dq) => {
122                    if dq.window_id == window_id {
123                        if dq.abs.x < self.caption_size.x && dq.abs.y < self.caption_size.y {
124                            if dq.abs.x < 50. {
125                                dq.response = WindowDragQueryResponse::SysMenu;
126                            }
127                            else {
128                                dq.response = WindowDragQueryResponse::Caption;
129                            }
130                        }
131                    }
132                    true
133                }
134                Event::FingerDown(ev) => ev.window_id != window_id,
135                Event::FingerMove(ev) => ev.window_id != window_id,
136                Event::FingerHover(ev) => ev.window_id != window_id,
137                Event::FingerUp(ev) => ev.window_id != window_id,
138                Event::FingerScroll(ev) => ev.window_id != window_id,
139                _ => false
140            };
141            if is_for_other_window {
142                DesktopWindowEvent::EventForOtherWindow
143            }
144            else {
145                DesktopWindowEvent::None
146            }
147        }
148        else {
149            DesktopWindowEvent::None
150        }
151    }
152    
153    pub fn begin_desktop_window(&mut self, cx: &mut Cx, menu: Option<&Menu>) -> ViewRedraw {
154        
155        if !self.main_view.view_will_redraw(cx) {
156            return Err(())
157        }
158        
159        self.window.begin_window(cx);
160        self.pass.begin_pass(cx);
161        self.pass.add_color_texture(cx, &mut self.color_texture, ClearColor::ClearWith(color256(30, 30, 30)));
162        self.pass.set_depth_texture(cx, &mut self.depth_texture, ClearDepth::ClearWith(1.0));
163        
164        let _ = self.main_view.begin_view(cx, Layout::default());
165        
166        if self.caption_view.begin_view(cx, Layout {
167            walk:Walk::wh(Width::Fill, Height::Compute),
168            ..Layout::default()
169        }).is_ok() {
170            self.caption_text.text_style = Self::text_style_window_caption().get(cx);
171            self.caption_bg.color = Theme::color_bg_selected_over().get(cx);//cx.colors[self.caption_bg_color];
172            // alright here we draw our platform buttons.
173            match cx.platform_type {
174                PlatformType::Linux | PlatformType::Windows => {
175                    
176                    let bg_inst = self.caption_bg.begin_quad(cx, Layout {
177                        align: Align::right_top(),
178                        walk: Walk::wh(Width::Fill, Height::Compute),
179                        ..Default::default()
180                    });
181                    
182                    // we need to draw the window menu here.
183                    if let Some(_menu) = menu {
184                        // lets draw the thing, check with the clone if it changed
185                        // then draw it
186                    }
187                    
188                    self.min_btn.draw_desktop_button(cx, DesktopButtonType::WindowsMin);
189                    if self.window.is_fullscreen(cx) {
190                        self.max_btn.draw_desktop_button(cx, DesktopButtonType::WindowsMaxToggled);
191                    }
192                    else {
193                        self.max_btn.draw_desktop_button(cx, DesktopButtonType::WindowsMax);
194                    }
195                    self.close_btn.draw_desktop_button(cx, DesktopButtonType::WindowsClose);
196                    
197                    // change alignment
198                    cx.change_turtle_align_x(0.5); //Align::center());
199                    cx.compute_turtle_height();
200                    cx.change_turtle_align_y(0.5); //Align::center());
201                    cx.reset_turtle_pos();
202                    cx.move_turtle(50., 0.);
203                    // we need to store our caption rect somewhere.
204                    self.caption_size = Vec2 {x: cx.get_width_left(), y: cx.get_height_left()};
205                    self.caption_text.draw_text(cx, &self.caption);
206                    self.caption_bg.end_quad(cx, &bg_inst);
207                    cx.turtle_new_line();
208                },
209                
210                PlatformType::OSX => { // mac still uses the built in buttons, TODO, replace that.
211                    if let Some(menu) = menu {
212                        cx.update_menu(menu);
213                    }
214                    else{
215                        cx.update_menu(&self.default_menu);
216                    }
217                    let bg_inst = self.caption_bg.begin_quad(cx, Layout {
218                        align: Align::center(),
219                        walk: Walk::wh(Width::Fill, Height::Fix(22.)),
220                        ..Default::default()
221                    });
222                    self.caption_size = Vec2 {x: cx.get_width_left(), y: cx.get_height_left()};
223                    self.caption_text.draw_text(cx, &self.caption);
224                    self.caption_bg.end_quad(cx, &bg_inst);
225                    cx.turtle_new_line();
226                },
227                _ => {
228                    
229                }
230            }
231            self.caption_view.end_view(cx);
232        }
233        cx.turtle_new_line();
234        
235        if self.inner_over_chrome {
236            let _ = self.inner_view.begin_view(cx, Layout {abs_origin: Some(Vec2::default()), ..Layout::default()});
237        }
238        else {
239            let _ = self.inner_view.begin_view(cx, Layout::default());
240        }
241        Ok(())
242    }
243    
244    pub fn end_desktop_window(&mut self, cx: &mut Cx) {
245        self.inner_view.end_view(cx);
246        // lets draw a VR button top right over the UI.
247        if cx.vr_can_present { // show a switch-to-VRMode button
248            cx.reset_turtle_pos();
249            cx.move_turtle(cx.get_width_total() - 50.0, 0.);
250            self.vr_btn.draw_desktop_button(cx, DesktopButtonType::VRMode);
251        }
252        self.main_view.end_view(cx);
253        
254        self.pass.end_pass(cx);
255        
256        self.window.end_window(cx);
257    }
258}
259