mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Remove serialization from Table<T> and make TaggedValue only store tooling/widget node inputs (#4129)
* Add TaggedValue::TypeDefault to avoid baking placeholder Tables into saved documents * Add TaggedValue::TypeDefault to avoid baking placeholder Tables into saved documents * Migrate empty Vector/Raster/Graphic/Artboard placeholder values to TypeDefault on load Documents written before the TypeDefault mechanism existed have empty Table<Vector>/<Raster>/<Graphic>/<Artboard> values baked into every unwired exposed input. Walk each migrated node's inputs and rewrite any such placeholder NodeInput::Value into the equivalent NodeInput::type_default, so re-saved documents shed the placeholder payloads. Marked with a TODO for eventual removal once enough documents have been re-saved. * Re-save demo artwork * Remove Graphic and Artboard placeholder containers from TaggedValue * Remove Raster placeholder TaggedValue variant * Simplify document migration * Remove Vector placeholder TaggedValue variant * Remove NodeIdTable from the TaggedValue * Remove StringTable from the TaggedValue * Remove F64Table in place of F64Array in TaggedValue * Replace TaggedValue::Color(Table<Color>) with ::Color(Option<Color>) * Replace TaggedValue::GradientTable(Table<GradientStops>) with ::Gradient(GradientStops) * Replace TaggedValue::BrushStrokeTable(Table<BrushStroke>) with ::BrushStrokes(Vec<BrushStroke>) * Make TaggedValue::DocumentNode runtime-only with TypeDefault placeholder * Make TaggedValue::ContextFeatures runtime-only * Remove Serialize/Deserialize from Table<T> * Add a widget for TaggedValue::BrushStrokes to visualize strokes and samples * Define a reusable list of TaggedValue::TypeDefault types for its generated methods * Re-save demo artwork
This commit is contained in:
@@ -29,6 +29,7 @@ use crate::messages::tool::tool_messages::tool_prelude::Key;
|
||||
use crate::messages::tool::utility_types::ToolType;
|
||||
use crate::node_graph_executor::NodeGraphExecutor;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::descriptor;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||
use graphene_std::math::quad::Quad;
|
||||
@@ -1760,12 +1761,7 @@ impl DocumentMessageHandler {
|
||||
}
|
||||
|
||||
pub fn deserialize_document(serialized_content: &str) -> Result<Self, EditorError> {
|
||||
// Walk the document JSON and rewrite any `TaggedValue` variants that have been removed since being released as `"None"` so the document still deserializes.
|
||||
// `migrate_node` then drops the resulting orphan node inputs so the value never reaches graph execution.
|
||||
let mut json_value: serde_json::Value = serde_json::from_str(serialized_content).map_err(|e| EditorError::DocumentDeserialization(e.to_string()))?;
|
||||
graph_craft::document::value::TaggedValue::scrub_removed_variants_from_json(&mut json_value);
|
||||
|
||||
let document_message_handler = serde_json::from_value::<DocumentMessageHandler>(json_value.clone())
|
||||
let document_message_handler = serde_json::from_str::<DocumentMessageHandler>(serialized_content)
|
||||
.or_else(|e| {
|
||||
log::warn!("Failed to directly load document with the following error: {e}. Trying old DocumentMessageHandler.");
|
||||
// TODO: Eventually remove this document upgrade code
|
||||
@@ -1804,7 +1800,7 @@ impl DocumentMessageHandler {
|
||||
pub snapping_state: SnappingState,
|
||||
}
|
||||
|
||||
serde_json::from_value::<OldDocumentMessageHandler>(json_value).map(|old_message_handler| DocumentMessageHandler {
|
||||
serde_json::from_str::<OldDocumentMessageHandler>(serialized_content).map(|old_message_handler| DocumentMessageHandler {
|
||||
network_interface: NodeNetworkInterface::from_old_network(old_message_handler.network),
|
||||
collapsed: old_message_handler.collapsed,
|
||||
commit_hash: old_message_handler.commit_hash,
|
||||
@@ -3349,7 +3345,7 @@ impl DocumentMessageHandler {
|
||||
/// Create a network interface with a single export
|
||||
fn default_document_network_interface() -> NodeNetworkInterface {
|
||||
let mut network_interface = NodeNetworkInterface::default();
|
||||
network_interface.add_export(TaggedValue::Artboard(Default::default()), -1, "", &[]);
|
||||
network_interface.add_export(TaggedValue::TypeDefault(descriptor!(graphene_std::table::Table<graphene_std::Artboard>)), -1, "", &[]);
|
||||
network_interface
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::descriptor;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::renderer::Quad;
|
||||
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::vector::style::{Fill, Gradient, GradientSpreadMethod, GradientStop, GradientStops, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphene_std::{Artboard, Color};
|
||||
|
||||
#[derive(ExtractField)]
|
||||
pub struct GraphOperationMessageContext<'a> {
|
||||
@@ -170,7 +170,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
|
||||
}
|
||||
|
||||
// Set the bottom input of the artboard back to artboard
|
||||
let bottom_input = NodeInput::value(TaggedValue::Artboard(Table::new()), true);
|
||||
let bottom_input = NodeInput::type_default(descriptor!(Table<Artboard>), true);
|
||||
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
|
||||
} else {
|
||||
// We have some non layers (e.g. just a rectangle node). We disconnect the bottom input and connect it to the left input.
|
||||
@@ -178,7 +178,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
|
||||
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 1), primary_input, &[]);
|
||||
|
||||
// Set the bottom input of the artboard back to artboard
|
||||
let bottom_input = NodeInput::value(TaggedValue::Artboard(Table::new()), true);
|
||||
let bottom_input = NodeInput::type_default(descriptor!(Table<Artboard>), true);
|
||||
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::messages::prelude::*;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput};
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete};
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete, descriptor};
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::Image;
|
||||
@@ -15,7 +15,7 @@ use graphene_std::table::Table;
|
||||
use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::vector::style::{Fill, GradientSpreadMethod, GradientType, Stroke};
|
||||
use graphene_std::vector::{GradientStops, PointId, Vector, VectorModification, VectorModificationType};
|
||||
use graphene_std::{Color, Graphic, NodeInputDecleration};
|
||||
use graphene_std::{Artboard, Color, Graphic, NodeInputDecleration};
|
||||
|
||||
#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum TransformIn {
|
||||
@@ -132,11 +132,11 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
/// Creates an artboard as the primary export for the document network.
|
||||
pub fn create_artboard(&mut self, new_id: NodeId, location: DVec2, dimensions: DVec2, background: Color, clip: bool) -> LayerNodeIdentifier {
|
||||
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::type_default(descriptor!(Table<Artboard>), true)),
|
||||
Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(location), false)),
|
||||
Some(NodeInput::value(TaggedValue::DVec2(dimensions), false)),
|
||||
Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(background)), false)),
|
||||
Some(NodeInput::value(TaggedValue::Color(Some(background)), false)),
|
||||
Some(NodeInput::value(TaggedValue::Bool(clip), false)),
|
||||
]);
|
||||
self.network_interface.insert_node(new_id, artboard_node_template, &[]);
|
||||
@@ -147,7 +147,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let boolean = resolve_proto_node_type(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER)
|
||||
.expect("Boolean node does not exist")
|
||||
.node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
|
||||
Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)),
|
||||
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
|
||||
]);
|
||||
|
||||
@@ -157,10 +157,9 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
pub fn insert_blend_data(&mut self, layer: LayerNodeIdentifier, count: f64) -> NodeId {
|
||||
let blend = resolve_network_node_type("Blend").expect("Blend node does not exist").node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::F64(count), false)),
|
||||
]);
|
||||
let blend = resolve_network_node_type("Blend")
|
||||
.expect("Blend node does not exist")
|
||||
.node_template_input_override([Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]);
|
||||
|
||||
let blend_id = NodeId::new();
|
||||
self.network_interface.insert_node(blend_id, blend, &[]);
|
||||
@@ -172,10 +171,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
pub fn insert_morph_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {
|
||||
let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)
|
||||
.expect("Morph node does not exist")
|
||||
.node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
|
||||
Some(NodeInput::value(TaggedValue::F64(0.5), false)),
|
||||
]);
|
||||
.node_template_input_override([Some(NodeInput::type_default(descriptor!(Table<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);
|
||||
|
||||
let morph_id = NodeId::new();
|
||||
self.network_interface.insert_node(morph_id, morph, &[]);
|
||||
@@ -298,10 +294,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
pub fn insert_color_value(&mut self, color: Color, layer: LayerNodeIdentifier) {
|
||||
let color_value = resolve_proto_node_type(graphene_std::math_nodes::color_value::IDENTIFIER)
|
||||
.expect("Color Value node does not exist")
|
||||
.node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::None, false)),
|
||||
Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(color)), false)),
|
||||
]);
|
||||
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::Color(Some(color)), false))]);
|
||||
|
||||
let color_value_id = NodeId::new();
|
||||
self.network_interface.insert_node(color_value_id, color_value, &[]);
|
||||
@@ -427,15 +420,15 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
match &fill {
|
||||
Fill::None => {
|
||||
let input_connector = InputConnector::node(fill_node_id, backup_color_index);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(Table::new()), false), true);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(None), false), true);
|
||||
}
|
||||
Fill::Solid(color) => {
|
||||
let input_connector = InputConnector::node(fill_node_id, backup_color_index);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(Table::new_from_element(*color)), false), true);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(Some(*color)), false), true);
|
||||
}
|
||||
Fill::Gradient(gradient) => {
|
||||
let input_connector = InputConnector::node(fill_node_id, backup_gradient_index);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Gradient(gradient.clone()), false), true);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::FillGradient(gradient.clone()), false), true);
|
||||
}
|
||||
}
|
||||
let input_connector = InputConnector::node(fill_node_id, fill_index);
|
||||
@@ -502,8 +495,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
return;
|
||||
};
|
||||
let input_connector = InputConnector::node(gradient_node_id, graphene_std::math_nodes::gradient_value::GradientInput::INDEX);
|
||||
let stops_table = Table::new_from_element(stops);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientTable(stops_table), false), false);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Gradient(stops), false), false);
|
||||
}
|
||||
|
||||
/// Update the gradient line so its endpoints are at `new_start` and `new_end`.
|
||||
@@ -606,10 +598,8 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
return;
|
||||
};
|
||||
|
||||
let stroke_color = if let Some(color) = stroke.color { Table::new_from_element(color) } else { Table::new() };
|
||||
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::ColorInput::INDEX);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(stroke_color), false), true);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Color(stroke.color), false), true);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::WeightInput::INDEX);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.weight), false), true);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::AlignInput::INDEX);
|
||||
@@ -623,8 +613,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::PaintOrderInput::INDEX);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(stroke.paint_order), false), false);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashLengthsInput::<graphene_std::table::Table<f64>>::INDEX);
|
||||
let dash_lengths_table = stroke.dash_lengths.into_iter().map(graphene_std::table::TableRow::new_from_element).collect();
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64Table(dash_lengths_table), false), true);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64Array(stroke.dash_lengths), false), true);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashOffsetInput::INDEX);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.dash_offset), false), true);
|
||||
}
|
||||
@@ -726,8 +715,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let Some(brush_node_id) = self.existing_proto_node_id(graphene_std::brush::brush::brush::IDENTIFIER, true) else {
|
||||
return;
|
||||
};
|
||||
let strokes_table = strokes.into_iter().map(graphene_std::table::TableRow::new_from_element).collect();
|
||||
self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokeTable(strokes_table), false), false);
|
||||
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: DVec2, dimensions: DVec2) {
|
||||
|
||||
@@ -13,9 +13,9 @@ use crate::messages::prelude::Message;
|
||||
use crate::node_graph_executor::NodeGraphExecutor;
|
||||
use glam::DVec2;
|
||||
use graph_craft::ProtoNodeIdentifier;
|
||||
use graph_craft::concrete;
|
||||
use graph_craft::document::value::*;
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::{concrete, descriptor};
|
||||
use graphene_std::extract_xy::XY;
|
||||
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
|
||||
use graphene_std::raster_types::{CPU, Raster};
|
||||
@@ -205,10 +205,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Graphic(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Graphic(Default::default()), true),
|
||||
],
|
||||
inputs: vec![NodeInput::type_default(descriptor!(Table<Graphic>), true), NodeInput::type_default(descriptor!(Table<Graphic>), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -342,11 +339,11 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Artboard(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Graphic(Default::default()), true),
|
||||
NodeInput::type_default(descriptor!(Table<Artboard>), true),
|
||||
NodeInput::type_default(descriptor!(Table<Graphic>), true),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::new(1920., 1080.)), false),
|
||||
NodeInput::value(TaggedValue::Color(Table::new_from_element(Color::WHITE)), false),
|
||||
NodeInput::value(TaggedValue::Color(Some(Color::WHITE)), false),
|
||||
NodeInput::value(TaggedValue::Bool(true), false),
|
||||
],
|
||||
..Default::default()
|
||||
@@ -576,11 +573,11 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::type_default(descriptor!(Table<Vector>), true),
|
||||
NodeInput::value(TaggedValue::F64(10.), false),
|
||||
NodeInput::value(TaggedValue::Bool(Default::default()), false),
|
||||
NodeInput::value(TaggedValue::InterpolationDistribution(Default::default()), false),
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), false),
|
||||
NodeInput::type_default(descriptor!(Table<Vector>), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
@@ -827,7 +824,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::Vector(Default::default()), true)],
|
||||
inputs: vec![NodeInput::type_default(descriptor!(Table<Vector>), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -1012,7 +1009,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::type_default(descriptor!(Table<Vector>), true),
|
||||
NodeInput::value(
|
||||
TaggedValue::Footprint(Footprint {
|
||||
transform: DAffine2::from_scale_angle_translation(DVec2::new(1000., 1000.), 0., DVec2::new(0., 0.)),
|
||||
@@ -1123,7 +1120,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
inputs: vec![NodeInput::type_default(descriptor!(Table<Raster<CPU>>), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -1278,7 +1275,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::Raster(Default::default()), true)],
|
||||
inputs: vec![NodeInput::type_default(descriptor!(Table<Raster<CPU>>), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -1328,7 +1325,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Extract,
|
||||
inputs: vec![NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true)],
|
||||
inputs: vec![NodeInput::type_default(descriptor!(DocumentNode), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
@@ -1480,7 +1477,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::type_default(descriptor!(Table<Vector>), true),
|
||||
NodeInput::value(TaggedValue::VectorModification(Default::default()), false),
|
||||
],
|
||||
..Default::default()
|
||||
|
||||
@@ -15,22 +15,22 @@ use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graph_craft::{Type, concrete};
|
||||
use graphene_std::ATTR_TRANSFORM;
|
||||
use graphene_std::NodeInputDecleration;
|
||||
use graphene_std::animation::RealTimeMode;
|
||||
use graphene_std::brush::brush_stroke::BrushStroke;
|
||||
use graphene_std::extract_xy::XY;
|
||||
use graphene_std::raster::{
|
||||
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
|
||||
SelectiveColorChoice,
|
||||
};
|
||||
use graphene_std::raster_types::Image;
|
||||
use graphene_std::table::{Table, TableRow};
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::text::{Font, TextAlign};
|
||||
use graphene_std::text_nodes::StringCapitalization;
|
||||
use graphene_std::transform::{Footprint, ReferencePoint, ScaleType, Transform};
|
||||
use graphene_std::vector::misc::BooleanOperation;
|
||||
use graphene_std::vector::misc::{ArcType, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType};
|
||||
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientSpreadMethod, GradientStops, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphene_std::vector::style::{Fill, FillChoice, GradientSpreadMethod, GradientStops, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphene_std::vector::{QRCodeErrorCorrectionLevel, VectorModification};
|
||||
|
||||
pub(crate) fn string_properties(text: &str) -> Vec<LayoutGroup> {
|
||||
@@ -218,6 +218,7 @@ pub(crate) fn property_from_type(
|
||||
Some(x) if x == TypeId::of::<Table<f64>>() => array_of_number_widget(default_info, TextInput::default()).into(),
|
||||
Some(x) if x == TypeId::of::<Table<Color>>() => color_widget(default_info, ColorInput::default().allow_none(true)),
|
||||
Some(x) if x == TypeId::of::<Table<GradientStops>>() => color_widget(default_info, ColorInput::default().allow_none(false)),
|
||||
Some(x) if x == TypeId::of::<Table<BrushStroke>>() => brush_strokes_widget(default_info).into(),
|
||||
// ============
|
||||
// STRUCT TYPES
|
||||
// ============
|
||||
@@ -233,7 +234,6 @@ pub(crate) fn property_from_type(
|
||||
// =========================
|
||||
// AUTO-GENERATED ENUM TYPES
|
||||
// =========================
|
||||
Some(x) if x == TypeId::of::<FillType>() => enum_choice::<FillType>().for_socket(default_info).property_row(),
|
||||
Some(x) if x == TypeId::of::<GradientType>() => enum_choice::<GradientType>().for_socket(default_info).property_row(),
|
||||
Some(x) if x == TypeId::of::<GradientSpreadMethod>() => enum_choice::<GradientSpreadMethod>().for_socket(default_info).property_row(),
|
||||
Some(x) if x == TypeId::of::<RealTimeMode>() => enum_choice::<RealTimeMode>().for_socket(default_info).property_row(),
|
||||
@@ -416,6 +416,33 @@ pub fn vector_modification_widget(parameter_widgets_info: ParameterWidgetsInfo)
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn brush_strokes_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetInstance> {
|
||||
let ParameterWidgetsInfo { document_node, node_id: _, index, .. } = parameter_widgets_info;
|
||||
|
||||
let mut widgets = start_widgets(parameter_widgets_info);
|
||||
|
||||
let Some(document_node) = document_node else { return widgets };
|
||||
let Some(input) = document_node.inputs.get(index) else { return widgets };
|
||||
|
||||
if let Some(TaggedValue::BrushStrokes(strokes)) = input.as_non_exposed_value() {
|
||||
let stroke_count = strokes.len();
|
||||
let sample_count: usize = strokes.iter().map(|s| s.trace.len()).sum();
|
||||
let label = if stroke_count == 0 {
|
||||
"Empty".to_string()
|
||||
} else {
|
||||
format!(
|
||||
"{stroke_count} {} / {sample_count} {}",
|
||||
if stroke_count == 1 { "Stroke" } else { "Strokes" },
|
||||
if sample_count == 1 { "Sample" } else { "Samples" }
|
||||
)
|
||||
};
|
||||
|
||||
widgets.extend_from_slice(&[Separator::new(SeparatorStyle::Unrelated).widget_instance(), TextLabel::new(label).widget_instance()]);
|
||||
}
|
||||
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn image_data_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetInstance> {
|
||||
let ParameterWidgetsInfo { document_node, node_id: _, index, .. } = parameter_widgets_info;
|
||||
|
||||
@@ -774,7 +801,7 @@ pub fn array_of_number_widget(parameter_widgets_info: ParameterWidgetsInfo, text
|
||||
.map(str::parse::<f64>)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.ok()
|
||||
.map(|values| TaggedValue::F64Table(values.into_iter().map(graphene_std::table::TableRow::new_from_element).collect()))
|
||||
.map(TaggedValue::F64Array)
|
||||
};
|
||||
|
||||
let Some(document_node) = document_node else { return Vec::new() };
|
||||
@@ -782,11 +809,11 @@ pub fn array_of_number_widget(parameter_widgets_info: ParameterWidgetsInfo, text
|
||||
log::warn!("A widget failed to be built because its node's input index is invalid.");
|
||||
return vec![];
|
||||
};
|
||||
if let Some(TaggedValue::F64Table(table)) = &input.as_non_exposed_value() {
|
||||
if let Some(TaggedValue::F64Array(values)) = &input.as_non_exposed_value() {
|
||||
widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
text_input
|
||||
.value(table.iter_element_values().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
|
||||
.value(values.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
|
||||
.on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index))
|
||||
.widget_instance(),
|
||||
])
|
||||
@@ -1077,15 +1104,6 @@ pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props:
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
]),
|
||||
Some(&TaggedValue::FVec2(vec2)) => widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
number_props
|
||||
// We use an arbitrary `y` instead of an arbitrary `x` here because the "Grid" node's "Spacing" value's height should be used from rectangular mode when transferred to "Y Spacing" in isometric mode
|
||||
.value(Some(vec2.y as f64))
|
||||
.on_update(update_value(move |x: &NumberInput| TaggedValue::F32(x.value.unwrap() as f32), node_id, index))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
]),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -1144,47 +1162,27 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button:
|
||||
|
||||
// Add the color input
|
||||
match &**tagged_value {
|
||||
TaggedValue::Color(color_table) => widgets.push(
|
||||
TaggedValue::Color(color) => widgets.push(
|
||||
color_button
|
||||
.value(match color_table.element(0) {
|
||||
.value(match color {
|
||||
Some(color) => FillChoice::Solid(*color),
|
||||
None => FillChoice::None,
|
||||
})
|
||||
.on_update(update_value(|input: &ColorInput| TaggedValue::Color(input.value.as_solid()), node_id, index))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
),
|
||||
TaggedValue::Gradient(stops) => widgets.push(
|
||||
color_button
|
||||
.value(FillChoice::Gradient(stops.clone()))
|
||||
.on_update(update_value(
|
||||
|input: &ColorInput| TaggedValue::Color(input.value.as_solid().iter().map(|&color| TableRow::new_from_element(color)).collect()),
|
||||
|input: &ColorInput| TaggedValue::Gradient(input.value.as_gradient().cloned().unwrap_or_default()),
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
),
|
||||
TaggedValue::GradientTable(gradient_table) => {
|
||||
let existing_transform: DAffine2 = gradient_table.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||
|
||||
widgets.push(
|
||||
color_button
|
||||
.value(match gradient_table.element(0) {
|
||||
Some(gradient) => FillChoice::Gradient(gradient.clone()),
|
||||
None => FillChoice::Gradient(GradientStops::default()),
|
||||
})
|
||||
.on_update(update_value(
|
||||
move |input: &ColorInput| {
|
||||
TaggedValue::GradientTable(
|
||||
input
|
||||
.value
|
||||
.as_gradient()
|
||||
.iter()
|
||||
.map(|&gradient| TableRow::new_from_element(gradient.clone()).with_attribute(ATTR_TRANSFORM, existing_transform))
|
||||
.collect(),
|
||||
)
|
||||
},
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
)
|
||||
}
|
||||
x => warn!("Color {x:?}"),
|
||||
}
|
||||
|
||||
@@ -2212,12 +2210,12 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
||||
};
|
||||
let uniform_val = match input.as_non_exposed_value() {
|
||||
Some(TaggedValue::F64(x)) => *x,
|
||||
Some(TaggedValue::F64Table(table)) => table.iter_element_values().copied().next().unwrap_or(0.),
|
||||
Some(TaggedValue::F64Array(values)) => values.first().copied().unwrap_or(0.),
|
||||
_ => 0.,
|
||||
};
|
||||
let individual_val = match input.as_non_exposed_value() {
|
||||
Some(&TaggedValue::F64(x)) => vec![x; 4],
|
||||
Some(TaggedValue::F64Table(table)) => table.iter_element_values().copied().collect(),
|
||||
Some(TaggedValue::F64Array(values)) => values.clone(),
|
||||
_ => vec![0.; 4],
|
||||
};
|
||||
|
||||
@@ -2255,7 +2253,7 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
||||
NodeGraphMessage::SetInputValue {
|
||||
node_id,
|
||||
input_index: CornerRadiusInput::<f64>::INDEX,
|
||||
value: TaggedValue::F64Table(individual_val_for_switch.iter().copied().map(graphene_std::table::TableRow::new_from_element).collect()),
|
||||
value: TaggedValue::F64Array(individual_val_for_switch.clone()),
|
||||
}
|
||||
.into(),
|
||||
]),
|
||||
@@ -2273,7 +2271,7 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
||||
.map(str::parse::<f64>)
|
||||
.collect::<Result<Vec<f64>, _>>()
|
||||
.ok()
|
||||
.map(|values| TaggedValue::F64Table(values.into_iter().take(4).map(graphene_std::table::TableRow::new_from_element).collect()))
|
||||
.map(|values| TaggedValue::F64Array(values.into_iter().take(4).collect()))
|
||||
};
|
||||
TextInput::default()
|
||||
.value(individual_val.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
|
||||
@@ -2444,7 +2442,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
||||
}
|
||||
};
|
||||
|
||||
let (fill, backup_color, backup_gradient) = if let (Some(TaggedValue::Fill(fill)), Some(TaggedValue::Color(backup_color)), Some(TaggedValue::Gradient(backup_gradient))) = (
|
||||
let (fill, backup_color, backup_gradient) = if let (Some(TaggedValue::Fill(fill)), Some(TaggedValue::Color(backup_color)), Some(TaggedValue::FillGradient(backup_gradient))) = (
|
||||
&document_node.inputs[FillInput::<Color>::INDEX].as_value(),
|
||||
&document_node.inputs[BackupColorInput::INDEX].as_value(),
|
||||
&document_node.inputs[BackupGradientInput::INDEX].as_value(),
|
||||
@@ -2454,7 +2452,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
||||
return vec![LayoutGroup::row(widgets_first_row)];
|
||||
};
|
||||
let fill2 = fill.clone();
|
||||
let backup_color_fill: Fill = backup_color.clone().into();
|
||||
let backup_color_fill: Fill = (*backup_color).into();
|
||||
let backup_gradient_fill: Fill = backup_gradient.clone().into();
|
||||
|
||||
match fill {
|
||||
@@ -2491,19 +2489,19 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
||||
Fill::None => NodeGraphMessage::SetInputValue {
|
||||
node_id,
|
||||
input_index: BackupColorInput::INDEX,
|
||||
value: TaggedValue::Color(Table::new()),
|
||||
value: TaggedValue::Color(None),
|
||||
}
|
||||
.into(),
|
||||
Fill::Solid(color) => NodeGraphMessage::SetInputValue {
|
||||
node_id,
|
||||
input_index: BackupColorInput::INDEX,
|
||||
value: TaggedValue::Color(Table::new_from_element(*color)),
|
||||
value: TaggedValue::Color(Some(*color)),
|
||||
}
|
||||
.into(),
|
||||
Fill::Gradient(gradient) => NodeGraphMessage::SetInputValue {
|
||||
node_id,
|
||||
input_index: BackupGradientInput::INDEX,
|
||||
value: TaggedValue::Gradient(gradient.clone()),
|
||||
value: TaggedValue::FillGradient(gradient.clone()),
|
||||
}
|
||||
.into(),
|
||||
},
|
||||
@@ -2635,7 +2633,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
||||
move |_: &()| {
|
||||
let mut new_gradient = gradient_for_backup.clone();
|
||||
new_gradient.spread_method = spread_method;
|
||||
TaggedValue::Gradient(new_gradient)
|
||||
TaggedValue::FillGradient(new_gradient)
|
||||
},
|
||||
node_id,
|
||||
BackupGradientInput::INDEX,
|
||||
@@ -2684,7 +2682,7 @@ pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -
|
||||
};
|
||||
|
||||
let has_dash_lengths = match &document_node.inputs[DashLengthsInput::<Table<f64>>::INDEX].as_value() {
|
||||
Some(TaggedValue::F64Table(table)) => table.is_empty(),
|
||||
Some(TaggedValue::F64Array(values)) => values.is_empty(),
|
||||
_ => true,
|
||||
};
|
||||
let miter_limit_disabled = join_value != &StrokeJoin::Miter;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::Type;
|
||||
use graphene_std::raster_types::{CPU, Raster};
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::{Artboard, Graphic};
|
||||
|
||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
@@ -21,14 +25,19 @@ pub enum FrontendGraphDataType {
|
||||
impl FrontendGraphDataType {
|
||||
pub fn from_type(input: &Type) -> Self {
|
||||
match TaggedValue::from_type_or_none(input) {
|
||||
TaggedValue::U32(_) | TaggedValue::U64(_) | TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::DVec2(_) | TaggedValue::F64Table(_) | TaggedValue::DAffine2(_) => Self::Number,
|
||||
TaggedValue::Artboard(_) => Self::Artboard,
|
||||
TaggedValue::Graphic(_) => Self::Graphic,
|
||||
TaggedValue::Raster(_) => Self::Raster,
|
||||
TaggedValue::Vector(_) => Self::Vector,
|
||||
TaggedValue::U32(_) | TaggedValue::U64(_) | TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::DVec2(_) | TaggedValue::F64Array(_) | TaggedValue::DAffine2(_) => Self::Number,
|
||||
TaggedValue::Color(_) => Self::Color,
|
||||
TaggedValue::Gradient(_) | TaggedValue::GradientTable(_) => Self::Gradient,
|
||||
TaggedValue::String(_) | TaggedValue::StringTable(_) => Self::Typography,
|
||||
TaggedValue::FillGradient(_) | TaggedValue::Gradient(_) => Self::Gradient,
|
||||
TaggedValue::String(_) => Self::Typography,
|
||||
// Types whose `TaggedValue` variant has been removed are routed through `TypeDefault` and identified by the descriptor's type name.
|
||||
TaggedValue::TypeDefault(td) => match td.name.as_ref() {
|
||||
n if n == std::any::type_name::<Table<Graphic>>() => Self::Graphic,
|
||||
n if n == std::any::type_name::<Table<Artboard>>() => Self::Artboard,
|
||||
n if n == std::any::type_name::<Table<Raster<CPU>>>() => Self::Raster,
|
||||
n if n == std::any::type_name::<Table<Vector>>() => Self::Vector,
|
||||
n if n == std::any::type_name::<Table<String>>() => Self::Typography,
|
||||
_ => Self::General,
|
||||
},
|
||||
_ => Self::General,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,11 @@ use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNodeImplementation, InlineRust, NodeInput};
|
||||
use graph_craft::proto::{GraphErrorType, GraphErrors};
|
||||
use graph_craft::{Type, concrete};
|
||||
use graphene_std::raster_types::{CPU, Raster};
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::{Artboard, Graphic};
|
||||
use interpreted_executor::dynamic_executor::{NodeTypes, ResolvedDocumentNodeTypesDelta};
|
||||
use interpreted_executor::node_registry::NODE_REGISTRY;
|
||||
|
||||
@@ -53,16 +57,21 @@ impl TypeSource {
|
||||
};
|
||||
match self.compiled_nested_type() {
|
||||
Some(nested_type) => match TaggedValue::from_type_or_none(nested_type) {
|
||||
TaggedValue::U32(_) | TaggedValue::U64(_) | TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::DVec2(_) | TaggedValue::F64Table(_) | TaggedValue::DAffine2(_) => {
|
||||
TaggedValue::U32(_) | TaggedValue::U64(_) | TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::DVec2(_) | TaggedValue::F64Array(_) | TaggedValue::DAffine2(_) => {
|
||||
FrontendGraphDataType::Number
|
||||
}
|
||||
TaggedValue::Artboard(_) => FrontendGraphDataType::Artboard,
|
||||
TaggedValue::Graphic(_) => FrontendGraphDataType::Graphic,
|
||||
TaggedValue::Raster(_) => FrontendGraphDataType::Raster,
|
||||
TaggedValue::Vector(_) => FrontendGraphDataType::Vector,
|
||||
TaggedValue::Color(_) => FrontendGraphDataType::Color,
|
||||
TaggedValue::Gradient(_) | TaggedValue::GradientTable(_) => FrontendGraphDataType::Gradient,
|
||||
TaggedValue::FillGradient(_) | TaggedValue::Gradient(_) => FrontendGraphDataType::Gradient,
|
||||
TaggedValue::String(_) => FrontendGraphDataType::Typography,
|
||||
// Types whose `TaggedValue` variant has been removed are routed through `TypeDefault` and identified by the descriptor's type name.
|
||||
TaggedValue::TypeDefault(td) => match td.name.as_ref() {
|
||||
n if n == std::any::type_name::<Table<Graphic>>() => FrontendGraphDataType::Graphic,
|
||||
n if n == std::any::type_name::<Table<Artboard>>() => FrontendGraphDataType::Artboard,
|
||||
n if n == std::any::type_name::<Table<Raster<CPU>>>() => FrontendGraphDataType::Raster,
|
||||
n if n == std::any::type_name::<Table<Vector>>() => FrontendGraphDataType::Vector,
|
||||
n if n == std::any::type_name::<Table<String>>() => FrontendGraphDataType::Typography,
|
||||
_ => FrontendGraphDataType::General,
|
||||
},
|
||||
_ => FrontendGraphDataType::General,
|
||||
},
|
||||
None => FrontendGraphDataType::General,
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate, OutputConnector};
|
||||
use crate::messages::prelude::DocumentMessageHandler;
|
||||
use glam::{DVec2, IVec2};
|
||||
use graph_craft::descriptor;
|
||||
use graph_craft::document::DocumentNode;
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue};
|
||||
use graphene_std::ProtoNodeIdentifier;
|
||||
@@ -2089,42 +2090,30 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
.set_input(&InputConnector::node(*node_id, 3), NodeInput::value(TaggedValue::Bool(false), false), network_path);
|
||||
}
|
||||
|
||||
// Migrate Path nodes that stored geometry directly in input 0 (as a Table<Vector>) to instead use a VectorModification in input 1
|
||||
// SVG-import legacy Path nodes baked their geometry at non-exposed input 0; move it to input 1 (the modern slot for VectorModification).
|
||||
// For exposed input 0, any baked value is unused at runtime, so just reset it.
|
||||
if reference == DefinitionIdentifier::Network("Path".into()) {
|
||||
let input_0 = node.inputs.first()?;
|
||||
if let NodeInput::Value { tagged_value, exposed } = input_0
|
||||
&& !exposed
|
||||
&& let TaggedValue::Vector(vector_table) = &**tagged_value
|
||||
&& !vector_table.is_empty()
|
||||
&& let TaggedValue::VectorModification(modification) = &**tagged_value
|
||||
{
|
||||
let vector = vector_table.element(0)?;
|
||||
let modification = Box::new(graphene_std::vector::VectorModification::create_from_vector(vector));
|
||||
let modification = modification.clone();
|
||||
let was_exposed = *exposed;
|
||||
|
||||
// Reset input 0 to the default exposed state
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 0), NodeInput::value(TaggedValue::Vector(Default::default()), true), network_path);
|
||||
document.network_interface.set_input(
|
||||
&InputConnector::node(*node_id, 0),
|
||||
NodeInput::type_default(descriptor!(graphene_std::table::Table<graphene_std::vector::Vector>), true),
|
||||
network_path,
|
||||
);
|
||||
|
||||
// Store the converted VectorModification in input 1
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::VectorModification(modification), false), network_path);
|
||||
if !was_exposed {
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::VectorModification(modification), false), network_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate Image nodes that stored a Table<Raster<CPU>> in input 1 to instead use bare Image<Color> via TaggedValue::ImageData
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
|
||||
&& let Some(NodeInput::Value { tagged_value, .. }) = node.inputs.get(1)
|
||||
&& let TaggedValue::Raster(raster_table) = &**tagged_value
|
||||
&& let Some(element) = raster_table.element(0)
|
||||
{
|
||||
let image = element.data().clone();
|
||||
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::ImageData(image), false), network_path);
|
||||
}
|
||||
|
||||
// ==================================
|
||||
// PUT ALL MIGRATIONS ABOVE THIS LINE
|
||||
// ==================================
|
||||
|
||||
@@ -282,13 +282,13 @@ pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI
|
||||
Some(gradient.clone())
|
||||
}
|
||||
|
||||
/// Get the gradient table of a layer.
|
||||
pub fn get_gradient_table(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Table<GradientStops>> {
|
||||
/// Get the gradient stops of a layer, if any.
|
||||
pub fn get_gradient_stops(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<GradientStops> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::gradient_value::IDENTIFIER))?;
|
||||
let TaggedValue::GradientTable(gradient_table) = inputs.get(graphene_std::math_nodes::gradient_value::GradientInput::INDEX)?.as_value()? else {
|
||||
let TaggedValue::Gradient(stops) = inputs.get(graphene_std::math_nodes::gradient_value::GradientInput::INDEX)?.as_value()? else {
|
||||
return None;
|
||||
};
|
||||
Some(gradient_table.clone())
|
||||
Some(stops.clone())
|
||||
}
|
||||
|
||||
/// Compute the transform from a gradient's local space to viewport space for the given layer. For a `Table<GradientStops>`
|
||||
|
||||
@@ -321,8 +321,8 @@ impl BrushToolData {
|
||||
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::brush::brush::brush::IDENTIFIER) && node_id != layer.to_node() {
|
||||
let points_input = node.inputs.get(1)?;
|
||||
let Some(TaggedValue::BrushStrokeTable(strokes)) = points_input.as_value() else { continue };
|
||||
self.strokes = strokes.iter_element_values().cloned().collect();
|
||||
let Some(TaggedValue::BrushStrokes(strokes)) = points_input.as_value() else { continue };
|
||||
self.strokes = strokes.clone();
|
||||
|
||||
return Some(layer);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::messages::portfolio::document::overlays::utility_types::{GizmoEmphasi
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeNetworkInterface};
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer, get_gradient_table};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer, get_gradient_stops};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::raster::color::Color;
|
||||
@@ -336,10 +336,9 @@ fn gradient_space_transform(layer: LayerNodeIdentifier, document: &DocumentMessa
|
||||
graph_modification_utils::gradient_space_transform(layer, &document.network_interface)
|
||||
}
|
||||
|
||||
// TODO: Remove this whole function once all gradients are `Table<GradientStops>`
|
||||
// TODO: Remove this whole function once all gradients are stored via the modern `Gradient(GradientStops)` slot
|
||||
fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Gradient> {
|
||||
if let Some(stops_table) = get_gradient_table(layer, network_interface) {
|
||||
let stops = stops_table.element(0).cloned().unwrap_or_default();
|
||||
if let Some(stops) = get_gradient_stops(layer, network_interface) {
|
||||
let GradientChainState {
|
||||
transform,
|
||||
gradient_type,
|
||||
@@ -505,7 +504,7 @@ fn calculate_insertion(start: DVec2, end: DVec2, stops: &GradientStops, mouse: D
|
||||
impl SelectedGradient {
|
||||
pub fn new(gradient: Gradient, layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Self {
|
||||
let transform = gradient_space_transform(layer, document);
|
||||
let is_gradient_table = get_gradient_table(layer, &document.network_interface).is_some();
|
||||
let is_gradient_table = get_gradient_stops(layer, &document.network_interface).is_some();
|
||||
Self {
|
||||
layer: Some(layer),
|
||||
transform,
|
||||
@@ -1243,7 +1242,7 @@ impl Fsm for GradientToolFsmState {
|
||||
for layer in document.network_interface.selected_nodes().selected_visible_layers(&document.network_interface) {
|
||||
let Some(gradient) = get_gradient(layer, &document.network_interface) else { continue };
|
||||
let transform = gradient_space_transform(layer, document);
|
||||
let is_gradient_table = get_gradient_table(layer, &document.network_interface).is_some();
|
||||
let is_gradient_table = get_gradient_stops(layer, &document.network_interface).is_some();
|
||||
|
||||
// Check for dragging a midpoint diamond
|
||||
if drag_hint.is_none() {
|
||||
@@ -1385,7 +1384,7 @@ impl Fsm for GradientToolFsmState {
|
||||
.network_interface
|
||||
.selected_nodes()
|
||||
.selected_visible_layers(&document.network_interface)
|
||||
.find(|&layer| get_gradient_table(layer, &document.network_interface).is_some())
|
||||
.find(|&layer| get_gradient_stops(layer, &document.network_interface).is_some())
|
||||
});
|
||||
|
||||
// Apply the gradient to the selected layer
|
||||
@@ -1750,7 +1749,7 @@ fn apply_gradient_update(
|
||||
|
||||
// Only check for the gradient table once we know we'll write back, since this is a graph traversal per layer
|
||||
// TODO: Drop the `Fill::Gradient` branch when all gradients become `Table<GradientStops>`
|
||||
if get_gradient_table(layer, &context.document.network_interface).is_some() {
|
||||
if get_gradient_stops(layer, &context.document.network_interface).is_some() {
|
||||
dispatch_gradient_writes(layer, &gradient, responses);
|
||||
} else {
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
@@ -1791,7 +1790,7 @@ fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessa
|
||||
continue;
|
||||
}
|
||||
|
||||
if get_gradient_table(layer, &context.document.network_interface).is_some() {
|
||||
if get_gradient_stops(layer, &context.document.network_interface).is_some() {
|
||||
responses.add(GraphOperationMessage::GradientStopsSet { layer, stops: stops.clone() });
|
||||
} else if let Some(mut gradient) = get_gradient(layer, &context.document.network_interface) {
|
||||
gradient.stops = stops.clone();
|
||||
@@ -1887,8 +1886,6 @@ mod test_gradient {
|
||||
pub use crate::test_utils::test_prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::ATTR_TRANSFORM;
|
||||
use graphene_std::table::{Table, TableRow};
|
||||
use graphene_std::vector::style::{Fill, Gradient};
|
||||
use graphene_std::vector::{GradientStop, GradientStops, fill};
|
||||
|
||||
@@ -1953,21 +1950,18 @@ mod test_gradient {
|
||||
.handle_message(NodeGraphMessage::SetInputValue {
|
||||
node_id: gradient_node_id,
|
||||
input_index: 1,
|
||||
value: TaggedValue::GradientTable(Table::new_from_row(
|
||||
TableRow::new_from_element(GradientStops::new([
|
||||
GradientStop {
|
||||
position: 0.,
|
||||
midpoint: 0.5,
|
||||
color: Color::RED,
|
||||
},
|
||||
GradientStop {
|
||||
position: 1.,
|
||||
midpoint: 0.5,
|
||||
color: Color::BLUE,
|
||||
},
|
||||
]))
|
||||
.with_attribute(ATTR_TRANSFORM, DAffine2::IDENTITY),
|
||||
)),
|
||||
value: TaggedValue::Gradient(GradientStops::new([
|
||||
GradientStop {
|
||||
position: 0.,
|
||||
midpoint: 0.5,
|
||||
color: Color::RED,
|
||||
},
|
||||
GradientStop {
|
||||
position: 1.,
|
||||
midpoint: 0.5,
|
||||
color: Color::BLUE,
|
||||
},
|
||||
])),
|
||||
})
|
||||
.await;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user