mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-14 14:22:39 +00:00
IDML: an item without corners keeps none over its object style
Object styles now export their corners, and an import gives an item without corner attributes the corners of its style chain and of [None]. An item with no corners whose style, a style it is based on, or [None] sets corners now writes None for each corner, so it keeps no corners after export and import. The lookup runs once per style.
This commit is contained in:
1 parent
b0f282f607
commit
737fcfec04
3 files changed
+74
-2
No files matched your search
@@ -106,6 +106,8 @@ struct Ex<'a> {
|
||||
/// Index topic path → first serialized sort key; See / See also cross-references.
|
||||
index_topics: BTreeMap<Vec<String>, String>,
|
||||
index_xrefs: Vec<(Vec<String>, &'static str, String)>,
|
||||
/// Object style name → whether its chain or `[None]` sets corners, found once per style.
|
||||
style_corners: HashMap<String, bool>,
|
||||
}
|
||||
|
||||
impl<'a> Ex<'a> {
|
||||
@@ -121,6 +123,7 @@ impl<'a> Ex<'a> {
|
||||
link_text_sources: Vec::new(),
|
||||
index_topics: BTreeMap::new(),
|
||||
index_xrefs: Vec::new(),
|
||||
style_corners: HashMap::new(),
|
||||
};
|
||||
ex.assign_swatch_ids();
|
||||
for s in d.stories.values() {
|
||||
|
||||
@@ -87,8 +87,10 @@ impl<'a> Ex<'a> {
|
||||
el.set("GradientStrokeAngle", num(a));
|
||||
}
|
||||
self.stroke_attrs(&mut el, &it.stroke);
|
||||
// Corner options: map path-order corners to the named corners by geometry.
|
||||
if !it.corners.is_none() {
|
||||
// Corner options: map path-order corners to the named corners by geometry. An item without
|
||||
// corners whose object style chain sets some writes None, so an import does not give it
|
||||
// the style's corners.
|
||||
if !it.corners.is_none() || self.style_sets_corners(os) {
|
||||
let names_by_index = corner_names(&it.path);
|
||||
for (i, c) in it.corners.corners.iter().enumerate() {
|
||||
let n = names_by_index[i];
|
||||
@@ -153,6 +155,36 @@ impl<'a> Ex<'a> {
|
||||
el
|
||||
}
|
||||
|
||||
/// Whether object style `name`, a style it is based on, or `[None]` (which an import reads
|
||||
/// after every item's style chain) sets corners other than None. A built-in style the
|
||||
/// document lacks counts as its default.
|
||||
fn style_sets_corners(&mut self, name: &str) -> bool {
|
||||
if let Some(&known) = self.style_corners.get(name) {
|
||||
return known;
|
||||
}
|
||||
let defaults = designcraft_doc::Styles::default();
|
||||
let style = |n: &str| self.d.styles.object_style(n).or_else(|| defaults.object_style(n));
|
||||
let rounds = |os: &designcraft_doc::ObjectStyle| os.corners.is_some_and(|c| !c.is_none());
|
||||
let mut seen: Vec<&str> = Vec::new();
|
||||
let mut cur = Some(name);
|
||||
let mut found = false;
|
||||
while let Some(n) = cur.take() {
|
||||
if seen.contains(&n) {
|
||||
break;
|
||||
}
|
||||
let Some(os) = style(n) else { break };
|
||||
if rounds(os) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
seen.push(n);
|
||||
cur = os.based_on.as_deref();
|
||||
}
|
||||
let found = found || style(designcraft_doc::NO_OBJECT_STYLE).is_some_and(rounds);
|
||||
self.style_corners.insert(name.to_string(), found);
|
||||
found
|
||||
}
|
||||
|
||||
fn append_transparency(&self, el: &mut El, it: &Item, os: &str) {
|
||||
// Transparency.
|
||||
// An item whose style sets effects writes the effects it has turned off too, so that on
|
||||
|
||||
@@ -232,6 +232,43 @@ fn exported_frames_keep_their_own_values_over_their_object_style() {
|
||||
assert_eq!(got.options, want);
|
||||
}
|
||||
|
||||
/// Items without corners keep none after export and import, though their object style, the style
|
||||
/// it is based on, or `[None]` (read after every style chain) sets rounded corners.
|
||||
#[test]
|
||||
fn exported_frames_keep_no_corners_over_their_object_style() {
|
||||
let mut d = small_doc();
|
||||
let lid = d.default_layer();
|
||||
let id = designcraft_doc::ItemId(d.alloc());
|
||||
let rect = designcraft_doc::Item::new(id, lid, Shape::Rectangle, shapes::rectangle(Rect::new(40.0, 420.0, 200.0, 500.0)));
|
||||
d.insert_item(SpreadRef::Doc(0), rect, None).unwrap();
|
||||
let rounded = Some(designcraft_geom::corners::CornerOptions {
|
||||
corners: [designcraft_geom::corners::Corner { shape: CornerShape::Rounded, size: 12.0 }; 4],
|
||||
});
|
||||
let styles = std::sync::Arc::make_mut(&mut d.styles);
|
||||
styles.object.push(designcraft_doc::ObjectStyle { name: "Round".into(), corners: rounded, ..Default::default() });
|
||||
styles.object.push(designcraft_doc::ObjectStyle { name: "Child".into(), based_on: Some("Round".into()), ..Default::default() });
|
||||
match styles.object.iter_mut().find(|o| o.name == designcraft_doc::NO_OBJECT_STYLE) {
|
||||
Some(none) => none.corners = rounded,
|
||||
None => {
|
||||
styles.object.push(designcraft_doc::ObjectStyle { name: designcraft_doc::NO_OBJECT_STYLE.into(), corners: rounded, ..Default::default() })
|
||||
}
|
||||
}
|
||||
styles.object.push(designcraft_doc::ObjectStyle { name: "Plain".into(), ..Default::default() });
|
||||
let names = ["Round", "Child", designcraft_doc::NO_OBJECT_STYLE, "Plain"];
|
||||
let ids: Vec<_> = d.spreads.iter().flat_map(|s| s.items.iter().map(|i| i.id)).take(4).collect();
|
||||
assert_eq!(ids.len(), 4);
|
||||
for (id, style) in ids.iter().zip(names) {
|
||||
let it = d.item_mut(*id).unwrap();
|
||||
it.object_style = style.into();
|
||||
assert!(it.corners.is_none());
|
||||
}
|
||||
let back = import_idml(&export_idml(&d)).unwrap();
|
||||
for style in names {
|
||||
let it = back.spreads.iter().flat_map(|s| s.items.iter()).find(|i| i.object_style == style).unwrap();
|
||||
assert!(it.corners.is_none(), "{style}: {:?}", it.corners);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_wrap_side_and_contour_come_from_the_style_for_frames_and_placed_graphics() {
|
||||
let styles = r#"<ObjectStyle Self="ObjectStyle/Contour" Name="Contour">
|
||||
|
||||
Reference in new issue
Block a user