forked from 1b-agent/opencadstudio-upstream
TRIM / EXTEND: Standard mode and TRIMEXTENDMODE (#1733)
Both commands gain a mOde option [Quick/Standard]. Quick (the default) starts ready to pick, every object a cutting or boundary edge; Standard starts by selecting those edges, Enter with none taking every object. The choice is TRIMEXTENDMODE (1 Quick, 0 Standard), kept in the profile and settable with SETVAR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7f411bc02d
commit
368dd0d7a5
5 files changed
+135
-4
No files matched your search
@@ -756,6 +756,7 @@ inventory::submit!(crate::command::CommandRegistration {
|
|||||||
"UOSNAP",
|
"UOSNAP",
|
||||||
"FIELDDISPLAY",
|
"FIELDDISPLAY",
|
||||||
"FILEDIA",
|
"FILEDIA",
|
||||||
|
"TRIMEXTENDMODE",
|
||||||
"SURFACEASSOCIATIVITY",
|
"SURFACEASSOCIATIVITY",
|
||||||
"LAYOUTCREATEVIEWPORT",
|
"LAYOUTCREATEVIEWPORT",
|
||||||
"FIELDEVAL",
|
"FIELDEVAL",
|
||||||
|
|||||||
@@ -1214,6 +1214,7 @@ impl OpenCADStudio {
|
|||||||
| "UOSNAP"
|
| "UOSNAP"
|
||||||
| "FIELDDISPLAY"
|
| "FIELDDISPLAY"
|
||||||
| "FILEDIA"
|
| "FILEDIA"
|
||||||
|
| "TRIMEXTENDMODE"
|
||||||
| "SURFACEASSOCIATIVITY"
|
| "SURFACEASSOCIATIVITY"
|
||||||
| "UCSORTHO"
|
| "UCSORTHO"
|
||||||
| "UCSVIEW"
|
| "UCSVIEW"
|
||||||
@@ -1603,6 +1604,33 @@ impl OpenCADStudio {
|
|||||||
}
|
}
|
||||||
return Some(self.finish_dispatch(cmd));
|
return Some(self.finish_dispatch(cmd));
|
||||||
}
|
}
|
||||||
|
if name == "TRIMEXTENDMODE" {
|
||||||
|
use crate::modules::draw::modify::trim;
|
||||||
|
let current = i16::from(trim::quick_mode());
|
||||||
|
let prompt = format!("Enter new value for TRIMEXTENDMODE <{current}>:");
|
||||||
|
match value
|
||||||
|
.as_deref()
|
||||||
|
.map(|v| v.trim().parse::<i16>().ok().filter(|v| (0..=1).contains(v)))
|
||||||
|
{
|
||||||
|
Some(Some(mode)) => {
|
||||||
|
if current != mode {
|
||||||
|
trim::set_quick_mode(mode == 1);
|
||||||
|
self.save_config();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(None) => {
|
||||||
|
self.command_line
|
||||||
|
.push_error(crate::t!("Requires 0 or 1 only.").as_ref());
|
||||||
|
self.command_line.push_output(&prompt);
|
||||||
|
self.pending_setvar = Some(name.clone());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.command_line.push_output(&prompt);
|
||||||
|
self.pending_setvar = Some(name.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(self.finish_dispatch(cmd));
|
||||||
|
}
|
||||||
if name == "FILEDIA" {
|
if name == "FILEDIA" {
|
||||||
let current = i16::from(crate::sys::file_dia());
|
let current = i16::from(crate::sys::file_dia());
|
||||||
match value
|
match value
|
||||||
|
|||||||
@@ -441,6 +441,8 @@ pub struct UserSettings {
|
|||||||
pub xref_fade: i32,
|
pub xref_fade: i32,
|
||||||
/// FILEDIA: file dialogs of commands that have a command-line form.
|
/// FILEDIA: file dialogs of commands that have a command-line form.
|
||||||
pub file_dia: bool,
|
pub file_dia: bool,
|
||||||
|
/// TRIMEXTENDMODE: TRIM and EXTEND start in Quick mode (else Standard).
|
||||||
|
pub trim_extend_quick: bool,
|
||||||
/// The file type ATTACH's picker was last left on (1-based).
|
/// The file type ATTACH's picker was last left on (1-based).
|
||||||
pub attach_filter: u32,
|
pub attach_filter: u32,
|
||||||
/// SURFACEASSOCIATIVITY: new surfaces stay associative to their sources.
|
/// SURFACEASSOCIATIVITY: new surfaces stay associative to their sources.
|
||||||
@@ -915,6 +917,7 @@ impl Default for UserSettings {
|
|||||||
field_display: true,
|
field_display: true,
|
||||||
xref_fade: 50,
|
xref_fade: 50,
|
||||||
file_dia: true,
|
file_dia: true,
|
||||||
|
trim_extend_quick: true,
|
||||||
attach_filter: 7,
|
attach_filter: 7,
|
||||||
surface_associativity: true,
|
surface_associativity: true,
|
||||||
ucs_ortho: true,
|
ucs_ortho: true,
|
||||||
|
|||||||
@@ -810,6 +810,7 @@ impl OpenCADStudio {
|
|||||||
field_display: crate::entities::field::display(),
|
field_display: crate::entities::field::display(),
|
||||||
xref_fade: crate::scene::cache::block_cache::xref_fade_ctl(),
|
xref_fade: crate::scene::cache::block_cache::xref_fade_ctl(),
|
||||||
file_dia: crate::sys::file_dia(),
|
file_dia: crate::sys::file_dia(),
|
||||||
|
trim_extend_quick: crate::modules::draw::modify::trim::quick_mode(),
|
||||||
attach_filter: crate::sys::attach_filter(),
|
attach_filter: crate::sys::attach_filter(),
|
||||||
surface_associativity: crate::scene::model::sweep_model::surface_associativity(),
|
surface_associativity: crate::scene::model::sweep_model::surface_associativity(),
|
||||||
ucs_ortho: crate::modules::view::view_cmd::ucs_ortho(),
|
ucs_ortho: crate::modules::view::view_cmd::ucs_ortho(),
|
||||||
@@ -946,6 +947,7 @@ impl OpenCADStudio {
|
|||||||
crate::scene::cache::block_cache::set_xref_fade_ctl(s.xref_fade);
|
crate::scene::cache::block_cache::set_xref_fade_ctl(s.xref_fade);
|
||||||
self.ribbon.xref_fade = crate::scene::cache::block_cache::xref_fade_ctl();
|
self.ribbon.xref_fade = crate::scene::cache::block_cache::xref_fade_ctl();
|
||||||
crate::sys::set_file_dia(s.file_dia);
|
crate::sys::set_file_dia(s.file_dia);
|
||||||
|
crate::modules::draw::modify::trim::set_quick_mode(s.trim_extend_quick);
|
||||||
crate::sys::set_attach_filter(s.attach_filter);
|
crate::sys::set_attach_filter(s.attach_filter);
|
||||||
crate::scene::model::sweep_model::set_surface_associativity(s.surface_associativity);
|
crate::scene::model::sweep_model::set_surface_associativity(s.surface_associativity);
|
||||||
crate::modules::view::view_cmd::set_ucs_ortho(s.ucs_ortho);
|
crate::modules::view::view_cmd::set_ucs_ortho(s.ucs_ortho);
|
||||||
|
|||||||
@@ -1755,6 +1755,73 @@ enum TrimMode {
|
|||||||
CrossSecond([f64; 2]),
|
CrossSecond([f64; 2]),
|
||||||
/// Erase mode: each pick deletes the object; Enter returns to Pick.
|
/// Erase mode: each pick deletes the object; Enter returns to Pick.
|
||||||
Erase,
|
Erase,
|
||||||
|
/// mOde: choosing between Quick and Standard (TRIMEXTENDMODE).
|
||||||
|
ChooseMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TRIMEXTENDMODE: 1 (Quick) starts TRIM and EXTEND ready to pick, every
|
||||||
|
/// object a cutting or boundary edge; 0 (Standard) starts them selecting
|
||||||
|
/// those edges first.
|
||||||
|
static QUICK_MODE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);
|
||||||
|
|
||||||
|
pub fn quick_mode() -> bool {
|
||||||
|
QUICK_MODE.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_quick_mode(quick: bool) {
|
||||||
|
QUICK_MODE.store(quick, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The mOde prompt, offering the current mode as the default.
|
||||||
|
fn mode_prompt(command: &str) -> String {
|
||||||
|
let current = if quick_mode() { "Quick" } else { "Standard" };
|
||||||
|
crate::tf!("{command} Enter a trim mode option [Quick/Standard] <{current}>:").into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mode_options() -> Vec<crate::command::CmdOption> {
|
||||||
|
use crate::command::CmdOption;
|
||||||
|
vec![CmdOption::new("Quick", "Q"), CmdOption::new("Standard", "S")]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The mOde option and its answer, shared by TRIM and EXTEND. Returns the
|
||||||
|
/// step's result and whether the edges must be rebuilt, or `None` for input
|
||||||
|
/// that is not about the mode.
|
||||||
|
fn choose_mode(
|
||||||
|
mode: &mut TrimMode,
|
||||||
|
edge_set: &mut Vec<Handle>,
|
||||||
|
text: &str,
|
||||||
|
) -> Option<(CmdResult, bool)> {
|
||||||
|
let word = text.trim().to_uppercase();
|
||||||
|
match (&*mode, word.as_str()) {
|
||||||
|
(TrimMode::Pick, "O" | "MODE") => *mode = TrimMode::ChooseMode,
|
||||||
|
(TrimMode::ChooseMode, "Q" | "QUICK") => {
|
||||||
|
set_quick_mode(true);
|
||||||
|
edge_set.clear();
|
||||||
|
*mode = TrimMode::Pick;
|
||||||
|
return Some((CmdResult::NeedPoint, true));
|
||||||
|
}
|
||||||
|
(TrimMode::ChooseMode, "S" | "STANDARD") => {
|
||||||
|
set_quick_mode(false);
|
||||||
|
edge_set.clear();
|
||||||
|
*mode = TrimMode::SelectEdges;
|
||||||
|
}
|
||||||
|
(TrimMode::ChooseMode, _) => {
|
||||||
|
let message = crate::t!("Invalid option keyword.").into_owned();
|
||||||
|
return Some((CmdResult::ReportError(message), false));
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
Some((CmdResult::NeedPoint, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The first step: picking in Quick mode or when edges were preselected,
|
||||||
|
/// selecting edges in Standard mode.
|
||||||
|
fn starting_mode(initial_edges: &[Handle]) -> TrimMode {
|
||||||
|
if quick_mode() || !initial_edges.is_empty() {
|
||||||
|
TrimMode::Pick
|
||||||
|
} else {
|
||||||
|
TrimMode::SelectEdges
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -2622,6 +2689,14 @@ pub struct TrimCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TrimCommand {
|
impl TrimCommand {
|
||||||
|
fn choose_mode(&mut self, text: &str) -> Option<CmdResult> {
|
||||||
|
let (result, rebuild) = choose_mode(&mut self.mode, &mut self.edge_set, text)?;
|
||||||
|
if rebuild {
|
||||||
|
self.rebuild_geos();
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(all_entities: Vec<EntityType>) -> Self {
|
pub fn new(all_entities: Vec<EntityType>) -> Self {
|
||||||
Self::with_cutting_edges(all_entities, Vec::new())
|
Self::with_cutting_edges(all_entities, Vec::new())
|
||||||
}
|
}
|
||||||
@@ -2638,7 +2713,7 @@ impl TrimCommand {
|
|||||||
all_entities,
|
all_entities,
|
||||||
entity_index,
|
entity_index,
|
||||||
geos: Vec::new(),
|
geos: Vec::new(),
|
||||||
mode: TrimMode::Pick,
|
mode: starting_mode(&initial_edges),
|
||||||
edge_set: initial_edges,
|
edge_set: initial_edges,
|
||||||
implied_edges: false,
|
implied_edges: false,
|
||||||
shift: false,
|
shift: false,
|
||||||
@@ -2745,6 +2820,7 @@ impl CadCommand for TrimCommand {
|
|||||||
TrimMode::Erase => {
|
TrimMode::Erase => {
|
||||||
t!("TRIM Erase: click objects to delete [Enter = done]:").into_owned()
|
t!("TRIM Erase: click objects to delete [Enter = done]:").into_owned()
|
||||||
}
|
}
|
||||||
|
TrimMode::ChooseMode => mode_prompt("TRIM"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2764,8 +2840,10 @@ impl CadCommand for TrimCommand {
|
|||||||
"E",
|
"E",
|
||||||
),
|
),
|
||||||
CmdOption::new("Erase", "R"),
|
CmdOption::new("Erase", "R"),
|
||||||
|
CmdOption::new("mOde", "O"),
|
||||||
CmdOption::enter("Done"),
|
CmdOption::enter("Done"),
|
||||||
],
|
],
|
||||||
|
TrimMode::ChooseMode => mode_options(),
|
||||||
_ => vec![CmdOption::enter("Done")],
|
_ => vec![CmdOption::enter("Done")],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2777,6 +2855,9 @@ impl CadCommand for TrimCommand {
|
|||||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||||
// Consumed inputs return Some(NeedPoint) — None would be offered to
|
// Consumed inputs return Some(NeedPoint) — None would be offered to
|
||||||
// the command a second time by the driver.
|
// the command a second time by the driver.
|
||||||
|
if let Some(result) = self.choose_mode(text) {
|
||||||
|
return Some(result);
|
||||||
|
}
|
||||||
match text.trim().to_uppercase().as_str() {
|
match text.trim().to_uppercase().as_str() {
|
||||||
"T" | "CUTTING" | "B" | "BOUNDARY" => {
|
"T" | "CUTTING" | "B" | "BOUNDARY" => {
|
||||||
self.edge_set.clear();
|
self.edge_set.clear();
|
||||||
@@ -3325,7 +3406,8 @@ impl CadCommand for TrimCommand {
|
|||||||
TrimMode::Fence(_)
|
TrimMode::Fence(_)
|
||||||
| TrimMode::CrossFirst
|
| TrimMode::CrossFirst
|
||||||
| TrimMode::CrossSecond(_)
|
| TrimMode::CrossSecond(_)
|
||||||
| TrimMode::Erase => CmdResult::NeedPoint,
|
| TrimMode::Erase
|
||||||
|
| TrimMode::ChooseMode => CmdResult::NeedPoint,
|
||||||
TrimMode::Pick => CmdResult::Cancel,
|
TrimMode::Pick => CmdResult::Cancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3357,6 +3439,14 @@ pub struct ExtendCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExtendCommand {
|
impl ExtendCommand {
|
||||||
|
fn choose_mode(&mut self, text: &str) -> Option<CmdResult> {
|
||||||
|
let (result, rebuild) = choose_mode(&mut self.mode, &mut self.edge_set, text)?;
|
||||||
|
if rebuild {
|
||||||
|
self.rebuild_geos();
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(all_entities: Vec<EntityType>) -> Self {
|
pub fn new(all_entities: Vec<EntityType>) -> Self {
|
||||||
Self::with_boundary_edges(all_entities, Vec::new())
|
Self::with_boundary_edges(all_entities, Vec::new())
|
||||||
}
|
}
|
||||||
@@ -3373,7 +3463,7 @@ impl ExtendCommand {
|
|||||||
all_entities,
|
all_entities,
|
||||||
entity_index,
|
entity_index,
|
||||||
geos: Vec::new(),
|
geos: Vec::new(),
|
||||||
mode: TrimMode::Pick,
|
mode: starting_mode(&initial_edges),
|
||||||
edge_set: initial_edges,
|
edge_set: initial_edges,
|
||||||
implied_edges: false,
|
implied_edges: false,
|
||||||
shift: false,
|
shift: false,
|
||||||
@@ -3443,6 +3533,7 @@ impl CadCommand for ExtendCommand {
|
|||||||
crate::tf!("EXTEND{edge} Crossing: opposite corner:").into_owned()
|
crate::tf!("EXTEND{edge} Crossing: opposite corner:").into_owned()
|
||||||
}
|
}
|
||||||
TrimMode::Erase => t!("EXTEND [Enter = done]:").into_owned(),
|
TrimMode::Erase => t!("EXTEND [Enter = done]:").into_owned(),
|
||||||
|
TrimMode::ChooseMode => mode_prompt("EXTEND"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3461,8 +3552,10 @@ impl CadCommand for ExtendCommand {
|
|||||||
},
|
},
|
||||||
"E",
|
"E",
|
||||||
),
|
),
|
||||||
|
CmdOption::new("mOde", "O"),
|
||||||
CmdOption::enter("Done"),
|
CmdOption::enter("Done"),
|
||||||
],
|
],
|
||||||
|
TrimMode::ChooseMode => mode_options(),
|
||||||
_ => vec![CmdOption::enter("Done")],
|
_ => vec![CmdOption::enter("Done")],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3472,6 +3565,9 @@ impl CadCommand for ExtendCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||||
|
if let Some(result) = self.choose_mode(text) {
|
||||||
|
return Some(result);
|
||||||
|
}
|
||||||
match text.trim().to_uppercase().as_str() {
|
match text.trim().to_uppercase().as_str() {
|
||||||
"B" | "BOUNDARY" | "T" | "CUTTING" => {
|
"B" | "BOUNDARY" | "T" | "CUTTING" => {
|
||||||
self.edge_set.clear();
|
self.edge_set.clear();
|
||||||
@@ -3788,7 +3884,8 @@ impl CadCommand for ExtendCommand {
|
|||||||
TrimMode::Fence(_)
|
TrimMode::Fence(_)
|
||||||
| TrimMode::CrossFirst
|
| TrimMode::CrossFirst
|
||||||
| TrimMode::CrossSecond(_)
|
| TrimMode::CrossSecond(_)
|
||||||
| TrimMode::Erase => CmdResult::NeedPoint,
|
| TrimMode::Erase
|
||||||
|
| TrimMode::ChooseMode => CmdResult::NeedPoint,
|
||||||
TrimMode::Pick => CmdResult::Cancel,
|
TrimMode::Pick => CmdResult::Cancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user