use bevy::prelude::*;
use super::super::protocol::{AnimatableProperty, AnimatedBindings, ValueKind};
use super::super::{SharedValues, eval_color, eval_scalar, props};
use super::AnimTargetsItem;
#[allow(clippy::too_many_arguments)]
pub(super) fn stage_node_and_colors(
entity: Entity,
commands: &mut Commands,
b: &AnimatedBindings,
values: &SharedValues,
opacity_alpha: Option<f32>,
promoted: bool,
dirt: &mut crate::layer::LayerContentDirt,
t: &mut AnimTargetsItem,
) {
use AnimatableProperty as P;
for (property, binding) in b.iter() {
if !matches!(
property.stage(),
props::PropStage::Node | props::PropStage::Color
) {
continue;
}
match property.value_kind() {
ValueKind::Color => {
let Some(rgba) = eval_color(binding, values) else {
continue;
};
let baked = |mut rgba: [f32; 4], bake: bool| {
if bake
&& !promoted
&& let Some(alpha) = opacity_alpha
{
rgba[3] = alpha;
}
Color::srgba(rgba[0], rgba[1], rgba[2], rgba[3])
};
macro_rules! color_rule {
($prop:tt, (color bg)) => {
if property == &$prop {
let color = baked(rgba, true);
match &mut t.bg {
Some(c) if c.0 != color => {
c.0 = color;
dirt.nodes.push(entity);
}
Some(_) => {}
None => {
commands.entity(entity).insert(BackgroundColor(color));
dirt.nodes.push(entity);
}
}
}
};
($prop:tt, (color border)) => {
if property == &$prop {
let color = baked(rgba, false);
let bc = BorderColor {
top: color,
right: color,
bottom: color,
left: color,
};
match &mut t.border {
Some(c) if **c != bc => {
**c = bc;
dirt.nodes.push(entity);
}
Some(_) => {}
None => {
commands.entity(entity).insert(bc);
dirt.nodes.push(entity);
}
}
}
};
($prop:tt, (color text)) => {
if property == &$prop {
let color = baked(rgba, true);
if let Some(tc) = &mut t.text
&& tc.0 != color
{
tc.0 = color;
dirt.nodes.push(entity);
}
}
};
($prop:tt, (color image_tint)) => {
if property == &$prop {
let color = baked(rgba, true);
if let Some(img) = &mut t.image
&& img.color != color
{
img.color = color;
dirt.nodes.push(entity);
}
}
};
($prop:tt, $other:tt) => {};
}
macro_rules! walk {
($(($prop:tt, $kind:ident, $acc:tt, $write:tt, $stage:ident, $park:ident),)*) => {
$(color_rule!($prop, $write);)*
};
}
props::with_animatable_props!(walk);
}
_ => {
let Some(v) = eval_scalar(binding, values) else {
continue;
};
if let Some(node) = t.node.as_mut()
&& write_node_value(node, property, v)
{
dirt.nodes.push(entity);
}
}
}
}
}
fn write_node_value<N: std::ops::DerefMut<Target = Node>>(
node: &mut N,
property: &AnimatableProperty,
v: f32,
) -> bool {
use AnimatableProperty as P;
let val = Val::Px(v);
macro_rules! rule {
($prop:tt, (node $field:ident)) => {
if property == &$prop {
if node.$field != val {
node.$field = val;
return true;
}
return false;
}
};
($prop:tt, (node_gap_both)) => {
if property == &$prop {
let mut wrote = false;
if node.row_gap != val {
node.row_gap = val;
wrote = true;
}
if node.column_gap != val {
node.column_gap = val;
wrote = true;
}
return wrote;
}
};
($prop:tt, (node_aspect)) => {
if property == &$prop {
if node.aspect_ratio != Some(v) {
node.aspect_ratio = Some(v);
return true;
}
return false;
}
};
($prop:tt, (color $target:ident)) => {};
($prop:tt, (none)) => {};
}
macro_rules! walk {
($(($prop:tt, $kind:ident, $acc:tt, $write:tt, $stage:ident, $park:ident),)*) => {
$(rule!($prop, $write);)*
};
}
props::with_animatable_props!(walk);
false
}