mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-26 11:27:10 -06:00
Merge PR #2599: Context menu: the ribbon's paste choices (Paste, Keep Text Only, Merge Formatting, Paste Special…) (#2583)
ROADMAP.md: kept main's status line; progress-log and change-log rows from both sides docs/ui-parity.md: kept main's status line; change-log rows from both sides crates/ui-egui/src/canvas.rs: kept both sides' new tests as separate functions
This commit is contained in:
@@ -151,6 +151,7 @@ Imported Word 97–2003 `.doc`/`.dot` files now ask for a supported DOCX target
|
||||
| 2026-10-17 | Equation arrays centre a row that has no `&` among rows that do, as Word does, so case equations like Word's "First Property of Radicals" no longer push the aligned row right (#2617). |
|
||||
| 2026-10-16 | English dialects (#1281, #1045): English (UK), (Australia), (Canada) and the other Englishes are proofed in their own spelling — *colour* is flagged in a US document and *color* in a British one, with the right form suggested first — from our own list of American/British spellings, so nothing to install. Review › Language lists them, the .docx `w:lang` keeps them, and an English interface on a British (or Canadian, Australian…) system starts new documents in that English |
|
||||
| 2026-10-15 | Triple borders (tables, paragraphs, the `###` AutoFormat line) draw as three lines on screen and in PDF, across the line for vertical borders too; they used to draw as double lines (#1740) |
|
||||
| 2026-10-17 | The document's right-click menu offers the ribbon's Paste menu, item for item (#2583): Paste (the clipboard's formatting kept, Word's Keep Source Formatting), Keep Text Only, Merge Formatting and Paste Special…, where it had a single Paste. Same commands and shortcuts, with the system clipboard |
|
||||
| 2026-10-14 | DOCX row table border exceptions render and survive saving. Explicit cell borders win; a row exception does not change other rows. |
|
||||
| 2026-10-14 | Tab stops edited on the ruler: the corner selector picks Left/Center/Right/Decimal/Bar, a click sets a stop (Alt skips the snap), dragging moves it with a guide line and position tooltip, dragging off the ruler clears it; markers draw per kind and mirror for RTL; one `para.tabs` call and one undo step per gesture |
|
||||
| 2026-10-12 | Fields keep `w:dirty` through DOCX saves (#877): a begin marker flagged by a generator that couldn't compute a result (pandoc-style TOC placeholders) keeps the flag on open/save — as a buffered field or a range field — so Word still refreshes it on open; computing a result (Update Field, Update Table) clears it, like Word's F9 |
|
||||
@@ -601,6 +602,7 @@ Footer page-table height and body wrapping are corrected. Other pagination gaps
|
||||
| 2026-10-17 | minor | Progress log: Scale to paper size on File › Print, #2108 |
|
||||
| 2026-10-17 | trivial | Non-overlapping body floating tables clear header tables; overlapping tables keep their requested position |
|
||||
| 2026-10-15 | trivial | Progress log: caret inside ligatures (#1974) |
|
||||
| 2026-10-17 | trivial | Progress log: the ribbon's paste choices in the context menu (#2583) |
|
||||
| 2026-10-14 | trivial | Progress log: row table border exceptions |
|
||||
| 2026-10-12 | minor | Czech proofing review: short-word splits rank after deletion, NOSUGGEST excludes suggestions while accepting typed forms, affix comments apply only to headers, ratios keep spaces and repeated-word messages use Czech quotes; synthetic engine end-to-end and latency checks |
|
||||
| 2026-10-12 | minor | Czech spelling from the installed Hunspell dictionary, runtime-table suggestions and generic checks; Czech interface writes cs-CZ documents; no Czech hyphenation patterns bundled; estimates unchanged |
|
||||
|
||||
@@ -3167,7 +3167,12 @@ fn context_menu(app: &mut WordApp, ui: &mut Ui) {
|
||||
}
|
||||
item(ui, app, "Cut", "edit.cut", json!({}));
|
||||
item(ui, app, "Copy", "edit.copy", json!({}));
|
||||
// How to paste, chosen before pasting (#2583): the ribbon's Paste menu, item for item. Paste
|
||||
// keeps the clipboard's formatting (Word's Keep Source Formatting).
|
||||
item(ui, app, "Paste", "edit.paste", json!({}));
|
||||
item(ui, app, "Keep Text Only", "edit.pasteText", json!({}));
|
||||
item(ui, app, "Merge Formatting", "edit.pasteMerge", json!({}));
|
||||
item(ui, app, "Paste Special…", "edit.pasteSpecial", json!({}));
|
||||
ui.separator();
|
||||
if let Some(syn) = app.canvas.context_synonyms.clone().and_then(|v| v.as_array().cloned()).filter(|a| !a.is_empty()) {
|
||||
ui.menu_button(tl!("Synonyms"), |ui| {
|
||||
@@ -4859,6 +4864,81 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// #2583: the context menu offers the ribbon's Paste menu, item for item, and each pastes its
|
||||
/// own way: Paste keeps the copied bold and colour (Word's Keep Source Formatting), Merge
|
||||
/// Formatting keeps only the bold, Keep Text Only neither; Paste Special… opens its dialog.
|
||||
#[test]
|
||||
fn context_menu_offers_the_ribbons_paste_items() {
|
||||
use egui_kittest::kittest::Queryable;
|
||||
use wordcraft_doc::props::{Rgb, TextColor};
|
||||
let red = Some(TextColor::Rgb(Rgb(0xC0, 0, 0)));
|
||||
let items = [
|
||||
("Paste", "edit.paste"),
|
||||
("Keep Text Only", "edit.pasteText"),
|
||||
("Merge Formatting", "edit.pasteMerge"),
|
||||
("Paste Special…", "edit.pasteSpecial"),
|
||||
];
|
||||
for (choice, pasted) in [
|
||||
("Paste", Some((true, red))),
|
||||
("Merge Formatting", Some((true, None))),
|
||||
("Keep Text Only", Some((false, None))),
|
||||
("Paste Special…", None),
|
||||
] {
|
||||
let mut a = WordApp::new(wordcraft_engine::Session::new(wordcraft_doc::Document::from_text("Bold\nTarget")), Default::default());
|
||||
a.session
|
||||
.doc
|
||||
.format_range(&Pos::body(0, 0), &Pos::body(0, 4), &|c| {
|
||||
c.bold = Some(true);
|
||||
c.color = red;
|
||||
})
|
||||
.unwrap();
|
||||
a.session.relayout();
|
||||
a.run("select.text", json!({"text": "Bold"})).unwrap();
|
||||
a.run("edit.copy", json!({})).unwrap();
|
||||
let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1440.0, 900.0)).build_ui_state(
|
||||
|ui, app: &mut WordApp| {
|
||||
let ctx = ui.ctx().clone();
|
||||
app.logic(&ctx);
|
||||
app.ui(ui);
|
||||
},
|
||||
a,
|
||||
);
|
||||
for _ in 0..6 {
|
||||
h.step();
|
||||
}
|
||||
let c = h.state_mut().session.layout().caret(&Pos::body(1, 6)).expect("laid out");
|
||||
let at = page_to_screen(h.state_mut(), c.page, c.x, c.top + c.height / 2.0).expect("on screen");
|
||||
h.event(egui::Event::PointerMoved(at));
|
||||
for pressed in [true, false] {
|
||||
h.event(egui::Event::PointerButton { pos: at, button: egui::PointerButton::Secondary, pressed, modifiers: Default::default() });
|
||||
h.step();
|
||||
}
|
||||
h.step();
|
||||
// Each item reads as its name and its shortcut (none for Merge Formatting).
|
||||
let labels: Vec<String> = items.iter().map(|(name, id)| format!("{name} {}", crate::widgets::shortcut_text(h.state(), id))).collect();
|
||||
for l in &labels {
|
||||
assert!(h.query_by_label(l).is_some(), "{choice}: {l:?} is offered");
|
||||
}
|
||||
let k = items.iter().position(|(name, _)| *name == choice).unwrap();
|
||||
h.get_by_label(&labels[k]).click();
|
||||
for _ in 0..3 {
|
||||
h.step();
|
||||
}
|
||||
match pasted {
|
||||
Some((bold, colour)) => {
|
||||
let doc = &h.state().session.doc;
|
||||
assert_eq!(doc.plain_text(StoryRef::Body), "Bold\nTargetBold", "{choice}: pasted at the end of the second paragraph");
|
||||
let p = doc.para_at(&Pos::body(1, 0)).expect("the target paragraph");
|
||||
assert_eq!(p.props_of_char(7).bold == Some(true), bold, "{choice}: bold");
|
||||
assert_eq!(p.props_of_char(7).color, colour, "{choice}: colour");
|
||||
}
|
||||
None => {
|
||||
assert!(matches!(h.state().dialog, Some(crate::dialogs::Dialog::PasteSpecial { .. })), "{choice}: the dialog opens");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// #996: on macOS a Control-click is the right-click (the trackpad's and the one-button
|
||||
/// mouse's way to it), so it opens the same menu and leaves the caret where the menu needs it.
|
||||
#[cfg(target_os = "macos")]
|
||||
|
||||
@@ -121,6 +121,7 @@ Footnote and endnote editing keeps body and note text at normal opacity, on ligh
|
||||
| 2026-10-15 | trivial | Text Highlight Color: No Color becomes the Highlight button's choice, as in Word, so the next click on the button removes highlighting instead of applying the colour picked before; the ribbon and the mini toolbar share one menu (#2105) |
|
||||
| 2026-10-16 | trivial | Body and active note text keep normal opacity while editing footnotes or endnotes (#2545); header/footer dimming is unchanged |
|
||||
| 2026-10-16 | trivial | Right-clicking a picture, shape, text box or chart offers Insert Caption…; a picture in a table gets a Figure caption in its cell. Page Setup has Headers and footers check boxes (Different Odd & Even Pages, Different First Page), applied on OK only if changed (#1230) |
|
||||
| 2026-10-17 | trivial | Context menu: Paste, Keep Text Only, Merge Formatting and Paste Special… replace the single Paste, the same items as Home › Paste's menu (#2583). Word's context menu shows its Paste Options as a row of icons; here they are labelled items with their shortcuts, as on the ribbon |
|
||||
| 2026-10-13 | trivial | New/Modify Table Style: No Border on a part that inherits its lines hides them; emptying the font box makes the part's font inherited again (#1288) |
|
||||
| 2026-10-17 | minor | Insert › Drop Cap is a menu (None, Dropped, In margin, Drop Cap Options…) with a Drop Cap dialog (position, font, lines 1–10, distance 0–22 in), #2601; Modal dialogs 56 → 57 |
|
||||
| 2026-10-14 | trivial | Tab stops edited on the ruler: corner kind selector, click to set, drag to move or off to clear, per-kind markers mirrored for RTL; each gesture one `para.tabs` call and one undo step; Rulers 85% → 90% |
|
||||
|
||||
Reference in New Issue
Block a user