scene.rs

  1use serde::Deserialize;
  2use serde_json::json;
  3use std::borrow::Cow;
  4
  5use crate::{
  6    color::Color,
  7    fonts::{FontId, GlyphId},
  8    geometry::{rect::RectF, vector::Vector2F},
  9    json::ToJson,
 10};
 11
 12pub struct Scene {
 13    scale_factor: f32,
 14    stacking_contexts: Vec<StackingContext>,
 15    active_stacking_context_stack: Vec<usize>,
 16}
 17
 18struct StackingContext {
 19    layers: Vec<Layer>,
 20    active_layer_stack: Vec<usize>,
 21}
 22
 23#[derive(Default)]
 24pub struct Layer {
 25    clip_bounds: Option<RectF>,
 26    quads: Vec<Quad>,
 27    underlines: Vec<Quad>,
 28    shadows: Vec<Shadow>,
 29    glyphs: Vec<Glyph>,
 30    icons: Vec<Icon>,
 31    paths: Vec<Path>,
 32}
 33
 34#[derive(Default, Debug)]
 35pub struct Quad {
 36    pub bounds: RectF,
 37    pub background: Option<Color>,
 38    pub border: Border,
 39    pub corner_radius: f32,
 40}
 41
 42#[derive(Debug)]
 43pub struct Shadow {
 44    pub bounds: RectF,
 45    pub corner_radius: f32,
 46    pub sigma: f32,
 47    pub color: Color,
 48}
 49
 50#[derive(Debug)]
 51pub struct Glyph {
 52    pub font_id: FontId,
 53    pub font_size: f32,
 54    pub id: GlyphId,
 55    pub origin: Vector2F,
 56    pub color: Color,
 57}
 58
 59pub struct Icon {
 60    pub bounds: RectF,
 61    pub svg: usvg::Tree,
 62    pub path: Cow<'static, str>,
 63    pub color: Color,
 64}
 65
 66#[derive(Clone, Copy, Default, Debug)]
 67pub struct Border {
 68    pub width: f32,
 69    pub color: Color,
 70    pub top: bool,
 71    pub right: bool,
 72    pub bottom: bool,
 73    pub left: bool,
 74}
 75
 76impl<'de> Deserialize<'de> for Border {
 77    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 78    where
 79        D: serde::Deserializer<'de>,
 80    {
 81        #[derive(Deserialize)]
 82        struct BorderData {
 83            pub width: f32,
 84            pub color: Color,
 85            #[serde(default)]
 86            pub top: bool,
 87            #[serde(default)]
 88            pub right: bool,
 89            #[serde(default)]
 90            pub bottom: bool,
 91            #[serde(default)]
 92            pub left: bool,
 93        }
 94
 95        let data = BorderData::deserialize(deserializer)?;
 96        let mut border = Border {
 97            width: data.width,
 98            color: data.color,
 99            top: data.top,
100            bottom: data.bottom,
101            left: data.left,
102            right: data.right,
103        };
104        if !border.top && !border.bottom && !border.left && !border.right {
105            border.top = true;
106            border.bottom = true;
107            border.left = true;
108            border.right = true;
109        }
110        Ok(border)
111    }
112}
113
114#[derive(Debug)]
115pub struct Path {
116    pub bounds: RectF,
117    pub color: Color,
118    pub vertices: Vec<PathVertex>,
119}
120
121#[derive(Debug)]
122pub struct PathVertex {
123    pub xy_position: Vector2F,
124    pub st_position: Vector2F,
125}
126
127impl Scene {
128    pub fn new(scale_factor: f32) -> Self {
129        let stacking_context = StackingContext::new(None);
130        Scene {
131            scale_factor,
132            stacking_contexts: vec![stacking_context],
133            active_stacking_context_stack: vec![0],
134        }
135    }
136
137    pub fn scale_factor(&self) -> f32 {
138        self.scale_factor
139    }
140
141    pub fn layers(&self) -> impl Iterator<Item = &Layer> {
142        self.stacking_contexts.iter().flat_map(|s| &s.layers)
143    }
144
145    pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
146        self.active_stacking_context_stack
147            .push(self.stacking_contexts.len());
148        self.stacking_contexts
149            .push(StackingContext::new(clip_bounds))
150    }
151
152    pub fn pop_stacking_context(&mut self) {
153        self.active_stacking_context_stack.pop();
154        assert!(!self.active_stacking_context_stack.is_empty());
155    }
156
157    pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
158        self.active_stacking_context().push_layer(clip_bounds);
159    }
160
161    pub fn pop_layer(&mut self) {
162        self.active_stacking_context().pop_layer();
163    }
164
165    pub fn push_quad(&mut self, quad: Quad) {
166        self.active_layer().push_quad(quad)
167    }
168
169    pub fn push_underline(&mut self, underline: Quad) {
170        self.active_layer().push_underline(underline)
171    }
172
173    pub fn push_shadow(&mut self, shadow: Shadow) {
174        self.active_layer().push_shadow(shadow)
175    }
176
177    pub fn push_glyph(&mut self, glyph: Glyph) {
178        self.active_layer().push_glyph(glyph)
179    }
180
181    pub fn push_icon(&mut self, icon: Icon) {
182        self.active_layer().push_icon(icon)
183    }
184
185    pub fn push_path(&mut self, path: Path) {
186        self.active_layer().push_path(path);
187    }
188
189    fn active_stacking_context(&mut self) -> &mut StackingContext {
190        let ix = *self.active_stacking_context_stack.last().unwrap();
191        &mut self.stacking_contexts[ix]
192    }
193
194    fn active_layer(&mut self) -> &mut Layer {
195        self.active_stacking_context().active_layer()
196    }
197}
198
199impl StackingContext {
200    fn new(clip_bounds: Option<RectF>) -> Self {
201        Self {
202            layers: vec![Layer::new(clip_bounds)],
203            active_layer_stack: vec![0],
204        }
205    }
206
207    fn active_layer(&mut self) -> &mut Layer {
208        &mut self.layers[*self.active_layer_stack.last().unwrap()]
209    }
210
211    fn push_layer(&mut self, clip_bounds: Option<RectF>) {
212        let parent_clip_bounds = self.active_layer().clip_bounds();
213        let clip_bounds = clip_bounds
214            .map(|clip_bounds| {
215                clip_bounds
216                    .intersection(parent_clip_bounds.unwrap_or(clip_bounds))
217                    .unwrap_or_else(|| {
218                        if !clip_bounds.is_empty() {
219                            log::warn!("specified clip bounds are disjoint from parent layer");
220                        }
221                        RectF::default()
222                    })
223            })
224            .or(parent_clip_bounds);
225
226        let ix = self.layers.len();
227        self.layers.push(Layer::new(clip_bounds));
228        self.active_layer_stack.push(ix);
229    }
230
231    fn pop_layer(&mut self) {
232        self.active_layer_stack.pop().unwrap();
233        assert!(!self.active_layer_stack.is_empty());
234    }
235}
236
237impl Layer {
238    pub fn new(clip_bounds: Option<RectF>) -> Self {
239        Self {
240            clip_bounds,
241            quads: Vec::new(),
242            underlines: Vec::new(),
243            shadows: Vec::new(),
244            glyphs: Vec::new(),
245            icons: Vec::new(),
246            paths: Vec::new(),
247        }
248    }
249
250    pub fn clip_bounds(&self) -> Option<RectF> {
251        self.clip_bounds
252    }
253
254    fn push_quad(&mut self, quad: Quad) {
255        self.quads.push(quad);
256    }
257
258    pub fn quads(&self) -> &[Quad] {
259        self.quads.as_slice()
260    }
261
262    fn push_underline(&mut self, underline: Quad) {
263        self.underlines.push(underline);
264    }
265
266    pub fn underlines(&self) -> &[Quad] {
267        self.underlines.as_slice()
268    }
269
270    fn push_shadow(&mut self, shadow: Shadow) {
271        self.shadows.push(shadow);
272    }
273
274    pub fn shadows(&self) -> &[Shadow] {
275        self.shadows.as_slice()
276    }
277
278    fn push_glyph(&mut self, glyph: Glyph) {
279        self.glyphs.push(glyph);
280    }
281
282    pub fn glyphs(&self) -> &[Glyph] {
283        self.glyphs.as_slice()
284    }
285
286    pub fn push_icon(&mut self, icon: Icon) {
287        self.icons.push(icon);
288    }
289
290    pub fn icons(&self) -> &[Icon] {
291        self.icons.as_slice()
292    }
293
294    fn push_path(&mut self, path: Path) {
295        if !path.bounds.is_empty() {
296            self.paths.push(path);
297        }
298    }
299
300    pub fn paths(&self) -> &[Path] {
301        self.paths.as_slice()
302    }
303}
304
305impl Border {
306    pub fn new(width: f32, color: Color) -> Self {
307        Self {
308            width,
309            color,
310            top: false,
311            left: false,
312            bottom: false,
313            right: false,
314        }
315    }
316
317    pub fn all(width: f32, color: Color) -> Self {
318        Self {
319            width,
320            color,
321            top: true,
322            left: true,
323            bottom: true,
324            right: true,
325        }
326    }
327
328    pub fn top(width: f32, color: Color) -> Self {
329        let mut border = Self::new(width, color);
330        border.top = true;
331        border
332    }
333
334    pub fn left(width: f32, color: Color) -> Self {
335        let mut border = Self::new(width, color);
336        border.left = true;
337        border
338    }
339
340    pub fn bottom(width: f32, color: Color) -> Self {
341        let mut border = Self::new(width, color);
342        border.bottom = true;
343        border
344    }
345
346    pub fn right(width: f32, color: Color) -> Self {
347        let mut border = Self::new(width, color);
348        border.right = true;
349        border
350    }
351
352    pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
353        self.top = top;
354        self.left = left;
355        self.bottom = bottom;
356        self.right = right;
357        self
358    }
359
360    pub fn top_width(&self) -> f32 {
361        if self.top {
362            self.width
363        } else {
364            0.0
365        }
366    }
367
368    pub fn left_width(&self) -> f32 {
369        if self.left {
370            self.width
371        } else {
372            0.0
373        }
374    }
375}
376
377impl ToJson for Border {
378    fn to_json(&self) -> serde_json::Value {
379        let mut value = json!({});
380        if self.top {
381            value["top"] = json!(self.width);
382        }
383        if self.right {
384            value["right"] = json!(self.width);
385        }
386        if self.bottom {
387            value["bottom"] = json!(self.width);
388        }
389        if self.left {
390            value["left"] = json!(self.width);
391        }
392        value
393    }
394}