mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Old value node migrations
This commit is contained in:
@@ -104,7 +104,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
},
|
||||
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<DocumentNodeDefinition> {
|
||||
..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<DocumentNodeDefinition> {
|
||||
},
|
||||
},
|
||||
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,
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Vec<NodeInput>> {
|
||||
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<Type>) {
|
||||
pub fn set_manual_composition(&mut self, node_id: &NodeId, network_path: &[NodeId], manual_composition: Option<Type>) {
|
||||
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;
|
||||
|
||||
@@ -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::<Vec<_>>();
|
||||
let all_layers: Vec<LayerNodeIdentifier> = LayerNodeIdentifier::ROOT_PARENT.descendants(document.network_interface.document_metadata()).collect::<Vec<_>>();
|
||||
for layer in all_layers {
|
||||
let (downstream_node, input_index) = document
|
||||
.network_interface
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -128,11 +128,11 @@ impl<'i, Root: Node<'i, I>, I: 'i + From<()>> ConsNode<I, Root> {
|
||||
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);
|
||||
|
||||
@@ -13,29 +13,6 @@ impl<'i, const N: u32, I> Node<'i, I> for IntNode<N> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub struct ValueNode<T>(pub T);
|
||||
|
||||
impl<'i, T: 'i, I> Node<'i, I> for ValueNode<T> {
|
||||
type Output = &'i T;
|
||||
#[inline(always)]
|
||||
fn eval(&'i self, _input: I) -> Self::Output {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValueNode<T> {
|
||||
pub const fn new(value: T) -> ValueNode<T> {
|
||||
ValueNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for ValueNode<T> {
|
||||
fn from(value: T) -> Self {
|
||||
ValueNode::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub struct AsRefNode<T: AsRef<U>, U>(pub T, PhantomData<U>);
|
||||
|
||||
@@ -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::<u32>::new();
|
||||
assert_eq!(node.eval(42), 0);
|
||||
|
||||
@@ -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<Color>) -> Option<Color> {
|
||||
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"))]
|
||||
|
||||
@@ -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<Self> {
|
||||
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<dyn std::any::Any + Send + Sync + 'static> {
|
||||
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::<RenderOutput>() => Ok(TaggedValue::RenderOutput(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<SurfaceFrame>() => Ok(TaggedValue::SurfaceFrame(*downcast(input).unwrap())),
|
||||
|
||||
|
||||
_ => Err(format!("Cannot convert {:?} to TaggedValue", DynAny::type_name(input.as_ref()))),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user