Lightningbeam/lightningbeam-ui/lightningbeam-core/src/actions/remove_shapes.rs

119 lines
3.2 KiB
Rust

//! Remove shapes action
//!
//! Handles removing shapes from a vector layer's keyframe (for cut/delete).
use crate::action::Action;
use crate::document::Document;
use crate::layer::AnyLayer;
use crate::shape::Shape;
use uuid::Uuid;
/// Action that removes shapes from a vector layer's keyframe
pub struct RemoveShapesAction {
/// Layer ID containing the shapes
layer_id: Uuid,
/// Shape IDs to remove
shape_ids: Vec<Uuid>,
/// Time of the keyframe
time: f64,
/// Saved shapes for rollback
saved_shapes: Vec<Shape>,
}
impl RemoveShapesAction {
pub fn new(layer_id: Uuid, shape_ids: Vec<Uuid>, time: f64) -> Self {
Self {
layer_id,
shape_ids,
time,
saved_shapes: Vec::new(),
}
}
}
impl Action for RemoveShapesAction {
fn execute(&mut self, document: &mut Document) -> Result<(), String> {
self.saved_shapes.clear();
let layer = document
.get_layer_mut(&self.layer_id)
.ok_or_else(|| format!("Layer {} not found", self.layer_id))?;
let vector_layer = match layer {
AnyLayer::Vector(vl) => vl,
_ => return Err("Not a vector layer".to_string()),
};
for shape_id in &self.shape_ids {
if let Some(shape) = vector_layer.remove_shape_from_keyframe(shape_id, self.time) {
self.saved_shapes.push(shape);
}
}
Ok(())
}
fn rollback(&mut self, document: &mut Document) -> Result<(), String> {
let layer = document
.get_layer_mut(&self.layer_id)
.ok_or_else(|| format!("Layer {} not found", self.layer_id))?;
let vector_layer = match layer {
AnyLayer::Vector(vl) => vl,
_ => return Err("Not a vector layer".to_string()),
};
for shape in self.saved_shapes.drain(..) {
vector_layer.add_shape_to_keyframe(shape, self.time);
}
Ok(())
}
fn description(&self) -> String {
let count = self.shape_ids.len();
if count == 1 {
"Delete shape".to_string()
} else {
format!("Delete {} shapes", count)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::layer::VectorLayer;
use crate::shape::Shape;
use vello::kurbo::BezPath;
#[test]
fn test_remove_shapes() {
let mut document = Document::new("Test");
let mut vector_layer = VectorLayer::new("Layer 1");
let mut path = BezPath::new();
path.move_to((0.0, 0.0));
path.line_to((100.0, 100.0));
let shape = Shape::new(path);
let shape_id = shape.id;
vector_layer.add_shape_to_keyframe(shape, 0.0);
let layer_id = document.root_mut().add_child(AnyLayer::Vector(vector_layer));
let mut action = RemoveShapesAction::new(layer_id, vec![shape_id], 0.0);
action.execute(&mut document).unwrap();
if let Some(AnyLayer::Vector(vl)) = document.get_layer(&layer_id) {
assert!(vl.shapes_at_time(0.0).is_empty());
}
action.rollback(&mut document).unwrap();
if let Some(AnyLayer::Vector(vl)) = document.get_layer(&layer_id) {
assert_eq!(vl.shapes_at_time(0.0).len(), 1);
}
}
}