forked from 1b-agent/opencadstudio-upstream
Merge remote-tracking branch 'origin/main' into merge-test/main-into-constraints
# Conflicts: # src/app/command_driver.rs # src/command.rs # src/ui/ribbon/mod.rs # src/ui/window/options.rs
This commit is contained in:
commit
ad718def3f
124 files changed
+9866
-692
No files matched your search
+123
@@ -744,6 +744,88 @@ impl CadCommand for TwoValuePromptCommand {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Mid between 2 points (MTP / M2P) ────────────────────────────────────────
|
||||
|
||||
/// Point-entry modifier that prompts for two points, draws a preview connecting line
|
||||
/// with a midpoint marker, and returns the midpoint to the caller.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Mid2PointCommand {
|
||||
pub first_point: Option<DVec3>,
|
||||
}
|
||||
|
||||
impl Mid2PointCommand {
|
||||
pub fn new() -> Self {
|
||||
Self { first_point: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for Mid2PointCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"MTP"
|
||||
}
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
if self.first_point.is_none() {
|
||||
crate::t!("_mtp Specify first point of mid:").into_owned()
|
||||
} else {
|
||||
crate::t!("_mtp Specify second point of mid:").into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
||||
if let Some(first) = self.first_point {
|
||||
let mid = (first + pt) * 0.5;
|
||||
CmdResult::ReturnPoint(mid)
|
||||
} else {
|
||||
self.first_point = Some(pt);
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
CmdResult::Cancel
|
||||
}
|
||||
|
||||
fn on_escape(&mut self) -> CmdResult {
|
||||
CmdResult::Cancel
|
||||
}
|
||||
|
||||
fn on_preview_wires(&mut self, pt: DVec3) -> Vec<WireModel> {
|
||||
let mut wires = Vec::new();
|
||||
if let Some(first) = self.first_point {
|
||||
// Rubber-band line connecting the first point to the cursor
|
||||
wires.push(WireModel::solid_f64(
|
||||
"mtp_rubber_band".to_string(),
|
||||
vec![[first.x, first.y, first.z], [pt.x, pt.y, pt.z]],
|
||||
WireModel::CYAN,
|
||||
false,
|
||||
));
|
||||
// Midpoint marker (AutoCAD style triangle glyph)
|
||||
let mid = (first + pt) * 0.5;
|
||||
let dist = (pt - first).length();
|
||||
let s = (dist * 0.02).clamp(0.5, 10.0);
|
||||
let h = s * 1.5;
|
||||
let w = s * 1.0;
|
||||
wires.push(WireModel::solid_f64(
|
||||
"mtp_mid_triangle".to_string(),
|
||||
vec![
|
||||
[mid.x, mid.y + h * (2.0 / 3.0), mid.z],
|
||||
[mid.x - w, mid.y - h * (1.0 / 3.0), mid.z],
|
||||
[mid.x + w, mid.y - h * (1.0 / 3.0), mid.z],
|
||||
],
|
||||
WireModel::CYAN,
|
||||
true,
|
||||
));
|
||||
}
|
||||
wires
|
||||
}
|
||||
}
|
||||
|
||||
inventory::submit!(CommandRegistration {
|
||||
names: &["MTP", "M2P"],
|
||||
});
|
||||
|
||||
|
||||
/// Generic interactive front-end for a keyword command that operates on the
|
||||
/// current selection (CHPROP, ADJUST, XDATA, UNDERLAY, DRAWORDER…). If nothing
|
||||
/// is selected when it starts it first gathers a selection (Enter confirms),
|
||||
@@ -1689,6 +1771,8 @@ pub enum CmdResult {
|
||||
UndoDocument,
|
||||
/// Sets the TEXTEDITMODE system variable and ends the command.
|
||||
SetTexteditMode(bool),
|
||||
/// Return a resolved point back to a suspended parent command (e.g. MTP / M2P).
|
||||
ReturnPoint(DVec3),
|
||||
}
|
||||
|
||||
/// What kind of value the active command is currently asking for. Drives
|
||||
@@ -2485,3 +2569,42 @@ mod constraint_registry_tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_mid2point_command() {
|
||||
let mut cmd = Mid2PointCommand::new();
|
||||
assert_eq!(cmd.name(), "MTP");
|
||||
assert_eq!(cmd.prompt(), "_mtp Specify first point of mid:");
|
||||
|
||||
// First point
|
||||
let res = cmd.on_point(DVec3::new(10.0, 20.0, 0.0));
|
||||
assert!(matches!(res, CmdResult::NeedPoint));
|
||||
assert_eq!(cmd.prompt(), "_mtp Specify second point of mid:");
|
||||
|
||||
// Preview wires
|
||||
let wires = cmd.on_preview_wires(DVec3::new(30.0, 40.0, 0.0));
|
||||
assert!(!wires.is_empty());
|
||||
|
||||
// Second point
|
||||
let res = cmd.on_point(DVec3::new(30.0, 40.0, 0.0));
|
||||
assert!(matches!(res, CmdResult::ReturnPoint(mid) if mid == DVec3::new(20.0, 30.0, 0.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mid2point_cancel() {
|
||||
let mut cmd = Mid2PointCommand::new();
|
||||
assert!(matches!(cmd.on_escape(), CmdResult::Cancel));
|
||||
assert!(matches!(cmd.on_enter(), CmdResult::Cancel));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mtp_registered() {
|
||||
let names = all_registered_command_names();
|
||||
assert!(names.contains(&"MTP"));
|
||||
assert!(names.contains(&"M2P"));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user