pub mod numeric;
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::ffi::CString;
use std::rc::Rc;
use std::ops::{Add, Deref, Mul, Neg};
#[macro_use]
extern crate lazy_static;
extern crate mut_static;
pub use crate::numeric::Numeric;
use mut_static::MutStatic;
use pax_message::{ModifierKeyMessage, MouseButtonMessage, TouchMessage};
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),
Combined(Numeric, Numeric),
}
impl Neg for Size {
type Output = Size;
fn neg(self) -> Self::Output {
match self {
Size::Pixels(pix) => Size::Pixels(-pix),
Size::Percent(per) => Size::Percent(-per),
Size::Combined(pix, per) => Size::Combined(-pix, -per),
}
}
}
impl Add for Size {
type Output = Size;
fn add(self, rhs: Self) -> Self::Output {
let mut pixel_component: Numeric = Default::default();
let mut percent_component: Numeric = Default::default();
[self, rhs].iter().for_each(|size| match size {
Size::Pixels(s) => pixel_component = pixel_component + *s,
Size::Percent(s) => percent_component = percent_component + *s,
Size::Combined(s0, s1) => {
pixel_component = pixel_component + *s0;
percent_component = percent_component + *s1;
}
});
Size::Combined(pixel_component, percent_component)
}
}
impl Size {
#[allow(non_snake_case)]
pub fn ZERO() -> Self {
Size::Pixels(Numeric::from(0.0))
}
pub fn expect_percent(&self) -> f64 {
match &self {
Size::Percent(val) => val.get_as_float() / 100.0,
_ => {
panic!("Percentage value expected but stored value was not a percentage.")
}
}
}
}
pub enum Axis {
X,
Y,
}
impl Size {
pub fn evaluate(&self, bounds: (f64, f64), axis: Axis) -> f64 {
let target_bound = match axis {
Axis::X => bounds.0,
Axis::Y => bounds.1,
};
match &self {
Size::Pixels(num) => num.get_as_float(),
Size::Percent(num) => target_bound * (*num / 100.0),
Size::Combined(pixel_component, percent_component) => {
(target_bound * (percent_component.get_as_float() / 100.0))
+ pixel_component.get_as_float()
}
}
}
}
pub struct CommonProperties {
pub x: Option<Rc<RefCell<dyn PropertyInstance<Size>>>>,
pub y: Option<Rc<RefCell<dyn PropertyInstance<Size>>>>,
pub scale_x: Option<Rc<RefCell<dyn PropertyInstance<Size>>>>,
pub scale_y: Option<Rc<RefCell<dyn PropertyInstance<Size>>>>,
pub skew_x: Option<Rc<RefCell<dyn PropertyInstance<Numeric>>>>,
pub skew_y: Option<Rc<RefCell<dyn PropertyInstance<Numeric>>>>,
pub rotate: Option<Rc<RefCell<dyn PropertyInstance<Rotation>>>>,
pub anchor_x: Option<Rc<RefCell<dyn PropertyInstance<Size>>>>,
pub anchor_y: Option<Rc<RefCell<dyn PropertyInstance<Size>>>>,
pub transform: Rc<RefCell<dyn PropertyInstance<Transform2D>>>,
pub width: Rc<RefCell<dyn PropertyInstance<Size>>>,
pub height: Rc<RefCell<dyn PropertyInstance<Size>>>,
}
impl CommonProperties {
pub fn get_default_properties_literal() -> Vec<(String, String)> {
Self::get_property_identifiers()
.iter()
.map(|id| {
if id.0 == "transform" {
(
id.0.to_string(),
"Transform2D::default_wrapped()".to_string(),
)
} else if id.0 == "width" || id.0 == "height" {
(
id.0.to_string(),
"Rc::new(RefCell::new(PropertyLiteral::new(Size::default())))".to_string(),
)
} else {
(id.0.to_string(), "Default::default()".to_string())
}
})
.collect()
}
pub fn get_property_identifiers() -> Vec<(String, String)> {
vec![
("x".to_string(), "Size".to_string()),
("y".to_string(), "Size".to_string()),
("scale_x".to_string(), "Size".to_string()),
("scale_y".to_string(), "Size".to_string()),
("skew_x".to_string(), "Numeric".to_string()),
("skew_y".to_string(), "Numeric".to_string()),
("anchor_x".to_string(), "Size".to_string()),
("anchor_y".to_string(), "Size".to_string()),
("rotate".to_string(), "Rotation".to_string()),
("transform".to_string(), "Transform2D".to_string()),
("width".to_string(), "Size".to_string()),
("height".to_string(), "Size".to_string()),
]
}
}
impl Default for CommonProperties {
fn default() -> Self {
Self {
x: Default::default(),
y: Default::default(),
scale_x: Default::default(),
scale_y: Default::default(),
skew_x: Default::default(),
skew_y: Default::default(),
rotate: Default::default(),
anchor_x: Default::default(),
anchor_y: Default::default(),
width: Rc::new(RefCell::new(PropertyLiteral::new(Size::default()))),
height: Rc::new(RefCell::new(PropertyLiteral::new(Size::default()))),
transform: Transform2D::default_wrapped(),
}
}
}
#[derive(Clone)]
pub enum Rotation {
Radians(Numeric),
Degrees(Numeric),
Percent(Numeric),
}
impl Rotation {
#[allow(non_snake_case)]
pub fn ZERO() -> Self {
Self::Radians(Numeric::from(0.0))
}
pub fn get_as_radians(&self) -> f64 {
if let Self::Radians(num) = self {
num.get_as_float()
} else if let Self::Degrees(num) = self {
num.get_as_float() * std::f64::consts::PI * 2.0 / 360.0
} else if let Self::Percent(num) = self {
num.get_as_float() * std::f64::consts::PI * 2.0 / 100.0
} else {
unreachable!()
}
}
}
impl Neg for Rotation {
type Output = Rotation;
fn neg(self) -> Self::Output {
match self {
Rotation::Degrees(deg) => Rotation::Degrees(-deg),
Rotation::Radians(rad) => Rotation::Radians(-rad),
Rotation::Percent(per) => Rotation::Percent(-per),
}
}
}
impl Into<Rotation> for Numeric {
fn into(self) -> Rotation {
Rotation::Radians(self)
}
}
impl Into<Rotation> for Size {
fn into(self) -> Rotation {
if let Size::Percent(pix) = self {
Rotation::Percent(pix)
} else {
panic!("Tried to coerce a pixel value into a rotation value; try `%` or `rad` instead of `px`.")
}
}
}
impl Default for Rotation {
fn default() -> Self {
Self::ZERO()
}
}
impl Size {
pub fn get_pixels(&self, parent: f64) -> f64 {
match &self {
Self::Pixels(p) => p.get_as_float(),
Self::Percent(p) => parent * (p.get_as_float() / 100.0),
Self::Combined(pix, per) => {
(parent * (per.get_as_float() / 100.0)) + pix.get_as_float()
}
}
}
}
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::Combined(pix, per) => {
let pix = *sp + ((*pix - *sp) * Numeric::from(t));
let per = *per;
Self::Combined(pix, per)
}
},
Self::Percent(sp) => match other {
Self::Pixels(op) => Self::Pixels(*op),
Self::Percent(op) => Self::Percent(*sp + ((*op - *sp) * Numeric::from(t))),
Self::Combined(pix, per) => {
let pix = *pix;
let per = *sp + ((*per - *sp) * Numeric::from(t));
Self::Combined(pix, per)
}
},
Self::Combined(pix, per) => match other {
Self::Pixels(op) => {
let pix = *pix + ((*op - *pix) * Numeric::from(t));
Self::Combined(pix, *per)
}
Self::Percent(op) => {
let per = *per + ((*op - *per) * Numeric::from(t));
Self::Combined(*pix, per)
}
Self::Combined(pix0, per0) => {
let pix = *pix + ((*pix0 - *pix) * Numeric::from(t));
let per = *per + ((*per0 - *per) * Numeric::from(t));
Self::Combined(pix, per)
}
},
}
}
}
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();
(closure)(msg.as_ptr());
}
}
}
impl Mul for Size {
type Output = Size;
fn mul(self, rhs: Self) -> Self::Output {
match self {
Size::Pixels(pix0) => {
match rhs {
Size::Pixels(pix1) => Size::Pixels(pix0 + pix1),
Size::Percent(per1) => Size::Pixels(pix0 * per1),
Size::Combined(pix1, per1) => Size::Pixels((pix0 * per1) + pix0 + pix1),
}
}
Size::Percent(per0) => match rhs {
Size::Pixels(pix1) => Size::Pixels(per0 * pix1),
Size::Percent(per1) => Size::Percent(per0 * per1),
Size::Combined(pix1, per1) => Size::Pixels((per0 * pix1) + (per0 * per1)),
},
Size::Combined(pix0, per0) => match rhs {
Size::Pixels(pix1) => Size::Pixels((pix0 * per0) + pix1),
Size::Percent(per1) => Size::Percent(pix0 * per0 * per1),
Size::Combined(pix1, per1) => Size::Pixels((pix0 * per0) + (pix1 * per1)),
},
}
}
}
#[derive(Default, Clone)]
pub struct Transform2D {
pub previous: Option<Box<Transform2D>>,
pub rotate: Option<Rotation>,
pub translate: Option<[Size; 2]>,
pub anchor: Option<[Size; 2]>,
pub scale: Option<[Size; 2]>,
pub skew: 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: Size, y: Size) -> Self {
let mut ret = Transform2D::default();
ret.scale = Some([x, y]);
ret
}
pub fn rotate(z: Rotation) -> Self {
let mut ret = Transform2D::default();
ret.rotate = Some(z);
ret
}
pub fn translate(x: Size, y: Size) -> Self {
let mut ret = Transform2D::default();
ret.translate = 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());
let _ = &self.transition_manager.queue.clear();
let _ = &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,
});
}
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
}
#[allow(dead_code)]
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 i64 {
fn interpolate(&self, other: &i64, t: f64) -> i64 {
(*self as f64 + (*other - self) as f64 * t) as i64
}
}
impl Interpolatable for u64 {
fn interpolate(&self, other: &u64, t: f64) -> u64 {
(*self as f64 + (*other - self) as f64 * t) as u64
}
}
impl Interpolatable for u8 {
fn interpolate(&self, other: &u8, t: f64) -> u8 {
(*self as f64 + (*other - *self) as f64 * t) as u8
}
}
impl Interpolatable for u16 {
fn interpolate(&self, other: &u16, t: f64) -> u16 {
(*self as f64 + (*other - *self) as f64 * t) as u16
}
}
impl Interpolatable for u32 {
fn interpolate(&self, other: &u32, t: f64) -> u32 {
(*self as f64 + (*other - *self) as f64 * t) as u32
}
}
impl Interpolatable for i8 {
fn interpolate(&self, other: &i8, t: f64) -> i8 {
(*self as f64 + (*other - *self) as f64 * t) as i8
}
}
impl Interpolatable for i16 {
fn interpolate(&self, other: &i16, t: f64) -> i16 {
(*self as f64 + (*other - *self) as f64 * t) as i16
}
}
impl Interpolatable for i32 {
fn interpolate(&self, other: &i32, t: f64) -> i32 {
(*self as f64 + (*other - *self) as f64 * t) as i32
}
}
impl Interpolatable for String {}
pub struct Timeline {
pub playhead_position: usize,
pub frame_count: usize,
pub is_playing: bool,
}
#[derive(Clone, PartialEq, Debug)]
pub enum Layer {
Native,
Scroller,
Canvas,
DontCare,
}
#[derive(Clone)]
pub struct ZIndex {
z_index: u32,
layer: Layer,
#[allow(dead_code)]
parent_scroller: Option<Vec<u32>>,
}
impl ZIndex {
pub fn new(scroller_id: Option<Vec<u32>>) -> Self {
ZIndex {
z_index: 0,
layer: Layer::Canvas,
parent_scroller: scroller_id,
}
}
pub fn get_level(&mut self) -> u32 {
self.z_index
}
pub fn get_current_layer(&mut self) -> Layer {
self.layer.clone()
}
pub fn update_z_index(&mut self, layer: Layer) {
match layer {
Layer::DontCare => {}
_ => {
if self.layer != layer {
if layer == Layer::Canvas || layer == Layer::Scroller {
self.z_index += 1;
}
}
self.layer = layer.clone();
}
}
}
pub fn generate_location_id(scroller_id: Option<Vec<u32>>, z_index: u32) -> String {
if let Some(id) = scroller_id {
format!("{:?}_{}", id, z_index)
} else {
format!("{}", z_index)
}
}
}