mirror of
https://github.com/storytold/deckcraft.git
synced 2026-11-10 20:39:36 -06:00
Honor bullet size schema bounds and inheritance
This commit is contained in:
@@ -271,8 +271,13 @@ impl ParaProps {
|
||||
if self.bullet_color.is_none() {
|
||||
self.bullet_color.clone_from(&p.bullet_color);
|
||||
}
|
||||
self.bullet_size = self.bullet_size.or(p.bullet_size);
|
||||
self.bullet_size_points = self.bullet_size_points.or(p.bullet_size_points);
|
||||
if self.bullet_size.is_none() && self.bullet_size_points.is_none() {
|
||||
if p.bullet_size_points.is_some() {
|
||||
self.bullet_size_points = p.bullet_size_points;
|
||||
} else {
|
||||
self.bullet_size = p.bullet_size;
|
||||
}
|
||||
}
|
||||
if self.tabs.is_none() {
|
||||
self.tabs.clone_from(&p.tabs);
|
||||
}
|
||||
@@ -287,6 +292,26 @@ impl ParaProps {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bullet_size_tests {
|
||||
use super::ParaProps;
|
||||
|
||||
#[test]
|
||||
fn bullet_size_inheritance_keeps_percentage_and_points_as_one_mode() {
|
||||
let parent = ParaProps { bullet_size_points: Some(12.0), ..Default::default() };
|
||||
let mut child = ParaProps { bullet_size: Some(2.0), ..Default::default() };
|
||||
child.inherit(&parent);
|
||||
assert_eq!(child.bullet_size, Some(2.0));
|
||||
assert_eq!(child.bullet_size_points, None);
|
||||
|
||||
let parent = ParaProps { bullet_size: Some(1.5), ..Default::default() };
|
||||
let mut child = ParaProps { bullet_size_points: Some(14.0), ..Default::default() };
|
||||
child.inherit(&parent);
|
||||
assert_eq!(child.bullet_size, None);
|
||||
assert_eq!(child.bullet_size_points, Some(14.0));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Caps {
|
||||
|
||||
@@ -432,10 +432,14 @@ pub fn ppr(imp: &mut Imp, part: &Part, p: &El) -> (Option<u8>, ParaProps, Option
|
||||
}
|
||||
"buFont" => pp.bullet_font = e.attr("typeface").map(String::from),
|
||||
"buClr" => pp.bullet_color = color(e),
|
||||
"buSzPct" => pp.bullet_size = pct(e, "val").map(|v| v.clamp(0.25, 4.0)),
|
||||
"buSzPct" => {
|
||||
pp.bullet_size_points = None;
|
||||
pp.bullet_size = pct(e, "val").map(|v| v.clamp(0.25, 4.0));
|
||||
}
|
||||
"buSzPts" => {
|
||||
pp.bullet_size = None;
|
||||
pp.bullet_size_points =
|
||||
e.attr("val").and_then(|v| v.parse::<f64>().ok()).filter(|v| v.is_finite() && *v > 0.0 && *v <= 40_000.0).map(|v| v / 100.0);
|
||||
e.attr("val").and_then(|v| v.parse::<u32>().ok()).filter(|v| (100..=400_000).contains(v)).map(|v| v as f64 / 100.0);
|
||||
}
|
||||
"tabLst" => {
|
||||
pp.tabs = Some(
|
||||
|
||||
@@ -557,12 +557,11 @@ pub fn ppr(w: &mut W, x: &mut Exp, o: &mut Out, tag: &str, level: Option<u8>, p:
|
||||
color(w, c);
|
||||
w.close("a:buClr");
|
||||
}
|
||||
if let Some(s) = p.bullet_size {
|
||||
if let Some(s) = p.bullet_size_points.filter(|s| s.is_finite() && (1.0..=4000.0).contains(s)) {
|
||||
w.val("a:buSzPts", ((s * 100.0).round() as u32).to_string());
|
||||
} else if let Some(s) = p.bullet_size {
|
||||
w.val("a:buSzPct", pct(s.clamp(0.25, 4.0)));
|
||||
}
|
||||
if let Some(s) = p.bullet_size_points {
|
||||
w.val("a:buSzPts", ((s.clamp(0.01, 400.0) * 100.0).round() as u32).to_string());
|
||||
}
|
||||
if let Some(f) = &p.bullet_font {
|
||||
w.empty("a:buFont", A::new().a("typeface", f));
|
||||
}
|
||||
|
||||
@@ -493,23 +493,26 @@ fn bullet_size_in_points_survives_two_pptx_round_trips() {
|
||||
let mut p = Presentation::default();
|
||||
let mut textbox = shape(&mut p, "Point-sized bullet", 20.0, 20.0, 400.0, 100.0);
|
||||
textbox.text = Some(TextBody {
|
||||
paragraphs: vec![Paragraph {
|
||||
props: deckcraft_model::text::ParaProps {
|
||||
bullet: Some(Bullet::Char { char: "•".into() }),
|
||||
bullet_size_points: Some(12.0),
|
||||
paragraphs: [12.0, 500.0, 4000.0]
|
||||
.into_iter()
|
||||
.map(|size| Paragraph {
|
||||
props: deckcraft_model::text::ParaProps {
|
||||
bullet: Some(Bullet::Char { char: "•".into() }),
|
||||
bullet_size_points: Some(size),
|
||||
..Default::default()
|
||||
},
|
||||
runs: vec![Run::with("Bullet text", RunProps::default())],
|
||||
..Default::default()
|
||||
},
|
||||
runs: vec![Run::with("Bullet text", RunProps::default())],
|
||||
..Default::default()
|
||||
}],
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
});
|
||||
Arc::make_mut(&mut p.slides[0]).shapes.push(textbox);
|
||||
|
||||
let q = round(&round(&p));
|
||||
let props = &by_name(&q.slides[0], "Point-sized bullet").text.as_ref().expect("text").paragraphs[0].props;
|
||||
assert_eq!(props.bullet_size_points, Some(12.0));
|
||||
assert_eq!(props.bullet_size, None);
|
||||
let props = &by_name(&q.slides[0], "Point-sized bullet").text.as_ref().expect("text").paragraphs;
|
||||
assert_eq!(props.iter().map(|p| p.props.bullet_size_points).collect::<Vec<_>>(), vec![Some(12.0), Some(500.0), Some(4000.0)]);
|
||||
assert!(props.iter().all(|p| p.props.bullet_size.is_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user