1pub mod iter;
4
5mod focus_info;
6pub use focus_info::*;
7
8use zng_app::{
9 AppExtension, DInstant, INSTANT,
10 access::{ACCESS_CLICK_EVENT, ACCESS_FOCUS_EVENT, ACCESS_FOCUS_NAV_ORIGIN_EVENT},
11 event::{event, event_args},
12 update::{EventUpdate, InfoUpdates, RenderUpdates, UPDATES},
13 view_process::raw_events::RAW_KEY_INPUT_EVENT,
14 widget::{
15 WidgetId,
16 info::{InteractionPath, WIDGET_INFO_CHANGED_EVENT, WidgetBoundsInfo, WidgetInfoTree},
17 },
18 window::WindowId,
19};
20
21pub mod cmd;
22use cmd::FocusCommands;
23use zng_app_context::app_local;
24use zng_ext_window::{WINDOW_FOCUS, WINDOW_FOCUS_CHANGED_EVENT, WINDOWS};
25use zng_layout::unit::{Px, PxPoint, PxRect, TimeUnits};
26use zng_unique_id::{IdEntry, IdMap};
27use zng_var::{AnyVar, ArcVar, ReadOnlyArcVar, Var, var};
28use zng_view_api::window::FrameId;
29
30use std::{mem, time::Duration};
31
32use crate::{mouse::MOUSE_INPUT_EVENT, touch::TOUCH_INPUT_EVENT};
33
34event_args! {
35 pub struct FocusChangedArgs {
37 pub prev_focus: Option<InteractionPath>,
39
40 pub new_focus: Option<InteractionPath>,
42
43 pub highlight: bool,
49
50 pub cause: FocusChangedCause,
52
53 pub enabled_nav: FocusNavAction,
57
58 ..
59
60 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
62 if let Some(prev) = &self.prev_focus {
63 list.insert_wgt(prev);
64 }
65 if let Some(new) = &self.new_focus {
66 list.insert_wgt(new);
67 }
68 }
69 }
70
71 pub struct ReturnFocusChangedArgs {
73 pub scope: Option<InteractionPath>,
77
78 pub prev_return: Option<InteractionPath>,
80
81 pub new_return: Option<InteractionPath>,
83
84 ..
85
86 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
89 if let Some(scope) = &self.scope {
90 list.insert_wgt(scope)
91 }
92 if let Some(prev_return) = &self.prev_return {
93 list.insert_wgt(prev_return)
94 }
95 if let Some(new_return) = &self.new_return {
96 list.insert_wgt(new_return)
97 }
98 }
99 }
100}
101
102impl FocusChangedArgs {
103 pub fn is_widget_move(&self) -> bool {
105 match (&self.prev_focus, &self.new_focus) {
106 (Some(prev), Some(new)) => prev.widget_id() == new.widget_id() && prev.as_path() != new.as_path(),
107 _ => false,
108 }
109 }
110
111 pub fn is_enabled_change(&self) -> bool {
113 match (&self.prev_focus, &self.new_focus) {
114 (Some(prev), Some(new)) => prev.as_path() == new.as_path() && prev.disabled_index() != new.disabled_index(),
115 _ => false,
116 }
117 }
118
119 pub fn is_highlight_changed(&self) -> bool {
121 self.prev_focus == self.new_focus
122 }
123
124 pub fn is_focus(&self, widget_id: WidgetId) -> bool {
126 match (&self.prev_focus, &self.new_focus) {
127 (Some(prev), Some(new)) => prev.widget_id() != widget_id && new.widget_id() == widget_id,
128 (None, Some(new)) => new.widget_id() == widget_id,
129 (_, None) => false,
130 }
131 }
132
133 pub fn is_blur(&self, widget_id: WidgetId) -> bool {
135 match (&self.prev_focus, &self.new_focus) {
136 (Some(prev), Some(new)) => prev.widget_id() == widget_id && new.widget_id() != widget_id,
137 (Some(prev), None) => prev.widget_id() == widget_id,
138 (None, _) => false,
139 }
140 }
141
142 pub fn is_focus_enter(&self, widget_id: WidgetId) -> bool {
144 match (&self.prev_focus, &self.new_focus) {
145 (Some(prev), Some(new)) => !prev.contains(widget_id) && new.contains(widget_id),
146 (None, Some(new)) => new.contains(widget_id),
147 (_, None) => false,
148 }
149 }
150
151 pub fn is_focus_leave(&self, widget_id: WidgetId) -> bool {
153 match (&self.prev_focus, &self.new_focus) {
154 (Some(prev), Some(new)) => prev.contains(widget_id) && !new.contains(widget_id),
155 (Some(prev), None) => prev.contains(widget_id),
156 (None, _) => false,
157 }
158 }
159
160 pub fn is_focused(&self, widget_id: WidgetId) -> bool {
162 self.new_focus.as_ref().map(|p| p.widget_id() == widget_id).unwrap_or(false)
163 }
164
165 pub fn is_focus_within(&self, widget_id: WidgetId) -> bool {
167 self.new_focus.as_ref().map(|p| p.contains(widget_id)).unwrap_or(false)
168 }
169}
170
171impl ReturnFocusChangedArgs {
172 pub fn is_widget_move(&self) -> bool {
174 match (&self.prev_return, &self.new_return) {
175 (Some(prev), Some(new)) => prev.widget_id() == new.widget_id() && prev != new,
176 _ => false,
177 }
178 }
179
180 pub fn is_alt_return(&self) -> bool {
183 if let Some(scope) = &self.scope {
184 match (&self.prev_return, &self.new_return) {
185 (Some(prev), None) => !prev.contains(scope.widget_id()),
186 (None, Some(new)) => !new.contains(scope.widget_id()),
187 _ => false,
188 }
189 } else {
190 false
191 }
192 }
193
194 pub fn lost_return_focus(&self, widget_id: WidgetId) -> bool {
199 self.prev_return.as_ref().map(|p| p.contains(widget_id)).unwrap_or(false)
200 && self.new_return.as_ref().map(|p| !p.contains(widget_id)).unwrap_or(true)
201 }
202
203 pub fn got_return_focus(&self, widget_id: WidgetId) -> bool {
208 self.prev_return.as_ref().map(|p| !p.contains(widget_id)).unwrap_or(true)
209 && self.new_return.as_ref().map(|p| p.contains(widget_id)).unwrap_or(false)
210 }
211
212 pub fn was_return_focus(&self, widget_id: WidgetId) -> bool {
217 self.prev_return.as_ref().map(|p| p.widget_id() == widget_id).unwrap_or(false)
218 && self.new_return.as_ref().map(|p| p.widget_id() != widget_id).unwrap_or(true)
219 }
220
221 pub fn is_return_focus(&self, widget_id: WidgetId) -> bool {
226 self.prev_return.as_ref().map(|p| p.widget_id() != widget_id).unwrap_or(true)
227 && self.new_return.as_ref().map(|p| p.widget_id() == widget_id).unwrap_or(false)
228 }
229
230 pub fn is_return_focus_enter(&self, widget_id: WidgetId) -> bool {
232 match (&self.prev_return, &self.new_return) {
233 (Some(prev), Some(new)) => !prev.contains(widget_id) && new.contains(widget_id),
234 (None, Some(new)) => new.contains(widget_id),
235 (_, None) => false,
236 }
237 }
238
239 pub fn is_return_focus_leave(&self, widget_id: WidgetId) -> bool {
241 match (&self.prev_return, &self.new_return) {
242 (Some(prev), Some(new)) => prev.contains(widget_id) && !new.contains(widget_id),
243 (Some(prev), None) => prev.contains(widget_id),
244 (None, _) => false,
245 }
246 }
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
251pub enum FocusChangedCause {
252 Request(FocusRequest),
254
255 ScopeGotFocus(bool),
259
260 Recovery,
262}
263impl FocusChangedCause {
264 pub fn request_target(self) -> Option<FocusTarget> {
266 match self {
267 Self::Request(r) => Some(r.target),
268 _ => None,
269 }
270 }
271}
272
273event! {
274 pub static FOCUS_CHANGED_EVENT: FocusChangedArgs;
280
281 pub static RETURN_FOCUS_CHANGED_EVENT: ReturnFocusChangedArgs;
287}
288
289#[derive(Default)]
323pub struct FocusManager {
324 commands: Option<FocusCommands>,
325 pending_render: Option<WidgetInfoTree>,
326}
327
328impl AppExtension for FocusManager {
329 fn init(&mut self) {
330 WINDOW_FOCUS.hook_focus_service(FOCUS.focused().boxed());
331 self.commands = Some(FocusCommands::new());
332 }
333
334 fn event_preview(&mut self, update: &mut EventUpdate) {
335 if let Some(args) = WIDGET_INFO_CHANGED_EVENT.on(update) {
336 if FOCUS_SV
337 .read()
338 .focused
339 .as_ref()
340 .map(|f| f.path.window_id() == args.window_id)
341 .unwrap_or_default()
342 {
343 if UPDATES.is_pending_render(args.window_id) {
346 self.pending_render = Some(args.tree.clone());
347 } else {
348 self.pending_render = None;
350 self.on_info_tree_update(args.tree.clone());
351 }
352 }
353 focus_info::FocusTreeData::consolidate_alt_scopes(&args.prev_tree, &args.tree);
354 } else if let Some(args) = ACCESS_FOCUS_EVENT.on(update) {
355 let is_focused = FOCUS.is_focused(args.widget_id).get();
356 if args.focus {
357 if !is_focused {
358 FOCUS.focus_widget(args.widget_id, false);
359 }
360 } else if is_focused {
361 FOCUS.focus_exit();
362 }
363 } else if let Some(args) = ACCESS_FOCUS_NAV_ORIGIN_EVENT.on(update) {
364 FOCUS.navigation_origin().set(Some(args.widget_id));
365 } else {
366 self.commands.as_mut().unwrap().event_preview(update);
367 }
368 }
369
370 fn render(&mut self, _: &mut RenderUpdates, _: &mut RenderUpdates) {
371 if let Some(tree) = self.pending_render.take() {
372 self.on_info_tree_update(tree);
373 } else {
374 let focus = FOCUS_SV.read();
376 let mut invalidated_cmds_or_focused = None;
377
378 if let Some(f) = &focus.focused {
379 let w_id = f.path.window_id();
380 if let Ok(tree) = WINDOWS.widget_tree(w_id) {
381 if focus.enabled_nav.needs_refresh(&tree) {
382 invalidated_cmds_or_focused = Some(tree);
383 }
384 }
385 }
386
387 if let Some(tree) = invalidated_cmds_or_focused {
388 drop(focus);
389 self.on_info_tree_update(tree);
390 }
391 }
392 }
393
394 fn event(&mut self, update: &mut EventUpdate) {
395 let mut request = None;
396
397 if let Some(args) = MOUSE_INPUT_EVENT.on(update) {
398 if args.is_mouse_down() {
399 request = Some(FocusRequest::direct_or_exit(args.target.widget_id(), true, false));
401 }
402 } else if let Some(args) = TOUCH_INPUT_EVENT.on(update) {
403 if args.is_touch_start() {
404 request = Some(FocusRequest::direct_or_exit(args.target.widget_id(), true, false));
406 }
407 } else if let Some(args) = ACCESS_CLICK_EVENT.on(update) {
408 request = Some(FocusRequest::direct_or_exit(args.widget_id, true, false));
410 } else if let Some(args) = WINDOW_FOCUS_CHANGED_EVENT.on(update) {
411 let mut focus = FOCUS_SV.write();
413 if args.new_focus.is_some() {
414 if let Some(pending) = focus.pending_window_focus.take() {
415 if args.is_focus(pending.window) {
416 request = Some(FocusRequest::direct_or_related(
417 pending.target,
418 pending.nav_origin.is_some(),
419 pending.highlight,
420 ));
421 }
422 }
423 }
424 if request.is_none() {
425 if let Some(args) = focus.continue_focus() {
426 self.notify(&mut focus, Some(args));
427 }
428 }
429
430 if let Some(window_id) = args.closed() {
431 for args in focus.cleanup_returns_win_closed(window_id) {
432 RETURN_FOCUS_CHANGED_EVENT.notify(args);
433 }
434 }
435 } else if let Some(args) = RAW_KEY_INPUT_EVENT.on(update) {
436 FOCUS_SV.write().last_keyboard_event = args.timestamp;
437 }
438
439 if let Some(request) = request {
440 let mut focus = FOCUS_SV.write();
441 if !matches!(&focus.request, PendingFocusRequest::Update(_)) {
442 focus.request = PendingFocusRequest::None;
443 focus.pending_highlight = false;
444 focus.pending_window_focus = None;
445 let args = focus.fulfill_request(request, false);
446 self.notify(&mut focus, args);
447 }
448 }
449 }
450
451 fn update(&mut self) {
452 let mut focus = FOCUS_SV.write();
453 if let Some((request, is_retry)) = focus.request.take_update() {
454 focus.pending_highlight = false;
455 let args = focus.fulfill_request(request, is_retry);
456 self.notify(&mut focus, args);
457 } else if mem::take(&mut focus.pending_highlight) {
458 let args = focus.continue_focus_highlight(true);
459 self.notify(&mut focus, args);
460 }
461
462 if let Some(wgt_id) = focus.navigation_origin_var.get_new() {
463 if wgt_id != focus.navigation_origin {
464 focus.navigation_origin = wgt_id;
465 focus.update_enabled_nav_with_origin();
466 let commands = self.commands.as_mut().unwrap();
467 commands.update_enabled(focus.enabled_nav.nav);
468 }
469 }
470 }
471
472 fn info(&mut self, _: &mut InfoUpdates) {
473 let mut focus = FOCUS_SV.write();
474 if let Some(r) = focus.request.take_info() {
475 focus.request = PendingFocusRequest::RetryUpdate(r);
476 UPDATES.update(None);
477 }
478 }
479}
480impl FocusManager {
481 fn on_info_tree_update(&mut self, tree: WidgetInfoTree) {
482 let mut focus = FOCUS_SV.write();
483 let focus = &mut *focus;
484 focus.update_focused_center();
485
486 let args = focus.continue_focus();
488 self.notify(focus, args);
489
490 for args in focus.cleanup_returns(FocusInfoTree::new(
492 tree,
493 focus.focus_disabled_widgets.get(),
494 focus.focus_hidden_widgets.get(),
495 )) {
496 RETURN_FOCUS_CHANGED_EVENT.notify(args);
497 }
498 }
499
500 fn notify(&mut self, focus: &mut FocusService, args: Option<FocusChangedArgs>) {
501 if let Some(mut args) = args {
502 if !args.highlight && args.new_focus.is_some() && focus.auto_highlight(args.timestamp) {
503 args.highlight = true;
504 focus.is_highlighting = true;
505 focus.is_highlighting_var.set(true);
506 }
507
508 let is_tab_cycle_reentry = matches!(args.cause.request_target(), Some(FocusTarget::Prev | FocusTarget::Next))
510 && match (&args.prev_focus, &args.new_focus) {
511 (Some(p), Some(n)) => p.contains(n.widget_id()),
512 _ => false,
513 };
514
515 let reverse = matches!(args.cause.request_target(), Some(FocusTarget::Prev));
516 let prev_focus = args.prev_focus.clone();
517 FOCUS_CHANGED_EVENT.notify(args);
518
519 while let Some(after_args) = focus.move_after_focus(is_tab_cycle_reentry, reverse) {
521 FOCUS_CHANGED_EVENT.notify(after_args);
522 }
523
524 for return_args in focus.update_returns(prev_focus) {
525 RETURN_FOCUS_CHANGED_EVENT.notify(return_args);
526 }
527 }
528
529 let commands = self.commands.as_mut().unwrap();
530 commands.update_enabled(focus.enabled_nav.nav);
531 }
532}
533
534app_local! {
535 static FOCUS_SV: FocusService = FocusService::new();
536}
537
538pub struct FOCUS;
544impl FOCUS {
545 #[must_use]
550 pub fn auto_highlight(&self) -> ArcVar<Option<Duration>> {
551 FOCUS_SV.read().auto_highlight.clone()
552 }
553
554 #[must_use]
565 pub fn focus_disabled_widgets(&self) -> ArcVar<bool> {
566 FOCUS_SV.read().focus_disabled_widgets.clone()
567 }
568
569 #[must_use]
580 pub fn focus_hidden_widgets(&self) -> ArcVar<bool> {
581 FOCUS_SV.read().focus_hidden_widgets.clone()
582 }
583
584 #[must_use]
596 pub fn navigation_origin(&self) -> ArcVar<Option<WidgetId>> {
597 FOCUS_SV.read().navigation_origin_var.clone()
598 }
599
600 #[must_use]
602 pub fn focused(&self) -> ReadOnlyArcVar<Option<InteractionPath>> {
603 FOCUS_SV.read().focused_var.read_only()
604 }
605
606 #[must_use]
608 pub fn return_focused(&self, scope_id: WidgetId) -> ReadOnlyArcVar<Option<InteractionPath>> {
609 FOCUS_SV
610 .write()
611 .return_focused_var
612 .entry(scope_id)
613 .or_insert_with(|| var(None))
614 .read_only()
615 }
616
617 pub fn is_window_focused(&self, window_id: WindowId) -> impl Var<bool> {
621 self.focused().map(move |p| matches!(p, Some(p) if p.window_id() == window_id))
622 }
623
624 pub fn is_focus_within(&self, widget_id: WidgetId) -> impl Var<bool> {
628 self.focused().map(move |p| matches!(p, Some(p) if p.contains(widget_id)))
629 }
630
631 pub fn is_focused(&self, widget_id: WidgetId) -> impl Var<bool> {
635 self.focused().map(move |p| matches!(p, Some(p) if p.widget_id() == widget_id))
636 }
637
638 #[must_use]
640 pub fn alt_return(&self) -> ReadOnlyArcVar<Option<InteractionPath>> {
641 FOCUS_SV.read().alt_return_var.read_only()
642 }
643
644 #[must_use]
646 pub fn in_alt(&self) -> impl Var<bool> {
647 FOCUS_SV.read().alt_return_var.map(|p| p.is_some())
648 }
649
650 #[must_use]
652 pub fn is_highlighting(&self) -> ReadOnlyArcVar<bool> {
653 FOCUS_SV.read().is_highlighting_var.read_only()
654 }
655
656 pub fn focus(&self, mut request: FocusRequest) {
660 let mut f = FOCUS_SV.write();
661 if !request.highlight && f.auto_highlight(INSTANT.now()) {
662 request.highlight = true;
663 }
664 f.pending_window_focus = None;
665 f.request = PendingFocusRequest::Update(request);
666 UPDATES.update(None);
667 }
668
669 fn on_disabled_cmd(&self) {
671 let f = FOCUS_SV.read();
672 if f.auto_highlight.get().is_some() && !f.is_highlighting {
673 drop(f);
674 self.highlight();
675 }
676 }
677
678 pub fn highlight(&self) {
682 let mut f = FOCUS_SV.write();
683 f.pending_highlight = true;
684 UPDATES.update(None);
685 }
686
687 pub fn focus_widget(&self, widget_id: impl Into<WidgetId>, highlight: bool) {
698 self.focus(FocusRequest::direct(widget_id.into(), highlight));
699 }
700
701 pub fn focus_widget_or_exit(&self, widget_id: impl Into<WidgetId>, navigation_origin: bool, highlight: bool) {
713 self.focus(FocusRequest::direct_or_exit(widget_id.into(), navigation_origin, highlight));
714 }
715
716 pub fn focus_widget_or_enter(&self, widget_id: impl Into<WidgetId>, navigation_origin: bool, highlight: bool) {
728 self.focus(FocusRequest::direct_or_enter(widget_id.into(), navigation_origin, highlight));
729 }
730
731 pub fn focus_widget_or_related(&self, widget_id: impl Into<WidgetId>, navigation_origin: bool, highlight: bool) {
744 self.focus(FocusRequest::direct_or_related(widget_id.into(), navigation_origin, highlight));
745 }
746
747 pub fn focus_enter(&self) {
753 let req = FocusRequest::enter(FOCUS_SV.read().is_highlighting);
754 self.focus(req);
755 }
756
757 pub fn focus_exit(&self) {
764 let req = FocusRequest::exit(FOCUS_SV.read().is_highlighting);
765 self.focus(req)
766 }
767
768 pub fn focus_next(&self) {
774 let req = FocusRequest::next(FOCUS_SV.read().is_highlighting);
775 self.focus(req);
776 }
777
778 pub fn focus_prev(&self) {
784 let req = FocusRequest::prev(FOCUS_SV.read().is_highlighting);
785 self.focus(req);
786 }
787
788 pub fn focus_up(&self) {
794 let req = FocusRequest::up(FOCUS_SV.read().is_highlighting);
795 self.focus(req);
796 }
797
798 pub fn focus_right(&self) {
804 let req = FocusRequest::right(FOCUS_SV.read().is_highlighting);
805 self.focus(req);
806 }
807
808 pub fn focus_down(&self) {
814 let req = FocusRequest::down(FOCUS_SV.read().is_highlighting);
815 self.focus(req);
816 }
817
818 pub fn focus_left(&self) {
824 let req = FocusRequest::left(FOCUS_SV.read().is_highlighting);
825 self.focus(req);
826 }
827
828 pub fn focus_alt(&self) {
834 let req = FocusRequest::alt(FOCUS_SV.read().is_highlighting);
835 self.focus(req);
836 }
837}
838
839enum PendingFocusRequest {
840 None,
841 InfoRetry(FocusRequest, DInstant),
842 Update(FocusRequest),
843 RetryUpdate(FocusRequest),
844}
845impl PendingFocusRequest {
846 fn take_update(&mut self) -> Option<(FocusRequest, bool)> {
847 match mem::replace(self, PendingFocusRequest::None) {
848 PendingFocusRequest::Update(r) => Some((r, false)),
849 PendingFocusRequest::RetryUpdate(r) => Some((r, true)),
850 r => {
851 *self = r;
852 None
853 }
854 }
855 }
856 fn take_info(&mut self) -> Option<FocusRequest> {
857 match mem::replace(self, PendingFocusRequest::None) {
858 PendingFocusRequest::InfoRetry(r, i) => {
859 if i.elapsed() < 100.ms() {
860 Some(r)
861 } else {
862 None
863 }
864 }
865 r => {
866 *self = r;
867 None
868 }
869 }
870 }
871}
872
873struct PendingWindowFocus {
874 window: WindowId,
875 target: WidgetId,
876 highlight: bool,
877 nav_origin: Option<WidgetId>,
878}
879
880struct FocusService {
881 auto_highlight: ArcVar<Option<Duration>>,
882 last_keyboard_event: DInstant,
883
884 focus_disabled_widgets: ArcVar<bool>,
885 focus_hidden_widgets: ArcVar<bool>,
886
887 request: PendingFocusRequest,
888
889 focused_var: ArcVar<Option<InteractionPath>>,
890 focused: Option<FocusedInfo>,
891 navigation_origin_var: ArcVar<Option<WidgetId>>,
892 navigation_origin: Option<WidgetId>,
893
894 return_focused_var: IdMap<WidgetId, ArcVar<Option<InteractionPath>>>,
895 return_focused: IdMap<WidgetId, InteractionPath>,
896
897 alt_return_var: ArcVar<Option<InteractionPath>>,
898 alt_return: Option<(InteractionPath, InteractionPath)>,
899
900 is_highlighting_var: ArcVar<bool>,
901 is_highlighting: bool,
902
903 enabled_nav: EnabledNavWithFrame,
904
905 pending_window_focus: Option<PendingWindowFocus>,
906 pending_highlight: bool,
907}
908impl FocusService {
909 #[must_use]
910 fn new() -> Self {
911 Self {
912 auto_highlight: var(Some(300.ms())),
913 last_keyboard_event: DInstant::EPOCH,
914
915 focus_disabled_widgets: var(true),
916 focus_hidden_widgets: var(true),
917
918 request: PendingFocusRequest::None,
919
920 focused_var: var(None),
921 focused: None,
922 navigation_origin_var: var(None),
923 navigation_origin: None,
924
925 return_focused_var: IdMap::default(),
926 return_focused: IdMap::default(),
927
928 alt_return_var: var(None),
929 alt_return: None,
930
931 is_highlighting_var: var(false),
932 is_highlighting: false,
933
934 enabled_nav: EnabledNavWithFrame::invalid(),
935
936 pending_window_focus: None,
937 pending_highlight: false,
938 }
939 }
940
941 fn auto_highlight(&self, timestamp: DInstant) -> bool {
942 if let Some(dur) = self.auto_highlight.get() {
943 if timestamp.duration_since(self.last_keyboard_event) <= dur {
944 return true;
945 }
946 }
947 false
948 }
949
950 fn update_enabled_nav_with_origin(&mut self) {
951 let mut origin = self
952 .focused
953 .as_ref()
954 .and_then(|f| WINDOWS.widget_tree(f.path.window_id()).ok()?.get(f.path.widget_id()));
955 if let (Some(id), Some(focused)) = (self.navigation_origin, &origin) {
956 if let Some(o) = focused.tree().get(id) {
957 origin = Some(o);
958 }
959 }
960
961 if let Some(o) = origin {
962 let o = o.into_focus_info(self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get());
963 self.enabled_nav = o.enabled_nav_with_frame();
964 } else {
965 self.enabled_nav.nav = FocusNavAction::empty();
966 }
967 }
968
969 #[must_use]
970 fn fulfill_request(&mut self, request: FocusRequest, is_info_retry: bool) -> Option<FocusChangedArgs> {
971 match request.target {
972 FocusTarget::Direct { target } => self.focus_direct(target, false, request.highlight, false, false, request),
973 FocusTarget::DirectOrExit { target, navigation_origin } => {
974 self.focus_direct(target, navigation_origin, request.highlight, false, true, request)
975 }
976 FocusTarget::DirectOrEnter { target, navigation_origin } => {
977 self.focus_direct(target, navigation_origin, request.highlight, true, false, request)
978 }
979 FocusTarget::DirectOrRelated { target, navigation_origin } => {
980 self.focus_direct(target, navigation_origin, request.highlight, true, true, request)
981 }
982 move_ => {
983 let origin;
984 let origin_tree;
985 if let Some(o) = self.navigation_origin_var.get() {
986 origin = Some(o);
987 origin_tree = WINDOWS.focused_info();
988 self.navigation_origin_var.set(None);
989 self.navigation_origin = None;
990 } else if let Some(prev) = &self.focused {
991 origin = Some(prev.path.widget_id());
992 origin_tree = WINDOWS.widget_tree(prev.path.window_id()).ok();
993 } else {
994 origin = None;
995 origin_tree = None;
996 }
997
998 if let (Some(info), Some(origin)) = (origin_tree, origin) {
999 if let Some(w) = info.get(origin) {
1000 let w = w.into_focus_info(self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get());
1001 if let Some(new_focus) = match move_ {
1002 FocusTarget::Next => w.next_tab(false),
1004 FocusTarget::Prev => w.prev_tab(false),
1005 FocusTarget::Enter => w.first_tab_descendant(),
1006 FocusTarget::Exit => {
1007 if self.alt_return.is_some() && (w.is_alt_scope() || w.ancestors().any(|w| w.is_alt_scope())) {
1008 self.new_focus_for_alt_exit(w, is_info_retry, request.highlight)
1009 } else {
1010 w.ancestors().next()
1011 }
1012 }
1013 FocusTarget::Up => w.next_up(),
1015 FocusTarget::Right => w.next_right(),
1016 FocusTarget::Down => w.next_down(),
1017 FocusTarget::Left => w.next_left(),
1018 FocusTarget::Alt => {
1020 if let Some(alt) = w.alt_scope() {
1021 Some(alt)
1022 } else if self.alt_return.is_some() {
1023 self.new_focus_for_alt_exit(w, is_info_retry, request.highlight)
1026 } else {
1027 None
1028 }
1029 }
1030 FocusTarget::Direct { .. }
1032 | FocusTarget::DirectOrExit { .. }
1033 | FocusTarget::DirectOrEnter { .. }
1034 | FocusTarget::DirectOrRelated { .. } => {
1035 unreachable!()
1036 }
1037 } {
1038 self.enabled_nav = new_focus.enabled_nav_with_frame();
1040 self.move_focus(
1041 Some(FocusedInfo::new(new_focus)),
1042 None,
1043 request.highlight,
1044 FocusChangedCause::Request(request),
1045 )
1046 } else {
1047 self.continue_focus_highlight(request.highlight)
1049 }
1050 } else {
1051 self.continue_focus_highlight(request.highlight)
1053 }
1054 } else {
1055 self.continue_focus_highlight(request.highlight)
1057 }
1058 }
1059 }
1060 }
1061
1062 #[must_use]
1064 fn new_focus_for_alt_exit(&mut self, prev_w: WidgetFocusInfo, is_info_retry: bool, highlight: bool) -> Option<WidgetFocusInfo> {
1065 let (_, return_path) = self.alt_return.as_ref().unwrap();
1066
1067 let return_int = return_path.interactivity();
1068 let return_id = return_path.widget_id();
1069 let info = prev_w.focus_tree();
1070
1071 let r = info.get_or_parent(return_path);
1072 if let Some(w) = &r {
1073 if w.info().id() != return_id && !is_info_retry && return_int.is_blocked() {
1074 if let Some(exists) = info.tree().get(return_id) {
1077 let exists = exists.into_focus_info(info.focus_disabled_widgets(), info.focus_hidden_widgets());
1078 if !exists.is_focusable() && exists.info().interactivity().is_blocked() {
1079 self.request =
1087 PendingFocusRequest::InfoRetry(FocusRequest::direct_or_related(return_id, false, highlight), INSTANT.now());
1088 }
1089 }
1090 }
1091 }
1092
1093 r
1094 }
1095
1096 #[must_use]
1098 fn continue_focus(&mut self) -> Option<FocusChangedArgs> {
1099 if let Some(focused) = &self.focused {
1100 if let Ok(true) = WINDOWS.is_focused(focused.path.window_id()) {
1101 let info = WINDOWS.widget_tree(focused.path.window_id()).unwrap();
1102 if let Some(widget) = info
1103 .get(focused.path.widget_id())
1104 .map(|w| w.into_focus_info(self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get()))
1105 {
1106 if widget.is_focusable() {
1107 self.enabled_nav = widget.enabled_nav_with_frame();
1109 return self.move_focus(
1110 Some(FocusedInfo::new(widget)),
1111 self.navigation_origin_var.get(),
1112 self.is_highlighting,
1113 FocusChangedCause::Recovery,
1114 );
1115 } else {
1116 if let Some(parent) = widget.parent() {
1118 let new_focus = parent.nearest(focused.center, Px::MAX).unwrap_or(parent);
1120 self.enabled_nav = new_focus.enabled_nav_with_frame();
1121 return self.move_focus(
1122 Some(FocusedInfo::new(new_focus)),
1123 self.navigation_origin_var.get(),
1124 self.is_highlighting,
1125 FocusChangedCause::Recovery,
1126 );
1127 } else {
1128 return self.focus_focused_window(self.is_highlighting);
1130 }
1131 }
1132 } else {
1133 for &parent in focused.path.ancestors().iter().rev() {
1135 if let Some(parent) = info
1136 .get(parent)
1137 .and_then(|w| w.into_focusable(self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get()))
1138 {
1139 let new_focus = parent.nearest(focused.center, Px::MAX).unwrap_or(parent);
1141 self.enabled_nav = new_focus.enabled_nav_with_frame();
1142 return self.move_focus(
1143 Some(FocusedInfo::new(new_focus)),
1144 self.navigation_origin_var.get(),
1145 self.is_highlighting,
1146 FocusChangedCause::Recovery,
1147 );
1148 }
1149 }
1150 }
1151 } } self.focus_focused_window(false)
1154 }
1155
1156 #[must_use]
1157 fn continue_focus_highlight(&mut self, highlight: bool) -> Option<FocusChangedArgs> {
1158 if let Some(mut args) = self.continue_focus() {
1159 args.highlight = highlight;
1160 self.is_highlighting = highlight;
1161 self.is_highlighting_var.set(highlight);
1162 Some(args)
1163 } else if self.is_highlighting != highlight {
1164 self.is_highlighting = highlight;
1165 self.is_highlighting_var.set(highlight);
1166 let focused = self.focused.as_ref().map(|p| p.path.clone());
1167 Some(FocusChangedArgs::now(
1168 focused.clone(),
1169 focused,
1170 highlight,
1171 FocusChangedCause::Recovery,
1172 self.enabled_nav.nav,
1173 ))
1174 } else {
1175 None
1176 }
1177 }
1178
1179 #[must_use]
1180 fn focus_direct(
1181 &mut self,
1182 widget_id: WidgetId,
1183 navigation_origin: bool,
1184 highlight: bool,
1185 fallback_to_children: bool,
1186 fallback_to_parents: bool,
1187 request: FocusRequest,
1188 ) -> Option<FocusChangedArgs> {
1189 let mut next_origin = None;
1190 let mut target = None;
1191 if let Some(w) = WINDOWS
1192 .widget_trees()
1193 .iter()
1194 .find_map(|info| info.get(widget_id))
1195 .map(|w| w.into_focus_info(self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get()))
1196 {
1197 if w.is_focusable() {
1198 let enable = w.enabled_nav_with_frame();
1199 target = Some((FocusedInfo::new(w), enable));
1200 } else if fallback_to_children {
1201 let enable = if navigation_origin {
1202 next_origin = Some(widget_id);
1203 Some(w.enabled_nav_with_frame())
1204 } else {
1205 None
1206 };
1207 if let Some(w) = w.descendants().next() {
1208 let enable = enable.unwrap_or_else(|| w.enabled_nav_with_frame());
1209 target = Some((FocusedInfo::new(w), enable));
1210 }
1211 } else if fallback_to_parents {
1212 let enable = if navigation_origin {
1213 next_origin = Some(widget_id);
1214 Some(w.enabled_nav_with_frame())
1215 } else {
1216 None
1217 };
1218 if let Some(w) = w.parent() {
1219 let enable = enable.unwrap_or_else(|| w.enabled_nav_with_frame());
1220 target = Some((FocusedInfo::new(w), enable));
1221 }
1222 }
1223 }
1224
1225 if let Some((target, enabled_nav)) = target {
1226 if let Ok(false) = WINDOWS.is_focused(target.path.window_id()) {
1227 if request.force_window_focus || WINDOWS.focused_window_id().is_some() {
1228 WINDOWS.focus(target.path.window_id()).unwrap();
1230 } else if request.window_indicator.is_some() {
1231 WINDOWS
1233 .vars(target.path.window_id())
1234 .unwrap()
1235 .focus_indicator()
1236 .set(request.window_indicator);
1237 }
1238
1239 self.pending_window_focus = Some(PendingWindowFocus {
1241 window: target.path.window_id(),
1242 target: target.path.widget_id(),
1243 highlight,
1244 nav_origin: next_origin,
1245 });
1246 self.navigation_origin = next_origin;
1247 self.navigation_origin_var.set(next_origin);
1248 None
1249 } else {
1250 self.enabled_nav = enabled_nav;
1251 self.move_focus(Some(target), next_origin, highlight, FocusChangedCause::Request(request))
1252 }
1253 } else {
1254 self.navigation_origin = next_origin;
1255 self.navigation_origin_var.set(next_origin);
1256 self.change_highlight(highlight, request)
1257 }
1258 }
1259
1260 #[must_use]
1261 fn change_highlight(&mut self, highlight: bool, request: FocusRequest) -> Option<FocusChangedArgs> {
1262 if self.is_highlighting != highlight {
1263 self.is_highlighting = highlight;
1264 self.is_highlighting_var.set(highlight);
1265 let focused = self.focused.as_ref().map(|p| p.path.clone());
1266 Some(FocusChangedArgs::now(
1267 focused.clone(),
1268 focused,
1269 highlight,
1270 FocusChangedCause::Request(request),
1271 self.enabled_nav.nav,
1272 ))
1273 } else {
1274 None
1275 }
1276 }
1277
1278 #[must_use]
1279 fn focus_focused_window(&mut self, highlight: bool) -> Option<FocusChangedArgs> {
1280 if let Some(info) = WINDOWS.focused_info() {
1281 let info = FocusInfoTree::new(info, self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get());
1282 if let Some(root) = info.focusable_root() {
1283 self.enabled_nav = root.enabled_nav_with_frame();
1285 self.move_focus(Some(FocusedInfo::new(root)), None, highlight, FocusChangedCause::Recovery)
1286 } else {
1287 self.enabled_nav = EnabledNavWithFrame::invalid();
1289 self.move_focus(None, None, false, FocusChangedCause::Recovery)
1290 }
1291 } else {
1292 self.enabled_nav = EnabledNavWithFrame::invalid();
1294 self.move_focus(None, None, false, FocusChangedCause::Recovery)
1295 }
1296 }
1297
1298 #[must_use]
1299 fn move_focus(
1300 &mut self,
1301 new_focus: Option<FocusedInfo>,
1302 new_origin: Option<WidgetId>,
1303 highlight: bool,
1304 cause: FocusChangedCause,
1305 ) -> Option<FocusChangedArgs> {
1306 let prev_highlight = std::mem::replace(&mut self.is_highlighting, highlight);
1307 self.is_highlighting_var.set(highlight);
1308
1309 self.navigation_origin = new_origin;
1310 if self.navigation_origin_var.get() != new_origin {
1311 self.navigation_origin_var.set(new_origin);
1312 }
1313
1314 let r = if self.focused.as_ref().map(|p| &p.path) != new_focus.as_ref().map(|p| &p.path) {
1315 let new_focus = new_focus.as_ref().map(|p| p.path.clone());
1316 let args = FocusChangedArgs::now(
1317 self.focused.take().map(|p| p.path),
1318 new_focus.clone(),
1319 self.is_highlighting,
1320 cause,
1321 self.enabled_nav.nav,
1322 );
1323 self.focused_var.set(new_focus);
1324 Some(args)
1325 } else if prev_highlight != highlight {
1326 let new_focus = new_focus.as_ref().map(|p| p.path.clone());
1327 Some(FocusChangedArgs::now(
1328 new_focus.clone(),
1329 new_focus,
1330 highlight,
1331 cause,
1332 self.enabled_nav.nav,
1333 ))
1334 } else {
1335 None
1336 };
1337
1338 self.focused = new_focus;
1340
1341 r
1342 }
1343
1344 #[must_use]
1345 fn move_after_focus(&mut self, is_tab_cycle_reentry: bool, reverse: bool) -> Option<FocusChangedArgs> {
1346 if let Some(focused) = &self.focused {
1347 if let Some(info) = WINDOWS.focused_info() {
1348 if let Some(widget) = FocusInfoTree::new(info, self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get())
1349 .get(focused.path.widget_id())
1350 {
1351 if let Some(nested) = widget.nested_window() {
1352 tracing::debug!("focus nested window {nested:?}");
1353 let _ = WINDOWS.focus(nested);
1354 } else if widget.is_scope() {
1355 let last_focused = |id| self.return_focused.get(&id).map(|p| p.as_path());
1356 if let Some(widget) = widget.on_focus_scope_move(last_focused, is_tab_cycle_reentry, reverse) {
1357 self.enabled_nav = widget.enabled_nav_with_frame();
1358 return self.move_focus(
1359 Some(FocusedInfo::new(widget)),
1360 self.navigation_origin,
1361 self.is_highlighting,
1362 FocusChangedCause::ScopeGotFocus(reverse),
1363 );
1364 }
1365 }
1366 }
1367 }
1368 }
1369 None
1370 }
1371
1372 #[must_use]
1374 fn update_returns(&mut self, prev_focus: Option<InteractionPath>) -> Vec<ReturnFocusChangedArgs> {
1375 let mut r = vec![];
1376
1377 if let Some((scope, _)) = &mut self.alt_return {
1378 let mut retain_alt = false;
1381 if let Some(new_focus) = &self.focused {
1382 if let Some(s) = new_focus.path.ancestor_path(scope.widget_id()) {
1383 retain_alt = true; *scope = s.into_owned();
1385 } else if let Ok(info) = WINDOWS.widget_tree(new_focus.path.window_id()) {
1386 if let Some(widget) = FocusInfoTree::new(info, self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get())
1387 .get(new_focus.path.widget_id())
1388 {
1389 let alt_scope = if widget.is_alt_scope() {
1390 Some(widget)
1391 } else {
1392 widget.scopes().find(|s| s.is_alt_scope())
1393 };
1394
1395 if let Some(alt_scope) = alt_scope {
1396 retain_alt = true;
1398 *scope = alt_scope.info().interaction_path();
1399 }
1400 }
1401 }
1402 }
1403
1404 if !retain_alt {
1405 let (scope, widget_path) = self.alt_return.take().unwrap();
1406 self.alt_return_var.set(None);
1407 r.push(ReturnFocusChangedArgs::now(scope, Some(widget_path), None));
1408 }
1409 } else if let Some(new_focus) = &self.focused {
1410 if let Ok(info) = WINDOWS.widget_tree(new_focus.path.window_id()) {
1414 if let Some(widget) = FocusInfoTree::new(info, self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get())
1415 .get(new_focus.path.widget_id())
1416 {
1417 let alt_scope = if widget.is_alt_scope() {
1418 Some(widget)
1419 } else {
1420 widget.scopes().find(|s| s.is_alt_scope())
1421 };
1422 if let Some(alt_scope) = alt_scope {
1423 let scope = alt_scope.info().interaction_path();
1424 if let Some(prev) = &prev_focus {
1427 r.push(ReturnFocusChangedArgs::now(scope.clone(), None, Some(prev.clone())));
1429 self.alt_return = Some((scope, prev.clone()));
1430 self.alt_return_var.set(prev.clone());
1431 } else if let Some(parent) = alt_scope.parent() {
1432 let parent_path = parent.info().interaction_path();
1434 r.push(ReturnFocusChangedArgs::now(scope.clone(), None, Some(parent_path.clone())));
1435 self.alt_return = Some((scope, parent_path.clone()));
1436 self.alt_return_var.set(parent_path);
1437 }
1438 }
1439 }
1440 }
1441 }
1442
1443 if let Some(new_focus) = &self.focused {
1448 if let Ok(info) = WINDOWS.widget_tree(new_focus.path.window_id()) {
1449 if let Some(widget) = FocusInfoTree::new(info, self.focus_disabled_widgets.get(), self.focus_hidden_widgets.get())
1450 .get(new_focus.path.widget_id())
1451 {
1452 if !widget.is_alt_scope() && widget.scopes().all(|s| !s.is_alt_scope()) {
1453 for scope in widget
1456 .scopes()
1457 .filter(|s| s.focus_info().scope_on_focus() == FocusScopeOnFocus::LastFocused)
1458 {
1459 let scope = scope.info().interaction_path();
1460 let path = widget.info().interaction_path();
1461 if let Some(current) = self.return_focused.get_mut(&scope.widget_id()) {
1462 if current != &path {
1463 let prev = std::mem::replace(current, path);
1464 self.return_focused_var.get(&scope.widget_id()).unwrap().set(current.clone());
1465 r.push(ReturnFocusChangedArgs::now(scope, Some(prev), Some(current.clone())));
1466 }
1467 } else {
1468 self.return_focused.insert(scope.widget_id(), path.clone());
1469 match self.return_focused_var.entry(scope.widget_id()) {
1470 IdEntry::Occupied(e) => e.get().set(Some(path.clone())),
1471 IdEntry::Vacant(e) => {
1472 e.insert(var(Some(path.clone())));
1473 }
1474 }
1475 r.push(ReturnFocusChangedArgs::now(scope, None, Some(path)));
1476 }
1477 }
1478 }
1479 }
1480 }
1481 }
1482
1483 r
1484 }
1485
1486 #[must_use]
1488 fn cleanup_returns(&mut self, info: FocusInfoTree) -> Vec<ReturnFocusChangedArgs> {
1489 let mut r = vec![];
1490
1491 if self.return_focused_var.len() > 20 {
1492 self.return_focused_var
1493 .retain(|_, var| var.strong_count() > 1 || var.with(Option::is_some))
1494 }
1495
1496 self.return_focused.retain(|&scope_id, widget_path| {
1497 if widget_path.window_id() != info.tree().window_id() {
1498 return true; }
1500
1501 let mut retain = false;
1502
1503 if let Some(widget) = info.tree().get(widget_path.widget_id()) {
1504 if let Some(scope) = widget
1505 .clone()
1506 .into_focus_info(info.focus_disabled_widgets(), info.focus_hidden_widgets())
1507 .scopes()
1508 .find(|s| s.info().id() == scope_id)
1509 {
1510 if scope.focus_info().scope_on_focus() == FocusScopeOnFocus::LastFocused {
1511 retain = true; let path = widget.interaction_path();
1514 if &path != widget_path {
1515 r.push(ReturnFocusChangedArgs::now(
1517 scope.info().interaction_path(),
1518 Some(widget_path.clone()),
1519 Some(path.clone()),
1520 ));
1521 *widget_path = path;
1522 }
1523 }
1524 } else if let Some(scope) = info.get(scope_id) {
1525 if scope.focus_info().scope_on_focus() == FocusScopeOnFocus::LastFocused {
1526 if let Some(first) = scope.first_tab_descendant() {
1528 retain = true;
1530
1531 let path = first.info().interaction_path();
1532 r.push(ReturnFocusChangedArgs::now(
1533 scope.info().interaction_path(),
1534 Some(widget_path.clone()),
1535 Some(path.clone()),
1536 ));
1537 *widget_path = path;
1538 }
1539 }
1540 }
1541 } else if let Some(parent) = info.get_or_parent(widget_path) {
1542 if let Some(scope) = parent.scopes().find(|s| s.info().id() == scope_id) {
1544 if scope.focus_info().scope_on_focus() == FocusScopeOnFocus::LastFocused {
1545 retain = true;
1547
1548 let path = parent.info().interaction_path();
1549 r.push(ReturnFocusChangedArgs::now(
1550 scope.info().interaction_path(),
1551 Some(widget_path.clone()),
1552 Some(path.clone()),
1553 ));
1554 *widget_path = path;
1555 }
1556 }
1557 }
1558
1559 if !retain {
1560 let scope_path = info.get(scope_id).map(|i| i.info().interaction_path());
1561
1562 if scope_path.is_some() {
1563 match self.return_focused_var.entry(scope_id) {
1564 IdEntry::Occupied(e) => {
1565 if e.get().strong_count() == 1 {
1566 e.remove();
1567 } else {
1568 e.get().set(None);
1569 }
1570 }
1571 IdEntry::Vacant(_) => {}
1572 }
1573 } else if let Some(var) = self.return_focused_var.remove(&scope_id) {
1574 if var.strong_count() > 1 {
1575 var.set(None);
1576 }
1577 }
1578
1579 r.push(ReturnFocusChangedArgs::now(scope_path, Some(widget_path.clone()), None));
1580 }
1581 retain
1582 });
1583
1584 let mut retain_alt = true;
1585 if let Some((scope, widget_path)) = &mut self.alt_return {
1586 if widget_path.window_id() == info.tree().window_id() {
1587 retain_alt = false; if let Some(widget) = info.tree().get(widget_path.widget_id()) {
1592 if !widget
1593 .clone()
1594 .into_focus_info(info.focus_disabled_widgets(), info.focus_hidden_widgets())
1595 .scopes()
1596 .any(|s| s.info().id() == scope.widget_id())
1597 {
1598 retain_alt = true; let path = widget.interaction_path();
1601 if &path != widget_path {
1602 r.push(ReturnFocusChangedArgs::now(
1604 scope.clone(),
1605 Some(widget_path.clone()),
1606 Some(path.clone()),
1607 ));
1608 *widget_path = path;
1609 }
1610 }
1611 } else if let Some(parent) = info.get_or_parent(widget_path) {
1612 if !parent.scopes().any(|s| s.info().id() == scope.widget_id()) {
1614 retain_alt = true;
1616
1617 let path = parent.info().interaction_path();
1618 r.push(ReturnFocusChangedArgs::now(
1619 scope.clone(),
1620 Some(widget_path.clone()),
1621 Some(path.clone()),
1622 ));
1623 *widget_path = path.clone();
1624 self.alt_return_var.set(path);
1625 }
1626 }
1627 }
1628 }
1629 if !retain_alt {
1630 let (scope_id, widget_path) = self.alt_return.take().unwrap();
1631 self.alt_return_var.set(None);
1632 r.push(ReturnFocusChangedArgs::now(scope_id, Some(widget_path), None));
1633 }
1634
1635 r
1636 }
1637
1638 #[must_use]
1640 fn cleanup_returns_win_closed(&mut self, window_id: WindowId) -> Vec<ReturnFocusChangedArgs> {
1641 let mut r = vec![];
1642
1643 if self
1644 .alt_return
1645 .as_ref()
1646 .map(|(_, w)| w.window_id() == window_id)
1647 .unwrap_or_default()
1648 {
1649 let (_, widget_path) = self.alt_return.take().unwrap();
1650 self.alt_return_var.set(None);
1651 r.push(ReturnFocusChangedArgs::now(None, Some(widget_path), None));
1652 }
1653
1654 self.return_focused.retain(|&scope_id, widget_path| {
1655 let retain = widget_path.window_id() != window_id;
1656
1657 if !retain {
1658 let var = self.return_focused_var.remove(&scope_id).unwrap();
1659 var.set(None);
1660
1661 r.push(ReturnFocusChangedArgs::now(None, Some(widget_path.clone()), None));
1662 }
1663
1664 retain
1665 });
1666
1667 r
1668 }
1669
1670 fn update_focused_center(&mut self) {
1671 if let Some(f) = &mut self.focused {
1672 let bounds = f.bounds_info.inner_bounds();
1673 if bounds != PxRect::zero() {
1674 f.center = bounds.center();
1675 }
1676 }
1677 }
1678}
1679
1680#[derive(Debug)]
1681struct FocusedInfo {
1682 path: InteractionPath,
1683 bounds_info: WidgetBoundsInfo,
1684 center: PxPoint,
1685}
1686impl FocusedInfo {
1687 pub fn new(focusable: WidgetFocusInfo) -> Self {
1688 FocusedInfo {
1689 path: focusable.info().interaction_path(),
1690 bounds_info: focusable.info().bounds_info(),
1691 center: focusable.info().center(),
1692 }
1693 }
1694}
1695
1696struct EnabledNavWithFrame {
1697 nav: FocusNavAction,
1698 spatial_frame_id: FrameId,
1699 visibility_id: FrameId,
1700}
1701impl EnabledNavWithFrame {
1702 fn invalid() -> Self {
1703 Self {
1704 nav: FocusNavAction::empty(),
1705 spatial_frame_id: FrameId::INVALID,
1706 visibility_id: FrameId::INVALID,
1707 }
1708 }
1709 fn needs_refresh(&self, tree: &WidgetInfoTree) -> bool {
1710 let stats = tree.stats();
1711 stats.bounds_updated_frame != self.spatial_frame_id || stats.vis_updated_frame != self.visibility_id
1712 }
1713}
1714trait EnabledNavWithFrameExt {
1715 fn enabled_nav_with_frame(&self) -> EnabledNavWithFrame;
1716}
1717impl EnabledNavWithFrameExt for WidgetFocusInfo {
1718 fn enabled_nav_with_frame(&self) -> EnabledNavWithFrame {
1719 let stats = self.info().tree().stats();
1720 EnabledNavWithFrame {
1721 nav: self.enabled_nav(),
1722 spatial_frame_id: stats.bounds_updated_frame,
1723 visibility_id: stats.vis_updated_frame,
1724 }
1725 }
1726}