pub mod numeric;
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use std::ffi::CString;
use std::ops::{Deref, Mul};
#[macro_use]
extern crate lazy_static;
extern crate mut_static;
use mut_static::MutStatic;
use pax_message::{ModifierKeyMessage, MouseButtonMessage, TouchMessage};
pub use crate::numeric::Numeric;
pub struct TransitionQueueEntry<T> {
pub global_frame_started: Option<usize>,
pub duration_frames: u64,
pub curve: EasingCurve,
pub starting_value: T,
pub ending_value: T,
}
pub trait PropertyInstance<T: Default + Clone> {
fn get(&self) -> &T;
fn _get_vtable_id(&self) -> Option<usize>;
fn get_mut(&mut self) -> &mut T;
fn set(&mut self, value: T);
fn _get_transition_manager(&mut self) -> Option<&mut TransitionManager<T>>;
fn ease_to(&mut self, new_value: T, duration_frames: u64, curve: EasingCurve);
fn ease_to_later(&mut self, new_value: T, duration_frames: u64, curve: EasingCurve);
}
impl<T: Default + Clone + 'static> Default for Box<dyn PropertyInstance<T>> {
fn default() -> Box<dyn PropertyInstance<T>> {
Box::new(PropertyLiteral::new(Default::default()))
}
}
impl<T: Default + Clone + 'static> Clone for Box<dyn PropertyInstance<T>> {
fn clone(&self) -> Self {
Box::new(PropertyLiteral::new(self.deref().get().clone()))
}
}
pub type Property<T> = Box<dyn PropertyInstance<T>>;
#[derive(Clone)]
pub struct RuntimeContext {
pub frames_elapsed: usize,
pub bounds_parent: (f64, f64),
}
#[derive(Clone)]
pub struct ArgsJab {
pub x: f64,
pub y: f64,
}
#[derive(Clone)]
pub struct ArgsScroll {
pub delta_x: f64,
pub delta_y: f64,
}
#[derive(Clone)]
pub struct Touch {
pub x: f64,
pub y: f64,
pub identifier: i64,
pub delta_x: f64,
pub delta_y: f64,
}
impl From<&TouchMessage> for Touch {
fn from(value: &TouchMessage) -> Self {
Touch {
x: value.x,
y: value.y,
identifier: value.identifier,
delta_x: value.delta_x,
delta_y: value.delta_x,
}
}
}
#[derive(Clone)]
pub struct ArgsTouchStart {
pub touches: Vec<Touch>,
}
#[derive(Clone)]
pub struct ArgsTouchMove {
pub touches: Vec<Touch>,
}
#[derive(Clone)]
pub struct ArgsTouchEnd {
pub touches: Vec<Touch>,
}
#[derive(Clone)]
pub struct KeyboardEventArgs {
pub key: String,
pub modifiers: Vec<ModifierKey>,
pub is_repeat: bool,
}
#[derive(Clone)]
pub struct ArgsKeyDown {
pub keyboard: KeyboardEventArgs,
}
#[derive(Clone)]
pub struct ArgsKeyUp {
pub keyboard: KeyboardEventArgs,
}
#[derive(Clone)]
pub struct ArgsKeyPress {
pub keyboard: KeyboardEventArgs,
}
#[derive(Clone)]
pub struct MouseEventArgs {
pub x: f64,
pub y: f64,
pub button: MouseButton,
pub modifiers: Vec<ModifierKey>,
}
#[derive(Clone)]
pub enum MouseButton {
Left,
Right,
Middle,
Unknown,
}
impl From<MouseButtonMessage> for MouseButton {
fn from(value: MouseButtonMessage) -> Self {
match value {
MouseButtonMessage::Left => {MouseButton::Left}
MouseButtonMessage::Right => {MouseButton::Right}
MouseButtonMessage::Middle => {MouseButton::Middle}
MouseButtonMessage::Unknown => {MouseButton::Unknown}
}
}
}
#[derive(Clone)]
pub enum ModifierKey {
Shift,
Control,
Alt,
Command,
}
impl From<&ModifierKeyMessage> for ModifierKey {
fn from(value: &ModifierKeyMessage) -> Self {
match value {
ModifierKeyMessage::Shift => {ModifierKey::Shift}
ModifierKeyMessage::Control => {ModifierKey::Control}
ModifierKeyMessage::Alt => {ModifierKey::Alt}
ModifierKeyMessage::Command => {ModifierKey::Command}
}
}
}
#[derive(Clone)]
pub struct ArgsClick {
pub mouse: MouseEventArgs,
}
#[derive(Clone)]
pub struct ArgsDoubleClick {
pub mouse: MouseEventArgs,
}
#[derive(Clone)]
pub struct ArgsMouseMove {
pub mouse: MouseEventArgs,
}
#[derive(Clone)]
pub struct ArgsWheel {
pub x: f64,
pub y: f64,
pub delta_x: f64,
pub delta_y: f64,
pub modifiers: Vec<ModifierKey>,
}
#[derive(Clone)]
pub struct ArgsMouseDown {
pub mouse: MouseEventArgs,
}
#[derive(Clone)]
pub struct ArgsMouseUp {
pub mouse: MouseEventArgs,
}
#[derive(Clone)]
pub struct ArgsMouseOver {
pub mouse: MouseEventArgs,
}
#[derive(Clone)]
pub struct ArgsMouseOut {
pub mouse: MouseEventArgs,
}
#[derive(Clone)]
pub struct ArgsContextMenu {
pub mouse: MouseEventArgs,
}
#[derive(Copy, Clone)]
pub enum Size {
Pixels(Numeric),
Percent(Numeric),
}
impl Interpolatable for Size {
fn interpolate(&self, other: &Self, t: f64) -> Self {
match &self {
Self::Pixels(sp) => {
match other {
Self::Pixels(op) => Self::Pixels(*sp + ((*op-*sp)*Numeric::from(t))),
Self::Percent(op) => Self::Percent(*op),
}
},
Self::Percent(sp) => {
match other {
Self::Percent(op) => Self::Percent(*sp + ((*op-*sp)*Numeric::from(t))),
Self::Pixels(op) => Self::Pixels(*op),
}
}
}
}
}
impl<T: Interpolatable> Interpolatable for Option<T> {
fn interpolate(&self, other: &Self, t: f64) -> Self {
match &self {
Self::Some(s) => {
match other {
Self::Some(o) => {
Some(s.interpolate(o, t))
},
_ => None,
}
},
Self::None => None,
}
}
}
impl Default for Size {
fn default() -> Self {
Self::Percent(100.0.into())
}
}
impl From<Size> for SizePixels {
fn from(value: Size) -> Self {
match value {
Size::Pixels(x) => {SizePixels(x)}
_ => {panic!("Non pixel Size cannot be coerced into SizePixels");}
}
}
}
#[derive(Copy, Clone)]
pub struct SizePixels(pub Numeric);
impl Default for SizePixels {
fn default() -> Self {
Self(Numeric::Float(150.0))
}
}
impl From<&SizePixels > for f64{
fn from(value: &SizePixels) -> Self {
value.0.get_as_float()
}
}
impl PartialEq<Numeric> for SizePixels {
fn eq(&self, other: &Numeric) -> bool {
self.0 == *other
}
}
impl PartialEq<SizePixels> for Numeric {
fn eq(&self, other: &SizePixels) -> bool {
other.0 == *self
}
}
pub enum PlatformSpecificLogger {
Web(fn(&str)),
MacOS(extern "C" fn(*const std::os::raw::c_char)),
}
pub struct Logger(PlatformSpecificLogger);
lazy_static! {
static ref LOGGER: MutStatic<Logger> = MutStatic::new();
}
pub fn register_logger(logger: PlatformSpecificLogger) {
LOGGER.borrow().set(Logger(logger)).unwrap();
}
pub fn log(msg: &str) {
let logging_variant = &(LOGGER.borrow().read().expect("Logger isn't registered").0);
match logging_variant {
PlatformSpecificLogger::Web(closure) => {
closure(msg)
},
PlatformSpecificLogger::MacOS(closure) => {
let msg = CString::new(msg).unwrap();
unsafe {(closure)(msg.as_ptr())};
}
}
}
impl Mul for Size {
type Output = Size;
fn mul(self, rhs: Self) -> Self::Output {
match self {
Size::Pixels(px0) => {
match rhs {
Size::Pixels(px1) => {
Size::Pixels(px0 + px1)
}
Size::Percent(pc1) => {
Size::Pixels(px0 * pc1)
}
}
}
Size::Percent(pc0) => {
match rhs {
Size::Pixels(px1) => {
Size::Pixels(pc0 * px1)
}
Size::Percent(pc1) => {
Size::Percent(pc0 * pc1)
}
}
}
}
}
}
pub struct TransformInstance {
rotate: Option<Box<dyn PropertyInstance<f64>>>
}
pub type Size2D = Rc<RefCell<[Box<dyn PropertyInstance<Size>>; 2]>>;
#[derive(Default, Clone)]
pub struct Transform2D { pub previous: Option<Box<Transform2D>>,
pub rotate: Option<f64>, pub translate: Option<[f64; 2]>,
pub anchor: Option<[Size; 2]>,
pub align: Option<[Size; 2]>,
pub scale: Option<[f64; 2]>,
}
impl Mul for Transform2D {
type Output = Transform2D;
fn mul(self, rhs: Self) -> Self::Output {
let mut ret = rhs.clone();
ret.previous = Some(Box::new(self));
ret
}
}
impl Transform2D {
pub fn scale(x: Numeric, y: Numeric) -> Self {
let mut ret = Transform2D::default();
ret.scale = Some([x.get_as_float(), y.get_as_float()]);
ret
}
pub fn rotate(z: Numeric) -> Self {
let mut ret = Transform2D::default();
ret.rotate = Some(z.get_as_float());
ret
}
pub fn translate(x: Numeric, y: Numeric) -> Self {
let mut ret = Transform2D::default();
ret.translate = Some([x.get_as_float(), y.get_as_float()]);
ret
}
pub fn align(x: Size, y: Size) -> Self {
let mut ret = Transform2D::default();
ret.align = Some([x, y]);
ret
}
pub fn anchor(x: Size, y: Size) -> Self {
let mut ret = Transform2D::default();
ret.anchor = Some([x, y]);
ret
}
pub fn default_wrapped() -> Rc<RefCell<dyn PropertyInstance<Self>>> {
Rc::new(RefCell::new(PropertyLiteral::new(Transform2D::default())))
}
}
pub struct TransitionManager<T> {
pub queue: VecDeque<TransitionQueueEntry<T>>,
pub value: Option<T>,
}
impl<T> TransitionManager<T> {
pub fn new() -> Self {
Self {
queue: VecDeque::new(),
value: None,
}
}
}
pub struct PropertyLiteral<T> {
value: T,
transition_manager: TransitionManager<T>,
}
impl<T> Into<Box<dyn PropertyInstance<T>>> for PropertyLiteral<T>
where T: Default + Clone + 'static {
fn into(self) -> Box<dyn PropertyInstance<T>> {
Box::new(self)
}
}
impl<T: Clone> PropertyLiteral<T> {
pub fn new(value: T) -> Self {
PropertyLiteral {
value,
transition_manager: TransitionManager::new(),
}
}
}
impl<T: Default + Clone> PropertyInstance<T> for PropertyLiteral<T> {
fn get(&self) -> &T {
&self.value
}
fn get_mut(&mut self) -> &mut T {
&mut self.value
}
fn _get_vtable_id(&self) -> Option<usize> {
None
}
fn set(&mut self, value: T) {
self.value = value;
}
fn ease_to(&mut self, new_value: T, duration_frames: u64, curve: EasingCurve) {
self.transition_manager.value = Some(self.get().clone());
&self.transition_manager.queue.clear();
&self.transition_manager.queue.push_back(TransitionQueueEntry {
global_frame_started: None,
duration_frames,
curve,
starting_value: self.value.clone(),
ending_value: new_value
});
}
fn ease_to_later(&mut self, new_value: T, duration_frames: u64, curve: EasingCurve) {
if let None = self.transition_manager.value {
self.transition_manager.value = Some(self.get().clone());
}
let starting_value = if self.transition_manager.queue.len() > 0 {
self.transition_manager.queue.get(self.transition_manager.queue.len() - 1).unwrap().ending_value.clone()
} else {
self.value.clone()
};
self.transition_manager.queue.push_back(TransitionQueueEntry {
global_frame_started: None,
duration_frames,
curve,
starting_value,
ending_value: new_value
});
}
#[allow(duplicate)]
fn _get_transition_manager(&mut self) -> Option<&mut TransitionManager<T>> {
if let None = self.transition_manager.value {
None
}else {
Some(&mut self.transition_manager)
}
}
}
pub enum EasingCurve {
Linear,
InQuad,
OutQuad,
InBack,
OutBack,
InOutBack,
Custom(Box<dyn Fn(f64) -> f64>),
}
struct EasingEvaluators {}
impl EasingEvaluators {
fn linear(t: f64) -> f64 {
t
}
fn none(t: f64) -> f64 {
if t == 1.0 { 1.0 } else { 0.0 }
}
fn in_quad(t: f64) -> f64 {
t * t
}
fn out_quad(t: f64) -> f64 {
1.0 - (1.0 - t) * (1.0 - t)
}
fn in_back(t: f64) -> f64 {
const C1: f64 = 1.70158;
const C3: f64 = C1 + 1.00;
C3 * t * t * t - C1 * t * t
}
fn out_back(t: f64) -> f64 {
const C1: f64 = 1.70158;
const C3: f64 = C1 + 1.00;
1.0 + C3 * (t - 1.0).powi(3) + C1 * (t - 1.0).powi(2)
}
fn in_out_back(t: f64) -> f64 {
const C1: f64 = 1.70158;
const C2 : f64 = C1 * 1.525;
if t < 0.5 {
((2.0 * t).powi(2) * ((C2 + 1.0) * 2.0 * t - C2)) / 2.0
} else {
((2.0 * t - 2.0).powi(2) * ((C2 + 1.0) * (t * 2.0 - 2.0) + C2) + 2.0) / 2.0
}
}
}
impl EasingCurve {
pub fn interpolate<T: Interpolatable>(&self, v0: &T, v1: &T, t: f64) -> T {
let multiplier = match self {
EasingCurve::Linear => {
EasingEvaluators::linear(t)
}
EasingCurve::InQuad => {
EasingEvaluators::in_quad(t)
}
EasingCurve::OutQuad => {
EasingEvaluators::out_quad(t)
}
EasingCurve::InBack => {
EasingEvaluators::in_back(t)
}
EasingCurve::OutBack => {
EasingEvaluators::out_back(t)
}
EasingCurve::InOutBack => {
EasingEvaluators::in_out_back(t)
}
EasingCurve::Custom(evaluator) => {
(*evaluator)(t)
}
};
v0.interpolate( v1, multiplier)
}
}
pub trait Interpolatable
where Self : Sized + Clone {
fn interpolate(&self, other: &Self, t: f64) -> Self {
self.clone()
}
}
impl<I: Interpolatable> Interpolatable for Vec<I> {
fn interpolate(&self, other: &Self, t: f64) -> Self {
assert_eq!(self.len(), other.len(), "cannot interpolate between vecs of different lengths");
self.iter().enumerate().map(|(i, elem)| {
elem.interpolate(other.get(i).unwrap(), t)
}).collect()
}
}
impl Interpolatable for f64 {
fn interpolate(&self, other: &f64, t: f64) -> f64 {
self + (*other - self) * t
}
}
impl Interpolatable for bool {
fn interpolate(&self, other: &bool, t: f64) -> bool {
*self
}
}
impl Interpolatable for usize {
fn interpolate(&self, other: &usize, t: f64) -> usize {
(*self as f64 + (*other - self) as f64 * t) as usize
}
}
impl Interpolatable for isize {
fn interpolate(&self, other: &isize, t: f64) -> isize {
(*self as f64 + (*other - self) as f64 * t) as isize
}
}
impl Interpolatable for String {}
pub struct Timeline {
pub playhead_position: usize,
pub frame_count: usize,
pub is_playing: bool,
}
#[derive(Clone, PartialEq)]
pub enum Layer {
Native,
Canvas,
DontCare
}
pub struct LayerInfo {
depth: usize,
layer: Layer,
}
impl LayerInfo {
pub fn new() -> Self {
LayerInfo {
depth: 0,
layer: Layer::Canvas,
}
}
pub fn get_depth(&mut self) -> usize {
self.depth
}
pub fn get_current_layer(&mut self) -> Layer {
self.layer.clone()
}
pub fn update_depth(&mut self, layer: Layer) {
match layer {
Layer::DontCare => {}
_ => {
if self.layer != layer {
if layer == Layer::Canvas {
self.depth += 1;
}
self.layer = layer.clone();
}
}
}
}
}