feat(ui): move full ACI palette to a separate "Select Color" window (#94)

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 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-14 11:14:14 +03:00
1 parent 3a87a18f32
commit 3d050fe1ab
7 files changed
+146 -24

No files matched your search

+20
View File
@@ -287,6 +287,9 @@ pub(super) struct OpenCADStudio {
layout_manager_window: Option<window::Id>,
plotstyle_window: Option<window::Id>,
dimstyle_window: Option<window::Id>,
/// Standalone "Select Color" palette window + the field it targets.
color_pick_window: Option<window::Id>,
color_pick_target: Option<ColorPickTarget>,
shortcuts_window: Option<window::Id>,
about_window: Option<window::Id>,
/// 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();
}
+46
View File
@@ -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();
+3
View File
@@ -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);
}
+73 -23
View File
@@ -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
+2 -1
View File
@@ -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)
+1
View File
@@ -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)
+1
View File
@@ -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)