feat: Layout Manager GUI (LAYOUTMANAGER / LAYOUTPANEL command)
Panel overlay showing all layouts with their active status. Supports: select, rename, new, delete, reorder (◀▶), set current. Also adds Scene::swap_layout_order() for tab-order resequencing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b8d15e5155
commit
85f9b930a2
6 changed files with 387 additions and 2 deletions
|
|
@ -178,7 +178,7 @@ Underlay (PDF/DWF/DGN)
|
||||||
| MLSTYLE | ✅ |
|
| MLSTYLE | ✅ |
|
||||||
| TABLESTYLE | ✅ |
|
| TABLESTYLE | ✅ |
|
||||||
| PLOTSTYLE (CTB/STB) | ✅ |
|
| PLOTSTYLE (CTB/STB) | ✅ |
|
||||||
| Plot style arayüzü (GUI) | ⬜ |
|
| Plot style arayüzü (GUI) | ✅ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1972,6 +1972,11 @@ impl H7CAD {
|
||||||
self.command_line.push_info("Opening Patreon page...");
|
self.command_line.push_info("Opening Patreon page...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Layout Manager GUI ─────────────────────────────────────────
|
||||||
|
"LAYOUTMANAGER"|"LAYOUTPANEL" => {
|
||||||
|
return Task::done(Message::LayoutManagerOpen);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Layout / viewport ──────────────────────────────────────────
|
// ── Layout / viewport ──────────────────────────────────────────
|
||||||
"MVIEW"|"MV" => {
|
"MVIEW"|"MV" => {
|
||||||
if self.tabs[i].scene.current_layout == "Model" {
|
if self.tabs[i].scene.current_layout == "Model" {
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,11 @@ pub(super) struct H7CAD {
|
||||||
/// Edit buffer for oblique angle (degrees).
|
/// Edit buffer for oblique angle (degrees).
|
||||||
textstyle_oblique: String,
|
textstyle_oblique: String,
|
||||||
|
|
||||||
|
// ── Layout Manager Panel ──────────────────────────────────────────────
|
||||||
|
layout_manager_open: bool,
|
||||||
|
layout_manager_selected: String,
|
||||||
|
layout_manager_rename_buf: String,
|
||||||
|
|
||||||
// ── Plot Style Panel ──────────────────────────────────────────────────
|
// ── Plot Style Panel ──────────────────────────────────────────────────
|
||||||
plotstyle_panel_open: bool,
|
plotstyle_panel_open: bool,
|
||||||
/// Selected ACI index in the panel (1-255).
|
/// Selected ACI index in the panel (1-255).
|
||||||
|
|
@ -338,6 +343,17 @@ pub enum Message {
|
||||||
LayoutContextMenu(String),
|
LayoutContextMenu(String),
|
||||||
/// Close the layout context menu.
|
/// Close the layout context menu.
|
||||||
LayoutContextMenuClose,
|
LayoutContextMenuClose,
|
||||||
|
// ── Layout Manager Panel ────────────────────────────────────────────
|
||||||
|
LayoutManagerOpen,
|
||||||
|
LayoutManagerClose,
|
||||||
|
LayoutManagerSelect(String),
|
||||||
|
LayoutManagerRenameBuf(String),
|
||||||
|
LayoutManagerRenameCommit,
|
||||||
|
LayoutManagerNew,
|
||||||
|
LayoutManagerDelete,
|
||||||
|
LayoutManagerMoveLeft,
|
||||||
|
LayoutManagerMoveRight,
|
||||||
|
LayoutManagerSetCurrent,
|
||||||
/// Close the viewport right-click context menu without performing any action.
|
/// Close the viewport right-click context menu without performing any action.
|
||||||
ViewportContextMenuClose,
|
ViewportContextMenuClose,
|
||||||
/// A window was closed by the OS (e.g. the user clicked the title-bar ✕).
|
/// A window was closed by the OS (e.g. the user clicked the title-bar ✕).
|
||||||
|
|
@ -514,6 +530,10 @@ impl H7CAD {
|
||||||
page_setup_scale: "Fit".to_string(),
|
page_setup_scale: "Fit".to_string(),
|
||||||
// Plot style
|
// Plot style
|
||||||
active_plot_style: None,
|
active_plot_style: None,
|
||||||
|
// Layout Manager
|
||||||
|
layout_manager_open: false,
|
||||||
|
layout_manager_selected: "Model".to_string(),
|
||||||
|
layout_manager_rename_buf: String::new(),
|
||||||
plotstyle_panel_open: false,
|
plotstyle_panel_open: false,
|
||||||
plotstyle_panel_aci: 1,
|
plotstyle_panel_aci: 1,
|
||||||
ps_color_buf: String::new(),
|
ps_color_buf: String::new(),
|
||||||
|
|
|
||||||
|
|
@ -2238,6 +2238,133 @@ impl H7CAD {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Layout Manager Panel ──────────────────────────────────────────
|
||||||
|
Message::LayoutManagerOpen => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let current = self.tabs[i].scene.current_layout.clone();
|
||||||
|
self.layout_manager_selected = current.clone();
|
||||||
|
self.layout_manager_rename_buf = if current == "Model" {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
current
|
||||||
|
};
|
||||||
|
self.layout_manager_open = true;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerClose => {
|
||||||
|
self.layout_manager_open = false;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerSelect(name) => {
|
||||||
|
self.layout_manager_rename_buf = if name == "Model" { String::new() } else { name.clone() };
|
||||||
|
self.layout_manager_selected = name;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerRenameBuf(s) => {
|
||||||
|
self.layout_manager_rename_buf = s;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerRenameCommit => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let old_name = self.layout_manager_selected.clone();
|
||||||
|
let new_name = self.layout_manager_rename_buf.trim().to_string();
|
||||||
|
if old_name == "Model" {
|
||||||
|
self.command_line.push_error("Cannot rename the Model layout.");
|
||||||
|
} else if new_name.is_empty() {
|
||||||
|
self.command_line.push_error("Layout name cannot be empty.");
|
||||||
|
} else if new_name == old_name {
|
||||||
|
// no-op
|
||||||
|
} else {
|
||||||
|
self.push_undo_snapshot(i, "LAYOUT RENAME");
|
||||||
|
self.tabs[i].scene.rename_layout(&old_name, &new_name);
|
||||||
|
if self.tabs[i].scene.current_layout == old_name {
|
||||||
|
self.tabs[i].scene.current_layout = new_name.clone();
|
||||||
|
}
|
||||||
|
self.layout_manager_selected = new_name.clone();
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
self.command_line.push_output(&format!("Layout renamed: '{old_name}' → '{new_name}'"));
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerNew => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let existing = self.tabs[i].scene.layout_names();
|
||||||
|
let n = (1usize..).find(|n| !existing.contains(&format!("Layout{n}"))).unwrap_or(1);
|
||||||
|
let name = format!("Layout{n}");
|
||||||
|
self.push_undo_snapshot(i, "LAYOUT NEW");
|
||||||
|
match self.tabs[i].scene.document.add_layout(&name) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
self.layout_manager_selected = name.clone();
|
||||||
|
self.layout_manager_rename_buf = name.clone();
|
||||||
|
self.command_line.push_output(&format!("Layout '{name}' created."));
|
||||||
|
}
|
||||||
|
Err(e) => self.command_line.push_error(&format!("LAYOUT: {e}")),
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerDelete => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let name = self.layout_manager_selected.clone();
|
||||||
|
if name == "Model" {
|
||||||
|
self.command_line.push_error("Cannot delete the Model layout.");
|
||||||
|
} else {
|
||||||
|
self.push_undo_snapshot(i, "LAYOUT DELETE");
|
||||||
|
self.tabs[i].scene.delete_layout(&name);
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
// Switch to Model if active layout was deleted.
|
||||||
|
if self.tabs[i].scene.current_layout == name {
|
||||||
|
self.tabs[i].scene.current_layout = "Model".to_string();
|
||||||
|
}
|
||||||
|
self.layout_manager_selected = "Model".to_string();
|
||||||
|
self.layout_manager_rename_buf = String::new();
|
||||||
|
self.command_line.push_output(&format!("Layout '{name}' deleted."));
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerMoveLeft => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let name = self.layout_manager_selected.clone();
|
||||||
|
if name == "Model" {
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
let names = self.tabs[i].scene.layout_names();
|
||||||
|
// Find position among paper layouts only.
|
||||||
|
let paper: Vec<&str> = names.iter().skip(1).map(|s| s.as_str()).collect();
|
||||||
|
if let Some(pos) = paper.iter().position(|&n| n == name) {
|
||||||
|
if pos > 0 {
|
||||||
|
self.push_undo_snapshot(i, "LAYOUT REORDER");
|
||||||
|
self.tabs[i].scene.swap_layout_order(&name, paper[pos - 1]);
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerMoveRight => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let name = self.layout_manager_selected.clone();
|
||||||
|
if name == "Model" {
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
let names = self.tabs[i].scene.layout_names();
|
||||||
|
let paper: Vec<&str> = names.iter().skip(1).map(|s| s.as_str()).collect();
|
||||||
|
if let Some(pos) = paper.iter().position(|&n| n == name) {
|
||||||
|
if pos + 1 < paper.len() {
|
||||||
|
self.push_undo_snapshot(i, "LAYOUT REORDER");
|
||||||
|
self.tabs[i].scene.swap_layout_order(&name, paper[pos + 1]);
|
||||||
|
self.tabs[i].dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::LayoutManagerSetCurrent => {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let name = self.layout_manager_selected.clone();
|
||||||
|
self.tabs[i].scene.current_layout = name.clone();
|
||||||
|
self.command_line.push_output(&format!("Switched to layout '{name}'."));
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
Message::ViewportContextMenuClose => {
|
Message::ViewportContextMenuClose => {
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
|
self.tabs[i].scene.selection.borrow_mut().context_menu = None;
|
||||||
|
|
|
||||||
215
src/app/view.rs
215
src/app/view.rs
|
|
@ -311,6 +311,21 @@ impl H7CAD {
|
||||||
iced::widget::Space::new().width(0).height(0).into()
|
iced::widget::Space::new().width(0).height(0).into()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ── Layout Manager Panel ─────────────────────────────────────────
|
||||||
|
let layout_manager_layer: Element<'_, Message> = if self.layout_manager_open {
|
||||||
|
let i = self.active_tab;
|
||||||
|
let layouts = self.tabs[i].scene.layout_names();
|
||||||
|
let current = self.tabs[i].scene.current_layout.clone();
|
||||||
|
layout_manager_overlay(
|
||||||
|
layouts,
|
||||||
|
&self.layout_manager_selected,
|
||||||
|
&self.layout_manager_rename_buf,
|
||||||
|
current,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
iced::widget::Space::new().width(0).height(0).into()
|
||||||
|
};
|
||||||
|
|
||||||
// ── Plot Style Panel ──────────────────────────────────────────────
|
// ── Plot Style Panel ──────────────────────────────────────────────
|
||||||
let plotstyle_layer: Element<'_, Message> = if self.plotstyle_panel_open {
|
let plotstyle_layer: Element<'_, Message> = if self.plotstyle_panel_open {
|
||||||
plotstyle_panel_overlay(
|
plotstyle_panel_overlay(
|
||||||
|
|
@ -352,7 +367,7 @@ impl H7CAD {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
stack![main_ui, self.app_menu.view(), snap_layer, dropdown_layer, layout_ctx_layer, page_setup_layer, textstyle_layer, tablestyle_layer, mlstyle_layer, plotstyle_layer, dimstyle_layer, viewport_ctx_layer].into()
|
stack![main_ui, self.app_menu.view(), snap_layer, dropdown_layer, layout_ctx_layer, page_setup_layer, textstyle_layer, tablestyle_layer, mlstyle_layer, plotstyle_layer, layout_manager_layer, dimstyle_layer, viewport_ctx_layer].into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription(&self) -> Subscription<Message> {
|
pub fn subscription(&self) -> Subscription<Message> {
|
||||||
|
|
@ -1983,3 +1998,201 @@ fn plotstyle_panel_overlay<'a>(
|
||||||
|
|
||||||
stack![catcher, positioned].into()
|
stack![catcher, positioned].into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Layout Manager Panel ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
fn layout_manager_overlay<'a>(
|
||||||
|
layouts: Vec<String>,
|
||||||
|
selected: &'a str,
|
||||||
|
rename_buf: &'a str,
|
||||||
|
current: String,
|
||||||
|
) -> Element<'a, Message> {
|
||||||
|
use iced::Length::Fill;
|
||||||
|
use iced::Color;
|
||||||
|
|
||||||
|
const PANEL_BG: Color = Color { r: 0.15, g: 0.15, b: 0.15, a: 1.0 };
|
||||||
|
const BORDER: Color = Color { r: 0.35, g: 0.35, b: 0.35, a: 1.0 };
|
||||||
|
const TEXT_COL: Color = Color { r: 0.88, g: 0.88, b: 0.88, a: 1.0 };
|
||||||
|
const DIM_COL: Color = Color { r: 0.55, g: 0.55, b: 0.55, a: 1.0 };
|
||||||
|
const ACCENT: Color = Color { r: 0.25, g: 0.50, b: 0.85, a: 1.0 };
|
||||||
|
const ACTIVE_BG: Color = Color { r: 0.20, g: 0.40, b: 0.70, a: 1.0 };
|
||||||
|
const WARN_COL: Color = Color { r: 0.80, g: 0.35, b: 0.25, a: 1.0 };
|
||||||
|
|
||||||
|
let btn_style = |accent: bool| move |_: &Theme, status: button::Status| button::Style {
|
||||||
|
background: Some(Background::Color(match (accent, status) {
|
||||||
|
(true, button::Status::Hovered | button::Status::Pressed) => Color { r: 0.20, g: 0.42, b: 0.72, a: 1.0 },
|
||||||
|
(false, button::Status::Hovered | button::Status::Pressed) => Color { r: 0.28, g: 0.28, b: 0.28, a: 1.0 },
|
||||||
|
(true, _) => ACCENT,
|
||||||
|
_ => Color { r: 0.22, g: 0.22, b: 0.22, a: 1.0 },
|
||||||
|
})),
|
||||||
|
text_color: TEXT_COL,
|
||||||
|
border: Border { color: BORDER, width: 1.0, radius: 4.0.into() },
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let field_style = |_: &Theme, _: text_input::Status| text_input::Style {
|
||||||
|
background: Background::Color(Color { r: 0.10, g: 0.10, b: 0.10, a: 1.0 }),
|
||||||
|
border: Border { color: BORDER, width: 1.0, radius: 3.0.into() },
|
||||||
|
icon: TEXT_COL,
|
||||||
|
placeholder: DIM_COL,
|
||||||
|
value: TEXT_COL,
|
||||||
|
selection: ACCENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Layout list
|
||||||
|
let list_items: Vec<Element<'_, Message>> = layouts.iter().map(|name| {
|
||||||
|
let is_sel = name.as_str() == selected;
|
||||||
|
let is_cur = name.as_str() == current.as_str();
|
||||||
|
let label = if is_cur { format!("{} ◀", name) } else { name.clone() };
|
||||||
|
button(text(label).size(12).color(TEXT_COL))
|
||||||
|
.on_press(Message::LayoutManagerSelect(name.clone()))
|
||||||
|
.style(move |_: &Theme, st| button::Style {
|
||||||
|
background: Some(Background::Color(match (is_sel, st) {
|
||||||
|
(true, _) => ACTIVE_BG,
|
||||||
|
(false, button::Status::Hovered | button::Status::Pressed) =>
|
||||||
|
Color { r: 0.26, g: 0.26, b: 0.26, a: 1.0 },
|
||||||
|
_ => Color::TRANSPARENT,
|
||||||
|
})),
|
||||||
|
text_color: TEXT_COL,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.padding([5, 10])
|
||||||
|
.width(Fill)
|
||||||
|
.into()
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let list_panel = container(
|
||||||
|
column(list_items).spacing(2)
|
||||||
|
)
|
||||||
|
.style(|_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(Color { r: 0.12, g: 0.12, b: 0.12, a: 1.0 })),
|
||||||
|
border: Border { color: BORDER, width: 1.0, radius: 4.0.into() },
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.padding(4)
|
||||||
|
.width(200)
|
||||||
|
.height(260);
|
||||||
|
|
||||||
|
let is_model = selected == "Model";
|
||||||
|
|
||||||
|
let right_panel = column![
|
||||||
|
text(if is_model { "Model Space" } else { "Paper Space Layout" })
|
||||||
|
.size(12).color(TEXT_COL),
|
||||||
|
Space::new().height(4),
|
||||||
|
row![
|
||||||
|
text("Name:").size(11).color(DIM_COL).width(70),
|
||||||
|
text(selected).size(11).color(TEXT_COL),
|
||||||
|
].spacing(8).align_y(iced::Center),
|
||||||
|
row![
|
||||||
|
text("Status:").size(11).color(DIM_COL).width(70),
|
||||||
|
text(if selected == current.as_str() { "Active ◀" } else { "Inactive" })
|
||||||
|
.size(11)
|
||||||
|
.color(if selected == current.as_str() { ACCENT } else { DIM_COL }),
|
||||||
|
].spacing(8).align_y(iced::Center),
|
||||||
|
Space::new().height(12),
|
||||||
|
text("Rename:").size(11).color(DIM_COL),
|
||||||
|
row![
|
||||||
|
text_input("New name…", rename_buf)
|
||||||
|
.on_input(Message::LayoutManagerRenameBuf)
|
||||||
|
.on_submit(Message::LayoutManagerRenameCommit)
|
||||||
|
.style(field_style)
|
||||||
|
.size(11)
|
||||||
|
.padding([4, 8]),
|
||||||
|
button(text("OK").size(11))
|
||||||
|
.on_press(Message::LayoutManagerRenameCommit)
|
||||||
|
.style(btn_style(true))
|
||||||
|
.padding([4, 8]),
|
||||||
|
].spacing(6).align_y(iced::Center),
|
||||||
|
Space::new().height(Fill),
|
||||||
|
row![
|
||||||
|
button(text("◀").size(11))
|
||||||
|
.on_press(Message::LayoutManagerMoveLeft)
|
||||||
|
.style(btn_style(false))
|
||||||
|
.padding([4, 8]),
|
||||||
|
button(text("▶").size(11))
|
||||||
|
.on_press(Message::LayoutManagerMoveRight)
|
||||||
|
.style(btn_style(false))
|
||||||
|
.padding([4, 8]),
|
||||||
|
Space::new().width(Fill),
|
||||||
|
button(text("Set Current").size(11))
|
||||||
|
.on_press(Message::LayoutManagerSetCurrent)
|
||||||
|
.style(btn_style(true))
|
||||||
|
.padding([5, 10]),
|
||||||
|
].spacing(6).align_y(iced::Center),
|
||||||
|
]
|
||||||
|
.spacing(6)
|
||||||
|
.width(240)
|
||||||
|
.height(260);
|
||||||
|
|
||||||
|
let panel = container(
|
||||||
|
column![
|
||||||
|
row![
|
||||||
|
text("Layout Manager").size(13).color(TEXT_COL),
|
||||||
|
Space::new().width(Fill),
|
||||||
|
button(text("✕").size(12).color(DIM_COL))
|
||||||
|
.on_press(Message::LayoutManagerClose)
|
||||||
|
.style(|_: &Theme, _| button::Style {
|
||||||
|
background: Some(Background::Color(Color::TRANSPARENT)),
|
||||||
|
text_color: DIM_COL,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.padding([2, 6]),
|
||||||
|
].align_y(iced::Center),
|
||||||
|
Space::new().height(8),
|
||||||
|
row![
|
||||||
|
list_panel,
|
||||||
|
Space::new().width(12),
|
||||||
|
right_panel,
|
||||||
|
].align_y(iced::alignment::Vertical::Top),
|
||||||
|
Space::new().height(8),
|
||||||
|
row![
|
||||||
|
button(text("New Layout").size(11))
|
||||||
|
.on_press(Message::LayoutManagerNew)
|
||||||
|
.style(btn_style(false))
|
||||||
|
.padding([5, 10]),
|
||||||
|
button(text("Delete").size(11))
|
||||||
|
.on_press(Message::LayoutManagerDelete)
|
||||||
|
.style(move |_: &Theme, st| button::Style {
|
||||||
|
background: Some(Background::Color(match st {
|
||||||
|
button::Status::Hovered | button::Status::Pressed =>
|
||||||
|
Color { r: 0.60, g: 0.20, b: 0.18, a: 1.0 },
|
||||||
|
_ => Color { r: 0.22, g: 0.22, b: 0.22, a: 1.0 },
|
||||||
|
})),
|
||||||
|
text_color: if is_model { DIM_COL } else { WARN_COL },
|
||||||
|
border: Border { color: BORDER, width: 1.0, radius: 4.0.into() },
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.padding([5, 10]),
|
||||||
|
Space::new().width(Fill),
|
||||||
|
button(text("Close").size(11))
|
||||||
|
.on_press(Message::LayoutManagerClose)
|
||||||
|
.style(btn_style(false))
|
||||||
|
.padding([5, 10]),
|
||||||
|
].spacing(8),
|
||||||
|
]
|
||||||
|
.spacing(6)
|
||||||
|
.padding(16)
|
||||||
|
)
|
||||||
|
.style(|_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(PANEL_BG)),
|
||||||
|
border: Border { color: BORDER, width: 1.0, radius: 6.0.into() },
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.width(490)
|
||||||
|
.height(370);
|
||||||
|
|
||||||
|
let catcher = mouse_area(container(Space::new().width(Fill).height(Fill))
|
||||||
|
.width(Fill).height(Fill)
|
||||||
|
.style(|_: &Theme| container::Style {
|
||||||
|
background: Some(Background::Color(Color { r: 0.0, g: 0.0, b: 0.0, a: 0.45 })),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
).on_press(Message::LayoutManagerClose);
|
||||||
|
|
||||||
|
let positioned = container(panel)
|
||||||
|
.width(Fill).height(Fill)
|
||||||
|
.align_x(iced::Alignment::Center)
|
||||||
|
.align_y(iced::Alignment::Center);
|
||||||
|
|
||||||
|
stack![catcher, positioned].into()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1057,6 +1057,26 @@ impl Scene {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Swap the `tab_order` of two paper layouts so they appear in swapped order.
|
||||||
|
pub fn swap_layout_order(&mut self, name_a: &str, name_b: &str) {
|
||||||
|
let mut order_a: Option<i16> = None;
|
||||||
|
let mut order_b: Option<i16> = None;
|
||||||
|
for obj in self.document.objects.values() {
|
||||||
|
if let ObjectType::Layout(l) = obj {
|
||||||
|
if l.name == name_a { order_a = Some(l.tab_order); }
|
||||||
|
if l.name == name_b { order_b = Some(l.tab_order); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let (Some(oa), Some(ob)) = (order_a, order_b) {
|
||||||
|
for obj in self.document.objects.values_mut() {
|
||||||
|
if let ObjectType::Layout(l) = obj {
|
||||||
|
if l.name == name_a { l.tab_order = ob; }
|
||||||
|
else if l.name == name_b { l.tab_order = oa; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Entity management ─────────────────────────────────────────────────
|
// ── Entity management ─────────────────────────────────────────────────
|
||||||
|
|
||||||
pub fn add_entity(&mut self, mut entity: EntityType) -> Handle {
|
pub fn add_entity(&mut self, mut entity: EntityType) -> Handle {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue