Keep viewport layer colour overrides through DXF save and reopen (#99) (#197)

This commit is contained in:
MarekSpodBiedry
2026-10-10 14:36:53 -04:00
committed by GitHub
parent 932ba8cc58
commit e5a91f2eee
4 changed files with 65 additions and 3 deletions
+19
View File
@@ -365,6 +365,25 @@ pub(crate) fn read_frozen(tags: &[Tag]) -> Vec<String> {
list.iter().take(MAX_XDATA_ITEMS).filter(|t| t.code == 1000).map(Tag::str).collect()
}
/// A viewport's layer colour overrides as CADCraft xdata: `1000 VPCOLORS`, `1002 {`, then per override
/// `1000 layer` and `1000 colour` (the [`Color::name`] text, which keeps true colours), `1002 }`.
pub(crate) fn layer_colors_xdata(colors: &[(String, Color)]) -> Vec<Tag> {
let mut v = vec![Tag::s(1000, "VPCOLORS"), Tag::s(1002, "{")];
for (layer, color) in colors {
v.push(Tag::s(1000, layer.clone()));
v.push(Tag::s(1000, color.name()));
}
v.push(Tag::s(1002, "}"));
v
}
/// The overrides written by [`layer_colors_xdata`]; empty for files from other writers, bad pairs are skipped.
pub(crate) fn read_layer_colors(tags: &[Tag]) -> Vec<(String, Color)> {
let list = xdata_list(xdata(tags, APP), "VPCOLORS");
let names: Vec<String> = list.iter().take(MAX_XDATA_ITEMS * 2).filter(|t| t.code == 1000).map(Tag::str).collect();
names.chunks_exact(2).filter_map(|p| Some((p.first()?.clone(), Color::parse(p.get(1)?)?))).collect()
}
const POINT_NAMES: [&str; 5] = ["defpt", "p13", "p14", "p15", "p16"];
/// Associativity links from CADCraft xdata; malformed links are skipped.
+1 -1
View File
@@ -307,7 +307,7 @@ fn entity(kind: &str, tags: &[Tag]) -> Option<(Common, EntityKind)> {
id: t.i(69).unwrap_or(0) as u32,
locked: t.i(90).unwrap_or(0) & 16384 != 0,
frozen_layers: crate::dxf_ext::read_frozen(tags),
layer_colors: Vec::new(),
layer_colors: crate::dxf_ext::read_layer_colors(tags),
}),
"WIPEOUT" => {
let o = t.p(10);
+8 -2
View File
@@ -792,9 +792,15 @@ fn entity(w: &mut W, d: &Drawing, e: &Entity, owner: &str, paper: bool, cx: &Ctx
w.f(45, v.view_height);
// Status flags: 16384 = display locked.
w.i(90, if v.locked { 16384 } else { 0 });
if !v.frozen_layers.is_empty() {
// One CADCraft xdata group holds both lists: readers stop at the first group of an app.
if !v.frozen_layers.is_empty() || !v.layer_colors.is_empty() {
w.s(1001, dxf_ext::APP);
w.xdata(dxf_ext::frozen_xdata(&v.frozen_layers));
if !v.frozen_layers.is_empty() {
w.xdata(dxf_ext::frozen_xdata(&v.frozen_layers));
}
if !v.layer_colors.is_empty() {
w.xdata(dxf_ext::layer_colors_xdata(&v.layer_colors));
}
}
}
EntityKind::Wipeout(wo) => {
+37
View File
@@ -571,6 +571,43 @@ fn viewport_frozen_layers_roundtrip() {
assert!(frozen.contains(&(3, Vec::new())), "{frozen:?}");
}
#[test]
fn viewport_layer_colors_roundtrip() {
let mut d = sample();
let paper = Space::Paper("Layout1".into());
let vp = |id: u32, frozen: Vec<String>, colors: Vec<(String, Color)>| {
EntityKind::Viewport(Viewport {
center: Vec3::new(5.0, 4.0, 0.0),
width: 8.0,
height: 6.0,
view_center: Vec2::new(5.0, 2.5),
view_height: 12.0,
id,
locked: false,
frozen_layers: frozen,
layer_colors: colors,
})
};
let colors = vec![("Walls".to_string(), Color::Index(5)), ("A B".to_string(), Color::True(cadcraft_color::Rgb(255, 128, 0)))];
d.add(&paper, Common::default(), vp(2, Vec::new(), colors.clone())).unwrap();
d.add(&paper, Common::default(), vp(3, Vec::new(), Vec::new())).unwrap();
// Frozen layers and colour overrides share one CADCraft xdata group.
d.add(&paper, Common::default(), vp(4, vec!["Walls".into()], colors.clone())).unwrap();
let back = roundtrip(&d);
let found: Vec<(u32, Vec<String>, Vec<(String, Color)>)> = back
.layouts
.iter()
.flat_map(|l| l.entities.iter())
.filter_map(|e| match &e.kind {
EntityKind::Viewport(v) => Some((v.id, v.frozen_layers.clone(), v.layer_colors.clone())),
_ => None,
})
.collect();
assert!(found.contains(&(2, Vec::new(), colors.clone())), "{found:?}");
assert!(found.contains(&(3, Vec::new(), Vec::new())), "{found:?}");
assert!(found.contains(&(4, vec!["Walls".to_string()], colors)), "{found:?}");
}
fn full_dim_style() -> DimStyle {
DimStyle {
name: "Mech".into(),