forked from 1b-agent/opencadstudio-upstream
Merge remote-tracking branch 'origin/main' into codex/block-definition-command-line
# Conflicts: # src/app/commands/inquiry.rs # src/modules/draw/modify/block_edit.rs
This commit is contained in:
commit
99e30f1548
33 files changed
+1660
-199
No files matched your search
@@ -38,7 +38,7 @@ impl OpenCADStudio {
|
||||
let mut saved = 0usize;
|
||||
let mut skipped = 0usize;
|
||||
for t in 0..self.tabs.len() {
|
||||
if self.tabs[t].is_start {
|
||||
if self.tabs[t].is_start || self.tabs[t].block_test.is_some() {
|
||||
continue;
|
||||
}
|
||||
if let Some(path) = self.tabs[t].current_path.clone() {
|
||||
|
||||
+121
-106
@@ -458,7 +458,6 @@ impl OpenCADStudio {
|
||||
}
|
||||
|
||||
"BEDIT" => {
|
||||
use crate::modules::draw::modify::block_edit::BlockEditPickCommand;
|
||||
if self.tabs[i].refedit_session.is_some() {
|
||||
self.command_line.push_error(
|
||||
crate::t!("BEDIT: finish the active REFEDIT (REFCLOSE) first.").as_ref(),
|
||||
@@ -476,12 +475,46 @@ impl OpenCADStudio {
|
||||
return Some(Task::none());
|
||||
}
|
||||
}
|
||||
let cmd_obj = BlockEditPickCommand::new();
|
||||
self.command_line.push_info(&cmd_obj.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(cmd_obj));
|
||||
self.open_bedit_dialog(i);
|
||||
}
|
||||
}
|
||||
|
||||
cmd if cmd.starts_with("BEDIT_NEW:") => {
|
||||
if self.tabs[i].refedit_session.is_some() {
|
||||
self.command_line.push_error(
|
||||
crate::t!("BEDIT: finish the active REFEDIT (REFCLOSE) first.").as_ref(),
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
let raw_name = &cmd["BEDIT_NEW:".len()..];
|
||||
let block_name = match crate::scene::block_service::validate_block_name(raw_name) {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
self.command_line.push_error(&e.to_string());
|
||||
return Some(Task::none());
|
||||
}
|
||||
};
|
||||
if let Some(br) = self.tabs[i].scene.document.block_records.get(&block_name) {
|
||||
let real_name = br.name.clone();
|
||||
return Some(self.dispatch_command(&format!("BEDIT_OPEN:{real_name}")));
|
||||
}
|
||||
if self.tabs[i].active_block_edit_session().is_some() {
|
||||
return Some(self.request_block_edit_close(
|
||||
i,
|
||||
crate::app::block_editor::BlockEditContinuation::Create(block_name),
|
||||
));
|
||||
}
|
||||
let pre_doc = self.tabs[i].scene.document.clone();
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.define_block_raw(&block_name, codec::types::Vector3::ZERO, vec![]);
|
||||
let Some(record) = self.tabs[i].scene.document.block_records.get(&block_name) else {
|
||||
return Some(Task::none());
|
||||
};
|
||||
let br_handle = record.handle;
|
||||
self.start_block_edit_session(i, block_name, br_handle, Some(pre_doc));
|
||||
}
|
||||
|
||||
cmd if cmd.starts_with("BEDIT_BEGIN:") || cmd.starts_with("BEDIT_OPEN:") => {
|
||||
if self.tabs[i].refedit_session.is_some() {
|
||||
self.command_line.push_error(
|
||||
@@ -489,7 +522,6 @@ impl OpenCADStudio {
|
||||
);
|
||||
return Some(Task::none());
|
||||
}
|
||||
use crate::modules::draw::modify::block_edit::BlockEditSession;
|
||||
use codec::Handle;
|
||||
|
||||
let block_name = if let Some(name) = cmd.strip_prefix("BEDIT_OPEN:") {
|
||||
@@ -512,36 +544,6 @@ impl OpenCADStudio {
|
||||
}
|
||||
};
|
||||
|
||||
// A name that is not a block yet opens an empty definition,
|
||||
// dropped again when the editor closes without saving.
|
||||
let mut created_for_edit = false;
|
||||
if self.tabs[i].scene.document.block_records.get(&block_name).is_none()
|
||||
&& cmd.starts_with("BEDIT_OPEN:")
|
||||
&& crate::ui::window::block_definition::invalid_block_name_char(&block_name)
|
||||
.is_none()
|
||||
&& !block_name.trim().is_empty()
|
||||
&& !block_name.starts_with('*')
|
||||
{
|
||||
let options = crate::scene::CreateBlockOptions {
|
||||
name: block_name.clone(),
|
||||
handles: Vec::new(),
|
||||
base_point: glam::DVec3::ZERO,
|
||||
world_to_block: codec::types::Transform::identity(),
|
||||
block_to_world: codec::types::Transform::identity(),
|
||||
mode: crate::ui::window::block_definition::BlockObjectMode::Retain,
|
||||
annotative: false,
|
||||
match_orientation: false,
|
||||
scale_uniformly: false,
|
||||
allow_exploding: true,
|
||||
unit: self.tabs[i].scene.document.header.insertion_units,
|
||||
description: String::new(),
|
||||
hyperlink_url: String::new(),
|
||||
hyperlink_desc: String::new(),
|
||||
redefine: false,
|
||||
};
|
||||
created_for_edit =
|
||||
self.tabs[i].scene.create_block_with_options(options).is_ok();
|
||||
}
|
||||
// Resolve the block record; reject external references (xrefs).
|
||||
let (br_handle, is_xref) =
|
||||
match self.tabs[i].scene.document.block_records.get(&block_name) {
|
||||
@@ -569,82 +571,14 @@ impl OpenCADStudio {
|
||||
));
|
||||
}
|
||||
|
||||
// Capture the camera before the editor reframes it, so leaving
|
||||
// the block editor returns the view exactly where it was (#425).
|
||||
let current_camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
let current_ucs = self.tabs[i].active_ucs.clone();
|
||||
let (return_layout, return_block, return_camera) =
|
||||
if let Some(parent_index) = self.tabs[i].active_block_edit {
|
||||
let parent = &mut self.tabs[i].block_edits[parent_index];
|
||||
parent.editor_camera = current_camera.clone();
|
||||
parent.editor_ucs = current_ucs;
|
||||
(
|
||||
parent.return_layout.clone(),
|
||||
Some(parent.block_name.clone()),
|
||||
parent.return_camera.clone(),
|
||||
)
|
||||
} else {
|
||||
self.tabs[i].scene.sync_camera_to_document();
|
||||
(
|
||||
self.tabs[i].scene.current_layout.clone(),
|
||||
None,
|
||||
current_camera.clone(),
|
||||
)
|
||||
};
|
||||
// A block editor renders in model style; switch to Model first so
|
||||
// the paper-space code paths stay off, then scope to the block.
|
||||
if self.tabs[i].scene.current_layout != "Model" {
|
||||
self.tabs[i].scene.set_current_layout("Model".to_string());
|
||||
}
|
||||
self.tabs[i].scene.block_edit_block = Some(br_handle);
|
||||
self.tabs[i].block_edits.push(BlockEditSession {
|
||||
block_name: block_name.clone(),
|
||||
br_handle,
|
||||
return_layout,
|
||||
return_block,
|
||||
return_camera,
|
||||
editor_camera: current_camera,
|
||||
editor_ucs: None,
|
||||
created_for_edit,
|
||||
});
|
||||
self.tabs[i].active_block_edit = Some(self.tabs[i].block_edits.len() - 1);
|
||||
// Every BEDIT tab owns an isolated local UCS. Never inherit or
|
||||
// overwrite the drawing's model-space UCS.
|
||||
self.tabs[i].refresh_active_ucs();
|
||||
|
||||
self.tabs[i].scene.deselect_all();
|
||||
// The first click of a double-click selects the model-space
|
||||
// INSERT and populates the cached grip overlay. Clearing only
|
||||
// Scene::selected leaves that INSERT's grips active inside the
|
||||
// block editor, where dragging one moves the outer reference
|
||||
// instead of block-local geometry (#517).
|
||||
self.tabs[i].active_grip = None;
|
||||
self.grip_hover = None;
|
||||
self.grip_popup = None;
|
||||
self.visibility_popup = None;
|
||||
// Entering BEDIT changes which block is assembled, not the
|
||||
// cached geometry of that block's entities.
|
||||
self.tabs[i].scene.bump_geometry_no_blocks();
|
||||
// Frame the camera on the block's own geometry (block-local, near
|
||||
// origin) — fit_all() goes through current_layout_block_handle so
|
||||
// it already scopes to the edited block. Without this the view
|
||||
// stays wherever model/paper space was. (#261)
|
||||
self.tabs[i].scene.fit_all();
|
||||
let editor_camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
if let Some(session) = self.tabs[i].active_block_edit_session_mut() {
|
||||
session.editor_camera = editor_camera;
|
||||
}
|
||||
self.tabs[i].last_synced_camera_gen = self.tabs[i].scene.camera_generation;
|
||||
self.refresh_properties();
|
||||
self.tabs[i].active_cmd = None;
|
||||
self.begin_block_edit_history(i);
|
||||
self.command_line
|
||||
.push_info(crate::tf!("Block Editor: editing {}", block_name).as_ref());
|
||||
self.start_block_edit_session(i, block_name, br_handle, None);
|
||||
}
|
||||
|
||||
"BSAVE" => {
|
||||
self.save_block_edit(i);
|
||||
}
|
||||
"BTESTBLOCK" => return Some(self.open_block_test(i)),
|
||||
"BCLOSETESTBLOCK" => return Some(self.close_block_test(i)),
|
||||
"BSAVEAS" => {
|
||||
self.open_block_save_as_dialog(i);
|
||||
}
|
||||
@@ -1056,6 +990,87 @@ impl OpenCADStudio {
|
||||
Some(self.finish_dispatch(cmd))
|
||||
}
|
||||
|
||||
pub(in crate::app) fn start_block_edit_session(
|
||||
&mut self,
|
||||
i: usize,
|
||||
block_name: String,
|
||||
br_handle: codec::Handle,
|
||||
unpersisted_pre_document: Option<codec::CadDocument>,
|
||||
) {
|
||||
use crate::modules::draw::modify::block_edit::BlockEditSession;
|
||||
// Capture the camera before the editor reframes it, so leaving
|
||||
// the block editor returns the view exactly where it was (#425).
|
||||
let current_camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
let current_ucs = self.tabs[i].active_ucs.clone();
|
||||
let (return_layout, return_block, return_camera) =
|
||||
if let Some(parent_index) = self.tabs[i].active_block_edit {
|
||||
let parent = &mut self.tabs[i].block_edits[parent_index];
|
||||
parent.editor_camera = current_camera.clone();
|
||||
parent.editor_ucs = current_ucs;
|
||||
(
|
||||
parent.return_layout.clone(),
|
||||
Some(parent.block_name.clone()),
|
||||
parent.return_camera.clone(),
|
||||
)
|
||||
} else {
|
||||
self.tabs[i].scene.sync_camera_to_document();
|
||||
(
|
||||
self.tabs[i].scene.current_layout.clone(),
|
||||
None,
|
||||
current_camera.clone(),
|
||||
)
|
||||
};
|
||||
// A block editor renders in model style; switch to Model first so
|
||||
// the paper-space code paths stay off, then scope to the block.
|
||||
if self.tabs[i].scene.current_layout != "Model" {
|
||||
self.tabs[i].scene.set_current_layout("Model".to_string());
|
||||
}
|
||||
self.tabs[i].scene.block_edit_block = Some(br_handle);
|
||||
self.tabs[i].block_edits.push(BlockEditSession {
|
||||
block_name: block_name.clone(),
|
||||
br_handle,
|
||||
return_layout,
|
||||
return_block,
|
||||
return_camera,
|
||||
editor_camera: current_camera,
|
||||
editor_ucs: None,
|
||||
unpersisted_pre_document,
|
||||
});
|
||||
self.tabs[i].active_block_edit = Some(self.tabs[i].block_edits.len() - 1);
|
||||
// Every BEDIT tab owns an isolated local UCS. Never inherit or
|
||||
// overwrite the drawing's model-space UCS.
|
||||
self.tabs[i].refresh_active_ucs();
|
||||
|
||||
self.tabs[i].scene.deselect_all();
|
||||
// The first click of a double-click selects the model-space
|
||||
// INSERT and populates the cached grip overlay. Clearing only
|
||||
// Scene::selected leaves that INSERT's grips active inside the
|
||||
// block editor, where dragging one moves the outer reference
|
||||
// instead of block-local geometry (#517).
|
||||
self.tabs[i].active_grip = None;
|
||||
self.grip_hover = None;
|
||||
self.grip_popup = None;
|
||||
self.visibility_popup = None;
|
||||
// Entering BEDIT changes which block is assembled, not the
|
||||
// cached geometry of that block's entities.
|
||||
self.tabs[i].scene.bump_geometry_no_blocks();
|
||||
// Frame the camera on the block's own geometry (block-local, near
|
||||
// origin) — fit_all() goes through current_layout_block_handle so
|
||||
// it already scopes to the edited block. Without this the view
|
||||
// stays wherever model/paper space was. (#261)
|
||||
self.tabs[i].scene.fit_all();
|
||||
let editor_camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
if let Some(session) = self.tabs[i].active_block_edit_session_mut() {
|
||||
session.editor_camera = editor_camera;
|
||||
}
|
||||
self.tabs[i].last_synced_camera_gen = self.tabs[i].scene.camera_generation;
|
||||
self.refresh_properties();
|
||||
self.tabs[i].active_cmd = None;
|
||||
self.begin_block_edit_history(i);
|
||||
self.command_line
|
||||
.push_info(crate::tf!("Block Editor: editing {}", block_name).as_ref());
|
||||
}
|
||||
|
||||
pub(in crate::app) fn restore_after_block_edit_close(
|
||||
&mut self,
|
||||
i: usize,
|
||||
|
||||
@@ -150,6 +150,33 @@ impl OpenCADStudio {
|
||||
};
|
||||
let resolved = self.resolve_alias(cmd);
|
||||
let cmd = resolved.as_deref().unwrap_or(cmd);
|
||||
if self.tabs[i].block_test.is_some() {
|
||||
let name = cmd.split([' ', ':']).next().unwrap_or(cmd);
|
||||
if matches!(
|
||||
name,
|
||||
"BEDIT"
|
||||
| "BEDIT_BEGIN"
|
||||
| "BEDIT_OPEN"
|
||||
| "REFEDIT"
|
||||
| "REFEDIT_BEGIN"
|
||||
| "BSAVE"
|
||||
| "BSAVEAS"
|
||||
| "SAVE"
|
||||
| "QSAVE"
|
||||
| "SAVEAS"
|
||||
| "SAVEALL"
|
||||
| "WBLOCK"
|
||||
| "EXPORT"
|
||||
| "ETRANSMIT"
|
||||
| "ARCHIVE"
|
||||
) {
|
||||
self.command_line.push_error(
|
||||
crate::t!("Close Test Block before saving or opening another block editor.")
|
||||
.as_ref(),
|
||||
);
|
||||
return Task::none();
|
||||
}
|
||||
}
|
||||
if is_spacemouse_command(cmd) {
|
||||
return self.run_action(cmd);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user