forked from 1b-agent/opencadstudio-upstream
feat(layout): copy a layout from its tab menu (#1822)
The layout tab's right-click menu gains New Layout, Copy, Page Setup and Plot beside Rename and Delete. Copy makes "<name> (2)" with the source's page setup, sheet view and every paper-space object, viewports included, and opens it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
38d81bf838
commit
0126ea212f
28 files changed
+172
-16
No files matched your search
@@ -3765,6 +3765,12 @@ pub enum Message {
|
||||
},
|
||||
/// Create a new paper space layout.
|
||||
LayoutCreate,
|
||||
/// Copy the named layout, its page setup and paper-space objects.
|
||||
LayoutCopy(String),
|
||||
/// Open the named layout's page setup.
|
||||
LayoutPageSetup(String),
|
||||
/// Plot the named layout.
|
||||
LayoutPlot(String),
|
||||
/// Delete the named paper space layout (Model cannot be deleted).
|
||||
LayoutDelete(String),
|
||||
/// Begin inline rename for the given layout tab.
|
||||
|
||||
@@ -8297,6 +8297,18 @@ impl OpenCADStudio {
|
||||
|
||||
Message::LayoutCreate => self.on_layout_create(),
|
||||
|
||||
Message::LayoutCopy(name) => self.on_layout_copy(name),
|
||||
|
||||
Message::LayoutPageSetup(name) => {
|
||||
let switch_task = self.on_layout_switch(name);
|
||||
Task::batch([switch_task, self.on_plot_dialog_open()])
|
||||
}
|
||||
|
||||
Message::LayoutPlot(name) => {
|
||||
let switch_task = self.on_layout_switch(name);
|
||||
Task::batch([switch_task, Task::done(Message::Command("PLOT".into()))])
|
||||
}
|
||||
|
||||
Message::LayoutDelete(name) => {
|
||||
let i = self.active_tab;
|
||||
let deleting_current = self.tabs[i].scene.current_layout == name;
|
||||
|
||||
@@ -6920,6 +6920,47 @@ properties={:.1}ms picked={}",
|
||||
cancel_task
|
||||
}
|
||||
|
||||
/// Copy layout `source` as "source (2)": its page setup and every
|
||||
/// paper-space object, viewports included. The copy opens.
|
||||
pub(super) fn on_layout_copy(&mut self, source: String) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i].is_start || source == "Model" {
|
||||
return Task::none();
|
||||
}
|
||||
let existing = self.tabs[i].scene.layout_names();
|
||||
let Some(name) = (2..)
|
||||
.map(|n| format!("{source} ({n})"))
|
||||
.find(|candidate| !existing.contains(candidate))
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
let cancel_task = self.cancel_active_command_for_space_change();
|
||||
self.push_undo_snapshot(i, "LAYOUT");
|
||||
let scene = &mut self.tabs[i].scene;
|
||||
if let Err(e) = scene.add_layout(&name) {
|
||||
self.command_line
|
||||
.push_error(crate::tf!("Failed to create layout: {e}").as_ref());
|
||||
return cancel_task;
|
||||
}
|
||||
scene.copy_layout_page(&source, &name);
|
||||
let handles = scene.layout_paper_entities(&source);
|
||||
let (entities, deps) = crate::app::copy_to_clipboard_kernel(&scene.document, &handles);
|
||||
crate::app::paste_entities_kernel(
|
||||
&mut scene.document,
|
||||
&entities,
|
||||
&deps,
|
||||
None,
|
||||
crate::app::PasteSpace::Layout(&name),
|
||||
);
|
||||
scene.populate_meshes_from_document();
|
||||
scene.bump_geometry();
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line
|
||||
.push_output(crate::tf!("Layout \"{source}\" copied as \"{name}\"").as_ref());
|
||||
let switch_task = self.on_layout_switch(name);
|
||||
Task::batch([cancel_task, switch_task])
|
||||
}
|
||||
|
||||
pub(super) fn on_layout_rename_commit(&mut self) -> Task<Message> {
|
||||
if let Some((orig, new_name)) = self.layout_rename_state.take() {
|
||||
let new_name = new_name.trim().to_string();
|
||||
|
||||
Reference in new issue
Block a user