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.
This commit is contained in:
霁伪
2026-11-02 06:34:15 +08:00
parent 9dc39260b8
commit df26fc5197
20 changed files with 84 additions and 20 deletions
+12 -10
View File
@@ -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
}
+31 -2
View File
@@ -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<Entry> {
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:<handle>` 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<Entry> {
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);
}
+1
View File
@@ -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. تغيّر الرسم. أغلق النافذة وافتحها مرة أخرى.
Can't render this file because it contains an unexpected character in line 1339 and column 24.
+1
View File
@@ -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.
Can't render this file because it contains an unexpected character in line 1448 and column 24.
+1
View File
@@ -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.
1 # CADCraft Czech interface catalog — original translations by @Losminek (AI-assisted).
1230
1231
1232
1233
+1
View File
@@ -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.
1 # CADCraft German interface catalog — original translations by the CADCraft contributors.
1047
1048
1049
1050
+1
View File
@@ -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. Το σχέδιο άλλαξε. Κλείστε το παράθυρο και ανοίξτε το ξανά.
1 # Greek interface catalog for CADCraft. Original, AI-assisted translation by @Camthalion77 with ChatGPT.
1341
1342
1343
1344
+1
View File
@@ -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.
1 # CADCraft Spanish interface catalog — original translations.
1261
1262
1263
1264
+1
View File
@@ -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.
1 # CADCraft French interface catalog — original translations by @pechnikov2026-star.
1020
1021
1022
1023
+1
View File
@@ -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.
Can't render this file because it contains an unexpected character in line 16 and column 72.
+1
View File
@@ -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.
1 # CADCraft Italian interface catalog — original translations by Emanuele Bottelli (AI-assisted, Claude).
1370
1371
1372
1373
+1
View File
@@ -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. 도면이 변경되었습니다. 창을 닫고 다시 여십시오.
1 # CADCraft Korean interface catalog — original Korean translations.
1250
1251
1252
1253
+1
View File
@@ -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.
1 # CADCraft Brazilian Portuguese (pt-BR) interface catalog.
1259
1260
1261
1262
+1
View File
@@ -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. Чертёж изменился. Закройте окно и откройте его снова.
1 # CADCraft Russian interface catalog — original translations by @pechnikov2026-star.
1021
1022
1023
1024
+1
View File
@@ -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.
1 # CADCraft Swedish interface catalog — original translations by the CADCraft contributors.
1454
1455
1456
1457
+1
View File
@@ -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.
Can't render this file because it contains an unexpected character in line 11 and column 13.
+1
View File
@@ -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. Креслення змінилося. Закрийте вікно та відкрийте його знову.
Can't render this file because it contains an unexpected character in line 1379 and column 24.
+1
View File
@@ -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.
Can't render this file because it contains an unexpected character in line 1447 and column 24.
+1
View File
@@ -1383,3 +1383,4 @@
Units 单位
Ctrl+Enter to apply Ctrl+Enter 应用
Edit Text 编辑文字
The drawing changed. Close the window and open it again. 图纸已切换。请关闭窗口后重新打开。
1 # CADCraft Simplified Chinese interface catalog — original translations.
1383
1384
1385
1386
+24 -8
View File
@@ -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::<State>(sid));
}
}