term_model/config/
font.rs
1use std::fmt;
2
3#[cfg(not(target_os = "fuchsia"))]
4use font::Size;
5use log::error;
6use serde::de::Visitor;
7use serde::{Deserialize, Deserializer};
8
9#[cfg(target_os = "macos")]
10use crate::config::DefaultTrueBool;
11use crate::config::{failure_default, Delta, LOG_TARGET_CONFIG};
12
13#[cfg(target_os = "fuchsia")]
14#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
15pub struct Size(i16);
16
17#[cfg(target_os = "fuchsia")]
18impl Size {
19 pub fn new(size: f32) -> Size {
21 Size((size * Size::factor()) as i16)
22 }
23
24 #[inline]
26 pub fn factor() -> f32 {
27 2.0
28 }
29
30 pub fn as_f32_pts(self) -> f32 {
32 f32::from(self.0) / Size::factor()
33 }
34}
35
36#[serde(default)]
43#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
44pub struct Font {
45 #[serde(deserialize_with = "failure_default")]
47 normal: FontDescription,
48
49 #[serde(deserialize_with = "failure_default")]
51 bold: SecondaryFontDescription,
52
53 #[serde(deserialize_with = "failure_default")]
55 italic: SecondaryFontDescription,
56
57 #[serde(deserialize_with = "failure_default")]
59 bold_italic: SecondaryFontDescription,
60
61 #[serde(deserialize_with = "DeserializeSize::deserialize")]
63 pub size: Size,
64
65 #[serde(deserialize_with = "failure_default")]
67 pub offset: Delta<i8>,
68
69 #[serde(deserialize_with = "failure_default")]
71 pub glyph_offset: Delta<i8>,
72
73 #[cfg(target_os = "macos")]
74 #[serde(deserialize_with = "failure_default")]
75 use_thin_strokes: DefaultTrueBool,
76}
77
78impl Default for Font {
79 fn default() -> Font {
80 Font {
81 size: default_font_size(),
82 normal: Default::default(),
83 bold: Default::default(),
84 italic: Default::default(),
85 bold_italic: Default::default(),
86 glyph_offset: Default::default(),
87 offset: Default::default(),
88 #[cfg(target_os = "macos")]
89 use_thin_strokes: Default::default(),
90 }
91 }
92}
93
94impl Font {
95 pub fn with_size(self, size: Size) -> Font {
97 Font { size, ..self }
98 }
99
100 pub fn normal(&self) -> &FontDescription {
102 &self.normal
103 }
104
105 pub fn bold(&self) -> FontDescription {
107 self.bold.desc(&self.normal)
108 }
109
110 pub fn italic(&self) -> FontDescription {
112 self.italic.desc(&self.normal)
113 }
114
115 pub fn bold_italic(&self) -> FontDescription {
117 self.bold_italic.desc(&self.normal)
118 }
119
120 #[cfg(target_os = "macos")]
121 pub fn use_thin_strokes(&self) -> bool {
122 self.use_thin_strokes.0
123 }
124
125 #[cfg(not(target_os = "macos"))]
126 pub fn use_thin_strokes(&self) -> bool {
127 false
128 }
129}
130
131fn default_font_size() -> Size {
132 Size::new(11.)
133}
134
135#[serde(default)]
137#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
138pub struct FontDescription {
139 #[serde(deserialize_with = "failure_default")]
140 pub family: String,
141 #[serde(deserialize_with = "failure_default")]
142 pub style: Option<String>,
143}
144
145impl Default for FontDescription {
146 fn default() -> FontDescription {
147 FontDescription {
148 #[cfg(not(any(target_os = "macos", windows)))]
149 family: "monospace".into(),
150 #[cfg(target_os = "macos")]
151 family: "Menlo".into(),
152 #[cfg(windows)]
153 family: "Consolas".into(),
154 style: None,
155 }
156 }
157}
158
159#[serde(default)]
161#[derive(Debug, Default, Deserialize, Clone, PartialEq, Eq)]
162pub struct SecondaryFontDescription {
163 #[serde(deserialize_with = "failure_default")]
164 family: Option<String>,
165 #[serde(deserialize_with = "failure_default")]
166 style: Option<String>,
167}
168
169impl SecondaryFontDescription {
170 pub fn desc(&self, fallback: &FontDescription) -> FontDescription {
171 FontDescription {
172 family: self.family.clone().unwrap_or_else(|| fallback.family.clone()),
173 style: self.style.clone(),
174 }
175 }
176}
177
178trait DeserializeSize: Sized {
179 fn deserialize<'a, D>(_: D) -> ::std::result::Result<Self, D::Error>
180 where
181 D: serde::de::Deserializer<'a>;
182}
183
184impl DeserializeSize for Size {
185 fn deserialize<'a, D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
186 where
187 D: serde::de::Deserializer<'a>,
188 {
189 use std::marker::PhantomData;
190
191 struct NumVisitor<__D> {
192 _marker: PhantomData<__D>,
193 }
194
195 impl<'a, __D> Visitor<'a> for NumVisitor<__D>
196 where
197 __D: serde::de::Deserializer<'a>,
198 {
199 type Value = f64;
200
201 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 f.write_str("f64 or u64")
203 }
204
205 fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Self::Value, E>
206 where
207 E: ::serde::de::Error,
208 {
209 Ok(value)
210 }
211
212 fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Self::Value, E>
213 where
214 E: ::serde::de::Error,
215 {
216 Ok(value as f64)
217 }
218 }
219
220 #[cfg(not(target_os = "fuchsia"))]
221 let value = serde_yaml::Value::deserialize(deserializer)?;
222 #[cfg(target_os = "fuchsia")]
223 let value = serde_json::Value::deserialize(deserializer)?;
224 let size = value
225 .deserialize_any(NumVisitor::<D> { _marker: PhantomData })
226 .map(|v| Size::new(v as _));
227
228 match size {
230 Ok(size) => Ok(size),
231 Err(err) => {
232 let size = default_font_size();
233 error!(
234 target: LOG_TARGET_CONFIG,
235 "Problem with config: {}; using size {}",
236 err,
237 size.as_f32_pts()
238 );
239 Ok(size)
240 },
241 }
242 }
243}