mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-24 19:06:56 -06:00
Merge pull request #1556 from silaghis/fix/stretch-ortho-window
Keep rectangle opposite corners free of ortho (STRETCH window and friends)
This commit is contained in:
@@ -1083,7 +1083,9 @@ impl Interactive for RevcloudM {
|
||||
let first_kw: &[&str] = &["Arc length", "Object", "Rectangular", "Polygonal", "Freehand", "Style"];
|
||||
match (self.kind, self.pts.len()) {
|
||||
(CloudKind::Rect, 0) => Prompt::new("Specify first corner point", Accept::POINT).kw(first_kw).default("Object"),
|
||||
(CloudKind::Rect, _) => Prompt::new("Specify opposite corner", Accept::POINT).base_opt(self.pts.first().copied()),
|
||||
(CloudKind::Rect, _) => {
|
||||
Prompt { corner: true, ..Prompt::new("Specify opposite corner", Accept::POINT).base_opt(self.pts.first().copied()) }
|
||||
}
|
||||
(CloudKind::Poly, 0) => Prompt::new("Specify start point", Accept::POINT).kw(first_kw).default("Object"),
|
||||
(CloudKind::Poly, 1) => Prompt::new("Specify next point", Accept::POINT).base_opt(self.pts.last().copied()),
|
||||
(CloudKind::Poly, _) => Prompt::new("Specify next point", Accept::POINT).kw(&["Undo"]).base_opt(self.pts.last().copied()),
|
||||
|
||||
@@ -637,13 +637,13 @@ impl Interactive for MviewM {
|
||||
Stage::Arrange => Prompt::new("Enter viewport arrangement", curves::KW)
|
||||
.kw(&["Horizontal", "Vertical", "Above", "Below", "Left", "Right"])
|
||||
.default("Right"),
|
||||
Stage::Opposite(a) => Prompt::new("Specify opposite corner", Accept::POINT).base(*a),
|
||||
Stage::Opposite(a) => Prompt::new("Specify opposite corner", Accept::POINT).corner(*a),
|
||||
Stage::Polygon(pi) => pi.prompt(),
|
||||
Stage::Object => Prompt::new("Select object to clip viewport", Accept::POINT),
|
||||
Stage::Lock => Prompt::new("Lock the view of viewports?", curves::KW).kw(&["ON", "OFF"]),
|
||||
Stage::RestoreName => Prompt::new("Enter viewport configuration name", Accept::TEXT).kw(&["?"]).default(VportConfig::ACTIVE),
|
||||
Stage::RestoreCorner(_) => Prompt::new("Specify first corner", Accept::POINT).kw(&["Fit"]).default("Fit"),
|
||||
Stage::RestoreOpposite(_, a) => Prompt::new("Specify opposite corner", Accept::POINT).base(*a),
|
||||
Stage::RestoreOpposite(_, a) => Prompt::new("Specify opposite corner", Accept::POINT).corner(*a),
|
||||
Stage::Select { .. } => Prompt::new("Select viewports", Accept::POINT),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,7 +517,7 @@ impl Interactive for StretchM {
|
||||
return m.prompt();
|
||||
}
|
||||
match (self.phase, self.corner) {
|
||||
(StretchPhase::Select, Some(c)) => Prompt::new("Specify opposite corner", Accept::POINT).base(c),
|
||||
(StretchPhase::Select, Some(c)) => Prompt::new("Specify opposite corner", Accept::POINT).corner(c),
|
||||
(StretchPhase::Select, None) => Prompt::new(if self.removing { "Remove objects" } else { "Select objects" }, Accept::POINT),
|
||||
(StretchPhase::Base, _) => Prompt::new("Specify base point", Accept::POINT).kw(&["Displacement"]).default("Displacement"),
|
||||
(StretchPhase::Displacement, _) => Prompt::new("Specify displacement", Accept::POINT).default("0,0"),
|
||||
|
||||
@@ -365,7 +365,7 @@ impl Interactive for PlotWindowM {
|
||||
fn prompt(&self, _s: &Session) -> Prompt {
|
||||
match self.first {
|
||||
None => Prompt::new("Specify first corner", Accept::POINT),
|
||||
Some(a) => Prompt::new("Specify opposite corner", Accept::POINT).base(a),
|
||||
Some(a) => Prompt::new("Specify opposite corner", Accept::POINT).corner(a),
|
||||
}
|
||||
}
|
||||
fn input(&mut self, s: &mut Session, i: Input) -> Result<Step> {
|
||||
|
||||
@@ -279,7 +279,7 @@ impl Interactive for ViewM {
|
||||
Stage::Restore => Prompt::new("Enter view name to restore", Accept::TEXT),
|
||||
Stage::Save | Stage::WindowName => Prompt::new("Enter view name to save", Accept::TEXT),
|
||||
Stage::WindowFirst => Prompt::new("Specify first corner", Accept::POINT),
|
||||
Stage::WindowSecond(a) => Prompt::new("Specify opposite corner", Accept::POINT).base(a),
|
||||
Stage::WindowSecond(a) => Prompt::new("Specify opposite corner", Accept::POINT).corner(a),
|
||||
Stage::Settings => Prompt::new("Enter an option", Accept::TEXT).kw(&["Layer snapshot"]),
|
||||
Stage::Snapshot => {
|
||||
let on = if s.settings.view_layer_snapshot { "Yes" } else { "No" };
|
||||
|
||||
@@ -434,7 +434,7 @@ impl SelectMode {
|
||||
};
|
||||
match last {
|
||||
None => Prompt::new(first, Accept::POINT),
|
||||
Some(p) if self.is_box() => Prompt::new(next, Accept::POINT).base(p),
|
||||
Some(p) if self.is_box() => Prompt::new(next, Accept::POINT).corner(p),
|
||||
Some(p) => Prompt::new(next, Accept::POINT).kw(&["Undo"]).base(p),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//! STRETCH's crossing window ignores ortho: the opposite corner is where the cursor is, so the
|
||||
//! window keeps its area and catches what it crosses. The same holds for every rectangle picked by
|
||||
//! two corners (PLOTWINDOW, MVIEW, -VIEW Window, REVCLOUD Rectangular).
|
||||
|
||||
use cadcraft_engine::snap::tracking::CursorQuery;
|
||||
use cadcraft_engine::{Input, Session};
|
||||
use cadcraft_geom::Vec2;
|
||||
use serde_json::json;
|
||||
|
||||
/// Move the cursor to `raw` at the current prompt, as the canvas does.
|
||||
fn hover(s: &mut Session, raw: Vec2) -> Vec2 {
|
||||
let p = s.current_prompt().unwrap();
|
||||
let q = CursorQuery { base: p.base, deferred: p.deferred, corner: p.corner, aperture: 1e-6, tol: 1e-6, now: 0.0, shift: false };
|
||||
let c = s.snap_cursor(raw, &q).point;
|
||||
s.cursor = c;
|
||||
c
|
||||
}
|
||||
|
||||
/// A session with ortho on, object snaps off and a line from 0,0 to 10,0.
|
||||
fn ortho_session() -> Session {
|
||||
let mut s = Session::new();
|
||||
s.execute("setvar", &json!({ "name": "OSMODE", "value": 0 })).unwrap();
|
||||
s.execute("setvar", &json!({ "name": "ORTHOMODE", "value": 1 })).unwrap();
|
||||
s.execute("line", &json!({ "points": [[0, 0], [10, 0]] })).unwrap();
|
||||
s
|
||||
}
|
||||
|
||||
/// Pick the window's opposite corner at `to`, stretch by 5,0 and return the extents.
|
||||
fn stretch_from_corner(mut s: Session, to: Vec2) -> (Vec2, Vec2) {
|
||||
assert_eq!(s.current_prompt().unwrap().message, "Specify opposite corner");
|
||||
let c = hover(&mut s, to);
|
||||
assert!(c.near(to, 1e-9), "the corner is where the cursor is: {c:?}");
|
||||
s.input(Input::Point(c)).unwrap();
|
||||
s.input(Input::Enter).unwrap();
|
||||
for t in ["0,0", "5,0"] {
|
||||
s.cmdline(t).unwrap();
|
||||
}
|
||||
assert!(s.current_prompt().is_none(), "STRETCH is done, still at {:?}", s.current_prompt().map(|p| p.message));
|
||||
let b = s.doc().unwrap().extents(&s.space());
|
||||
(b.min, b.max)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stretch_implied_window_ignores_ortho() {
|
||||
let mut s = ortho_session();
|
||||
s.cmdline("stretch").unwrap();
|
||||
// Right to left: a crossing window.
|
||||
s.input(Input::Point(Vec2::new(12.0, 1.0))).unwrap();
|
||||
assert_eq!(stretch_from_corner(s, Vec2::new(8.0, -1.0)), (Vec2::ZERO, Vec2::new(15.0, 0.0)), "the line's end moved by 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stretch_crossing_mode_ignores_ortho() {
|
||||
let mut s = ortho_session();
|
||||
for t in ["stretch", "c", "8,-1"] {
|
||||
s.cmdline(t).unwrap();
|
||||
}
|
||||
assert_eq!(stretch_from_corner(s, Vec2::new(12.0, 1.0)), (Vec2::ZERO, Vec2::new(15.0, 0.0)), "the line's end moved by 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rectangle_corner_prompts_ignore_ortho() {
|
||||
for script in [&["plotwindow", "0,0"][..], &["mview", "0,0"], &["-view", "w", "v1", "0,0"], &["revcloud", "r", "0,0"]] {
|
||||
let mut s = Session::new();
|
||||
s.execute("setvar", &json!({ "name": "OSMODE", "value": 0 })).unwrap();
|
||||
s.execute("setvar", &json!({ "name": "ORTHOMODE", "value": 1 })).unwrap();
|
||||
if script[0] == "mview" {
|
||||
s.cmdline("layout s Layout1").unwrap();
|
||||
}
|
||||
for t in script {
|
||||
s.cmdline(t).unwrap();
|
||||
}
|
||||
let p = s.current_prompt().unwrap();
|
||||
assert_eq!(p.message, "Specify opposite corner", "{script:?}");
|
||||
assert!(p.corner, "{script:?}: the opposite corner ignores ortho");
|
||||
let c = hover(&mut s, Vec2::new(10.0, 4.0));
|
||||
assert!(c.near(Vec2::new(10.0, 4.0), 1e-9), "{script:?}: the corner is where the cursor is: {c:?}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user