use crate::api::{Axis, Size, Transform2D};
use crate::math::{Generic, Transform2, Vector2};
use crate::node_interface::NodeLocal;
use crate::{ExpandedNode, TransformAndBounds};
pub fn compute_tab(node: &ExpandedNode, container_tab: &TransformAndBounds) -> TransformAndBounds {
let new_accumulated_bounds_and_current_node_size =
{ node.get_size_computed(container_tab.bounds) };
let node_transform_property_computed = {
node.get_common_properties()
.borrow()
.transform
.get()
.compute_transform2d_matrix(
new_accumulated_bounds_and_current_node_size.clone(),
container_tab.bounds,
)
.cast_spaces::<NodeLocal, NodeLocal>()
};
let desugared_transform = {
let comm = node.get_common_properties();
let comm = comm.borrow();
let mut desugared_transform2d = Transform2D::default();
let translate = [
if let Some(ref val) = comm.x {
val.get().clone()
} else {
Size::ZERO()
},
if let Some(ref val) = comm.y {
val.get().clone()
} else {
Size::ZERO()
},
];
desugared_transform2d.translate = Some(translate);
let anchor = [
if let Some(ref val) = comm.anchor_x {
val.get().clone()
} else {
Size::ZERO()
},
if let Some(ref val) = comm.anchor_y {
val.get().clone()
} else {
Size::ZERO()
},
];
desugared_transform2d.anchor = Some(anchor);
let scale = [
if let Some(ref val) = comm.scale_x {
val.get().clone()
} else {
Size::Percent(crate::numeric::Numeric::from(100.0))
},
if let Some(ref val) = comm.scale_y {
val.get().clone()
} else {
Size::Percent(crate::numeric::Numeric::from(100.0))
},
];
desugared_transform2d.scale = Some(scale);
let skew = [
if let Some(ref val) = comm.skew_x {
val.get().get_as_float()
} else {
0.0
},
if let Some(ref val) = comm.skew_y {
val.get().get_as_float()
} else {
0.0
},
];
desugared_transform2d.skew = Some(skew);
let rotate = if let Some(ref val) = comm.rotate {
val.get().clone()
} else {
crate::api::Rotation::ZERO()
};
desugared_transform2d.rotate = Some(rotate);
desugared_transform2d
.compute_transform2d_matrix(
new_accumulated_bounds_and_current_node_size.clone(),
container_tab.bounds,
)
.cast_spaces::<NodeLocal, NodeLocal>()
};
let new_accumulated_transform =
container_tab.transform * desugared_transform * node_transform_property_computed;
TransformAndBounds {
transform: new_accumulated_transform,
bounds: new_accumulated_bounds_and_current_node_size,
}
}
pub trait ComputableTransform {
fn compute_transform2d_matrix(
&self,
node_size: (f64, f64),
container_bounds: (f64, f64),
) -> Transform2;
}
impl ComputableTransform for Transform2D {
fn compute_transform2d_matrix(
&self,
node_size: (f64, f64),
container_bounds: (f64, f64),
) -> Transform2 {
let anchor_transform = match &self.anchor {
Some(anchor) => Transform2::translate(Vector2::<Generic>::new(
match anchor[0] {
Size::Pixels(pix) => -pix.get_as_float(),
Size::Percent(per) => -node_size.0 * (per / 100.0),
Size::Combined(pix, per) => {
-pix.get_as_float() + (-node_size.0 * (per / 100.0))
}
},
match anchor[1] {
Size::Pixels(pix) => -pix.get_as_float(),
Size::Percent(per) => -node_size.1 * (per / 100.0),
Size::Combined(pix, per) => {
-pix.get_as_float() + (-node_size.0 * (per / 100.0))
}
},
)),
None => Transform2::default(),
};
let (scale_x, scale_y) = if let Some(scale) = self.scale {
(scale[0].expect_percent(), scale[1].expect_percent())
} else {
(1.0, 1.0)
};
let (skew_x, skew_y) = if let Some(skew) = self.skew {
(skew[0], skew[1])
} else {
(0.0, 0.0)
};
let (translate_x, translate_y) = if let Some(translate) = &self.translate {
(
translate[0].evaluate(container_bounds, Axis::X),
translate[1].evaluate(container_bounds, Axis::Y),
)
} else {
(0.0, 0.0)
};
let rotate_rads = if let Some(rotate) = &self.rotate {
rotate.get_as_radians()
} else {
0.0
};
let cos_theta = rotate_rads.cos();
let sin_theta = rotate_rads.sin();
let a = scale_x * cos_theta - scale_y * skew_x * sin_theta;
let b = scale_x * sin_theta + scale_y * skew_x * cos_theta;
let c = -scale_y * sin_theta + scale_x * skew_y * cos_theta;
let d = scale_y * cos_theta + scale_x * skew_y * sin_theta;
let e = translate_x;
let f = translate_y;
let coeffs = [a, b, c, d, e, f];
let transform = Transform2::new(coeffs);
let previous_transform = match &self.previous {
Some(previous) => (*previous).compute_transform2d_matrix(node_size, container_bounds),
None => Transform2::default(),
};
transform * anchor_transform * previous_transform
}
}