From 3d050fe1abe4fe76c076abc4cfaeaced20367c2f Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Sun, 14 Jun 2026 11:14:14 +0300 Subject: [PATCH] feat(ui): move full ACI palette to a separate "Select Color" window (#94) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The colour selector popup now lists only the named colours (ByLayer, ByBlock, ACI 1-9) plus a "More…" entry. "More…" opens a standalone "Select Color" window with the full 256-colour grid; picking there applies to the originating field (dimension/multileader/table style) and closes the window. Routed via a ColorPickTarget so one window serves every field. Co-Authored-By: Claude Opus 4.8 --- src/app/mod.rs | 20 +++++++++ src/app/update.rs | 46 ++++++++++++++++++++ src/app/view.rs | 3 ++ src/ui/color_select.rs | 96 ++++++++++++++++++++++++++++++++---------- src/ui/dimstyle.rs | 3 +- src/ui/mleaderstyle.rs | 1 + src/ui/tablestyle.rs | 1 + 7 files changed, 146 insertions(+), 24 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index 551034aa4..eea872c8c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -287,6 +287,9 @@ pub(super) struct OpenCADStudio { layout_manager_window: Option, plotstyle_window: Option, dimstyle_window: Option, + /// Standalone "Select Color" palette window + the field it targets. + color_pick_window: Option, + color_pick_target: Option, shortcuts_window: Option, about_window: Option, /// New-release notification window — opened on startup when the @@ -565,6 +568,14 @@ pub(super) enum PendingClose { Quit, } +/// Where a colour chosen in the standalone palette window should be applied. +#[derive(Debug, Clone)] +pub enum ColorPickTarget { + DimStyle(DsField), + MLeader(&'static str), + Table(u8, &'static str), +} + /// Identifies a DimStyle field that can be edited in the dialog. #[derive(Debug, Clone, PartialEq, Eq)] pub enum DsField { @@ -1267,6 +1278,10 @@ pub enum Message { DsToggle(DsField), /// Toggle the expanded colour palette for a DimStyle colour field. DsColorMore(DsField), + /// Open the standalone palette window targeting the given field. + OpenColorWindow(ColorPickTarget), + /// A colour was chosen in the standalone palette window. + ColorWindowPick(acadrust::types::Color), /// Set a block/linetype Handle field on the selected dim style from a /// dropdown of available block-records / linetypes (by name). DsSetHandle { @@ -1377,6 +1392,8 @@ impl OpenCADStudio { layout_manager_window: None, plotstyle_window: None, dimstyle_window: None, + color_pick_window: None, + color_pick_target: None, shortcuts_window: None, about_window: None, update_notice_window: None, @@ -1656,6 +1673,9 @@ pub fn run() -> iced::Result { if Some(window_id) == state.layer_window { return "Layer Properties Manager".into(); } + if Some(window_id) == state.color_pick_window { + return "Select Color".into(); + } if Some(window_id) == state.page_setup_window { return "Page Setup".into(); } diff --git a/src/app/update.rs b/src/app/update.rs index 3f3cde367..c3d026f15 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -1624,6 +1624,10 @@ impl OpenCADStudio { self.dimstyle_window = None; self.ribbon.deactivate_tool_if("DIMSTYLE"); } + if self.color_pick_window == Some(id) { + self.color_pick_window = None; + self.color_pick_target = None; + } if self.shortcuts_window == Some(id) { self.shortcuts_window = None; self.ribbon.deactivate_tool_if("SHORTCUTS"); @@ -7321,6 +7325,48 @@ impl OpenCADStudio { }; Task::none() } + Message::OpenColorWindow(target) => { + self.color_pick_target = Some(target); + self.ds_color_open = None; + self.mls_color_open = None; + self.ts_color_open = None; + if let Some(id) = self.color_pick_window { + return window::gain_focus(id); + } + let (id, task) = window::open(window::Settings { + size: iced::Size::new(420.0, 470.0), + resizable: true, + level: window::Level::AlwaysOnTop, + ..Default::default() + }); + self.color_pick_window = Some(id); + task.map(|_| Message::Noop) + } + Message::ColorWindowPick(color) => { + let s = crate::ui::color_select::color_to_aci_string(color); + let edit = match self.color_pick_target.take() { + Some(crate::app::ColorPickTarget::DimStyle(f)) => Some(Message::DsEdit(f, s)), + Some(crate::app::ColorPickTarget::MLeader(f)) => { + Some(Message::MLeaderStyleEdit { field: f, value: s }) + } + Some(crate::app::ColorPickTarget::Table(r, f)) => { + Some(Message::TableStyleCellEdit { + row: r, + field: f, + value: s, + }) + } + None => None, + }; + let mut tasks = Vec::new(); + if let Some(m) = edit { + tasks.push(self.update(m)); + } + if let Some(id) = self.color_pick_window.take() { + tasks.push(window::close(id)); + } + Task::batch(tasks) + } Message::DsSetHandle { field, value } => { let i = self.active_tab; let name = self.dimstyle_selected.clone(); diff --git a/src/app/view.rs b/src/app/view.rs index a55d9a4da..d4ffd71a9 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -465,6 +465,9 @@ impl OpenCADStudio { &self.style_rename_buf, ); } + if Some(window_id) == self.color_pick_window { + return crate::ui::color_select::color_grid_window(Message::ColorWindowPick); + } if Some(window_id) == self.shortcuts_window { return crate::ui::shortcuts::view_window(&self.shortcut_overrides); } diff --git a/src/ui/color_select.rs b/src/ui/color_select.rs index c4d3c64c1..ae1a1390b 100644 --- a/src/ui/color_select.rs +++ b/src/ui/color_select.rs @@ -95,6 +95,7 @@ pub fn color_selector<'a>( extras: ColorExtras, on_select: impl Fn(AcadColor) -> Message + 'a, on_toggle: Message, + on_more: Message, ) -> Element<'a, Message> { let (cur_bg, cur_name) = acad_color_display(current); @@ -150,13 +151,65 @@ pub fn color_selector<'a>( for i in 1u8..=9 { list = list.push(named_row(AcadColor::Index(i))); } + // "More…" opens the full ACI palette in a separate window. + list = list.push( + button(text("More…").size(11).color(TEXT)) + .on_press(on_more) + .style(|_: &Theme, status| button::Style { + background: matches!(status, button::Status::Hovered) + .then_some(Background::Color(Color { + r: 0.25, + g: 0.25, + b: 0.30, + a: 1.0, + })), + ..Default::default() + }) + .padding([2, 4]) + .width(Length::Fill), + ); + + let popup = container(list) + .style(|_: &Theme| container::Style { + background: Some(Background::Color(PICKER_BG)), + border: Border { + color: BORDER, + width: 1.0, + radius: 2.0.into(), + }, + ..Default::default() + }) + .padding(5) + .width(220); + + // The popup is shown as a floating overlay (anchored below the button) so + // it doesn't push the surrounding form down. + Element::new(Floating { + base: head.into(), + popup: popup.into(), + }) +} + +/// Full ACI palette as a standalone window body: ByLayer / ByBlock plus the +/// 256-colour grid. `on_pick` is called with the chosen colour. +pub fn color_grid_window(on_pick: impl Fn(AcadColor) -> Message) -> Element<'static, Message> { + let chip = |color: AcadColor, label: &'static str| -> Element<'static, Message> { + let (bg, _) = acad_color_display(color); + button( + row![swatch(bg), text(label).size(11).color(TEXT)] + .spacing(5) + .align_y(iced::Center), + ) + .on_press(on_pick(color)) + .padding([3, 6]) + .into() + }; - // Full ACI palette grid (10-255) below the named colours. const COLS: u16 = 16; - let mut grid = column![].spacing(1); + let mut grid = column![].spacing(2); let mut idx: u16 = 1; while idx <= 255 { - let mut r = row![].spacing(1); + let mut r = row![].spacing(2); for _ in 0..COLS { if idx > 255 { break; @@ -164,8 +217,8 @@ pub fn color_selector<'a>( let ci = idx as u8; let (bg, _) = acad_color_display(AcadColor::Index(ci)); r = r.push( - button(text("").width(12).height(12)) - .on_press(on_select(AcadColor::Index(ci))) + button(text("").width(18).height(18)) + .on_press(on_pick(AcadColor::Index(ci))) .style(move |_: &Theme, status| button::Style { background: Some(Background::Color(bg)), border: Border { @@ -195,25 +248,22 @@ pub fn color_selector<'a>( grid = grid.push(r); } - let popup = container(column![list, scrollable(grid).height(120)].spacing(4)) - .style(|_: &Theme| container::Style { - background: Some(Background::Color(PICKER_BG)), - border: Border { - color: BORDER, - width: 1.0, - radius: 2.0.into(), - }, - ..Default::default() - }) - .padding(5) - .width(220); - - // The popup is shown as a floating overlay (anchored below the button) so - // it doesn't push the surrounding form down. - Element::new(Floating { - base: head.into(), - popup: popup.into(), + container( + column![ + text("Select Color").size(13).color(TEXT), + row![chip(AcadColor::ByLayer, "ByLayer"), chip(AcadColor::ByBlock, "ByBlock")].spacing(6), + scrollable(grid).height(Length::Fill), + ] + .spacing(8), + ) + .style(|_: &Theme| container::Style { + background: Some(Background::Color(PICKER_BG)), + ..Default::default() }) + .padding(10) + .width(Length::Fill) + .height(Length::Fill) + .into() } /// A widget that renders `base` inline and `popup` as a floating overlay diff --git a/src/ui/dimstyle.rs b/src/ui/dimstyle.rs index 82031b8b1..af4e38b2e 100644 --- a/src/ui/dimstyle.rs +++ b/src/ui/dimstyle.rs @@ -1,6 +1,6 @@ //! Dimension Style Manager window — fills the entire OS window. -use crate::app::{DsField, Message}; +use crate::app::{ColorPickTarget, DsField, Message}; use iced::widget::{ button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Space, }; @@ -308,6 +308,7 @@ pub fn view_window<'a>( }, move |c| Message::DsEdit(f_sel.clone(), crate::ui::color_select::color_to_aci_string(c)), Message::DsColorMore(fld.clone()), + Message::OpenColorWindow(ColorPickTarget::DimStyle(fld.clone())), ); row![lbl(label), selector] .spacing(8) diff --git a/src/ui/mleaderstyle.rs b/src/ui/mleaderstyle.rs index dccbf0716..6ad8767e2 100644 --- a/src/ui/mleaderstyle.rs +++ b/src/ui/mleaderstyle.rs @@ -149,6 +149,7 @@ fn color_row<'a>( value: crate::ui::color_select::color_to_aci_string(c), }, Message::MLeaderColorMore(field), + Message::OpenColorWindow(crate::app::ColorPickTarget::MLeader(field)), ); row![text(label).size(11).color(DIM).width(150), selector] .spacing(8) diff --git a/src/ui/tablestyle.rs b/src/ui/tablestyle.rs index 79a184042..b96ef808a 100644 --- a/src/ui/tablestyle.rs +++ b/src/ui/tablestyle.rs @@ -140,6 +140,7 @@ pub fn view_window<'a>( value: crate::ui::color_select::color_to_aci_string(c), }, Message::TableColorMore(row, field), + Message::OpenColorWindow(crate::app::ColorPickTarget::Table(row, field)), ); row![text(label).size(11).color(DIM).width(150), selector] .spacing(8)