diff --git a/src/entities/hatch.rs b/src/entities/hatch.rs index 30d500774..d0d22f532 100644 --- a/src/entities/hatch.rs +++ b/src/entities/hatch.rs @@ -63,6 +63,17 @@ fn properties(h: &Hatch) -> PropSection { if h.is_associative { "Yes" } else { "No" }, ), edit("Elevation", "elevation", h.elevation), + ro("Seed Points", "seed_count", h.seed_points.len().to_string()), + ro( + "Pixel Size", + "pixel_size", + format!("{:.6}", h.pixel_size), + ), + ro( + "Normal", + "normal", + format!("{:.3}, {:.3}, {:.3}", h.normal.x, h.normal.y, h.normal.z), + ), ], } } diff --git a/src/entities/leader.rs b/src/entities/leader.rs index 8d643d7e2..c7d83759b 100644 --- a/src/entities/leader.rs +++ b/src/entities/leader.rs @@ -227,6 +227,25 @@ fn properties(leader: &Leader) -> PropSection { // Stats ro("Vertices", "vertex_count", n.to_string()), ro("Length", "length", format!("{:.4}", leader.length())), + // Annotation reference + dim-style colour override (read-only — + // they are written by the file and survive a round-trip). + ro( + "Annotation", + "annotation_handle", + if leader.annotation_handle.is_null() { + "(none)".to_string() + } else { + format!("{:X}", leader.annotation_handle.value()) + }, + ), + ro( + "Override Color", + "override_color", + match leader.override_color.rgb() { + Some((r, g, b)) => format!("RGB({},{},{})", r, g, b), + None => format!("{:?}", leader.override_color), + }, + ), ]; // Arrow point (vertex[0]) diff --git a/src/entities/mline.rs b/src/entities/mline.rs index 143e09e4b..b663a2241 100644 --- a/src/entities/mline.rs +++ b/src/entities/mline.rs @@ -156,12 +156,41 @@ impl Grippable for MLine { impl PropertyEditable for MLine { fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection { + let just_str = match self.justification { + acadrust::entities::MLineJustification::Top => "Top", + acadrust::entities::MLineJustification::Zero => "Zero", + acadrust::entities::MLineJustification::Bottom => "Bottom", + }; PropSection { title: "Geometry".into(), props: vec![ ro("Style", "ml_style", self.style_name.clone()), + ro( + "Style Handle", + "ml_style_handle", + match self.style_handle { + Some(h) if !h.is_null() => format!("{:X}", h.value()), + _ => "(none)".to_string(), + }, + ), ro("Vertices", "ml_verts", self.vertices.len().to_string()), + ro( + "Style Elements", + "ml_style_elem_count", + self.style_element_count.to_string(), + ), edit("Scale", "ml_scale", self.scale_factor), + Property { + label: "Justification".into(), + field: "ml_justification", + value: PropValue::Choice { + selected: just_str.to_string(), + options: ["Top", "Zero", "Bottom"] + .into_iter() + .map(str::to_string) + .collect(), + }, + }, Property { label: "Closed".into(), field: "ml_closed", @@ -186,6 +215,14 @@ impl PropertyEditable for MLine { .set(acadrust::entities::MLineFlags::CLOSED, closed); return; } + "ml_justification" => { + self.justification = match value { + "Top" => acadrust::entities::MLineJustification::Top, + "Bottom" => acadrust::entities::MLineJustification::Bottom, + _ => acadrust::entities::MLineJustification::Zero, + }; + return; + } _ => {} } let Ok(v) = value.trim().parse::() else { diff --git a/src/entities/ole2frame.rs b/src/entities/ole2frame.rs index 1f8a5012a..1aaa4ba3d 100644 --- a/src/entities/ole2frame.rs +++ b/src/entities/ole2frame.rs @@ -88,6 +88,32 @@ fn properties(ole: &Ole2Frame) -> PropSection { edit("Upper Left Y", "ole_uly", ole.upper_left_corner.y), edit("Lower Right X", "ole_lrx", ole.lower_right_corner.x), edit("Lower Right Y", "ole_lry", ole.lower_right_corner.y), + ro("Version", "ole_version", ole.version.to_string()), + ro( + "Source App", + "ole_source_app", + if ole.source_application.is_empty() { + "(unknown)".to_string() + } else { + ole.source_application.clone() + }, + ), + ro( + "Data Size", + "ole_data_size", + format!("{} bytes", ole.binary_data.len()), + ), + ro("DWG Mode", "ole_dwg_mode", ole.dwg_mode.to_string()), + ro( + "DWG Trailing Byte", + "ole_dwg_trailing", + format!("{:#04x}", ole.dwg_trailing_byte), + ), + ro( + "Paper Space", + "ole_paper_space", + if ole.is_paper_space { "Yes" } else { "No" }, + ), ], } } diff --git a/src/entities/polyline.rs b/src/entities/polyline.rs index 22f63334b..65b89619d 100644 --- a/src/entities/polyline.rs +++ b/src/entities/polyline.rs @@ -347,11 +347,29 @@ impl Grippable for Polyline2D { impl PropertyEditable for Polyline2D { fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection { + let smooth = match self.smooth_surface { + acadrust::entities::SmoothSurfaceType::None => "None", + acadrust::entities::SmoothSurfaceType::QuadraticBSpline => "Quadratic", + acadrust::entities::SmoothSurfaceType::CubicBSpline => "Cubic", + acadrust::entities::SmoothSurfaceType::Bezier => "Bezier", + }; PropSection { title: "Geometry".into(), props: vec![ ro("Vertices", "vertices", self.vertices.len().to_string()), edit("Elevation", "pl2_elevation", self.elevation), + edit("Default Start W", "pl2_start_w", self.start_width), + edit("Default End W", "pl2_end_w", self.end_width), + edit("Thickness", "pl2_thickness", self.thickness), + ro("Smooth Surface", "pl2_smooth", smooth), + ro( + "Normal", + "pl2_normal", + format!( + "{:.3}, {:.3}, {:.3}", + self.normal.x, self.normal.y, self.normal.z + ), + ), Property { label: "Closed".into(), field: "pl2_closed", @@ -383,6 +401,25 @@ impl PropertyEditable for Polyline2D { self.elevation = v; } } + "pl2_start_w" => { + if let Ok(v) = value.trim().parse::() { + if v >= 0.0 { + self.start_width = v; + } + } + } + "pl2_end_w" => { + if let Ok(v) = value.trim().parse::() { + if v >= 0.0 { + self.end_width = v; + } + } + } + "pl2_thickness" => { + if let Ok(v) = value.trim().parse::() { + self.thickness = v; + } + } _ => {} } } diff --git a/src/entities/raster_image.rs b/src/entities/raster_image.rs index 83e7ff409..44e060fe8 100644 --- a/src/entities/raster_image.rs +++ b/src/entities/raster_image.rs @@ -186,6 +186,27 @@ impl PropertyEditable for RasterImage { value: self.clipping_enabled, }, }, + ro( + "Class Version", + "ri_class_version", + self.class_version.to_string(), + ), + ro( + "Definition", + "ri_def_handle", + match self.definition_handle { + Some(h) if !h.is_null() => format!("{:X}", h.value()), + _ => "(none)".to_string(), + }, + ), + ro( + "Def Reactor", + "ri_def_reactor_handle", + match self.definition_reactor_handle { + Some(h) if !h.is_null() => format!("{:X}", h.value()), + _ => "(none)".to_string(), + }, + ), ], } } @@ -421,6 +442,32 @@ impl PropertyEditable for Wipeout { value: self.clipping_enabled, }, }, + ro( + "Class Version", + "wo_class_version", + self.class_version.to_string(), + ), + ro( + "Clip Mode", + "wo_clip_mode", + format!("{:?}", self.clip_mode), + ), + ro( + "Definition", + "wo_def_handle", + match self.definition_handle { + Some(h) if !h.is_null() => format!("{:X}", h.value()), + _ => "(none)".to_string(), + }, + ), + ro( + "Def Reactor", + "wo_def_reactor_handle", + match self.definition_reactor_handle { + Some(h) if !h.is_null() => format!("{:X}", h.value()), + _ => "(none)".to_string(), + }, + ), ], } } diff --git a/src/entities/solid3d.rs b/src/entities/solid3d.rs index 17da80bf9..637c48679 100644 --- a/src/entities/solid3d.rs +++ b/src/entities/solid3d.rs @@ -87,6 +87,28 @@ impl PropertyEditable for Solid3D { format!("{:.4}", self.point_of_reference.z), ), ro("ACIS Data", "s3d_acis", size), + ro( + "UID", + "s3d_uid", + if self.uid.is_empty() { + "(none)".to_string() + } else { + self.uid.clone() + }, + ), + ro( + "Silhouettes", + "s3d_silhouettes", + self.silhouettes.len().to_string(), + ), + ro( + "History", + "s3d_history", + match self.history_handle { + Some(h) if !h.is_null() => format!("{:X}", h.value()), + _ => "(none)".to_string(), + }, + ), ], } } @@ -141,6 +163,20 @@ impl PropertyEditable for Region { format!("{:.4}", self.point_of_reference.z), ), ro("ACIS Data", "rgn_acis", size), + ro( + "UID", + "rgn_uid", + if self.uid.is_empty() { + "(none)".to_string() + } else { + self.uid.clone() + }, + ), + ro( + "Silhouettes", + "rgn_silhouettes", + self.silhouettes.len().to_string(), + ), ], } } @@ -195,6 +231,20 @@ impl PropertyEditable for Body { format!("{:.4}", self.point_of_reference.z), ), ro("ACIS Data", "bdy_acis", size), + ro( + "UID", + "bdy_uid", + if self.uid.is_empty() { + "(none)".to_string() + } else { + self.uid.clone() + }, + ), + ro( + "Silhouettes", + "bdy_silhouettes", + self.silhouettes.len().to_string(), + ), ], } } diff --git a/src/entities/tolerance.rs b/src/entities/tolerance.rs index 661ad9187..1e276192e 100644 --- a/src/entities/tolerance.rs +++ b/src/entities/tolerance.rs @@ -290,6 +290,41 @@ impl PropertyEditable for Tolerance { edit("Insert X", "tol_ix", self.insertion_point.x), edit("Insert Y", "tol_iy", self.insertion_point.y), edit("Insert Z", "tol_iz", self.insertion_point.z), + ro( + "Dim Style", + "tol_dim_style", + if self.dimension_style_name.is_empty() { + "(default)".to_string() + } else { + self.dimension_style_name.clone() + }, + ), + ro( + "Dim Style Handle", + "tol_dim_style_handle", + match self.dimension_style_handle { + Some(h) if !h.is_null() => format!("{:X}", h.value()), + _ => "(none)".to_string(), + }, + ), + edit("Text Height", "tol_text_height", self.text_height), + edit("Dim Gap", "tol_dim_gap", self.dimension_gap), + ro( + "Direction", + "tol_direction", + format!( + "{:.3}, {:.3}, {:.3}", + self.direction.x, self.direction.y, self.direction.z + ), + ), + ro( + "Normal", + "tol_normal", + format!( + "{:.3}, {:.3}, {:.3}", + self.normal.x, self.normal.y, self.normal.z + ), + ), ], } } @@ -302,6 +337,8 @@ impl PropertyEditable for Tolerance { "tol_ix" => self.insertion_point.x = v, "tol_iy" => self.insertion_point.y = v, "tol_iz" => self.insertion_point.z = v, + "tol_text_height" if v > 0.0 => self.text_height = v, + "tol_dim_gap" => self.dimension_gap = v, _ => {} } } diff --git a/src/entities/underlay.rs b/src/entities/underlay.rs index 5b16ceb83..5145dfba2 100644 --- a/src/entities/underlay.rs +++ b/src/entities/underlay.rs @@ -195,6 +195,11 @@ impl PropertyEditable for Underlay { "No" }, ), + ro( + "Clip Inverted", + "ul_clip_inverted", + if self.clip_inverted { "Yes" } else { "No" }, + ), ], } } diff --git a/src/entities/viewport.rs b/src/entities/viewport.rs index 79d91d073..fe7549233 100644 --- a/src/entities/viewport.rs +++ b/src/entities/viewport.rs @@ -2,7 +2,9 @@ use acadrust::entities::{Viewport, ViewportRenderMode}; use glam::Vec3; use crate::command::EntityTransform; -use crate::entities::common::{diamond_grip, edit_prop as edit, parse_f64, square_grip}; +use crate::entities::common::{ + diamond_grip, edit_prop as edit, parse_f64, ro_prop as ro, square_grip, +}; use crate::entities::traits::{Grippable, PropertyEditable, Transformable}; use crate::scene::object::{GripApply, GripDef, PropSection, PropValue, Property}; @@ -230,6 +232,84 @@ fn properties(vp: &Viewport) -> PropSection { edit("UCS Y-Axis X", "vp_ucs_yx", vp.ucs_y_axis.x), edit("UCS Y-Axis Y", "vp_ucs_yy", vp.ucs_y_axis.y), edit("UCS Y-Axis Z", "vp_ucs_yz", vp.ucs_y_axis.z), + // Snap / grid metadata (drives the snap-aware UI; not rendered + // into the viewport contents directly). + edit("Snap Base X", "vp_snap_bx", vp.snap_base.x), + edit("Snap Base Y", "vp_snap_by", vp.snap_base.y), + edit("Snap Spacing X", "vp_snap_sx", vp.snap_spacing.x), + edit("Snap Spacing Y", "vp_snap_sy", vp.snap_spacing.y), + edit("Snap Angle", "vp_snap_ang", vp.snap_angle.to_degrees()), + edit("Twist Angle", "vp_twist", vp.twist_angle.to_degrees()), + edit("Front Clip Z", "vp_front_clip", vp.front_clip_z), + edit("Back Clip Z", "vp_back_clip", vp.back_clip_z), + edit( + "Circle Sides", + "vp_circle_sides", + vp.circle_sides as f64, + ), + ro( + "Grid Flags", + "vp_grid_flags", + format!("{:#06b}", vp.grid_flags.to_bits()), + ), + ro("Grid Major", "vp_grid_major", vp.grid_major.to_string()), + ro( + "Base UCS", + "vp_base_ucs_handle", + if vp.base_ucs_handle.is_null() { + "(none)".to_string() + } else { + format!("{:X}", vp.base_ucs_handle.value()) + }, + ), + ro( + "UCS Ortho", + "vp_ucs_ortho", + vp.ucs_ortho_type.to_string(), + ), + ro( + "Background", + "vp_background_handle", + if vp.background_handle.is_null() { + "(none)".to_string() + } else { + format!("{:X}", vp.background_handle.value()) + }, + ), + ro( + "Shade Plot", + "vp_shade_plot_handle", + if vp.shade_plot_handle.is_null() { + "(none)".to_string() + } else { + format!("{:X}", vp.shade_plot_handle.value()) + }, + ), + ro( + "Visual Style", + "vp_visual_style_handle", + if vp.visual_style_handle.is_null() { + "(none)".to_string() + } else { + format!("{:X}", vp.visual_style_handle.value()) + }, + ), + // 3D lighting (not yet applied to the viewport mesh path). + ro( + "Default Lighting", + "vp_default_lighting", + if vp.default_lighting { "Yes" } else { "No" }, + ), + ro( + "Lighting Type", + "vp_lighting_type", + vp.default_lighting_type.to_string(), + ), + ro( + "Ambient Color", + "vp_ambient_color", + format!("{:#010x}", vp.ambient_color as u32), + ), ], } } @@ -404,6 +484,17 @@ fn apply_geom_prop(vp: &mut Viewport, field: &str, value: &str) { "vp_ucs_yx" => vp.ucs_y_axis.x = v, "vp_ucs_yy" => vp.ucs_y_axis.y = v, "vp_ucs_yz" => vp.ucs_y_axis.z = v, + "vp_snap_bx" => vp.snap_base.x = v, + "vp_snap_by" => vp.snap_base.y = v, + "vp_snap_sx" if v >= 0.0 => vp.snap_spacing.x = v, + "vp_snap_sy" if v >= 0.0 => vp.snap_spacing.y = v, + "vp_snap_ang" => vp.snap_angle = v.to_radians(), + "vp_twist" => vp.twist_angle = v.to_radians(), + "vp_front_clip" => vp.front_clip_z = v, + "vp_back_clip" => vp.back_clip_z = v, + "vp_circle_sides" if v >= 0.0 && v <= i16::MAX as f64 => { + vp.circle_sides = v as i16; + } _ => {} } }