use bevy::{platform::collections::HashMap, prelude::*};
use velato::{
Composition,
model::{Brush, Shape},
};
use vello::peniko::color::DynamicColor;
#[derive(PartialEq, Component, Default, Clone, Debug, Reflect)]
#[reflect(Component)]
pub struct Theme {
pub(crate) colors: HashMap<String, Color>,
}
impl Theme {
pub fn new() -> Self {
Self {
colors: HashMap::default(),
}
}
pub fn add(mut self, layer_name: &str, color: Color) -> Self {
self.colors.insert(layer_name.to_string(), color);
self
}
pub fn edit(&mut self, layer_name: &str, color: Color) -> &mut Self {
self.colors.insert(layer_name.to_string(), color);
self
}
pub fn get(&self, layer_name: &str) -> Option<&Color> {
self.colors.get(layer_name)
}
pub fn get_mut(&mut self, layer_name: &str) -> Option<&mut Color> {
self.colors.get_mut(layer_name)
}
}
impl Theme {
pub fn recolor(&self, composition: &Composition) -> Composition {
let mut composition = composition.clone();
'layers: for layer in composition.layers.iter_mut() {
let Some(target_color) = self.colors.get(&layer.name) else {
continue 'layers;
};
let shapes = match &mut layer.content {
velato::model::Content::Shape(shapes) => shapes,
velato::model::Content::None | velato::model::Content::Instance { .. } => {
continue 'layers;
}
};
let target_color = target_color.to_srgba();
let target_color = vello::peniko::Color::new([
target_color.red as _,
target_color.green as _,
target_color.blue as _,
target_color.alpha as _,
]);
for shape in shapes.iter_mut() {
recolor_shape(shape, target_color);
}
}
composition
}
}
fn recolor_shape(shape: &mut Shape, target_color: vello::peniko::Color) {
match shape {
velato::model::Shape::Group(shapes, _) => {
for shape in shapes.iter_mut() {
recolor_shape(shape, target_color);
}
}
velato::model::Shape::Draw(draw) => {
recolor_brush(&mut draw.brush, target_color);
}
velato::model::Shape::Repeater(_)
| velato::model::Shape::Geometry(_)
| velato::model::Shape::Trim(_) => {}
}
}
fn recolor_brush(brush: &mut Brush, target_color: vello::peniko::Color) {
match brush {
velato::model::Brush::Fixed(brush) => match brush {
vello::peniko::Brush::Solid(solid) => {
*solid = target_color;
}
vello::peniko::Brush::Gradient(gradient) => {
for stop in gradient.stops.0.as_mut() {
stop.color = DynamicColor::from_alpha_color(target_color);
}
}
vello::peniko::Brush::Image(_) => {}
},
velato::model::Brush::Animated(brush) => match brush {
velato::model::animated::Brush::Solid(brush) => match brush {
velato::model::Value::Fixed(solid) => {
*solid = target_color;
}
velato::model::Value::Animated(keyframes) => {
for solid in keyframes.values.iter_mut() {
*solid = target_color;
}
}
},
velato::model::animated::Brush::Gradient(gr) => match &mut gr.stops {
velato::model::ColorStops::Fixed(stops) => {
for stop in stops.0.as_mut() {
stop.color = DynamicColor::from_alpha_color(target_color);
}
}
velato::model::ColorStops::Animated(stops) => {
for _ in 0..stops.count {
for stop in stops.values.iter_mut() {
let _offset = stop[0];
let [cr, cg, cb, ca] = target_color.components;
let r = &mut stop[1];
*r = cr as f64;
let g = &mut stop[2];
*g = cg as f64;
let b = &mut stop[3];
*b = cb as f64;
let a = &mut stop[4];
*a = ca as f64;
}
}
}
},
},
}
}