Release focus when the sheet tab rename ends (#145)

This commit is contained in:
MarekSpodBiedry
2026-10-10 19:10:19 +02:00
parent 19094e2d62
commit 2cc7dde6c3
2 changed files with 81 additions and 1 deletions
+21 -1
View File
@@ -8,6 +8,12 @@ use crate::SheetApp;
use crate::icons::{self, Icon};
use crate::theme::{self, Tokens};
/// The rename field asks for focus only while it has not got it yet. Asking again on the frame it lost focus (Enter or a click elsewhere)
/// would keep the field focused after it is closed, so the keyboard stayed stuck in the sheet name.
fn rename_needs_focus(has_focus: bool, lost_focus: bool) -> bool {
!has_focus && !lost_focus
}
pub fn sheet_tabs(app: &mut SheetApp, ui: &mut Ui) {
let t = Tokens::get(ui.ctx());
egui::Panel::bottom("sheet_tabs").exact_size(32.0).frame(egui::Frame::NONE.fill(t.tab_bar)).show(ui, |ui| {
@@ -61,7 +67,9 @@ pub fn sheet_tabs(app: &mut SheetApp, ui: &mut Ui) {
let mut child = ui.new_child(egui::UiBuilder::new().max_rect(r.shrink2(vec2(6.0, 5.0))));
let ed = child.add(egui::TextEdit::singleline(&mut text).font(theme::ui_font(13.0)).desired_width(r.width() - 12.0));
app.grid.rename_text = text.clone();
ed.request_focus();
if rename_needs_focus(ed.has_focus(), ed.lost_focus()) {
ed.request_focus();
}
if ed.lost_focus() {
if !ui.input(|i| i.key_pressed(egui::Key::Escape)) && text != name {
app.run_or_alert("sheet.rename", json!({"sheet": i, "name": text}));
@@ -285,3 +293,15 @@ pub fn status_bar(app: &mut SheetApp, ui: &mut Ui) {
},
);
}
#[cfg(test)]
mod tests {
use super::rename_needs_focus;
#[test]
fn rename_field_takes_focus_once_and_lets_go_on_commit() {
assert!(rename_needs_focus(false, false), "first frame: grab focus");
assert!(!rename_needs_focus(true, false), "already focused: do not ask again");
assert!(!rename_needs_focus(false, true), "Enter or click-away: must not take focus back");
}
}
+60
View File
@@ -0,0 +1,60 @@
//! Renaming a sheet tab: the name field must let go of the keyboard when the user is done (#145).
use egui::{Event, Key, Modifiers, PointerButton};
use gridcraft_engine::Session;
use gridcraft_engine::core::CellRef;
use gridcraft_ui_egui::{SheetApp, grid::Geo};
fn harness() -> egui_kittest::Harness<'static, SheetApp> {
let mut s = Session::new();
s.new_workbook();
let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state(
|ui, app: &mut SheetApp| {
let ctx = ui.ctx().clone();
app.logic(&ctx);
app.ui(ui);
},
SheetApp::new(s, Default::default()),
);
h.run_steps(4);
h
}
fn start_rename(h: &mut egui_kittest::Harness<'static, SheetApp>, new_name: &str) {
h.state_mut().grid.renaming_tab = Some(0);
h.state_mut().grid.rename_text = new_name.to_string();
h.run_steps(3);
}
fn sheet_name(h: &egui_kittest::Harness<'static, SheetApp>) -> String {
h.state().session.active().unwrap().wb.sheets[0].name.clone()
}
#[test]
fn enter_saves_the_sheet_name_and_closes_the_field() {
let mut h = harness();
start_rename(&mut h, "Budget");
h.input_mut().events.push(Event::Key { key: Key::Enter, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE });
h.input_mut().events.push(Event::Key { key: Key::Enter, physical_key: None, pressed: false, repeat: false, modifiers: Modifiers::NONE });
h.run_steps(3);
assert_eq!(h.state().grid.renaming_tab, None, "Enter must close the rename field");
assert_eq!(sheet_name(&h), "Budget");
}
#[test]
fn clicking_a_cell_saves_the_sheet_name_and_closes_the_field() {
let mut h = harness();
start_rename(&mut h, "Ledger");
let app = h.state();
let sheet = app.session.active().unwrap().wb.active().unwrap();
let geo = Geo::new(sheet, app.grid.rect.unwrap(), app.view().scroll);
let pos = geo.cell_rect(sheet, CellRef::parse("B2").unwrap()).center();
h.input_mut().events.extend([
Event::PointerMoved(pos),
Event::PointerButton { pos, button: PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE },
Event::PointerButton { pos, button: PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE },
]);
h.run_steps(3);
assert_eq!(h.state().grid.renaming_tab, None, "clicking elsewhere must close the rename field");
assert_eq!(sheet_name(&h), "Ledger");
}