prototty_render/
view.rs

1use super::{blend_mode, Blend, Coord, Rgb24, Size};
2use crate::col_modify::ColModify;
3use crate::context::*;
4use crate::view_cell::*;
5
6fn set_cell_relative_to_draw<F: ?Sized + Frame, C: ColModify>(
7    frame: &mut F,
8    relative_coord: Coord,
9    relative_depth: i8,
10    relative_cell: ViewCell,
11    context: ViewContext<C>,
12) {
13    if relative_coord.is_valid(context.size) {
14        let absolute_coord = relative_coord + context.offset;
15        let absolute_depth = relative_depth + context.depth;
16        let absolute_cell = ViewCell {
17            style: Style {
18                foreground: context.col_modify.foreground(relative_cell.style.foreground),
19                background: context.col_modify.background(relative_cell.style.background),
20                ..relative_cell.style
21            },
22            ..relative_cell
23        };
24        frame.set_cell_absolute(absolute_coord, absolute_depth, absolute_cell);
25    }
26}
27
28fn blend_cell_background_relative_to_draw<F: ?Sized + Frame, C: ColModify, B: Blend>(
29    frame: &mut F,
30    relative_coord: Coord,
31    relative_depth: i8,
32    rgb24: Rgb24,
33    alpha: u8,
34    blend: B,
35    context: ViewContext<C>,
36) {
37    if relative_coord.is_valid(context.size) {
38        let absolute_coord = relative_coord + context.offset;
39        let absolute_depth = relative_depth + context.depth;
40        if let Some(modified_rgb24) = context.col_modify.background(Some(rgb24)) {
41            frame.blend_cell_background_absolute(absolute_coord, absolute_depth, modified_rgb24, alpha, blend);
42        }
43    }
44}
45
46fn set_cell_relative_to_measure_size<F: ?Sized + Frame, C: ColModify>(
47    frame: &mut F,
48    relative_coord: Coord,
49    context: ViewContext<C>,
50) {
51    if relative_coord.is_valid(context.size) {
52        let absolute_coord = relative_coord + context.offset;
53        const DEFAULT_CELL: ViewCell = ViewCell::new();
54        frame.set_cell_absolute(absolute_coord, 0, DEFAULT_CELL);
55    }
56}
57
58fn blend_cell_background_relative_to_measure_size<F: ?Sized + Frame, C: ColModify>(
59    frame: &mut F,
60    relative_coord: Coord,
61    context: ViewContext<C>,
62) {
63    if relative_coord.is_valid(context.size) {
64        let absolute_coord = relative_coord + context.offset;
65        frame.blend_cell_background_absolute(absolute_coord, 0, Rgb24::new(0, 0, 0), 0, blend_mode::Replace);
66    }
67}
68
69pub trait Frame {
70    fn set_cell_relative<C: ColModify>(
71        &mut self,
72        relative_coord: Coord,
73        relative_depth: i8,
74        relative_cell: ViewCell,
75        context: ViewContext<C>,
76    ) {
77        set_cell_relative_to_draw(self, relative_coord, relative_depth, relative_cell, context);
78    }
79    fn set_cell_absolute(&mut self, absolute_coord: Coord, absolute_depth: i8, absolute_cell: ViewCell);
80    fn blend_cell_background_relative<C: ColModify, B: Blend>(
81        &mut self,
82        relative_coord: Coord,
83        relative_depth: i8,
84        rgb24: Rgb24,
85        alpha: u8,
86        blend: B,
87        context: ViewContext<C>,
88    ) {
89        blend_cell_background_relative_to_draw(self, relative_coord, relative_depth, rgb24, alpha, blend, context);
90    }
91    fn blend_cell_background_absolute<B: Blend>(
92        &mut self,
93        absolute_coord: Coord,
94        absolute_depth: i8,
95        rgb24: Rgb24,
96        alpha: u8,
97        blend: B,
98    );
99}
100
101struct MeasureBounds {
102    max_absolute_coord: Coord,
103}
104
105impl MeasureBounds {
106    fn new() -> Self {
107        Self {
108            max_absolute_coord: Coord::new(0, 0),
109        }
110    }
111    fn size(&self, offset: Coord) -> Size {
112        (self.max_absolute_coord - offset)
113            .to_size()
114            .unwrap_or_else(|coord_2d::NegativeDimension| Size::new(0, 0))
115            + Size::new(1, 1)
116    }
117    fn set_max(&mut self, coord: Coord) {
118        self.max_absolute_coord.x = self.max_absolute_coord.x.max(coord.x);
119        self.max_absolute_coord.y = self.max_absolute_coord.y.max(coord.y);
120    }
121}
122
123impl Frame for MeasureBounds {
124    fn set_cell_relative<C: ColModify>(
125        &mut self,
126        relative_coord: Coord,
127        _relative_depth: i8,
128        _relative_cell: ViewCell,
129        context: ViewContext<C>,
130    ) {
131        set_cell_relative_to_measure_size(self, relative_coord, context);
132    }
133    fn set_cell_absolute(&mut self, absolute_coord: Coord, _absolute_depth: i8, _absolute_cell: ViewCell) {
134        self.set_max(absolute_coord);
135    }
136    fn blend_cell_background_relative<C: ColModify, B: Blend>(
137        &mut self,
138        relative_coord: Coord,
139        _relative_depth: i8,
140        _rgb24: Rgb24,
141        _alpha: u8,
142        _blend: B,
143        context: ViewContext<C>,
144    ) {
145        blend_cell_background_relative_to_measure_size(self, relative_coord, context);
146    }
147    fn blend_cell_background_absolute<B: Blend>(
148        &mut self,
149        absolute_coord: Coord,
150        _absolute_depth: i8,
151        _rgb24: Rgb24,
152        _alpha: u8,
153        _blend: B,
154    ) {
155        self.set_max(absolute_coord);
156    }
157}
158
159pub struct MeasureBoundsAndDraw<'a, D> {
160    draw: &'a mut D,
161    measure_bounds: MeasureBounds,
162}
163
164impl<'a, D> MeasureBoundsAndDraw<'a, D>
165where
166    D: Frame,
167{
168    pub fn new(draw: &'a mut D) -> Self {
169        Self {
170            draw,
171            measure_bounds: MeasureBounds::new(),
172        }
173    }
174    fn size(&self, offset: Coord) -> Size {
175        self.measure_bounds.size(offset)
176    }
177}
178
179pub fn measure_size<V, T, C>(view: &mut V, data: T, context: ViewContext<C>) -> Size
180where
181    V: View<T> + ?Sized,
182    C: ColModify,
183{
184    let mut measure_bounds = MeasureBounds::new();
185    view.view(data, context, &mut measure_bounds);
186    measure_bounds.size(context.offset)
187}
188
189pub fn measure_size_and_draw<V, T, C, F>(view: &mut V, data: T, context: ViewContext<C>, frame: &mut F) -> Size
190where
191    V: View<T> + ?Sized,
192    C: ColModify,
193    F: Frame,
194{
195    let mut measure_bounds_and_draw = MeasureBoundsAndDraw::new(frame);
196    view.view(data, context, &mut measure_bounds_and_draw);
197    measure_bounds_and_draw.size(context.offset)
198}
199
200impl<'a, D> Frame for MeasureBoundsAndDraw<'a, D>
201where
202    D: Frame,
203{
204    fn set_cell_relative<C: ColModify>(
205        &mut self,
206        relative_coord: Coord,
207        relative_depth: i8,
208        relative_cell: ViewCell,
209        context: ViewContext<C>,
210    ) {
211        self.draw
212            .set_cell_relative(relative_coord, relative_depth, relative_cell, context);
213        self.measure_bounds
214            .set_cell_relative(relative_coord, relative_depth, relative_cell, context);
215    }
216    fn set_cell_absolute(&mut self, absolute_coord: Coord, absolute_depth: i8, absolute_cell: ViewCell) {
217        self.draw
218            .set_cell_absolute(absolute_coord, absolute_depth, absolute_cell);
219        self.measure_bounds
220            .set_cell_absolute(absolute_coord, absolute_depth, absolute_cell);
221    }
222    fn blend_cell_background_relative<C: ColModify, B: Blend>(
223        &mut self,
224        relative_coord: Coord,
225        relative_depth: i8,
226        rgb24: Rgb24,
227        alpha: u8,
228        blend: B,
229        context: ViewContext<C>,
230    ) {
231        self.draw
232            .blend_cell_background_relative(relative_coord, relative_depth, rgb24, alpha, blend, context);
233        self.measure_bounds.blend_cell_background_relative(
234            relative_coord,
235            relative_depth,
236            rgb24,
237            alpha,
238            blend,
239            context,
240        );
241    }
242    fn blend_cell_background_absolute<B: Blend>(
243        &mut self,
244        absolute_coord: Coord,
245        absolute_depth: i8,
246        rgb24: Rgb24,
247        alpha: u8,
248        blend: B,
249    ) {
250        self.draw
251            .blend_cell_background_absolute(absolute_coord, absolute_depth, rgb24, alpha, blend);
252        self.measure_bounds
253            .blend_cell_background_absolute(absolute_coord, absolute_depth, rgb24, alpha, blend);
254    }
255}
256
257pub trait View<T> {
258    fn view<F: Frame, C: ColModify>(&mut self, data: T, context: ViewContext<C>, frame: &mut F);
259
260    fn size<C: ColModify>(&mut self, data: T, context: ViewContext<C>) -> Size {
261        measure_size(self, data, context)
262    }
263
264    fn view_size<F: Frame, C: ColModify>(&mut self, data: T, context: ViewContext<C>, frame: &mut F) -> Size {
265        measure_size_and_draw(self, data, context, frame)
266    }
267}
268
269impl<'a, T, V: View<T>> View<T> for &'a mut V {
270    fn view<F: Frame, C: ColModify>(&mut self, data: T, context: ViewContext<C>, frame: &mut F) {
271        (*self).view(data, context, frame)
272    }
273    fn size<C: ColModify>(&mut self, data: T, context: ViewContext<C>) -> Size {
274        (*self).size(data, context)
275    }
276    fn view_size<F: Frame, C: ColModify>(&mut self, data: T, context: ViewContext<C>, frame: &mut F) -> Size {
277        (*self).view_size(data, context, frame)
278    }
279}