graphic design tool
git clone https://git.lucas.co/cce-designer.git
refactor(focus): drive focus through UiContext::focus_widget / unfocus_widget
A direct w.focus() / w.unfocus() left the window's record of focus (the Tab
walk, the accessibility tree) behind: on a widget that had let go, or beside
a newly focused one. The UiContext helpers do what the direct call did and
keep the record in step (cce-ui's global-state RFC, phase 2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/app.rs | 24 ++++++++++++------------
src/main.rs | 8 ++++----
2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index b0c10f4..636388e 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -7122,7 +7122,7 @@ impl State {
if self.focused_pane != LEFT_MENUBAR_IDX {
self.focused_pane = LEFT_MENUBAR_IDX;
if let Some(old) = self.focused_widget.take() {
- self.slots.get_dyn_mut(old).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(old));
}
self.sync_pane_focus();
}
@@ -9424,7 +9424,7 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
self.slots.param_menubar.set_selected(PARAM_MENUBAR_IDX == f);
self.slots.spreadsheet_menubar.set_selected(SPREADSHEET_MENUBAR_IDX == f);
if self.focused_pane != PARAM_MENUBAR_IDX {
- self.slots.param.unfocus();
+ self.ui_context.unfocus_widget(&mut self.slots.param);
self.sync_parameters_to_project();
}
self.sync_context_dropdowns();
@@ -11150,10 +11150,10 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
if on_border {
self.focused_pane = LEFT_MENUBAR_IDX;
if let Some(old) = self.focused_widget {
- self.slots.get_dyn_mut(old).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(old));
self.focused_widget = None;
}
- self.slots.param.unfocus();
+ self.ui_context.unfocus_widget(&mut self.slots.param);
self.sync_parameters_to_project();
return true;
}
@@ -11185,7 +11185,7 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
});
self.focused_pane = PARAM_MENUBAR_IDX;
if let Some(old) = self.focused_widget {
- self.slots.get_dyn_mut(old).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(old));
self.focused_widget = None;
}
return true;
@@ -11204,7 +11204,7 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
});
self.focused_pane = SPREADSHEET_MENUBAR_IDX;
if let Some(old) = self.focused_widget {
- self.slots.get_dyn_mut(old).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(old));
self.focused_widget = None;
}
return true;
@@ -11253,7 +11253,7 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
self.grid_cursor_drag = Some((col, row));
self.focused_pane = LEFT_MENUBAR_IDX;
if let Some(old) = self.focused_widget.take() {
- self.slots.get_dyn_mut(old).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(old));
}
self.sync_pane_focus();
return true;
@@ -11280,7 +11280,7 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
}
self.focused_pane = RIGHT_MENUBAR_IDX;
if let Some(old) = self.focused_widget {
- self.slots.get_dyn_mut(old).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(old));
self.focused_widget = None;
}
self.sync_pane_focus();
@@ -11419,12 +11419,12 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
if let Some(old) = self.focused_widget {
if click_target != Some(old) && click_target != Some(PARAM_IDX) {
- self.slots.get_dyn_mut(old).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(old));
self.focused_widget = None;
}
}
if click_target != Some(PARAM_IDX) {
- self.slots.param.unfocus();
+ self.ui_context.unfocus_widget(&mut self.slots.param);
self.sync_parameters_to_project();
}
if click_target.is_none() && in_circle_network_pane {
@@ -11470,12 +11470,12 @@ pub(crate) fn geometry_to_spreadsheet_columns(geom: &Detail) -> (Vec<String>, Ve
self.drag_press_cursor = Some((self.cursor_x, self.cursor_y));
}
if i != PARAM_IDX {
- self.slots.get_dyn_mut(i).focus();
+ self.ui_context.focus_widget(self.slots.get_dyn_mut(i));
self.focused_widget = Some(i);
if self.menubar_at(i).map(|m| m.is_menu_bar()).unwrap_or(false)
&& !self.slots.get_dyn_mut(i).focused(&self.ui_context)
{
- self.slots.get_dyn_mut(i).unfocus();
+ self.ui_context.unfocus_widget(self.slots.get_dyn_mut(i));
self.focused_widget = None;
}
}
diff --git a/src/main.rs b/src/main.rs
index b8e8b3b..1ef7d16 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2528,7 +2528,7 @@ mod tests {
assert!((state.geo_opacity - 0.40).abs() < 1e-6);
// Press on the band's right end: 100%, live; drag back; release.
- let band = context_menu::CONTEXT_MENU.with(|m| m.borrow().slider_band(i));
+ let band = context_menu::with_state(|m| m.borrow().slider_band(i));
state.cursor_x = band.x + band.width - 1.0;
state.handle_event(&WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left });
assert!((state.geo_opacity - 1.0).abs() < 1e-6, "{}", state.geo_opacity);
@@ -3266,7 +3266,7 @@ mod tests {
assert!(kdl.contains("wire_width (f64)3") || kdl.contains("wire_width 3"), "persisted: {kdl}");
assert!(state.viewport_menu_open());
- let band = context_menu::CONTEXT_MENU.with(|m| m.borrow().slider_band(i));
+ let band = context_menu::with_state(|m| m.borrow().slider_band(i));
state.cursor_x = band.x + 1.0;
state.handle_event(&WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left });
state.handle_event(&WindowEvent::MouseInput { state: ElementState::Released, button: MouseButton::Left });
@@ -3290,7 +3290,7 @@ mod tests {
state.cursor_x = 300.0;
state.cursor_y = 200.0;
state.open_viewport_context_menu();
- let full = context_menu::CONTEXT_MENU.with(|m| m.borrow().content_h);
+ let full = context_menu::with_state(|m| m.borrow().content_h);
context_menu::place(300.0, 0.0, full * 0.5);
// Over the first row, which is Frame All — an action, not a slider.
@@ -3301,7 +3301,7 @@ mod tests {
position: LocalPosition { x: state.cursor_x as f64, y: state.cursor_y as f64 },
});
state.handle_event(&WindowEvent::MouseWheel { delta: MouseScrollDelta::LineDelta(0.0, -3.0) });
- let scroll = context_menu::CONTEXT_MENU.with(|m| m.borrow().scroll);
+ let scroll = context_menu::with_state(|m| m.borrow().scroll);
assert_eq!(scroll, 3.0 * context_menu::ROW_H, "three notches down, three rows");
assert!(state.viewport_menu_open(), "scrolling keeps the menu up");