parent
b629dc32de
commit
c21f3e1a19
6 changed files with 457 additions and 16 deletions
|
|
@ -1497,6 +1497,12 @@ pub enum Message {
|
|||
TabNew,
|
||||
/// Switch to the given tab index.
|
||||
TabSwitch(usize),
|
||||
/// Move a drawing tab before/after another drawing tab.
|
||||
TabReorder {
|
||||
from: usize,
|
||||
to: usize,
|
||||
after: bool,
|
||||
},
|
||||
/// Close the given tab index.
|
||||
TabClose(usize),
|
||||
/// Open/close the right-click menu for a drawing tab.
|
||||
|
|
@ -1934,6 +1940,12 @@ pub enum Message {
|
|||
PspaceCommand,
|
||||
/// Switch to a named layout ("Model" or paper space layout name).
|
||||
LayoutSwitch(String),
|
||||
/// Move a paper layout before/after another paper layout.
|
||||
LayoutReorder {
|
||||
from: String,
|
||||
to: String,
|
||||
after: bool,
|
||||
},
|
||||
/// Create a new paper space layout.
|
||||
LayoutCreate,
|
||||
/// Delete the named paper space layout (Model cannot be deleted).
|
||||
|
|
|
|||
|
|
@ -57,6 +57,17 @@ fn format_size(bytes: u64) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn reorder_insertion_index(from: usize, to: usize, after: bool, len: usize) -> Option<usize> {
|
||||
if from >= len || to >= len || from == to {
|
||||
return None;
|
||||
}
|
||||
let mut insertion = to + usize::from(after);
|
||||
if from < insertion {
|
||||
insertion -= 1;
|
||||
}
|
||||
(insertion != from).then_some(insertion)
|
||||
}
|
||||
|
||||
mod command;
|
||||
mod dialog;
|
||||
mod dynamic;
|
||||
|
|
@ -962,6 +973,28 @@ impl OpenCADStudio {
|
|||
Task::none()
|
||||
}
|
||||
|
||||
Message::TabReorder { from, to, after } => {
|
||||
let Some(insertion) =
|
||||
reorder_insertion_index(from, to, after, self.tabs.len())
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
if self.tabs.get(from).is_some_and(|tab| tab.is_start)
|
||||
|| self.tabs.get(to).is_some_and(|tab| tab.is_start)
|
||||
{
|
||||
return Task::none();
|
||||
}
|
||||
|
||||
let active_id = self.tabs[self.active_tab].id;
|
||||
let moved = self.tabs.remove(from);
|
||||
self.tabs.insert(insertion, moved);
|
||||
if let Some(index) = self.tabs.iter().position(|tab| tab.id == active_id) {
|
||||
self.active_tab = index;
|
||||
}
|
||||
self.doc_tab_context_menu = None;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TabClose(idx) => {
|
||||
self.doc_tab_context_menu = None;
|
||||
self.on_tab_close(idx)
|
||||
|
|
@ -3325,6 +3358,38 @@ impl OpenCADStudio {
|
|||
self.on_layout_switch(name)
|
||||
}
|
||||
|
||||
Message::LayoutReorder { from, to, after } => {
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i].is_start {
|
||||
return Task::none();
|
||||
}
|
||||
let mut paper: Vec<String> = self.tabs[i]
|
||||
.scene
|
||||
.layout_names()
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.collect();
|
||||
let Some(from_index) = paper.iter().position(|name| name == &from) else {
|
||||
return Task::none();
|
||||
};
|
||||
let Some(to_index) = paper.iter().position(|name| name == &to) else {
|
||||
return Task::none();
|
||||
};
|
||||
let Some(insertion) =
|
||||
reorder_insertion_index(from_index, to_index, after, paper.len())
|
||||
else {
|
||||
return Task::none();
|
||||
};
|
||||
|
||||
let moved = paper.remove(from_index);
|
||||
paper.insert(insertion, moved);
|
||||
self.push_undo_snapshot(i, "LAYOUT REORDER");
|
||||
self.tabs[i].scene.set_layout_tab_order(&paper);
|
||||
self.tabs[i].dirty = true;
|
||||
self.layout_context_menu = None;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::LayoutCreate => self.on_layout_create(),
|
||||
|
||||
Message::LayoutDelete(name) => {
|
||||
|
|
|
|||
|
|
@ -1424,6 +1424,11 @@ impl OpenCADStudio {
|
|||
let last_coord = self.last_point.map(to_readout);
|
||||
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());
|
||||
}
|
||||
self.status_bar.view(
|
||||
&self.snapper,
|
||||
self.snap_popup_open,
|
||||
|
|
@ -1433,15 +1438,8 @@ impl OpenCADStudio {
|
|||
self.polar_popup_open,
|
||||
self.dyn_input,
|
||||
self.snapper.otrack_enabled,
|
||||
{
|
||||
// In a BEDIT block editor, show the block as an extra
|
||||
// active space tab alongside Model/layouts. (#261)
|
||||
let mut names = tab.scene.layout_names();
|
||||
if let Some(be) = &tab.block_edit {
|
||||
names.push(be.block_name.clone());
|
||||
}
|
||||
names
|
||||
},
|
||||
displayed_layouts,
|
||||
layout_names.into_iter().skip(1).collect(),
|
||||
tab.block_edit
|
||||
.as_ref()
|
||||
.map(|be| be.block_name.clone())
|
||||
|
|
@ -2096,6 +2094,12 @@ pub(super) fn doc_tab_bar<'a>(tabs: &'a [DocumentTab], active_tab: usize) -> Ele
|
|||
// Document tabs live in a flex-wrap flow so they spill onto lower rows when
|
||||
// there are more tabs than the width can hold on one line.
|
||||
let mut items: Vec<Element<'_, Message>> = Vec::new();
|
||||
let drag_targets: std::sync::Arc<[usize]> = tabs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, tab)| (!tab.is_start).then_some(idx))
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
|
||||
for (idx, tab) in tabs.iter().enumerate() {
|
||||
let is_active = idx == active_tab;
|
||||
|
|
@ -2147,6 +2151,16 @@ pub(super) fn doc_tab_bar<'a>(tabs: &'a [DocumentTab], active_tab: usize) -> Ele
|
|||
shadow: iced::Shadow::default(),
|
||||
snap: false,
|
||||
});
|
||||
let title_btn: Element<'_, Message> = if tab.is_start {
|
||||
title_btn.into()
|
||||
} else {
|
||||
crate::ui::wrap_bar::ReorderTab::document(
|
||||
idx,
|
||||
drag_targets.clone(),
|
||||
title_btn,
|
||||
)
|
||||
.into()
|
||||
};
|
||||
|
||||
// Start tab is fixed — no close button. Every other tab gets a close.
|
||||
let row_inner: Row<'_, Message> = if tab.is_start {
|
||||
|
|
|
|||
Loading…
Reference in a new issue