Skip to content

Commit

Permalink
Allow the Pen tool to connect layers by their endpoints, merging into…
Browse files Browse the repository at this point in the history
… a single layer (GraphiteEditor#2076)

* Merge vector data layers

* Fix early return

* Fix layer space multiplication error

* Recalculate positions when changing layer space

* Add transform node

* Remove pen tool layer state
  • Loading branch information
adamgerhant authored Nov 1, 2024
1 parent 018e983 commit c7b0824
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::transform_utils;
use super::utility_types::ModifyInputsContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface};
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface, OutputConnector};
use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers;
use crate::messages::prelude::*;

Expand Down Expand Up @@ -95,14 +95,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageData<'_>> for Gr
}
}
GraphOperationMessage::SetUpstreamToChain { layer } => {
let Some(first_chain_node) = network_interface
.upstream_flow_back_from_nodes(
vec![layer.to_node()],
&[],
crate::messages::portfolio::document::utility_types::network_interface::FlowType::HorizontalFlow,
)
.nth(1)
else {
let Some(OutputConnector::Node { node_id: first_chain_node, .. }) = network_interface.upstream_output_connector(&InputConnector::node(layer.to_node(), 1), &[]) else {
return;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ pub enum NodeGraphMessage {
output_connector: OutputConnector,
input_connector: InputConnector,
},
ConnectUpstreamOutputToInput {
downstream_input: InputConnector,
input_connector: InputConnector,
},
Cut,
DeleteNodes {
node_ids: Vec<NodeId>,
Expand Down Expand Up @@ -70,6 +74,10 @@ pub enum NodeGraphMessage {
parent: LayerNodeIdentifier,
insert_index: usize,
},
MoveNodeToChainStart {
node_id: NodeId,
parent: LayerNodeIdentifier,
},
PasteNodes {
serialized_nodes: String,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,16 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
});
responses.add(NodeGraphMessage::SendGraph);
}
NodeGraphMessage::ConnectUpstreamOutputToInput { downstream_input, input_connector } => {
let Some(upstream_node) = network_interface.upstream_output_connector(&downstream_input, selection_network_path) else {
log::error!("Failed to find upstream node for downstream_input");
return;
};
responses.add(NodeGraphMessage::CreateWire {
output_connector: upstream_node,
input_connector,
});
}
NodeGraphMessage::Cut => {
responses.add(NodeGraphMessage::Copy);
responses.add(NodeGraphMessage::DeleteSelectedNodes { delete_children: true });
Expand Down Expand Up @@ -323,6 +333,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
NodeGraphMessage::MoveLayerToStack { layer, parent, insert_index } => {
network_interface.move_layer_to_stack(layer, parent, insert_index, selection_network_path);
}
NodeGraphMessage::MoveNodeToChainStart { node_id, parent } => {
network_interface.move_node_to_chain_start(&node_id, parent, selection_network_path);
}
NodeGraphMessage::PasteNodes { serialized_nodes } => {
let data = match serde_json::from_str::<Vec<(NodeId, NodeTemplate)>>(&serialized_nodes) {
Ok(d) => d,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ impl DocumentMetadata {
self.upstream_transforms.get(&node_id).copied().map(|(_, transform)| transform).unwrap_or(DAffine2::IDENTITY)
}

pub fn downstream_transform_to_document(&self, layer: LayerNodeIdentifier) -> DAffine2 {
self.document_to_viewport.inverse() * self.downstream_transform_to_viewport(layer)
}

pub fn downstream_transform_to_viewport(&self, layer: LayerNodeIdentifier) -> DAffine2 {
if layer == LayerNodeIdentifier::ROOT_PARENT {
return self.transform_to_viewport(layer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4894,6 +4894,32 @@ impl NodeNetworkInterface {
self.create_wire(&OutputConnector::node(*node_id, 0), &InputConnector::node(parent.to_node(), 1), network_path);
self.set_chain_position(node_id, network_path);
} else {
// TODO: Implement a more robust horizontal shift system when inserting a node into a chain.
// This should be done by breaking the chain and shifting the sole dependents for each node upstream of the insertion.
// Before inserting the node, shift the layer right 7 units so that all sole dependents are also shifted
// let input_connector = InputConnector::node(parent.to_node(), 0);
// let old_upstream = self.upstream_output_connector(&input_connector, network_path);
// This also needs to disconnect from the downstream layer
// self.disconnect_input(&input_connector, network_path);
// let Some(selected_nodes) = self.selected_nodes_mut(network_path) else {
// log::error!("Could not get selected nodes in move_layer_to_stack");
// return;
// };
// let old_selected_nodes = selected_nodes.replace_with(vec![parent.to_node()]);

// for _ in 0..7 {
// self.shift_selected_nodes(Direction::Left, false, network_path);
// }
// // Grip drag it back to the right
// for _ in 0..7 {
// self.shift_selected_nodes(Direction::Right, true, network_path);
// }
// let _ = self.selected_nodes_mut(network_path).unwrap().replace_with(old_selected_nodes);
// if let Some(old_upstream) = old_upstream {
// self.create_wire(&old_upstream, &input_connector, network_path);
// }

// Insert the node in the gap and set the upstream to a chain
self.insert_node_between(node_id, &InputConnector::node(parent.to_node(), 1), 0, network_path);
self.force_set_upstream_to_chain(node_id, network_path);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ use graphene_std::vector::PointId;
use glam::DVec2;

/// Determines if a path should be extended. Goal in viewport space. Returns the path and if it is extending from the start, if applicable.
pub fn should_extend(document: &DocumentMessageHandler, goal: DVec2, tolerance: f64) -> Option<(LayerNodeIdentifier, PointId, DVec2)> {
pub fn should_extend(document: &DocumentMessageHandler, goal: DVec2, tolerance: f64, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Option<(LayerNodeIdentifier, PointId, DVec2)> {
let mut best = None;
let mut best_distance_squared = tolerance * tolerance;

for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()) {
for layer in layers {
let viewspace = document.metadata().transform_to_viewport(layer);

let vector_data = document.network_interface.compute_modified_vector(layer)?;
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
continue;
};
for id in vector_data.single_connected_points() {
let Some(point) = vector_data.point_domain.position_from_id(id) else { continue };

Expand Down
3 changes: 2 additions & 1 deletion editor/src/messages/tool/tool_messages/freehand_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ impl Fsm for FreehandToolFsmState {
tool_data.weight = tool_options.line_weight;

// Extend an endpoint of the selected path
if let Some((layer, point, position)) = should_extend(document, input.mouse.position, crate::consts::SNAP_POINT_TOLERANCE) {
let selected_nodes = document.network_interface.selected_nodes(&[]).unwrap();
if let Some((layer, point, position)) = should_extend(document, input.mouse.position, crate::consts::SNAP_POINT_TOLERANCE, selected_nodes.selected_layers(document.metadata())) {
tool_data.layer = Some(layer);
tool_data.end_point = Some((position, point));

Expand Down
Loading

0 comments on commit c7b0824

Please sign in to comment.