From 90be1f42c601f15ca14b9d763d141f0aafc9a1fb Mon Sep 17 00:00:00 2001 From: mTvare Date: Wed, 30 Apr 2025 08:54:48 +0530 Subject: [PATCH] Fix 'Shallow Select' mode behavior for selection context transference (#2604) * Fix ancestor always returning None during shallow select * Fixes * fix shift remove on both * cleanup * one more cleanup * final(?) fix * some cleanup * more stuff * make shallow the default * fixes * fix * fix * fix * Code review --------- Co-authored-by: Keavon Chambers --- .../document/overlays/utility_types.rs | 7 +- .../utility_types/document_metadata.rs | 12 +- .../tool/common_functionality/measure.rs | 1 + .../tool/tool_messages/artboard_tool.rs | 14 +- .../tool/tool_messages/select_tool.rs | 201 +++++++++++++----- .../messages/tool/tool_messages/text_tool.rs | 4 +- .../transform_layer_message_handler.rs | 11 +- 7 files changed, 179 insertions(+), 71 deletions(-) diff --git a/editor/src/messages/portfolio/document/overlays/utility_types.rs b/editor/src/messages/portfolio/document/overlays/utility_types.rs index 2ddb8169..25e8a32b 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/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index 73b4348c..52509903 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -261,11 +261,21 @@ 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 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 the 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/common_functionality/measure.rs b/editor/src/messages/tool/common_functionality/measure.rs index 28e3de71..5a76a5bd 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 6e67fa68..0c9b0f7f 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 f99a0b63..a6f6eb63 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -52,8 +52,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 { @@ -115,7 +115,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:?}")) @@ -125,7 +125,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() } @@ -288,11 +288,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, } @@ -918,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 } + 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 { @@ -954,7 +967,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(); } @@ -964,13 +978,13 @@ 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, extend), + _ => drag_deepest_manipulation(responses, selected, tool_data, document, false), } 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 } @@ -986,7 +1000,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); } @@ -1028,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(), @@ -1039,6 +1062,8 @@ impl Fsm for SelectToolFsmState { axis, using_compass, has_dragged: true, + deepest, + remove, } } (SelectToolFsmState::ResizingBounds, SelectToolMessage::PointerMove(modifier_keys)) => { @@ -1080,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(), @@ -1169,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(), @@ -1190,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(), @@ -1227,17 +1252,32 @@ impl Fsm for SelectToolFsmState { let selection = tool_data.nested_selection_behavior; SelectToolFsmState::Ready { selection } } - (SelectToolFsmState::Dragging { axis, using_compass, has_dragged }, SelectToolMessage::PointerOutsideViewport(_)) => { - // AutoPanning + ( + SelectToolFsmState::Dragging { + axis, + using_compass, + has_dragged, + deepest, + remove, + }, + SelectToolMessage::PointerOutsideViewport(_), + ) => { + // Auto-panning 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 + // 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; @@ -1248,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; } @@ -1262,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(), @@ -1271,7 +1311,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; @@ -1306,15 +1346,28 @@ 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 { - 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 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); + + 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), + NestedSelectionBehavior::Shallowest if !deepest => drag_shallowest_manipulation(responses, selected, tool_data, document, false, true), + _ => { + responses.add(DocumentMessage::DeselectAllLayers); + tool_data.layers_dragging.clear(); + drag_deepest_manipulation(responses, selected, tool_data, document, false) + } + } + + tool_data.get_snap_candidates(document, input); + + responses.add(DocumentMessage::StartTransaction); } } } @@ -1528,7 +1581,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![ @@ -1591,16 +1644,59 @@ 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) { - for layer in selected { - let ancestor = layer - .ancestors(document.metadata()) - .filter(not_artboard(document)) - .find(|&ancestor| document.network_interface.selected_nodes().selected_layers_contains(ancestor, document.metadata())); +fn drag_shallowest_manipulation(responses: &mut VecDeque, selected: Vec, tool_data: &mut SelectToolData, document: &DocumentMessageHandler, remove: bool, exists: bool) { + if selected.is_empty() { + return; + } - 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 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 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 = document.network_interface.selected_nodes().selected_layers(document.metadata()).collect::>(); + if !relevant_layers.contains(&clicked_layer) { + relevant_layers.push(clicked_layer); + } + clicked_layer + .ancestors(metadata) + .filter(not_artboard(document)) + .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))) { + 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(); + } + + 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); + if selected_layers.contains(&new_selected) { + tool_data.layers_dragging.retain(|&selected_layer| new_selected != selected_layer); + } } responses.add(NodeGraphMessage::SelectedNodesSet { @@ -1619,15 +1715,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 diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 9e144ae6..a503fbae 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 ec4b58fb..e8487ce7 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) => { @@ -274,7 +275,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);