From 12e502c20337a78c37432ef3041734ffb70fe94f Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 1 Oct 2026 12:35:09 -0400 Subject: [PATCH] M4: inner shadow, outer glow, basic feather commands; drop shadow spread/color Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/object.rs | 64 ++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/object.rs b/crates/engine/src/cmd/object.rs index 889258256..e6abd3efc 100644 --- a/crates/engine/src/cmd/object.rs +++ b/crates/engine/src/cmd/object.rs @@ -162,7 +162,7 @@ pub fn specs() -> Vec { "Drop Shadow", ["Object", "Effects"], Some("Cmd+Alt+M"), - "{on?: bool, distance?, angle?, opacity?, size?, ids?}", + "{on?: bool, distance?, angle?, opacity?, size?, spread? (%), color? (swatch), ids?}", has_selection, |s, p| { let p2 = p.clone(); @@ -176,11 +176,73 @@ pub fn specs() -> Vec { ds.angle = f64_or(&p2, "angle", ds.angle); ds.opacity = f64_or(&p2, "opacity", ds.opacity as f64) as f32; ds.size = f64_or(&p2, "size", ds.size); + ds.spread = f64_or(&p2, "spread", ds.spread); + if let Some(c) = str_param(&p2, "color") { + ds.color = c.into(); + } }, false, ) } ), + cmd!( + "object.innerShadow", + "Inner Shadow", + ["Object", "Effects"], + None, + "{on?: bool, distance?, angle?, opacity?, size?, choke? (%), color?, ids?}", + has_selection, + |s, p| { + let p2 = p.clone(); + set_flag( + s, + p, + move |i| { + let e = &mut i.effects.inner_shadow; + e.on = p2.get("on").and_then(Value::as_bool).unwrap_or(!e.on); + e.distance = f64_or(&p2, "distance", e.distance); + e.angle = f64_or(&p2, "angle", e.angle); + e.opacity = f64_or(&p2, "opacity", e.opacity as f64) as f32; + e.size = f64_or(&p2, "size", e.size); + e.choke = f64_or(&p2, "choke", e.choke); + if let Some(c) = str_param(&p2, "color") { + e.color = c.into(); + } + }, + false, + ) + } + ), + cmd!( + "object.outerGlow", + "Outer Glow", + ["Object", "Effects"], + None, + "{on?: bool, opacity?, size?, spread? (%), color?, ids?}", + has_selection, + |s, p| { + let p2 = p.clone(); + set_flag( + s, + p, + move |i| { + let e = &mut i.effects.outer_glow; + e.on = p2.get("on").and_then(Value::as_bool).unwrap_or(!e.on); + e.opacity = f64_or(&p2, "opacity", e.opacity as f64) as f32; + e.size = f64_or(&p2, "size", e.size); + e.spread = f64_or(&p2, "spread", e.spread); + if let Some(c) = str_param(&p2, "color") { + e.color = c.into(); + } + }, + false, + ) + } + ), + cmd!("object.feather", "Basic Feather", ["Object", "Effects"], None, "{width (0 = off), ids?}", has_selection, |s, p| { + let w = f64_or(p, "width", 9.0).max(0.0); + set_flag(s, p, move |i| i.effects.feather = w, false) + }), cmd!("object.content", "Content", ["Object", "Content"], None, "{type: graphic|text|unassigned, ids?}", has_selection, content_type), cmd!( "object.textFrameOptions",