forked from 1b-agent/opencadstudio-upstream
Count: measured messages and listing, groups, Current area, boundary checks, fills and solids recoloured
- COUNTCOLOR / COUNTERRORCOLOR / COUNTSERVICE reject any other value with the range message; COUNTTABLE ? lists in the reference order, padded, 22 lines a page with Press ENTER to continue:, then the totals. - Target picks report N found / N found, M total; several objects (or one that is not a block reference) count their copies, shown as Geometries in the palette. - Current area is the area in use (kept aside by Entire model space), otherwise all of model space; an invalid Object boundary ends with the reference message. - Count colours reach solids and fills; the palette list and the count are recomputed only when the drawing changes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
d830e40bfa
commit
0a26709d13
31 files changed
+214
-60
No files matched your search
@@ -144,8 +144,16 @@ impl CadCommand for CountCommand {
|
||||
}
|
||||
|
||||
fn on_selection_complete(&mut self, handles: Vec<Handle>) -> CmdResult {
|
||||
// The selection arrives whole after every pick: `1 found`, then
|
||||
// `1 found, 2 total`.
|
||||
let found = handles.iter().filter(|h| !self.targets.contains(h)).count();
|
||||
let first = self.targets.is_empty();
|
||||
self.targets = handles;
|
||||
CmdResult::ReportMeasurement(format!("{} found", self.targets.len()))
|
||||
CmdResult::ReportMeasurement(if first {
|
||||
format!("{found} found")
|
||||
} else {
|
||||
format!("{found} found, {} total", self.targets.len())
|
||||
})
|
||||
}
|
||||
|
||||
fn needs_entity_pick(&self) -> bool {
|
||||
@@ -162,11 +170,13 @@ impl CadCommand for CountCommand {
|
||||
|
||||
fn on_entity_pick(&mut self, handle: Handle, _pt: DVec3) -> CmdResult {
|
||||
match self.picked.take() {
|
||||
Some(EntityType::LwPolyline(pl)) if pl.is_closed && pl.vertices.len() >= 3 => {
|
||||
Some(EntityType::LwPolyline(pl)) if codec::count::valid_boundary(&pl) => {
|
||||
self.area_done(format!("O {:X}", handle.value()))
|
||||
}
|
||||
// Anything else: the prompt again.
|
||||
_ => CmdResult::NeedPoint,
|
||||
_ => CmdResult::CancelWithMessage(
|
||||
"Invalid count area boundary object. Select a closed polyline consisting of line segments and does not intersect itself."
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +254,8 @@ pub struct CountTableCommand {
|
||||
blocks: Vec<String>,
|
||||
others: [usize; 3],
|
||||
names: Vec<String>,
|
||||
/// Listing lines still to show after `Press ENTER to continue:`.
|
||||
pending: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
@@ -251,38 +263,75 @@ enum TableStep {
|
||||
Names,
|
||||
List,
|
||||
Point,
|
||||
Page,
|
||||
}
|
||||
|
||||
impl CountTableCommand {
|
||||
pub fn new(blocks: Vec<String>, others: [usize; 3]) -> Self {
|
||||
Self { step: TableStep::Names, blocks, others, names: Vec::new() }
|
||||
Self { step: TableStep::Names, blocks, others, names: Vec::new(), pending: Vec::new() }
|
||||
}
|
||||
|
||||
/// The palette's Create Table: the blocks are chosen, only the point is asked.
|
||||
pub fn placing(names: Vec<String>) -> Self {
|
||||
Self { step: TableStep::Point, blocks: Vec::new(), others: [0; 3], names }
|
||||
Self { step: TableStep::Point, blocks: Vec::new(), others: [0; 3], names, pending: Vec::new() }
|
||||
}
|
||||
|
||||
/// `?`: the defined blocks matching the pattern and the summary.
|
||||
fn listing(&self, pattern: &str) -> String {
|
||||
/// `?`: the defined blocks matching the pattern, paged by 22 lines
|
||||
/// (`Press ENTER to continue:` in between), then the summary.
|
||||
fn listing(&mut self, pattern: &str) -> CmdResult {
|
||||
let pattern = if pattern.trim().is_empty() { "*" } else { pattern.trim() };
|
||||
let mut out = String::from("Defined blocks.");
|
||||
for name in &self.blocks {
|
||||
if pattern.split(',').any(|p| crate::io::xref_model::wildcard_match(name, p.trim())) {
|
||||
out.push_str(&format!("\n \"{name}\""));
|
||||
}
|
||||
let mut names: Vec<&String> = self
|
||||
.blocks
|
||||
.iter()
|
||||
.filter(|name| pattern.split(',').any(|p| crate::io::xref_model::wildcard_match(name, p.trim())))
|
||||
.collect();
|
||||
names.sort_by_key(|name| list_order(name));
|
||||
self.pending = std::iter::once(String::new())
|
||||
.chain(std::iter::once("Defined blocks.".to_string()))
|
||||
.chain(names.iter().map(|name| format!(" {:<31}", format!("\"{name}\""))))
|
||||
.collect();
|
||||
self.next_page()
|
||||
}
|
||||
|
||||
fn next_page(&mut self) -> CmdResult {
|
||||
let page: Vec<String> = self.pending.drain(..self.pending.len().min(22)).collect();
|
||||
if !self.pending.is_empty() {
|
||||
self.step = TableStep::Page;
|
||||
return CmdResult::ReportMeasurement(page.join("
|
||||
"));
|
||||
}
|
||||
out.push_str(&format!(
|
||||
"\n\nUser External Dependent Unnamed\nBlocks References Blocks Blocks\n{:>5}{:>11}{:>13}{:>12}",
|
||||
CmdResult::Measurement(format!(
|
||||
"{}
|
||||
|
||||
User External Dependent Unnamed
|
||||
Blocks References Blocks Blocks
|
||||
{:>5}{:>10}{:>12}{:>12}
|
||||
",
|
||||
page.join("
|
||||
"),
|
||||
self.blocks.len(),
|
||||
self.others[0],
|
||||
self.others[1],
|
||||
self.others[2]
|
||||
));
|
||||
out
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Block listing order: `_` first, then `-`, space and other punctuation,
|
||||
/// digits, and letters without case.
|
||||
fn list_order(name: &str) -> Vec<(u32, u32)> {
|
||||
name.chars()
|
||||
.map(|c| match c {
|
||||
'_' => (0, 0),
|
||||
'-' => (1, 0),
|
||||
' ' => (2, 0),
|
||||
'0'..='9' => (4, c as u32),
|
||||
c if c.is_alphabetic() => (5, c.to_lowercase().next().unwrap_or(c) as u32),
|
||||
c => (3, c as u32),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl CadCommand for CountTableCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"COUNTTABLE"
|
||||
@@ -293,6 +342,7 @@ impl CadCommand for CountTableCommand {
|
||||
TableStep::Names => "Enter block name(s) to include or [?] <all blocks>:".into(),
|
||||
TableStep::List => "Enter block(s) to list <*>:".into(),
|
||||
TableStep::Point => "Specify insertion point:".into(),
|
||||
TableStep::Page => "Press ENTER to continue:".into(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +377,8 @@ impl CadCommand for CountTableCommand {
|
||||
self.step = TableStep::Point;
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
TableStep::List => CmdResult::Measurement(self.listing(text)),
|
||||
TableStep::List => self.listing(text),
|
||||
TableStep::Page => self.next_page(),
|
||||
TableStep::Point => return None,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user