Skip to main content

diffenator3_lib/
setting.rs

1use std::fmt::{Display, Formatter};
2
3use skrifa::setting::VariationSetting;
4
5use crate::dfont::DFont;
6
7/// A position across both fonts to test; could be an
8/// instance, could be a location
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum Setting {
12    Instance(String),
13    Location(Vec<VariationSetting>),
14    Default,
15}
16
17impl Eq for Setting {}
18impl std::hash::Hash for Setting {
19    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
20        format!("{:?}", self).hash(state);
21    }
22}
23
24pub fn parse_location(variations: &str) -> Result<Vec<VariationSetting>, String> {
25    let mut settings: Vec<VariationSetting> = vec![];
26    for variation in variations.split(&[',', ' ']) {
27        if variation.is_empty() {
28            continue;
29        }
30        let mut parts = variation.split('=');
31        let axis = parts.next().ok_or("Couldn't parse axis".to_string())?;
32        let value = parts.next().ok_or("Couldn't parse value".to_string())?;
33        let value = value
34            .parse::<f32>()
35            .map_err(|_| "Couldn't parse value".to_string())?;
36        settings.push((axis, value).into());
37    }
38    Ok(settings)
39}
40
41impl Display for Setting {
42    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43        match self {
44            Setting::Instance(inst) => write!(f, "{} instance", inst),
45            Setting::Location(loc) => {
46                let loc = loc
47                    .iter()
48                    .map(|vs| format!("{}={}", vs.selector, vs.value))
49                    .collect::<Vec<String>>()
50                    .join(",");
51                write!(f, "{}", loc)
52            }
53            Setting::Default => write!(f, "default location"),
54        }
55    }
56}
57impl Setting {
58    pub fn from_instance(instance: String) -> Self {
59        Setting::Instance(instance)
60    }
61    pub fn from_setting(location: Vec<VariationSetting>) -> Self {
62        Setting::Location(location)
63    }
64    pub fn set_on_fonts(&self, font_a: &mut DFont, font_b: &mut DFont) -> Result<(), String> {
65        match self {
66            Setting::Instance(inst) => {
67                font_a
68                    .set_instance(inst)
69                    .map_err(|_e| format!("Old font does not contain instance '{}'", inst))?;
70                font_b
71                    .set_instance(inst)
72                    .map_err(|_e| format!("New font does not contain instance '{}'", inst))?;
73            }
74            Setting::Location(loc) => {
75                font_a.location = loc.clone();
76                font_a.normalize_location();
77                font_b.location = loc.clone();
78                font_b.normalize_location();
79            }
80            Setting::Default => {}
81        }
82        log::debug!("Font A location is: {:?}", font_a.location);
83        log::debug!("Font B location is: {:?}", font_b.location);
84        log::debug!(
85            "Font A normalized location is: {:?}",
86            font_a.normalized_location
87        );
88        log::debug!(
89            "Font B normalized location is: {:?}",
90            font_b.normalized_location
91        );
92        Ok(())
93    }
94
95    pub fn name(&self) -> String {
96        match self {
97            Setting::Instance(inst) => inst.clone(),
98            Setting::Location(loc) => loc
99                .iter()
100                .map(|vs| format!("{}={}", vs.selector, vs.value))
101                .collect::<Vec<String>>()
102                .join(","),
103            Setting::Default => "Default".to_string(),
104        }
105    }
106}