feat(ui): use the shared colour selector in properties, ribbon and layers
Replace the bespoke colour pickers with the shared color_selector / color_list widget so colour selection is identical everywhere: - left properties panel (selected entities' colour) - ribbon Home-tab colour dropdown - layer manager per-layer colour Each routes its "More…" entry to the standalone Select Color window via a ColorPickTarget (Properties / Ribbon / Layer). Extracted color_list as the shared popup content; the colour selector button now fills its container. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
dfb2c6f9d7
commit
f7734b698f
6 changed files with 91 additions and 167 deletions
|
|
@ -574,6 +574,12 @@ pub enum ColorPickTarget {
|
||||||
DimStyle(DsField),
|
DimStyle(DsField),
|
||||||
MLeader(&'static str),
|
MLeader(&'static str),
|
||||||
Table(u8, &'static str),
|
Table(u8, &'static str),
|
||||||
|
/// Selected entities' colour (left properties panel).
|
||||||
|
Properties,
|
||||||
|
/// Current creation colour (ribbon).
|
||||||
|
Ribbon,
|
||||||
|
/// A layer's colour, by panel row index.
|
||||||
|
Layer(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identifies a DimStyle field that can be edited in the dialog.
|
/// Identifies a DimStyle field that can be edited in the dialog.
|
||||||
|
|
|
||||||
|
|
@ -7330,6 +7330,10 @@ impl OpenCADStudio {
|
||||||
self.ds_color_open = None;
|
self.ds_color_open = None;
|
||||||
self.mls_color_open = None;
|
self.mls_color_open = None;
|
||||||
self.ts_color_open = None;
|
self.ts_color_open = None;
|
||||||
|
self.ribbon.close_dropdown();
|
||||||
|
let i = self.active_tab;
|
||||||
|
self.tabs[i].properties.color_picker_open = false;
|
||||||
|
self.tabs[i].layers.color_picker_row = None;
|
||||||
if let Some(id) = self.color_pick_window {
|
if let Some(id) = self.color_pick_window {
|
||||||
return window::gain_focus(id);
|
return window::gain_focus(id);
|
||||||
}
|
}
|
||||||
|
|
@ -7356,6 +7360,19 @@ impl OpenCADStudio {
|
||||||
value: s,
|
value: s,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Some(crate::app::ColorPickTarget::Properties) => {
|
||||||
|
Some(Message::PropColorChanged(color))
|
||||||
|
}
|
||||||
|
Some(crate::app::ColorPickTarget::Ribbon) => {
|
||||||
|
Some(Message::RibbonColorChanged(color))
|
||||||
|
}
|
||||||
|
Some(crate::app::ColorPickTarget::Layer(idx)) => {
|
||||||
|
self.tabs[self.active_tab].layers.selected = Some(idx);
|
||||||
|
match color {
|
||||||
|
acadrust::types::Color::Index(i) => Some(Message::LayerColorSet(i)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -111,13 +111,41 @@ pub fn color_selector<'a>(
|
||||||
)
|
)
|
||||||
.on_press(on_toggle)
|
.on_press(on_toggle)
|
||||||
.padding([3, 6])
|
.padding([3, 6])
|
||||||
.width(170);
|
.width(Length::Fill);
|
||||||
|
|
||||||
if !open {
|
if !open {
|
||||||
return head.into();
|
return head.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// One named-colour row (swatch + name), selectable.
|
let popup = container(color_list(extras, on_select, on_more))
|
||||||
|
.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(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The colour list shown inside a picker popup: named ACI colours (with
|
||||||
|
/// swatches) plus a "More…" entry that opens the full palette window. Shared by
|
||||||
|
/// `color_selector` and the ribbon's colour overlay.
|
||||||
|
pub fn color_list<'a>(
|
||||||
|
extras: ColorExtras,
|
||||||
|
on_select: impl Fn(AcadColor) -> Message + 'a,
|
||||||
|
on_more: Message,
|
||||||
|
) -> Element<'a, Message> {
|
||||||
let named_row = |color: AcadColor| -> Element<'a, Message> {
|
let named_row = |color: AcadColor| -> Element<'a, Message> {
|
||||||
let (bg, name) = acad_color_display(color);
|
let (bg, name) = acad_color_display(color);
|
||||||
button(
|
button(
|
||||||
|
|
@ -151,7 +179,6 @@ pub fn color_selector<'a>(
|
||||||
for i in 1u8..=9 {
|
for i in 1u8..=9 {
|
||||||
list = list.push(named_row(AcadColor::Index(i)));
|
list = list.push(named_row(AcadColor::Index(i)));
|
||||||
}
|
}
|
||||||
// "More…" opens the full ACI palette in a separate window.
|
|
||||||
list = list.push(
|
list = list.push(
|
||||||
button(text("More…").size(11).color(TEXT))
|
button(text("More…").size(11).color(TEXT))
|
||||||
.on_press(on_more)
|
.on_press(on_more)
|
||||||
|
|
@ -168,26 +195,7 @@ pub fn color_selector<'a>(
|
||||||
.padding([2, 4])
|
.padding([2, 4])
|
||||||
.width(Length::Fill),
|
.width(Length::Fill),
|
||||||
);
|
);
|
||||||
|
list.into()
|
||||||
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
|
/// Full ACI palette as a standalone window body: ByLayer / ByBlock plus the
|
||||||
|
|
|
||||||
107
src/ui/layers.rs
107
src/ui/layers.rs
|
|
@ -1,7 +1,7 @@
|
||||||
//! Layer Manager — floating window.
|
//! Layer Manager — floating window.
|
||||||
|
|
||||||
use crate::app::Message;
|
use crate::app::Message;
|
||||||
use crate::ui::properties::{color_picker_dropdown, lw_options, LinetypeItem, LwItem};
|
use crate::ui::properties::{lw_options, LinetypeItem, LwItem};
|
||||||
use crate::ui::ROW_H;
|
use crate::ui::ROW_H;
|
||||||
use acadrust::tables::layer::Layer as DocLayer;
|
use acadrust::tables::layer::Layer as DocLayer;
|
||||||
use acadrust::tables::Table;
|
use acadrust::tables::Table;
|
||||||
|
|
@ -271,10 +271,6 @@ impl LayerPanel {
|
||||||
&self.vp_cols,
|
&self.vp_cols,
|
||||||
));
|
));
|
||||||
|
|
||||||
// Insert color picker dropdown below this row when open.
|
|
||||||
if color_open {
|
|
||||||
rows_col = rows_col.push(color_picker_palette(self.color_full_palette));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let table = scrollable(rows_col).height(Fill);
|
let table = scrollable(rows_col).height(Fill);
|
||||||
|
|
@ -559,77 +555,23 @@ fn layer_row<'a>(
|
||||||
// Color cell — looks like a combo_box input; click opens swatch dropdown below row.
|
// Color cell — looks like a combo_box input; click opens swatch dropdown below row.
|
||||||
let aci = iced_to_aci(layer.color);
|
let aci = iced_to_aci(layer.color);
|
||||||
let cur_color_name = color_label_aci(aci).to_string();
|
let cur_color_name = color_label_aci(aci).to_string();
|
||||||
let layer_color = layer.color;
|
let _ = cur_color_name;
|
||||||
|
// Shared colour selector. Layers carry a concrete colour (no ByLayer /
|
||||||
let swatch = container(text(""))
|
// ByBlock); the chosen index is applied to this row.
|
||||||
.style(move |_: &Theme| container::Style {
|
let color_cell: Element<'_, Message> = container(crate::ui::color_select::color_selector(
|
||||||
background: Some(Background::Color(layer_color)),
|
acadrust::types::Color::Index(aci),
|
||||||
border: Border {
|
color_picker_open,
|
||||||
color: Color {
|
crate::ui::color_select::ColorExtras {
|
||||||
r: 0.0,
|
by_layer: false,
|
||||||
g: 0.0,
|
by_block: false,
|
||||||
b: 0.0,
|
|
||||||
a: 0.5,
|
|
||||||
},
|
|
||||||
width: 1.0,
|
|
||||||
radius: 1.0.into(),
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.width(12)
|
|
||||||
.height(12);
|
|
||||||
|
|
||||||
let color_cell: Element<'_, Message> = button(
|
|
||||||
row![
|
|
||||||
swatch,
|
|
||||||
text(cur_color_name).size(FONT_SZ).color(ROW_TEXT),
|
|
||||||
iced::widget::Space::new().width(Fill),
|
|
||||||
text(if color_picker_open { "▲" } else { "▼" })
|
|
||||||
.size(FONT_SZ * 0.75)
|
|
||||||
.color(DIM),
|
|
||||||
]
|
|
||||||
.spacing(4)
|
|
||||||
.align_y(iced::Center),
|
|
||||||
)
|
|
||||||
.on_press(Message::LayerColorPickerToggle(index))
|
|
||||||
.style(move |_: &Theme, status| button::Style {
|
|
||||||
background: Some(Background::Color(match status {
|
|
||||||
button::Status::Hovered => Color {
|
|
||||||
r: 0.20,
|
|
||||||
g: 0.20,
|
|
||||||
b: 0.20,
|
|
||||||
a: 1.0,
|
|
||||||
},
|
|
||||||
_ => Color {
|
|
||||||
r: 0.13,
|
|
||||||
g: 0.13,
|
|
||||||
b: 0.13,
|
|
||||||
a: 1.0,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
border: Border {
|
|
||||||
radius: 2.0.into(),
|
|
||||||
width: 1.0,
|
|
||||||
color: if color_picker_open {
|
|
||||||
Color {
|
|
||||||
r: 0.45,
|
|
||||||
g: 0.65,
|
|
||||||
b: 0.90,
|
|
||||||
a: 1.0,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BORDER_COLOR
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
..Default::default()
|
|c| match c {
|
||||||
})
|
acadrust::types::Color::Index(i) => Message::LayerColorSet(i),
|
||||||
.padding(Padding {
|
_ => Message::LayerColorSet(7),
|
||||||
top: COMBO_PAD_V,
|
},
|
||||||
bottom: COMBO_PAD_V,
|
Message::LayerColorPickerToggle(index),
|
||||||
left: 4.0,
|
Message::OpenColorWindow(crate::app::ColorPickTarget::Layer(index)),
|
||||||
right: 4.0,
|
))
|
||||||
})
|
|
||||||
.height(Length::Fixed(ROW_H))
|
|
||||||
.width(Length::Fixed(COL_COLOR))
|
.width(Length::Fixed(COL_COLOR))
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
|
@ -815,21 +757,6 @@ fn combo_input_style(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Color picker palette (shown below row) ────────────────────────────────
|
|
||||||
|
|
||||||
fn color_picker_palette<'a>(full: bool) -> Element<'a, Message> {
|
|
||||||
// Horizontal offset to align dropdown under the Color column.
|
|
||||||
const LEFT_OFFSET: f32 =
|
|
||||||
20.0 + 4.0 + COL_NAME + 4.0 + COL_ICON + 4.0 + COL_ICON + 4.0 + COL_ICON + 4.0 + 8.0;
|
|
||||||
|
|
||||||
// Use the shared color_picker_dropdown from properties — no ByLayer/ByBlock for layers.
|
|
||||||
let dropdown = color_picker_dropdown(full, Message::LayerColorMorePalette, None, None, |aci| {
|
|
||||||
Message::LayerColorSet(aci)
|
|
||||||
});
|
|
||||||
|
|
||||||
row![iced::widget::Space::new().width(LEFT_OFFSET), dropdown,].into()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Display helpers ───────────────────────────────────────────────────────
|
// ── Display helpers ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
||||||
|
|
@ -377,53 +377,18 @@ impl PropertiesPanel {
|
||||||
// ── Color row (custom picker) ─────────────────────────────────────────
|
// ── Color row (custom picker) ─────────────────────────────────────────
|
||||||
|
|
||||||
fn render_color_row<'a>(&'a self, label: &'a str, color: AcadColor) -> Element<'a, Message> {
|
fn render_color_row<'a>(&'a self, label: &'a str, color: AcadColor) -> Element<'a, Message> {
|
||||||
let (swatch_bg, color_label) = acad_color_display(color);
|
let selector = crate::ui::color_select::color_selector(
|
||||||
|
color,
|
||||||
// The button that shows current color + opens picker
|
self.color_picker_open,
|
||||||
let color_btn = button(
|
crate::ui::color_select::ColorExtras {
|
||||||
row![
|
by_layer: true,
|
||||||
container(text("").width(SWATCH_SZ).height(SWATCH_SZ))
|
by_block: true,
|
||||||
.style(move |_: &Theme| container::Style {
|
},
|
||||||
background: Some(Background::Color(swatch_bg)),
|
Message::PropColorChanged,
|
||||||
border: Border {
|
Message::PropColorPickerToggle,
|
||||||
color: Color {
|
Message::OpenColorWindow(crate::app::ColorPickTarget::Properties),
|
||||||
r: 0.0,
|
);
|
||||||
g: 0.0,
|
prop_row_widget(label, selector)
|
||||||
b: 0.0,
|
|
||||||
a: 0.5
|
|
||||||
},
|
|
||||||
width: 1.0,
|
|
||||||
radius: 2.0.into()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.width(SWATCH_SZ)
|
|
||||||
.height(SWATCH_SZ),
|
|
||||||
text(color_label).size(FONT_SZ).color(VALUE_COLOR),
|
|
||||||
]
|
|
||||||
.spacing(4)
|
|
||||||
.align_y(iced::Center),
|
|
||||||
)
|
|
||||||
.on_press(Message::PropColorPickerToggle)
|
|
||||||
.style(combo_btn_style)
|
|
||||||
.padding(Padding {
|
|
||||||
top: COMBO_PAD_V,
|
|
||||||
bottom: COMBO_PAD_V,
|
|
||||||
left: 6.0,
|
|
||||||
right: 6.0,
|
|
||||||
})
|
|
||||||
.width(Length::Fill);
|
|
||||||
|
|
||||||
let color_row = prop_row_widget(label, color_btn.into());
|
|
||||||
|
|
||||||
// Color picker dropdown (inline)
|
|
||||||
if self.color_picker_open {
|
|
||||||
column![color_row, self.render_color_picker()]
|
|
||||||
.spacing(0)
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
color_row
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_color_varies_row<'a>(&'a self, label: &'a str) -> Element<'a, Message> {
|
fn render_color_varies_row<'a>(&'a self, label: &'a str) -> Element<'a, Message> {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use iced::{Background, Border, Color, Element, Fill, Length, Padding, Theme};
|
||||||
use crate::app::Message;
|
use crate::app::Message;
|
||||||
use crate::modules::{CadModule, IconKind, RibbonItem};
|
use crate::modules::{CadModule, IconKind, RibbonItem};
|
||||||
use crate::plugin::all_ribbon_modules;
|
use crate::plugin::all_ribbon_modules;
|
||||||
use crate::ui::properties::{color_picker_dropdown, lw_options, LinetypeItem};
|
use crate::ui::properties::{lw_options, LinetypeItem};
|
||||||
|
|
||||||
mod widgets;
|
mod widgets;
|
||||||
use widgets::{StyleContext, *};
|
use widgets::{StyleContext, *};
|
||||||
|
|
@ -817,12 +817,13 @@ impl Ribbon {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prop_color_overlay(&self) -> Option<Element<'_, Message>> {
|
fn prop_color_overlay(&self) -> Option<Element<'_, Message>> {
|
||||||
let picker = color_picker_dropdown(
|
let picker = crate::ui::color_select::color_list(
|
||||||
self.prop_color_palette_open,
|
crate::ui::color_select::ColorExtras {
|
||||||
Message::RibbonColorPaletteToggle,
|
by_layer: true,
|
||||||
Some(Message::RibbonColorChanged(AcadColor::ByLayer)),
|
by_block: true,
|
||||||
Some(Message::RibbonColorChanged(AcadColor::ByBlock)),
|
},
|
||||||
|aci| Message::RibbonColorChanged(AcadColor::Index(aci)),
|
Message::RibbonColorChanged,
|
||||||
|
Message::OpenColorWindow(crate::app::ColorPickTarget::Ribbon),
|
||||||
);
|
);
|
||||||
|
|
||||||
let panel = container(picker)
|
let panel = container(picker)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue