From ca70fd8380b0180d72bd7dd9c61f2ea187ed36bf Mon Sep 17 00:00:00 2001 From: Trevor Paley <10186337+TheUnlocked@users.noreply.github.com> Date: Sun, 12 Oct 2025 11:14:02 -0700 Subject: [PATCH] Add quick measurement between objects and artboards (#3274) --- .../portfolio/document/document_message_handler.rs | 14 ++++++++++++++ .../src/messages/tool/tool_messages/select_tool.rs | 7 ++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index c25c6f5a..27a2d5c3 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1759,6 +1759,20 @@ impl DocumentMessageHandler { }) } + /// Find layers (including artboards) under the location in viewport space that was clicked, listed by their depth in the layer tree hierarchy. + pub fn click_list_with_artboards<'a>(&'a self, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'a> { + self.click_xray(ipp) + .skip_while(|&layer| layer == LayerNodeIdentifier::ROOT_PARENT) + .scan(true, |last_had_children, layer| { + if *last_had_children { + *last_had_children = layer.has_children(self.network_interface.document_metadata()); + Some(layer) + } else { + None + } + }) + } + pub fn click_list_no_parents<'a>(&'a self, ipp: &InputPreprocessorMessageHandler) -> impl Iterator + use<'a> { self.click_xray(ipp) .filter(move |&layer| !self.network_interface.is_artboard(&layer.to_node(), &[]) && !layer.has_children(self.network_interface.document_metadata())) diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index c61a5501..e5ab5edb 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -660,10 +660,11 @@ impl Fsm for SelectToolFsmState { // TODO: Don't use `Key::MouseMiddle` directly, instead take it as a variable from the input mappings list like in all other places; or find a better way than checking the key state if !matches!(self, Self::Drawing { .. }) && !input.keyboard.get(Key::MouseMiddle as usize) { // Get the layer the user is hovering over - let click = document.click(input); + // Artboards are included since they're needed for quick measurement, but will be filtered out for selection later on + let click = document.click_list_with_artboards(input).last(); let not_selected_click = click.filter(|&hovered_layer| !document.network_interface.selected_nodes().selected_layers_contains(hovered_layer, document.metadata())); if let Some(layer) = not_selected_click { - if overlay_context.visibility_settings.hover_outline() { + if overlay_context.visibility_settings.hover_outline() && !document.network_interface.is_artboard(&layer.to_node(), &[]) { let layer_to_viewport = document.metadata().transform_to_viewport(layer); let mut hover_overlay_draw = |layer: LayerNodeIdentifier, color: Option<&str>| { if layer.has_children(document.metadata()) { @@ -707,7 +708,7 @@ impl Fsm for SelectToolFsmState { .network_interface .selected_nodes() .selected_visible_and_unlocked_layers(&document.network_interface) - // Exclude layers that are artboards + // Exclude layers that are artboards from the selection bounding box .filter(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[])) // For each remaining layer, try to get its document-space bounding box and convert it to a Rect .filter_map(|layer| document.metadata().bounding_box_document(layer).map(Rect::from_box))