From cb0ba1a8c3c0a2e024c1526984085f03f1462534 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Mon, 21 Apr 2025 19:18:43 +0530 Subject: [PATCH 01/14] Fix ancestor always returning None during shallow select --- .../tool/tool_messages/select_tool.rs | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index fc897a9a7a..cd52375fae 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -29,6 +29,7 @@ use graph_craft::document::NodeId; use graphene_core::renderer::Quad; use graphene_std::renderer::Rect; use graphene_std::vector::misc::BooleanOperation; +use std::collections::HashSet; use std::fmt; #[derive(Default)] @@ -1590,16 +1591,56 @@ fn not_artboard(document: &DocumentMessageHandler) -> impl Fn(&LayerNodeIdentifi } fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) { - for layer in selected { - let ancestor = layer - .ancestors(document.metadata()) + if selected.is_empty() { + return; + } + + let clicked_layer = document.find_deepest(&selected).unwrap_or_else(|| { + LayerNodeIdentifier::ROOT_PARENT + .children(document.metadata()) + .next() + .expect("ROOT_PARENT should have at least one layer when clicking") + }); + + let selected_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); + let metadata = document.metadata(); + + let final_selection: Option> = (!selected_layers.is_empty() && selected_layers != vec![LayerNodeIdentifier::ROOT_PARENT]).then_some(()).and_then(|_| { + let mut relevant_layers = selected_layers; + if !relevant_layers.contains(&clicked_layer) { + relevant_layers.push(clicked_layer); + } + clicked_layer + .ancestors(metadata) .filter(not_artboard(document)) - .find(|&ancestor| document.network_interface.selected_nodes().selected_layers_contains(ancestor, document.metadata())); + .find(|&potential_lca| { + relevant_layers + .iter() + .all(|layer| *layer == potential_lca || layer.ancestors(metadata).any(|ancestor| ancestor == potential_lca)) + }) + .map(|lca| { + let direct_children_of_lca: Vec<_> = lca.children(metadata).collect(); + let mut relevant_siblings = HashSet::new(); + for layer_to_check in &relevant_layers { + if *layer_to_check == lca { + relevant_siblings.clear(); + relevant_siblings.insert(lca); + break; + } + if let Some(relevant_child) = direct_children_of_lca + .iter() + .find(|&&child| *layer_to_check == child || layer_to_check.ancestors(metadata).any(|ancestor| ancestor == child)) + { + relevant_siblings.insert(*relevant_child); + } + } + relevant_siblings.into_iter().collect() + }) + }); - let new_selected = ancestor.unwrap_or_else(|| layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(layer)); - tool_data.layers_dragging.retain(|layer| !layer.ancestors(document.metadata()).any(|ancestor| ancestor == new_selected)); - tool_data.layers_dragging.push(new_selected); - } + let new_selected = final_selection.unwrap_or_else(|| vec![clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)]); + tool_data.layers_dragging.clear(); + tool_data.layers_dragging.extend(new_selected); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: tool_data From 437c835f3c0e970150e6fdda775e9c9ad37bf873 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 12:41:37 +0530 Subject: [PATCH 02/14] Fixes --- .../tool/tool_messages/select_tool.rs | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index f09c2c43cf..98bc5948ff 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1606,7 +1606,7 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec let selected_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); let metadata = document.metadata(); - let final_selection: Option> = (!selected_layers.is_empty() && selected_layers != vec![LayerNodeIdentifier::ROOT_PARENT]).then_some(()).and_then(|_| { + let final_selection: Option = (!selected_layers.is_empty() && selected_layers != vec![LayerNodeIdentifier::ROOT_PARENT]).then_some(()).and_then(|_| { let mut relevant_layers = selected_layers; if !relevant_layers.contains(&clicked_layer) { relevant_layers.push(clicked_layer); @@ -1619,29 +1619,20 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec .iter() .all(|layer| *layer == potential_lca || layer.ancestors(metadata).any(|ancestor| ancestor == potential_lca)) }) - .map(|lca| { + .and_then(|lca| { let direct_children_of_lca: Vec<_> = lca.children(metadata).collect(); - let mut relevant_siblings = HashSet::new(); - for layer_to_check in &relevant_layers { - if *layer_to_check == lca { - relevant_siblings.clear(); - relevant_siblings.insert(lca); - break; - } - if let Some(relevant_child) = direct_children_of_lca + if clicked_layer == lca { + Some(lca) + } else { + direct_children_of_lca .iter() - .find(|&&child| *layer_to_check == child || layer_to_check.ancestors(metadata).any(|ancestor| ancestor == child)) - { - relevant_siblings.insert(*relevant_child); - } + .find(|&&child| clicked_layer == child || clicked_layer.ancestors(metadata).any(|ancestor| ancestor == child)).copied() } - relevant_siblings.into_iter().collect() }) }); - let new_selected = final_selection.unwrap_or_else(|| vec![clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)]); - tool_data.layers_dragging.clear(); - tool_data.layers_dragging.extend(new_selected); + let new_selected = final_selection.unwrap_or_else(|| clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)); + tool_data.layers_dragging.extend(vec![new_selected]); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: tool_data From 2347e2141a00af2868f0f58dcd096f4e137cee10 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 16:39:54 +0530 Subject: [PATCH 03/14] fix shift remove on both --- .../tool/tool_messages/select_tool.rs | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 98bc5948ff..af71271c35 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -964,8 +964,8 @@ impl Fsm for SelectToolFsmState { selected = intersection_list; match tool_data.nested_selection_behavior { - NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document), - _ => drag_deepest_manipulation(responses, selected, tool_data, document), + NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document, false), + _ => drag_deepest_manipulation(responses, selected, tool_data, document, false), } tool_data.get_snap_candidates(document, input); @@ -1309,12 +1309,19 @@ impl Fsm for SelectToolFsmState { } else if let Some(selecting_layer) = tool_data.select_single_layer.take() { // Previously, we may have had many layers selected. If the user clicks without dragging, we should just select the one layer that has been clicked. if !has_dragged { - if selecting_layer == LayerNodeIdentifier::ROOT_PARENT { - log::error!("selecting_layer should not be ROOT_PARENT"); - } else { - responses.add(NodeGraphMessage::SelectedNodesSet { - nodes: vec![selecting_layer.to_node()], - }); + let intersection_list = document.click_list(input).collect::>(); + let intersection = document.find_deepest(&intersection_list); + if let Some(intersection) = intersection { + tool_data.layer_selected_on_start = Some(intersection); + let selected = intersection_list; + + match tool_data.nested_selection_behavior { + NestedSelectionBehavior::Shallowest => drag_shallowest_manipulation(responses, selected, tool_data, document, true), + _ => drag_deepest_manipulation(responses, selected, tool_data, document, true), + } + tool_data.get_snap_candidates(document, input); + + responses.add(DocumentMessage::StartTransaction); } } } @@ -1591,7 +1598,7 @@ fn not_artboard(document: &DocumentMessageHandler) -> impl Fn(&LayerNodeIdentifi |&layer| layer != LayerNodeIdentifier::ROOT_PARENT && !document.network_interface.is_artboard(&layer.to_node(), &[]) } -fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) { +fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler, remove: bool) { if selected.is_empty() { return; } @@ -1626,13 +1633,17 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec } else { direct_children_of_lca .iter() - .find(|&&child| clicked_layer == child || clicked_layer.ancestors(metadata).any(|ancestor| ancestor == child)).copied() + .find(|&&child| clicked_layer == child || clicked_layer.ancestors(metadata).any(|ancestor| ancestor == child)) + .copied() } }) }); let new_selected = final_selection.unwrap_or_else(|| clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)); tool_data.layers_dragging.extend(vec![new_selected]); + if remove { + tool_data.layers_dragging.retain(|&selected_layer| clicked_layer != selected_layer); + } responses.add(NodeGraphMessage::SelectedNodesSet { nodes: tool_data @@ -1650,15 +1661,18 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec }); } -fn drag_deepest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) { - tool_data.layers_dragging.append(&mut vec![ - document.find_deepest(&selected).unwrap_or( - LayerNodeIdentifier::ROOT_PARENT - .children(document.metadata()) - .next() - .expect("ROOT_PARENT should have a layer child when clicking"), - ), - ]); +fn drag_deepest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler, remove: bool) { + let layer = document.find_deepest(&selected).unwrap_or( + LayerNodeIdentifier::ROOT_PARENT + .children(document.metadata()) + .next() + .expect("ROOT_PARENT should have a layer child when clicking"), + ); + if !remove { + tool_data.layers_dragging.extend(vec![layer]); + } else { + tool_data.layers_dragging.retain(|&selected_layer| layer != selected_layer); + } responses.add(NodeGraphMessage::SelectedNodesSet { nodes: tool_data .layers_dragging From 72f1e6a3a399c28af51d7a1e5a4149028f3b9b18 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 16:46:59 +0530 Subject: [PATCH 04/14] cleanup --- editor/src/messages/tool/tool_messages/select_tool.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index af71271c35..7ef7ba1e73 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -29,7 +29,6 @@ use graph_craft::document::NodeId; use graphene_core::renderer::Quad; use graphene_std::renderer::Rect; use graphene_std::vector::misc::BooleanOperation; -use std::collections::HashSet; use std::fmt; #[derive(Default)] @@ -1306,7 +1305,7 @@ impl Fsm for SelectToolFsmState { .collect(), }); } - } else if let Some(selecting_layer) = tool_data.select_single_layer.take() { + } else if tool_data.select_single_layer.take().is_some() { // Previously, we may have had many layers selected. If the user clicks without dragging, we should just select the one layer that has been clicked. if !has_dragged { let intersection_list = document.click_list(input).collect::>(); From 0900df74a2088a3005f63359badc7088a53df81a Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 16:53:02 +0530 Subject: [PATCH 05/14] one more cleanup --- editor/src/messages/tool/tool_messages/select_tool.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 7ef7ba1e73..264e2a9e90 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1627,14 +1627,12 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec }) .and_then(|lca| { let direct_children_of_lca: Vec<_> = lca.children(metadata).collect(); - if clicked_layer == lca { - Some(lca) - } else { + (clicked_layer == lca).then_some(lca).or_else(|| { direct_children_of_lca .iter() .find(|&&child| clicked_layer == child || clicked_layer.ancestors(metadata).any(|ancestor| ancestor == child)) .copied() - } + }) }) }); From 5c1f5f3e8d945e0a397cf009e81f4980d70a1bef Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 17:17:21 +0530 Subject: [PATCH 06/14] final(?) fix --- editor/src/messages/tool/tool_messages/select_tool.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 264e2a9e90..e1245f0136 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1609,11 +1609,11 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec .expect("ROOT_PARENT should have at least one layer when clicking") }); - let selected_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); let metadata = document.metadata(); + let selected_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); let final_selection: Option = (!selected_layers.is_empty() && selected_layers != vec![LayerNodeIdentifier::ROOT_PARENT]).then_some(()).and_then(|_| { - let mut relevant_layers = selected_layers; + let mut relevant_layers = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); if !relevant_layers.contains(&clicked_layer) { relevant_layers.push(clicked_layer); } @@ -1636,6 +1636,10 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec }) }); + if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| selected.children(metadata).any(|child| child == layer))) { + return; + }; + let new_selected = final_selection.unwrap_or_else(|| clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)); tool_data.layers_dragging.extend(vec![new_selected]); if remove { From b6ec7f07a3dc8ec6889387d7c418fb866f14a07f Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 18:54:56 +0530 Subject: [PATCH 07/14] some cleanup --- .../utility_types/document_metadata.rs | 10 ++++++++++ .../tool/tool_messages/select_tool.rs | 20 +++++++------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index 73b4348c38..a209235e4f 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -266,6 +266,16 @@ impl LayerNodeIdentifier { self.first_child(metadata).is_some() } + /// Is the layer a child of given layer + pub fn is_child_of(self, metadata: &DocumentMetadata, parent: &LayerNodeIdentifier) -> bool { + parent.children(metadata).any(|child| child == self) + } + + /// Is the layer an ancestor of given layer + pub fn is_ancestor_of(self, metadata: &DocumentMetadata, child: &LayerNodeIdentifier) -> bool { + child.ancestors(metadata).any(|ancestor| ancestor == self) + } + /// Iterator over all direct children (excluding self and recursive children) pub fn children(self, metadata: &DocumentMetadata) -> AxisIter { AxisIter { diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index e1245f0136..b62b5c8ca0 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1620,28 +1620,22 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec clicked_layer .ancestors(metadata) .filter(not_artboard(document)) - .find(|&potential_lca| { - relevant_layers - .iter() - .all(|layer| *layer == potential_lca || layer.ancestors(metadata).any(|ancestor| ancestor == potential_lca)) - }) + .find(|&potential_lca| relevant_layers.iter().all(|layer| *layer == potential_lca || potential_lca.is_ancestor_of(metadata, layer))) .and_then(|lca| { - let direct_children_of_lca: Vec<_> = lca.children(metadata).collect(); - (clicked_layer == lca).then_some(lca).or_else(|| { - direct_children_of_lca - .iter() - .find(|&&child| clicked_layer == child || clicked_layer.ancestors(metadata).any(|ancestor| ancestor == child)) - .copied() - }) + let lca_children: Vec<_> = lca.children(metadata).collect(); + (clicked_layer == lca) + .then_some(lca) + .or_else(|| lca_children.iter().find(|&&child| clicked_layer == child || child.is_ancestor_of(metadata, &clicked_layer)).copied()) }) }); - if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| selected.children(metadata).any(|child| child == layer))) { + if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| layer.is_child_of(metadata, selected))) { return; }; let new_selected = final_selection.unwrap_or_else(|| clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)); tool_data.layers_dragging.extend(vec![new_selected]); + tool_data.layers_dragging.retain(|&selected_layer| !selected_layer.is_child_of(metadata, &new_selected)); if remove { tool_data.layers_dragging.retain(|&selected_layer| clicked_layer != selected_layer); } From c01c7632fc4f92758b9d22b57a587de7e68bb7ab Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 19:15:16 +0530 Subject: [PATCH 08/14] more stuff --- .../tool/tool_messages/select_tool.rs | 74 +++++++++++++++---- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index b62b5c8ca0..156d107d94 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -287,11 +287,24 @@ impl ToolTransition for SelectTool { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum SelectToolFsmState { - Ready { selection: NestedSelectionBehavior }, - Drawing { selection_shape: SelectionShapeType, has_drawn: bool }, - Dragging { axis: Axis, using_compass: bool, has_dragged: bool }, + Ready { + selection: NestedSelectionBehavior, + }, + Drawing { + selection_shape: SelectionShapeType, + has_drawn: bool, + }, + Dragging { + axis: Axis, + using_compass: bool, + has_dragged: bool, + deepest: bool, + remove: bool, + }, ResizingBounds, - SkewingBounds { skew: Key }, + SkewingBounds { + skew: Key, + }, RotatingBounds, DraggingPivot, } @@ -917,7 +930,7 @@ impl Fsm for SelectToolFsmState { let axis_state = compass_rose_state.axis_type().filter(|_| can_grab_compass_rose); (axis_state.unwrap_or_default(), axis_state.is_some()) }; - SelectToolFsmState::Dragging { axis, using_compass, has_dragged: false } + SelectToolFsmState::Dragging { axis, using_compass, has_dragged: false, deepest: input.keyboard.key(select_deepest), remove: input.keyboard.key(extend_selection)} } // Dragging near the transform cage bounding box to rotate it else if rotating_bounds { @@ -969,7 +982,7 @@ impl Fsm for SelectToolFsmState { tool_data.get_snap_candidates(document, input); responses.add(DocumentMessage::StartTransaction); - SelectToolFsmState::Dragging { axis: Axis::None, using_compass: false, has_dragged: false } + SelectToolFsmState::Dragging { axis: Axis::None, using_compass: false, has_dragged: false, deepest: input.keyboard.key(select_deepest), remove: input.keyboard.key(extend_selection)} } else { let selection_shape = if input.keyboard.key(lasso_select) { SelectionShapeType::Lasso } else { SelectionShapeType::Box }; SelectToolFsmState::Drawing { selection_shape, has_drawn: false } @@ -985,7 +998,16 @@ impl Fsm for SelectToolFsmState { let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } } - (SelectToolFsmState::Dragging { axis, using_compass, has_dragged }, SelectToolMessage::PointerMove(modifier_keys)) => { + ( + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged, + deepest, + remove, + }, + SelectToolMessage::PointerMove(modifier_keys), + ) => { if !has_dragged { responses.add(ToolMessage::UpdateHints); } @@ -1038,6 +1060,8 @@ impl Fsm for SelectToolFsmState { axis, using_compass, has_dragged: true, + deepest, + remove, } } (SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerMove(modifier_keys)) => { @@ -1226,14 +1250,29 @@ impl Fsm for SelectToolFsmState { let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } } - (SelectToolFsmState::Dragging { axis, using_compass, has_dragged }, SelectToolMessage::PointerOutsideViewport(_)) => { + ( + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged, + deepest, + remove, + }, + SelectToolMessage::PointerOutsideViewport(_), + ) => { // AutoPanning if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { tool_data.drag_current += shift; tool_data.drag_start += shift; } - SelectToolFsmState::Dragging { axis, using_compass, has_dragged } + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged, + deepest, + remove, + } } (SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport(_)) => { // AutoPanning @@ -1270,7 +1309,7 @@ impl Fsm for SelectToolFsmState { state } - (SelectToolFsmState::Dragging { has_dragged, .. }, SelectToolMessage::DragStop { remove_from_selection }) => { + (SelectToolFsmState::Dragging { has_dragged, remove, deepest, .. }, SelectToolMessage::DragStop { remove_from_selection }) => { // Deselect layer if not snap dragging responses.add(DocumentMessage::EndTransaction); tool_data.axis_align = false; @@ -1315,8 +1354,17 @@ impl Fsm for SelectToolFsmState { let selected = intersection_list; match tool_data.nested_selection_behavior { - NestedSelectionBehavior::Shallowest => drag_shallowest_manipulation(responses, selected, tool_data, document, true), - _ => drag_deepest_manipulation(responses, selected, tool_data, document, true), + NestedSelectionBehavior::Shallowest if remove && !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, true), + NestedSelectionBehavior::Deepest if remove => drag_deepest_manipulation(responses, selected, tool_data, document, true), + _ => { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + if tool_data.nested_selection_behavior == NestedSelectionBehavior::Shallowest && !deepest { + drag_shallowest_manipulation(responses, selected, tool_data, document, false) + } else { + drag_deepest_manipulation(responses, selected, tool_data, document, false) + } + } } tool_data.get_snap_candidates(document, input); @@ -1534,7 +1582,7 @@ impl Fsm for SelectToolFsmState { ]); responses.add(FrontendMessage::UpdateInputHints { hint_data }); } - SelectToolFsmState::Dragging { axis, using_compass, has_dragged } if *has_dragged => { + SelectToolFsmState::Dragging { axis, using_compass, has_dragged, .. } if *has_dragged => { let mut hint_data = vec![ HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]), HintGroup(vec![ From 74122badfbf83031021784ab37f23ea66a43f956 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 23 Apr 2025 20:43:31 +0530 Subject: [PATCH 09/14] make shallow the default --- editor/src/messages/tool/tool_messages/select_tool.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 156d107d94..0220cb88da 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -51,8 +51,8 @@ pub enum SelectOptionsUpdate { #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum NestedSelectionBehavior { #[default] - Deepest, Shallowest, + Deepest, } impl fmt::Display for NestedSelectionBehavior { @@ -114,7 +114,7 @@ impl ToolMetadata for SelectTool { impl SelectTool { fn deep_selection_widget(&self) -> WidgetHolder { - let layer_selection_behavior_entries = [NestedSelectionBehavior::Deepest, NestedSelectionBehavior::Shallowest] + let layer_selection_behavior_entries = [NestedSelectionBehavior::Shallowest, NestedSelectionBehavior::Deepest] .iter() .map(|mode| { MenuListEntry::new(format!("{mode:?}")) @@ -124,7 +124,7 @@ impl SelectTool { .collect(); DropdownInput::new(vec![layer_selection_behavior_entries]) - .selected_index(Some((self.tool_data.nested_selection_behavior == NestedSelectionBehavior::Shallowest) as u32)) + .selected_index(Some((self.tool_data.nested_selection_behavior == NestedSelectionBehavior::Deepest) as u32)) .tooltip("Choose if clicking nested layers directly selects the deepest, or selects the shallowest and deepens by double clicking") .widget_holder() } From f84f504aab7dd524f2598100b21957b353233812 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 24 Apr 2025 13:06:37 +0530 Subject: [PATCH 10/14] fixes --- .../tool/tool_messages/select_tool.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 0220cb88da..bae92976c3 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -976,7 +976,7 @@ impl Fsm for SelectToolFsmState { selected = intersection_list; match tool_data.nested_selection_behavior { - NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document, false), + NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document, false, false), _ => drag_deepest_manipulation(responses, selected, tool_data, document, false), } tool_data.get_snap_candidates(document, input); @@ -1352,18 +1352,14 @@ impl Fsm for SelectToolFsmState { if let Some(intersection) = intersection { tool_data.layer_selected_on_start = Some(intersection); let selected = intersection_list; - match tool_data.nested_selection_behavior { - NestedSelectionBehavior::Shallowest if remove && !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, true), + NestedSelectionBehavior::Shallowest if remove && !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, true, false), NestedSelectionBehavior::Deepest if remove => drag_deepest_manipulation(responses, selected, tool_data, document, true), + NestedSelectionBehavior::Shallowest if !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, false, true), _ => { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); - if tool_data.nested_selection_behavior == NestedSelectionBehavior::Shallowest && !deepest { - drag_shallowest_manipulation(responses, selected, tool_data, document, false) - } else { - drag_deepest_manipulation(responses, selected, tool_data, document, false) - } + drag_deepest_manipulation(responses, selected, tool_data, document, false) } } tool_data.get_snap_candidates(document, input); @@ -1645,7 +1641,7 @@ fn not_artboard(document: &DocumentMessageHandler) -> impl Fn(&LayerNodeIdentifi |&layer| layer != LayerNodeIdentifier::ROOT_PARENT && !document.network_interface.is_artboard(&layer.to_node(), &[]) } -fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler, remove: bool) { +fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler, remove: bool, exists: bool) { if selected.is_empty() { return; } @@ -1668,18 +1664,22 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec clicked_layer .ancestors(metadata) .filter(not_artboard(document)) - .find(|&potential_lca| relevant_layers.iter().all(|layer| *layer == potential_lca || potential_lca.is_ancestor_of(metadata, layer))) - .and_then(|lca| { - let lca_children: Vec<_> = lca.children(metadata).collect(); - (clicked_layer == lca) - .then_some(lca) - .or_else(|| lca_children.iter().find(|&&child| clicked_layer == child || child.is_ancestor_of(metadata, &clicked_layer)).copied()) + .find(|&ancestor| relevant_layers.iter().all(|layer| *layer == ancestor || ancestor.is_ancestor_of(metadata, layer))) + .and_then(|least_common_ancestor| { + let common_siblings: Vec<_> = least_common_ancestor.children(metadata).collect(); + (clicked_layer == least_common_ancestor) + .then_some(least_common_ancestor) + .or_else(|| common_siblings.iter().find(|&&child| clicked_layer == child || child.is_ancestor_of(metadata, &clicked_layer)).copied()) }) }); if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| layer.is_child_of(metadata, selected))) { return; - }; + } + if !exists { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + } let new_selected = final_selection.unwrap_or_else(|| clicked_layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(clicked_layer)); tool_data.layers_dragging.extend(vec![new_selected]); From 442754b48c40b09e0c93b3e143de2b53c830cfff Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 24 Apr 2025 16:47:10 +0530 Subject: [PATCH 11/14] fix --- .../messages/portfolio/document/overlays/utility_types.rs | 7 ++----- editor/src/messages/tool/tool_messages/select_tool.rs | 5 +++-- .../transform_layer/transform_layer_message_handler.rs | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 2ddb8169db..25e8a32b77 100644 --- a/editor/src/messages/portfolio/document/overlays/utility_types.rs +++ b/editor/src/messages/portfolio/document/overlays/utility_types.rs @@ -310,13 +310,10 @@ impl OverlayContext { } pub fn draw_angle(&mut self, pivot: DVec2, radius: f64, arc_radius: f64, offset_angle: f64, angle: f64) { - let color_line = COLOR_OVERLAY_BLUE; - let end_point1 = pivot + radius * DVec2::from_angle(angle + offset_angle); let end_point2 = pivot + radius * DVec2::from_angle(offset_angle); - self.line(pivot, end_point1, Some(color_line), None); - self.line(pivot, end_point2, Some(color_line), None); - + self.line(pivot, end_point1, None, None); + self.dashed_line(pivot, end_point2, None, None, Some(2.), Some(2.), Some(0.5)); self.draw_arc(pivot, arc_radius, offset_angle, (angle) % TAU + offset_angle); } diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 9bb3b5ea85..a9700fbdda 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -966,7 +966,8 @@ impl Fsm for SelectToolFsmState { // Dragging a selection box else { tool_data.layers_dragging = selected; - if !input.keyboard.key(extend_selection) && !input.keyboard.key(remove_from_selection) { + let extend = input.keyboard.key(extend_selection); + if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); } @@ -976,7 +977,7 @@ impl Fsm for SelectToolFsmState { selected = intersection_list; match tool_data.nested_selection_behavior { - NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document, false, false), + NestedSelectionBehavior::Shallowest if !input.keyboard.key(select_deepest) => drag_shallowest_manipulation(responses, selected, tool_data, document, false, extend), _ => drag_deepest_manipulation(responses, selected, tool_data, document, false), } tool_data.get_snap_candidates(document, input); diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 30f1c239e1..61c4b8dac6 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -274,7 +274,7 @@ impl MessageHandler> for TransformLayer let end_point = pivot + local_edge * scale.max(1.); if scale > 0. { - overlay_context.dashed_line(pivot, boundary_point, None, None, Some(4.), Some(4.), Some(0.5)); + overlay_context.dashed_line(pivot, boundary_point, None, None, Some(2.), Some(2.), Some(0.5)); } overlay_context.line(boundary_point, end_point, None, None); From ecd25d69457535a049eb61f0ab32b10f2a3ffb13 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 25 Apr 2025 03:15:23 +0530 Subject: [PATCH 12/14] fix --- editor/src/messages/tool/tool_messages/select_tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index a9700fbdda..ed2cb3afdf 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1677,7 +1677,7 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| layer.is_child_of(metadata, selected))) { return; } - if !exists { + if !exists && !remove { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); } From 317e278f7abdff24c6a0e777da4d886158f13529 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Fri, 25 Apr 2025 12:58:35 +0530 Subject: [PATCH 13/14] fix --- editor/src/messages/tool/tool_messages/select_tool.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index ed2cb3afdf..368db26beb 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -1354,7 +1354,7 @@ impl Fsm for SelectToolFsmState { tool_data.layer_selected_on_start = Some(intersection); let selected = intersection_list; match tool_data.nested_selection_behavior { - NestedSelectionBehavior::Shallowest if remove && !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, true, false), + NestedSelectionBehavior::Shallowest if remove && !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, true, true), NestedSelectionBehavior::Deepest if remove => drag_deepest_manipulation(responses, selected, tool_data, document, true), NestedSelectionBehavior::Shallowest if !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, false, true), _ => { @@ -1675,8 +1675,13 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec }); if final_selection.is_some_and(|layer| selected_layers.iter().any(|selected| layer.is_child_of(metadata, selected))) { + if exists && remove && selected_layers.len() == 1 { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + } return; } + if !exists && !remove { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); @@ -1687,6 +1692,9 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec tool_data.layers_dragging.retain(|&selected_layer| !selected_layer.is_child_of(metadata, &new_selected)); if remove { tool_data.layers_dragging.retain(|&selected_layer| clicked_layer != selected_layer); + if selected_layers.contains(&new_selected) { + tool_data.layers_dragging.retain(|&selected_layer| new_selected != selected_layer); + } } responses.add(NodeGraphMessage::SelectedNodesSet { From c7e01b5ee117422f12531e669d3b8ad2a351b98a Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Tue, 29 Apr 2025 20:17:28 -0700 Subject: [PATCH 14/14] Code review --- .../utility_types/document_metadata.rs | 6 ++-- .../tool/common_functionality/measure.rs | 1 + .../tool/tool_messages/artboard_tool.rs | 14 ++++----- .../tool/tool_messages/select_tool.rs | 31 ++++++++++--------- .../messages/tool/tool_messages/text_tool.rs | 4 +-- .../transform_layer_message_handler.rs | 9 +++--- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index a209235e4f..52509903c0 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -261,17 +261,17 @@ impl LayerNodeIdentifier { metadata.get_relations(self).and_then(|relations| relations.last_child) } - /// Does the layer have children? If so, then it is a folder + /// Does the layer have children? If so, then it is a folder. pub fn has_children(self, metadata: &DocumentMetadata) -> bool { self.first_child(metadata).is_some() } - /// Is the layer a child of given layer + /// Is the layer a child of the given layer? pub fn is_child_of(self, metadata: &DocumentMetadata, parent: &LayerNodeIdentifier) -> bool { parent.children(metadata).any(|child| child == self) } - /// Is the layer an ancestor of given layer + /// Is the layer an ancestor of the given layer? pub fn is_ancestor_of(self, metadata: &DocumentMetadata, child: &LayerNodeIdentifier) -> bool { child.ancestors(metadata).any(|ancestor| ancestor == self) } diff --git a/editor/src/messages/tool/common_functionality/measure.rs b/editor/src/messages/tool/common_functionality/measure.rs index 28e3de719b..5a76a5bd22 100644 --- a/editor/src/messages/tool/common_functionality/measure.rs +++ b/editor/src/messages/tool/common_functionality/measure.rs @@ -10,6 +10,7 @@ fn draw_dashed_line(line_start: DVec2, line_end: DVec2, transform: DAffine2, ove overlay_context.dashed_line(min_viewport, max_viewport, None, None, Some(2.), Some(2.), Some(0.5)); } + /// Draws a solid line with a length annotation between two points transformed by the given affine transformations. fn draw_line_with_length(line_start: DVec2, line_end: DVec2, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext, label_alignment: LabelAlignment) { let transform_to_document = document_to_viewport.inverse() * transform; diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index 6e67fa6823..0c9b0f7fb9 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -267,7 +267,7 @@ impl Fsm for ArtboardToolFsmState { let constrain_square = input.keyboard.get(constrain_axis_or_aspect as usize); tool_data.resize_artboard(responses, document, input, from_center, constrain_square); - // AutoPanning + // Auto-panning let messages = [ ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), @@ -306,7 +306,7 @@ impl Fsm for ArtboardToolFsmState { bounds.bounds[0] = position.round(); bounds.bounds[1] = position.round() + size.round(); - // AutoPanning + // Auto-panning let messages = [ ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), @@ -345,7 +345,7 @@ impl Fsm for ArtboardToolFsmState { }) } - // AutoPanning + // Auto-panning let messages = [ ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), @@ -377,25 +377,25 @@ impl Fsm for ArtboardToolFsmState { ArtboardToolFsmState::Ready { hovered } } (ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerOutsideViewport { .. }) => { - // AutoPanning + // Auto-panning let _ = tool_data.auto_panning.shift_viewport(input, responses); ArtboardToolFsmState::ResizingBounds } (ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerOutsideViewport { .. }) => { - // AutoPanning + // Auto-panning tool_data.auto_panning.shift_viewport(input, responses); ArtboardToolFsmState::Dragging } (ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerOutsideViewport { .. }) => { - // AutoPanning + // Auto-panning tool_data.auto_panning.shift_viewport(input, responses); ArtboardToolFsmState::Drawing } (state, ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }) => { - // AutoPanning + // Auto-panning let messages = [ ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(), ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(), diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index c80716512d..a6f6eb63e2 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -931,7 +931,7 @@ impl Fsm for SelectToolFsmState { let axis_state = compass_rose_state.axis_type().filter(|_| can_grab_compass_rose); (axis_state.unwrap_or_default(), axis_state.is_some()) }; - SelectToolFsmState::Dragging { axis, using_compass, has_dragged: false, deepest: input.keyboard.key(select_deepest), remove: input.keyboard.key(extend_selection)} + SelectToolFsmState::Dragging { axis, using_compass, has_dragged: false, deepest: input.keyboard.key(select_deepest), remove: input.keyboard.key(extend_selection) } } // Dragging near the transform cage bounding box to rotate it else if rotating_bounds { @@ -967,7 +967,7 @@ impl Fsm for SelectToolFsmState { // Dragging a selection box else { tool_data.layers_dragging = selected; - let extend = input.keyboard.key(extend_selection); + let extend = input.keyboard.key(extend_selection); if !extend && !input.keyboard.key(remove_from_selection) { responses.add(DocumentMessage::DeselectAllLayers); tool_data.layers_dragging.clear(); @@ -984,7 +984,7 @@ impl Fsm for SelectToolFsmState { tool_data.get_snap_candidates(document, input); responses.add(DocumentMessage::StartTransaction); - SelectToolFsmState::Dragging { axis: Axis::None, using_compass: false, has_dragged: false, deepest: input.keyboard.key(select_deepest), remove: input.keyboard.key(extend_selection)} + SelectToolFsmState::Dragging { axis: Axis::None, using_compass: false, has_dragged: false, deepest: input.keyboard.key(select_deepest), remove: input.keyboard.key(extend_selection) } } else { let selection_shape = if input.keyboard.key(lasso_select) { SelectionShapeType::Lasso } else { SelectionShapeType::Box }; SelectToolFsmState::Drawing { selection_shape, has_drawn: false } @@ -1051,7 +1051,7 @@ impl Fsm for SelectToolFsmState { } tool_data.drag_current += mouse_delta; - // AutoPanning + // Auto-panning let messages = [ SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), SelectToolMessage::PointerMove(modifier_keys).into(), @@ -1105,7 +1105,7 @@ impl Fsm for SelectToolFsmState { selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse(), None); - // AutoPanning + // Auto-panning let messages = [ SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), SelectToolMessage::PointerMove(modifier_keys).into(), @@ -1194,7 +1194,7 @@ impl Fsm for SelectToolFsmState { let snapped_mouse_position = mouse_position; tool_data.pivot.set_viewport_position(snapped_mouse_position, document, responses); - // AutoPanning + // Auto-panning let messages = [ SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), SelectToolMessage::PointerMove(modifier_keys).into(), @@ -1215,7 +1215,7 @@ impl Fsm for SelectToolFsmState { extend_lasso(&mut tool_data.lasso_polygon, tool_data.drag_current); } - // AutoPanning + // Auto-panning let messages = [ SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), SelectToolMessage::PointerMove(modifier_keys).into(), @@ -1262,7 +1262,7 @@ impl Fsm for SelectToolFsmState { }, SelectToolMessage::PointerOutsideViewport(_), ) => { - // AutoPanning + // Auto-panning if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { tool_data.drag_current += shift; tool_data.drag_start += shift; @@ -1277,7 +1277,7 @@ impl Fsm for SelectToolFsmState { } } (SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport(_)) => { - // AutoPanning + // Auto-panning if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { if let Some(bounds) = &mut tool_data.bounding_box_manager { bounds.center_of_transformation += shift; @@ -1288,13 +1288,13 @@ impl Fsm for SelectToolFsmState { self } (SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerOutsideViewport(_)) => { - // AutoPanning + // Auto-panning let _ = tool_data.auto_panning.shift_viewport(input, responses); self } (SelectToolFsmState::Drawing { .. }, SelectToolMessage::PointerOutsideViewport(_)) => { - // AutoPanning + // Auto-panning if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { tool_data.drag_start += shift; } @@ -1302,7 +1302,7 @@ impl Fsm for SelectToolFsmState { self } (state, SelectToolMessage::PointerOutsideViewport(modifier_keys)) => { - // AutoPanning + // Auto-panning let messages = [ SelectToolMessage::PointerOutsideViewport(modifier_keys.clone()).into(), SelectToolMessage::PointerMove(modifier_keys).into(), @@ -1349,11 +1349,11 @@ impl Fsm for SelectToolFsmState { } else if tool_data.select_single_layer.take().is_some() { // Previously, we may have had many layers selected. If the user clicks without dragging, we should just select the one layer that has been clicked. if !has_dragged { - let intersection_list = document.click_list(input).collect::>(); - let intersection = document.find_deepest(&intersection_list); + let selected = document.click_list(input).collect::>(); + let intersection = document.find_deepest(&selected); if let Some(intersection) = intersection { tool_data.layer_selected_on_start = Some(intersection); - let selected = intersection_list; + match tool_data.nested_selection_behavior { NestedSelectionBehavior::Shallowest if remove && !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, true, true), NestedSelectionBehavior::Deepest if remove => drag_deepest_manipulation(responses, selected, tool_data, document, true), @@ -1364,6 +1364,7 @@ impl Fsm for SelectToolFsmState { drag_deepest_manipulation(responses, selected, tool_data, document, false) } } + tool_data.get_snap_candidates(document, input); responses.add(DocumentMessage::StartTransaction); diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 9e144ae6dc..a503fbae8f 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -702,7 +702,7 @@ impl Fsm for TextToolFsmState { }); responses.add(NodeGraphMessage::RunDocumentGraph); - // AutoPanning + // Auto-panning let messages = [ TextToolMessage::PointerOutsideViewport { center, lock_ratio }.into(), TextToolMessage::PointerMove { center, lock_ratio }.into(), @@ -725,7 +725,7 @@ impl Fsm for TextToolFsmState { TextToolFsmState::Placing } (TextToolFsmState::ResizingBounds | TextToolFsmState::Dragging, TextToolMessage::PointerOutsideViewport { .. }) => { - // AutoPanning + // Auto-panning if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) { if let Some(bounds) = &mut tool_data.bounding_box_manager { bounds.center_of_transformation += shift; diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 639c5a61cf..e8487ce7fb 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -242,7 +242,7 @@ impl MessageHandler> for TransformLayer if matches!(axis_constraint, Axis::Both | Axis::X) && translation.x != 0. { let end = if self.local { (quad[1] - quad[0]).rotate(e1) + quad[0] } else { quad[1] }; - overlay_context.line(quad[0], end, None, None); + overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); let x_transform = DAffine2::from_translation((quad[0] + end) / 2.); overlay_context.text(&format_rounded(translation.x, 3), COLOR_OVERLAY_BLUE, None, x_transform, 4., [Pivot::Middle, Pivot::End]); @@ -250,7 +250,7 @@ impl MessageHandler> for TransformLayer if matches!(axis_constraint, Axis::Both | Axis::Y) && translation.y != 0. { let end = if self.local { (quad[3] - quad[0]).rotate(e1) + quad[0] } else { quad[3] }; - overlay_context.line(quad[0], end, None, None); + overlay_context.dashed_line(quad[0], end, None, None, Some(2.), Some(2.), Some(0.5)); let x_parameter = viewport_translate.x.clamp(-1., 1.); let y_transform = DAffine2::from_translation((quad[0] + end) / 2. + x_parameter * DVec2::X * 0.); let pivot_selection = if x_parameter >= -1e-3 { Pivot::Start } else { Pivot::End }; @@ -258,9 +258,10 @@ impl MessageHandler> for TransformLayer overlay_context.text(&format_rounded(translation.y, 2), COLOR_OVERLAY_BLUE, None, y_transform, 3., [pivot_selection, Pivot::Middle]); } } + if matches!(axis_constraint, Axis::Both) && translation.x != 0. && translation.y != 0. { - overlay_context.dashed_line(quad[1], quad[2], None, None, Some(2.), Some(2.), Some(0.5)); - overlay_context.dashed_line(quad[3], quad[2], None, None, Some(2.), Some(2.), Some(0.5)); + overlay_context.line(quad[1], quad[2], None, None); + overlay_context.line(quad[3], quad[2], None, None); } } TransformOperation::Scaling(scale) => {