From df26fc51975cbbcefae2f04e25b97ef56769d1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=81=E4=BC=AA?= <56018602+r4x2t7@users.noreply.github.com> Date: Mon, 2 Nov 2026 06:34:15 +0800 Subject: [PATCH] TEXTEDIT: the window opens from the shortcut menu; the double-click keeps its in-place editing The double-click on a text object goes back to starting the in-place TEXTEDIT (#842), which the text_double_click tests guard. The window is what the shortcut menu's Edit Text entry opens for a single selected text, mtext or attribute definition; with several objects selected the command line still runs. The window records the drawing it was opened for and refuses to commit into another one, and its state now lives exactly as long as the window does, so a cancelled edit cannot resurface. --- crates/ui-egui/src/canvas/pick.rs | 22 +++++++++++--------- crates/ui-egui/src/context_menu.rs | 33 ++++++++++++++++++++++++++++-- crates/ui-egui/src/i18n/ar.tsv | 1 + crates/ui-egui/src/i18n/bs.tsv | 1 + crates/ui-egui/src/i18n/cs.tsv | 1 + crates/ui-egui/src/i18n/de.tsv | 1 + crates/ui-egui/src/i18n/el.tsv | 1 + crates/ui-egui/src/i18n/es.tsv | 1 + crates/ui-egui/src/i18n/fr.tsv | 1 + crates/ui-egui/src/i18n/hu.tsv | 1 + crates/ui-egui/src/i18n/it.tsv | 1 + crates/ui-egui/src/i18n/ko.tsv | 1 + crates/ui-egui/src/i18n/pt_br.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/sv.tsv | 1 + crates/ui-egui/src/i18n/tr.tsv | 1 + crates/ui-egui/src/i18n/uk.tsv | 1 + crates/ui-egui/src/i18n/vi.tsv | 1 + crates/ui-egui/src/i18n/zh.tsv | 1 + crates/ui-egui/src/textdlg.rs | 32 +++++++++++++++++++++-------- 20 files changed, 84 insertions(+), 20 deletions(-) diff --git a/crates/ui-egui/src/canvas/pick.rs b/crates/ui-egui/src/canvas/pick.rs index 112740d06..3bd28b017 100644 --- a/crates/ui-egui/src/canvas/pick.rs +++ b/crates/ui-egui/src/canvas/pick.rs @@ -1,4 +1,4 @@ -use super::{CadApp, Handle, Vec2}; +use super::{CadApp, Handle, Input, Vec2}; /// The vertical wheel scroll this frame that zooms, in points, read from the raw wheel events so /// each notch zooms by its whole step at once, as in standard CAD (#660). egui's smoothed delta @@ -26,18 +26,20 @@ pub(super) fn wheel_zoom_points(events: &[egui::Event], opts: &egui::InputOption } /// The model space tiles on screen (none without tiling): each tile's rectangle in `full`. -/// Open Edit Text on the text, mtext or attribute definition at `p` (the objects the shortcut -/// menu offers Edit Text for); false when there is none. +/// Start TEXTEDIT on the text, mtext or attribute definition at `p` (the objects its shortcut menu +/// offers Edit Text for); false when there is none. pub(super) fn edit_text_at(app: &mut CadApp, p: Vec2) -> bool { use cadcraft_engine::doc::EntityKind; - let hit = cadcraft_engine::cmd::curves::pick_at(&app.session, p).and_then(|h| { - let e = app.session.doc().ok()?.entity(h)?; - matches!(e.kind, EntityKind::Text(_) | EntityKind::MText(_) | EntityKind::AttDef(_)).then_some(h) + let is_text = cadcraft_engine::cmd::curves::pick_at(&app.session, p).and_then(|h| { + app.session.doc().ok()?.entity(h).map(|e| matches!(e.kind, EntityKind::Text(_) | EntityKind::MText(_) | EntityKind::AttDef(_))) }); - let Some(h) = hit else { return false }; - // The window edits the object in place of the command line, which used to take the caret and - // hide the drawing behind it. - app.ui.dialog = Some(format!("textedit:{}", h.hex())); + if is_text != Some(true) { + return false; + } + app.start("textedit"); + if let Err(e) = app.session.input(Input::Point(p)) { + app.session.echo(e.to_string()); + } true } diff --git a/crates/ui-egui/src/context_menu.rs b/crates/ui-egui/src/context_menu.rs index bbaf48df3..0b00d933c 100644 --- a/crates/ui-egui/src/context_menu.rs +++ b/crates/ui-egui/src/context_menu.rs @@ -153,9 +153,35 @@ fn object_commands(app: &CadApp) -> Vec<(&'static str, Option<&'static str>)> { } } -/// [`object_commands`] that are registered, as menu items. +/// [`object_commands`] that are registered, as menu items. The Edit Text entry of a single +/// selected text, mtext or attribute definition opens the Edit Text window instead of the +/// TEXTEDIT command line; the double-click keeps its in-place editing (#842), and several +/// selected texts still take the command line. pub fn object_entries(app: &CadApp) -> Vec { - object_commands(app).into_iter().filter_map(|(id, label)| item(app, id, label)).collect() + object_commands(app) + .into_iter() + .filter_map(|(id, label)| { + if id == "textedit" { + edit_text_window_entry(app).or_else(|| item(app, id, label)) + } else { + item(app, id, label) + } + }) + .collect() +} + +/// The Edit Text entry as the `textedit:` dialog id, for a single selected text, mtext +/// or attribute definition; `None` otherwise, so the command line entry stands in. +fn edit_text_window_entry(app: &CadApp) -> Option { + use cadcraft_engine::doc::EntityKind; + let sel = app.session.selection(); + if sel.len() != 1 { + return None; + } + let h = *sel.first()?; + let d = app.session.doc().ok()?; + d.entity(h).filter(|e| matches!(e.kind, EntityKind::Text(_) | EntityKind::MText(_) | EntityKind::AttDef(_)))?; + Some(Entry::Item { label: "Edit Text".into(), id: format!("textedit:{}", h.hex()), shortcut: None, enabled: true }) } /// The command menu while a command runs (`None` when none does): Enter and Cancel, Recent Input, @@ -213,6 +239,9 @@ pub fn choose(app: &mut CadApp, id: &str) { } } else if let Some(s) = id.strip_prefix(SNAP) { choose_snap(app, s); + } else if id.starts_with("textedit:") { + // The Edit Text window of the single selected text object; the id carries the handle. + app.ui.dialog = Some(id.to_string()); } else { activate(app, id); } diff --git a/crates/ui-egui/src/i18n/ar.tsv b/crates/ui-egui/src/i18n/ar.tsv index 657ec3fd1..75538130a 100644 --- a/crates/ui-egui/src/i18n/ar.tsv +++ b/crates/ui-egui/src/i18n/ar.tsv @@ -1374,3 +1374,4 @@ menu View عرض {command} is an unknown command. {command} أمر غير معروف. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. تغيّر الرسم. أغلق النافذة وافتحها مرة أخرى. diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index 508fd7422..f2ee28566 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -1450,3 +1450,4 @@ menu Modify Izmijeni Associate Poveži Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Crtež se promijenio. Zatvorite prozor i otvorite ga ponovo. diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 1d5db0700..422b0a1b7 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -1230,3 +1230,4 @@ menu Modify Modifikace Could not check for updates. Aktualizace se nepodařilo zkontrolovat. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Výkres se změnil. Zavřete okno a otevřete jej znovu. diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 213aa4f5a..cf1be2ca0 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -1047,3 +1047,4 @@ Could not check for updates. Die Suche nach Updates ist fehlgeschlagen. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Die Zeichnung hat sich geändert. Schließen Sie das Fenster und öffnen Sie es erneut. diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 9a1b0784d..981a3054f 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -1341,3 +1341,4 @@ menu View Προβολή Could not check for updates. Δεν ήταν δυνατός ο έλεγχος για ενημερώσεις. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Το σχέδιο άλλαξε. Κλείστε το παράθυρο και ανοίξτε το ξανά. diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index e02790314..16e8ce57d 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -1261,3 +1261,4 @@ Could not check for updates. No se pudo buscar actualizaciones. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. El dibujo cambió. Cierre la ventana y ábrala de nuevo. diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 031519a07..d53fbd216 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -1020,3 +1020,4 @@ Could not check for updates. Impossible de rechercher les mises à jour. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Le dessin a changé. Fermez la fenêtre et rouvrez-la. diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index cd47b5ca6..c40c4b898 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -1352,3 +1352,4 @@ menu View Nézet Could not check for updates. A frissítések keresése nem sikerült. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. A rajz megváltozott. Zárja be az ablakot, és nyissa meg újra. diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 550e3aeae..485790efa 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -1370,3 +1370,4 @@ menu Modify Edita Could not check for updates. Impossibile verificare gli aggiornamenti. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Il disegno è cambiato. Chiudere la finestra e riaprirla. diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 847c78149..166e42c4f 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -1250,3 +1250,4 @@ menu Modify 수정 Could not check for updates. 업데이트를 확인하지 못했습니다. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. 도면이 변경되었습니다. 창을 닫고 다시 여십시오. diff --git a/crates/ui-egui/src/i18n/pt_br.tsv b/crates/ui-egui/src/i18n/pt_br.tsv index 0e272cced..6fa9d6b45 100644 --- a/crates/ui-egui/src/i18n/pt_br.tsv +++ b/crates/ui-egui/src/i18n/pt_br.tsv @@ -1259,3 +1259,4 @@ Could not check for updates. Não foi possível verificar atualizações. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. O desenho mudou. Feche a janela e abra-a novamente. diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 3bcdb5aa7..4407bb82e 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -1021,3 +1021,4 @@ Could not check for updates. Не удалось проверить обновления. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Чертёж изменился. Закройте окно и откройте его снова. diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index bd5b8d59e..54c609d64 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -1454,3 +1454,4 @@ menu Modify Ändra Could not check for updates. Det gick inte att söka efter uppdateringar. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Ritningen har ändrats. Stäng fönstret och öppna det igen. diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 2ad0e4a72..c002c60ba 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -1355,3 +1355,4 @@ menu View Görünüm Could not check for updates. Güncellemeler denetlenemedi. Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Çizim değişti. Pencereyi kapatıp yeniden açın. diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 10edda9a5..8c9d18b57 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -1379,3 +1379,4 @@ Save changes to block "{name}"? Зберегти зміни в блоці «{name}»? Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Креслення змінилося. Закрийте вікно та відкрийте його знову. diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 195616277..8908bb7ad 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -1454,3 +1454,4 @@ menu Modify Hiệu chỉnh Save Layout as Template Lưu layout thành mẫu Ctrl+Enter to apply Ctrl+Enter to apply Edit Text Edit Text + The drawing changed. Close the window and open it again. Bản vẽ đã thay đổi. Đóng cửa sổ và mở lại. diff --git a/crates/ui-egui/src/i18n/zh.tsv b/crates/ui-egui/src/i18n/zh.tsv index 8656cd4cf..d410b37de 100644 --- a/crates/ui-egui/src/i18n/zh.tsv +++ b/crates/ui-egui/src/i18n/zh.tsv @@ -1383,3 +1383,4 @@ Units 单位 Ctrl+Enter to apply Ctrl+Enter 应用 Edit Text 编辑文字 + The drawing changed. Close the window and open it again. 图纸已切换。请关闭窗口后重新打开。 diff --git a/crates/ui-egui/src/textdlg.rs b/crates/ui-egui/src/textdlg.rs index b3d13ae9f..c9a279660 100644 --- a/crates/ui-egui/src/textdlg.rs +++ b/crates/ui-egui/src/textdlg.rs @@ -1,10 +1,11 @@ -//! Edit Text: the window a double-click on a text object opens. +//! Edit Text: the window behind the shortcut menu's Edit Text entry. //! -//! TEXTEDIT already existed, but only as a command line: double-clicking a single-line text put -//! the caret in the command bar, one line, no context, and the text under the cursor was out of -//! sight. The window shows the same edit over the drawing: the object's own text, its type and -//! handle, and OK/Cancel. The engine call is unchanged (`textedit` with a handle and the new -//! text), so undo, locked layers and the DXF round trip behave exactly as before. +//! TEXTEDIT already existed, but only as a command line: it put the caret in the command bar, +//! one line, no context, and the text under the cursor was out of sight. The window shows the +//! same edit over the drawing: the object's own text, its type and handle, and OK/Cancel. The +//! engine call is unchanged (`textedit` with a handle and the new text), so undo, locked layers +//! and the DXF round trip behave exactly as before. The double-click keeps its in-place editing +//! (#842); the window is the shortcut menu's way in. use egui::RichText; use serde_json::json; @@ -33,13 +34,17 @@ struct State { text: String, /// What the drawing holds now, to tell an edit from a no-op. original: String, + /// The drawing the window was opened for: a handle means nothing once another drawing is + /// active, and committing to it would edit an object the user never saw. + uid: u64, message: String, } /// Read the object the window is for. A handle that no longer exists, or an object that is not /// text, leaves the window empty instead of failing: the drawing may have changed under it. fn initial(app: &CadApp, hex: &str) -> State { - let mut st = State { handle: hex.to_string(), ..Default::default() }; + let uid = app.session.state().map(|s| s.uid).unwrap_or_default(); + let mut st = State { handle: hex.to_string(), uid, ..Default::default() }; let Some(h) = cadcraft_doc::Handle::parse_hex(hex) else { return st }; let Ok(d) = app.session.doc() else { return st }; let Some(e) = d.entity(h) else { return st }; @@ -100,6 +105,11 @@ pub fn dialog(app: &mut CadApp, ctx: &egui::Context, spec: &str, open: &mut bool // keeps the undo stack honest. if st.text == st.original { keep = false; + } else if app.session.state().map(|s| s.uid).ok() != Some(st.uid) { + // The drawing switched while the window sat open: the handle now names another + // drawing's object, so the commit is refused and the user reopens on the drawing + // they meant to edit. + st.message = crate::tl!("The drawing changed. Close the window and open it again.").to_string(); } else { let params = json!({ "handles": [st.handle.clone()], "text": st.text }); match app.run("textedit", params) { @@ -112,5 +122,11 @@ pub fn dialog(app: &mut CadApp, ctx: &egui::Context, spec: &str, open: &mut bool } } *open = keep; - ctx.data_mut(|d| d.insert_temp(sid, st)); + // The state lives exactly as long as the window does: a closed window leaves nothing + // behind, so reopening it reads the drawing's text instead of an edit the user cancelled. + if keep { + ctx.data_mut(|d| d.insert_temp(sid, st)); + } else { + ctx.data_mut(|d| d.remove_temp::(sid)); + } }