neophyte_ui/
options.rs

1impl From<String> for GuiFont {
2    fn from(option: String) -> Self {
3        let mut out = GuiFont::default();
4        let mut state = ParseState::Normal;
5        let mut current = String::new();
6        for c in option.chars() {
7            match state {
8                ParseState::Normal => {
9                    if c.is_whitespace() && current.is_empty() {
10                        continue;
11                    }
12
13                    match c {
14                        '\\' => state = ParseState::Escape,
15                        ',' => {
16                            out.fonts.push(current);
17                            current = String::default();
18                            state = ParseState::Normal;
19                        }
20                        '_' => current.push(' '),
21                        ':' => state = ParseState::OptionStart,
22                        _ => current.push(c),
23                    }
24                }
25
26                ParseState::Escape => {
27                    current.push(c);
28                    state = ParseState::Normal;
29                }
30
31                ParseState::OptionStart => {
32                    state = match c {
33                        'w' | 'W' => ParseState::OptionSize(0, SizeKind::Width),
34                        'h' | 'H' => ParseState::OptionSize(0, SizeKind::Height),
35                        _ => ParseState::OptionUnknown,
36                    };
37                }
38
39                ParseState::OptionSize(size, kind) => match c {
40                    '0'..='9' => {
41                        let size = size * 10 + c as u32 - '0' as u32;
42                        state = ParseState::OptionSize(size, kind);
43                    }
44                    ',' => {
45                        out.fonts.push(current);
46                        out.size = FontSize::new(size as f32, kind);
47                        current = String::default();
48                        state = ParseState::Normal;
49                    }
50                    ':' => {
51                        out.size = FontSize::new(size as f32, kind);
52                        state = ParseState::OptionStart;
53                    }
54                    _ => {
55                        log::warn!("Bad font height option");
56                        break;
57                    }
58                },
59
60                ParseState::OptionUnknown => match c {
61                    ',' => {
62                        out.fonts.push(current);
63                        current = String::default();
64                        state = ParseState::Normal;
65                    }
66                    ':' => state = ParseState::OptionStart,
67                    _ => {}
68                },
69            }
70        }
71
72        if let ParseState::OptionSize(size, kind) = state {
73            out.size = FontSize::new(size as f32, kind);
74        }
75
76        if !current.is_empty() {
77            out.fonts.push(current);
78        }
79
80        out
81    }
82}
83
84#[derive(Debug, Default, Clone, PartialEq)]
85pub struct GuiFont {
86    pub fonts: Vec<String>,
87    pub size: FontSize,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq)]
91pub enum FontSize {
92    Width(f32),
93    Height(f32),
94}
95
96impl FontSize {
97    fn new(size: f32, kind: SizeKind) -> Self {
98        match kind {
99            SizeKind::Width => Self::Width(size),
100            SizeKind::Height => Self::Height(size),
101        }
102    }
103}
104
105impl Default for FontSize {
106    fn default() -> Self {
107        Self::Height(18.)
108    }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112enum ParseState {
113    /// Appending chars as normal
114    Normal,
115    /// Found a backslash escape sequence
116    Escape,
117    /// Found a :
118    OptionStart,
119    /// Found a :h or :w
120    OptionSize(u32, SizeKind),
121    /// An unknown option is being specified
122    OptionUnknown,
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126enum SizeKind {
127    Width,
128    Height,
129}