diff --git a/editor/src/consts.rs b/editor/src/consts.rs index 3dcbd72736..0b8c27796d 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -8,8 +8,6 @@ pub const IMPORTS_TO_LEFT_EDGE_PIXEL_GAP: u32 = 120; // Viewport pub const VIEWPORT_ZOOM_WHEEL_RATE: f64 = (1. / 600.) * 3.; pub const VIEWPORT_ZOOM_MOUSE_RATE: f64 = 1. / 400.; -pub const VIEWPORT_ZOOM_SCALE_MIN: f64 = 0.000_000_1; -pub const VIEWPORT_ZOOM_SCALE_MAX: f64 = 10_000.; pub const VIEWPORT_ZOOM_MIN_FRACTION_COVER: f64 = 0.01; pub const VIEWPORT_ZOOM_LEVELS: [f64; 74] = [ 0.0001, 0.000125, 0.00016, 0.0002, 0.00025, 0.00032, 0.0004, 0.0005, 0.00064, 0.0008, 0.001, 0.0016, 0.002, 0.0025, 0.0032, 0.004, 0.005, 0.0064, 0.008, 0.01, 0.01125, 0.015, 0.02, 0.025, 0.03, diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 36ac6bb5d5..a60b964525 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -2,7 +2,7 @@ use super::node_graph::utility_types::Transform; use super::utility_types::clipboards::Clipboard; use super::utility_types::error::EditorError; use super::utility_types::misc::{SnappingOptions, SnappingState, GET_SNAP_BOX_FUNCTIONS, GET_SNAP_GEOMETRY_FUNCTIONS}; -use super::utility_types::network_interface::{NodeNetworkInterface, TransactionStatus}; +use super::utility_types::network_interface::{NodeNetworkInterface, NodeNetworkPersistentMetadata, TransactionStatus}; use super::utility_types::nodes::{CollapsedLayers, SelectedNodes}; use crate::application::{generate_uuid, GRAPHITE_GIT_COMMIT_HASH}; use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ROTATE_SNAP_INTERVAL}; @@ -13,7 +13,7 @@ use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData; use crate::messages::portfolio::document::overlays::grid_overlays::{grid_overlay, overlay_options}; use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; -use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ}; +use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis}; use crate::messages::portfolio::document::utility_types::nodes::RawBuffer; use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::prelude::*; @@ -24,7 +24,7 @@ use crate::messages::tool::utility_types::ToolType; use crate::node_graph_executor::NodeGraphExecutor; use graph_craft::document::value::TaggedValue; -use graph_craft::document::{NodeId, NodeNetwork, OldNodeNetwork}; +use graph_craft::document::{NodeId, NodeNetwork, OldNodeNetwork, PTZ}; use graphene_core::raster::BlendMode; use graphene_core::raster::ImageFrame; use graphene_core::vector::style::ViewMode; @@ -779,10 +779,7 @@ impl MessageHandler> for DocumentMessag } DocumentMessage::RenderRulers => { let current_ptz = if self.graph_view_overlay_open { - let Some(network_metadata) = self.network_interface.network_metadata(&self.breadcrumb_network_path) else { - return; - }; - &network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz + self.network_interface.navigation_metadata(&self.breadcrumb_network_path) } else { &self.document_ptz }; @@ -1112,7 +1109,7 @@ impl MessageHandler> for DocumentMessag let transform = self .navigation_handler - .calculate_offset_transform(ipp.viewport_bounds.center(), &network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz); + .calculate_offset_transform(ipp.viewport_bounds.center(), &self.network_interface.navigation_metadata(&self.breadcrumb_network_path).node_graph_ptz); self.network_interface.set_transform(transform, &self.breadcrumb_network_path); let imports = self.network_interface.frontend_imports(&self.breadcrumb_network_path).unwrap_or_default(); let exports = self.network_interface.frontend_exports(&self.breadcrumb_network_path).unwrap_or_default(); @@ -1981,5 +1978,6 @@ impl DocumentMessageHandler { fn default_document_network_interface() -> NodeNetworkInterface { let mut network_interface = NodeNetworkInterface::default(); network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::EMPTY), -1, "".to_string(), &[]); + network_interface.insert_network_metadata(&[], NodeNetworkPersistentMetadata::default()); network_interface } diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index 9523c5701c..23f266108e 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -1,11 +1,11 @@ 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::NodeNetworkInterface; use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers; use crate::messages::prelude::*; -use graph_craft::document::{generate_uuid, NodeId, NodeInput}; +use graph_craft::document::{generate_uuid, NodeId, NodeInput, InputConnector}; use graphene_core::renderer::Quad; use graphene_core::text::Font; use graphene_core::vector::style::{Fill, Gradient, GradientStops, GradientType, LineCap, LineJoin, Stroke}; diff --git a/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs index 64ae4577fb..9106fc5c1c 100644 --- a/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs +++ b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs @@ -1,7 +1,7 @@ -use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface}; +use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; use bezier_rs::Subpath; -use graph_craft::document::{value::TaggedValue, NodeId, NodeInput}; +use graph_craft::document::{value::TaggedValue, InputConnector, NodeId, NodeInput}; use graphene_core::vector::PointId; use glam::{DAffine2, DVec2}; diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index a49238b1c7..0d9f80943a 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -1,12 +1,12 @@ use super::transform_utils; use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; -use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, OutputConnector}; +use crate::messages::portfolio::document::utility_types::network_interface::{self, NodeNetworkInterface}; use crate::messages::prelude::*; use bezier_rs::Subpath; use graph_craft::document::value::TaggedValue; -use graph_craft::document::{generate_uuid, NodeId, NodeInput}; +use graph_craft::document::{generate_uuid, InputConnector, NodeId, NodeInput, OutputConnector}; use graphene_core::raster::{BlendMode, ImageFrame}; use graphene_core::text::Font; use graphene_core::vector::brush_stroke::BrushStroke; diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs index a1929f95c2..3b3e4df385 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -1,17 +1,16 @@ use crate::consts::{ - VIEWPORT_ROTATE_SNAP_INTERVAL, VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MIN_FRACTION_COVER, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN, - VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR, VIEWPORT_ZOOM_WHEEL_RATE, + VIEWPORT_ROTATE_SNAP_INTERVAL, VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MIN_FRACTION_COVER, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR, + VIEWPORT_ZOOM_WHEEL_RATE, }; use crate::messages::frontend::utility_types::MouseCursorIcon; use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, MouseMotion}; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; use crate::messages::portfolio::document::navigation::utility_types::NavigationOperation; -use crate::messages::portfolio::document::utility_types::misc::PTZ; use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; use crate::messages::prelude::*; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; -use graph_craft::document::NodeId; +use graph_craft::document::{NodeId, PTZ}; use glam::{DAffine2, DVec2}; @@ -46,8 +45,7 @@ impl MessageHandler> for Navigation if !graph_view_overlay_open { Some(document_ptz) } else { - let network_metadata = network_interface.network_metadata(breadcrumb_network_path)?; - Some(&network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz) + Some(network_interface.navigation_metadata(breadcrumb_network_path).node_graph_ptz) } } @@ -249,7 +247,7 @@ impl MessageHandler> for Navigation log::error!("Could not get mutable PTZ in CanvasZoomSet"); return; }; - let zoom = zoom_factor.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX); + let zoom = zoom_factor.clamp(graphene_std::consts::VIEWPORT_ZOOM_SCALE_MIN, graphene_std::consts::VIEWPORT_ZOOM_SCALE_MAX); let zoom = zoom * Self::clamp_zoom(zoom, document_bounds, old_zoom, ipp); ptz.set_zoom(zoom); responses.add(PortfolioMessage::UpdateDocumentWidgets); diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs index 8f7f016d13..dc4f5ca84e 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs @@ -1,11 +1,11 @@ use super::utility_types::Direction; use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; -use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate, OutputConnector}; +use crate::messages::portfolio::document::utility_types::network_interface::NodeTemplate; use crate::messages::prelude::*; use graph_craft::document::value::TaggedValue; -use graph_craft::document::{NodeId, NodeInput}; +use graph_craft::document::{InputConnector, NodeId, NodeInput, OutputConnector}; use graph_craft::proto::GraphErrors; use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypesDelta; diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 0722b302f0..ca1e19d998 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -6,12 +6,12 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext; use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; -use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, NodeTemplate, OutputConnector, Previewing}; +use crate::messages::portfolio::document::utility_types::network_interface::{self, NodeNetworkInterface, NodeTemplate}; use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry}; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; -use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; +use graph_craft::document::{DocumentNodeImplementation, InputConnector, NodeId, NodeInput, OutputConnector, Previewing}; use graph_craft::proto::GraphErrors; use graphene_core::*; use renderer::{ClickTarget, Quad}; @@ -158,13 +158,8 @@ impl<'a> MessageHandler> for NodeGrap responses.add(NodeGraphMessage::ShiftNodePosition { node_id, x, y }); // Only auto connect to the dragged wire if the node is being added to the currently opened network if let Some(output_connector_position) = self.wire_in_progress_from_connector { - let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { - log::error!("Could not get network metadata in CreateNodeFromContextMenu"); - return; - }; - let output_connector_position_viewport = network_metadata - .persistent_metadata - .navigation_metadata + let output_connector_position_viewport = network_interface + .navigation_metadata(selection_network_path) .node_graph_to_viewport .transform_point2(output_connector_position); let Some(output_connector) = &network_interface.output_connector_from_click(output_connector_position_viewport, breadcrumb_network_path) else { @@ -339,14 +334,10 @@ impl<'a> MessageHandler> for NodeGrap log::error!("Selection network path does not match breadcrumb network path in PointerDown"); return; } - let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { - log::error!("Could not get network metadata in PointerDown"); - return; - }; let click = ipp.mouse.position; - let node_graph_point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let node_graph_point = network_interface.navigation_metadata(selection_network_path).node_graph_to_viewport.inverse().transform_point2(click); if network_interface .layer_click_target_from_click(click, network_interface::LayerClickTargetTypes::Grip, selection_network_path) @@ -358,7 +349,6 @@ impl<'a> MessageHandler> for NodeGrap let clicked_id = network_interface.node_from_click(click, selection_network_path); let clicked_input = network_interface.input_connector_from_click(click, selection_network_path); let clicked_output = network_interface.output_connector_from_click(click, selection_network_path); - let network_metadata = network_interface.network_metadata(selection_network_path).unwrap(); // Create the add node popup on right click, then exit if right_click { @@ -402,11 +392,11 @@ impl<'a> MessageHandler> for NodeGrap let node_graph_shift = if matches!(context_menu_data, ContextMenuData::CreateNode) { let appear_right_of_mouse = if click.x > ipp.viewport_bounds.size().x - 180. { -180. } else { 0. }; let appear_above_mouse = if click.y > ipp.viewport_bounds.size().y - 200. { -200. } else { 0. }; - DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x + DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_interface.navigation_metadata(selection_network_path).node_graph_to_viewport.matrix2.x_axis.x } else { let appear_right_of_mouse = if click.x > ipp.viewport_bounds.size().x - 173. { -173. } else { 0. }; let appear_above_mouse = if click.y > ipp.viewport_bounds.size().y - 34. { -34. } else { 0. }; - DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x + DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_interface.navigation_metadata(selection_network_path).node_graph_to_viewport.matrix2.x_axis.x }; let context_menu_coordinates = ((node_graph_point.x + node_graph_shift.x) as i32, (node_graph_point.y + node_graph_shift.y) as i32); @@ -430,9 +420,8 @@ impl<'a> MessageHandler> for NodeGrap // If the user is clicking on the create nodes list or context menu, break here if let Some(context_menu) = &self.context_menu { - let context_menu_viewport = network_metadata - .persistent_metadata - .navigation_metadata + let context_menu_viewport = network_interface + .navigation_metadata(selection_network_path) .node_graph_to_viewport .transform_point2(DVec2::new(context_menu.context_menu_coordinates.0 as f64, context_menu.context_menu_coordinates.1 as f64)); let (width, height) = if matches!(context_menu.context_menu_data, ContextMenuData::ToggleLayer { .. }) { @@ -576,18 +565,14 @@ impl<'a> MessageHandler> for NodeGrap log::error!("Selection network path does not match breadcrumb network path in PointerMove"); return; } - let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { - return; - }; // Auto-panning let messages = [NodeGraphMessage::PointerOutsideViewport { shift }.into(), NodeGraphMessage::PointerMove { shift }.into()]; self.auto_panning.setup_by_mouse_position(ipp, &messages, responses); let viewport_location = ipp.mouse.position; - let point = network_metadata - .persistent_metadata - .navigation_metadata + let point = network_interface + .navigation_metadata(selection_network_path) .node_graph_to_viewport .inverse() .transform_point2(viewport_location); @@ -628,12 +613,8 @@ impl<'a> MessageHandler> for NodeGrap if let (Some(wire_in_progress_from_connector), Some(wire_in_progress_to_connector)) = (self.wire_in_progress_from_connector, self.wire_in_progress_to_connector) { // If performance is a concern this can be stored as a field in the wire_in_progress_from/to_connector struct, and updated when snapping to an output - let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { - return; - }; - let from_connector_viewport = network_metadata - .persistent_metadata - .navigation_metadata + let from_connector_viewport = network_interface + .navigation_metadata(selection_network_path) .node_graph_to_viewport .transform_point2(wire_in_progress_from_connector); let from_connector_is_layer = network_interface @@ -747,10 +728,6 @@ impl<'a> MessageHandler> for NodeGrap log::error!("Could not get selected nodes in PointerUp"); return; }; - let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else { - warn!("No network_metadata"); - return; - }; responses.add(DocumentMessage::EndTransaction); @@ -764,16 +741,15 @@ impl<'a> MessageHandler> for NodeGrap responses.add(NodeGraphMessage::SelectedNodesSet { nodes: new_selected_nodes }); self.deselect_on_pointer_up = None; } - let point = network_metadata - .persistent_metadata - .navigation_metadata + let point = network_interface + .navigation_metadata(selection_network_path) .node_graph_to_viewport .inverse() .transform_point2(ipp.mouse.position); // Disconnect if the wire was previously connected to an input if let (Some(wire_in_progress_from_connector), Some(wire_in_progress_to_connector)) = (self.wire_in_progress_from_connector, self.wire_in_progress_to_connector) { // Check if dragged connector is reconnected to another input - let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport; + let node_graph_to_viewport = network_interface.navigation_metadata(selection_network_path).node_graph_to_viewport; let from_connector_viewport = node_graph_to_viewport.transform_point2(wire_in_progress_from_connector); let to_connector_viewport = node_graph_to_viewport.transform_point2(wire_in_progress_to_connector); let output_connector = network_interface.output_connector_from_click(from_connector_viewport, selection_network_path); @@ -800,7 +776,8 @@ impl<'a> MessageHandler> for NodeGrap let appear_right_of_mouse = if ipp.mouse.position.x > ipp.viewport_bounds.size().x - 173. { -173. } else { 0. }; let appear_above_mouse = if ipp.mouse.position.y > ipp.viewport_bounds.size().y - 34. { -34. } else { 0. }; - let node_graph_shift = DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x; + let node_graph_shift = + DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_interface.navigation_metadata(selection_network_path).node_graph_to_viewport.matrix2.x_axis.x; self.context_menu = Some(ContextMenuInformation { context_menu_coordinates: ((point.x + node_graph_shift.x) as i32, (point.y + node_graph_shift.y) as i32), @@ -1283,7 +1260,10 @@ impl<'a> MessageHandler> for NodeGrap return; }; - let box_selection_start_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(box_selection_start); + let box_selection_start_viewport = network_interface + .navigation_metadata(selection_network_path) + .node_graph_to_viewport + .transform_point2(box_selection_start); let box_selection = Some(BoxSelection { start_x: box_selection_start_viewport.x.max(0.) as u32, @@ -1291,9 +1271,8 @@ impl<'a> MessageHandler> for NodeGrap end_x: ipp.mouse.position.x.max(0.) as u32, end_y: ipp.mouse.position.y.max(0.) as u32, }); - let box_selection_end_graph = network_metadata - .persistent_metadata - .navigation_metadata + let box_selection_end_graph = network_interface + .navigation_metadata(selection_network_path) .node_graph_to_viewport .inverse() .transform_point2(ipp.mouse.position); diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index ac04885825..6abacab59e 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -1,9 +1,7 @@ use graph_craft::document::value::TaggedValue; -use graph_craft::document::NodeId; +use graph_craft::document::{NodeId, InputConnector, OutputConnector}; use graphene_core::Type; -use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, OutputConnector}; - #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FrontendGraphDataType { #[default] diff --git a/editor/src/messages/portfolio/document/utility_types/misc.rs b/editor/src/messages/portfolio/document/utility_types/misc.rs index 34610ea5fc..7e925e6df1 100644 --- a/editor/src/messages/portfolio/document/utility_types/misc.rs +++ b/editor/src/messages/portfolio/document/utility_types/misc.rs @@ -1,5 +1,6 @@ use crate::consts::COLOR_OVERLAY_GRAY; +use graph_craft::document::PTZ; use graphene_core::raster::Color; use glam::DVec2; @@ -440,27 +441,3 @@ impl fmt::Display for SnappingOptions { } } } - -#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)] -#[serde(default)] -pub struct PTZ { - pub pan: DVec2, - pub tilt: f64, - zoom: f64, -} - -impl Default for PTZ { - fn default() -> Self { - Self { pan: DVec2::ZERO, tilt: 0., zoom: 1. } - } -} - -impl PTZ { - pub fn zoom(&self) -> f64 { - self.zoom - } - - pub fn set_zoom(&mut self, zoom: f64) { - self.zoom = zoom.clamp(crate::consts::VIEWPORT_ZOOM_SCALE_MIN, crate::consts::VIEWPORT_ZOOM_SCALE_MAX) - } -} diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index 79407649d3..5525011559 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -1,5 +1,4 @@ use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier, NodeRelations}; -use super::misc::PTZ; use super::nodes::SelectedNodes; use crate::consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP}; use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; @@ -8,6 +7,7 @@ use crate::messages::tool::common_functionality::graph_modification_utils; use bezier_rs::Subpath; use graph_craft::document::{value::TaggedValue, DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork}; +use graph_craft::document::{InputConnector, NavigationMetadata, OutputConnector, Previewing, RootNode, PTZ}; use graph_craft::{concrete, Type}; use graphene_std::renderer::{ClickTarget, Quad}; use graphene_std::vector::{PointId, VectorData, VectorModificationType}; @@ -998,12 +998,16 @@ impl NodeNetworkInterface { upstream_nodes_below_layer } - pub fn previewing(&self, network_path: &[NodeId]) -> Previewing { - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in previewing"); - return Previewing::No; + pub fn previewing(&self, network_path: &[NodeId]) -> Option<&Previewing> { + let Some(tagged_value) = self.metadata_value(&network_path, Metadata::Previewing) else { + log::error!("Could not get tagged value in previewing"); + return None; }; - network_metadata.persistent_metadata.previewing + let TaggedValue::Previewing(previewing) = tagged_value else { + log::error!("Tagged value should be Previewing in previewing"); + return None; + }; + Some(previewing) } /// Returns the root node (the node that the solid line is connect to), or None if no nodes are connected to the output @@ -1012,11 +1016,8 @@ impl NodeNetworkInterface { log::error!("Could not get network in root_node"); return None; }; - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in root_node"); - return None; - }; - match &network_metadata.persistent_metadata.previewing { + let previewing = self.previewing(network_path); + match &previewing { Previewing::Yes { root_node_to_restore } => *root_node_to_restore, Previewing::No => network.exports.first().and_then(|export| { if let NodeInput::Node { node_id, output_index, .. } = export { @@ -1031,23 +1032,35 @@ impl NodeNetworkInterface { } } + pub fn navigation_metadata(&self, network_path: &[NodeId]) -> Option<&NavigationMetadata> { + let Some(tagged_value) = self.metadata_value(&network_path, Metadata::NavigationMetadata) else { + log::error!("Could not get tagged value in navigation_metadata"); + return None; + }; + let TaggedValue::NavigationMetadata(navigation_metadata) = tagged_value else { + log::error!("Tagged value should be Previewing in previewing"); + return None; + }; + Some(navigation_metadata) + } + pub fn reference(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option { self.node_metadata(node_id, network_path) .and_then(|node_metadata| node_metadata.persistent_metadata.reference.as_ref().map(|reference| reference.to_string())) } - pub fn display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String { + pub fn display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&String> { let mut node_id_path = network_path.to_vec(); node_id_path.push(*node_id); - let Some(tagged_value, ..) = self.metadata_value(&node_id_path, Metadata::DisplayName) else { + let Some(tagged_value) = self.metadata_value(&node_id_path, Metadata::DisplayName) else { log::error!("Could not get tagged value in display_name"); - return "".to_string(); + return None; }; let TaggedValue::String(display_name) = tagged_value else { log::error!("Tagged value should be String in display_name"); - return "".to_string(); + return None; }; - display_name.clone() + Some(display_name) } pub fn frontend_display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String { @@ -1842,9 +1855,8 @@ impl NodeNetworkInterface { let mut import_export_ports = Ports::new(); - let viewport_top_right = network_metadata - .persistent_metadata - .navigation_metadata + let viewport_top_right = self + .navigation_metadata(network_path) .node_graph_to_viewport .inverse() .transform_point2(rounded_network_edge_distance.exports_to_edge_distance); @@ -1864,9 +1876,8 @@ impl NodeNetworkInterface { import_export_ports.insert_input_port_at_center(input_index, export_top_right + DVec2::new(0., input_index as f64 * 24.)); } - let viewport_top_left = network_metadata - .persistent_metadata - .navigation_metadata + let viewport_top_left = self + .navigation_metadata(network_path) .node_graph_to_viewport .inverse() .transform_point2(rounded_network_edge_distance.imports_to_edge_distance); @@ -2541,15 +2552,13 @@ impl NodeNetworkInterface { let import_exports_viewport_top_left = rounded_network_edge_distance.imports_to_edge_distance; let import_exports_viewport_bottom_right = rounded_network_edge_distance.exports_to_edge_distance; - let node_graph_top_left = network_metadata - .persistent_metadata - .navigation_metadata + let node_graph_top_left = self + .navigation_metadata(network_path) .node_graph_to_viewport .inverse() .transform_point2(import_exports_viewport_top_left); - let node_graph_bottom_right = network_metadata - .persistent_metadata - .navigation_metadata + let node_graph_bottom_right = self + .navigation_metadata(network_path) .node_graph_to_viewport .inverse() .transform_point2(import_exports_viewport_bottom_right); @@ -2597,22 +2606,18 @@ impl NodeNetworkInterface { log::error!("Could not get nested network_metadata in node_graph_ptz_mut"); return None; }; - Some(&mut network_metadata.persistent_metadata.navigation_metadata.node_graph_ptz) + Some(&mut self.navigation_metadata(network_path).node_graph_ptz) } // TODO: Optimize getting click target intersections from click by using a spacial data structure like a quadtree instead of linear search /// Click target getter methods pub fn node_from_click(&mut self, click: DVec2, network_path: &[NodeId]) -> Option { - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in node_from_click"); - return None; - }; let Some(network) = self.network(network_path) else { log::error!("Could not get nested network in node_from_click"); return None; }; - let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let point = self.navigation_metadata(network_path).node_graph_to_viewport.inverse().transform_point2(click); let nodes = network.nodes.keys().copied().collect::>(); let clicked_nodes = nodes .iter() @@ -2649,7 +2654,7 @@ impl NodeNetworkInterface { return None; }; - let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let point = self.navigation_metadata(network_path).node_graph_to_viewport.inverse().transform_point2(click); let node_ids: Vec<_> = network.nodes.keys().copied().collect(); node_ids @@ -2670,16 +2675,12 @@ impl NodeNetworkInterface { } pub fn input_connector_from_click(&mut self, click: DVec2, network_path: &[NodeId]) -> Option { - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in input_connector_from_click"); - return None; - }; let Some(network) = self.network(network_path) else { log::error!("Could not get nested network in input_connector_from_click"); return None; }; - let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let point = self.navigation_metadata(network_path).node_graph_to_viewport.inverse().transform_point2(click); network .nodes .keys() @@ -2703,16 +2704,12 @@ impl NodeNetworkInterface { } pub fn output_connector_from_click(&mut self, click: DVec2, network_path: &[NodeId]) -> Option { - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in output_connector_from_click"); - return None; - }; let Some(network) = self.network(network_path) else { log::error!("Could not get nested network in output_connector_from_click"); return None; }; - let point = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(click); + let point = self.navigation_metadata(network_path).node_graph_to_viewport.inverse().transform_point2(click); let nodes = network.nodes.keys().copied().collect::>(); nodes .iter() @@ -2773,15 +2770,11 @@ impl NodeNetworkInterface { /// Get the combined bounding box of the click targets of the selected nodes in the node graph in viewport space pub fn selected_nodes_bounding_box_viewport(&mut self, network_path: &[NodeId]) -> Option<[DVec2; 2]> { // Always get the bounding box for nodes in the currently viewed network - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in selected_nodes_bounding_box_viewport"); - return None; - }; let Some(selected_nodes) = self.selected_nodes(network_path) else { log::error!("Could not get selected nodes in selected_nodes_bounding_box_viewport"); return None; }; - let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport; + let node_graph_to_viewport = self.navigation_metadata(network_path).node_graph_to_viewport; selected_nodes .selected_nodes() .cloned() @@ -2797,13 +2790,8 @@ impl NodeNetworkInterface { /// Gets the bounding box in viewport coordinates for each node in the node graph pub fn graph_bounds_viewport_space(&mut self, network_path: &[NodeId]) -> Option<[DVec2; 2]> { let bounds = *self.all_nodes_bounding_box(network_path)?; - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in graph_bounds_viewport_space"); - return None; - }; - let bounding_box_subpath = bezier_rs::Subpath::::new_rect(bounds[0], bounds[1]); - bounding_box_subpath.bounding_box_with_transform(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport) + bounding_box_subpath.bounding_box_with_transform(self.navigation_metadata(network_path).node_graph_to_viewport) } pub fn collect_layer_widths(&mut self, network_path: &[NodeId]) -> (HashMap, HashMap) { @@ -2943,27 +2931,26 @@ impl NodeNetworkInterface { pub fn copy_all_navigation_metadata(&mut self, other_interface: &NodeNetworkInterface) { let mut stack = vec![vec![]]; while let Some(path) = stack.pop() { - let Some(self_network_metadata) = self.network_metadata_mut(&path) else { + let Some(self_network_metadata) = self.network_metadata(&path) else { continue; }; - if let Some(other_network_metadata) = other_interface.network_metadata(&path) { - self_network_metadata.persistent_metadata.navigation_metadata = other_network_metadata.persistent_metadata.navigation_metadata.clone(); - } - stack.extend(self_network_metadata.persistent_metadata.node_metadata.keys().map(|node_id| { let mut current_path = path.clone(); current_path.push(*node_id); current_path })); + if let Some(other_network_metadata) = other_interface.network_metadata(&path) { + let Some(navigation_metadata) = self.navigation_metadata_mut(&path) else { + log::error!("Could not get nested navigation_metadata in copy_all_navigation_metadata"); + continue; + }; + *navigation_metadata = other_network_metadata.persistent_metadata.navigation_metadata.clone(); + }; } } pub fn set_transform(&mut self, transform: DAffine2, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network in set_transform"); - return; - }; - network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport = transform; + self.navigation_metadata(network_path).node_graph_to_viewport = transform; self.unload_import_export_ports(network_path); } @@ -3468,8 +3455,27 @@ impl NodeNetworkInterface { node_path.push(node_id); let display_name_node_id = Self::metadata_node_id(&node_path, Metadata::DisplayName); self.insert_node_metadata(display_name_node_id, TaggedValue::String(persistent_metadata.display_name)); + // TODO: Add the rest of the node metadata nodes + + if let Some(nested_network) = persistent_metadata.network_metadata { + self.insert_network_metadata(&node_path, nested_network.persistent_metadata); + } } + /// Adds nodes for the network metadata. Should always be called when creating a new NodeNetwork + pub fn insert_network_metadata(&mut self, network_path: &[NodeId], persistent_metadata: NodeNetworkPersistentMetadata) { + let previewing_node_id = Self::metadata_node_id(network_path, Metadata::Previewing); + let navigation_metadata_id = Self::metadata_node_id(network_path, Metadata::NavigationMetadata); + self.insert_node_metadata(previewing_node_id, TaggedValue::Previewing(persistent_metadata.previewing)); + self.insert_node_metadata(navigation_metadata_id, TaggedValue::NavigationMetadata(persistent_metadata.navigation_metadata)); + // TODO: Add the rest of the network metadata nodes + + for (node_id, node_metadata) in persistent_metadata.node_metadata { + self.insert_all_node_metadata(node_id, network_path, node_metadata.persistent_metadata); + } + } + + /// Adds a node for the metadata. TODO: Consider calling this if a metadata node cannot be found. fn insert_node_metadata(&mut self, metadata_node_id: NodeId, tagged_value: TaggedValue) { let network = self.network_mut(&[]).unwrap(); log::debug!("Inserting metadata node with id {metadata_node_id}"); @@ -3667,15 +3673,11 @@ impl NodeNetworkInterface { pub fn start_previewing_without_restore(&mut self, network_path: &[NodeId]) { // Some logic will have to be performed to prevent the graph positions from being completely changed when the export changes to some previewed node - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in start_previewing_without_restore"); - return; - }; - network_metadata.persistent_metadata.previewing = Previewing::Yes { root_node_to_restore: None }; + self.set_previewing(network_path, Previewing::Yes { root_node_to_restore: None }); } fn stop_previewing(&mut self, network_path: &[NodeId]) { - if let Previewing::Yes { + if let Some(Previewing::Yes) { root_node_to_restore: Some(root_node_to_restore), } = self.previewing(network_path) { @@ -3685,11 +3687,57 @@ impl NodeNetworkInterface { network_path, ); } - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in stop_previewing"); + self.set_previewing(network_path, Previewing::No); + } + + fn set_previewing(&mut self, network_path: &[NodeId], previewing: Previewing) { + let network = self.network_mut(&[]).unwrap(); + + let previewing_node_id = Self::metadata_node_id(&network_path, Metadata::Previewing); + + let Some(previewing_node) = network.nodes.get_mut(&previewing_node_id) else { + log::error!("Could not get display name node with id {previewing_node_id} in set_previewing"); return; }; - network_metadata.persistent_metadata.previewing = Previewing::No; + + let Some(previewing_input) = previewing_node.inputs.get_mut(0) else { + log::error!("Could not get display name input in set_previewing"); + return; + }; + + let Some(TaggedValue::Previewing(current_previewing)) = previewing_input.as_value() else { + log::error!("Could not get current display name in set_previewing"); + return; + }; + + if *current_previewing == previewing { + return; + } + + *previewing_input = NodeInput::value(TaggedValue::Previewing(previewing), false); + } + + fn navigation_metadata_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NavigationMetadata> { + let network = self.network_mut(&[]).unwrap(); + + let navigation_metadata_id = Self::metadata_node_id(&network_path, Metadata::NavigationMetadata); + + let Some(navigation_metadata_node) = network.nodes.get_mut(&navigation_metadata_id) else { + log::error!("Could not get navigation metadata node with id {navigation_metadata_id} in set_navigation_metadata"); + return None; + }; + + let Some(navigation_metadata_input) = navigation_metadata_node.inputs.get_mut(0) else { + log::error!("Could not get navigation metadata input in set_navigation_metadata"); + return None; + }; + + let Some(TaggedValue::NavigationMetadata(current_navigation_metadata)) = navigation_metadata_input.as_value_mut().as_deref_mut() else { + log::error!("Could not get current navigation metadata in set_navigation_metadata"); + return None; + }; + + Some(current_navigation_metadata) } /// Sets the root node only if a node is being previewed @@ -3709,7 +3757,7 @@ impl NodeNetworkInterface { // } pub fn set_display_name(&mut self, node_id: &NodeId, display_name: String, network_path: &[NodeId]) { - let network = self.network_mut(network_path).unwrap(); + let network = self.network_mut(&[]).unwrap(); let mut node_path = network_path.to_vec(); node_path.push(*node_id); @@ -3911,7 +3959,7 @@ impl NodeNetworkInterface { // The export is clicked if *node_id == toggle_id { // If the current export is clicked and is being previewed end the preview and set either export back to root node or disconnect - if let Previewing::Yes { root_node_to_restore } = self.previewing(network_path) { + if let Some(Previewing::Yes { root_node_to_restore }) = self.previewing(network_path) { new_export = root_node_to_restore.map(|root_node| root_node.to_connector()); new_previewing_state = Previewing::No; } @@ -3930,7 +3978,7 @@ impl NodeNetworkInterface { new_export = Some(OutputConnector::node(toggle_id, 0)); // There is currently a dashed line being drawn - if let Previewing::Yes { root_node_to_restore } = self.previewing(network_path) { + if let Some(Previewing::Yes { root_node_to_restore }) = self.previewing(network_path) { // There is also a solid line being drawn if let Some(root_node_to_restore) = root_node_to_restore { // If the node with the solid line is clicked, then start previewing that node without restore @@ -3940,7 +3988,7 @@ impl NodeNetworkInterface { } else { // Root node to restore does not change new_previewing_state = Previewing::Yes { - root_node_to_restore: Some(root_node_to_restore), + root_node_to_restore: Some(*root_node_to_restore), }; } } @@ -3976,10 +4024,7 @@ impl NodeNetworkInterface { self.disconnect_input(&InputConnector::Export(0), network_path); } } - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - return; - }; - network_metadata.persistent_metadata.previewing = new_previewing_state; + self.set_previewing(network_path, new_previewing_state); } /// Sets the position of a node to an absolute position @@ -4932,86 +4977,6 @@ impl<'a> Iterator for FlowIter<'a> { } } -/// Represents an input connector with index based on the [`DocumentNode::inputs`] index, not the visible input index -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] -pub enum InputConnector { - #[serde(rename = "node")] - Node { - #[serde(rename = "nodeId")] - node_id: NodeId, - #[serde(rename = "inputIndex")] - input_index: usize, - }, - #[serde(rename = "export")] - Export(usize), -} - -impl Default for InputConnector { - fn default() -> Self { - InputConnector::Export(0) - } -} - -impl InputConnector { - pub fn node(node_id: NodeId, input_index: usize) -> Self { - InputConnector::Node { node_id, input_index } - } - - pub fn input_index(&self) -> usize { - match self { - InputConnector::Node { input_index, .. } => *input_index, - InputConnector::Export(input_index) => *input_index, - } - } - - pub fn node_id(&self) -> Option { - match self { - InputConnector::Node { node_id, .. } => Some(*node_id), - _ => None, - } - } -} - -/// Represents an output connector -#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] -pub enum OutputConnector { - #[serde(rename = "node")] - Node { - #[serde(rename = "nodeId")] - node_id: NodeId, - #[serde(rename = "outputIndex")] - output_index: usize, - }, - #[serde(rename = "import")] - Import(usize), -} - -impl Default for OutputConnector { - fn default() -> Self { - OutputConnector::Import(0) - } -} - -impl OutputConnector { - pub fn node(node_id: NodeId, output_index: usize) -> Self { - OutputConnector::Node { node_id, output_index } - } - - pub fn index(&self) -> usize { - match self { - OutputConnector::Node { output_index, .. } => *output_index, - OutputConnector::Import(output_index) => *output_index, - } - } - - pub fn node_id(&self) -> Option { - match self { - OutputConnector::Node { node_id, .. } => Some(*node_id), - _ => None, - } - } -} - #[derive(Debug, Clone)] pub struct Ports { input_ports: Vec<(usize, ClickTarget)>, @@ -5097,30 +5062,6 @@ impl Ports { } } -#[derive(PartialEq, Debug, Clone, Copy, Hash, Default, serde::Serialize, serde::Deserialize)] -pub struct RootNode { - pub node_id: NodeId, - pub output_index: usize, -} - -impl RootNode { - pub fn to_connector(&self) -> OutputConnector { - OutputConnector::Node { - node_id: self.node_id, - output_index: self.output_index, - } - } -} - -#[derive(PartialEq, Debug, Clone, Copy, Hash, Default, serde::Serialize, serde::Deserialize)] -pub enum Previewing { - /// If there is a node to restore the connection to the export for, then it is stored in the option. - /// Otherwise, nothing gets restored and the primary export is disconnected. - Yes { root_node_to_restore: Option }, - #[default] - No, -} - /// All fields in NetworkMetadata should automatically be updated by using the network interface API. If a field is none then it should be calculated based on the network state. #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] pub struct NodeNetworkMetadata { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index ad8327c46b..5fb4b2f345 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -1,5 +1,5 @@ use super::document::utility_types::document_metadata::LayerNodeIdentifier; -use super::document::utility_types::network_interface::{self, InputConnector, OutputConnector}; +use super::document::utility_types::network_interface; use super::utility_types::{PanelType, PersistentData}; use crate::application::generate_uuid; use crate::consts::DEFAULT_DOCUMENT_NAME; @@ -13,7 +13,7 @@ use crate::messages::tool::utility_types::{HintData, HintGroup}; use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor}; use graph_craft::document::value::TaggedValue; -use graph_craft::document::{NodeId, NodeInput}; +use graph_craft::document::{InputConnector, NodeId, NodeInput, OutputConnector}; use graphene_core::text::Font; use graphene_std::vector::style::{Fill, FillType, Gradient}; use interpreted_executor::dynamic_executor::IntrospectError; diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index a68afe7469..41a56c3aec 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -5,12 +5,11 @@ 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, NodeInput}; +use graph_craft::document::{InputConnector, NodeId, NodeInput}; use graphene_core::renderer::Quad; use graphene_core::text::{load_face, Font, FontCache}; use graphene_core::vector::style::Fill; diff --git a/node-graph/gcore/src/consts.rs b/node-graph/gcore/src/consts.rs index 3ca96f7ce4..b30fcddc2b 100644 --- a/node-graph/gcore/src/consts.rs +++ b/node-graph/gcore/src/consts.rs @@ -7,3 +7,7 @@ pub const LAYER_OUTLINE_STROKE_WEIGHT: f64 = 1.; // Fonts pub const DEFAULT_FONT_FAMILY: &str = "Cabin"; pub const DEFAULT_FONT_STYLE: &str = "Normal (400)"; + +// Zoom +pub const VIEWPORT_ZOOM_SCALE_MIN: f64 = 0.000_000_1; +pub const VIEWPORT_ZOOM_SCALE_MAX: f64 = 10_000.; diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 82b790d084..8a09aa019b 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -6,7 +6,7 @@ use graphene_core::memo::MemoHashGuard; pub use graphene_core::uuid::generate_uuid; use graphene_core::{Cow, MemoHash, ProtoNodeIdentifier, Type}; -use glam::IVec2; +use glam::{DAffine2, DVec2, IVec2}; use log::Metadata; use rustc_hash::FxHashMap; use std::collections::hash_map::DefaultHasher; @@ -1356,6 +1356,162 @@ impl<'a> Iterator for RecursiveNodeIter<'a> { } } +#[derive(PartialEq, Debug, Clone, Copy, Hash, Default, serde::Serialize, serde::Deserialize, DynAny)] +pub enum Previewing { + /// If there is a node to restore the connection to the export for, then it is stored in the option. + /// Otherwise, nothing gets restored and the primary export is disconnected. + Yes { root_node_to_restore: Option }, + #[default] + No, +} + +#[derive(PartialEq, Debug, Clone, Copy, Hash, Default, serde::Serialize, serde::Deserialize, DynAny)] +pub struct RootNode { + pub node_id: NodeId, + pub output_index: usize, +} + +impl RootNode { + pub fn to_connector(&self) -> OutputConnector { + OutputConnector::Node { + node_id: self.node_id, + output_index: self.output_index, + } + } +} + +/// Represents an input connector with index based on the [`DocumentNode::inputs`] index, not the visible input index +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum InputConnector { + #[serde(rename = "node")] + Node { + #[serde(rename = "nodeId")] + node_id: NodeId, + #[serde(rename = "inputIndex")] + input_index: usize, + }, + #[serde(rename = "export")] + Export(usize), +} + +impl Default for InputConnector { + fn default() -> Self { + InputConnector::Export(0) + } +} + +impl InputConnector { + pub fn node(node_id: NodeId, input_index: usize) -> Self { + InputConnector::Node { node_id, input_index } + } + + pub fn input_index(&self) -> usize { + match self { + InputConnector::Node { input_index, .. } => *input_index, + InputConnector::Export(input_index) => *input_index, + } + } + + pub fn node_id(&self) -> Option { + match self { + InputConnector::Node { node_id, .. } => Some(*node_id), + _ => None, + } + } +} + +/// Represents an output connector +#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum OutputConnector { + #[serde(rename = "node")] + Node { + #[serde(rename = "nodeId")] + node_id: NodeId, + #[serde(rename = "outputIndex")] + output_index: usize, + }, + #[serde(rename = "import")] + Import(usize), +} + +impl Default for OutputConnector { + fn default() -> Self { + OutputConnector::Import(0) + } +} + +impl OutputConnector { + pub fn node(node_id: NodeId, output_index: usize) -> Self { + OutputConnector::Node { node_id, output_index } + } + + pub fn index(&self) -> usize { + match self { + OutputConnector::Node { output_index, .. } => *output_index, + OutputConnector::Import(output_index) => *output_index, + } + } + + pub fn node_id(&self) -> Option { + match self { + OutputConnector::Node { node_id, .. } => Some(*node_id), + _ => None, + } + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, DynAny)] +pub struct NavigationMetadata { + /// The current pan, and zoom state of the viewport's view of the node graph. + /// Ensure `DocumentMessage::UpdateDocumentTransform` is called when the pan, zoom, or transform changes. + pub node_graph_ptz: PTZ, + // TODO: Remove and replace with calculate_offset_transform from the node_graph_ptz. This will be difficult since it requires both the navigation message handler and the IPP + /// Transform from node graph space to viewport space. + pub node_graph_to_viewport: DAffine2, + /// The viewport pixel distance distance between the left edge of the node graph and the exports. Rounded to nearest grid space when the panning ends. + #[serde(skip)] + pub exports_to_edge_distance: DVec2, + /// The viewport pixel distance between the left edge of the node graph and the imports. Rounded to nearest grid space when the panning ends. + #[serde(skip)] + pub imports_to_edge_distance: DVec2, +} + +impl Default for NavigationMetadata { + fn default() -> NavigationMetadata { + //Default PTZ and transform + NavigationMetadata { + node_graph_ptz: PTZ::default(), + node_graph_to_viewport: DAffine2::IDENTITY, + exports_to_edge_distance: DVec2::ZERO, + imports_to_edge_distance: DVec2::ZERO, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize, DynAny)] +#[serde(default)] +pub struct PTZ { + pub pan: DVec2, + pub tilt: f64, + zoom: f64, +} + +impl Default for PTZ { + fn default() -> Self { + Self { pan: DVec2::ZERO, tilt: 0., zoom: 1. } + } +} + +impl PTZ { + pub fn zoom(&self) -> f64 { + self.zoom + } + + pub fn set_zoom(&mut self, zoom: f64) { + self.zoom = zoom.clamp(graphene_core::consts::VIEWPORT_ZOOM_SCALE_MIN, graphene_core::consts::VIEWPORT_ZOOM_SCALE_MAX) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 32b62b4b81..17b451a6df 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -178,6 +178,8 @@ tagged_value! { CentroidType(graphene_core::vector::misc::CentroidType), BooleanOperation(graphene_core::vector::misc::BooleanOperation), FontCache(Arc), + Previewing(crate::document::Previewing), + NavigationMetadata(crate::document::NavigationMetadata) } impl TaggedValue { @@ -297,4 +299,19 @@ mod fake_hash { self.1.hash(state) } } + impl FakeHash for crate::document::PTZ { + fn hash(&self, state: &mut H) { + self.pan.hash(state); + self.tilt.hash(state); + self.zoom.hash(state); + } + } + impl FakeHash for crate::document::NavigationMetadata { + fn hash(&self, state: &mut H) { + self.node_graph_ptz.hash(state); + self.node_graph_to_viewport.hash(state); + self.exports_to_edge_distance.hash(state); + self.imports_to_edge_distance.hash(state); + } + } }