Dock: Layer Manager pallet, double-click to float / dock

- LAYERS opens the Layer Manager as a dockable pallet instead of a modal
  dialog with a darkened backdrop. It floats over the middle of the
  drawing the first time and keeps its place after that; LAYERS again
  (or its close button) hides it. The table keeps its natural width and
  scrolls sideways when the pallet is narrower, and the Name column
  divider now drags through the dock's pointer capture. Ctrl+A selects
  all layers while a layer row is selected in the open pallet.
- The Layer Manager is listed in the tab-row pallet menu like the others.
- Double-clicking a docked title bar floats the panel beside its edge;
  double-clicking a floating title bar docks the panel on the side its
  title bar faces.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
This commit is contained in:
Claude committed 2026-10-09 15:24:33 +00:00
1 parent 1f3fae6d1e
commit 09e4792a0a
7 files changed
+177 -45

No files matched your search

+14 -12
View File
@@ -49,6 +49,10 @@ pub enum DockMsg {
/// Pallet menu pick: show `panel` as a tab of the slot, or hide it when
/// it already shows there.
TabMenuToggle(DockSide, usize, PanelId),
/// Double-click on a docked title bar: float the panel.
FloatOut(PanelId),
/// Double-click on a floating title bar: dock the panel on that side.
DockTo(PanelId, DockSide),
/// Bring floating `panel` to the front.
FloatRaise(PanelId),
/// The pointer left the edge column; collapse any auto-collapsing panel.
@@ -72,11 +76,13 @@ pub enum PanelId {
Count,
/// The open sheet sets: subsets and sheets.
SheetSetManager,
/// The Layer Manager (LAYERS).
Layers,
}
impl PanelId {
/// Every panel, in the order the pallet menu lists them.
pub const ALL: [PanelId; 8] = [
pub const ALL: [PanelId; 9] = [
PanelId::Properties,
PanelId::BlockPalette,
PanelId::ExternalReferences,
@@ -85,6 +91,7 @@ impl PanelId {
PanelId::PointCloudManager,
PanelId::Count,
PanelId::SheetSetManager,
PanelId::Layers,
];
/// Localized-friendly display name used by the collapsed/edge chrome.
@@ -98,6 +105,7 @@ impl PanelId {
PanelId::PointCloudManager => "Point Cloud Manager",
PanelId::Count => "Count",
PanelId::SheetSetManager => "Sheet Set Manager",
PanelId::Layers => "Layer Manager",
}
}
@@ -112,6 +120,7 @@ impl PanelId {
PanelId::PointCloudManager => include_bytes!("../../assets/icons/pc_attach.svg"),
PanelId::Count => include_bytes!("../../assets/icons/data_extract.svg"),
PanelId::SheetSetManager => include_bytes!("../../assets/icons/sheetset.svg"),
PanelId::Layers => include_bytes!("../../assets/icons/layers/panel.svg"),
}
}
@@ -126,6 +135,7 @@ impl PanelId {
PanelId::PointCloudManager => 280.0,
PanelId::Count => 280.0,
PanelId::SheetSetManager => 280.0,
PanelId::Layers => 560.0,
}
}
@@ -133,7 +143,7 @@ impl PanelId {
/// column-rich, so it allows double the shared maximum.
fn max_width(self) -> f32 {
match self {
PanelId::ExternalReferences => DOCK_MAX_W * 2.0,
PanelId::ExternalReferences | PanelId::Layers => DOCK_MAX_W * 2.0,
_ => DOCK_MAX_W,
}
}
@@ -699,6 +709,7 @@ pub fn title_bar<'a>(id: PanelId, title: String, chrome: Chrome) -> Element<'a,
.padding([3, 6]),
)
.on_press(Message::Dock(DockMsg::DockGrab(id)))
.on_double_click(Message::Dock(DockMsg::FloatOut(id)))
.on_enter(Message::Dock(DockMsg::TitleHover(Some(id))))
.on_exit(Message::Dock(DockMsg::TitleHover(None)))
.interaction(iced::mouse::Interaction::Grab)
@@ -1098,16 +1109,7 @@ mod tests {
#[test]
fn every_panel_has_its_own_icon() {
let ids = [
PanelId::Properties,
PanelId::BlockPalette,
PanelId::ExternalReferences,
PanelId::Browser,
PanelId::NodeGraph,
PanelId::PointCloudManager,
PanelId::Count,
PanelId::SheetSetManager,
];
let ids = PanelId::ALL;
for (i, a) in ids.iter().enumerate() {
assert!(a.icon().starts_with(b"<svg"), "{a:?} icon is not an SVG");
for b in &ids[i + 1..] {
+37 -4
View File
@@ -323,13 +323,46 @@ impl LayerPanel {
self.linetype_items = items;
}
/// Render the layer panel as the full content of its own OS window.
pub fn view_window(
/// The Layer Manager as a dock pallet: its title bar, then the table at
/// its natural width, scrolling sideways when the pallet is narrower.
pub fn view_panel(
&self,
name_col_w: f32,
sizing: crate::ui::modal::ModalSizing,
width: f32,
chrome: crate::ui::dock::Chrome,
) -> Element<'_, Message> {
self.view_content(name_col_w, sizing)
use crate::ui::dock::PanelId;
let title_bar = crate::ui::dock::title_bar(
PanelId::Layers,
crate::tr!("modal", "layer-manager"),
chrome,
);
let table = self.view_content(
name_col_w,
crate::ui::modal::ModalSizing {
width: Length::Shrink,
height: Length::Fill,
},
);
let body = scrollable(table)
.direction(iced::widget::scrollable::Direction::Horizontal(
iced::widget::scrollable::Scrollbar::new(),
))
.width(Length::Fill)
.height(Length::Fill);
container(column![title_bar, body])
.width(Length::Fixed(width))
.height(Length::Fill)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(theme.palette().background.base.color)),
border: Border {
color: theme.palette().background.neutral.color,
width: 1.0,
radius: 0.0.into(),
},
..Default::default()
})
.into()
}
fn view_content(