forked from 1b-agent/opencadstudio-upstream
Merge pull request #1793 from ramox81/codex/block-definition-command-line
Block Definition: command-line forms, block record data and dialog defaults Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
838e397a6c
23 files changed
+1860
-435
No files matched your search
@@ -629,14 +629,7 @@ impl OpenCADStudio {
|
||||
self.block_palette.source_tab_id = Some(self.tabs[i].id);
|
||||
self.block_palette.source_block_epoch = self.tabs[i].scene.block_epoch;
|
||||
let doc = &self.tabs[i].scene.document;
|
||||
let annotative = |name: &str| {
|
||||
doc.block_records.get(name).is_some_and(|br| {
|
||||
matches!(
|
||||
doc.get_entity(br.block_entity_handle),
|
||||
Some(codec::EntityType::Block(b)) if b.common.extended_data.records().iter().any(|r| r.application_name == "AcadAnnotative")
|
||||
)
|
||||
})
|
||||
};
|
||||
let annotative = |name: &str| crate::scene::annotative::block_is_annotative(doc, name);
|
||||
let entries: Vec<BlockEntry> = names
|
||||
.into_iter()
|
||||
.map(|name| BlockEntry {
|
||||
|
||||
@@ -768,6 +768,8 @@ impl OpenCADStudio {
|
||||
|
||||
/// Snapshot the persisted UI preferences from live state.
|
||||
pub(in crate::app) fn current_settings(&self) -> crate::app::settings::UserSettings {
|
||||
// One copy: the guard must not be held across the literal below.
|
||||
let block_defaults = *crate::modules::insert::block_cmdline::defaults();
|
||||
crate::app::settings::UserSettings {
|
||||
spacemouse: self.spacemouse_preferences,
|
||||
dyn_input: self.dyn_input,
|
||||
@@ -795,6 +797,14 @@ impl OpenCADStudio {
|
||||
grip_object_limit: self.grip_object_limit,
|
||||
image_frame: crate::scene::frame::profile_image_mode(),
|
||||
attdef_on_screen: crate::modules::draw::draw::attdef::session().on_screen,
|
||||
block_base_on_screen: block_defaults.base_on_screen,
|
||||
block_objects_on_screen: block_defaults.objects_on_screen,
|
||||
block_object_mode: crate::modules::insert::block_cmdline::mode_code(block_defaults.mode),
|
||||
block_allow_exploding: block_defaults.allow_exploding,
|
||||
block_open_in_editor: block_defaults.open_in_editor,
|
||||
wblock_object_mode: crate::modules::insert::block_cmdline::mode_code(
|
||||
block_defaults.wblock_mode,
|
||||
),
|
||||
field_display: crate::entities::field::display(),
|
||||
xref_fade: crate::scene::cache::block_cache::xref_fade_ctl(),
|
||||
file_dia: crate::sys::file_dia(),
|
||||
@@ -920,6 +930,16 @@ impl OpenCADStudio {
|
||||
self.grip_object_limit = s.grip_object_limit.clamp(0, 32767);
|
||||
crate::scene::frame::set_profile_image_mode(s.image_frame);
|
||||
crate::modules::draw::draw::attdef::session().on_screen = s.attdef_on_screen;
|
||||
{
|
||||
use crate::modules::insert::block_cmdline as bc;
|
||||
let mut remembered = bc::defaults();
|
||||
remembered.base_on_screen = s.block_base_on_screen;
|
||||
remembered.objects_on_screen = s.block_objects_on_screen;
|
||||
remembered.mode = bc::mode_from_code(s.block_object_mode);
|
||||
remembered.allow_exploding = s.block_allow_exploding;
|
||||
remembered.open_in_editor = s.block_open_in_editor;
|
||||
remembered.wblock_mode = bc::mode_from_code(s.wblock_object_mode);
|
||||
}
|
||||
crate::entities::field::set_display(s.field_display);
|
||||
crate::scene::cache::block_cache::set_xref_fade_ctl(s.xref_fade);
|
||||
self.ribbon.xref_fade = crate::scene::cache::block_cache::xref_fade_ctl();
|
||||
@@ -2336,6 +2356,102 @@ impl OpenCADStudio {
|
||||
])
|
||||
}
|
||||
|
||||
/// Write `source` to `path` (WBLOCK and -WBLOCK): an existing block, the
|
||||
/// whole drawing, or objects, which then are kept, converted to a block
|
||||
/// named after the file, or deleted.
|
||||
pub(in crate::app) fn wblock_write(
|
||||
&mut self,
|
||||
i: usize,
|
||||
source: crate::modules::insert::block_cmdline::WblockSource,
|
||||
path: std::path::PathBuf,
|
||||
unit: i16,
|
||||
) -> Task<Message> {
|
||||
let mut path = path;
|
||||
if path.extension().is_none() {
|
||||
path.set_extension("dwg");
|
||||
}
|
||||
let document = self.tabs[i].scene.document_for_save();
|
||||
if let crate::modules::insert::block_cmdline::WblockSource::Objects {
|
||||
handles,
|
||||
base,
|
||||
mode,
|
||||
} = &source
|
||||
{
|
||||
match mode {
|
||||
crate::ui::window::block_definition::BlockObjectMode::Retain => {}
|
||||
crate::ui::window::block_definition::BlockObjectMode::Delete => {
|
||||
self.push_undo_snapshot(i, "WBLOCK");
|
||||
self.tabs[i].scene.erase_entities(handles);
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
self.refresh_properties();
|
||||
}
|
||||
crate::ui::window::block_definition::BlockObjectMode::Convert => {
|
||||
let name = path
|
||||
.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("WBLOCK")
|
||||
.to_string();
|
||||
self.push_undo_snapshot(i, "WBLOCK");
|
||||
let ucs = self.tabs[i].ucs_xform();
|
||||
let options = crate::scene::CreateBlockOptions {
|
||||
name,
|
||||
handles: handles.clone(),
|
||||
base_point: *base,
|
||||
world_to_block: ucs.to_ucs_transform_at(*base),
|
||||
block_to_world: ucs.to_wcs_transform_at(*base),
|
||||
mode: crate::ui::window::block_definition::BlockObjectMode::Convert,
|
||||
annotative: false,
|
||||
match_orientation: false,
|
||||
scale_uniformly: false,
|
||||
allow_exploding: true,
|
||||
unit,
|
||||
description: String::new(),
|
||||
hyperlink_url: String::new(),
|
||||
hyperlink_desc: String::new(),
|
||||
redefine: true,
|
||||
};
|
||||
let _ = self.tabs[i].scene.create_block_with_options(options);
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
self.refresh_properties();
|
||||
}
|
||||
}
|
||||
}
|
||||
let display = match &source {
|
||||
crate::modules::insert::block_cmdline::WblockSource::Block(name) => name.clone(),
|
||||
_ => "*".to_string(),
|
||||
};
|
||||
let worker_path = path.clone();
|
||||
background_task(
|
||||
crate::t!("WBLOCK save"),
|
||||
move || {
|
||||
let out_doc = match source {
|
||||
crate::modules::insert::block_cmdline::WblockSource::Block(name) => {
|
||||
let mut d =
|
||||
crate::modules::insert::wblock::extract_block_to_doc(&document, &name)
|
||||
.map_err(|e| e.to_string())?;
|
||||
d.header.insertion_units = unit;
|
||||
d
|
||||
}
|
||||
crate::modules::insert::block_cmdline::WblockSource::Drawing => {
|
||||
let mut d = document.clone();
|
||||
d.header.insertion_units = unit;
|
||||
d
|
||||
}
|
||||
crate::modules::insert::block_cmdline::WblockSource::Objects { handles, base, .. } => {
|
||||
crate::modules::insert::wblock::extract_entities_to_doc_with_base(
|
||||
&document, &handles, base, unit,
|
||||
)
|
||||
.map_err(|e| e.to_string())?
|
||||
}
|
||||
};
|
||||
crate::io::save(&out_doc, &worker_path).map_err(|e| e.to_string())
|
||||
},
|
||||
move |result| Message::WblockWriteFinished(display, path, result),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn on_wblock_save_result_some(
|
||||
&mut self,
|
||||
block_name: String,
|
||||
|
||||
+37
-100
@@ -1837,10 +1837,15 @@ impl OpenCADStudio {
|
||||
|
||||
Message::WblockSave(block_name) => {
|
||||
let name = block_name.clone();
|
||||
let title = if block_name == "-" {
|
||||
crate::t!("Create Drawing File").into_owned()
|
||||
} else {
|
||||
crate::t!("Save Block As").into_owned()
|
||||
};
|
||||
Task::perform(
|
||||
async move {
|
||||
let path = crate::sys::file_dialog()
|
||||
.set_title(crate::t!("Save Block As").as_ref())
|
||||
.set_title(&title)
|
||||
.set_file_name("block.dwg")
|
||||
.add_filter(crate::t!("DWG Files").as_ref(), &["dwg"])
|
||||
.save_file()
|
||||
@@ -1852,6 +1857,10 @@ impl OpenCADStudio {
|
||||
)
|
||||
}
|
||||
|
||||
// -WBLOCK with FILEDIA 1: the file came from the dialog, the
|
||||
// command line asks for the rest.
|
||||
Message::WblockSaveResult(block_name, Some(path)) if block_name == "-" => self
|
||||
.dispatch_command(&format!("_-WBLOCKFILE {}", path.display())),
|
||||
Message::WblockSaveResult(block_name, Some(path)) => {
|
||||
self.on_wblock_save_result_some(block_name, path)
|
||||
}
|
||||
@@ -1859,14 +1868,12 @@ impl OpenCADStudio {
|
||||
Message::WblockSaveResult(_, None) => Task::none(),
|
||||
|
||||
Message::WblockWriteFinished(block_name, path, result) => {
|
||||
match result {
|
||||
Ok(()) => self.command_line.push_output(
|
||||
crate::tf!("WBLOCK Saved \"{block_name}\" → \"{}\"", path.display())
|
||||
.as_ref(),
|
||||
),
|
||||
Err(error) => self
|
||||
.command_line
|
||||
.push_error(crate::tf!("WBLOCK save failed: {error}").as_ref()),
|
||||
// A written file is not reported (as in the reference); a
|
||||
// failed write is.
|
||||
let _ = (&block_name, &path);
|
||||
if let Err(error) = result {
|
||||
self.command_line
|
||||
.push_error(crate::tf!("WBLOCK save failed: {error}").as_ref());
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
@@ -5820,13 +5827,14 @@ impl OpenCADStudio {
|
||||
};
|
||||
let name = state.name.trim().to_string();
|
||||
if name.is_empty() {
|
||||
state.error_message =
|
||||
Some(crate::t!("Block name cannot be empty.").into_owned());
|
||||
state.error_message = Some(
|
||||
crate::t!("The name must be at least one character long.").into_owned(),
|
||||
);
|
||||
return Task::none();
|
||||
}
|
||||
if let Some(_ch) = state.invalid_name_char() {
|
||||
state.error_message = Some(
|
||||
crate::t!("Block name cannot contain: \\ / : * ? \" < > | = `")
|
||||
crate::t!("The name contains unsupported characters. The following characters are not supported: \\ < > / ? \" : ; * | , = `")
|
||||
.into_owned(),
|
||||
);
|
||||
return Task::none();
|
||||
@@ -6064,96 +6072,25 @@ impl OpenCADStudio {
|
||||
|
||||
let state = self.wblock.take().unwrap();
|
||||
self.active_modal = None;
|
||||
let document = self.tabs[i].scene.document_for_save();
|
||||
let source_mode = state.source_mode;
|
||||
let block_name = state.block_name.trim().to_string();
|
||||
let handles = state.selected_handles.clone();
|
||||
let base_point = state.parse_base_point();
|
||||
let unit = state.unit;
|
||||
let object_mode = state.object_mode;
|
||||
|
||||
if source_mode == WblockSourceMode::Objects {
|
||||
match object_mode {
|
||||
WblockObjectMode::Retain => {}
|
||||
WblockObjectMode::Delete => {
|
||||
self.push_undo_snapshot(i, "WBLOCK");
|
||||
self.tabs[i].scene.erase_entities(&handles);
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
self.refresh_properties();
|
||||
}
|
||||
WblockObjectMode::Convert => {
|
||||
let block_name_for_conv = path
|
||||
.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or("WBLOCK")
|
||||
.to_string();
|
||||
self.push_undo_snapshot(i, "WBLOCK");
|
||||
let ucs = self.tabs[i].ucs_xform();
|
||||
let world_to_block = ucs.to_ucs_transform_at(base_point);
|
||||
let block_to_world = ucs.to_wcs_transform_at(base_point);
|
||||
let options = crate::scene::CreateBlockOptions {
|
||||
name: block_name_for_conv,
|
||||
handles: handles.clone(),
|
||||
base_point,
|
||||
world_to_block,
|
||||
block_to_world,
|
||||
mode: crate::ui::window::block_definition::BlockObjectMode::Convert,
|
||||
annotative: false,
|
||||
match_orientation: false,
|
||||
scale_uniformly: false,
|
||||
allow_exploding: true,
|
||||
unit,
|
||||
description: String::new(),
|
||||
hyperlink_url: String::new(),
|
||||
hyperlink_desc: String::new(),
|
||||
redefine: true,
|
||||
};
|
||||
let _ = self.tabs[i].scene.create_block_with_options(options);
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
self.refresh_properties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let worker_path = path.clone();
|
||||
let display_name = match source_mode {
|
||||
WblockSourceMode::Block => block_name.clone(),
|
||||
WblockSourceMode::EntireDrawing => "*".to_string(),
|
||||
WblockSourceMode::Objects => "*".to_string(),
|
||||
use crate::modules::insert::block_cmdline::WblockSource;
|
||||
use crate::ui::window::block_definition::BlockObjectMode;
|
||||
let mode = match state.object_mode {
|
||||
WblockObjectMode::Retain => BlockObjectMode::Retain,
|
||||
WblockObjectMode::Convert => BlockObjectMode::Convert,
|
||||
WblockObjectMode::Delete => BlockObjectMode::Delete,
|
||||
};
|
||||
let worker_display = display_name.clone();
|
||||
|
||||
file::background_task(
|
||||
crate::t!("WBLOCK save"),
|
||||
move || {
|
||||
let out_doc = match source_mode {
|
||||
WblockSourceMode::Block => {
|
||||
let mut d = crate::modules::insert::wblock::extract_block_to_doc(
|
||||
&document,
|
||||
&block_name,
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
d.header.insertion_units = unit;
|
||||
d
|
||||
}
|
||||
WblockSourceMode::EntireDrawing => {
|
||||
let mut d = document.clone();
|
||||
d.header.insertion_units = unit;
|
||||
d
|
||||
}
|
||||
WblockSourceMode::Objects => {
|
||||
crate::modules::insert::wblock::extract_entities_to_doc_with_base(
|
||||
&document, &handles, base_point, unit,
|
||||
)
|
||||
.map_err(|e| e.to_string())?
|
||||
}
|
||||
};
|
||||
crate::io::save(&out_doc, &worker_path).map_err(|e| e.to_string())
|
||||
crate::modules::insert::block_cmdline::defaults().wblock_mode = mode;
|
||||
self.persist_settings_if_changed();
|
||||
let source = match state.source_mode {
|
||||
WblockSourceMode::Block => WblockSource::Block(state.block_name.trim().to_string()),
|
||||
WblockSourceMode::EntireDrawing => WblockSource::Drawing,
|
||||
WblockSourceMode::Objects => WblockSource::Objects {
|
||||
handles: state.selected_handles.clone(),
|
||||
base: state.parse_base_point(),
|
||||
mode,
|
||||
},
|
||||
move |result| Message::WblockWriteFinished(worker_display, path, result),
|
||||
)
|
||||
};
|
||||
self.wblock_write(i, source, path, state.unit)
|
||||
}
|
||||
Message::ToleranceDialogField(field) => {
|
||||
if let Some(state) = self.geometric_tolerance.as_mut() {
|
||||
|
||||
Reference in new issue
Block a user