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