mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-03 07:01:09 -06:00
M4: object styles (create from selection, apply fill/stroke/text frame options/paragraph style)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
86588e8347
commit
6eb2cf2f83
@@ -40,6 +40,8 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"object": st.doc.styles.object.iter().map(|p| &p.name).collect::<Vec<_>>(),
|
||||
}))
|
||||
}),
|
||||
cmd!("style.object.apply", "Apply Object Style", [], None, "{name, ids?}", super::has_selection, apply_object),
|
||||
cmd!("style.object.create", "New Object Style…", [], None, "{name, fromSelection?: true, fill?, paragraphStyle?}", has_doc, create_object),
|
||||
cmd!(
|
||||
"swatch.create",
|
||||
"New Color Swatch…",
|
||||
@@ -276,3 +278,61 @@ pub fn parse_color(v: &Value) -> Option<designcraft_color::Color> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_object(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let name = str_param(p, "name").ok_or_else(|| bad("style.object.apply", "missing name"))?.to_string();
|
||||
let os = s.doc()?.doc.styles.object_style(&name).cloned().ok_or_else(|| bad("style.object.apply", format!("no object style `{name}`")))?;
|
||||
let ids = super::targets(s, p)?;
|
||||
s.edit(|d, _| {
|
||||
let mut stories = Vec::new();
|
||||
for id in &ids {
|
||||
let Some(it) = d.item_mut(*id) else { continue };
|
||||
it.object_style = name.clone();
|
||||
if let Some(f) = &os.fill {
|
||||
it.fill = f.clone();
|
||||
}
|
||||
if let Some(st) = &os.stroke {
|
||||
it.stroke = st.clone();
|
||||
}
|
||||
if let Some(tf) = it.text_frame_mut() {
|
||||
if let Some(o) = &os.text_frame {
|
||||
tf.options = o.clone();
|
||||
}
|
||||
stories.push(tf.story);
|
||||
}
|
||||
}
|
||||
if let Some(ps) = &os.paragraph_style {
|
||||
for sid in stories {
|
||||
if let Some(st) = d.story_mut(sid) {
|
||||
let len = st.len();
|
||||
st.format_paras(0..len, |f| f.style = ps.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Value::Null)
|
||||
})
|
||||
}
|
||||
|
||||
fn create_object(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let base = str_param(p, "name").unwrap_or("Object Style 1").to_string();
|
||||
let from_sel = p.get("fromSelection").and_then(Value::as_bool).unwrap_or(true);
|
||||
let src = if from_sel { s.doc()?.selection.items.first().and_then(|i| s.doc().ok()?.doc.item(*i).cloned()) } else { None };
|
||||
let mut os = designcraft_doc::ObjectStyle::default();
|
||||
if let Some(it) = &src {
|
||||
os.fill = Some(it.fill.clone());
|
||||
os.stroke = Some(it.stroke.clone());
|
||||
os.text_frame = it.text_frame().map(|t| t.options.clone());
|
||||
}
|
||||
if let Some(sw) = str_param(p, "fill") {
|
||||
os.fill = Some(designcraft_doc::Fill::swatch(sw));
|
||||
}
|
||||
if let Some(ps) = str_param(p, "paragraphStyle") {
|
||||
os.paragraph_style = Some(ps.to_string());
|
||||
}
|
||||
s.edit(|d, _| {
|
||||
let name = Styles::unique_name(|n| d.styles.object_style(n).is_some(), &base);
|
||||
os.name = name.clone();
|
||||
d.styles_mut().object.push(os.clone());
|
||||
Ok(json!({"name": name}))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -271,6 +271,22 @@ fn snippets_roundtrip_between_documents() {
|
||||
st.doc.check().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_styles_create_and_apply() {
|
||||
let mut s = session();
|
||||
let a = s.execute("frame.create", &json!({"rect": [36, 36, 136, 136], "content": "unassigned"})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("object.fill", &json!({"swatch": "C=0 M=100 Y=0 K=0"})).unwrap();
|
||||
s.execute("object.stroke", &json!({"weight": 4.0})).unwrap();
|
||||
s.execute("style.object.create", &json!({"name": "Magenta Box"})).unwrap();
|
||||
let b = s.execute("frame.create", &json!({"rect": [200, 36, 300, 136], "content": "unassigned"})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("style.object.apply", &json!({"name": "Magenta Box"})).unwrap();
|
||||
let d = &s.doc().unwrap().doc;
|
||||
let (ia, ib) = (d.item(designcraft_doc::ItemId(a)).unwrap(), d.item(designcraft_doc::ItemId(b)).unwrap());
|
||||
assert_eq!(ia.fill, ib.fill);
|
||||
assert_eq!(ib.stroke.weight, 4.0);
|
||||
assert_eq!(ib.object_style, "Magenta Box");
|
||||
}
|
||||
|
||||
/// Unicode text per page, through hayro's interpreter (ToUnicode / ActualText).
|
||||
fn pdf_text(bytes: &[u8]) -> Vec<String> {
|
||||
use hayro_interpret::font::Glyph;
|
||||
|
||||
Reference in New Issue
Block a user