1use std::collections::{HashMap, HashSet, VecDeque};
2use std::fmt::Display;
3use std::hash::Hasher;
4use std::ops::{Add, Deref, Mul, Neg, Sub};
5use std::time::Instant;
6
7use crate::math::Space;
8use kurbo::BezPath;
9pub use pax_message::*;
10pub use pax_value::numeric::Numeric;
11pub use pax_value::{CoercionRules, ImplToFromPaxAny, PaxValue, ToPaxValue};
12use piet::{PaintBrush, UnitPoint};
13use properties::{PropertyValue, UntypedProperty};
14pub mod cursor;
15
16pub trait Store: 'static {}
22
23use std::cell::Cell;
24use std::hash::Hash;
25use std::rc::{Rc, Weak};
26
27pub mod constants;
28pub mod math;
29pub mod pax_value;
30pub mod properties;
31
32pub use pax_value::functions;
33pub use properties::Property;
34
35pub use pax_value::functions::register_function;
36pub use pax_value::functions::Functions;
37pub use pax_value::functions::HelperFunctions;
38
39use crate::constants::COMMON_PROPERTIES_TYPE;
40pub use paste;
41pub use pax_message::serde;
42use serde::{Deserialize, Serialize};
43
44pub struct TransitionQueueEntry<T> {
45 pub duration_frames: u64,
46 pub curve: EasingCurve,
47 pub ending_value: T,
48}
49
50pub trait RenderContext {
51 fn fill(&mut self, layer: usize, path: BezPath, brush: &PaintBrush);
52 fn stroke(&mut self, layer: usize, path: BezPath, brush: &PaintBrush, width: f64);
53 fn save(&mut self, layer: usize);
54 fn restore(&mut self, layer: usize);
55 fn clip(&mut self, layer: usize, path: BezPath);
56 fn load_image(&mut self, path: &str, image: &[u8], width: usize, height: usize);
57 fn draw_image(&mut self, layer: usize, image_path: &str, rect: kurbo::Rect);
58 fn get_image_size(&mut self, image_path: &str) -> Option<(usize, usize)>;
59 fn transform(&mut self, layer: usize, affine: kurbo::Affine);
60 fn layers(&self) -> usize;
61}
62
63#[cfg(debug_assertions)]
64impl<T> std::fmt::Debug for TransitionQueueEntry<T> {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("TransitionQueueEntry")
67 .field("duration_frames", &self.duration_frames)
68 .finish()
70 }
71}
72
73#[derive(Default, Debug, Clone, Copy)]
74pub enum OS {
75 Mac,
76 Linux,
77 Windows,
78 Android,
79 IPhone,
80 #[default]
81 Unknown,
82}
83
84impl OS {
85 pub fn is_mobile(&self) -> bool {
86 match self {
87 OS::Android | OS::IPhone => true,
88 _ => false,
89 }
90 }
91
92 pub fn is_desktop(&self) -> bool {
93 match self {
94 OS::Mac | OS::Linux | OS::Windows => true,
95 _ => false,
96 }
97 }
98}
99
100#[derive(Default, Debug, Clone, Copy)]
101pub enum Platform {
102 Web,
103 Native,
104 #[default]
105 Unknown,
106}
107
108#[derive(Default, Debug, Clone, Copy)]
109pub struct Viewport {
110 pub width: f64,
111 pub height: f64,
112}
113
114impl ToPaxValue for Viewport {
115 fn to_pax_value(self) -> PaxValue {
116 PaxValue::Object(
117 vec![
118 ("width".to_string(), self.width.to_pax_value()),
119 ("height".to_string(), self.height.to_pax_value()),
120 ]
121 .into_iter()
122 .collect(),
123 )
124 }
125}
126
127impl Interpolatable for Viewport {
128 fn interpolate(&self, other: &Self, t: f64) -> Self {
129 Viewport {
130 width: self.width + (other.width - self.width) * t,
131 height: self.height + (other.height - self.height) * t,
132 }
133 }
134}
135
136pub struct Window;
137
138impl Space for Window {}
139
140#[derive(Clone)]
143pub struct Event<T> {
144 pub args: T,
145 cancelled: Rc<Cell<bool>>,
146}
147
148impl<T: Clone + 'static> ImplToFromPaxAny for Event<T> {}
149
150impl<T> Event<T> {
151 pub fn new(args: T) -> Self {
152 Self {
153 args,
154 cancelled: Default::default(),
155 }
156 }
157
158 pub fn prevent_default(&self) {
159 self.cancelled.set(true);
160 }
161
162 pub fn cancelled(&self) -> bool {
163 self.cancelled.get()
164 }
165}
166
167impl<T> Deref for Event<T> {
168 type Target = T;
169
170 fn deref(&self) -> &Self::Target {
171 &self.args
172 }
173}
174
175#[derive(Clone)]
180pub struct Clap {
181 pub x: f64,
182 pub y: f64,
183}
184
185#[derive(Clone)]
190pub struct Scroll {
191 pub delta_x: f64,
192 pub delta_y: f64,
193}
194
195#[derive(Clone)]
199pub struct Touch {
200 pub x: f64,
201 pub y: f64,
202 pub identifier: i64,
203 pub delta_x: f64,
204 pub delta_y: f64,
205}
206
207impl From<&TouchMessage> for Touch {
208 fn from(value: &TouchMessage) -> Self {
209 Touch {
210 x: value.x,
211 y: value.y,
212 identifier: value.identifier,
213 delta_x: value.delta_x,
214 delta_y: value.delta_x,
215 }
216 }
217}
218
219#[derive(Clone)]
222pub struct TouchStart {
223 pub touches: Vec<Touch>,
224}
225
226#[derive(Clone)]
229pub struct TouchMove {
230 pub touches: Vec<Touch>,
231}
232
233#[derive(Clone)]
236pub struct TouchEnd {
237 pub touches: Vec<Touch>,
238}
239
240#[derive(Clone)]
244pub struct KeyboardEventArgs {
245 pub key: String,
246 pub modifiers: Vec<ModifierKey>,
247 pub is_repeat: bool,
248}
249
250#[derive(Clone)]
252pub struct KeyDown {
253 pub keyboard: KeyboardEventArgs,
254}
255
256#[derive(Clone)]
258pub struct SelectStart {}
259
260#[derive(Clone)]
262pub struct KeyUp {
263 pub keyboard: KeyboardEventArgs,
264}
265
266#[derive(Clone)]
268pub struct KeyPress {
269 pub keyboard: KeyboardEventArgs,
270}
271
272#[derive(Clone)]
274pub struct Focus {}
275
276#[derive(Clone)]
280pub struct MouseEventArgs {
281 pub x: f64,
282 pub y: f64,
283 pub button: MouseButton,
284 pub modifiers: Vec<ModifierKey>,
285}
286
287#[derive(Clone, PartialEq)]
288pub enum MouseButton {
289 Left,
290 Right,
291 Middle,
292 Unknown,
293}
294
295impl From<MouseButtonMessage> for MouseButton {
296 fn from(value: MouseButtonMessage) -> Self {
297 match value {
298 MouseButtonMessage::Left => MouseButton::Left,
299 MouseButtonMessage::Right => MouseButton::Right,
300 MouseButtonMessage::Middle => MouseButton::Middle,
301 MouseButtonMessage::Unknown => MouseButton::Unknown,
302 }
303 }
304}
305
306#[derive(Clone)]
307pub enum ModifierKey {
308 Shift,
309 Control,
310 Alt,
311 Command,
312}
313
314impl From<&ModifierKeyMessage> for ModifierKey {
315 fn from(value: &ModifierKeyMessage) -> Self {
316 match value {
317 ModifierKeyMessage::Shift => ModifierKey::Shift,
318 ModifierKeyMessage::Control => ModifierKey::Control,
319 ModifierKeyMessage::Alt => ModifierKey::Alt,
320 ModifierKeyMessage::Command => ModifierKey::Command,
321 }
322 }
323}
324
325#[derive(Clone)]
327pub struct Click {
328 pub mouse: MouseEventArgs,
329}
330
331#[derive(Clone)]
333pub struct Drop {
334 pub x: f64,
335 pub y: f64,
336 pub name: String,
337 pub mime_type: String,
338 pub data: Vec<u8>,
339}
340
341#[derive(Clone)]
343pub struct DoubleClick {
344 pub mouse: MouseEventArgs,
345}
346
347#[derive(Clone)]
349pub struct MouseMove {
350 pub mouse: MouseEventArgs,
351}
352
353#[derive(Clone)]
355pub struct Wheel {
356 pub x: f64,
357 pub y: f64,
358 pub delta_x: f64,
359 pub delta_y: f64,
360 pub modifiers: Vec<ModifierKey>,
361}
362
363#[derive(Clone)]
364pub struct CheckboxChange {
365 pub checked: bool,
366}
367
368#[derive(Clone)]
369pub struct TextInput {
370 pub text: String,
371}
372
373#[derive(Clone)]
374pub struct TextboxChange {
375 pub text: String,
376}
377
378#[derive(Clone)]
379pub struct TextboxInput {
380 pub text: String,
381}
382
383#[derive(Clone)]
384pub struct ButtonClick {}
385
386#[derive(Clone)]
388pub struct MouseDown {
389 pub mouse: MouseEventArgs,
390}
391
392#[derive(Clone)]
394pub struct MouseUp {
395 pub mouse: MouseEventArgs,
396}
397
398#[derive(Clone)]
400pub struct MouseOver {}
401
402#[derive(Clone)]
404pub struct MouseOut {}
405
406#[derive(Clone)]
408pub struct ContextMenu {
409 pub mouse: MouseEventArgs,
410}
411
412#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Hash)]
416#[serde(crate = "crate::serde")]
417pub enum Size {
418 Pixels(Numeric),
419 Percent(Numeric),
420 Combined(Numeric, Numeric),
422}
423
424impl Display for Size {
425 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
426 match self {
427 Size::Pixels(val) => write!(f, "{}px", val),
428 Size::Percent(val) => write!(f, "{}%", val),
429 Size::Combined(pix, per) => write!(f, "{}px + {}%", pix, per),
430 }
431 }
432}
433
434impl Neg for Size {
435 type Output = Size;
436 fn neg(self) -> Self::Output {
437 match self {
438 Size::Pixels(pix) => Size::Pixels(-pix),
439 Size::Percent(per) => Size::Percent(-per),
440 Size::Combined(pix, per) => Size::Combined(-pix, -per),
441 }
442 }
443}
444
445impl Add for Size {
446 type Output = Size;
447 fn add(self, rhs: Self) -> Self::Output {
448 let mut pixel_component: Numeric = Default::default();
449 let mut percent_component: Numeric = Default::default();
450
451 [self, rhs].iter().for_each(|size| match size {
452 Size::Pixels(s) => pixel_component = pixel_component + *s,
453 Size::Percent(s) => percent_component = percent_component + *s,
454 Size::Combined(s0, s1) => {
455 pixel_component = pixel_component + *s0;
456 percent_component = percent_component + *s1;
457 }
458 });
459
460 Size::Combined(pixel_component, percent_component)
461 }
462}
463
464impl Add<Percent> for Size {
465 type Output = Size;
466 fn add(self, rhs: Percent) -> Self::Output {
467 self + Size::Percent(rhs.0)
468 }
469}
470
471impl Sub<Percent> for Size {
472 type Output = Size;
473 fn sub(self, rhs: Percent) -> Self::Output {
474 self - Size::Percent(rhs.0)
475 }
476}
477
478impl Add<Size> for Percent {
479 type Output = Size;
480 fn add(self, rhs: Size) -> Self::Output {
481 Size::Percent(self.0) + rhs
482 }
483}
484
485impl Sub<Size> for Percent {
486 type Output = Size;
487 fn sub(self, rhs: Size) -> Self::Output {
488 Size::Percent(self.0) - rhs
489 }
490}
491
492impl Sub for Size {
493 type Output = Size;
494 fn sub(self, rhs: Self) -> Self::Output {
495 let mut pixel_component: Numeric = Default::default();
496 let mut percent_component: Numeric = Default::default();
497
498 let sizes = [(self, 1), (rhs, -1)];
499 for (size, multiplier) in sizes.iter() {
500 match size {
501 Size::Pixels(s) => {
502 pixel_component = pixel_component + *s * Numeric::from(*multiplier)
503 }
504 Size::Percent(s) => {
505 percent_component = percent_component + *s * Numeric::from(*multiplier)
506 }
507 Size::Combined(s0, s1) => {
508 pixel_component = pixel_component + *s0 * Numeric::from(*multiplier);
509 percent_component = percent_component + *s1 * Numeric::from(*multiplier);
510 }
511 }
512 }
513
514 Size::Combined(pixel_component, percent_component)
515 }
516}
517
518impl Size {
519 #[allow(non_snake_case)]
520 pub fn ZERO() -> Self {
521 Size::Pixels(Numeric::F64(0.0))
522 }
523
524 pub fn expect_percent(&self) -> f64 {
527 match &self {
528 Size::Percent(val) => val.to_float() / 100.0,
529 Size::Pixels(val) => {
530 log::warn!("Percentage value expected but stored value was pixel.");
531 val.to_float() / 100.0
532 }
533 Size::Combined(_, percent) => {
534 log::warn!("Percentage value expected but stored value was a combination.");
535 percent.to_float() / 100.0
536 }
537 }
538 }
539
540 pub fn expect_pixels(&self) -> Numeric {
543 match &self {
544 Size::Pixels(val) => val.clone(),
545 Size::Percent(val) => {
546 log::warn!("Pixel value expected but stored value was percentage.");
547 val.clone()
548 }
549 Size::Combined(pixels, _) => {
550 log::warn!("Pixel value expected but stored value was a combination.");
551 pixels.clone()
552 }
553 }
554 }
555}
556
557#[derive(Clone, Copy)]
558pub enum Axis {
559 X,
560 Y,
561}
562
563impl Size {
564 pub fn evaluate(&self, bounds: (f64, f64), axis: Axis) -> f64 {
567 let target_bound = match axis {
568 Axis::X => bounds.0,
569 Axis::Y => bounds.1,
570 };
571 match &self {
572 Size::Pixels(num) => num.to_float(),
573 Size::Percent(num) => target_bound * (num.to_float() / 100.0),
574 Size::Combined(pixel_component, percent_component) => {
575 (target_bound * (percent_component.to_float() / 100.0)) + pixel_component.to_float()
577 }
578 }
579 }
580}
581
582#[derive(Debug, Default, Serialize, Deserialize)]
583pub struct CommonProperty {
584 name: String,
585 property_type: String,
586 optional: bool,
587}
588
589#[derive(Debug, Default, Clone)]
594pub struct CommonProperties {
595 pub id: Property<Option<String>>,
596 pub x: Property<Option<Size>>,
597 pub y: Property<Option<Size>>,
598 pub width: Property<Option<Size>>,
599 pub height: Property<Option<Size>>,
600 pub anchor_x: Property<Option<Size>>,
601 pub anchor_y: Property<Option<Size>>,
602 pub scale_x: Property<Option<Size>>,
604 pub scale_y: Property<Option<Size>>,
605 pub skew_x: Property<Option<Rotation>>,
606 pub skew_y: Property<Option<Rotation>>,
607 pub rotate: Property<Option<Rotation>>,
608 pub transform: Property<Option<Transform2D>>,
609 pub unclippable: Property<Option<bool>>,
610 pub _raycastable: Property<Option<bool>>,
611 pub _suspended: Property<Option<bool>>,
612}
613
614impl CommonProperties {
615 pub fn get_default_properties_literal() -> Vec<(String, String)> {
616 Self::get_property_identifiers()
617 .iter()
618 .map(|id| {
619 if id.0 == "transform" {
620 (
621 id.0.to_string(),
622 "Transform2D::default_wrapped()".to_string(),
623 )
624 } else {
625 (id.0.to_string(), "Default::default()".to_string())
626 }
627 })
628 .collect()
629 }
630
631 pub fn get_property_identifiers() -> Vec<(String, String)> {
632 COMMON_PROPERTIES_TYPE
633 .iter()
634 .map(|(c, t)| (c.to_string(), t.to_string()))
635 .collect()
636 }
637
638 pub fn get_as_common_property() -> Vec<CommonProperty> {
639 Self::get_property_identifiers()
640 .iter()
641 .map(|id| CommonProperty {
642 name: id.0.to_string(),
643 property_type: id.1.to_string(),
644 optional: (id.0 == "transform" || id.0 == "width" || id.0 == "height"),
645 })
646 .collect()
647 }
648
649 pub fn retrieve_property_scope(&self) -> HashMap<String, Variable> {
650 let CommonProperties {
651 id,
652 x,
653 y,
654 width,
655 height,
656 anchor_x,
657 anchor_y,
658 scale_x,
659 scale_y,
660 skew_x,
661 skew_y,
662 rotate,
663 transform,
664 unclippable,
665 _raycastable,
666 _suspended,
667 } = self;
669
670 HashMap::from([
671 (
672 "id".to_string(),
673 Variable::new_from_typed_property(id.clone()),
674 ),
675 (
676 "x".to_string(),
677 Variable::new_from_typed_property(x.clone()),
678 ),
679 (
680 "y".to_string(),
681 Variable::new_from_typed_property(y.clone()),
682 ),
683 (
684 "scale_x".to_string(),
685 Variable::new_from_typed_property(scale_x.clone()),
686 ),
687 (
688 "scale_y".to_string(),
689 Variable::new_from_typed_property(scale_y.clone()),
690 ),
691 (
692 "skew_x".to_string(),
693 Variable::new_from_typed_property(skew_x.clone()),
694 ),
695 (
696 "skew_y".to_string(),
697 Variable::new_from_typed_property(skew_y.clone()),
698 ),
699 (
700 "rotate".to_string(),
701 Variable::new_from_typed_property(rotate.clone()),
702 ),
703 (
704 "anchor_x".to_string(),
705 Variable::new_from_typed_property(anchor_x.clone()),
706 ),
707 (
708 "anchor_y".to_string(),
709 Variable::new_from_typed_property(anchor_y.clone()),
710 ),
711 (
712 "transform".to_string(),
713 Variable::new_from_typed_property(transform.clone()),
714 ),
715 (
716 "width".to_string(),
717 Variable::new_from_typed_property(width.clone()),
718 ),
719 (
720 "height".to_string(),
721 Variable::new_from_typed_property(height.clone()),
722 ),
723 (
724 "unclippable".to_string(),
725 Variable::new_from_typed_property(unclippable.clone()),
726 ),
727 (
728 "_raycastable".to_string(),
729 Variable::new_from_typed_property(_raycastable.clone()),
730 ),
731 (
732 "_suspended".to_string(),
733 Variable::new_from_typed_property(_suspended.clone()),
734 ),
735 ])
736 }
737}
738
739impl<T: Interpolatable> Interpolatable for Option<T> {
740 fn interpolate(&self, other: &Self, t: f64) -> Self {
741 match &self {
742 Self::Some(s) => match other {
743 Self::Some(o) => Some(s.interpolate(o, t)),
744 _ => None,
745 },
746 Self::None => None,
747 }
748 }
749}
750
751pub struct TransitionManager<T> {
752 queue: VecDeque<TransitionQueueEntry<T>>,
753 transition_checkpoint_value: T,
755 origin_frames_elapsed: u64,
757}
758
759#[cfg(debug_assertions)]
760impl<T> std::fmt::Debug for TransitionManager<T> {
761 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
762 f.debug_struct("TransitionManager")
763 .field("queue", &self.queue)
764 .finish()
766 }
767}
768
769impl<T: Interpolatable> TransitionManager<T> {
770 pub fn new(value: T, current_time: u64) -> Self {
771 Self {
772 queue: VecDeque::new(),
773 transition_checkpoint_value: value,
774 origin_frames_elapsed: current_time,
775 }
776 }
777
778 pub fn push_transition(&mut self, transition: TransitionQueueEntry<T>) {
779 self.queue.push_back(transition);
780 }
781
782 pub fn reset_transitions(&mut self, current_time: u64) {
783 let eased_value = self.compute_eased_value(current_time);
785 self.transition_checkpoint_value =
786 eased_value.unwrap_or(self.transition_checkpoint_value.clone());
787 self.queue.clear();
788 self.origin_frames_elapsed = current_time;
789 }
790
791 pub fn compute_eased_value(&mut self, frames_elapsed: u64) -> Option<T> {
792 let global_fe = frames_elapsed;
793 let origin_fe = &mut self.origin_frames_elapsed;
794
795 while global_fe - *origin_fe > self.queue.front()?.duration_frames {
797 let curr = self.queue.pop_front()?;
798 *origin_fe += curr.duration_frames;
799 self.transition_checkpoint_value = curr.ending_value;
800 }
801 let current_transition = self.queue.front()?;
802 let local_fe = global_fe - *origin_fe;
803 let progress = local_fe as f64 / current_transition.duration_frames as f64;
804 let interpolated_val = current_transition.curve.interpolate(
805 &self.transition_checkpoint_value,
806 ¤t_transition.ending_value,
807 progress,
808 );
809 Some(interpolated_val)
810 }
811}
812
813pub enum EasingCurve {
814 Linear,
815 InQuad,
816 OutQuad,
817 InBack,
818 OutBack,
819 InOutBack,
820 Custom(Box<dyn Fn(f64) -> f64>),
821}
822
823struct EasingEvaluators {}
824impl EasingEvaluators {
825 fn linear(t: f64) -> f64 {
826 t
827 }
828 #[allow(dead_code)]
829 fn none(t: f64) -> f64 {
830 if t == 1.0 {
831 1.0
832 } else {
833 0.0
834 }
835 }
836 fn in_quad(t: f64) -> f64 {
837 t * t
838 }
839 fn out_quad(t: f64) -> f64 {
840 1.0 - (1.0 - t) * (1.0 - t)
841 }
842 fn in_back(t: f64) -> f64 {
843 const C1: f64 = 1.70158;
844 const C3: f64 = C1 + 1.00;
845 C3 * t * t * t - C1 * t * t
846 }
847 fn out_back(t: f64) -> f64 {
848 const C1: f64 = 1.70158;
849 const C3: f64 = C1 + 1.00;
850 1.0 + C3 * (t - 1.0).powi(3) + C1 * (t - 1.0).powi(2)
851 }
852
853 fn in_out_back(t: f64) -> f64 {
854 const C1: f64 = 1.70158;
855 const C2: f64 = C1 * 1.525;
856 if t < 0.5 {
857 ((2.0 * t).powi(2) * ((C2 + 1.0) * 2.0 * t - C2)) / 2.0
858 } else {
859 ((2.0 * t - 2.0).powi(2) * ((C2 + 1.0) * (t * 2.0 - 2.0) + C2) + 2.0) / 2.0
860 }
861 }
862}
863
864impl EasingCurve {
865 pub fn interpolate<T: Interpolatable>(&self, v0: &T, v1: &T, t: f64) -> T {
868 let multiplier = match self {
869 EasingCurve::Linear => EasingEvaluators::linear(t),
870 EasingCurve::InQuad => EasingEvaluators::in_quad(t),
871 EasingCurve::OutQuad => EasingEvaluators::out_quad(t),
872 EasingCurve::InBack => EasingEvaluators::in_back(t),
873 EasingCurve::OutBack => EasingEvaluators::out_back(t),
874 EasingCurve::InOutBack => EasingEvaluators::in_out_back(t),
875 EasingCurve::Custom(evaluator) => (*evaluator)(t),
876 };
877
878 v0.interpolate(v1, multiplier)
879 }
880}
881
882impl<I: Clone + 'static> ImplToFromPaxAny for std::ops::Range<I> {}
883impl<T: 'static> ImplToFromPaxAny for Rc<T> {}
884impl<T: Clone + 'static> ImplToFromPaxAny for Weak<T> {}
885impl<T: Clone + 'static> ImplToFromPaxAny for Option<T> {}
886
887impl<T1: Clone + 'static, T2: Clone + 'static> ImplToFromPaxAny for (T1, T2) {}
888
889pub trait Interpolatable
890where
891 Self: Sized + Clone,
892{
893 fn interpolate(&self, _other: &Self, _t: f64) -> Self {
896 self.clone()
897 }
898}
899
900impl<I: Interpolatable> Interpolatable for std::ops::Range<I> {
901 fn interpolate(&self, _other: &Self, _t: f64) -> Self {
902 self.start.interpolate(&_other.start, _t)..self.end.interpolate(&_other.end, _t)
903 }
904}
905impl Interpolatable for () {}
906
907impl<T: ?Sized + Clone> Interpolatable for HashSet<T> {}
908impl<T: ?Sized + Clone> Interpolatable for VecDeque<T> {}
909impl<T: ?Sized> Interpolatable for Rc<T> {}
910impl<T: Interpolatable> Interpolatable for Weak<T> {}
911impl<T1: Interpolatable, T2: Interpolatable> Interpolatable for (T1, T2) {}
912
913impl<I: Interpolatable> Interpolatable for Vec<I> {
914 fn interpolate(&self, other: &Self, t: f64) -> Self {
915 assert_eq!(
917 self.len(),
918 other.len(),
919 "cannot interpolate between vecs of different lengths"
920 );
921
922 self.iter()
923 .enumerate()
924 .map(|(i, elem)| elem.interpolate(other.get(i).unwrap(), t))
925 .collect()
926 }
927}
928
929impl Interpolatable for kurbo::BezPath {}
930
931impl Interpolatable for Instant {}
932
933impl Interpolatable for char {}
934
935impl Interpolatable for f64 {
936 fn interpolate(&self, other: &f64, t: f64) -> f64 {
937 self + (*other - self) * t
938 }
939}
940
941impl Interpolatable for bool {
942 fn interpolate(&self, _other: &bool, _t: f64) -> bool {
943 *self
944 }
945}
946
947impl Interpolatable for usize {
948 fn interpolate(&self, other: &usize, t: f64) -> usize {
949 (*self as f64 + (*other - self) as f64 * t) as usize
950 }
951}
952
953impl Interpolatable for isize {
954 fn interpolate(&self, other: &isize, t: f64) -> isize {
955 (*self as f64 + (*other - self) as f64 * t) as isize
956 }
957}
958
959impl Interpolatable for i64 {
960 fn interpolate(&self, other: &i64, t: f64) -> i64 {
961 (*self as f64 + (*other - self) as f64 * t) as i64
962 }
963}
964
965impl Interpolatable for i128 {
966 fn interpolate(&self, other: &i128, t: f64) -> i128 {
967 (*self as f64 + (*other - self) as f64 * t) as i128
968 }
969}
970
971impl Interpolatable for u128 {
972 fn interpolate(&self, other: &u128, t: f64) -> u128 {
973 (*self as f64 + (*other - self) as f64 * t) as u128
974 }
975}
976
977impl Interpolatable for u64 {
978 fn interpolate(&self, other: &u64, t: f64) -> u64 {
979 (*self as f64 + (*other - self) as f64 * t) as u64
980 }
981}
982
983impl Interpolatable for u8 {
984 fn interpolate(&self, other: &u8, t: f64) -> u8 {
985 (*self as f64 + (*other - *self) as f64 * t) as u8
986 }
987}
988
989impl Interpolatable for u16 {
990 fn interpolate(&self, other: &u16, t: f64) -> u16 {
991 (*self as f64 + (*other - *self) as f64 * t) as u16
992 }
993}
994
995impl Interpolatable for u32 {
996 fn interpolate(&self, other: &u32, t: f64) -> u32 {
997 (*self as f64 + (*other - *self) as f64 * t) as u32
998 }
999}
1000
1001impl Interpolatable for i8 {
1002 fn interpolate(&self, other: &i8, t: f64) -> i8 {
1003 (*self as f64 + (*other - *self) as f64 * t) as i8
1004 }
1005}
1006
1007impl Interpolatable for i16 {
1008 fn interpolate(&self, other: &i16, t: f64) -> i16 {
1009 (*self as f64 + (*other - *self) as f64 * t) as i16
1010 }
1011}
1012
1013impl Interpolatable for i32 {
1014 fn interpolate(&self, other: &i32, t: f64) -> i32 {
1015 (*self as f64 + (*other - *self) as f64 * t) as i32
1016 }
1017}
1018
1019impl Interpolatable for String {}
1020
1021pub struct Timeline {
1022 pub playhead_position: usize,
1023 pub frame_count: usize,
1024 pub is_playing: bool,
1025}
1026
1027#[derive(Debug, Clone, Copy, PartialEq)]
1028pub enum Layer {
1029 Native,
1030 Canvas,
1031 DontCare,
1032}
1033
1034#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
1040pub struct Percent(pub Numeric);
1041
1042impl Display for Percent {
1043 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1044 write!(f, "{}%", self.0)
1045 }
1046}
1047
1048impl Interpolatable for Percent {
1049 fn interpolate(&self, other: &Self, t: f64) -> Self {
1050 Self(self.0.interpolate(&other.0, t))
1051 }
1052}
1053
1054impl From<f64> for ColorChannel {
1055 fn from(value: f64) -> Self {
1056 Numeric::F64(value).into()
1057 }
1058}
1059
1060impl From<i32> for ColorChannel {
1061 fn from(value: i32) -> Self {
1062 Numeric::from(value).into()
1063 }
1064}
1065
1066impl Into<ColorChannel> for Percent {
1067 fn into(self) -> ColorChannel {
1068 ColorChannel::Percent(self.0)
1069 }
1070}
1071
1072impl Into<Size> for Percent {
1073 fn into(self) -> Size {
1074 Size::Percent(self.0)
1075 }
1076}
1077
1078impl Into<Rotation> for Percent {
1079 fn into(self) -> Rotation {
1080 Rotation::Percent(self.0)
1081 }
1082}
1083
1084#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1085pub enum ColorChannel {
1086 Rotation(Rotation),
1087 Integer(u8),
1089 Percent(Numeric),
1091}
1092
1093impl Display for ColorChannel {
1094 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1095 match self {
1096 ColorChannel::Rotation(rot) => write!(f, "{}", rot),
1097 ColorChannel::Integer(int) => write!(f, "{}", int),
1098 ColorChannel::Percent(per) => write!(f, "{}%", per),
1099 }
1100 }
1101}
1102
1103impl Default for ColorChannel {
1104 fn default() -> Self {
1105 Self::Percent(Numeric::F64(50.0))
1106 }
1107}
1108
1109impl From<Numeric> for Rotation {
1110 fn from(value: Numeric) -> Self {
1111 Rotation::Degrees(value)
1112 }
1113}
1114
1115impl From<Numeric> for ColorChannel {
1116 fn from(value: Numeric) -> Self {
1117 Self::Integer(value.to_int().clamp(0, 255) as u8)
1118 }
1119}
1120
1121impl ColorChannel {
1122 pub fn to_float_0_1(&self) -> f64 {
1124 match self {
1125 Self::Percent(per) => (per.to_float() / 100.0).clamp(0_f64, 1_f64),
1126 Self::Integer(zero_to_255) => {
1127 let f_zero = (*zero_to_255) as f64;
1128 (f_zero / 255.0_f64).clamp(0_f64, 1_f64)
1129 }
1130 Self::Rotation(rot) => rot.to_float_0_1(),
1131 }
1132 }
1133}
1134
1135#[allow(non_camel_case_types)]
1136#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq)]
1137pub enum Color {
1138 rgb(ColorChannel, ColorChannel, ColorChannel),
1140 rgba(ColorChannel, ColorChannel, ColorChannel, ColorChannel),
1142
1143 hsl(Rotation, ColorChannel, ColorChannel),
1145 hsla(Rotation, ColorChannel, ColorChannel, ColorChannel),
1147
1148 #[default]
1149 SLATE,
1150 GRAY,
1151 ZINC,
1152 NEUTRAL,
1153 STONE,
1154 RED,
1155 ORANGE,
1156 AMBER,
1157 YELLOW,
1158 LIME,
1159 GREEN,
1160 EMERALD,
1161 TEAL,
1162 CYAN,
1163 SKY,
1164 BLUE,
1165 INDIGO,
1166 VIOLET,
1167 PURPLE,
1168 FUCHSIA,
1169 PINK,
1170 ROSE,
1171 BLACK,
1172 WHITE,
1173 TRANSPARENT,
1174 NONE,
1175}
1176
1177impl Hash for Color {
1178 fn hash<H: Hasher>(&self, state: &mut H) {
1179 core::mem::discriminant(self).hash(state);
1180 }
1181}
1182
1183impl Display for Color {
1185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1186 match self {
1187 Self::rgb(r, g, b) => write!(f, "rgb({}, {}, {})", r, g, b),
1188 Self::rgba(r, g, b, a) => write!(f, "rgba({}, {}, {}, {})", r, g, b, a),
1189 Self::hsl(h, s, l) => write!(f, "hsl({}, {}, {})", h, s, l),
1190 Self::hsla(h, s, l, a) => write!(f, "hsla({}, {}, {}, {})", h, s, l, a),
1191 Self::SLATE => write!(f, "SLATE"),
1192 Self::GRAY => write!(f, "GRAY"),
1193 Self::ZINC => write!(f, "ZINC"),
1194 Self::NEUTRAL => write!(f, "NEUTRAL"),
1195 Self::STONE => write!(f, "STONE"),
1196 Self::RED => write!(f, "RED"),
1197 Self::ORANGE => write!(f, "ORANGE"),
1198 Self::AMBER => write!(f, "AMBER"),
1199 Self::YELLOW => write!(f, "YELLOW"),
1200 Self::LIME => write!(f, "LIME"),
1201 Self::GREEN => write!(f, "GREEN"),
1202 Self::EMERALD => write!(f, "EMERALD"),
1203 Self::TEAL => write!(f, "TEAL"),
1204 Self::CYAN => write!(f, "CYAN"),
1205 Self::SKY => write!(f, "SKY"),
1206 Self::BLUE => write!(f, "BLUE"),
1207 Self::INDIGO => write!(f, "INDIGO"),
1208 Self::VIOLET => write!(f, "VIOLET"),
1209 Self::PURPLE => write!(f, "PURPLE"),
1210 Self::FUCHSIA => write!(f, "FUCHSIA"),
1211 Self::PINK => write!(f, "PINK"),
1212 Self::ROSE => write!(f, "ROSE"),
1213 Self::BLACK => write!(f, "BLACK"),
1214 Self::WHITE => write!(f, "WHITE"),
1215 Self::TRANSPARENT => write!(f, "TRANSPARENT"),
1216 Self::NONE => write!(f, "NONE"),
1217 }
1218 }
1219}
1220
1221impl Color {
1222 pub fn rgb(r: ColorChannel, g: ColorChannel, b: ColorChannel) -> Self {
1226 Self::rgb(r, g, b)
1227 }
1228
1229 pub fn rgba(r: ColorChannel, g: ColorChannel, b: ColorChannel, a: ColorChannel) -> Self {
1230 Self::rgba(r, g, b, a)
1231 }
1232
1233 pub fn hsl(h: Rotation, s: ColorChannel, l: ColorChannel) -> Self {
1234 Self::hsl(h, s, l)
1235 }
1236
1237 pub fn hsla(h: Rotation, s: ColorChannel, l: ColorChannel, a: ColorChannel) -> Self {
1238 Self::hsla(h, s, l, a)
1239 }
1240
1241 pub fn to_piet_color(&self) -> piet::Color {
1242 let rgba = self.to_rgba_0_1();
1243 piet::Color::rgba(rgba[0], rgba[1], rgba[2], rgba[3])
1244 }
1245
1246 pub fn from_rgba_0_1(rgba_0_1: [f64; 4]) -> Self {
1247 Self::rgba(
1248 ColorChannel::Percent(Numeric::F64(rgba_0_1[0] * 100.0)),
1249 ColorChannel::Percent(Numeric::F64(rgba_0_1[1] * 100.0)),
1250 ColorChannel::Percent(Numeric::F64(rgba_0_1[2] * 100.0)),
1251 ColorChannel::Percent(Numeric::F64(rgba_0_1[3] * 100.0)),
1252 )
1253 }
1254
1255 pub fn from_hex(hex: &str) -> Self {
1256 let r = u8::from_str_radix(&hex[0..2], 16).unwrap() as f64 / 255.0;
1257 let g = u8::from_str_radix(&hex[2..4], 16).unwrap() as f64 / 255.0;
1258 let b = u8::from_str_radix(&hex[4..6], 16).unwrap() as f64 / 255.0;
1259 let a = if hex.len() == 8 {
1260 u8::from_str_radix(&hex[6..8], 16).unwrap() as f64 / 255.0
1261 } else {
1262 1.0
1263 };
1264 Self::rgba(
1265 ColorChannel::Percent(Numeric::F64(r * 100.0)),
1266 ColorChannel::Percent(Numeric::F64(g * 100.0)),
1267 ColorChannel::Percent(Numeric::F64(b * 100.0)),
1268 ColorChannel::Percent(Numeric::F64(a * 100.0)),
1269 )
1270 }
1271
1272 pub fn to_rgba_0_1(&self) -> [f64; 4] {
1274 match self {
1275 Self::hsla(h, s, l, a) => {
1276 let rgb = hsl_to_rgb(h.to_float_0_1(), s.to_float_0_1(), l.to_float_0_1());
1277 [rgb[0], rgb[1], rgb[2], a.to_float_0_1()]
1278 }
1279 Self::hsl(h, s, l) => {
1280 let rgb = hsl_to_rgb(h.to_float_0_1(), s.to_float_0_1(), l.to_float_0_1());
1281 [rgb[0], rgb[1], rgb[2], 1.0]
1282 }
1283 Self::rgba(r, g, b, a) => [
1284 r.to_float_0_1(),
1285 g.to_float_0_1(),
1286 b.to_float_0_1(),
1287 a.to_float_0_1(),
1288 ],
1289 Self::rgb(r, g, b) => [r.to_float_0_1(), g.to_float_0_1(), b.to_float_0_1(), 1.0],
1290
1291 Self::SLATE => Self::rgb(
1293 Numeric::from(0x64).into(),
1294 Numeric::from(0x74).into(),
1295 Numeric::from(0x8b).into(),
1296 )
1297 .to_rgba_0_1(),
1298 Self::GRAY => Self::rgb(
1299 Numeric::from(0x6b).into(),
1300 Numeric::from(0x72).into(),
1301 Numeric::from(0x80).into(),
1302 )
1303 .to_rgba_0_1(),
1304 Self::ZINC => Self::rgb(
1305 Numeric::from(0x71).into(),
1306 Numeric::from(0x71).into(),
1307 Numeric::from(0x7a).into(),
1308 )
1309 .to_rgba_0_1(),
1310 Self::NEUTRAL => Self::rgb(
1311 Numeric::from(0x73).into(),
1312 Numeric::from(0x73).into(),
1313 Numeric::from(0x73).into(),
1314 )
1315 .to_rgba_0_1(),
1316 Self::STONE => Self::rgb(
1317 Numeric::from(0x78).into(),
1318 Numeric::from(0x71).into(),
1319 Numeric::from(0x6c).into(),
1320 )
1321 .to_rgba_0_1(),
1322 Self::RED => Self::rgb(
1323 Numeric::from(0xeF).into(),
1324 Numeric::from(0x44).into(),
1325 Numeric::from(0x44).into(),
1326 )
1327 .to_rgba_0_1(),
1328 Self::ORANGE => Self::rgb(
1329 Numeric::from(0xf9).into(),
1330 Numeric::from(0x73).into(),
1331 Numeric::from(0x16).into(),
1332 )
1333 .to_rgba_0_1(),
1334 Self::AMBER => Self::rgb(
1335 Numeric::from(0xf5).into(),
1336 Numeric::from(0x9e).into(),
1337 Numeric::from(0x0b).into(),
1338 )
1339 .to_rgba_0_1(),
1340 Self::YELLOW => Self::rgb(
1341 Numeric::from(0xea).into(),
1342 Numeric::from(0xb3).into(),
1343 Numeric::from(0x08).into(),
1344 )
1345 .to_rgba_0_1(),
1346 Self::LIME => Self::rgb(
1347 Numeric::from(0x84).into(),
1348 Numeric::from(0xcc).into(),
1349 Numeric::from(0x16).into(),
1350 )
1351 .to_rgba_0_1(),
1352 Self::GREEN => Self::rgb(
1353 Numeric::from(0x22).into(),
1354 Numeric::from(0xc5).into(),
1355 Numeric::from(0x5e).into(),
1356 )
1357 .to_rgba_0_1(),
1358 Self::EMERALD => Self::rgb(
1359 Numeric::from(0x10).into(),
1360 Numeric::from(0xb9).into(),
1361 Numeric::from(0x81).into(),
1362 )
1363 .to_rgba_0_1(),
1364 Self::TEAL => Self::rgb(
1365 Numeric::from(0x14).into(),
1366 Numeric::from(0xb8).into(),
1367 Numeric::from(0xa6).into(),
1368 )
1369 .to_rgba_0_1(),
1370 Self::CYAN => Self::rgb(
1371 Numeric::from(0x06).into(),
1372 Numeric::from(0xb6).into(),
1373 Numeric::from(0xd4).into(),
1374 )
1375 .to_rgba_0_1(),
1376 Self::SKY => Self::rgb(
1377 Numeric::from(0x0e).into(),
1378 Numeric::from(0xa5).into(),
1379 Numeric::from(0xe9).into(),
1380 )
1381 .to_rgba_0_1(),
1382 Self::BLUE => Self::rgb(
1383 Numeric::from(0x3b).into(),
1384 Numeric::from(0x82).into(),
1385 Numeric::from(0xf6).into(),
1386 )
1387 .to_rgba_0_1(),
1388 Self::INDIGO => Self::rgb(
1389 Numeric::from(0x63).into(),
1390 Numeric::from(0x66).into(),
1391 Numeric::from(0xf1).into(),
1392 )
1393 .to_rgba_0_1(),
1394 Self::VIOLET => Self::rgb(
1395 Numeric::from(0x8b).into(),
1396 Numeric::from(0x5c).into(),
1397 Numeric::from(0xf6).into(),
1398 )
1399 .to_rgba_0_1(),
1400 Self::PURPLE => Self::rgb(
1401 Numeric::from(0xa8).into(),
1402 Numeric::from(0x55).into(),
1403 Numeric::from(0xf7).into(),
1404 )
1405 .to_rgba_0_1(),
1406 Self::FUCHSIA => Self::rgb(
1407 Numeric::from(0xd9).into(),
1408 Numeric::from(0x46).into(),
1409 Numeric::from(0xef).into(),
1410 )
1411 .to_rgba_0_1(),
1412 Self::PINK => Self::rgb(
1413 Numeric::from(0xec).into(),
1414 Numeric::from(0x48).into(),
1415 Numeric::from(0x99).into(),
1416 )
1417 .to_rgba_0_1(),
1418 Self::ROSE => Self::rgb(
1419 Numeric::from(0xf4).into(),
1420 Numeric::from(0x3f).into(),
1421 Numeric::from(0x5e).into(),
1422 )
1423 .to_rgba_0_1(),
1424 Self::BLACK => Self::rgb(
1425 Numeric::from(0x00).into(),
1426 Numeric::from(0x00).into(),
1427 Numeric::from(0x00).into(),
1428 )
1429 .to_rgba_0_1(),
1430 Self::WHITE => Self::rgb(
1431 Numeric::from(0xff).into(),
1432 Numeric::from(0xff).into(),
1433 Numeric::from(0xff).into(),
1434 )
1435 .to_rgba_0_1(),
1436 Self::TRANSPARENT | Self::NONE => Self::rgba(
1437 Numeric::from(0xff).into(),
1438 Numeric::from(0xff).into(),
1439 Numeric::from(0xFF).into(),
1440 Numeric::from(0x00).into(),
1441 )
1442 .to_rgba_0_1(),
1443 }
1444 }
1445
1446 pub fn to_hsla_0_1(&self) -> [f64; 4] {
1448 let [r, g, b, a] = self.to_rgba_0_1();
1449
1450 let max = r.max(g).max(b);
1451 let min = r.min(g).min(b);
1452 let chroma = max - min;
1453
1454 let h = if chroma == 0.0 {
1455 0.0
1456 } else if max == r {
1457 ((g - b) / chroma + 6.0) % 6.0 / 6.0
1458 } else if max == g {
1459 ((b - r) / chroma + 2.0) / 6.0
1460 } else {
1461 ((r - g) / chroma + 4.0) / 6.0
1462 };
1463
1464 let l = (max + min) / 2.0;
1465
1466 let s = if l == 0.0 || l == 1.0 {
1467 0.0
1468 } else {
1469 (max - l) / l.min(1.0 - l)
1470 };
1471
1472 [h, s, l, a]
1473 }
1474}
1475
1476const RGB_UNIT_MAX: f64 = 255.0;
1478fn hsl_to_rgb(h: f64, s: f64, l: f64) -> [f64; 3] {
1479 if s == 0.0 {
1480 let unit = RGB_UNIT_MAX * l;
1481 return [
1482 unit / RGB_UNIT_MAX,
1483 unit / RGB_UNIT_MAX,
1484 unit / RGB_UNIT_MAX,
1485 ];
1486 }
1487
1488 let temp1 = if l < 0.5 {
1489 l * (1.0 + s)
1490 } else {
1491 l + s - l * s
1492 };
1493
1494 let temp2 = 2.0 * l - temp1;
1495 let hue = h;
1496
1497 let temp_r = bound(hue + (1.0 / 3.0), 1.0);
1498 let temp_g = bound(hue, 1.0);
1499 let temp_b = bound(hue - (1.0 / 3.0), 1.0);
1500
1501 let r = calc_rgb_unit(temp_r, temp1, temp2);
1502 let g = calc_rgb_unit(temp_g, temp1, temp2);
1503 let b = calc_rgb_unit(temp_b, temp1, temp2);
1504 [r / RGB_UNIT_MAX, g / RGB_UNIT_MAX, b / RGB_UNIT_MAX]
1505}
1506
1507fn calc_rgb_unit(unit: f64, temp1: f64, temp2: f64) -> f64 {
1508 let mut result = temp2;
1509 if 6.0 * unit < 1.0 {
1510 result = temp2 + (temp1 - temp2) * 6.0 * unit
1511 } else if 2.0 * unit < 1.0 {
1512 result = temp1
1513 } else if 3.0 * unit < 2.0 {
1514 result = temp2 + (temp1 - temp2) * ((2.0 / 3.0) - unit) * 6.0
1515 }
1516 result * RGB_UNIT_MAX
1517}
1518
1519pub fn bound(r: f64, entire: f64) -> f64 {
1520 let mut n = r;
1521 loop {
1522 let less = n < 0.0;
1523 let bigger = n > entire;
1524 if !less && !bigger {
1525 break n;
1526 }
1527 if less {
1528 n += entire;
1529 } else {
1530 n -= entire;
1531 }
1532 }
1533}
1534
1535impl Into<ColorMessage> for &Color {
1536 fn into(self) -> ColorMessage {
1537 let rgba = self.to_rgba_0_1();
1538 ColorMessage::Rgba(rgba)
1539 }
1540}
1541impl PartialEq<ColorMessage> for Color {
1542 fn eq(&self, other: &ColorMessage) -> bool {
1543 let self_rgba = self.to_rgba_0_1();
1544
1545 match other {
1546 ColorMessage::Rgb(other_rgba) => {
1547 self_rgba[0] == other_rgba[0]
1548 && self_rgba[1] == other_rgba[1]
1549 && self_rgba[2] == other_rgba[2]
1550 && self_rgba[3] == 1.0
1551 }
1552 ColorMessage::Rgba(other_rgba) => {
1553 self_rgba[0] == other_rgba[0]
1554 && self_rgba[1] == other_rgba[1]
1555 && self_rgba[2] == other_rgba[2]
1556 && self_rgba[3] == other_rgba[3]
1557 }
1558 }
1559 }
1560}
1561impl Interpolatable for Color {
1562 fn interpolate(&self, other: &Self, t: f64) -> Self {
1563 let rgba_s = self.to_rgba_0_1();
1564 let rgba_o = other.to_rgba_0_1();
1565 let rgba_i = [
1566 rgba_s[0].interpolate(&rgba_o[0], t),
1567 rgba_s[1].interpolate(&rgba_o[1], t),
1568 rgba_s[2].interpolate(&rgba_o[2], t),
1569 rgba_s[3].interpolate(&rgba_o[3], t),
1570 ];
1571 Color::from_rgba_0_1(rgba_i)
1572 }
1573}
1574
1575#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Copy)]
1576pub enum Rotation {
1577 Radians(Numeric),
1578 Degrees(Numeric),
1579 Percent(Numeric),
1580}
1581
1582impl Display for Rotation {
1583 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1584 match self {
1585 Rotation::Radians(rad) => write!(f, "{}rad", rad),
1586 Rotation::Degrees(deg) => write!(f, "{}deg", deg),
1587 Rotation::Percent(per) => write!(f, "{}%", per),
1588 }
1589 }
1590}
1591
1592impl Default for Rotation {
1593 fn default() -> Self {
1594 Self::Degrees(Numeric::F64(0.0))
1595 }
1596}
1597
1598impl Interpolatable for Rotation {
1599 fn interpolate(&self, other: &Self, t: f64) -> Self {
1600 Self::Percent(Numeric::F64(
1601 other.to_float_0_1() - self.to_float_0_1() * t / 100.0,
1602 ))
1603 }
1604}
1605
1606impl Rotation {
1607 #[allow(non_snake_case)]
1608 pub fn ZERO() -> Self {
1609 Self::Degrees(Numeric::F64(0.0))
1610 }
1611
1612 pub fn to_float_0_1(&self) -> f64 {
1615 match self {
1616 Self::Radians(rad) => rad.to_float() / (std::f64::consts::PI * 2.0),
1617 Self::Degrees(deg) => deg.to_float() / 360.0_f64,
1618 Self::Percent(per) => per.to_float(),
1619 }
1620 }
1621
1622 pub fn get_as_radians(&self) -> f64 {
1623 if let Self::Radians(num) = self {
1624 num.to_float()
1625 } else if let Self::Degrees(num) = self {
1626 num.to_float() * std::f64::consts::PI * 2.0 / 360.0
1627 } else if let Self::Percent(num) = self {
1628 num.to_float() * std::f64::consts::PI * 2.0 / 100.0
1629 } else {
1630 unreachable!()
1631 }
1632 }
1633
1634 pub fn get_as_degrees(&self) -> f64 {
1635 if let Self::Radians(num) = self {
1636 num.to_float() * 180.0 / std::f64::consts::PI
1637 } else if let Self::Degrees(num) = self {
1638 num.to_float()
1639 } else if let Self::Percent(num) = self {
1640 num.to_float() * 360.0 / 100.0
1641 } else {
1642 unreachable!()
1643 }
1644 }
1645}
1646impl Neg for Rotation {
1647 type Output = Rotation;
1648 fn neg(self) -> Self::Output {
1649 match self {
1650 Rotation::Degrees(deg) => Rotation::Degrees(-deg),
1651 Rotation::Radians(rad) => Rotation::Radians(-rad),
1652 Rotation::Percent(per) => Rotation::Percent(-per),
1653 }
1654 }
1655}
1656
1657impl Add for Rotation {
1658 type Output = Rotation;
1659
1660 fn add(self, rhs: Self) -> Self::Output {
1661 let self_rad = self.get_as_radians();
1662 let other_rad = rhs.get_as_radians();
1663 Rotation::Radians(Numeric::F64(self_rad + other_rad))
1664 }
1665}
1666
1667#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1668#[serde(crate = "crate::serde")]
1669pub enum PathElement {
1670 #[default]
1671 Empty,
1672 Point(Size, Size),
1673 Line,
1674 Quadratic(Size, Size),
1675 Cubic(Box<(Size, Size, Size, Size)>),
1676 Close,
1677}
1678
1679impl Interpolatable for PathElement {}
1680impl HelperFunctions for PathElement {}
1681
1682#[derive(Debug, Clone, Serialize, Deserialize)]
1683#[serde(crate = "crate::serde")]
1684pub struct Stroke {
1685 pub color: Property<Color>,
1686 pub width: Property<Size>,
1687}
1688
1689impl Default for Stroke {
1690 fn default() -> Self {
1691 Self {
1692 color: Default::default(),
1693 width: Property::new(Size::Pixels(Numeric::F64(0.0))),
1694 }
1695 }
1696}
1697
1698impl PartialEq for Stroke {
1699 fn eq(&self, other: &Self) -> bool {
1700 self.color.get() == other.color.get() && self.width.get() == other.width.get()
1701 }
1702}
1703
1704impl Interpolatable for Stroke {
1705 fn interpolate(&self, _other: &Self, _t: f64) -> Self {
1706 self.clone()
1708 }
1709}
1710
1711pub enum NavigationTarget {
1712 Current,
1713 New,
1714}
1715
1716#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1717#[serde(crate = "crate::serde")]
1718pub enum Fill {
1719 Solid(Color),
1720 LinearGradient(LinearGradient),
1721 RadialGradient(RadialGradient),
1722}
1723
1724impl Hash for Fill {
1725 fn hash<H: Hasher>(&self, state: &mut H) {
1726 match self {
1727 Fill::Solid(color) => {
1728 state.write_u8(0);
1729 color.hash(state);
1730 }
1731 Fill::LinearGradient(linear) => {
1732 state.write_u8(1);
1733 linear.start.hash(state);
1734 linear.end.hash(state);
1735 linear.stops.hash(state);
1736 }
1737 Fill::RadialGradient(radial) => {
1738 state.write_u8(2);
1739 radial.start.hash(state);
1740 radial.end.hash(state);
1741 radial.radius.to_bits().hash(state);
1742 radial.stops.hash(state);
1743 }
1744 }
1745 }
1746}
1747
1748impl Hash for Stroke {
1749 fn hash<H: Hasher>(&self, state: &mut H) {
1750 self.width.get().hash(state);
1751 self.color.get().hash(state);
1752 }
1753}
1754
1755impl Interpolatable for Fill {
1756 fn interpolate(&self, _other: &Self, _t: f64) -> Self {
1757 self.clone()
1759 }
1760}
1761
1762#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Hash)]
1763#[serde(crate = "crate::serde")]
1764pub struct LinearGradient {
1765 pub start: (Size, Size),
1766 pub end: (Size, Size),
1767 pub stops: Vec<GradientStop>,
1768}
1769
1770#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1771#[serde(crate = "crate::serde")]
1772pub struct RadialGradient {
1773 pub end: (Size, Size),
1774 pub start: (Size, Size),
1775 pub radius: f64,
1776 pub stops: Vec<GradientStop>,
1777}
1778
1779#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Hash)]
1780#[serde(crate = "crate::serde")]
1781pub struct GradientStop {
1782 pub position: Size,
1783 pub color: Color,
1784}
1785
1786impl GradientStop {
1787 pub fn get(color: Color, position: Size) -> GradientStop {
1788 GradientStop { position, color }
1789 }
1790}
1791
1792impl Default for Fill {
1793 fn default() -> Self {
1794 Self::Solid(Color::default())
1795 }
1796}
1797
1798impl Fill {
1799 pub fn to_unit_point((x, y): (Size, Size), (width, height): (f64, f64)) -> UnitPoint {
1800 let normalized_x = match x {
1801 Size::Pixels(val) => val.to_float() / width,
1802 Size::Percent(val) => val.to_float() / 100.0,
1803 Size::Combined(pix, per) => (pix.to_float() / width) + (per.to_float() / 100.0),
1804 };
1805
1806 let normalized_y = match y {
1807 Size::Pixels(val) => val.to_float() / height,
1808 Size::Percent(val) => val.to_float() / 100.0,
1809 Size::Combined(pix, per) => (pix.to_float() / width) + (per.to_float() / 100.0),
1810 };
1811 UnitPoint::new(normalized_x, normalized_y)
1812 }
1813
1814 pub fn to_piet_gradient_stops(stops: Vec<GradientStop>) -> Vec<piet::GradientStop> {
1815 let mut ret = Vec::new();
1816 for gradient_stop in stops {
1817 match gradient_stop.position {
1818 Size::Pixels(_) => {
1819 panic!("Gradient stops must be specified in percentages");
1820 }
1821 Size::Percent(p) => {
1822 ret.push(piet::GradientStop {
1823 pos: (p.to_float() / 100.0) as f32,
1824 color: gradient_stop.color.to_piet_color(),
1825 });
1826 }
1827 Size::Combined(_, _) => {
1828 panic!("Gradient stops must be specified in percentages");
1829 }
1830 }
1831 }
1832 ret
1833 }
1834
1835 #[allow(non_snake_case)]
1836 pub fn linearGradient(
1837 start: (Size, Size),
1838 end: (Size, Size),
1839 stops: Vec<GradientStop>,
1840 ) -> Fill {
1841 Fill::LinearGradient(LinearGradient { start, end, stops })
1842 }
1843}
1844
1845impl Into<Rotation> for Size {
1846 fn into(self) -> Rotation {
1847 if let Size::Percent(pix) = self {
1848 Rotation::Percent(pix)
1849 } else {
1850 panic!("Tried to coerce a pixel value into a rotation value; try `%` or `rad` instead of `px`.")
1851 }
1852 }
1853}
1854
1855impl Size {
1856 pub fn get_pixels(&self, parent: f64) -> f64 {
1857 match &self {
1858 Self::Pixels(p) => p.to_float(),
1859 Self::Percent(p) => parent * (p.to_float() / 100.0),
1860 Self::Combined(pix, per) => (parent * (per.to_float() / 100.0)) + pix.to_float(),
1861 }
1862 }
1863}
1864
1865impl Interpolatable for Size {
1866 fn interpolate(&self, other: &Self, t: f64) -> Self {
1867 match &self {
1868 Self::Pixels(sp) => match other {
1869 Self::Pixels(op) => Self::Pixels(*sp + ((*op - *sp) * Numeric::F64(t))),
1870 Self::Percent(op) => Self::Percent(*op),
1871 Self::Combined(pix, per) => {
1872 let pix = *sp + ((*pix - *sp) * Numeric::F64(t));
1873 let per = *per;
1874 Self::Combined(pix, per)
1875 }
1876 },
1877 Self::Percent(sp) => match other {
1878 Self::Pixels(op) => Self::Pixels(*op),
1879 Self::Percent(op) => Self::Percent(*sp + ((*op - *sp) * Numeric::F64(t))),
1880 Self::Combined(pix, per) => {
1881 let pix = *pix;
1882 let per = *sp + ((*per - *sp) * Numeric::F64(t));
1883 Self::Combined(pix, per)
1884 }
1885 },
1886 Self::Combined(pix, per) => match other {
1887 Self::Pixels(op) => {
1888 let pix = *pix + ((*op - *pix) * Numeric::F64(t));
1889 Self::Combined(pix, *per)
1890 }
1891 Self::Percent(op) => {
1892 let per = *per + ((*op - *per) * Numeric::F64(t));
1893 Self::Combined(*pix, per)
1894 }
1895 Self::Combined(pix0, per0) => {
1896 let pix = *pix + ((*pix0 - *pix) * Numeric::F64(t));
1897 let per = *per + ((*per0 - *per) * Numeric::F64(t));
1898 Self::Combined(pix, per)
1899 }
1900 },
1901 }
1902 }
1903}
1904
1905impl Default for Size {
1906 fn default() -> Self {
1907 Self::Percent(Numeric::F64(100.0))
1908 }
1909}
1910
1911impl Mul for Size {
1912 type Output = Size;
1913
1914 fn mul(self, rhs: Self) -> Self::Output {
1915 match self {
1916 Size::Pixels(pix0) => {
1917 match rhs {
1918 Size::Pixels(pix1) => Size::Pixels(pix0 + pix1),
1923 Size::Percent(per1) => Size::Pixels(pix0 * per1),
1924 Size::Combined(pix1, per1) => Size::Pixels((pix0 * per1) + pix0 + pix1),
1925 }
1926 }
1927 Size::Percent(per0) => match rhs {
1928 Size::Pixels(pix1) => Size::Pixels(per0 * pix1),
1929 Size::Percent(per1) => Size::Percent(per0 * per1),
1930 Size::Combined(pix1, per1) => Size::Pixels((per0 * pix1) + (per0 * per1)),
1931 },
1932 Size::Combined(pix0, per0) => match rhs {
1933 Size::Pixels(pix1) => Size::Pixels((pix0 * per0) + pix1),
1934 Size::Percent(per1) => Size::Percent(pix0 * per0 * per1),
1935 Size::Combined(pix1, per1) => Size::Pixels((pix0 * per0) + (pix1 * per1)),
1936 },
1937 }
1938 }
1939}
1940
1941#[derive(Debug, Default, Clone, Deserialize, Serialize)]
1952pub struct Transform2D {
1953 pub previous: Option<Box<Transform2D>>,
1955 pub rotate: Option<Rotation>,
1957 pub translate: Option<[Size; 2]>,
1958 pub anchor: Option<[Size; 2]>,
1959 pub scale: Option<[Size; 2]>,
1960 pub skew: Option<[Rotation; 2]>,
1961}
1962
1963impl Interpolatable for Transform2D {}
1964
1965impl Mul for Transform2D {
1966 type Output = Transform2D;
1967
1968 fn mul(self, rhs: Self) -> Self::Output {
1969 let mut ret = rhs.clone();
1970 ret.previous = Some(Box::new(self));
1971 ret
1972 }
1973}
1974
1975impl Transform2D {
1976 pub fn scale(x: Size, y: Size) -> Self {
1978 let mut ret = Transform2D::default();
1979 ret.scale = Some([x, y]);
1980 ret
1981 }
1982 pub fn rotate(z: Rotation) -> Self {
1984 let mut ret = Transform2D::default();
1985 ret.rotate = Some(z);
1986 ret
1987 }
1988 pub fn translate(x: Size, y: Size) -> Self {
1990 let mut ret = Transform2D::default();
1991 ret.translate = Some([x, y]);
1992 ret
1993 }
1994 pub fn anchor(x: Size, y: Size) -> Self {
1996 let mut ret = Transform2D::default();
1997 ret.anchor = Some([x, y]);
1998 ret
1999 }
2000}
2001
2002#[derive(Clone)]
2003pub struct Variable {
2004 untyped_property: UntypedProperty,
2005 convert_to_pax_value: Rc<dyn Fn(UntypedProperty) -> PaxValue>,
2006}
2007
2008impl Variable {
2009 pub fn new<T: PropertyValue + ToPaxValue>(untyped_property: UntypedProperty) -> Self {
2010 let closure = |untyped_property: UntypedProperty| {
2011 let property: Property<T> = Property::new_from_untyped(untyped_property.clone());
2012 property.get().to_pax_value()
2013 };
2014
2015 Variable {
2016 untyped_property,
2017 convert_to_pax_value: Rc::new(closure),
2018 }
2019 }
2020
2021 pub fn new_from_typed_property<T: PropertyValue + ToPaxValue>(property: Property<T>) -> Self {
2022 let untyped_property = property.untyped();
2023 let closure = |untyped_property: UntypedProperty| {
2024 let property: Property<T> = Property::new_from_untyped(untyped_property.clone());
2025 property.get().to_pax_value()
2026 };
2027
2028 Variable {
2029 untyped_property,
2030 convert_to_pax_value: Rc::new(closure),
2031 }
2032 }
2033
2034 pub fn get_untyped_property(&self) -> &UntypedProperty {
2035 &self.untyped_property
2036 }
2037 pub fn get_as_pax_value(&self) -> PaxValue {
2038 (self.convert_to_pax_value)(self.untyped_property.clone())
2039 }
2040}