1use std::borrow::Cow;
2
3use serde_json::json;
4
5use crate::{
6 color::ColorU,
7 fonts::{FontId, GlyphId},
8 geometry::{rect::RectF, vector::Vector2F},
9 json::ToJson,
10};
11
12pub struct Scene {
13 scale_factor: f32,
14 layers: Vec<Layer>,
15 active_layer_stack: Vec<usize>,
16}
17
18#[derive(Default)]
19pub struct Layer {
20 clip_bounds: Option<RectF>,
21 quads: Vec<Quad>,
22 shadows: Vec<Shadow>,
23 glyphs: Vec<Glyph>,
24 icons: Vec<Icon>,
25 paths: Vec<Path>,
26}
27
28#[derive(Default, Debug)]
29pub struct Quad {
30 pub bounds: RectF,
31 pub background: Option<ColorU>,
32 pub border: Border,
33 pub corner_radius: f32,
34}
35
36#[derive(Debug)]
37pub struct Shadow {
38 pub bounds: RectF,
39 pub corner_radius: f32,
40 pub sigma: f32,
41 pub color: ColorU,
42}
43
44#[derive(Debug)]
45pub struct Glyph {
46 pub font_id: FontId,
47 pub font_size: f32,
48 pub id: GlyphId,
49 pub origin: Vector2F,
50 pub color: ColorU,
51}
52
53pub struct Icon {
54 pub bounds: RectF,
55 pub svg: usvg::Tree,
56 pub path: Cow<'static, str>,
57 pub color: ColorU,
58}
59
60#[derive(Clone, Copy, Default, Debug)]
61pub struct Border {
62 pub width: f32,
63 pub color: Option<ColorU>,
64 pub top: bool,
65 pub right: bool,
66 pub bottom: bool,
67 pub left: bool,
68}
69
70#[derive(Debug)]
71pub struct Path {
72 pub bounds: RectF,
73 pub color: ColorU,
74 pub vertices: Vec<PathVertex>,
75}
76
77#[derive(Debug)]
78pub struct PathVertex {
79 pub xy_position: Vector2F,
80 pub st_position: Vector2F,
81}
82
83impl Scene {
84 pub fn new(scale_factor: f32) -> Self {
85 Scene {
86 scale_factor,
87 layers: vec![Layer::new(None)],
88 active_layer_stack: vec![0],
89 }
90 }
91
92 pub fn scale_factor(&self) -> f32 {
93 self.scale_factor
94 }
95
96 pub fn layers(&self) -> &[Layer] {
97 self.layers.as_slice()
98 }
99
100 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
101 let ix = self.layers.len();
102 self.layers.push(Layer::new(clip_bounds));
103 self.active_layer_stack.push(ix);
104 }
105
106 pub fn pop_layer(&mut self) {
107 assert!(self.active_layer_stack.len() > 1);
108 self.active_layer_stack.pop();
109 }
110
111 pub fn push_quad(&mut self, quad: Quad) {
112 self.active_layer().push_quad(quad)
113 }
114
115 pub fn push_shadow(&mut self, shadow: Shadow) {
116 self.active_layer().push_shadow(shadow)
117 }
118
119 pub fn push_glyph(&mut self, glyph: Glyph) {
120 self.active_layer().push_glyph(glyph)
121 }
122
123 pub fn push_icon(&mut self, icon: Icon) {
124 self.active_layer().push_icon(icon)
125 }
126
127 pub fn push_path(&mut self, path: Path) {
128 self.active_layer().push_path(path);
129 }
130
131 fn active_layer(&mut self) -> &mut Layer {
132 &mut self.layers[*self.active_layer_stack.last().unwrap()]
133 }
134}
135
136impl Layer {
137 pub fn new(clip_bounds: Option<RectF>) -> Self {
138 Self {
139 clip_bounds,
140 quads: Vec::new(),
141 shadows: Vec::new(),
142 glyphs: Vec::new(),
143 icons: Vec::new(),
144 paths: Vec::new(),
145 }
146 }
147
148 pub fn clip_bounds(&self) -> Option<RectF> {
149 self.clip_bounds
150 }
151
152 fn push_quad(&mut self, quad: Quad) {
153 self.quads.push(quad);
154 }
155
156 pub fn quads(&self) -> &[Quad] {
157 self.quads.as_slice()
158 }
159
160 fn push_shadow(&mut self, shadow: Shadow) {
161 self.shadows.push(shadow);
162 }
163
164 pub fn shadows(&self) -> &[Shadow] {
165 self.shadows.as_slice()
166 }
167
168 fn push_glyph(&mut self, glyph: Glyph) {
169 self.glyphs.push(glyph);
170 }
171
172 pub fn glyphs(&self) -> &[Glyph] {
173 self.glyphs.as_slice()
174 }
175
176 pub fn push_icon(&mut self, icon: Icon) {
177 self.icons.push(icon);
178 }
179
180 pub fn icons(&self) -> &[Icon] {
181 self.icons.as_slice()
182 }
183
184 fn push_path(&mut self, path: Path) {
185 if !path.bounds.is_empty() {
186 self.paths.push(path);
187 }
188 }
189
190 pub fn paths(&self) -> &[Path] {
191 self.paths.as_slice()
192 }
193}
194
195impl Border {
196 pub fn new(width: f32, color: impl Into<ColorU>) -> Self {
197 Self {
198 width,
199 color: Some(color.into()),
200 top: false,
201 left: false,
202 bottom: false,
203 right: false,
204 }
205 }
206
207 pub fn all(width: f32, color: impl Into<ColorU>) -> Self {
208 Self {
209 width,
210 color: Some(color.into()),
211 top: true,
212 left: true,
213 bottom: true,
214 right: true,
215 }
216 }
217
218 pub fn top(width: f32, color: impl Into<ColorU>) -> Self {
219 let mut border = Self::new(width, color);
220 border.top = true;
221 border
222 }
223
224 pub fn left(width: f32, color: impl Into<ColorU>) -> Self {
225 let mut border = Self::new(width, color);
226 border.left = true;
227 border
228 }
229
230 pub fn bottom(width: f32, color: impl Into<ColorU>) -> Self {
231 let mut border = Self::new(width, color);
232 border.bottom = true;
233 border
234 }
235
236 pub fn right(width: f32, color: impl Into<ColorU>) -> Self {
237 let mut border = Self::new(width, color);
238 border.right = true;
239 border
240 }
241
242 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
243 self.top = top;
244 self.left = left;
245 self.bottom = bottom;
246 self.right = right;
247 self
248 }
249
250 pub fn top_width(&self) -> f32 {
251 if self.top {
252 self.width
253 } else {
254 0.0
255 }
256 }
257
258 pub fn left_width(&self) -> f32 {
259 if self.left {
260 self.width
261 } else {
262 0.0
263 }
264 }
265}
266
267impl ToJson for Border {
268 fn to_json(&self) -> serde_json::Value {
269 let mut value = json!({});
270 if self.top {
271 value["top"] = json!(self.width);
272 }
273 if self.right {
274 value["right"] = json!(self.width);
275 }
276 if self.bottom {
277 value["bottom"] = json!(self.width);
278 }
279 if self.left {
280 value["left"] = json!(self.width);
281 }
282 value
283 }
284}