forked from 1b-agent/opencadstudio-upstream
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:
1 parent
3a87a18f32
commit
3d050fe1ab
7 files changed
+146
-24
No files matched your search
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user