embedded_text/plugin/
private.rs

1//! Plugin trait.
2
3use embedded_graphics::{
4    draw_target::DrawTarget,
5    prelude::PixelColor,
6    primitives::Rectangle,
7    text::renderer::{CharacterStyle, TextRenderer},
8};
9use object_chain::{Chain, ChainElement, Link};
10
11use crate::{
12    parser::Token,
13    rendering::{cursor::Cursor, TextBoxProperties},
14};
15
16/// Plugin trait.
17///
18/// Plugins allow modifying and extending TextBox's internals.
19///
20/// *Important*:
21/// This is an experimental, unstable feature. It can be, and probably will be modified without
22/// any prior notice.
23/// Using plugins require enabling the `plugin` crate feature.
24pub trait Plugin<'a, C>: Clone
25where
26    C: PixelColor,
27{
28    /// Called when a new line is started.
29    #[inline]
30    fn new_line(&mut self) {}
31
32    /// Generate the next text token.
33    #[inline]
34    fn next_token(
35        &mut self,
36        mut next_token: impl FnMut() -> Option<Token<'a, C>>,
37    ) -> Option<Token<'a, C>> {
38        next_token()
39    }
40
41    /// Modify the current token immediately before it is rendered.
42    ///
43    /// This function must return the same token type as the input, otherwise the returned token
44    /// is ignored.
45    #[inline]
46    fn render_token(&mut self, token: Token<'a, C>) -> Option<Token<'a, C>> {
47        Some(token)
48    }
49
50    /// Called after a piece of text is rendered.
51    #[inline]
52    fn post_render<T, D>(
53        &mut self,
54        _draw_target: &mut D,
55        _character_style: &T,
56        _text: Option<&str>,
57        _bounds: Rectangle,
58    ) -> Result<(), D::Error>
59    where
60        T: TextRenderer<Color = C>,
61        D: DrawTarget<Color = C>,
62    {
63        Ok(())
64    }
65
66    /// Called before TextBox rendering is started.
67    #[inline]
68    fn on_start_render<S: CharacterStyle + TextRenderer>(
69        &mut self,
70        _cursor: &mut Cursor,
71        _props: &TextBoxProperties<'_, S>,
72    ) {
73    }
74
75    /// Called after rendering has finished.
76    #[inline]
77    fn on_rendering_finished(&mut self) {}
78}
79
80impl<'a, C> Plugin<'a, C> for super::NoPlugin<C> where C: PixelColor {}
81
82impl<'a, C, P> Plugin<'a, C> for Chain<P>
83where
84    P: Plugin<'a, C>,
85    C: PixelColor,
86    Chain<P>: Clone,
87{
88    fn new_line(&mut self) {
89        self.object.new_line();
90    }
91
92    fn next_token(
93        &mut self,
94        next_token: impl FnMut() -> Option<Token<'a, C>>,
95    ) -> Option<Token<'a, C>> {
96        self.object.next_token(next_token)
97    }
98
99    fn render_token(&mut self, token: Token<'a, C>) -> Option<Token<'a, C>> {
100        self.object.render_token(token)
101    }
102
103    fn post_render<T, D>(
104        &mut self,
105        draw_target: &mut D,
106        character_style: &T,
107        text: Option<&str>,
108        bounds: Rectangle,
109    ) -> Result<(), D::Error>
110    where
111        T: TextRenderer<Color = C>,
112        D: DrawTarget<Color = C>,
113    {
114        self.object
115            .post_render(draw_target, character_style, text, bounds)
116    }
117
118    fn on_start_render<S: CharacterStyle + TextRenderer>(
119        &mut self,
120        cursor: &mut Cursor,
121        props: &TextBoxProperties<'_, S>,
122    ) {
123        self.object.on_start_render(cursor, props);
124    }
125
126    fn on_rendering_finished(&mut self) {
127        self.object.on_rendering_finished();
128    }
129}
130
131impl<'a, C, P, CE> Plugin<'a, C> for Link<P, CE>
132where
133    CE: ChainElement + Plugin<'a, C>,
134    P: Plugin<'a, C>,
135    C: PixelColor,
136    Link<P, CE>: Clone,
137{
138    fn new_line(&mut self) {
139        self.parent.new_line();
140        self.object.new_line();
141    }
142
143    fn next_token(
144        &mut self,
145        mut next_token: impl FnMut() -> Option<Token<'a, C>>,
146    ) -> Option<Token<'a, C>> {
147        let parent = &mut self.parent;
148        let next_token = || parent.next_token(&mut next_token);
149        self.object.next_token(next_token)
150    }
151
152    fn render_token(&mut self, token: Token<'a, C>) -> Option<Token<'a, C>> {
153        self.parent
154            .render_token(token)
155            .and_then(|t| self.object.render_token(t))
156    }
157
158    fn post_render<T, D>(
159        &mut self,
160        draw_target: &mut D,
161        character_style: &T,
162        text: Option<&str>,
163        bounds: Rectangle,
164    ) -> Result<(), D::Error>
165    where
166        T: TextRenderer<Color = C>,
167        D: DrawTarget<Color = C>,
168    {
169        self.parent
170            .post_render(draw_target, character_style, text, bounds)?;
171        self.object
172            .post_render(draw_target, character_style, text, bounds)
173    }
174
175    fn on_start_render<S: CharacterStyle + TextRenderer>(
176        &mut self,
177        cursor: &mut Cursor,
178        props: &TextBoxProperties<'_, S>,
179    ) {
180        self.parent.on_start_render(cursor, props);
181        self.object.on_start_render(cursor, props);
182    }
183
184    fn on_rendering_finished(&mut self) {
185        self.parent.on_rendering_finished();
186        self.object.on_rendering_finished();
187    }
188}