feat: WBLOCK — write block or selected entities to external file

- src/modules/insert/wblock.rs: extract_block_to_doc() copies a named
  block's entities into a fresh CadDocument; extract_entities_to_doc()
  does the same for a selection set; layer definitions are carried over
- WBLOCK <name> writes the named block; WBLOCK * writes selected entities
- WblockSave / WblockSaveResult messages drive the async save-dialog flow
- ROADMAP.md: 1.10 WBLOCK marked ✅

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Sonnet 4.6 committed 2026-04-08 00:05:04 +03:00
1 parent 64837e9aed
commit b15be3af3d
6 files changed
+176 -2

No files matched your search

+2
View File
@@ -7,6 +7,7 @@ mod cylinder;
pub(crate) mod insert_block;
mod open_obj;
mod sphere;
pub(crate) mod wblock;
pub(crate) mod xattach;
use crate::modules::{CadModule, RibbonGroup};
@@ -40,6 +41,7 @@ impl CadModule for InsertModule {
tools: vec![
create_block::tool().into(),
insert_block::tool().into(),
wblock::tool().into(),
xattach::tool().into(),
],
},
+106
View File
@@ -0,0 +1,106 @@
// WBLOCK — write a block (or selected entities) to an external DWG/DXF file.
//
// Two modes:
// block name → copies the named block definition to a new document
// * → copies currently selected model-space entities
use acadrust::{CadDocument, EntityType};
use crate::modules::{IconKind, ModuleEvent, ToolDef};
pub fn tool() -> ToolDef {
ToolDef {
id: "WBLOCK",
label: "Write Block",
icon: IconKind::Svg(include_bytes!("../../../assets/icons/blocks/insert.svg")),
event: ModuleEvent::Command("WBLOCK".to_string()),
}
}
/// Build a standalone `CadDocument` containing the named block's entities
/// extracted into model space.
///
/// Returns `Err` if the block is not found or has no entities.
pub fn extract_block_to_doc(
src: &CadDocument,
block_name: &str,
) -> Result<CadDocument, String> {
let br = src
.block_records
.get(block_name)
.ok_or_else(|| format!("Block \"{block_name}\" not found."))?;
let handles = br.entity_handles.clone();
if handles.is_empty() {
return Err(format!("Block \"{block_name}\" has no entities."));
}
let mut out = CadDocument::new();
// Copy layers referenced by the block entities.
for h in &handles {
if let Some(e) = src.get_entity(*h) {
let layer = e.common().layer.clone();
if !layer.is_empty() && !layer.eq("0") && out.layers.get(&layer).is_none() {
if let Some(src_layer) = src.layers.get(&layer) {
let _ = out.layers.add(src_layer.clone());
}
}
}
}
for h in handles {
if let Some(entity) = src.get_entity(h) {
if matches!(entity, EntityType::Block(_) | EntityType::BlockEnd(_)) {
continue;
}
let mut clone = entity.clone();
clone.common_mut().handle = acadrust::types::Handle::NULL;
clone.common_mut().owner_handle = acadrust::types::Handle::NULL;
let _ = out.add_entity(clone);
}
}
if out.entities().count() == 0 {
return Err(format!("Block \"{block_name}\" produced no exportable entities."));
}
Ok(out)
}
/// Build a standalone `CadDocument` from an explicit list of entity handles
/// (the "selected entities" mode, `*`).
pub fn extract_entities_to_doc(
src: &CadDocument,
handles: &[acadrust::Handle],
) -> Result<CadDocument, String> {
if handles.is_empty() {
return Err("No entities selected for WBLOCK.".into());
}
let mut out = CadDocument::new();
for &h in handles {
if let Some(entity) = src.get_entity(h) {
if matches!(entity, EntityType::Block(_) | EntityType::BlockEnd(_)) {
continue;
}
// Copy layer definition.
let layer = entity.common().layer.clone();
if !layer.is_empty() && !layer.eq("0") && out.layers.get(&layer).is_none() {
if let Some(src_layer) = src.layers.get(&layer) {
let _ = out.layers.add(src_layer.clone());
}
}
let mut clone = entity.clone();
clone.common_mut().handle = acadrust::types::Handle::NULL;
clone.common_mut().owner_handle = acadrust::types::Handle::NULL;
let _ = out.add_entity(clone);
}
}
if out.entities().count() == 0 {
return Err("None of the selected entities could be exported.".into());
}
Ok(out)
}