Merge main into codex/graphic-attributes-cleanup

Conflicts were additions on both sides, kept together: the Count palette
and Sheet Set toggles next to the Graphic Attributes toggle in the ribbon,
main's new locale groups and catalog entries next to graphic-attributes,
and module declarations. The palette code follows main's crate renames
(acadrust -> codec, cadkernel -> kernel).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu
This commit is contained in:
Claude committed 2026-10-07 20:11:05 +00:00
commit 7a03e1c43c
625 files changed
+104397 -28053

No files matched your search

+140 -37
View File
@@ -8,21 +8,21 @@
use crate::scene::model::hatch_model::HatchModel;
use crate::scene::model::wire_model::WireModel;
use crate::scene::Scene;
use acadrust::{EntityType, Handle};
use codec::{EntityType, Handle};
use glam::DVec3;
#[derive(Clone, Debug)]
pub enum HatchEditOperation {
Appearance {
color: Option<acadrust::types::Color>,
color: Option<codec::types::Color>,
layer: Option<String>,
transparency: Option<acadrust::types::Transparency>,
transparency: Option<codec::types::Transparency>,
},
Update {
origin: Option<(f64, f64)>,
store_origin: bool,
disassociate: bool,
style: Option<acadrust::entities::HatchStyleType>,
style: Option<codec::entities::HatchStyleType>,
annotative: Option<bool>,
},
RecreateBoundary {
@@ -30,7 +30,7 @@ pub enum HatchEditOperation {
region: bool,
},
BeginAssociate,
AssociatePaths(Vec<acadrust::entities::BoundaryPath>),
AssociatePaths(Vec<codec::entities::BoundaryPath>),
DrawOrderBoundary {
above: bool,
},
@@ -110,8 +110,8 @@ impl WorkingPlane {
(direction.x.hypot(direction.y) > f64::EPSILON).then(|| direction.y.atan2(direction.x))
}
pub fn to_world_transform(self) -> acadrust::types::Transform {
use acadrust::types::{Matrix4, Transform};
pub fn to_world_transform(self) -> codec::types::Transform {
use codec::types::{Matrix4, Transform};
Transform::from_matrix(Matrix4 {
m: [
[self.x.x, self.y.x, self.z.x, self.origin.x],
@@ -122,8 +122,8 @@ impl WorkingPlane {
})
}
pub fn to_local_transform(self) -> acadrust::types::Transform {
use acadrust::types::{Matrix4, Transform};
pub fn to_local_transform(self) -> codec::types::Transform {
use codec::types::{Matrix4, Transform};
Transform::from_matrix(Matrix4 {
m: [
[self.x.x, self.x.y, self.x.z, -self.origin.dot(self.x)],
@@ -249,18 +249,25 @@ pub enum EntityTransform {
},
/// General affine transform. Used when a complete UCS basis must be baked
/// into block-local geometry instead of stored as drawing UCS state.
Affine(acadrust::types::Transform),
Affine(codec::types::Transform),
}
// ── Tangent object ─────────────────────────────────────────────────────────
/// Geometric representation of a tangent-snap target.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TangentObject {
/// Infinite line through two world-space XZ-plane points.
Line { p1: DVec3, p2: DVec3 },
/// Circle in the world XY plane.
Circle { center: DVec3, radius: f64 },
/// Planar ellipse in world space.
Ellipse {
center: DVec3,
major_axis: DVec3,
normal: DVec3,
minor_axis_ratio: f64,
},
}
/// One unit of input to the active command's step machine.
@@ -417,6 +424,10 @@ impl CadCommand for UcsPickCommand {
true
}
fn entity_pick_includes_fills(&self) -> bool {
self.face
}
fn entity_pick_uses_surface_point(&self) -> bool {
self.face
}
@@ -1385,6 +1396,9 @@ pub struct SweepOptions {
pub scale: f64,
/// Total twist along the path, in radians.
pub twist_angle: f64,
/// Where the path was picked: an open path is swept from its end nearest
/// this point (seen from above), as the reference does.
pub path_pick: Option<DVec3>,
}
impl Default for SweepOptions {
@@ -1395,6 +1409,7 @@ impl Default for SweepOptions {
base_point: None,
scale: 1.0,
twist_angle: 0.0,
path_pick: None,
}
}
}
@@ -1499,13 +1514,13 @@ pub enum CmdResult {
InterimWire(WireModel),
/// Update the in-progress (cyan) preview wire in the viewport.
Preview(WireModel),
/// Commit an acadrust entity to the document; keep the command active.
/// Commit an opencadcodec entity to the document; keep the command active.
CommitEntity(EntityType),
/// Commit several acadrust entities in one undo step; keep the command active.
/// Commit several opencadcodec entities in one undo step; keep the command active.
CommitEntities(Vec<EntityType>),
/// Commit several entities in one undo step and end the command.
CommitEntitiesAndExit(Vec<EntityType>),
/// Commit an acadrust entity to the document and end the command.
/// Commit an opencadcodec entity to the document and end the command.
CommitAndExit(EntityType),
/// Commit a dimension using the drawing's association mode.
CommitDimension {
@@ -1534,16 +1549,16 @@ pub enum CmdResult {
handles: Vec<Handle>,
point: DVec3,
},
/// Commit a Model-tab 3D solid: the acadrust entity (for selection /
/// Commit a Model-tab 3D solid: the opencadcodec entity (for selection /
/// persistence) plus its B-rep (cached for boolean ops + shaded
/// rendering). Ends the command.
CommitSolid {
entity: EntityType,
solid: Box<cadkernel::brep::Body>,
history: acadrust::objects::SolidHistoryOperation,
solid: Box<kernel::brep::Body>,
history: codec::objects::SolidHistoryOperation,
erase_source: Option<Handle>,
},
/// Commit an acadrust entity, end the command, and open the in-place text
/// Commit an opencadcodec entity, end the command, and open the in-place text
/// editor on it (used by MLEADER to type the annotation after placement).
CommitAndEditText(EntityType),
/// Commit several entities, end the command, and open the in-place text
@@ -1578,24 +1593,50 @@ pub enum CmdResult {
/// Commit a hatch with the selected hatch's entity colour and transparency.
CommitStyledHatch {
hatch: HatchModel,
color: acadrust::types::Color,
transparency: acadrust::types::Transparency,
color: codec::types::Color,
transparency: codec::types::Transparency,
},
/// Commit a hatch and retain each boundary ring as an entity.
CommitHatchWithBoundaries {
hatch: HatchModel,
boundaries: Vec<EntityType>,
entity_style: Option<(acadrust::types::Color, acadrust::types::Transparency)>,
entity_style: Option<(codec::types::Color, codec::types::Transparency)>,
},
/// Commit independently editable hatch entities for every selected region.
CommitHatches {
hatches: Vec<HatchModel>,
entity_style: Option<(acadrust::types::Color, acadrust::types::Transparency)>,
entity_style: Option<(codec::types::Color, codec::types::Transparency)>,
},
/// Copy selected entities with multiple transforms (e.g. rectangular array); end command.
BatchCopy(Vec<Handle>, Vec<EntityTransform>),
/// Erase `handle` and replace with new entities; command stays active.
ReplaceEntity(Handle, Vec<EntityType>),
/// XCLIP on block references; ends the command.
XClip {
inserts: Vec<Handle>,
action: crate::modules::insert::xclip::XclipAction,
},
/// Open the PDF Import Settings dialog; the command keeps its prompt.
OpenPdfImportSettings,
/// Import a page of a file (PDFIMPORT File); ends the command.
PdfImportFile(crate::modules::insert::pdf_import::PdfFileImport),
/// Attach a point cloud: the host creates or reuses its definition,
/// commits the cloud in one undo step, then ends the command. The
/// message is the last prompt's echo.
AttachPointCloud {
placement: crate::modules::insert::pc_attach::PointCloudPlacement,
message: String,
},
/// Attach PDF pages: each page's underlay with its file (as stored) and
/// page; the host creates or reuses the definitions and commits them all
/// in one undo step, then ends the command.
AttachPdfPages {
kind: codec::entities::UnderlayType,
path: String,
pages: Vec<(String, EntityType)>,
},
/// Import the vector content of a PDF underlay (PDFIMPORT); ends the command.
PdfImport(crate::modules::insert::pdf_import::PdfImportRequest),
/// Update one entity in place, preserve its handle, and end the command.
UpdateEntityAndFinish {
handle: Handle,
@@ -1633,7 +1674,7 @@ pub enum CmdResult {
AddHorizontalConstraint {
kind: crate::scene::parametric_constraints::ConstraintKind,
selection: HorizontalConstraintSelection,
direction: acadrust::types::Vector3,
direction: codec::types::Vector3,
label: &'static str,
},
/// Resolves the first 2Points pick of a Horizontal or Vertical constraint
@@ -1895,6 +1936,12 @@ pub enum CmdResult {
ReportError(String),
/// Reports an error and ends the command (`Lines are parallel.`).
CancelWithMessage(String),
/// Explode this block reference and commit its pieces; end the command
/// unless `keep_going` (repeated placement).
CommitExplodedInsert {
insert: EntityType,
keep_going: bool,
},
/// Print a measurement result, clear the current selection, and keep the command active.
ReportMeasurementAndDeselect(String),
/// Clear the current selection and keep the command active at its updated step.
@@ -1952,7 +1999,7 @@ pub enum CmdResult {
/// Create a paper-space viewport. `preserve_view` keeps an explicitly
/// selected/defined view instead of applying the normal model-extents fit.
MviewCreate {
viewport: acadrust::entities::Viewport,
viewport: codec::entities::Viewport,
preserve_view: bool,
},
/// Create a viewport clipped by either a new polygon boundary or an
@@ -1960,6 +2007,9 @@ pub enum CmdResult {
MviewCreateClipped {
boundary: Option<EntityType>,
boundary_handle: Handle,
/// VPCLIP: the viewport to clip instead of creating one (NULL for
/// MVIEW). With neither boundary nor handle its clip is deleted.
target: Handle,
},
/// Create a wipeout from an existing closed polyline in the active space.
/// `erase_source` controls whether the source boundary is consumed.
@@ -2001,7 +2051,7 @@ pub enum CmdResult {
/// command (boundary, rotation, attachment, spacing and columns).
/// Existing-entity edits leave this as `None` and load the document
/// entity instead.
template: Option<Box<acadrust::MText>>,
template: Option<Box<codec::MText>>,
},
/// Collect rich text without creating an MText entity.
SuspendForMTextInput {
@@ -2024,7 +2074,7 @@ pub enum CmdResult {
/// the command resumes so another line can be placed directly below it.
SuspendForTextInput {
pos: DVec3,
entity: acadrust::entities::Text,
entity: codec::entities::Text,
},
/// Apply new pattern/scale/angle to an existing hatch entity.
HatcheditApply {
@@ -2094,6 +2144,9 @@ pub enum CmdResult {
mode: ExtrudeMode,
options: SweepOptions,
color: [f32; 4],
/// Scale and twist expressions entered with the Expression option;
/// a swept surface stays linked to them.
expressions: [Option<String>; 2],
},
/// Loft through ordered cross-sections, with optional guides or a path.
LoftEntities {
@@ -2107,8 +2160,8 @@ pub enum CmdResult {
/// Round or bevel one or more resolved B-rep edges on a solid.
SolidEdgeBlend {
handle: Handle,
edges: Vec<cadkernel::brep::EdgeKey>,
base_face: Option<cadkernel::brep::FaceKey>,
edges: Vec<kernel::brep::EdgeKey>,
base_face: Option<kernel::brep::FaceKey>,
value: f64,
other_value: f64,
fillet: bool,
@@ -2129,13 +2182,13 @@ pub enum CmdResult {
/// containing that WCS point.
SliceEntities {
targets: Vec<Handle>,
plane: cadkernel::space::Plane,
plane: kernel::space::Plane,
keep_point: Option<DVec3>,
},
/// Split selected solids or surfaces with one selected analytic sheet.
SliceSurfaceEntities {
targets: Vec<Handle>,
cutter: Box<cadkernel::brep::Body>,
cutter: Box<kernel::brep::Body>,
keep_point: Option<DVec3>,
},
/// INSERT landed on a block that has AttributeDefinitions.
@@ -2426,7 +2479,7 @@ pub trait CadCommand: Send {
None
}
/// Symbol localization is committed together with the extracted entities.
fn nested_copy_symbol_names(&self) -> Option<&acadrust::nested_copy::NestedCopySymbolNames> {
fn nested_copy_symbol_names(&self) -> Option<&codec::nested_copy::NestedCopySymbolNames> {
None
}
/// Keep the layer already carried by entities committed by this command
@@ -2632,6 +2685,12 @@ pub trait CadCommand: Send {
/// Resume the command with collected rich text.
fn on_editor_text(&mut self, _value: String) {}
/// A field (code and referenced objects) to attach to the entity this
/// command commits.
fn text_field(&self) -> Option<(String, Vec<Handle>)> {
None
}
fn on_editor_display_height(&mut self, _height: f64) {}
/// Called when the user clicks and `needs_entity_pick()` is true.
@@ -2699,6 +2758,12 @@ pub trait CadCommand: Send {
/// Commands that stay active across replaces should update their internal snapshots here.
fn on_entity_replaced(&mut self, _old: Handle, _new_handles: &[Handle]) {}
/// Called after `CmdResult::CommitEntity` / `CommitEntities` added
/// entities while the command stays active, with the entities as stored
/// (fresh handles). Commands that pick from a snapshot add them here so
/// their own results can be hovered and picked next. (#673)
fn on_entities_committed(&mut self, _entities: &[codec::EntityType]) {}
/// Called after a PEDIT operation changed its target.
fn on_pedit_applied(&mut self) {}
@@ -2747,6 +2812,16 @@ pub trait CadCommand: Send {
self.on_mouse_move(pt).into_iter().collect()
}
/// Called on every mouse-move with optional live tangent snap target under the cursor.
/// Default: forwards to `on_preview_wires(pt)`.
fn on_preview_wires_with_tangent(
&mut self,
pt: DVec3,
_tangent: Option<TangentObject>,
) -> Vec<WireModel> {
self.on_preview_wires(pt)
}
/// Source entities replaced by the current live preview. The host removes
/// these from the resident render until the command commits or cancels.
/// Commands such as COPY keep their sources visible and use the default.
@@ -2832,6 +2907,22 @@ pub trait CadCommand: Send {
false
}
/// The command takes block references only (XCLIP): the host drops the
/// rest and says how many were ineligible.
fn selection_keeps_block_references(&self) -> bool {
false
}
/// The command moves, turns or resizes what it gathers: the host drops
/// locked point clouds from each completed selection and says so.
fn selection_drops_locked_point_clouds(&self) -> bool {
false
}
/// Before each input the host says which block references carry a clip
/// boundary.
fn inject_clipped(&mut self, _clipped: &dyn Fn(Handle) -> bool) {}
/// Called after a selection action completes while `is_selection_gathering` is true.
/// `handles` is the full set of currently selected entities.
/// Return `Relaunch` to fire the pending command, or `NeedPoint` to keep gathering.
@@ -2864,6 +2955,12 @@ pub trait CadCommand: Send {
false
}
/// The step draws a window that selects objects rather than placing
/// geometry: no coordinate boxes at the cursor. Default `false`.
fn selects_by_window(&self) -> bool {
false
}
/// The already-picked first corner of the selection window (world space)
/// while `window_corner_pick()` is true and the opposite corner is being
/// dragged. The host projects it and draws a filled selection marquee to the
@@ -2886,22 +2983,28 @@ pub trait CadCommand: Send {
/// The block reference an ATTEDIT pick has resolved to, awaiting the
/// attribute editor dialog; else None.
fn attedit_pending_handle(&self) -> Option<acadrust::Handle> {
fn attedit_pending_handle(&self) -> Option<codec::Handle> {
None
}
/// Inject block attribute definitions after the INSERT point is picked.
fn attreq_set_attdefs(
&mut self,
_attdefs: Vec<acadrust::entities::AttributeDefinition>,
) -> Option<acadrust::EntityType> {
_attdefs: Vec<codec::entities::AttributeDefinition>,
) -> Option<codec::EntityType> {
None
}
/// After the host commits an ATTREQ insert: keep the command running
/// (repeated placement) instead of ending it.
fn attreq_continue(&self) -> bool {
false
}
/// Returns the INSERT entity built so far (pending attr fill) if this is an
/// ATTREQ-aware INSERT command waiting for attdef injection.
/// Called by the host after `AttreqNeeded` to commit the completed Insert.
fn attreq_take_insert(&mut self) -> Option<acadrust::EntityType> {
fn attreq_take_insert(&mut self) -> Option<codec::EntityType> {
None
}
@@ -2944,13 +3047,13 @@ pub trait CadCommand: Send {
/// Called by update.rs to inject the cloned entity into commands
/// that need to read/modify it (e.g. DIMTEDIT, MLEADERADD, MLEADERREMOVE).
/// Default: no-op.
fn inject_picked_entity(&mut self, _entity: acadrust::EntityType) {}
fn inject_picked_entity(&mut self, _entity: codec::EntityType) {}
/// The host undid one document step on the command's behalf
/// (`CmdResult::UndoDocument`) and the command stays active. Commands
/// that cache document entities (FILLET, CHAMFER) refresh them here so
/// the next pick sees the restored geometry. Default: no-op.
fn on_document_undone(&mut self, _document: &acadrust::CadDocument) {}
fn on_document_undone(&mut self, _document: &codec::CadDocument) {}
/// Supply the tessellated surface area associated with the picked entity.
/// Commands that measure mesh-backed objects can opt in without owning the