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 WROOT_BASE: u32 = 0xFFFF_7F00;
76
77pub(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;
90const UWW_HIDE: u32 = 2;
91const UWW_RECT: u32 = 4;
92const UWW_TITLE: u32 = 8;
93const UWW_ACTIVATE: u32 = 16;
94const UWW_CREATE: u32 = 64;
95const UWW_FS: u32 = 128; pub struct Shared<T: Copy>(Rc<Cell<T>>);
100
101impl<T: Copy> Shared<T> {
102 pub fn new(v: T) -> Shared<T> {
103 Shared(Rc::new(Cell::new(v)))
104 }
105 pub fn get(&self) -> T {
106 self.0.get()
107 }
108 pub fn set(&self, v: T) {
109 self.0.set(v)
110 }
111}
112
113impl<T: Copy> Clone for Shared<T> {
114 fn clone(&self) -> Shared<T> {
115 Shared(self.0.clone())
116 }
117}
118
119impl<T: Copy + Default> Default for Shared<T> {
120 fn default() -> Shared<T> {
121 Shared::new(T::default())
122 }
123}
124
125pub(crate) struct Rec {
127 pub(crate) id: u32,
129 pub(crate) flags: u32,
131 pub(crate) state: u32,
133 pub(crate) owner: u32,
135 pub(crate) seen: u32,
137 pub(crate) z: u32,
139 pub(crate) openp: Option<Shared<i32>>,
141 pub(crate) rect: Shared<WinRect>,
143 pub(crate) own: Shared<WinRect>,
144 pub(crate) save: Option<Box<WinParts>>,
147 pub(crate) applied: WinRect,
149 pub(crate) want: u32,
151 pub(crate) tbh: i32,
153 pub(crate) autoh: i32,
155 pub(crate) sx: i32,
157 pub(crate) sy: i32,
158 pub(crate) title: String,
160 pub(crate) snap: [i32; 5],
162 pub(crate) fs: bool,
166 pub(crate) fs_plat: bool,
167}
168
169impl Default for Rec {
170 fn default() -> Rec {
171 let own = Shared::default();
172 Rec {
173 id: 0,
174 flags: 0,
175 state: 0,
176 owner: 0,
177 seen: 0,
178 z: 0,
179 openp: None,
180 rect: own.clone(),
181 own,
182 save: None,
183 applied: WinRect::default(),
184 want: 0,
185 tbh: 0,
186 autoh: 0,
187 sx: 0,
188 sy: 0,
189 title: String::new(),
190 snap: [0; 5],
191 fs: false,
192 fs_plat: false,
193 }
194 }
195}
196
197#[derive(Default)]
199struct Ex {
200 owner: u32,
202 item: u32,
204 rect: [i32; 4],
206 used: bool,
208 shown: bool,
210 nat: [i32; 2],
213 key: [i32; 2],
214 sf: Surface,
215}
216
217pub(crate) struct S {
219 pub(crate) recs: [Rec; WIN_MAX],
220 pub(crate) active: u32,
222 pub(crate) modal: u32,
224 pub(crate) inert: u32,
226 pub(crate) ptr: i32,
228 pub(crate) edges: u32,
230 pub(crate) used: u32,
232 pub(crate) noaccel: bool,
234 stack: [u32; WSTACK_MAX],
235 sp: u32,
236 over: u32,
237 hooks: bool,
239 synchook: Option<fn() -> bool>,
240 zc: u32,
241 pub(crate) kfocus: u32,
244 fwd: u32,
245 fwd_to: u32,
246 fwdq: Vec<u32>,
247 fwdt: Vec<u32>,
248 ex: [Ex; EXT_MAX],
250 pub(crate) screen: [i32; 4],
253 disabled: u32,
255 follow: u32,
257 placed: u32,
259 origin_ok: bool,
261 u2p: [u8; WIN_MAX],
263 p2u: [u8; WIN_MAX],
264 zero_fb: Surface,
266 pub(crate) saved: Vec<super::winstate::Saved>,
269 pub(crate) norm: super::winstate::MainState,
270 pub(crate) cand: Option<super::winstate::MainState>,
271}
272
273impl Default for S {
274 fn default() -> S {
275 S {
276 recs: Default::default(),
277 active: 0,
278 modal: 0,
279 inert: 0,
280 ptr: 0,
281 edges: 0,
282 used: 0,
283 noaccel: false,
284 stack: [0; WSTACK_MAX],
285 sp: 0,
286 over: 0,
287 hooks: false,
288 synchook: None,
289 zc: 0,
290 kfocus: 0,
291 fwd: 0,
292 fwd_to: 0,
293 fwdq: Vec::new(),
294 fwdt: Vec::new(),
295 ex: Default::default(),
296 screen: [0; 4],
297 disabled: 0,
298 follow: 0,
299 placed: 0,
300 origin_ok: false,
301 u2p: [0xFF; WIN_MAX],
302 p2u: [0xFF; WIN_MAX],
303 zero_fb: Surface::new(0, 0, FMT_XRGB),
304 saved: Vec::new(),
305 norm: Default::default(),
306 cand: None,
307 }
308 }
309}
310
311struct Published {
317 hits: [Vec<Hit>; WIN_MAX],
318 modal: [u32; WIN_MAX],
319 drawable: u32,
321 p2u: [u8; WIN_MAX],
322 mirror: [i32; WIN_MAX],
324 zones: [Vec<super::dnd::Zone>; WIN_MAX],
327 accept: u32,
328 own: u32,
329 snap: [[i32; 6]; WIN_MAX],
332}
333
334static PUBLISHED: SpinLock<Published> = SpinLock::new(Published {
335 hits: [const { Vec::new() }; WIN_MAX],
336 modal: [0; WIN_MAX],
337 drawable: 1,
338 p2u: [0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
339 mirror: [0; WIN_MAX],
340 zones: [const { Vec::new() }; WIN_MAX],
341 accept: plat::DT_FILES,
342 own: 0,
343 snap: [[0; 6]; WIN_MAX],
344});
345
346pub(crate) fn uiw_hit_pw(pw: i32, x: i32, y: i32) -> u32 {
349 if !(0..WIN_MAX as i32).contains(&pw) {
350 return 0;
351 }
352 let p = PUBLISHED.lock();
353 let i = p.p2u[pw as usize];
354 if i == 0xFF || (p.drawable >> i) & 1 == 0 {
355 return 0;
356 }
357 let i = i as usize;
358 let x = if p.mirror[i] > 0 { p.mirror[i] - 1 - x } else { x };
360 super::ctx::hit_find_list(&p.hits[i], p.modal[i], x, y).1
361}
362
363pub(crate) fn uiw_drag_pw(pw: i32, x: i32, y: i32, types: u32) -> (u32, u32) {
367 if !(0..WIN_MAX as i32).contains(&pw) {
368 return (0, 0);
369 }
370 let p = PUBLISHED.lock();
371 let i = p.p2u[pw as usize];
372 if i == 0xFF || (p.drawable >> i) & 1 == 0 {
373 return (0, 0);
374 }
375 let i = i as usize;
376 let x = if p.mirror[i] > 0 { p.mirror[i] - 1 - x } else { x }; let offered = types & plat::DT_STD;
378 let all = offered | p.own; let t = match super::dnd::zone_find(&p.zones[i], &p.hits[i], p.modal[i], x, y, all) {
380 Some(z) => z.types & all,
381 None => p.accept & all,
382 };
383 let t = if t != 0 && t & offered == 0 { offered } else { t & offered };
385 (t, if t != 0 { plat::DE_ALL } else { 0 })
386}
387
388pub(crate) fn uiw_publish_dnd(accept: u32, own: u32) {
391 let mut p = PUBLISHED.lock();
392 p.accept = accept;
393 p.own = own;
394}
395
396pub(crate) fn uiw_moving_pw(pw: i32, r: &mut [i32; 4]) {
400 if !(0..WIN_MAX as i32).contains(&pw) {
401 return;
402 }
403 let (s, opw) = {
404 let p = PUBLISHED.lock();
405 let i = p.p2u[pw as usize];
406 if i == 0xFF {
407 return;
408 }
409 let s = p.snap[i as usize];
410 if s[5] == 0 {
411 return;
412 }
413 (s, p.p2u.iter().position(|&u| u as i32 == s[0]))
414 };
415 let o = opw.and_then(|o| plat::win_get_rect(o as i32)).unwrap_or([0; 4]);
418 let a = [o[0] + s[1], o[1] + s[2], s[3], s[4]];
419 (r[0], r[1]) = snap_to(r[0], r[1], r[2], r[3], a, s[5]);
420}
421
422fn snap_to(x: i32, y: i32, w: i32, h: i32, a: [i32; 4], d: i32) -> (i32, i32) {
427 let axis = |p: i32, s: i32, lo: i32, len: i32| {
428 let near = (p - lo).abs(); let far = (p + s - lo - len).abs(); if near <= d && near <= far {
431 lo
432 } else if far <= d {
433 lo + len - s
434 } else {
435 p
436 }
437 };
438 let mut r = (x, y);
439 if y < a[1] + a[3] + d && y + h > a[1] - d {
440 r.0 = axis(x, w, a[0], a[2]);
441 }
442 if x < a[0] + a[2] + d && x + w > a[0] - d {
443 r.1 = axis(y, h, a[1], a[3]);
444 }
445 r
446}
447
448const POPUP_PANEL_ROOM: i32 = 96;
451
452fn dip2px_at(dip: i32, dpi: i32) -> i32 {
454 let v = dip.wrapping_mul(dpi);
455 if v < 0 { (v - 48) / 96 } else { (v + 48) / 96 }
456}
457
458fn blit_copy(dst: &mut Surface, src: &Surface, x: i32, y: i32) {
460 let x0 = x.max(0);
461 let y0 = y.max(0);
462 let x1 = (x + src.w).min(dst.w);
463 let y1 = (y + src.h).min(dst.h);
464 if x1 <= x0 || y1 <= y0 {
465 return;
466 }
467 let n = (x1 - x0) as usize * 4;
468 for yy in y0..y1 {
469 let d = yy as usize * dst.stride as usize + x0 as usize * 4;
470 let s = (yy - y) as usize * src.stride as usize + (x0 - x) as usize * 4;
471 dst.px[d..d + n].copy_from_slice(&src.px[s..s + n]);
472 }
473}
474
475impl Ui {
476 pub(crate) fn uiw_index(&self, id: u32) -> i32 {
480 if id == 0 {
481 return 0;
482 }
483 (1..WIN_MAX).find(|&i| self.m.win.recs[i].id == id).map_or(-1, |i| i as i32)
484 }
485
486 pub(crate) fn uiw_rec_id(&self, i: u32) -> u32 {
488 self.m.win.recs[(i as usize) & (WIN_MAX - 1)].id
489 }
490
491 pub(crate) fn uiw_title(&self, i: u32) -> &str {
493 &self.m.win.recs[(i as usize) & (WIN_MAX - 1)].title
494 }
495
496 pub(crate) fn uiw_any_used(&self) -> bool {
498 self.m.win.used != 0
499 }
500
501 pub(crate) fn uiw_init(&mut self) {
503 let w = &mut self.m.win;
504 w.recs[0].state = UWI_OPEN | UWI_VISIBLE | UWI_CREATED | UWI_SHOWN;
505 let r = &w.recs[0];
506 r.rect.set(WinRect { flags: WRF_ABS, ..r.rect.get() });
507 self.wp.lay.root_id = 1;
508 w.u2p = [0xFF; WIN_MAX];
510 w.p2u = [0xFF; WIN_MAX];
511 w.u2p[0] = 0;
512 w.p2u[0] = 0;
513 self.uiw_cur = 0;
514 w.active = 0;
515 w.modal = 0;
516 w.ptr = 0;
517 }
518
519 pub(crate) fn uiw_use(&mut self, i: u32) {
522 let i = (i as usize) & (WIN_MAX - 1);
523 let cur = self.uiw_cur as usize & (WIN_MAX - 1);
524 if i == cur {
525 return;
526 }
527 let Some(mut b) = self.m.win.recs[i].save.take() else {
528 return; };
530 core::mem::swap(&mut self.wp, &mut *b);
531 self.m.win.recs[cur].save = Some(b);
532 self.uiw_cur = i as u32;
533 plat::win_use(self.uiw_pw(i as u32));
535 }
536
537 pub(crate) fn uiw_parts(&self, i: u32) -> Option<&WinParts> {
540 let i = (i as usize) & (WIN_MAX - 1);
541 if i == self.uiw_cur as usize {
542 Some(&self.wp)
543 } else {
544 self.m.win.recs[i].save.as_deref()
545 }
546 }
547
548 pub(crate) fn uiw_parts_mut(&mut self, i: u32) -> Option<&mut WinParts> {
549 let i = (i as usize) & (WIN_MAX - 1);
550 if i == self.uiw_cur as usize {
551 Some(&mut self.wp)
552 } else {
553 self.m.win.recs[i].save.as_deref_mut()
554 }
555 }
556
557 pub(crate) fn win_dpi(&self, i: u32) -> i32 {
559 self.uiw_parts(i).map_or(0, |p| p.rt.dpi)
560 }
561
562 pub(crate) fn win_fb(&self, i: u32) -> &Surface {
564 match self.uiw_parts(i) {
565 Some(p) => &p.rt.fb,
566 None => &self.m.win.zero_fb,
567 }
568 }
569
570 fn win_focus(&self, i: u32) -> u32 {
572 self.uiw_parts(i).map_or(0, |p| p.ctx.focus)
573 }
574
575 pub(crate) fn uiw_take_newshow(&mut self, i: u32) -> bool {
577 let r = &mut self.m.win.recs[(i as usize) & (WIN_MAX - 1)];
578 let n = r.state & UWI_NEWSHOW != 0;
579 r.state &= !UWI_NEWSHOW;
580 n
581 }
582
583 pub(crate) fn uiw_frame_begin(&mut self) {
587 let w = &mut self.m.win;
588 if w.used != 0 {
589 for r in w.recs.iter_mut() {
590 r.state &= !UWI_SEEN;
591 }
592 }
593 w.sp = 0;
594 w.over = 0;
595 }
596
597 pub(crate) fn uiw_frame_end(&mut self) {
599 if self.m.win.used == 0 {
600 return; }
602 if self.uiw_modal_update() {
603 self.repass = true;
604 }
605 }
606
607 pub(crate) fn uiw_unwind(&mut self) {
610 while self.m.win.sp != 0 {
611 self.warn("ui_window_begin without ui_window_end");
612 self.window_end();
613 }
614 self.m.win.over = 0;
615 self.uiw_use(0);
616 }
617
618 fn uiw_modal_update(&mut self) -> bool {
621 let mut modal = 0u32;
622 let mut mz: i32 = -1;
623 if self.headless || self.m.win.hooks {
626 for i in 1..WIN_MAX {
627 let r = &self.m.win.recs[i];
628 if r.state & (UWI_VISIBLE | UWI_CREATED) != UWI_VISIBLE | UWI_CREATED || r.flags & WF_MODAL == 0 {
629 continue;
630 }
631 if r.z as i32 > mz {
632 mz = r.z as i32;
633 modal = i as u32;
634 }
635 }
636 }
637 let mut inert = 0u32;
639 if modal != 0 {
640 for i in 0..WIN_MAX as u32 {
641 if i != modal && !self.uiw_owned_by(i, modal) {
642 inert |= 1 << i;
643 }
644 }
645 }
646 self.m.win.inert = inert;
647 if modal == self.m.win.modal {
648 return false;
649 }
650 self.m.win.modal = modal;
651 if modal != 0 {
652 self.uiw_activate(modal); }
654 true
655 }
656
657 fn uiw_owned_by(&self, i: u32, owner: u32) -> bool {
659 let mut i = i;
660 for _ in 0..WIN_MAX {
661 if i == 0 {
662 return false;
663 }
664 i = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].owner;
665 if i == owner {
666 return true;
667 }
668 }
669 false
670 }
671
672 pub(crate) fn uiw_inert_now(&self) -> bool {
674 (self.m.win.inert >> (self.uiw_cur & 31)) & 1 != 0
675 }
676
677 pub(crate) fn uiw_border(&mut self) -> i32 {
680 let cur = self.uiw_cur;
681 let r = &self.m.win.recs[(cur as usize) & (WIN_MAX - 1)];
682 if cur == 0 || r.flags & WF_SYSFRAME != 0 || r.fs {
683 return 0;
684 }
685 self.hair()
686 }
687
688 pub(crate) fn uiw_escape(&mut self) {
691 let r = &self.m.win.recs[(self.uiw_cur as usize) & (WIN_MAX - 1)];
692 let (id, flags) = (r.id, r.flags);
693 let mut cmd = UIC_ESCAPE;
694 if id != 0 && flags & WF_DIALOG != 0 {
695 if flags & WF_NOCLOSE != 0 {
696 return;
697 }
698 cmd = UIC_WINCLOSE;
699 }
700 self.cmd_run(cmd, id);
701 }
702
703 pub(crate) fn uiw_focus_arrived(&mut self) {
707 let id = self.focus_req;
708 self.focus_req = 0;
709 self.wp.ctx.focus = id;
710 self.wp.ctx.focus_visible = true;
711 let from = self.focus_req_win;
712 if from == self.uiw_cur {
713 return;
714 }
715 let old = self.focus_req_old;
716 if let Some(p) = self.uiw_parts_mut(from) {
717 p.ctx.focus = old;
718 }
719 self.repass = true;
720 let cur = self.uiw_cur;
721 if cur != self.m.win.active {
722 self.uiw_activate(cur);
723 }
724 }
725
726 pub(crate) fn uiw_clear_edges(&mut self) {
729 self.dnd_clear_edges(); self.input_clear_edges(); let e = self.m.win.edges & !1;
732 self.m.win.edges = 0;
733 if e == 0 {
734 return;
735 }
736 for i in 1..WIN_MAX as u32 {
737 if (e >> i) & 1 != 0 && self.uiw_drawable(i) {
738 self.uiw_use(i);
739 self.input_clear_edges();
740 }
741 }
742 self.uiw_use(0);
743 }
744
745 pub fn window_title_height(&self, flags: u32) -> i32 {
749 let h = self.style.metric(if flags & WF_TOOL != 0 { SM_WIN_TBH_TOOL } else { SM_WIN_TBH_DIALOG });
750 if self.m.touch.on { h.max(super::touch::TITLE_DIP) } else { h } }
752
753 pub(crate) fn uiw_drawable(&self, i: u32) -> bool {
754 let s = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].state;
755 s & (UWI_VISIBLE | UWI_CREATED) == UWI_VISIBLE | UWI_CREATED
756 }
757
758 #[cfg_attr(jfgui_dev, track_caller)]
764 pub fn window_begin(&mut self, id: u32, title: &str, open: Option<&Shared<i32>>, flags: u32, rect: Option<&Shared<WinRect>>) -> bool {
765 let _src = self.src_scope();
766 let mut flags = flags;
767 let sp = self.m.win.sp;
768 if sp as usize >= WSTACK_MAX {
769 self.m.win.over += 1;
770 self.limit_hit(super::ctx::LIM_WINNEST);
771 return false;
772 }
773 let owner = self.uiw_cur; self.m.win.stack[sp as usize & (WSTACK_MAX - 1)] = owner; self.m.win.sp += 1;
776 if id == 0 {
777 self.warn("ui_window_begin: window id 0");
778 return false;
779 }
780 if self.uiw_depth() >= NEST_MAX {
782 self.warn(&alloc::format!("window {}: windows nested too deeply", id));
783 return false;
784 }
785 if !self.m.win.saved.is_empty() {
787 self.ws_open(id, flags, open);
788 }
789 let mut i = self.uiw_index(id);
790 if i < 0 {
791 if let Some(o) = open {
793 if o.get() == 0 {
794 return false;
795 }
796 }
797 i = self.uiw_alloc();
798 if i < 0 {
799 self.warn(&alloc::format!("window {}: too many windows ({} besides the main window)", id, WIN_MAX - 1));
800 return false;
801 }
802 self.m.win.recs[i as usize].id = id;
803 self.m.win.used |= 1 << i;
804 }
805 let i = i as u32;
806 let iu = i as usize;
807 if self.m.win.recs[iu].state & (UWI_SEEN | UWI_BUILDING) != 0 {
808 self.warn(&alloc::format!("window {} begun twice in one pass", id));
809 return false;
810 }
811 let frame = self.frame;
812 {
813 let r = &mut self.m.win.recs[iu];
814 r.state |= UWI_SEEN;
815 r.seen = frame;
816 }
817 if flags & WF_SYSFRAME != 0 && !self.uiw_sysframe_ok() {
819 flags &= !WF_SYSFRAME;
820 }
821 let tbh = if flags & WF_SYSFRAME != 0 || self.m.win.recs[iu].fs {
823 0
824 } else {
825 self.window_title_height(flags)
826 };
827 {
828 let r = &mut self.m.win.recs[iu];
829 r.flags = flags;
830 r.owner = owner;
831 r.openp = open.cloned();
832 r.rect = match rect {
833 Some(p) => p.clone(),
834 None => r.own.clone(),
835 };
836 r.tbh = tbh;
837 let t = super::basic::cstr(title);
839 let mut n = t.len().min(TITLE_MAX - 1);
840 while !t.is_char_boundary(n) {
841 n -= 1;
842 }
843 if r.title != t[..n] {
844 r.title = String::from(&t[..n]);
845 r.want |= UWW_TITLE;
846 }
847 }
848 if !self.m.win.saved.is_empty() {
850 self.ws_rect(i, id);
851 }
852 let is_open = open.is_none_or(|o| o.get() != 0);
854 if !is_open {
855 let r = &mut self.m.win.recs[iu];
856 r.state &= !UWI_OPEN;
857 if r.state & UWI_VISIBLE != 0 {
858 self.uiw_hide(i);
859 }
860 return false;
861 }
862 self.m.win.recs[iu].state |= UWI_OPEN;
863 if self.m.win.recs[iu].state & UWI_CREATED == 0 && !self.uiw_create(i) {
864 self.warn(&alloc::format!("window {}: out of memory", id));
865 return false;
866 }
867 if self.m.win.recs[iu].state & UWI_VISIBLE == 0 {
868 self.uiw_show(i);
869 }
870 let top = (self.m.win.sp - 1) as usize & (WSTACK_MAX - 1);
872 self.m.win.stack[top] = i << 8 | owner | WSE_ENTERED;
873 self.uiw_use(i);
874 self.m.win.recs[iu].state |= UWI_BUILDING;
875 if self.m.win.recs[iu].state & UWI_FRESH != 0 {
876 self.m.win.recs[iu].state &= !UWI_FRESH;
877 self.wp.ctx.focus = 0;
880 self.wp.ctx.focus_visible = false;
881 self.wp.ctx.active = 0;
882 self.wp.ctx.kb.autofocus = flags & WF_DIALOG != 0;
883 }
884 self.uiw_apply_rect(i);
885 let (w, h) = (self.wp.rt.fb.w, self.wp.rt.fb.h);
886 self.uiw_pass_begin(w, h);
887 self.win_chrome_begin(i);
888 true
889 }
890
891 fn uiw_depth(&self) -> u32 {
893 let n = (self.m.win.sp as usize).min(WSTACK_MAX);
894 self.m.win.stack[..n].iter().filter(|&&e| e & WSE_ENTERED != 0).count() as u32
895 }
896
897 fn uiw_alloc(&mut self) -> i32 {
900 if let Some(i) = (1..WIN_MAX).find(|&i| self.m.win.recs[i].id == 0) {
901 return i as i32;
902 }
903 let mut cand: i32 = -1;
905 let mut oldest = u32::MAX;
906 for i in 1..WIN_MAX {
907 let r = &self.m.win.recs[i];
908 if r.state & (UWI_VISIBLE | UWI_BUILDING | UWI_SEEN) != 0 {
909 continue;
910 }
911 if r.seen < oldest {
912 oldest = r.seen;
913 cand = i as i32;
914 }
915 }
916 if cand < 0 {
917 return -1;
918 }
919 let id = self.m.win.recs[cand as usize].id;
920 self.window_destroy(id);
921 cand
922 }
923
924 #[cfg_attr(jfgui_dev, track_caller)]
926 pub fn window_end(&mut self) {
927 let _src = self.src_scope();
928 if self.m.win.over != 0 {
929 self.m.win.over -= 1;
930 return;
931 }
932 if self.m.win.sp == 0 {
933 self.warn("ui_window_end without ui_window_begin");
934 return;
935 }
936 let sp = (self.m.win.sp - 1) & (WSTACK_MAX as u32 - 1);
937 self.m.win.sp = sp;
938 let e = self.m.win.stack[sp as usize];
939 if e & WSE_ENTERED == 0 {
940 return;
941 }
942 let i = (e >> 8) & 255; let back = e & 255; let iu = (i as usize) & (WIN_MAX - 1);
945 let h = self.win_chrome_end(i); let flags = self.m.win.recs[iu].flags;
947 if flags & WF_AUTOHEIGHT != 0 {
948 self.m.win.recs[iu].autoh = h;
949 }
950 if flags & (WF_RESIZABLE | WF_SYSFRAME) == WF_RESIZABLE {
952 self.edge_grips();
953 }
954 self.m.win.noaccel = flags & WF_DIALOG != 0;
955 self.uiw_pass_end();
956 self.m.win.noaccel = false;
957 self.m.win.recs[iu].state &= !UWI_BUILDING;
958 self.uiw_use(back);
959 }
960
961 fn uiw_create(&mut self, i: u32) -> bool {
964 let iu = (i as usize) & (WIN_MAX - 1);
965 let owner = self.m.win.recs[iu].owner;
966 let dpi = self.win_dpi(owner);
967 let mut p = Box::new(WinParts::new());
968 p.rt.dpi = dpi;
969 p.ctx.mx = -1;
970 p.ctx.my = -1;
971 p.lay.root_id = i | WROOT_BASE;
972 p.cmd = super::cmd::W::new(&super::cmd::CAPS_SMALL);
973 p.dirty.full = true; self.m.win.recs[iu].save = Some(p);
975 let r = &mut self.m.win.recs[iu];
976 r.state |= UWI_CREATED;
977 r.want |= UWW_CREATE;
978 true
979 }
980
981 fn uiw_show(&mut self, i: u32) {
984 let iu = (i as usize) & (WIN_MAX - 1);
985 let mut rc = self.m.win.recs[iu].rect.get();
986 if rc.w <= 0 {
987 rc.w = DEF_W;
988 }
989 if rc.h <= 0 {
990 rc.h = DEF_H;
991 }
992 self.m.win.recs[iu].rect.set(rc);
993 if rc.flags & WRF_POS == 0 {
994 self.uiw_place_default(i);
995 self.m.win.recs[iu].state |= UWI_DEFPOS;
996 }
997 self.m.win.zc = self.m.win.zc.wrapping_add(1);
998 let zc = self.m.win.zc;
999 let r = &mut self.m.win.recs[iu];
1000 r.state |= UWI_VISIBLE | UWI_NEWSHOW | UWI_SHOWN | UWI_FRESH;
1001 r.want = (r.want & !UWW_HIDE) | UWW_SHOW;
1002 r.z = zc;
1003 if r.flags & (WF_TOOL | WF_NOACTIVATE) == 0 {
1004 self.uiw_activate(i);
1005 }
1006 }
1007
1008 pub(crate) fn uiw_hide(&mut self, i: u32) {
1010 let iu = (i as usize) & (WIN_MAX - 1);
1011 let r = &mut self.m.win.recs[iu];
1012 r.state &= !(UWI_VISIBLE | UWI_NEWSHOW);
1013 r.want = (r.want & !UWW_SHOW) | UWW_HIDE;
1014 let mut owner = r.owner;
1015 if self.m.win.ptr == i as i32 {
1016 self.m.win.ptr = -1;
1017 }
1018 if self.m.win.active != i {
1019 return;
1020 }
1021 let mut n = WIN_MAX;
1023 loop {
1024 let o = owner;
1025 if self.uiw_drawable(o) || o == 0 {
1026 break;
1027 }
1028 owner = self.m.win.recs[(o as usize) & (WIN_MAX - 1)].owner;
1029 n -= 1;
1030 if n == 0 {
1031 owner = 0;
1032 break;
1033 }
1034 }
1035 self.uiw_activate(owner);
1036 }
1037
1038 pub(crate) fn uiw_activate(&mut self, i: u32) {
1040 let i = i & (WIN_MAX as u32 - 1);
1041 if self.m.win.active == i {
1042 return;
1043 }
1044 if i != 0 && !self.headless && !self.m.win.hooks {
1046 return;
1047 }
1048 self.m.win.active = i;
1049 self.m.win.recs[i as usize].want |= UWW_ACTIVATE;
1050 if i != 0 {
1051 self.m.win.zc = self.m.win.zc.wrapping_add(1);
1052 self.m.win.recs[i as usize].z = self.m.win.zc;
1053 }
1054 self.invalidate();
1055 }
1056
1057 fn uiw_place_default(&mut self, i: u32) {
1061 let iu = (i as usize) & (WIN_MAX - 1);
1062 let (owner, flags, tbh) = {
1063 let r = &self.m.win.recs[iu];
1064 (r.owner, r.flags, r.tbh)
1065 };
1066 let mut rc = self.m.win.recs[iu].rect.get();
1067 if flags & WF_DIALOG == 0 {
1068 let mut k = 0;
1070 for j in 1..WIN_MAX {
1071 if j == iu {
1072 continue;
1073 }
1074 let r = &self.m.win.recs[j];
1075 if r.id != 0 && r.owner == owner && r.state & UWI_SHOWN != 0 && r.flags & WF_DIALOG == 0 {
1076 k += 1;
1077 }
1078 }
1079 rc.x = k * 32 + 24;
1080 rc.y = k * 32 + 48;
1081 } else {
1082 let (ow, oh, oy) = self.uiw_outer_dip(owner);
1084 rc.x = (ow - rc.w) >> 1;
1085 rc.y = ((oh - (tbh + rc.h)) >> 1) + oy;
1086 }
1087 rc.flags |= WRF_POS;
1088 self.m.win.recs[iu].rect.set(rc);
1089 }
1090
1091 fn uiw_outer_dip(&self, i: u32) -> (i32, i32, i32) {
1094 if i == 0 {
1095 let fb = self.win_fb(0);
1097 let dpi = self.win_dpi(0);
1098 return (px2dip_at(fb.w, dpi), px2dip_at(fb.h, dpi), 0);
1099 }
1100 let r = &self.m.win.recs[(i as usize) & (WIN_MAX - 1)];
1101 let rc = r.rect.get();
1102 (rc.w, rc.h + r.tbh, -r.tbh)
1103 }
1104
1105 fn uiw_apply_rect(&mut self, i: u32) {
1108 let iu = (i as usize) & (WIN_MAX - 1);
1109 let mut rc = self.m.win.recs[iu].rect.get();
1110 if rc.w <= 0 {
1111 rc.w = DEF_W;
1112 }
1113 if rc.h <= 0 {
1114 rc.h = DEF_H;
1115 }
1116 if rc.w > SIZE_MAX_DIP {
1117 rc.w = SIZE_MAX_DIP;
1118 }
1119 if rc.h > SIZE_MAX_DIP {
1120 rc.h = SIZE_MAX_DIP;
1121 }
1122 self.m.win.recs[iu].rect.set(rc);
1123 if !self.wp.rt.fb.px.is_empty() && rc == self.m.win.recs[iu].applied {
1124 return;
1125 }
1126 let tbh = {
1127 let r = &mut self.m.win.recs[iu];
1128 r.applied = rc;
1129 r.want |= UWW_RECT;
1130 r.tbh
1131 };
1132 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 {
1136 return;
1137 }
1138 if self.wp.rt.fb.px.is_empty() {
1139 self.wp.rt.fb = Surface::new(w, h, FMT_XRGB);
1140 } else {
1141 self.wp.rt.fb.resize(w, h);
1142 }
1143 self.dirty_force_full();
1144 }
1145
1146 pub(crate) fn uiw_settle(&mut self) -> bool {
1152 let mut changed = false;
1153 if self.m.win.used != 0 {
1154 for i in 1..WIN_MAX as u32 {
1155 let iu = i as usize;
1156 let (state, flags, autoh) = {
1157 let r = &self.m.win.recs[iu];
1158 (r.state, r.flags, r.autoh)
1159 };
1160 if state & UWI_VISIBLE == 0 {
1161 continue;
1162 }
1163 if state & UWI_SEEN == 0 {
1164 self.uiw_hide(i);
1165 changed = true;
1166 continue;
1167 }
1168 if flags & WF_AUTOHEIGHT == 0 || autoh <= 0 {
1169 continue;
1170 }
1171 let mut rc = self.m.win.recs[iu].rect.get();
1172 if rc.h == autoh {
1173 continue;
1174 }
1175 rc.h = autoh;
1176 self.m.win.recs[iu].rect.set(rc);
1177 changed = true;
1178 if state & UWI_DEFPOS != 0 && flags & WF_DIALOG != 0 {
1180 self.uiw_place_default(i);
1181 }
1182 }
1183 changed |= self.uiw_modal_update();
1184 }
1185 if !changed {
1187 self.uiw_sync();
1188 }
1189 changed
1190 }
1191
1192 fn uiw_sync(&mut self) {
1194 if !self.m.win.hooks || self.headless {
1195 return; }
1197 self.uiw_enable_sync(1); for i in 0..WIN_MAX as u32 {
1199 let iu = i as usize;
1200 let want = self.m.win.recs[iu].want;
1201 if want == 0 {
1202 continue;
1203 }
1204 self.m.win.recs[iu].want = 0;
1205 if i != 0 {
1206 if want & UWW_CREATE != 0 {
1207 let (flags, owner) = (self.m.win.recs[iu].flags, self.m.win.recs[iu].owner);
1208 self.uwp_create(i, flags, owner);
1209 }
1210 if want & UWW_RECT != 0 && !self.m.win.recs[iu].fs {
1211 let rc = self.m.win.recs[iu].rect.get();
1213 self.uwp_rect(i, &rc);
1214 }
1215 if want & UWW_TITLE != 0 {
1216 let t = self.m.win.recs[iu].title.clone();
1217 self.uwp_title(i, &t);
1218 }
1219 if want & UWW_SHOW != 0 {
1220 self.m.win.recs[iu].want |= want & (UWW_SHOW | UWW_ACTIVATE | UWW_FS);
1222 continue;
1223 }
1224 if want & UWW_HIDE != 0 {
1225 self.uwp_show(i, false);
1226 }
1227 }
1228 if i == 0 && want & UWW_RECT != 0 {
1229 let rc = self.m.win.recs[0].rect.get();
1231 self.uwp_rect(0, &rc);
1232 }
1233 if want & UWW_ACTIVATE != 0 {
1234 self.uwp_activate(i);
1235 }
1236 if want & UWW_FS != 0 {
1237 self.uwp_fullscreen(i);
1238 }
1239 }
1240 }
1241
1242 fn uwp_fullscreen(&mut self, i: u32) {
1244 let pw = self.uiw_pw(i);
1245 if pw < 0 {
1246 return;
1247 }
1248 let on = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].fs;
1249 plat::win_cmd(pw, if on { plat::WCMD_FULLSCREEN } else { plat::WCMD_WINDOWED });
1250 let now = plat::win_state(pw) & plat::WST_FULLSCREEN != 0;
1252 self.m.win.recs[(i as usize) & (WIN_MAX - 1)].fs_plat = now;
1253 }
1254
1255 pub(crate) fn uiw_fs_check(&mut self, i: u32) {
1259 if !self.uiw_os() {
1260 return;
1261 }
1262 let iu = (i as usize) & (WIN_MAX - 1);
1263 let on = self.uiw_plat_state(i) & plat::WST_FULLSCREEN != 0;
1264 if on == self.m.win.recs[iu].fs_plat {
1265 return;
1266 }
1267 self.m.win.recs[iu].fs_plat = on;
1268 if on != self.m.win.recs[iu].fs {
1269 self.uiw_fs_changed(i, on);
1270 }
1271 }
1272
1273 pub(crate) fn uiw_fs_changed(&mut self, i: u32, on: bool) {
1276 let iu = (i as usize) & (WIN_MAX - 1);
1277 let r = &mut self.m.win.recs[iu];
1278 r.fs = on;
1279 r.want &= !UWW_FS;
1280 let id = r.id;
1281 self.cmd_run(UIC_FULLSCREEN, id);
1282 self.invalidate();
1283 }
1284
1285 pub(crate) fn uiw_sync_show(&mut self) {
1288 if !self.m.win.hooks || self.headless {
1289 return;
1290 }
1291 for i in 1..WIN_MAX as u32 {
1292 let iu = i as usize;
1293 let r = &self.m.win.recs[iu];
1294 if r.want & UWW_SHOW == 0 || r.state & UWI_VISIBLE == 0 {
1295 continue;
1296 }
1297 self.m.win.recs[iu].want &= !UWW_SHOW;
1298 self.uwp_show(i, true);
1299 if self.m.win.recs[iu].want & UWW_ACTIVATE != 0 {
1300 self.m.win.recs[iu].want &= !UWW_ACTIVATE;
1301 self.uwp_activate(i);
1302 }
1303 }
1304 self.uiw_enable_sync(2); }
1306
1307 pub(crate) fn win_hooks_set(&mut self, on: bool) {
1310 self.m.win.hooks = on;
1311 }
1312
1313 pub fn sync_hook_set(&mut self, f: Option<fn() -> bool>) {
1316 self.m.win.synchook = f;
1317 }
1318
1319 pub(crate) fn uiw_sync_pending(&mut self) -> bool {
1321 match self.m.win.synchook {
1322 Some(f) => f(),
1323 None => false,
1324 }
1325 }
1326
1327 pub(crate) fn uiw_present(&mut self, n: i32) {
1330 let cur = self.uiw_cur;
1331 let pw = if self.headless {
1332 if !self.gp_scripted() {
1334 return;
1335 }
1336 self.gp_script_pw(cur)
1337 } else if cur == 0 {
1338 0
1339 } else if !self.m.win.hooks {
1340 return;
1341 } else {
1342 self.uiw_pw(cur) };
1344 if pw < 0 {
1345 return;
1346 }
1347 if self.gp_present(cur, pw, n) {
1348 return;
1349 }
1350 let rects = if n < 0 { None } else { Some(&self.drects[..n as usize]) };
1351 plat::win_present(pw, &Ui::frame_of(&self.wp.rt.fb), rects);
1352 self.gp_cpu_done(cur, pw);
1353 }
1354
1355 pub(crate) fn uiw_publish_hits(&mut self) {
1359 if self.headless {
1360 return;
1361 }
1362 let cur = (self.uiw_cur as usize) & (WIN_MAX - 1);
1363 let mut drawable = 0;
1364 for i in 0..WIN_MAX as u32 {
1365 if self.uiw_drawable(i) {
1366 drawable |= 1 << i;
1367 }
1368 }
1369 let c = &self.wp.ctx;
1370 let mut p = PUBLISHED.lock();
1371 p.hits[cur].clear();
1372 p.hits[cur].extend_from_slice(&c.hits[c.hit_cur ^ 1]);
1373 p.zones[cur].clear();
1374 p.zones[cur].extend_from_slice(&c.zones[c.hit_cur ^ 1]);
1375 p.modal[cur] = c.modal_prev;
1376 p.mirror[cur] = if self.rtl { self.wp.rt.fb.w } else { 0 };
1377 p.drawable = drawable;
1378 p.p2u = self.m.win.p2u;
1379 }
1380
1381 fn publish_state(&self) {
1383 if self.headless {
1384 return;
1385 }
1386 let mut drawable = 0;
1387 for i in 0..WIN_MAX as u32 {
1388 if self.uiw_drawable(i) {
1389 drawable |= 1 << i;
1390 }
1391 }
1392 let mut p = PUBLISHED.lock();
1393 p.drawable = drawable;
1394 p.p2u = self.m.win.p2u;
1395 }
1396
1397 pub(crate) fn uiw_input_target(&mut self, ev: &Event) -> i32 {
1406 let w = ev.win as u32;
1407 if w as usize >= WIN_MAX || (w != 0 && !self.uiw_drawable(w)) {
1408 return -1; }
1410 let t = match ev.typ {
1411 plat::E_KEY_DOWN | plat::E_KEY_UP | plat::E_TEXT | plat::E_IME_COMMIT | plat::E_PREEDIT => self.uiw_key_target(w),
1412 plat::E_LEAVE => {
1413 if self.m.win.ptr == w as i32 {
1414 self.m.win.ptr = -1;
1415 }
1416 w
1417 }
1418 plat::E_FOCUS_OUT => w,
1419 _ => {
1420 let last = self.m.win.ptr;
1422 if last != w as i32 {
1423 self.m.win.ptr = w as i32;
1424 if last >= 0 && self.uiw_drawable(last as u32) {
1425 self.uiw_use(last as u32);
1426 let leave = Event { typ: plat::E_LEAVE, btn: 0, mods: ev.mods, win: last as u8, x: -1, y: -1, data: 0 };
1427 self.input_event(&leave);
1428 self.m.win.edges |= 1 << last;
1429 }
1430 }
1431 if ev.typ == plat::E_DOWN {
1432 self.uiw_kfocus_press(w, ev.x, ev.y);
1433 self.uiw_popups_dismiss(w); if self.headless {
1435 self.uiw_click_activate(w, ev.x, ev.y);
1436 }
1437 }
1438 w
1439 }
1440 };
1441 let t = t & (WIN_MAX as u32 - 1);
1442 self.m.win.edges |= 1 << t;
1443 t as i32
1444 }
1445
1446 fn uiw_key_target(&mut self, i: u32) -> u32 {
1448 let mut b = i;
1449 if b != 0 && !self.uiw_drawable(b) {
1450 b = self.m.win.active; }
1452 if (self.m.win.inert >> (b & 31)) & 1 != 0 {
1453 return self.m.win.modal & (WIN_MAX as u32 - 1);
1454 }
1455 let kf = self.m.win.kfocus;
1459 if kf != 0 {
1460 let t = kf - 1;
1461 if self.uiw_borrows(t) && (b == t || b == self.m.win.recs[(t as usize) & (WIN_MAX - 1)].owner) {
1462 self.m.win.fwd |= 1 << (t & 31);
1463 return t & (WIN_MAX as u32 - 1);
1464 }
1465 }
1466 let mut n = WIN_MAX;
1467 loop {
1468 if b == 0 {
1469 break;
1470 }
1471 let r = &self.m.win.recs[(b as usize) & (WIN_MAX - 1)];
1472 if r.flags & WF_TOOL == 0 || r.flags & WF_KEYS != 0 {
1473 break;
1474 }
1475 let owner = r.owner;
1476 if self.uiw_focus_is_text(b) {
1477 break;
1478 }
1479 if self.uiw_borrows(b) {
1481 self.m.win.fwd |= 1 << (b & 31);
1482 break;
1483 }
1484 b = owner;
1485 n -= 1;
1486 if n == 0 {
1487 break;
1488 }
1489 }
1490 b & (WIN_MAX as u32 - 1)
1491 }
1492
1493 pub(crate) fn uiw_keys_window(&self) -> u32 {
1496 let mut b = self.m.win.active & (WIN_MAX as u32 - 1);
1497 if (self.m.win.inert >> b) & 1 != 0 {
1498 return self.m.win.modal & (WIN_MAX as u32 - 1);
1499 }
1500 let kf = self.m.win.kfocus;
1501 if kf != 0 {
1502 let t = kf - 1;
1503 if self.uiw_borrows(t) && (b == t || b == self.m.win.recs[(t as usize) & (WIN_MAX - 1)].owner) {
1504 return t & (WIN_MAX as u32 - 1);
1505 }
1506 }
1507 for _ in 0..WIN_MAX {
1508 if b == 0 {
1509 break;
1510 }
1511 let r = &self.m.win.recs[(b as usize) & (WIN_MAX - 1)];
1512 if r.flags & WF_TOOL == 0 || r.flags & WF_KEYS != 0 || self.uiw_focus_is_text(b) || self.uiw_borrows(b) {
1513 break;
1514 }
1515 b = r.owner;
1516 }
1517 b & (WIN_MAX as u32 - 1)
1518 }
1519
1520 fn uiw_borrows(&self, i: u32) -> bool {
1523 if i == 0 || i as usize >= WIN_MAX || !self.uiw_drawable(i) || (self.m.win.inert >> i) & 1 != 0 {
1524 return false;
1525 }
1526 if self.m.win.recs[i as usize].flags & (WF_TOOL | WF_KEYS) != WF_TOOL {
1527 return false;
1528 }
1529 self.win_focus(i) != 0
1530 }
1531
1532 fn uiw_kfocus_press(&mut self, i: u32, x: i32, y: i32) {
1536 self.m.win.kfocus = 0;
1537 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 {
1539 return;
1540 }
1541 if self.hit_flags_win(i, x, y) & HB_TEXT != 0 {
1542 return; }
1544 self.m.win.kfocus = i + 1;
1545 }
1546
1547 pub(crate) fn uiw_fwd_take(&mut self) {
1551 let cur = self.uiw_cur;
1552 if cur as usize >= WIN_MAX || (self.m.win.fwd >> cur) & 1 == 0 {
1553 return;
1554 }
1555 self.m.win.fwd &= !(1 << cur);
1556 if self.popup_count() != 0 {
1557 return; }
1559 self.m.win.fwd_to = self.m.win.recs[cur as usize].owner & (WIN_MAX as u32 - 1);
1560 let n = FWDQ_MAX - self.m.win.fwdq.len().min(FWDQ_MAX);
1561 let k = self.kb_take_rest(n); self.m.win.fwdq.extend_from_slice(&k);
1563 let n = FWDT_MAX - self.m.win.fwdt.len().min(FWDT_MAX);
1564 let t = self.text_take(n);
1565 self.m.win.fwdt.extend_from_slice(&t);
1566 }
1567
1568 pub(crate) fn uiw_fwd_inject(&mut self) -> bool {
1572 self.m.win.fwd = 0;
1573 if self.m.win.fwdq.is_empty() && self.m.win.fwdt.is_empty() {
1574 return false;
1575 }
1576 let to = self.m.win.fwd_to;
1577 let mut r = false;
1578 if self.uiw_drawable(to) {
1579 self.uiw_use(to);
1580 let q = core::mem::take(&mut self.m.win.fwdq);
1581 self.keys_inject(&q);
1582 let t = core::mem::take(&mut self.m.win.fwdt);
1583 self.text_inject(&t);
1584 self.uiw_use(0);
1585 self.m.win.edges |= 1 << to;
1586 self.repass = true;
1587 r = true;
1588 }
1589 self.m.win.fwdq.clear();
1590 self.m.win.fwdt.clear();
1591 r
1592 }
1593
1594 pub(crate) fn uiw_fwd_arm(&mut self, i: u32) {
1598 if self.uiw_borrows(i) && !self.uiw_focus_is_text(i) {
1599 self.m.win.fwd |= 1 << (i & 31);
1600 }
1601 }
1602
1603 fn uiw_focus_is_text(&self, i: u32) -> bool {
1605 let Some(p) = self.uiw_parts(i) else { return false };
1606 let f = p.ctx.focus;
1607 if f == 0 {
1608 return false;
1609 }
1610 let list = &p.ctx.hits[p.ctx.hit_cur ^ 1];
1611 match list.iter().rev().find(|h| h.id == f) {
1612 Some(h) => h.flags as u32 & HB_TEXT != 0,
1613 None => false,
1614 }
1615 }
1616
1617 fn uiw_click_activate(&mut self, i: u32, x: i32, y: i32) {
1621 if (self.m.win.inert >> (i & 31)) & 1 != 0 {
1622 return;
1623 }
1624 if i != 0 {
1625 let f = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].flags;
1626 if f & (WF_TOOL | WF_NOACTIVATE) != 0 {
1627 if f & WF_NOACTIVATE != 0 || self.hit_flags_win(i, x, y) & HB_TEXT == 0 {
1628 return;
1629 }
1630 }
1631 }
1632 self.uiw_activate(i);
1633 }
1634
1635 pub(crate) fn hit_flags_win(&mut self, i: u32, x: i32, y: i32) -> u32 {
1638 let i = i & (WIN_MAX as u32 - 1);
1639 if !self.uiw_drawable(i) {
1640 return 0;
1641 }
1642 let Some(p) = self.uiw_parts(i) else { return 0 };
1643 let c = &p.ctx;
1644 super::ctx::hit_find_list(&c.hits[c.hit_cur ^ 1], c.modal_prev, x, y).1
1645 }
1646
1647 pub(crate) fn uiw_moved_passes(&mut self) -> bool {
1649 if self.m.win.used == 0 {
1650 if !self.wp.ctx.moved {
1652 return false;
1653 }
1654 let r = self.needs_move_pass();
1655 self.wp.ctx.moved = false;
1656 return r;
1657 }
1658 let mut r = false;
1659 for i in 0..WIN_MAX as u32 {
1660 if !self.uiw_drawable(i) || !self.uiw_parts(i).is_some_and(|p| p.ctx.moved) {
1661 continue;
1662 }
1663 self.uiw_use(i);
1664 r |= self.needs_move_pass();
1665 self.wp.ctx.moved = false;
1666 }
1667 self.uiw_use(0);
1668 r
1669 }
1670
1671 pub(crate) fn uiw_resize(&mut self, app: &mut dyn super::App, i: u32, w: i32, h: i32) {
1673 if i != 0 {
1674 if i as usize >= WIN_MAX || !self.uiw_drawable(i) || w <= 0 || h <= 0 {
1675 return;
1676 }
1677 let iu = i as usize;
1679 let dpi = self.win_dpi(i);
1680 self.uiw_use(i);
1681 let b2 = self.uiw_border() * 2;
1682 let tbh = self.m.win.recs[iu].tbh;
1683 let mut rc = self.m.win.recs[iu].rect.get();
1684 rc.w = px2dip_at(w - b2, dpi);
1685 rc.h = (px2dip_at(h - b2, dpi) - tbh).max(1);
1686 rc.flags |= WRF_CHANGED;
1687 if !self.headless {
1688 rc.flags &= !WRF_MAX;
1689 if self.uiw_plat_state(i) & plat::WST_MAXIMIZED != 0 {
1690 rc.flags |= WRF_MAX;
1691 }
1692 }
1693 self.m.win.recs[iu].rect.set(rc);
1694 self.m.win.recs[iu].applied = rc;
1695 }
1696 self.uiw_use(i);
1697 self.resize(app, w, h);
1698 self.uiw_use(0);
1699 if i == 0 {
1700 self.ws_track(); }
1702 self.uiw_fs_check(i); }
1704
1705 pub(crate) fn uiw_dpi(&mut self, i: u32, dpi: i32) {
1708 if i as usize >= WIN_MAX || !self.uiw_drawable(i) || dpi < 24 {
1709 return;
1710 }
1711 self.uiw_use(i);
1712 self.wp.rt.dpi = dpi;
1713 self.dirty_force_full();
1714 if i == 0 {
1715 self.cmd_run(UIC_DPI, dpi as u32);
1716 } else {
1717 self.m.win.recs[i as usize].applied.w = -1; }
1719 self.uiw_use(0);
1720 self.invalidate();
1721 }
1722
1723 pub(crate) fn uiw_focus_in(&mut self, i: u32) {
1725 if i as usize >= WIN_MAX || !self.uiw_drawable(i) || i == self.m.win.active {
1726 return;
1727 }
1728 self.uiw_activate(i);
1729 }
1730
1731 pub(crate) fn uiw_winpos(&mut self, i: u32, x: i32, y: i32) {
1735 if i as usize >= WIN_MAX {
1736 return;
1737 }
1738 let iu = i as usize;
1739 if self.m.win.recs[iu].state == 0 {
1740 return;
1741 }
1742 self.m.win.recs[iu].sx = x;
1743 self.m.win.recs[iu].sy = y;
1744 let mut rc = self.m.win.recs[iu].rect.get();
1745 if i == 0 {
1746 rc.x = x;
1747 rc.y = y;
1748 rc.flags |= WRF_ABS | WRF_POS;
1749 let a = &mut self.m.win.recs[0].applied;
1750 a.flags = rc.flags;
1751 a.x = x;
1752 a.y = y;
1753 } else {
1754 let (ox, oy) = self.uiw_owner_origin(i);
1756 let odpi = self.win_dpi(self.m.win.recs[iu].owner);
1757 rc.x = px2dip_at(x - ox, odpi);
1758 rc.y = px2dip_at(y - oy, odpi);
1759 rc.flags |= WRF_POS | WRF_CHANGED;
1760 let r = &mut self.m.win.recs[iu];
1761 r.applied.x = rc.x;
1762 r.applied.y = rc.y;
1763 r.applied.flags = rc.flags;
1764 r.state &= !UWI_DEFPOS;
1765 }
1766 self.m.win.recs[iu].rect.set(rc);
1767 if i == 0 {
1768 self.ws_track(); }
1770 self.uiw_follow_owner(i);
1772 }
1773
1774 pub(crate) fn uiw_close_request(&mut self, i: u32) {
1777 if i == 0 || i as usize >= WIN_MAX {
1778 return;
1779 }
1780 let r = &self.m.win.recs[i as usize];
1781 if r.id == 0 || r.flags & WF_NOCLOSE != 0 {
1782 return;
1783 }
1784 let id = r.id;
1785 self.cmd_run(UIC_WINCLOSE, id);
1786 self.invalidate();
1787 }
1788
1789 pub(crate) fn uiw_cmd_done(&mut self, id: u32, arg: u32, r: bool) {
1792 if id != UIC_WINCLOSE || r {
1793 return;
1794 }
1795 let i = self.uiw_index(arg);
1796 if i <= 0 {
1797 return;
1798 }
1799 let rec = &self.m.win.recs[i as usize];
1800 if let Some(o) = &rec.openp {
1801 o.set(0);
1802 }
1803 if rec.state & UWI_VISIBLE != 0 {
1804 self.uiw_hide(i as u32);
1805 }
1806 }
1807
1808 pub fn window_place(&mut self, id: u32, rect: &WinRect) {
1813 let i = self.uiw_index(id);
1814 if i < 0 {
1815 return;
1816 }
1817 let iu = i as usize;
1818 self.m.win.recs[iu].state &= !UWI_DEFPOS;
1819 self.m.win.recs[iu].rect.set(*rect);
1820 if i == 0 {
1821 if !self.headless {
1823 self.m.win.recs[0].want |= UWW_RECT;
1824 } else if rect.w > 0 && rect.h > 0 {
1825 let (w, h) = (self.dp(rect.w), self.dp(rect.h));
1826 self.resize_noapp(w, h);
1829 }
1830 }
1831 self.invalidate();
1832 }
1833
1834 pub fn window_snap(&mut self, id: u32, area: [i32; 4], dist: i32) {
1842 let i = self.uiw_index(id);
1843 if i <= 0 {
1844 return;
1845 }
1846 let iu = i as usize;
1847 let s = [area[0], area[1], area[2], area[3], dist.max(0)];
1848 self.m.win.recs[iu].snap = s;
1849 if self.headless {
1850 return;
1851 }
1852 let owner = self.m.win.recs[iu].owner;
1855 let dpi = self.win_dpi(owner);
1856 let mut p = [0; 6];
1857 if s[4] != 0 && dpi >= 24 {
1858 let tb = if owner != 0 { dip2px_at(self.m.win.recs[(owner as usize) & (WIN_MAX - 1)].tbh, dpi) } else { 0 };
1859 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)];
1860 }
1861 PUBLISHED.lock().snap[iu] = p;
1862 }
1863
1864 pub(crate) fn uiw_snap_dip(&self, i: u32, x: i32, y: i32) -> (i32, i32) {
1867 let iu = (i as usize) & (WIN_MAX - 1);
1868 let r = &self.m.win.recs[iu];
1869 let s = r.snap;
1870 if s[4] == 0 {
1871 return (x, y);
1872 }
1873 let rc = r.rect.get();
1875 let (fb, dpi) = (self.win_fb(i), self.win_dpi(i));
1876 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) };
1877 snap_to(x, y, w, h, [s[0], s[1], s[2], s[3]], s[4])
1878 }
1879
1880 pub fn window_rect(&self, id: u32) -> Option<WinRect> {
1882 let i = self.uiw_index(id);
1883 if i < 0 {
1884 return None;
1885 }
1886 Some(self.m.win.recs[i as usize].rect.get())
1887 }
1888
1889 pub fn window_state(&mut self, id: u32) -> u32 {
1892 let i = self.uiw_index(id);
1893 if i < 0 {
1894 return 0;
1895 }
1896 let i = i as u32;
1897 let st = self.m.win.recs[i as usize].state;
1898 let mut s = 0;
1899 if st & UWI_OPEN != 0 {
1900 s |= UWS_OPEN;
1901 }
1902 if st & (UWI_VISIBLE | UWI_CREATED) != UWI_VISIBLE | UWI_CREATED {
1903 return s;
1904 }
1905 s |= UWS_VISIBLE;
1906 if i == self.m.win.active {
1907 s |= UWS_ACTIVE;
1908 }
1909 if self.uiw_plat_state(i) & plat::WST_MINIMIZED != 0 {
1910 s |= UWS_MINIMIZED;
1911 }
1912 if self.m.win.recs[i as usize].fs {
1913 s |= UWS_FULLSCREEN;
1914 }
1915 s
1916 }
1917
1918 pub fn window_fullscreen(&mut self, id: u32, on: bool) {
1931 let i = self.uiw_index(id);
1932 if i < 0 {
1933 return;
1934 }
1935 let iu = i as usize;
1936 if self.m.win.recs[iu].fs == on {
1937 return;
1938 }
1939 if on && self.uiw_os() && self.uiw_plat_state(i as u32) & plat::WST_CHILD != 0 {
1940 return; }
1942 if cfg!(target_os = "android") {
1943 return;
1944 }
1945 self.m.win.recs[iu].fs = on;
1946 self.m.win.recs[iu].want |= UWW_FS;
1947 self.invalidate();
1948 }
1949
1950 pub fn window_activate(&mut self, id: u32) {
1952 let i = self.uiw_index(id);
1953 if i < 0 || !self.uiw_drawable(i as u32) {
1954 return;
1955 }
1956 self.uiw_activate(i as u32);
1957 }
1958
1959 pub fn window_destroy(&mut self, id: u32) {
1962 let i = self.uiw_index(id);
1963 if i <= 0 {
1964 return;
1965 }
1966 let i = i as u32;
1967 let iu = i as usize;
1968 if self.m.win.recs[iu].state & UWI_BUILDING != 0 || i == self.uiw_cur {
1969 self.warn("ui_window_destroy: the window is being built");
1970 return;
1971 }
1972 if self.m.win.recs[iu].state & UWI_VISIBLE != 0 {
1973 self.uiw_hide(i);
1974 }
1975 if self.m.win.recs[iu].state & UWI_CREATED != 0 {
1976 self.m.win.recs[iu].save = None; if self.m.win.hooks && !self.headless {
1978 self.uwp_destroy(i);
1979 }
1980 }
1981 self.m.win.used &= !(1 << i);
1982 self.m.win.recs[iu] = Rec::default();
1983 if !self.headless {
1984 PUBLISHED.lock().snap[iu] = [0; 6];
1985 }
1986 self.uiw_modal_update();
1987 self.publish_state();
1988 }
1989
1990 pub fn window_current(&self) -> u32 {
1992 self.uiw_rec_id(self.uiw_cur)
1993 }
1994
1995 pub fn window_modal(&self) -> u32 {
1997 let m = self.m.win.modal;
1998 if m == 0 { 0 } else { self.uiw_rec_id(m) }
1999 }
2000
2001 fn resize_noapp(&mut self, w: i32, h: i32) {
2004 if w <= 0 || h <= 0 || (w == self.wp.rt.fb.w && h == self.wp.rt.fb.h) {
2005 return;
2006 }
2007 self.wp.rt.fb.resize(w, h);
2008 self.dirty_force_full();
2009 self.need = true;
2010 }
2011
2012 pub(crate) fn uiw_desk_pos(&self, i: u32) -> (i32, i32) {
2017 let (mut x, mut y) = (0, 0);
2018 let mut b = i;
2019 for _ in 0..WIN_MAX {
2020 if b == 0 {
2021 break;
2022 }
2023 let r = &self.m.win.recs[(b as usize) & (WIN_MAX - 1)];
2024 let rc = r.rect.get();
2025 x += rc.x;
2026 y += rc.y;
2027 b = r.owner;
2028 if b == 0 {
2029 break;
2030 }
2031 y += self.m.win.recs[(b as usize) & (WIN_MAX - 1)].tbh;
2033 }
2034 (x, y)
2035 }
2036
2037 pub(crate) fn uiw_user_rect(&mut self, i: u32, x: i32, y: i32, w: i32, h: i32) {
2040 if i == 0 || i as usize >= WIN_MAX {
2041 return;
2042 }
2043 let iu = i as usize;
2044 let mut rc = self.m.win.recs[iu].rect.get();
2045 if x != i32::MIN {
2046 rc.x = x;
2047 rc.y = y;
2048 rc.flags |= WRF_POS | WRF_CHANGED;
2049 self.m.win.recs[iu].state &= !UWI_DEFPOS;
2050 }
2051 if w > 0 {
2052 rc.w = w;
2053 if h > 0 {
2054 rc.h = h;
2055 rc.flags |= WRF_CHANGED;
2056 }
2057 }
2058 self.m.win.recs[iu].rect.set(rc);
2059 self.m.win.recs[iu].want |= UWW_RECT;
2060 self.invalidate();
2061 }
2062
2063 pub fn window_pw(&self, id: u32) -> (i32, i32) {
2073 let i = self.uiw_index(id);
2074 if i < 0 {
2075 return (i, -1);
2076 }
2077 (i, self.uiw_pw(i as u32))
2078 }
2079
2080 pub(crate) fn uiw_pw(&self, i: u32) -> i32 {
2082 let p = self.m.win.u2p[(i as usize) & (WIN_MAX - 1)];
2083 if p == 0xFF { -1 } else { p as i32 }
2084 }
2085
2086 pub(crate) fn uiw_from_pw(&self, pw: i32) -> i32 {
2088 if !(0..WIN_MAX as i32).contains(&pw) {
2089 return -1;
2090 }
2091 let u = self.m.win.p2u[pw as usize];
2092 if u == 0xFF { -1 } else { u as i32 }
2093 }
2094
2095 fn uiw_os(&self) -> bool {
2097 !self.headless && self.m.win.hooks
2098 }
2099
2100 pub(crate) fn uiw_plat_state(&self, i: u32) -> u32 {
2102 if !self.uiw_os() {
2103 return 0;
2104 }
2105 let pw = self.uiw_pw(i);
2106 if pw < 0 { 0 } else { plat::win_state(pw) }
2107 }
2108
2109 pub(crate) fn uiw_app_active(&self) -> bool {
2111 if self.headless {
2112 return true;
2113 }
2114 plat::win_state(0) & plat::WST_ACTIVE != 0
2115 }
2116
2117 fn uiw_sysframe_ok(&self) -> bool {
2120 if !self.uiw_os() {
2121 return true;
2122 }
2123 plat::win_state(0) & plat::WST_CSD == 0
2124 }
2125
2126 fn uiw_owner_origin(&mut self, i: u32) -> (i32, i32) {
2132 let owner = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].owner;
2133 let ou = (owner as usize) & (WIN_MAX - 1);
2134 let (mut x, mut y) = (self.m.win.recs[ou].sx, self.m.win.recs[ou].sy);
2135 self.m.win.origin_ok = true;
2136 if self.uiw_os() {
2137 self.m.win.origin_ok = false;
2138 let own_pw = self.uiw_pw(i);
2139 let pw = self.uiw_pw(owner);
2140 if own_pw >= 0 && plat::win_state(own_pw) & plat::WST_CHILD != 0 {
2141 self.m.win.origin_ok = true;
2142 x = 0;
2143 y = 0;
2144 } else if pw >= 0 {
2145 if let Some(r) = plat::win_get_rect(pw) {
2146 self.m.win.origin_ok = true;
2147 x = r[0];
2148 y = r[1];
2149 }
2150 }
2151 }
2152 if owner != 0 {
2153 let dpi = self.win_dpi(owner);
2155 y += dip2px_at(self.m.win.recs[ou].tbh, dpi);
2156 }
2157 (x, y)
2158 }
2159
2160 fn uiw_attached(&self, i: u32) -> bool {
2164 let r = &self.m.win.recs[(i as usize) & (WIN_MAX - 1)];
2165 let rc = r.rect.get();
2166 let owner = r.owner;
2167 let odpi = self.win_dpi(owner);
2168 if odpi < 24 {
2169 return false;
2170 }
2171 let fb = self.win_fb(owner);
2172 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;
2174 let cx = (rc.w >> 1) + rc.x; if cx < 0 || cx >= ow {
2176 return false;
2177 }
2178 let cy = ((rc.h + r.tbh) >> 1) + rc.y;
2179 cy >= 0 && cy < oh
2180 }
2181
2182 fn uiw_follow_owner(&mut self, i: u32) {
2187 if !self.uiw_os() || self.m.win.follow as usize >= WIN_MAX {
2188 return; }
2190 self.m.win.follow += 1;
2191 for j in 1..WIN_MAX as u32 {
2192 if j == i {
2193 continue;
2194 }
2195 let r = &self.m.win.recs[j as usize];
2196 if r.id == 0 || r.owner != i || !self.uiw_drawable(j) {
2197 continue;
2198 }
2199 if (self.m.win.placed >> j) & 1 == 0 || self.uiw_attached(j) {
2200 self.m.win.recs[j as usize].want |= UWW_RECT;
2204 self.invalidate();
2205 continue;
2206 }
2207 let pw = self.uiw_pw(j);
2208 if pw < 0 {
2209 continue;
2210 }
2211 if let Some(r) = plat::win_get_rect(pw) {
2212 self.uiw_winpos(j, r[0], r[1]);
2213 }
2214 }
2215 self.m.win.follow -= 1;
2216 }
2217
2218 fn uiw_enable_sync(&mut self, phase: u32) {
2222 if !self.m.win.hooks {
2223 return;
2224 }
2225 for i in 0..WIN_MAX as u32 {
2226 if self.uiw_pw(i) < 0 {
2227 continue;
2228 }
2229 let want = (self.m.win.inert >> i) & 1 == 0; let now = (self.m.win.disabled >> i) & 1 == 0;
2231 if want == now {
2232 continue;
2233 }
2234 if phase == 1 {
2235 if !want {
2236 continue; }
2238 self.m.win.disabled &= !(1 << i);
2239 } else {
2240 if want {
2241 continue; }
2243 self.m.win.disabled |= 1 << i;
2244 }
2245 self.uwp_enable(i, want);
2246 }
2247 }
2248
2249 fn uwp_create(&mut self, i: u32, flags: u32, owner: u32) -> bool {
2254 let i = i & (WIN_MAX as u32 - 1);
2255 let opw = self.uiw_pw(owner);
2256 if opw < 0 {
2257 return false; }
2259 let dpi = self.win_dpi(i);
2260 let fb = self.win_fb(i);
2261 let (w, h) = (px2dip_at(fb.w, dpi), px2dip_at(fb.h, dpi));
2262 let title = self.m.win.recs[i as usize].title.clone();
2263 let pw = plat::win_create(&title, w, h, flags & plat::PWF_MASK, opw, plat::PW_DEFAULT, plat::PW_DEFAULT);
2264 if pw < 0 || pw as usize >= WIN_MAX {
2265 return false;
2266 }
2267 self.m.win.u2p[i as usize] = pw as u8;
2268 self.m.win.p2u[pw as usize] = i as u8;
2269 self.m.win.disabled &= !(1 << i);
2270 if flags & WF_RESIZABLE != 0 {
2271 let tbh = self.m.win.recs[i as usize].tbh;
2272 plat::win_set_min_size(pw, 120, tbh + 48);
2273 }
2274 self.publish_state();
2275 let d = plat::win_dpi(pw);
2277 if d != dpi {
2278 self.uiw_dpi(i, d);
2279 }
2280 true
2281 }
2282
2283 fn uwp_destroy(&mut self, i: u32) {
2285 let i = i & (WIN_MAX as u32 - 1);
2286 let pw = self.uiw_pw(i);
2287 if pw < 0 {
2288 return;
2289 }
2290 self.gp_window_gone(i); let pw = pw as usize & (WIN_MAX - 1);
2292 self.m.win.p2u[pw] = 0xFF;
2293 self.m.win.u2p[i as usize] = 0xFF;
2294 self.m.win.disabled &= !(1 << i);
2295 self.m.win.placed &= !(1 << i);
2296 self.publish_state();
2297 plat::win_destroy(pw as i32);
2298 }
2299
2300 fn uwp_show(&mut self, i: u32, show: bool) {
2302 let pw = self.uiw_pw(i);
2303 if pw < 0 {
2304 return;
2305 }
2306 self.gp_window_show(i, show);
2307 let mut mode = plat::PWS_HIDE;
2308 if show {
2309 mode = plat::PWS_SHOW;
2310 if self.m.win.recs[(i as usize) & (WIN_MAX - 1)].flags & (WF_TOOL | WF_NOACTIVATE) != 0 {
2311 mode = plat::PWS_SHOWNA;
2312 }
2313 }
2314 plat::win_show(pw, mode);
2315 }
2316
2317 fn uwp_rect(&mut self, i: u32, rc: &WinRect) {
2321 let pw = self.uiw_pw(i);
2322 if pw < 0 {
2323 return;
2324 }
2325 if i != 0 {
2326 let (fw, fh) = {
2327 let fb = self.win_fb(i);
2328 (fb.w, fb.h)
2329 };
2330 let (mut x, mut y) = (plat::PW_KEEP, plat::PW_KEEP);
2331 if rc.flags & WRF_POS != 0 {
2332 let owner = self.m.win.recs[(i as usize) & (WIN_MAX - 1)].owner;
2333 let odpi = self.win_dpi(owner);
2334 let (ox, oy) = self.uiw_owner_origin(i);
2335 if self.m.win.origin_ok {
2336 self.m.win.placed |= 1 << i;
2337 x = ox + dip2px_at(rc.x, odpi);
2338 y = oy + dip2px_at(rc.y, odpi);
2339 }
2340 }
2342 plat::win_set_rect(pw, x, y, fw, fh);
2343 return;
2344 }
2345 let dpi = self.win_dpi(0);
2346 let st = plat::win_state(pw);
2347 if rc.flags & WRF_MAX != 0 {
2348 if st & plat::WST_MAXIMIZED == 0 {
2349 plat::win_cmd(pw, plat::WCMD_MAXIMIZE);
2350 }
2351 return;
2352 }
2353 if st & plat::WST_MAXIMIZED != 0 {
2354 plat::win_cmd(pw, plat::WCMD_RESTORE);
2355 }
2356 let (mut x, mut y) = (plat::PW_KEEP, plat::PW_KEEP);
2357 if rc.flags & WRF_POS != 0 {
2358 x = rc.x;
2359 y = rc.y;
2360 }
2361 let w = if rc.w > 0 { dip2px_at(rc.w, dpi) } else { plat::PW_KEEP };
2362 let h = if rc.h > 0 { dip2px_at(rc.h, dpi) } else { plat::PW_KEEP };
2363 plat::win_set_rect(pw, x, y, w, h);
2364 if w == plat::PW_KEEP && h == plat::PW_KEEP {
2367 return;
2368 }
2369 let (cw, ch) = plat::win_size(pw);
2370 if cw <= 0 || ch <= 0 {
2371 return;
2372 }
2373 self.resize_noapp(cw, ch); }
2375
2376 fn uwp_title(&mut self, i: u32, s: &str) {
2378 let pw = self.uiw_pw(i);
2379 if pw >= 0 {
2380 plat::win_set_title(pw, s);
2381 }
2382 }
2383
2384 fn uwp_activate(&mut self, i: u32) {
2386 let pw = self.uiw_pw(i);
2387 if pw >= 0 {
2388 plat::win_activate(pw);
2389 }
2390 }
2391
2392 fn uwp_enable(&mut self, i: u32, on: bool) {
2394 let pw = self.uiw_pw(i);
2395 if pw >= 0 {
2396 plat::win_enable(pw, on);
2397 }
2398 }
2399
2400 pub(crate) fn uiw_popup_area(&mut self) -> Option<([i32; 4], bool)> {
2420 let cur = self.uiw_cur;
2421 if cur as usize >= WIN_MAX {
2422 return None;
2423 }
2424 let mut a = [0i32; 4];
2425 let mut known = true;
2426 if self.uiw_os() {
2427 let pw = self.uiw_pw(cur);
2429 if pw < 0 {
2430 return None;
2431 }
2432 match (plat::win_get_rect(pw), plat::win_work_area(pw)) {
2433 (Some(wr), Some(wa)) => {
2434 a[0] = wa[0] - wr[0];
2435 a[2] = a[0] + wa[2];
2436 a[1] = wa[1] - wr[1];
2437 a[3] = a[1] + wa[3];
2438 }
2439 _ => {
2440 a = [-4096, -4096, self.wp.rt.fb.w + 4096, self.wp.rt.fb.h + 4096];
2442 known = false;
2443 }
2444 }
2445 } else {
2446 let scr = self.m.win.screen;
2448 let [sx, sy, sw, sh] = if scr[2] > 0 && scr[3] > 0 {
2449 scr
2450 } else if cur == 0 {
2451 return None;
2452 } else {
2453 let mdpi = self.win_dpi(0);
2454 let fb = self.win_fb(0);
2455 [0, 0, px2dip_at(fb.w, mdpi), px2dip_at(fb.h, mdpi)]
2456 };
2457 let (wx, wy) = self.uiw_desk_pos(cur); let dpi = self.wp.rt.dpi;
2459 a[0] = dip2px_at(sx - wx, dpi);
2460 a[1] = dip2px_at(sy - wy, dpi);
2461 a[2] = dip2px_at(sx + sw - wx, dpi);
2462 a[3] = dip2px_at(sy + sh - wy, dpi);
2463 }
2464 a[0] = a[0].min(0);
2466 a[1] = a[1].min(0);
2467 a[2] = a[2].max(self.wp.rt.fb.w);
2468 a[3] = a[3].max(self.wp.rt.fb.h);
2469 Some((a, known))
2470 }
2471
2472 pub(crate) fn uiw_popup_screen_h(&mut self) -> Option<i32> {
2477 if !self.uiw_os() || self.uiw_cur as usize >= WIN_MAX {
2478 return None;
2479 }
2480 let pw = self.uiw_pw(self.uiw_cur);
2481 if pw < 0 || (plat::win_get_rect(pw).is_some() && plat::win_work_area(pw).is_some()) {
2482 return None;
2483 }
2484 let h = plat::monitors().iter().map(|m| m.work[3]).filter(|&h| h > 0).min()?;
2486 Some(dip2px_at((h - POPUP_PANEL_ROOM).max(h / 2), self.wp.rt.dpi).max(self.wp.rt.fb.h))
2487 }
2488
2489 pub(crate) fn uiw_popup_nudge(&self, item: u32, key: [i32; 2]) -> (i32, i32) {
2494 if !self.uiw_os() {
2495 return (0, 0);
2496 }
2497 let own = self.uiw_cur + 1;
2498 let Some(k) = (0..EXT_MAX).find(|&k| {
2499 let e = &self.m.win.ex[k];
2500 e.owner == own && e.item == item && e.shown && e.key == key
2501 }) else {
2502 return (0, 0);
2503 };
2504 let nat = self.m.win.ex[k].nat;
2505 match plat::popup_placed(k as u32) {
2506 Some(p) => (p[0] - nat[0], p[1] - nat[1]),
2507 None => (0, 0),
2508 }
2509 }
2510
2511 pub(crate) fn uiw_popups_render(&mut self, i: u32) {
2518 if i as usize >= WIN_MAX {
2519 return;
2520 }
2521 let all = i == 0 && (1..WIN_MAX as u32).any(|j| self.uiw_drawable(j));
2524 let own = i + 1;
2525 for e in self.m.win.ex.iter_mut() {
2527 if e.owner == own {
2528 e.used = false;
2529 }
2530 }
2531 for item in 0..POPUP_ITEMS {
2532 let rect = if all { self.popup_rect(item) } else { self.popup_ext(item) };
2533 let Some(rect) = rect else { continue };
2534 let k = match (0..EXT_MAX).find(|&k| self.m.win.ex[k].owner == own && self.m.win.ex[k].item == item) {
2536 Some(k) => k,
2537 None => match (0..EXT_MAX).find(|&k| self.m.win.ex[k].owner == 0) {
2538 Some(k) => {
2539 let e = &mut self.m.win.ex[k];
2540 e.owner = own;
2541 e.item = item;
2542 e.shown = false;
2543 e.rect[2] = 0;
2544 k
2545 }
2546 None => {
2547 self.limit_hit(super::ctx::LIM_POPUP_SLOTS); continue;
2549 }
2550 },
2551 };
2552 let mut changed = self.wp.rt.present_n != 0;
2554 {
2555 let e = &mut self.m.win.ex[k];
2556 e.used = true;
2557 if e.rect != rect {
2558 changed = true;
2559 e.rect = rect;
2560 }
2561 if !e.shown {
2562 changed = true;
2563 }
2564 }
2565 if !changed {
2566 continue;
2567 }
2568 let mut sf = core::mem::take(&mut self.m.win.ex[k].sf);
2570 if sf.w != rect[2] || sf.h != rect[3] || sf.px.is_empty() {
2571 sf = Surface::new(rect[2], rect[3], FMT_XRGB);
2572 if sf.px.is_empty() {
2573 self.m.win.ex[k].owner = 0;
2574 continue;
2575 }
2576 }
2577 self.dc.begin(&sf);
2578 let c = self.color(T_FLYOUT) | 0xFF00_0000;
2579 self.dc.set_color(c);
2580 self.dc.fill(&mut sf, 0, 0, rect[2], rect[3]);
2581 self.render_popup(&mut sf, -rect[0], -rect[1]);
2582 self.dc.end();
2583 if self.uiw_os() {
2584 let pw = self.uiw_pw(i);
2585 if pw >= 0 {
2586 let (anchor, kind, nat, key) =
2588 self.popup_place(item).unwrap_or(([rect[0], rect[1], 1, 1], plat::PA_FREE, [rect[0], rect[1]], [rect[0], rect[1]]));
2589 plat::popup_anchor(k as u32, anchor, kind, nat);
2590 plat::popup(k as u32, pw, Some(rect), Some(&Ui::frame_of(&sf)));
2591 let e = &mut self.m.win.ex[k];
2592 e.shown = true;
2593 e.nat = nat;
2594 e.key = key;
2595 }
2596 }
2597 self.m.win.ex[k].sf = sf;
2598 }
2599 self.uiw_popups_drop_ex(i, true);
2600 }
2601
2602 pub(crate) fn uiw_popups_drop(&mut self, i: u32) {
2604 self.uiw_popups_drop_ex(i, false);
2605 }
2606
2607 fn uiw_popups_drop_ex(&mut self, i: u32, unused_only: bool) {
2610 let own = i + 1;
2611 for k in 0..EXT_MAX {
2612 let e = &self.m.win.ex[k];
2613 if e.owner != own || (unused_only && e.used) {
2614 continue;
2615 }
2616 if e.shown && self.uiw_os() {
2617 plat::popup(k as u32, 0, None, None); }
2619 let e = &mut self.m.win.ex[k];
2620 e.sf = Surface::default();
2621 e.owner = 0;
2622 e.shown = false;
2623 e.used = false;
2624 }
2625 }
2626
2627 pub(crate) fn uiw_popups_blit(&mut self, sf: &mut Surface, i: u32, x0: i32, y0: i32, dpi: i32) {
2630 let own = i + 1;
2631 let (wx, wy) = self.uiw_desk_pos(i);
2632 let wdpi = self.win_dpi(i);
2633 for k in 0..EXT_MAX {
2634 let e = &self.m.win.ex[k];
2635 if e.owner != own || !e.used || e.sf.px.is_empty() {
2636 continue;
2637 }
2638 let x = dip2px_at(px2dip_at(e.rect[0], wdpi) + wx - x0, dpi);
2639 let y = dip2px_at(px2dip_at(e.rect[1], wdpi) + wy - y0, dpi);
2640 blit_copy(sf, &e.sf, x, y);
2641 }
2642 }
2643
2644 pub(crate) fn uiw_popups_dismiss(&mut self, i: u32) {
2647 let mut swapped = false;
2648 for j in 0..WIN_MAX as u32 {
2649 if j == i || (j != 0 && !self.uiw_drawable(j)) {
2650 continue;
2651 }
2652 self.uiw_use(j);
2653 swapped = true;
2654 if self.popup_count() != 0 {
2655 self.popup_close();
2656 self.invalidate();
2657 }
2658 }
2659 if swapped {
2660 self.uiw_use(0);
2661 }
2662 }
2663}