From e0f317e67e750babbd6336977ccdf1b0c91f5762 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 15 Jul 2025 02:44:36 -0700 Subject: [PATCH] Old value node migrations --- .../node_graph/document_node_definitions.rs | 160 +++++++++++++++++- .../document/node_graph/node_properties.rs | 12 +- .../utility_types/network_interface.rs | 34 ++-- .../messages/portfolio/document_migration.rs | 76 +++++---- .../floating-menus/NodeCatalog.svelte | 5 +- node-graph/gcore/src/structural.rs | 6 +- node-graph/gcore/src/value.rs | 30 ---- node-graph/gmath-nodes/src/lib.rs | 52 +----- node-graph/graph-craft/src/document/value.rs | 20 ++- 9 files changed, 258 insertions(+), 137 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index 2ae8d8c748..a89de42564 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -104,7 +104,7 @@ fn static_nodes() -> Vec { }, DocumentNodeDefinition { identifier: "Value", - category: "General", + category: "Value", node_template: NodeTemplate { document_node: DocumentNode { implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), @@ -113,12 +113,164 @@ fn static_nodes() -> Vec { ..Default::default() }, persistent_node_metadata: DocumentNodePersistentMetadata { - input_metadata: vec![("", "Value").into()], + input_metadata: vec![("Value", "").into()], output_names: vec!["Out".to_string()], ..Default::default() }, }, - description: Cow::Borrowed("Returns the value stored in its input"), + description: Cow::Borrowed("Construct any value using the dropdown menu."), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "Number Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::F64(0.), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Constructs a number which can be set to any real number"), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "Percentage Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::Percentage(0.), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Constructs a decimal value between 0 and 1."), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "Number Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::U32(0), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Constructs a positive integer value."), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "Bool Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::Bool(true), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Constructs a value which can be true or false"), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "String Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::Percentage(0.), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Constructs a string value which can be set to any plain text."), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "Coordinate Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::DVec2(DVec2::new(0., 0.)), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Constructs a string value which can be set to any plain text."), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "Color Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::OptionalColor(None), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed("Constructs a color value which may to set to any color, or no color"), + properties: Some("value_properties"), + }, + DocumentNodeDefinition { + identifier: "Gradient Value", + category: "Value", + node_template: NodeTemplate { + document_node: DocumentNode { + implementation: DocumentNodeImplementation::ProtoNode(ops::identity::IDENTIFIER), + manual_composition: Some(generic!(T)), + inputs: vec![NodeInput::value(TaggedValue::OptionalColor(None), false)], + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + input_metadata: vec![("Value", "").into()], + output_names: vec!["Out".to_string()], + ..Default::default() + }, + }, + description: Cow::Borrowed(" Constructs a gradient value which may be set to any sequence of color stops to represent the transition between colors."), properties: Some("value_properties"), }, // TODO: Auto-generate this from its proto node macro @@ -936,7 +1088,7 @@ fn static_nodes() -> Vec { }, }, description: Cow::Borrowed( - "Decomposes the X and Y components of a 2D coordinate.\n\nThe inverse of this node is \"Coordinate Value\", which can have either or both its X and Y exposed as graph inputs.", + "Decomposes the X and Y components of a 2D coordinate.\n\nThe inverse of this node is \"Coordinate from Numbers\", which can have either or both its X and Y exposed as graph inputs.", ), properties: None, }, diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 5116e65cb3..c935f36242 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -256,7 +256,6 @@ pub(crate) fn property_from_type( Type::Fn(_, out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, exposable, context), Type::Future(out) => return property_from_type(node_id, index, out, number_options, unit, display_decimal_places, step, exposable, context), }; - extra_widgets.push(widgets); Ok(extra_widgets) @@ -840,6 +839,17 @@ pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: .on_commit(commit_value) .widget_holder(), ]), + Some(&TaggedValue::Percentage(x)) => widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + number_props + .percentage() + .min(0.) + .max(100.) + .value(Some(x)) + .on_update(update_value(move |x: &NumberInput| TaggedValue::Percentage(x.value.unwrap()), node_id, index)) + .on_commit(commit_value) + .widget_holder(), + ]), Some(&TaggedValue::U32(x)) => widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), number_props diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index 9a96be9f7f..b2d277f984 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -4087,20 +4087,32 @@ impl NodeNetworkInterface { self.unload_stack_dependents(network_path); } - /// Replaces the implementation and corresponding metadata. - pub fn replace_implementation(&mut self, node_id: &NodeId, network_path: &[NodeId], new_template: &mut NodeTemplate) { + pub fn set_implementation(&mut self, node_id: &NodeId, network_path: &[NodeId], implementation: DocumentNodeImplementation) { let Some(network) = self.network_mut(network_path) else { - log::error!("Could not get nested network in set_implementation"); + log::error!("Could not get nested network in replace_implementation"); return; }; let Some(node) = network.nodes.get_mut(node_id) else { - log::error!("Could not get node in set_implementation"); + log::error!("Could not get node in replace_implementation"); + return; + }; + node.implementation = implementation; + } + + /// Replaces the implementation and corresponding metadata. + pub fn replace_implementation(&mut self, node_id: &NodeId, network_path: &[NodeId], new_template: &mut NodeTemplate) { + let Some(network) = self.network_mut(network_path) else { + log::error!("Could not get nested network in replace_implementation"); + return; + }; + let Some(node) = network.nodes.get_mut(node_id) else { + log::error!("Could not get node in replace_implementation"); return; }; let new_implementation = std::mem::take(&mut new_template.document_node.implementation); let _ = std::mem::replace(&mut node.implementation, new_implementation); let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { - log::error!("Could not get metadata in set_implementation"); + log::error!("Could not get metadata in replace_implementation"); return; }; let new_metadata = std::mem::take(&mut new_template.persistent_node_metadata.network_metadata); @@ -4110,17 +4122,17 @@ impl NodeNetworkInterface { /// Replaces the inputs and corresponding metadata. pub fn replace_inputs(&mut self, node_id: &NodeId, network_path: &[NodeId], new_template: &mut NodeTemplate) -> Option> { let Some(network) = self.network_mut(network_path) else { - log::error!("Could not get nested network in set_implementation"); + log::error!("Could not get nested network in replace_inputs"); return None; }; let Some(node) = network.nodes.get_mut(node_id) else { - log::error!("Could not get node in set_implementation"); + log::error!("Could not get node in replace_inputs"); return None; }; let new_inputs = std::mem::take(&mut new_template.document_node.inputs); let old_inputs = std::mem::replace(&mut node.inputs, new_inputs); let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { - log::error!("Could not get metadata in set_implementation"); + log::error!("Could not get metadata in replace_inputs"); return None; }; let new_metadata = std::mem::take(&mut new_template.persistent_node_metadata.input_metadata); @@ -4177,13 +4189,13 @@ impl NodeNetworkInterface { } /// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts - pub fn set_manual_compostion(&mut self, node_id: &NodeId, network_path: &[NodeId], manual_composition: Option) { + pub fn set_manual_composition(&mut self, node_id: &NodeId, network_path: &[NodeId], manual_composition: Option) { let Some(network) = self.network_mut(network_path) else { - log::error!("Could not get nested network in set_implementation"); + log::error!("Could not get nested network in set_manual_composition"); return; }; let Some(node) = network.nodes.get_mut(node_id) else { - log::error!("Could not get node in set_implementation"); + log::error!("Could not get node in set_manual_composition"); return; }; node.manual_composition = manual_composition; diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index a55d63ff53..a6dc4f9acf 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -173,42 +173,10 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ node: graphene_std::math_nodes::logical_not::IDENTIFIER, aliases: &["graphene_core::ops::LogicalNotNode", "graphene_core::ops::LogicOrNode", "graphene_core::logic::LogicOrNode"], }, - NodeReplacement { - node: graphene_std::math_nodes::bool_value::IDENTIFIER, - aliases: &["graphene_core::ops::BoolValueNode"], - }, - NodeReplacement { - node: graphene_std::math_nodes::number_value::IDENTIFIER, - aliases: &["graphene_core::ops::NumberValueNode"], - }, - NodeReplacement { - node: graphene_std::math_nodes::percentage_value::IDENTIFIER, - aliases: &["graphene_core::ops::PercentageValueNode"], - }, - NodeReplacement { - node: graphene_std::math_nodes::coordinate_value::IDENTIFIER, - aliases: &[ - "graphene_core::ops::CoordinateValueNode", - "graphene_core::ops::ConstructVector2", - "graphene_core::ops::Vector2ValueNode", - ], - }, - NodeReplacement { - node: graphene_std::math_nodes::color_value::IDENTIFIER, - aliases: &["graphene_core::ops::ColorValueNode"], - }, - NodeReplacement { - node: graphene_std::math_nodes::gradient_value::IDENTIFIER, - aliases: &["graphene_core::ops::GradientValueNode"], - }, NodeReplacement { node: graphene_std::math_nodes::sample_gradient::IDENTIFIER, aliases: &["graphene_core::ops::SampleGradientNode"], }, - NodeReplacement { - node: graphene_std::math_nodes::string_value::IDENTIFIER, - aliases: &["graphene_core::ops::StringValueNode"], - }, NodeReplacement { node: graphene_std::math_nodes::dot_product::IDENTIFIER, aliases: &["graphene_core::ops::DotProductNode"], @@ -510,7 +478,7 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_ let mut default_template = NodeTemplate::default(); default_template.document_node.implementation = DocumentNodeImplementation::ProtoNode(new.clone()); document.network_interface.replace_implementation(node_id, &network_path, &mut default_template); - document.network_interface.set_manual_compostion(node_id, &network_path, Some(graph_craft::Type::Generic("T".into()))); + document.network_interface.set_manual_composition(node_id, &network_path, Some(graph_craft::Type::Generic("T".into()))); } } } @@ -539,7 +507,45 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], if node.manual_composition == Some(graph_craft::concrete!(())) || node.manual_composition == Some(graph_craft::concrete!(graphene_std::transform::Footprint)) { document .network_interface - .set_manual_compostion(node_id, network_path, graph_craft::concrete!(graphene_std::Context).into()); + .set_manual_composition(node_id, network_path, graph_craft::concrete!(graphene_std::Context).into()); + } + + // Update old value nodes after https://github.com/GraphiteEditor/Graphite/pull/2822 + if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = &node.implementation { + let value_node_names = [ + "graphene_math_nodes::BoolValueNode", + "graphene_math_nodes::ColorValueNode", + "graphene_math_nodes::PercentageValueNode", + "graphene_math_nodes::NumberValueNode", + "graphene_math_nodes::StringValueNode", + "graphene_math_nodes::GradientValueNode", + ]; + if value_node_names.iter().any(|&s| s == name) { + let mut template = resolve_document_node_type("Value")?.default_node_template(); + document.network_interface.replace_implementation(node_id, &network_path, &mut template); + let mut old_inputs = document.network_interface.replace_inputs(node_id, &network_path, &mut template)?; + document.network_interface.set_reference(node_id, network_path, Some("Value".to_string())); + if name == "graphene_math_nodes::PercentageValueNode" { + if let NodeInput::Value { tagged_value, .. } = &old_inputs[1] { + if let TaggedValue::F64(value) = &**tagged_value { + old_inputs[1] = NodeInput::value(TaggedValue::Percentage(*value), false); + } + } + } + // Only migrate value inputs, if its a wire the value is unknown. + if let NodeInput::Value { tagged_value, .. } = old_inputs[1].clone() { + document + .network_interface + .set_input(&InputConnector::node(*node_id, 0), NodeInput::value(tagged_value.into_inner(), false), network_path); + } + } else if name == "graphene_math_nodes::CoordinateValueNode" { + document.network_interface.set_implementation( + node_id, + &network_path, + DocumentNodeImplementation::ProtoNode(graphene_std::math_nodes::coordinate_from_numbers::IDENTIFIER), + ); + document.network_interface.set_reference(node_id, network_path, Some("Coordinate From Numbers".to_string())) + } } // Only nodes that have not been modified and still refer to a definition can be updated @@ -1007,7 +1013,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], // Ensure layers are positioned as stacks if they are upstream siblings of another layer document.network_interface.load_structure(); - let all_layers = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::>(); + let all_layers: Vec = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::>(); for layer in all_layers { let (downstream_node, input_index) = document .network_interface diff --git a/frontend/src/components/floating-menus/NodeCatalog.svelte b/frontend/src/components/floating-menus/NodeCatalog.svelte index a0f2cbe241..65b867004c 100644 --- a/frontend/src/components/floating-menus/NodeCatalog.svelte +++ b/frontend/src/components/floating-menus/NodeCatalog.svelte @@ -54,7 +54,10 @@ // Quick and dirty hack to alias "Layer" to "Merge" in the search const layerAliasMatch = node.name === "Merge" && "layer".includes(term); - return nameMatch || categoryMatch || layerAliasMatch; + // Alias "Identity" to "Pass Through" + const identityAliasMatch = node.name === "Pass Through" && "identity".includes(term); + + return nameMatch || categoryMatch || layerAliasMatch || identityAliasMatch; }); } diff --git a/node-graph/gcore/src/structural.rs b/node-graph/gcore/src/structural.rs index b6488c573c..cdba7eade4 100644 --- a/node-graph/gcore/src/structural.rs +++ b/node-graph/gcore/src/structural.rs @@ -128,11 +128,11 @@ impl<'i, Root: Node<'i, I>, I: 'i + From<()>> ConsNode { mod test { use super::*; use crate::generic::FnNode; - use crate::value::ValueNode; + use crate::value::ClonedNode; #[test] fn compose() { - let value = ValueNode::new(4u32); + let value = ClonedNode::new(4u32); let compose = value.then(FnNode::new(|x| x)); assert_eq!(compose.eval(()), &4u32); let type_erased = &compose as &dyn Node<'_, (), Output = &'_ u32>; @@ -141,7 +141,7 @@ mod test { #[test] fn test_ref_eval() { - let value = ValueNode::new(5); + let value = ClonedNode::new(5); assert_eq!(value.eval(()), &5); let id = FnNode::new(|x| x); diff --git a/node-graph/gcore/src/value.rs b/node-graph/gcore/src/value.rs index 185aa22dd2..9f38a2c92f 100644 --- a/node-graph/gcore/src/value.rs +++ b/node-graph/gcore/src/value.rs @@ -13,29 +13,6 @@ impl<'i, const N: u32, I> Node<'i, I> for IntNode { } } -#[derive(Default, Debug, Clone, Copy)] -pub struct ValueNode(pub T); - -impl<'i, T: 'i, I> Node<'i, I> for ValueNode { - type Output = &'i T; - #[inline(always)] - fn eval(&'i self, _input: I) -> Self::Output { - &self.0 - } -} - -impl ValueNode { - pub const fn new(value: T) -> ValueNode { - ValueNode(value) - } -} - -impl From for ValueNode { - fn from(value: T) -> Self { - ValueNode::new(value) - } -} - #[derive(Default, Debug, Clone, Copy)] pub struct AsRefNode, U>(pub T, PhantomData); @@ -192,13 +169,6 @@ mod test { assert_eq!(node.eval(()), 5); } #[test] - fn test_value_node() { - let node = ValueNode::new(5); - assert_eq!(node.eval(()), &5); - let type_erased = &node as &dyn for<'a> Node<'a, (), Output = &'a i32>; - assert_eq!(type_erased.eval(()), &5); - } - #[test] fn test_default_node() { let node = DefaultNode::::new(); assert_eq!(node.eval(42), 0); diff --git a/node-graph/gmath-nodes/src/lib.rs b/node-graph/gmath-nodes/src/lib.rs index f79bc88684..730c0f3211 100644 --- a/node-graph/gmath-nodes/src/lib.rs +++ b/node-graph/gmath-nodes/src/lib.rs @@ -1,5 +1,6 @@ use glam::{DAffine2, DVec2}; use graphene_core::gradient::GradientStops; +use graphene_core::registry::types::Fraction; use graphene_core::registry::types::{Fraction, Percentage, PixelSize, TextArea}; use graphene_core::transform::Footprint; use graphene_core::{Color, Ctx, num_traits}; @@ -633,35 +634,7 @@ fn logical_not( !input } -/// Constructs a bool value which may be set to true or false. -#[node_macro::node(category("Value"))] -fn bool_value(_: impl Ctx, _primary: (), #[name("Bool")] bool_value: bool) -> bool { - bool_value -} - -/// Constructs a number value which may be set to any real number. -#[node_macro::node(category("Value"))] -fn number_value(_: impl Ctx, _primary: (), number: f64) -> f64 { - number -} - -/// Constructs a number value which may be set to any value from 0% to 100% by dragging the slider. -#[node_macro::node(category("Value"))] -fn percentage_value(_: impl Ctx, _primary: (), percentage: Percentage) -> f64 { - percentage -} - /// Constructs a two-dimensional vector value which may be set to any XY coordinate. -#[node_macro::node(category("Value"))] -fn coordinate_value(_: impl Ctx, _primary: (), x: f64, y: f64) -> DVec2 { - DVec2::new(x, y) -} - -/// Constructs a color value which may be set to any color, or no color. -#[node_macro::node(category("Value"))] -fn color_value(_: impl Ctx, _primary: (), #[default(Color::BLACK)] color: Option) -> Option { - color -} /// Gets the color at the specified position along the gradient, given a position from 0 (left) to 1 (right). #[node_macro::node(category("Color"))] @@ -670,26 +643,9 @@ fn sample_gradient(_: impl Ctx, _primary: (), gradient: GradientStops, position: gradient.evaluate(position) } -/// Constructs a gradient value which may be set to any sequence of color stops to represent the transition between colors. -#[node_macro::node(category("Value"))] -fn gradient_value(_: impl Ctx, _primary: (), gradient: GradientStops) -> GradientStops { - gradient -} - -/// Constructs a string value which may be set to any plain text. -#[node_macro::node(category("Value"))] -fn string_value(_: impl Ctx, _primary: (), string: TextArea) -> String { - string -} - -/// Constructs a footprint value which may be set to any transformation of a unit square describing a render area, and a render resolution at least 1x1 integer pixels. -#[node_macro::node(category("Value"))] -fn footprint_value(_: impl Ctx, _primary: (), transform: DAffine2, #[default(100., 100.)] resolution: PixelSize) -> Footprint { - Footprint { - transform, - resolution: resolution.max(DVec2::ONE).as_uvec2(), - ..Default::default() - } +#[node_macro::node(category("Math: Vector"))] +fn coordinate_from_numbers(_: impl Ctx, _primary: (), #[expose] x: f64, #[expose] y: f64) -> DVec2 { + DVec2::new(x, y) } #[node_macro::node(category("Math: Vector"))] diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index a7b142226a..3bcecc8aed 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -9,6 +9,7 @@ use graphene_brush::brush_cache::BrushCache; use graphene_brush::brush_stroke::BrushStroke; use graphene_core::raster::Image; use graphene_core::raster_types::CPU; +use graphene_core::registry::types::Percentage; use graphene_core::registry::{ChoiceTypeStatic, ChoiceWidgetHint, VariantMetadata}; use graphene_core::transform::ReferencePoint; use graphene_core::uuid::NodeId; @@ -21,7 +22,6 @@ use std::hash::Hash; use std::marker::PhantomData; use std::str::FromStr; pub use std::sync::Arc; - pub struct TaggedValueTypeError; /// Macro to generate the tagged value enum. @@ -32,6 +32,7 @@ macro_rules! tagged_value { #[allow(clippy::large_enum_variant)] // TODO(TrueDoctor): Properly solve this disparity between the size of the largest and next largest variants pub enum TaggedValue { None, + Percentage(Percentage), $( $(#[$meta] ) *$identifier( $ty ), )* RenderOutput(RenderOutput), SurfaceFrame(SurfaceFrame), @@ -43,6 +44,7 @@ macro_rules! tagged_value { #[repr(u32)] pub enum TaggedValueChoice { None, + Percentage, $($identifier,)* } @@ -50,12 +52,14 @@ macro_rules! tagged_value { pub fn to_tagged_value(&self) -> TaggedValue { match self { TaggedValueChoice::None => TaggedValue::None, + TaggedValueChoice::Percentage => TaggedValue::Percentage(0.), $(TaggedValueChoice::$identifier => TaggedValue::$identifier(Default::default()),)* } } pub fn from_tagged_value(value: &TaggedValue) -> Option { match value { TaggedValue::None => Some(TaggedValueChoice::None), + TaggedValue::Percentage(_) => Some(TaggedValueChoice::Percentage), $( TaggedValue::$identifier(_) => Some(TaggedValueChoice::$identifier), )* _ => None } @@ -71,7 +75,7 @@ macro_rules! tagged_value { const COUNT: usize = 0 $( + one!($identifier) )*; // Define static array of (choice, metadata) tuples - static VALUES: [(TaggedValueChoice, VariantMetadata); 1 + COUNT] = [ + static VALUES: [(TaggedValueChoice, VariantMetadata); 2 + COUNT] = [ (TaggedValueChoice::None, VariantMetadata { name: Cow::Borrowed(stringify!(None)), @@ -79,6 +83,12 @@ macro_rules! tagged_value { docstring: None, icon: None, }), + (TaggedValueChoice::Percentage, VariantMetadata { + name: Cow::Borrowed(stringify!(Percentage)), + label: Cow::Borrowed(stringify!(Percentage)), + docstring: None, + icon: None, + }), $( (TaggedValueChoice::$identifier, VariantMetadata { name: Cow::Borrowed(stringify!($identifier)), @@ -105,6 +115,7 @@ macro_rules! tagged_value { core::mem::discriminant(self).hash(state); match self { Self::None => {} + Self::Percentage(x) => {x.hash(state)}, $( Self::$identifier(x) => {x.hash(state)}),* Self::RenderOutput(x) => x.hash(state), Self::SurfaceFrame(x) => x.hash(state), @@ -117,6 +128,7 @@ macro_rules! tagged_value { pub fn to_dynany(self) -> DAny<'a> { match self { Self::None => Box::new(()), + Self::Percentage(x) => Box::new(x), $( Self::$identifier(x) => Box::new(x), )* Self::RenderOutput(x) => Box::new(x), Self::SurfaceFrame(x) => Box::new(x), @@ -127,6 +139,7 @@ macro_rules! tagged_value { pub fn to_any(self) -> Arc { match self { Self::None => Arc::new(()), + Self::Percentage(x) => Arc::new(x), $( Self::$identifier(x) => Arc::new(x), )* Self::RenderOutput(x) => Arc::new(x), Self::SurfaceFrame(x) => Arc::new(x), @@ -137,6 +150,7 @@ macro_rules! tagged_value { pub fn ty(&self) -> Type { match self { Self::None => concrete!(()), + Self::Percentage(_) => concrete!(Percentage), $( Self::$identifier(_) => concrete!($ty), )* Self::RenderOutput(_) => concrete!(RenderOutput), Self::SurfaceFrame(_) => concrete!(SurfaceFrame), @@ -153,8 +167,6 @@ macro_rules! tagged_value { $( x if x == TypeId::of::<$ty>() => Ok(TaggedValue::$identifier(*downcast(input).unwrap())), )* x if x == TypeId::of::() => Ok(TaggedValue::RenderOutput(*downcast(input).unwrap())), x if x == TypeId::of::() => Ok(TaggedValue::SurfaceFrame(*downcast(input).unwrap())), - - _ => Err(format!("Cannot convert {:?} to TaggedValue", DynAny::type_name(input.as_ref()))), } }