mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-14 14:26:45 -04:00
This commit is contained in:
1 parent
5b0238fc26
commit
2effc8bf3e
2 files changed
+104
No files matched your search
@@ -1207,6 +1207,15 @@ pub fn show(app: &mut CadApp, ui: &mut egui::Ui) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Double-click text to edit it, as in AutoCAD: TEXTEDIT with that object already picked.
|
||||
if inside
|
||||
&& dbl_primary
|
||||
&& app.session.running.is_none()
|
||||
&& let Some(hp) = hover_pos
|
||||
&& edit_text_at(app, xf.to_world(hp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Double-click a hatch (no command running) to edit it in the Hatch Edit dialog. The click is
|
||||
// used up: it must not also start a grip edit on the hatch's centre grip below.
|
||||
@@ -1627,6 +1636,23 @@ pub fn show(app: &mut CadApp, ui: &mut egui::Ui) {
|
||||
}
|
||||
|
||||
/// The model space tiles on screen (none without tiling): each tile's rectangle in `full`.
|
||||
/// 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.
|
||||
fn edit_text_at(app: &mut CadApp, p: Vec2) -> bool {
|
||||
use cadcraft_engine::doc::EntityKind;
|
||||
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(_)))
|
||||
});
|
||||
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
|
||||
}
|
||||
|
||||
fn tile_rects(app: &CadApp, full: Rect) -> Vec<(Rect, cadcraft_engine::ModelTile)> {
|
||||
let x = |f: f64| full.left() + full.width() * f.clamp(0.0, 1.0) as f32;
|
||||
let y = |f: f64| full.bottom() - full.height() * f.clamp(0.0, 1.0) as f32;
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
//! Double-clicking text with no command running edits it, as in AutoCAD (#842).
|
||||
|
||||
use cadcraft_engine::doc::EntityKind;
|
||||
use cadcraft_engine::geom::Vec2;
|
||||
use cadcraft_engine::{Input, Session};
|
||||
use cadcraft_ui_egui::{CadApp, Services};
|
||||
use egui::{Event, Modifiers, PointerButton, Pos2, vec2};
|
||||
use egui_kittest::Harness;
|
||||
use serde_json::json;
|
||||
|
||||
fn harness() -> Harness<'static, CadApp> {
|
||||
let mut app = CadApp::new(Session::new(), Services::default());
|
||||
app.run("text", json!({ "at": [0, 0], "text": "HELLO", "height": 2.5 })).unwrap();
|
||||
app.run("mtext", json!({ "at": [0, 20], "text": "first\\Psecond", "height": 2.5, "width": 20 })).unwrap();
|
||||
app.run("line", json!({ "points": [[30, 0], [30, 20]] })).unwrap();
|
||||
app.session.execute("view.set", &json!({ "center": [15, 10], "height": 40 })).unwrap();
|
||||
app.canvas.zoom_pending = false;
|
||||
// 60 frames a second: the default step (0.25 s) spreads two clicks past the double-click delay.
|
||||
let mut h = Harness::builder().with_size(vec2(1600.0, 1000.0)).with_step_dt(1.0 / 60.0).build_ui_state(
|
||||
|ui, app: &mut CadApp| {
|
||||
app.logic(ui.ctx());
|
||||
app.ui(ui);
|
||||
},
|
||||
app,
|
||||
);
|
||||
h.run_steps(5);
|
||||
h
|
||||
}
|
||||
|
||||
fn double_click(h: &mut Harness<'_, CadApp>, at: Vec2) {
|
||||
let pos: Pos2 = h.state().canvas.xf.unwrap().to_screen(at);
|
||||
h.event(Event::PointerMoved(pos));
|
||||
h.run_steps(2);
|
||||
for _ in 0..2 {
|
||||
for pressed in [true, false] {
|
||||
h.event(Event::PointerButton { pos, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE });
|
||||
h.run_steps(1);
|
||||
}
|
||||
}
|
||||
h.run_steps(2);
|
||||
}
|
||||
|
||||
fn text_at(h: &Harness<'_, CadApp>, i: usize) -> String {
|
||||
let d = h.state().session.doc().unwrap();
|
||||
let e = d.model.iter().nth(i).unwrap();
|
||||
match &e.kind {
|
||||
EntityKind::Text(t) => t.value.clone(),
|
||||
EntityKind::MText(t) => t.contents.clone(),
|
||||
k => panic!("not text: {}", k.type_name()),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_click_on_text_starts_textedit_for_that_object() {
|
||||
for (i, at, old, new) in [(0, Vec2::new(4.0, 1.2), "HELLO", "HELLO WORLD"), (1, Vec2::new(3.0, 18.8), "first\nsecond", "edited")] {
|
||||
let mut h = harness();
|
||||
double_click(&mut h, at);
|
||||
let s = &h.state().session;
|
||||
assert_eq!(s.running.as_ref().map(|r| r.id.as_str()), Some("textedit"), "object {i}");
|
||||
let p = s.current_prompt().unwrap();
|
||||
assert_eq!(p.message, "Enter new text", "object {i}: the clicked text is already picked");
|
||||
assert_eq!(p.default.as_deref(), Some(old), "object {i}");
|
||||
h.state_mut().session.input(Input::Text(new.into())).unwrap();
|
||||
h.run_steps(2);
|
||||
assert_eq!(text_at(&h, i), new);
|
||||
// TEXTEDIT goes on asking for objects (its Multiple mode), as AutoCAD's does.
|
||||
assert_eq!(h.state().session.current_prompt().unwrap().message, "Select an annotation object");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_click_elsewhere_starts_no_command() {
|
||||
for at in [Vec2::new(30.0, 5.0), Vec2::new(15.0, 30.0)] {
|
||||
let mut h = harness();
|
||||
double_click(&mut h, at);
|
||||
assert_eq!(h.state().session.running.as_ref().map(|r| r.id.as_str()), None, "{at:?}");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user