mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 15:48: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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user