mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Merge pull request #989 from Zetenypapp/fix/find-focus-951
This commit is contained in:
@@ -132,6 +132,7 @@ app's JSON control channel (`deckcraft --control PORT`).
|
||||
| Date | What landed |
|
||||
|---|---|
|
||||
| 2026-10-22 | Table text takes the master's other-text style (`otherStyle`), shapes and text boxes the presentation's default text style, as PowerPoint for Mac draws them (synthetic probe: 14 pt cells under a 14 pt `otherStyle` and a 26 pt `defaultTextStyle`); a private deck's table had been drawn 20 pt instead of 18 |
|
||||
| 2026-10-18 | Find (Ctrl+F): "Find what:" has the keyboard as soon as the dialog opens, and keeps it after Enter finds a match, so the search can be typed and changed without clicking the field (#951) |
|
||||
| 2026-10-18 | Native chart sidecar bytes move from JSON arrays into referenced ZIP entries, with shared media byte/item limits and bounded reads; older inline sidecars still load. Synthetic format regressions cover large workbooks and malformed members |
|
||||
| 2026-10-18 | Slide thumbnails and the Slide Sorter render only the slides in view: on a deck of more than 600 slides they used to evict their own thumbnails, so the pane flashed white and never finished (#969) |
|
||||
| 2026-10-18 | Resizing with the mouse snaps the edge being dragged to the slide, guides and other shapes: a fixed edge that already lined up used to take the snap and leave the dragged edge free, and a fixed edge near a line shifted the dragged one (#961) |
|
||||
|
||||
@@ -3196,7 +3196,18 @@ fn tabs_dialog(app: &mut SlideApp, ui: &mut Ui, d: &mut Dialog) -> bool {
|
||||
/// Home › Find / Replace: step through matches (slide text, table cells, notes) or replace them.
|
||||
fn find_dialog(app: &mut SlideApp, ui: &mut Ui, d: &mut Dialog) -> bool {
|
||||
let replace_mode = d.get("replace", "0") == "1";
|
||||
field(ui, d, "Find what:", "text", "");
|
||||
// "Find what:" has the keyboard when the dialog opens, so Ctrl+F and typing finds (#951).
|
||||
let mut what = d.get("text", "");
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_sized(vec2(120.0, 20.0), egui::Label::new("Find what:"));
|
||||
let r = ui.add(egui::TextEdit::singleline(&mut what).desired_width(180.0));
|
||||
// Enter finds the next match and leaves the keyboard here, so the search can be changed.
|
||||
if !d.fields.contains_key("focused") || (r.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter))) {
|
||||
r.request_focus();
|
||||
d.fields.insert("focused".into(), "1".into());
|
||||
}
|
||||
});
|
||||
d.fields.insert("text".into(), what);
|
||||
if replace_mode {
|
||||
field(ui, d, "Replace with:", "with", "");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//! Home › Find (Ctrl+F): "Find what:" has the keyboard as soon as the dialog opens (#951).
|
||||
|
||||
use deckcraft_engine::Session;
|
||||
use egui_kittest::Harness;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{Services, SlideApp};
|
||||
|
||||
#[test]
|
||||
fn ctrl_f_puts_the_caret_in_find_what() {
|
||||
let mut s = Session::with_new();
|
||||
s.execute("slide.new", &json!({"layout": "blank"})).unwrap();
|
||||
s.execute("insert.textBox", &json!({"rect": [40, 40, 400, 80], "text": "Hello there"})).unwrap();
|
||||
s.execute("text.exit", &json!({})).unwrap();
|
||||
s.doc_mut().unwrap().selection.shapes.clear();
|
||||
let app = SlideApp::new(s, Services::default());
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).with_step_dt(1.0 / 60.0).build_ui_state(
|
||||
|ui, app: &mut SlideApp| {
|
||||
app.logic(ui.ctx());
|
||||
app.ui(ui);
|
||||
},
|
||||
app,
|
||||
);
|
||||
h.run_steps(3);
|
||||
h.key_press_modifiers(egui::Modifiers::COMMAND, egui::Key::F);
|
||||
h.run_steps(3);
|
||||
assert_eq!(h.state().dialog.as_ref().map(|d| d.id.as_str()), Some("find"));
|
||||
// Typing right away goes into the field, without clicking it first.
|
||||
h.event(egui::Event::Text("there".into()));
|
||||
h.run_steps(3);
|
||||
let typed = h.state().dialog.as_ref().and_then(|d| d.fields.get("text").cloned());
|
||||
assert_eq!(typed.as_deref(), Some("there"));
|
||||
// Enter finds it.
|
||||
h.key_press(egui::Key::Enter);
|
||||
h.run_steps(3);
|
||||
let status = h.state().dialog.as_ref().and_then(|d| d.fields.get("status").cloned());
|
||||
assert!(status.as_deref().is_some_and(|m| m.starts_with("Match 1 of 1")), "Enter didn't find the text: {status:?}");
|
||||
// The keyboard stays in the field afterwards: more typing adds to it.
|
||||
h.event(egui::Event::Text("!".into()));
|
||||
h.run_steps(3);
|
||||
let typed = h.state().dialog.as_ref().and_then(|d| d.fields.get("text").cloned());
|
||||
assert_eq!(typed.as_deref(), Some("there!"));
|
||||
}
|
||||
@@ -2052,6 +2052,8 @@ mod compare_tests;
|
||||
#[cfg(test)]
|
||||
mod eyedropper_tests;
|
||||
#[cfg(test)]
|
||||
mod find_dialog_tests;
|
||||
#[cfg(test)]
|
||||
mod huge_deck_tests;
|
||||
#[cfg(test)]
|
||||
mod ime_tests;
|
||||
|
||||
Reference in New Issue
Block a user