From bf3b05070cffce168d07478cc7d1152adedf2e16 Mon Sep 17 00:00:00 2001 From: Tarun Prabhu <77986110+tarunprabhu11@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:06:56 +0530 Subject: [PATCH] Add a "Reverse" command to the "Order" menu (#2273) * addded reverse for layer ordering * added reverse to layer odering * fixed indentation and spacing * added reverse for layer ordering * Added Reverse to layer ordering * Update document_message_handler.rs * Update document_message_handler.rs * Cleanup, fix compiling, fix history bug --------- Co-authored-by: Keavon Chambers --- .../portfolio/document/document_message.rs | 1 + .../document/document_message_handler.rs | 95 +++++++++++++++++++ .../menu_bar/menu_bar_message_handler.rs | 3 +- 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs index 315702db..8ae84271 100644 --- a/editor/src/messages/portfolio/document/document_message.rs +++ b/editor/src/messages/portfolio/document/document_message.rs @@ -114,6 +114,7 @@ pub enum DocumentMessage { SelectedLayersLowerToBack, SelectedLayersRaise, SelectedLayersRaiseToFront, + SelectedLayersReverse, SelectedLayersReorder { relative_index_offset: isize, }, diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 57f95761..efcb5201 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -948,6 +948,9 @@ impl MessageHandler> for DocumentMessag DocumentMessage::SelectedLayersRaiseToFront => { responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: isize::MIN }); } + DocumentMessage::SelectedLayersReverse => { + self.selected_layers_reverse(responses); + } DocumentMessage::SelectedLayersReorder { relative_index_offset } => { self.selected_layers_reorder(relative_index_offset, responses); } @@ -2149,6 +2152,98 @@ impl DocumentMessageHandler { }); } + pub fn selected_layers_reverse(&mut self, responses: &mut VecDeque) { + let selected_layers = self.network_interface.selected_nodes(&[]).unwrap(); + let metadata = self.metadata(); + let selected_layer_set = selected_layers.selected_layers(metadata).collect::>(); + + // Ignore those with selected ancestors + let mut top_level_layers = Vec::new(); + for &layer in &selected_layer_set { + let mut is_top_level = true; + let mut current_layer = layer; + + while let Some(parent) = current_layer.parent(metadata) { + if selected_layer_set.contains(&parent) { + is_top_level = false; + break; + } + current_layer = parent; + } + + if is_top_level { + top_level_layers.push(layer); + } + } + + // Group selected layers by their parent + let mut grouped_layers: HashMap> = HashMap::new(); + for &layer in &top_level_layers { + if let Some(parent) = layer.parent(metadata) { + let index = parent.children(metadata).position(|child| child == layer).unwrap_or(usize::MAX); + + grouped_layers.entry(parent).or_default().push((index, layer)); + } + } + + let mut modified = false; + + // Process each group separately + for (parent, mut layers) in grouped_layers { + // Retrieve all children under the parent + let all_children = parent.children(metadata).collect::>(); + + // Separate unselected layers with their original indices + let unselected_layers = all_children + .iter() + .enumerate() + .filter_map(|(index, &layer)| if !selected_layer_set.contains(&layer) { Some((index, layer)) } else { None }) + .collect::>(); + + layers.sort_by_key(|(index, _)| *index); + + let reversed_layers = layers.iter().rev().map(|(_, layer)| *layer).collect::>(); + let selected_positions = layers.iter().map(|(index, _)| *index).collect::>(); + let selected_iter = reversed_layers.into_iter(); + let mut merged_layers = vec![None; all_children.len()]; + + for (&original_index, new_layer) in selected_positions.iter().zip(selected_iter) { + merged_layers[original_index] = Some(new_layer); + } + + // Place unselected layers at their original positions + for (index, layer) in unselected_layers { + if merged_layers[index].is_none() { + merged_layers[index] = Some(layer); + } + } + + let final_layers = merged_layers.into_iter().flatten().collect::>(); + if final_layers.is_empty() { + continue; + } + + if !modified { + responses.add(DocumentMessage::AddTransaction); + } + + for (index, layer) in final_layers.iter().enumerate() { + responses.add(NodeGraphMessage::MoveLayerToStack { + layer: *layer, + parent, + insert_index: index, + }); + } + + modified = true; + } + + if modified { + responses.add(NodeGraphMessage::RunDocumentGraph); + responses.add(NodeGraphMessage::SendGraph); + } + } + pub fn selected_layers_reorder(&mut self, relative_index_offset: isize, responses: &mut VecDeque) { let selected_nodes = self.network_interface.selected_nodes(&[]).unwrap(); let mut selected_layers = selected_nodes.selected_layers(self.metadata()); diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs index fa241fd3..9ae11ee3 100644 --- a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs +++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs @@ -346,8 +346,7 @@ impl LayoutHolder for MenuBarMessageHandler { vec![MenuBarEntry { label: "Reverse".into(), icon: Some("StackReverse".into()), - // shortcut: action_keys!(DocumentMessageDiscriminant::SelectedLayersReverse), - action: MenuBarEntry::create_action(|_| DialogMessage::RequestComingSoonDialog { issue: Some(2271) }.into()), + action: MenuBarEntry::create_action(|_| DocumentMessage::SelectedLayersReverse.into()), disabled: no_active_document || !has_selected_layers, ..MenuBarEntry::default() }],