1use crate::{
2 makepad_derive_widget::*,
3 debug_view::DebugView,
4 performance_view::PerformanceView,
5 makepad_draw::*,
6 nav_control::NavControl,
7 desktop_button::*,
8 view::*,
9 widget::*,
10};
11
12live_design!{
13 link widgets;
14 use link::widgets::*;
15 use link::theme::*;
16 use makepad_draw::shader::std::*;
17
18 pub WindowBase = {{Window}} {demo:false}
19 pub Window = <WindowBase> {
20 pass: { clear_color: (THEME_COLOR_BG_APP) }
21 flow: Down
22 nav_control: <NavControl> {}
23 caption_bar = <SolidView> {
24 visible: false,
25
26 flow: Right
27
28 draw_bg: {color: (THEME_COLOR_APP_CAPTION_BAR)}
29 height: 27,
30 caption_label = <View> {
31 width: Fill, height: Fill,
32 align: {x: 0.5, y: 0.5},
33 label = <Label> {text: "Makepad", margin: {left: 100}}
34 }
35 windows_buttons = <View> {
36 visible: false,
37 width: Fit, height: Fit,
38 min = <DesktopButton> {draw_bg: {button_type: WindowsMin}}
39 max = <DesktopButton> {draw_bg: {button_type: WindowsMax}}
40 close = <DesktopButton> {draw_bg: {button_type: WindowsClose}}
41 }
42 web_fullscreen = <View> {
43 visible: false,
44 width: Fit, height: Fit,
45 fullscreen = <DesktopButton> {draw_bg: {button_type: Fullscreen}}
46 }
47 web_xr = <View> {
48 visible: false,
49 width: Fit, height: Fit,
50 xr_on = <DesktopButton> {draw_bg: {button_type: XRMode}}
51 }
52 }
53
54 window_menu = <WindowMenu> {
55 main = Main{items:[app]}
56 app = Sub { name:"Makepad", items:[quit] }
57 quit = Item {
58 name:"Quit",
59 shift: false,
60 key: KeyQ,
61 enabled: true
62 }
63 }
64 body = <KeyboardView> {
65 width: Fill, height: Fill,
66 keyboard_min_shift: 30,
67 }
68
69 cursor: Default
70 mouse_cursor_size: vec2(20, 20),
71 draw_cursor: {
72 uniform border_size: 1.5
73 uniform color: (THEME_COLOR_CURSOR)
74 uniform border_color: (THEME_COLOR_CURSOR_BORDER)
75
76 fn get_color(self) -> vec4 {
77 return self.color
78 }
79
80 fn get_border_color(self) -> vec4 {
81 return self.border_color
82 }
83
84 fn pixel(self) -> vec4 {
85 let sdf = Sdf2d::viewport(self.pos * self.rect_size)
86 sdf.move_to(1.0, 1.0);
87 sdf.line_to(self.rect_size.x - 1.0, self.rect_size.y * 0.5)
88 sdf.line_to(self.rect_size.x * 0.5, self.rect_size.y - 1.0)
89 sdf.close_path();
90 sdf.fill_keep(self.get_color())
91 if self.border_size > 0.0 {
92 sdf.stroke(self.get_border_color(), self.border_size)
93 }
94 return sdf.result
95 }
96 }
97 window: {
98 inner_size: vec2(1024, 768)
99 }
100 }
101
102}
103
104#[derive(Live, Widget)]
105pub struct Window {
106 #[live] last_mouse_pos: DVec2,
108 #[live] mouse_cursor_size: DVec2,
109 #[live] demo: bool,
110 #[rust] demo_next_frame: NextFrame,
111 #[live] cursor_draw_list: DrawList2d,
112 #[live] draw_cursor: DrawQuad,
113 #[live] debug_view: DebugView,
114 #[live] performance_view: PerformanceView,
115 #[live] nav_control: NavControl,
116 #[live] window: WindowHandle,
117 #[live] stdin_size: DrawColor,
118 #[rust(Overlay::new(cx))] overlay: Overlay,
119 #[rust(DrawList2d::new(cx))] main_draw_list: DrawList2d,
120 #[live] pass: Pass,
121 #[rust(Texture::new(cx))] depth_texture: Texture,
122 #[live] hide_caption_on_fullscreen: bool,
123 #[live] show_performance_view: bool,
124 #[rust(Mat4::nonuniform_scaled_translation(vec3(0.0004,-0.0004,-0.0004),vec3(-0.25,0.25,-0.5)))] xr_view_matrix: Mat4,
125 #[deref] view: View,
126 #[rust] draw_state: DrawStateWrap<DrawState>,
139
140}
141
142#[derive(Clone)]
143enum DrawState {
144 Drawing,
145}
146
147impl LiveHook for Window {
148 fn after_new_from_doc(&mut self, cx: &mut Cx) {
149 self.window.set_pass(cx, &self.pass);
150 self.depth_texture = Texture::new_with_format(cx, TextureFormat::DepthD32{
152 size:TextureSize::Auto,
153 initial: true,
154 });
155 self.pass.set_depth_texture(cx, &self.depth_texture, PassClearDepth::ClearWith(1.0));
156 if cx.xr_capabilities().vr_supported {
158 self.view(id!(web_xr)).set_visible(cx, true);
160 log!("VR IS SUPPORTED");
161 }
162
163 }
164
165 fn after_apply(&mut self, cx: &mut Cx, _apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
166 if self.demo{
167 self.demo_next_frame = cx.new_next_frame();
168 }
169 match cx.os_type() {
170 OsType::Windows => {
171 if !cx.in_makepad_studio(){
172 self.view(id!(caption_bar)).set_visible(cx, true);
173 self.view(id!(windows_buttons)).set_visible(cx, true);
174 }
175 }
176 OsType::Macos => {
177 }
190 OsType::LinuxWindow(_) |
191 OsType::LinuxDirect |
192 OsType::Android(_) => {
193 }
195 OsType::Web(_) => {
196 }
198 _ => ()
199 }
200 }
201}
202
203#[derive(Clone, Debug, DefaultNone)]
204pub enum WindowAction {
205 EventForOtherWindow,
206 WindowClosed,
207 WindowGeomChange(WindowGeomChangeEvent),
208 None
209}
210
211impl Window {
212
213 pub fn begin(&mut self, cx: &mut Cx2d) -> Redrawing {
214
215 if !cx.will_redraw(&mut self.main_draw_list, Walk::default()) {
216 return Redrawing::no()
217 }
218
219 cx.begin_pass(&self.pass, None);
220
221 self.main_draw_list.begin_always(cx);
222
223 let size = cx.current_pass_size();
224 cx.begin_sized_turtle(size, Layout::flow_down());
225
226 self.overlay.begin(cx);
227
228 Redrawing::yes()
229 }
230
231 pub fn end(&mut self, cx: &mut Cx2d) {
232 self.debug_view.draw(cx);
234
235 if let OsType::LinuxDirect = cx.os_type() {
237 self.cursor_draw_list.begin_overlay_last(cx);
238 self.draw_cursor.draw_abs(cx, Rect {
239 pos: self.last_mouse_pos,
240 size: self.mouse_cursor_size
241 });
242 self.cursor_draw_list.end(cx);
243 }
244
245 self.overlay.end(cx);
246 fn encode_size(x: f64)->Vec4{
248 let x = x as usize;
249 let r = ((x >> 8)&0xff) as f32 / 255.0;
250 let b = ((x >> 0)&0xff) as f32 / 255.0;
251 vec4(r,0.0,b,1.0)
252 }
253
254 if cx.in_makepad_studio(){
256 let df = cx.current_dpi_factor();
257 let size = self.pass.size(cx).unwrap() * df;
258 self.stdin_size.color = encode_size(size.x);
259 self.stdin_size.draw_abs(cx, Rect{pos:dvec2(0.0,0.0),size:dvec2(1.0/df,1.0/df)});
260 self.stdin_size.color = encode_size(size.y);
261 self.stdin_size.draw_abs(cx, Rect{pos:dvec2(1.0/df,0.0),size:dvec2(1.0/df,1.0/df)});
262 }
263
264 if self.show_performance_view {
265 self.performance_view.draw_all(cx, &mut Scope::empty());
266 }
267
268 cx.end_pass_sized_turtle();
269
270 self.main_draw_list.end(cx);
271 cx.end_pass(&self.pass);
272 }
273 pub fn resize(&self, cx: &mut Cx, size: DVec2) {
274 self.window.resize(cx, size);
275 }
276 pub fn reposition(&self, cx: &mut Cx, size: DVec2) {
277 self.window.reposition(cx, size);
278 }
279 pub fn set_fullscreen(&mut self, cx: &mut Cx) {
280 self.window.fullscreen(cx);
281 }
282
283}
284
285impl WindowRef{
286 pub fn get_inner_size(&self, cx:&Cx)->DVec2{
287 if let Some(inner) = self.borrow(){
288 inner.window.get_inner_size(cx)
289 }
290 else{
291 dvec2(0.0,0.0)
292 }
293 }
294
295 pub fn get_position(&self, cx:&Cx)->DVec2{
296 if let Some(inner) = self.borrow(){
297 inner.window.get_position(cx)
298 }
299 else{
300 dvec2(0.0,0.0)
301 }
302 }
303 pub fn is_fullscreen(&self, cx:&Cx)->bool{
304 if let Some(inner) = self.borrow(){
305 inner.window.is_fullscreen(cx)
306 }
307 else{
308 false
309 }
310 }
311 pub fn resize(&self, cx: &mut Cx, size: DVec2) {
312 if let Some(inner) = self.borrow() {
313 inner.resize(cx, size);
314 }
315 }
316
317 pub fn reposition(&self, cx: &mut Cx, size: DVec2) {
318 if let Some(inner) = self.borrow() {
319 inner.reposition(cx, size);
320 }
321 }
322
323}
324
325impl Widget for Window {
326 fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
327 if let Event::Draw(e) = event {
328 let mut cx_draw = CxDraw::new(cx, e);
329 let cx = &mut Cx2d::new(&mut cx_draw);
330 self.draw_all(cx, scope);
331 return
332 }
333
334 let uid = self.widget_uid();
335
336 self.debug_view.handle_event(cx, event);
337 if self.show_performance_view {
338 self.performance_view.handle_widget(cx, event);
339 }
340
341 self.nav_control.handle_event(cx, event, self.main_draw_list.draw_list_id());
342 self.overlay.handle_event(cx, event);
343 if self.demo_next_frame.is_event(event).is_some(){
344 if self.demo{
345 self.demo_next_frame = cx.new_next_frame();
346 }
347 cx.repaint_pass_and_child_passes(self.pass.pass_id());
348 }
349 let is_for_other_window = match event {
350 Event::WindowCloseRequested(ev) => ev.window_id != self.window.window_id(),
351 Event::WindowClosed(ev) => {
352 if ev.window_id == self.window.window_id() {
353 cx.widget_action(uid, &scope.path, WindowAction::WindowClosed)
354 }
355 true
356 }
357 Event::WindowGeomChange(ev) => {
358 if ev.window_id == self.window.window_id() {
359 match cx.os_type() {
360 OsType::Windows | OsType::Macos => {
361 if self.hide_caption_on_fullscreen{
362 if ev.new_geom.is_fullscreen && !ev.old_geom.is_fullscreen {
363 self.view(id!(caption_bar)).set_visible(cx, false);
364 }
365 else if !ev.new_geom.is_fullscreen && ev.old_geom.is_fullscreen {
366 self.view(id!(caption_bar)).set_visible(cx, true);
367 };
368 }
369 }
370 _ => ()
371 }
372 cx.widget_action(uid, &scope.path, WindowAction::WindowGeomChange(ev.clone()));
373 return
374 }
375 true
376 },
377 Event::WindowDragQuery(dq) => {
378 if dq.window_id == self.window.window_id() {
379
380 if self.view(id!(caption_bar)).visible() {
381 let size = self.window.get_inner_size(cx);
382
383 if dq.abs.y < 25. {
384 if dq.abs.x < size.x - 135.0 {
385 dq.response.set(WindowDragQueryResponse::Caption);
386 }
387 cx.set_cursor(MouseCursor::Default);
388
389 }
390 }
394 }
395 true
396 }
397 Event::TouchUpdate(ev) => ev.window_id != self.window.window_id(),
398 Event::MouseDown(ev) => ev.window_id != self.window.window_id(),
399 Event::MouseMove(ev) => ev.window_id != self.window.window_id(),
400 Event::MouseUp(ev) => ev.window_id != self.window.window_id(),
401 Event::Scroll(ev) => ev.window_id != self.window.window_id(),
402 _ => false
403 };
404
405 if is_for_other_window {
406 cx.widget_action(uid, &scope.path, WindowAction::EventForOtherWindow);
407 return
408 }
409 else {
410 if cx.in_xr_mode(){
412 if let Event::XrUpdate(e) = &event{
413 let event = Event::XrLocal(XrLocalEvent::from_update_event(e, &self.xr_view_matrix));
414 self.view.handle_event(cx, &event, scope);
415 }
416 else{
417 self.view.handle_event(cx, event, scope);
418 }
419 }
420 else{
421 self.view.handle_event(cx, event, scope);
422 }
423 }
424
425 if let Event::Actions(actions) = event{
426 if self.desktop_button(id!(windows_buttons.min)).clicked(&actions) {
427 self.window.minimize(cx);
428 }
429 if self.desktop_button(id!(windows_buttons.max)).clicked(&actions) {
430 if self.window.is_fullscreen(cx) {
431 self.window.restore(cx);
432 }
433 else {
434 self.window.maximize(cx);
435 }
436 }
437 if self.desktop_button(id!(windows_buttons.close)).clicked(&actions) {
438 self.window.close(cx);
439 }
440 if self.desktop_button(id!(web_xr.xr_on)).clicked(&actions) {
441 cx.xr_start_presenting();
442 }
443 }
444
445 if let Event::ClearAtlasses = event {
446 CxDraw::reset_icon_atlas(cx);
447 }
448
449 if let Event::MouseMove(ev) = event {
450 if let OsType::LinuxDirect = cx.os_type() {
451 self.last_mouse_pos = ev.abs;
453 self.draw_cursor.update_abs(cx, Rect {
454 pos: ev.abs,
455 size: self.mouse_cursor_size
456 })
457 }
458 }
459 }
460
461 fn draw_walk(&mut self, cx: &mut Cx2d, scope:&mut Scope, walk: Walk) -> DrawStep {
462 if self.draw_state.begin(cx, DrawState::Drawing) {
463 if self.begin(cx).is_not_redrawing() {
464 self.draw_state.end();
465 return DrawStep::done();
466 }
467 }
468
469 if let Some(DrawState::Drawing) = self.draw_state.get() {
470 self.view.draw_walk(cx, scope, walk)?;
471 self.draw_state.end();
472 self.end(cx);
473 }
474
475 DrawStep::done()
476 }
477
478 fn draw_3d(&mut self, cx: &mut Cx3d, scope:&mut Scope)->DrawStep{
479 let cx = &mut Cx2d::new(cx.cx);
481
482 self.main_draw_list.begin_always(cx);
483
484 let size = dvec2(1500.0,1200.0);
485 cx.begin_sized_turtle(size, Layout::flow_down());
486
487 self.overlay.begin(cx);
488
489 self.view.draw_walk_all(cx, scope, Walk::default());
490
491 self.debug_view.draw(cx);
492
493 self.main_draw_list.set_view_transform(cx, &self.xr_view_matrix);
494
495 cx.end_pass_sized_turtle();
496
497 self.main_draw_list.end(cx);
498
499 DrawStep::done()
500 }
501}