scal_core/anim_obj.rs
1use std::ops::Range;
2
3use glam::Vec2;
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::anim_builders::{
8 CodeAddLinesBuilder, CodeHighlightBuilder, CodeModifyLineBuilder, CodeRemoveLinesBuilder,
9};
10use crate::anim_op::{AnimOP, CodeAnimationStyle};
11use crate::color::Color;
12use crate::ease::Ease;
13use crate::theme::Theme;
14use crate::transform::Transform;
15
16#[derive(Clone, Debug, Serialize, Deserialize)]
17/// Generic for all object type. Conversion is done using ``IntoAnimOp`` trait.
18pub struct AnimObj {
19 /// Each object has it's UUID so that you can apply animations over IPC to this object's clone in the
20 /// runtime.
21 pub id: Uuid,
22 #[allow(missing_docs)]
23 pub transform: Transform,
24 #[allow(missing_docs)]
25 pub kind: AnimObjKind,
26}
27
28impl AnimObj {
29 /// Returns an animation that instantly adds that object to the scene.
30 /// ```
31 /// let pointer = svg()
32 /// .path("./pointer-tool.svg")
33 /// .build();
34 /// Project {
35 /// scene_settings,
36 /// timeline: timeline![
37 /// cw.instantiate(),
38 /// ]
39 /// }
40 /// ```
41 #[must_use]
42 pub fn instantiate(&self) -> AnimOP {
43 AnimOP::Instantiate(Box::new(self.clone()), None)
44 }
45}
46
47#[derive(Clone, Debug, Serialize, Deserialize)]
48#[allow(missing_docs)]
49pub enum AnimObjKind {
50 Rectangle {
51 size: Vec2,
52 corner_radius: f32,
53 color: Color,
54 },
55 Circle {
56 radius: f32,
57 color: Color,
58 },
59 Polygon {
60 radius: f32,
61 sides: u32,
62 color: Color,
63 },
64 Text {
65 value: String,
66 font_family: String,
67 alignment: TextAlign,
68 color: Color,
69 font_size: f32,
70 },
71 Code {
72 source_code: String,
73 font_family: String,
74 font_size: f32,
75 syntax: Syntax,
76 theme: Option<Theme>,
77 padding: f32,
78 show_line_numbers: bool,
79 line_number_color: Color,
80 },
81 Image {
82 path: String,
83 size: Vec2,
84 color: Color,
85 stretch: StretchMode,
86 },
87 Svg {
88 path: String,
89 size: Vec2,
90 tint: Color,
91 fill: Option<Color>,
92 stroke: Option<Color>,
93 stroke_width: Option<f32>,
94 stretch: StretchMode,
95 },
96 CodeWindow {
97 source_code: String,
98 font_family: String,
99 font_size: f32,
100 syntax: Syntax,
101 theme: Option<Theme>,
102 title: String,
103 title_font_size: f32,
104 width: f32,
105 height: f32,
106 background_color: Color,
107 code_id: Uuid,
108 close_btn_id: Uuid,
109 minimize_btn_id: Uuid,
110 maximize_btn_id: Uuid,
111 title_id: Uuid,
112 bg_id: Uuid,
113 container_id: Uuid,
114 title_bar_bg_id: Uuid,
115 show_line_numbers: bool,
116 line_number_color: Color,
117 },
118 Group {
119 children: Vec<AnimObj>,
120 },
121}
122
123#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
124#[allow(missing_docs)]
125pub enum TextAlign {
126 Center,
127 Left,
128 Right,
129}
130
131#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Hash, Eq)]
132#[allow(missing_docs)]
133pub enum Syntax {
134 Rust,
135 Nix,
136 Python,
137 JS,
138 Zig,
139}
140
141#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
142#[allow(missing_docs)]
143pub enum StretchMode {
144 Fit,
145 Fill,
146}
147
148/// Wrapper around the ``AnimObj`` struct that allows for clean animation construction for specific
149/// ``AnimObj`` kind.
150pub struct CodeHandle(pub AnimObj);
151
152impl std::ops::Deref for CodeHandle {
153 type Target = AnimObj;
154 fn deref(&self) -> &AnimObj {
155 &self.0
156 }
157}
158
159impl CodeHandle {
160 /// Returns an animation that instantly adds that object to the scene.
161 /// ```
162 /// let pointer = svg()
163 /// .path("./pointer-tool.svg")
164 /// .build();
165 /// Project {
166 /// scene_settings,
167 /// timeline: timeline![
168 /// cw.instantiate(),
169 /// ]
170 /// }
171 /// ```
172 #[must_use]
173 pub fn instantiate(&self) -> AnimOP {
174 AnimOP::Instantiate(Box::new(self.0.clone()), None)
175 }
176
177 /// Returns a builder for an animation of adding code lines to the code block.
178 /// ```
179 /// code.add_lines()
180 /// .str(
181 /// r"
182 ///fn fib(n: u32) -> u32 {
183 /// match n {
184 /// 0 => 0,
185 /// 1 => 1,
186 /// _ => fib(n - 1) + fib(n - 2),
187 /// }
188 ///}
189 /// "
190 /// )
191 /// .over(5.s())
192 /// .style(CodeAnimationStyle::TypeWriter),
193 /// ```
194 #[must_use]
195 pub const fn add_lines(&self) -> CodeAddLinesBuilder {
196 CodeAddLinesBuilder {
197 uuid: self.0.id,
198 text: String::new(),
199 from_line: 0,
200 duration: 1.0,
201 ease: Ease::Linear,
202 style: CodeAnimationStyle::TypeWriter,
203 }
204 }
205
206 /// Returns a builder for an animation of modifying a line of code.
207 /// ```
208 /// code.modify_line()
209 /// .str("New Line Contents")
210 /// .line(25)
211 /// .over(5.s())
212 /// .style(CodeAnimationStyle::TypeWriter),
213 /// ```
214 #[must_use]
215 pub const fn modify_line(&self) -> CodeModifyLineBuilder {
216 CodeModifyLineBuilder {
217 uuid: self.0.id,
218 line: 0,
219 text: String::new(),
220 duration: 1.0,
221 ease: Ease::Linear,
222 style: CodeAnimationStyle::TypeWriter,
223 }
224 }
225
226 /// Returns a builder for an animation of highlighting code by line range or regex pattern.
227 /// ```
228 /// code.highlight()
229 /// .lines(3..6)
230 /// .color(Color::new(1.0, 1.0, 0.0, 0.3))
231 /// .over(1.s())
232 /// .ease(Ease::InOutCubic),
233 /// ```
234 #[must_use]
235 pub fn highlight(&self) -> CodeHighlightBuilder {
236 CodeHighlightBuilder {
237 uuid: self.0.id,
238 ranges: Vec::new(),
239 regex: None,
240 color: Color::new(1.0, 1.0, 0.0, 0.3),
241 duration: 1.0,
242 ease: Ease::Linear,
243 }
244 }
245
246 /// Returns a builder for an animation of removing lines form a code block.
247 /// ```
248 /// code.remove_lines()
249 /// .range(0..25)
250 /// .over(5.s())
251 /// .style(CodeAnimationStyle::TypeWriter),
252 /// ```
253 #[must_use]
254 pub const fn remove_lines(&self) -> CodeRemoveLinesBuilder {
255 CodeRemoveLinesBuilder {
256 uuid: self.0.id,
257 range: 0..0,
258 duration: 1.0,
259 ease: Ease::Linear,
260 style: CodeAnimationStyle::TypeWriter,
261 }
262 }
263}
264
265/// Wrapper around the ``AnimObj`` struct that allows for clean animation construction for specific
266/// ``AnimObj`` kind.
267pub struct CodeWindowHandle(pub AnimObj);
268
269impl std::ops::Deref for CodeWindowHandle {
270 type Target = AnimObj;
271 fn deref(&self) -> &AnimObj {
272 &self.0
273 }
274}
275
276impl CodeWindowHandle {
277 /// Returns an animation that instantly adds that object to the scene.
278 /// ```
279 /// let pointer = svg()
280 /// .path("./pointer-tool.svg")
281 /// .build();
282 /// Project {
283 /// scene_settings,
284 /// timeline: timeline![
285 /// cw.instantiate(),
286 /// ]
287 /// }
288 /// ```
289 #[must_use]
290 pub fn instantiate(&self) -> AnimOP {
291 AnimOP::Instantiate(Box::new(self.0.clone()), None)
292 }
293 /// Returns a builder for an animation of adding code lines to the code block.
294 /// ```
295 /// code.add_lines()
296 /// .str(
297 /// r"
298 ///fn fib(n: u32) -> u32 {
299 /// match n {
300 /// 0 => 0,
301 /// 1 => 1,
302 /// _ => fib(n - 1) + fib(n - 2),
303 /// }
304 ///}
305 /// "
306 /// )
307 /// .over(5.s())
308 /// .style(CodeAnimationStyle::TypeWriter),
309 /// ```
310 #[must_use]
311 pub const fn add_lines(&self) -> CodeAddLinesBuilder {
312 let code_id = if let AnimObjKind::CodeWindow { code_id, .. } = &self.0.kind {
313 *code_id
314 } else {
315 self.0.id
316 };
317 CodeAddLinesBuilder {
318 uuid: code_id,
319 text: String::new(),
320 from_line: 0,
321 duration: 1.0,
322 ease: Ease::Linear,
323 style: CodeAnimationStyle::TypeWriter,
324 }
325 }
326
327 /// Returns a builder for an animation of modifying a line of code.
328 /// ```
329 /// code.modify_line()
330 /// .str("New Line Contents")
331 /// .line(25)
332 /// .over(5.s())
333 /// .style(CodeAnimationStyle::TypeWriter),
334 /// ```
335 #[must_use]
336 pub const fn modify_line(&self, line: u32) -> CodeModifyLineBuilder {
337 let code_id = if let AnimObjKind::CodeWindow { code_id, .. } = &self.0.kind {
338 *code_id
339 } else {
340 self.0.id
341 };
342 CodeModifyLineBuilder {
343 uuid: code_id,
344 line,
345 text: String::new(),
346 duration: 1.0,
347 ease: Ease::Linear,
348 style: CodeAnimationStyle::TypeWriter,
349 }
350 }
351
352 /// Returns a builder for an animation of highlighting code by line range or regex pattern.
353 /// ```
354 /// cw.highlight()
355 /// .lines(3..6)
356 /// .color(Color::new(1.0, 1.0, 0.0, 0.3))
357 /// .over(1.s())
358 /// .ease(Ease::InOutCubic),
359 /// ```
360 #[must_use]
361 pub fn highlight(&self) -> CodeHighlightBuilder {
362 let code_id = if let AnimObjKind::CodeWindow { code_id, .. } = &self.0.kind {
363 *code_id
364 } else {
365 self.0.id
366 };
367 CodeHighlightBuilder {
368 uuid: code_id,
369 ranges: Vec::new(),
370 regex: None,
371 color: Color::new(1.0, 1.0, 0.0, 0.3),
372 duration: 1.0,
373 ease: Ease::Linear,
374 }
375 }
376
377 /// Returns a builder for an animation of removing lines form a code block.
378 /// ```
379 /// code.remove_lines()
380 /// .range(0..25)
381 /// .over(5.s())
382 /// .style(CodeAnimationStyle::TypeWriter),
383 /// ```
384 #[must_use]
385 pub const fn remove_lines(&self, range: Range<u32>) -> CodeRemoveLinesBuilder {
386 let code_id = if let AnimObjKind::CodeWindow { code_id, .. } = &self.0.kind {
387 *code_id
388 } else {
389 self.0.id
390 };
391 CodeRemoveLinesBuilder {
392 uuid: code_id,
393 range,
394 duration: 1.0,
395 ease: Ease::Linear,
396 style: CodeAnimationStyle::TypeWriter,
397 }
398 }
399
400 #[must_use]
401 /// Returns handle to one of the objects that are used inside of the code window. This allows
402 /// you to animate them or use the as a reference point for movement.
403 pub const fn close_button(&self) -> CircleHandle {
404 if let AnimObjKind::CodeWindow { close_btn_id, .. } = &self.0.kind {
405 CircleHandle(*close_btn_id)
406 } else {
407 CircleHandle(self.0.id)
408 }
409 }
410 #[must_use]
411 /// Returns handle to one of the objects that are used inside of the code window. This allows
412 /// you to animate them or use the as a reference point for movement.
413 pub const fn minimize_button(&self) -> CircleHandle {
414 if let AnimObjKind::CodeWindow {
415 minimize_btn_id, ..
416 } = &self.0.kind
417 {
418 CircleHandle(*minimize_btn_id)
419 } else {
420 CircleHandle(self.0.id)
421 }
422 }
423 #[must_use]
424 /// Returns handle to one of the objects that are used inside of the code window. This allows
425 /// you to animate them or use the as a reference point for movement.
426 pub const fn maximize_button(&self) -> CircleHandle {
427 if let AnimObjKind::CodeWindow {
428 maximize_btn_id, ..
429 } = &self.0.kind
430 {
431 CircleHandle(*maximize_btn_id)
432 } else {
433 CircleHandle(self.0.id)
434 }
435 }
436 #[must_use]
437 /// Returns handle to one of the objects that are used inside of the code window. This allows
438 /// you to animate them or use the as a reference point for movement.
439 pub const fn title_text(&self) -> TextHandle {
440 if let AnimObjKind::CodeWindow { title_id, .. } = &self.0.kind {
441 TextHandle(*title_id)
442 } else {
443 TextHandle(self.0.id)
444 }
445 }
446 #[must_use]
447 /// Returns handle to one of the objects that are used inside of the code window. This allows
448 /// you to animate them or use the as a reference point for movement.
449 pub const fn window_background(&self) -> RectangleHandle {
450 RectangleHandle(self.0.id)
451 }
452 #[must_use]
453 /// Returns handle to one of the objects that are used inside of the code window. This allows
454 /// you to animate them or use the as a reference point for movement.
455 pub const fn container(&self) -> RectangleHandle {
456 if let AnimObjKind::CodeWindow { container_id, .. } = &self.0.kind {
457 RectangleHandle(*container_id)
458 } else {
459 RectangleHandle(self.0.id)
460 }
461 }
462 #[must_use]
463 /// Returns handle to one of the objects that are used inside of the code window. This allows
464 /// you to animate them or use the as a reference point for movement.
465 pub const fn title_bar_background(&self) -> RectangleHandle {
466 if let AnimObjKind::CodeWindow {
467 title_bar_bg_id, ..
468 } = &self.0.kind
469 {
470 RectangleHandle(*title_bar_bg_id)
471 } else {
472 RectangleHandle(self.0.id)
473 }
474 }
475}
476
477macro_rules! impl_handle {
478 ($type:ty) => {
479 impl $type {
480 /// Returns a builder for an animation that moves this object to a target position.
481 /// ```
482 /// handle.position()
483 /// .to(Vec2::new(100.0, 200.0))
484 /// .over(5.s())
485 /// .ease(Ease::InOutCubic),
486 /// ```
487 #[must_use]
488 pub const fn position(&self) -> crate::transform::PositionBuilder {
489 crate::transform::PositionBuilder {
490 uuid: self.0,
491 target: None,
492 object: None,
493 duration: 1.0,
494 ease: Ease::Linear,
495 }
496 }
497 /// Returns a builder for an animation that scales this object.
498 /// ```
499 /// handle.scale()
500 /// .to(Vec2::new(2.0, 2.0))
501 /// .over(5.s())
502 /// .ease(Ease::InOutCubic),
503 /// ```
504 #[must_use]
505 pub const fn scale(&self) -> crate::transform::ScaleBuilder {
506 crate::transform::ScaleBuilder {
507 uuid: self.0,
508 target: None,
509 object: None,
510 duration: 1.0,
511 ease: Ease::Linear,
512 }
513 }
514 /// Returns a builder for an animation that rotates this object.
515 /// ```
516 /// handle.rotation()
517 /// .to(360.0)
518 /// .over(5.s())
519 /// .ease(Ease::InOutCubic),
520 /// ```
521 #[must_use]
522 pub const fn rotation(&self) -> crate::transform::RotateBuilder {
523 crate::transform::RotateBuilder {
524 uuid: self.0,
525 target: None,
526 duration: 1.0,
527 ease: Ease::Linear,
528 }
529 }
530 }
531 impl From<$type> for Uuid {
532 fn from(h: $type) -> Uuid {
533 h.0
534 }
535 }
536 };
537}
538
539/// Handle to a Circle sub-object of a code window, for use in animation builders.
540pub struct CircleHandle(pub Uuid);
541/// Handle to a Text sub-object of a code window, for use in animation builders.
542pub struct TextHandle(pub Uuid);
543/// Handle to a Rectangle sub-object of a code window, for use in animation builders.
544pub struct RectangleHandle(pub Uuid);
545
546impl_handle!(CircleHandle);
547impl_handle!(TextHandle);
548impl_handle!(RectangleHandle);