forked from 1b-agent/opencadstudio-upstream
feat: node graph overlay; move to opencadcodec/opencadkernel/opencadgraph
The codec and kernel repositories and crates are renamed opencadcodec and opencadkernel. Inside OCS they are depended on under short keys, so code reads `codec::`, `kernel::` and the new `graph::` (opencadgraph, the node graph engine). File-format and protocol spellings stay as they were: the ACIS product id `acadrust`, the ACADRUST_* switches and the plugin version keys `acadrust_version` / `acadrust_source`. A button left of MCP on the command line opens a translucent node graph over the viewport, with a palette of object, input, math, logic, list, text and geometry nodes added by click or drag. An object node owns drawing entities and its rows are the Properties panel's own rows for them: the single-object page is extracted from refresh_properties as entity_property_sections, values use the control protocol's property_json, and writes go through set_property_value with a property target override, so the panel, MCP and the graph share one read/write path. A list reaching an object row makes one entity per element. Each graph action is one undo step; the canvas pans and zooms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
56c04408d6
commit
f537aff75c
430 files changed
+9925
-8540
No files matched your search
+103
-103
@@ -21,8 +21,8 @@ use crate::scene::{
|
||||
};
|
||||
use crate::ui::PropertiesPanel;
|
||||
use crate::ui::window::attribute_editor::{AttrRow, AttrTab};
|
||||
use acadrust::types::Color as AcadColor;
|
||||
use acadrust::{EntityType as AcadEntityType, Handle};
|
||||
use codec::types::Color as AcadColor;
|
||||
use codec::{EntityType as AcadEntityType, Handle};
|
||||
use iced::time::Instant;
|
||||
use iced::{mouse, Point, Task};
|
||||
|
||||
@@ -1233,7 +1233,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
|
||||
// Toggle frozen_layers on the viewport entity
|
||||
for e in self.tabs[i].scene.document.entities_mut() {
|
||||
if let acadrust::EntityType::Viewport(vp) = e {
|
||||
if let codec::EntityType::Viewport(vp) = e {
|
||||
if vp.common.handle == vp_handle {
|
||||
if vp.frozen_layers.contains(&layer_handle) {
|
||||
vp.frozen_layers.retain(|h| h != &layer_handle);
|
||||
@@ -1271,7 +1271,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
n += 1;
|
||||
};
|
||||
self.push_undo_snapshot(i, "LAYER NEW");
|
||||
use acadrust::tables::layer::Layer as DocLayer;
|
||||
use codec::tables::layer::Layer as DocLayer;
|
||||
// A layer needs a real handle or it is dropped on a DWG save
|
||||
// (the format is handle-based; issue #67).
|
||||
let mut dl = DocLayer::new(&new_name);
|
||||
@@ -1370,7 +1370,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
return Task::none();
|
||||
};
|
||||
self.push_undo_snapshot(i, "LAYER DELETE");
|
||||
let handles: Vec<acadrust::Handle> = self.tabs[i]
|
||||
let handles: Vec<codec::Handle> = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.entities()
|
||||
@@ -1448,7 +1448,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.layers
|
||||
.get(&name)
|
||||
.map(|l| l.handle)
|
||||
.unwrap_or(acadrust::types::Handle::NULL);
|
||||
.unwrap_or(codec::types::Handle::NULL);
|
||||
self.tabs[i].scene.document.header.current_layer_name = name.clone();
|
||||
self.tabs[i].scene.document.header.current_layer_handle = handle;
|
||||
self.tabs[i].active_layer = name.clone();
|
||||
@@ -1508,7 +1508,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
) {
|
||||
let is_dimension = matches!(
|
||||
self.tabs[i].scene.document.get_entity(popup.handle),
|
||||
Some(acadrust::EntityType::Dimension(_))
|
||||
Some(codec::EntityType::Dimension(_))
|
||||
);
|
||||
if is_dimension {
|
||||
let movement = match item.action {
|
||||
@@ -1544,7 +1544,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// Only multileaders use the whole-object grip.
|
||||
let is_multileader = matches!(
|
||||
self.tabs[i].scene.document.get_entity(popup.handle),
|
||||
Some(acadrust::EntityType::MultiLeader(_))
|
||||
Some(codec::EntityType::MultiLeader(_))
|
||||
);
|
||||
let (grip_id, is_translate) =
|
||||
if matches!(item.action, GripMenuAction::MoveWithLeader)
|
||||
@@ -1722,7 +1722,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// structural, so it can't ride the in-place apply below.
|
||||
if matches!(item.action, GripMenuAction::BreakVertex) {
|
||||
let pieces = match self.tabs[i].scene.document.get_entity(popup.handle) {
|
||||
Some(acadrust::EntityType::LwPolyline(p)) => {
|
||||
Some(codec::EntityType::LwPolyline(p)) => {
|
||||
crate::entities::lwpolyline::break_at_vertex(p, popup.grip_id)
|
||||
}
|
||||
_ => None,
|
||||
@@ -1839,12 +1839,12 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.document
|
||||
.get_entity(popup.handle)
|
||||
.is_some_and(|entity| match (item.action, entity) {
|
||||
(GripMenuAction::ShowFit, acadrust::EntityType::Spline(spline)) => {
|
||||
(GripMenuAction::ShowFit, codec::EntityType::Spline(spline)) => {
|
||||
crate::entities::spline::shows_fit_points(spline)
|
||||
}
|
||||
(
|
||||
GripMenuAction::ShowControlVertices,
|
||||
acadrust::EntityType::Spline(spline),
|
||||
codec::EntityType::Spline(spline),
|
||||
) => {
|
||||
crate::entities::spline::shows_control_vertices(spline)
|
||||
}
|
||||
@@ -1862,7 +1862,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.document
|
||||
.get_entity(popup.handle)
|
||||
.and_then(|e| match e {
|
||||
acadrust::EntityType::MultiLeader(ml) => Some(
|
||||
codec::EntityType::MultiLeader(ml) => Some(
|
||||
ml.context
|
||||
.leader_roots
|
||||
.iter()
|
||||
@@ -2089,7 +2089,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.layers
|
||||
.get(&layer)
|
||||
.map(|l| l.handle)
|
||||
.unwrap_or(acadrust::types::Handle::NULL);
|
||||
.unwrap_or(codec::types::Handle::NULL);
|
||||
self.tabs[i].scene.document.header.current_layer_name = layer.clone();
|
||||
self.tabs[i].scene.document.header.current_layer_handle = handle;
|
||||
self.tabs[i].active_layer = layer.clone();
|
||||
@@ -2161,7 +2161,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.iter()
|
||||
.find(|x| x.name.eq_ignore_ascii_case(<))
|
||||
.map(|x| x.handle)
|
||||
.unwrap_or(acadrust::types::Handle::NULL);
|
||||
.unwrap_or(codec::types::Handle::NULL);
|
||||
self.tabs[i].scene.document.header.current_linetype_name = lt.clone();
|
||||
self.tabs[i].scene.document.header.current_linetype_handle = handle;
|
||||
self.tabs[i].dirty = true;
|
||||
@@ -2244,7 +2244,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if let Some(entry) = hatch_patterns::find(&name) {
|
||||
self.push_undo_snapshot(i, "HATCHEDIT");
|
||||
for &handle in &handles {
|
||||
if let Some(acadrust::EntityType::Hatch(dxf)) =
|
||||
if let Some(codec::EntityType::Hatch(dxf)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
let mut pattern = hatch_patterns::build_dxf_pattern(entry);
|
||||
@@ -2268,7 +2268,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
crate::scene::model::hatch_model::HatchPattern::Solid
|
||||
);
|
||||
dxf.pattern_type =
|
||||
acadrust::entities::HatchPatternType::Predefined;
|
||||
codec::entities::HatchPatternType::Predefined;
|
||||
dxf.gradient_color.enabled = false;
|
||||
}
|
||||
if let Some(model) = self.tabs[i].scene.hatches.get_mut(&handle) {
|
||||
@@ -2304,12 +2304,12 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
};
|
||||
let document = &self.tabs[i].scene.document;
|
||||
let (toggle, current) = match document.get_entity(handle) {
|
||||
Some(acadrust::EntityType::MText(text)) => ("is_annotative", text.is_annotative),
|
||||
Some(codec::EntityType::MText(text)) => ("is_annotative", text.is_annotative),
|
||||
Some(entity) => (
|
||||
"annotative_ctx",
|
||||
crate::scene::annotative::is_annotative(document, entity)
|
||||
|| match entity {
|
||||
acadrust::EntityType::Dimension(dimension) => {
|
||||
codec::EntityType::Dimension(dimension) => {
|
||||
crate::scene::annotative::dim_style_is_annotative(
|
||||
document,
|
||||
&dimension.base().style_name,
|
||||
@@ -2339,7 +2339,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
) {
|
||||
let unchanged = handles.iter().all(|handle| {
|
||||
match self.tabs[i].scene.document.get_entity(*handle) {
|
||||
Some(acadrust::EntityType::Spline(spline)) => match field {
|
||||
Some(codec::EntityType::Spline(spline)) => match field {
|
||||
"spline_method" => {
|
||||
value
|
||||
== if crate::entities::spline::shows_fit_points(spline) {
|
||||
@@ -2367,7 +2367,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
Some(acadrust::EntityType::Hatch(hatch)) => match field {
|
||||
Some(codec::EntityType::Hatch(hatch)) => match field {
|
||||
"fill_type" => {
|
||||
value
|
||||
== if hatch.gradient_color.is_single_color {
|
||||
@@ -2386,21 +2386,21 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
"style" => {
|
||||
value
|
||||
== match hatch.style {
|
||||
acadrust::entities::HatchStyleType::Normal => "Normal",
|
||||
acadrust::entities::HatchStyleType::Outer => "Outer",
|
||||
acadrust::entities::HatchStyleType::Ignore => "Ignore",
|
||||
codec::entities::HatchStyleType::Normal => "Normal",
|
||||
codec::entities::HatchStyleType::Outer => "Outer",
|
||||
codec::entities::HatchStyleType::Ignore => "Ignore",
|
||||
}
|
||||
}
|
||||
"pattern_type_label" => {
|
||||
value
|
||||
== match hatch.pattern_type {
|
||||
acadrust::entities::HatchPatternType::Predefined => {
|
||||
codec::entities::HatchPatternType::Predefined => {
|
||||
"Predefined"
|
||||
}
|
||||
acadrust::entities::HatchPatternType::UserDefined => {
|
||||
codec::entities::HatchPatternType::UserDefined => {
|
||||
"User Defined"
|
||||
}
|
||||
acadrust::entities::HatchPatternType::Custom => "Custom",
|
||||
codec::entities::HatchPatternType::Custom => "Custom",
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
@@ -2428,7 +2428,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.document
|
||||
.get_entity(handle)
|
||||
.and_then(|entity| match entity {
|
||||
acadrust::EntityType::Surface(surface) => Some(
|
||||
codec::EntityType::Surface(surface) => Some(
|
||||
crate::entities::solid3d::surface_property_state(surface),
|
||||
),
|
||||
_ => None,
|
||||
@@ -2480,7 +2480,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
} else if field == "tol_text_style" {
|
||||
use crate::entities::dim_override as dov;
|
||||
use acadrust::xdata::XDataValue;
|
||||
use codec::xdata::XDataValue;
|
||||
let style_handle = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
@@ -2493,7 +2493,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if self.tabs[i].scene.is_layer_locked(handle)
|
||||
|| !matches!(
|
||||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(acadrust::EntityType::Tolerance(_))
|
||||
Some(codec::EntityType::Tolerance(_))
|
||||
)
|
||||
{
|
||||
continue;
|
||||
@@ -2520,7 +2520,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if self.tabs[i].scene.is_layer_locked(handle) {
|
||||
continue;
|
||||
}
|
||||
if let Some(acadrust::EntityType::Tolerance(tolerance)) =
|
||||
if let Some(codec::EntityType::Tolerance(tolerance)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
tolerance.dimension_style_handle = Some(style_handle);
|
||||
@@ -2551,7 +2551,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
if matches!(
|
||||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(acadrust::EntityType::Dimension(_))
|
||||
Some(codec::EntityType::Dimension(_))
|
||||
) {
|
||||
let applied = crate::entities::dim_override::set_property(
|
||||
&mut self.tabs[i].scene.document,
|
||||
@@ -2560,8 +2560,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
&value,
|
||||
);
|
||||
if applied && field == "dim_text_inside" {
|
||||
if let Some(acadrust::EntityType::Dimension(
|
||||
acadrust::entities::Dimension::LargeRadial(dimension),
|
||||
if let Some(codec::EntityType::Dimension(
|
||||
codec::entities::Dimension::LargeRadial(dimension),
|
||||
)) = self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
dimension.base.text_user_positioned = false;
|
||||
@@ -2573,7 +2573,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
for &handle in &handles {
|
||||
if matches!(
|
||||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(acadrust::EntityType::Viewport(_))
|
||||
Some(codec::EntityType::Viewport(_))
|
||||
) {
|
||||
let _ = self.tabs[i]
|
||||
.scene
|
||||
@@ -2591,7 +2591,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.cloned();
|
||||
if let Some(ucs) = ucs_data {
|
||||
for handle in &handles {
|
||||
if let Some(acadrust::EntityType::Viewport(vp)) =
|
||||
if let Some(codec::EntityType::Viewport(vp)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(*handle)
|
||||
{
|
||||
vp.ucs_handle = ucs.handle;
|
||||
@@ -2613,7 +2613,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.cloned();
|
||||
if let Some(view) = view_data {
|
||||
for handle in &handles {
|
||||
if let Some(acadrust::EntityType::Viewport(vp)) =
|
||||
if let Some(codec::EntityType::Viewport(vp)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(*handle)
|
||||
{
|
||||
vp.view_target = view.target.clone();
|
||||
@@ -2642,13 +2642,13 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
let resolved_mleader_style = (field == "mleader_style")
|
||||
.then(|| {
|
||||
doc.objects.values().find_map(|object| match object {
|
||||
acadrust::objects::ObjectType::MultiLeaderStyle(style)
|
||||
codec::objects::ObjectType::MultiLeaderStyle(style)
|
||||
if style.name == value => Some(style.clone()),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
let resolved: Option<acadrust::Handle> = match field {
|
||||
let resolved: Option<codec::Handle> = match field {
|
||||
"mleader_style" => {
|
||||
resolved_mleader_style.as_ref().map(|style| style.handle)
|
||||
}
|
||||
@@ -2698,7 +2698,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
);
|
||||
style_annotation = Some(style.is_annotative);
|
||||
}
|
||||
} else if let Some(acadrust::EntityType::MultiLeader(ml)) =
|
||||
} else if let Some(codec::EntityType::MultiLeader(ml)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
match field {
|
||||
@@ -2707,7 +2707,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
ml.text_style_handle = Some(h);
|
||||
ml.context.text_style_handle = Some(h);
|
||||
ml.property_override_flags.insert(
|
||||
acadrust::entities::MultiLeaderPropertyOverrideFlags::TEXT_STYLE,
|
||||
codec::entities::MultiLeaderPropertyOverrideFlags::TEXT_STYLE,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2717,12 +2717,12 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
for line in &mut root.lines {
|
||||
line.arrowhead_handle = resolved;
|
||||
line.override_flags.insert(
|
||||
acadrust::entities::LeaderLinePropertyOverrideFlags::ARROWHEAD,
|
||||
codec::entities::LeaderLinePropertyOverrideFlags::ARROWHEAD,
|
||||
);
|
||||
}
|
||||
}
|
||||
ml.property_override_flags.insert(
|
||||
acadrust::entities::MultiLeaderPropertyOverrideFlags::ARROWHEAD,
|
||||
codec::entities::MultiLeaderPropertyOverrideFlags::ARROWHEAD,
|
||||
);
|
||||
}
|
||||
"line_type_handle" => {
|
||||
@@ -2731,12 +2731,12 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
for line in &mut root.lines {
|
||||
line.line_type_handle = resolved;
|
||||
line.override_flags.insert(
|
||||
acadrust::entities::LeaderLinePropertyOverrideFlags::LINE_TYPE,
|
||||
codec::entities::LeaderLinePropertyOverrideFlags::LINE_TYPE,
|
||||
);
|
||||
}
|
||||
}
|
||||
ml.property_override_flags.insert(
|
||||
acadrust::entities::MultiLeaderPropertyOverrideFlags::LEADER_LINE_TYPE,
|
||||
codec::entities::MultiLeaderPropertyOverrideFlags::LEADER_LINE_TYPE,
|
||||
);
|
||||
}
|
||||
"block_content_handle" => {
|
||||
@@ -2747,7 +2747,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
ml.context.block_content_location =
|
||||
ml.context.content_base_point;
|
||||
ml.property_override_flags.insert(
|
||||
acadrust::entities::MultiLeaderPropertyOverrideFlags::BLOCK_CONTENT,
|
||||
codec::entities::MultiLeaderPropertyOverrideFlags::BLOCK_CONTENT,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2780,8 +2780,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// reverts to the style); the other two map a label to
|
||||
// the DIMLWD / DIMTAD enum value.
|
||||
use crate::entities::dim_override as dov;
|
||||
use acadrust::xdata::XDataValue;
|
||||
let arrow_h: Option<acadrust::Handle> =
|
||||
use codec::xdata::XDataValue;
|
||||
let arrow_h: Option<codec::Handle> =
|
||||
if field == "arrow_block" && value != "Closed filled" {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
@@ -2803,7 +2803,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// a multi-type selection can't get stray overrides.
|
||||
if !matches!(
|
||||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(acadrust::EntityType::Leader(_))
|
||||
Some(codec::EntityType::Leader(_))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
@@ -2835,7 +2835,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
doc,
|
||||
handle,
|
||||
dov::DIMLDRBLK,
|
||||
Some(XDataValue::Handle(acadrust::Handle::NULL)),
|
||||
Some(XDataValue::Handle(codec::Handle::NULL)),
|
||||
);
|
||||
} else if let Some(h) = arrow_h {
|
||||
dov::set(
|
||||
@@ -2871,7 +2871,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if self.tabs[i].scene.is_layer_locked(handle) {
|
||||
continue;
|
||||
}
|
||||
if let Some(acadrust::EntityType::Insert(ins)) =
|
||||
if let Some(codec::EntityType::Insert(ins)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
if ins.block_name != canon {
|
||||
@@ -2894,7 +2894,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.objects
|
||||
.iter()
|
||||
.find_map(|(handle, object)| match object {
|
||||
acadrust::objects::ObjectType::TableStyle(style)
|
||||
codec::objects::ObjectType::TableStyle(style)
|
||||
if style.name.eq_ignore_ascii_case(value.trim()) =>
|
||||
{
|
||||
Some(*handle)
|
||||
@@ -2903,7 +2903,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
});
|
||||
if let Some(style_handle) = style_handle {
|
||||
for &handle in &handles {
|
||||
if let Some(acadrust::EntityType::Table(table)) =
|
||||
if let Some(codec::EntityType::Table(table)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
table.table_style_handle = Some(style_handle);
|
||||
@@ -2929,7 +2929,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// ACAD_PLOTSTYLENAME dictionary to its placeholder handle.
|
||||
let dict_h =
|
||||
self.tabs[i].scene.document.header.acad_plotstylename_dict_handle;
|
||||
let ph: Option<acadrust::Handle> =
|
||||
let ph: Option<codec::Handle> =
|
||||
crate::scene::annotative::as_dict(&self.tabs[i].scene.document, dict_h)
|
||||
.and_then(|d| {
|
||||
d.entries
|
||||
@@ -2970,13 +2970,13 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// Material source: ByLayer / ByBlock clear the handle; a
|
||||
// named material sets flag 3 + its handle (resolved here
|
||||
// because the update loop holds the document).
|
||||
let mat_handle: Option<acadrust::Handle> = self.tabs[i]
|
||||
let mat_handle: Option<codec::Handle> = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.objects
|
||||
.iter()
|
||||
.find_map(|(h, o)| match o {
|
||||
acadrust::objects::ObjectType::Material(m) if m.name == value => {
|
||||
codec::objects::ObjectType::Material(m) if m.name == value => {
|
||||
Some(*h)
|
||||
}
|
||||
_ => None,
|
||||
@@ -3022,7 +3022,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.document
|
||||
.get_entity(handle)
|
||||
.and_then(|entity| match entity {
|
||||
acadrust::EntityType::MLine(mline) => {
|
||||
codec::EntityType::MLine(mline) => {
|
||||
crate::entities::mline::resolved_mline_style(
|
||||
mline,
|
||||
&self.tabs[i].scene.document,
|
||||
@@ -3048,7 +3048,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
);
|
||||
if matches!(field, "ml_justification" | "ml_scale") {
|
||||
if let (
|
||||
acadrust::EntityType::MLine(mline),
|
||||
codec::EntityType::MLine(mline),
|
||||
Some(style),
|
||||
) = (entity, mline_style.as_ref())
|
||||
{
|
||||
@@ -3062,7 +3062,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
if field.starts_with("tbl_") {
|
||||
for &handle in &handles {
|
||||
if let Some(acadrust::EntityType::Table(table)) =
|
||||
if let Some(codec::EntityType::Table(table)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
table.block_record_handle = None;
|
||||
@@ -3105,13 +3105,13 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
self.refresh_properties();
|
||||
}
|
||||
"material" => {
|
||||
let mat_handle: Option<acadrust::Handle> = self.tabs[i]
|
||||
let mat_handle: Option<codec::Handle> = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.objects
|
||||
.iter()
|
||||
.find_map(|(h, o)| match o {
|
||||
acadrust::objects::ObjectType::Material(m) if m.name == value => {
|
||||
codec::objects::ObjectType::Material(m) if m.name == value => {
|
||||
Some(*h)
|
||||
}
|
||||
_ => None,
|
||||
@@ -3119,7 +3119,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
match value.as_str() {
|
||||
"ByLayer" | "ByBlock" | "Global" => {
|
||||
self.tabs[i].scene.document.header.current_material_handle =
|
||||
acadrust::Handle::NULL;
|
||||
codec::Handle::NULL;
|
||||
}
|
||||
_ => {
|
||||
if let Some(h) = mat_handle {
|
||||
@@ -3161,7 +3161,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.objects
|
||||
.values()
|
||||
.find_map(|object| {
|
||||
let acadrust::objects::ObjectType::Layout(layout) = object
|
||||
let codec::objects::ObjectType::Layout(layout) = object
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
@@ -3176,7 +3176,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if current != next {
|
||||
self.push_undo_snapshot(i, "PLOTSTYLE");
|
||||
for object in self.tabs[i].scene.document.objects.values_mut() {
|
||||
if let acadrust::objects::ObjectType::Layout(layout) = object {
|
||||
if let codec::objects::ObjectType::Layout(layout) = object {
|
||||
if layout.name.eq_ignore_ascii_case(&layout_name) {
|
||||
layout.plot_style_sheet = next.clone();
|
||||
layout.plot_flags.plot_plot_styles = !next.is_empty();
|
||||
@@ -3212,7 +3212,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
let current = active_viewport
|
||||
.and_then(|handle| self.tabs[i].scene.document.get_entity(handle))
|
||||
.and_then(|entity| match entity {
|
||||
acadrust::EntityType::Viewport(viewport) => {
|
||||
codec::EntityType::Viewport(viewport) => {
|
||||
Some(viewport.ucs_icon_visible)
|
||||
}
|
||||
_ => None,
|
||||
@@ -3235,7 +3235,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if current != next {
|
||||
self.push_undo_snapshot(i, "UCSICON");
|
||||
if let Some(handle) = active_viewport {
|
||||
if let Some(acadrust::EntityType::Viewport(viewport)) =
|
||||
if let Some(codec::EntityType::Viewport(viewport)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
viewport.ucs_icon_visible = next;
|
||||
@@ -3266,7 +3266,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
let current = active_viewport
|
||||
.and_then(|handle| self.tabs[i].scene.document.get_entity(handle))
|
||||
.and_then(|entity| match entity {
|
||||
acadrust::EntityType::Viewport(viewport) => {
|
||||
codec::EntityType::Viewport(viewport) => {
|
||||
Some(viewport.status.ucs_icon_at_origin)
|
||||
}
|
||||
_ => None,
|
||||
@@ -3289,7 +3289,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if current != next {
|
||||
self.push_undo_snapshot(i, "UCSICON");
|
||||
if let Some(handle) = active_viewport {
|
||||
if let Some(acadrust::EntityType::Viewport(viewport)) =
|
||||
if let Some(codec::EntityType::Viewport(viewport)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
viewport.status.ucs_icon_at_origin = next;
|
||||
@@ -3320,7 +3320,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
let current = active_viewport
|
||||
.and_then(|handle| self.tabs[i].scene.document.get_entity(handle))
|
||||
.and_then(|entity| match entity {
|
||||
acadrust::EntityType::Viewport(viewport) => {
|
||||
codec::EntityType::Viewport(viewport) => {
|
||||
Some(viewport.ucs_per_viewport)
|
||||
}
|
||||
_ => None,
|
||||
@@ -3343,7 +3343,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if current != next {
|
||||
self.push_undo_snapshot(i, "UCSVP");
|
||||
if let Some(handle) = active_viewport {
|
||||
if let Some(acadrust::EntityType::Viewport(viewport)) =
|
||||
if let Some(codec::EntityType::Viewport(viewport)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
viewport.ucs_per_viewport = next;
|
||||
@@ -3367,7 +3367,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
self.refresh_properties();
|
||||
}
|
||||
"view_visual_style" => {
|
||||
use acadrust::entities::ViewportRenderMode as Mode;
|
||||
use codec::entities::ViewportRenderMode as Mode;
|
||||
let mode = match value.as_str() {
|
||||
"2D Wireframe" | "Wireframe 2D" => Some(Mode::Wireframe2D),
|
||||
"3D Wireframe" | "Wireframe 3D" => Some(Mode::Wireframe3D),
|
||||
@@ -3469,7 +3469,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
"ul_width" | "ul_height" => {
|
||||
let scale = handles.iter().find_map(|handle| {
|
||||
match self.tabs[i].scene.document.get_entity(*handle) {
|
||||
Some(acadrust::EntityType::Underlay(underlay)) => {
|
||||
Some(codec::EntityType::Underlay(underlay)) => {
|
||||
crate::entities::underlay::size_to_scale(
|
||||
underlay,
|
||||
&self.tabs[i].scene.document,
|
||||
@@ -3498,17 +3498,17 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
match (field, entity) {
|
||||
(
|
||||
"current_fit_point",
|
||||
acadrust::EntityType::Spline(spline),
|
||||
codec::EntityType::Spline(spline),
|
||||
) => Some(spline.fit_points.len()),
|
||||
(
|
||||
"current_control_point",
|
||||
acadrust::EntityType::Spline(spline),
|
||||
codec::EntityType::Spline(spline),
|
||||
) => Some(
|
||||
crate::entities::spline::control_vertex_count(spline),
|
||||
),
|
||||
(
|
||||
"pm_current_vertex",
|
||||
acadrust::EntityType::PolygonMesh(mesh),
|
||||
codec::EntityType::PolygonMesh(mesh),
|
||||
) => Some(mesh.vertices.len()),
|
||||
_ => None,
|
||||
}
|
||||
@@ -3533,7 +3533,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.objects
|
||||
.iter()
|
||||
.find_map(|(handle, object)| match object {
|
||||
acadrust::objects::ObjectType::TableStyle(style)
|
||||
codec::objects::ObjectType::TableStyle(style)
|
||||
if style.name.eq_ignore_ascii_case(val.trim()) =>
|
||||
{
|
||||
Some(*handle)
|
||||
@@ -3542,7 +3542,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
});
|
||||
if let Some(style_handle) = style_handle {
|
||||
for &handle in &handles {
|
||||
if let Some(acadrust::EntityType::Table(table)) =
|
||||
if let Some(codec::EntityType::Table(table)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
table.table_style_handle = Some(style_handle);
|
||||
@@ -3567,7 +3567,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
let host = self.tabs[i].scene.document.header.insertion_units;
|
||||
for &handle in &handles {
|
||||
let factor = match self.tabs[i].scene.document.get_entity(handle) {
|
||||
Some(acadrust::EntityType::Insert(ins)) => self.tabs[i]
|
||||
Some(codec::EntityType::Insert(ins)) => self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.block_records
|
||||
@@ -3578,7 +3578,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.unwrap_or(1.0),
|
||||
_ => continue,
|
||||
};
|
||||
if let Some(acadrust::EntityType::Insert(ins)) =
|
||||
if let Some(codec::EntityType::Insert(ins)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
match axis {
|
||||
@@ -3597,7 +3597,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
self.apply_block_name_commit(i, &handles, val.trim());
|
||||
} else if field == "frozen_layers" {
|
||||
// Resolve layer names → handles, then apply to viewports.
|
||||
let layer_handles: Vec<acadrust::Handle> = val
|
||||
let layer_handles: Vec<codec::Handle> = val
|
||||
.split(',')
|
||||
.map(|s| s.trim())
|
||||
.filter(|s| !s.is_empty())
|
||||
@@ -3612,7 +3612,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
})
|
||||
.collect();
|
||||
for &handle in &handles {
|
||||
if let Some(acadrust::EntityType::Viewport(vp)) =
|
||||
if let Some(codec::EntityType::Viewport(vp)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
vp.frozen_layers = layer_handles.clone();
|
||||
@@ -3651,7 +3651,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
&mut self.tabs[i].scene.document,
|
||||
handle,
|
||||
dov::DIMTXT,
|
||||
Some(acadrust::xdata::XDataValue::Real(height)),
|
||||
Some(codec::xdata::XDataValue::Real(height)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3659,7 +3659,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
_ if field.starts_with("dim_") => {
|
||||
if matches!(
|
||||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(acadrust::EntityType::Dimension(_))
|
||||
Some(codec::EntityType::Dimension(_))
|
||||
) {
|
||||
let applied = crate::entities::dim_override::set_property(
|
||||
&mut self.tabs[i].scene.document,
|
||||
@@ -3668,8 +3668,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
&val,
|
||||
);
|
||||
if applied && field == "dim_text_inside" {
|
||||
if let Some(acadrust::EntityType::Dimension(
|
||||
acadrust::entities::Dimension::LargeRadial(
|
||||
if let Some(codec::EntityType::Dimension(
|
||||
codec::entities::Dimension::LargeRadial(
|
||||
dimension,
|
||||
),
|
||||
)) = self.tabs[i]
|
||||
@@ -3688,7 +3688,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
let vals = if val.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(vec![acadrust::xdata::XDataValue::String(
|
||||
Some(vec![codec::xdata::XDataValue::String(
|
||||
val.clone(),
|
||||
)])
|
||||
};
|
||||
@@ -3724,7 +3724,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
&mut self.tabs[i].scene.document,
|
||||
handle,
|
||||
code,
|
||||
Some(acadrust::xdata::XDataValue::Real(n)),
|
||||
Some(codec::xdata::XDataValue::Real(n)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3767,7 +3767,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.document
|
||||
.get_entity(handle)
|
||||
.and_then(|entity| match entity {
|
||||
acadrust::EntityType::MLine(mline) => {
|
||||
codec::EntityType::MLine(mline) => {
|
||||
crate::entities::mline::resolved_mline_style(
|
||||
mline,
|
||||
&self.tabs[i].scene.document,
|
||||
@@ -3796,7 +3796,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
);
|
||||
if field == "ml_scale" {
|
||||
if let (
|
||||
acadrust::EntityType::MLine(mline),
|
||||
codec::EntityType::MLine(mline),
|
||||
Some(style),
|
||||
) = (entity, mline_style.as_ref())
|
||||
{
|
||||
@@ -3817,7 +3817,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
if field.starts_with("tbl_") {
|
||||
for &handle in &handles {
|
||||
if let Some(acadrust::EntityType::Table(table)) =
|
||||
if let Some(codec::EntityType::Table(table)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
table.block_record_handle = None;
|
||||
@@ -3866,7 +3866,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
/// the definition the (single-block) selection references is renamed and
|
||||
/// every insert of it follows. Anonymous/xref definitions never get here —
|
||||
/// their Name row stays read-only.
|
||||
fn apply_block_name_commit(&mut self, i: usize, handles: &[acadrust::Handle], new: &str) {
|
||||
fn apply_block_name_commit(&mut self, i: usize, handles: &[codec::Handle], new: &str) {
|
||||
if new.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -3887,7 +3887,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if self.tabs[i].scene.is_layer_locked(handle) {
|
||||
continue;
|
||||
}
|
||||
if let Some(acadrust::EntityType::Insert(ins)) =
|
||||
if let Some(codec::EntityType::Insert(ins)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
if ins.block_name != canon {
|
||||
@@ -3905,7 +3905,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// same definition; a mixed selection makes the rename target ambiguous.
|
||||
let mut old: Option<String> = None;
|
||||
for &handle in handles {
|
||||
if let Some(acadrust::EntityType::Insert(ins)) =
|
||||
if let Some(codec::EntityType::Insert(ins)) =
|
||||
self.tabs[i].scene.document.get_entity(handle)
|
||||
{
|
||||
match &old {
|
||||
@@ -3938,7 +3938,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
};
|
||||
self.push_undo_snapshot(i, "ATTEDIT");
|
||||
for &handle in &handles {
|
||||
if let Some(acadrust::EntityType::Insert(ins)) =
|
||||
if let Some(codec::EntityType::Insert(ins)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
if let Some(attr) = ins.attributes.iter_mut().find(|a| a.tag == tag) {
|
||||
@@ -3955,7 +3955,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
/// Open the attribute editor dialog for the given INSERT, loading a working
|
||||
/// copy of its attribute values. No-op (with a hint) when the block has no
|
||||
/// attributes. Entry points: double-clicking such a block, or ATTEDIT.
|
||||
pub(crate) fn open_attribute_editor(&mut self, handle: acadrust::Handle) {
|
||||
pub(crate) fn open_attribute_editor(&mut self, handle: codec::Handle) {
|
||||
let i = self.active_tab;
|
||||
if self.reject_locked_edit(i, handle) {
|
||||
return;
|
||||
@@ -3964,7 +3964,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
// Ok((block, rows)) to open; Err(msg) to report and stay closed. The
|
||||
// borrow of `doc` ends with this match, before any `self` mutation.
|
||||
let result = match doc.get_entity(handle) {
|
||||
Some(acadrust::EntityType::Insert(ins)) if !ins.attributes.is_empty() => {
|
||||
Some(codec::EntityType::Insert(ins)) if !ins.attributes.is_empty() => {
|
||||
// The prompt text lives on the block's ATTDEFs, not on the
|
||||
// attribute instances — map tag → prompt from the definition.
|
||||
let prompts = block_attr_prompts(doc, &ins.block_name);
|
||||
@@ -3975,7 +3975,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
.collect::<Vec<_>>();
|
||||
Ok((ins.block_name.clone(), rows))
|
||||
}
|
||||
Some(acadrust::EntityType::Insert(_)) => {
|
||||
Some(codec::EntityType::Insert(_)) => {
|
||||
Err("ATTEDIT This block has no attributes.")
|
||||
}
|
||||
_ => Err("ATTEDIT Select a block with attributes."),
|
||||
@@ -4043,7 +4043,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
|
||||
self.push_undo_snapshot(i, "ATTEDIT");
|
||||
let mut changed = false;
|
||||
if let Some(acadrust::EntityType::Insert(ins)) =
|
||||
if let Some(codec::EntityType::Insert(ins)) =
|
||||
self.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
if ins.block_name == block && rows.len() == ins.attributes.len() {
|
||||
@@ -4067,7 +4067,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
/// Build the editor's working copy of one attribute. Angles are shown in
|
||||
/// degrees; numeric fields become strings so the user can type freely.
|
||||
fn attr_row_from_entity(
|
||||
a: &acadrust::entities::AttributeEntity,
|
||||
a: &codec::entities::AttributeEntity,
|
||||
prompts: &rustc_hash::FxHashMap<String, String>,
|
||||
) -> AttrRow {
|
||||
let fmt = |v: f64| format!("{v}");
|
||||
@@ -4094,7 +4094,7 @@ fn attr_row_from_entity(
|
||||
/// Write one edited row back onto its attribute; returns whether anything
|
||||
/// changed. Numeric fields are parsed (angles from degrees); an unparseable
|
||||
/// field is left as-is.
|
||||
fn apply_attr_row(a: &mut acadrust::entities::AttributeEntity, row: &AttrRow) -> bool {
|
||||
fn apply_attr_row(a: &mut codec::entities::AttributeEntity, row: &AttrRow) -> bool {
|
||||
let mut ch = false;
|
||||
if a.get_value() != row.value {
|
||||
a.set_value(row.value.clone());
|
||||
@@ -4171,13 +4171,13 @@ fn apply_attr_row(a: &mut acadrust::entities::AttributeEntity, row: &AttrRow) ->
|
||||
/// ATTDEF. Attribute instances (ATTRIB) carry only tag + value; the prompt is
|
||||
/// defined once on the block definition. Tags with no definition are absent.
|
||||
fn block_attr_prompts(
|
||||
doc: &acadrust::CadDocument,
|
||||
doc: &codec::CadDocument,
|
||||
block_name: &str,
|
||||
) -> rustc_hash::FxHashMap<String, String> {
|
||||
let mut map = rustc_hash::FxHashMap::default();
|
||||
if let Some(br) = doc.block_records.get(block_name) {
|
||||
for &eh in &br.entity_handles {
|
||||
if let Some(acadrust::EntityType::AttributeDefinition(ad)) = doc.get_entity(eh) {
|
||||
if let Some(codec::EntityType::AttributeDefinition(ad)) = doc.get_entity(eh) {
|
||||
map.insert(ad.tag.clone(), ad.prompt.clone());
|
||||
}
|
||||
}
|
||||
@@ -4188,8 +4188,8 @@ fn block_attr_prompts(
|
||||
#[cfg(test)]
|
||||
mod layer_rename_tests {
|
||||
use crate::app::OpenCADStudio;
|
||||
use acadrust::entities::Line;
|
||||
use acadrust::{EntityType, Handle};
|
||||
use codec::entities::Line;
|
||||
use codec::{EntityType, Handle};
|
||||
|
||||
fn app_with_editing_layer() -> OpenCADStudio {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
|
||||
Reference in new issue
Block a user