From c79cf41c2899ac7bc212ff08354dadd683671528 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sun, 7 May 2023 01:30:16 -0700 Subject: [PATCH] Show outline for image frames on hover and when selected with frame tools --- .../common_functionality/overlay_renderer.rs | 4 +- .../tool/common_functionality/path_outline.rs | 55 +++++++++++-------- .../messages/tool/tool_messages/frame_tool.rs | 22 ++++++++ .../tool/tool_messages/imaginate_tool.rs | 22 ++++++++ node-graph/gcore/src/vector/subpath.rs | 2 +- .../interpreted-executor/src/node_registry.rs | 1 - 6 files changed, 78 insertions(+), 28 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/overlay_renderer.rs b/editor/src/messages/tool/common_functionality/overlay_renderer.rs index 7146a443..06001ded 100644 --- a/editor/src/messages/tool/common_functionality/overlay_renderer.rs +++ b/editor/src/messages/tool/common_functionality/overlay_renderer.rs @@ -56,13 +56,13 @@ impl OverlayRenderer { // Create an outline if we do not have a cached one if outline_cache.is_none() { - let outline_path = self.create_shape_outline_overlay(graphene_core::vector::Subpath::from_bezier_crate(&vector_data.subpaths), responses); + let outline_path = self.create_shape_outline_overlay(graphene_core::vector::Subpath::from_bezier_rs(&vector_data.subpaths), responses); self.shape_overlay_cache.insert(*layer_id, outline_path.clone()); Self::place_outline_overlays(outline_path.clone(), &transform, responses); trace!("Overlay: Creating new outline {:?}", &outline_path); } else if let Some(outline_path) = outline_cache { trace!("Overlay: Updating overlays for {:?} owning layer: {:?}", outline_path, layer_id); - Self::modify_outline_overlays(outline_path.clone(), graphene_core::vector::Subpath::from_bezier_crate(&vector_data.subpaths), responses); + Self::modify_outline_overlays(outline_path.clone(), graphene_core::vector::Subpath::from_bezier_rs(&vector_data.subpaths), responses); Self::place_outline_overlays(outline_path.clone(), &transform, responses); } diff --git a/editor/src/messages/tool/common_functionality/path_outline.rs b/editor/src/messages/tool/common_functionality/path_outline.rs index e25584db..f4355f88 100644 --- a/editor/src/messages/tool/common_functionality/path_outline.rs +++ b/editor/src/messages/tool/common_functionality/path_outline.rs @@ -30,50 +30,57 @@ impl PathOutline { // Get layer data let document_layer = document.document_legacy.layer(&document_layer_path).ok()?; - // TODO Purge this area of BezPath and Kurbo - // Get the bezpath from the shape or text + // Get the subpath from the shape let subpath = match &document_layer.data { LayerDataType::Shape(shape) => Some(shape.shape.clone()), - LayerDataType::Layer(layer) => layer.as_vector_data().map(|vector_data| Subpath::from_bezier_crate(&vector_data.subpaths)), + LayerDataType::Layer(layer) => { + if let Some(vector_data) = layer.as_vector_data() { + // Vector graph output + Some(Subpath::from_bezier_rs(&vector_data.subpaths)) + } else { + // Frame graph output + Some(Subpath::new_rect(DVec2::new(0., 0.), DVec2::new(1., 1.))) + } + } _ => document_layer.aabb_for_transform(DAffine2::IDENTITY, render_data).map(|[p1, p2]| Subpath::new_rect(p1, p2)), }?; // Generate a new overlay layer if necessary - let overlay = match overlay_path { - Some(path) => path, - None => { - let overlay_path = vec![generate_uuid()]; - let operation = Operation::AddShape { + let overlay = overlay_path.unwrap_or_else(|| { + let overlay_path = vec![generate_uuid()]; + + responses.add(DocumentMessage::Overlays( + (Operation::AddShape { path: overlay_path.clone(), subpath: Default::default(), style: style::PathStyle::new(Some(Stroke::new(Some(COLOR_ACCENT), PATH_OUTLINE_WEIGHT)), Fill::None), insert_index: -1, transform: DAffine2::IDENTITY.to_cols_array(), - }; + }) + .into(), + )); - responses.add(DocumentMessage::Overlays(operation.into())); + overlay_path + }); - overlay_path - } - }; - - // Update the shape bezpath - let operation = Operation::SetShapePath { path: overlay.clone(), subpath }; - responses.add(DocumentMessage::Overlays(operation.into())); + // Update the shape subpath + responses.add(DocumentMessage::Overlays((Operation::SetShapePath { path: overlay.clone(), subpath }).into())); // Update the transform to match the document - let operation = Operation::SetLayerTransform { - path: overlay.clone(), - transform: document.document_legacy.multiply_transforms(&document_layer_path).unwrap().to_cols_array(), - }; - responses.add(DocumentMessage::Overlays(operation.into())); + responses.add(DocumentMessage::Overlays( + (Operation::SetLayerTransform { + path: overlay.clone(), + transform: document.document_legacy.multiply_transforms(&document_layer_path).unwrap().to_cols_array(), + }) + .into(), + )); Some(overlay) } - /// Creates an outline of a layer either with a pre-existing overlay or by generating a new one + /// Creates an outline of a layer either with a pre-existing overlay or by generating a new one. /// - /// Creates an outline, discarding the overlay on failure + /// Creates an outline, discarding the overlay on failure. fn create_outline( document_layer_path: Vec, overlay_path: Option>, diff --git a/editor/src/messages/tool/tool_messages/frame_tool.rs b/editor/src/messages/tool/tool_messages/frame_tool.rs index acacbbcd..167e742a 100644 --- a/editor/src/messages/tool/tool_messages/frame_tool.rs +++ b/editor/src/messages/tool/tool_messages/frame_tool.rs @@ -3,6 +3,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMot use crate::messages::layout::utility_types::layout_widget::PropertyHolder; use crate::messages::portfolio::document::node_graph; use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::path_outline::PathOutline; use crate::messages::tool::common_functionality::resize::Resize; use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; @@ -25,6 +26,10 @@ pub enum FrameToolMessage { // Standard messages #[remain::unsorted] Abort, + #[remain::unsorted] + DocumentIsDirty, + #[remain::unsorted] + SelectionChanged, // Tool-specific messages DragStart, @@ -73,7 +78,9 @@ impl ToolMetadata for FrameTool { impl ToolTransition for FrameTool { fn event_to_message_map(&self) -> EventToMessageMap { EventToMessageMap { + document_dirty: Some(FrameToolMessage::DocumentIsDirty.into()), tool_abort: Some(FrameToolMessage::Abort.into()), + selection_changed: Some(FrameToolMessage::SelectionChanged.into()), ..Default::default() } } @@ -89,6 +96,7 @@ enum NodeGraphToolFsmState { #[derive(Clone, Debug, Default)] struct NodeGraphToolData { data: Resize, + path_outlines: PathOutline, } impl Fsm for NodeGraphToolFsmState { @@ -110,7 +118,15 @@ impl Fsm for NodeGraphToolFsmState { if let ToolMessage::Frame(event) = event { match (self, event) { + (_, DocumentIsDirty | SelectionChanged) => { + tool_data.path_outlines.clear_selected(responses); + tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, render_data); + + self + } (Ready, DragStart) => { + tool_data.path_outlines.clear_selected(responses); + shape_data.start(responses, document, input, render_data); responses.add(DocumentMessage::StartTransaction); shape_data.path = Some(document.get_path_for_new_layer()); @@ -147,6 +163,12 @@ impl Fsm for NodeGraphToolFsmState { responses.add(DocumentMessage::AbortTransaction); shape_data.cleanup(responses); + tool_data.path_outlines.clear_selected(responses); + + Ready + } + (_, Abort) => { + tool_data.path_outlines.clear_selected(responses); Ready } diff --git a/editor/src/messages/tool/tool_messages/imaginate_tool.rs b/editor/src/messages/tool/tool_messages/imaginate_tool.rs index 7643452a..6603fc0d 100644 --- a/editor/src/messages/tool/tool_messages/imaginate_tool.rs +++ b/editor/src/messages/tool/tool_messages/imaginate_tool.rs @@ -3,6 +3,7 @@ use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMot use crate::messages::layout::utility_types::layout_widget::PropertyHolder; use crate::messages::portfolio::document::node_graph::{self, IMAGINATE_NODE}; use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::path_outline::PathOutline; use crate::messages::tool::common_functionality::resize::Resize; use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; @@ -25,6 +26,10 @@ pub enum ImaginateToolMessage { // Standard messages #[remain::unsorted] Abort, + #[remain::unsorted] + DocumentIsDirty, + #[remain::unsorted] + SelectionChanged, // Tool-specific messages DragStart, @@ -73,7 +78,9 @@ impl ToolMetadata for ImaginateTool { impl ToolTransition for ImaginateTool { fn event_to_message_map(&self) -> EventToMessageMap { EventToMessageMap { + document_dirty: Some(ImaginateToolMessage::DocumentIsDirty.into()), tool_abort: Some(ImaginateToolMessage::Abort.into()), + selection_changed: Some(ImaginateToolMessage::SelectionChanged.into()), ..Default::default() } } @@ -89,6 +96,7 @@ enum ImaginateToolFsmState { #[derive(Clone, Debug, Default)] struct ImaginateToolData { data: Resize, + path_outlines: PathOutline, } impl Fsm for ImaginateToolFsmState { @@ -110,7 +118,15 @@ impl Fsm for ImaginateToolFsmState { if let ToolMessage::Imaginate(event) = event { match (self, event) { + (_, DocumentIsDirty | SelectionChanged) => { + tool_data.path_outlines.clear_selected(responses); + tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, render_data); + + self + } (Ready, DragStart) => { + tool_data.path_outlines.clear_selected(responses); + shape_data.start(responses, document, input, render_data); responses.add(DocumentMessage::StartTransaction); shape_data.path = Some(document.get_path_for_new_layer()); @@ -178,6 +194,12 @@ impl Fsm for ImaginateToolFsmState { responses.add(DocumentMessage::AbortTransaction); shape_data.cleanup(responses); + tool_data.path_outlines.clear_selected(responses); + + Ready + } + (_, Abort) => { + tool_data.path_outlines.clear_selected(responses); Ready } diff --git a/node-graph/gcore/src/vector/subpath.rs b/node-graph/gcore/src/vector/subpath.rs index 2ae3a4ae..9bdacba5 100644 --- a/node-graph/gcore/src/vector/subpath.rs +++ b/node-graph/gcore/src/vector/subpath.rs @@ -47,7 +47,7 @@ impl Subpath { } /// Convert to the legacy Subpath from the `bezier_rs::Subpath`. - pub fn from_bezier_crate(value: &[bezier_rs::Subpath]) -> Self { + pub fn from_bezier_rs(value: &[bezier_rs::Subpath]) -> Self { let mut groups = IdBackedVec::new(); for subpath in value { for group in subpath.manipulator_groups() { diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 2e2c93d1..a9f9c2c3 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -202,7 +202,6 @@ fn node_registry() -> HashMap