1use alloc::boxed::Box;
39use alloc::rc::Rc;
40use alloc::string::String;
41use alloc::vec::Vec;
42use core::cell::Cell;
43
44use super::consts::*;
45use super::ctx::Hit;
46use super::layout::px2dip_at;
47use super::{Ui, WinParts};
48use gfx::{Surface, FMT_XRGB};
49use plat::Event;
50use rt::sync::SpinLock;
51
52const WSTACK_MAX: usize = 16; const NEST_MAX: u32 = 4; const DEF_W: i32 = 280;
57const DEF_H: i32 = 400;
58const WSE_ENTERED: u32 = 0x10000; const TITLE_MAX: usize = 256;
60const SIZE_MAX_DIP: i32 = 8192; const FWDQ_MAX: usize = super::ctx::KEYQ_MAX; const FWDT_MAX: usize = super::ctx::TEXTQ_MAX; const EXT_MAX: usize = 4;
66const POPUP_ITEMS: u32 = 7; pub(crate) const WCH_BASE: u32 = 0xFFFF_7800;
70pub(crate) const WCH_CLOSE: u32 = 1; pub(crate) const WCH_CONTENT: u32 = 2; pub(crate) const WCH_FOOTER: u32 = 3; pub(crate) const WCH_BTN: u32 = 4; pub(crate) const WCH_ROLL: u32 = 7; pub(crate) const WROOT_BASE: u32 = 0xFFFF_7F00;
77
78pub(crate) const UWI_OPEN: u32 = 1; pub(crate) const UWI_VISIBLE: u32 = 2; pub(crate) const UWI_CREATED: u32 = 16; pub(crate) const UWI_SEEN: u32 = 32; pub(crate) const UWI_SHOWN: u32 = 64; pub(crate) const UWI_NEWSHOW: u32 = 128; pub(crate) const UWI_BUILDING: u32 = 256; pub(crate) const UWI_FRESH: u32 = 512; pub(crate) const UWI_DEFPOS: u32 = 1024; const UWW_SHOW: u32 = 1;
91const UWW_HIDE: u32 = 2;
92const UWW_RECT: u32 = 4;
93const UWW_TITLE: u32 = 8;
94const UWW_ACTIVATE: u32 = 16;
95const UWW_CREATE: u32 = 64;
96const UWW_FS: u32 = 128; pub struct Shared<T: Copy>(Rc<Cell<T>>);
101
102impl<T: Copy> Shared<T> {
103 pub fn new(v: T) -> Shared<T> {
104 Shared(Rc::new(Cell::new(v)))
105 }
106 pub fn get(&self) -> T {
107 self.0.get()
108 }
109 pub fn set(&self, v: T) {
110 self.0.set(v)
111 }
112}
113
114impl<T: Copy> Clone for Shared<T> {
115 fn clone(&self) -> Shared<T> {
116 Shared(self.0.clone())
117 }
118}
119
120impl<T: Copy + Default> Default for Shared<T> {
121 fn default() -> Shared<T> {
122 Shared::new(T::default())
123 }
124}
125
126pub(crate) struct Rec {
128 pub(crate) id: u32,
130 pub(crate) flags: u32,
132 pub(crate) state: u32,
134 pub(crate) owner: u32,
136 pub(crate) seen: u32,
138 pub(crate) z: u32,
140 pub(crate) openp: Option<Shared<i32>>,
142 pub(crate) rect: Shared<WinRect>,
144 pub(crate) own: Shared<WinRect>,
145 pub(crate) save: Option<Box<WinParts>>,
148 pub(crate) applied: WinRect,
150 pub(crate) want: u32,
152 pub(crate) tbh: i32,
154 pub(crate) autoh: i32,
156 pub(crate) sx: i32,
158 pub(crate) sy: i32,
159 pub(crate) title: String,
161 pub(crate) snap: [i32; 5],
163 pub(crate) fs: bool,
167 pub(crate) fs_plat: bool,
168}
169
170impl Default for Rec {
171 fn default() -> Rec {
172 let own = Shared::default();
173 Rec {
174 id: 0,
175 flags: 0,
176 state: 0,
177 owner: 0,
178 seen: 0,
179 z: 0,
180 openp: None,
181 rect: own.clone(),
182 own,
183 save: None,
184 applied: WinRect::default(),
185 want: 0,
186 tbh: 0,
187 autoh: 0,
188 sx: 0,
189 sy: 0,
190 title: String::new(),
191 snap: [0; 5],
192 fs: false,
193 fs_plat: false,
194 }
195 }
196}
197
198#[derive(Default)]
200struct Ex {
201 owner: u32,
203 item: u32,
205 rect: [i32; 4],
207 used: bool,
209 shown: bool,
211 nat: [i32; 2],
214 key: [i32; 2],
215 sf: Surface,
216}
217
218pub(crate) struct S {
220 pub(crate) recs: [Rec; WIN_MAX],
221 pub(crate) active: u32,
223 pub(crate) modal: u32,
225 pub(crate) inert: u32,
227 pub(crate) ptr: i32,
229 pub(crate) edges: u32,
231 pub(crate) used: u32,
233 pub(crate) noaccel: bool,
235 stack: [u32; WSTACK_MAX],
236 sp: u32,
237 over: u32,
238 hooks: bool,
240 synchook: Option<fn() -> bool>,
241 zc: u32,
242 pub(crate) kfocus: u32,
245 fwd: u32,
246 fwd_to: u32,
247 fwdq: Vec<u32>,
248 fwdt: Vec<u32>,
249 ex: [Ex; EXT_MAX],
251 pub(crate) screen: [i32; 4],
254 disabled: u32,
256 follow: u32,
258 placed: u32,
260 origin_ok: bool,
262 u2p: [u8; WIN_MAX],
264 p2u: [u8; WIN_MAX],
265 zero_fb: Surface,
267 pub(crate) saved: Vec<super::winstate::Saved>,
270 pub(crate) norm: super::winstate::MainState,
271 pub(crate) cand: Option<super::winstate::MainState>,
272}
273
274impl Default for S {
275 fn default() -> S {
276 S {
277 recs: Default::default(),
278 active: 0,
279 modal: 0,
280 inert: 0,
281 ptr: 0,
282 edges: 0,
283 used: 0,
284 noaccel: false,
285 stack: [0; WSTACK_MAX],
286 sp: 0,
287 over: 0,
288 hooks: false,
289 synchook: None,
290 zc: 0,
291 kfocus: 0,
292 fwd: 0,
293 fwd_to: 0,
294 fwdq: Vec::new(),
295 fwdt: Vec::new(),
296 ex: Default::default(),
297 screen: [0; 4],
298 disabled: 0,
299 follow: 0,
300 placed: 0,
301 origin_ok: false,
302 u2p: [0xFF; WIN_MAX],
303 p2u: [0xFF; WIN_MAX],
304 zero_fb: Surface::new(0, 0, FMT_XRGB),
305 saved: Vec::new(),
306 norm: Default::default(),
307 cand: None,
308 }
309 }
310}
311
312struct Published {
318 hits: [Vec<Hit>; WIN_MAX],
319 modal: [u32; WIN_MAX],
320 drawable: u32,
322 p2u: [u8; WIN_MAX],
323 mirror: [i32; WIN_MAX],
325 zones: [Vec<super::dnd::Zone>; WIN_MAX],
328 accept: u32,
329 own: u32,
330 snap: [[i32; 6]; WIN_MAX],
333}
334
335static PUBLISHED: SpinLock<Published> = SpinLock::new(Published {
336 hits: [const { Vec::new() }; WIN_MAX],
337 modal: [0; WIN_MAX],
338 drawable: 1,
339 p2u: [0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
340 mirror: [0; WIN_MAX],
341 zones: [const { Vec::new() }; WIN_MAX],
342 accept: plat::DT_FILES,
343 own: 0,
344 snap: [[0; 6]; WIN_MAX],
345});
346
347pub(crate) fn uiw_hit_pw(pw: i32, x: i32, y: i32) -> u32 {
350 if !(0..WIN_MAX as i32).contains(&pw) {
351 return 0;
352 }
353 let p = PUBLISHED.lock();
354 let i = p.p2u[pw as usize];
355 if i == 0xFF || (p.drawable >> i) & 1 == 0 {
356 return 0;
357 }
358 let i = i as usize;
359 let x = if p.mirror[i] > 0 { p.mirror[i] - 1 - x } else { x };
361 super::ctx::hit_find_list(&p.hits[i], p.modal[i], x, y).1
362}
363
364pub(crate) fn uiw_drag_pw(pw: i32, x: i32, y: i32, types: u32) -> (u32, u32) {
369 if !(0..WIN_MAX as i32).contains(&pw) {
370 return (0, 0);
371 }
372 let p = PUBLISHED.lock();
373 let i = p.p2u[pw as usize];
374 if i == 0xFF || (p.drawable >> i) & 1 == 0 {
375 return (0, 0);
376 }
377 let i = i as usize;
378 let x = if p.mirror[i] > 0 { p.mirror[i] - 1 - x } else { x }; super::dnd::drag_answer(&p.zones[i], &p.hits[i], p.modal[i], p.accept, p.own, x, y, types)
380}
381
382pub(crate) fn uiw_publish_dnd(accept: u32, own: u32) {
385 let mut p = PUBLISHED.lock();
386 p.accept = accept;
387 p.own = own;
388}
389
390pub(crate) fn uiw_moving_pw(pw: i32, r: &mut [i32; 4]) {
394 if !(0..WIN_MAX as i32).contains(&pw) {
395 return;
396 }
397 let (s, opw) = {
398 let p = PUBLISHED.lock();
399 let i = p.p2u[pw as usize];
400 if i == 0xFF {
401 return;
402 }
403 let s = p.snap[i as usize];
404 if s[5] == 0 {
405 return;
406 }
407 (s, p.p2u.iter().position(|&u| u as i32 == s[0]))
408 };
409 let o = opw.and_then(|o| plat::win_get_rect(o as i32)).unwrap_or([0; 4]);
412 let a = [o[0] + s[1], o[1] + s[2], s[3], s[4]];
413 (r[0], r[1]) = snap_to(r[0], r[1], r[2], r[3], a, s[5]);
414}
415
416fn snap_to(x: i32, y: i32, w: i32, h: i32, a: [i32; 4], d: i32) -> (i32, i32) {
421 let axis = |p: i32, s: i32, lo: i32, len: i32| {
422 let near = (p - lo).abs(); let far = (p + s - lo - len).abs(); if near <= d && near <= far {
425 lo
426 } else if far <= d {
427 lo + len - s
428 } else {
429 p
430 }
431 };
432 let mut r = (x, y);
433 if y < a[1] + a[3] + d && y + h > a[1] - d {
434 r.0 = axis(x, w, a[0], a[2]);
435 }
436 if x < a[0] + a[2] + d && x + w > a[0] - d {
437 r.1 = axis(y, h, a[1], a[3]);
438 }
439 r
440}
441
442const POPUP_PANEL_ROOM: i32 = 96;
445
446fn dip2px_at(dip: i32, dpi: i32) -> i32 {
448 let v = dip.wrapping_mul(dpi);
449 if v < 0 { (v - 48) / 96 } else { (v + 48) / 96 }
450}
451
452fn blit_copy(dst: &mut Surface, src: &Surface, x: i32, y: i32) {
454 let x0 = x.max(0);
455 let y0 = y.max(0);
456 let x1 = (x + src.w).min(dst.w);
457 let y1 = (y + src.h).min(dst.h);
458 if x1 <= x0 || y1 <= y0 {
459 return;
460 }
461 let n = (x1 - x0) as usize * 4;
462 for yy in y0..y1 {
463 let d = yy as usize * dst.stride as usize + x0 as usize * 4;
464 let s = (yy - y) as usize * src.stride as usize + (x0 - x) as usize * 4;
465 dst.px[d..d + n].copy_from_slice(&src.px[s..s + n]);
466 }
467}
468
469impl Ui {
470 pub(crate) fn uiw_index(&self, id: u32) -> i32 {
474 if id == 0 {
475 return 0;
476 }
477 (1..WIN_MAX).find(|&i| self.m.win.recs[i].id == id).map_or(-1, |i| i as i32)
478 }
479
480 pub(crate) fn uiw_rec_id(&self, i: u32) -> u32 {
482 self.m.win.recs[(i as usize) & (WIN_MAX - 1)].id
483 }
484
485 pub(crate) fn uiw_title(&self, i: u32) -> &str {
487 &self.m.win.recs[(i as usize) & (WIN_MAX - 1)].title
488 }
489
490 pub(crate) fn uiw_any_used(&self) -> bool {
492 self.m.win.used != 0
493 }
494
495 pub(crate) fn uiw_init(&mut self) {
497 let w = &mut self.m.win;
498 w.recs[0].state = UWI_OPEN | UWI_VISIBLE | UWI_CREATED | UWI_SHOWN;
499 let r = &w.recs[0];
500 r.rect.set(WinRect { flags: WRF_ABS, ..r.rect.get() });
501 self.wp.lay.root_id = 1;
502 w.u2p = [0xFF; WIN_MAX];
504 w.p2u = [0xFF; WIN_MAX];
505 w.u2p[0] = 0;
506 w.p2u[0] = 0;
507 self.uiw_cur = 0;
508 w.active = 0;
509 w.modal = 0;
510 w.ptr = 0;
511 }
512
513 pub(crate) fn uiw_use(&mut self, i: u32) {
516 let i = (i as usize) & (WIN_MAX - 1);
517 let cur = self.uiw_cur as usize & (WIN_MAX - 1);
518 if i == cur {
519 return;
520 }
521 let Some(mut b) = self.m.win.recs[i].save.take() else {
522 return; };
524 core::mem::swap(&mut self.wp, &mut *b);
525 self.m.win.recs[cur].save = Some(b);
526 self.uiw_cur = i as u32;
527 plat::win_use(self.uiw_pw(i as u32));
529 }
530
531 pub(crate) fn uiw_parts(&self, i: u32) -> Option<&WinParts> {
534 let i = (i as usize) & (WIN_MAX - 1);
535 if i == self.uiw_cur as usize {
536 Some(&self.wp)
537 } else {
538 self.m.win.recs[i].save.as_deref()
539 }
540 }
541
542 pub(crate) fn uiw_parts_mut(&mut self, i: u32) -> Option<&mut WinParts> {
543 let i = (i as usize) & (WIN_MAX - 1);
544 if i == self.uiw_cur as usize {
545 Some(&mut self.wp)
546 } else {
547 self.m.win.recs[i].save.as_deref_mut()
548 }
549 }
550
551 pub(crate) fn win_dpi(&self, i: u32) -> i32 {
553 self.uiw_parts(i).map_or(0, |p| p.rt.dpi)
554 }
555
556 pub(crate) fn win_fb(&self, i: u32) -> &Surface {
558 match self.uiw_parts(i) {
559 Some(p) => &p.rt.fb,
560 None => &self.m.win.zero_fb,
561 }
562 }
563
564 fn win_focus(&self, i: u32) -> u32 {
566 self.uiw_parts(i).map_or(0, |p| p.ctx.focus)
567 }
568
569 pub(crate) fn uiw_take_newshow(&mut self, i: u32) -> bool {
571 let r = &mut self.m.win.recs[(i as usize) & (WIN_MAX - 1)];
572 let n = r.state & UWI_NEWSHOW != 0;
573 r.state &= !UWI_NEWSHOW;
574 n
575 }
576
577 pub(crate) fn uiw_frame_begin(&mut self) {
581 let w = &mut self.m.win;
582 if w.used != 0 {
583 for r in w.recs.iter_mut() {
584 r.state &= !UWI_SEEN;
585 }
586 }
587 w.sp = 0;
588 w.over = 0;
589 }
590
591 pub(crate) fn uiw_frame_end(&mut self) {
593 if self.m.win.used == 0 {
594 return; }
596 if self.uiw_modal_update() {
597 self.repass = true;
598 }
599 }
600
601 pub(crate) fn uiw_unwind(&mut self) {
604 while self.m.win.sp != 0 {
605 self.warn("ui_window_begin without ui_window_end");
606 self.window_end();
607 }
608 self.m.win.over = 0;
609 self.uiw_use(0);
610 }
611
612 fn uiw_modal_update(&mut self) -> bool {
615 let mut modal = 0u32;
616 let mut mz: i32 = -1;
617 if self.headless || self.m.win.hooks {
620 for i in 1..WIN_MAX {
621 let r = &self.m.win.recs[i];
622 if r.state & (UWI_VISIBLE | UWI_CREATED) != UWI_VISIBLE | UWI_CREATED || r.flags & WF_MODAL == 0 {
623 continue;
624 }
625 if r.z as i32 > mz {
626 mz = r.z as i32;
627 modal = i as u32;
628 }
629 }
630 }
631 let mut inert = 0u32;
633 if modal != 0 {
634 for i in 0..WIN_MAX as u32 {
635 if i != modal && !self.uiw_owned_by(i, modal) {
636 inert |= 1 << i;
637 }
638 }
639 }
640 self.m.win.inert = inert;
641 if modal == self.m.win.modal {
642 return false;
643 }
644 self.m.win.modal = modal;
645 if modal != 0 {
646 self.uiw_activate(modal); }
648 true
649 }
650
651 fn uiw_owned_by(&self, i: u32, owner: u32) -> bool {
653 let mut i = i;
654 for _ in 0..WIN_MAX {
655 if i == 0 {
656 return false;
657 }
658 i = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].owner;
659 if i == owner {
660 return true;
661 }
662 }
663 false
664 }
665
666 pub(crate) fn uiw_inert_now(&self) -> bool {
668 (self.m.win.inert >> (self.uiw_cur & 31)) & 1 != 0
669 }
670
671 pub(crate) fn uiw_border(&mut self) -> i32 {
674 let cur = self.uiw_cur;
675 let r = &self.m.win.recs[(cur as usize) & (WIN_MAX - 1)];
676 if cur == 0 || r.flags & WF_SYSFRAME != 0 || r.fs {
677 return 0;
678 }
679 self.hair()
680 }
681
682 pub(crate) fn uiw_escape(&mut self) {
685 let r = &self.m.win.recs[(self.uiw_cur as usize) & (WIN_MAX - 1)];
686 let (id, flags) = (r.id, r.flags);
687 let mut cmd = UIC_ESCAPE;
688 if id != 0 && flags & WF_DIALOG != 0 {
689 if flags & WF_NOCLOSE != 0 {
690 return;
691 }
692 cmd = UIC_WINCLOSE;
693 }
694 self.cmd_run(cmd, id);
695 }
696
697 pub(crate) fn uiw_focus_arrived(&mut self) {
701 let id = self.focus_req;
702 self.focus_req = 0;
703 self.wp.ctx.focus = id;
704 self.wp.ctx.focus_visible = true;
705 let from = self.focus_req_win;
706 if from == self.uiw_cur {
707 return;
708 }
709 let old = self.focus_req_old;
710 if let Some(p) = self.uiw_parts_mut(from) {
711 p.ctx.focus = old;
712 }
713 self.repass = true;
714 let cur = self.uiw_cur;
715 if cur != self.m.win.active {
716 self.uiw_activate(cur);
717 }
718 }
719
720 pub(crate) fn uiw_clear_edges(&mut self) {
723 self.dnd_clear_edges(); self.input_clear_edges(); let e = self.m.win.edges & !1;
726 self.m.win.edges = 0;
727 if e == 0 {
728 return;
729 }
730 for i in 1..WIN_MAX as u32 {
731 if (e >> i) & 1 != 0 && self.uiw_drawable(i) {
732 self.uiw_use(i);
733 self.input_clear_edges();
734 }
735 }
736 self.uiw_use(0);
737 }
738
739 pub fn window_title_height(&self, flags: u32) -> i32 {
743 let h = self.style.metric(if flags & WF_TOOL != 0 { SM_WIN_TBH_TOOL } else { SM_WIN_TBH_DIALOG });
744 if self.m.touch.on { h.max(super::touch::TITLE_DIP) } else { h } }
746
747 pub(crate) fn uiw_drawable(&self, i: u32) -> bool {
748 let s = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].state;
749 s & (UWI_VISIBLE | UWI_CREATED) == UWI_VISIBLE | UWI_CREATED
750 }
751
752 #[cfg_attr(jfgui_dev, track_caller)]
758 pub fn window_begin(&mut self, id: u32, title: &str, open: Option<&Shared<i32>>, flags: u32, rect: Option<&Shared<WinRect>>) -> bool {
759 let _src = self.src_scope();
760 let mut flags = flags;
761 let sp = self.m.win.sp;
762 if sp as usize >= WSTACK_MAX {
763 self.m.win.over += 1;
764 self.limit_hit(super::ctx::LIM_WINNEST);
765 return false;
766 }
767 let owner = self.uiw_cur; self.m.win.stack[sp as usize & (WSTACK_MAX - 1)] = owner; self.m.win.sp += 1;
770 if id == 0 {
771 self.warn("ui_window_begin: window id 0");
772 return false;
773 }
774 if self.uiw_depth() >= NEST_MAX {
776 self.warn(&alloc::format!("window {}: windows nested too deeply", id));
777 return false;
778 }
779 if !self.m.win.saved.is_empty() {
781 self.ws_open(id, flags, open);
782 }
783 let mut i = self.uiw_index(id);
784 if i < 0 {
785 if let Some(o) = open {
787 if o.get() == 0 {
788 return false;
789 }
790 }
791 i = self.uiw_alloc();
792 if i < 0 {
793 self.warn(&alloc::format!("window {}: too many windows ({} besides the main window)", id, WIN_MAX - 1));
794 return false;
795 }
796 self.m.win.recs[i as usize].id = id;
797 self.m.win.used |= 1 << i;
798 }
799 let i = i as u32;
800 let iu = i as usize;
801 if self.m.win.recs[iu].state & (UWI_SEEN | UWI_BUILDING) != 0 {
802 self.warn(&alloc::format!("window {} begun twice in one pass", id));
803 return false;
804 }
805 let frame = self.frame;
806 {
807 let r = &mut self.m.win.recs[iu];
808 r.state |= UWI_SEEN;
809 r.seen = frame;
810 }
811 if flags & WF_SYSFRAME != 0 && !self.uiw_sysframe_ok() {
813 flags &= !WF_SYSFRAME;
814 }
815 let tbh = if flags & (WF_SYSFRAME | WF_APP) != 0 || self.m.win.recs[iu].fs {
817 0
818 } else {
819 self.window_title_height(flags)
820 };
821 {
822 let r = &mut self.m.win.recs[iu];
823 r.flags = flags;
824 r.owner = owner;
825 r.openp = open.cloned();
826 r.rect = match rect {
827 Some(p) => p.clone(),
828 None => r.own.clone(),
829 };
830 r.tbh = tbh;
831 let t = super::basic::cstr(title);
833 let mut n = t.len().min(TITLE_MAX - 1);
834 while !t.is_char_boundary(n) {
835 n -= 1;
836 }
837 if r.title != t[..n] {
838 r.title = String::from(&t[..n]);
839 r.want |= UWW_TITLE;
840 }
841 }
842 if !self.m.win.saved.is_empty() {
844 self.ws_rect(i, id);
845 }
846 let is_open = open.is_none_or(|o| o.get() != 0);
848 if !is_open {
849 let r = &mut self.m.win.recs[iu];
850 r.state &= !UWI_OPEN;
851 if r.state & UWI_VISIBLE != 0 {
852 self.uiw_hide(i);
853 }
854 return false;
855 }
856 self.m.win.recs[iu].state |= UWI_OPEN;
857 if self.m.win.recs[iu].state & UWI_CREATED == 0 && !self.uiw_create(i) {
858 self.warn(&alloc::format!("window {}: out of memory", id));
859 return false;
860 }
861 if self.m.win.recs[iu].state & UWI_VISIBLE == 0 {
862 self.uiw_show(i);
863 }
864 let top = (self.m.win.sp - 1) as usize & (WSTACK_MAX - 1);
866 self.m.win.stack[top] = i << 8 | owner | WSE_ENTERED;
867 self.uiw_use(i);
868 self.m.win.recs[iu].state |= UWI_BUILDING;
869 if self.m.win.recs[iu].state & UWI_FRESH != 0 {
870 self.m.win.recs[iu].state &= !UWI_FRESH;
871 self.wp.ctx.focus = 0;
874 self.wp.ctx.focus_visible = false;
875 self.wp.ctx.active = 0;
876 self.wp.ctx.kb.autofocus = flags & WF_DIALOG != 0;
877 }
878 self.uiw_apply_rect(i);
879 let (w, h) = (self.wp.rt.fb.w, self.wp.rt.fb.h);
880 self.uiw_pass_begin(w, h);
881 self.win_chrome_begin(i);
882 true
883 }
884
885 fn uiw_depth(&self) -> u32 {
887 let n = (self.m.win.sp as usize).min(WSTACK_MAX);
888 self.m.win.stack[..n].iter().filter(|&&e| e & WSE_ENTERED != 0).count() as u32
889 }
890
891 fn uiw_alloc(&mut self) -> i32 {
894 if let Some(i) = (1..WIN_MAX).find(|&i| self.m.win.recs[i].id == 0) {
895 return i as i32;
896 }
897 let mut cand: i32 = -1;
899 let mut oldest = u32::MAX;
900 for i in 1..WIN_MAX {
901 let r = &self.m.win.recs[i];
902 if r.state & (UWI_VISIBLE | UWI_BUILDING | UWI_SEEN) != 0 {
903 continue;
904 }
905 if r.seen < oldest {
906 oldest = r.seen;
907 cand = i as i32;
908 }
909 }
910 if cand < 0 {
911 return -1;
912 }
913 let id = self.m.win.recs[cand as usize].id;
914 self.window_destroy(id);
915 cand
916 }
917
918 #[cfg_attr(jfgui_dev, track_caller)]
920 pub fn window_end(&mut self) {
921 let _src = self.src_scope();
922 if self.m.win.over != 0 {
923 self.m.win.over -= 1;
924 return;
925 }
926 if self.m.win.sp == 0 {
927 self.warn("ui_window_end without ui_window_begin");
928 return;
929 }
930 let sp = (self.m.win.sp - 1) & (WSTACK_MAX as u32 - 1);
931 self.m.win.sp = sp;
932 let e = self.m.win.stack[sp as usize];
933 if e & WSE_ENTERED == 0 {
934 return;
935 }
936 let i = (e >> 8) & 255; let back = e & 255; let iu = (i as usize) & (WIN_MAX - 1);
939 let h = self.win_chrome_end(i); let flags = self.m.win.recs[iu].flags;
941 if flags & WF_AUTOHEIGHT != 0 {
942 self.m.win.recs[iu].autoh = h;
943 }
944 if flags & (WF_RESIZABLE | WF_SYSFRAME) == WF_RESIZABLE {
946 self.edge_grips();
947 }
948 self.m.win.noaccel = flags & WF_DIALOG != 0;
949 self.uiw_pass_end();
950 self.m.win.noaccel = false;
951 self.m.win.recs[iu].state &= !UWI_BUILDING;
952 self.uiw_use(back);
953 }
954
955 fn uiw_create(&mut self, i: u32) -> bool {
958 let iu = (i as usize) & (WIN_MAX - 1);
959 let owner = self.m.win.recs[iu].owner;
960 let dpi = self.win_dpi(owner);
961 let mut p = Box::new(WinParts::new());
962 p.rt.dpi = dpi;
963 p.ctx.mx = -1;
964 p.ctx.my = -1;
965 p.lay.root_id = i | WROOT_BASE;
966 p.cmd = super::cmd::W::new(&super::cmd::CAPS_SMALL);
967 p.dirty.full = true; self.m.win.recs[iu].save = Some(p);
969 let r = &mut self.m.win.recs[iu];
970 r.state |= UWI_CREATED;
971 r.want |= UWW_CREATE;
972 true
973 }
974
975 fn uiw_show(&mut self, i: u32) {
978 let iu = (i as usize) & (WIN_MAX - 1);
979 let mut rc = self.m.win.recs[iu].rect.get();
980 if rc.w <= 0 {
981 rc.w = DEF_W;
982 }
983 if rc.h <= 0 {
984 rc.h = DEF_H;
985 }
986 self.m.win.recs[iu].rect.set(rc);
987 if rc.flags & WRF_POS == 0 {
988 self.uiw_place_default(i);
989 self.m.win.recs[iu].state |= UWI_DEFPOS;
990 }
991 self.m.win.zc = self.m.win.zc.wrapping_add(1);
992 let zc = self.m.win.zc;
993 let r = &mut self.m.win.recs[iu];
994 r.state |= UWI_VISIBLE | UWI_NEWSHOW | UWI_SHOWN | UWI_FRESH;
995 r.want = (r.want & !UWW_HIDE) | UWW_SHOW;
996 r.z = zc;
997 if r.flags & (WF_TOOL | WF_NOACTIVATE) == 0 {
998 self.uiw_activate(i);
999 }
1000 }
1001
1002 pub(crate) fn uiw_hide(&mut self, i: u32) {
1004 let iu = (i as usize) & (WIN_MAX - 1);
1005 let r = &mut self.m.win.recs[iu];
1006 r.state &= !(UWI_VISIBLE | UWI_NEWSHOW);
1007 r.want = (r.want & !UWW_SHOW) | UWW_HIDE;
1008 let mut owner = r.owner;
1009 if self.m.win.ptr == i as i32 {
1010 self.m.win.ptr = -1;
1011 }
1012 if self.m.win.active != i {
1013 return;
1014 }
1015 let mut n = WIN_MAX;
1017 loop {
1018 let o = owner;
1019 if self.uiw_drawable(o) || o == 0 {
1020 break;
1021 }
1022 owner = self.m.win.recs[(o as usize) & (WIN_MAX - 1)].owner;
1023 n -= 1;
1024 if n == 0 {
1025 owner = 0;
1026 break;
1027 }
1028 }
1029 self.uiw_activate(owner);
1030 }
1031
1032 pub(crate) fn uiw_activate(&mut self, i: u32) {
1034 let i = i & (WIN_MAX as u32 - 1);
1035 if self.m.win.active == i {
1036 return;
1037 }
1038 if i != 0 && !self.headless && !self.m.win.hooks {
1040 return;
1041 }
1042 self.m.win.active = i;
1043 self.m.win.recs[i as usize].want |= UWW_ACTIVATE;
1044 if i != 0 {
1045 self.m.win.zc = self.m.win.zc.wrapping_add(1);
1046 self.m.win.recs[i as usize].z = self.m.win.zc;
1047 }
1048 self.invalidate();
1049 }
1050
1051 fn uiw_place_default(&mut self, i: u32) {
1055 let iu = (i as usize) & (WIN_MAX - 1);
1056 let (owner, flags, tbh) = {
1057 let r = &self.m.win.recs[iu];
1058 (r.owner, r.flags, r.tbh)
1059 };
1060 let mut rc = self.m.win.recs[iu].rect.get();
1061 if flags & WF_DIALOG == 0 {
1062 let mut k = 0;
1064 for j in 1..WIN_MAX {
1065 if j == iu {
1066 continue;
1067 }
1068 let r = &self.m.win.recs[j];
1069 if r.id != 0 && r.owner == owner && r.state & UWI_SHOWN != 0 && r.flags & WF_DIALOG == 0 {
1070 k += 1;
1071 }
1072 }
1073 rc.x = k * 32 + 24;
1074 rc.y = k * 32 + 48;
1075 } else {
1076 let (ow, oh, oy) = self.uiw_outer_dip(owner);
1078 rc.x = (ow - rc.w) >> 1;
1079 rc.y = ((oh - (tbh + rc.h)) >> 1) + oy;
1080 }
1081 rc.flags |= WRF_POS;
1082 self.m.win.recs[iu].rect.set(rc);
1083 }
1084
1085 fn uiw_keep_on_screen(&self, iu: usize, rc: &mut WinRect) {
1088 if iu == 0 {
1089 return;
1090 }
1091 let (owner, tbh) = (self.m.win.recs[iu].owner, self.m.win.recs[iu].tbh);
1092 let (mw, mh, _) = self.uiw_outer_dip(0);
1093 let edge = 2; rc.w = rc.w.min(mw - edge).max(1);
1095 rc.h = rc.h.min(mh - tbh - edge).max(1);
1096 if owner == 0 && rc.flags & WRF_POS != 0 {
1097 rc.x = rc.x.min(mw - edge - rc.w).max(0);
1098 rc.y = rc.y.min(mh - edge - rc.h).max(tbh);
1099 }
1100 }
1101
1102 fn uiw_outer_dip(&self, i: u32) -> (i32, i32, i32) {
1105 if i == 0 {
1106 let fb = self.win_fb(0);
1108 let dpi = self.win_dpi(0);
1109 return (px2dip_at(fb.w, dpi), px2dip_at(fb.h, dpi), 0);
1110 }
1111 let r = &self.m.win.recs[(i as usize) & (WIN_MAX - 1)];
1112 let rc = r.rect.get();
1113 (rc.w, rc.h + r.tbh, -r.tbh)
1114 }
1115
1116 fn uiw_apply_rect(&mut self, i: u32) {
1119 let iu = (i as usize) & (WIN_MAX - 1);
1120 let mut rc = self.m.win.recs[iu].rect.get();
1121 if rc.w <= 0 {
1122 rc.w = DEF_W;
1123 }
1124 if rc.h <= 0 {
1125 rc.h = DEF_H;
1126 }
1127 if rc.w > SIZE_MAX_DIP {
1128 rc.w = SIZE_MAX_DIP;
1129 }
1130 if rc.h > SIZE_MAX_DIP {
1131 rc.h = SIZE_MAX_DIP;
1132 }
1133 if self.mobile() {
1134 self.uiw_keep_on_screen(iu, &mut rc);
1135 }
1136 self.m.win.recs[iu].rect.set(rc);
1137 if !self.wp.rt.fb.px.is_empty() && rc == self.m.win.recs[iu].applied {
1138 return;
1139 }
1140 let tbh = {
1141 let r = &mut self.m.win.recs[iu];
1142 r.applied = rc;
1143 r.want |= UWW_RECT;
1144 r.tbh
1145 };
1146 let b2 = self.uiw_border() * 2; let w = self.dp(rc.w) + b2; let h = self.dp(rc.h + tbh) + b2; if !self.wp.rt.fb.px.is_empty() && w == self.wp.rt.fb.w && h == self.wp.rt.fb.h {
1150 return;
1151 }
1152 if self.wp.rt.fb.px.is_empty() {
1153 self.wp.rt.fb = Surface::new(w, h, FMT_XRGB);
1154 } else {
1155 self.wp.rt.fb.resize(w, h);
1156 }
1157 self.dirty_force_full();
1158 }
1159
1160 pub(crate) fn uiw_settle(&mut self) -> bool {
1166 let mut changed = false;
1167 if self.m.win.used != 0 {
1168 for i in 1..WIN_MAX as u32 {
1169 let iu = i as usize;
1170 let (state, flags, autoh) = {
1171 let r = &self.m.win.recs[iu];
1172 (r.state, r.flags, r.autoh)
1173 };
1174 if state & UWI_VISIBLE == 0 {
1175 continue;
1176 }
1177 if state & UWI_SEEN == 0 {
1178 self.uiw_hide(i);
1179 changed = true;
1180 continue;
1181 }
1182 if flags & WF_AUTOHEIGHT == 0 || autoh <= 0 {
1183 continue;
1184 }
1185 let mut rc = self.m.win.recs[iu].rect.get();
1186 if rc.h == autoh {
1187 continue;
1188 }
1189 rc.h = autoh;
1190 self.m.win.recs[iu].rect.set(rc);
1191 changed = true;
1192 if state & UWI_DEFPOS != 0 && flags & WF_DIALOG != 0 {
1194 self.uiw_place_default(i);
1195 }
1196 }
1197 changed |= self.uiw_modal_update();
1198 }
1199 if !changed {
1201 self.uiw_sync();
1202 }
1203 changed
1204 }
1205
1206 fn uiw_sync(&mut self) {
1208 if !self.m.win.hooks || self.headless {
1209 return; }
1211 self.uiw_enable_sync(1); for i in 0..WIN_MAX as u32 {
1213 let iu = i as usize;
1214 let want = self.m.win.recs[iu].want;
1215 if want == 0 {
1216 continue;
1217 }
1218 self.m.win.recs[iu].want = 0;
1219 if i != 0 {
1220 if want & UWW_CREATE != 0 {
1221 let (flags, owner) = (self.m.win.recs[iu].flags, self.m.win.recs[iu].owner);
1222 self.uwp_create(i, flags, owner);
1223 }
1224 if want & UWW_RECT != 0 && !self.m.win.recs[iu].fs {
1225 let rc = self.m.win.recs[iu].rect.get();
1227 self.uwp_rect(i, &rc);
1228 }
1229 if want & UWW_TITLE != 0 {
1230 let t = self.m.win.recs[iu].title.clone();
1231 self.uwp_title(i, &t);
1232 }
1233 if want & UWW_SHOW != 0 {
1234 self.m.win.recs[iu].want |= want & (UWW_SHOW | UWW_ACTIVATE | UWW_FS);
1236 continue;
1237 }
1238 if want & UWW_HIDE != 0 {
1239 self.uwp_show(i, false);
1240 }
1241 }
1242 if i == 0 && want & UWW_RECT != 0 {
1243 let rc = self.m.win.recs[0].rect.get();
1245 self.uwp_rect(0, &rc);
1246 }
1247 if want & UWW_ACTIVATE != 0 {
1248 self.uwp_activate(i);
1249 }
1250 if want & UWW_FS != 0 {
1251 self.uwp_fullscreen(i);
1252 }
1253 }
1254 }
1255
1256 fn uwp_fullscreen(&mut self, i: u32) {
1258 let pw = self.uiw_pw(i);
1259 if pw < 0 {
1260 return;
1261 }
1262 let on = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].fs;
1263 plat::win_cmd(pw, if on { plat::WCMD_FULLSCREEN } else { plat::WCMD_WINDOWED });
1264 let now = plat::win_state(pw) & plat::WST_FULLSCREEN != 0;
1266 self.m.win.recs[(i as usize) & (WIN_MAX - 1)].fs_plat = now;
1267 }
1268
1269 pub(crate) fn uiw_fs_check(&mut self, i: u32) {
1273 if !self.uiw_os() {
1274 return;
1275 }
1276 let iu = (i as usize) & (WIN_MAX - 1);
1277 let on = self.uiw_plat_state(i) & plat::WST_FULLSCREEN != 0;
1278 if on == self.m.win.recs[iu].fs_plat {
1279 return;
1280 }
1281 self.m.win.recs[iu].fs_plat = on;
1282 if on != self.m.win.recs[iu].fs {
1283 self.uiw_fs_changed(i, on);
1284 }
1285 }
1286
1287 pub(crate) fn uiw_fs_changed(&mut self, i: u32, on: bool) {
1290 let iu = (i as usize) & (WIN_MAX - 1);
1291 let r = &mut self.m.win.recs[iu];
1292 r.fs = on;
1293 r.want &= !UWW_FS;
1294 let id = r.id;
1295 self.cmd_run(UIC_FULLSCREEN, id);
1296 self.invalidate();
1297 }
1298
1299 pub(crate) fn uiw_sync_show(&mut self) {
1302 if !self.m.win.hooks || self.headless {
1303 return;
1304 }
1305 for i in 1..WIN_MAX as u32 {
1306 let iu = i as usize;
1307 let r = &self.m.win.recs[iu];
1308 if r.want & UWW_SHOW == 0 || r.state & UWI_VISIBLE == 0 {
1309 continue;
1310 }
1311 self.m.win.recs[iu].want &= !UWW_SHOW;
1312 self.uwp_show(i, true);
1313 if self.m.win.recs[iu].want & UWW_ACTIVATE != 0 {
1314 self.m.win.recs[iu].want &= !UWW_ACTIVATE;
1315 self.uwp_activate(i);
1316 }
1317 }
1318 self.uiw_enable_sync(2); }
1320
1321 pub(crate) fn win_hooks_set(&mut self, on: bool) {
1324 self.m.win.hooks = on;
1325 }
1326
1327 pub fn sync_hook_set(&mut self, f: Option<fn() -> bool>) {
1330 self.m.win.synchook = f;
1331 }
1332
1333 pub(crate) fn uiw_sync_pending(&mut self) -> bool {
1335 match self.m.win.synchook {
1336 Some(f) => f(),
1337 None => false,
1338 }
1339 }
1340
1341 pub(crate) fn uiw_present(&mut self, n: i32) {
1344 let cur = self.uiw_cur;
1345 let pw = if self.headless {
1346 if !self.gp_scripted() {
1348 return;
1349 }
1350 self.gp_script_pw(cur)
1351 } else if cur == 0 {
1352 0
1353 } else if !self.m.win.hooks {
1354 return;
1355 } else {
1356 self.uiw_pw(cur) };
1358 if pw < 0 {
1359 return;
1360 }
1361 #[cfg(target_os = "android")]
1363 if cur == 0 && !self.headless {
1364 plat::host_edges(super::form::edge_colors(&self.wp.rt.fb));
1365 }
1366 if self.gp_present(cur, pw, n) {
1367 return;
1368 }
1369 let rects = if n < 0 { None } else { Some(&self.drects[..n as usize]) };
1370 plat::win_present(pw, &Ui::frame_of(&self.wp.rt.fb), rects);
1371 self.gp_cpu_done(cur, pw);
1372 }
1373
1374 pub(crate) fn uiw_publish_hits(&mut self) {
1378 if self.headless {
1379 return;
1380 }
1381 let cur = (self.uiw_cur as usize) & (WIN_MAX - 1);
1382 let mut drawable = 0;
1383 for i in 0..WIN_MAX as u32 {
1384 if self.uiw_drawable(i) {
1385 drawable |= 1 << i;
1386 }
1387 }
1388 let c = &self.wp.ctx;
1389 let mut p = PUBLISHED.lock();
1390 p.hits[cur].clear();
1391 p.hits[cur].extend_from_slice(&c.hits[c.hit_cur ^ 1]);
1392 p.zones[cur].clear();
1393 p.zones[cur].extend_from_slice(&c.zones[c.hit_cur ^ 1]);
1394 p.modal[cur] = c.modal_prev;
1395 p.mirror[cur] = if self.rtl { self.wp.rt.fb.w } else { 0 };
1396 p.drawable = drawable;
1397 p.p2u = self.m.win.p2u;
1398 }
1399
1400 fn publish_state(&self) {
1402 if self.headless {
1403 return;
1404 }
1405 let mut drawable = 0;
1406 for i in 0..WIN_MAX as u32 {
1407 if self.uiw_drawable(i) {
1408 drawable |= 1 << i;
1409 }
1410 }
1411 let mut p = PUBLISHED.lock();
1412 p.drawable = drawable;
1413 p.p2u = self.m.win.p2u;
1414 }
1415
1416 pub(crate) fn uiw_input_target(&mut self, ev: &Event) -> i32 {
1425 let w = ev.win as u32;
1426 if w as usize >= WIN_MAX || (w != 0 && !self.uiw_drawable(w)) {
1427 return -1; }
1429 let t = match ev.typ {
1430 plat::E_KEY_DOWN | plat::E_KEY_UP | plat::E_TEXT | plat::E_IME_COMMIT | plat::E_PREEDIT => self.uiw_key_target(w),
1431 plat::E_LEAVE => {
1432 if self.m.win.ptr == w as i32 {
1433 self.m.win.ptr = -1;
1434 }
1435 w
1436 }
1437 plat::E_FOCUS_OUT => w,
1438 _ => {
1439 let last = self.m.win.ptr;
1441 if last != w as i32 {
1442 self.m.win.ptr = w as i32;
1443 if last >= 0 && self.uiw_drawable(last as u32) {
1444 self.uiw_use(last as u32);
1445 let leave = Event { typ: plat::E_LEAVE, btn: 0, mods: ev.mods, win: last as u8, x: -1, y: -1, data: 0 };
1446 self.input_event(&leave);
1447 self.m.win.edges |= 1 << last;
1448 }
1449 }
1450 if ev.typ == plat::E_DOWN {
1451 self.uiw_kfocus_press(w, ev.x, ev.y);
1452 self.uiw_popups_dismiss(w); if self.headless {
1454 self.uiw_click_activate(w, ev.x, ev.y);
1455 }
1456 }
1457 w
1458 }
1459 };
1460 let t = t & (WIN_MAX as u32 - 1);
1461 self.m.win.edges |= 1 << t;
1462 t as i32
1463 }
1464
1465 fn uiw_key_target(&mut self, i: u32) -> u32 {
1467 let mut b = i;
1468 if b != 0 && !self.uiw_drawable(b) {
1469 b = self.m.win.active; }
1471 if (self.m.win.inert >> (b & 31)) & 1 != 0 {
1472 return self.m.win.modal & (WIN_MAX as u32 - 1);
1473 }
1474 let kf = self.m.win.kfocus;
1478 if kf != 0 {
1479 let t = kf - 1;
1480 if self.uiw_borrows(t) && (b == t || b == self.m.win.recs[(t as usize) & (WIN_MAX - 1)].owner) {
1481 self.m.win.fwd |= 1 << (t & 31);
1482 return t & (WIN_MAX as u32 - 1);
1483 }
1484 }
1485 let mut n = WIN_MAX;
1486 loop {
1487 if b == 0 {
1488 break;
1489 }
1490 let r = &self.m.win.recs[(b as usize) & (WIN_MAX - 1)];
1491 if r.flags & WF_TOOL == 0 || r.flags & WF_KEYS != 0 {
1492 break;
1493 }
1494 let owner = r.owner;
1495 if self.uiw_focus_is_text(b) {
1496 break;
1497 }
1498 if self.uiw_borrows(b) {
1500 self.m.win.fwd |= 1 << (b & 31);
1501 break;
1502 }
1503 b = owner;
1504 n -= 1;
1505 if n == 0 {
1506 break;
1507 }
1508 }
1509 b & (WIN_MAX as u32 - 1)
1510 }
1511
1512 pub(crate) fn uiw_keys_window(&self) -> u32 {
1515 let mut b = self.m.win.active & (WIN_MAX as u32 - 1);
1516 if (self.m.win.inert >> b) & 1 != 0 {
1517 return self.m.win.modal & (WIN_MAX as u32 - 1);
1518 }
1519 let kf = self.m.win.kfocus;
1520 if kf != 0 {
1521 let t = kf - 1;
1522 if self.uiw_borrows(t) && (b == t || b == self.m.win.recs[(t as usize) & (WIN_MAX - 1)].owner) {
1523 return t & (WIN_MAX as u32 - 1);
1524 }
1525 }
1526 for _ in 0..WIN_MAX {
1527 if b == 0 {
1528 break;
1529 }
1530 let r = &self.m.win.recs[(b as usize) & (WIN_MAX - 1)];
1531 if r.flags & WF_TOOL == 0 || r.flags & WF_KEYS != 0 || self.uiw_focus_is_text(b) || self.uiw_borrows(b) {
1532 break;
1533 }
1534 b = r.owner;
1535 }
1536 b & (WIN_MAX as u32 - 1)
1537 }
1538
1539 fn uiw_borrows(&self, i: u32) -> bool {
1542 if i == 0 || i as usize >= WIN_MAX || !self.uiw_drawable(i) || (self.m.win.inert >> i) & 1 != 0 {
1543 return false;
1544 }
1545 if self.m.win.recs[i as usize].flags & (WF_TOOL | WF_KEYS) != WF_TOOL {
1546 return false;
1547 }
1548 self.win_focus(i) != 0
1549 }
1550
1551 fn uiw_kfocus_press(&mut self, i: u32, x: i32, y: i32) {
1555 self.m.win.kfocus = 0;
1556 self.m.kbnav.tool = false; if i == 0 || self.m.win.recs[(i as usize) & (WIN_MAX - 1)].flags & (WF_TOOL | WF_KEYS) != WF_TOOL {
1558 return;
1559 }
1560 if self.hit_flags_win(i, x, y) & HB_TEXT != 0 {
1561 return; }
1563 self.m.win.kfocus = i + 1;
1564 }
1565
1566 pub(crate) fn uiw_fwd_take(&mut self) {
1570 let cur = self.uiw_cur;
1571 if cur as usize >= WIN_MAX || (self.m.win.fwd >> cur) & 1 == 0 {
1572 return;
1573 }
1574 self.m.win.fwd &= !(1 << cur);
1575 if self.popup_count() != 0 {
1576 return; }
1578 self.m.win.fwd_to = self.m.win.recs[cur as usize].owner & (WIN_MAX as u32 - 1);
1579 let n = FWDQ_MAX - self.m.win.fwdq.len().min(FWDQ_MAX);
1580 let k = self.kb_take_rest(n); self.m.win.fwdq.extend_from_slice(&k);
1582 let n = FWDT_MAX - self.m.win.fwdt.len().min(FWDT_MAX);
1583 let t = self.text_take(n);
1584 self.m.win.fwdt.extend_from_slice(&t);
1585 }
1586
1587 pub(crate) fn uiw_fwd_inject(&mut self) -> bool {
1591 self.m.win.fwd = 0;
1592 if self.m.win.fwdq.is_empty() && self.m.win.fwdt.is_empty() {
1593 return false;
1594 }
1595 let to = self.m.win.fwd_to;
1596 let mut r = false;
1597 if self.uiw_drawable(to) {
1598 self.uiw_use(to);
1599 let q = core::mem::take(&mut self.m.win.fwdq);
1600 self.keys_inject(&q);
1601 let t = core::mem::take(&mut self.m.win.fwdt);
1602 self.text_inject(&t);
1603 self.uiw_use(0);
1604 self.m.win.edges |= 1 << to;
1605 self.repass = true;
1606 r = true;
1607 }
1608 self.m.win.fwdq.clear();
1609 self.m.win.fwdt.clear();
1610 r
1611 }
1612
1613 pub(crate) fn uiw_fwd_arm(&mut self, i: u32) {
1617 if self.uiw_borrows(i) && !self.uiw_focus_is_text(i) {
1618 self.m.win.fwd |= 1 << (i & 31);
1619 }
1620 }
1621
1622 fn uiw_focus_is_text(&self, i: u32) -> bool {
1625 let Some(p) = self.uiw_parts(i) else { return false };
1626 let f = p.ctx.focus;
1627 if f == 0 {
1628 return false;
1629 }
1630 let list = &p.ctx.hits[p.ctx.hit_cur ^ 1];
1631 match list.iter().rev().find(|h| h.id == f) {
1632 Some(h) => h.flags as u32 & HB_TEXT != 0 || h.keys,
1633 None => false,
1634 }
1635 }
1636
1637 fn uiw_click_activate(&mut self, i: u32, x: i32, y: i32) {
1641 if (self.m.win.inert >> (i & 31)) & 1 != 0 {
1642 return;
1643 }
1644 if i != 0 {
1645 let f = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].flags;
1646 if f & (WF_TOOL | WF_NOACTIVATE) != 0 {
1647 if f & WF_NOACTIVATE != 0 || self.hit_flags_win(i, x, y) & HB_TEXT == 0 {
1648 return;
1649 }
1650 }
1651 }
1652 self.uiw_activate(i);
1653 }
1654
1655 pub(crate) fn hit_flags_win(&mut self, i: u32, x: i32, y: i32) -> u32 {
1658 let i = i & (WIN_MAX as u32 - 1);
1659 if !self.uiw_drawable(i) {
1660 return 0;
1661 }
1662 let Some(p) = self.uiw_parts(i) else { return 0 };
1663 let c = &p.ctx;
1664 super::ctx::hit_find_list(&c.hits[c.hit_cur ^ 1], c.modal_prev, x, y).1
1665 }
1666
1667 pub(crate) fn uiw_moved_passes(&mut self) -> bool {
1669 if self.m.win.used == 0 {
1670 if !self.wp.ctx.moved {
1672 return false;
1673 }
1674 let r = self.needs_move_pass();
1675 self.wp.ctx.moved = false;
1676 return r;
1677 }
1678 let mut r = false;
1679 for i in 0..WIN_MAX as u32 {
1680 if !self.uiw_drawable(i) || !self.uiw_parts(i).is_some_and(|p| p.ctx.moved) {
1681 continue;
1682 }
1683 self.uiw_use(i);
1684 r |= self.needs_move_pass();
1685 self.wp.ctx.moved = false;
1686 }
1687 self.uiw_use(0);
1688 r
1689 }
1690
1691 pub(crate) fn uiw_resize(&mut self, app: &mut dyn super::App, i: u32, w: i32, h: i32) {
1693 if i != 0 {
1694 if i as usize >= WIN_MAX || !self.uiw_drawable(i) || w <= 0 || h <= 0 {
1695 return;
1696 }
1697 let iu = i as usize;
1699 let dpi = self.win_dpi(i);
1700 self.uiw_use(i);
1701 let b2 = self.uiw_border() * 2;
1702 let tbh = self.m.win.recs[iu].tbh;
1703 let mut rc = self.m.win.recs[iu].rect.get();
1704 rc.w = px2dip_at(w - b2, dpi);
1705 rc.h = (px2dip_at(h - b2, dpi) - tbh).max(1);
1706 rc.flags |= WRF_CHANGED;
1707 if !self.headless {
1708 rc.flags &= !WRF_MAX;
1709 if self.uiw_plat_state(i) & plat::WST_MAXIMIZED != 0 {
1710 rc.flags |= WRF_MAX;
1711 }
1712 }
1713 self.m.win.recs[iu].rect.set(rc);
1714 self.m.win.recs[iu].applied = rc;
1715 }
1716 self.uiw_use(i);
1717 self.resize(app, w, h);
1718 self.uiw_use(0);
1719 if i == 0 {
1720 self.ws_track(); }
1722 self.uiw_fs_check(i); }
1724
1725 pub(crate) fn uiw_dpi(&mut self, i: u32, dpi: i32) {
1728 if i as usize >= WIN_MAX || !self.uiw_drawable(i) || dpi < 24 {
1729 return;
1730 }
1731 self.uiw_use(i);
1732 self.wp.rt.dpi = dpi;
1733 self.dirty_force_full();
1734 if i == 0 {
1735 self.cmd_run(UIC_DPI, dpi as u32);
1736 } else {
1737 self.m.win.recs[i as usize].applied.w = -1; }
1739 self.uiw_use(0);
1740 self.invalidate();
1741 }
1742
1743 pub(crate) fn uiw_focus_in(&mut self, i: u32) {
1745 if i as usize >= WIN_MAX || !self.uiw_drawable(i) || i == self.m.win.active {
1746 return;
1747 }
1748 self.uiw_activate(i);
1749 }
1750
1751 pub(crate) fn uiw_winpos(&mut self, i: u32, x: i32, y: i32) {
1755 if i as usize >= WIN_MAX {
1756 return;
1757 }
1758 let iu = i as usize;
1759 if self.m.win.recs[iu].state == 0 {
1760 return;
1761 }
1762 self.m.win.recs[iu].sx = x;
1763 self.m.win.recs[iu].sy = y;
1764 let mut rc = self.m.win.recs[iu].rect.get();
1765 if i == 0 {
1766 rc.x = x;
1767 rc.y = y;
1768 rc.flags |= WRF_ABS | WRF_POS;
1769 let a = &mut self.m.win.recs[0].applied;
1770 a.flags = rc.flags;
1771 a.x = x;
1772 a.y = y;
1773 } else {
1774 let (ox, oy) = self.uiw_owner_origin(i);
1776 let odpi = self.win_dpi(self.m.win.recs[iu].owner);
1777 rc.x = px2dip_at(x - ox, odpi);
1778 rc.y = px2dip_at(y - oy, odpi);
1779 rc.flags |= WRF_POS | WRF_CHANGED;
1780 let r = &mut self.m.win.recs[iu];
1781 r.applied.x = rc.x;
1782 r.applied.y = rc.y;
1783 r.applied.flags = rc.flags;
1784 r.state &= !UWI_DEFPOS;
1785 }
1786 self.m.win.recs[iu].rect.set(rc);
1787 if i == 0 {
1788 self.ws_track(); }
1790 self.uiw_follow_owner(i);
1792 }
1793
1794 pub(crate) fn uiw_close_request(&mut self, i: u32) {
1797 if i == 0 || i as usize >= WIN_MAX {
1798 return;
1799 }
1800 let r = &self.m.win.recs[i as usize];
1801 if r.id == 0 || r.flags & WF_NOCLOSE != 0 {
1802 return;
1803 }
1804 let id = r.id;
1805 self.cmd_run(UIC_WINCLOSE, id);
1806 self.invalidate();
1807 }
1808
1809 pub(crate) fn uiw_cmd_done(&mut self, id: u32, arg: u32, r: bool) {
1812 if id != UIC_WINCLOSE || r {
1813 return;
1814 }
1815 let i = self.uiw_index(arg);
1816 if i <= 0 {
1817 return;
1818 }
1819 let rec = &self.m.win.recs[i as usize];
1820 if let Some(o) = &rec.openp {
1821 o.set(0);
1822 }
1823 if rec.state & UWI_VISIBLE != 0 {
1824 self.uiw_hide(i as u32);
1825 }
1826 }
1827
1828 pub fn window_place(&mut self, id: u32, rect: &WinRect) {
1833 let i = self.uiw_index(id);
1834 if i < 0 {
1835 return;
1836 }
1837 let iu = i as usize;
1838 self.m.win.recs[iu].state &= !UWI_DEFPOS;
1839 self.m.win.recs[iu].rect.set(*rect);
1840 if i == 0 {
1841 if !self.headless {
1843 self.m.win.recs[0].want |= UWW_RECT;
1844 } else if rect.w > 0 && rect.h > 0 {
1845 let (w, h) = (self.dp(rect.w), self.dp(rect.h));
1846 self.resize_noapp(w, h);
1849 }
1850 }
1851 self.invalidate();
1852 }
1853
1854 pub fn window_snap(&mut self, id: u32, area: [i32; 4], dist: i32) {
1862 let i = self.uiw_index(id);
1863 if i <= 0 {
1864 return;
1865 }
1866 let iu = i as usize;
1867 let s = [area[0], area[1], area[2], area[3], dist.max(0)];
1868 self.m.win.recs[iu].snap = s;
1869 if self.headless {
1870 return;
1871 }
1872 let owner = self.m.win.recs[iu].owner;
1875 let dpi = self.win_dpi(owner);
1876 let mut p = [0; 6];
1877 if s[4] != 0 && dpi >= 24 {
1878 let tb = if owner != 0 { dip2px_at(self.m.win.recs[(owner as usize) & (WIN_MAX - 1)].tbh, dpi) } else { 0 };
1879 p = [owner as i32, dip2px_at(s[0], dpi), tb + dip2px_at(s[1], dpi), dip2px_at(s[2], dpi), dip2px_at(s[3], dpi), dip2px_at(s[4], dpi)];
1880 }
1881 PUBLISHED.lock().snap[iu] = p;
1882 }
1883
1884 pub(crate) fn uiw_snap_dip(&self, i: u32, x: i32, y: i32) -> (i32, i32) {
1887 let iu = (i as usize) & (WIN_MAX - 1);
1888 let r = &self.m.win.recs[iu];
1889 let s = r.snap;
1890 if s[4] == 0 {
1891 return (x, y);
1892 }
1893 let rc = r.rect.get();
1895 let (fb, dpi) = (self.win_fb(i), self.win_dpi(i));
1896 let (w, h) = if fb.w > 0 && dpi >= 24 { (px2dip_at(fb.w, dpi), px2dip_at(fb.h, dpi)) } else { (rc.w, rc.h + r.tbh) };
1897 snap_to(x, y, w, h, [s[0], s[1], s[2], s[3]], s[4])
1898 }
1899
1900 pub fn window_rect(&self, id: u32) -> Option<WinRect> {
1902 let i = self.uiw_index(id);
1903 if i < 0 {
1904 return None;
1905 }
1906 Some(self.m.win.recs[i as usize].rect.get())
1907 }
1908
1909 pub fn window_state(&mut self, id: u32) -> u32 {
1912 let i = self.uiw_index(id);
1913 if i < 0 {
1914 return 0;
1915 }
1916 let i = i as u32;
1917 let st = self.m.win.recs[i as usize].state;
1918 let mut s = 0;
1919 if st & UWI_OPEN != 0 {
1920 s |= UWS_OPEN;
1921 }
1922 if st & (UWI_VISIBLE | UWI_CREATED) != UWI_VISIBLE | UWI_CREATED {
1923 return s;
1924 }
1925 s |= UWS_VISIBLE;
1926 if i == self.m.win.active {
1927 s |= UWS_ACTIVE;
1928 }
1929 if self.uiw_plat_state(i) & plat::WST_MINIMIZED != 0 {
1930 s |= UWS_MINIMIZED;
1931 }
1932 if self.m.win.recs[i as usize].fs {
1933 s |= UWS_FULLSCREEN;
1934 }
1935 s
1936 }
1937
1938 pub fn window_fullscreen(&mut self, id: u32, on: bool) {
1951 let i = self.uiw_index(id);
1952 if i < 0 {
1953 return;
1954 }
1955 let iu = i as usize;
1956 if self.m.win.recs[iu].fs == on {
1957 return;
1958 }
1959 if on && self.uiw_os() && self.uiw_plat_state(i as u32) & plat::WST_CHILD != 0 {
1960 return; }
1962 if cfg!(any(target_os = "android", target_os = "ios")) {
1963 return; }
1965 self.m.win.recs[iu].fs = on;
1966 self.m.win.recs[iu].want |= UWW_FS;
1967 self.invalidate();
1968 }
1969
1970 pub fn window_activate(&mut self, id: u32) {
1972 let i = self.uiw_index(id);
1973 if i < 0 || !self.uiw_drawable(i as u32) {
1974 return;
1975 }
1976 self.uiw_activate(i as u32);
1977 }
1978
1979 pub fn window_destroy(&mut self, id: u32) {
1982 let i = self.uiw_index(id);
1983 if i <= 0 {
1984 return;
1985 }
1986 let i = i as u32;
1987 let iu = i as usize;
1988 if self.m.win.recs[iu].state & UWI_BUILDING != 0 || i == self.uiw_cur {
1989 self.warn("ui_window_destroy: the window is being built");
1990 return;
1991 }
1992 if self.m.win.recs[iu].state & UWI_VISIBLE != 0 {
1993 self.uiw_hide(i);
1994 }
1995 if self.m.win.recs[iu].state & UWI_CREATED != 0 {
1996 self.m.win.recs[iu].save = None; if self.m.win.hooks && !self.headless {
1998 self.uwp_destroy(i);
1999 }
2000 }
2001 self.m.win.used &= !(1 << i);
2002 self.m.win.recs[iu] = Rec::default();
2003 if !self.headless {
2004 PUBLISHED.lock().snap[iu] = [0; 6];
2005 }
2006 self.uiw_modal_update();
2007 self.publish_state();
2008 }
2009
2010 pub fn window_current(&self) -> u32 {
2012 self.uiw_rec_id(self.uiw_cur)
2013 }
2014
2015 pub fn window_modal(&self) -> u32 {
2017 let m = self.m.win.modal;
2018 if m == 0 { 0 } else { self.uiw_rec_id(m) }
2019 }
2020
2021 fn resize_noapp(&mut self, w: i32, h: i32) {
2024 if w <= 0 || h <= 0 || (w == self.wp.rt.fb.w && h == self.wp.rt.fb.h) {
2025 return;
2026 }
2027 self.wp.rt.fb.resize(w, h);
2028 self.dirty_force_full();
2029 self.need = true;
2030 }
2031
2032 pub(crate) fn uiw_desk_pos(&self, i: u32) -> (i32, i32) {
2037 let (mut x, mut y) = (0, 0);
2038 let mut b = i;
2039 for _ in 0..WIN_MAX {
2040 if b == 0 {
2041 break;
2042 }
2043 let r = &self.m.win.recs[(b as usize) & (WIN_MAX - 1)];
2044 let rc = r.rect.get();
2045 x += rc.x;
2046 y += rc.y;
2047 b = r.owner;
2048 if b == 0 {
2049 break;
2050 }
2051 y += self.m.win.recs[(b as usize) & (WIN_MAX - 1)].tbh;
2053 }
2054 (x, y)
2055 }
2056
2057 pub(crate) fn uiw_user_rect(&mut self, i: u32, x: i32, y: i32, w: i32, h: i32) {
2060 if i == 0 || i as usize >= WIN_MAX {
2061 return;
2062 }
2063 let iu = i as usize;
2064 let mut rc = self.m.win.recs[iu].rect.get();
2065 if x != i32::MIN {
2066 rc.x = x;
2067 rc.y = y;
2068 rc.flags |= WRF_POS | WRF_CHANGED;
2069 self.m.win.recs[iu].state &= !UWI_DEFPOS;
2070 }
2071 if w > 0 {
2072 rc.w = w;
2073 if h > 0 {
2074 rc.h = h;
2075 rc.flags |= WRF_CHANGED;
2076 }
2077 }
2078 self.m.win.recs[iu].rect.set(rc);
2079 self.m.win.recs[iu].want |= UWW_RECT;
2080 self.invalidate();
2081 }
2082
2083 pub fn window_pw(&self, id: u32) -> (i32, i32) {
2093 let i = self.uiw_index(id);
2094 if i < 0 {
2095 return (i, -1);
2096 }
2097 (i, self.uiw_pw(i as u32))
2098 }
2099
2100 pub(crate) fn uiw_pw(&self, i: u32) -> i32 {
2102 let p = self.m.win.u2p[(i as usize) & (WIN_MAX - 1)];
2103 if p == 0xFF { -1 } else { p as i32 }
2104 }
2105
2106 pub(crate) fn uiw_from_pw(&self, pw: i32) -> i32 {
2108 if !(0..WIN_MAX as i32).contains(&pw) {
2109 return -1;
2110 }
2111 let u = self.m.win.p2u[pw as usize];
2112 if u == 0xFF { -1 } else { u as i32 }
2113 }
2114
2115 fn uiw_os(&self) -> bool {
2117 !self.headless && self.m.win.hooks
2118 }
2119
2120 pub(crate) fn uiw_plat_state(&self, i: u32) -> u32 {
2122 if !self.uiw_os() {
2123 return 0;
2124 }
2125 let pw = self.uiw_pw(i);
2126 if pw < 0 { 0 } else { plat::win_state(pw) }
2127 }
2128
2129 pub(crate) fn uiw_app_active(&self) -> bool {
2131 if self.headless {
2132 return true;
2133 }
2134 plat::win_state(0) & plat::WST_ACTIVE != 0
2135 }
2136
2137 fn uiw_sysframe_ok(&self) -> bool {
2140 if !self.uiw_os() {
2141 return true;
2142 }
2143 plat::win_state(0) & plat::WST_CSD == 0
2144 }
2145
2146 fn uiw_owner_origin(&mut self, i: u32) -> (i32, i32) {
2152 let owner = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].owner;
2153 let ou = (owner as usize) & (WIN_MAX - 1);
2154 let (mut x, mut y) = (self.m.win.recs[ou].sx, self.m.win.recs[ou].sy);
2155 self.m.win.origin_ok = true;
2156 if self.uiw_os() {
2157 self.m.win.origin_ok = false;
2158 let own_pw = self.uiw_pw(i);
2159 let pw = self.uiw_pw(owner);
2160 if own_pw >= 0 && plat::win_state(own_pw) & plat::WST_CHILD != 0 {
2161 self.m.win.origin_ok = true;
2162 x = 0;
2163 y = 0;
2164 } else if pw >= 0 {
2165 if let Some(r) = plat::win_get_rect(pw) {
2166 self.m.win.origin_ok = true;
2167 x = r[0];
2168 y = r[1];
2169 }
2170 }
2171 }
2172 if owner != 0 {
2173 let dpi = self.win_dpi(owner);
2175 y += dip2px_at(self.m.win.recs[ou].tbh, dpi);
2176 }
2177 (x, y)
2178 }
2179
2180 fn uiw_attached(&self, i: u32) -> bool {
2184 let r = &self.m.win.recs[(i as usize) & (WIN_MAX - 1)];
2185 let rc = r.rect.get();
2186 let owner = r.owner;
2187 let odpi = self.win_dpi(owner);
2188 if odpi < 24 {
2189 return false;
2190 }
2191 let fb = self.win_fb(owner);
2192 let ow = px2dip_at(fb.w, odpi); let oh = px2dip_at(fb.h, odpi) - self.m.win.recs[(owner as usize) & (WIN_MAX - 1)].tbh;
2194 let cx = (rc.w >> 1) + rc.x; if cx < 0 || cx >= ow {
2196 return false;
2197 }
2198 let cy = ((rc.h + r.tbh) >> 1) + rc.y;
2199 cy >= 0 && cy < oh
2200 }
2201
2202 fn uiw_follow_owner(&mut self, i: u32) {
2207 if !self.uiw_os() || self.m.win.follow as usize >= WIN_MAX {
2208 return; }
2210 self.m.win.follow += 1;
2211 for j in 1..WIN_MAX as u32 {
2212 if j == i {
2213 continue;
2214 }
2215 let r = &self.m.win.recs[j as usize];
2216 if r.id == 0 || r.owner != i || !self.uiw_drawable(j) {
2217 continue;
2218 }
2219 if (self.m.win.placed >> j) & 1 == 0 || self.uiw_attached(j) {
2220 self.m.win.recs[j as usize].want |= UWW_RECT;
2224 self.invalidate();
2225 continue;
2226 }
2227 let pw = self.uiw_pw(j);
2228 if pw < 0 {
2229 continue;
2230 }
2231 if let Some(r) = plat::win_get_rect(pw) {
2232 self.uiw_winpos(j, r[0], r[1]);
2233 }
2234 }
2235 self.m.win.follow -= 1;
2236 }
2237
2238 fn uiw_enable_sync(&mut self, phase: u32) {
2242 if !self.m.win.hooks {
2243 return;
2244 }
2245 for i in 0..WIN_MAX as u32 {
2246 if self.uiw_pw(i) < 0 {
2247 continue;
2248 }
2249 let want = (self.m.win.inert >> i) & 1 == 0; let now = (self.m.win.disabled >> i) & 1 == 0;
2251 if want == now {
2252 continue;
2253 }
2254 if phase == 1 {
2255 if !want {
2256 continue; }
2258 self.m.win.disabled &= !(1 << i);
2259 } else {
2260 if want {
2261 continue; }
2263 self.m.win.disabled |= 1 << i;
2264 }
2265 self.uwp_enable(i, want);
2266 }
2267 }
2268
2269 fn uwp_create(&mut self, i: u32, flags: u32, owner: u32) -> bool {
2274 let i = i & (WIN_MAX as u32 - 1);
2275 let opw = self.uiw_pw(owner);
2276 if opw < 0 {
2277 return false; }
2279 let dpi = self.win_dpi(i);
2280 let fb = self.win_fb(i);
2281 let (w, h) = (px2dip_at(fb.w, dpi), px2dip_at(fb.h, dpi));
2282 let title = self.m.win.recs[i as usize].title.clone();
2283 let mut pw = -1;
2286 if flags & WF_APP != 0 && !cfg!(any(target_arch = "wasm32", target_os = "android", target_os = "ios")) {
2287 pw = plat::win_create(&title, w, h, flags & plat::PWF_MASK, plat::PW_NOOWNER, plat::PW_DEFAULT, plat::PW_DEFAULT);
2288 }
2289 if pw < 0 {
2290 pw = plat::win_create(&title, w, h, flags & plat::PWF_MASK, opw, plat::PW_DEFAULT, plat::PW_DEFAULT);
2291 }
2292 if pw < 0 || pw as usize >= WIN_MAX {
2293 return false;
2294 }
2295 self.m.win.u2p[i as usize] = pw as u8;
2296 self.m.win.p2u[pw as usize] = i as u8;
2297 self.m.win.disabled &= !(1 << i);
2298 if flags & WF_RESIZABLE != 0 {
2299 let tbh = self.m.win.recs[i as usize].tbh;
2300 plat::win_set_min_size(pw, 120, tbh + 48);
2301 }
2302 self.publish_state();
2303 let d = plat::win_dpi(pw);
2305 if d != dpi {
2306 self.uiw_dpi(i, d);
2307 }
2308 true
2309 }
2310
2311 fn uwp_destroy(&mut self, i: u32) {
2313 let i = i & (WIN_MAX as u32 - 1);
2314 let pw = self.uiw_pw(i);
2315 if pw < 0 {
2316 return;
2317 }
2318 self.gp_window_gone(i); let pw = pw as usize & (WIN_MAX - 1);
2320 self.m.win.p2u[pw] = 0xFF;
2321 self.m.win.u2p[i as usize] = 0xFF;
2322 self.m.win.disabled &= !(1 << i);
2323 self.m.win.placed &= !(1 << i);
2324 self.publish_state();
2325 plat::win_destroy(pw as i32);
2326 }
2327
2328 fn uwp_show(&mut self, i: u32, show: bool) {
2330 let pw = self.uiw_pw(i);
2331 if pw < 0 {
2332 return;
2333 }
2334 self.gp_window_show(i, show);
2335 let mut mode = plat::PWS_HIDE;
2336 if show {
2337 mode = plat::PWS_SHOW;
2338 if self.m.win.recs[(i as usize) & (WIN_MAX - 1)].flags & (WF_TOOL | WF_NOACTIVATE) != 0 {
2339 mode = plat::PWS_SHOWNA;
2340 }
2341 }
2342 plat::win_show(pw, mode);
2343 }
2344
2345 fn uwp_rect(&mut self, i: u32, rc: &WinRect) {
2349 let pw = self.uiw_pw(i);
2350 if pw < 0 {
2351 return;
2352 }
2353 if i != 0 {
2354 let (fw, fh) = {
2355 let fb = self.win_fb(i);
2356 (fb.w, fb.h)
2357 };
2358 let (mut x, mut y) = (plat::PW_KEEP, plat::PW_KEEP);
2359 if rc.flags & WRF_POS != 0 {
2360 let owner = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].owner;
2361 let odpi = self.win_dpi(owner);
2362 let (ox, oy) = self.uiw_owner_origin(i);
2363 if self.m.win.origin_ok {
2364 self.m.win.placed |= 1 << i;
2365 x = ox + dip2px_at(rc.x, odpi);
2366 y = oy + dip2px_at(rc.y, odpi);
2367 }
2368 }
2370 plat::win_set_rect(pw, x, y, fw, fh);
2371 return;
2372 }
2373 let dpi = self.win_dpi(0);
2374 let st = plat::win_state(pw);
2375 if rc.flags & WRF_MAX != 0 {
2376 if st & plat::WST_MAXIMIZED == 0 {
2377 plat::win_cmd(pw, plat::WCMD_MAXIMIZE);
2378 }
2379 return;
2380 }
2381 if st & plat::WST_MAXIMIZED != 0 {
2382 plat::win_cmd(pw, plat::WCMD_RESTORE);
2383 }
2384 let (mut x, mut y) = (plat::PW_KEEP, plat::PW_KEEP);
2385 if rc.flags & WRF_POS != 0 {
2386 x = rc.x;
2387 y = rc.y;
2388 }
2389 let w = if rc.w > 0 { dip2px_at(rc.w, dpi) } else { plat::PW_KEEP };
2390 let h = if rc.h > 0 { dip2px_at(rc.h, dpi) } else { plat::PW_KEEP };
2391 plat::win_set_rect(pw, x, y, w, h);
2392 if w == plat::PW_KEEP && h == plat::PW_KEEP {
2395 return;
2396 }
2397 let (cw, ch) = plat::win_size(pw);
2398 if cw <= 0 || ch <= 0 {
2399 return;
2400 }
2401 self.resize_noapp(cw, ch); }
2403
2404 fn uwp_title(&mut self, i: u32, s: &str) {
2406 let pw = self.uiw_pw(i);
2407 if pw >= 0 {
2408 plat::win_set_title(pw, s);
2409 }
2410 }
2411
2412 fn uwp_activate(&mut self, i: u32) {
2414 let pw = self.uiw_pw(i);
2415 if pw >= 0 {
2416 plat::win_activate(pw);
2417 }
2418 }
2419
2420 fn uwp_enable(&mut self, i: u32, on: bool) {
2422 let pw = self.uiw_pw(i);
2423 if pw >= 0 {
2424 plat::win_enable(pw, on);
2425 }
2426 }
2427
2428 pub(crate) fn uiw_popup_area(&mut self) -> Option<([i32; 4], bool)> {
2448 let cur = self.uiw_cur;
2449 if cur as usize >= WIN_MAX {
2450 return None;
2451 }
2452 let mut a = [0i32; 4];
2453 let mut known = true;
2454 if self.uiw_os() {
2455 let pw = self.uiw_pw(cur);
2457 if pw < 0 {
2458 return None;
2459 }
2460 match (plat::win_get_rect(pw), plat::win_work_area(pw)) {
2461 (Some(wr), Some(wa)) => {
2462 a[0] = wa[0] - wr[0];
2463 a[2] = a[0] + wa[2];
2464 a[1] = wa[1] - wr[1];
2465 a[3] = a[1] + wa[3];
2466 }
2467 _ => {
2468 a = [-4096, -4096, self.wp.rt.fb.w + 4096, self.wp.rt.fb.h + 4096];
2470 known = false;
2471 }
2472 }
2473 } else {
2474 let scr = self.m.win.screen;
2476 let [sx, sy, sw, sh] = if scr[2] > 0 && scr[3] > 0 {
2477 scr
2478 } else if cur == 0 {
2479 return None;
2480 } else {
2481 let mdpi = self.win_dpi(0);
2482 let fb = self.win_fb(0);
2483 [0, 0, px2dip_at(fb.w, mdpi), px2dip_at(fb.h, mdpi)]
2484 };
2485 let (wx, wy) = self.uiw_desk_pos(cur); let dpi = self.wp.rt.dpi;
2487 a[0] = dip2px_at(sx - wx, dpi);
2488 a[1] = dip2px_at(sy - wy, dpi);
2489 a[2] = dip2px_at(sx + sw - wx, dpi);
2490 a[3] = dip2px_at(sy + sh - wy, dpi);
2491 }
2492 a[0] = a[0].min(0);
2494 a[1] = a[1].min(0);
2495 a[2] = a[2].max(self.wp.rt.fb.w);
2496 a[3] = a[3].max(self.wp.rt.fb.h);
2497 Some((a, known))
2498 }
2499
2500 pub(crate) fn uiw_popup_screen_h(&mut self) -> Option<i32> {
2505 if !self.uiw_os() || self.uiw_cur as usize >= WIN_MAX {
2506 return None;
2507 }
2508 let pw = self.uiw_pw(self.uiw_cur);
2509 if pw < 0 || (plat::win_get_rect(pw).is_some() && plat::win_work_area(pw).is_some()) {
2510 return None;
2511 }
2512 let h = plat::monitors().iter().map(|m| m.work[3]).filter(|&h| h > 0).min()?;
2514 Some(dip2px_at((h - POPUP_PANEL_ROOM).max(h / 2), self.wp.rt.dpi).max(self.wp.rt.fb.h))
2515 }
2516
2517 pub(crate) fn uiw_popup_nudge(&self, item: u32, key: [i32; 2]) -> (i32, i32) {
2522 if !self.uiw_os() {
2523 return (0, 0);
2524 }
2525 let own = self.uiw_cur + 1;
2526 let Some(k) = (0..EXT_MAX).find(|&k| {
2527 let e = &self.m.win.ex[k];
2528 e.owner == own && e.item == item && e.shown && e.key == key
2529 }) else {
2530 return (0, 0);
2531 };
2532 let nat = self.m.win.ex[k].nat;
2533 match plat::popup_placed(k as u32) {
2534 Some(p) => (p[0] - nat[0], p[1] - nat[1]),
2535 None => (0, 0),
2536 }
2537 }
2538
2539 pub(crate) fn uiw_popups_render(&mut self, i: u32) {
2546 if i as usize >= WIN_MAX {
2547 return;
2548 }
2549 let all = i == 0 && (1..WIN_MAX as u32).any(|j| self.uiw_drawable(j));
2552 let own = i + 1;
2553 for e in self.m.win.ex.iter_mut() {
2555 if e.owner == own {
2556 e.used = false;
2557 }
2558 }
2559 for item in 0..POPUP_ITEMS {
2560 let rect = if all { self.popup_rect(item) } else { self.popup_ext(item) };
2561 let Some(rect) = rect else { continue };
2562 let k = match (0..EXT_MAX).find(|&k| self.m.win.ex[k].owner == own && self.m.win.ex[k].item == item) {
2564 Some(k) => k,
2565 None => match (0..EXT_MAX).find(|&k| self.m.win.ex[k].owner == 0) {
2566 Some(k) => {
2567 let e = &mut self.m.win.ex[k];
2568 e.owner = own;
2569 e.item = item;
2570 e.shown = false;
2571 e.rect[2] = 0;
2572 k
2573 }
2574 None => {
2575 self.limit_hit(super::ctx::LIM_POPUP_SLOTS); continue;
2577 }
2578 },
2579 };
2580 let mut changed = self.wp.rt.present_n != 0;
2582 {
2583 let e = &mut self.m.win.ex[k];
2584 e.used = true;
2585 if e.rect != rect {
2586 changed = true;
2587 e.rect = rect;
2588 }
2589 if !e.shown {
2590 changed = true;
2591 }
2592 }
2593 if !changed {
2594 continue;
2595 }
2596 let mut sf = core::mem::take(&mut self.m.win.ex[k].sf);
2598 if sf.w != rect[2] || sf.h != rect[3] || sf.px.is_empty() {
2599 sf = Surface::new(rect[2], rect[3], FMT_XRGB);
2600 if sf.px.is_empty() {
2601 self.m.win.ex[k].owner = 0;
2602 continue;
2603 }
2604 }
2605 self.dc.begin(&sf);
2606 let c = self.color(T_FLYOUT) | 0xFF00_0000;
2607 self.dc.set_color(c);
2608 self.dc.fill(&mut sf, 0, 0, rect[2], rect[3]);
2609 self.render_popup(&mut sf, -rect[0], -rect[1]);
2610 self.dc.end();
2611 if self.uiw_os() {
2612 let pw = self.uiw_pw(i);
2613 if pw >= 0 {
2614 let (anchor, kind, nat, key) =
2616 self.popup_place(item).unwrap_or(([rect[0], rect[1], 1, 1], plat::PA_FREE, [rect[0], rect[1]], [rect[0], rect[1]]));
2617 plat::popup_anchor(k as u32, anchor, kind, nat);
2618 plat::popup(k as u32, pw, Some(rect), Some(&Ui::frame_of(&sf)));
2619 let e = &mut self.m.win.ex[k];
2620 e.shown = true;
2621 e.nat = nat;
2622 e.key = key;
2623 }
2624 }
2625 self.m.win.ex[k].sf = sf;
2626 }
2627 self.uiw_popups_drop_ex(i, true);
2628 }
2629
2630 pub(crate) fn uiw_popups_drop(&mut self, i: u32) {
2632 self.uiw_popups_drop_ex(i, false);
2633 }
2634
2635 fn uiw_popups_drop_ex(&mut self, i: u32, unused_only: bool) {
2638 let own = i + 1;
2639 for k in 0..EXT_MAX {
2640 let e = &self.m.win.ex[k];
2641 if e.owner != own || (unused_only && e.used) {
2642 continue;
2643 }
2644 if e.shown && self.uiw_os() {
2645 plat::popup(k as u32, 0, None, None); }
2647 let e = &mut self.m.win.ex[k];
2648 e.sf = Surface::default();
2649 e.owner = 0;
2650 e.shown = false;
2651 e.used = false;
2652 }
2653 }
2654
2655 pub(crate) fn uiw_popups_blit(&mut self, sf: &mut Surface, i: u32, x0: i32, y0: i32, dpi: i32) {
2658 let own = i + 1;
2659 let (wx, wy) = self.uiw_desk_pos(i);
2660 let wdpi = self.win_dpi(i);
2661 for k in 0..EXT_MAX {
2662 let e = &self.m.win.ex[k];
2663 if e.owner != own || !e.used || e.sf.px.is_empty() {
2664 continue;
2665 }
2666 let x = dip2px_at(px2dip_at(e.rect[0], wdpi) + wx - x0, dpi);
2667 let y = dip2px_at(px2dip_at(e.rect[1], wdpi) + wy - y0, dpi);
2668 blit_copy(sf, &e.sf, x, y);
2669 }
2670 }
2671
2672 pub(crate) fn uiw_popups_dismiss(&mut self, i: u32) {
2675 let mut swapped = false;
2676 for j in 0..WIN_MAX as u32 {
2677 if j == i || (j != 0 && !self.uiw_drawable(j)) {
2678 continue;
2679 }
2680 self.uiw_use(j);
2681 swapped = true;
2682 if self.popup_count() != 0 {
2683 self.popup_close();
2684 self.invalidate();
2685 }
2686 }
2687 if swapped {
2688 self.uiw_use(0);
2689 }
2690 }
2691}