Align linear dimension properties and grips
This commit is contained in:
parent
f556a2b027
commit
f0d00c1d53
5 changed files with 749 additions and 36 deletions
|
|
@ -1021,7 +1021,11 @@ impl OpenCADStudio {
|
||||||
&& s.name.eq_ignore_ascii_case("Standard"))
|
&& s.name.eq_ignore_ascii_case("Standard"))
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
sections.extend(crate::entities::dimension::style_sections(style));
|
sections.extend(crate::entities::dimension::style_sections(
|
||||||
|
style,
|
||||||
|
d,
|
||||||
|
&self.tabs[i].scene.document,
|
||||||
|
));
|
||||||
|
|
||||||
// The style groups are a read-only mirror, but the
|
// The style groups are a read-only mirror, but the
|
||||||
// dim-line colour is an editable per-object override:
|
// dim-line colour is an editable per-object override:
|
||||||
|
|
@ -1036,6 +1040,25 @@ impl OpenCADStudio {
|
||||||
"dim_line_color",
|
"dim_line_color",
|
||||||
PropValue::ColorChoice(dim_c),
|
PropValue::ColorChoice(dim_c),
|
||||||
);
|
);
|
||||||
|
for (field, code, inherited) in [
|
||||||
|
("dim_ext_line_color", dov::DIMCLRE, style.dimclre),
|
||||||
|
("dim_text_color", dov::DIMCLRT, style.dimclrt),
|
||||||
|
(
|
||||||
|
"dim_text_fill_color",
|
||||||
|
dov::DIMTFILLCLR,
|
||||||
|
style.dimtfillclr,
|
||||||
|
),
|
||||||
|
] {
|
||||||
|
let color = dov::color(&d.base().common.extended_data, code)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
acadrust::types::Color::from_index(inherited)
|
||||||
|
});
|
||||||
|
set_row_value(
|
||||||
|
&mut sections,
|
||||||
|
field,
|
||||||
|
PropValue::ColorChoice(color),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1140,6 +1140,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||||
if matches!(
|
if matches!(
|
||||||
item.action,
|
item.action,
|
||||||
GripMenuAction::Stretch
|
GripMenuAction::Stretch
|
||||||
|
| GripMenuAction::MoveWithDimLine
|
||||||
| GripMenuAction::MoveWithLeader
|
| GripMenuAction::MoveWithLeader
|
||||||
| GripMenuAction::MoveIndependent
|
| GripMenuAction::MoveIndependent
|
||||||
) {
|
) {
|
||||||
|
|
@ -1839,7 +1840,24 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||||
}
|
}
|
||||||
self.push_undo_snapshot(i, "CHPROP");
|
self.push_undo_snapshot(i, "CHPROP");
|
||||||
|
|
||||||
if field == "vscale_std" {
|
if field.starts_with("dim_") {
|
||||||
|
for &handle in &handles {
|
||||||
|
if self.tabs[i].scene.is_layer_locked(handle) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if matches!(
|
||||||
|
self.tabs[i].scene.document.get_entity(handle),
|
||||||
|
Some(acadrust::EntityType::Dimension(_))
|
||||||
|
) {
|
||||||
|
crate::entities::dim_override::set_property(
|
||||||
|
&mut self.tabs[i].scene.document,
|
||||||
|
handle,
|
||||||
|
field,
|
||||||
|
&value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if field == "vscale_std" {
|
||||||
for &handle in &handles {
|
for &handle in &handles {
|
||||||
if matches!(
|
if matches!(
|
||||||
self.tabs[i].scene.document.get_entity(handle),
|
self.tabs[i].scene.document.get_entity(handle),
|
||||||
|
|
@ -2410,6 +2428,19 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match field {
|
match field {
|
||||||
|
_ if field.starts_with("dim_") => {
|
||||||
|
if matches!(
|
||||||
|
self.tabs[i].scene.document.get_entity(handle),
|
||||||
|
Some(acadrust::EntityType::Dimension(_))
|
||||||
|
) {
|
||||||
|
crate::entities::dim_override::set_property(
|
||||||
|
&mut self.tabs[i].scene.document,
|
||||||
|
handle,
|
||||||
|
field,
|
||||||
|
&val,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
"hyperlink" => {
|
"hyperlink" => {
|
||||||
// Stored in the standard PE_URL XDATA
|
// Stored in the standard PE_URL XDATA
|
||||||
// record; an empty value clears it.
|
// record; an empty value clears it.
|
||||||
|
|
|
||||||
|
|
@ -4834,8 +4834,20 @@ impl OpenCADStudio {
|
||||||
// line with the rest of the dim-colour stack (index-only through
|
// line with the rest of the dim-colour stack (index-only through
|
||||||
// the file layer). Guarded to leaders / dimensions so a mixed
|
// the file layer). Guarded to leaders / dimensions so a mixed
|
||||||
// selection can't stamp the override onto other entities.
|
// selection can't stamp the override onto other entities.
|
||||||
if field == "dim_line_color" {
|
if matches!(
|
||||||
|
field.as_str(),
|
||||||
|
"dim_line_color"
|
||||||
|
| "dim_ext_line_color"
|
||||||
|
| "dim_text_color"
|
||||||
|
| "dim_text_fill_color"
|
||||||
|
) {
|
||||||
let aci = color.approximate_index();
|
let aci = color.approximate_index();
|
||||||
|
let code = match field.as_str() {
|
||||||
|
"dim_ext_line_color" => crate::entities::dim_override::DIMCLRE,
|
||||||
|
"dim_text_color" => crate::entities::dim_override::DIMCLRT,
|
||||||
|
"dim_text_fill_color" => crate::entities::dim_override::DIMTFILLCLR,
|
||||||
|
_ => crate::entities::dim_override::DIMCLRD,
|
||||||
|
};
|
||||||
let targets: Vec<acadrust::Handle> = handles
|
let targets: Vec<acadrust::Handle> = handles
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
|
|
@ -4853,7 +4865,7 @@ impl OpenCADStudio {
|
||||||
crate::entities::dim_override::set(
|
crate::entities::dim_override::set(
|
||||||
&mut self.tabs[i].scene.document,
|
&mut self.tabs[i].scene.document,
|
||||||
handle,
|
handle,
|
||||||
crate::entities::dim_override::DIMCLRD,
|
code,
|
||||||
Some(acadrust::xdata::XDataValue::Integer16(aci)),
|
Some(acadrust::xdata::XDataValue::Integer16(aci)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
use acadrust::types::Color;
|
use acadrust::types::Color;
|
||||||
use acadrust::xdata::{ExtendedData, XDataValue};
|
use acadrust::xdata::{ExtendedData, XDataValue};
|
||||||
use acadrust::{CadDocument, Handle};
|
use acadrust::{CadDocument, EntityType, Handle};
|
||||||
|
|
||||||
// DXF group codes of the dimension variables surfaced on the leader panel.
|
// DXF group codes of the dimension variables surfaced on the leader panel.
|
||||||
pub const DIMSCALE: i16 = 40; // overall scale (real)
|
pub const DIMSCALE: i16 = 40; // overall scale (real)
|
||||||
|
|
@ -229,3 +229,273 @@ pub fn set(doc: &mut CadDocument, handle: Handle, code: i16, value: Option<XData
|
||||||
}
|
}
|
||||||
write_pairs(doc, handle, kept);
|
write_pairs(doc, handle, kept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn property_real_code(field: &str) -> Option<i16> {
|
||||||
|
Some(match field {
|
||||||
|
"dim_arrow_size" => DIMASZ,
|
||||||
|
"dim_line_ext" => DIMDLE,
|
||||||
|
"dim_ext_line_ext" => DIMEXE,
|
||||||
|
"dim_ext_line_offset" => DIMEXO,
|
||||||
|
"dim_ext_line_fixed_length" => DIMFXL,
|
||||||
|
"dim_text_height" => DIMTXT,
|
||||||
|
"dim_text_offset" => DIMGAP,
|
||||||
|
"dim_scale_overall" => DIMSCALE,
|
||||||
|
"dim_roundoff" => DIMRND,
|
||||||
|
"dim_scale_linear" => DIMLFAC,
|
||||||
|
"dim_alt_scale_factor" => DIMALTF,
|
||||||
|
"dim_alt_roundoff" => DIMALTRND,
|
||||||
|
"dim_tolerance_limit_lower" => DIMTM,
|
||||||
|
"dim_tolerance_limit_upper" => DIMTP,
|
||||||
|
"dim_tolerance_text_height" => DIMTFAC,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn property_int_code(field: &str) -> Option<i16> {
|
||||||
|
Some(match field {
|
||||||
|
"dim_line_lineweight" => DIMLWD,
|
||||||
|
"dim_ext_line_lineweight" => DIMLWE,
|
||||||
|
"dim_ext_line_fixed" => DIMFXLON,
|
||||||
|
"dim_text_pos_vert" => DIMTAD,
|
||||||
|
"dim_text_pos_hor" => DIMJUST,
|
||||||
|
"dim_text_outside_align" => DIMTOH,
|
||||||
|
"dim_text_inside_align" => DIMTIH,
|
||||||
|
"dim_fit" => DIMATFIT,
|
||||||
|
"dim_text_inside" => DIMTIX,
|
||||||
|
"dim_text_movement" => DIMTMOVE,
|
||||||
|
"dim_line_forced" => DIMTOFL,
|
||||||
|
"dim_line_inside" => DIMSOXD,
|
||||||
|
"dim_units" => DIMLUNIT,
|
||||||
|
"dim_precision" => DIMDEC,
|
||||||
|
"dim_decimal_separator" => DIMDSEP,
|
||||||
|
"dim_angle_format" => DIMAUNIT,
|
||||||
|
"dim_angle_precision" => DIMADEC,
|
||||||
|
"dim_alt_enabled" => DIMALT,
|
||||||
|
"dim_alt_format" => DIMALTU,
|
||||||
|
"dim_alt_precision" => DIMALTD,
|
||||||
|
"dim_tolerance_precision" => DIMTDEC,
|
||||||
|
"dim_tolerance_pos_vert" => DIMTOLJ,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn property_string_code(field: &str) -> Option<i16> {
|
||||||
|
Some(match field {
|
||||||
|
"dim_prefix_suffix" => DIMPOST,
|
||||||
|
"dim_alt_prefix_suffix" => DIMAPOST,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn yes(value: &str) -> Option<i16> {
|
||||||
|
match value.trim().to_ascii_lowercase().as_str() {
|
||||||
|
"yes" | "on" | "true" | "1" => Some(1),
|
||||||
|
"no" | "off" | "false" | "0" => Some(0),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inherited_int(doc: &CadDocument, handle: Handle, code: i16) -> i16 {
|
||||||
|
let Some(EntityType::Dimension(dimension)) = doc.get_entity(handle) else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
if let Some(value) = int(&dimension.base().common.extended_data, code) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
let Some(style) = doc.dim_styles.iter().find(|style| {
|
||||||
|
style.name.eq_ignore_ascii_case(&dimension.base().style_name)
|
||||||
|
|| (dimension.base().style_name.trim().is_empty()
|
||||||
|
&& style.name.eq_ignore_ascii_case("Standard"))
|
||||||
|
}) else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
match code {
|
||||||
|
DIMSD1 => style.dimsd1 as i16,
|
||||||
|
DIMSD2 => style.dimsd2 as i16,
|
||||||
|
DIMSE1 => style.dimse1 as i16,
|
||||||
|
DIMSE2 => style.dimse2 as i16,
|
||||||
|
DIMZIN => style.dimzin,
|
||||||
|
DIMALTZ => style.dimaltz,
|
||||||
|
DIMTZIN => style.dimtzin,
|
||||||
|
DIMTOL => style.dimtol as i16,
|
||||||
|
DIMLIM => style.dimlim as i16,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_property(
|
||||||
|
doc: &mut CadDocument,
|
||||||
|
handle: Handle,
|
||||||
|
field: &str,
|
||||||
|
value: &str,
|
||||||
|
) -> bool {
|
||||||
|
let trimmed = value.trim();
|
||||||
|
let handle_field = match field {
|
||||||
|
"dim_arrowhead_1" => Some((DIMBLK1, true)),
|
||||||
|
"dim_arrowhead_2" => Some((DIMBLK2, true)),
|
||||||
|
"dim_linetype" => Some((DIMLTYPE, false)),
|
||||||
|
"dim_ext_linetype_1" => Some((DIMLTEX1, false)),
|
||||||
|
"dim_ext_linetype_2" => Some((DIMLTEX2, false)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some((code, block)) = handle_field {
|
||||||
|
let resolved = if block {
|
||||||
|
(trimmed != "Closed filled")
|
||||||
|
.then(|| {
|
||||||
|
doc.block_records
|
||||||
|
.iter()
|
||||||
|
.find(|record| record.name == trimmed)
|
||||||
|
.map(|record| record.handle)
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
} else {
|
||||||
|
doc.line_types
|
||||||
|
.iter()
|
||||||
|
.find(|line_type| line_type.name == trimmed)
|
||||||
|
.map(|line_type| line_type.handle)
|
||||||
|
};
|
||||||
|
set(doc, handle, code, resolved.map(XDataValue::Handle));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let inverse_boolean_code = match field {
|
||||||
|
"dim_line_1" => Some(DIMSD1),
|
||||||
|
"dim_line_2" => Some(DIMSD2),
|
||||||
|
"dim_ext_line_1" => Some(DIMSE1),
|
||||||
|
"dim_ext_line_2" => Some(DIMSE2),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(code) = inverse_boolean_code {
|
||||||
|
let Some(visible) = yes(trimmed) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
set(doc, handle, code, Some(XDataValue::Integer16((visible == 0) as i16)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let bit_field = match field {
|
||||||
|
"dim_suppress_leading_zeros" => Some((DIMZIN, 4)),
|
||||||
|
"dim_suppress_trailing_zeros" => Some((DIMZIN, 8)),
|
||||||
|
"dim_alt_suppress_leading_zeros" => Some((DIMALTZ, 4)),
|
||||||
|
"dim_alt_suppress_trailing_zeros" => Some((DIMALTZ, 8)),
|
||||||
|
"dim_tolerance_suppress_leading_zeros" => Some((DIMTZIN, 4)),
|
||||||
|
"dim_tolerance_suppress_trailing_zeros" => Some((DIMTZIN, 8)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some((code, bit)) = bit_field {
|
||||||
|
let Some(enabled) = yes(trimmed) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let current = inherited_int(doc, handle, code);
|
||||||
|
let value = if enabled != 0 {
|
||||||
|
current | bit
|
||||||
|
} else {
|
||||||
|
current & !bit
|
||||||
|
};
|
||||||
|
set(doc, handle, code, Some(XDataValue::Integer16(value)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if field == "dim_tolerance_display" {
|
||||||
|
let (tolerance, limits) = match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"deviation" => (1, 0),
|
||||||
|
"limits" => (0, 1),
|
||||||
|
"none" => (0, 0),
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
set(doc, handle, DIMTOL, Some(XDataValue::Integer16(tolerance)));
|
||||||
|
set(doc, handle, DIMLIM, Some(XDataValue::Integer16(limits)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if let Some(code) = property_real_code(field) {
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
set(doc, handle, code, None);
|
||||||
|
} else if let Ok(number) = trimmed.parse::<f64>() {
|
||||||
|
set(doc, handle, code, Some(XDataValue::Real(number)));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if let Some(code) = property_string_code(field) {
|
||||||
|
set(
|
||||||
|
doc,
|
||||||
|
handle,
|
||||||
|
code,
|
||||||
|
(!trimmed.is_empty()).then(|| XDataValue::String(value.to_string())),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if let Some(code) = property_int_code(field) {
|
||||||
|
let parsed = match field {
|
||||||
|
"dim_ext_line_fixed"
|
||||||
|
| "dim_text_outside_align"
|
||||||
|
| "dim_text_inside_align"
|
||||||
|
| "dim_text_inside"
|
||||||
|
| "dim_line_forced"
|
||||||
|
| "dim_line_inside"
|
||||||
|
| "dim_alt_enabled" => yes(trimmed),
|
||||||
|
"dim_decimal_separator" => trimmed
|
||||||
|
.chars()
|
||||||
|
.next()
|
||||||
|
.map(|character| character as i16),
|
||||||
|
"dim_units" => match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"scientific" => Some(1),
|
||||||
|
"decimal" => Some(2),
|
||||||
|
"engineering" => Some(3),
|
||||||
|
"architectural" => Some(4),
|
||||||
|
"fractional" => Some(5),
|
||||||
|
"desktop" => Some(6),
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
},
|
||||||
|
"dim_angle_format" => match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"decimal degrees" => Some(0),
|
||||||
|
"degrees/minutes/seconds" => Some(1),
|
||||||
|
"gradians" => Some(2),
|
||||||
|
"radians" => Some(3),
|
||||||
|
"surveyors units" => Some(4),
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
},
|
||||||
|
"dim_text_pos_vert" => match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"centered" => Some(0),
|
||||||
|
"above" => Some(1),
|
||||||
|
"outside" => Some(2),
|
||||||
|
"jis" => Some(3),
|
||||||
|
"below" => Some(4),
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
},
|
||||||
|
"dim_text_pos_hor" => match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"centered" => Some(0),
|
||||||
|
"at extension line 1" => Some(1),
|
||||||
|
"at extension line 2" => Some(2),
|
||||||
|
"over extension line 1" => Some(3),
|
||||||
|
"over extension line 2" => Some(4),
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
},
|
||||||
|
"dim_fit" => match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"either text or arrows" => Some(0),
|
||||||
|
"arrows" => Some(1),
|
||||||
|
"text" => Some(2),
|
||||||
|
"both text and arrows" => Some(3),
|
||||||
|
"always keep text" => Some(4),
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
},
|
||||||
|
"dim_text_movement" => match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"move dimension line" => Some(0),
|
||||||
|
"add leader" => Some(1),
|
||||||
|
"move text freely" => Some(2),
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
},
|
||||||
|
"dim_tolerance_pos_vert" => match trimmed.to_ascii_lowercase().as_str() {
|
||||||
|
"bottom" => Some(0),
|
||||||
|
"middle" => Some(1),
|
||||||
|
"top" => Some(2),
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
},
|
||||||
|
_ => trimmed.parse().ok(),
|
||||||
|
};
|
||||||
|
let Some(number) = parsed else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
set(doc, handle, code, Some(XDataValue::Integer16(number)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,44 @@ fn base_props(base: &DimensionBase) -> Vec<crate::scene::model::object::Property
|
||||||
}
|
}
|
||||||
|
|
||||||
fn properties(dim: &Dimension) -> Vec<PropSection> {
|
fn properties(dim: &Dimension) -> Vec<PropSection> {
|
||||||
|
if let Dimension::Linear(d) = dim {
|
||||||
|
let base = &d.base;
|
||||||
|
return vec![PropSection {
|
||||||
|
title: t!("Misc").into_owned(),
|
||||||
|
props: vec![
|
||||||
|
crate::scene::model::object::Property {
|
||||||
|
label: t!("Dimension style").into_owned(),
|
||||||
|
field: "style_name",
|
||||||
|
value: crate::scene::model::object::PropValue::PlainText(
|
||||||
|
base.style_name.clone(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
ro(
|
||||||
|
t!("Measurement").as_ref(),
|
||||||
|
"measurement",
|
||||||
|
format!("{:.4}", d.measurement()),
|
||||||
|
),
|
||||||
|
crate::scene::model::object::Property {
|
||||||
|
label: t!("Text override").into_owned(),
|
||||||
|
field: "text_override",
|
||||||
|
value: crate::scene::model::object::PropValue::PlainText(
|
||||||
|
base.text_override().unwrap_or("").to_string(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
edit_angle(
|
||||||
|
t!("Text rotation").as_ref(),
|
||||||
|
"text_rotation",
|
||||||
|
base.text_rotation.to_degrees(),
|
||||||
|
),
|
||||||
|
edit_angle(t!("Dim line angle").as_ref(), "rotation", d.rotation.to_degrees()),
|
||||||
|
edit_angle(
|
||||||
|
t!("Extension line angle").as_ref(),
|
||||||
|
"ext_line_rotation",
|
||||||
|
d.ext_line_rotation.to_degrees(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}];
|
||||||
|
}
|
||||||
let mut props = base_props(dim.base());
|
let mut props = base_props(dim.base());
|
||||||
match dim {
|
match dim {
|
||||||
Dimension::Aligned(d) => {
|
Dimension::Aligned(d) => {
|
||||||
|
|
@ -234,16 +272,12 @@ fn angular_props(
|
||||||
|
|
||||||
fn apply_base_prop(base: &mut DimensionBase, field: &str, value: &str) -> bool {
|
fn apply_base_prop(base: &mut DimensionBase, field: &str, value: &str) -> bool {
|
||||||
match field {
|
match field {
|
||||||
"text" => {
|
"text" | "user_text" | "text_override" => {
|
||||||
base.text = value.to_string();
|
base.set_text_override(if value.trim().is_empty() {
|
||||||
true
|
|
||||||
}
|
|
||||||
"user_text" => {
|
|
||||||
base.user_text = if value.trim().is_empty() {
|
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(value.to_string())
|
Some(value.to_string())
|
||||||
};
|
});
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
"style_name" => {
|
"style_name" => {
|
||||||
|
|
@ -305,6 +339,8 @@ fn apply_geom_prop(dim: &mut Dimension, field: &str, value: &str) {
|
||||||
Dimension::Arc(d) => apply_arc_fields(d, field, value),
|
Dimension::Arc(d) => apply_arc_fields(d, field, value),
|
||||||
Dimension::LargeRadial(d) => apply_large_radial_fields(d, field, value),
|
Dimension::LargeRadial(d) => apply_large_radial_fields(d, field, value),
|
||||||
}
|
}
|
||||||
|
let definition_point = dim.definition_point();
|
||||||
|
dim.base_mut().definition_point = definition_point;
|
||||||
dim.base_mut().actual_measurement = dim.measurement();
|
dim.base_mut().actual_measurement = dim.measurement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1031,6 +1067,24 @@ fn dimension_line_grip_position(dim: &Dimension) -> Option<DVec3> {
|
||||||
Some((p1 + p2) * 0.5)
|
Some((p1 + p2) * 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn above_dimension_text_position(dim: &Dimension) -> Option<DVec3> {
|
||||||
|
let center = dimension_line_grip_position(dim)?;
|
||||||
|
let (ax, ay) = match dim {
|
||||||
|
Dimension::Linear(d) => (d.rotation.cos(), d.rotation.sin()),
|
||||||
|
Dimension::Aligned(d) => {
|
||||||
|
let dx = d.second_point.x - d.first_point.x;
|
||||||
|
let dy = d.second_point.y - d.first_point.y;
|
||||||
|
let length = (dx * dx + dy * dy).sqrt();
|
||||||
|
if length <= 1e-12 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
(dx / length, dy / length)
|
||||||
|
}
|
||||||
|
_ => return Some(center + DVec3::Y),
|
||||||
|
};
|
||||||
|
Some(center + DVec3::new(-ay, ax, 0.0))
|
||||||
|
}
|
||||||
|
|
||||||
impl Grippable for Dimension {
|
impl Grippable for Dimension {
|
||||||
fn grips(&self) -> Vec<GripDef> {
|
fn grips(&self) -> Vec<GripDef> {
|
||||||
// Auto-placed dimensions carry a zero text_middle_point sentinel; put
|
// Auto-placed dimensions carry a zero text_middle_point sentinel; put
|
||||||
|
|
@ -1212,6 +1266,8 @@ impl Grippable for Dimension {
|
||||||
restore_dim_text_relative_position(self, saved);
|
restore_dim_text_relative_position(self, saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let definition_point = self.definition_point();
|
||||||
|
self.base_mut().definition_point = definition_point;
|
||||||
self.base_mut().actual_measurement = self.measurement();
|
self.base_mut().actual_measurement = self.measurement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1301,33 +1357,62 @@ impl Grippable for Dimension {
|
||||||
b.text_middle_point.x = 0.0;
|
b.text_middle_point.x = 0.0;
|
||||||
b.text_middle_point.y = 0.0;
|
b.text_middle_point.y = 0.0;
|
||||||
b.text_middle_point.z = 0.0;
|
b.text_middle_point.z = 0.0;
|
||||||
|
b.text_user_positioned = false;
|
||||||
}
|
}
|
||||||
A::Center if grip_id == text_grip => {
|
A::Center if grip_id == text_grip => {
|
||||||
// Snap text to the centre of the dimension line.
|
if let Some(point) = dimension_line_grip_position(self) {
|
||||||
// Approximate as midpoint of first/second extension
|
let base = self.base_mut();
|
||||||
// origins for Linear / Aligned dimensions.
|
base.text_middle_point = Vector3::new(point.x, point.y, point.z);
|
||||||
match self {
|
base.text_user_positioned = true;
|
||||||
Dimension::Linear(d) => {
|
}
|
||||||
let mx = (d.first_point.x + d.second_point.x) * 0.5;
|
}
|
||||||
let my = (d.first_point.y + d.second_point.y) * 0.5;
|
A::ReverseArrows => {
|
||||||
d.base.text_middle_point.x = mx;
|
let base = self.base_mut();
|
||||||
d.base.text_middle_point.y = my;
|
base.flip_arrow1 = !base.flip_arrow1;
|
||||||
}
|
base.flip_arrow2 = !base.flip_arrow2;
|
||||||
Dimension::Aligned(d) => {
|
}
|
||||||
let mx = (d.first_point.x + d.second_point.x) * 0.5;
|
A::AboveDimLine if grip_id == text_grip => {
|
||||||
let my = (d.first_point.y + d.second_point.y) * 0.5;
|
if let Some(point) = above_dimension_text_position(self) {
|
||||||
d.base.text_middle_point.x = mx;
|
let base = self.base_mut();
|
||||||
d.base.text_middle_point.y = my;
|
base.text_middle_point = Vector3::new(point.x, point.y + 1.0, point.z);
|
||||||
}
|
base.text_user_positioned = true;
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Stretch / Move-variants / Reverse Arrows / Rotate Text /
|
|
||||||
// Above Dim Line need either a follow-up drag or a numeric
|
|
||||||
// prompt — wired to default Stretch behaviour for now.
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn grip_menu_value_prompt(
|
||||||
|
&self,
|
||||||
|
grip_id: usize,
|
||||||
|
action: crate::scene::model::object::GripMenuAction,
|
||||||
|
) -> Option<&'static str> {
|
||||||
|
use crate::scene::model::object::GripMenuAction as A;
|
||||||
|
let text_grip = match self {
|
||||||
|
Dimension::Linear(_) | Dimension::Aligned(_) => 3,
|
||||||
|
Dimension::Radius(_) | Dimension::Diameter(_) => 2,
|
||||||
|
Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_) => 4,
|
||||||
|
Dimension::Ordinate(_) => 3,
|
||||||
|
Dimension::Arc(d) => if d.has_leader { 6 } else { 4 },
|
||||||
|
Dimension::LargeRadial(_) => 4,
|
||||||
|
};
|
||||||
|
(grip_id == text_grip && matches!(action, A::RotateText))
|
||||||
|
.then_some("Specify text rotation")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_grip_menu_value(
|
||||||
|
&mut self,
|
||||||
|
grip_id: usize,
|
||||||
|
action: crate::scene::model::object::GripMenuAction,
|
||||||
|
value: f64,
|
||||||
|
) {
|
||||||
|
use crate::scene::model::object::GripMenuAction as A;
|
||||||
|
if self.grip_menu_value_prompt(grip_id, action).is_some()
|
||||||
|
&& matches!(action, A::RotateText)
|
||||||
|
{
|
||||||
|
self.base_mut().text_rotation = value.to_radians();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Tessellation ─────────────────────────────────────────────────────────
|
// ── Tessellation ─────────────────────────────────────────────────────────
|
||||||
|
|
@ -1347,7 +1432,11 @@ use acadrust::types::{Color as AcadColor, Vector3};
|
||||||
/// Units, Alternate Units, Tolerances) built from the resolved DimStyle. These
|
/// Units, Alternate Units, Tolerances) built from the resolved DimStyle. These
|
||||||
/// are read-only mirrors of the style's dimension variables, injected by the
|
/// are read-only mirrors of the style's dimension variables, injected by the
|
||||||
/// panel after the entity's own Misc/Geometry groups.
|
/// panel after the entity's own Misc/Geometry groups.
|
||||||
pub fn style_sections(style: &DimStyle) -> Vec<crate::scene::model::object::PropSection> {
|
pub fn style_sections(
|
||||||
|
style: &DimStyle,
|
||||||
|
dimension: &Dimension,
|
||||||
|
document: &CadDocument,
|
||||||
|
) -> Vec<crate::scene::model::object::PropSection> {
|
||||||
let s = style;
|
let s = style;
|
||||||
let yn = |b: bool| if b { "Yes" } else { "No" };
|
let yn = |b: bool| if b { "Yes" } else { "No" };
|
||||||
let onoff = |b: bool| if b { "On" } else { "Off" };
|
let onoff = |b: bool| if b { "On" } else { "Off" };
|
||||||
|
|
@ -1368,11 +1457,36 @@ pub fn style_sections(style: &DimStyle) -> Vec<crate::scene::model::object::Prop
|
||||||
"None"
|
"None"
|
||||||
};
|
};
|
||||||
|
|
||||||
vec![
|
let mut sections = vec![
|
||||||
PropSection {
|
PropSection {
|
||||||
title: t!("Lines & Arrows").into_owned(),
|
title: t!("Lines & Arrows").into_owned(),
|
||||||
props: vec![
|
props: vec![
|
||||||
ro(t!("Arrow size").as_ref(), "dim_arrow_size", f(s.dimasz)),
|
ro(t!("Arrow size").as_ref(), "dim_arrow_size", f(s.dimasz)),
|
||||||
|
ro(
|
||||||
|
t!("Arrowhead 1").as_ref(),
|
||||||
|
"dim_arrowhead_1",
|
||||||
|
block_name(document, s.dimblk1, &s.dimblk1_name),
|
||||||
|
),
|
||||||
|
ro(
|
||||||
|
t!("Arrowhead 2").as_ref(),
|
||||||
|
"dim_arrowhead_2",
|
||||||
|
block_name(document, s.dimblk2, &s.dimblk2_name),
|
||||||
|
),
|
||||||
|
ro(
|
||||||
|
t!("Dimension linetype").as_ref(),
|
||||||
|
"dim_linetype",
|
||||||
|
linetype_name(document, s.dimltex_handle),
|
||||||
|
),
|
||||||
|
ro(
|
||||||
|
t!("Extension linetype 1").as_ref(),
|
||||||
|
"dim_ext_linetype_1",
|
||||||
|
linetype_name(document, s.dimltex1_handle),
|
||||||
|
),
|
||||||
|
ro(
|
||||||
|
t!("Extension linetype 2").as_ref(),
|
||||||
|
"dim_ext_linetype_2",
|
||||||
|
linetype_name(document, s.dimltex2_handle),
|
||||||
|
),
|
||||||
ro(t!("Dim line color").as_ref(), "dim_line_color", s.dimclrd.to_string()),
|
ro(t!("Dim line color").as_ref(), "dim_line_color", s.dimclrd.to_string()),
|
||||||
ro(
|
ro(
|
||||||
t!("Dim line lineweight").as_ref(),
|
t!("Dim line lineweight").as_ref(),
|
||||||
|
|
@ -1502,7 +1616,271 @@ pub fn style_sections(style: &DimStyle) -> Vec<crate::scene::model::object::Prop
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
|
let data = &dimension.base().common.extended_data;
|
||||||
|
let yes_no = |value: bool| if value { "Yes" } else { "No" }.to_string();
|
||||||
|
for property in sections
|
||||||
|
.iter_mut()
|
||||||
|
.flat_map(|section| section.props.iter_mut())
|
||||||
|
{
|
||||||
|
let inherited = match &property.value {
|
||||||
|
crate::scene::model::object::PropValue::ReadOnly(value) => value.clone(),
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
if let Some(code) = crate::entities::dim_override::property_real_code(property.field) {
|
||||||
|
let value = crate::entities::dim_override::real(data, code)
|
||||||
|
.map(|number| number.to_string())
|
||||||
|
.unwrap_or(inherited);
|
||||||
|
property.value = crate::scene::model::object::PropValue::EditText(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(code) = crate::entities::dim_override::property_string_code(property.field) {
|
||||||
|
let value = crate::entities::dim_override::string(data, code).unwrap_or(inherited);
|
||||||
|
property.value = crate::scene::model::object::PropValue::PlainText(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(code) = crate::entities::dim_override::property_int_code(property.field) {
|
||||||
|
let number = crate::entities::dim_override::int(data, code);
|
||||||
|
let value = number.map(|number| number.to_string()).unwrap_or(inherited);
|
||||||
|
property.value = match property.field {
|
||||||
|
"dim_ext_line_fixed"
|
||||||
|
| "dim_text_outside_align"
|
||||||
|
| "dim_text_inside_align"
|
||||||
|
| "dim_text_inside"
|
||||||
|
| "dim_line_forced"
|
||||||
|
| "dim_line_inside"
|
||||||
|
| "dim_alt_enabled" => crate::scene::model::object::PropValue::Choice {
|
||||||
|
selected: number.map(|number| yes_no(number != 0)).unwrap_or(value),
|
||||||
|
options: vec!["Yes".to_string(), "No".to_string()],
|
||||||
|
},
|
||||||
|
"dim_units" => crate::scene::model::object::PropValue::Choice {
|
||||||
|
selected: linear_unit_label(number.unwrap_or(s.dimlunit)).to_string(),
|
||||||
|
options: vec![
|
||||||
|
"Scientific", "Decimal", "Engineering", "Architectural",
|
||||||
|
"Fractional", "Desktop",
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(str::to_string)
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
"dim_angle_format" => crate::scene::model::object::PropValue::Choice {
|
||||||
|
selected: angle_unit_label(number.unwrap_or(s.dimaunit)).to_string(),
|
||||||
|
options: vec![
|
||||||
|
"Decimal degrees", "Degrees/minutes/seconds", "Gradians",
|
||||||
|
"Radians", "Surveyors units",
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(str::to_string)
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
"dim_text_pos_vert" => choice_value(
|
||||||
|
match number.unwrap_or(s.dimtad) {
|
||||||
|
1 => "Above",
|
||||||
|
2 => "Outside",
|
||||||
|
3 => "JIS",
|
||||||
|
4 => "Below",
|
||||||
|
_ => "Centered",
|
||||||
|
},
|
||||||
|
&["Centered", "Above", "Outside", "JIS", "Below"],
|
||||||
|
),
|
||||||
|
"dim_text_pos_hor" => choice_value(
|
||||||
|
match number.unwrap_or(s.dimjust) {
|
||||||
|
1 => "At extension line 1",
|
||||||
|
2 => "At extension line 2",
|
||||||
|
3 => "Over extension line 1",
|
||||||
|
4 => "Over extension line 2",
|
||||||
|
_ => "Centered",
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
"Centered", "At extension line 1", "At extension line 2",
|
||||||
|
"Over extension line 1", "Over extension line 2",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
"dim_fit" => choice_value(
|
||||||
|
match number.unwrap_or(s.dimatfit) {
|
||||||
|
1 => "Arrows",
|
||||||
|
2 => "Text",
|
||||||
|
3 => "Both text and arrows",
|
||||||
|
4 => "Always keep text",
|
||||||
|
_ => "Either text or arrows",
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
"Either text or arrows", "Arrows", "Text",
|
||||||
|
"Both text and arrows", "Always keep text",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
"dim_text_movement" => choice_value(
|
||||||
|
match number.unwrap_or(s.dimtmove) {
|
||||||
|
1 => "Add leader",
|
||||||
|
2 => "Move text freely",
|
||||||
|
_ => "Move dimension line",
|
||||||
|
},
|
||||||
|
&["Move dimension line", "Add leader", "Move text freely"],
|
||||||
|
),
|
||||||
|
"dim_tolerance_pos_vert" => choice_value(
|
||||||
|
match number.unwrap_or(s.dimtolj) {
|
||||||
|
1 => "Middle",
|
||||||
|
2 => "Top",
|
||||||
|
_ => "Bottom",
|
||||||
|
},
|
||||||
|
&["Bottom", "Middle", "Top"],
|
||||||
|
),
|
||||||
|
_ => crate::scene::model::object::PropValue::EditText(value),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let integer_or = |code, inherited| {
|
||||||
|
crate::entities::dim_override::int(data, code).unwrap_or(inherited)
|
||||||
|
};
|
||||||
|
for property in sections
|
||||||
|
.iter_mut()
|
||||||
|
.flat_map(|section| section.props.iter_mut())
|
||||||
|
{
|
||||||
|
let selected = match property.field {
|
||||||
|
"dim_line_1" => Some(if integer_or(crate::entities::dim_override::DIMSD1, s.dimsd1 as i16) == 0 { "On" } else { "Off" }),
|
||||||
|
"dim_line_2" => Some(if integer_or(crate::entities::dim_override::DIMSD2, s.dimsd2 as i16) == 0 { "On" } else { "Off" }),
|
||||||
|
"dim_ext_line_1" => Some(if integer_or(crate::entities::dim_override::DIMSE1, s.dimse1 as i16) == 0 { "On" } else { "Off" }),
|
||||||
|
"dim_ext_line_2" => Some(if integer_or(crate::entities::dim_override::DIMSE2, s.dimse2 as i16) == 0 { "On" } else { "Off" }),
|
||||||
|
"dim_suppress_leading_zeros" => Some(if integer_or(crate::entities::dim_override::DIMZIN, s.dimzin) & 4 != 0 { "Yes" } else { "No" }),
|
||||||
|
"dim_suppress_trailing_zeros" => Some(if integer_or(crate::entities::dim_override::DIMZIN, s.dimzin) & 8 != 0 { "Yes" } else { "No" }),
|
||||||
|
"dim_alt_suppress_leading_zeros" => Some(if integer_or(crate::entities::dim_override::DIMALTZ, s.dimaltz) & 4 != 0 { "Yes" } else { "No" }),
|
||||||
|
"dim_alt_suppress_trailing_zeros" => Some(if integer_or(crate::entities::dim_override::DIMALTZ, s.dimaltz) & 8 != 0 { "Yes" } else { "No" }),
|
||||||
|
"dim_tolerance_suppress_leading_zeros" => Some(if integer_or(crate::entities::dim_override::DIMTZIN, s.dimtzin) & 4 != 0 { "Yes" } else { "No" }),
|
||||||
|
"dim_tolerance_suppress_trailing_zeros" => Some(if integer_or(crate::entities::dim_override::DIMTZIN, s.dimtzin) & 8 != 0 { "Yes" } else { "No" }),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(selected) = selected {
|
||||||
|
let options = if matches!(
|
||||||
|
property.field,
|
||||||
|
"dim_line_1" | "dim_line_2" | "dim_ext_line_1" | "dim_ext_line_2"
|
||||||
|
) {
|
||||||
|
&["On", "Off"][..]
|
||||||
|
} else {
|
||||||
|
&["Yes", "No"][..]
|
||||||
|
};
|
||||||
|
property.value = choice_value(selected, options);
|
||||||
|
}
|
||||||
|
if property.field == "dim_tolerance_display" {
|
||||||
|
let limits = integer_or(crate::entities::dim_override::DIMLIM, s.dimlim as i16) != 0;
|
||||||
|
let tolerance = integer_or(crate::entities::dim_override::DIMTOL, s.dimtol as i16) != 0;
|
||||||
|
let selected = if limits { "Limits" } else if tolerance { "Deviation" } else { "None" };
|
||||||
|
property.value = choice_value(selected, &["None", "Deviation", "Limits"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let arrow_options: Vec<String> = std::iter::once("Closed filled".to_string())
|
||||||
|
.chain(
|
||||||
|
document
|
||||||
|
.block_records
|
||||||
|
.iter()
|
||||||
|
.map(|record| record.name.clone())
|
||||||
|
.filter(|name| !name.is_empty()),
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
let linetype_options: Vec<String> = document
|
||||||
|
.line_types
|
||||||
|
.iter()
|
||||||
|
.map(|line_type| line_type.name.clone())
|
||||||
|
.filter(|name| !name.is_empty())
|
||||||
|
.collect();
|
||||||
|
for property in sections
|
||||||
|
.iter_mut()
|
||||||
|
.flat_map(|section| section.props.iter_mut())
|
||||||
|
{
|
||||||
|
let mut current = match &property.value {
|
||||||
|
crate::scene::model::object::PropValue::ReadOnly(value) => value.clone(),
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
if matches!(property.field, "dim_arrowhead_1" | "dim_arrowhead_2") {
|
||||||
|
let code = if property.field == "dim_arrowhead_1" {
|
||||||
|
crate::entities::dim_override::DIMBLK1
|
||||||
|
} else {
|
||||||
|
crate::entities::dim_override::DIMBLK2
|
||||||
|
};
|
||||||
|
if let Some(handle) = crate::entities::dim_override::handle(data, code) {
|
||||||
|
current = block_name(document, handle, "");
|
||||||
|
}
|
||||||
|
property.value = crate::scene::model::object::PropValue::Choice {
|
||||||
|
selected: current,
|
||||||
|
options: arrow_options.clone(),
|
||||||
|
};
|
||||||
|
} else if matches!(
|
||||||
|
property.field,
|
||||||
|
"dim_linetype" | "dim_ext_linetype_1" | "dim_ext_linetype_2"
|
||||||
|
) {
|
||||||
|
let code = match property.field {
|
||||||
|
"dim_linetype" => crate::entities::dim_override::DIMLTYPE,
|
||||||
|
"dim_ext_linetype_1" => crate::entities::dim_override::DIMLTEX1,
|
||||||
|
_ => crate::entities::dim_override::DIMLTEX2,
|
||||||
|
};
|
||||||
|
if let Some(handle) = crate::entities::dim_override::handle(data, code) {
|
||||||
|
current = linetype_name(document, handle);
|
||||||
|
}
|
||||||
|
property.value = crate::scene::model::object::PropValue::Choice {
|
||||||
|
selected: current,
|
||||||
|
options: linetype_options.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sections
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choice_value(
|
||||||
|
selected: &str,
|
||||||
|
options: &[&str],
|
||||||
|
) -> crate::scene::model::object::PropValue {
|
||||||
|
crate::scene::model::object::PropValue::Choice {
|
||||||
|
selected: selected.to_string(),
|
||||||
|
options: options.iter().map(|value| (*value).to_string()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_name(document: &CadDocument, handle: acadrust::Handle, fallback: &str) -> String {
|
||||||
|
if handle.is_null() {
|
||||||
|
return if fallback.is_empty() {
|
||||||
|
"Closed filled".to_string()
|
||||||
|
} else {
|
||||||
|
fallback.to_string()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
document
|
||||||
|
.block_records
|
||||||
|
.iter()
|
||||||
|
.find(|record| record.handle == handle)
|
||||||
|
.map(|record| record.name.clone())
|
||||||
|
.unwrap_or_else(|| fallback.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linetype_name(document: &CadDocument, handle: acadrust::Handle) -> String {
|
||||||
|
document
|
||||||
|
.line_types
|
||||||
|
.iter()
|
||||||
|
.find(|line_type| line_type.handle == handle)
|
||||||
|
.map(|line_type| line_type.name.clone())
|
||||||
|
.unwrap_or_else(|| "ByBlock".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linear_unit_label(value: i16) -> &'static str {
|
||||||
|
match value {
|
||||||
|
1 => "Scientific",
|
||||||
|
3 => "Engineering",
|
||||||
|
4 => "Architectural",
|
||||||
|
5 => "Fractional",
|
||||||
|
6 => "Desktop",
|
||||||
|
_ => "Decimal",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn angle_unit_label(value: i16) -> &'static str {
|
||||||
|
match value {
|
||||||
|
1 => "Degrees/minutes/seconds",
|
||||||
|
2 => "Gradians",
|
||||||
|
3 => "Radians",
|
||||||
|
4 => "Surveyors units",
|
||||||
|
_ => "Decimal degrees",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
use acadrust::{CadDocument, EntityType, Handle};
|
use acadrust::{CadDocument, EntityType, Handle};
|
||||||
|
|
||||||
|
|
@ -4143,4 +4521,3 @@ mod arch_format_tests {
|
||||||
assert_eq!(format_fractional(6.5, 0), "6 1/2");
|
assert_eq!(format_fractional(6.5, 0), "6 1/2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue