diff --git a/crates/slideshow/src/settings.rs b/crates/slideshow/src/settings.rs index fd3b327ef..488819e77 100644 --- a/crates/slideshow/src/settings.rs +++ b/crates/slideshow/src/settings.rs @@ -218,22 +218,35 @@ impl SlideSettings { /// These settings with the keys `p` names changed (the others kept), validated and clamped. /// A wrong type, an unknown key or a non-finite number is an error, and nothing changes. - /// With `linkMargins` on (already, or set in `p`), a margin given sets all four; `margins` - /// sets all four in any case. + /// With `linkMargins` on (already, or set in `p`), a margin given sets all four (unless all four are given); + /// `margins` sets all four in any case. pub fn merged(&self, p: &Value) -> Result { let Some(obj) = p.as_object() else { return Err("parameters must be an object".into()) }; let mut s = self.clone(); let mut margin: Option = None; + let mut margin_keys = 0; for (k, v) in obj { match k.as_str() { "margins" => { let m = number(k, v)?; (s.margin_left, s.margin_right, s.margin_top, s.margin_bottom) = (m, m, m, m); } - "marginLeft" => s.margin_left = *margin.insert(number(k, v)?), - "marginRight" => s.margin_right = *margin.insert(number(k, v)?), - "marginTop" => s.margin_top = *margin.insert(number(k, v)?), - "marginBottom" => s.margin_bottom = *margin.insert(number(k, v)?), + "marginLeft" => { + s.margin_left = *margin.insert(number(k, v)?); + margin_keys += 1; + } + "marginRight" => { + s.margin_right = *margin.insert(number(k, v)?); + margin_keys += 1; + } + "marginTop" => { + s.margin_top = *margin.insert(number(k, v)?); + margin_keys += 1; + } + "marginBottom" => { + s.margin_bottom = *margin.insert(number(k, v)?); + margin_keys += 1; + } "linkMargins" => s.link_margins = boolean(k, v)?, "showGuides" => s.show_guides = boolean(k, v)?, "aspect" => { @@ -264,7 +277,9 @@ impl SlideSettings { other => return Err(format!("unknown setting `{other}` ({KEYS})")), } } + // all four given: an explicit full state (e.g. `to_json`), kept as is if s.link_margins + && margin_keys < 4 && let Some(m) = margin { (s.margin_left, s.margin_right, s.margin_top, s.margin_bottom) = (m, m, m, m); @@ -319,6 +334,21 @@ pub fn hex(c: [u8; 3]) -> String { mod tests { use super::*; + #[test] + fn merge_restores_unequal_linked_margins() { + let d = SlideSettings::default(); + let st = SlideSettings { link_margins: true, margin_left: 0.1, margin_right: 0.0, margin_top: 0.3, margin_bottom: 0.0, ..d.clone() }; + assert_eq!(d.merged(&st.to_json()).unwrap(), st); + } + + #[test] + fn merge_copies_last_of_three_linked_margins() { + let d = SlideSettings::default(); + // keys are visited in key order (bottom, left, top): the last one, `marginTop`, wins + let s = d.merged(&json!({"marginLeft": 0.1, "marginTop": 0.3, "marginBottom": 0.2})).unwrap(); + assert_eq!((s.margin_left, s.margin_right, s.margin_top, s.margin_bottom), (0.3, 0.3, 0.3, 0.3)); + } + #[test] fn merge_validates_links_margins_and_round_trips() { let d = SlideSettings::default();