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