Show outline for image frames on hover and when selected with frame tools

This commit is contained in:
Keavon Chambers
2023-05-07 01:30:16 -07:00
parent 88fa95d18d
commit ebb702b7ec
6 changed files with 78 additions and 28 deletions
@@ -56,13 +56,13 @@ impl OverlayRenderer {
// Create an outline if we do not have a cached one // Create an outline if we do not have a cached one
if outline_cache.is_none() { 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.shape_overlay_cache.insert(*layer_id, outline_path.clone());
Self::place_outline_overlays(outline_path.clone(), &transform, responses); Self::place_outline_overlays(outline_path.clone(), &transform, responses);
trace!("Overlay: Creating new outline {:?}", &outline_path); trace!("Overlay: Creating new outline {:?}", &outline_path);
} else if let Some(outline_path) = outline_cache { } else if let Some(outline_path) = outline_cache {
trace!("Overlay: Updating overlays for {:?} owning layer: {:?}", outline_path, layer_id); 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); Self::place_outline_overlays(outline_path.clone(), &transform, responses);
} }
@@ -30,50 +30,57 @@ impl PathOutline {
// Get layer data // Get layer data
let document_layer = document.document_legacy.layer(&document_layer_path).ok()?; let document_layer = document.document_legacy.layer(&document_layer_path).ok()?;
// TODO Purge this area of BezPath and Kurbo // Get the subpath from the shape
// Get the bezpath from the shape or text
let subpath = match &document_layer.data { let subpath = match &document_layer.data {
LayerDataType::Shape(shape) => Some(shape.shape.clone()), 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)), _ => document_layer.aabb_for_transform(DAffine2::IDENTITY, render_data).map(|[p1, p2]| Subpath::new_rect(p1, p2)),
}?; }?;
// Generate a new overlay layer if necessary // Generate a new overlay layer if necessary
let overlay = match overlay_path { let overlay = overlay_path.unwrap_or_else(|| {
Some(path) => path, let overlay_path = vec![generate_uuid()];
None => {
let overlay_path = vec![generate_uuid()]; responses.add(DocumentMessage::Overlays(
let operation = Operation::AddShape { (Operation::AddShape {
path: overlay_path.clone(), path: overlay_path.clone(),
subpath: Default::default(), subpath: Default::default(),
style: style::PathStyle::new(Some(Stroke::new(Some(COLOR_ACCENT), PATH_OUTLINE_WEIGHT)), Fill::None), style: style::PathStyle::new(Some(Stroke::new(Some(COLOR_ACCENT), PATH_OUTLINE_WEIGHT)), Fill::None),
insert_index: -1, insert_index: -1,
transform: DAffine2::IDENTITY.to_cols_array(), transform: DAffine2::IDENTITY.to_cols_array(),
}; })
.into(),
));
responses.add(DocumentMessage::Overlays(operation.into())); overlay_path
});
overlay_path // Update the shape subpath
} responses.add(DocumentMessage::Overlays((Operation::SetShapePath { path: overlay.clone(), subpath }).into()));
};
// Update the shape bezpath
let operation = Operation::SetShapePath { path: overlay.clone(), subpath };
responses.add(DocumentMessage::Overlays(operation.into()));
// Update the transform to match the document // Update the transform to match the document
let operation = Operation::SetLayerTransform { responses.add(DocumentMessage::Overlays(
path: overlay.clone(), (Operation::SetLayerTransform {
transform: document.document_legacy.multiply_transforms(&document_layer_path).unwrap().to_cols_array(), path: overlay.clone(),
}; transform: document.document_legacy.multiply_transforms(&document_layer_path).unwrap().to_cols_array(),
responses.add(DocumentMessage::Overlays(operation.into())); })
.into(),
));
Some(overlay) 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( fn create_outline(
document_layer_path: Vec<LayerId>, document_layer_path: Vec<LayerId>,
overlay_path: Option<Vec<LayerId>>, overlay_path: Option<Vec<LayerId>>,
@@ -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::layout::utility_types::layout_widget::PropertyHolder;
use crate::messages::portfolio::document::node_graph; use crate::messages::portfolio::document::node_graph;
use crate::messages::prelude::*; 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::common_functionality::resize::Resize;
use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType}; use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
@@ -25,6 +26,10 @@ pub enum FrameToolMessage {
// Standard messages // Standard messages
#[remain::unsorted] #[remain::unsorted]
Abort, Abort,
#[remain::unsorted]
DocumentIsDirty,
#[remain::unsorted]
SelectionChanged,
// Tool-specific messages // Tool-specific messages
DragStart, DragStart,
@@ -73,7 +78,9 @@ impl ToolMetadata for FrameTool {
impl ToolTransition for FrameTool { impl ToolTransition for FrameTool {
fn event_to_message_map(&self) -> EventToMessageMap { fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap { EventToMessageMap {
document_dirty: Some(FrameToolMessage::DocumentIsDirty.into()),
tool_abort: Some(FrameToolMessage::Abort.into()), tool_abort: Some(FrameToolMessage::Abort.into()),
selection_changed: Some(FrameToolMessage::SelectionChanged.into()),
..Default::default() ..Default::default()
} }
} }
@@ -89,6 +96,7 @@ enum NodeGraphToolFsmState {
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct NodeGraphToolData { struct NodeGraphToolData {
data: Resize, data: Resize,
path_outlines: PathOutline,
} }
impl Fsm for NodeGraphToolFsmState { impl Fsm for NodeGraphToolFsmState {
@@ -110,7 +118,15 @@ impl Fsm for NodeGraphToolFsmState {
if let ToolMessage::Frame(event) = event { if let ToolMessage::Frame(event) = event {
match (self, 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) => { (Ready, DragStart) => {
tool_data.path_outlines.clear_selected(responses);
shape_data.start(responses, document, input, render_data); shape_data.start(responses, document, input, render_data);
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
shape_data.path = Some(document.get_path_for_new_layer()); shape_data.path = Some(document.get_path_for_new_layer());
@@ -147,6 +163,12 @@ impl Fsm for NodeGraphToolFsmState {
responses.add(DocumentMessage::AbortTransaction); responses.add(DocumentMessage::AbortTransaction);
shape_data.cleanup(responses); shape_data.cleanup(responses);
tool_data.path_outlines.clear_selected(responses);
Ready
}
(_, Abort) => {
tool_data.path_outlines.clear_selected(responses);
Ready Ready
} }
@@ -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::layout::utility_types::layout_widget::PropertyHolder;
use crate::messages::portfolio::document::node_graph::{self, IMAGINATE_NODE}; use crate::messages::portfolio::document::node_graph::{self, IMAGINATE_NODE};
use crate::messages::prelude::*; 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::common_functionality::resize::Resize;
use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType}; use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
@@ -25,6 +26,10 @@ pub enum ImaginateToolMessage {
// Standard messages // Standard messages
#[remain::unsorted] #[remain::unsorted]
Abort, Abort,
#[remain::unsorted]
DocumentIsDirty,
#[remain::unsorted]
SelectionChanged,
// Tool-specific messages // Tool-specific messages
DragStart, DragStart,
@@ -73,7 +78,9 @@ impl ToolMetadata for ImaginateTool {
impl ToolTransition for ImaginateTool { impl ToolTransition for ImaginateTool {
fn event_to_message_map(&self) -> EventToMessageMap { fn event_to_message_map(&self) -> EventToMessageMap {
EventToMessageMap { EventToMessageMap {
document_dirty: Some(ImaginateToolMessage::DocumentIsDirty.into()),
tool_abort: Some(ImaginateToolMessage::Abort.into()), tool_abort: Some(ImaginateToolMessage::Abort.into()),
selection_changed: Some(ImaginateToolMessage::SelectionChanged.into()),
..Default::default() ..Default::default()
} }
} }
@@ -89,6 +96,7 @@ enum ImaginateToolFsmState {
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct ImaginateToolData { struct ImaginateToolData {
data: Resize, data: Resize,
path_outlines: PathOutline,
} }
impl Fsm for ImaginateToolFsmState { impl Fsm for ImaginateToolFsmState {
@@ -110,7 +118,15 @@ impl Fsm for ImaginateToolFsmState {
if let ToolMessage::Imaginate(event) = event { if let ToolMessage::Imaginate(event) = event {
match (self, 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) => { (Ready, DragStart) => {
tool_data.path_outlines.clear_selected(responses);
shape_data.start(responses, document, input, render_data); shape_data.start(responses, document, input, render_data);
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
shape_data.path = Some(document.get_path_for_new_layer()); shape_data.path = Some(document.get_path_for_new_layer());
@@ -178,6 +194,12 @@ impl Fsm for ImaginateToolFsmState {
responses.add(DocumentMessage::AbortTransaction); responses.add(DocumentMessage::AbortTransaction);
shape_data.cleanup(responses); shape_data.cleanup(responses);
tool_data.path_outlines.clear_selected(responses);
Ready
}
(_, Abort) => {
tool_data.path_outlines.clear_selected(responses);
Ready Ready
} }
+1 -1
View File
@@ -47,7 +47,7 @@ impl Subpath {
} }
/// Convert to the legacy Subpath from the `bezier_rs::Subpath`. /// Convert to the legacy Subpath from the `bezier_rs::Subpath`.
pub fn from_bezier_crate(value: &[bezier_rs::Subpath<ManipulatorGroupId>]) -> Self { pub fn from_bezier_rs(value: &[bezier_rs::Subpath<ManipulatorGroupId>]) -> Self {
let mut groups = IdBackedVec::new(); let mut groups = IdBackedVec::new();
for subpath in value { for subpath in value {
for group in subpath.manipulator_groups() { for group in subpath.manipulator_groups() {
@@ -202,7 +202,6 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let bounds_transform = bounds.eval(()).transform; let bounds_transform = bounds.eval(()).transform;
if bounds_transform != DAffine2::ZERO { if bounds_transform != DAffine2::ZERO {
background_bounds = CopiedNode::new(bounds_transform); background_bounds = CopiedNode::new(bounds_transform);
log::debug!("setting transform to {:?}", bounds_transform);
} }
let background_image = background_bounds.then(EmptyImageNode::new(CopiedNode::new(Color::TRANSPARENT))); let background_image = background_bounds.then(EmptyImageNode::new(CopiedNode::new(Color::TRANSPARENT)));