parent
00cc17ea55
commit
d77eb8f419
8 changed files with 296 additions and 79 deletions
|
|
@ -335,11 +335,7 @@ impl OpenCADStudio {
|
|||
|
||||
"BEDIT" => {
|
||||
use crate::modules::draw::modify::block_edit::BlockEditPickCommand;
|
||||
if self.tabs[i].block_edit.is_some() {
|
||||
self.command_line.push_error(
|
||||
"BEDIT: a block editor is already open. Save or discard it first.",
|
||||
);
|
||||
} else if self.tabs[i].refedit_session.is_some() {
|
||||
if self.tabs[i].refedit_session.is_some() {
|
||||
self.command_line
|
||||
.push_error("BEDIT: finish the active REFEDIT (REFCLOSE) first.");
|
||||
} else {
|
||||
|
|
@ -399,6 +395,16 @@ impl OpenCADStudio {
|
|||
.push_error("BEDIT: cannot edit an external reference (xref).");
|
||||
return Some(Task::none());
|
||||
}
|
||||
if self.tabs[i]
|
||||
.block_edits
|
||||
.iter()
|
||||
.any(|session| session.br_handle == br_handle)
|
||||
{
|
||||
self.tabs[i].active_cmd = None;
|
||||
return Some(Task::done(Message::BlockEditSwitch(
|
||||
insert.block_name.clone(),
|
||||
)));
|
||||
}
|
||||
|
||||
// Snapshot the block's block-local entities so Discard can restore
|
||||
// them (skip structural Block/BlockEnd/AttDef, mirroring REFEDIT).
|
||||
|
|
@ -425,23 +431,42 @@ impl OpenCADStudio {
|
|||
|
||||
self.push_undo_snapshot(i, "BEDIT");
|
||||
|
||||
let return_layout = self.tabs[i].scene.current_layout.clone();
|
||||
// Capture the camera before the editor reframes it, so leaving
|
||||
// the block editor returns the view exactly where it was (#425).
|
||||
let return_camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
let current_camera = self.tabs[i].scene.camera.borrow().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.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 return_layout != "Model" {
|
||||
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_edit = Some(BlockEditSession {
|
||||
self.tabs[i].block_edits.push(BlockEditSession {
|
||||
block_name: insert.block_name.clone(),
|
||||
br_handle,
|
||||
return_layout,
|
||||
return_block,
|
||||
snapshot,
|
||||
return_camera,
|
||||
editor_camera: current_camera,
|
||||
});
|
||||
self.tabs[i].active_block_edit = Some(self.tabs[i].block_edits.len() - 1);
|
||||
|
||||
self.tabs[i].scene.deselect_all();
|
||||
// The first click of a double-click selects the model-space
|
||||
|
|
@ -461,6 +486,11 @@ impl OpenCADStudio {
|
|||
// 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.tabs[i].dirty = true;
|
||||
|
|
@ -471,27 +501,28 @@ impl OpenCADStudio {
|
|||
}
|
||||
|
||||
"BEDIT_SAVE" => {
|
||||
let session = match self.tabs[i].block_edit.take() {
|
||||
Some(s) => s,
|
||||
let session = match self.tabs[i].active_block_edit.take() {
|
||||
Some(index) if index < self.tabs[i].block_edits.len() => {
|
||||
self.tabs[i].block_edits.remove(index)
|
||||
}
|
||||
None => {
|
||||
self.command_line
|
||||
.push_error("BEDIT_SAVE: no block editor is open.");
|
||||
return Some(Task::none());
|
||||
}
|
||||
Some(_) => {
|
||||
self.command_line
|
||||
.push_error("BEDIT_SAVE: invalid block editor state.");
|
||||
return Some(Task::none());
|
||||
}
|
||||
};
|
||||
// Edits are live on the block record — just leave the block space.
|
||||
self.tabs[i].scene.block_edit_block = None;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].active_grip = None;
|
||||
self.grip_hover = None;
|
||||
self.grip_popup = None;
|
||||
self.visibility_popup = None;
|
||||
self.tabs[i].scene.set_current_layout(session.return_layout.clone());
|
||||
// Return the view to where it was when BEDIT began (#425).
|
||||
*self.tabs[i].scene.camera.borrow_mut() = session.return_camera.clone();
|
||||
self.tabs[i].scene.camera_generation += 1;
|
||||
self.tabs[i].scene.rebuild_derived_caches();
|
||||
self.refresh_properties();
|
||||
self.restore_after_block_edit_close(
|
||||
i,
|
||||
session.return_block.as_deref(),
|
||||
&session.return_layout,
|
||||
&session.return_camera,
|
||||
);
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(&format!(
|
||||
"BEDIT: Block \"{}\" saved. All references updated.",
|
||||
|
|
@ -500,13 +531,20 @@ impl OpenCADStudio {
|
|||
}
|
||||
|
||||
"BEDIT_DISCARD" => {
|
||||
let session = match self.tabs[i].block_edit.take() {
|
||||
Some(s) => s,
|
||||
let session = match self.tabs[i].active_block_edit.take() {
|
||||
Some(index) if index < self.tabs[i].block_edits.len() => {
|
||||
self.tabs[i].block_edits.remove(index)
|
||||
}
|
||||
None => {
|
||||
self.command_line
|
||||
.push_error("BEDIT_DISCARD: no block editor is open.");
|
||||
return Some(Task::none());
|
||||
}
|
||||
Some(_) => {
|
||||
self.command_line
|
||||
.push_error("BEDIT_DISCARD: invalid block editor state.");
|
||||
return Some(Task::none());
|
||||
}
|
||||
};
|
||||
// Restore the block definition to its on-entry snapshot: remove the
|
||||
// block's current entities, then re-add the snapshot ones (mirrors
|
||||
|
|
@ -531,27 +569,25 @@ impl OpenCADStudio {
|
|||
{
|
||||
br.entity_handles.clear();
|
||||
}
|
||||
let block_name = session.block_name.clone();
|
||||
let return_block = session.return_block.clone();
|
||||
let return_layout = session.return_layout.clone();
|
||||
let return_camera = session.return_camera.clone();
|
||||
for mut entity in session.snapshot {
|
||||
entity.common_mut().handle = acadrust::Handle::NULL;
|
||||
entity.common_mut().owner_handle = session.br_handle;
|
||||
let _ = self.tabs[i].scene.document.add_entity(entity);
|
||||
}
|
||||
self.tabs[i].scene.block_edit_block = None;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].active_grip = None;
|
||||
self.grip_hover = None;
|
||||
self.grip_popup = None;
|
||||
self.visibility_popup = None;
|
||||
self.tabs[i].scene.set_current_layout(session.return_layout.clone());
|
||||
// Return the view to where it was when BEDIT began (#425).
|
||||
*self.tabs[i].scene.camera.borrow_mut() = session.return_camera.clone();
|
||||
self.tabs[i].scene.camera_generation += 1;
|
||||
self.tabs[i].scene.rebuild_derived_caches();
|
||||
self.refresh_properties();
|
||||
self.restore_after_block_edit_close(
|
||||
i,
|
||||
return_block.as_deref(),
|
||||
&return_layout,
|
||||
&return_camera,
|
||||
);
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line.push_output(&format!(
|
||||
"BEDIT: Block \"{}\" edit discarded.",
|
||||
session.block_name
|
||||
block_name
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -1150,6 +1186,60 @@ impl OpenCADStudio {
|
|||
Some(self.finish_dispatch(cmd))
|
||||
}
|
||||
|
||||
fn restore_after_block_edit_close(
|
||||
&mut self,
|
||||
i: usize,
|
||||
return_block: Option<&str>,
|
||||
return_layout: &str,
|
||||
return_camera: &crate::scene::view::camera::Camera,
|
||||
) {
|
||||
self.tabs[i].scene.block_edit_block = None;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].active_grip = None;
|
||||
self.grip_hover = None;
|
||||
self.grip_popup = None;
|
||||
self.visibility_popup = None;
|
||||
|
||||
let parent_index = return_block.and_then(|parent_name| {
|
||||
self.tabs[i]
|
||||
.block_edits
|
||||
.iter()
|
||||
.position(|candidate| candidate.block_name == parent_name)
|
||||
});
|
||||
if let Some(parent_index) = parent_index {
|
||||
let (br_handle, editor_camera) = {
|
||||
let parent = &self.tabs[i].block_edits[parent_index];
|
||||
(parent.br_handle, parent.editor_camera.clone())
|
||||
};
|
||||
self.tabs[i].scene.set_current_layout("Model".to_string());
|
||||
self.tabs[i].scene.block_edit_block = Some(br_handle);
|
||||
self.tabs[i].active_block_edit = Some(parent_index);
|
||||
*self.tabs[i].scene.camera.borrow_mut() = editor_camera;
|
||||
} else {
|
||||
let return_layout = if self.tabs[i]
|
||||
.scene
|
||||
.layout_names()
|
||||
.iter()
|
||||
.any(|name| name == return_layout)
|
||||
{
|
||||
return_layout.to_string()
|
||||
} else {
|
||||
"Model".to_string()
|
||||
};
|
||||
self.tabs[i].active_block_edit = None;
|
||||
self.tabs[i].scene.set_current_layout(return_layout);
|
||||
*self.tabs[i].scene.camera.borrow_mut() = return_camera.clone();
|
||||
}
|
||||
|
||||
self.tabs[i].scene.camera_generation += 1;
|
||||
self.tabs[i].last_synced_camera_gen = self.tabs[i].scene.camera_generation;
|
||||
self.tabs[i].scene.rebuild_derived_caches();
|
||||
self.tabs[i].refresh_active_ucs();
|
||||
self.refresh_properties();
|
||||
self.adopt_view_display(i);
|
||||
self.sync_dyn_fields();
|
||||
}
|
||||
|
||||
/// ADDSELECTED — start the draw command that creates the same kind of
|
||||
/// object as the currently-selected one, adopting its general properties
|
||||
/// (layer, colour, linetype, lineweight, linetype scale) as the current
|
||||
|
|
|
|||
|
|
@ -231,8 +231,11 @@ pub(super) struct DocumentTab {
|
|||
pub(super) paper_bg_color: Option<[f32; 4]>,
|
||||
/// Active REFEDIT session, if any.
|
||||
pub(super) refedit_session: Option<RefEditSession>,
|
||||
/// Active BEDIT block-editor space session, if any (issue #261).
|
||||
pub(super) block_edit: Option<BlockEditSession>,
|
||||
/// Open BEDIT block tabs. Definitions are edited live; each tab owns its
|
||||
/// entry snapshot and camera so nested blocks can remain open independently.
|
||||
pub(super) block_edits: Vec<BlockEditSession>,
|
||||
/// Index of the block tab currently shown, or `None` for Model/Paper space.
|
||||
pub(super) active_block_edit: Option<usize>,
|
||||
/// Currently active MLeader style name.
|
||||
pub(super) active_mleader_style: String,
|
||||
/// Last camera_generation value written back to the document.
|
||||
|
|
@ -258,6 +261,16 @@ pub(super) struct DocumentTab {
|
|||
}
|
||||
|
||||
impl DocumentTab {
|
||||
pub(super) fn active_block_edit_session(&self) -> Option<&BlockEditSession> {
|
||||
self.active_block_edit
|
||||
.and_then(|index| self.block_edits.get(index))
|
||||
}
|
||||
|
||||
pub(super) fn active_block_edit_session_mut(&mut self) -> Option<&mut BlockEditSession> {
|
||||
self.active_block_edit
|
||||
.and_then(|index| self.block_edits.get_mut(index))
|
||||
}
|
||||
|
||||
/// The active WCS↔UCS converter for this tab — identity when no UCS is set.
|
||||
/// Every consumer that needs UCS-relative coordinates goes through this.
|
||||
pub(super) fn ucs_xform(&self) -> super::helpers::UcsXform {
|
||||
|
|
@ -478,7 +491,8 @@ impl DocumentTab {
|
|||
bg_color: None,
|
||||
paper_bg_color: None,
|
||||
refedit_session: None,
|
||||
block_edit: None,
|
||||
block_edits: Vec::new(),
|
||||
active_block_edit: None,
|
||||
active_mleader_style: "Standard".to_string(),
|
||||
last_synced_camera_gen: 0,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
|
|
|||
|
|
@ -1957,6 +1957,8 @@ pub enum Message {
|
|||
PspaceCommand,
|
||||
/// Switch to a named layout ("Model" or paper space layout name).
|
||||
LayoutSwitch(String),
|
||||
/// Switch to an already-open BEDIT block tab.
|
||||
BlockEditSwitch(String),
|
||||
/// Move a paper layout before/after another paper layout.
|
||||
LayoutReorder {
|
||||
from: String,
|
||||
|
|
|
|||
|
|
@ -3358,6 +3358,11 @@ impl OpenCADStudio {
|
|||
self.on_layout_switch(name)
|
||||
}
|
||||
|
||||
Message::BlockEditSwitch(name) => {
|
||||
self.layout_list_open = false;
|
||||
self.on_block_edit_switch(name)
|
||||
}
|
||||
|
||||
Message::LayoutReorder { from, to, after } => {
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i].is_start {
|
||||
|
|
|
|||
|
|
@ -370,7 +370,12 @@ impl OpenCADStudio {
|
|||
let gen = self.tabs[i].scene.camera_generation;
|
||||
if gen != self.tabs[i].last_synced_camera_gen {
|
||||
self.tabs[i].last_synced_camera_gen = gen;
|
||||
if self.tabs[i].scene.sync_camera_to_document() {
|
||||
if self.tabs[i].active_block_edit.is_some() {
|
||||
let camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
if let Some(session) = self.tabs[i].active_block_edit_session_mut() {
|
||||
session.editor_camera = camera;
|
||||
}
|
||||
} else if self.tabs[i].scene.sync_camera_to_document() {
|
||||
self.tabs[i].dirty = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -3134,17 +3139,14 @@ impl OpenCADStudio {
|
|||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(AcadEntityType::Insert(ins)) if !ins.attributes.is_empty()
|
||||
);
|
||||
if insert_has_attrs {
|
||||
if insert_has_attrs && self.tabs[i].active_block_edit.is_none() {
|
||||
return Task::done(Message::AttrEditorOpen(handle));
|
||||
}
|
||||
let is_insert = matches!(
|
||||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(AcadEntityType::Insert(_))
|
||||
);
|
||||
if is_insert
|
||||
&& self.tabs[i].refedit_session.is_none()
|
||||
&& self.tabs[i].block_edit.is_none()
|
||||
{
|
||||
if is_insert && self.tabs[i].refedit_session.is_none() {
|
||||
return Task::done(Message::Command(format!(
|
||||
"BEDIT_BEGIN:{}",
|
||||
handle.value()
|
||||
|
|
@ -3679,6 +3681,59 @@ impl OpenCADStudio {
|
|||
self.on_layout_switch_inner(name, false)
|
||||
}
|
||||
|
||||
pub(crate) fn on_block_edit_switch(&mut self, name: String) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i].is_start {
|
||||
return Task::none();
|
||||
}
|
||||
let Some(target_index) = self.tabs[i]
|
||||
.block_edits
|
||||
.iter()
|
||||
.position(|session| session.block_name == name)
|
||||
else {
|
||||
self.command_line
|
||||
.push_error(&format!("BEDIT: block tab \"{name}\" is not open."));
|
||||
return Task::none();
|
||||
};
|
||||
if self.tabs[i].active_block_edit == Some(target_index) {
|
||||
return Task::none();
|
||||
}
|
||||
|
||||
let cancel_task = self.cancel_active_command_for_space_change();
|
||||
let current_camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
if let Some(active_index) = self.tabs[i].active_block_edit {
|
||||
if let Some(session) = self.tabs[i].block_edits.get_mut(active_index) {
|
||||
session.editor_camera = current_camera;
|
||||
}
|
||||
} else {
|
||||
self.tabs[i].scene.sync_camera_to_document();
|
||||
}
|
||||
|
||||
let (br_handle, editor_camera) = {
|
||||
let session = &self.tabs[i].block_edits[target_index];
|
||||
(session.br_handle, session.editor_camera.clone())
|
||||
};
|
||||
self.layout_rename_state = None;
|
||||
self.tabs[i].scene.active_viewport = None;
|
||||
self.tabs[i].scene.set_current_layout("Model".to_string());
|
||||
self.tabs[i].scene.block_edit_block = Some(br_handle);
|
||||
self.tabs[i].active_block_edit = Some(target_index);
|
||||
*self.tabs[i].scene.camera.borrow_mut() = editor_camera;
|
||||
self.tabs[i].scene.camera_generation += 1;
|
||||
self.tabs[i].last_synced_camera_gen = self.tabs[i].scene.camera_generation;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].active_grip = None;
|
||||
self.grip_hover = None;
|
||||
self.grip_popup = None;
|
||||
self.visibility_popup = None;
|
||||
self.tabs[i].refresh_active_ucs();
|
||||
self.tabs[i].scene.bump_geometry_no_blocks();
|
||||
self.refresh_properties();
|
||||
self.adopt_view_display(i);
|
||||
self.sync_dyn_fields();
|
||||
cancel_task
|
||||
}
|
||||
|
||||
/// MVIEW's "Insert view > New" flow deliberately visits Model space to
|
||||
/// define a view and then returns to its paper layout. This is the only
|
||||
/// layout transition allowed to preserve an active command.
|
||||
|
|
@ -3700,19 +3755,16 @@ impl OpenCADStudio {
|
|||
.push_info("Open or create a drawing to switch layouts.");
|
||||
return Task::none();
|
||||
}
|
||||
// A BEDIT block editor locks the active space; finish it with
|
||||
// Save Block or Discard before switching spaces. (#261)
|
||||
if self.tabs[i].block_edit.is_some() {
|
||||
self.command_line.push_info(
|
||||
"Finish the block editor (Save Block or Discard) before switching spaces.",
|
||||
);
|
||||
return Task::none();
|
||||
}
|
||||
let perf = crate::perf::enabled();
|
||||
let perf_total = Instant::now();
|
||||
let perf_from = self.tabs[i].scene.current_layout.clone();
|
||||
let context_changed =
|
||||
self.tabs[i].scene.current_layout != name || self.tabs[i].scene.active_viewport.is_some();
|
||||
let leaving_block_edit = self.tabs[i].active_block_edit.is_some();
|
||||
let perf_from = self.tabs[i]
|
||||
.active_block_edit_session()
|
||||
.map(|session| session.block_name.clone())
|
||||
.unwrap_or_else(|| self.tabs[i].scene.current_layout.clone());
|
||||
let context_changed = leaving_block_edit
|
||||
|| self.tabs[i].scene.current_layout != name
|
||||
|| self.tabs[i].scene.active_viewport.is_some();
|
||||
let preserve_active_command = preserve_active_command
|
||||
&& self.tabs[i]
|
||||
.active_cmd
|
||||
|
|
@ -3730,6 +3782,24 @@ impl OpenCADStudio {
|
|||
} else {
|
||||
Task::none()
|
||||
};
|
||||
if let Some(active_index) = self.tabs[i].active_block_edit.take() {
|
||||
let camera = self.tabs[i].scene.camera.borrow().clone();
|
||||
let (return_layout, return_camera) = {
|
||||
let session = &mut self.tabs[i].block_edits[active_index];
|
||||
session.editor_camera = camera;
|
||||
(session.return_layout.clone(), session.return_camera.clone())
|
||||
};
|
||||
let return_layout = if self.tabs[i].scene.layout_names().contains(&return_layout) {
|
||||
return_layout
|
||||
} else {
|
||||
"Model".to_string()
|
||||
};
|
||||
self.tabs[i].scene.block_edit_block = None;
|
||||
self.tabs[i].scene.set_current_layout(return_layout);
|
||||
*self.tabs[i].scene.camera.borrow_mut() = return_camera;
|
||||
self.tabs[i].scene.camera_generation += 1;
|
||||
self.tabs[i].scene.bump_geometry_no_blocks();
|
||||
}
|
||||
let going_to_paper = name != "Model";
|
||||
// Persist the camera of the layout we're leaving BEFORE switching
|
||||
// so returning to it restores where the user left off (the
|
||||
|
|
@ -3849,10 +3919,8 @@ impl OpenCADStudio {
|
|||
// BEDIT block tab: renaming it renames the BLOCK itself —
|
||||
// its record, marker and every INSERT reference. (#261)
|
||||
let is_block_tab = self.tabs[i]
|
||||
.block_edit
|
||||
.as_ref()
|
||||
.map(|be| be.block_name == orig)
|
||||
.unwrap_or(false);
|
||||
.active_block_edit_session()
|
||||
.is_some_and(|session| session.block_name == orig);
|
||||
if is_block_tab {
|
||||
if self.tabs[i]
|
||||
.scene
|
||||
|
|
@ -3866,8 +3934,15 @@ impl OpenCADStudio {
|
|||
} else {
|
||||
self.push_undo_snapshot(i, "BLOCK RENAME");
|
||||
if self.tabs[i].scene.rename_block(&orig, &new_name) {
|
||||
if let Some(be) = self.tabs[i].block_edit.as_mut() {
|
||||
be.block_name = new_name.clone();
|
||||
if let Some(session) =
|
||||
self.tabs[i].active_block_edit_session_mut()
|
||||
{
|
||||
session.block_name = new_name.clone();
|
||||
}
|
||||
for session in &mut self.tabs[i].block_edits {
|
||||
if session.return_block.as_deref() == Some(orig.as_str()) {
|
||||
session.return_block = Some(new_name.clone());
|
||||
}
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line
|
||||
|
|
|
|||
|
|
@ -1084,7 +1084,7 @@ impl OpenCADStudio {
|
|||
}
|
||||
|
||||
// BEDIT block editor: right-edge Save Block / Discard toolbar (#261).
|
||||
if tab.block_edit.is_some() && !tab.is_start {
|
||||
if tab.active_block_edit.is_some() && !tab.is_start {
|
||||
if let Some(tb) = crate::ui::side_toolbar::view(
|
||||
&crate::modules::draw::modify::block_edit::block_edit_tools(),
|
||||
) {
|
||||
|
|
@ -1375,10 +1375,14 @@ impl OpenCADStudio {
|
|||
let coords_mode = tab.scene.document.header.coords_mode;
|
||||
let picking = tab.active_cmd.is_some();
|
||||
let layout_names = tab.scene.layout_names();
|
||||
let mut displayed_layouts = layout_names.clone();
|
||||
if let Some(be) = &tab.block_edit {
|
||||
displayed_layouts.push(be.block_name.clone());
|
||||
}
|
||||
let block_tabs = tab
|
||||
.block_edits
|
||||
.iter()
|
||||
.map(|session| session.block_name.clone())
|
||||
.collect();
|
||||
let active_block = tab
|
||||
.active_block_edit_session()
|
||||
.map(|session| session.block_name.clone());
|
||||
let status_menu_data = crate::ui::statusbar::StatusMenuData {
|
||||
layout_names: layout_names.clone(),
|
||||
polar_custom_input: &self.polar_custom_input,
|
||||
|
|
@ -1401,12 +1405,11 @@ impl OpenCADStudio {
|
|||
self.polar_increment_deg,
|
||||
self.dyn_input,
|
||||
self.snapper.otrack_enabled,
|
||||
displayed_layouts,
|
||||
layout_names.clone(),
|
||||
block_tabs,
|
||||
layout_names.into_iter().skip(1).collect(),
|
||||
tab.block_edit
|
||||
.as_ref()
|
||||
.map(|be| be.block_name.clone())
|
||||
.unwrap_or_else(|| tab.scene.current_layout.clone()),
|
||||
tab.scene.current_layout.clone(),
|
||||
active_block,
|
||||
tab.is_start,
|
||||
self.layout_rename_state.as_ref(),
|
||||
tab.scene.first_viewport_scale(),
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub fn block_edit_tools() -> Vec<ToolDef> {
|
|||
|
||||
// ── Session state (held in DocumentTab) ───────────────────────────────────
|
||||
|
||||
/// Active BEDIT block-editor session. Lives in `DocumentTab::block_edit`.
|
||||
/// One open BEDIT block-editor tab. Lives in `DocumentTab::block_edits`.
|
||||
#[derive(Clone)]
|
||||
pub struct BlockEditSession {
|
||||
/// Name of the block being edited (also the space-tab label).
|
||||
|
|
@ -52,12 +52,18 @@ pub struct BlockEditSession {
|
|||
/// Space to return to when the block editor closes (the layout that was
|
||||
/// active when BEDIT began).
|
||||
pub return_layout: String,
|
||||
/// Parent block tab to return to for a nested BEDIT session. `None` returns
|
||||
/// to `return_layout`.
|
||||
pub return_block: Option<String>,
|
||||
/// The block's block-local entities captured on entry, so Discard can
|
||||
/// restore the definition (structural Block/BlockEnd/AttDef excluded).
|
||||
pub snapshot: Vec<EntityType>,
|
||||
/// Camera state of the space that was active when BEDIT began, restored
|
||||
/// on Save/Discard so the view returns exactly where it was (#425).
|
||||
pub return_camera: crate::scene::view::camera::Camera,
|
||||
/// Camera owned by this block tab. Updated whenever another space tab is
|
||||
/// activated, then restored when the user returns to this block.
|
||||
pub editor_camera: crate::scene::view::camera::Camera,
|
||||
}
|
||||
|
||||
// ── BEDIT pick command ─────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -60,8 +60,10 @@ impl StatusBar {
|
|||
dyn_input: bool,
|
||||
otrack: bool,
|
||||
layouts: Vec<String>,
|
||||
block_tabs: Vec<String>,
|
||||
reorderable_layouts: Vec<String>,
|
||||
current_layout: String,
|
||||
active_block: Option<String>,
|
||||
// Start/welcome view has no drawing to own layouts.
|
||||
is_start: bool,
|
||||
// If `Some((original, edit_value))`, the named tab shows a text input.
|
||||
|
|
@ -413,10 +415,11 @@ impl StatusBar {
|
|||
if show_layout_tabs {
|
||||
let reorderable_layouts: Arc<[String]> = reorderable_layouts.into();
|
||||
for name in layouts {
|
||||
let is_active = name == current_layout;
|
||||
let is_active = active_block.is_none() && name == current_layout;
|
||||
let renaming = rename_state
|
||||
.filter(|(orig, _)| *orig == name)
|
||||
.map(|(_, edit)| edit.as_str());
|
||||
let switch_msg = Message::LayoutSwitch(name.clone());
|
||||
left.push(
|
||||
space_tab(
|
||||
name,
|
||||
|
|
@ -424,6 +427,24 @@ impl StatusBar {
|
|||
renaming,
|
||||
!is_start,
|
||||
reorderable_layouts.clone(),
|
||||
switch_msg,
|
||||
"SB_LAYOUT_TAB",
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
for name in block_tabs {
|
||||
let is_active = active_block.as_deref() == Some(name.as_str());
|
||||
let switch_msg = Message::BlockEditSwitch(name.clone());
|
||||
left.push(
|
||||
space_tab(
|
||||
name,
|
||||
is_active,
|
||||
None,
|
||||
!is_start,
|
||||
Arc::from(Vec::<String>::new()),
|
||||
switch_msg,
|
||||
"SB_BLOCK_TAB",
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
|
|
@ -760,6 +781,8 @@ fn space_tab<'a>(
|
|||
rename_edit: Option<&'a str>,
|
||||
enabled: bool,
|
||||
reorderable_layouts: Arc<[String]>,
|
||||
switch_msg: Message,
|
||||
report_key_prefix: &'static str,
|
||||
) -> Element<'a, Message> {
|
||||
let tab_style = move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
|
|
@ -791,7 +814,7 @@ fn space_tab<'a>(
|
|||
.style(tab_style)
|
||||
.padding([4, 10]);
|
||||
crate::ui::wrap_bar::PosReport::owned(
|
||||
format!("SB_LAYOUT_TAB:{label}"),
|
||||
format!("{report_key_prefix}:{label}"),
|
||||
tip(
|
||||
display.into(),
|
||||
"Open or create a drawing to switch layouts.",
|
||||
|
|
@ -827,9 +850,8 @@ fn space_tab<'a>(
|
|||
.style(tab_style)
|
||||
.padding([4, 10]);
|
||||
|
||||
let switch_msg = Message::LayoutSwitch(label.clone());
|
||||
let has_context_menu = reorderable_layouts.contains(&label);
|
||||
let report_key = format!("SB_LAYOUT_TAB:{label}");
|
||||
let report_key = format!("{report_key_prefix}:{label}");
|
||||
let tab = mouse_area(display).on_press(switch_msg);
|
||||
let tab: Element<'a, Message> = if has_context_menu {
|
||||
crate::ui::wrap_bar::ReorderTab::layout(
|
||||
|
|
|
|||
Loading…
Reference in a new issue