From 7d57deb8ae2706d2379e0ff103ee7bb94967108e Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Thu, 14 Oct 2021 13:44:21 -0700 Subject: [PATCH] Move the focus state from Panel up to widgetry in general, so two different panels don't clash --- widgetry/src/event_ctx.rs | 10 ++++++++++ widgetry/src/runner.rs | 17 ++++++++++++++++- widgetry/src/widgets/containers.rs | 2 +- widgetry/src/widgets/mod.rs | 3 --- widgetry/src/widgets/panel.rs | 12 ++---------- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/widgetry/src/event_ctx.rs b/widgetry/src/event_ctx.rs index 5bffcdf0b8..c44dcf1611 100644 --- a/widgetry/src/event_ctx.rs +++ b/widgetry/src/event_ctx.rs @@ -34,6 +34,12 @@ pub struct EventCtx<'a> { pub(crate) style: &'a mut Style, pub(crate) updates_requested: Vec, pub(crate) canvas_movement_called: bool, + + /// This widget (in some panel) exclusively owns focus. Don't modify. + pub(crate) focus_owned_by: Option, + /// While handling an event, this widget (in some panel) this widget declared that it owns + /// focus. This will become `focus_owned_by` during the next event. + pub(crate) next_focus_owned_by: Option, } impl<'a> EventCtx<'a> { @@ -84,6 +90,8 @@ impl<'a> EventCtx<'a> { style: self.style, updates_requested: vec![], canvas_movement_called: false, + focus_owned_by: None, + next_focus_owned_by: None, }; let result = cb(&mut tmp); self.updates_requested.extend(tmp.updates_requested); @@ -268,6 +276,8 @@ impl<'a> LoadingScreen<'a> { style: &mut self.style, updates_requested: vec![], canvas_movement_called: false, + focus_owned_by: None, + next_focus_owned_by: None, }; let mut txt = Text::from(Line(&self.title).small_heading()); diff --git a/widgetry/src/runner.rs b/widgetry/src/runner.rs index 81b2b24c7f..da4407115f 100644 --- a/widgetry/src/runner.rs +++ b/widgetry/src/runner.rs @@ -25,6 +25,8 @@ pub(crate) struct State { pub(crate) app: App, pub(crate) canvas: Canvas, style: Style, + + focus_owned_by: Option, } impl State { @@ -108,9 +110,15 @@ impl State { style: &mut self.style, updates_requested: vec![], canvas_movement_called: false, + + focus_owned_by: self.focus_owned_by.take(), + // If the widget owning focus doesn't renew it, then it'll expire by the end of + // this event. + next_focus_owned_by: None, }; let started = Instant::now(); self.app.event(&mut ctx); + self.focus_owned_by = ctx.next_focus_owned_by.take(); if DEBUG_PERFORMANCE { println!("- event() took {}s", elapsed_seconds(started)); } @@ -356,6 +364,8 @@ pub fn run< style: &mut style, updates_requested: vec![], canvas_movement_called: false, + focus_owned_by: None, + next_focus_owned_by: None, }); timer.stop("setup app"); let app = App { @@ -364,7 +374,12 @@ pub fn run< }; timer.done(); - let mut state = State { app, canvas, style }; + let mut state = State { + app, + canvas, + style, + focus_owned_by: None, + }; let dump_raw_events = settings.dump_raw_events; diff --git a/widgetry/src/widgets/containers.rs b/widgetry/src/widgets/containers.rs index d97fcdbf7f..36c1b00e50 100644 --- a/widgetry/src/widgets/containers.rs +++ b/widgetry/src/widgets/containers.rs @@ -48,7 +48,7 @@ impl WidgetImpl for Container { fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) { for w in &mut self.members { - if let Some(id) = output.prev_focus_owned_by.as_ref() { + if let Some(id) = ctx.focus_owned_by.as_ref() { // Container is the only place that needs to actually enforce focus. If a Panel // consists of only one top-level widget, then there's nothing else to conflict // with focus. And in the common case, we have a tree of Containers, with diff --git a/widgetry/src/widgets/mod.rs b/widgetry/src/widgets/mod.rs index c6eed16314..0a258a72d2 100644 --- a/widgetry/src/widgets/mod.rs +++ b/widgetry/src/widgets/mod.rs @@ -98,8 +98,6 @@ pub struct WidgetOutput { /// This widget produced an Outcome, and event handling should immediately stop. Most widgets /// shouldn't set this. pub outcome: Outcome, - /// This widget exclusively owned focus as of the last event. Don't modify. - pub prev_focus_owned_by: Option, } impl WidgetOutput { @@ -107,7 +105,6 @@ impl WidgetOutput { WidgetOutput { redo_layout: false, outcome: Outcome::Nothing, - prev_focus_owned_by: None, } } } diff --git a/widgetry/src/widgets/panel.rs b/widgetry/src/widgets/panel.rs index cb81a579f2..8cc14e9196 100644 --- a/widgetry/src/widgets/panel.rs +++ b/widgetry/src/widgets/panel.rs @@ -31,10 +31,6 @@ pub struct Panel { contents_dims: ScreenDims, container_dims: ScreenDims, clip_rect: Option, - - // TODO Currently this only works for widgets in the same Panel, but this should handle all - // Panels on-screen. - focus_owned_by: Option, } impl Panel { @@ -310,9 +306,6 @@ impl Panel { let before = self.scroll_offset(); let mut output = WidgetOutput::new(); - // If the widget owning focus doesn't renew it, then it'll expire by the end of this event. - output.prev_focus_owned_by = self.focus_owned_by.take(); - self.top_level.widget.event(ctx, &mut output); if output.redo_layout { @@ -323,7 +316,8 @@ impl Panel { // Remember this for the next event if let Outcome::Focused(ref id) = output.outcome { - self.focus_owned_by = Some(id.clone()); + assert!(ctx.next_focus_owned_by.is_none()); + ctx.next_focus_owned_by = Some(id.clone()); } output.outcome @@ -616,8 +610,6 @@ impl PanelBuilder { container_dims: ScreenDims::new(0.0, 0.0), clip_rect: None, cached_flexbox: None, - - focus_owned_by: None, }; match panel.dims { Dims::ExactPercent(w, h) => {