text_document/
format.rs

1use crate::font::Font;
2use crate::text_document::Tab;
3use crate::ModelError;
4
5pub(crate) type FormatChangeResult = Result<Option<()>, ModelError>;
6
7#[derive(Clone, Eq, PartialEq, Debug)]
8pub enum Format {
9    FrameFormat(FrameFormat),
10    TextFormat(TextFormat),
11    BlockFormat(BlockFormat),
12    ImageFormat(ImageFormat),
13}
14
15pub(crate) trait IsFormat {
16    fn merge_with(&mut self, other_format: &Self) -> FormatChangeResult
17    where
18        Self: Sized;
19}
20
21#[derive(Default, Clone, Eq, PartialEq, Debug)]
22pub struct FrameFormat {
23    pub height: Option<usize>,
24    pub width: Option<usize>,
25    pub top_margin: Option<usize>,
26    pub bottom_margin: Option<usize>,
27    pub left_margin: Option<usize>,
28    pub right_margin: Option<usize>,
29    pub padding: Option<usize>,
30    pub border: Option<usize>,
31    pub position: Option<Position>,
32}
33
34impl FrameFormat {
35    pub fn new() -> Self {
36        FrameFormat {
37            ..Default::default()
38        }
39    }
40}
41
42impl IsFormat for FrameFormat {
43    fn merge_with(&mut self, other_format: &Self) -> FormatChangeResult
44    where
45        Self: Sized,
46    {
47        if let Some(value) = other_format.height {
48            self.height = Some(value);
49        }
50        if let Some(value) = other_format.width {
51            self.width = Some(value);
52        }
53        if let Some(value) = other_format.top_margin {
54            self.top_margin = Some(value);
55        }
56        if let Some(value) = other_format.bottom_margin {
57            self.bottom_margin = Some(value);
58        }
59        if let Some(value) = other_format.left_margin {
60            self.left_margin = Some(value);
61        }
62        if let Some(value) = other_format.right_margin {
63            self.right_margin = Some(value);
64        }
65        if let Some(value) = other_format.padding {
66            self.padding = Some(value);
67        }
68        if let Some(value) = other_format.border {
69            self.border = Some(value);
70        }
71        if let Some(value) = other_format.position {
72            self.position = Some(value);
73        }
74
75        Ok(Some(()))
76    }
77}
78
79#[derive(Clone, Copy, Eq, PartialEq, Debug)]
80pub enum Position {
81    InFlow,
82    FloatLeft,
83    FloatRight,
84}
85
86#[derive(Default, Clone, Eq, PartialEq, Debug)]
87pub struct TextFormat {
88    pub anchor_href: Option<String>,
89    pub anchor_names: Option<Vec<String>>,
90    pub is_anchor: Option<bool>,
91    pub font: Font,
92    //pub text_outline: Pen
93    pub tool_tip: Option<String>,
94    //pub underline_color: color
95    pub underline_style: Option<UnderlineStyle>,
96    pub vertical_alignment: Option<CharVerticalAlignment>,
97}
98
99impl TextFormat {
100    pub fn new() -> Self {
101        TextFormat {
102            ..Default::default()
103        }
104    }
105}
106
107impl IsFormat for TextFormat {
108    fn merge_with(&mut self, other_format: &Self) -> FormatChangeResult
109    where
110        Self: Sized,
111    {
112        if let Some(value) = &other_format.anchor_href {
113            self.anchor_href = Some(value.clone());
114        }
115
116        if let Some(value) = &other_format.anchor_names {
117            self.anchor_names = Some(value.clone());
118        }
119
120        if let Some(value) = other_format.is_anchor {
121            self.is_anchor = Some(value);
122        }
123
124        self.font.merge_with(&other_format.font)?;
125
126        if let Some(value) = &other_format.tool_tip {
127            self.tool_tip = Some(value.clone());
128        }
129
130        if let Some(value) = other_format.underline_style {
131            self.underline_style = Some(value);
132        }
133
134        if let Some(value) = other_format.vertical_alignment {
135            self.vertical_alignment = Some(value);
136        }
137
138        Ok(Some(()))
139    }
140}
141
142impl std::ops::Deref for TextFormat {
143    type Target = Font;
144    fn deref(&self) -> &Self::Target {
145        &self.font
146    }
147}
148
149impl std::ops::DerefMut for TextFormat {
150    fn deref_mut(&mut self) -> &mut Self::Target {
151        &mut self.font
152    }
153}
154
155#[derive(Clone, Copy, Eq, PartialEq, Debug)]
156pub enum CharVerticalAlignment {
157    AlignNormal,
158    AlignSuperScript,
159    AlignSubScript,
160    AlignMiddle,
161    AlignBottom,
162    AlignTop,
163    AlignBaseline,
164}
165
166#[derive(Clone, Copy, Eq, PartialEq, Debug)]
167pub enum UnderlineStyle {
168    NoUnderline,
169    SingleUnderline,
170    DashUnderline,
171    DotLine,
172    DashDotLine,
173    DashDotDotLine,
174    WaveUnderline,
175    SpellCheckUnderline,
176}
177
178#[derive(Clone, Eq, PartialEq, Debug, Default)]
179pub struct BlockFormat {
180    pub alignment: Option<Alignment>,
181    pub top_margin: Option<usize>,
182    pub bottom_margin: Option<usize>,
183    pub left_margin: Option<usize>,
184    pub right_margin: Option<usize>,
185    pub heading_level: Option<u8>,
186    pub indent: Option<u8>,
187    pub text_indent: Option<usize>,
188    pub tab_positions: Option<Vec<Tab>>,
189    pub marker: Option<MarkerType>,
190}
191
192impl BlockFormat {
193    pub fn new() -> Self {
194        BlockFormat {
195            ..Default::default()
196        }
197    }
198}
199
200impl IsFormat for BlockFormat {
201    fn merge_with(&mut self, other_format: &Self) -> FormatChangeResult
202    where
203        Self: Sized,
204    {
205        if let Some(value) = other_format.alignment {
206            self.alignment = Some(value);
207        }
208        if let Some(value) = other_format.top_margin {
209            self.top_margin = Some(value);
210        }
211        if let Some(value) = other_format.bottom_margin {
212            self.bottom_margin = Some(value);
213        }
214        if let Some(value) = other_format.left_margin {
215            self.left_margin = Some(value);
216        }
217        if let Some(value) = other_format.right_margin {
218            self.right_margin = Some(value);
219        }
220        if let Some(value) = other_format.heading_level {
221            self.heading_level = Some(value);
222        }
223
224        if let Some(value) = other_format.indent {
225            self.indent = Some(value);
226        }
227
228        if let Some(value) = other_format.text_indent {
229            self.text_indent = Some(value);
230        }
231
232        if let Some(value) = &other_format.tab_positions {
233            self.tab_positions = Some(value.clone());
234        }
235
236        if let Some(value) = other_format.marker {
237            self.marker = Some(value);
238        }
239
240        Ok(Some(()))
241    }
242}
243
244#[derive(Clone, Copy, Eq, PartialEq, Debug)]
245pub enum Alignment {
246    AlignLeft,
247    AlignRight,
248    AlignHCenter,
249    AlignJustify,
250}
251
252#[derive(Clone, Copy, Eq, PartialEq, Debug)]
253pub enum MarkerType {
254    NoMarker,
255    Unchecked,
256    Checked,
257}
258
259#[derive(Default, Clone, Eq, PartialEq, Debug)]
260pub struct ImageFormat {
261    pub(crate) text_format: TextFormat,
262    pub height: Option<usize>,
263    pub width: Option<usize>,
264    pub quality: Option<u8>,
265    pub name: Option<String>,
266}
267
268impl ImageFormat {
269    pub fn new() -> Self {
270        ImageFormat {
271            ..Default::default()
272        }
273    }
274}
275
276impl IsFormat for ImageFormat {
277    /// Merge with the other format. The other format fields, if filled, overwrite the fields of the first format
278    fn merge_with(&mut self, other_format: &Self) -> FormatChangeResult
279    where
280        Self: Sized,
281    {
282        self.text_format.merge_with(&other_format.text_format)?;
283
284        if let Some(value) = other_format.height {
285            self.height = Some(value)
286        }
287
288        if let Some(value) = other_format.width {
289            self.width = Some(value)
290        }
291
292        if let Some(value) = other_format.quality {
293            self.quality = Some(value)
294        }
295
296        if let Some(value) = other_format.name.clone() {
297            self.name = Some(value)
298        }
299
300        Ok(Some(()))
301    }
302}
303
304impl std::ops::Deref for ImageFormat {
305    type Target = TextFormat;
306    fn deref(&self) -> &Self::Target {
307        &self.text_format
308    }
309}
310
311pub(crate) trait FormattedElement<F: IsFormat> {
312    fn format(&self) -> F;
313
314    fn set_format(&self, format: &F) -> FormatChangeResult;
315
316    fn merge_format(&self, format: &F) -> FormatChangeResult;
317}
318
319#[cfg(test)]
320mod tests {
321
322    use super::*;
323
324    #[test]
325    fn merge_image_formats() {
326        let mut first = ImageFormat::new();
327        first.width = Some(40);
328        let mut second = ImageFormat::new();
329        second.height = Some(10);
330
331        first.merge_with(&second).unwrap();
332
333        assert_eq!(first.width, Some(40));
334        assert_eq!(first.height, Some(10));
335    }
336
337    #[test]
338    fn merge_block_formats() {
339        let mut first = BlockFormat::new();
340        first.alignment = Some(Alignment::AlignRight);
341        let mut second = BlockFormat::new();
342        second.left_margin = Some(10);
343
344        first.merge_with(&second).unwrap();
345
346        assert_eq!(first.alignment, Some(Alignment::AlignRight));
347        assert_eq!(first.left_margin, Some(10));
348    }
349
350    #[test]
351    fn merge_frame_formats() {
352        let mut first = FrameFormat::new();
353        first.position = Some(Position::FloatLeft);
354        let mut second = FrameFormat::new();
355        second.height = Some(10);
356
357        first.merge_with(&second).unwrap();
358
359        assert_eq!(first.position, Some(Position::FloatLeft));
360        assert_eq!(first.height, Some(10));
361    }
362
363    #[test]
364    fn merge_char_foramts() {
365        let mut first = TextFormat::new();
366        first.letter_spacing = Some(40);
367        let mut second = TextFormat::new();
368        second.underline = Some(true);
369
370        first.merge_with(&second).unwrap();
371
372        assert_eq!(first.letter_spacing, Some(40));
373        assert_eq!(first.underline, Some(true));
374    }
375}