//! Group layers action //! //! Creates a new GroupLayer containing the selected sibling layers. use crate::action::Action; use crate::document::Document; use crate::layer::{AnyLayer, GroupLayer}; use uuid::Uuid; /// Action that groups sibling layers into a new GroupLayer. /// /// All layers must share the same parent (root or a specific GroupLayer). pub struct GroupLayersAction { /// IDs of layers to group layer_ids: Vec, /// Parent group ID (None = document root) parent_group_id: Option, /// Pre-generated UUID for the new GroupLayer group_id: Uuid, /// Rollback: index where the group was inserted insert_index: Option, /// Rollback: (original_index, layer) pairs, sorted by index ascending removed_layers: Vec<(usize, AnyLayer)>, } impl GroupLayersAction { pub fn new(layer_ids: Vec, parent_group_id: Option, group_id: Uuid) -> Self { Self { layer_ids, parent_group_id, group_id, insert_index: None, removed_layers: Vec::new(), } } } /// Get a mutable reference to the children vec of the given parent. fn get_parent_children<'a>( document: &'a mut Document, parent_group_id: Option, ) -> Result<&'a mut Vec, String> { match parent_group_id { None => Ok(&mut document.root.children), Some(id) => { let layer = document.root.get_child_mut(&id) .ok_or_else(|| format!("Parent group {} not found", id))?; match layer { AnyLayer::Group(g) => Ok(&mut g.children), _ => Err(format!("Layer {} is not a group", id)), } } } } impl Action for GroupLayersAction { fn execute(&mut self, document: &mut Document) -> Result<(), String> { let children = get_parent_children(document, self.parent_group_id)?; // Find indices of all selected layers within the parent's children let mut indices: Vec = Vec::new(); for layer_id in &self.layer_ids { if let Some(idx) = children.iter().position(|l| l.id() == *layer_id) { indices.push(idx); } else { return Err(format!("Layer {} not found in parent", layer_id)); } } indices.sort(); // Record the insert position (topmost selected layer) let insert_index = indices[0]; self.insert_index = Some(insert_index); // Remove layers back-to-front to preserve indices self.removed_layers.clear(); for &idx in indices.iter().rev() { let layer = children.remove(idx); self.removed_layers.push((idx, layer)); } // Reverse so removed_layers is sorted by index ascending self.removed_layers.reverse(); // Build the new GroupLayer with children in their original order let mut group = GroupLayer::new("Group"); group.layer.id = self.group_id; for (_, layer) in &self.removed_layers { group.add_child(layer.clone()); } // Insert the group at the topmost position let children = get_parent_children(document, self.parent_group_id)?; children.insert(insert_index, AnyLayer::Group(group)); Ok(()) } fn rollback(&mut self, document: &mut Document) -> Result<(), String> { let Some(insert_index) = self.insert_index else { return Err("Cannot rollback: action was not executed".to_string()); }; // Remove the GroupLayer let children = get_parent_children(document, self.parent_group_id)?; children.remove(insert_index); // Re-insert original layers at their original indices (ascending order) for (idx, layer) in &self.removed_layers { let children = get_parent_children(document, self.parent_group_id)?; children.insert(*idx, layer.clone()); } self.insert_index = None; Ok(()) } fn description(&self) -> String { format!("Group {} layers", self.layer_ids.len()) } }