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:
Keavon Chambers
2026-05-08 16:11:25 -07:00
committed by GitHub
parent d97fe835b5
commit cb21e5960b
35 changed files with 615 additions and 937 deletions
@@ -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;