forked from 1b-agent/opencadstudio-upstream
Select Color and ribbon: ByLayer shows the layer's colour
ByLayer swatches were always gray. The Select Color panel's Current/New band and info line now show the colour of the layer the colour is for (the newest selected object's layer, or the current layer for new objects); the ribbon's colour control and the ByLayer row of its colour dropdown show the current layer's colour. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013rGmDUNr1hUf4zo1X3dak8
This commit is contained in:
5 files changed
+79
-12
No files matched your search
@@ -11563,12 +11563,14 @@ impl OpenCADStudio {
|
||||
let mut picker = crate::ui::color_select::ColorPicker::new(target, current, varies);
|
||||
if !matches!(picker.target, crate::app::ColorPickTarget::Interface(_)) {
|
||||
self.read_color_books();
|
||||
let by_layer = self.color_picker_layer_color(&picker.target);
|
||||
let tab = &self.tabs[self.active_tab];
|
||||
picker = picker.with_drawing(
|
||||
crate::ui::color_select::document::collect(&tab.scene.document),
|
||||
&tab.recent_colors,
|
||||
std::sync::Arc::clone(&self.color_books),
|
||||
name,
|
||||
by_layer,
|
||||
);
|
||||
}
|
||||
self.color_picker = Some(picker);
|
||||
@@ -11734,6 +11736,29 @@ impl OpenCADStudio {
|
||||
(newest, true, name_of(newest_handle))
|
||||
}
|
||||
|
||||
/// The colour ByLayer stands for in the Select Color panel: the layer of
|
||||
/// the newest selected object, or the current layer for new objects.
|
||||
fn color_picker_layer_color(
|
||||
&self,
|
||||
target: &crate::app::ColorPickTarget,
|
||||
) -> Option<codec::types::Color> {
|
||||
let i = self.active_tab;
|
||||
let document = &self.tabs[i].scene.document;
|
||||
let layer = match target {
|
||||
crate::app::ColorPickTarget::Properties => self
|
||||
.property_target_handles(i)
|
||||
.into_iter()
|
||||
.max()
|
||||
.and_then(|handle| document.get_entity(handle))
|
||||
.map_or(self.tabs[i].active_layer.as_str(), |entity| {
|
||||
entity.as_entity().layer()
|
||||
}),
|
||||
crate::app::ColorPickTarget::Ribbon => self.tabs[i].active_layer.as_str(),
|
||||
_ => return None,
|
||||
};
|
||||
document.layers.get(layer).map(|layer| layer.color)
|
||||
}
|
||||
|
||||
/// Read the built-in colour books and the ones remembered in the
|
||||
/// settings, once per session. A loaded book replaces a built-in one of
|
||||
/// the same name.
|
||||
|
||||
@@ -104,6 +104,8 @@ pub struct ColorPicker {
|
||||
book_query: String,
|
||||
/// Why the last colour book did not load.
|
||||
status: Option<String>,
|
||||
/// What ByLayer looks like here: the layer's colour.
|
||||
by_layer: Option<AcadColor>,
|
||||
}
|
||||
|
||||
impl ColorPicker {
|
||||
@@ -127,18 +129,23 @@ impl ColorPicker {
|
||||
book_page: 0,
|
||||
book_query: String::new(),
|
||||
status: None,
|
||||
by_layer: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill the Document and Color books tabs. `current_name` is the
|
||||
/// `BOOK$NAME` of the current colour; the Color books tab shows its page.
|
||||
/// `by_layer` is the colour of the layer the colour is for, so ByLayer
|
||||
/// shows that colour instead of gray.
|
||||
pub fn with_drawing(
|
||||
mut self,
|
||||
mut doc: Vec<DocColor>,
|
||||
recent: &[AcadColor],
|
||||
books: Arc<Vec<ColorBook>>,
|
||||
current_name: Option<String>,
|
||||
by_layer: Option<AcadColor>,
|
||||
) -> Self {
|
||||
self.by_layer = by_layer;
|
||||
document::sort(&mut doc, self.doc_sort, recent);
|
||||
self.doc = doc;
|
||||
self.recent = recent.to_vec();
|
||||
@@ -330,6 +337,14 @@ impl ColorPicker {
|
||||
None
|
||||
}
|
||||
|
||||
/// How a colour looks; ByLayer takes the layer's colour when known.
|
||||
fn shown(&self, color: AcadColor) -> Color {
|
||||
match (color, self.by_layer) {
|
||||
(AcadColor::ByLayer, Some(layer)) => acad_color_display(layer).0,
|
||||
_ => acad_color_display(color).0,
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_book(&mut self, index: usize) {
|
||||
let books = Arc::clone(&self.books);
|
||||
let Some(book) = books.get(self.book) else {
|
||||
@@ -366,8 +381,7 @@ impl ColorPicker {
|
||||
if self.tab == ColorPickerTab::Index {
|
||||
body = body.push(Space::new().height(Length::Fill));
|
||||
}
|
||||
let fill =
|
||||
math::color_rgb(self.pending).map_or(Color::from_rgb8(128, 128, 128), rgb_color);
|
||||
let fill = self.shown(self.pending);
|
||||
let info = match (&self.status, &self.pending_name) {
|
||||
(Some(status), _) => status.clone(),
|
||||
(None, Some(name)) => {
|
||||
@@ -469,8 +483,8 @@ impl ColorPicker {
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
};
|
||||
let (current_bg, _) = acad_color_display(self.current);
|
||||
let (new_bg, _) = acad_color_display(self.pending);
|
||||
let current_bg = self.shown(self.current);
|
||||
let new_bg = self.shown(self.pending);
|
||||
// A colour-book colour shows its own name, without the book.
|
||||
let name = |color: AcadColor, identity: &Option<String>| match identity {
|
||||
Some(identity) => identity
|
||||
@@ -1336,7 +1350,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn book_colours_keep_their_name_until_edited() {
|
||||
let mut p = picker(AcadColor::Index(30)).with_drawing(Vec::new(), &[], ral(), None);
|
||||
let mut p = picker(AcadColor::Index(30)).with_drawing(Vec::new(), &[], ral(), None, None);
|
||||
p.update(ColorPickerMsg::PickBook(2));
|
||||
assert_eq!(p.book_page, 1, "turns to the colour's page");
|
||||
assert_eq!(
|
||||
@@ -1367,7 +1381,13 @@ mod tests {
|
||||
g: 113,
|
||||
b: 179,
|
||||
})
|
||||
.with_drawing(Vec::new(), &[], ral(), Some("RAL CLASSIC$RAL 5015".into()));
|
||||
.with_drawing(
|
||||
Vec::new(),
|
||||
&[],
|
||||
ral(),
|
||||
Some("RAL CLASSIC$RAL 5015".into()),
|
||||
None,
|
||||
);
|
||||
assert_eq!(p.book_selection(), Some(2));
|
||||
assert_eq!(p.book_page, 1);
|
||||
}
|
||||
@@ -1377,7 +1397,7 @@ mod tests {
|
||||
// A new drawing's layer 0 is white.
|
||||
let doc = document::collect(&codec::CadDocument::new());
|
||||
assert!(doc.iter().any(|c| c.color == AcadColor::Index(7)));
|
||||
let mut p = picker(AcadColor::Index(30)).with_drawing(doc, &[], Arc::default(), None);
|
||||
let mut p = picker(AcadColor::Index(30)).with_drawing(doc, &[], Arc::default(), None, None);
|
||||
p.update(ColorPickerMsg::Tab(ColorPickerTab::Document));
|
||||
p.update(ColorPickerMsg::Arrow(ArrowKey::Right));
|
||||
assert_eq!(
|
||||
@@ -1587,6 +1607,7 @@ mod tests {
|
||||
&[],
|
||||
books,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
p.update(ColorPickerMsg::Tab(tab));
|
||||
if name == "books" {
|
||||
|
||||
@@ -157,12 +157,14 @@ fn divider<'a>() -> Element<'a, Message> {
|
||||
.into()
|
||||
}
|
||||
|
||||
/// `shown` overrides the swatch, so ByLayer can show the layer's colour.
|
||||
fn logical_row<'a>(
|
||||
color: AcadColor,
|
||||
cur_color: AcadColor,
|
||||
label: &'static str,
|
||||
shown: Option<iced::Color>,
|
||||
) -> Element<'a, Message> {
|
||||
let (bg, _) = acad_color_display(color);
|
||||
let bg = shown.unwrap_or_else(|| acad_color_display(color).0);
|
||||
let selected = color == cur_color;
|
||||
|
||||
let swatch = container(
|
||||
@@ -212,13 +214,15 @@ fn more_colors_row<'a>(active_color: AcadColor) -> Element<'a, Message> {
|
||||
}
|
||||
|
||||
/// Builds the complete 5-section color dropdown panel element.
|
||||
/// `layer_color` is the current layer's colour, shown on the ByLayer row.
|
||||
pub fn color_dropdown_panel<'a>(
|
||||
active_color: AcadColor,
|
||||
recent_colors: &[AcadColor],
|
||||
layer_color: Option<iced::Color>,
|
||||
) -> Element<'a, Message> {
|
||||
// 1. ByLayer and ByBlock
|
||||
let by_layer = logical_row(AcadColor::ByLayer, active_color, "ByLayer");
|
||||
let by_block = logical_row(AcadColor::ByBlock, active_color, "ByBlock");
|
||||
let by_layer = logical_row(AcadColor::ByLayer, active_color, "ByLayer", layer_color);
|
||||
let by_block = logical_row(AcadColor::ByBlock, active_color, "ByBlock", None);
|
||||
let section1 = column![by_layer, by_block].spacing(2);
|
||||
|
||||
// 2. 45-swatch Quick Pick Grid (5 rows × 9 columns)
|
||||
|
||||
+13
-1
@@ -174,6 +174,14 @@ fn position_ribbon_dropdown<'a>(
|
||||
}
|
||||
|
||||
impl Ribbon {
|
||||
/// The current layer's colour: what ByLayer looks like for new objects.
|
||||
pub fn active_layer_color(&self) -> Option<Color> {
|
||||
self.layer_infos
|
||||
.iter()
|
||||
.find(|layer| layer.name == self.active_layer)
|
||||
.map(|layer| layer.color)
|
||||
}
|
||||
|
||||
/// The colour-book identity of the active colour, while the active colour
|
||||
/// is still the one picked from the book.
|
||||
pub fn active_color_name(&self) -> Option<String> {
|
||||
@@ -1232,7 +1240,11 @@ impl Ribbon {
|
||||
win: (f32, f32),
|
||||
recent_colors: &[AcadColor],
|
||||
) -> Option<Element<'_, Message>> {
|
||||
let panel = color_dropdown::color_dropdown_panel(self.active_color, recent_colors);
|
||||
let panel = color_dropdown::color_dropdown_panel(
|
||||
self.active_color,
|
||||
recent_colors,
|
||||
self.active_layer_color(),
|
||||
);
|
||||
|
||||
let (align_right, h_pad, top) =
|
||||
self.dd_anchor(PROP_COLOR_ID, color_dropdown::PANEL_W, win.0);
|
||||
|
||||
@@ -1167,7 +1167,12 @@ pub(super) fn render_large<'a>(item: &RibbonItem, ctx: &RenderCtx<'_>) -> Elemen
|
||||
.width(Length::Fixed(PROP_W))
|
||||
};
|
||||
|
||||
let (color_swatch, _) = acad_color_display(active_color);
|
||||
// ByLayer shows the current layer's colour.
|
||||
let color_swatch = layer_infos
|
||||
.iter()
|
||||
.find(|layer| layer.name == active_layer)
|
||||
.filter(|_| active_color == AcadColor::ByLayer)
|
||||
.map_or_else(|| acad_color_display(active_color).0, |layer| layer.color);
|
||||
let color_row = prop_row(
|
||||
crate::ui::color_select::color_display_name(active_color),
|
||||
PROP_COLOR_ID,
|
||||
|
||||
Reference in new issue
Block a user