mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-24 00:48:12 +08:00
Replace node definition string-based lookups with DefinitionIdentifier instances (#3451)
* create definition identifier and integrate it * Bug fixes and code review * formatting * Fix migrations * Fix remove handles migration * formatting * Fix test * Fix tests 2 * fix deserialization * Code review * Small fixes * Consolidate 'Morph' node migrations * Add old SamplePointsNode name to migrations list * Fix tests * Unrelated small fix * Fix migration crashes * Fix tests * Final code review * fmt * Add metadata --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
4fea2b0fe7
commit
a6052c5819
@@ -2,6 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument};
|
||||
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
|
||||
use crate::messages::input_mapper::utility_types::misc::ActionShortcut;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{
|
||||
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphErrorDiagnostic, Transform,
|
||||
};
|
||||
@@ -60,7 +61,7 @@ pub enum FrontendMessage {
|
||||
// Send prefix: Send global, static data to the frontend that is never updated
|
||||
SendUIMetadata {
|
||||
#[serde(rename = "nodeDescriptions")]
|
||||
node_descriptions: Vec<(String, String)>,
|
||||
node_descriptions: Vec<(DefinitionIdentifier, String)>,
|
||||
#[serde(rename = "nodeTypes")]
|
||||
node_types: Vec<FrontendNodeType>,
|
||||
},
|
||||
|
||||
@@ -287,11 +287,7 @@ impl LayoutMessageHandler {
|
||||
responses.add(callback_message);
|
||||
}
|
||||
WidgetValueAction::Update => {
|
||||
let Some(value) = value.as_str().map(|s| s.to_string()) else {
|
||||
error!("NodeCatalog update was not of type String");
|
||||
return;
|
||||
};
|
||||
let callback_message = (node_type_input.on_update.callback)(&value);
|
||||
let callback_message = (node_type_input.on_update.callback)(&value.into());
|
||||
responses.add(callback_message);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -790,23 +790,19 @@ impl DiffUpdate {
|
||||
};
|
||||
|
||||
// Recursively fill menu list entries with their realized shortcut keys specific to the current bindings and platform
|
||||
let apply_action_shortcut_to_menu_lists = |entry_sections: &mut MenuListEntrySections| {
|
||||
struct RecursiveWrapper<'a>(&'a dyn Fn(&mut MenuListEntrySections, &RecursiveWrapper));
|
||||
let recursive_wrapper = RecursiveWrapper(&|entry_sections: &mut MenuListEntrySections, recursive_wrapper| {
|
||||
for entries in entry_sections {
|
||||
for entry in entries {
|
||||
// Convert `ActionShortcut::Action` to `ActionShortcut::Shortcut`
|
||||
if let Some(tooltip_shortcut) = &mut entry.tooltip_shortcut {
|
||||
tooltip_shortcut.realize_shortcut(action_input_mapping);
|
||||
}
|
||||
|
||||
// Recursively call this inner closure on the menu's children
|
||||
(recursive_wrapper.0)(&mut entry.children, recursive_wrapper);
|
||||
fn apply_action_shortcut_to_menu_lists(entry_sections: &mut MenuListEntrySections, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) {
|
||||
for entries in entry_sections {
|
||||
for entry in entries {
|
||||
// Convert `ActionShortcut::Action` to `ActionShortcut::Shortcut`
|
||||
if let Some(tooltip_shortcut) = &mut entry.tooltip_shortcut {
|
||||
tooltip_shortcut.realize_shortcut(action_input_mapping);
|
||||
}
|
||||
|
||||
// Recursively call this function on the menu's children
|
||||
apply_action_shortcut_to_menu_lists(&mut entry.children, action_input_mapping);
|
||||
}
|
||||
});
|
||||
(recursive_wrapper.0)(entry_sections, &recursive_wrapper)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Hash the menu list entry sections for caching purposes
|
||||
let hash_menu_list_entry_sections = |entry_sections: &MenuListEntrySections| {
|
||||
@@ -833,11 +829,11 @@ impl DiffUpdate {
|
||||
// Apply shortcut conversions to all widgets that have menu lists
|
||||
let convert_menu_lists = |widget_instance: &mut WidgetInstance| match &mut *widget_instance.widget {
|
||||
Widget::DropdownInput(dropdown_input) => {
|
||||
apply_action_shortcut_to_menu_lists(&mut dropdown_input.entries);
|
||||
apply_action_shortcut_to_menu_lists(&mut dropdown_input.entries, action_input_mapping);
|
||||
dropdown_input.entries_hash = hash_menu_list_entry_sections(&dropdown_input.entries);
|
||||
}
|
||||
Widget::TextButton(text_button) => {
|
||||
apply_action_shortcut_to_menu_lists(&mut text_button.menu_list_children);
|
||||
apply_action_shortcut_to_menu_lists(&mut text_button.menu_list_children, action_input_mapping);
|
||||
text_button.menu_list_children_hash = hash_menu_list_entry_sections(&text_button.menu_list_children);
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::messages::input_mapper::utility_types::misc::ActionShortcut;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use derivative::*;
|
||||
use graphene_std::Color;
|
||||
use graphene_std::raster::curve::Curve;
|
||||
@@ -273,7 +274,7 @@ pub struct NodeCatalog {
|
||||
// Callbacks
|
||||
#[serde(skip)]
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
pub on_update: WidgetCallback<String>,
|
||||
pub on_update: WidgetCallback<DefinitionIdentifier>,
|
||||
#[serde(skip)]
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
pub on_commit: WidgetCallback<()>,
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::data_panel::{DataPanelMessageContext, DataPanelMessageHandler};
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::NodeGraphMessageContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType;
|
||||
use crate::messages::portfolio::document::overlays::grid_overlays::{grid_overlay, overlay_options};
|
||||
use crate::messages::portfolio::document::overlays::utility_types::{OverlaysType, OverlaysVisibilitySettings, Pivot};
|
||||
@@ -1548,7 +1549,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||
// Create an artboard and set its dimensions to the bounding box size and location
|
||||
let node_id = NodeId::new();
|
||||
let node_layer_id = LayerNodeIdentifier::new_unchecked(node_id);
|
||||
let new_artboard_node = document_node_definitions::resolve_document_node_type("Artboard")
|
||||
let new_artboard_node = document_node_definitions::resolve_network_node_type("Artboard")
|
||||
.expect("Failed to create artboard node")
|
||||
.default_node_template();
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
@@ -2133,8 +2134,7 @@ impl DocumentMessageHandler {
|
||||
network_interface.upstream_flow_back_from_nodes(vec![selected_id.to_node()], &[], FlowType::HorizontalFlow).find(|id| {
|
||||
network_interface
|
||||
.reference(id, &[])
|
||||
.map(|name| name.as_deref().unwrap_or_default() == "Boolean Operation")
|
||||
.unwrap_or_default()
|
||||
.is_some_and(|reference| reference == DefinitionIdentifier::Network("Boolean Operation".into()))
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -382,7 +382,7 @@ fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node,
|
||||
|
||||
modify_inputs.insert_vector(subpaths, layer, true, path.fill().is_some(), path.stroke().is_some());
|
||||
|
||||
if let Some(transform_node_id) = modify_inputs.existing_node_id("Transform", true) {
|
||||
if let Some(transform_node_id) = modify_inputs.existing_network_node_id("Transform", true) {
|
||||
transform_utils::update_transform(modify_inputs.network_interface, &transform_node_id, transform * usvg_transform(node.abs_transform()));
|
||||
}
|
||||
|
||||
|
||||
@@ -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::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type, resolve_network_node_type, resolve_proto_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::prelude::*;
|
||||
use glam::{DAffine2, IVec2};
|
||||
use graph_craft::concrete;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete};
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::raster::BlendMode;
|
||||
@@ -123,14 +123,14 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
|
||||
/// Creates a new layer and adds it to the document network. network_interface.move_layer_to_stack should be called after
|
||||
pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier {
|
||||
let new_merge_node = resolve_document_node_type("Merge").expect("Merge node").default_node_template();
|
||||
let new_merge_node = resolve_network_node_type("Merge").expect("Merge node").default_node_template();
|
||||
self.network_interface.insert_node(new_id, new_merge_node, &[]);
|
||||
LayerNodeIdentifier::new(new_id, self.network_interface)
|
||||
}
|
||||
|
||||
/// Creates an artboard as the primary export for the document network
|
||||
pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier {
|
||||
let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([
|
||||
let artboard_node_template = resolve_network_node_type("Artboard").expect("Node").node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::Artboard(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(artboard.location.into()), false)),
|
||||
@@ -143,7 +143,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
pub fn insert_boolean_data(&mut self, operation: graphene_std::path_bool::BooleanOperation, layer: LayerNodeIdentifier) {
|
||||
let boolean = resolve_document_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([
|
||||
let boolean = resolve_network_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
|
||||
]);
|
||||
@@ -156,7 +156,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
pub fn insert_vector(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {
|
||||
let vector = Table::new_from_element(Vector::from_subpaths(subpaths, true));
|
||||
|
||||
let shape = resolve_document_node_type("Path")
|
||||
let shape = resolve_network_node_type("Path")
|
||||
.expect("Path node does not exist")
|
||||
.node_template_input_override([Some(NodeInput::value(TaggedValue::Vector(vector), false))]);
|
||||
let shape_id = NodeId::new();
|
||||
@@ -164,21 +164,25 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
self.network_interface.move_node_to_chain_start(&shape_id, layer, &[]);
|
||||
|
||||
if include_transform {
|
||||
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template();
|
||||
let transform = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
|
||||
let transform_id = NodeId::new();
|
||||
self.network_interface.insert_node(transform_id, transform, &[]);
|
||||
self.network_interface.move_node_to_chain_start(&transform_id, layer, &[]);
|
||||
}
|
||||
|
||||
if include_fill {
|
||||
let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_node_template();
|
||||
let fill = resolve_proto_node_type(graphene_std::vector_nodes::fill::IDENTIFIER)
|
||||
.expect("Fill node does not exist")
|
||||
.default_node_template();
|
||||
let fill_id = NodeId::new();
|
||||
self.network_interface.insert_node(fill_id, fill, &[]);
|
||||
self.network_interface.move_node_to_chain_start(&fill_id, layer, &[]);
|
||||
}
|
||||
|
||||
if include_stroke {
|
||||
let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_node_template();
|
||||
let stroke = resolve_proto_node_type(graphene_std::vector_nodes::stroke::IDENTIFIER)
|
||||
.expect("Stroke node does not exist")
|
||||
.default_node_template();
|
||||
let stroke_id = NodeId::new();
|
||||
self.network_interface.insert_node(stroke_id, stroke, &[]);
|
||||
self.network_interface.move_node_to_chain_start(&stroke_id, layer, &[]);
|
||||
@@ -186,21 +190,27 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
pub fn insert_text(&mut self, text: String, font: Font, typesetting: TypesettingConfig, layer: LayerNodeIdentifier) {
|
||||
let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_node_template();
|
||||
let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_node_template();
|
||||
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template();
|
||||
let text = resolve_document_node_type("Text").expect("Text node does not exist").node_template_input_override([
|
||||
Some(NodeInput::scope("editor-api")),
|
||||
Some(NodeInput::value(TaggedValue::String(text), false)),
|
||||
Some(NodeInput::value(TaggedValue::Font(font), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)),
|
||||
Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_width), false)),
|
||||
Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_height), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)),
|
||||
Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)),
|
||||
]);
|
||||
let stroke = resolve_proto_node_type(graphene_std::vector_nodes::stroke::IDENTIFIER)
|
||||
.expect("Stroke node does not exist")
|
||||
.default_node_template();
|
||||
let fill = resolve_proto_node_type(graphene_std::vector_nodes::fill::IDENTIFIER)
|
||||
.expect("Fill node does not exist")
|
||||
.default_node_template();
|
||||
let transform = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
|
||||
let text = resolve_proto_node_type(graphene_std::text::text::IDENTIFIER)
|
||||
.expect("Text node does not exist")
|
||||
.node_template_input_override([
|
||||
Some(NodeInput::scope("editor-api")),
|
||||
Some(NodeInput::value(TaggedValue::String(text), false)),
|
||||
Some(NodeInput::value(TaggedValue::Font(font), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)),
|
||||
Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_width), false)),
|
||||
Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_height), false)),
|
||||
Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)),
|
||||
Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)),
|
||||
]);
|
||||
|
||||
let text_id = NodeId::new();
|
||||
self.network_interface.insert_node(text_id, text, &[]);
|
||||
@@ -220,8 +230,8 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
pub fn insert_image_data(&mut self, image_frame: Table<Raster<CPU>>, layer: LayerNodeIdentifier) {
|
||||
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template();
|
||||
let image = resolve_document_node_type("Image Value")
|
||||
let transform = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
|
||||
let image = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER)
|
||||
.expect("ImageValue node does not exist")
|
||||
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::Raster(image_frame), false))]);
|
||||
|
||||
@@ -245,18 +255,26 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets the node id of a node with a specific reference that is upstream from the layer node, and optionally creates it if it does not exist.
|
||||
/// The returned node is based on the selection dots in the layer. The right most dot will always insert/access the path that flows directly into the layer.
|
||||
/// Each dot after that represents an existing path node. If there is an existing upstream node, then it will always be returned first.
|
||||
pub fn existing_node_id(&mut self, reference_name: &'static str, create_if_nonexistent: bool) -> Option<NodeId> {
|
||||
/// Gets the node id of a network node with a specific reference that is upstream from the layer node, and optionally creates it if it does not exist.
|
||||
pub fn existing_network_node_id(&mut self, reference: &str, create_if_nonexistent: bool) -> Option<NodeId> {
|
||||
self.existing_node_id(&DefinitionIdentifier::Network(reference.into()), create_if_nonexistent)
|
||||
}
|
||||
|
||||
/// Gets the node id of a proto node with a specific reference that is upstream from the layer node, and optionally creates it if it does not exist.
|
||||
pub fn existing_proto_node_id(&mut self, reference: ProtoNodeIdentifier, create_if_nonexistent: bool) -> Option<NodeId> {
|
||||
self.existing_node_id(&DefinitionIdentifier::ProtoNode(reference), create_if_nonexistent)
|
||||
}
|
||||
|
||||
/// Gets the node id of a document node with a specific reference that is upstream from the layer node, and optionally creates it if it does not exist.
|
||||
fn existing_node_id(&mut self, reference: &DefinitionIdentifier, create_if_nonexistent: bool) -> Option<NodeId> {
|
||||
// Start from the layer node or export
|
||||
let output_layer = self.get_output_layer()?;
|
||||
|
||||
let existing_node_id = Self::locate_node_in_layer_chain(reference_name, output_layer, self.network_interface);
|
||||
let existing_node_id = Self::locate_node_in_layer_chain(reference, output_layer, self.network_interface);
|
||||
|
||||
// Create a new node if the node does not exist and update its inputs
|
||||
if create_if_nonexistent {
|
||||
return existing_node_id.or_else(|| self.create_node(reference_name));
|
||||
return existing_node_id.or_else(|| self.create_node(reference));
|
||||
}
|
||||
|
||||
existing_node_id
|
||||
@@ -265,16 +283,13 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
/// Gets the node id of a node with a specific reference (name) that is upstream (leftward) from the layer node, but before reaching another upstream layer stack.
|
||||
/// For example, if given a parent layer, this would find a requested "Transform" or "Boolean Operation" node in its chain, between the parent layer and its layer stack child contents.
|
||||
/// It would also travel up an entire layer that's not fed by a stack until reaching the generator node, such as a "Rectangle" or "Path" layer.
|
||||
pub fn locate_node_in_layer_chain(reference_name: &str, left_of_layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
pub fn locate_node_in_layer_chain(reference: &DefinitionIdentifier, left_of_layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
let upstream = network_interface.upstream_flow_back_from_nodes(vec![left_of_layer.to_node()], &[], network_interface::FlowType::HorizontalFlow);
|
||||
|
||||
// Look at all of the upstream nodes
|
||||
for upstream_node in upstream {
|
||||
// Check if this is the node we have been searching for.
|
||||
if network_interface
|
||||
.reference(&upstream_node, &[])
|
||||
.is_some_and(|node_reference| *node_reference == Some(reference_name.to_string()))
|
||||
{
|
||||
if network_interface.reference(&upstream_node, &[]).is_some_and(|node_reference| node_reference == *reference) {
|
||||
if !network_interface.is_visible(&upstream_node, &[]) {
|
||||
continue;
|
||||
}
|
||||
@@ -293,10 +308,10 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
/// Create a new node inside the layer
|
||||
pub fn create_node(&mut self, reference: &str) -> Option<NodeId> {
|
||||
pub fn create_node(&mut self, reference: &DefinitionIdentifier) -> Option<NodeId> {
|
||||
let output_layer = self.get_output_layer()?;
|
||||
let Some(node_definition) = resolve_document_node_type(reference) else {
|
||||
log::error!("Node type {reference} does not exist in ModifyInputsContext::existing_node_id");
|
||||
log::error!("Node {reference:?} does not exist in ModifyInputsContext::existing_node_id");
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -305,7 +320,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
if node_definition.identifier == "Path" {
|
||||
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]);
|
||||
if layer_input_type.compiled_nested_type() == Some(&concrete!(Table<Graphic>)) {
|
||||
let Some(flatten_path_definition) = resolve_document_node_type("Flatten Path") else {
|
||||
let Some(flatten_path_definition) = resolve_proto_node_type(graphene_std::vector_nodes::flatten_path::IDENTIFIER) else {
|
||||
log::error!("Flatten Path does not exist in ModifyInputsContext::existing_node_id");
|
||||
return None;
|
||||
};
|
||||
@@ -325,7 +340,9 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let backup_color_index = 2;
|
||||
let backup_gradient_index = 3;
|
||||
|
||||
let Some(fill_node_id) = self.existing_node_id("Fill", true) else { return };
|
||||
let Some(fill_node_id) = self.existing_proto_node_id(graphene_std::vector_nodes::fill::IDENTIFIER, true) else {
|
||||
return;
|
||||
};
|
||||
match &fill {
|
||||
Fill::None => {
|
||||
let input_connector = InputConnector::node(fill_node_id, backup_color_index);
|
||||
@@ -345,32 +362,42 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
pub fn blend_mode_set(&mut self, blend_mode: BlendMode) {
|
||||
let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return };
|
||||
let Some(blend_node_id) = self.existing_proto_node_id(graphene_std::blending_nodes::blending::IDENTIFIER, true) else {
|
||||
return;
|
||||
};
|
||||
let input_connector = InputConnector::node(blend_node_id, 1);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::BlendMode(blend_mode), false), false);
|
||||
}
|
||||
|
||||
pub fn opacity_set(&mut self, opacity: f64) {
|
||||
let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return };
|
||||
let Some(blend_node_id) = self.existing_proto_node_id(graphene_std::blending_nodes::blending::IDENTIFIER, true) else {
|
||||
return;
|
||||
};
|
||||
let input_connector = InputConnector::node(blend_node_id, 2);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(opacity * 100.), false), false);
|
||||
}
|
||||
|
||||
pub fn blending_fill_set(&mut self, fill: f64) {
|
||||
let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return };
|
||||
let Some(blend_node_id) = self.existing_proto_node_id(graphene_std::blending_nodes::blending::IDENTIFIER, true) else {
|
||||
return;
|
||||
};
|
||||
let input_connector = InputConnector::node(blend_node_id, 3);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(fill * 100.), false), false);
|
||||
}
|
||||
|
||||
pub fn clip_mode_toggle(&mut self, clip_mode: Option<bool>) {
|
||||
let clip = !clip_mode.unwrap_or(false);
|
||||
let Some(clip_node_id) = self.existing_node_id("Blending", true) else { return };
|
||||
let Some(clip_node_id) = self.existing_proto_node_id(graphene_std::blending_nodes::blending::IDENTIFIER, true) else {
|
||||
return;
|
||||
};
|
||||
let input_connector = InputConnector::node(clip_node_id, 4);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Bool(clip), false), false);
|
||||
}
|
||||
|
||||
pub fn stroke_set(&mut self, stroke: Stroke) {
|
||||
let Some(stroke_node_id) = self.existing_node_id("Stroke", true) else { return };
|
||||
let Some(stroke_node_id) = self.existing_proto_node_id(graphene_std::vector::stroke::IDENTIFIER, true) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let stroke_color = if let Some(color) = stroke.color { Table::new_from_element(color) } else { Table::new() };
|
||||
|
||||
@@ -399,7 +426,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
pub fn transform_change_with_parent(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, skip_rerender: bool) {
|
||||
// Get the existing upstream Transform node and its transform, if present, otherwise use the identity transform
|
||||
let (layer_transform, transform_node_id) = self
|
||||
.existing_node_id("Transform", false)
|
||||
.existing_network_node_id("Transform", false)
|
||||
.and_then(|transform_node_id| {
|
||||
let document_node = self.network_interface.document_network().nodes.get(&transform_node_id)?;
|
||||
Some((transform_utils::get_current_transform(&document_node.inputs), transform_node_id))
|
||||
@@ -423,7 +450,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
/// A new Transform node is created if one does not exist, unless it would be given the identity transform.
|
||||
pub fn transform_set(&mut self, transform: DAffine2, transform_in: TransformIn, skip_rerender: bool) {
|
||||
// Get the existing upstream Transform node, if present
|
||||
let transform_node_id = self.existing_node_id("Transform", false);
|
||||
let transform_node_id = self.existing_network_node_id("Transform", false);
|
||||
|
||||
// Get a transform appropriate for the requested space
|
||||
let to_transform = match transform_in {
|
||||
@@ -448,7 +475,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
// Create the Transform node
|
||||
self.existing_node_id("Transform", true)
|
||||
self.existing_network_node_id("Transform", true)
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
@@ -464,19 +491,23 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
pub fn vector_modify(&mut self, modification_type: VectorModificationType) {
|
||||
let Some(path_node_id) = self.existing_node_id("Path", true) else { return };
|
||||
let Some(path_node_id) = self.existing_network_node_id("Path", true) else {
|
||||
return;
|
||||
};
|
||||
self.network_interface.vector_modify(&path_node_id, modification_type);
|
||||
self.responses.add(PropertiesPanelMessage::Refresh);
|
||||
self.responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
|
||||
pub fn brush_modify(&mut self, strokes: Vec<BrushStroke>) {
|
||||
let Some(brush_node_id) = self.existing_node_id("Brush", true) else { return };
|
||||
let Some(brush_node_id) = self.existing_network_node_id("Brush", true) else {
|
||||
return;
|
||||
};
|
||||
self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokes(strokes), false), false);
|
||||
}
|
||||
|
||||
pub fn resize_artboard(&mut self, location: IVec2, dimensions: IVec2) {
|
||||
let Some(artboard_node_id) = self.existing_node_id("Artboard", true) else {
|
||||
let Some(artboard_node_id) = self.existing_network_node_id("Artboard", true) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::transform::Footprint;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::*;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use serde_json::Value;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
pub struct NodePropertiesContext<'a> {
|
||||
pub persistent_data: &'a PersistentData,
|
||||
@@ -54,10 +55,63 @@ impl NodePropertiesContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The key used to access definitions for a network node or proto node.
|
||||
/// For proto nodes, this is their [`ProtoNodeIdentifier`].
|
||||
/// For network nodes, it doesn't necessarily have to be the same as the network's display name, but it often is.
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
#[serde(tag = "type", content = "data")]
|
||||
pub enum DefinitionIdentifier {
|
||||
ProtoNode(ProtoNodeIdentifier),
|
||||
Network(String),
|
||||
}
|
||||
|
||||
impl DefinitionIdentifier {
|
||||
pub fn implementation_name_from_identifier(&self) -> String {
|
||||
match self {
|
||||
DefinitionIdentifier::Network(name) => name.clone(),
|
||||
DefinitionIdentifier::ProtoNode(proto_node_identifier) => registry::NODE_METADATA
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(proto_node_identifier)
|
||||
.map(|metadata| metadata.display_name.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
let mut last_segment = proto_node_identifier.as_str().split("::").last().unwrap_or_default().to_string();
|
||||
last_segment = last_segment.strip_suffix("Node").unwrap_or(&last_segment).to_string();
|
||||
last_segment
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Value> for DefinitionIdentifier {
|
||||
fn from(value: Value) -> Self {
|
||||
match value {
|
||||
Value::Object(mut map) => {
|
||||
let ty = map.remove("type").unwrap().as_str().unwrap().to_owned();
|
||||
|
||||
match ty.as_ref() {
|
||||
"Network" => {
|
||||
let data = map.remove("data").unwrap().as_str().unwrap().to_owned();
|
||||
DefinitionIdentifier::Network(data)
|
||||
}
|
||||
"ProtoNode" => {
|
||||
let value = map.remove("data").unwrap();
|
||||
let proto: ProtoNodeIdentifier = serde_json::from_value(value).unwrap();
|
||||
DefinitionIdentifier::ProtoNode(proto)
|
||||
}
|
||||
_ => panic!("Unknown `DefinitionIdentifier` type: {:?}", ty),
|
||||
}
|
||||
}
|
||||
|
||||
_ => panic!("Expected a JSON object to convert to `DefinitionIdentifier`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Acts as a description for a [DocumentNode] before it gets instantiated as one.
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DocumentNodeDefinition {
|
||||
/// Used by the reference field in [`DocumentNodeMetadata`] to prevent storing a copy of the implementation, if it is unchanged from the definition.
|
||||
/// Used to create the [`DefinitionIdentifier::Network`] identifier.
|
||||
pub identifier: &'static str,
|
||||
|
||||
/// All data required to construct a [`DocumentNode`] and [`DocumentNodeMetadata`]
|
||||
@@ -75,14 +129,14 @@ pub struct DocumentNodeDefinition {
|
||||
pub properties: Option<&'static str>,
|
||||
}
|
||||
|
||||
// We use the once cell for lazy initialization to avoid the overhead of reconstructing the node list every time.
|
||||
// TODO: make document nodes not require a `'static` lifetime to avoid having to split the construction into const and non-const parts.
|
||||
static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy<Vec<DocumentNodeDefinition>> = once_cell::sync::Lazy::new(static_nodes);
|
||||
// We use the once_cell to use the document node definitions throughout the editor without passing a reference
|
||||
// TODO: If dynamic node library is required, use a Mutex as well
|
||||
static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy<HashMap<DefinitionIdentifier, DocumentNodeDefinition>> = once_cell::sync::Lazy::new(document_node_definitions);
|
||||
|
||||
// TODO: Dynamic node library
|
||||
/// Defines the "signature" or "header file"-like metadata for the document nodes, but not the implementation (which is defined in the node registry).
|
||||
/// The [`DocumentNode`] is the instance while these [`DocumentNodeDefinition`]s are the "classes" or "blueprints" from which the instances are built.
|
||||
fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
/// Only the position can be set for protonodes within a definition. The rest of the metadata comes from the node macro in NODE_METADATA
|
||||
fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefinition> {
|
||||
let custom = vec![
|
||||
// TODO: Auto-generate this from its proto node macro
|
||||
DocumentNodeDefinition {
|
||||
@@ -100,7 +154,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed("Returns the input value without changing it. This is useful for rerouting wires for organization purposes."),
|
||||
description: Cow::Borrowed("Passes-through the input value without changing it. This is useful for rerouting wires for organization purposes."),
|
||||
properties: None,
|
||||
},
|
||||
// TODO: Auto-generate this from its proto node macro
|
||||
@@ -140,6 +194,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
description: Cow::Borrowed("An empty node network you can use to create your own custom nodes."),
|
||||
properties: None,
|
||||
},
|
||||
// TODO: Auto-generate this from its proto node macro
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Cache",
|
||||
category: "General",
|
||||
@@ -224,7 +279,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "To Graphic".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -232,7 +286,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Wrap Graphic".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -240,7 +293,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Source Node ID".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -248,7 +300,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Monitor".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -256,7 +307,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extend".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -375,7 +425,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Create Artboard".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -383,7 +432,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Source Node ID".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -391,7 +439,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Monitor".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -399,7 +446,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extend".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -4)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -989,7 +1035,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Load Resource".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -997,7 +1042,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Decode Image".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1071,7 +1115,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Create Surface".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1079,7 +1122,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Cache".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 2)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1087,7 +1129,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Rasterize".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1108,12 +1149,13 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
// TODO: Auto-generate this from its proto node macro
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Noise Pattern",
|
||||
category: "Raster: Pattern",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::std_nodes::noise_pattern::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::raster_nodes::std_nodes::noise_pattern::IDENTIFIER),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::None, false),
|
||||
NodeInput::value(TaggedValue::Bool(true), false),
|
||||
@@ -1228,7 +1270,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extract Channel".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1236,7 +1277,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extract Channel".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1244,7 +1284,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extract Channel".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 4)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1252,7 +1291,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extract Channel".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 6)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1312,7 +1350,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extract XY".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1320,7 +1357,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extract XY".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1382,7 +1418,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Brush".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1402,6 +1437,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
// TODO: Auto-generate this from its proto node macro
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Memoize",
|
||||
category: "Debug",
|
||||
@@ -1463,7 +1499,13 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Extract Executor".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1471,20 +1513,11 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Upload Texture".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Cache".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -1592,7 +1625,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Monitor".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1600,7 +1632,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Path Modify".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1621,6 +1652,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
// TODO: Auto-generate this from its proto node macro
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Text",
|
||||
category: "Text",
|
||||
@@ -1788,7 +1820,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Monitor".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1796,15 +1827,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Transform".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
input_metadata: vec![
|
||||
("Value", "TODO").into(),
|
||||
("Translation", "TODO").into(),
|
||||
("Rotation", "TODO").into(),
|
||||
("Scale", "TODO").into(),
|
||||
("Skew", "TODO").into(),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -1891,7 +1914,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Boolean Operation".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1899,7 +1921,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Memoize".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1981,7 +2002,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Subpath Segment Lengths".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 7)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1989,7 +2009,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Sample Polyline".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1997,7 +2016,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Memoize".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -2104,7 +2122,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Poisson-Disk Points".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -2112,7 +2129,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Memoize".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -2637,102 +2653,48 @@ fn static_input_properties() -> InputProperties {
|
||||
map
|
||||
}
|
||||
|
||||
pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefinition> {
|
||||
DOCUMENT_NODE_TYPES.iter().find(|definition| definition.identifier == identifier)
|
||||
pub fn resolve_network_node_type(identifier: &str) -> Option<&'static DocumentNodeDefinition> {
|
||||
resolve_document_node_type(&DefinitionIdentifier::Network(identifier.into()))
|
||||
}
|
||||
|
||||
pub fn resolve_proto_node_type(identifier: ProtoNodeIdentifier) -> Option<&'static DocumentNodeDefinition> {
|
||||
resolve_document_node_type(&DefinitionIdentifier::ProtoNode(identifier))
|
||||
}
|
||||
|
||||
pub fn resolve_document_node_type(identifier: &DefinitionIdentifier) -> Option<&'static DocumentNodeDefinition> {
|
||||
DOCUMENT_NODE_TYPES.get(identifier)
|
||||
}
|
||||
|
||||
pub fn collect_node_types() -> Vec<FrontendNodeType> {
|
||||
// Create a mapping from registry ID to document node identifier
|
||||
let id_to_identifier_map: HashMap<ProtoNodeIdentifier, &'static str> = DOCUMENT_NODE_TYPES
|
||||
DOCUMENT_NODE_TYPES
|
||||
.iter()
|
||||
.filter_map(|definition| {
|
||||
if let DocumentNodeImplementation::ProtoNode(name) = &definition.node_template.document_node.implementation {
|
||||
Some((name.clone(), definition.identifier))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let mut extracted_node_types = Vec::new();
|
||||
|
||||
let node_registry = registry::NODE_REGISTRY.lock().unwrap();
|
||||
let node_metadata = registry::NODE_METADATA.lock().unwrap();
|
||||
for (id, metadata) in node_metadata.iter() {
|
||||
if let Some(implementations) = node_registry.get(id) {
|
||||
let identifier = match id_to_identifier_map.get(id) {
|
||||
Some(&id) => id,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// Extract category from metadata (already creates an owned String)
|
||||
let category = metadata.category.unwrap_or_default();
|
||||
|
||||
// Extract input types (already creates owned Strings)
|
||||
let input_types = implementations
|
||||
.iter()
|
||||
.flat_map(|(_, node_io)| node_io.inputs.iter().map(|ty| ty.nested_type().to_cow_string()))
|
||||
.collect::<HashSet<Cow<'static, str>>>()
|
||||
.into_iter()
|
||||
.collect::<Vec<Cow<'static, str>>>();
|
||||
|
||||
// Create a FrontendNodeType
|
||||
let node_type = FrontendNodeType::with_input_types(identifier, category, input_types);
|
||||
|
||||
// Store the created node_type
|
||||
extracted_node_types.push(node_type);
|
||||
}
|
||||
}
|
||||
|
||||
let node_types: Vec<FrontendNodeType> = DOCUMENT_NODE_TYPES
|
||||
.iter()
|
||||
.filter(|definition| !definition.category.is_empty())
|
||||
.map(|definition| {
|
||||
.filter(|(_, definition)| !definition.category.is_empty())
|
||||
.map(|(identifier, definition)| {
|
||||
let input_types = definition
|
||||
.node_template
|
||||
.document_node
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_cow_string()))
|
||||
.collect::<Vec<Cow<'static, str>>>();
|
||||
|
||||
FrontendNodeType::with_input_types(definition.identifier, definition.category, input_types)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Update categories in extracted_node_types from node_types
|
||||
for extracted_node in &mut extracted_node_types {
|
||||
if extracted_node.category.is_empty() {
|
||||
// Find matching node in node_types and update category if found
|
||||
if let Some(matching_node) = node_types.iter().find(|node_type| node_type.name == extracted_node.name) {
|
||||
extracted_node.category = matching_node.category.clone();
|
||||
.map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_string()).unwrap_or_default())
|
||||
.collect::<Vec<String>>();
|
||||
let mut name = definition.node_template.persistent_node_metadata.display_name.clone();
|
||||
if name.is_empty() {
|
||||
name = identifier.implementation_name_from_identifier()
|
||||
}
|
||||
}
|
||||
}
|
||||
let missing_nodes: Vec<FrontendNodeType> = node_types
|
||||
.iter()
|
||||
.filter(|node| !extracted_node_types.iter().any(|extracted| extracted.name == node.name))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
// Add the missing nodes to extracted_node_types
|
||||
for node in missing_nodes {
|
||||
extracted_node_types.push(node);
|
||||
}
|
||||
// Remove entries with empty categories
|
||||
extracted_node_types.retain(|node| !node.category.is_empty());
|
||||
|
||||
extracted_node_types
|
||||
FrontendNodeType {
|
||||
identifier: identifier.clone(),
|
||||
name,
|
||||
category: definition.category.to_string(),
|
||||
input_types,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn collect_node_descriptions() -> Vec<(String, String)> {
|
||||
pub fn collect_node_descriptions() -> Vec<(DefinitionIdentifier, String)> {
|
||||
DOCUMENT_NODE_TYPES
|
||||
.iter()
|
||||
.map(|definition| {
|
||||
(
|
||||
definition.identifier.to_string(),
|
||||
if definition.description != "TODO" { definition.description.to_string() } else { String::new() },
|
||||
)
|
||||
})
|
||||
.map(|(identifier, definition)| (identifier.clone(), if definition.description != "TODO" { definition.description.to_string() } else { String::new() }))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -2744,8 +2706,9 @@ impl DocumentNodeDefinition {
|
||||
// TODO: Replace the .enumerate() with changing the iterator to take a tuple of (index, input) so the user is forced to provide the correct index
|
||||
input_override.into_iter().enumerate().for_each(|(index, input_override)| {
|
||||
if let Some(input_override) = input_override {
|
||||
// Only value inputs can be overridden, since node inputs change graph structure and must be handled by the network interface
|
||||
// assert!(matches!(input_override, NodeInput::Value { .. }), "Only value inputs are supported for input overrides");
|
||||
// Only value inputs should be overridden, since node inputs change graph structure and must be handled by the network interface.
|
||||
// However, this would require changing some tooling which creates multiple nodes at once, before they are inserted into the network.
|
||||
// debug_assert!(input_override.as_node().is_none(), "Node inputs are not supported in input overrides");
|
||||
template.document_node.inputs[index] = input_override;
|
||||
}
|
||||
});
|
||||
@@ -2806,12 +2769,6 @@ impl DocumentNodeDefinition {
|
||||
}
|
||||
populate_input_properties(&mut template, Vec::new());
|
||||
|
||||
// Set the reference to the node definition
|
||||
template.persistent_node_metadata.reference = Some(self.identifier.to_string());
|
||||
// If the display name is empty and it is not a merge node, then set it to the reference
|
||||
if template.persistent_node_metadata.display_name.is_empty() && self.identifier != "Merge" {
|
||||
template.persistent_node_metadata.display_name = self.identifier.to_string();
|
||||
}
|
||||
template
|
||||
}
|
||||
|
||||
|
||||
+106
-96
@@ -1,72 +1,34 @@
|
||||
use super::DocumentNodeDefinition;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{DocumentNodePersistentMetadata, InputMetadata, NodeTemplate, WidgetOverride};
|
||||
use graph_craft::ProtoNodeIdentifier;
|
||||
use graph_craft::document::*;
|
||||
use graphene_std::registry::*;
|
||||
use graphene_std::*;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
/// Traverses a document node template and metadata in parallel to link the protonodes to their reference
|
||||
fn traverse_node(node: &DocumentNode, node_metadata: &mut DocumentNodePersistentMetadata) {
|
||||
match &node.implementation {
|
||||
DocumentNodeImplementation::Network(node_network) => {
|
||||
for (nested_node_id, nested_node) in node_network.nodes.iter() {
|
||||
let nested_metadata = node_metadata
|
||||
.network_metadata
|
||||
.as_mut()
|
||||
.expect("Network node must have network metadata")
|
||||
.persistent_metadata
|
||||
.node_metadata
|
||||
.get_mut(nested_node_id)
|
||||
.expect("Network metadata must have corresponding node id");
|
||||
traverse_node(nested_node, &mut nested_metadata.persistent_metadata);
|
||||
}
|
||||
}
|
||||
DocumentNodeImplementation::ProtoNode(proto_node_identifier) => {
|
||||
if let Some(metadata) = NODE_METADATA.lock().unwrap().get(proto_node_identifier) {
|
||||
node_metadata.reference = Some(metadata.display_name.to_string());
|
||||
}
|
||||
}
|
||||
DocumentNodeImplementation::Extract => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn post_process_nodes(mut custom: Vec<DocumentNodeDefinition>) -> Vec<DocumentNodeDefinition> {
|
||||
// Link the protonodes with custom networks to their reference
|
||||
for node in custom.iter_mut() {
|
||||
traverse_node(&node.node_template.document_node, &mut node.node_template.persistent_node_metadata);
|
||||
}
|
||||
|
||||
// Remove struct generics
|
||||
for DocumentNodeDefinition { node_template, .. } in custom.iter_mut() {
|
||||
let NodeTemplate {
|
||||
document_node: DocumentNode { implementation, .. },
|
||||
..
|
||||
} = node_template;
|
||||
|
||||
if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = implementation
|
||||
&& let Some((new_name, _suffix)) = name.rsplit_once("<")
|
||||
{
|
||||
*name = Cow::Owned(new_name.to_string())
|
||||
};
|
||||
}
|
||||
pub(super) fn post_process_nodes(custom: Vec<DocumentNodeDefinition>) -> HashMap<DefinitionIdentifier, DocumentNodeDefinition> {
|
||||
// Create hashmap for the protonodes added by the macro.
|
||||
let mut definitions_map = HashMap::new();
|
||||
// First remove the custom protonodes and add them to the definitions map since they contain different metadata
|
||||
// from the macro and must be inserted first so that network nodes which reference them use the correct metadata.
|
||||
let network_nodes = custom
|
||||
.into_iter()
|
||||
.filter_map(|definition| {
|
||||
if let DocumentNodeImplementation::ProtoNode(proto_node_identifier) = &definition.node_template.document_node.implementation {
|
||||
definitions_map.insert(DefinitionIdentifier::ProtoNode(proto_node_identifier.clone()), definition);
|
||||
return None;
|
||||
};
|
||||
Some(definition)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Add the rest of the protonodes from the macro
|
||||
let node_registry = NODE_REGISTRY.lock().unwrap();
|
||||
'outer: for (id, metadata) in NODE_METADATA.lock().unwrap().iter() {
|
||||
for node in custom.iter() {
|
||||
let DocumentNodeDefinition {
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode { implementation, .. },
|
||||
..
|
||||
},
|
||||
..
|
||||
} = node;
|
||||
match implementation {
|
||||
DocumentNodeImplementation::ProtoNode(name) if name == id => continue 'outer,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
for (id, metadata) in NODE_METADATA.lock().unwrap().iter() {
|
||||
let identifier = DefinitionIdentifier::ProtoNode(id.clone());
|
||||
if definitions_map.contains_key(&identifier) {
|
||||
continue;
|
||||
};
|
||||
let NodeMetadata {
|
||||
display_name,
|
||||
category,
|
||||
@@ -78,48 +40,96 @@ pub(super) fn post_process_nodes(mut custom: Vec<DocumentNodeDefinition>) -> Vec
|
||||
|
||||
let Some(implementations) = &node_registry.get(id) else { continue };
|
||||
|
||||
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
|
||||
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
|
||||
|
||||
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
|
||||
let input_type = if valid_inputs.len() > 1 { &const { generic!(D) } } else { &first_node_io.call_argument };
|
||||
let output_type = &first_node_io.return_value;
|
||||
|
||||
let inputs = preprocessor::node_inputs(fields, first_node_io);
|
||||
let node = DocumentNodeDefinition {
|
||||
identifier: display_name,
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
inputs,
|
||||
call_argument: input_type.clone(),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(id.clone()),
|
||||
visible: true,
|
||||
skip_deduplication: false,
|
||||
context_features: ContextDependencies::from(context_features.as_slice()),
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
// TODO: Store information for input overrides in the node macro
|
||||
input_metadata: fields
|
||||
.iter()
|
||||
.map(|f| match f.widget_override {
|
||||
RegistryWidgetOverride::None => (f.name, f.description).into(),
|
||||
RegistryWidgetOverride::Hidden => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Hidden),
|
||||
RegistryWidgetOverride::String(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::String(str.to_string())),
|
||||
RegistryWidgetOverride::Custom(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Custom(str.to_string())),
|
||||
})
|
||||
.collect(),
|
||||
output_names: vec![output_type.to_string()],
|
||||
locked: false,
|
||||
..Default::default()
|
||||
definitions_map.insert(
|
||||
identifier,
|
||||
DocumentNodeDefinition {
|
||||
identifier: display_name,
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
inputs,
|
||||
call_argument: input_type.clone(),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(id.clone()),
|
||||
visible: true,
|
||||
skip_deduplication: false,
|
||||
context_features: ContextDependencies::from(context_features.as_slice()),
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
// TODO: Store information for input overrides in the node macro
|
||||
input_metadata: fields
|
||||
.iter()
|
||||
.map(|f| match f.widget_override {
|
||||
RegistryWidgetOverride::None => (f.name, f.description).into(),
|
||||
RegistryWidgetOverride::Hidden => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Hidden),
|
||||
RegistryWidgetOverride::String(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::String(str.to_string())),
|
||||
RegistryWidgetOverride::Custom(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Custom(str.to_string())),
|
||||
})
|
||||
.collect(),
|
||||
locked: false,
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
category: category.unwrap_or("UNCATEGORIZED"),
|
||||
description: Cow::Borrowed(description),
|
||||
properties: *properties,
|
||||
},
|
||||
category: category.unwrap_or("UNCATEGORIZED"),
|
||||
description: Cow::Borrowed(description),
|
||||
properties: *properties,
|
||||
};
|
||||
|
||||
custom.push(node);
|
||||
);
|
||||
}
|
||||
|
||||
custom
|
||||
// If any protonode does not have metadata then set its display name to its identifier string
|
||||
for definition in definitions_map.values_mut() {
|
||||
let metadata = NODE_METADATA.lock().unwrap();
|
||||
if let DocumentNodeImplementation::ProtoNode(id) = &definition.node_template.document_node.implementation
|
||||
&& !metadata.contains_key(id)
|
||||
{
|
||||
definition.node_template.persistent_node_metadata.display_name = definition.identifier.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the rest of the network nodes to the map and add the metadata for their internal protonodes
|
||||
for mut network_node in network_nodes {
|
||||
traverse_node(&network_node.node_template.document_node, &mut network_node.node_template.persistent_node_metadata, &definitions_map);
|
||||
// Set the reference to the node identifier
|
||||
if let Some(nested_metadata) = network_node.node_template.persistent_node_metadata.network_metadata.as_mut() {
|
||||
nested_metadata.persistent_metadata.reference = Some(network_node.identifier.to_string());
|
||||
// If it is not a merge node, then set the display name to the identifier/reference
|
||||
if network_node.identifier != "Merge" {
|
||||
network_node.node_template.persistent_node_metadata.display_name = network_node.identifier.to_string();
|
||||
}
|
||||
}
|
||||
definitions_map.insert(DefinitionIdentifier::Network(network_node.identifier.to_string()), network_node);
|
||||
}
|
||||
|
||||
definitions_map
|
||||
}
|
||||
|
||||
/// Traverses a document node template and metadata in parallel to add metadata to the protonodes
|
||||
fn traverse_node(node: &DocumentNode, node_metadata: &mut DocumentNodePersistentMetadata, definitions_map: &HashMap<DefinitionIdentifier, DocumentNodeDefinition>) {
|
||||
match &node.implementation {
|
||||
DocumentNodeImplementation::Network(node_network) => {
|
||||
for (nested_node_id, nested_node) in node_network.nodes.iter() {
|
||||
let nested_metadata = node_metadata.network_metadata.as_mut().unwrap().persistent_metadata.node_metadata.get_mut(nested_node_id).unwrap();
|
||||
traverse_node(nested_node, &mut nested_metadata.persistent_metadata, definitions_map);
|
||||
}
|
||||
}
|
||||
DocumentNodeImplementation::ProtoNode(id) => {
|
||||
// Set all the metadata except the position to the proto node information from the macro
|
||||
// TODO: Use options in the template to specify what you want to default and what you want to override
|
||||
// If this fails then the proto node id in the definition doesn't match what is generated by the macro
|
||||
let Some(definition) = definitions_map.get(&DefinitionIdentifier::ProtoNode(id.clone())) else {
|
||||
// log::error!("Could not get definition for id {} when filling in protonode metadata for a custom node", id.clone());
|
||||
return;
|
||||
};
|
||||
let mut new_metadata = definition.node_template.persistent_node_metadata.clone();
|
||||
new_metadata.node_type_metadata = node_metadata.node_type_metadata.clone();
|
||||
*node_metadata = new_metadata
|
||||
}
|
||||
DocumentNodeImplementation::Extract => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::utility_types::Direction;
|
||||
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{ImportOrExport, InputConnector, NodeTemplate, OutputConnector};
|
||||
use crate::messages::prelude::*;
|
||||
@@ -27,16 +28,16 @@ pub enum NodeGraphMessage {
|
||||
SelectedNodesUpdated,
|
||||
Copy,
|
||||
CreateNodeInLayerNoTransaction {
|
||||
node_type: String,
|
||||
node_type: DefinitionIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
},
|
||||
CreateNodeInLayerWithTransaction {
|
||||
node_type: String,
|
||||
node_type: DefinitionIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
},
|
||||
CreateNodeFromContextMenu {
|
||||
node_id: Option<NodeId>,
|
||||
node_type: String,
|
||||
node_type: DefinitionIdentifier,
|
||||
xy: Option<(i32, i32)>,
|
||||
add_transaction: bool,
|
||||
},
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use super::node_properties;
|
||||
use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart, FrontendNode};
|
||||
use super::{document_node_definitions, node_properties};
|
||||
use crate::consts::GRID_SIZE;
|
||||
use crate::messages::clipboard::utility_types::ClipboardContent;
|
||||
use crate::messages::input_mapper::utility_types::macros::{action_shortcut, action_shortcut_manual};
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::document_message_handler::navigation_controls;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{
|
||||
DefinitionIdentifier, NodePropertiesContext, resolve_document_node_type, resolve_network_node_type, resolve_proto_node_type,
|
||||
};
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, NodeGraphErrorDiagnostic};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
|
||||
@@ -131,7 +133,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
}
|
||||
NodeGraphMessage::AddPathNode => {
|
||||
if let Some(layer) = make_path_editable_is_allowed(network_interface) {
|
||||
responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type: "Path".to_string(), layer });
|
||||
responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction {
|
||||
node_type: DefinitionIdentifier::Network("Path".into()),
|
||||
layer,
|
||||
});
|
||||
responses.add(EventMessage::SelectionChanged);
|
||||
}
|
||||
}
|
||||
@@ -208,7 +213,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
let mid_point = (network_interface.get_output_center(&output_connector, breadcrumb_network_path).unwrap()
|
||||
+ network_interface.get_input_center(&input_connector, breadcrumb_network_path).unwrap())
|
||||
/ 2.;
|
||||
let node_template = Box::new(document_node_definitions::resolve_document_node_type("Passthrough").unwrap().default_node_template());
|
||||
let node_template = Box::new(resolve_proto_node_type(graphene_core::ops::identity::IDENTIFIER).unwrap().default_node_template());
|
||||
|
||||
let node_id = NodeId::new();
|
||||
responses.add(NodeGraphMessage::InsertNode { node_id, node_template });
|
||||
@@ -274,10 +279,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
|
||||
let node_id = node_id.unwrap_or_else(NodeId::new);
|
||||
|
||||
let Some(document_node_type) = document_node_definitions::resolve_document_node_type(&node_type) else {
|
||||
let Some(document_node_type) = resolve_document_node_type(&node_type) else {
|
||||
responses.add(DialogMessage::DisplayDialogError {
|
||||
title: "Cannot insert node".to_string(),
|
||||
description: format!("The document node '{node_type}' does not exist in the document node list"),
|
||||
description: format!("The document node '{node_type:?}' does not exist in the document node list"),
|
||||
});
|
||||
return;
|
||||
};
|
||||
@@ -639,9 +644,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
|
||||
// Use the network interface to add a default node, then set the imports, exports, paste the nodes inside, and connect them to the imports/exports
|
||||
let encapsulating_node_id = NodeId::new();
|
||||
let mut default_node_template = document_node_definitions::resolve_document_node_type("Default Network")
|
||||
.expect("Default Network node should exist")
|
||||
.default_node_template();
|
||||
let mut default_node_template = resolve_network_node_type("Default Network").expect("Default Network node should exist").default_node_template();
|
||||
let Some(center_of_selected_nodes) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path).map(|[a, b]| (a + b) / 2.) else {
|
||||
log::error!("Could not get center of selected_nodes");
|
||||
return;
|
||||
@@ -1701,7 +1704,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||
input,
|
||||
});
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
if !(network_interface.reference(&node_id, selection_network_path).is_none() || input_index == 0) && network_interface.connected_to_output(&node_id, selection_network_path) {
|
||||
if network_interface.connected_to_output(&node_id, selection_network_path) {
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
}
|
||||
@@ -2596,8 +2599,9 @@ impl NodeGraphMessageHandler {
|
||||
.node_metadata(&node_id, breadcrumb_network_path)
|
||||
.is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
|
||||
can_be_layer: network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path),
|
||||
reference: network_interface.reference(&node_id, breadcrumb_network_path).cloned().unwrap_or_default(),
|
||||
reference: network_interface.reference(&node_id, breadcrumb_network_path),
|
||||
display_name: network_interface.display_name(&node_id, breadcrumb_network_path),
|
||||
implementation_name: network_interface.implementation_name(&node_id, breadcrumb_network_path),
|
||||
primary_input,
|
||||
exposed_inputs,
|
||||
primary_output,
|
||||
@@ -2711,10 +2715,16 @@ impl NodeGraphMessageHandler {
|
||||
}
|
||||
});
|
||||
|
||||
let Some(reference) = network_interface.reference(&node_id, &[]) else {
|
||||
log::error!("Could not get reference for layer {node_id} in update_layer_panel");
|
||||
continue;
|
||||
};
|
||||
|
||||
let clippable = layer.can_be_clipped(network_interface.document_metadata());
|
||||
|
||||
let data = LayerPanelEntry {
|
||||
id: node_id,
|
||||
reference: network_interface.reference(&node_id, &[]).and_then(|x| x.as_ref()).cloned().unwrap_or_default(),
|
||||
reference,
|
||||
alias: network_interface.display_name(&node_id, &[]),
|
||||
in_selected_network: selection_network_path.is_empty(),
|
||||
children_allowed,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use super::document_node_definitions::{NODE_OVERRIDES, NodePropertiesContext};
|
||||
use super::utility_types::FrontendGraphDataType;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::portfolio::utility_types::{FontCatalogStyle, PersistentData};
|
||||
use crate::messages::prelude::*;
|
||||
@@ -1705,10 +1706,8 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
|
||||
if let Some(properties_override) = context
|
||||
.network_interface
|
||||
.reference(&node_id, context.selection_network_path)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.as_ref()
|
||||
.and_then(|reference| super::document_node_definitions::resolve_document_node_type(reference))
|
||||
.and_then(|identifier| resolve_document_node_type(identifier))
|
||||
.and_then(|definition| definition.properties)
|
||||
.and_then(|properties| NODE_OVERRIDES.get(properties))
|
||||
{
|
||||
@@ -1773,25 +1772,20 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
|
||||
if layout.is_empty() {
|
||||
layout = node_no_properties(node_id, context);
|
||||
}
|
||||
let name = context
|
||||
let name = context.network_interface.implementation_name(&node_id, context.selection_network_path);
|
||||
|
||||
let description = context
|
||||
.network_interface
|
||||
.reference(&node_id, context.selection_network_path)
|
||||
.cloned()
|
||||
.unwrap_or_default() // If there is an error getting the reference, default to empty string
|
||||
.or_else(|| {
|
||||
// If there is no reference, try to get the proto node name
|
||||
context.network_interface.implementation(&node_id, context.selection_network_path).and_then(|implementation|{
|
||||
if let DocumentNodeImplementation::ProtoNode(protonode) = implementation {
|
||||
Some(protonode.name.clone().into_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap_or("Custom Node".to_string());
|
||||
let description = context.network_interface.description(&node_id, context.selection_network_path);
|
||||
.as_ref()
|
||||
.and_then(|identifier| resolve_document_node_type(identifier))
|
||||
.map(|definition| definition.description.to_string())
|
||||
.filter(|string| string != "TODO")
|
||||
.unwrap_or_default();
|
||||
|
||||
let visible = context.network_interface.is_visible(&node_id, context.selection_network_path);
|
||||
let pinned = context.network_interface.is_pinned(&node_id, context.selection_network_path);
|
||||
|
||||
LayoutGroup::Section {
|
||||
name,
|
||||
description,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::document_node_definitions::DefinitionIdentifier;
|
||||
use glam::{DVec2, IVec2};
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::Type;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub enum FrontendGraphDataType {
|
||||
@@ -79,9 +79,11 @@ pub struct FrontendNode {
|
||||
pub is_layer: bool,
|
||||
#[serde(rename = "canBeLayer")]
|
||||
pub can_be_layer: bool,
|
||||
pub reference: Option<String>,
|
||||
pub reference: Option<DefinitionIdentifier>,
|
||||
#[serde(rename = "displayName")]
|
||||
pub display_name: String,
|
||||
#[serde(rename = "implementationName")]
|
||||
pub implementation_name: String,
|
||||
#[serde(rename = "primaryInput")]
|
||||
pub primary_input: Option<FrontendGraphInput>,
|
||||
#[serde(rename = "exposedInputs")]
|
||||
@@ -102,29 +104,13 @@ pub struct FrontendNode {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub struct FrontendNodeType {
|
||||
pub name: Cow<'static, str>,
|
||||
pub category: Cow<'static, str>,
|
||||
pub identifier: DefinitionIdentifier,
|
||||
pub name: String,
|
||||
pub category: String,
|
||||
#[serde(rename = "inputTypes")]
|
||||
pub input_types: Option<Vec<Cow<'static, str>>>,
|
||||
pub input_types: Vec<String>,
|
||||
}
|
||||
|
||||
impl FrontendNodeType {
|
||||
pub fn new(name: impl Into<Cow<'static, str>>, category: impl Into<Cow<'static, str>>) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
category: category.into(),
|
||||
input_types: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_input_types(name: impl Into<Cow<'static, str>>, category: impl Into<Cow<'static, str>>, input_types: Vec<Cow<'static, str>>) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
category: category.into(),
|
||||
input_types: Some(input_types),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub struct DragStart {
|
||||
pub start_x: f64,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::portfolio::document::graph_operation::transform_utils;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use glam::{DAffine2, DVec2};
|
||||
@@ -91,7 +92,8 @@ impl DocumentMetadata {
|
||||
|
||||
let mut use_local = true;
|
||||
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, network_interface);
|
||||
if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path")
|
||||
let identifier = DefinitionIdentifier::Network("Path".into());
|
||||
if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer(&identifier)
|
||||
&& let Some(&source) = self.first_element_source_ids.get(&layer.to_node())
|
||||
&& !network_interface
|
||||
.upstream_flow_back_from_nodes(vec![path_node], &[], FlowType::HorizontalFlow)
|
||||
@@ -114,7 +116,7 @@ impl DocumentMetadata {
|
||||
let local_transform = self.local_transforms.get(&layer.to_node()).copied();
|
||||
|
||||
let transform = local_transform.unwrap_or_else(|| {
|
||||
let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface);
|
||||
let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain(&DefinitionIdentifier::Network("Transform".into()), layer, network_interface);
|
||||
let transform_node = transform_node_id.and_then(|id| network_interface.document_node(&id, &[]));
|
||||
transform_node.map(|node| transform_utils::get_current_transform(node.inputs.as_slice())).unwrap_or_default()
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ 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;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DocumentNodeDefinition, resolve_document_node_type};
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type};
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets, FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput};
|
||||
use crate::messages::portfolio::document::overlays::utility_functions::text_width;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::resolved_types::ResolvedDocumentNodeTypes;
|
||||
@@ -79,7 +79,7 @@ impl NodeNetworkInterface {
|
||||
fix_network(network);
|
||||
}
|
||||
if let DocumentNodeImplementation::ProtoNode(protonode) = &node.implementation
|
||||
&& protonode.name.contains("PathModifyNode")
|
||||
&& protonode.as_str().contains("PathModifyNode")
|
||||
&& node.inputs.len() < 3
|
||||
{
|
||||
node.inputs.push(NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath));
|
||||
@@ -470,12 +470,6 @@ impl NodeNetworkInterface {
|
||||
node_template
|
||||
}
|
||||
|
||||
/// Try and get the [`DocumentNodeDefinition`] for a node
|
||||
pub fn get_node_definition(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeDefinition> {
|
||||
let metadata = self.node_metadata(node_id, network_path)?;
|
||||
resolve_document_node_type(metadata.persistent_metadata.reference.as_ref()?)
|
||||
}
|
||||
|
||||
pub fn input_from_connector(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<&NodeInput> {
|
||||
let Some(network) = self.nested_network(network_path) else {
|
||||
log::error!("Could not get network in input_from_connector");
|
||||
@@ -916,12 +910,30 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reference(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&Option<String>> {
|
||||
let Some(node_metadata) = self.node_metadata(node_id, network_path) else {
|
||||
log::error!("Could not get reference for node: {node_id:?}");
|
||||
pub fn reference(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<DefinitionIdentifier> {
|
||||
let Some(document_node) = self.document_node(node_id, network_path) else {
|
||||
log::error!("Could not get document_node for node in reference: {node_id:?}");
|
||||
return None;
|
||||
};
|
||||
Some(&node_metadata.persistent_metadata.reference)
|
||||
match &document_node.implementation {
|
||||
DocumentNodeImplementation::Network(_) => {
|
||||
let Some(node_metadata) = self.node_metadata(node_id, network_path) else {
|
||||
log::error!("Could not get reference for node in reference: {node_id:?}");
|
||||
return None;
|
||||
};
|
||||
node_metadata
|
||||
.persistent_metadata
|
||||
.network_metadata
|
||||
.as_ref()
|
||||
.expect("Network metadata must exist for network node in reference")
|
||||
.persistent_metadata
|
||||
.reference
|
||||
.clone()
|
||||
.map(DefinitionIdentifier::Network)
|
||||
}
|
||||
DocumentNodeImplementation::ProtoNode(protonode_id) => Some(DefinitionIdentifier::ProtoNode(protonode_id.clone())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn implementation(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeImplementation> {
|
||||
@@ -982,11 +994,6 @@ impl NodeNetworkInterface {
|
||||
pub fn display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
|
||||
let is_layer = self.is_layer(node_id, network_path);
|
||||
|
||||
let Some(reference) = self.reference(node_id, network_path) else {
|
||||
log::error!("Could not get reference in untitled_layer_label");
|
||||
return "".to_string();
|
||||
};
|
||||
|
||||
let display_name = if let Some(node_metadata) = self.node_metadata(node_id, network_path) {
|
||||
node_metadata.persistent_metadata.display_name.clone()
|
||||
} else {
|
||||
@@ -998,18 +1005,19 @@ impl NodeNetworkInterface {
|
||||
if is_layer {
|
||||
"Untitled Layer".to_string()
|
||||
} else {
|
||||
reference.clone().unwrap_or("Untitled Node".to_string())
|
||||
// TODO: Have this displayed in italics in the UI
|
||||
self.implementation_name(node_id, network_path)
|
||||
}
|
||||
} else {
|
||||
display_name
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the description of the node, or an empty string if it is not set.
|
||||
pub fn description(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
|
||||
self.get_node_definition(node_id, network_path)
|
||||
.map(|node_definition| node_definition.description.to_string())
|
||||
.unwrap_or_default()
|
||||
/// The uneditable name in the Properties panel which represents the function name of the node implementation.
|
||||
pub fn implementation_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
|
||||
self.reference(node_id, network_path)
|
||||
.map(|identifier| identifier.implementation_name_from_identifier())
|
||||
.unwrap_or("Custom Node".to_string())
|
||||
}
|
||||
|
||||
pub fn is_locked(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
||||
@@ -1125,7 +1133,7 @@ impl NodeNetworkInterface {
|
||||
|
||||
pub fn is_artboard(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
||||
self.reference(node_id, network_path)
|
||||
.is_some_and(|reference| *reference == Some("Artboard".to_string()) && self.connected_to_output(node_id, &[]))
|
||||
.is_some_and(|reference| reference == DefinitionIdentifier::Network("Artboard".into()) && self.connected_to_output(node_id, &[]))
|
||||
}
|
||||
|
||||
pub fn all_artboards(&self) -> HashSet<LayerNodeIdentifier> {
|
||||
@@ -1134,12 +1142,13 @@ impl NodeNetworkInterface {
|
||||
.node_metadata
|
||||
.iter()
|
||||
.filter_map(|(node_id, node_metadata)| {
|
||||
if node_metadata
|
||||
.persistent_metadata
|
||||
.reference
|
||||
.as_ref()
|
||||
.is_some_and(|reference| reference == "Artboard" && self.connected_to_output(node_id, &[]) && self.is_layer(node_id, &[]))
|
||||
{
|
||||
if node_metadata.persistent_metadata.network_metadata.as_ref().is_some_and(|network_metadata| {
|
||||
network_metadata
|
||||
.persistent_metadata
|
||||
.reference
|
||||
.as_ref()
|
||||
.is_some_and(|reference| reference == "Artboard" && self.connected_to_output(node_id, &[]) && self.is_layer(node_id, &[]))
|
||||
}) {
|
||||
Some(LayerNodeIdentifier::new(*node_id, self))
|
||||
} else {
|
||||
None
|
||||
@@ -1345,7 +1354,6 @@ impl NodeNetworkInterface {
|
||||
node.skip_deduplication = old_node.skip_deduplication;
|
||||
node.original_location = old_node.original_location;
|
||||
node_metadata.persistent_metadata.display_name = old_node.alias;
|
||||
node_metadata.persistent_metadata.reference = if old_node.name.is_empty() { None } else { Some(old_node.name) };
|
||||
node_metadata.persistent_metadata.locked = old_node.locked;
|
||||
node_metadata.persistent_metadata.node_type_metadata = if old_node.is_layer {
|
||||
NodeTypePersistentMetadata::Layer(LayerPersistentMetadata {
|
||||
@@ -3047,7 +3055,7 @@ impl NodeNetworkInterface {
|
||||
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<Vector> {
|
||||
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
||||
|
||||
if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path")
|
||||
if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer(&DefinitionIdentifier::Network("Path".into()))
|
||||
&& let Some(vector) = self.document_metadata.vector_modify.get(&path_node)
|
||||
{
|
||||
let mut modified = vector.clone();
|
||||
@@ -3200,14 +3208,6 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_reference(&mut self, node_id: &NodeId, network_path: &[NodeId], reference: Option<String>) {
|
||||
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||
log::error!("Could not get node_metadata in set_reference");
|
||||
return;
|
||||
};
|
||||
node_metadata.persistent_metadata.reference = reference;
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -3278,7 +3278,9 @@ impl NodeNetworkInterface {
|
||||
encapsulating_node_metadata.persistent_metadata.output_names.insert(insert_index as usize, output_name.to_string());
|
||||
}
|
||||
// Clear the reference to the nodes definition
|
||||
encapsulating_node_metadata.persistent_metadata.reference = None;
|
||||
if let Some(network_metadata) = encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut() {
|
||||
network_metadata.persistent_metadata.reference = None
|
||||
}
|
||||
};
|
||||
|
||||
// Update the export ports and outward wires for the current network
|
||||
@@ -3347,7 +3349,9 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
|
||||
// Clear the reference to the nodes definition
|
||||
node_metadata.persistent_metadata.reference = None;
|
||||
if let Some(network_metadata) = node_metadata.persistent_metadata.network_metadata.as_mut() {
|
||||
network_metadata.persistent_metadata.reference = None
|
||||
}
|
||||
|
||||
// Update the metadata for the encapsulating node
|
||||
self.unload_node_click_targets(&node_id, &encapsulating_network_path);
|
||||
@@ -3403,7 +3407,9 @@ impl NodeNetworkInterface {
|
||||
return;
|
||||
};
|
||||
encapsulating_node_metadata.persistent_metadata.output_names.remove(export_index);
|
||||
encapsulating_node_metadata.persistent_metadata.reference = None;
|
||||
if let Some(network_metadata) = encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut() {
|
||||
network_metadata.persistent_metadata.reference = None;
|
||||
}
|
||||
|
||||
// Update the metadata for the encapsulating node
|
||||
self.unload_outward_wires(&encapsulating_network_path);
|
||||
@@ -3477,7 +3483,9 @@ impl NodeNetworkInterface {
|
||||
return;
|
||||
};
|
||||
encapsulating_node_metadata.persistent_metadata.input_metadata.remove(import_index);
|
||||
encapsulating_node_metadata.persistent_metadata.reference = None;
|
||||
if let Some(network_metadata) = encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut() {
|
||||
network_metadata.persistent_metadata.reference = None;
|
||||
}
|
||||
|
||||
// Update the metadata for the encapsulating node
|
||||
self.unload_outward_wires(encapsulating_network_path);
|
||||
@@ -3523,7 +3531,9 @@ impl NodeNetworkInterface {
|
||||
|
||||
let name = encapsulating_node_metadata.persistent_metadata.output_names.remove(start_index);
|
||||
encapsulating_node_metadata.persistent_metadata.output_names.insert(end_index, name);
|
||||
encapsulating_node_metadata.persistent_metadata.reference = None;
|
||||
if let Some(network_metadata) = encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut() {
|
||||
network_metadata.persistent_metadata.reference = None;
|
||||
}
|
||||
|
||||
// Update the metadata for the encapsulating network
|
||||
self.unload_outward_wires(&encapsulating_network_path);
|
||||
@@ -3615,7 +3625,9 @@ impl NodeNetworkInterface {
|
||||
|
||||
let properties_row = encapsulating_node_metadata.persistent_metadata.input_metadata.remove(start_index);
|
||||
encapsulating_node_metadata.persistent_metadata.input_metadata.insert(end_index, properties_row);
|
||||
encapsulating_node_metadata.persistent_metadata.reference = None;
|
||||
if let Some(network_metadata) = encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut() {
|
||||
network_metadata.persistent_metadata.reference = None;
|
||||
}
|
||||
|
||||
// Update the metadata for the outer network
|
||||
self.unload_outward_wires(&encapsulating_network_path);
|
||||
@@ -3721,28 +3733,17 @@ impl NodeNetworkInterface {
|
||||
let number_of_inputs = node.inputs.len();
|
||||
let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return };
|
||||
for added_input_index in metadata.persistent_metadata.input_metadata.len()..number_of_inputs {
|
||||
let reference = metadata.persistent_metadata.reference.as_ref();
|
||||
let definition = reference.and_then(|reference| resolve_document_node_type(reference));
|
||||
let input_metadata = definition
|
||||
let input_metadata = self
|
||||
.reference(node_id, network_path)
|
||||
.as_ref()
|
||||
.and_then(resolve_document_node_type)
|
||||
.and_then(|definition| definition.node_template.persistent_node_metadata.input_metadata.get(added_input_index))
|
||||
.cloned();
|
||||
let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return };
|
||||
metadata.persistent_metadata.input_metadata.push(input_metadata.unwrap_or_default());
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to ensure the display name is the reference name in case it is empty.
|
||||
pub fn validate_display_name_metadata(&mut self, node_id: &NodeId, network_path: &[NodeId]) {
|
||||
let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return };
|
||||
if metadata.persistent_metadata.display_name.is_empty()
|
||||
&& let Some(reference) = metadata.persistent_metadata.reference.clone()
|
||||
{
|
||||
// Keep the name for merge nodes as empty
|
||||
if reference != "Merge" {
|
||||
metadata.persistent_metadata.display_name = reference;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When opening an old document to ensure the output names match the number of exports
|
||||
pub fn validate_output_names(&mut self, node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId]) {
|
||||
if let DocumentNodeImplementation::Network(network) = &node.implementation {
|
||||
@@ -3755,13 +3756,17 @@ impl NodeNetworkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts
|
||||
pub fn replace_reference_name(&mut self, node_id: &NodeId, network_path: &[NodeId], reference_name: String) {
|
||||
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||
log::error!("Could not get node metadata in replace_reference_name");
|
||||
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts.
|
||||
/// Only works with network nodes. Proto nodes use their ID as the reference.
|
||||
pub fn set_reference(&mut self, node_id: &NodeId, network_path: &[NodeId], reference_name: Option<String>) {
|
||||
let Some(node_network_metadata) = self
|
||||
.node_metadata_mut(node_id, network_path)
|
||||
.and_then(|node_metadata| node_metadata.persistent_metadata.network_metadata.as_mut())
|
||||
else {
|
||||
log::error!("Could not get network metadata in replace_reference_name");
|
||||
return;
|
||||
};
|
||||
node_metadata.persistent_metadata.reference = Some(reference_name);
|
||||
node_network_metadata.persistent_metadata.reference = reference_name;
|
||||
}
|
||||
|
||||
/// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts
|
||||
@@ -4397,7 +4402,10 @@ impl NodeNetworkInterface {
|
||||
node_metadata.persistent_metadata.display_name.clone_from(&display_name);
|
||||
|
||||
// Keep the alias in sync with the `ToArtboard` name input
|
||||
if node_metadata.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Artboard") {
|
||||
if self
|
||||
.reference(node_id, network_path)
|
||||
.is_some_and(|reference| reference == DefinitionIdentifier::Network("Artboard".into()))
|
||||
{
|
||||
let Some(nested_network) = self.network_mut(network_path) else {
|
||||
return;
|
||||
};
|
||||
@@ -5382,7 +5390,9 @@ impl NodeNetworkInterface {
|
||||
// If a non artboard layer is attempted to be connected to the exports, and there is already an artboard connected, then connect the layer to the artboard.
|
||||
if let Some(first_layer) = LayerNodeIdentifier::ROOT_PARENT.children(&self.document_metadata).next()
|
||||
&& parent == LayerNodeIdentifier::ROOT_PARENT
|
||||
&& self.reference(&layer.to_node(), network_path).is_none_or(|reference| *reference != Some("Artboard".to_string()))
|
||||
&& self
|
||||
.reference(&layer.to_node(), network_path)
|
||||
.is_none_or(|reference| reference != DefinitionIdentifier::Network("Artboard".into()))
|
||||
&& self.is_artboard(&first_layer.to_node(), network_path)
|
||||
{
|
||||
parent = first_layer;
|
||||
@@ -5974,6 +5984,12 @@ impl NodeNetworkMetadata {
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct NodeNetworkPersistentMetadata {
|
||||
/// The identifier for the node definition created for custom network nodes in [`DocumentNodeDefinition`].
|
||||
/// It is only used to associate network nodes with their definition. Protonodes use their ProtonodeIdentifier.
|
||||
/// The reference is removed once the node is modified, since the node now stores its own implementation and inputs.
|
||||
/// TODO: Used during serialization/deserialization to prevent storing implementation or inputs (and possible other fields) if they are the same as the definition.
|
||||
/// TODO: Implement node versioning so that references to old nodes can be updated to the new node definition.
|
||||
pub reference: Option<String>,
|
||||
/// Node metadata must exist for every document node in the network
|
||||
#[serde(serialize_with = "graphene_std::vector::serialize_hashmap", deserialize_with = "graphene_std::vector::deserialize_hashmap")]
|
||||
pub node_metadata: HashMap<NodeId, DocumentNodeMetadata>,
|
||||
@@ -6218,13 +6234,9 @@ struct InputTransientMetadata {
|
||||
|
||||
/// Persistent metadata for each node in the network, which must be included when creating, serializing, and deserializing saving a node.
|
||||
#[derive(Default, Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct DocumentNodePersistentMetadata {
|
||||
/// The name of the node definition, as originally set by [`DocumentNodeDefinition`], used to display in the UI and to display the appropriate properties if no display name is set.
|
||||
// TODO: Used during serialization/deserialization to prevent storing implementation or inputs (and possible other fields) if they are the same as the definition.
|
||||
// TODO: The reference is removed once the node is modified, since the node now stores its own implementation and inputs.
|
||||
// TODO: Implement node versioning so that references to old nodes can be updated to the new node definition.
|
||||
pub reference: Option<String>,
|
||||
/// A name chosen by the user for this instance of the node. Empty indicates no given name, in which case the reference name is displayed to the user in italics.
|
||||
/// A name chosen by the user for this instance of the node. Empty indicates no given name, in which case the implementation name is displayed to the user in italics.
|
||||
#[serde(default)]
|
||||
pub display_name: String,
|
||||
/// Stores metadata to override the properties in the properties panel for each input. These can either be generated automatically based on the type, or with a custom function.
|
||||
@@ -6463,7 +6475,9 @@ mod network_interface_tests {
|
||||
async fn copy_isolated_node() {
|
||||
let mut editor = EditorTestUtils::create();
|
||||
editor.new_document().await;
|
||||
let rectangle = editor.create_node_by_name("Rectangle").await;
|
||||
let rectangle = editor
|
||||
.create_node_by_name(DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::rectangle::IDENTIFIER))
|
||||
.await;
|
||||
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![rectangle] }).await;
|
||||
let frontend_messages = editor.handle_message(NodeGraphMessage::Copy).await;
|
||||
let serialized_nodes = frontend_messages
|
||||
|
||||
+78
-19
@@ -19,13 +19,14 @@ pub struct DocumentNodePersistentMetadataInputNames {
|
||||
pub network_metadata: Option<NodeNetworkMetadata>,
|
||||
}
|
||||
|
||||
impl From<DocumentNodePersistentMetadataInputNames> for DocumentNodePersistentMetadata {
|
||||
impl From<DocumentNodePersistentMetadataInputNames> for DocumentNodePersistentMetadataPropertiesRow {
|
||||
fn from(old: DocumentNodePersistentMetadataInputNames) -> Self {
|
||||
DocumentNodePersistentMetadata {
|
||||
input_metadata: Vec::new(),
|
||||
DocumentNodePersistentMetadataPropertiesRow {
|
||||
reference: old.reference,
|
||||
input_properties: Vec::new(),
|
||||
display_name: old.display_name,
|
||||
output_names: old.output_names,
|
||||
has_primary_output: old.has_primary_output,
|
||||
locked: old.locked,
|
||||
pinned: old.pinned,
|
||||
node_type_metadata: old.node_type_metadata,
|
||||
@@ -60,7 +61,7 @@ pub struct PropertiesRow {
|
||||
pub input_description: String,
|
||||
}
|
||||
|
||||
impl From<DocumentNodePersistentMetadataPropertiesRow> for DocumentNodePersistentMetadata {
|
||||
impl From<DocumentNodePersistentMetadataPropertiesRow> for DocumentNodePersistentMetadataHasPrimaryOutput {
|
||||
fn from(old: DocumentNodePersistentMetadataPropertiesRow) -> Self {
|
||||
let mut input_metadata = Vec::new();
|
||||
for properties_row in old.input_properties {
|
||||
@@ -74,11 +75,12 @@ impl From<DocumentNodePersistentMetadataPropertiesRow> for DocumentNodePersisten
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
DocumentNodePersistentMetadata {
|
||||
DocumentNodePersistentMetadataHasPrimaryOutput {
|
||||
reference: old.reference,
|
||||
display_name: old.display_name,
|
||||
input_metadata: Vec::new(),
|
||||
output_names: old.output_names,
|
||||
has_primary_output: old.has_primary_output,
|
||||
locked: old.locked,
|
||||
pinned: old.pinned,
|
||||
node_type_metadata: old.node_type_metadata,
|
||||
@@ -104,9 +106,9 @@ pub struct DocumentNodePersistentMetadataHasPrimaryOutput {
|
||||
pub network_metadata: Option<NodeNetworkMetadata>,
|
||||
}
|
||||
|
||||
impl From<DocumentNodePersistentMetadataHasPrimaryOutput> for DocumentNodePersistentMetadata {
|
||||
impl From<DocumentNodePersistentMetadataHasPrimaryOutput> for DocumentNodePersistentMetadataStringReference {
|
||||
fn from(old: DocumentNodePersistentMetadataHasPrimaryOutput) -> Self {
|
||||
DocumentNodePersistentMetadata {
|
||||
DocumentNodePersistentMetadataStringReference {
|
||||
reference: old.reference,
|
||||
display_name: old.display_name,
|
||||
input_metadata: old.input_metadata,
|
||||
@@ -119,6 +121,49 @@ impl From<DocumentNodePersistentMetadataHasPrimaryOutput> for DocumentNodePersis
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
struct DocumentNodePersistentMetadataStringReference {
|
||||
pub reference: Option<String>,
|
||||
#[serde(default)]
|
||||
pub display_name: String,
|
||||
pub input_metadata: Vec<InputMetadata>,
|
||||
pub output_names: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub locked: bool,
|
||||
#[serde(default)]
|
||||
pub pinned: bool,
|
||||
pub node_type_metadata: NodeTypePersistentMetadata,
|
||||
pub network_metadata: Option<NodeNetworkMetadata>,
|
||||
}
|
||||
|
||||
impl From<DocumentNodePersistentMetadataStringReference> for DocumentNodePersistentMetadata {
|
||||
fn from(mut old: DocumentNodePersistentMetadataStringReference) -> Self {
|
||||
if let Some(metadata) = old.network_metadata.as_mut() {
|
||||
metadata.persistent_metadata.reference = old.reference;
|
||||
}
|
||||
DocumentNodePersistentMetadata {
|
||||
display_name: old.display_name,
|
||||
input_metadata: old.input_metadata,
|
||||
output_names: old.output_names,
|
||||
locked: old.locked,
|
||||
pinned: old.pinned,
|
||||
node_type_metadata: old.node_type_metadata,
|
||||
network_metadata: old.network_metadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum DocumentNodePersistentMetadataVersioned {
|
||||
// Newest first
|
||||
Current(DocumentNodePersistentMetadata),
|
||||
StringReference(DocumentNodePersistentMetadataStringReference),
|
||||
HasPrimaryOutput(DocumentNodePersistentMetadataHasPrimaryOutput),
|
||||
PropertiesRow(DocumentNodePersistentMetadataPropertiesRow),
|
||||
InputNames(DocumentNodePersistentMetadataInputNames),
|
||||
}
|
||||
|
||||
pub fn deserialize_node_persistent_metadata<'de, D>(deserializer: D) -> Result<DocumentNodePersistentMetadata, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
@@ -126,17 +171,31 @@ where
|
||||
use serde::Deserialize;
|
||||
|
||||
let value = Value::deserialize(deserializer)?;
|
||||
if let Ok(document) = serde_json::from_value::<DocumentNodePersistentMetadataHasPrimaryOutput>(value.clone()) {
|
||||
return Ok(document.into());
|
||||
|
||||
let versioned_document = serde_json::from_value::<DocumentNodePersistentMetadataVersioned>(value).map_err(serde::de::Error::custom)?;
|
||||
|
||||
let current: DocumentNodePersistentMetadata = match versioned_document {
|
||||
DocumentNodePersistentMetadataVersioned::Current(v) => v,
|
||||
DocumentNodePersistentMetadataVersioned::StringReference(v) => {
|
||||
let v: DocumentNodePersistentMetadataStringReference = v;
|
||||
v.into()
|
||||
}
|
||||
DocumentNodePersistentMetadataVersioned::HasPrimaryOutput(v) => {
|
||||
let v: DocumentNodePersistentMetadataStringReference = v.into();
|
||||
v.into()
|
||||
}
|
||||
DocumentNodePersistentMetadataVersioned::PropertiesRow(v) => {
|
||||
let v: DocumentNodePersistentMetadataHasPrimaryOutput = v.into();
|
||||
let v: DocumentNodePersistentMetadataStringReference = v.into();
|
||||
v.into()
|
||||
}
|
||||
DocumentNodePersistentMetadataVersioned::InputNames(v) => {
|
||||
let v: DocumentNodePersistentMetadataPropertiesRow = v.into();
|
||||
let v: DocumentNodePersistentMetadataHasPrimaryOutput = v.into();
|
||||
let v: DocumentNodePersistentMetadataStringReference = v.into();
|
||||
v.into()
|
||||
}
|
||||
};
|
||||
if let Ok(document) = serde_json::from_value::<DocumentNodePersistentMetadata>(value.clone()) {
|
||||
return Ok(document);
|
||||
};
|
||||
if let Ok(document) = serde_json::from_value::<DocumentNodePersistentMetadataPropertiesRow>(value.clone()) {
|
||||
return Ok(document.into());
|
||||
};
|
||||
match serde_json::from_value::<DocumentNodePersistentMetadataInputNames>(value.clone()) {
|
||||
Ok(document) => Ok(document.into()),
|
||||
Err(e) => Err(serde::de::Error::custom(e)),
|
||||
}
|
||||
|
||||
Ok(current)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
use super::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::{NodeId, NodeNetwork};
|
||||
@@ -34,7 +35,7 @@ impl serde::Serialize for JsRawBuffer {
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
||||
pub struct LayerPanelEntry {
|
||||
pub id: NodeId,
|
||||
pub reference: String,
|
||||
pub reference: DefinitionIdentifier,
|
||||
pub alias: String,
|
||||
#[serde(rename = "inSelectedNetwork")]
|
||||
pub in_selected_network: bool,
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::network_interface::NodeNetworkInterface;
|
||||
use crate::consts::{ROTATE_INCREMENT, SCALE_INCREMENT};
|
||||
use crate::messages::portfolio::document::graph_operation::transform_utils;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::{ModifyInputsContext, TransformIn};
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
@@ -53,7 +54,7 @@ impl OriginalTransforms {
|
||||
|
||||
/// Gets the transform from the most downstream transform node
|
||||
fn get_layer_transform(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<DAffine2> {
|
||||
let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface)?;
|
||||
let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain(&DefinitionIdentifier::Network("Transform".into()), layer, network_interface)?;
|
||||
|
||||
let document_node = network_interface.document_network().nodes.get(&transform_node_id)?;
|
||||
Some(transform_utils::get_current_transform(&document_node.inputs))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// TODO: Eventually remove this document upgrade code
|
||||
// This file contains lots of hacky code for upgrading old documents to the new format
|
||||
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type, resolve_network_node_type, resolve_proto_node_type};
|
||||
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::prelude::DocumentMessageHandler;
|
||||
@@ -734,12 +734,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::auto_tangents::IDENTIFIER,
|
||||
aliases: &[
|
||||
"graphene_core::vector::vector_nodes::AutoTangentsNode",
|
||||
"graphene_core::vector::AutoTangentsNode",
|
||||
"graphene_core::vector::GenerateHandlesNode",
|
||||
"graphene_core::vector::RemoveHandlesNode",
|
||||
],
|
||||
aliases: &["graphene_core::vector::vector_nodes::AutoTangentsNode", "graphene_core::vector::AutoTangentsNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::bevel::IDENTIFIER,
|
||||
@@ -919,7 +914,11 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::sample_polyline::IDENTIFIER,
|
||||
aliases: &["graphene_core::vector::SamplePolylineNode"],
|
||||
aliases: &[
|
||||
"graphene_core::vector::SamplePolylineNode",
|
||||
"graphene_core::vector::SamplePointsNode",
|
||||
"graphene_core::vector::vector_nodes::SamplePointsNode",
|
||||
],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::separate_subpaths::IDENTIFIER,
|
||||
@@ -1000,7 +999,7 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
|
||||
|
||||
for (node_id, node, network_path) in network.recursive_nodes() {
|
||||
if let DocumentNodeImplementation::ProtoNode(protonode_id) = &node.implementation {
|
||||
let node_path_without_type_args = protonode_id.name.split('<').next();
|
||||
let node_path_without_type_args = protonode_id.as_str().split('<').next();
|
||||
if let Some(new) = node_path_without_type_args.and_then(|node_path| replacements.get(node_path)) {
|
||||
let mut default_template = NodeTemplate::default();
|
||||
default_template.document_node.implementation = DocumentNodeImplementation::ProtoNode(new.clone());
|
||||
@@ -1023,8 +1022,8 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
|
||||
}
|
||||
|
||||
fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document: &mut DocumentMessageHandler, reset_node_definitions_on_open: bool) -> Option<()> {
|
||||
if reset_node_definitions_on_open && let Some(Some(reference)) = document.network_interface.reference(node_id, network_path) {
|
||||
let node_definition = resolve_document_node_type(reference)?;
|
||||
if reset_node_definitions_on_open && let Some(reference) = document.network_interface.reference(node_id, network_path) {
|
||||
let node_definition = resolve_document_node_type(&reference)?;
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template());
|
||||
}
|
||||
|
||||
@@ -1034,14 +1033,13 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Only nodes that have not been modified and still refer to a definition can be updated
|
||||
let reference = document.network_interface.reference(node_id, network_path).cloned().flatten()?;
|
||||
let reference = &reference;
|
||||
let reference = document.network_interface.reference(node_id, network_path)?;
|
||||
|
||||
let inputs_count = node.inputs.len();
|
||||
|
||||
// Upgrade Stroke node to reorder parameters and add "Align" and "Paint Order" (#2644)
|
||||
if reference == "Stroke" && inputs_count == 8 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::stroke::IDENTIFIER) && inputs_count == 8 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
|
||||
let align_input = NodeInput::value(TaggedValue::StrokeAlign(StrokeAlign::Center), false);
|
||||
@@ -1059,19 +1057,18 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 9), old_inputs[4].clone(), network_path);
|
||||
}
|
||||
|
||||
// Rename the old "Splines from Points" node to "Spline" and upgrade it to the new "Spline" node
|
||||
if reference == "Splines from Points" {
|
||||
document.network_interface.set_reference(node_id, network_path, Some("Spline".to_string()));
|
||||
}
|
||||
|
||||
// Upgrade the old "Spline" node to the new "Spline" node
|
||||
if reference == "Spline" {
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::spline::IDENTIFIER)
|
||||
|| reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::SplineNode"))
|
||||
|| reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SplineNode"))
|
||||
|| reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SplinesFromPointsNode"))
|
||||
{
|
||||
// Retrieve the proto node identifier and verify it is the old "Spline" node, otherwise skip it if this is the new "Spline" node
|
||||
let identifier = document
|
||||
.network_interface
|
||||
.implementation(node_id, network_path)
|
||||
.and_then(|implementation| implementation.get_proto_node());
|
||||
if identifier.map(|identifier| &identifier.name) != Some(&"graphene_core::vector::generator_nodes::SplineNode".into()) {
|
||||
if identifier.map(|identifier| identifier.as_str()) != Some("graphene_core::vector::generator_nodes::SplineNode") {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -1096,7 +1093,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
};
|
||||
|
||||
// Get the "Path" node definition and fill it in with the Vector path and default vector modification
|
||||
let Some(path_node_type) = resolve_document_node_type("Path") else {
|
||||
let Some(path_node_type) = resolve_network_node_type("Path") else {
|
||||
log::error!("Path node does not exist.");
|
||||
return None;
|
||||
};
|
||||
@@ -1106,7 +1103,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
]);
|
||||
|
||||
// Get the "Spline" node definition and wire it up with the "Path" node as input
|
||||
let Some(spline_node_type) = resolve_document_node_type("Spline") else {
|
||||
let Some(spline_node_type) = resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER) else {
|
||||
log::error!("Spline node does not exist.");
|
||||
return None;
|
||||
};
|
||||
@@ -1137,8 +1134,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016
|
||||
if reference == "Text" && inputs_count != 11 {
|
||||
let mut template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER) && inputs_count != 11 {
|
||||
let mut template: NodeTemplate = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut template);
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template)?;
|
||||
|
||||
@@ -1212,8 +1209,12 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Upgrade Sine, Cosine, and Tangent nodes to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default
|
||||
if (reference == "Sine" || reference == "Cosine" || reference == "Tangent") && inputs_count == 1 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if inputs_count == 1
|
||||
&& (reference == DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::sine::IDENTIFIER)
|
||||
|| reference == DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::cosine::IDENTIFIER)
|
||||
|| reference == DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::tangent::IDENTIFIER))
|
||||
{
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1225,8 +1226,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Upgrade the 'Tangent on Path' node to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default
|
||||
if (reference == "Tangent on Path") && inputs_count == 4 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::tangent_on_path::IDENTIFIER) && inputs_count == 4 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1241,8 +1242,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Upgrade the Modulo node to include a boolean input for whether the output should be always positive, which was previously not an option
|
||||
if reference == "Modulo" && inputs_count == 2 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::modulo::IDENTIFIER) && inputs_count == 2 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1255,8 +1256,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Upgrade the Mirror node to add the `keep_original` boolean input
|
||||
if reference == "Mirror" && inputs_count == 3 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::mirror::IDENTIFIER) && inputs_count == 3 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1270,8 +1271,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Upgrade the Mirror node to add the `reference_point` input and change `offset` from `DVec2` to `f64`
|
||||
if reference == "Mirror" && inputs_count == 4 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::mirror::IDENTIFIER) && inputs_count == 4 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1293,24 +1294,23 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Upgrade artboard name being passed as hidden value input to "Create Artboard"
|
||||
if reference == "Artboard" && reset_node_definitions_on_open {
|
||||
if reference == DefinitionIdentifier::Network("Artboard".into()) && reset_node_definitions_on_open {
|
||||
let label = document.network_interface.display_name(node_id, network_path);
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(NodeId(0), 1), NodeInput::value(TaggedValue::String(label), false), &[*node_id]);
|
||||
}
|
||||
|
||||
if reference == "Image" && inputs_count == 1 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER) && inputs_count == 1 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
// Insert a new empty input for the image
|
||||
document.network_interface.add_import(TaggedValue::None, false, 0, "Empty", "", &[*node_id]);
|
||||
document.network_interface.set_reference(node_id, network_path, Some("Image".to_string()));
|
||||
}
|
||||
|
||||
if reference == "Noise Pattern" && inputs_count == 15 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::noise_pattern::IDENTIFIER) && inputs_count == 15 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1323,8 +1323,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
}
|
||||
|
||||
if reference == "Instance on Points" && inputs_count == 2 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::instance_on_points::IDENTIFIER) && inputs_count == 2 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1333,20 +1333,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
|
||||
}
|
||||
|
||||
if reference == "Morph" && inputs_count == 4 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
|
||||
// We have removed the last input, so we don't add index 3
|
||||
}
|
||||
|
||||
if reference == "Brush" && inputs_count == 4 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::brush::brush::brush::IDENTIFIER) && inputs_count == 4 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1357,19 +1345,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[3].clone(), network_path);
|
||||
}
|
||||
|
||||
if reference == "Flatten Vector Elements" {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
|
||||
|
||||
document.network_interface.replace_reference_name(node_id, network_path, "Flatten Path".to_string());
|
||||
}
|
||||
|
||||
if reference == "Remove Handles" {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::RemoveHandlesNode")) {
|
||||
let mut node_template = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::auto_tangents::IDENTIFIER))?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1381,12 +1358,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path);
|
||||
|
||||
document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string());
|
||||
}
|
||||
|
||||
if reference == "Generate Handles" {
|
||||
let mut node_template = resolve_document_node_type("Auto-Tangents")?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::GenerateHandlesNode")) {
|
||||
let mut node_template = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::auto_tangents::IDENTIFIER))?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1396,12 +1371,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(true), false), network_path);
|
||||
|
||||
document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string());
|
||||
}
|
||||
|
||||
if reference == "Merge by Distance" && inputs_count == 2 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::merge_by_distance::IDENTIFIER) && inputs_count == 2 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1415,8 +1388,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
);
|
||||
}
|
||||
|
||||
if reference == "Spatial Merge by Distance" {
|
||||
let mut node_template = resolve_document_node_type("Merge by Distance")?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SpatialMergeByDistanceNode")) {
|
||||
let mut node_template = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::merge_by_distance::IDENTIFIER))?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1428,12 +1401,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Spatial), false),
|
||||
network_path,
|
||||
);
|
||||
|
||||
document.network_interface.replace_reference_name(node_id, network_path, "Merge by Distance".to_string());
|
||||
}
|
||||
|
||||
if reference == "Sample Points" && inputs_count == 5 {
|
||||
let mut node_template = resolve_document_node_type("Sample Polyline")?.default_node_template();
|
||||
if reference == DefinitionIdentifier::Network("Sample Points".into()) && inputs_count == 5 {
|
||||
let mut node_template = resolve_network_node_type("Sample Polyline")?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1447,12 +1418,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[2].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[4].clone(), network_path);
|
||||
|
||||
document.network_interface.replace_reference_name(node_id, network_path, "Sample Polyline".to_string());
|
||||
}
|
||||
|
||||
// Make the "Quantity" parameter a u32 instead of f64
|
||||
if reference == "Sample Polyline" {
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::sample_polyline::IDENTIFIER) {
|
||||
// Get the inputs, obtain the quantity value, and put the inputs back
|
||||
let quantity_value = document
|
||||
.network_interface
|
||||
@@ -1467,8 +1436,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Make the "Grid" node, if its input of index 3 is a DVec2 for "angles" instead of a u32 for the "columns" input that now succeeds "angles", move the angle to index 5 (after "columns" and "rows")
|
||||
if reference == "Grid" && inputs_count == 6 {
|
||||
let node_definition = resolve_document_node_type(reference)?;
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::grid::IDENTIFIER) && inputs_count == 6 {
|
||||
let node_definition = resolve_document_node_type(&reference)?;
|
||||
let mut new_node_template = node_definition.default_node_template();
|
||||
|
||||
let mut current_node_template = document.network_interface.create_node_template(node_id, network_path)?;
|
||||
@@ -1497,8 +1466,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Add the "Depth" parameter to the "Instance Index" node
|
||||
if reference == "Instance Index" && inputs_count == 0 {
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::instance_index::IDENTIFIER) && inputs_count == 0 {
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
document.network_interface.set_display_name(node_id, "Instance Index".to_string(), network_path);
|
||||
|
||||
@@ -1510,8 +1479,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
|
||||
// Migrate the Transform node to use degrees instead of radians
|
||||
if reference == "Transform" && node.inputs.get(6).is_none() {
|
||||
let mut node_template = resolve_document_node_type("Transform")?.default_node_template();
|
||||
if reference == DefinitionIdentifier::Network("Transform".into()) && node.inputs.get(6).is_none() {
|
||||
let mut node_template = resolve_network_node_type("Transform")?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
@@ -1547,7 +1516,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
NodeInput::Node { .. } => {
|
||||
// Construct a new Multiply node for converting from degrees to radians
|
||||
let Some(multiply_node) = resolve_document_node_type("Multiply") else {
|
||||
let Some(multiply_node) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::multiply::IDENTIFIER)) else {
|
||||
log::error!("Could not get multiply node from definition when upgrading transform");
|
||||
return None;
|
||||
};
|
||||
@@ -1587,18 +1556,21 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
// The old version would zip the source and target table rows, interpoleating each pair together.
|
||||
// The migrated version will instead deeply flatten both merged tables and morph sequentially between all source vectors and all target vector elements.
|
||||
// This migration assumes most usages didn't involve multiple parallel vector elements, and instead morphed from a single source to a single target vector element.
|
||||
if reference == "Morph" && inputs_count == 3 {
|
||||
// Old signature:
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::morph::IDENTIFIER) && (inputs_count == 3 || inputs_count == 4) {
|
||||
// 3 inputs - old signature (#3405):
|
||||
// async fn morph(_: impl Ctx, source: Table<Vector>, #[expose] target: Table<Vector>, #[default(0.5)] time: Fraction) -> Table<Vector> { ... }
|
||||
//
|
||||
// 4 inputs - even older signature (commit 80b8df8d4298b6669f124b929ce61bfabfc44e41):
|
||||
// async fn morph(_: impl Ctx, source: Table<Vector>, #[expose] target: Table<Vector>, #[default(0.5)] time: Fraction, #[min(0.)] start_index: IntegerCount) -> Table<Vector> { ... }
|
||||
//
|
||||
// New signature:
|
||||
// async fn morph<I: IntoGraphicTable>(_: impl Ctx, content: #[implementations(Table<Graphic>, Table<Vector>)] content: I, progression: Progression) -> Table<Vector> { ... }
|
||||
// async fn morph<I: IntoGraphicTable>(_: impl Ctx, #[implementations(Table<Graphic>, Table<Vector>)] content: I, progression: Progression) -> Table<Vector> { ... }
|
||||
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
|
||||
// Create a new Merge node
|
||||
let Some(merge_node_type) = resolve_document_node_type("Merge") else {
|
||||
let Some(merge_node_type) = resolve_network_node_type("Merge") else {
|
||||
log::error!("Could not get merge node from definition when upgrading morph");
|
||||
return None;
|
||||
};
|
||||
@@ -1631,7 +1603,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
|
||||
// Add context features to nodes that don't have them (fine-grained context caching migration)
|
||||
if node.context_features == graphene_std::ContextDependencies::default()
|
||||
&& let Some(reference) = document.network_interface.reference(node_id, network_path).cloned().flatten()
|
||||
&& let Some(reference) = document.network_interface.reference(node_id, network_path).clone()
|
||||
&& let Some(node_definition) = resolve_document_node_type(&reference)
|
||||
{
|
||||
let context_features = node_definition.node_template.document_node.context_features;
|
||||
@@ -1678,7 +1650,7 @@ mod tests {
|
||||
NODE_REPLACEMENTS.iter().for_each(|node| {
|
||||
*hashmap.entry(node.node.clone()).or_default() += 1;
|
||||
});
|
||||
let duplicates = hashmap.iter().filter(|(_, count)| **count > 1).map(|(node, _)| &node.name).collect::<Vec<_>>();
|
||||
let duplicates = hashmap.iter().filter(|(_, count)| **count > 1).map(|(node, _)| node.as_str()).collect::<Vec<_>>();
|
||||
if !duplicates.is_empty() {
|
||||
panic!("Duplicate entries in `NODE_REPLACEMENTS`: {duplicates:?}");
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ use crate::messages::input_mapper::utility_types::macros::{action_shortcut, acti
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::DocumentMessageContext;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{self, resolve_network_node_type};
|
||||
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::OutputConnector;
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
@@ -522,7 +521,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
// Ensure each node has the metadata for its inputs
|
||||
for (node_id, node, path) in document.network_interface.document_network().clone().recursive_nodes() {
|
||||
document.network_interface.validate_input_metadata(node_id, node, &path);
|
||||
document.network_interface.validate_display_name_metadata(node_id, &path);
|
||||
document.network_interface.validate_output_names(node_id, node, &path);
|
||||
}
|
||||
|
||||
@@ -664,7 +662,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
let mut layers = Vec::new();
|
||||
|
||||
for (_, new_vector, transform) in data {
|
||||
let Some(node_type) = resolve_document_node_type("Path") else {
|
||||
let Some(node_type) = resolve_network_node_type("Path") else {
|
||||
error!("Path node does not exist");
|
||||
continue;
|
||||
};
|
||||
|
||||
+5
-2
@@ -2,6 +2,7 @@ use crate::consts::GIZMO_HIDE_THRESHOLD;
|
||||
use crate::consts::{COLOR_OVERLAY_RED, POINT_RADIUS_HANDLE_SNAP_THRESHOLD};
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::{overlays::utility_types::OverlayContext, utility_types::network_interface::InputConnector};
|
||||
use crate::messages::prelude::FrontendMessage;
|
||||
@@ -331,7 +332,8 @@ impl PointRadiusHandle {
|
||||
fn calculate_snap_radii(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, radius_index: usize) -> Vec<f64> {
|
||||
let mut snap_radii = Vec::new();
|
||||
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star") else {
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER))
|
||||
else {
|
||||
return snap_radii;
|
||||
};
|
||||
|
||||
@@ -449,7 +451,8 @@ impl PointRadiusHandle {
|
||||
}
|
||||
|
||||
fn check_if_radius_flipped(&mut self, original_radius: f64, new_radius: f64, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, radius_index: usize) {
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star") else {
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{self, DefinitionIdentifier};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeNetworkInterface, NodeTemplate};
|
||||
use crate::messages::prelude::*;
|
||||
@@ -24,9 +24,13 @@ pub fn find_spline(document: &DocumentMessageHandler, layer: LayerNodeIdentifier
|
||||
document
|
||||
.network_interface
|
||||
.upstream_flow_back_from_nodes([layer.to_node()].to_vec(), &[], FlowType::HorizontalFlow)
|
||||
.map(|node_id| (document.network_interface.reference(&node_id, &[]).unwrap(), node_id))
|
||||
.take_while(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref != "Path"))
|
||||
.find(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref == "Spline"))
|
||||
.map(|node_id| (document.network_interface.reference(&node_id, &[]), node_id))
|
||||
.take_while(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref != &DefinitionIdentifier::Network("Path".into())))
|
||||
.find(|(reference, _)| {
|
||||
reference
|
||||
.as_ref()
|
||||
.is_some_and(|node_ref| *node_ref == DefinitionIdentifier::ProtoNode(graphene_std::vector::spline::IDENTIFIER))
|
||||
})
|
||||
.map(|node| node.1)
|
||||
}
|
||||
|
||||
@@ -73,7 +77,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
|
||||
// Merge the inputs of the two layers
|
||||
let merge_node_id = NodeId::new();
|
||||
let merge_node = document_node_definitions::resolve_document_node_type("Merge")
|
||||
let merge_node = document_node_definitions::resolve_network_node_type("Merge")
|
||||
.expect("Failed to create merge node")
|
||||
.default_node_template();
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
@@ -99,7 +103,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
|
||||
// Add a Flatten Path node after the merge
|
||||
let flatten_node_id = NodeId::new();
|
||||
let flatten_node = document_node_definitions::resolve_document_node_type("Flatten Path")
|
||||
let flatten_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::flatten_path::IDENTIFIER)
|
||||
.expect("Failed to create flatten node")
|
||||
.default_node_template();
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
@@ -113,7 +117,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
|
||||
// Add a path node after the flatten node
|
||||
let path_node_id = NodeId::new();
|
||||
let path_node = document_node_definitions::resolve_document_node_type("Path")
|
||||
let path_node = document_node_definitions::resolve_network_node_type("Path")
|
||||
.expect("Failed to create path node")
|
||||
.default_node_template();
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
@@ -128,7 +132,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
// Add a Spline node after the Path node if both the layers we are merging is spline.
|
||||
if current_and_other_layer_is_spline {
|
||||
let spline_node_id = NodeId::new();
|
||||
let spline_node = document_node_definitions::resolve_document_node_type("Spline")
|
||||
let spline_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER)
|
||||
.expect("Failed to create Spline node")
|
||||
.default_node_template();
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
@@ -143,7 +147,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
|
||||
|
||||
// Add a transform node to ensure correct tooling modifications
|
||||
let transform_node_id = NodeId::new();
|
||||
let transform_node = document_node_definitions::resolve_document_node_type("Transform")
|
||||
let transform_node = document_node_definitions::resolve_network_node_type("Transform")
|
||||
.expect("Failed to create transform node")
|
||||
.default_node_template();
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
@@ -251,7 +255,7 @@ pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerN
|
||||
pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<DVec2> {
|
||||
use graphene_std::transform_nodes::transform::*;
|
||||
|
||||
if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", TranslationInput::INDEX)? {
|
||||
if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input(&DefinitionIdentifier::Network("Transform".into()), TranslationInput::INDEX)? {
|
||||
Some(*origin)
|
||||
} else {
|
||||
None
|
||||
@@ -273,7 +277,7 @@ pub fn get_viewport_center(layer: LayerNodeIdentifier, network_interface: &NodeN
|
||||
pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Gradient> {
|
||||
let fill_index = 1;
|
||||
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER))?;
|
||||
let TaggedValue::Fill(Fill::Gradient(gradient)) = inputs.get(fill_index)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -284,7 +288,7 @@ pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI
|
||||
pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Color> {
|
||||
let fill_index = 1;
|
||||
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER))?;
|
||||
let TaggedValue::Fill(Fill::Solid(color)) = inputs.get(fill_index)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -293,7 +297,7 @@ pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetwor
|
||||
|
||||
/// Get the current blend mode of a layer from the closest "Blending" node.
|
||||
pub fn get_blend_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<BlendMode> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?;
|
||||
let TaggedValue::BlendMode(blend_mode) = inputs.get(1)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -309,7 +313,7 @@ pub fn get_blend_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetwor
|
||||
///
|
||||
/// With those limitations in mind, the intention of this function is to show just the value already present in an upstream Opacity node so that value can be directly edited.
|
||||
pub fn get_opacity(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?;
|
||||
let TaggedValue::F64(opacity) = inputs.get(2)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -317,7 +321,7 @@ pub fn get_opacity(layer: LayerNodeIdentifier, network_interface: &NodeNetworkIn
|
||||
}
|
||||
|
||||
pub fn get_clip_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<bool> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?;
|
||||
let TaggedValue::Bool(clip) = inputs.get(4)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -325,7 +329,7 @@ pub fn get_clip_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetwork
|
||||
}
|
||||
|
||||
pub fn get_fill(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?;
|
||||
let TaggedValue::F64(fill) = inputs.get(3)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
@@ -333,56 +337,56 @@ pub fn get_fill(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
|
||||
}
|
||||
|
||||
pub fn get_fill_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Fill")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::fill::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_circle_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Circle")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::circle::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_ellipse_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Ellipse")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::ellipse::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_line_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Line")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::line::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_polygon_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Regular Polygon")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::regular_polygon::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_rectangle_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Rectangle")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::rectangle::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_star_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Star")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::star::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_arc_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Arc")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::arc::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_arrow_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Arrow")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::arrow::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_spiral_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Spiral")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::spiral::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Text")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER))
|
||||
}
|
||||
|
||||
pub fn get_grid_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Grid")
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::grid::IDENTIFIER))
|
||||
}
|
||||
|
||||
/// Gets properties from the Text node
|
||||
pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, TypesettingConfig, bool)> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Text")?;
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER))?;
|
||||
|
||||
let Some(TaggedValue::String(text)) = &inputs[1].as_value() else { return None };
|
||||
let Some(TaggedValue::Font(font)) = &inputs[2].as_value() else { return None };
|
||||
@@ -409,7 +413,7 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter
|
||||
|
||||
pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<f64> {
|
||||
let weight_node_input_index = graphene_std::vector::stroke::WeightInput::INDEX;
|
||||
if let TaggedValue::F64(width) = NodeGraphLayer::new(layer, network_interface).find_input("Stroke", weight_node_input_index)? {
|
||||
if let TaggedValue::F64(width) = NodeGraphLayer::new(layer, network_interface).find_input(&DefinitionIdentifier::ProtoNode(graphene_std::vector::stroke::IDENTIFIER), weight_node_input_index)? {
|
||||
Some(*width)
|
||||
} else {
|
||||
None
|
||||
@@ -417,8 +421,8 @@ pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetw
|
||||
}
|
||||
|
||||
/// Checks if a specified layer uses an upstream node matching the given name.
|
||||
pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, node_name: &str) -> bool {
|
||||
NodeGraphLayer::new(layer, network_interface).find_node_inputs(node_name).is_some()
|
||||
pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, identifier: &DefinitionIdentifier) -> bool {
|
||||
NodeGraphLayer::new(layer, network_interface).find_node_inputs(identifier).is_some()
|
||||
}
|
||||
|
||||
/// An immutable reference to a layer within the document node graph for easy access.
|
||||
@@ -443,19 +447,19 @@ impl<'a> NodeGraphLayer<'a> {
|
||||
}
|
||||
|
||||
/// Node id of a node if it exists in the layer's primary flow
|
||||
pub fn upstream_node_id_from_name(&self, node_name: &str) -> Option<NodeId> {
|
||||
pub fn upstream_node_id_from_name(&self, identifier: &DefinitionIdentifier) -> Option<NodeId> {
|
||||
self.horizontal_layer_flow()
|
||||
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| *reference == Some(node_name.to_string())))
|
||||
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == *identifier))
|
||||
}
|
||||
|
||||
/// Node id of a visible node if it exists in the layer's primary flow until another layer
|
||||
pub fn upstream_visible_node_id_from_name_in_layer(&self, node_name: &str) -> Option<NodeId> {
|
||||
pub fn upstream_visible_node_id_from_name_in_layer(&self, identifier: &DefinitionIdentifier) -> Option<NodeId> {
|
||||
// `.skip(1)` is used to skip self
|
||||
self.horizontal_layer_flow()
|
||||
.skip(1)
|
||||
.take_while(|node_id| !self.network_interface.is_layer(node_id, &[]))
|
||||
.filter(|node_id| self.network_interface.is_visible(node_id, &[]))
|
||||
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| *reference == Some(node_name.to_string())))
|
||||
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == *identifier))
|
||||
}
|
||||
|
||||
/// Node id of a protonode if it exists in the layer's primary flow
|
||||
@@ -471,19 +475,19 @@ impl<'a> NodeGraphLayer<'a> {
|
||||
}
|
||||
|
||||
/// Find all of the inputs of a specific node within the layer's primary flow, up until the next layer is reached.
|
||||
pub fn find_node_inputs(&self, node_name: &str) -> Option<&'a Vec<NodeInput>> {
|
||||
pub fn find_node_inputs(&self, identifier: &DefinitionIdentifier) -> Option<&'a Vec<NodeInput>> {
|
||||
// `.skip(1)` is used to skip self
|
||||
self.horizontal_layer_flow()
|
||||
.skip(1)
|
||||
.take_while(|node_id| !self.network_interface.is_layer(node_id, &[]))
|
||||
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| *reference == Some(node_name.to_string())))
|
||||
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == *identifier))
|
||||
.and_then(|node_id| self.network_interface.document_network().nodes.get(&node_id).map(|node| &node.inputs))
|
||||
}
|
||||
|
||||
/// Find a specific input of a node within the layer's primary flow
|
||||
pub fn find_input(&self, node_name: &str, index: usize) -> Option<&'a TaggedValue> {
|
||||
pub fn find_input(&self, identifier: &DefinitionIdentifier, index: usize) -> Option<&'a TaggedValue> {
|
||||
// TODO: Find a better way to accept a node input rather than using its index (which is quite unclear and fragile)
|
||||
self.find_node_inputs(node_name)?.get(index)?.as_value()
|
||||
self.find_node_inputs(identifier)?.get(index)?.as_value()
|
||||
}
|
||||
|
||||
/// Check if a layer is a raster layer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::shape_utility::ShapeToolModifierKey;
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_proto_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_arc_radius_handle::{RadiusHandle, RadiusHandleState};
|
||||
@@ -133,7 +133,7 @@ pub struct Arc;
|
||||
|
||||
impl Arc {
|
||||
pub fn create_node(arc_type: ArcType) -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Arc").expect("Ellipse node does not exist");
|
||||
let node_type = resolve_proto_node_type(graphene_std::vector::generator_nodes::arc::IDENTIFIER).expect("Ellipse node does not exist");
|
||||
node_type.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::F64(0.5), false)),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::shape_utility::ShapeToolModifierKey;
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_proto_node_type;
|
||||
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, NodeTemplate};
|
||||
@@ -16,7 +16,7 @@ pub struct Arrow;
|
||||
|
||||
impl Arrow {
|
||||
pub fn create_node(document: &DocumentMessageHandler, drag_start: DVec2) -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Arrow").expect("Arrow node does not exist");
|
||||
let node_type = resolve_proto_node_type(graphene_std::vector_nodes::arrow::IDENTIFIER).expect("Arrow node does not exist");
|
||||
let viewport_pos = document.metadata().document_to_viewport.transform_point2(drag_start);
|
||||
node_type.node_template_input_override([
|
||||
None,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_proto_node_type;
|
||||
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, NodeTemplate};
|
||||
@@ -82,7 +82,7 @@ pub struct Circle;
|
||||
|
||||
impl Circle {
|
||||
pub fn create_node() -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Circle").expect("Circle can't be found");
|
||||
let node_type = resolve_proto_node_type(graphene_std::vector::generator_nodes::circle::IDENTIFIER).expect("Circle can't be found");
|
||||
node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.), false))])
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::shape_utility::ShapeToolModifierKey;
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_proto_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
@@ -16,7 +16,7 @@ pub struct Ellipse;
|
||||
|
||||
impl Ellipse {
|
||||
pub fn create_node() -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Ellipse").expect("Ellipse node can't be found");
|
||||
let node_type = resolve_proto_node_type(graphene_std::vector::generator_nodes::ellipse::IDENTIFIER).expect("Ellipse node can't be found");
|
||||
node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.5), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))])
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::shape_utility::ShapeToolModifierKey;
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_proto_node_type;
|
||||
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, NodeTemplate};
|
||||
@@ -86,7 +86,7 @@ pub struct Grid;
|
||||
|
||||
impl Grid {
|
||||
pub fn create_node(grid_type: GridType) -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Grid").expect("Grid can't be found");
|
||||
let node_type = resolve_proto_node_type(graphene_std::vector::generator_nodes::grid::IDENTIFIER).expect("Grid can't be found");
|
||||
node_type.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::GridType(grid_type), false)),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::shape_utility::ShapeToolModifierKey;
|
||||
use crate::consts::{BOUNDS_SELECT_THRESHOLD, LINE_ROTATE_SNAP_ANGLE};
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type};
|
||||
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, NodeTemplate};
|
||||
@@ -37,7 +37,8 @@ pub struct Line;
|
||||
|
||||
impl Line {
|
||||
pub fn create_node(document: &DocumentMessageHandler, drag_start: DVec2) -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Line").expect("Line node can't be found");
|
||||
let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER);
|
||||
let node_type = resolve_document_node_type(&identifier).expect("Line node can't be found");
|
||||
node_type.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::DVec2(document.metadata().document_to_viewport.transform_point2(drag_start)), false)),
|
||||
@@ -88,7 +89,8 @@ impl Line {
|
||||
.selected_nodes()
|
||||
.selected_visible_and_unlocked_layers(&document.network_interface)
|
||||
.filter_map(|layer| {
|
||||
let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Line")?;
|
||||
let node_inputs =
|
||||
NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER))?;
|
||||
|
||||
let (Some(&TaggedValue::DVec2(start)), Some(&TaggedValue::DVec2(end))) = (node_inputs[1].as_value(), node_inputs[2].as_value()) else {
|
||||
return None;
|
||||
@@ -171,7 +173,7 @@ fn generate_line(tool_data: &mut ShapeToolData, snap_data: SnapData, lock_angle:
|
||||
}
|
||||
|
||||
pub fn clicked_on_line_endpoints(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, shape_tool_data: &mut ShapeToolData) -> bool {
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Line") else {
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER)) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -216,7 +218,7 @@ mod test_line_tool {
|
||||
.selected_nodes()
|
||||
.selected_visible_and_unlocked_layers(network_interface)
|
||||
.filter_map(|layer| {
|
||||
let node_inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Line")?;
|
||||
let node_inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER))?;
|
||||
let (Some(&TaggedValue::DVec2(start)), Some(&TaggedValue::DVec2(end))) = (node_inputs[1].as_value(), node_inputs[2].as_value()) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::shape_utility::{ShapeToolModifierKey, update_radius_sign};
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type};
|
||||
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, NodeTemplate};
|
||||
@@ -109,7 +109,8 @@ pub struct Polygon;
|
||||
|
||||
impl Polygon {
|
||||
pub fn create_node(vertices: u32) -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Regular Polygon").expect("Regular Polygon can't be found");
|
||||
let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::regular_polygon::IDENTIFIER);
|
||||
let node_type = resolve_document_node_type(&identifier).expect("Regular Polygon can't be found");
|
||||
node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::U32(vertices), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))])
|
||||
}
|
||||
|
||||
@@ -167,8 +168,8 @@ impl Polygon {
|
||||
};
|
||||
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface)
|
||||
.find_node_inputs("Regular Polygon")
|
||||
.or(NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star"))
|
||||
.find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::regular_polygon::IDENTIFIER))
|
||||
.or(NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER)))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::shape_utility::ShapeToolModifierKey;
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_proto_node_type;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
@@ -16,7 +16,7 @@ pub struct Rectangle;
|
||||
|
||||
impl Rectangle {
|
||||
pub fn create_node() -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Rectangle").expect("Rectangle node can't be found");
|
||||
let node_type = resolve_proto_node_type(graphene_std::vector::generator_nodes::rectangle::IDENTIFIER).expect("Rectangle node can't be found");
|
||||
node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(1.), false)), Some(NodeInput::value(TaggedValue::F64(1.), false))])
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::ShapeToolData;
|
||||
use crate::consts::{ARC_SWEEP_GIZMO_RADIUS, ARC_SWEEP_GIZMO_TEXT_HEIGHT};
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
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;
|
||||
@@ -157,8 +158,15 @@ pub fn update_radius_sign(end: DVec2, start: DVec2, layer: LayerNodeIdentifier,
|
||||
let sign_num = if end[1] > start[1] { 1. } else { -1. };
|
||||
let new_layer = NodeGraphLayer::new(layer, &document.network_interface);
|
||||
|
||||
if new_layer.find_input("Regular Polygon", 1).unwrap_or(&TaggedValue::U32(0)).to_u32() % 2 == 1 {
|
||||
let Some(polygon_node_id) = new_layer.upstream_node_id_from_name("Regular Polygon") else { return };
|
||||
if new_layer
|
||||
.find_input(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::regular_polygon::IDENTIFIER), 1)
|
||||
.unwrap_or(&TaggedValue::U32(0))
|
||||
.to_u32()
|
||||
% 2 == 1
|
||||
{
|
||||
let Some(polygon_node_id) = new_layer.upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::regular_polygon::IDENTIFIER)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(polygon_node_id, 2),
|
||||
@@ -167,8 +175,15 @@ pub fn update_radius_sign(end: DVec2, start: DVec2, layer: LayerNodeIdentifier,
|
||||
return;
|
||||
}
|
||||
|
||||
if new_layer.find_input("Star", 1).unwrap_or(&TaggedValue::U32(0)).to_u32() % 2 == 1 {
|
||||
let Some(star_node_id) = new_layer.upstream_node_id_from_name("Star") else { return };
|
||||
if new_layer
|
||||
.find_input(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER), 1)
|
||||
.unwrap_or(&TaggedValue::U32(0))
|
||||
.to_u32()
|
||||
% 2 == 1
|
||||
{
|
||||
let Some(star_node_id) = new_layer.upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::star::IDENTIFIER)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(star_node_id, 2),
|
||||
@@ -237,7 +252,7 @@ pub fn anchor_overlays(document: &DocumentMessageHandler, overlay_context: &mut
|
||||
/// Extract the node input values of Star.
|
||||
/// Returns an option of (sides, radius1, radius2).
|
||||
pub fn extract_star_parameters(layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler) -> Option<(u32, f64, f64)> {
|
||||
let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Star")?;
|
||||
let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER))?;
|
||||
|
||||
let (Some(&TaggedValue::U32(sides)), Some(&TaggedValue::F64(radius_1)), Some(&TaggedValue::F64(radius_2))) =
|
||||
(node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value(), node_inputs.get(3)?.as_value())
|
||||
@@ -251,7 +266,8 @@ pub fn extract_star_parameters(layer: Option<LayerNodeIdentifier>, document: &Do
|
||||
/// Extract the node input values of Polygon.
|
||||
/// Returns an option of (sides, radius).
|
||||
pub fn extract_polygon_parameters(layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler) -> Option<(u32, f64)> {
|
||||
let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Regular Polygon")?;
|
||||
let node_inputs =
|
||||
NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::regular_polygon::IDENTIFIER))?;
|
||||
|
||||
let (Some(&TaggedValue::U32(n)), Some(&TaggedValue::F64(radius))) = (node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value()) else {
|
||||
return None;
|
||||
@@ -263,7 +279,7 @@ pub fn extract_polygon_parameters(layer: Option<LayerNodeIdentifier>, document:
|
||||
/// Extract the node input values of an arc.
|
||||
/// Returns an option of (radius, start angle, sweep angle, arc type).
|
||||
pub fn extract_arc_parameters(layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler) -> Option<(f64, f64, f64, ArcType)> {
|
||||
let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Arc")?;
|
||||
let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::arc::IDENTIFIER))?;
|
||||
|
||||
let (Some(&TaggedValue::F64(radius)), Some(&TaggedValue::F64(start_angle)), Some(&TaggedValue::F64(sweep_angle)), Some(&TaggedValue::ArcType(arc_type))) = (
|
||||
node_inputs.get(1)?.as_value(),
|
||||
@@ -303,7 +319,7 @@ pub fn arc_end_points_ignore_layer(radius: f64, start_angle: f64, sweep_angle: f
|
||||
/// Extract the node input values of Circle.
|
||||
/// Returns an option of (radius).
|
||||
pub fn extract_circle_radius(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option<f64> {
|
||||
let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Circle")?;
|
||||
let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::circle::IDENTIFIER))?;
|
||||
|
||||
let Some(&TaggedValue::F64(radius)) = node_inputs.get(1)?.as_value() else {
|
||||
return None;
|
||||
@@ -499,7 +515,7 @@ pub fn calculate_arc_text_transform(angle: f64, offset_angle: f64, center: DVec2
|
||||
pub fn extract_grid_parameters(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option<(GridType, DVec2, u32, u32, DVec2)> {
|
||||
use graphene_std::vector::generator_nodes::grid::*;
|
||||
|
||||
let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Grid")?;
|
||||
let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::grid::IDENTIFIER))?;
|
||||
|
||||
let (Some(&TaggedValue::GridType(grid_type)), Some(&TaggedValue::DVec2(spacing)), Some(&TaggedValue::U32(columns)), Some(&TaggedValue::U32(rows)), Some(&TaggedValue::DVec2(angles))) = (
|
||||
node_inputs.get(GridTypeInput::INDEX)?.as_value(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer};
|
||||
@@ -24,7 +24,8 @@ impl Spiral {
|
||||
SpiralType::Logarithmic => 0.1,
|
||||
};
|
||||
|
||||
let node_type = resolve_document_node_type("Spiral").expect("Spiral node can't be found");
|
||||
let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::spiral::IDENTIFIER);
|
||||
let node_type = resolve_document_node_type(&identifier).expect("Spiral node can't be found");
|
||||
node_type.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::SpiralType(spiral_type), false)),
|
||||
@@ -62,7 +63,8 @@ impl Spiral {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Spiral") else {
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::spiral::IDENTIFIER))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -93,7 +95,8 @@ impl Spiral {
|
||||
pub fn update_turns(decrease: bool, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
use graphene_std::vector::generator_nodes::spiral::*;
|
||||
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Spiral") else {
|
||||
let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::spiral::IDENTIFIER))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::shape_utility::{ShapeToolModifierKey, update_radius_sign};
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type};
|
||||
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, NodeTemplate};
|
||||
@@ -109,7 +109,8 @@ pub struct Star;
|
||||
|
||||
impl Star {
|
||||
pub fn create_node(vertices: u32) -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Star").expect("Star node can't be found");
|
||||
let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER);
|
||||
let node_type = resolve_document_node_type(&identifier).expect("Star node can't be found");
|
||||
node_type.node_template_input_override([
|
||||
None,
|
||||
Some(NodeInput::value(TaggedValue::U32(vertices), false)),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::snapping::{SnapCandidatePoint, SnapData, SnapManager};
|
||||
use super::transformation_cage::{BoundingBoxManager, SizeSnapData};
|
||||
use crate::consts::ROTATE_INCREMENT;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{NodeNetworkInterface, OutputConnector};
|
||||
use crate::messages::portfolio::document::utility_types::transformation::Selected;
|
||||
@@ -581,7 +582,7 @@ pub fn make_path_editable_is_allowed(network_interface: &mut NodeNetworkInterfac
|
||||
|
||||
// Must not already have an existing Path node, in the right-most part of the layer chain, which has an empty set of modifications
|
||||
// (otherwise users could repeatedly keep running this command and stacking up empty Path nodes)
|
||||
if let Some(TaggedValue::VectorModification(modifications)) = NodeGraphLayer::new(first_layer, network_interface).find_input("Path", 1)
|
||||
if let Some(TaggedValue::VectorModification(modifications)) = NodeGraphLayer::new(first_layer, network_interface).find_input(&DefinitionIdentifier::Network("Path".into()), 1)
|
||||
&& modifications.as_ref() == &VectorModification::default()
|
||||
{
|
||||
return None;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::tool_prelude::*;
|
||||
use crate::consts::DEFAULT_BRUSH_SIZE;
|
||||
use crate::messages::portfolio::document::graph_operation::transform_utils::get_current_transform;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_network_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};
|
||||
@@ -316,7 +316,7 @@ impl BrushToolData {
|
||||
continue;
|
||||
};
|
||||
|
||||
if *reference == Some("Brush".to_string()) && node_id != layer.to_node() {
|
||||
if reference == DefinitionIdentifier::Network("Brush".into()) && node_id != layer.to_node() {
|
||||
let points_input = node.inputs.get(1)?;
|
||||
let Some(TaggedValue::BrushStrokes(strokes)) = points_input.as_value() else { continue };
|
||||
self.strokes.clone_from(strokes);
|
||||
@@ -324,7 +324,7 @@ impl BrushToolData {
|
||||
return Some(layer);
|
||||
}
|
||||
|
||||
if *reference == Some("Transform".to_string()) {
|
||||
if reference == DefinitionIdentifier::Network("Transform".into()) {
|
||||
self.transform = get_current_transform(&node.inputs) * self.transform;
|
||||
}
|
||||
}
|
||||
@@ -475,7 +475,7 @@ 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").default_node_template();
|
||||
let brush_node = resolve_network_node_type("Brush").expect("Brush node does not exist").default_node_template();
|
||||
|
||||
let id = NodeId::new();
|
||||
responses.add(GraphOperationMessage::NewCustomLayer {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::tool_prelude::*;
|
||||
use crate::consts::DEFAULT_STROKE_WIDTH;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_network_node_type;
|
||||
use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
@@ -285,7 +285,7 @@ impl Fsm for FreehandToolFsmState {
|
||||
|
||||
let parent = document.new_layer_bounding_artboard(input, viewport);
|
||||
|
||||
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
|
||||
let node_type = resolve_network_node_type("Path").expect("Path node does not exist");
|
||||
let node = node_type.default_node_template();
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
|
||||
@@ -402,7 +402,7 @@ mod test_freehand {
|
||||
.filter_map(|layer| {
|
||||
let graph_layer = NodeGraphLayer::new(layer, &document.network_interface);
|
||||
// Only get layers with path nodes
|
||||
let _ = graph_layer.upstream_visible_node_id_from_name_in_layer("Path")?;
|
||||
let _ = graph_layer.upstream_visible_node_id_from_name_in_layer(&DefinitionIdentifier::Network("Path".into()))?;
|
||||
|
||||
let vector = document.network_interface.compute_modified_vector(layer)?;
|
||||
let transform = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::consts::{
|
||||
use crate::messages::clipboard::utility_types::ClipboardContent;
|
||||
use crate::messages::input_mapper::utility_types::macros::action_shortcut_manual;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_network_node_type;
|
||||
use crate::messages::portfolio::document::overlays::utility_functions::{path_overlays, selected_segments};
|
||||
use crate::messages::portfolio::document::overlays::utility_types::{DrawHandles, OverlayContext};
|
||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||
@@ -2826,7 +2826,7 @@ impl Fsm for PathToolFsmState {
|
||||
let layer = if shape_editor.selected_shape_state.contains_key(&layer) {
|
||||
layer
|
||||
} else {
|
||||
let Some(node_type) = resolve_document_node_type("Path") else {
|
||||
let Some(node_type) = resolve_network_node_type("Path") else {
|
||||
error!("Could not resolve node type for Path");
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::tool_prelude::*;
|
||||
use crate::consts::{COLOR_OVERLAY_BLUE, DEFAULT_STROKE_WIDTH, HIDE_HANDLE_DISTANCE, LINE_ROTATE_SNAP_ANGLE, SEGMENT_OVERLAY_SIZE};
|
||||
use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_network_node_type;
|
||||
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::{DrawHandles, OverlayContext};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
@@ -1282,7 +1282,7 @@ impl PenToolData {
|
||||
}
|
||||
|
||||
// New path layer
|
||||
let node_type = resolve_document_node_type("Path").expect("Path node does not exist");
|
||||
let node_type = resolve_network_node_type("Path").expect("Path node does not exist");
|
||||
let nodes = vec![(NodeId(0), node_type.default_node_template())];
|
||||
|
||||
let parent = document.new_layer_bounding_artboard(input, viewport);
|
||||
|
||||
@@ -4,6 +4,7 @@ use super::tool_prelude::*;
|
||||
use crate::consts::*;
|
||||
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
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::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType};
|
||||
@@ -624,7 +625,7 @@ impl Fsm for SelectToolFsmState {
|
||||
let layer_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||
overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, None);
|
||||
|
||||
if is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") {
|
||||
if is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)) {
|
||||
let transformed_quad = layer_to_viewport * text_bounding_box(layer, document, &persistent_data.font_cache);
|
||||
overlay_context.dashed_quad(transformed_quad, None, None, Some(7.), Some(5.), None);
|
||||
}
|
||||
@@ -1579,7 +1580,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
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_interface, "Text") {
|
||||
if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)) {
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
|
||||
responses.add(TextToolMessage::EditSelected);
|
||||
}
|
||||
@@ -1933,7 +1934,7 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer:
|
||||
/// Called when a double click on a layer in deep select mode.
|
||||
/// If the layer is text, the text tool is selected.
|
||||
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") {
|
||||
if is_layer_fed_by_node_of_name(layer, network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)) {
|
||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
|
||||
responses.add(TextToolMessage::EditSelected);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::tool_prelude::*;
|
||||
use crate::consts::{DEFAULT_STROKE_WIDTH, DRAG_THRESHOLD, PATH_JOIN_THRESHOLD, SNAP_POINT_TOLERANCE};
|
||||
use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::{resolve_network_node_type, resolve_proto_node_type};
|
||||
use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
@@ -388,9 +388,9 @@ impl Fsm for SplineToolFsmState {
|
||||
|
||||
let parent = document.new_layer_bounding_artboard(input, viewport);
|
||||
|
||||
let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist");
|
||||
let path_node_type = resolve_network_node_type("Path").expect("Path node does not exist");
|
||||
let path_node = path_node_type.default_node_template();
|
||||
let spline_node_type = resolve_document_node_type("Spline").expect("Spline node does not exist");
|
||||
let spline_node_type = resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER).expect("Spline node does not exist");
|
||||
let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]);
|
||||
let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)];
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use super::tool_prelude::*;
|
||||
use crate::consts::{COLOR_OVERLAY_BLUE, COLOR_OVERLAY_RED, DRAG_THRESHOLD};
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
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;
|
||||
@@ -512,7 +513,7 @@ impl TextToolData {
|
||||
document
|
||||
.metadata()
|
||||
.all_layers()
|
||||
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text"))
|
||||
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)))
|
||||
.find(|&layer| {
|
||||
let transformed_quad = document.metadata().transform_to_viewport(layer) * text_bounding_box(layer, document, font_cache);
|
||||
let mouse = DVec2::new(input.mouse.position.x, input.mouse.position.y);
|
||||
@@ -541,7 +542,7 @@ fn can_edit_selected(document: &DocumentMessageHandler) -> Option<LayerNodeIdent
|
||||
return None;
|
||||
}
|
||||
|
||||
if !is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") {
|
||||
if !is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -610,7 +611,7 @@ impl Fsm for TextToolFsmState {
|
||||
// TODO: implement bounding box for multiple layers
|
||||
let selected = document.network_interface.selected_nodes();
|
||||
let mut all_layers = selected.selected_visible_and_unlocked_layers(&document.network_interface);
|
||||
let layer = all_layers.find(|layer| is_layer_fed_by_node_of_name(*layer, &document.network_interface, "Text"));
|
||||
let layer = all_layers.find(|layer| is_layer_fed_by_node_of_name(*layer, &document.network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)));
|
||||
let bounds = layer.map(|layer| text_bounding_box(layer, document, font_cache));
|
||||
let layer_transform = layer.map(|layer| document.metadata().transform_to_viewport(layer)).unwrap_or(DAffine2::IDENTITY);
|
||||
|
||||
@@ -671,7 +672,7 @@ impl Fsm for TextToolFsmState {
|
||||
|
||||
let selected = document.network_interface.selected_nodes();
|
||||
let mut all_selected = selected.selected_visible_and_unlocked_layers(&document.network_interface);
|
||||
let selected = all_selected.find(|layer| is_layer_fed_by_node_of_name(*layer, &document.network_interface, "Text"));
|
||||
let selected = all_selected.find(|layer| is_layer_fed_by_node_of_name(*layer, &document.network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)));
|
||||
|
||||
if dragging_bounds.is_some() {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
@@ -710,7 +711,7 @@ impl Fsm for TextToolFsmState {
|
||||
// This ensures the cursor only changes if a layer is selected
|
||||
let selected = document.network_interface.selected_nodes();
|
||||
let mut all_selected = selected.selected_visible_and_unlocked_layers(&document.network_interface);
|
||||
let layer = all_selected.find(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text"));
|
||||
let layer = all_selected.find(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)));
|
||||
|
||||
let mut cursor = tool_data
|
||||
.bounding_box_manager
|
||||
|
||||
@@ -754,6 +754,7 @@ fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &D
|
||||
mod test_transform_layer {
|
||||
use crate::messages::portfolio::document::graph_operation::transform_utils;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
|
||||
use crate::messages::prelude::Message;
|
||||
use crate::messages::tool::transform_layer::transform_layer_message_handler::VectorModificationType;
|
||||
@@ -766,7 +767,7 @@ mod test_transform_layer {
|
||||
let document = editor.active_document();
|
||||
let network_interface = &document.network_interface;
|
||||
let _responses: VecDeque<Message> = VecDeque::new();
|
||||
let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface)?;
|
||||
let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain(&DefinitionIdentifier::Network("Transform".into()), layer, network_interface)?;
|
||||
let document_node = network_interface.document_network().nodes.get(&transform_node_id)?;
|
||||
Some(transform_utils::get_current_transform(&document_node.inputs))
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::application::Editor;
|
||||
use crate::application::set_uuid_seed;
|
||||
use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
||||
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition};
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
use crate::messages::portfolio::utility_types::Platform;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::Key;
|
||||
@@ -307,11 +308,11 @@ impl EditorTestUtils {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn create_node_by_name(&mut self, name: impl Into<String>) -> NodeId {
|
||||
pub async fn create_node_by_name(&mut self, node_type: DefinitionIdentifier) -> NodeId {
|
||||
let node_id = NodeId::new();
|
||||
self.handle_message(NodeGraphMessage::CreateNodeFromContextMenu {
|
||||
node_id: Some(node_id),
|
||||
node_type: name.into(),
|
||||
node_type,
|
||||
xy: None,
|
||||
add_transaction: true,
|
||||
})
|
||||
@@ -340,6 +341,7 @@ pub mod test_prelude {
|
||||
pub use crate::float_eq;
|
||||
pub use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
|
||||
pub use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys;
|
||||
pub use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||
pub use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||
pub use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
pub use crate::messages::prelude::*;
|
||||
|
||||
Reference in New Issue
Block a user