chargrid_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
19                    .col_modify
20                    .foreground(relative_cell.style.foreground),
21                background: context
22                    .col_modify
23                    .background(relative_cell.style.background),
24                ..relative_cell.style
25            },
26            ..relative_cell
27        };
28        frame.set_cell_absolute(absolute_coord, absolute_depth, absolute_cell);
29    }
30}
31
32fn blend_cell_background_relative_to_draw<F: ?Sized + Frame, C: ColModify, B: Blend>(
33    frame: &mut F,
34    relative_coord: Coord,
35    relative_depth: i8,
36    rgb24: Rgb24,
37    alpha: u8,
38    blend: B,
39    context: ViewContext<C>,
40) {
41    if relative_coord.is_valid(context.size) {
42        let absolute_coord = relative_coord + context.offset;
43        let absolute_depth = relative_depth + context.depth;
44        if let Some(modified_rgb24) = context.col_modify.background(Some(rgb24)) {
45            frame.blend_cell_background_absolute(
46                absolute_coord,
47                absolute_depth,
48                modified_rgb24,
49                alpha,
50                blend,
51            );
52        }
53    }
54}
55
56fn set_cell_relative_to_measure_size<F: ?Sized + Frame, C: ColModify>(
57    frame: &mut F,
58    relative_coord: Coord,
59    context: ViewContext<C>,
60) {
61    if relative_coord.is_valid(context.size) {
62        let absolute_coord = relative_coord + context.offset;
63        const DEFAULT_CELL: ViewCell = ViewCell::new();
64        frame.set_cell_absolute(absolute_coord, 0, DEFAULT_CELL);
65    }
66}
67
68fn blend_cell_background_relative_to_measure_size<F: ?Sized + Frame, C: ColModify>(
69    frame: &mut F,
70    relative_coord: Coord,
71    context: ViewContext<C>,
72) {
73    if relative_coord.is_valid(context.size) {
74        let absolute_coord = relative_coord + context.offset;
75        frame.blend_cell_background_absolute(
76            absolute_coord,
77            0,
78            Rgb24::new(0, 0, 0),
79            0,
80            blend_mode::Replace,
81        );
82    }
83}
84
85pub trait Frame {
86    fn set_cell_relative<C: ColModify>(
87        &mut self,
88        relative_coord: Coord,
89        relative_depth: i8,
90        relative_cell: ViewCell,
91        context: ViewContext<C>,
92    ) {
93        set_cell_relative_to_draw(self, relative_coord, relative_depth, relative_cell, context);
94    }
95    fn set_cell_absolute(
96        &mut self,
97        absolute_coord: Coord,
98        absolute_depth: i8,
99        absolute_cell: ViewCell,
100    );
101    fn blend_cell_background_relative<C: ColModify, B: Blend>(
102        &mut self,
103        relative_coord: Coord,
104        relative_depth: i8,
105        rgb24: Rgb24,
106        alpha: u8,
107        blend: B,
108        context: ViewContext<C>,
109    ) {
110        blend_cell_background_relative_to_draw(
111            self,
112            relative_coord,
113            relative_depth,
114            rgb24,
115            alpha,
116            blend,
117            context,
118        );
119    }
120    fn blend_cell_background_absolute<B: Blend>(
121        &mut self,
122        absolute_coord: Coord,
123        absolute_depth: i8,
124        rgb24: Rgb24,
125        alpha: u8,
126        blend: B,
127    );
128}
129
130struct MeasureBounds {
131    max_absolute_coord: Coord,
132}
133
134impl MeasureBounds {
135    fn new() -> Self {
136        Self {
137            max_absolute_coord: Coord::new(0, 0),
138        }
139    }
140    fn size(&self, offset: Coord) -> Size {
141        (self.max_absolute_coord - offset)
142            .to_size()
143            .unwrap_or_else(|coord_2d::NegativeDimension| Size::new(0, 0))
144            + Size::new(1, 1)
145    }
146    fn set_max(&mut self, coord: Coord) {
147        self.max_absolute_coord.x = self.max_absolute_coord.x.max(coord.x);
148        self.max_absolute_coord.y = self.max_absolute_coord.y.max(coord.y);
149    }
150}
151
152impl Frame for MeasureBounds {
153    fn set_cell_relative<C: ColModify>(
154        &mut self,
155        relative_coord: Coord,
156        _relative_depth: i8,
157        _relative_cell: ViewCell,
158        context: ViewContext<C>,
159    ) {
160        set_cell_relative_to_measure_size(self, relative_coord, context);
161    }
162    fn set_cell_absolute(
163        &mut self,
164        absolute_coord: Coord,
165        _absolute_depth: i8,
166        _absolute_cell: ViewCell,
167    ) {
168        self.set_max(absolute_coord);
169    }
170    fn blend_cell_background_relative<C: ColModify, B: Blend>(
171        &mut self,
172        relative_coord: Coord,
173        _relative_depth: i8,
174        _rgb24: Rgb24,
175        _alpha: u8,
176        _blend: B,
177        context: ViewContext<C>,
178    ) {
179        blend_cell_background_relative_to_measure_size(self, relative_coord, context);
180    }
181    fn blend_cell_background_absolute<B: Blend>(
182        &mut self,
183        absolute_coord: Coord,
184        _absolute_depth: i8,
185        _rgb24: Rgb24,
186        _alpha: u8,
187        _blend: B,
188    ) {
189        self.set_max(absolute_coord);
190    }
191}
192
193pub struct MeasureBoundsAndDraw<'a, D> {
194    draw: &'a mut D,
195    measure_bounds: MeasureBounds,
196}
197
198impl<'a, D> MeasureBoundsAndDraw<'a, D>
199where
200    D: Frame,
201{
202    pub fn new(draw: &'a mut D) -> Self {
203        Self {
204            draw,
205            measure_bounds: MeasureBounds::new(),
206        }
207    }
208    fn size(&self, offset: Coord) -> Size {
209        self.measure_bounds.size(offset)
210    }
211}
212
213pub fn measure_size<V, T, C>(view: &mut V, data: T, context: ViewContext<C>) -> Size
214where
215    V: View<T> + ?Sized,
216    C: ColModify,
217{
218    let mut measure_bounds = MeasureBounds::new();
219    view.view(data, context, &mut measure_bounds);
220    measure_bounds.size(context.offset)
221}
222
223pub fn measure_size_and_draw<V, T, C, F>(
224    view: &mut V,
225    data: T,
226    context: ViewContext<C>,
227    frame: &mut F,
228) -> Size
229where
230    V: View<T> + ?Sized,
231    C: ColModify,
232    F: Frame,
233{
234    let mut measure_bounds_and_draw = MeasureBoundsAndDraw::new(frame);
235    view.view(data, context, &mut measure_bounds_and_draw);
236    measure_bounds_and_draw.size(context.offset)
237}
238
239impl<'a, D> Frame for MeasureBoundsAndDraw<'a, D>
240where
241    D: Frame,
242{
243    fn set_cell_relative<C: ColModify>(
244        &mut self,
245        relative_coord: Coord,
246        relative_depth: i8,
247        relative_cell: ViewCell,
248        context: ViewContext<C>,
249    ) {
250        self.draw
251            .set_cell_relative(relative_coord, relative_depth, relative_cell, context);
252        self.measure_bounds.set_cell_relative(
253            relative_coord,
254            relative_depth,
255            relative_cell,
256            context,
257        );
258    }
259    fn set_cell_absolute(
260        &mut self,
261        absolute_coord: Coord,
262        absolute_depth: i8,
263        absolute_cell: ViewCell,
264    ) {
265        self.draw
266            .set_cell_absolute(absolute_coord, absolute_depth, absolute_cell);
267        self.measure_bounds
268            .set_cell_absolute(absolute_coord, absolute_depth, absolute_cell);
269    }
270    fn blend_cell_background_relative<C: ColModify, B: Blend>(
271        &mut self,
272        relative_coord: Coord,
273        relative_depth: i8,
274        rgb24: Rgb24,
275        alpha: u8,
276        blend: B,
277        context: ViewContext<C>,
278    ) {
279        self.draw.blend_cell_background_relative(
280            relative_coord,
281            relative_depth,
282            rgb24,
283            alpha,
284            blend,
285            context,
286        );
287        self.measure_bounds.blend_cell_background_relative(
288            relative_coord,
289            relative_depth,
290            rgb24,
291            alpha,
292            blend,
293            context,
294        );
295    }
296    fn blend_cell_background_absolute<B: Blend>(
297        &mut self,
298        absolute_coord: Coord,
299        absolute_depth: i8,
300        rgb24: Rgb24,
301        alpha: u8,
302        blend: B,
303    ) {
304        self.draw.blend_cell_background_absolute(
305            absolute_coord,
306            absolute_depth,
307            rgb24,
308            alpha,
309            blend,
310        );
311        self.measure_bounds.blend_cell_background_absolute(
312            absolute_coord,
313            absolute_depth,
314            rgb24,
315            alpha,
316            blend,
317        );
318    }
319}
320
321pub trait View<T> {
322    fn view<F: Frame, C: ColModify>(&mut self, data: T, context: ViewContext<C>, frame: &mut F);
323
324    fn size<C: ColModify>(&mut self, data: T, context: ViewContext<C>) -> Size {
325        measure_size(self, data, context)
326    }
327
328    fn view_size<F: Frame, C: ColModify>(
329        &mut self,
330        data: T,
331        context: ViewContext<C>,
332        frame: &mut F,
333    ) -> Size {
334        measure_size_and_draw(self, data, context, frame)
335    }
336}
337
338impl<'a, T, V: View<T>> View<T> for &'a mut V {
339    fn view<F: Frame, C: ColModify>(&mut self, data: T, context: ViewContext<C>, frame: &mut F) {
340        (*self).view(data, context, frame)
341    }
342    fn size<C: ColModify>(&mut self, data: T, context: ViewContext<C>) -> Size {
343        (*self).size(data, context)
344    }
345    fn view_size<F: Frame, C: ColModify>(
346        &mut self,
347        data: T,
348        context: ViewContext<C>,
349        frame: &mut F,
350    ) -> Size {
351        (*self).view_size(data, context, frame)
352    }
353}