feat(iced): make panels movable with Properties on right side
This commit is contained in:
@@ -4972,17 +4972,17 @@ impl HcieIcedApp {
|
||||
// ══════════════════════════════════════════
|
||||
// Window menu (7) — Photopea-style
|
||||
// ══════════════════════════════════════════
|
||||
(7, 0) => self.dock.reopen_pane(PaneType::Layers),
|
||||
(7, 1) => self.dock.reopen_pane(PaneType::History),
|
||||
(7, 2) => self.dock.reopen_pane(PaneType::Brushes),
|
||||
(7, 3) => self.dock.reopen_pane(PaneType::Filters),
|
||||
(7, 4) => self.dock.reopen_pane(PaneType::ColorPicker),
|
||||
(7, 5) => self.dock.reopen_pane(PaneType::Properties),
|
||||
(7, 6) => self.dock.reopen_pane(PaneType::AiChat),
|
||||
(7, 7) => self.dock.reopen_pane(PaneType::Geometry),
|
||||
(7, 8) => self.dock.reopen_pane(PaneType::Script),
|
||||
(7, 9) => self.dock.reopen_pane(PaneType::LayerDetails),
|
||||
(7, 10) => self.dock.reopen_pane(PaneType::AiScript),
|
||||
(7, 0) => self.dock.toggle_pane(PaneType::Layers),
|
||||
(7, 1) => self.dock.toggle_pane(PaneType::History),
|
||||
(7, 2) => self.dock.toggle_pane(PaneType::Brushes),
|
||||
(7, 3) => self.dock.toggle_pane(PaneType::Filters),
|
||||
(7, 4) => self.dock.toggle_pane(PaneType::ColorPicker),
|
||||
(7, 5) => self.dock.toggle_pane(PaneType::Properties),
|
||||
(7, 6) => self.dock.toggle_pane(PaneType::AiChat),
|
||||
(7, 7) => self.dock.toggle_pane(PaneType::Geometry),
|
||||
(7, 8) => self.dock.toggle_pane(PaneType::Script),
|
||||
(7, 9) => self.dock.toggle_pane(PaneType::LayerDetails),
|
||||
(7, 10) => self.dock.toggle_pane(PaneType::AiScript),
|
||||
// (7, 11) = separator
|
||||
(7, 12) => return Task::perform(async {}, |_| Message::ThemeChanged(crate::theme::ThemePreset::Photopea)),
|
||||
(7, 13) => return Task::perform(async {}, |_| Message::ThemeChanged(crate::theme::ThemePreset::Photoshop)),
|
||||
@@ -5391,7 +5391,7 @@ impl HcieIcedApp {
|
||||
&self.dock_profile_new_name,
|
||||
));
|
||||
}
|
||||
if let Some(menu_overlay) = panels::menus::dropdown_overlay(self.active_menu, &self.recent_files, self.theme_state.colors()) {
|
||||
if let Some(menu_overlay) = panels::menus::dropdown_overlay(self.active_menu, &self.recent_files, self.theme_state.colors(), Some(&self.dock)) {
|
||||
stack = stack.push(menu_overlay);
|
||||
}
|
||||
if let Some((cx, cy)) = self.canvas_context_menu {
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
//!
|
||||
//! ```text
|
||||
//! +--------+------------+-----------+---------+
|
||||
//! | | Brushes | | Layers |
|
||||
//! | Tools | & Tips | |---------|
|
||||
//! | (36px) |------------| Canvas | Properties
|
||||
//! | | Filters | |---------|
|
||||
//! | | | ColorBox | History |
|
||||
//! | | | | Layers |
|
||||
//! | Brushes| | |---------|
|
||||
//! |--------| Canvas | ColorBox |Properties|
|
||||
//! | Filters| |-----------|---------|
|
||||
//! | | | History | |
|
||||
//! +--------+------------+-----------+---------+
|
||||
//! ```
|
||||
|
||||
@@ -89,11 +89,12 @@ impl DockState {
|
||||
/// Dock layout (without toolbox), left → right:
|
||||
/// ```text
|
||||
/// +------------+-----------+-----------+-----------+
|
||||
/// | Brushes | | ColorBox | Layers |
|
||||
/// |------------| Canvas |-----------|-----------|
|
||||
/// | Filters | | History | Properties|
|
||||
/// | Brushes | | Layers | |
|
||||
/// |------------| Canvas |-----------|Properties |
|
||||
/// | Filters | | ColorBox |-----------|
|
||||
/// | | |-----------| History |
|
||||
/// +------------+-----------+-----------+-----------+
|
||||
/// ~17% ~66% ~8.5% ~8.5%
|
||||
/// ~14% ~66% ~10% ~10%
|
||||
/// ```
|
||||
///
|
||||
/// Axis semantics in iced PaneGrid:
|
||||
@@ -108,16 +109,21 @@ impl DockState {
|
||||
b: Box::new(Configuration::Pane(PaneType::Filters)),
|
||||
};
|
||||
|
||||
// Right column 1: ColorBox (top) / History (bottom)
|
||||
// Right column 1: Layers (top) / ColorBox (bottom) — horizontal split
|
||||
let right_col1 = Configuration::Split {
|
||||
axis: iced::widget::pane_grid::Axis::Horizontal,
|
||||
ratio: 0.4,
|
||||
a: Box::new(Configuration::Pane(PaneType::ColorPicker)),
|
||||
b: Box::new(Configuration::Pane(PaneType::History)),
|
||||
ratio: 0.5,
|
||||
a: Box::new(Configuration::Pane(PaneType::Layers)),
|
||||
b: Box::new(Configuration::Pane(PaneType::ColorPicker)),
|
||||
};
|
||||
|
||||
// Right column 2: Layers (full column)
|
||||
let right_col2 = Configuration::Pane(PaneType::Layers);
|
||||
// Right column 2: Properties (top) / History (bottom) — horizontal split
|
||||
let right_col2 = Configuration::Split {
|
||||
axis: iced::widget::pane_grid::Axis::Horizontal,
|
||||
ratio: 0.5,
|
||||
a: Box::new(Configuration::Pane(PaneType::Properties)),
|
||||
b: Box::new(Configuration::Pane(PaneType::History)),
|
||||
};
|
||||
|
||||
// Right side: right_col1 (left) / right_col2 (right) — vertical split
|
||||
let right_side = Configuration::Split {
|
||||
@@ -128,10 +134,10 @@ impl DockState {
|
||||
};
|
||||
|
||||
// Center + right: Canvas (left) / right_side (right) — vertical split
|
||||
// Canvas gets ~65% — right panels need room for layers + styles
|
||||
// Canvas gets ~66% — right panels need room for layers + properties
|
||||
let center_right = Configuration::Split {
|
||||
axis: iced::widget::pane_grid::Axis::Vertical,
|
||||
ratio: 0.65,
|
||||
ratio: 0.66,
|
||||
a: Box::new(Configuration::Pane(PaneType::Canvas)),
|
||||
b: Box::new(right_side),
|
||||
};
|
||||
@@ -238,4 +244,26 @@ impl DockState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a pane type is currently open in the dock.
|
||||
pub fn is_pane_open(&self, pane_type: PaneType) -> bool {
|
||||
self.pane_grid.iter().any(|(_, t)| *t == pane_type)
|
||||
}
|
||||
|
||||
/// Toggle a pane: close it if open, reopen it if closed.
|
||||
pub fn toggle_pane(&mut self, pane_type: PaneType) {
|
||||
let is_open = self.pane_grid.iter().any(|(_, t)| *t == pane_type);
|
||||
let pane = self.pane_grid.iter().find(|(_, t)| **t == pane_type).map(|(p, _)| *p);
|
||||
|
||||
if is_open {
|
||||
// Don't close the canvas pane
|
||||
if pane_type != PaneType::Canvas {
|
||||
if let Some(pane) = pane {
|
||||
self.close_pane(pane);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.reopen_pane(pane_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
//! - Sub-menus: indicated by ">" arrow on the right
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::dock::state::{DockState, PaneType};
|
||||
use crate::theme::ThemeColors;
|
||||
use hcie_engine_api::Tool;
|
||||
use iced::widget::{column, container, horizontal_rule, mouse_area, row, text};
|
||||
@@ -333,6 +334,7 @@ pub fn dropdown_overlay(
|
||||
active_menu: Option<usize>,
|
||||
recent_files: &[crate::app::RecentFileEntry],
|
||||
colors: ThemeColors,
|
||||
dock: Option<&DockState>,
|
||||
) -> Option<Element<'static, Message>> {
|
||||
let menu_idx = active_menu?;
|
||||
let menus = all_menus(recent_files);
|
||||
@@ -418,9 +420,35 @@ pub fn dropdown_overlay(
|
||||
let sht = item.shortcut.clone();
|
||||
let has_sub = item.has_submenu;
|
||||
|
||||
// Check if this is a Window menu item that should show a checkmark
|
||||
let is_window_panel = menu_idx == 7 && item_idx <= 10;
|
||||
let is_checked = if is_window_panel {
|
||||
let pane_type = match item_idx {
|
||||
0 => Some(PaneType::Layers),
|
||||
1 => Some(PaneType::History),
|
||||
2 => Some(PaneType::Brushes),
|
||||
3 => Some(PaneType::Filters),
|
||||
4 => Some(PaneType::ColorPicker),
|
||||
5 => Some(PaneType::Properties),
|
||||
6 => Some(PaneType::AiChat),
|
||||
7 => Some(PaneType::Geometry),
|
||||
8 => Some(PaneType::Script),
|
||||
9 => Some(PaneType::LayerDetails),
|
||||
10 => Some(PaneType::AiScript),
|
||||
_ => None,
|
||||
};
|
||||
pane_type.and_then(|pt| dock.map(|d| d.is_pane_open(pt))).unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Photopea-style: label left, shortcut right in gray, submenu arrow ">" if needed
|
||||
// Add checkmark prefix for open panels in Window menu
|
||||
let label_row: Element<'static, Message> = {
|
||||
let mut row_items = vec![];
|
||||
if is_checked {
|
||||
row_items.push(text("✓ ").size(13).color(iced::Color::from_rgba(0.2, 0.6, 0.2, 1.0)).into());
|
||||
}
|
||||
row_items.push(text(lbl).size(13).width(Length::Fill).into());
|
||||
if !sht.is_empty() {
|
||||
row_items.push(text(sht).size(12).color(iced::Color::from_rgba(0.4, 0.4, 0.4, 1.0)).into());
|
||||
|
||||
Reference in New Issue
Block a user