fix(color): show color book identity

This commit is contained in:
Hakan Seven committed 2026-09-01 08:44:28 +03:00
1 parent 7ea4f338f6
commit 6d6defa0ad
19 files changed
+142 -30

No files matched your search

Generated
+1 -1
View File
@@ -72,7 +72,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
[[package]]
name = "acadrust"
version = "0.4.1"
source = "git+https://[email protected]/HakanSeven12/cadcodec.git?rev=c91a1c1de89a0fbc006dc360ddb0251ac8c207d1#c91a1c1de89a0fbc006dc360ddb0251ac8c207d1"
source = "git+https://[email protected]/HakanSeven12/cadcodec.git?rev=a0f7d444f1607bc4b2c881060cbe7ea1014253cb#a0f7d444f1607bc4b2c881060cbe7ea1014253cb"
dependencies = [
"ahash 0.8.12",
"anyhow",
+2 -2
View File
@@ -27,7 +27,7 @@ glam = { version = "0.33", features = ["bytemuck"] }
rfd = "0.17"
clap = { version = "4", features = ["derive"] }
env_logger = "0.11"
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "c91a1c1de89a0fbc006dc360ddb0251ac8c207d1", features = ["serde"] }
acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "a0f7d444f1607bc4b2c881060cbe7ea1014253cb", features = ["serde"] }
cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "48c634995fa60d3928c37bae49b12b421c56c886", features = ["acis", "offset"] }
dwg-thumbnailer = { path = "crates/dwg-thumbnailer" }
flate2 = "1"
@@ -61,7 +61,7 @@ iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aa
iced_widget = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
[patch."https://github.com/HakanSeven12/cadcodec.git"]
acadrust = { git = "https://[email protected]/HakanSeven12/cadcodec.git", rev = "c91a1c1de89a0fbc006dc360ddb0251ac8c207d1" }
acadrust = { git = "https://[email protected]/HakanSeven12/cadcodec.git", rev = "a0f7d444f1607bc4b2c881060cbe7ea1014253cb" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
+1
View File
@@ -2466,6 +2466,7 @@ impl OpenCADStudio {
dst_common.linetype_handle = common.linetype_handle;
dst_common.linetype_scale = common.linetype_scale;
dst_common.transparency = common.transparency.clone();
dst_common.color_name = common.color_name.clone();
dst_common.color_book_handle = common.color_book_handle;
dst_common.full_visual_style_handle =
common.full_visual_style_handle;
+2
View File
@@ -128,6 +128,8 @@ impl OpenCADStudio {
if let Some(l) = self.tabs[i].scene.document.layers.get_mut(&layer_name)
{
l.color = acadrust::types::Color::from_index(idx);
l.color_name = None;
l.book_name = None;
self.push_undo_snapshot(i, "LAYER COLOR");
self.tabs[i].dirty = true;
// By-layer colour is baked into every wire on
+4
View File
@@ -616,6 +616,8 @@ impl OpenCADStudio {
}
"COLOR" => {
common.color = color_val.unwrap();
common.color_name = None;
common.color_book_handle = None;
changed += 1;
}
"TRANSPARENCY" => {
@@ -661,6 +663,8 @@ impl OpenCADStudio {
if let Some(entity) = self.tabs[i].scene.document.get_entity_mut(*handle) {
let common = entity.common_mut();
common.color = acadrust::types::Color::ByLayer;
common.color_name = None;
common.color_book_handle = None;
common.linetype = "ByLayer".to_string();
common.line_weight = acadrust::types::LineWeight::ByLayer;
changed += 1;
+48 -19
View File
@@ -509,37 +509,59 @@ impl OpenCADStudio {
{
let doc = &self.tabs[i].scene.document;
let common = entity.common();
if let Some(acadrust::objects::ObjectType::BookColor(book)) = common
let named_color = common
.color_book_handle
.filter(|handle| handle.is_valid())
.and_then(|handle| doc.objects.get(&handle))
{
.and_then(|object| match object {
acadrust::objects::ObjectType::BookColor(book) => Some((
book.color,
book.book_name.clone(),
book.color_name.clone(),
)),
_ => None,
})
.or_else(|| {
let identity = common.color_name.as_deref()?;
let (book_name, color_name) = identity
.split_once('$')
.map(|(book, color)| (book.to_string(), color.to_string()))
.unwrap_or_else(|| (String::new(), identity.to_string()));
Some((common.color, book_name, color_name))
});
if let Some((color, book_name, color_name)) = named_color {
for section in sections.iter_mut() {
if let Some(row) =
section.props.iter_mut().find(|row| row.field == "color")
{
row.value =
crate::scene::model::object::PropValue::ColorChoice(
book.color,
);
row.value = crate::scene::model::object::PropValue::NamedColorChoice {
color,
name: color_name.clone(),
};
}
}
use crate::entities::common::ro_prop;
let mut props = Vec::new();
if !book_name.is_empty() {
props.push(ro_prop(
t!("Book").as_ref(),
"book_color_book",
book_name,
));
}
props.push(ro_prop(
t!("Color Name").as_ref(),
"book_color_name",
color_name,
));
props.push(ro_prop(
t!("Color").as_ref(),
"book_color_value",
format!("{:?}", color),
));
sections.push(crate::scene::model::object::PropSection {
title: t!("Color Book").into_owned(),
props: vec![
ro_prop(t!("Book").as_ref(), "book_color_book", book.book_name.clone()),
ro_prop(
t!("Color Name").as_ref(),
"book_color_name",
book.color_name.clone(),
),
ro_prop(
t!("Color").as_ref(),
"book_color_value",
format!("{:?}", book.color),
),
],
props,
});
}
@@ -2916,6 +2938,7 @@ fn make_sections_read_only(
acadrust::types::Color::Index(index) => index.to_string(),
acadrust::types::Color::Rgb { r, g, b } => format!("{r},{g},{b}"),
},
PropValue::NamedColorChoice { name, .. } => name.clone(),
PropValue::ColorVaries
| PropValue::LwVaries
| PropValue::FieldLwVaries { .. } => VARIES_LABEL.to_string(),
@@ -3075,6 +3098,9 @@ fn merge_prop_value(
PropValue::LayerChoice(VARIES_LABEL.into())
}
(PropValue::ColorChoice(_), PropValue::ColorChoice(_))
| (PropValue::NamedColorChoice { .. }, PropValue::NamedColorChoice { .. })
| (PropValue::ColorChoice(_), PropValue::NamedColorChoice { .. })
| (PropValue::NamedColorChoice { .. }, PropValue::ColorChoice(_))
| (PropValue::ColorVaries, _)
| (_, PropValue::ColorVaries) => PropValue::ColorVaries,
(PropValue::LwChoice(_), PropValue::LwChoice(_))
@@ -3261,6 +3287,9 @@ fn update_row_color(
};
match &mut row.value {
PropValue::ColorChoice(current) => *current = color,
PropValue::NamedColorChoice { .. } => {
row.value = PropValue::ColorChoice(color)
}
PropValue::ReadOnly(current) => *current = label,
PropValue::ReadOnlyWithTooltip { value: current, .. } => *current = label,
_ => {}
+2
View File
@@ -3226,6 +3226,8 @@ fn apply_attr_row(a: &mut acadrust::entities::AttributeEntity, row: &AttrRow) ->
}
if a.common.color != row.color {
a.common.color = row.color;
a.common.color_name = None;
a.common.color_book_handle = None;
ch = true;
}
if a.common.linetype != row.linetype {
+4
View File
@@ -2633,11 +2633,15 @@ impl OpenCADStudio {
for name in &names {
if let Some(dl) = self.tabs[i].scene.document.layers.get_mut(name) {
dl.color = color;
dl.color_name = None;
dl.book_name = None;
}
}
for pl in self.tabs[i].layers.layers.iter_mut() {
if names.contains(&pl.name) {
pl.color = color;
pl.color_name = None;
pl.book_name = None;
}
}
self.tabs[i].dirty = true;
+2
View File
@@ -1750,6 +1750,8 @@ pub(crate) fn block_content_insert(
insert.normal = ml.context.block_content_normal;
insert.common = ml.common.clone();
insert.common.color = ml.block_content_color.clone();
insert.common.color_name = None;
insert.common.color_book_handle = None;
Some(insert)
}
+2
View File
@@ -215,6 +215,8 @@ pub fn merge_layer(scene: &mut Scene, from: &str, to: &str, force_bylayer: bool)
common.layer = to.to_string();
if force_bylayer {
common.color = acadrust::Color::ByLayer;
common.color_name = None;
common.color_book_handle = None;
common.linetype = String::new();
common.linetype_handle = None;
common.line_weight = acadrust::LineWeight::ByLayer;
+2
View File
@@ -260,6 +260,8 @@ fn blend_common(source: &EntityCommon) -> EntityCommon {
let mut common = EntityCommon::new();
common.layer = source.layer.clone();
common.color = source.color;
common.color_name = source.color_name.clone();
common.color_book_handle = source.color_book_handle;
common.line_weight = source.line_weight;
common.linetype = source.linetype.clone();
common.linetype_handle = source.linetype_handle;
+4
View File
@@ -714,6 +714,8 @@ fn dim_common(base: &acadrust::entities::EntityCommon, clr: i16, lw: i16) -> aca
c.handle = Handle::NULL;
if clr != 0 && clr != 256 {
c.color = acadrust::types::Color::from_index(clr);
c.color_name = None;
c.color_book_handle = None;
}
if lw >= 0 {
c.line_weight = acadrust::types::LineWeight::from_value(lw);
@@ -1223,6 +1225,8 @@ fn explode_dimension(dim: &Dimension, doc: &CadDocument) -> Vec<EntityType> {
// Apply the text colour / lineweight (DIMCLRT) onto the entity.
let tc = dim_common(&base.common, met.dimclrt, -2);
tent.common_mut().color = tc.color;
tent.common_mut().color_name = tc.color_name;
tent.common_mut().color_book_handle = tc.color_book_handle;
tent.common_mut().line_weight = tc.line_weight;
result.push(tent);
}
+13 -1
View File
@@ -17,6 +17,18 @@ pub fn general_section(entity: &EntityType) -> PropSection {
((alpha as f64 / 255.0 * 100.0).round() as u32).to_string()
}
};
let color_value = common.color_name.as_deref().map_or_else(
|| PropValue::ColorChoice(common.color),
|identity| PropValue::NamedColorChoice {
color: common.color,
name: identity
.split_once('$')
.map(|(_, color_name)| color_name)
.filter(|color_name| !color_name.is_empty())
.unwrap_or(identity)
.to_string(),
},
);
// Hyperlink is stored in XDATA under the "PE_URL" application.
let hyperlink = common
@@ -36,7 +48,7 @@ pub fn general_section(entity: &EntityType) -> PropSection {
Property {
label: t!("Color").into_owned(),
field: "color",
value: PropValue::ColorChoice(common.color),
value: color_value,
},
Property {
label: t!("Layer").into_owned(),
+2
View File
@@ -30,6 +30,8 @@ pub enum PropValue {
},
/// ACI/RGB/ByLayer/ByBlock color — rendered as a color picker.
ColorChoice(AcadColor),
/// Color-book color with its file-provided display name.
NamedColorChoice { color: AcadColor, name: String },
/// Color varies across the current multi-selection.
ColorVaries,
/// Line weight — rendered as a combo_box.
+10 -2
View File
@@ -568,7 +568,8 @@ impl Scene {
}
QSelectValueEditor::Choice(values)
}
PropValue::ColorChoice(_) => QSelectValueEditor::Choice(vec![
PropValue::ColorChoice(_)
| PropValue::NamedColorChoice { .. } => QSelectValueEditor::Choice(vec![
"ByLayer".into(),
"ByBlock".into(),
]),
@@ -659,7 +660,13 @@ impl Scene {
match field {
"handle" => Some(entity.common().handle.value().to_string()),
"layer" => Some(entity.common().layer.clone()),
"color" => Some(Self::format_color(entity.common().color)),
"color" => Some(
entity
.common()
.color_name
.clone()
.unwrap_or_else(|| Self::format_color(entity.common().color)),
),
"linetype" => Some(if entity.common().linetype.is_empty() {
"ByLayer".to_string()
} else {
@@ -732,6 +739,7 @@ impl Scene {
PropValue::Choice { selected, .. } => selected,
PropValue::EditChoice { value, .. } => value,
PropValue::ColorChoice(c) => Self::format_color(c),
PropValue::NamedColorChoice { name, .. } => name,
PropValue::LwChoice(lw)
| PropValue::FieldLwChoice { value: lw, .. } => {
Self::format_lineweight(lw)
+3 -1
View File
@@ -296,7 +296,9 @@ pub fn toggle_invisible(entity: &mut EntityType) {
pub fn apply_color(entity: &mut EntityType, color: AcadColor) {
entity.as_entity_mut().set_color(color);
entity.common_mut().color_book_handle = None;
let common = entity.common_mut();
common.color_name = None;
common.color_book_handle = None;
}
pub fn apply_line_weight(entity: &mut EntityType, lw: LineWeight) {
+23 -1
View File
@@ -124,9 +124,31 @@ pub fn color_selector<'a>(
on_select: impl Fn(AcadColor) -> Message + 'a,
on_toggle: Message,
on_more: Message,
) -> Element<'a, Message> {
color_selector_with_name(
current,
None,
open,
extras,
on_select,
on_toggle,
on_more,
)
}
pub fn color_selector_with_name<'a>(
current: AcadColor,
display_name: Option<&'a str>,
open: bool,
extras: ColorExtras,
on_select: impl Fn(AcadColor) -> Message + 'a,
on_toggle: Message,
on_more: Message,
) -> Element<'a, Message> {
let (cur_bg, _) = acad_color_display(current);
let cur_name = color_display_name(current);
let cur_name = display_name
.map(str::to_string)
.unwrap_or_else(|| color_display_name(current));
let on_dismiss = on_toggle.clone();
// Closed button: current swatch + name + caret.
+9 -2
View File
@@ -776,7 +776,12 @@ impl PropertiesPanel {
label: &'a str,
) -> Element<'a, Message> {
match &prop.value {
PropValue::ColorChoice(color) => self.render_color_row(label, prop.field, *color),
PropValue::ColorChoice(color) => {
self.render_color_row(label, prop.field, *color, None)
}
PropValue::NamedColorChoice { color, name } => {
self.render_color_row(label, prop.field, *color, Some(name))
}
PropValue::ColorVaries => self.render_color_varies_row(label),
PropValue::LayerChoice(layer) => self.render_layer_row(label, layer),
PropValue::LwChoice(lw) => self.render_lw_row(label, *lw),
@@ -848,6 +853,7 @@ impl PropertiesPanel {
label: &'a str,
field: &'static str,
color: AcadColor,
display_name: Option<&'a str>,
) -> Element<'a, Message> {
// MTEXT background colour uses its own picker state + messages so it
// routes to `background_color`, not the entity's main colour.
@@ -929,8 +935,9 @@ impl PropertiesPanel {
);
return prop_row_widget(label, selector);
}
let selector = crate::ui::color_select::color_selector(
let selector = crate::ui::color_select::color_selector_with_name(
color,
display_name,
self.color_picker_open,
crate::ui::color_select::ColorExtras {
by_layer: true,
+8 -1
View File
@@ -90,6 +90,8 @@ pub struct Layer {
pub locked: bool,
pub plottable: bool,
pub color: AcadColor,
pub color_name: Option<String>,
pub book_name: Option<String>,
pub linetype: String,
pub lineweight: LineWeight,
pub transparency: i32,
@@ -106,6 +108,8 @@ impl Layer {
locked: false,
plottable: true,
color,
color_name: None,
book_name: None,
linetype: "Continuous".to_string(),
lineweight: LineWeight::Default,
transparency: 0,
@@ -220,6 +224,8 @@ impl LayerPanel {
locked: l.flags.locked,
plottable: l.is_plottable,
color: l.color,
color_name: l.color_name.clone(),
book_name: l.book_name.clone(),
linetype: if l.line_type.is_empty() {
"Continuous".to_string()
} else {
@@ -808,8 +814,9 @@ fn layer_row<'a>(
// Color cell — looks like a combo_box input; click opens swatch dropdown below row.
// Shared colour selector. Layers carry a concrete colour (no ByLayer /
// ByBlock); true colours stay RGB instead of being collapsed to ACI 7.
let color_cell: Element<'_, Message> = container(crate::ui::color_select::color_selector(
let color_cell: Element<'_, Message> = container(crate::ui::color_select::color_selector_with_name(
layer.color,
layer.color_name.as_deref(),
color_picker_open,
crate::ui::color_select::ColorExtras {
by_layer: false,