From 3bb284cfdd15b357bf252449e68f54cd67cc983f Mon Sep 17 00:00:00 2001 From: Alexander Alber <90604107+alexanderalber@users.noreply.github.com> Date: Sun, 11 Oct 2026 09:26:42 +0200 Subject: [PATCH] Text: typing goes on after Tab in a text box (#78) The engine handled Tab (a tab character, or a list level at the start of a paragraph), but egui also treated it as focus navigation: with no widget focused it focused the first ribbon widget, and since the slide only takes keys while nothing is focused, every key after Tab was lost. When the slide has the keyboard, the keyboard handler now cancels that focus move. This also covers the "can't type after indenting" part of #93. generated with Claude Code --- crates/ui-egui/src/lib.rs | 44 +++++++++++++++++++++++++++++++++++++++ docs/gaps.md | 6 +----- docs/ui-parity.md | 3 ++- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index bef64a4f..6983f1c7 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -664,6 +664,12 @@ impl SlideApp { } } egui::Event::Key { key, pressed: true, modifiers, .. } => { + if key == egui::Key::Tab { + // The slide has the keyboard, so Tab is ours (indent, tab character, next + // shape). Left to egui it would also focus the first ribbon widget, and + // every key after it would go there instead of the slide (#78). + ctx.memory_mut(|m| m.move_focus(egui::FocusDirection::None)); + } let mods = Mods { shift: modifiers.shift, alt: modifiers.alt, cmd: modifiers.command || modifiers.ctrl }; if !self.session.tool.drawing_freeform() && menus::ui_shortcut(self, key, mods) { continue; @@ -932,6 +938,44 @@ mod tests { assert_eq!(harness.state().session.documents().len(), 2); } + /// #78: after Tab in a text box, typing and deleting no longer reached the text. + #[test] + fn typing_goes_on_after_tab_in_a_text_box() { + let mut harness = egui_kittest::Harness::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( + |ui, app: &mut SlideApp| { + app.logic(ui.ctx()); + app.ui(ui); + }, + SlideApp::new(Session::with_new(), Services::default()), + ); + harness.run_steps(2); + let title = harness.state().session.active().unwrap().doc.slides[0].shapes[0].id.0; + harness.state_mut().session.execute("text.edit", &json!({"id": title})).unwrap(); + harness.event(egui::Event::Text("ab".into())); + harness.run_steps(2); + harness.key_press(egui::Key::Tab); + harness.run_steps(2); + harness.event(egui::Event::Text("c".into())); + harness.run_steps(2); + assert_eq!(title_text(harness.state()), "ab\tc"); + harness.key_press(egui::Key::Backspace); + harness.run_steps(2); + assert_eq!(title_text(harness.state()), "ab\t"); + assert!(harness.state().session.active().unwrap().selection.text.is_some(), "still editing"); + // Tab at the start of a paragraph indents it, and typing goes on there too (#93). + harness.key_press(egui::Key::Enter); + harness.run_steps(2); + harness.key_press(egui::Key::Tab); + harness.run_steps(2); + harness.event(egui::Event::Text("d".into())); + harness.run_steps(2); + assert_eq!(title_text(harness.state()), "ab\t\nd"); + let level = |h: &egui_kittest::Harness| { + h.state().session.active().unwrap().doc.slides[0].shapes[0].text.as_ref().unwrap().paragraphs[1].level + }; + assert_eq!(level(&harness), 1); + } + #[test] fn home_needs_an_open_presentation() { let mut app = SlideApp::new(Session::new(), Services::default()); diff --git a/docs/gaps.md b/docs/gaps.md index 6ea4130a..fa303000 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -138,11 +138,6 @@ Detail in [file-format-parity.md](file-format-parity.md). - **Impact:** copy-paste of screenshots is a core workflow. - **Estimate:** 2โ€“4 h. **Beta blocker.** -### Tab inside a text box ends text entry (#78) -- **Evidence:** #78. -- **Impact:** tab stops and indented lists can't be typed. -- **Estimate:** 1โ€“2 h. - ### Charts: data grid, elements and the newer chart types - **Evidence:** checklist rows "Edit chart data" (P0, partial), "Chart elements" (partial), "Other chart types" (partial); `chartex` parts (waterfall, funnel, treemap, sunburst, histogram, box & @@ -247,5 +242,6 @@ Detail in [localization-parity.md](localization-parity.md). | Date | Change | Summary | |---|---|---| +| 2026-10-11 | minor | Removed "Tab inside a text box ends text entry" (#78, fixed) | | 2026-10-10 | minor | Noted that no gap blocks alpha (core-workflow gate passes) | | 2026-10-10 | major | Created: every gap from the 2026-10-10 re-measure and the 16 open GitHub issues, ranked, with beta blockers marked | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 5c7c50b9..8fe5e08d 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -48,7 +48,7 @@ AGENTS.md ยง2). Dimension score: **~60% ready** (estimated), **30โ€“50 h** to pa | Connector glue and rerouting | yes | yes | | Edit points on freeforms | yes | **no** | | Crop handles, crop to shape, aspect ratio | yes | partial | -| Text caret, selection, double/triple click, drag-select | yes | yes; Tab in text boxes ends editing (#78) | +| Text caret, selection, double/triple click, drag-select | yes | yes | | Exact size/position, lock aspect | yes | yes | | Rulers with indent markers and tab stops | yes | rulers yes; tab stops partial | | Context menus on shapes, slides, text, thumbnails | yes | yes, shorter | @@ -87,4 +87,5 @@ imitate Microsoft's. No pixel comparison against PowerPoint screenshots has been | Date | Change | Summary | |---|---|---| +| 2026-10-11 | minor | Tab in text boxes keeps editing (#78) | | 2026-10-10 | major | Created: shell, panes and dialogs, direct manipulation, shortcuts and visual fidelity against PowerPoint 16.113 |