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 = if self.focus_has_keys() { 0 } else { self.wp.ctx.keyq.len() };
455 for qi in 0..n {
456 let k = self.wp.ctx.keyq[qi];
457 if (k as i32) < 0 {
458 continue;
459 }
460 if self.kb_key(k) {
461 if let Some(e) = self.wp.ctx.keyq.get_mut(qi) {
462 *e |= 0x8000_0000;
463 }
464 break;
465 }
466 }
467 self.kb_remember();
468 }
469
470 fn kb_key(&mut self, k: u32) -> bool {
472 let vk = k & 0xFFFF;
473 let m = (k >> 16) & MOD3;
474 let shift = m & MOD_SHIFT != 0;
475 match vk {
476 VK_TAB if m & (MOD_CTRL | MOD_ALT) == 0 => {
477 self.focus_step(shift);
478 true
479 }
480 VK_LEFT | VK_RIGHT | VK_UP | VK_DOWN | VK_HOME | VK_END if m == 0 => self.kb_group_move(vk),
481 VK_F6 if m & MOD_ALT == 0 && self.accel_find(VK_F6, m).is_none() => {
482 if m & MOD_CTRL != 0 {
483 self.kb_window_switch(shift);
484 } else {
485 self.kb_pane_switch(shift);
486 }
487 true
488 }
489 VK_F8 if m & (MOD_CTRL | MOD_ALT) == 0 && self.accel_find(VK_F8, m).is_none() => self.kb_splitter_step(shift),
490 VK_APPS => self.kb_ctx_request(),
491 VK_F10 if m == MOD_SHIFT => self.kb_ctx_request(),
492 VK_ESCAPE if m == 0 => self.kb_escape(),
493 _ => false,
494 }
495 }
496
497 fn kb_autofocus(&mut self) {
499 if !self.wp.ctx.kb.autofocus {
500 return;
501 }
502 self.wp.ctx.kb.autofocus = false;
503 if self.wp.ctx.focus != 0 {
504 return;
505 }
506 let c = &self.wp.ctx;
507 let list = &c.hits[c.hit_cur];
508 let (st, top) = stops(list, 0, &c.kb.gmem);
509 if top != L_BASE as i32 {
510 return;
511 }
512 if let Some(&i) = st.first() {
513 let id = list[i].id;
514 self.wp.ctx.focus = id;
515 self.wp.ctx.focus_visible = false;
516 self.wp.ctx.kb.soft = id;
517 self.repass = true;
518 }
519 }
520
521 fn kb_remember(&mut self) {
524 let c = &mut self.wp.ctx;
525 let f = c.focus;
526 if f != c.kb.soft {
527 c.kb.soft = 0;
528 }
529 if f == 0 {
530 return;
531 }
532 let list = &c.hits[c.hit_cur];
533 let Some(h) = list.iter().find(|h| h.id == f && focusable(h)) else { return };
534 if h.group != 0 {
535 mem_put(&mut c.kb.gmem, h.group, f);
536 }
537 mem_put(&mut c.kb.pmem, h.pane, f);
538 let (st, _) = stops(list, f, &c.kb.gmem);
539 if let Some(pos) = st.iter().position(|&i| list[i].id == f) {
540 let n = st.len();
541 c.kb.anchor = [f, list[st[(pos + 1) % n]].id, list[st[(pos + n - 1) % n]].id];
542 }
543 }
544
545 fn focus_step(&mut self, back: bool) {
547 let c = &self.wp.ctx;
548 let list = &c.hits[c.hit_cur];
549 let f = c.focus;
550 let (st, _) = stops(list, f, &c.kb.gmem);
551 let n = st.len();
552 if n == 0 {
553 return;
554 }
555 let t = match st.iter().position(|&i| list[i].id == f) {
556 Some(p) => {
557 if back {
558 (p + n - 1) % n
559 } else {
560 (p + 1) % n
561 }
562 }
563 None => {
564 let at = if f != 0 { list.iter().position(|h| h.id == f && h.flags as u32 & (HB_FOCUS | HB_SPLITTER) != 0) } else { None };
567 match at {
568 Some(a) => {
569 if back {
570 st.iter().rposition(|&i| i < a).unwrap_or(n - 1)
571 } else {
572 st.iter().position(|&i| i > a).unwrap_or(0)
573 }
574 }
575 None => {
576 let an = c.kb.anchor;
578 let want = if f != 0 && an[0] == f { if back { an[2] } else { an[1] } } else { 0 };
579 match st.iter().position(|&i| want != 0 && list[i].id == want) {
580 Some(p) => p,
581 None => {
582 if back {
583 n - 1
584 } else {
585 0
586 }
587 }
588 }
589 }
590 }
591 }
592 };
593 let id = list[st[t]].id;
594 self.wp.ctx.focus = id;
595 self.wp.ctx.focus_visible = true;
596 self.repass = true;
597 }
598
599 fn kb_focus_group(&self) -> u32 {
601 let c = &self.wp.ctx;
602 let f = c.focus;
603 if f == 0 {
604 return 0;
605 }
606 let list = &c.hits[c.hit_cur];
607 let Some(h) = list.iter().find(|h| h.id == f && focusable(h)) else { return 0 };
608 if h.group == 0 || h.flags as u32 & HB_TEXT != 0 {
609 return 0;
610 }
611 let g = h.group;
612 if list.iter().any(|m| m.group == g && m.id != f && focusable(m)) { g } else { 0 }
613 }
614
615 fn kb_group_move(&mut self, vk: u32) -> bool {
617 let g = self.kb_focus_group();
618 if g == 0 {
619 return false;
620 }
621 let c = &self.wp.ctx;
622 let f = c.focus;
623 let list = &c.hits[c.hit_cur];
624 let layer = list.iter().find(|h| h.id == f && focusable(h)).map_or(0, |h| h.layer);
625 let mut ms: Vec<(u32, [i32; 4])> = Vec::new();
627 for h in list.iter() {
628 if h.group == g && h.layer == layer && focusable(h) && !ms.iter().any(|m| m.0 == h.id) {
629 ms.push((h.id, [h.x0, h.y0, h.x1, h.y1]));
630 }
631 }
632 let n = ms.len();
633 let Some(cur) = ms.iter().position(|m| m.0 == f) else { return false };
634 let t = match vk {
635 VK_HOME => 0,
636 VK_END => n - 1,
637 _ => {
638 let r0 = ms[0].1;
639 let row = ms.iter().all(|m| span_gap(r0[1], r0[3], m.1[1], m.1[3]) == 0 && m.1[3] > r0[1]);
640 let col = ms.iter().all(|m| span_gap(r0[0], r0[2], m.1[0], m.1[2]) == 0 && m.1[2] > r0[0]);
641 if row || col {
642 if matches!(vk, VK_RIGHT | VK_DOWN) {
643 (cur + 1) % n
644 } else {
645 (cur + n - 1) % n
646 }
647 } else {
648 match nearest(&ms, cur, vk) {
649 Some(t) => t,
650 None => return true, }
652 }
653 }
654 };
655 let id = ms[t].0;
656 if id != f {
657 self.wp.ctx.focus = id;
658 self.m.kbnav.moved = id;
659 self.repass = true;
660 }
661 self.wp.ctx.focus_visible = true;
662 true
663 }
664
665 fn kb_ctx_request(&mut self) -> bool {
668 let f = self.wp.ctx.focus;
669 if f == 0 || self.popup_count() != 0 {
670 return false;
671 }
672 let c = &self.wp.ctx;
673 if !c.hits[c.hit_cur].iter().any(|h| h.id == f) {
674 return false;
675 }
676 self.m.kbnav.ctx = f;
677 self.m.kbnav.ctx_set = self.frame;
678 self.repass = true;
679 true
680 }
681
682 fn kb_tool_here(&self) -> bool {
684 let cur = self.uiw_cur;
685 cur != 0 && self.m.kbnav.tool && self.m.win.kfocus == cur + 1
686 }
687
688 fn kb_escape(&mut self) -> bool {
691 if self.kb_on_splitter() {
692 self.kb_split_return();
693 return true;
694 }
695 if !self.kb_tool_here() {
696 return false;
697 }
698 let cur = self.uiw_cur;
699 self.m.win.kfocus = 0;
700 self.m.kbnav.tool = false;
701 self.wp.ctx.focus_visible = false;
702 let o = self.m.win.recs[(cur as usize) & (WIN_MAX - 1)].owner;
703 if let Some(p) = self.uiw_parts_mut(o) {
704 p.ctx.focus_visible = p.ctx.focus != 0;
705 }
706 self.repass = true;
707 self.invalidate();
708 true
709 }
710
711 fn kb_pane_switch(&mut self, back: bool) {
715 if self.wp.ctx.modal_cur != 0 {
716 return; }
718 let others = self.kb_ring().len() > 1;
719 let mv = {
720 let c = &self.wp.ctx;
721 let list = &c.hits[c.hit_cur];
722 let f = c.focus;
723 let (st, top) = stops(list, f, &c.kb.gmem);
724 if top > L_BASE as i32 {
725 return;
726 }
727 let mut panes: Vec<u32> = Vec::new();
729 for &i in &st {
730 if !panes.contains(&list[i].pane) {
731 panes.push(list[i].pane);
732 }
733 }
734 let n = panes.len();
735 let cur = list
736 .iter()
737 .find(|h| f != 0 && h.id == f && h.flags as u32 & (HB_FOCUS | HB_SPLITTER) != 0)
738 .and_then(|h| panes.iter().position(|&p| p == h.pane));
739 let t = match cur {
740 None if n == 0 => None,
741 None => Some(if back { n - 1 } else { 0 }),
742 Some(ci) if !back && ci + 1 < n => Some(ci + 1),
743 Some(ci) if back && ci > 0 => Some(ci - 1),
744 Some(_) if others => None,
745 Some(ci) => Some(if n == 1 { ci } else if back { n - 1 } else { 0 }),
746 };
747 match t {
748 None if others => PaneMove::Window(back),
749 None => PaneMove::None,
750 Some(t) => {
751 let p = panes[t];
752 let m = mem_get(&c.kb.pmem, p);
753 let id = if m != 0 && list.iter().any(|h| h.id == m && h.pane == p && focusable(h)) {
754 m
755 } else {
756 st.iter().map(|&i| &list[i]).find(|h| h.pane == p).map_or(0, |h| h.id)
757 };
758 PaneMove::Focus(id)
759 }
760 }
761 };
762 match mv {
763 PaneMove::Focus(id) if id != 0 => {
764 self.wp.ctx.focus = id;
765 self.wp.ctx.focus_visible = true;
766 self.repass = true;
767 }
768 PaneMove::Window(back) => self.kb_window_switch(back),
769 _ => {}
770 }
771 }
772
773 fn kb_ring(&self) -> Vec<u32> {
776 let mut v = Vec::new();
777 for i in 0..WIN_MAX as u32 {
778 if i != 0 && !self.uiw_drawable(i) || (self.m.win.inert >> i) & 1 != 0 {
779 continue;
780 }
781 let Some(p) = self.uiw_parts(i) else { continue };
782 let c = &p.ctx;
783 let list = if i == self.uiw_cur { &c.hits[c.hit_cur] } else { &c.hits[c.hit_cur ^ 1] };
784 if list.iter().any(focusable) {
785 v.push(i);
786 }
787 }
788 v
789 }
790
791 fn kb_window_switch(&mut self, back: bool) {
794 let ring = self.kb_ring();
795 let n = ring.len();
796 if n < 2 {
797 return;
798 }
799 let live = self.uiw_cur;
800 let ci = ring.iter().position(|&w| w == live).unwrap_or(0);
801 let j = if back { ring[(ci + n - 1) % n] } else { ring[(ci + 1) % n] };
802 self.wp.ctx.focus_visible = false; if let Some(p) = self.uiw_parts_mut(j) {
804 let c = &mut p.ctx;
805 let nf = {
806 let list = if j == live { &c.hits[c.hit_cur] } else { &c.hits[c.hit_cur ^ 1] };
807 let f = c.focus;
808 if f != 0 && list.iter().any(|h| h.id == f && focusable(h)) {
809 f
810 } else {
811 let (st, _) = stops(list, 0, &c.kb.gmem);
812 st.first().map_or(0, |&i| list[i].id)
813 }
814 };
815 c.focus = nf;
816 c.focus_visible = nf != 0;
817 }
818 let r = &self.m.win.recs[(j as usize) & (WIN_MAX - 1)];
819 if j != 0 && r.flags & (WF_TOOL | WF_KEYS) == WF_TOOL {
820 let o = r.owner;
822 self.m.win.kfocus = j + 1;
823 self.m.kbnav.tool = true;
824 self.uiw_activate(o);
825 } else {
826 self.m.win.kfocus = 0;
827 self.m.kbnav.tool = false;
828 self.uiw_activate(j);
829 }
830 self.repass = true;
831 self.invalidate();
832 }
833
834 fn kb_splitters(&self) -> Vec<u32> {
838 let c = &self.wp.ctx;
839 let mut v: Vec<u32> = Vec::new();
840 for h in &c.hits[c.hit_cur] {
841 if h.flags as u32 & (HB_SPLITTER | HB_DISABLED) == HB_SPLITTER && h.layer as u32 == L_BASE && !v.contains(&h.id) {
842 v.push(h.id);
843 }
844 }
845 v
846 }
847
848 fn kb_on_splitter(&self) -> bool {
850 let c = &self.wp.ctx;
851 c.focus != 0 && c.hits[c.hit_cur].iter().any(|h| h.id == c.focus && h.flags as u32 & HB_SPLITTER != 0)
852 }
853
854 fn kb_splitter_step(&mut self, back: bool) -> bool {
856 let sp = self.kb_splitters();
857 let n = sp.len();
858 if n == 0 {
859 return false;
860 }
861 let f = self.wp.ctx.focus;
862 let t = match sp.iter().position(|&s| s == f) {
863 None => {
864 self.wp.ctx.kb.split_ret = f;
865 if back { n - 1 } else { 0 }
866 }
867 Some(p) => {
868 let q = if back { p as i32 - 1 } else { p as i32 + 1 };
869 if q < 0 || q >= n as i32 {
870 self.kb_split_return();
871 return true;
872 }
873 q as usize
874 }
875 };
876 self.wp.ctx.focus = sp[t];
877 self.wp.ctx.focus_visible = true;
878 self.repass = true;
879 true
880 }
881
882 fn kb_split_return(&mut self) {
884 let r = core::mem::take(&mut self.wp.ctx.kb.split_ret);
885 self.wp.ctx.focus = r;
886 self.wp.ctx.focus_visible = r != 0;
887 self.repass = true;
888 }
889}