Skip to main content

laser_pdf/serde_elements/
elements.rs

1use std::ops::Index;
2
3use elements::rotate::Rotation;
4
5use crate::{
6    elements::{h_align::HorizontalAlignment, row::Flex, text::TextAlign},
7    *,
8};
9
10use super::{Font, SerdeElement, SerdeElementElement};
11
12const fn default_false() -> bool {
13    false
14}
15
16const fn default_0u8() -> u8 {
17    0
18}
19
20#[derive(Clone, Serialize, Deserialize)]
21pub enum SerdeLinkTarget {
22    Uri(String),
23}
24
25impl SerdeLinkTarget {
26    pub fn as_link_target(&self) -> LinkTarget<'_> {
27        match self {
28            SerdeLinkTarget::Uri(uri) => LinkTarget::Uri(uri),
29        }
30    }
31}
32
33#[derive(Clone, Serialize, Deserialize)]
34pub struct None;
35
36impl SerdeElement for None {
37    fn element(
38        &self,
39        _: &impl for<'a> Index<&'a str, Output = Font>,
40        _: impl CompositeElementCallback,
41    ) {
42    }
43}
44
45#[derive(Clone, Serialize, Deserialize)]
46pub struct Empty;
47
48impl SerdeElement for Empty {
49    fn element(
50        &self,
51        _: &impl for<'a> Index<&'a str, Output = Font>,
52        callback: impl CompositeElementCallback,
53    ) {
54        callback.call(&elements::empty::Empty);
55    }
56}
57
58#[derive(Clone, Serialize, Deserialize)]
59pub struct Debug<E> {
60    pub element: Box<E>,
61
62    #[serde(default = "default_0u8")]
63    pub color: u8,
64
65    #[serde(default = "default_false")]
66    pub show_max_width: bool,
67
68    #[serde(default = "default_false")]
69    pub show_last_location_max_height: bool,
70}
71
72impl<E: SerdeElement> SerdeElement for Debug<E> {
73    fn element(
74        &self,
75        fonts: &impl for<'a> Index<&'a str, Output = Font>,
76        callback: impl CompositeElementCallback,
77    ) {
78        callback.call(&elements::debug::Debug {
79            element: SerdeElementElement {
80                element: &*self.element,
81                fonts,
82            },
83            color: self.color,
84            show_max_width: self.show_max_width,
85            show_last_location_max_height: self.show_last_location_max_height,
86        });
87    }
88}
89
90#[derive(Clone, Serialize, Deserialize)]
91pub struct Text {
92    pub text: String,
93    pub font: String,
94    pub size: f32,
95    pub color: u32,
96    pub underline: bool,
97    pub extra_character_spacing: f32,
98    pub extra_word_spacing: f32,
99    pub extra_line_height: f32,
100    pub align: TextAlign,
101    /// Link to be added as a link annotation
102    #[serde(default)]
103    pub link: Option<SerdeLinkTarget>,
104}
105
106impl SerdeElement for Text {
107    fn element(
108        &self,
109        fonts: &impl for<'a> Index<&'a str, Output = Font>,
110        callback: impl CompositeElementCallback,
111    ) {
112        callback.call(&elements::text::Text {
113            text: &self.text,
114            font: &*fonts[&self.font],
115            size: self.size,
116            color: self.color,
117            underline: self.underline,
118            extra_character_spacing: self.extra_character_spacing,
119            extra_word_spacing: self.extra_word_spacing,
120            extra_line_height: self.extra_line_height,
121            align: self.align,
122            link: self.link.as_ref().map(SerdeLinkTarget::as_link_target),
123        });
124    }
125}
126
127#[derive(Clone, Serialize, Deserialize)]
128pub struct RichTextSpan {
129    /// The text content to render
130    pub text: String,
131    /// Font reference
132    pub font: String,
133    /// Font size in points
134    pub size: f32,
135    /// Text color as RGBA (default: black 0x00_00_00_FF)
136    pub color: u32,
137    /// Whether to underline the text
138    pub underline: bool,
139    /// Additional spacing between characters
140    pub extra_character_spacing: f32,
141    /// Additional spacing between words
142    pub extra_word_spacing: f32,
143    /// Additional line height
144    pub extra_line_height: f32,
145    /// Link to be added as a link annotation
146    #[serde(default)]
147    pub link: Option<SerdeLinkTarget>,
148}
149
150#[derive(Clone, Serialize, Deserialize)]
151pub struct RichText {
152    pub spans: Vec<RichTextSpan>,
153    pub align: TextAlign,
154}
155
156impl SerdeElement for RichText {
157    fn element(
158        &self,
159        fonts: &impl for<'a> Index<&'a str, Output = Font>,
160        callback: impl CompositeElementCallback,
161    ) {
162        callback.call(&elements::rich_text::RichText {
163            spans: self.spans.iter().map(|s| elements::rich_text::Span {
164                text: &s.text,
165                font: &*fonts[&s.font],
166                size: s.size,
167                color: s.color,
168                underline: s.underline,
169                extra_character_spacing: s.extra_character_spacing,
170                extra_word_spacing: s.extra_word_spacing,
171                extra_line_height: s.extra_line_height,
172                link: s.link.as_ref().map(SerdeLinkTarget::as_link_target),
173            }),
174            align: self.align,
175        });
176    }
177}
178
179#[derive(Clone, Serialize, Deserialize)]
180pub struct VGap {
181    pub gap: f32,
182}
183
184impl SerdeElement for VGap {
185    fn element(
186        &self,
187        _: &impl for<'a> Index<&'a str, Output = Font>,
188        callback: impl CompositeElementCallback,
189    ) {
190        callback.call(&elements::v_gap::VGap(self.gap));
191    }
192}
193
194#[derive(Clone, Serialize, Deserialize)]
195pub struct HAlign<E> {
196    pub alignment: HorizontalAlignment,
197    pub element: Box<E>,
198}
199
200impl<E: SerdeElement> SerdeElement for HAlign<E> {
201    fn element(
202        &self,
203        fonts: &impl for<'a> Index<&'a str, Output = Font>,
204        callback: impl CompositeElementCallback,
205    ) {
206        callback.call(&elements::h_align::HAlign(
207            self.alignment,
208            SerdeElementElement {
209                element: &*self.element,
210                fonts,
211            },
212        ));
213    }
214}
215
216#[derive(Clone, Serialize, Deserialize)]
217pub struct Padding<E> {
218    pub left: f32,
219    pub right: f32,
220    pub top: f32,
221    pub bottom: f32,
222    pub element: Box<E>,
223}
224
225impl<E: SerdeElement> SerdeElement for Padding<E> {
226    fn element(
227        &self,
228        fonts: &impl for<'a> Index<&'a str, Output = Font>,
229        callback: impl CompositeElementCallback,
230    ) {
231        callback.call(&elements::padding::Padding {
232            left: self.left,
233            right: self.right,
234            top: self.top,
235            bottom: self.bottom,
236            element: SerdeElementElement {
237                element: &*self.element,
238                fonts,
239            },
240        });
241    }
242}
243
244#[derive(Clone, Serialize, Deserialize)]
245pub struct StyledBox<E> {
246    pub element: Box<E>,
247    pub padding_left: f32,
248    pub padding_right: f32,
249    pub padding_top: f32,
250    pub padding_bottom: f32,
251    pub border_radius: f32,
252    pub fill: Option<u32>,
253    pub outline: Option<LineStyle>,
254}
255
256impl<E: SerdeElement> SerdeElement for StyledBox<E> {
257    fn element(
258        &self,
259        fonts: &impl for<'a> Index<&'a str, Output = Font>,
260        callback: impl CompositeElementCallback,
261    ) {
262        callback.call(&elements::styled_box::StyledBox {
263            element: SerdeElementElement {
264                element: &*self.element,
265                fonts,
266            },
267            padding_left: self.padding_left,
268            padding_right: self.padding_right,
269            padding_top: self.padding_top,
270            padding_bottom: self.padding_bottom,
271            border_radius: self.border_radius,
272            fill: self.fill,
273            outline: self.outline,
274        });
275    }
276}
277
278#[derive(Clone, Serialize, Deserialize)]
279pub struct Line {
280    pub style: LineStyle,
281}
282
283impl SerdeElement for Line {
284    fn element(
285        &self,
286        _: &impl for<'a> Index<&'a str, Output = Font>,
287        callback: impl CompositeElementCallback,
288    ) {
289        callback.call(&elements::line::Line { style: self.style });
290    }
291}
292
293#[derive(Clone, Deserialize)]
294pub struct Image {
295    #[serde(rename = "path", deserialize_with = "crate::image::deserialize_image")]
296    pub image: crate::image::Image,
297}
298
299impl SerdeElement for Image {
300    fn element(
301        &self,
302        _: &impl for<'a> Index<&'a str, Output = Font>,
303        callback: impl CompositeElementCallback,
304    ) {
305        callback.call(&elements::image::ImageElement { image: &self.image });
306    }
307}
308
309#[derive(Clone, Serialize, Deserialize)]
310pub struct Rectangle {
311    pub size: (f32, f32),
312    pub fill: Option<u32>,
313    pub outline: Option<(f32, u32)>,
314}
315
316impl SerdeElement for Rectangle {
317    fn element(
318        &self,
319        _: &impl for<'a> Index<&'a str, Output = Font>,
320        callback: impl CompositeElementCallback,
321    ) {
322        callback.call(&elements::rectangle::Rectangle {
323            size: self.size,
324            fill: self.fill,
325            outline: self.outline,
326        });
327    }
328}
329
330#[derive(Clone, Serialize, Deserialize)]
331pub struct Circle {
332    pub radius: f32,
333    pub fill: Option<u32>,
334    pub outline: Option<(f32, u32)>,
335}
336
337impl SerdeElement for Circle {
338    fn element(
339        &self,
340        _: &impl for<'a> Index<&'a str, Output = Font>,
341        callback: impl CompositeElementCallback,
342    ) {
343        callback.call(&elements::circle::Circle {
344            radius: self.radius,
345            fill: self.fill,
346            outline: self.outline,
347        });
348    }
349}
350
351#[derive(Clone, Serialize, Deserialize)]
352pub struct Column<E> {
353    pub content: Vec<E>,
354    pub gap: f32,
355
356    #[serde(default = "default_false")]
357    pub collapse: bool,
358}
359
360impl<E: SerdeElement> SerdeElement for Column<E> {
361    fn element(
362        &self,
363        fonts: &impl for<'a> Index<&'a str, Output = Font>,
364        callback: impl CompositeElementCallback,
365    ) {
366        callback.call(&elements::column::Column {
367            content: |mut content| {
368                for element in &self.content {
369                    content = content.add(&SerdeElementElement { element, fonts })?;
370                }
371
372                Option::None
373            },
374            gap: self.gap,
375            collapse: self.collapse,
376        });
377    }
378}
379
380#[derive(Clone, Serialize, Deserialize)]
381pub struct RowElement<E> {
382    pub element: E,
383    pub flex: Flex,
384}
385
386#[derive(Clone, Serialize, Deserialize)]
387pub struct Row<E> {
388    pub content: Vec<RowElement<E>>,
389    pub gap: f32,
390    pub expand: bool,
391    pub collapse: bool,
392}
393
394impl<E: SerdeElement> SerdeElement for Row<E> {
395    fn element(
396        &self,
397        fonts: &impl for<'a> Index<&'a str, Output = Font>,
398        callback: impl CompositeElementCallback,
399    ) {
400        callback.call(&elements::row::Row {
401            content: |content| {
402                for RowElement { element, flex } in &self.content {
403                    content.add(&SerdeElementElement { element, fonts }, *flex);
404                }
405            },
406            gap: self.gap,
407            expand: self.expand,
408            collapse: self.collapse,
409        });
410    }
411}
412
413#[derive(Clone, Serialize, Deserialize)]
414pub struct BreakList<E> {
415    pub content: Vec<E>,
416    pub gap: f32,
417}
418
419impl<E: SerdeElement> SerdeElement for BreakList<E> {
420    fn element(
421        &self,
422        fonts: &impl for<'a> Index<&'a str, Output = Font>,
423        callback: impl CompositeElementCallback,
424    ) {
425        callback.call(&elements::break_list::BreakList {
426            content: |mut content| {
427                for element in &self.content {
428                    content = content.add(&SerdeElementElement { element, fonts })?;
429                }
430
431                Option::None
432            },
433            gap: self.gap,
434        });
435    }
436}
437
438#[derive(Clone, Serialize, Deserialize)]
439pub struct Stack<E> {
440    pub content: Vec<E>,
441    pub expand: bool,
442}
443
444impl<E: SerdeElement> SerdeElement for Stack<E> {
445    fn element(
446        &self,
447        fonts: &impl for<'a> Index<&'a str, Output = Font>,
448        callback: impl CompositeElementCallback,
449    ) {
450        callback.call(&elements::stack::Stack {
451            content: |content| {
452                for element in &self.content {
453                    content.add(&SerdeElementElement { element, fonts });
454                }
455            },
456            expand: self.expand,
457        });
458    }
459}
460
461#[derive(Clone, Serialize, Deserialize)]
462pub struct TableRowElement<E> {
463    pub element: E,
464    pub flex: elements::table_row::Flex,
465}
466
467#[derive(Clone, Serialize, Deserialize)]
468pub struct TableRow<E> {
469    pub content: Vec<TableRowElement<E>>,
470    pub line_style: LineStyle,
471
472    #[serde(alias = "y_expand")]
473    pub expand: bool,
474}
475
476impl<E: SerdeElement> SerdeElement for TableRow<E> {
477    fn element(
478        &self,
479        fonts: &impl for<'a> Index<&'a str, Output = Font>,
480        callback: impl CompositeElementCallback,
481    ) {
482        callback.call(&elements::table_row::TableRow {
483            content: |content| {
484                for TableRowElement { element, flex } in &self.content {
485                    content.add(&SerdeElementElement { element, fonts }, *flex);
486                }
487            },
488            line_style: self.line_style,
489            expand: self.expand,
490        });
491    }
492}
493
494#[derive(Clone, Serialize, Deserialize)]
495pub struct Titled<E> {
496    pub title: Box<E>,
497    pub content: Box<E>,
498    pub gap: f32,
499
500    #[serde(default = "default_false")]
501    pub collapse_on_empty_content: bool,
502}
503
504impl<E: SerdeElement> SerdeElement for Titled<E> {
505    fn element(
506        &self,
507        fonts: &impl for<'a> Index<&'a str, Output = Font>,
508        callback: impl CompositeElementCallback,
509    ) {
510        callback.call(&elements::titled::Titled {
511            title: SerdeElementElement {
512                element: &*self.title,
513                fonts,
514            },
515            content: SerdeElementElement {
516                element: &*self.content,
517                fonts,
518            },
519            gap: self.gap,
520            collapse_on_empty_content: self.collapse_on_empty_content,
521        });
522    }
523}
524
525#[derive(Clone, Serialize, Deserialize)]
526pub struct TitleOrBreak<E> {
527    pub title: Box<E>,
528    pub content: Box<E>,
529    pub gap: f32,
530
531    #[serde(default = "default_false")]
532    pub collapse_on_empty_content: bool,
533}
534
535impl<E: SerdeElement> SerdeElement for TitleOrBreak<E> {
536    fn element(
537        &self,
538        fonts: &impl for<'a> Index<&'a str, Output = Font>,
539        callback: impl CompositeElementCallback,
540    ) {
541        callback.call(&elements::title_or_break::TitleOrBreak {
542            title: &SerdeElementElement {
543                element: &*self.title,
544                fonts,
545            },
546            content: &SerdeElementElement {
547                element: &*self.content,
548                fonts,
549            },
550            gap: self.gap,
551            collapse_on_empty_content: self.collapse_on_empty_content,
552        });
553    }
554}
555
556#[derive(Clone, Serialize, Deserialize)]
557pub struct ChangingTitle<E> {
558    pub first_title: Box<E>,
559
560    #[serde(alias = "second_title")]
561    pub remaining_title: Box<E>,
562
563    pub content: Box<E>,
564    pub gap: f32,
565
566    #[serde(default = "default_false")]
567    pub collapse: bool,
568}
569
570impl<E: SerdeElement> SerdeElement for ChangingTitle<E> {
571    fn element(
572        &self,
573        fonts: &impl for<'a> Index<&'a str, Output = Font>,
574        callback: impl CompositeElementCallback,
575    ) {
576        callback.call(&elements::changing_title::ChangingTitle {
577            first_title: SerdeElementElement {
578                element: &*self.first_title,
579                fonts,
580            },
581            remaining_title: SerdeElementElement {
582                element: &*self.remaining_title,
583                fonts,
584            },
585            content: SerdeElementElement {
586                element: &*self.content,
587                fonts,
588            },
589            gap: self.gap,
590            collapse: self.collapse,
591        });
592    }
593}
594
595#[derive(Clone, Serialize, Deserialize)]
596pub struct RepeatAfterBreak<E> {
597    pub title: Box<E>,
598    pub content: Box<E>,
599    pub gap: f32,
600
601    #[serde(default = "default_false")]
602    pub collapse_on_empty_content: bool,
603}
604
605impl<E: SerdeElement> SerdeElement for RepeatAfterBreak<E> {
606    fn element(
607        &self,
608        fonts: &impl for<'a> Index<&'a str, Output = Font>,
609        callback: impl CompositeElementCallback,
610    ) {
611        callback.call(&elements::repeat_after_break::RepeatAfterBreak {
612            title: &SerdeElementElement {
613                element: &*self.title,
614                fonts,
615            },
616            content: &SerdeElementElement {
617                element: &*self.content,
618                fonts,
619            },
620            gap: self.gap,
621            collapse_on_empty_content: self.collapse_on_empty_content,
622        });
623    }
624}
625
626#[derive(Clone, Serialize, Deserialize)]
627pub struct RepeatBottom<E> {
628    pub content: Box<E>,
629    pub bottom: Box<E>,
630    pub gap: f32,
631
632    #[serde(default = "default_false")]
633    pub collapse: bool,
634}
635
636impl<E: SerdeElement> SerdeElement for RepeatBottom<E> {
637    fn element(
638        &self,
639        fonts: &impl for<'a> Index<&'a str, Output = Font>,
640        callback: impl CompositeElementCallback,
641    ) {
642        callback.call(&elements::repeat_bottom::RepeatBottom {
643            content: SerdeElementElement {
644                element: &*self.content,
645                fonts,
646            },
647            bottom: SerdeElementElement {
648                element: &*self.bottom,
649                fonts,
650            },
651            gap: self.gap,
652            collapse: self.collapse,
653        });
654    }
655}
656
657#[derive(Clone, Serialize, Deserialize)]
658pub struct PinBelow<E> {
659    pub content: Box<E>,
660    pub pinned_element: Box<E>,
661    pub gap: f32,
662
663    #[serde(default = "default_false")]
664    pub collapse: bool,
665}
666
667impl<E: SerdeElement> SerdeElement for PinBelow<E> {
668    fn element(
669        &self,
670        fonts: &impl for<'a> Index<&'a str, Output = Font>,
671        callback: impl CompositeElementCallback,
672    ) {
673        callback.call(&elements::pin_below::PinBelow {
674            content: SerdeElementElement {
675                element: &*self.content,
676                fonts,
677            },
678            pinned_element: SerdeElementElement {
679                element: &*self.pinned_element,
680                fonts,
681            },
682            gap: self.gap,
683            collapse: self.collapse,
684        });
685    }
686}
687
688#[derive(Clone, Serialize, Deserialize)]
689pub struct ForceBreak;
690
691impl SerdeElement for ForceBreak {
692    fn element(
693        &self,
694        _: &impl for<'a> Index<&'a str, Output = Font>,
695        callback: impl CompositeElementCallback,
696    ) {
697        callback.call(&elements::force_break::ForceBreak);
698    }
699}
700
701#[derive(Clone, Serialize, Deserialize)]
702pub struct BreakWhole<E> {
703    pub element: Box<E>,
704}
705
706impl<E: SerdeElement> SerdeElement for BreakWhole<E> {
707    fn element(
708        &self,
709        fonts: &impl for<'a> Index<&'a str, Output = Font>,
710        callback: impl CompositeElementCallback,
711    ) {
712        callback.call(&elements::break_whole::BreakWhole(&SerdeElementElement {
713            element: &*self.element,
714            fonts,
715        }));
716    }
717}
718
719#[derive(Clone, Serialize, Deserialize)]
720pub struct MinFirstHeight<E> {
721    pub element: Box<E>,
722    pub min_first_height: f32,
723}
724
725impl<E: SerdeElement> SerdeElement for MinFirstHeight<E> {
726    fn element(
727        &self,
728        fonts: &impl for<'a> Index<&'a str, Output = Font>,
729        callback: impl CompositeElementCallback,
730    ) {
731        callback.call(&elements::min_first_height::MinFirstHeight {
732            element: SerdeElementElement {
733                element: &*self.element,
734                fonts,
735            },
736            min_first_height: self.min_first_height,
737        });
738    }
739}
740
741#[derive(Clone, Serialize, Deserialize)]
742pub struct AlignLocationBottom<E> {
743    pub element: Box<E>,
744}
745
746impl<E: SerdeElement> SerdeElement for AlignLocationBottom<E> {
747    fn element(
748        &self,
749        fonts: &impl for<'a> Index<&'a str, Output = Font>,
750        callback: impl CompositeElementCallback,
751    ) {
752        callback.call(&elements::align_location_bottom::AlignLocationBottom(
753            SerdeElementElement {
754                element: &*self.element,
755                fonts,
756            },
757        ));
758    }
759}
760
761#[derive(Clone, Serialize, Deserialize)]
762pub struct AlignPreferredHeightBottom<E> {
763    pub element: Box<E>,
764}
765
766impl<E: SerdeElement> SerdeElement for AlignPreferredHeightBottom<E> {
767    fn element(
768        &self,
769        fonts: &impl for<'a> Index<&'a str, Output = Font>,
770        callback: impl CompositeElementCallback,
771    ) {
772        callback.call(
773            &elements::align_preferred_height_bottom::AlignPreferredHeightBottom(
774                SerdeElementElement {
775                    element: &*self.element,
776                    fonts,
777                },
778            ),
779        );
780    }
781}
782
783#[derive(Clone, Serialize, Deserialize)]
784pub struct ExpandToPreferredHeight<E> {
785    pub element: Box<E>,
786}
787
788impl<E: SerdeElement> SerdeElement for ExpandToPreferredHeight<E> {
789    fn element(
790        &self,
791        fonts: &impl for<'a> Index<&'a str, Output = Font>,
792        callback: impl CompositeElementCallback,
793    ) {
794        callback.call(
795            &elements::expand_to_preferred_height::ExpandToPreferredHeight(SerdeElementElement {
796                element: &*self.element,
797                fonts,
798            }),
799        );
800    }
801}
802
803#[derive(Clone, Serialize, Deserialize)]
804pub struct CenterInPreferredHeight<E> {
805    pub element: Box<E>,
806}
807
808impl<E: SerdeElement> SerdeElement for CenterInPreferredHeight<E> {
809    fn element(
810        &self,
811        fonts: &impl for<'a> Index<&'a str, Output = Font>,
812        callback: impl CompositeElementCallback,
813    ) {
814        callback.call(
815            &elements::center_in_preferred_height::CenterInPreferredHeight(SerdeElementElement {
816                element: &*self.element,
817                fonts,
818            }),
819        );
820    }
821}
822
823#[derive(Clone, Serialize, Deserialize)]
824pub struct ShrinkToFit<E> {
825    pub element: Box<E>,
826    pub min_height: f32,
827}
828
829impl<E: SerdeElement> SerdeElement for ShrinkToFit<E> {
830    fn element(
831        &self,
832        fonts: &impl for<'a> Index<&'a str, Output = Font>,
833        callback: impl CompositeElementCallback,
834    ) {
835        callback.call(&elements::shrink_to_fit::ShrinkToFit {
836            element: SerdeElementElement {
837                element: &*self.element,
838                fonts,
839            },
840            min_height: self.min_height,
841        });
842    }
843}
844
845#[derive(Clone, Serialize, Deserialize)]
846pub struct Rotate<E> {
847    pub element: Box<E>,
848    pub rotation: Rotation,
849}
850
851impl<E: SerdeElement> SerdeElement for Rotate<E> {
852    fn element(
853        &self,
854        fonts: &impl for<'a> Index<&'a str, Output = Font>,
855        callback: impl CompositeElementCallback,
856    ) {
857        callback.call(&elements::rotate::Rotate {
858            element: SerdeElementElement {
859                element: &*self.element,
860                fonts,
861            },
862            rotation: self.rotation,
863        });
864    }
865}
866
867#[derive(Clone, Serialize, Deserialize)]
868pub struct MaxWidth<E> {
869    pub element: Box<E>,
870    pub max_width: f32,
871}
872
873impl<E: SerdeElement> SerdeElement for MaxWidth<E> {
874    fn element(
875        &self,
876        fonts: &impl for<'a> Index<&'a str, Output = Font>,
877        callback: impl CompositeElementCallback,
878    ) {
879        callback.call(&elements::max_width::MaxWidth {
880            element: SerdeElementElement {
881                element: &*self.element,
882                fonts,
883            },
884            max_width: self.max_width,
885        });
886    }
887}
888
889#[derive(Clone, Serialize, Deserialize)]
890pub enum PageNumberText {
891    Current {
892        before: String,
893        after: String,
894    },
895    Total {
896        before: String,
897        after: String,
898    },
899    CurrentAndTotal {
900        before: String,
901        between: String,
902        after: String,
903    },
904}
905
906#[derive(Clone, Serialize, Deserialize)]
907pub struct PageNumber {
908    pub skip_pages: usize,
909    pub pos: (elements::page::X, elements::page::Y),
910    pub text: PageNumberText,
911    pub font: String,
912    pub size: f32,
913    pub color: u32,
914    pub underline: bool,
915}
916
917#[derive(Clone, Serialize, Deserialize)]
918pub struct DecorationElement<E> {
919    pub element: E,
920    pub pos: (elements::page::X, elements::page::Y),
921    pub width: Option<f32>,
922    pub skip_pages: usize,
923    pub repeat: bool,
924}
925
926#[derive(Clone, Serialize, Deserialize)]
927pub struct Page<E> {
928    pub primary: Box<E>,
929    pub border_left: f32,
930    pub border_right: f32,
931    pub border_top: f32,
932    pub border_bottom: f32,
933    pub decoration_elements: Vec<DecorationElement<E>>,
934    pub page_numbers: Vec<PageNumber>,
935}
936
937impl<E: SerdeElement> SerdeElement for Page<E> {
938    fn element(
939        &self,
940        fonts: &impl for<'a> Index<&'a str, Output = Font>,
941        callback: impl CompositeElementCallback,
942    ) {
943        callback.call(&elements::page::Page {
944            primary: SerdeElementElement {
945                element: &*self.primary,
946                fonts,
947            },
948            border_left: self.border_left,
949            border_right: self.border_right,
950            border_top: self.border_top,
951            border_bottom: self.border_bottom,
952            decoration_elements: |content, page, page_count| {
953                for decoration_element in &self.decoration_elements {
954                    if page == decoration_element.skip_pages
955                        || decoration_element.repeat && page > decoration_element.skip_pages
956                    {
957                        content.add(
958                            &SerdeElementElement {
959                                element: &decoration_element.element,
960                                fonts,
961                            },
962                            decoration_element.pos,
963                            decoration_element.width,
964                        );
965                    }
966                }
967
968                for page_number in &self.page_numbers {
969                    if page >= page_number.skip_pages {
970                        content.add(
971                            &elements::text::Text {
972                                underline: page_number.underline,
973                                color: page_number.color,
974                                ..elements::text::Text::new(
975                                    // Since the decoration_elements callback is only called when
976                                    // drawing it shouldn't be a problem to be allocating a string here,
977                                    // but it could potentially be optimized by reusing the buffer.
978                                    &match page_number.text {
979                                        PageNumberText::Current {
980                                            ref before,
981                                            ref after,
982                                        } => {
983                                            format!("{before}{}{after}", page + 1)
984                                        }
985                                        PageNumberText::Total {
986                                            ref before,
987                                            ref after,
988                                        } => format!("{before}{page_count}{after}"),
989                                        PageNumberText::CurrentAndTotal {
990                                            ref before,
991                                            ref between,
992                                            ref after,
993                                        } => {
994                                            format!(
995                                                "{before}{}{between}{page_count}{after}",
996                                                page + 1
997                                            )
998                                        }
999                                    },
1000                                    &*fonts[&page_number.font],
1001                                    page_number.size,
1002                                )
1003                            },
1004                            page_number.pos,
1005                            Option::None,
1006                        );
1007                    }
1008                }
1009            },
1010        });
1011    }
1012}
1013
1014#[derive(Clone, Serialize, Deserialize)]
1015pub struct Link<E> {
1016    pub element: Box<E>,
1017    pub target: SerdeLinkTarget,
1018}
1019
1020impl<E: SerdeElement> SerdeElement for Link<E> {
1021    fn element(
1022        &self,
1023        fonts: &impl for<'a> Index<&'a str, Output = Font>,
1024        callback: impl CompositeElementCallback,
1025    ) {
1026        callback.call(&elements::link::Link {
1027            element: SerdeElementElement {
1028                element: &*self.element,
1029                fonts,
1030            },
1031            target: self.target.as_link_target(),
1032        });
1033    }
1034}