Merge PR #3121: Insert Caption picks the label used last, as the reference app does (#3120)

ROADMAP.md: main's status lines; both progress-log and revision rows kept.
docs/ui-parity.md: main's status line; revision rows unioned.
This commit is contained in:
aiongg committed 2026-10-22 01:21:28 +00:00
commit 3bcb07633f
4 files changed
+57 -2

No files matched your search

+2
View File
@@ -144,6 +144,7 @@ Imported Word 97–2003 `.doc`/`.dot` files now ask for a supported DOCX target
| Date | What landed |
| 2026-10-19 | Personal templates (#2852): File › New lists the `.dotx` and `.dotm` files in your templates folder under Personal (a subfolder per category; the search box covers them), and one opens as a new untitled document attached to it, as in Word. Save As › Save as Word Template starts in that folder, made on first use in the settings folder; File › Options › Advanced › File locations › User templates points it elsewhere. Agents list them with `file.listTemplates`. |
| 2026-10-15 | A picture anchored further down a page but placed higher up it (fixed on the page, or moved up from its paragraph) has the paragraphs above its anchor wrap around it too, instead of running behind it, also when that wrap pushes the anchor onto the next page (#2048) |
| 2026-10-19 | Insert Caption picks the label used last, as Word does, and keeps it between runs (#3120). |
| 2026-10-19 | Save As, Export and Open no longer do nothing on Linux desktops whose file chooser portal fails to show its dialog (#2999): a "cancel" quicker than anyone could make one asks again without the parent window, then opens the built-in file browser. |
| 2026-10-18 | Long navigation headings wrap onto further lines inside the resizable pane instead of ending in an ellipsis: the row grows with the text and the pane keeps its width (#759, #3015). |
| 2026-10-18 | Clearing a font query with no matches keeps Recently Used Fonts visible at the top of a scrollable list. The initial scroll position no longer skips its heading; measured keyboard scrolling is unchanged (#2068). |
@@ -519,6 +520,7 @@ Footer page-table height and body wrapping are corrected. Other pagination gaps
| Date | Change | Summary |
|---|---|---|
| 2026-10-19 | trivial | Progress log: Insert Caption picks the label used last (#3120) |
| 2026-10-16 | trivial | Progress log: `HYPERLINK` fields read as links (#2174) |
| 2026-10-18 | trivial | Progress log: German text hyphenates by the German patterns |
| 2026-10-21 | trivial | Progress log: File › Recover follows the app theme (#3243) |
+51 -2
View File
@@ -251,8 +251,10 @@ impl CaptionForm {
.body
.get(app.session.sel.focus.path.0.first().copied().unwrap_or(0) as usize)
.is_some_and(|b| matches!(&**b, Block::Table(_)));
let last = &app.ui.last_caption_label;
let label = if labels.contains(last) { last.as_str() } else { "Figure" };
CaptionForm {
label: if in_table { "Table" } else { "Figure" }.into(),
label: if in_table { "Table" } else { label }.into(),
labels,
text: String::new(),
position: "below".into(),
@@ -294,6 +296,13 @@ impl CaptionForm {
}
v
}
/// Insert the caption and remember its label for next time.
pub fn insert(&self, app: &mut WordApp) -> Result<(), String> {
app.run("references.caption", self.params())?;
app.ui.last_caption_label = self.label.clone();
Ok(())
}
}
fn caption_ui(app: &mut WordApp, ui: &mut Ui, f: &mut CaptionForm) -> Next {
@@ -339,7 +348,7 @@ fn caption_ui(app: &mut WordApp, ui: &mut Ui, f: &mut CaptionForm) -> Next {
return go(g);
}
let (ok, cancel) = buttons(ui, tl!("OK"));
if ok && let Err(e) = app.run("references.caption", f.params()) {
if ok && let Err(e) = f.insert(app) {
app.status(e);
}
if ok || cancel { Next::Close } else { Next::Stay }
@@ -1221,6 +1230,46 @@ mod tests {
assert_eq!(a.prefs().caption_labels, vec!["Plate".to_string()]);
}
/// #3120: Insert Caption picks the label used last, and saves it with the preferences.
#[test]
fn caption_dialog_remembers_the_last_label() {
use egui::accesskit::Role;
use egui_kittest::kittest::Queryable;
let mut a = app("A chart\nA photo");
a.ui.caption_labels.push("Diagram".into());
a.run("select.text", json!({"text": "A chart"})).unwrap();
a.run("references.caption", json!({})).unwrap();
let mut h = egui_kittest::Harness::builder().with_size(vec2(1440.0, 900.0)).build_ui_state(
|ui, app: &mut WordApp| {
let ctx = ui.ctx().clone();
app.logic(&ctx);
app.ui(ui);
},
a,
);
h.run_steps(4);
h.get_by_value("Figure").click();
h.run_steps(3);
h.get_by_label("Diagram").click();
h.run_steps(3);
h.get_by_role_and_label(Role::Button, "OK").click();
h.run_steps(3);
assert!(h.state().dialog.is_none(), "OK closes the dialog");
assert!(h.state().session.doc.plain_text(StoryRef::Body).contains("Diagram 1"));
h.state_mut().run("select.text", json!({"text": "A photo"})).unwrap();
h.state_mut().run("references.caption", json!({})).unwrap();
h.run_steps(4);
h.get_by_value("Diagram");
assert_eq!(h.state().prefs().last_caption_label, "Diagram");
// In a table it is still Table; a deleted label falls back to Figure.
let a = h.state_mut();
a.run("insert.table", json!({"rows": 1, "cols": 2})).unwrap();
assert_eq!(CaptionForm::read(a).label, "Table");
a.run("select.text", json!({"text": "A chart"})).unwrap();
a.ui.caption_labels.clear();
assert_eq!(CaptionForm::read(a).label, "Figure");
}
/// #916: Cross-reference from the ribbon opens a dialog listing the targets of each type
/// (equation captions too) and inserts a `REF` field to the one picked.
#[test]
+3
View File
@@ -321,6 +321,8 @@ pub struct UiState {
/// Caption labels the user added (References › Insert Caption › New Label), kept between
/// runs like Word keeps them in its Normal template (#402).
pub caption_labels: Vec<String>,
/// The label of the last caption inserted, picked again next time (#3120).
pub last_caption_label: String,
/// Draw › Add Pen: the pens added to the pen gallery; the session owns them while running.
/// Entries that aren't pens are dropped on reading.
#[serde(deserialize_with = "wordcraft_engine::cmd::draw::lenient_pens")]
@@ -399,6 +401,7 @@ impl Default for UiState {
keyboard: wordcraft_engine::KeyMap::default(),
ribbon: wordcraft_engine::RibbonLayout::default(),
caption_labels: Vec::new(),
last_caption_label: String::new(),
ink_pens: Vec::new(),
initials: String::new(),
options_pane: "general".into(),
+1
View File
@@ -74,6 +74,7 @@ Footnote and endnote editing keeps body and note text at normal opacity, on ligh
| Date | Change | Summary |
|---|---|---|
| 2026-10-19 | trivial | Insert Caption picks the label used last, as Word does, and keeps it between runs (#3120) |
| 2026-10-21 | trivial | File › Recover uses the same fills and text colours as the other Backstage pages; it no longer draws black with forced white text in the light theme (#3243, part of #2348) |
| 2026-10-18 | trivial | Long navigation headings wrap onto further lines inside the pane instead of ending in an ellipsis; the row grows with the text and the pane still resizes (#759, #3015) |
| 2026-10-18 | trivial | Font list starts at its first row after clearing a no-match query; recent heading remains visible (#2068) |