#[allow(unused)]
use crate::*;
use pax_engine::api::Numeric;
use pax_engine::api::{Property, Size};
use pax_engine::*;
use pax_runtime::api::NodeContext;
#[pax]
#[engine_import_path("pax_engine")]
#[custom(Default)]
#[inlined(
for (cell_spec, i) in self._cell_specs {
<Group
transform={Transform2D::translate((cell_spec.x_px)px, (cell_spec.y_px)px)}
width={(cell_spec.width_px)px}
height={(cell_spec.height_px)px}
>
slot(i)
</Group>
}
@settings {
@mount: on_mount
}
)]
pub struct Stacker {
pub direction: Property<StackerDirection>,
pub _cell_specs: Property<Vec<StackerCell>>,
pub gutter: Property<Size>,
pub sizes: Property<Vec<Option<Size>>>,
}
impl Default for Stacker {
fn default() -> Self {
Self {
direction: Property::new(StackerDirection::Vertical),
_cell_specs: Property::new(vec![]),
gutter: Property::new(Size::Pixels(Numeric::I32(0))),
sizes: Property::new(vec![]),
}
}
}
impl Stacker {
pub fn on_mount(&mut self, ctx: &NodeContext) {
let sizes = self.sizes.clone();
let bound = ctx.bounds_self.clone();
let slot_children_count = ctx.slot_children_count.clone();
let gutter = self.gutter.clone();
let direction = self.direction.clone();
let deps = [
bound.untyped(),
direction.untyped(),
sizes.untyped(),
gutter.untyped(),
slot_children_count.untyped(),
];
self._cell_specs.replace_with(Property::computed_with_name(
move || {
let cells: f64 = slot_children_count.get() as f64;
let bounds = bound.get();
let active_bound = match direction.get() {
StackerDirection::Horizontal => bounds.0,
StackerDirection::Vertical => bounds.1,
};
let gutter_calc = match gutter.get() {
Size::Pixels(pix) => pix,
Size::Percent(per) => Numeric::F64(active_bound) * (per / Numeric::F64(100.0)),
Size::Combined(pix, per) => {
pix + (Numeric::F64(active_bound) * (per / Numeric::F64(100.0)))
}
};
let usable_interior_space = active_bound - (cells - 1.0) * gutter_calc.to_float();
let per_cell_space = usable_interior_space / cells;
let mut cell_space = vec![per_cell_space; cells as usize];
let mut sizes = sizes.get();
while sizes.len() < cell_space.len() {
sizes.push(None)
}
if sizes.len() > 0 {
let mut used_space = 0.0;
let mut remaining_cells = 0.0;
for (i, size) in sizes.iter().take(cells as usize).enumerate() {
if let Some(s) = size {
let space = match s {
Size::Pixels(pix) => *pix,
Size::Percent(per) => {
Numeric::F64(active_bound) * (*per / Numeric::F64(100.0))
}
Size::Combined(pix, per) => {
*pix + (Numeric::F64(active_bound)
* (*per / Numeric::F64(100.0)))
}
}
.to_float();
used_space += space;
cell_space[i] = space;
} else {
cell_space[i] = -1.0;
remaining_cells += 1.0;
}
}
let remaining_per_cell_space =
(usable_interior_space - used_space) / remaining_cells;
let remaining_per_cell_space = remaining_per_cell_space.max(5.0);
for i in &mut cell_space {
if *i == -1.0 {
*i = remaining_per_cell_space;
}
}
}
let mut used_space = 0.0;
let new_cell_specs = (0..cells as usize)
.into_iter()
.map(|i| {
let ret = match direction.get() {
StackerDirection::Horizontal => StackerCell {
height_px: bounds.1,
width_px: cell_space[i],
x_px: ((i) as f64) * gutter_calc.to_float() + used_space,
y_px: 0.0,
},
StackerDirection::Vertical => StackerCell {
height_px: cell_space[i],
width_px: bounds.0,
x_px: 0.0,
y_px: ((i) as f64) * gutter_calc.to_float() + used_space,
},
};
used_space += cell_space[i];
ret
})
.collect();
new_cell_specs
},
&deps,
"stacker _cell_specs",
));
}
}
#[pax]
#[engine_import_path("pax_engine")]
pub struct StackerCell {
pub x_px: f64,
pub y_px: f64,
pub width_px: f64,
pub height_px: f64,
}
#[pax]
#[engine_import_path("pax_engine")]
pub enum StackerDirection {
#[default]
Vertical,
Horizontal,
}