mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 01:08:13 +08:00
Add layer node chains, import/export edge connectors, and refactor graph editing to go thru a NodeNetworkInterface (#1794)
* WIP: NodeNetworkInterface * Organize ModifyInputsContext to use network interface * Improve ClickTarget and Position state * Rework ClickTarget state * Continue fixing NodeGraphMessageHandler * Restructure network_metadata * Final(?) NodeNetworkInterface struct * Final(??) NodeNetworkInterface * Final(???) NodeNetworkInterface. Separated persistent and transient data * Final NodeNetworkInterface data structure. Implemented all basic getters * Continue migrating functionality to network interface * Migrate all NodeGraphMessage's to use network interface * Fix all helper functions in NodeGraphMessageHandler * Move document metadata to network interface, remove various cached fields * Move all editor only NodeNetwork implementations to NodeNetworkInterface * Fix all DocumentNodeDefinitions * Rework and migrate GraphOperationMessages to network interface * Continue migration to NodeNetworkInterface * Save point before merging master * Fix all errors in network_interface * 850 -> 160 errors * Fix all errors :D * Render default document * Visualize click targets * merge conflicts * Cache transient metadata separately, store entire interface in document history * Start migration to storing selected nodes for each network * Remove selected nodes from document message handler * Move outward wires and all nodes bounding box to transient metadata * Fix connecting/disconnecting nodes * Layer stack organization for disconnecting/connecting nodes * Basic chain locking * Improve chain positioning * Add copy/pasting * Move upstream nodes on shift+drag * merge conflict fixes * Improve Graph.svelte code quality * Final improvements to Graph.svelte * Fix layer panel * Performance optimizations * Bug fixes and derived PTZ * Chain organization improvement and bug fixes * Bug fixes, remove all warnings * Automatic file upgrade * Final code review * Fix editor tests * Fix compile errors * Remove select tool intersection check when panning * WIP: Import/Exports * Fix JS issues * Finish simplified import/export UI * Import/Export viewport edge UI * Remove minimum y bound on import/export ports * Improve performance while panning graph * cargo fmt * Fix CI code build * Format the demo artwork graph with chains * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com> Co-authored-by: dennis@kobert.dev <dennis@kobert.dev>
This commit is contained in:
co-authored by
Keavon Chambers
dennis@kobert.dev
parent
ea44d1440a
commit
0dbbabe73e
@@ -1,7 +1,8 @@
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate};
|
||||
use crate::messages::prelude::*;
|
||||
use bezier_rs::Subpath;
|
||||
use graph_craft::document::{value::TaggedValue, DocumentNode, NodeId, NodeInput, NodeNetwork};
|
||||
use graph_craft::document::{value::TaggedValue, NodeId, NodeInput};
|
||||
use graphene_core::raster::{BlendMode, ImageFrame};
|
||||
use graphene_core::text::Font;
|
||||
use graphene_core::vector::style::Gradient;
|
||||
@@ -13,7 +14,7 @@ use std::collections::VecDeque;
|
||||
|
||||
/// Create a new vector layer from a vector of [`bezier_rs::Subpath`].
|
||||
pub fn new_vector_layer(subpaths: Vec<Subpath<PointId>>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
|
||||
let insert_index = -1;
|
||||
let insert_index = 0;
|
||||
responses.add(GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index });
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });
|
||||
|
||||
@@ -22,7 +23,7 @@ pub fn new_vector_layer(subpaths: Vec<Subpath<PointId>>, id: NodeId, parent: Lay
|
||||
|
||||
/// Create a new bitmap layer from an [`graphene_core::raster::ImageFrame<Color>`]
|
||||
pub fn new_image_layer(image_frame: ImageFrame<Color>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
|
||||
let insert_index = -1;
|
||||
let insert_index = 0;
|
||||
responses.add(GraphOperationMessage::NewBitmapLayer {
|
||||
id,
|
||||
image_frame,
|
||||
@@ -34,7 +35,7 @@ pub fn new_image_layer(image_frame: ImageFrame<Color>, id: NodeId, parent: Layer
|
||||
|
||||
/// Create a new group layer from an svg
|
||||
pub fn new_svg_layer(svg: String, transform: glam::DAffine2, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
|
||||
let insert_index = -1;
|
||||
let insert_index = 0;
|
||||
responses.add(DocumentMessage::ImportSvg {
|
||||
id,
|
||||
svg,
|
||||
@@ -44,39 +45,37 @@ pub fn new_svg_layer(svg: String, transform: glam::DAffine2, id: NodeId, parent:
|
||||
});
|
||||
LayerNodeIdentifier::new_unchecked(id)
|
||||
}
|
||||
pub fn new_custom(id: NodeId, nodes: HashMap<NodeId, DocumentNode>, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
|
||||
responses.add(GraphOperationMessage::NewCustomLayer {
|
||||
id,
|
||||
nodes,
|
||||
parent,
|
||||
insert_index: -1,
|
||||
alias: String::new(),
|
||||
|
||||
pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
|
||||
responses.add(GraphOperationMessage::NewCustomLayer { id, nodes, parent, insert_index: 0 });
|
||||
responses.add(GraphOperationMessage::SetUpstreamToChain {
|
||||
layer: LayerNodeIdentifier::new_unchecked(id),
|
||||
});
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });
|
||||
LayerNodeIdentifier::new_unchecked(id)
|
||||
}
|
||||
|
||||
/// Locate the final pivot from the transform (TODO: decide how the pivot should actually work)
|
||||
pub fn get_pivot(layer: LayerNodeIdentifier, network: &NodeNetwork) -> Option<DVec2> {
|
||||
pub fn get_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<DVec2> {
|
||||
let pivot_node_input_index = 5;
|
||||
if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, network).find_input("Transform", pivot_node_input_index)? {
|
||||
if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", pivot_node_input_index)? {
|
||||
Some(*pivot)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_viewport_pivot(layer: LayerNodeIdentifier, document_network: &NodeNetwork, document_metadata: &DocumentMetadata) -> DVec2 {
|
||||
let [min, max] = document_metadata.nonzero_bounding_box(layer);
|
||||
let pivot = get_pivot(layer, document_network).unwrap_or(DVec2::splat(0.5));
|
||||
document_metadata.transform_to_viewport(layer).transform_point2(min + (max - min) * pivot)
|
||||
pub fn get_viewport_pivot(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DVec2 {
|
||||
let [min, max] = network_interface.document_metadata().nonzero_bounding_box(layer);
|
||||
let pivot = get_pivot(layer, network_interface).unwrap_or(DVec2::splat(0.5));
|
||||
network_interface.document_metadata().transform_to_viewport(layer).transform_point2(min + (max - min) * pivot)
|
||||
}
|
||||
|
||||
/// Get the current gradient of a layer from the closest Fill node
|
||||
pub fn get_gradient(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<Gradient> {
|
||||
pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Gradient> {
|
||||
let fill_index = 1;
|
||||
|
||||
let inputs = NodeGraphLayer::new(layer, document_network).find_node_inputs("Fill")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?;
|
||||
let TaggedValue::Fill(graphene_std::vector::style::Fill::Gradient(gradient)) = inputs.get(fill_index)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -84,10 +83,10 @@ pub fn get_gradient(layer: LayerNodeIdentifier, document_network: &NodeNetwork)
|
||||
}
|
||||
|
||||
/// Get the current fill of a layer from the closest Fill node
|
||||
pub fn get_fill_color(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<Color> {
|
||||
pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Color> {
|
||||
let fill_index = 1;
|
||||
|
||||
let inputs = NodeGraphLayer::new(layer, document_network).find_node_inputs("Fill")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?;
|
||||
let TaggedValue::Fill(graphene_std::vector::style::Fill::Solid(color)) = inputs.get(fill_index)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -95,8 +94,8 @@ pub fn get_fill_color(layer: LayerNodeIdentifier, document_network: &NodeNetwork
|
||||
}
|
||||
|
||||
/// Get the current blend mode of a layer from the closest Blend Mode node
|
||||
pub fn get_blend_mode(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<BlendMode> {
|
||||
let inputs = NodeGraphLayer::new(layer, document_network).find_node_inputs("Blend Mode")?;
|
||||
pub fn get_blend_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<BlendMode> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blend Mode")?;
|
||||
let TaggedValue::BlendMode(blend_mode) = inputs.get(1)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -110,25 +109,25 @@ pub fn get_blend_mode(layer: LayerNodeIdentifier, document_network: &NodeNetwork
|
||||
/// - Already factored into the pixel alpha channel of an image
|
||||
/// - The default value of 100% if no Opacity node is present, but this function returns None in that case
|
||||
/// With those limitations in mind, the intention of this function is to show just the value already present in an upstream Opacity node so that value can be directly edited.
|
||||
pub fn get_opacity(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<f64> {
|
||||
let inputs = NodeGraphLayer::new(layer, document_network).find_node_inputs("Opacity")?;
|
||||
pub fn get_opacity(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Opacity")?;
|
||||
let TaggedValue::F64(opacity) = inputs.get(1)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
Some(*opacity)
|
||||
}
|
||||
|
||||
pub fn get_fill_id(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, document_network).upstream_node_id_from_name("Fill")
|
||||
pub fn get_fill_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Fill")
|
||||
}
|
||||
|
||||
pub fn get_text_id(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, document_network).upstream_node_id_from_name("Text")
|
||||
pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Text")
|
||||
}
|
||||
|
||||
/// Gets properties from the Text node
|
||||
pub fn get_text(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<(&String, &Font, f64)> {
|
||||
let inputs = NodeGraphLayer::new(layer, document_network).find_node_inputs("Text")?;
|
||||
pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, f64)> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Text")?;
|
||||
|
||||
let Some(TaggedValue::String(text)) = &inputs[1].as_value() else { return None };
|
||||
let Some(TaggedValue::Font(font)) = &inputs[2].as_value() else { return None };
|
||||
@@ -137,9 +136,9 @@ pub fn get_text(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> O
|
||||
Some((text, font, font_size))
|
||||
}
|
||||
|
||||
pub fn get_stroke_width(layer: LayerNodeIdentifier, network: &NodeNetwork) -> Option<f64> {
|
||||
pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {
|
||||
let weight_node_input_index = 2;
|
||||
if let TaggedValue::F64(width) = NodeGraphLayer::new(layer, network).find_input("Stroke", weight_node_input_index)? {
|
||||
if let TaggedValue::F64(width) = NodeGraphLayer::new(layer, network_interface).find_input("Stroke", weight_node_input_index)? {
|
||||
Some(*width)
|
||||
} else {
|
||||
None
|
||||
@@ -147,43 +146,44 @@ pub fn get_stroke_width(layer: LayerNodeIdentifier, network: &NodeNetwork) -> Op
|
||||
}
|
||||
|
||||
/// Checks if a specified layer uses an upstream node matching the given name.
|
||||
pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, document_network: &NodeNetwork, node_name: &str) -> bool {
|
||||
NodeGraphLayer::new(layer, document_network).find_node_inputs(node_name).is_some()
|
||||
pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, node_name: &str) -> bool {
|
||||
NodeGraphLayer::new(layer, network_interface).find_node_inputs(node_name).is_some()
|
||||
}
|
||||
|
||||
/// An immutable reference to a layer within the document node graph for easy access.
|
||||
pub struct NodeGraphLayer<'a> {
|
||||
node_graph: &'a NodeNetwork,
|
||||
network_interface: &'a NodeNetworkInterface,
|
||||
layer_node: NodeId,
|
||||
}
|
||||
|
||||
impl<'a> NodeGraphLayer<'a> {
|
||||
/// Get the layer node from the document
|
||||
pub fn new(layer: LayerNodeIdentifier, network: &'a NodeNetwork) -> Self {
|
||||
pub fn new(layer: LayerNodeIdentifier, network_interface: &'a NodeNetworkInterface) -> Self {
|
||||
debug_assert!(layer != LayerNodeIdentifier::ROOT_PARENT, "Cannot create new NodeGraphLayer from ROOT_PARENT");
|
||||
Self {
|
||||
node_graph: network,
|
||||
network_interface,
|
||||
layer_node: layer.to_node(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterator up the horizontal flow of the layer
|
||||
pub fn horizontal_layer_flow(&self) -> impl Iterator<Item = (&'a DocumentNode, NodeId)> {
|
||||
self.node_graph.upstream_flow_back_from_nodes(vec![self.layer_node], graph_craft::document::FlowType::HorizontalFlow)
|
||||
pub fn horizontal_layer_flow(&self) -> impl Iterator<Item = NodeId> + 'a {
|
||||
self.network_interface.upstream_flow_back_from_nodes(vec![self.layer_node], &[], FlowType::HorizontalFlow)
|
||||
}
|
||||
|
||||
/// Node id of a node if it exists in the layer's primary flow
|
||||
pub fn upstream_node_id_from_name(&self, node_name: &str) -> Option<NodeId> {
|
||||
self.horizontal_layer_flow().find(|(node, _)| node.name == node_name).map(|(_, id)| id)
|
||||
self.horizontal_layer_flow()
|
||||
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == node_name))
|
||||
}
|
||||
|
||||
/// Find all of the inputs of a specific node within the layer's primary flow, up until the next layer is reached.
|
||||
pub fn find_node_inputs(&self, node_name: &str) -> Option<&'a Vec<NodeInput>> {
|
||||
self.horizontal_layer_flow()
|
||||
.skip(1)// Skip self
|
||||
.take_while(|(node, _)| !node.is_layer)
|
||||
.find(|(node, _)| node.name == node_name)
|
||||
.map(|(node, _id)| &node.inputs)
|
||||
.take_while(|node_id| !self.network_interface.is_layer(node_id,&[]))
|
||||
.find(|node_id| self.network_interface.reference(node_id,&[]).is_some_and(|reference| reference == node_name))
|
||||
.and_then(|node_id| self.network_interface.network(&[]).unwrap().nodes.get(&node_id).map(|node| &node.inputs))
|
||||
}
|
||||
|
||||
/// Find a specific input of a node within the layer's primary flow
|
||||
|
||||
@@ -45,7 +45,11 @@ impl Pivot {
|
||||
|
||||
/// Recomputes the pivot position and transform.
|
||||
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
|
||||
let mut layers = document.selected_nodes.selected_visible_and_unlocked_layers(document.metadata());
|
||||
let mut layers = document
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface);
|
||||
let Some(first) = layers.next() else {
|
||||
// If no layers are selected then we revert things back to default
|
||||
self.normalized_pivot = DVec2::splat(0.5);
|
||||
@@ -58,16 +62,18 @@ impl Pivot {
|
||||
|
||||
// If just one layer is selected we can use its inner transform (as it accounts for rotation)
|
||||
if selected_layers_count == 1 {
|
||||
let normalized_pivot = graph_modification_utils::get_pivot(first, &document.network).unwrap_or(DVec2::splat(0.5));
|
||||
let normalized_pivot = graph_modification_utils::get_pivot(first, &document.network_interface).unwrap_or(DVec2::splat(0.5));
|
||||
self.normalized_pivot = normalized_pivot;
|
||||
self.transform_from_normalized = Self::get_layer_pivot_transform(first, document);
|
||||
self.pivot = Some(self.transform_from_normalized.transform_point2(normalized_pivot));
|
||||
} else {
|
||||
// If more than one layer is selected we use the AABB with the mean of the pivots
|
||||
let xy_summation = document
|
||||
.selected_nodes
|
||||
.selected_visible_and_unlocked_layers(document.metadata())
|
||||
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network, &document.metadata))
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network_interface))
|
||||
.reduce(|a, b| a + b)
|
||||
.unwrap_or_default();
|
||||
|
||||
@@ -101,7 +107,12 @@ impl Pivot {
|
||||
|
||||
/// Sets the viewport position of the pivot for all selected layers.
|
||||
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for layer in document.selected_nodes.selected_visible_and_unlocked_layers(document.metadata()) {
|
||||
for layer in document
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||
{
|
||||
let transform = Self::get_layer_pivot_transform(layer, document);
|
||||
let pivot = transform.inverse().transform_point2(position);
|
||||
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
||||
|
||||
@@ -37,15 +37,15 @@ impl Resize {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !document.network().nodes.contains_key(&layer.to_node()) {
|
||||
if !document.network_interface.network(&[]).unwrap().nodes.contains_key(&layer.to_node()) {
|
||||
self.layer.take();
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = self.viewport_drag_start(document);
|
||||
let mouse = input.mouse.position;
|
||||
let to_viewport = document.metadata().document_to_viewport;
|
||||
let document_mouse = to_viewport.inverse().transform_point2(mouse);
|
||||
let document_to_viewport = document.navigation_handler.calculate_offset_transform(input.viewport_bounds.center(), &document.document_ptz);
|
||||
let document_mouse = document_to_viewport.inverse().transform_point2(mouse);
|
||||
let mut points_viewport = [start, mouse];
|
||||
let ignore = if let Some(layer) = self.layer { vec![layer] } else { vec![] };
|
||||
let ratio = input.keyboard.get(lock_ratio as usize);
|
||||
@@ -55,7 +55,7 @@ impl Resize {
|
||||
let size = points_viewport[1] - points_viewport[0];
|
||||
let size = size.abs().max(size.abs().yx()) * size.signum();
|
||||
points_viewport[1] = points_viewport[0] + size;
|
||||
let end_document = to_viewport.inverse().transform_point2(points_viewport[1]);
|
||||
let end_document = document_to_viewport.inverse().transform_point2(points_viewport[1]);
|
||||
let constraint = SnapConstraint::Line {
|
||||
origin: self.drag_start,
|
||||
direction: end_document - self.drag_start,
|
||||
@@ -65,24 +65,24 @@ impl Resize {
|
||||
let far = SnapCandidatePoint::handle(2. * self.drag_start - end_document);
|
||||
let snapped_far = self.snap_manager.constrained_snap(&snap_data, &far, constraint, None);
|
||||
let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far };
|
||||
points_viewport[0] = to_viewport.transform_point2(best.snapped_point_document);
|
||||
points_viewport[1] = to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document);
|
||||
points_viewport[0] = document_to_viewport.transform_point2(best.snapped_point_document);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document);
|
||||
self.snap_manager.update_indicator(best);
|
||||
} else {
|
||||
let snapped = self.snap_manager.constrained_snap(&snap_data, &SnapCandidatePoint::handle(end_document), constraint, None);
|
||||
points_viewport[1] = to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
self.snap_manager.update_indicator(snapped);
|
||||
}
|
||||
} else if center {
|
||||
let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), None, false);
|
||||
let snapped_far = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(2. * self.drag_start - document_mouse), None, false);
|
||||
let best = if snapped_far.other_snap_better(&snapped) { snapped } else { snapped_far };
|
||||
points_viewport[0] = to_viewport.transform_point2(best.snapped_point_document);
|
||||
points_viewport[1] = to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document);
|
||||
points_viewport[0] = document_to_viewport.transform_point2(best.snapped_point_document);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(self.drag_start * 2. - best.snapped_point_document);
|
||||
self.snap_manager.update_indicator(best);
|
||||
} else {
|
||||
let snapped = self.snap_manager.free_snap(&snap_data, &SnapCandidatePoint::handle(document_mouse), None, false);
|
||||
points_viewport[1] = to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
points_viewport[1] = document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
self.snap_manager.update_indicator(snapped);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ use super::graph_modification_utils;
|
||||
use super::snapping::{SnapCandidatePoint, SnapData, SnapManager, SnappedPoint};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
use crate::messages::portfolio::document::utility_types::misc::{GeometrySnapSource, SnapSource};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use bezier_rs::{Bezier, BezierHandles, TValue};
|
||||
use graph_craft::document::NodeNetwork;
|
||||
use graphene_core::transform::Transform;
|
||||
use graphene_core::vector::{ManipulatorPointId, PointId, VectorData, VectorModificationType};
|
||||
|
||||
@@ -171,7 +171,7 @@ impl ShapeState {
|
||||
let mut snap_data = SnapData::new(document, input);
|
||||
|
||||
for (layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(*layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(*layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
for point in &state.selected_points {
|
||||
@@ -180,15 +180,20 @@ impl ShapeState {
|
||||
}
|
||||
}
|
||||
|
||||
let mouse_delta = document.metadata.document_to_viewport.inverse().transform_vector2(input.mouse.position - previous_mouse);
|
||||
let mouse_delta = document
|
||||
.network_interface
|
||||
.document_metadata()
|
||||
.document_to_viewport
|
||||
.inverse()
|
||||
.transform_vector2(input.mouse.position - previous_mouse);
|
||||
let mut offset = mouse_delta;
|
||||
let mut best_snapped = SnappedPoint::infinite_snap(document.metadata.document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let mut best_snapped = SnappedPoint::infinite_snap(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
for (layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(*layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(*layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let to_document = document.metadata.transform_to_document(*layer);
|
||||
let to_document = document.metadata().transform_to_document(*layer);
|
||||
|
||||
for &selected in &state.selected_points {
|
||||
let source = match selected {
|
||||
@@ -218,25 +223,18 @@ impl ShapeState {
|
||||
}
|
||||
}
|
||||
snap_manager.update_indicator(best_snapped);
|
||||
document.metadata.document_to_viewport.transform_vector2(offset)
|
||||
document.metadata().document_to_viewport.transform_vector2(offset)
|
||||
}
|
||||
|
||||
/// Select/deselect the first point within the selection threshold.
|
||||
/// Returns a tuple of the points if found and the offset, or `None` otherwise.
|
||||
pub fn change_point_selection(
|
||||
&mut self,
|
||||
document_network: &NodeNetwork,
|
||||
document_metadata: &DocumentMetadata,
|
||||
mouse_position: DVec2,
|
||||
select_threshold: f64,
|
||||
add_to_selection: bool,
|
||||
) -> Option<Option<SelectedPointsInfo>> {
|
||||
pub fn change_point_selection(&mut self, network_interface: &NodeNetworkInterface, mouse_position: DVec2, select_threshold: f64, add_to_selection: bool) -> Option<Option<SelectedPointsInfo>> {
|
||||
if self.selected_shape_state.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some((layer, manipulator_point_id)) = self.find_nearest_point_indices(document_network, document_metadata, mouse_position, select_threshold) {
|
||||
let vector_data = document_metadata.compute_modified_vector(layer, document_network)?;
|
||||
if let Some((layer, manipulator_point_id)) = self.find_nearest_point_indices(network_interface, mouse_position, select_threshold) {
|
||||
let vector_data = network_interface.document_metadata().compute_modified_vector(layer, network_interface)?;
|
||||
let point_position = manipulator_point_id.get_position(&vector_data)?;
|
||||
|
||||
let selected_shape_state = self.selected_shape_state.get(&layer)?;
|
||||
@@ -246,7 +244,7 @@ impl ShapeState {
|
||||
let new_selected = if already_selected { !add_to_selection } else { true };
|
||||
|
||||
// Offset to snap the selected point to the cursor
|
||||
let offset = mouse_position - document_metadata.transform_to_viewport(layer).transform_point2(point_position);
|
||||
let offset = mouse_position - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(point_position);
|
||||
|
||||
// This is selecting the manipulator only for now, next to generalize to points
|
||||
if new_selected {
|
||||
@@ -287,10 +285,10 @@ impl ShapeState {
|
||||
|
||||
/// Selects all anchors connected to the selected subpath, and deselects all handles, for the given layer.
|
||||
pub fn select_connected_anchors(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, mouse: DVec2) {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(layer, &document.network_interface) else {
|
||||
return;
|
||||
};
|
||||
let to_viewport = document.metadata.transform_to_viewport(layer);
|
||||
let to_viewport = document.metadata().transform_to_viewport(layer);
|
||||
let layer_mouse = to_viewport.inverse().transform_point2(mouse);
|
||||
let state = self.selected_shape_state.entry(layer).or_default();
|
||||
|
||||
@@ -335,7 +333,7 @@ impl ShapeState {
|
||||
|
||||
/// Internal helper function that selects all anchors, and deselects all handles, for a layer given its [`LayerNodeIdentifier`] and [`SelectedLayerState`].
|
||||
fn select_all_anchors_in_layer_with_state(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, state: &mut SelectedLayerState) {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(layer, &document.network_interface) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -429,14 +427,13 @@ impl ShapeState {
|
||||
pub fn reposition_control_point(
|
||||
&self,
|
||||
point: &ManipulatorPointId,
|
||||
network: &NodeNetwork,
|
||||
metadata: &DocumentMetadata,
|
||||
network_interface: &NodeNetworkInterface,
|
||||
new_position: DVec2,
|
||||
layer: LayerNodeIdentifier,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Option<()> {
|
||||
let vector_data = metadata.compute_modified_vector(layer, network)?;
|
||||
let transform = metadata.transform_to_document(layer).inverse();
|
||||
let vector_data = network_interface.document_metadata().compute_modified_vector(layer, network_interface)?;
|
||||
let transform = network_interface.document_metadata().transform_to_document(layer).inverse();
|
||||
let position = transform.transform_point2(new_position);
|
||||
let current_position = point.get_position(&vector_data)?;
|
||||
let delta = position - current_position;
|
||||
@@ -464,12 +461,12 @@ impl ShapeState {
|
||||
|
||||
/// Iterates over the selected manipulator groups, returning whether their handles have mixed, colinear, or free angles.
|
||||
/// If there are no points selected this function returns mixed.
|
||||
pub fn selected_manipulator_angles(&self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata) -> ManipulatorAngle {
|
||||
pub fn selected_manipulator_angles(&self, network_interface: &NodeNetworkInterface) -> ManipulatorAngle {
|
||||
// This iterator contains a bool indicating whether or not selected points' manipulator groups have colinear handles.
|
||||
let mut points_colinear_status = self
|
||||
.selected_shape_state
|
||||
.iter()
|
||||
.map(|(&layer, selection_state)| (document_metadata.compute_modified_vector(layer, document_network), selection_state))
|
||||
.map(|(&layer, selection_state)| (network_interface.document_metadata().compute_modified_vector(layer, network_interface), selection_state))
|
||||
.flat_map(|(data, selection_state)| selection_state.selected_points.iter().map(move |&point| data.as_ref().map_or(false, |data| data.colinear(point))));
|
||||
|
||||
let Some(first_is_colinear) = points_colinear_status.next() else { return ManipulatorAngle::Mixed };
|
||||
@@ -547,10 +544,10 @@ impl ShapeState {
|
||||
let mut skip_set = HashSet::new();
|
||||
|
||||
for (&layer, layer_state) in self.selected_shape_state.iter() {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
let transform = document.metadata.transform_to_document(layer);
|
||||
let transform = document.metadata().transform_to_document(layer);
|
||||
|
||||
for &point in layer_state.selected_points.iter() {
|
||||
let Some(handles) = point.get_handle_pair(&vector_data) else { continue };
|
||||
@@ -622,12 +619,12 @@ impl ShapeState {
|
||||
/// Move the selected points by dragging the mouse.
|
||||
pub fn move_selected_points(&self, handle_lengths: Option<OpposingHandleLengths>, document: &DocumentMessageHandler, delta: DVec2, equidistant: bool, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
let opposing_handles = handle_lengths.as_ref().and_then(|handle_lengths| handle_lengths.get(&layer));
|
||||
|
||||
let transform = document.metadata.transform_to_viewport(layer);
|
||||
let transform = document.metadata().transform_to_viewport(layer);
|
||||
let delta = transform.inverse().transform_vector2(delta);
|
||||
|
||||
for &point in state.selected_points.iter() {
|
||||
@@ -662,7 +659,7 @@ impl ShapeState {
|
||||
let new_relative = if equidistant {
|
||||
-(handle_position - anchor_position)
|
||||
} else {
|
||||
let transform = document.metadata.document_to_viewport.inverse() * transform;
|
||||
let transform = document.metadata().document_to_viewport.inverse() * transform;
|
||||
let Some(other_position) = other.to_manipulator_point().get_position(&vector_data) else {
|
||||
continue;
|
||||
};
|
||||
@@ -683,8 +680,8 @@ impl ShapeState {
|
||||
self.selected_shape_state
|
||||
.iter()
|
||||
.filter_map(|(&layer, state)| {
|
||||
let vector_data = document.metadata.compute_modified_vector(layer, &document.network)?;
|
||||
let transform = document.metadata.transform_to_document(layer);
|
||||
let vector_data = document.metadata().compute_modified_vector(layer, &document.network_interface)?;
|
||||
let transform = document.metadata().transform_to_document(layer);
|
||||
let opposing_handle_lengths = vector_data
|
||||
.colinear_manipulators
|
||||
.iter()
|
||||
@@ -749,7 +746,7 @@ impl ShapeState {
|
||||
pub fn delete_selected_points(&self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let mut missing_anchors = HashMap::new();
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -840,7 +837,7 @@ impl ShapeState {
|
||||
|
||||
pub fn break_path_at_selected_point(&self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -886,7 +883,7 @@ impl ShapeState {
|
||||
/// Delete point(s) and adjacent segments.
|
||||
pub fn delete_point_and_break_path(&self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = document.metadata.compute_modified_vector(layer, &document.network) else {
|
||||
let Some(vector_data) = document.metadata().compute_modified_vector(layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -907,9 +904,11 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
/// Disable colinear handles colinear.
|
||||
pub fn disable_colinear_handles_state_on_selected(&self, metadata: &DocumentMetadata, network: &NodeNetwork, responses: &mut VecDeque<Message>) {
|
||||
pub fn disable_colinear_handles_state_on_selected(&self, network_interface: &NodeNetworkInterface, responses: &mut VecDeque<Message>) {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector_data) = metadata.compute_modified_vector(layer, network) else { continue };
|
||||
let Some(vector_data) = network_interface.document_metadata().compute_modified_vector(layer, network_interface) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for &point in &state.selected_points {
|
||||
if let ManipulatorPointId::Anchor(point) = point {
|
||||
@@ -928,13 +927,7 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
/// Find a [ManipulatorPoint] that is within the selection threshold and return the layer path, an index to the [ManipulatorGroup], and an enum index for [ManipulatorPoint].
|
||||
pub fn find_nearest_point_indices(
|
||||
&mut self,
|
||||
document_network: &NodeNetwork,
|
||||
document_metadata: &DocumentMetadata,
|
||||
mouse_position: DVec2,
|
||||
select_threshold: f64,
|
||||
) -> Option<(LayerNodeIdentifier, ManipulatorPointId)> {
|
||||
pub fn find_nearest_point_indices(&mut self, network_interface: &NodeNetworkInterface, mouse_position: DVec2, select_threshold: f64) -> Option<(LayerNodeIdentifier, ManipulatorPointId)> {
|
||||
if self.selected_shape_state.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@@ -943,7 +936,7 @@ impl ShapeState {
|
||||
|
||||
// Find the closest control point among all elements of shapes_to_modify
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
if let Some((manipulator_point_id, distance_squared)) = Self::closest_point_in_layer(document_network, document_metadata, layer, mouse_position) {
|
||||
if let Some((manipulator_point_id, distance_squared)) = Self::closest_point_in_layer(network_interface, layer, mouse_position) {
|
||||
// Choose the first point under the threshold
|
||||
if distance_squared < select_threshold_squared {
|
||||
trace!("Selecting... manipulator point: {manipulator_point_id:?}");
|
||||
@@ -959,12 +952,12 @@ impl ShapeState {
|
||||
/// Find the closest manipulator, manipulator point, and distance so we can select path elements.
|
||||
/// Brute force comparison to determine which manipulator (handle or anchor) we want to select taking O(n) time.
|
||||
/// Return value is an `Option` of the tuple representing `(ManipulatorPointId, distance squared)`.
|
||||
fn closest_point_in_layer(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier, pos: glam::DVec2) -> Option<(ManipulatorPointId, f64)> {
|
||||
fn closest_point_in_layer(network_interface: &NodeNetworkInterface, layer: LayerNodeIdentifier, pos: glam::DVec2) -> Option<(ManipulatorPointId, f64)> {
|
||||
let mut closest_distance_squared: f64 = f64::MAX;
|
||||
let mut manipulator_point = None;
|
||||
|
||||
let vector_data = document_metadata.compute_modified_vector(layer, document_network)?;
|
||||
let viewspace = document_metadata.transform_to_viewport(layer);
|
||||
let vector_data = network_interface.document_metadata().compute_modified_vector(layer, network_interface)?;
|
||||
let viewspace = network_interface.document_metadata().transform_to_viewport(layer);
|
||||
|
||||
// Handles
|
||||
for (segment_id, bezier, _, _) in vector_data.segment_bezier_iter() {
|
||||
@@ -999,8 +992,8 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
/// Find the `t` value along the path segment we have clicked upon, together with that segment ID.
|
||||
fn closest_segment(&self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier, position: glam::DVec2, tolerance: f64) -> Option<ClosestSegment> {
|
||||
let transform = document_metadata.transform_to_viewport(layer);
|
||||
fn closest_segment(&self, network_interface: &NodeNetworkInterface, layer: LayerNodeIdentifier, position: glam::DVec2, tolerance: f64) -> Option<ClosestSegment> {
|
||||
let transform = network_interface.document_metadata().transform_to_viewport(layer);
|
||||
let layer_pos = transform.inverse().transform_point2(position);
|
||||
|
||||
let tolerance = tolerance + 0.5;
|
||||
@@ -1008,7 +1001,7 @@ impl ShapeState {
|
||||
let mut closest = None;
|
||||
let mut closest_distance_squared: f64 = tolerance * tolerance;
|
||||
|
||||
let vector_data = document_metadata.compute_modified_vector(layer, document_network)?;
|
||||
let vector_data = network_interface.document_metadata().compute_modified_vector(layer, network_interface)?;
|
||||
|
||||
for (segment, mut bezier, start, end) in vector_data.segment_bezier_iter() {
|
||||
let t = bezier.project(layer_pos);
|
||||
@@ -1023,7 +1016,7 @@ impl ShapeState {
|
||||
// 0.5 is half the line (center to side) but it's convenient to allow targeting slightly more than half the line width
|
||||
const STROKE_WIDTH_PERCENT: f64 = 0.7;
|
||||
|
||||
let stroke_width = graph_modification_utils::get_stroke_width(layer, document_network).unwrap_or(1.) as f64 * STROKE_WIDTH_PERCENT;
|
||||
let stroke_width = graph_modification_utils::get_stroke_width(layer, network_interface).unwrap_or(1.) as f64 * STROKE_WIDTH_PERCENT;
|
||||
|
||||
// Convert to linear if handes are on top of control points
|
||||
if let bezier_rs::BezierHandles::Cubic { handle_start, handle_end } = bezier.handles {
|
||||
@@ -1054,22 +1047,22 @@ impl ShapeState {
|
||||
}
|
||||
|
||||
/// find closest to the position segment on selected layers. If there is more than one layers with close enough segment it return upper from them
|
||||
pub fn upper_closest_segment(&self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, position: glam::DVec2, tolerance: f64) -> Option<ClosestSegment> {
|
||||
let closest_seg = |layer| self.closest_segment(document_network, document_metadata, layer, position, tolerance);
|
||||
pub fn upper_closest_segment(&self, network_interface: &NodeNetworkInterface, position: glam::DVec2, tolerance: f64) -> Option<ClosestSegment> {
|
||||
let closest_seg = |layer| self.closest_segment(network_interface, layer, position, tolerance);
|
||||
match self.selected_shape_state.len() {
|
||||
0 => None,
|
||||
1 => self.selected_layers().next().copied().and_then(closest_seg),
|
||||
_ => self.sorted_selected_layers(document_metadata).find_map(closest_seg),
|
||||
_ => self.sorted_selected_layers(network_interface.document_metadata()).find_map(closest_seg),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a nearby clicked anchor point's handles between sharp (zero-length handles) and smooth (pulled-apart handle(s)).
|
||||
/// If both handles aren't zero-length, they are set that. If both are zero-length, they are stretched apart by a reasonable amount.
|
||||
/// This can can be activated by double clicking on an anchor with the Path tool.
|
||||
pub fn flip_smooth_sharp(&self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, target: glam::DVec2, tolerance: f64, responses: &mut VecDeque<Message>) -> bool {
|
||||
pub fn flip_smooth_sharp(&self, network_interface: &NodeNetworkInterface, target: glam::DVec2, tolerance: f64, responses: &mut VecDeque<Message>) -> bool {
|
||||
let mut process_layer = |layer| {
|
||||
let vector_data = document_metadata.compute_modified_vector(layer, document_network)?;
|
||||
let transform_to_screenspace = document_metadata.transform_to_viewport(layer);
|
||||
let vector_data = network_interface.document_metadata().compute_modified_vector(layer, network_interface)?;
|
||||
let transform_to_screenspace = network_interface.document_metadata().transform_to_viewport(layer);
|
||||
|
||||
let mut result = None;
|
||||
let mut closest_distance_squared = tolerance * tolerance;
|
||||
@@ -1145,15 +1138,15 @@ impl ShapeState {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn select_all_in_quad(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, quad: [DVec2; 2], clear_selection: bool) {
|
||||
pub fn select_all_in_quad(&mut self, network_interface: &NodeNetworkInterface, quad: [DVec2; 2], clear_selection: bool) {
|
||||
for (&layer, state) in &mut self.selected_shape_state {
|
||||
if clear_selection {
|
||||
state.clear_points()
|
||||
}
|
||||
|
||||
let vector_data = document_metadata.compute_modified_vector(layer, document_network);
|
||||
let vector_data = network_interface.document_metadata().compute_modified_vector(layer, network_interface);
|
||||
let Some(vector_data) = vector_data else { continue };
|
||||
let transform = document_metadata.transform_to_viewport(layer);
|
||||
let transform = network_interface.document_metadata().transform_to_viewport(layer);
|
||||
|
||||
assert_eq!(vector_data.segment_domain.ids().len(), vector_data.segment_domain.start_point().len());
|
||||
assert_eq!(vector_data.segment_domain.ids().len(), vector_data.segment_domain.end_point().len());
|
||||
|
||||
@@ -187,7 +187,7 @@ impl SnapManager {
|
||||
self.indicator = None;
|
||||
}
|
||||
pub fn preview_draw(&mut self, snap_data: &SnapData, mouse: DVec2) {
|
||||
let point = SnapCandidatePoint::handle(snap_data.document.metadata.document_to_viewport.inverse().transform_point2(mouse));
|
||||
let point = SnapCandidatePoint::handle(snap_data.document.metadata().document_to_viewport.inverse().transform_point2(mouse));
|
||||
let snapped = self.free_snap(snap_data, &point, None, false);
|
||||
self.update_indicator(snapped);
|
||||
}
|
||||
@@ -230,7 +230,7 @@ impl SnapManager {
|
||||
let mut best_point = None;
|
||||
|
||||
for point in snapped_points {
|
||||
let viewport_point = document.metadata.document_to_viewport.transform_point2(point.snapped_point_document);
|
||||
let viewport_point = document.metadata().document_to_viewport.transform_point2(point.snapped_point_document);
|
||||
let on_screen = viewport_point.cmpgt(DVec2::ZERO).all() && viewport_point.cmplt(snap_data.input.viewport_bounds.size()).all();
|
||||
if !on_screen && !off_screen {
|
||||
continue;
|
||||
@@ -258,29 +258,29 @@ impl SnapManager {
|
||||
if candidates.len() > 10 {
|
||||
return;
|
||||
}
|
||||
if !document.selected_nodes.layer_visible(layer, &document.metadata) {
|
||||
if !document.network_interface.selected_nodes(&[]).unwrap().layer_visible(layer, &document.network_interface) {
|
||||
return;
|
||||
}
|
||||
if snap_data.ignore.contains(&layer) {
|
||||
return;
|
||||
}
|
||||
if document.metadata.is_folder(layer) {
|
||||
for layer in layer.children(&document.metadata) {
|
||||
if layer.has_children(document.metadata()) {
|
||||
for layer in layer.children(document.metadata()) {
|
||||
add_candidates(layer, snap_data, quad, candidates);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let Some(bounds) = document.metadata.bounding_box_with_transform(layer, DAffine2::IDENTITY) else {
|
||||
let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) else {
|
||||
return;
|
||||
};
|
||||
let layer_bounds = document.metadata.transform_to_document(layer) * Quad::from_box(bounds);
|
||||
let screen_bounds = document.metadata.document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.input.viewport_bounds.size()]);
|
||||
let layer_bounds = document.metadata().transform_to_document(layer) * Quad::from_box(bounds);
|
||||
let screen_bounds = document.metadata().document_to_viewport.inverse() * Quad::from_box([DVec2::ZERO, snap_data.input.viewport_bounds.size()]);
|
||||
if quad.intersects(layer_bounds) && screen_bounds.intersects(layer_bounds) {
|
||||
candidates.push(layer);
|
||||
}
|
||||
}
|
||||
|
||||
for layer in LayerNodeIdentifier::ROOT_PARENT.children(&document.metadata) {
|
||||
for layer in LayerNodeIdentifier::ROOT_PARENT.children(document.metadata()) {
|
||||
add_candidates(layer, snap_data, quad, &mut candidates);
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ impl SnapManager {
|
||||
}
|
||||
|
||||
pub fn draw_overlays(&mut self, snap_data: SnapData, overlay_context: &mut OverlayContext) {
|
||||
let to_viewport = snap_data.document.metadata.document_to_viewport;
|
||||
let to_viewport = snap_data.document.metadata().document_to_viewport;
|
||||
if let Some(ind) = &self.indicator {
|
||||
for curve in &ind.curves {
|
||||
let Some(curve) = curve else { continue };
|
||||
|
||||
@@ -22,13 +22,16 @@ impl LayerSnapper {
|
||||
return;
|
||||
}
|
||||
|
||||
let bounds = if document.metadata.is_artboard(layer) {
|
||||
document.metadata.bounding_box_with_transform(layer, document.metadata.transform_to_document(layer)).map(Quad::from_box)
|
||||
let bounds = if document.network_interface.is_artboard(&layer.to_node(), &[]) {
|
||||
document
|
||||
.metadata()
|
||||
.bounding_box_with_transform(layer, document.metadata().transform_to_document(layer))
|
||||
.map(Quad::from_box)
|
||||
} else {
|
||||
document
|
||||
.metadata
|
||||
.metadata()
|
||||
.bounding_box_with_transform(layer, DAffine2::IDENTITY)
|
||||
.map(|bounds| document.metadata.transform_to_document(layer) * Quad::from_box(bounds))
|
||||
.map(|bounds| document.metadata().transform_to_document(layer) * Quad::from_box(bounds))
|
||||
};
|
||||
let Some(bounds) = bounds else { return };
|
||||
|
||||
@@ -53,21 +56,21 @@ impl LayerSnapper {
|
||||
let document = snap_data.document;
|
||||
self.paths_to_snap.clear();
|
||||
|
||||
for layer in document.metadata.all_layers() {
|
||||
if !document.metadata.is_artboard(layer) || snap_data.ignore.contains(&layer) {
|
||||
for layer in document.metadata().all_layers() {
|
||||
if !document.network_interface.is_artboard(&layer.to_node(), &[]) || snap_data.ignore.contains(&layer) {
|
||||
continue;
|
||||
}
|
||||
self.add_layer_bounds(document, layer, SnapTarget::Board(BoardSnapTarget::Edge));
|
||||
}
|
||||
for &layer in snap_data.get_candidates() {
|
||||
let transform = document.metadata.transform_to_document(layer);
|
||||
let transform = document.metadata().transform_to_document(layer);
|
||||
if !transform.is_finite() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if document.snapping_state.target_enabled(SnapTarget::Geometry(GeometrySnapTarget::Intersection)) || document.snapping_state.target_enabled(SnapTarget::Geometry(GeometrySnapTarget::Path))
|
||||
{
|
||||
for subpath in document.metadata.layer_outline(layer) {
|
||||
for subpath in document.metadata().layer_outline(layer) {
|
||||
for (start_index, curve) in subpath.iter().enumerate() {
|
||||
let document_curve = curve.apply_transformation(|p| transform.transform_point2(p));
|
||||
let start = subpath.manipulator_groups()[start_index].id;
|
||||
@@ -175,13 +178,17 @@ impl LayerSnapper {
|
||||
let document = snap_data.document;
|
||||
self.points_to_snap.clear();
|
||||
|
||||
for layer in document.metadata.all_layers() {
|
||||
if !document.metadata.is_artboard(layer) || snap_data.ignore.contains(&layer) {
|
||||
for layer in document.metadata().all_layers() {
|
||||
if !document.network_interface.is_artboard(&layer.to_node(), &[]) || snap_data.ignore.contains(&layer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if document.snapping_state.target_enabled(SnapTarget::Board(BoardSnapTarget::Corner)) {
|
||||
let Some(bounds) = document.metadata.bounding_box_with_transform(layer, document.metadata.transform_to_document(layer)) else {
|
||||
let Some(bounds) = document
|
||||
.network_interface
|
||||
.document_metadata()
|
||||
.bounding_box_with_transform(layer, document.metadata().transform_to_document(layer))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -194,10 +201,10 @@ impl LayerSnapper {
|
||||
if snap_data.ignore_bounds(layer) {
|
||||
continue;
|
||||
}
|
||||
let Some(bounds) = document.metadata.bounding_box_with_transform(layer, DAffine2::IDENTITY) else {
|
||||
let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) else {
|
||||
continue;
|
||||
};
|
||||
let quad = document.metadata.transform_to_document(layer) * Quad::from_box(bounds);
|
||||
let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds);
|
||||
let values = BBoxSnapValues::BOUNDING_BOX;
|
||||
get_bbox_points(quad, &mut self.points_to_snap, values, document);
|
||||
}
|
||||
@@ -441,17 +448,17 @@ pub fn are_manipulator_handles_colinear(group: &bezier_rs::ManipulatorGroup<Poin
|
||||
pub fn get_layer_snap_points(layer: LayerNodeIdentifier, snap_data: &SnapData, points: &mut Vec<SnapCandidatePoint>) {
|
||||
let document = snap_data.document;
|
||||
|
||||
if document.metadata().is_artboard(layer) {
|
||||
if document.network_interface.is_artboard(&layer.to_node(), &[]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if document.metadata().is_folder(layer) {
|
||||
if layer.has_children(document.metadata()) {
|
||||
for child in layer.descendants(document.metadata()) {
|
||||
get_layer_snap_points(child, snap_data, points);
|
||||
}
|
||||
} else if document.metadata.layer_outline(layer).next().is_some() {
|
||||
let to_document = document.metadata.transform_to_document(layer);
|
||||
for subpath in document.metadata.layer_outline(layer) {
|
||||
} else if document.metadata().layer_outline(layer).next().is_some() {
|
||||
let to_document = document.metadata().transform_to_document(layer);
|
||||
for subpath in document.metadata().layer_outline(layer) {
|
||||
subpath_anchor_snap_points(layer, subpath, snap_data, points, to_document);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl SelectedEdges {
|
||||
}
|
||||
|
||||
if let Some(SizeSnapData { manager, points, snap_data }) = snap {
|
||||
let view_to_doc = snap_data.document.metadata.document_to_viewport.inverse();
|
||||
let view_to_doc = snap_data.document.metadata().document_to_viewport.inverse();
|
||||
let bounds_to_doc = view_to_doc * transform;
|
||||
let mut best_snap = SnappedPoint::infinite_snap(pivot);
|
||||
let mut best_scale_factor = DVec2::ONE;
|
||||
@@ -220,10 +220,10 @@ pub fn axis_align_drag(axis_align: bool, position: DVec2, start: DVec2) -> DVec2
|
||||
pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &Vec<SnapCandidatePoint>) -> DVec2 {
|
||||
let mouse_position = axis_align_drag(axis_align, snap_data.input.mouse.position, start);
|
||||
let document = snap_data.document;
|
||||
let total_mouse_delta_document = document.metadata.document_to_viewport.inverse().transform_vector2(mouse_position - start);
|
||||
let mouse_delta_document = document.metadata.document_to_viewport.inverse().transform_vector2(mouse_position - current);
|
||||
let total_mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - start);
|
||||
let mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - current);
|
||||
let mut offset = mouse_delta_document;
|
||||
let mut best_snap = SnappedPoint::infinite_snap(document.metadata.document_to_viewport.inverse().transform_point2(mouse_position));
|
||||
let mut best_snap = SnappedPoint::infinite_snap(document.metadata().document_to_viewport.inverse().transform_point2(mouse_position));
|
||||
|
||||
for point in candidates {
|
||||
let mut point = point.clone();
|
||||
@@ -251,7 +251,7 @@ pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: Snap
|
||||
|
||||
snap_manager.update_indicator(best_snap);
|
||||
|
||||
document.metadata.document_to_viewport.transform_vector2(offset)
|
||||
document.metadata().document_to_viewport.transform_vector2(offset)
|
||||
}
|
||||
|
||||
/// Contains info on the overlays for the bounding box and transform handles
|
||||
|
||||
@@ -10,10 +10,10 @@ pub fn should_extend(document: &DocumentMessageHandler, goal: DVec2, tolerance:
|
||||
let mut best = None;
|
||||
let mut best_distance_squared = tolerance * tolerance;
|
||||
|
||||
for layer in document.selected_nodes.selected_layers(document.metadata()) {
|
||||
for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()) {
|
||||
let viewspace = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
let vector_data = document.metadata.compute_modified_vector(layer, document.network())?;
|
||||
let vector_data = document.metadata().compute_modified_vector(layer, &document.network_interface)?;
|
||||
for id in vector_data.single_connected_points() {
|
||||
let Some(point) = vector_data.point_domain.position_from_id(id) else { continue };
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use graphene_core::raster::color::Color;
|
||||
|
||||
pub struct ToolMessageData<'a> {
|
||||
pub document_id: DocumentId,
|
||||
pub document: &'a DocumentMessageHandler,
|
||||
pub document: &'a mut DocumentMessageHandler,
|
||||
pub input: &'a InputPreprocessorMessageHandler,
|
||||
pub persistent_data: &'a PersistentData,
|
||||
pub node_graph: &'a NodeGraphExecutor,
|
||||
|
||||
@@ -119,7 +119,7 @@ impl ArtboardToolData {
|
||||
|
||||
let Some(layer) = self.selected_artboard else { return };
|
||||
|
||||
if let Some(bounds) = document.metadata.bounding_box_with_transform(layer, document.metadata.transform_to_document(layer)) {
|
||||
if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, document.metadata().transform_to_document(layer)) {
|
||||
snapping::get_bbox_points(Quad::from_box(bounds), &mut self.snap_candidates, snapping::BBoxSnapValues::ARTBOARD, document);
|
||||
}
|
||||
}
|
||||
@@ -142,9 +142,7 @@ impl ArtboardToolData {
|
||||
}
|
||||
|
||||
fn hovered_artboard(document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) -> Option<LayerNodeIdentifier> {
|
||||
document
|
||||
.click_xray(input.mouse.position)
|
||||
.find(|&layer| document.network.nodes.get(&layer.to_node()).map_or(false, |document_node| document_node.is_artboard()))
|
||||
document.click_xray(input).find(|&layer| document.network_interface.is_artboard(&layer.to_node(), &[]))
|
||||
}
|
||||
|
||||
fn select_artboard(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> bool {
|
||||
@@ -196,7 +194,7 @@ impl ArtboardToolData {
|
||||
let size = (max - min).abs();
|
||||
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
id: self.selected_artboard.unwrap().to_node(),
|
||||
layer: self.selected_artboard.unwrap(),
|
||||
location: position.round().as_ivec2(),
|
||||
dimensions: size.round().as_ivec2(),
|
||||
});
|
||||
@@ -294,7 +292,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||
return ArtboardToolFsmState::Ready { hovered };
|
||||
}
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
id: tool_data.selected_artboard.unwrap().to_node(),
|
||||
layer: tool_data.selected_artboard.unwrap(),
|
||||
location: position.round().as_ivec2(),
|
||||
dimensions: size.round().as_ivec2(),
|
||||
});
|
||||
@@ -350,7 +348,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||
log::error!("Selected artboard cannot be ROOT_PARENT");
|
||||
} else {
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
id: artboard.to_node(),
|
||||
layer: artboard,
|
||||
location: start.min(end).round().as_ivec2(),
|
||||
dimensions: (start.round() - end.round()).abs().as_ivec2(),
|
||||
});
|
||||
@@ -460,12 +458,17 @@ impl Fsm for ArtboardToolFsmState {
|
||||
ArtboardToolFsmState::Ready { hovered }
|
||||
}
|
||||
(_, ArtboardToolMessage::UpdateSelectedArtboard) => {
|
||||
tool_data.selected_artboard = document.selected_nodes.selected_layers(document.metadata()).find(|layer| document.metadata().is_artboard(*layer));
|
||||
tool_data.selected_artboard = document
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_layers(document.metadata())
|
||||
.find(|layer| document.network_interface.is_artboard(&layer.to_node(), &[]));
|
||||
self
|
||||
}
|
||||
(_, ArtboardToolMessage::DeleteSelected) => {
|
||||
tool_data.selected_artboard.take();
|
||||
responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
|
||||
responses.add(DocumentMessage::DeleteSelectedLayers);
|
||||
|
||||
ArtboardToolFsmState::Ready { hovered }
|
||||
}
|
||||
@@ -475,7 +478,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||
log::error!("Selected artboard cannot be ROOT_PARENT");
|
||||
} else {
|
||||
responses.add(GraphOperationMessage::ResizeArtboard {
|
||||
id: tool_data.selected_artboard.unwrap().to_node(),
|
||||
layer: tool_data.selected_artboard.unwrap(),
|
||||
location: DVec2::new(bounds.bounds[0].x + delta_x, bounds.bounds[0].y + delta_y).round().as_ivec2(),
|
||||
dimensions: (bounds.bounds[1] - bounds.bounds[0]).round().as_ivec2(),
|
||||
});
|
||||
|
||||
@@ -2,10 +2,11 @@ use super::tool_prelude::*;
|
||||
use crate::messages::portfolio::document::graph_operation::transform_utils::{get_current_normalized_pivot, get_current_transform};
|
||||
use crate::messages::portfolio::document::node_graph::document_node_types::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNodeMetadata, NodeId};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_core::raster::BlendMode;
|
||||
use graphene_core::uuid::generate_uuid;
|
||||
use graphene_core::vector::brush_stroke::{BrushInputSample, BrushStroke, BrushStyle};
|
||||
@@ -259,14 +260,20 @@ impl BrushToolData {
|
||||
fn load_existing_strokes(&mut self, document: &DocumentMessageHandler) -> Option<LayerNodeIdentifier> {
|
||||
self.transform = DAffine2::IDENTITY;
|
||||
|
||||
if document.selected_nodes.selected_layers(document.metadata()).count() != 1 {
|
||||
if document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).count() != 1 {
|
||||
return None;
|
||||
}
|
||||
let layer = document.selected_nodes.selected_layers(document.metadata()).next()?;
|
||||
let layer = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).next()?;
|
||||
|
||||
self.layer = Some(layer);
|
||||
for (node, node_id) in document.network().upstream_flow_back_from_nodes(vec![layer.to_node()], graph_craft::document::FlowType::HorizontalFlow) {
|
||||
if node.name == "Brush" && node_id != layer.to_node() {
|
||||
for node_id in document.network_interface.upstream_flow_back_from_nodes(vec![layer.to_node()], &[], FlowType::HorizontalFlow) {
|
||||
let Some(node) = document.network_interface.network(&[]).unwrap().nodes.get(&node_id) else {
|
||||
continue;
|
||||
};
|
||||
let Some(reference) = document.network_interface.reference(&node_id, &[]) else {
|
||||
continue;
|
||||
};
|
||||
if reference == "Brush" && node_id != layer.to_node() {
|
||||
let points_input = node.inputs.get(2)?;
|
||||
let Some(TaggedValue::BrushStrokes(strokes)) = points_input.as_value() else {
|
||||
continue;
|
||||
@@ -274,7 +281,7 @@ impl BrushToolData {
|
||||
self.strokes.clone_from(strokes);
|
||||
|
||||
return Some(layer);
|
||||
} else if node.name == "Transform" {
|
||||
} else if reference == "Transform" {
|
||||
let upstream = document.metadata().upstream_transform(node_id);
|
||||
let pivot = DAffine2::from_translation(upstream.transform_point2(get_current_normalized_pivot(&node.inputs)));
|
||||
self.transform = pivot * get_current_transform(&node.inputs) * pivot.inverse() * self.transform;
|
||||
@@ -313,7 +320,12 @@ impl Fsm for BrushToolFsmState {
|
||||
tool_data.layer = Some(layer);
|
||||
|
||||
let parent = layer.parent(document.metadata()).unwrap_or_else(|| document.new_layer_parent(true));
|
||||
let parent_transform = document.metadata().transform_to_viewport(parent).inverse().transform_point2(input.mouse.position);
|
||||
let parent_transform = document
|
||||
.network_interface
|
||||
.document_metadata()
|
||||
.transform_to_viewport(parent)
|
||||
.inverse()
|
||||
.transform_point2(input.mouse.position);
|
||||
let layer_position = tool_data.transform.inverse().transform_point2(parent_transform);
|
||||
|
||||
let layer_document_scale = document.metadata().transform_to_document(parent) * tool_data.transform;
|
||||
@@ -351,7 +363,12 @@ impl Fsm for BrushToolFsmState {
|
||||
if let Some(layer) = tool_data.layer {
|
||||
if let Some(stroke) = tool_data.strokes.last_mut() {
|
||||
let parent = layer.parent(document.metadata()).unwrap_or(LayerNodeIdentifier::ROOT_PARENT);
|
||||
let parent_position = document.metadata().transform_to_viewport(parent).inverse().transform_point2(input.mouse.position);
|
||||
let parent_position = document
|
||||
.network_interface
|
||||
.document_metadata()
|
||||
.transform_to_viewport(parent)
|
||||
.inverse()
|
||||
.transform_point2(input.mouse.position);
|
||||
let layer_position = tool_data.transform.inverse().transform_point2(parent_position);
|
||||
|
||||
stroke.trace.push(BrushInputSample { position: layer_position })
|
||||
@@ -407,17 +424,14 @@ impl Fsm for BrushToolFsmState {
|
||||
fn new_brush_layer(document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
|
||||
responses.add(DocumentMessage::DeselectAllLayers);
|
||||
|
||||
let brush_node = resolve_document_node_type("Brush")
|
||||
.expect("Brush node does not exist")
|
||||
.to_document_node_default_inputs([], DocumentNodeMetadata::position((-6, 0)));
|
||||
let brush_node = resolve_document_node_type("Brush").expect("Brush node does not exist").default_node_template();
|
||||
|
||||
let id = NodeId(generate_uuid());
|
||||
responses.add(GraphOperationMessage::NewCustomLayer {
|
||||
id,
|
||||
nodes: HashMap::from([(NodeId(0), brush_node)]),
|
||||
nodes: vec![(NodeId(0), brush_node)],
|
||||
parent: document.new_layer_parent(true),
|
||||
insert_index: -1,
|
||||
alias: String::new(),
|
||||
insert_index: 0,
|
||||
});
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });
|
||||
|
||||
|
||||
@@ -201,15 +201,10 @@ impl Fsm for EllipseToolFsmState {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
// Create a new ellipse vector shape
|
||||
let nodes = {
|
||||
let node_type = resolve_document_node_type("Ellipse").expect("Ellipse node does not exist");
|
||||
let node = node_type.to_document_node_default_inputs(
|
||||
[None, Some(NodeInput::value(TaggedValue::F64(0.5), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))],
|
||||
Default::default(),
|
||||
);
|
||||
let node_type = resolve_document_node_type("Ellipse").expect("Ellipse node does not exist");
|
||||
let node = node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.5), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
HashMap::from([(NodeId(0), node)])
|
||||
};
|
||||
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(true), responses);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
|
||||
|
||||
@@ -87,7 +87,7 @@ impl Fsm for FillToolFsmState {
|
||||
|
||||
match (self, event) {
|
||||
(FillToolFsmState::Ready, color_event) => {
|
||||
let Some(layer_identifier) = document.click(input.mouse.position, &document.network) else {
|
||||
let Some(layer_identifier) = document.click(input) else {
|
||||
return self;
|
||||
};
|
||||
let fill = match color_event {
|
||||
|
||||
@@ -224,12 +224,9 @@ impl Fsm for FreehandToolFsmState {
|
||||
|
||||
let parent = document.new_layer_parent(true);
|
||||
|
||||
let nodes = {
|
||||
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
|
||||
let node = node_type.to_document_node_default_inputs([], Default::default());
|
||||
|
||||
HashMap::from([(NodeId(0), node)])
|
||||
};
|
||||
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
|
||||
let node = node_type.default_node_template();
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, parent, responses);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
|
||||
@@ -249,8 +249,8 @@ impl Fsm for GradientToolFsmState {
|
||||
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
|
||||
let selected = tool_data.selected_gradient.as_ref();
|
||||
|
||||
for layer in document.selected_nodes.selected_visible_layers(document.metadata()) {
|
||||
let Some(gradient) = get_gradient(layer, &document.network) else { continue };
|
||||
for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_visible_layers(&document.network_interface) {
|
||||
let Some(gradient) = get_gradient(layer, &document.network_interface) else { continue };
|
||||
let transform = gradient_space_transform(layer, document);
|
||||
let dragging = selected
|
||||
.filter(|selected| selected.layer.map_or(false, |selected_layer| selected_layer == layer))
|
||||
@@ -324,8 +324,8 @@ impl Fsm for GradientToolFsmState {
|
||||
self
|
||||
}
|
||||
(_, GradientToolMessage::InsertStop) => {
|
||||
for layer in document.selected_nodes.selected_visible_layers(document.metadata()) {
|
||||
let Some(mut gradient) = get_gradient(layer, &document.network) else { continue };
|
||||
for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_visible_layers(&document.network_interface) {
|
||||
let Some(mut gradient) = get_gradient(layer, &document.network_interface) else { continue };
|
||||
let transform = gradient_space_transform(layer, document);
|
||||
|
||||
let mouse = input.mouse.position;
|
||||
@@ -363,8 +363,8 @@ impl Fsm for GradientToolFsmState {
|
||||
let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
|
||||
|
||||
let mut dragging = false;
|
||||
for layer in document.selected_nodes.selected_visible_layers(document.metadata()) {
|
||||
let Some(gradient) = get_gradient(layer, &document.network) else { continue };
|
||||
for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_visible_layers(&document.network_interface) {
|
||||
let Some(gradient) = get_gradient(layer, &document.network_interface) else { continue };
|
||||
let transform = gradient_space_transform(layer, document);
|
||||
|
||||
// Check for dragging step
|
||||
@@ -399,11 +399,11 @@ impl Fsm for GradientToolFsmState {
|
||||
document.backup_nonmut(responses);
|
||||
GradientToolFsmState::Drawing
|
||||
} else {
|
||||
let selected_layer = document.click(input.mouse.position, &document.network);
|
||||
let selected_layer = document.click(input);
|
||||
|
||||
// Apply the gradient to the selected layer
|
||||
if let Some(layer) = selected_layer {
|
||||
if !document.selected_nodes.selected_layers_contains(layer, document.metadata()) {
|
||||
if !document.network_interface.selected_nodes(&[]).unwrap().selected_layers_contains(layer, document.metadata()) {
|
||||
let nodes = vec![layer.to_node()];
|
||||
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes });
|
||||
@@ -412,7 +412,7 @@ impl Fsm for GradientToolFsmState {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
// Use the already existing gradient if it exists
|
||||
let gradient = if let Some(gradient) = get_gradient(layer, &document.network) {
|
||||
let gradient = if let Some(gradient) = get_gradient(layer, &document.network_interface) {
|
||||
gradient.clone()
|
||||
} else {
|
||||
// Generate a new gradient
|
||||
|
||||
@@ -101,7 +101,7 @@ impl Fsm for ImaginateToolFsmState {
|
||||
(ImaginateToolFsmState::Ready, ImaginateToolMessage::DragStart) => {
|
||||
shape_data.start(document, input);
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
shape_data.layer = Some(LayerNodeIdentifier::new(NodeId(generate_uuid()), document.network()));
|
||||
shape_data.layer = Some(LayerNodeIdentifier::new(NodeId(generate_uuid()), &document.network_interface));
|
||||
responses.add(DocumentMessage::DeselectAllLayers);
|
||||
|
||||
// // Utility function to offset the position of each consecutive node
|
||||
@@ -120,7 +120,7 @@ impl Fsm for ImaginateToolFsmState {
|
||||
|
||||
// // Give them a unique ID
|
||||
// let transform_node_id = NodeId(100);
|
||||
let imaginate_node_id = NodeId(101);
|
||||
//let imaginate_node_id = NodeId(101);
|
||||
|
||||
// Create the network based on the Input -> Output passthrough default network
|
||||
// let mut network = new_image_network(16, imaginate_node_id);
|
||||
@@ -134,7 +134,7 @@ impl Fsm for ImaginateToolFsmState {
|
||||
// imaginate_node_id,
|
||||
// imaginate_node_type.to_document_node_default_inputs([Some(NodeInput::node(transform_node_id, 0))], next_pos()),
|
||||
// );
|
||||
responses.add(NodeGraphMessage::ShiftNode { node_id: imaginate_node_id });
|
||||
// responses.add(NodeGraphMessage::ShiftNode { node_id: imaginate_node_id });
|
||||
|
||||
// // Add a layer with a frame to the document
|
||||
// responses.add(Operation::AddFrame {
|
||||
|
||||
@@ -173,25 +173,20 @@ impl Fsm for LineToolFsmState {
|
||||
self
|
||||
}
|
||||
(LineToolFsmState::Ready, LineToolMessage::DragStart) => {
|
||||
let point = SnapCandidatePoint::handle(document.metadata.document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, None, false);
|
||||
tool_data.drag_start = snapped.snapped_point_document;
|
||||
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
let nodes = {
|
||||
let node_type = resolve_document_node_type("Line").expect("Line node does not exist");
|
||||
let node = node_type.to_document_node_default_inputs(
|
||||
[
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(DVec2::X), false)),
|
||||
],
|
||||
Default::default(),
|
||||
);
|
||||
let node_type = resolve_document_node_type("Line").expect("Line node does not exist");
|
||||
let node = node_type.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(DVec2::X), false)),
|
||||
]);
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
HashMap::from([(NodeId(0), node)])
|
||||
};
|
||||
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(false), responses);
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
|
||||
tool_data.layer = Some(layer);
|
||||
@@ -296,7 +291,7 @@ impl Fsm for LineToolFsmState {
|
||||
}
|
||||
|
||||
fn generate_transform(tool_data: &mut LineToolData, snap_data: SnapData, lock_angle: bool, snap_angle: bool, center: bool) -> Message {
|
||||
let document_to_viewport = snap_data.document.metadata.document_to_viewport;
|
||||
let document_to_viewport = snap_data.document.metadata().document_to_viewport;
|
||||
let mut document_points = [tool_data.drag_start, document_to_viewport.inverse().transform_point2(tool_data.drag_current)];
|
||||
|
||||
let mut angle = -(document_points[1] - document_points[0]).angle_to(DVec2::X);
|
||||
|
||||
@@ -2,12 +2,12 @@ use super::tool_prelude::*;
|
||||
use crate::consts::{COLOR_OVERLAY_YELLOW, DRAG_THRESHOLD, INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
|
||||
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::shape_editor::{ClosestSegment, ManipulatorAngle, ManipulatorPointInfo, OpposingHandleLengths, SelectedPointsInfo, ShapeState};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapData, SnapManager};
|
||||
|
||||
use graph_craft::document::NodeNetwork;
|
||||
use graphene_core::renderer::Quad;
|
||||
use graphene_core::vector::ManipulatorPointId;
|
||||
|
||||
@@ -272,10 +272,10 @@ impl PathToolData {
|
||||
PathToolFsmState::InsertPoint
|
||||
}
|
||||
|
||||
fn update_insertion(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, mouse_position: DVec2) -> PathToolFsmState {
|
||||
fn update_insertion(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, input: &InputPreprocessorMessageHandler) -> PathToolFsmState {
|
||||
if let Some(closed_segment) = &mut self.segment {
|
||||
closed_segment.update_closest_point(&document.metadata, mouse_position);
|
||||
if closed_segment.too_far(mouse_position, INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE, &document.metadata) {
|
||||
closed_segment.update_closest_point(document.metadata(), input.mouse.position);
|
||||
if closed_segment.too_far(input.mouse.position, INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE, document.metadata()) {
|
||||
self.end_insertion(shape_editor, responses, InsertEndKind::Abort)
|
||||
} else {
|
||||
PathToolFsmState::InsertPoint
|
||||
@@ -317,13 +317,10 @@ impl PathToolData {
|
||||
self.double_click_handled = false;
|
||||
self.opposing_handle_lengths = None;
|
||||
|
||||
let document_network = document.network();
|
||||
let document_metadata = document.metadata();
|
||||
|
||||
self.drag_start_pos = input.mouse.position;
|
||||
|
||||
// Select the first point within the threshold (in pixels)
|
||||
if let Some(selected_points) = shape_editor.change_point_selection(document_network, document_metadata, input.mouse.position, SELECTION_THRESHOLD, add_to_selection) {
|
||||
if let Some(selected_points) = shape_editor.change_point_selection(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD, add_to_selection) {
|
||||
if let Some(selected_points) = selected_points {
|
||||
self.drag_start_pos = input.mouse.position;
|
||||
self.start_dragging_point(selected_points, input, document, responses);
|
||||
@@ -332,7 +329,7 @@ impl PathToolData {
|
||||
PathToolFsmState::Dragging
|
||||
}
|
||||
// We didn't find a point nearby, so now we'll try to add a point into the closest path segment
|
||||
else if let Some(closed_segment) = shape_editor.upper_closest_segment(document_network, document_metadata, input.mouse.position, SELECTION_TOLERANCE) {
|
||||
else if let Some(closed_segment) = shape_editor.upper_closest_segment(&document.network_interface, input.mouse.position, SELECTION_TOLERANCE) {
|
||||
if direct_insert_without_sliding {
|
||||
self.start_insertion(responses, closed_segment);
|
||||
self.end_insertion(shape_editor, responses, InsertEndKind::Add { shift: add_to_selection })
|
||||
@@ -341,14 +338,14 @@ impl PathToolData {
|
||||
}
|
||||
}
|
||||
// We didn't find a segment path, so consider selecting the nearest shape instead
|
||||
else if let Some(layer) = document.click(input.mouse.position, &document.network) {
|
||||
else if let Some(layer) = document.click(input) {
|
||||
if add_to_selection {
|
||||
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![layer.to_node()] });
|
||||
} else {
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
|
||||
}
|
||||
self.drag_start_pos = input.mouse.position;
|
||||
self.previous_mouse_position = document.metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
shape_editor.select_connected_anchors(document, layer, input.mouse.position);
|
||||
|
||||
PathToolFsmState::Dragging
|
||||
@@ -356,7 +353,7 @@ impl PathToolData {
|
||||
// Start drawing a box
|
||||
else {
|
||||
self.drag_start_pos = input.mouse.position;
|
||||
self.previous_mouse_position = document.metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
|
||||
PathToolFsmState::DrawingBox
|
||||
}
|
||||
@@ -383,7 +380,7 @@ impl PathToolData {
|
||||
}
|
||||
selected_points.points.extend(additional_selected_points);
|
||||
|
||||
let viewport_to_document = document.metadata.document_to_viewport.inverse();
|
||||
let viewport_to_document = document.metadata().document_to_viewport.inverse();
|
||||
self.previous_mouse_position = viewport_to_document.transform_point2(input.mouse.position - selected_points.offset);
|
||||
}
|
||||
|
||||
@@ -397,7 +394,7 @@ impl PathToolData {
|
||||
ManipulatorAngle::Mixed => false,
|
||||
});
|
||||
if colinear {
|
||||
shape_editor.disable_colinear_handles_state_on_selected(&document.metadata, &document.network, responses);
|
||||
shape_editor.disable_colinear_handles_state_on_selected(&document.network_interface, responses);
|
||||
} else {
|
||||
shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document);
|
||||
}
|
||||
@@ -414,11 +411,11 @@ impl PathToolData {
|
||||
|
||||
fn drag(&mut self, equidistant: bool, shape_editor: &mut ShapeState, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
// Move the selected points with the mouse
|
||||
let previous_mouse = document.metadata.document_to_viewport.transform_point2(self.previous_mouse_position);
|
||||
let previous_mouse = document.metadata().document_to_viewport.transform_point2(self.previous_mouse_position);
|
||||
let snapped_delta = shape_editor.snap(&mut self.snap_manager, document, input, previous_mouse);
|
||||
let handle_lengths = if equidistant { None } else { self.opposing_handle_lengths.take() };
|
||||
shape_editor.move_selected_points(handle_lengths, document, snapped_delta, equidistant, responses);
|
||||
self.previous_mouse_position += document.metadata.document_to_viewport.inverse().transform_vector2(snapped_delta);
|
||||
self.previous_mouse_position += document.metadata().document_to_viewport.inverse().transform_vector2(snapped_delta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +432,7 @@ impl Fsm for PathToolFsmState {
|
||||
match (self, event) {
|
||||
(_, PathToolMessage::SelectionChanged) => {
|
||||
// Set the newly targeted layers to visible
|
||||
let target_layers = document.selected_nodes.selected_layers(document.metadata()).collect();
|
||||
let target_layers = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect();
|
||||
shape_editor.set_selected_layers(target_layers);
|
||||
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
@@ -454,7 +451,7 @@ impl Fsm for PathToolFsmState {
|
||||
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
||||
}
|
||||
Self::InsertPoint => {
|
||||
let state = tool_data.update_insertion(shape_editor, document, responses, input.mouse.position);
|
||||
let state = tool_data.update_insertion(shape_editor, document, responses, input);
|
||||
|
||||
if let Some(closest_segment) = &tool_data.segment {
|
||||
overlay_context.manipulator_anchor(closest_segment.closest_point_to_viewport(), false, Some(COLOR_OVERLAY_YELLOW));
|
||||
@@ -552,7 +549,7 @@ impl Fsm for PathToolFsmState {
|
||||
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
|
||||
} else {
|
||||
shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
|
||||
shape_editor.select_all_in_quad(&document.network_interface, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
|
||||
}
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
|
||||
@@ -576,7 +573,7 @@ impl Fsm for PathToolFsmState {
|
||||
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
|
||||
} else {
|
||||
shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !equidistant);
|
||||
shape_editor.select_all_in_quad(&document.network_interface, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !equidistant);
|
||||
}
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
responses.add(PathToolMessage::SelectedPointUpdated);
|
||||
@@ -586,7 +583,7 @@ impl Fsm for PathToolFsmState {
|
||||
(_, PathToolMessage::DragStop { equidistant }) => {
|
||||
let equidistant = input.keyboard.get(equidistant as usize);
|
||||
|
||||
let nearest_point = shape_editor.find_nearest_point_indices(&document.network, &document.metadata, input.mouse.position, SELECTION_THRESHOLD);
|
||||
let nearest_point = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD);
|
||||
|
||||
if let Some((layer, nearest_point)) = nearest_point {
|
||||
if tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD && !equidistant {
|
||||
@@ -623,7 +620,7 @@ impl Fsm for PathToolFsmState {
|
||||
}
|
||||
(_, PathToolMessage::FlipSmoothSharp) => {
|
||||
if !tool_data.double_click_handled {
|
||||
shape_editor.flip_smooth_sharp(&document.network, &document.metadata, input.mouse.position, SELECTION_TOLERANCE, responses);
|
||||
shape_editor.flip_smooth_sharp(&document.network_interface, input.mouse.position, SELECTION_TOLERANCE, responses);
|
||||
responses.add(PathToolMessage::SelectedPointUpdated);
|
||||
}
|
||||
self
|
||||
@@ -650,18 +647,18 @@ impl Fsm for PathToolFsmState {
|
||||
}
|
||||
(_, PathToolMessage::SelectedPointXChanged { new_x }) => {
|
||||
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
|
||||
shape_editor.reposition_control_point(&id, &document.network, &document.metadata, DVec2::new(new_x, coordinates.y), layer, responses);
|
||||
shape_editor.reposition_control_point(&id, &document.network_interface, DVec2::new(new_x, coordinates.y), layer, responses);
|
||||
}
|
||||
PathToolFsmState::Ready
|
||||
}
|
||||
(_, PathToolMessage::SelectedPointYChanged { new_y }) => {
|
||||
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
|
||||
shape_editor.reposition_control_point(&id, &document.network, &document.metadata, DVec2::new(coordinates.x, new_y), layer, responses);
|
||||
shape_editor.reposition_control_point(&id, &document.network_interface, DVec2::new(coordinates.x, new_y), layer, responses);
|
||||
}
|
||||
PathToolFsmState::Ready
|
||||
}
|
||||
(_, PathToolMessage::SelectedPointUpdated) => {
|
||||
tool_data.selection_status = get_selection_status(&document.network, &document.metadata, shape_editor);
|
||||
tool_data.selection_status = get_selection_status(&document.network_interface, shape_editor);
|
||||
self
|
||||
}
|
||||
(_, PathToolMessage::ManipulatorMakeHandlesColinear) => {
|
||||
@@ -673,7 +670,7 @@ impl Fsm for PathToolFsmState {
|
||||
}
|
||||
(_, PathToolMessage::ManipulatorMakeHandlesFree) => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
shape_editor.disable_colinear_handles_state_on_selected(&document.metadata, &document.network, responses);
|
||||
shape_editor.disable_colinear_handles_state_on_selected(&document.network_interface, responses);
|
||||
responses.add(DocumentMessage::CommitTransaction);
|
||||
PathToolFsmState::Ready
|
||||
}
|
||||
@@ -776,7 +773,7 @@ struct SingleSelectedPoint {
|
||||
|
||||
/// Sets the cumulative description of the selected points: if `None` are selected, if `One` is selected, or if `Multiple` are selected.
|
||||
/// Applies to any selected points, whether they are anchors or handles; and whether they are from a single shape or across multiple shapes.
|
||||
fn get_selection_status(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, shape_state: &mut ShapeState) -> SelectionStatus {
|
||||
fn get_selection_status(network_interface: &NodeNetworkInterface, shape_state: &mut ShapeState) -> SelectionStatus {
|
||||
let mut selection_layers = shape_state.selected_shape_state.iter().map(|(k, v)| (*k, v.selected_points_count()));
|
||||
let total_selected_points = selection_layers.clone().map(|(_, v)| v).sum::<usize>();
|
||||
|
||||
@@ -785,7 +782,7 @@ fn get_selection_status(document_network: &NodeNetwork, document_metadata: &Docu
|
||||
let Some(layer) = selection_layers.find(|(_, v)| *v > 0).map(|(k, _)| k) else {
|
||||
return SelectionStatus::None;
|
||||
};
|
||||
let Some(vector_data) = document_metadata.compute_modified_vector(layer, document_network) else {
|
||||
let Some(vector_data) = network_interface.document_metadata().compute_modified_vector(layer, network_interface) else {
|
||||
return SelectionStatus::None;
|
||||
};
|
||||
let Some(&point) = shape_state.selected_points().next() else {
|
||||
@@ -795,7 +792,7 @@ fn get_selection_status(document_network: &NodeNetwork, document_metadata: &Docu
|
||||
return SelectionStatus::None;
|
||||
};
|
||||
|
||||
let coordinates = document_metadata.transform_to_document(layer).transform_point2(local_position);
|
||||
let coordinates = network_interface.document_metadata().transform_to_document(layer).transform_point2(local_position);
|
||||
let manipulator_angle = if vector_data.colinear(point) { ManipulatorAngle::Colinear } else { ManipulatorAngle::Free };
|
||||
|
||||
return SelectionStatus::One(SingleSelectedPoint {
|
||||
@@ -809,7 +806,7 @@ fn get_selection_status(document_network: &NodeNetwork, document_metadata: &Docu
|
||||
// Check to see if multiple manipulator groups are selected
|
||||
if total_selected_points > 1 {
|
||||
return SelectionStatus::Multiple(MultipleSelectedPoints {
|
||||
manipulator_angle: shape_state.selected_manipulator_angles(document_network, document_metadata),
|
||||
manipulator_angle: shape_state.selected_manipulator_angles(network_interface),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ impl PenToolData {
|
||||
|
||||
// Break the control
|
||||
let Some(last_pos) = self.latest_point().map(|point| point.pos) else { return };
|
||||
let transform = document.metadata.document_to_viewport * transform;
|
||||
let transform = document.metadata().document_to_viewport * transform;
|
||||
let on_top = transform.transform_point2(self.next_point).distance_squared(transform.transform_point2(last_pos)) < crate::consts::SNAP_POINT_TOLERANCE.powi(2);
|
||||
if on_top {
|
||||
if let Some(point) = self.latest_point_mut() {
|
||||
@@ -269,9 +269,9 @@ impl PenToolData {
|
||||
// Get close path
|
||||
let mut end = None;
|
||||
let layer = self.layer?;
|
||||
let vector_data = document.metadata.compute_modified_vector(layer, &document.network)?;
|
||||
let vector_data = document.metadata().compute_modified_vector(layer, &document.network_interface)?;
|
||||
let start = self.latest_point()?.id;
|
||||
let transform = document.metadata.document_to_viewport * transform;
|
||||
let transform = document.metadata().document_to_viewport * transform;
|
||||
for id in vector_data.single_connected_points().filter(|&point| point != start) {
|
||||
let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue };
|
||||
let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(next_point));
|
||||
@@ -348,7 +348,7 @@ impl PenToolData {
|
||||
fn compute_snapped_angle(&mut self, snap_data: SnapData, transform: DAffine2, colinear: bool, mouse: DVec2, relative: Option<DVec2>, neighbor: bool) -> DVec2 {
|
||||
let ModifierState { snap_angle, lock_angle, .. } = self.modifiers;
|
||||
let document = snap_data.document;
|
||||
let mut document_pos = document.metadata.document_to_viewport.inverse().transform_point2(mouse);
|
||||
let mut document_pos = document.metadata().document_to_viewport.inverse().transform_point2(mouse);
|
||||
let snap = &mut self.snap_manager;
|
||||
|
||||
let neighbors = relative.filter(|_| neighbor).map_or(Vec::new(), |neighbor| vec![neighbor]);
|
||||
@@ -455,7 +455,7 @@ impl Fsm for PenToolFsmState {
|
||||
self
|
||||
}
|
||||
(_, PenToolMessage::Overlays(mut overlay_context)) => {
|
||||
let transform = document.metadata.document_to_viewport * transform;
|
||||
let transform = document.metadata().document_to_viewport * transform;
|
||||
if let (Some((start, handle_start)), Some(handle_end)) = (tool_data.latest_point().map(|point| (point.pos, point.handle_start)), tool_data.handle_end) {
|
||||
let handles = BezierHandles::Cubic { handle_start, handle_end };
|
||||
let bezier = Bezier {
|
||||
@@ -508,9 +508,9 @@ impl Fsm for PenToolFsmState {
|
||||
(PenToolFsmState::Ready, PenToolMessage::DragStart) => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
let point = SnapCandidatePoint::handle(document.metadata.document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let snapped = tool_data.snap_manager.free_snap(&SnapData::new(document, input), &point, None, false);
|
||||
let viewport = document.metadata.document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||
|
||||
// Perform extension of an existing path
|
||||
if let Some((layer, point, position)) = should_extend(document, viewport, crate::consts::SNAP_POINT_TOLERANCE) {
|
||||
@@ -525,10 +525,8 @@ impl Fsm for PenToolFsmState {
|
||||
tool_data.next_handle_start = position;
|
||||
} else {
|
||||
// New path layer
|
||||
let nodes = {
|
||||
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
|
||||
HashMap::from([(NodeId(0), node_type.to_document_node_default_inputs([], Default::default()))])
|
||||
};
|
||||
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
|
||||
let nodes = vec![(NodeId(0), node_type.default_node_template())];
|
||||
|
||||
let parent = document.new_layer_parent(true);
|
||||
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, parent, responses);
|
||||
|
||||
@@ -244,31 +244,24 @@ impl Fsm for PolygonToolFsmState {
|
||||
polygon_data.start(document, input);
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
let nodes = {
|
||||
let node = match tool_options.polygon_type {
|
||||
PolygonType::Convex => resolve_document_node_type("Regular Polygon")
|
||||
.expect("Regular Polygon node does not exist")
|
||||
.to_document_node_default_inputs(
|
||||
[
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::U32(tool_options.vertices), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(0.5), false)),
|
||||
],
|
||||
Default::default(),
|
||||
),
|
||||
PolygonType::Star => resolve_document_node_type("Star").expect("Star node does not exist").to_document_node_default_inputs(
|
||||
[
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::U32(tool_options.vertices), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(0.5), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(0.25), false)),
|
||||
],
|
||||
Default::default(),
|
||||
),
|
||||
};
|
||||
|
||||
HashMap::from([(NodeId(0), node)])
|
||||
let node = match tool_options.polygon_type {
|
||||
PolygonType::Convex => resolve_document_node_type("Regular Polygon")
|
||||
.expect("Regular Polygon node does not exist")
|
||||
.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::U32(tool_options.vertices), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(0.5), false)),
|
||||
]),
|
||||
PolygonType::Star => resolve_document_node_type("Star").expect("Star node does not exist").node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::U32(tool_options.vertices), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(0.5), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(0.25), false)),
|
||||
]),
|
||||
};
|
||||
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(false), responses);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
|
||||
|
||||
@@ -207,15 +207,10 @@ impl Fsm for RectangleToolFsmState {
|
||||
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
let nodes = {
|
||||
let node_type = resolve_document_node_type("Rectangle").expect("Rectangle node does not exist");
|
||||
let node = node_type.to_document_node_default_inputs(
|
||||
[None, Some(NodeInput::value(TaggedValue::F64(1.), false)), Some(NodeInput::value(TaggedValue::F64(1.), false))],
|
||||
Default::default(),
|
||||
);
|
||||
let node_type = resolve_document_node_type("Rectangle").expect("Rectangle node does not exist");
|
||||
let node = node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(1.), false)), Some(NodeInput::value(TaggedValue::F64(1.), false))]);
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
HashMap::from([(NodeId(0), node)])
|
||||
};
|
||||
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(true), responses);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::transformation::Selected;
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name;
|
||||
@@ -15,7 +16,7 @@ use crate::messages::tool::common_functionality::pivot::Pivot;
|
||||
use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapManager};
|
||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||
|
||||
use graph_craft::document::{DocumentNode, NodeId, NodeNetwork};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_core::renderer::Quad;
|
||||
use graphene_std::vector::misc::BooleanOperation;
|
||||
|
||||
@@ -288,8 +289,8 @@ impl SelectToolData {
|
||||
if (self.snap_candidates.len() as f64) < document.snapping_state.tolerance {
|
||||
snapping::get_layer_snap_points(layer, &SnapData::new(document, input), &mut self.snap_candidates);
|
||||
}
|
||||
if let Some(bounds) = document.metadata.bounding_box_with_transform(layer, DAffine2::IDENTITY) {
|
||||
let quad = document.metadata.transform_to_document(layer) * Quad::from_box(bounds);
|
||||
if let Some(bounds) = document.metadata().bounding_box_with_transform(layer, DAffine2::IDENTITY) {
|
||||
let quad = document.metadata().transform_to_document(layer) * Quad::from_box(bounds);
|
||||
snapping::get_bbox_points(quad, &mut self.snap_candidates, snapping::BBoxSnapValues::BOUNDING_BOX, document);
|
||||
}
|
||||
}
|
||||
@@ -310,20 +311,11 @@ impl SelectToolData {
|
||||
}
|
||||
|
||||
/// Duplicates the currently dragging layers. Called when Alt is pressed and the layers have not yet been duplicated.
|
||||
fn start_duplicates(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
fn start_duplicates(&mut self, document: &mut DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
self.non_duplicated_layers = Some(self.layers_dragging.clone());
|
||||
let mut new_dragging = Vec::new();
|
||||
for layer_ancestors in document.metadata().shallowest_unique_layers(self.layers_dragging.iter().copied().rev()) {
|
||||
let Some(layer) = layer_ancestors.last().copied() else { continue };
|
||||
|
||||
// `layer` cannot be `ROOT_PARENT`, since `ROOT_PARENT` cannot be part of `layers_dragging`
|
||||
if layer == LayerNodeIdentifier::ROOT_PARENT {
|
||||
log::error!("ROOT_PARENT cannot be in layers_dragging");
|
||||
continue;
|
||||
}
|
||||
|
||||
// `parent` can be `ROOT_PARENT`
|
||||
let Some(parent) = layer.parent(&document.metadata) else { continue };
|
||||
for layer in document.network_interface.shallowest_unique_layers(&[]) {
|
||||
let Some(parent) = layer.parent(document.metadata()) else { continue };
|
||||
|
||||
// Moves the layer back to its starting position.
|
||||
responses.add(GraphOperationMessage::TransformChange {
|
||||
@@ -335,36 +327,32 @@ impl SelectToolData {
|
||||
|
||||
// Copy the layer
|
||||
let mut copy_ids = HashMap::new();
|
||||
let node = layer.to_node();
|
||||
copy_ids.insert(node, NodeId(0_u64));
|
||||
if let Some(input_node) = document
|
||||
.network()
|
||||
.nodes
|
||||
.get(&node)
|
||||
.and_then(|node| if node.is_layer { node.inputs.get(1) } else { node.inputs.first() })
|
||||
.and_then(|input| input.as_node())
|
||||
{
|
||||
document
|
||||
.network()
|
||||
.upstream_flow_back_from_nodes(vec![input_node], graph_craft::document::FlowType::UpstreamFlow)
|
||||
.enumerate()
|
||||
.for_each(|(index, (_, node_id))| {
|
||||
copy_ids.insert(node_id, NodeId((index + 1) as u64));
|
||||
});
|
||||
};
|
||||
let nodes: HashMap<NodeId, DocumentNode> =
|
||||
NodeGraphMessageHandler::copy_nodes(document.network(), &document.node_graph_handler.network, &document.node_graph_handler.resolved_types, ©_ids).collect();
|
||||
let node_id = layer.to_node();
|
||||
copy_ids.insert(node_id, NodeId(0));
|
||||
|
||||
let insert_index = DocumentMessageHandler::get_calculated_insert_index(&document.metadata, &document.selected_nodes, parent);
|
||||
document
|
||||
.network_interface
|
||||
.upstream_flow_back_from_nodes(vec![layer.to_node()], &[], FlowType::LayerChildrenUpstreamFlow)
|
||||
.enumerate()
|
||||
.for_each(|(index, node_id)| {
|
||||
copy_ids.insert(node_id, NodeId((index + 1) as u64));
|
||||
});
|
||||
|
||||
let new_ids: HashMap<_, _> = nodes.iter().map(|(&id, _)| (id, NodeId(generate_uuid()))).collect();
|
||||
let nodes = document.network_interface.copy_nodes(©_ids, &[]).collect::<Vec<(NodeId, NodeTemplate)>>();
|
||||
|
||||
let insert_index = DocumentMessageHandler::get_calculated_insert_index(document.metadata(), document.network_interface.selected_nodes(&[]).unwrap(), parent);
|
||||
|
||||
let new_ids: HashMap<_, _> = nodes.iter().map(|(id, _)| (*id, NodeId(generate_uuid()))).collect();
|
||||
|
||||
let layer_id = *new_ids.get(&NodeId(0)).expect("Node Id 0 should be a layer");
|
||||
responses.add(GraphOperationMessage::AddNodesAsChild { nodes, new_ids, parent, insert_index });
|
||||
new_dragging.push(LayerNodeIdentifier::new_unchecked(layer_id));
|
||||
let layer = LayerNodeIdentifier::new_unchecked(layer_id);
|
||||
new_dragging.push(layer);
|
||||
responses.add(NodeGraphMessage::AddNodes { nodes, new_ids });
|
||||
responses.add(NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index });
|
||||
}
|
||||
let nodes = new_dragging.iter().map(|layer| layer.to_node()).collect();
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes });
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
self.layers_dragging = new_dragging;
|
||||
}
|
||||
|
||||
@@ -375,12 +363,7 @@ impl SelectToolData {
|
||||
};
|
||||
|
||||
// Delete the duplicated layers
|
||||
for layer_ancestors in document.metadata().shallowest_unique_layers(self.layers_dragging.iter().copied()) {
|
||||
let layer = layer_ancestors.last().unwrap();
|
||||
if *layer == LayerNodeIdentifier::ROOT_PARENT {
|
||||
log::error!("ROOT_PARENT cannot be in layers_dragging");
|
||||
continue;
|
||||
}
|
||||
for layer in document.network_interface.shallowest_unique_layers(&[]) {
|
||||
responses.add(NodeGraphMessage::DeleteNodes {
|
||||
node_ids: vec![layer.to_node()],
|
||||
reconnect: true,
|
||||
@@ -425,19 +408,26 @@ impl Fsm for SelectToolFsmState {
|
||||
(_, SelectToolMessage::Overlays(mut overlay_context)) => {
|
||||
tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
||||
|
||||
let selected_layers_count = document.selected_nodes.selected_unlocked_layers(document.metadata()).count();
|
||||
let selected_layers_count = document.network_interface.selected_nodes(&[]).unwrap().selected_unlocked_layers(&document.network_interface).count();
|
||||
tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count;
|
||||
tool_data.selected_layers_count = selected_layers_count;
|
||||
|
||||
// Outline selected layers
|
||||
for layer in document.selected_nodes.selected_visible_and_unlocked_layers(document.metadata()) {
|
||||
for layer in document
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||
{
|
||||
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
|
||||
}
|
||||
|
||||
// Update bounds
|
||||
let transform = document
|
||||
.selected_nodes
|
||||
.selected_visible_and_unlocked_layers(document.metadata())
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||
.next()
|
||||
.map(|layer| document.metadata().transform_to_viewport(layer));
|
||||
let transform = transform.unwrap_or(DAffine2::IDENTITY);
|
||||
@@ -445,8 +435,10 @@ impl Fsm for SelectToolFsmState {
|
||||
return self;
|
||||
}
|
||||
let bounds = document
|
||||
.selected_nodes
|
||||
.selected_visible_and_unlocked_layers(document.metadata())
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||
.filter_map(|layer| {
|
||||
document
|
||||
.metadata()
|
||||
@@ -473,16 +465,17 @@ impl Fsm for SelectToolFsmState {
|
||||
let quad = Quad::from_box([tool_data.drag_start, tool_data.drag_current]);
|
||||
|
||||
// Draw outline visualizations on the layers to be selected
|
||||
for layer in document.intersect_quad(quad, &document.network) {
|
||||
for layer in document.intersect_quad(quad, input) {
|
||||
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
|
||||
}
|
||||
|
||||
// Update the selection box
|
||||
overlay_context.quad(quad);
|
||||
} else {
|
||||
// Only highlight layers if the viewport is not being panned (middle mouse button is pressed)
|
||||
} else if !input.keyboard.get(Key::Mmb as usize) {
|
||||
// Get the layer the user is hovering over
|
||||
let click = document.click(input.mouse.position, &document.network);
|
||||
let not_selected_click = click.filter(|&hovered_layer| !document.selected_nodes.selected_layers_contains(hovered_layer, document.metadata()));
|
||||
let click = document.click(input);
|
||||
let not_selected_click = click.filter(|&hovered_layer| !document.network_interface.selected_nodes(&[]).unwrap().selected_layers_contains(hovered_layer, document.metadata()));
|
||||
if let Some(layer) = not_selected_click {
|
||||
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
|
||||
}
|
||||
@@ -492,10 +485,10 @@ impl Fsm for SelectToolFsmState {
|
||||
}
|
||||
(_, SelectToolMessage::EditLayer) => {
|
||||
// Edit the clicked layer
|
||||
if let Some(intersect) = document.click(input.mouse.position, &document.network) {
|
||||
if let Some(intersect) = document.click(input) {
|
||||
match tool_data.nested_selection_behavior {
|
||||
NestedSelectionBehavior::Shallowest => edit_layer_shallowest_manipulation(document, intersect, responses),
|
||||
NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, &document.network, responses),
|
||||
NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, &document.network_interface, responses),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,9 +516,14 @@ impl Fsm for SelectToolFsmState {
|
||||
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut selected: Vec<_> = document.selected_nodes.selected_visible_and_unlocked_layers(document.metadata()).collect();
|
||||
let intersection_list = document.click_list(input.mouse.position, &document.network).collect::<Vec<_>>();
|
||||
let intersection = document.find_deepest(&intersection_list, &document.network);
|
||||
let mut selected: Vec<_> = document
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||
.collect();
|
||||
let intersection_list = document.click_list(input).collect::<Vec<_>>();
|
||||
let intersection = document.find_deepest(&intersection_list);
|
||||
|
||||
// If the user is dragging the bounding box bounds, go into ResizingBounds mode.
|
||||
// If the user is dragging the rotate trigger, go into RotatingBounds mode.
|
||||
@@ -554,7 +552,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
tool_data.layers_dragging.retain(|layer| {
|
||||
if *layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
document.network.nodes.contains_key(&layer.to_node())
|
||||
document.network_interface.network(&[]).unwrap().nodes.contains_key(&layer.to_node())
|
||||
} else {
|
||||
log::error!("ROOT_PARENT should not be part of layers_dragging");
|
||||
false
|
||||
@@ -566,8 +564,7 @@ impl Fsm for SelectToolFsmState {
|
||||
&mut bounds.center_of_transformation,
|
||||
&tool_data.layers_dragging,
|
||||
responses,
|
||||
&document.network,
|
||||
&document.metadata,
|
||||
&document.network_interface,
|
||||
None,
|
||||
&ToolType::Select,
|
||||
);
|
||||
@@ -584,7 +581,7 @@ impl Fsm for SelectToolFsmState {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
tool_data.layers_dragging.retain(|layer| {
|
||||
if *layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
document.network.nodes.contains_key(&layer.to_node())
|
||||
document.network_interface.network(&[]).unwrap().nodes.contains_key(&layer.to_node())
|
||||
} else {
|
||||
log::error!("ROOT_PARENT should not be part of layers_dragging");
|
||||
false
|
||||
@@ -595,8 +592,7 @@ impl Fsm for SelectToolFsmState {
|
||||
&mut bounds.center_of_transformation,
|
||||
&selected,
|
||||
responses,
|
||||
&document.network,
|
||||
&document.metadata,
|
||||
&document.network_interface,
|
||||
None,
|
||||
&ToolType::Select,
|
||||
);
|
||||
@@ -615,7 +611,7 @@ impl Fsm for SelectToolFsmState {
|
||||
if tool_data.nested_selection_behavior == NestedSelectionBehavior::Deepest {
|
||||
tool_data.select_single_layer = intersection;
|
||||
} else {
|
||||
tool_data.select_single_layer = intersection.and_then(|intersection| intersection.ancestors(&document.metadata).find(|ancestor| selected.contains(ancestor)));
|
||||
tool_data.select_single_layer = intersection.and_then(|intersection| intersection.ancestors(document.metadata()).find(|ancestor| selected.contains(ancestor)));
|
||||
}
|
||||
|
||||
tool_data.layers_dragging = selected;
|
||||
@@ -686,9 +682,9 @@ impl Fsm for SelectToolFsmState {
|
||||
let mouse_delta = snap_drag(start, current, axis_align, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates);
|
||||
|
||||
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
|
||||
for layer_ancestors in document.metadata().shallowest_unique_layers(tool_data.layers_dragging.iter().copied()) {
|
||||
for layer in document.network_interface.shallowest_unique_layers(&[]) {
|
||||
responses.add_front(GraphOperationMessage::TransformChange {
|
||||
layer: *layer_ancestors.last().unwrap(),
|
||||
layer,
|
||||
transform: DAffine2::from_translation(mouse_delta),
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
@@ -724,23 +720,14 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
tool_data.layers_dragging.retain(|layer| {
|
||||
if *layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
document.network.nodes.contains_key(&layer.to_node())
|
||||
document.network_interface.network(&[]).unwrap().nodes.contains_key(&layer.to_node())
|
||||
} else {
|
||||
log::error!("ROOT_PARENT should not be part of layers_dragging");
|
||||
false
|
||||
}
|
||||
});
|
||||
let selected = &tool_data.layers_dragging;
|
||||
let mut selected = Selected::new(
|
||||
&mut bounds.original_transforms,
|
||||
&mut pivot,
|
||||
selected,
|
||||
responses,
|
||||
&document.network,
|
||||
&document.metadata,
|
||||
None,
|
||||
&ToolType::Select,
|
||||
);
|
||||
let mut selected = Selected::new(&mut bounds.original_transforms, &mut pivot, selected, responses, &document.network_interface, None, &ToolType::Select);
|
||||
|
||||
selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse());
|
||||
|
||||
@@ -774,7 +761,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
tool_data.layers_dragging.retain(|layer| {
|
||||
if *layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
document.network().nodes.contains_key(&layer.to_node())
|
||||
document.network_interface.network(&[]).unwrap().nodes.contains_key(&layer.to_node())
|
||||
} else {
|
||||
log::error!("ROOT_PARENT should not be part of replacement_selected_layers");
|
||||
false
|
||||
@@ -785,8 +772,7 @@ impl Fsm for SelectToolFsmState {
|
||||
&mut bounds.center_of_transformation,
|
||||
&tool_data.layers_dragging,
|
||||
responses,
|
||||
&document.network,
|
||||
&document.metadata,
|
||||
&document.network_interface,
|
||||
None,
|
||||
&ToolType::Select,
|
||||
);
|
||||
@@ -902,11 +888,13 @@ impl Fsm for SelectToolFsmState {
|
||||
// Deselect layer if not snap dragging
|
||||
if !tool_data.has_dragged && input.keyboard.key(remove_from_selection) && tool_data.layer_selected_on_start.is_none() {
|
||||
let quad = tool_data.selection_quad();
|
||||
let intersection = document.intersect_quad(quad, &document.network);
|
||||
let intersection = document.intersect_quad(quad, input);
|
||||
|
||||
if let Some(path) = intersection.last() {
|
||||
let replacement_selected_layers: Vec<_> = document
|
||||
.selected_nodes
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_layers(document.metadata())
|
||||
.filter(|&layer| !path.starts_with(layer, document.metadata()))
|
||||
.collect();
|
||||
@@ -994,8 +982,8 @@ impl Fsm for SelectToolFsmState {
|
||||
}
|
||||
(SelectToolFsmState::DrawingBox { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||
let quad = tool_data.selection_quad();
|
||||
let new_selected: HashSet<_> = document.intersect_quad(quad, &document.network).collect();
|
||||
let current_selected: HashSet<_> = document.selected_nodes.selected_layers(document.metadata()).collect();
|
||||
let new_selected: HashSet<_> = document.intersect_quad(quad, input).collect();
|
||||
let current_selected: HashSet<_> = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect();
|
||||
if new_selected != current_selected {
|
||||
tool_data.layers_dragging = new_selected.into_iter().collect();
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
@@ -1020,11 +1008,11 @@ impl Fsm for SelectToolFsmState {
|
||||
SelectToolFsmState::Ready { selection }
|
||||
}
|
||||
(SelectToolFsmState::Ready { .. }, SelectToolMessage::Enter) => {
|
||||
let mut selected_layers = document.selected_nodes.selected_layers(document.metadata());
|
||||
let mut selected_layers = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata());
|
||||
|
||||
if let Some(layer) = selected_layers.next() {
|
||||
// Check that only one layer is selected
|
||||
if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.network, "Text") {
|
||||
if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") {
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
|
||||
responses.add(TextToolMessage::EditSelected);
|
||||
}
|
||||
@@ -1044,7 +1032,7 @@ impl Fsm for SelectToolFsmState {
|
||||
(_, SelectToolMessage::Abort) => {
|
||||
tool_data.layers_dragging.retain(|layer| {
|
||||
if *layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
document.network().nodes.contains_key(&layer.to_node())
|
||||
document.network_interface.network(&[]).unwrap().nodes.contains_key(&layer.to_node())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -1055,8 +1043,7 @@ impl Fsm for SelectToolFsmState {
|
||||
&mut bounding_box_overlays.opposite_pivot,
|
||||
&tool_data.layers_dragging,
|
||||
responses,
|
||||
&document.network,
|
||||
&document.metadata,
|
||||
&document.network_interface,
|
||||
None,
|
||||
&ToolType::Select,
|
||||
);
|
||||
@@ -1155,7 +1142,7 @@ impl Fsm for SelectToolFsmState {
|
||||
}
|
||||
|
||||
fn not_artboard(document: &DocumentMessageHandler) -> impl Fn(&LayerNodeIdentifier) -> bool + '_ {
|
||||
|&layer| !document.metadata.is_artboard(layer)
|
||||
|&layer| !document.network_interface.is_artboard(&layer.to_node(), &[])
|
||||
}
|
||||
|
||||
fn drag_shallowest_manipulation(responses: &mut VecDeque<Message>, selected: Vec<LayerNodeIdentifier>, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) {
|
||||
@@ -1163,7 +1150,7 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque<Message>, selected: Vec
|
||||
let ancestor = layer
|
||||
.ancestors(document.metadata())
|
||||
.filter(not_artboard(document))
|
||||
.find(|&ancestor| document.selected_nodes.selected_layers_contains(ancestor, document.metadata()));
|
||||
.find(|&ancestor| document.network_interface.selected_nodes(&[]).unwrap().selected_layers_contains(ancestor, document.metadata()));
|
||||
|
||||
let new_selected = ancestor.unwrap_or_else(|| {
|
||||
layer
|
||||
@@ -1194,12 +1181,10 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque<Message>, selected: Vec
|
||||
}
|
||||
|
||||
fn drag_deepest_manipulation(responses: &mut VecDeque<Message>, selected: Vec<LayerNodeIdentifier>, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) {
|
||||
tool_data
|
||||
.layers_dragging
|
||||
.append(&mut vec![document.find_deepest(&selected, &document.network).unwrap_or(LayerNodeIdentifier::new(
|
||||
document.network.get_root_node().expect("Root node should exist when dragging layers").id,
|
||||
&document.network,
|
||||
))]);
|
||||
tool_data.layers_dragging.append(&mut vec![document.find_deepest(&selected).unwrap_or(LayerNodeIdentifier::new(
|
||||
document.network_interface.root_node(&[]).expect("Root node should exist when dragging layers").node_id,
|
||||
&document.network_interface,
|
||||
))]);
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet {
|
||||
nodes: tool_data
|
||||
.layers_dragging
|
||||
@@ -1217,7 +1202,7 @@ fn drag_deepest_manipulation(responses: &mut VecDeque<Message>, selected: Vec<La
|
||||
}
|
||||
|
||||
fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) {
|
||||
if document.selected_nodes.selected_layers_contains(layer, document.metadata()) {
|
||||
if document.network_interface.selected_nodes(&[]).unwrap().selected_layers_contains(layer, document.metadata()) {
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path });
|
||||
return;
|
||||
}
|
||||
@@ -1225,7 +1210,7 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer:
|
||||
let Some(new_selected) = layer.ancestors(document.metadata()).filter(not_artboard(document)).find(|ancestor| {
|
||||
ancestor
|
||||
.parent(document.metadata())
|
||||
.is_some_and(|parent| document.selected_nodes.selected_layers_contains(parent, document.metadata()))
|
||||
.is_some_and(|parent| document.network_interface.selected_nodes(&[]).unwrap().selected_layers_contains(parent, document.metadata()))
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
@@ -1238,11 +1223,11 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer:
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_selected.to_node()] });
|
||||
}
|
||||
|
||||
fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, document_network: &NodeNetwork, responses: &mut VecDeque<Message>) {
|
||||
if is_layer_fed_by_node_of_name(layer, document_network, "Text") {
|
||||
fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, responses: &mut VecDeque<Message>) {
|
||||
if is_layer_fed_by_node_of_name(layer, network_interface, "Text") {
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
|
||||
responses.add(TextToolMessage::EditSelected);
|
||||
} else if is_layer_fed_by_node_of_name(layer, document_network, "Path") {
|
||||
} else if is_layer_fed_by_node_of_name(layer, network_interface, "Path") {
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,12 +216,10 @@ impl Fsm for SplineToolFsmState {
|
||||
|
||||
tool_data.weight = tool_options.line_weight;
|
||||
|
||||
let nodes = {
|
||||
let node_type = resolve_document_node_type("Spline").expect("Spline node does not exist");
|
||||
let node = node_type.to_document_node_default_inputs([None, Some(NodeInput::value(TaggedValue::VecDVec2(Vec::new()), false))], Default::default());
|
||||
let node_type = resolve_document_node_type("Spline").expect("Spline node does not exist");
|
||||
let node = node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::VecDVec2(Vec::new()), false))]);
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
HashMap::from([(NodeId(0), node)])
|
||||
};
|
||||
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, parent, responses);
|
||||
tool_options.fill.apply_fill(layer, responses);
|
||||
tool_options.stroke.apply_stroke(tool_data.weight, layer, responses);
|
||||
@@ -330,7 +328,7 @@ fn update_spline(document: &DocumentMessageHandler, tool_data: &SplineToolData,
|
||||
|
||||
let Some(layer) = tool_data.layer else { return };
|
||||
|
||||
let Some(node_id) = graph_modification_utils::NodeGraphLayer::new(layer, document.network()).upstream_node_id_from_name("Spline") else {
|
||||
let Some(node_id) = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface).upstream_node_id_from_name("Spline") else {
|
||||
return;
|
||||
};
|
||||
responses.add_front(NodeGraphMessage::SetInputValue { node_id, input_index: 1, value });
|
||||
|
||||
@@ -5,11 +5,12 @@ use crate::application::generate_uuid;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name};
|
||||
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graphene_core::renderer::Quad;
|
||||
use graphene_core::text::{load_face, Font, FontCache};
|
||||
use graphene_core::vector::style::Fill;
|
||||
@@ -213,9 +214,8 @@ struct TextToolData {
|
||||
impl TextToolData {
|
||||
/// Set the editing state of the currently modifying layer
|
||||
fn set_editing(&self, editable: bool, font_cache: &FontCache, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
// TODO: Should always set visibility for document network, but `node_id` is not a layer so it crashes
|
||||
if let Some(node_id) = graph_modification_utils::get_fill_id(self.layer, &document.network) {
|
||||
responses.add(GraphOperationMessage::SetVisibility { node_id, visible: !editable });
|
||||
if let Some(node_id) = graph_modification_utils::get_fill_id(self.layer, &document.network_interface) {
|
||||
responses.add(NodeGraphMessage::SetVisibility { node_id, visible: !editable });
|
||||
}
|
||||
|
||||
if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) {
|
||||
@@ -234,8 +234,8 @@ impl TextToolData {
|
||||
|
||||
fn load_layer_text_node(&mut self, document: &DocumentMessageHandler) -> Option<()> {
|
||||
let transform = document.metadata().transform_to_viewport(self.layer);
|
||||
let color = graph_modification_utils::get_fill_color(self.layer, &document.network).unwrap_or(Color::BLACK);
|
||||
let (text, font, font_size) = graph_modification_utils::get_text(self.layer, &document.network)?;
|
||||
let color = graph_modification_utils::get_fill_color(self.layer, &document.network_interface).unwrap_or(Color::BLACK);
|
||||
let (text, font, font_size) = graph_modification_utils::get_text(self.layer, &document.network_interface)?;
|
||||
self.editing_text = Some(EditingText {
|
||||
text: text.clone(),
|
||||
font: font.clone(),
|
||||
@@ -266,12 +266,16 @@ impl TextToolData {
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] });
|
||||
}
|
||||
|
||||
fn interact(&mut self, state: TextToolFsmState, mouse: DVec2, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) -> TextToolFsmState {
|
||||
fn interact(
|
||||
&mut self,
|
||||
state: TextToolFsmState,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
document: &DocumentMessageHandler,
|
||||
font_cache: &FontCache,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> TextToolFsmState {
|
||||
// Check if the user has selected an existing text layer
|
||||
if let Some(clicked_text_layer_path) = document
|
||||
.click(mouse, document.network())
|
||||
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network, "Text"))
|
||||
{
|
||||
if let Some(clicked_text_layer_path) = document.click(input).filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text")) {
|
||||
self.start_editing_layer(clicked_text_layer_path, state, document, font_cache, responses);
|
||||
|
||||
TextToolFsmState::Editing
|
||||
@@ -288,7 +292,7 @@ impl TextToolData {
|
||||
font: editing_text.font.clone(),
|
||||
size: editing_text.font_size,
|
||||
parent: document.new_layer_parent(true),
|
||||
insert_index: -1,
|
||||
insert_index: 0,
|
||||
});
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: self.layer,
|
||||
@@ -316,7 +320,7 @@ impl TextToolData {
|
||||
}
|
||||
|
||||
fn can_edit_selected(document: &DocumentMessageHandler) -> Option<LayerNodeIdentifier> {
|
||||
let mut selected_layers = document.selected_nodes.selected_layers(document.metadata());
|
||||
let mut selected_layers = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata());
|
||||
let layer = selected_layers.next()?;
|
||||
|
||||
// Check that only one layer is selected
|
||||
@@ -324,7 +328,7 @@ fn can_edit_selected(document: &DocumentMessageHandler) -> Option<LayerNodeIdent
|
||||
return None;
|
||||
}
|
||||
|
||||
if !is_layer_fed_by_node_of_name(layer, &document.network, "Text") {
|
||||
if !is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -364,8 +368,8 @@ impl Fsm for TextToolFsmState {
|
||||
TextToolFsmState::Editing
|
||||
}
|
||||
(_, TextToolMessage::Overlays(mut overlay_context)) => {
|
||||
for layer in document.selected_nodes.selected_layers(document.metadata()) {
|
||||
let Some((text, font, font_size)) = graph_modification_utils::get_text(layer, &document.network) else {
|
||||
for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()) {
|
||||
let Some((text, font, font_size)) = graph_modification_utils::get_text(layer, &document.network_interface) else {
|
||||
continue;
|
||||
};
|
||||
let buzz_face = font_cache.get(font).map(|data| load_face(data));
|
||||
@@ -387,7 +391,7 @@ impl Fsm for TextToolFsmState {
|
||||
});
|
||||
tool_data.new_text = String::new();
|
||||
|
||||
tool_data.interact(state, input.mouse.position, document, font_cache, responses)
|
||||
tool_data.interact(state, input, document, font_cache, responses)
|
||||
}
|
||||
(state, TextToolMessage::EditSelected) => {
|
||||
if let Some(layer) = can_edit_selected(document) {
|
||||
@@ -410,10 +414,9 @@ impl Fsm for TextToolFsmState {
|
||||
TextToolFsmState::Editing
|
||||
}
|
||||
(TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => {
|
||||
responses.add(NodeGraphMessage::SetQualifiedInputValue {
|
||||
node_id: graph_modification_utils::get_text_id(tool_data.layer, &document.network).unwrap(),
|
||||
input_index: 1,
|
||||
value: TaggedValue::String(new_text),
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(graph_modification_utils::get_text_id(tool_data.layer, &document.network_interface).unwrap(), 1),
|
||||
input: NodeInput::value(TaggedValue::String(new_text), false),
|
||||
});
|
||||
|
||||
tool_data.set_editing(false, font_cache, document, responses);
|
||||
|
||||
@@ -44,10 +44,13 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
||||
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, (document, input, tool_data, shape_editor): TransformData) {
|
||||
let using_path_tool = tool_data.active_tool_type == ToolType::Path;
|
||||
|
||||
// TODO: Add support for transforming layer not in the document network
|
||||
let selected_layers = document
|
||||
.selected_nodes
|
||||
.network_interface
|
||||
.selected_nodes(&[])
|
||||
.unwrap()
|
||||
.selected_layers(document.metadata())
|
||||
.filter(|&layer| document.metadata().node_is_visible(layer.to_node()) && !document.metadata().node_is_locked(layer.to_node()))
|
||||
.filter(|&layer| document.network_interface.is_visible(&layer.to_node(), &[]) && !document.network_interface.is_locked(&layer.to_node(), &[]))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut selected = Selected::new(
|
||||
@@ -55,8 +58,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
||||
&mut self.pivot,
|
||||
&selected_layers,
|
||||
responses,
|
||||
&document.network,
|
||||
&document.metadata,
|
||||
&document.network_interface,
|
||||
Some(shape_editor),
|
||||
&tool_data.active_tool_type,
|
||||
);
|
||||
@@ -68,7 +70,10 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
||||
}
|
||||
|
||||
if using_path_tool {
|
||||
if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.metadata.compute_modified_vector(layer, &document.network)) {
|
||||
if let Some(vector_data) = selected_layers
|
||||
.first()
|
||||
.and_then(|&layer| document.metadata().compute_modified_vector(layer, &document.network_interface))
|
||||
{
|
||||
*selected.original_transforms = OriginalTransforms::default();
|
||||
let viewspace = document.metadata().transform_to_viewport(selected_layers[0]);
|
||||
|
||||
@@ -212,7 +217,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
||||
self.mouse_position = input.mouse.position;
|
||||
}
|
||||
TransformLayerMessage::SelectionChanged => {
|
||||
let target_layers = document.selected_nodes.selected_layers(document.metadata()).collect();
|
||||
let target_layers = document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()).collect();
|
||||
shape_editor.set_selected_layers(target_layers);
|
||||
}
|
||||
TransformLayerMessage::TypeBackspace => self.transform_operation.grs_typed(self.typing.type_backspace(), &mut selected, self.snap),
|
||||
|
||||
@@ -18,7 +18,7 @@ use graphene_std::text::FontCache;
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
pub struct ToolActionHandlerData<'a> {
|
||||
pub document: &'a DocumentMessageHandler,
|
||||
pub document: &'a mut DocumentMessageHandler,
|
||||
pub document_id: DocumentId,
|
||||
pub global_tool_data: &'a DocumentToolData,
|
||||
pub input: &'a InputPreprocessorMessageHandler,
|
||||
@@ -28,7 +28,7 @@ pub struct ToolActionHandlerData<'a> {
|
||||
}
|
||||
impl<'a> ToolActionHandlerData<'a> {
|
||||
pub fn new(
|
||||
document: &'a DocumentMessageHandler,
|
||||
document: &'a mut DocumentMessageHandler,
|
||||
document_id: DocumentId,
|
||||
global_tool_data: &'a DocumentToolData,
|
||||
input: &'a InputPreprocessorMessageHandler,
|
||||
|
||||
Reference in New Issue
Block a user