1use crate::{
2    makepad_derive_widget::*,
3    debug_view::DebugView,
4    makepad_draw::*,
5    nav_control::NavControl,
6    button::*,
7    view::*,
8    widget::*,
9};
10
11live_design!{
12    WindowBase = {{Window}} {demo:false}
13}
14
15#[derive(Live)]
16pub struct Window {
17    #[live] last_mouse_pos: DVec2,
19    #[live] mouse_cursor_size: DVec2,
20    #[live] demo: bool,
21    #[rust] demo_next_frame: NextFrame,
22    #[live] cursor_draw_list: DrawList2d,
23    #[live] draw_cursor: DrawQuad,
24    #[live] debug_view: DebugView,
25    #[live] nav_control: NavControl,
26    #[live] window: WindowHandle,
27    #[live] overlay: Overlay,
28    #[live] main_draw_list: DrawList2d,
29    #[live] pass: Pass,
30    #[live] depth_texture: Texture,
31    #[live] hide_caption_on_fullscreen: bool, 
32    #[deref] view: View,
33    #[rust] draw_state: DrawStateWrap<DrawState>,
46    
47}
48
49#[derive(Clone)]
50enum DrawState {
51    Drawing,
52}
53
54impl LiveHook for Window {
55    fn before_live_design(cx: &mut Cx) {
56        register_widget!(cx, Window)
57    }
58    
59    fn after_new_from_doc(&mut self, cx: &mut Cx) {
60        self.window.set_pass(cx, &self.pass);
61        self.pass.set_depth_texture(cx, &self.depth_texture, PassClearDepth::ClearWith(1.0));
63        if cx.xr_capabilities().vr_supported {
65            self.view(id!(web_xr)).set_visible(true);
67            log!("VR IS SUPPORTED");
68        }
69        match cx.os_type() {
70            OsType::Windows => {
71                if !cx.in_makepad_studio(){
72                    self.view(id!(caption_bar)).set_visible(true);
73                    self.view(id!(windows_buttons)).set_visible(true);
74                }
75            }
76            OsType::Macos => {
77                }
79            OsType::LinuxWindow(_) |
80            OsType::LinuxDirect |
81            OsType::Android(_) => {
82                }
84            OsType::Web(_) => {
85                }
87            _ => ()
88        }
89    }
90    
91    fn after_apply(&mut self, cx: &mut Cx, _apply_from: ApplyFrom, _index: usize, _nodes: &[LiveNode]) {
92        if self.demo{
93            self.demo_next_frame = cx.new_next_frame();
94        }
95    }
96}
97
98#[derive(Clone, WidgetAction)]
99pub enum WindowAction {
100    EventForOtherWindow,
101    WindowClosed,
102    WindowGeomChange(WindowGeomChangeEvent),
103    ViewActions(Vec<WidgetActionItem>),
104    None
105}
106
107impl Window {
108    pub fn handle_event_with(&mut self, cx: &mut Cx, event: &Event, dispatch_action: &mut dyn FnMut(&mut Cx, WindowAction)) {
109        
110        self.debug_view.handle_event(cx, event);
111        self.nav_control.handle_event(cx, event, self.main_draw_list.draw_list_id());
112        self.overlay.handle_event(cx, event);
113        if self.demo_next_frame.is_event(event).is_some(){
114            if self.demo{
115                self.demo_next_frame = cx.new_next_frame();
116            }
117            cx.repaint_pass_and_child_passes(self.pass.pass_id());
118        }
119        let is_for_other_window = match event {
120            Event::WindowCloseRequested(ev) => ev.window_id != self.window.window_id(),
121            Event::WindowClosed(ev) => {
122                if ev.window_id == self.window.window_id() {
123                    return dispatch_action(cx, WindowAction::WindowClosed)
124                }
125                true
126            }
127            Event::WindowGeomChange(ev) => {
128                if ev.window_id == self.window.window_id() {
129                    match cx.os_type() {
130                        OsType::Macos => {
131                            if self.hide_caption_on_fullscreen{
132                                if ev.new_geom.is_fullscreen && !ev.old_geom.is_fullscreen {
133                                    self.view(id!(caption_bar)).set_visible(false);
134                                    self.redraw(cx);
135                                }
136                                else if !ev.new_geom.is_fullscreen && ev.old_geom.is_fullscreen {
137                                    self.view(id!(caption_bar)).set_visible(true);
138                                    self.redraw(cx);
139                                };
140                            }
141                        }
142                        _ => ()
143                    }
144                    
145                    return dispatch_action(cx, WindowAction::WindowGeomChange(ev.clone()))
146                }
147                true
148            },
149            Event::WindowDragQuery(dq) => {
150                if dq.window_id == self.window.window_id() {
151                    let size = self.window.get_inner_size(cx);
152                    
153                    if dq.abs.y < 25.{
154                        if dq.abs.x < 50. {
155                            dq.response.set(WindowDragQueryResponse::SysMenu);
156                        }
157                        else if dq.abs.x < size.x - 135.0{
158                            dq.response.set(WindowDragQueryResponse::Caption);
159                        }
160                        cx.set_cursor(MouseCursor::Default);
161                    }
162                    }
166                true
167            }
168            Event::TouchUpdate(ev) => ev.window_id != self.window.window_id(),
169            Event::MouseDown(ev) => ev.window_id != self.window.window_id(),
170            Event::MouseMove(ev) => ev.window_id != self.window.window_id(),
171            Event::MouseUp(ev) => ev.window_id != self.window.window_id(),
172            Event::Scroll(ev) => ev.window_id != self.window.window_id(),
173            _ => false
174        };
175        
176        if is_for_other_window {
177            return dispatch_action(cx, WindowAction::EventForOtherWindow)
178        }
179        else {
180            let actions = self.view.handle_widget_event(cx, event);
181            if actions.not_empty() {
182                if self.button(id!(min)).clicked(&actions) {
183                    self.window.minimize(cx);
184                }
185                if self.button(id!(max)).clicked(&actions) {
186                    if self.window.is_fullscreen(cx) {
187                        self.window.restore(cx);
188                    }
189                    else {
190                        self.window.maximize(cx);
191                    }
192                }
193                if self.button(id!(close)).clicked(&actions) {
194                    self.window.close(cx);
195                }
196                if self.button(id!(xr_on)).clicked(&actions) {
197                    cx.xr_start_presenting();
198                }
199                dispatch_action(cx, WindowAction::ViewActions(actions));
200            }
201        }
202        
203        if let Event::ClearAtlasses = event {
204            Cx2d::reset_fonts_atlas(cx);
205            Cx2d::reset_icon_atlas(cx);
206        }
207        if let Event::MouseMove(ev) = event {
208            if let OsType::LinuxDirect = cx.os_type() {
209                self.last_mouse_pos = ev.abs;
211                self.draw_cursor.update_abs(cx, Rect {
212                    pos: ev.abs,
213                    size: self.mouse_cursor_size
214                })
215            }
216        }
217    }
218    
219    pub fn begin(&mut self, cx: &mut Cx2d) -> Redrawing {
220
221        if !cx.will_redraw(&mut self.main_draw_list, Walk::default()) {
222            return Redrawing::no()
223        }
224        
225        cx.begin_pass(&self.pass, None);
226
227        self.main_draw_list.begin_always(cx);
228        
229        cx.begin_pass_sized_turtle(Layout::flow_down());
230        
231        self.overlay.begin(cx);
232        
233        Redrawing::yes()
234    }
235    
236    pub fn end(&mut self, cx: &mut Cx2d) {
237        self.debug_view.draw(cx);
239        
240        if let OsType::LinuxDirect = cx.os_type() {
242            self.cursor_draw_list.begin_overlay_last(cx);
243            self.draw_cursor.draw_abs(cx, Rect {
244                pos: self.last_mouse_pos,
245                size: self.mouse_cursor_size
246            });
247            self.cursor_draw_list.end(cx);
248        }
249        
250        self.overlay.end(cx);
251        cx.end_pass_sized_turtle();
252        
253        self.main_draw_list.end(cx);
254        cx.end_pass(&self.pass);
255    }
256}
257
258impl Widget for Window {
259    fn handle_widget_event_with(
260        &mut self,
261        cx: &mut Cx,
262        event: &Event,
263        dispatch_action: &mut dyn FnMut(&mut Cx, WidgetActionItem)
264    ) {
265        let uid = self.widget_uid();
266        self.handle_event_with(cx, event, &mut | cx, action | {
267            if let WindowAction::ViewActions(actions) = action {
268                for action in actions {
269                    dispatch_action(cx, action)
270                }
271            }
272            else {
273                dispatch_action(cx, WidgetActionItem::new(action.into(), uid));
274            }
275        });
276    }
277    
278    fn walk(&mut self, _cx:&mut Cx) -> Walk {Walk::default()}
279    
280    fn redraw(&mut self, cx: &mut Cx) {
281        self.view.redraw(cx)
282    }
283    
284    fn find_widgets(&mut self, path: &[LiveId], cached: WidgetCache, results: &mut WidgetSet) {
285        self.view.find_widgets(path, cached, results);
286    }
287    
288    fn draw_walk_widget(&mut self, cx: &mut Cx2d, walk: Walk) -> WidgetDraw {
289        if self.draw_state.begin(cx, DrawState::Drawing) {
290            if self.begin(cx).is_not_redrawing() {
291                self.draw_state.end();
292                return WidgetDraw::done();
293            }
294        }
295        
296        if let Some(DrawState::Drawing) = self.draw_state.get() {
297            self.view.draw_walk_widget(cx, walk)?;
298            self.draw_state.end();
299            self.end(cx);
300        }
301        
302        WidgetDraw::done()
303    }
304}
305