mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-14 22:35:26 +00:00
Merge branch 'object-style-attributes' into object-styles-panel
This commit is contained in:
commit
7ae3c35fd5
3 files changed
+65
-13
No files matched your search
@@ -1254,6 +1254,8 @@ impl Effects {
|
||||
ds.size = len("dropShadow.size", ds.size)?;
|
||||
ds.spread = pct("dropShadow.spread", ds.spread)?;
|
||||
self.feather = len("feather", self.feather)?;
|
||||
// As IDML import reads it, so a round trip keeps it.
|
||||
self.feather_options.choke = pct("featherOptions.choke", self.feather_options.choke)?;
|
||||
let e = &mut self.inner_shadow;
|
||||
e.opacity = opacity("innerShadow.opacity", e.opacity)?;
|
||||
e.angle = finite("innerShadow.angle", e.angle)?;
|
||||
|
||||
@@ -377,7 +377,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Clear Object Style Overrides",
|
||||
[],
|
||||
None,
|
||||
"{ids?} — each item takes its object style's fill, stroke, effects and text frame options again → {changed}",
|
||||
"{ids?} — each item takes its object style's fill, stroke, effects and text frame options again, and a text frame's story its paragraph style → {changed}",
|
||||
super::has_selection,
|
||||
clear_object_overrides
|
||||
),
|
||||
@@ -1430,18 +1430,33 @@ fn apply_object(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
fn clear_object_overrides(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let ids = super::targets(s, p)?;
|
||||
// Each target with its style's attributes applied, kept only where that changes the item.
|
||||
// Each target with its style's attributes applied, kept only where that changes the item;
|
||||
// and a text frame's story back in the style's paragraph style, as applying the style does.
|
||||
let d = &s.doc()?.doc;
|
||||
let changed: Vec<Item> = ids
|
||||
.iter()
|
||||
.filter_map(|id| {
|
||||
let it = d.item(*id)?;
|
||||
let mut next = it.clone();
|
||||
d.styles.object_style(&it.object_style)?.apply_to(&mut next);
|
||||
(next != *it).then_some(next)
|
||||
})
|
||||
.collect();
|
||||
if changed.is_empty() {
|
||||
let mut changed: Vec<Item> = Vec::new();
|
||||
let mut restyled: Vec<(designcraft_doc::StoryId, String)> = Vec::new();
|
||||
let mut n = 0;
|
||||
for id in &ids {
|
||||
let Some(it) = d.item(*id) else { continue };
|
||||
let Some(os) = d.styles.object_style(&it.object_style) else { continue };
|
||||
let mut next = it.clone();
|
||||
os.apply_to(&mut next);
|
||||
let item_changed = next != *it;
|
||||
if item_changed {
|
||||
changed.push(next);
|
||||
}
|
||||
let mut story_changed = false;
|
||||
if let (Some(ps), Some(tf)) = (&os.paragraph_style, it.text_frame())
|
||||
&& d.story(tf.story).is_some_and(|st| st.paras.iter().any(|f| f.style != *ps))
|
||||
{
|
||||
story_changed = true;
|
||||
if !restyled.iter().any(|(sid, _)| *sid == tf.story) {
|
||||
restyled.push((tf.story, ps.clone()));
|
||||
}
|
||||
}
|
||||
n += usize::from(item_changed || story_changed);
|
||||
}
|
||||
if n == 0 {
|
||||
return Ok(json!({"changed": 0}));
|
||||
}
|
||||
s.edit(|d, _| {
|
||||
@@ -1450,7 +1465,13 @@ fn clear_object_overrides(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
*it = next.clone();
|
||||
}
|
||||
}
|
||||
Ok(json!({"changed": changed.len()}))
|
||||
for (sid, ps) in &restyled {
|
||||
if let Some(st) = d.story_mut(*sid) {
|
||||
let len = st.len();
|
||||
st.format_paras(0..len, |f| f.style = ps.clone());
|
||||
}
|
||||
}
|
||||
Ok(json!({"changed": n}))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1710,3 +1710,32 @@ fn a_line_fits_when_its_baseline_does() {
|
||||
assert!(!overset(&mut s, 78.5), "the line is set; its descenders hang below the frame");
|
||||
assert!(overset(&mut s, 50.0), "a baseline below the frame still oversets the line");
|
||||
}
|
||||
|
||||
/// Clear Overrides puts a text frame's story back in its object style's paragraph style, as
|
||||
/// applying the style does; and a style's feather choke is kept to 0–100 %, as IDML reads it.
|
||||
#[test]
|
||||
fn object_style_clear_overrides_restores_the_paragraph_style_and_choke_is_clamped() {
|
||||
let mut s = session();
|
||||
s.execute("style.paragraph.create", &json!({"name": "Caption"})).unwrap();
|
||||
s.execute("style.object.create", &json!({"name": "Captioned", "fromSelection": false, "paragraphStyle": "Caption"})).unwrap();
|
||||
let f = s.execute("frame.create", &json!({"rect": [36, 36, 300, 200], "content": "text", "text": "One\nTwo"})).unwrap();
|
||||
let (id, sid) = (f["id"].as_u64().unwrap(), designcraft_doc::StoryId(f["story"].as_u64().unwrap()));
|
||||
s.execute("style.object.apply", &json!({"name": "Captioned", "ids": [id]})).unwrap();
|
||||
let styles = |s: &Session| s.doc().unwrap().doc.story(sid).unwrap().paras.iter().map(|p| p.style.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(styles(&s), ["Caption", "Caption"]);
|
||||
{
|
||||
let doc = std::sync::Arc::make_mut(&mut s.doc_mut().unwrap().doc);
|
||||
let st = std::sync::Arc::make_mut(doc.stories.get_mut(&sid).unwrap());
|
||||
st.paras[1].style = designcraft_doc::BASIC_PARAGRAPH.into();
|
||||
}
|
||||
let r = s.execute("style.object.clearOverrides", &json!({"ids": [id]})).unwrap();
|
||||
assert_eq!(r["changed"], 1);
|
||||
assert_eq!(styles(&s), ["Caption", "Caption"]);
|
||||
let r = s.execute("style.object.clearOverrides", &json!({"ids": [id]})).unwrap();
|
||||
assert_eq!(r["changed"], 0, "nothing left to clear");
|
||||
|
||||
s.execute("style.object.create", &json!({"name": "Soft", "fromSelection": false, "effects": {"feather": 4, "featherOptions": {"choke": 150}}}))
|
||||
.unwrap();
|
||||
let fx = s.doc().unwrap().doc.styles.object_style("Soft").unwrap().effects.clone().unwrap();
|
||||
assert_eq!(fx.feather_options.choke, 100.0);
|
||||
}
|
||||
Reference in new issue
Block a user