1use alloc::vec::Vec;
35
36use super::consts::*;
37use super::ctx::Hit;
38use super::keys::*;
39use super::Ui;
40
41const MEM_MAX: usize = 64; const GRIP_STEP: i32 = 8; const MOD3: u32 = MOD_SHIFT | MOD_CTRL | MOD_ALT;
44
45#[derive(Default)]
48pub(crate) struct W {
49 groups: Vec<u32>,
50 panes: Vec<u32>,
51 next: u32,
53 notab: u32,
55 auto_addr: usize,
56 auto_serial: u32,
57 auto_seen: u64,
58 gmem: Vec<(u32, u32)>,
59 pmem: Vec<(u32, u32)>,
60 anchor: [u32; 3],
62 pub(crate) autofocus: bool,
65 pub(crate) soft: u32,
66 split_ret: u32,
68}
69
70impl W {
71 pub(crate) fn gmem(&self) -> &[(u32, u32)] {
73 &self.gmem
74 }
75
76 pub(crate) fn pass_begin(&mut self) {
78 self.groups.clear();
79 self.panes.clear();
80 self.next = 0;
81 self.notab = 0;
82 self.auto_addr = 0;
83 self.auto_serial = 0;
84 self.auto_seen = 0;
85 }
86
87 pub(crate) fn hit_keys(&mut self, hb: u32) -> (u32, u32, u32) {
89 let pane = self.panes.last().copied().unwrap_or(0);
90 if hb & HB_FOCUS == 0 {
91 return (0, pane, 0);
92 }
93 let g = if self.next != 0 {
94 core::mem::take(&mut self.next)
95 } else if hb & HB_TEXT != 0 {
96 0
97 } else {
98 self.groups.last().copied().unwrap_or(0)
99 };
100 (g, pane, if self.notab != 0 { HB_NOTAB } else { 0 })
101 }
102}
103
104#[derive(Default)]
106pub(crate) struct S {
107 pub(crate) ctx: u32,
109 ctx_set: u32,
111 ctx_frame: u32,
112 ctx_rect: [i32; 4],
113 moved: u32,
115 pub(crate) tool: bool,
117 pub(crate) toggle: bool,
119}
120
121fn mem_get(m: &[(u32, u32)], k: u32) -> u32 {
122 m.iter().find(|e| e.0 == k).map_or(0, |e| e.1)
123}
124
125fn mem_put(m: &mut Vec<(u32, u32)>, k: u32, v: u32) {
126 if let Some(i) = m.iter().position(|e| e.0 == k) {
127 if m[i].1 == v {
128 return;
129 }
130 m.remove(i);
131 }
132 if m.len() >= MEM_MAX {
133 m.remove(0);
134 }
135 m.push((k, v));
136}
137
138fn focusable(h: &Hit) -> bool {
140 h.flags as u32 & (HB_FOCUS | HB_DISABLED) == HB_FOCUS
141}
142
143pub(crate) fn stops(list: &[Hit], focus: u32, gmem: &[(u32, u32)]) -> (Vec<usize>, i32) {
147 let tab = |h: &Hit| focusable(h) && h.flags as u32 & HB_NOTAB == 0 && !h.continuation;
148 let top = list.iter().filter(|h| tab(h)).map(|h| h.layer as i32).max().unwrap_or(-1);
149 let mut out = Vec::new();
150 if top < 0 {
151 return (out, top);
152 }
153 let cand = |h: &Hit| tab(h) && h.layer as i32 == top;
154 let mut gs: Vec<(u32, usize, u8)> = Vec::new();
156 for (i, h) in list.iter().enumerate() {
157 if !cand(h) || h.group == 0 {
158 continue;
159 }
160 let rank = if focus != 0 && h.id == focus {
161 0
162 } else if h.flags as u32 & HB_CURRENT != 0 {
163 1
164 } else if mem_get(gmem, h.group) == h.id {
165 2
166 } else {
167 3
168 };
169 match gs.iter_mut().find(|e| e.0 == h.group) {
170 Some(e) => {
171 if rank < e.2 {
172 e.1 = i;
173 e.2 = rank;
174 }
175 }
176 None => gs.push((h.group, i, rank)),
177 }
178 }
179 for (i, h) in list.iter().enumerate() {
180 if cand(h) && (h.group == 0 || gs.iter().any(|e| e.0 == h.group && e.1 == i)) {
181 out.push(i);
182 }
183 }
184 let mut first: Vec<(u32, usize)> = Vec::new();
187 for (k, &i) in out.iter().enumerate() {
188 let p = list[i].pane;
189 if p != 0 && !first.iter().any(|e| e.0 == p) {
190 first.push((p, k));
191 }
192 }
193 if !first.is_empty() {
194 let mut keyed: Vec<(usize, usize, usize)> = out
195 .iter()
196 .enumerate()
197 .map(|(k, &i)| {
198 let p = list[i].pane;
199 (if p == 0 { k } else { first.iter().find(|e| e.0 == p).map_or(k, |e| e.1) }, k, i)
200 })
201 .collect();
202 keyed.sort_unstable();
203 out = keyed.into_iter().map(|e| e.2).collect();
204 }
205 (out, top)
206}
207
208fn span_gap(a0: i32, a1: i32, b0: i32, b1: i32) -> i32 {
210 if b1 <= a0 {
211 a0 - b1
212 } else if b0 >= a1 {
213 b0 - a1
214 } else {
215 0
216 }
217}
218
219fn nearest(ms: &[(u32, [i32; 4])], cur: usize, vk: u32) -> Option<usize> {
221 let r = ms[cur].1;
222 let (cx, cy) = ((r[0] + r[2]) / 2, (r[1] + r[3]) / 2);
223 let mut best: Option<(i64, usize)> = None;
224 for (i, m) in ms.iter().enumerate() {
225 if i == cur {
226 continue;
227 }
228 let q = m.1;
229 let (qx, qy) = ((q[0] + q[2]) / 2, (q[1] + q[3]) / 2);
230 let (along, gap) = match vk {
231 VK_LEFT => (cx - qx, span_gap(r[1], r[3], q[1], q[3])),
232 VK_RIGHT => (qx - cx, span_gap(r[1], r[3], q[1], q[3])),
233 VK_UP => (cy - qy, span_gap(r[0], r[2], q[0], q[2])),
234 _ => (qy - cy, span_gap(r[0], r[2], q[0], q[2])),
235 };
236 if along <= 0 {
237 continue;
238 }
239 let score = along as i64 + gap as i64 * 4;
240 if best.is_none_or(|b| score < b.0) {
241 best = Some((score, i));
242 }
243 }
244 best.map(|b| b.1)
245}
246
247enum PaneMove {
249 None,
250 Focus(u32),
251 Window(bool),
252}
253
254impl Ui {
255 pub fn focus_group_begin(&mut self, id: u32) {
260 let k = if id != 0 { id } else { self.box_id().wrapping_mul(0x9E37_79B1) | 1 };
261 self.wp.ctx.kb.groups.push(k);
262 }
263
264 pub fn focus_group_end(&mut self) {
266 self.wp.ctx.kb.groups.pop();
267 }
268
269 pub fn focus_pane_begin(&mut self, id: u32) {
271 self.wp.ctx.kb.panes.push(id);
272 }
273
274 pub fn focus_pane_end(&mut self) {
276 self.wp.ctx.kb.panes.pop();
277 }
278
279 pub(crate) fn kb_auto_group(&mut self, addr: usize, mine: i32) {
285 let k = &mut self.wp.ctx.kb;
286 if !k.groups.is_empty() {
287 return;
288 }
289 let bit = 1u64 << (mine as u32 & 63);
290 if addr != k.auto_addr || k.auto_seen & bit != 0 {
291 k.auto_addr = addr;
292 k.auto_serial = k.auto_serial.wrapping_add(1);
293 k.auto_seen = 0;
294 }
295 k.auto_seen |= bit;
296 let h = (addr as u64).wrapping_mul(0x9E37_79B9_7F4A_7C15) ^ (k.auto_serial as u64).wrapping_mul(0xC2B2_AE3D_27D4_EB4F);
297 k.next = ((h >> 32) as u32) | 0x8000_0001;
298 }
299
300 pub(crate) fn kb_box_group(&mut self, salt: u32) {
303 if !self.wp.ctx.kb.groups.is_empty() {
304 return;
305 }
306 let b = self.box_id();
307 self.wp.ctx.kb.next = (b.wrapping_mul(0x9E37_79B1) ^ salt) | 0x8000_0001;
308 }
309
310 pub(crate) fn kb_chord(&mut self, vk: u32, mods: u32) -> bool {
313 let q = &mut self.wp.ctx.keyq;
314 match q.iter().position(|&k| (k as i32) >= 0 && k & 0xFFFF == vk && (k >> 16) & MOD3 == mods) {
315 Some(i) => {
316 q[i] |= 0x8000_0000;
317 true
318 }
319 None => false,
320 }
321 }
322
323 pub fn group_arrived(&mut self, id: u32) -> bool {
327 self.kb_moved(id)
328 }
329
330 pub(crate) fn kb_moved(&mut self, id: u32) -> bool {
332 if id != 0 && self.m.kbnav.moved == id {
333 self.m.kbnav.moved = 0;
334 return true;
335 }
336 false
337 }
338
339 pub(crate) fn kb_notab(&mut self, on: bool) {
341 let k = &mut self.wp.ctx.kb;
342 if on {
343 k.notab += 1;
344 } else if k.notab > 0 {
345 k.notab -= 1;
346 }
347 }
348
349 pub(crate) fn kb_ctx_take(&mut self) -> u32 {
351 let k = &mut self.m.kbnav;
352 k.ctx = 0;
353 k.ctx_frame = self.frame;
354 k.ctx_rect = self.wp.ctx.last_rect;
355 EV_RCLICK
356 }
357
358 pub(crate) fn kb_ctx_rect(&self) -> Option<[i32; 4]> {
361 let k = &self.m.kbnav;
362 if k.ctx_frame != 0 && k.ctx_frame == self.frame { Some(k.ctx_rect) } else { None }
363 }
364
365 pub(crate) fn kb_ctx_redirect(&mut self, from: u32, to: u32) {
368 if self.m.kbnav.ctx == from && from != 0 {
369 self.m.kbnav.ctx = to;
370 }
371 }
372
373 pub fn splitter_keys(&mut self, ev: u32, along_x: bool) -> i32 {
378 self.kb_grip(ev, along_x)
379 }
380
381 pub(crate) fn kb_grip(&mut self, ev: u32, along_x: bool) -> i32 {
383 if ev & EV_FOCUS == 0 {
384 return 0;
385 }
386 let (dec, inc) = if along_x { (VK_LEFT, VK_RIGHT) } else { (VK_UP, VK_DOWN) };
387 let step = if self.mods & MOD_SHIFT != 0 { 1 } else { GRIP_STEP };
388 let mut d = 0;
389 if self.key(dec) {
390 d -= step;
391 }
392 if self.key(inc) {
393 d += step;
394 }
395 if self.key(VK_HOME) {
396 d = i32::MIN / 2;
397 }
398 if self.key(VK_END) {
399 d = i32::MAX / 2;
400 }
401 if self.key(VK_RETURN) || self.key(VK_ESCAPE) {
402 self.kb_split_return();
403 } else if d != 0 {
404 self.wp.ctx.focus_visible = true;
405 }
406 d
407 }
408
409 pub(crate) fn kb_keeps(&self, k: u32) -> bool {
412 let vk = k & 0xFFFF;
413 let m = (k >> 16) & MOD3;
414 match vk {
415 VK_TAB => m & (MOD_CTRL | MOD_ALT) == 0,
416 VK_F6 => m & MOD_ALT == 0 && self.accel_find(VK_F6, m).is_none(),
417 VK_F8 => m & (MOD_CTRL | MOD_ALT) == 0 && self.accel_find(VK_F8, m).is_none() && !self.kb_splitters().is_empty(),
418 VK_APPS => self.wp.ctx.focus != 0,
419 VK_F10 => m == MOD_SHIFT && self.wp.ctx.focus != 0,
420 VK_ESCAPE => m == 0 && self.kb_tool_here(),
421 VK_LEFT | VK_RIGHT | VK_UP | VK_DOWN | VK_HOME | VK_END => m == 0 && self.kb_focus_group() != 0,
422 _ => false,
423 }
424 }
425
426 pub(crate) fn kb_take_rest(&mut self, cap: usize) -> Vec<u32> {
429 let keep: Vec<bool> = self.wp.ctx.keyq.iter().map(|&k| (k as i32) < 0 || self.kb_keeps(k)).collect();
430 let mut out = Vec::new();
431 for (i, k) in self.wp.ctx.keyq.iter_mut().enumerate() {
432 if keep[i] {
433 continue;
434 }
435 if out.len() >= cap {
436 break;
437 }
438 out.push(*k);
439 *k |= 0x8000_0000;
440 }
441 out
442 }
443
444 pub(crate) fn kb_nav(&mut self) {
449 if self.m.kbnav.ctx != 0 && self.frame.wrapping_sub(self.m.kbnav.ctx_set) > 2 {
450 self.m.kbnav.ctx = 0;
451 }
452 self.kb_autofocus();
453 let n = self.wp.ctx.keyq.len();
454 for qi in 0..n {
455 let k = self.wp.ctx.keyq[qi];
456 if (k as i32) < 0 {
457 continue;
458 }
459 if self.kb_key(k) {
460 if let Some(e) = self.wp.ctx.keyq.get_mut(qi) {
461 *e |= 0x8000_0000;
462 }
463 break;
464 }
465 }
466 self.kb_remember();
467 }
468
469 fn kb_key(&mut self, k: u32) -> bool {
471 let vk = k & 0xFFFF;
472 let m = (k >> 16) & MOD3;
473 let shift = m & MOD_SHIFT != 0;
474 match vk {
475 VK_TAB if m & (MOD_CTRL | MOD_ALT) == 0 => {
476 self.focus_step(shift);
477 true
478 }
479 VK_LEFT | VK_RIGHT | VK_UP | VK_DOWN | VK_HOME | VK_END if m == 0 => self.kb_group_move(vk),
480 VK_F6 if m & MOD_ALT == 0 && self.accel_find(VK_F6, m).is_none() => {
481 if m & MOD_CTRL != 0 {
482 self.kb_window_switch(shift);
483 } else {
484 self.kb_pane_switch(shift);
485 }
486 true
487 }
488 VK_F8 if m & (MOD_CTRL | MOD_ALT) == 0 && self.accel_find(VK_F8, m).is_none() => self.kb_splitter_step(shift),
489 VK_APPS => self.kb_ctx_request(),
490 VK_F10 if m == MOD_SHIFT => self.kb_ctx_request(),
491 VK_ESCAPE if m == 0 => self.kb_escape(),
492 _ => false,
493 }
494 }
495
496 fn kb_autofocus(&mut self) {
498 if !self.wp.ctx.kb.autofocus {
499 return;
500 }
501 self.wp.ctx.kb.autofocus = false;
502 if self.wp.ctx.focus != 0 {
503 return;
504 }
505 let c = &self.wp.ctx;
506 let list = &c.hits[c.hit_cur];
507 let (st, top) = stops(list, 0, &c.kb.gmem);
508 if top != L_BASE as i32 {
509 return;
510 }
511 if let Some(&i) = st.first() {
512 let id = list[i].id;
513 self.wp.ctx.focus = id;
514 self.wp.ctx.focus_visible = false;
515 self.wp.ctx.kb.soft = id;
516 self.repass = true;
517 }
518 }
519
520 fn kb_remember(&mut self) {
523 let c = &mut self.wp.ctx;
524 let f = c.focus;
525 if f != c.kb.soft {
526 c.kb.soft = 0;
527 }
528 if f == 0 {
529 return;
530 }
531 let list = &c.hits[c.hit_cur];
532 let Some(h) = list.iter().find(|h| h.id == f && focusable(h)) else { return };
533 if h.group != 0 {
534 mem_put(&mut c.kb.gmem, h.group, f);
535 }
536 mem_put(&mut c.kb.pmem, h.pane, f);
537 let (st, _) = stops(list, f, &c.kb.gmem);
538 if let Some(pos) = st.iter().position(|&i| list[i].id == f) {
539 let n = st.len();
540 c.kb.anchor = [f, list[st[(pos + 1) % n]].id, list[st[(pos + n - 1) % n]].id];
541 }
542 }
543
544 fn focus_step(&mut self, back: bool) {
546 let c = &self.wp.ctx;
547 let list = &c.hits[c.hit_cur];
548 let f = c.focus;
549 let (st, _) = stops(list, f, &c.kb.gmem);
550 let n = st.len();
551 if n == 0 {
552 return;
553 }
554 let t = match st.iter().position(|&i| list[i].id == f) {
555 Some(p) => {
556 if back {
557 (p + n - 1) % n
558 } else {
559 (p + 1) % n
560 }
561 }
562 None => {
563 let at = if f != 0 { list.iter().position(|h| h.id == f && h.flags as u32 & (HB_FOCUS | HB_SPLITTER) != 0) } else { None };
566 match at {
567 Some(a) => {
568 if back {
569 st.iter().rposition(|&i| i < a).unwrap_or(n - 1)
570 } else {
571 st.iter().position(|&i| i > a).unwrap_or(0)
572 }
573 }
574 None => {
575 let an = c.kb.anchor;
577 let want = if f != 0 && an[0] == f { if back { an[2] } else { an[1] } } else { 0 };
578 match st.iter().position(|&i| want != 0 && list[i].id == want) {
579 Some(p) => p,
580 None => {
581 if back {
582 n - 1
583 } else {
584 0
585 }
586 }
587 }
588 }
589 }
590 }
591 };
592 let id = list[st[t]].id;
593 self.wp.ctx.focus = id;
594 self.wp.ctx.focus_visible = true;
595 self.repass = true;
596 }
597
598 fn kb_focus_group(&self) -> u32 {
600 let c = &self.wp.ctx;
601 let f = c.focus;
602 if f == 0 {
603 return 0;
604 }
605 let list = &c.hits[c.hit_cur];
606 let Some(h) = list.iter().find(|h| h.id == f && focusable(h)) else { return 0 };
607 if h.group == 0 || h.flags as u32 & HB_TEXT != 0 {
608 return 0;
609 }
610 let g = h.group;
611 if list.iter().any(|m| m.group == g && m.id != f && focusable(m)) { g } else { 0 }
612 }
613
614 fn kb_group_move(&mut self, vk: u32) -> bool {
616 let g = self.kb_focus_group();
617 if g == 0 {
618 return false;
619 }
620 let c = &self.wp.ctx;
621 let f = c.focus;
622 let list = &c.hits[c.hit_cur];
623 let layer = list.iter().find(|h| h.id == f && focusable(h)).map_or(0, |h| h.layer);
624 let mut ms: Vec<(u32, [i32; 4])> = Vec::new();
626 for h in list.iter() {
627 if h.group == g && h.layer == layer && focusable(h) && !ms.iter().any(|m| m.0 == h.id) {
628 ms.push((h.id, [h.x0, h.y0, h.x1, h.y1]));
629 }
630 }
631 let n = ms.len();
632 let Some(cur) = ms.iter().position(|m| m.0 == f) else { return false };
633 let t = match vk {
634 VK_HOME => 0,
635 VK_END => n - 1,
636 _ => {
637 let r0 = ms[0].1;
638 let row = ms.iter().all(|m| span_gap(r0[1], r0[3], m.1[1], m.1[3]) == 0 && m.1[3] > r0[1]);
639 let col = ms.iter().all(|m| span_gap(r0[0], r0[2], m.1[0], m.1[2]) == 0 && m.1[2] > r0[0]);
640 if row || col {
641 if matches!(vk, VK_RIGHT | VK_DOWN) {
642 (cur + 1) % n
643 } else {
644 (cur + n - 1) % n
645 }
646 } else {
647 match nearest(&ms, cur, vk) {
648 Some(t) => t,
649 None => return true, }
651 }
652 }
653 };
654 let id = ms[t].0;
655 if id != f {
656 self.wp.ctx.focus = id;
657 self.m.kbnav.moved = id;
658 self.repass = true;
659 }
660 self.wp.ctx.focus_visible = true;
661 true
662 }
663
664 fn kb_ctx_request(&mut self) -> bool {
667 let f = self.wp.ctx.focus;
668 if f == 0 || self.popup_count() != 0 {
669 return false;
670 }
671 let c = &self.wp.ctx;
672 if !c.hits[c.hit_cur].iter().any(|h| h.id == f) {
673 return false;
674 }
675 self.m.kbnav.ctx = f;
676 self.m.kbnav.ctx_set = self.frame;
677 self.repass = true;
678 true
679 }
680
681 fn kb_tool_here(&self) -> bool {
683 let cur = self.uiw_cur;
684 cur != 0 && self.m.kbnav.tool && self.m.win.kfocus == cur + 1
685 }
686
687 fn kb_escape(&mut self) -> bool {
690 if self.kb_on_splitter() {
691 self.kb_split_return();
692 return true;
693 }
694 if !self.kb_tool_here() {
695 return false;
696 }
697 let cur = self.uiw_cur;
698 self.m.win.kfocus = 0;
699 self.m.kbnav.tool = false;
700 self.wp.ctx.focus_visible = false;
701 let o = self.m.win.recs[(cur as usize) & (WIN_MAX - 1)].owner;
702 if let Some(p) = self.uiw_parts_mut(o) {
703 p.ctx.focus_visible = p.ctx.focus != 0;
704 }
705 self.repass = true;
706 self.invalidate();
707 true
708 }
709
710 fn kb_pane_switch(&mut self, back: bool) {
714 if self.wp.ctx.modal_cur != 0 {
715 return; }
717 let others = self.kb_ring().len() > 1;
718 let mv = {
719 let c = &self.wp.ctx;
720 let list = &c.hits[c.hit_cur];
721 let f = c.focus;
722 let (st, top) = stops(list, f, &c.kb.gmem);
723 if top > L_BASE as i32 {
724 return;
725 }
726 let mut panes: Vec<u32> = Vec::new();
728 for &i in &st {
729 if !panes.contains(&list[i].pane) {
730 panes.push(list[i].pane);
731 }
732 }
733 let n = panes.len();
734 let cur = list
735 .iter()
736 .find(|h| f != 0 && h.id == f && h.flags as u32 & (HB_FOCUS | HB_SPLITTER) != 0)
737 .and_then(|h| panes.iter().position(|&p| p == h.pane));
738 let t = match cur {
739 None if n == 0 => None,
740 None => Some(if back { n - 1 } else { 0 }),
741 Some(ci) if !back && ci + 1 < n => Some(ci + 1),
742 Some(ci) if back && ci > 0 => Some(ci - 1),
743 Some(_) if others => None,
744 Some(ci) => Some(if n == 1 { ci } else if back { n - 1 } else { 0 }),
745 };
746 match t {
747 None if others => PaneMove::Window(back),
748 None => PaneMove::None,
749 Some(t) => {
750 let p = panes[t];
751 let m = mem_get(&c.kb.pmem, p);
752 let id = if m != 0 && list.iter().any(|h| h.id == m && h.pane == p && focusable(h)) {
753 m
754 } else {
755 st.iter().map(|&i| &list[i]).find(|h| h.pane == p).map_or(0, |h| h.id)
756 };
757 PaneMove::Focus(id)
758 }
759 }
760 };
761 match mv {
762 PaneMove::Focus(id) if id != 0 => {
763 self.wp.ctx.focus = id;
764 self.wp.ctx.focus_visible = true;
765 self.repass = true;
766 }
767 PaneMove::Window(back) => self.kb_window_switch(back),
768 _ => {}
769 }
770 }
771
772 fn kb_ring(&self) -> Vec<u32> {
775 let mut v = Vec::new();
776 for i in 0..WIN_MAX as u32 {
777 if i != 0 && !self.uiw_drawable(i) || (self.m.win.inert >> i) & 1 != 0 {
778 continue;
779 }
780 let Some(p) = self.uiw_parts(i) else { continue };
781 let c = &p.ctx;
782 let list = if i == self.uiw_cur { &c.hits[c.hit_cur] } else { &c.hits[c.hit_cur ^ 1] };
783 if list.iter().any(focusable) {
784 v.push(i);
785 }
786 }
787 v
788 }
789
790 fn kb_window_switch(&mut self, back: bool) {
793 let ring = self.kb_ring();
794 let n = ring.len();
795 if n < 2 {
796 return;
797 }
798 let live = self.uiw_cur;
799 let ci = ring.iter().position(|&w| w == live).unwrap_or(0);
800 let j = if back { ring[(ci + n - 1) % n] } else { ring[(ci + 1) % n] };
801 self.wp.ctx.focus_visible = false; if let Some(p) = self.uiw_parts_mut(j) {
803 let c = &mut p.ctx;
804 let nf = {
805 let list = if j == live { &c.hits[c.hit_cur] } else { &c.hits[c.hit_cur ^ 1] };
806 let f = c.focus;
807 if f != 0 && list.iter().any(|h| h.id == f && focusable(h)) {
808 f
809 } else {
810 let (st, _) = stops(list, 0, &c.kb.gmem);
811 st.first().map_or(0, |&i| list[i].id)
812 }
813 };
814 c.focus = nf;
815 c.focus_visible = nf != 0;
816 }
817 let r = &self.m.win.recs[(j as usize) & (WIN_MAX - 1)];
818 if j != 0 && r.flags & (WF_TOOL | WF_KEYS) == WF_TOOL {
819 let o = r.owner;
821 self.m.win.kfocus = j + 1;
822 self.m.kbnav.tool = true;
823 self.uiw_activate(o);
824 } else {
825 self.m.win.kfocus = 0;
826 self.m.kbnav.tool = false;
827 self.uiw_activate(j);
828 }
829 self.repass = true;
830 self.invalidate();
831 }
832
833 fn kb_splitters(&self) -> Vec<u32> {
837 let c = &self.wp.ctx;
838 let mut v: Vec<u32> = Vec::new();
839 for h in &c.hits[c.hit_cur] {
840 if h.flags as u32 & (HB_SPLITTER | HB_DISABLED) == HB_SPLITTER && h.layer as u32 == L_BASE && !v.contains(&h.id) {
841 v.push(h.id);
842 }
843 }
844 v
845 }
846
847 fn kb_on_splitter(&self) -> bool {
849 let c = &self.wp.ctx;
850 c.focus != 0 && c.hits[c.hit_cur].iter().any(|h| h.id == c.focus && h.flags as u32 & HB_SPLITTER != 0)
851 }
852
853 fn kb_splitter_step(&mut self, back: bool) -> bool {
855 let sp = self.kb_splitters();
856 let n = sp.len();
857 if n == 0 {
858 return false;
859 }
860 let f = self.wp.ctx.focus;
861 let t = match sp.iter().position(|&s| s == f) {
862 None => {
863 self.wp.ctx.kb.split_ret = f;
864 if back { n - 1 } else { 0 }
865 }
866 Some(p) => {
867 let q = if back { p as i32 - 1 } else { p as i32 + 1 };
868 if q < 0 || q >= n as i32 {
869 self.kb_split_return();
870 return true;
871 }
872 q as usize
873 }
874 };
875 self.wp.ctx.focus = sp[t];
876 self.wp.ctx.focus_visible = true;
877 self.repass = true;
878 true
879 }
880
881 fn kb_split_return(&mut self) {
883 let r = core::mem::take(&mut self.wp.ctx.kb.split_ret);
884 self.wp.ctx.focus = r;
885 self.wp.ctx.focus_visible = r != 0;
886 self.repass = true;
887 }
888}