From d5e31c23bbd4d18fbcd49068f2c329dcd602769f Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Tue, 4 Aug 2026 05:15:21 -0700 Subject: [PATCH] Rename spread method to gradient spread so it matches the other gradient attribute names (#4404) * Rename spread method to gradient spread so it matches the other gradient attribute names * Keep the legacy gradient struct's spread method field name matching its on-disk key --- .../color_picker/color_picker_message.rs | 6 +- .../color_picker_message_handler.rs | 38 +++--- .../data_panel/data_panel_message_handler.rs | 12 +- .../graph_operation_message.rs | 8 +- .../graph_operation_message_handler.rs | 26 ++-- .../document/graph_operation/utility_types.rs | 18 +-- .../document/node_graph/node_properties.rs | 18 +-- .../storage_tests/round_trip_tests.rs | 14 +- .../messages/portfolio/document_migration.rs | 40 +++--- .../graph_modification_utils.rs | 10 +- .../tool/tool_messages/gradient_tool.rs | 120 +++++++++--------- node-graph/graph-craft/src/document/value.rs | 23 ++-- node-graph/libraries/core-types/src/list.rs | 2 +- node-graph/libraries/graphic-types/src/lib.rs | 2 +- .../libraries/rendering/src/render_ext.rs | 14 +- .../libraries/rendering/src/renderer.rs | 30 ++--- .../libraries/vector-types/src/gradient.rs | 64 +++++----- node-graph/libraries/vector-types/src/lib.rs | 4 +- .../libraries/vector-types/src/markers.rs | 8 +- node-graph/nodes/graphic/src/graphic.rs | 6 +- node-graph/nodes/math/src/lib.rs | 10 +- node-graph/nodes/path-bool/src/lib.rs | 8 +- node-graph/nodes/raster/src/gradient_map.rs | 4 +- 23 files changed, 245 insertions(+), 240 deletions(-) diff --git a/editor/src/messages/color_picker/color_picker_message.rs b/editor/src/messages/color_picker/color_picker_message.rs index 7cd658e820..ab7ab9a296 100644 --- a/editor/src/messages/color_picker/color_picker_message.rs +++ b/editor/src/messages/color_picker/color_picker_message.rs @@ -1,6 +1,6 @@ use crate::messages::layout::utility_types::widgets::input_widgets::{SpectrumInputUpdate, VisualColorPickersInputUpdate}; use crate::messages::prelude::*; -use graphene_std::vector::style::{FillChoice, GradientSpreadMethod}; +use graphene_std::vector::style::{FillChoice, GradientSpread}; /// Identifies which RGB channel a numeric input change targets. #[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] @@ -47,8 +47,8 @@ pub enum ColorPickerMessage { /// `SpectrumInput` change: marker move/insert/delete, midpoint move/reset, or active marker selection changed. GradientUpdate { update: SpectrumInputUpdate }, - /// Spread method choice from the gradient "Ends" selection. - SetSpreadMethod { spread_method: GradientSpreadMethod }, + /// Gradient spread choice from the gradient "Ends" selection. + SetGradientSpread { gradient_spread: GradientSpread }, /// Tell the frontend to start an undo transaction (forwarded as a `FrontendMessage` it bridges out to the picker's parent). StartTransaction, diff --git a/editor/src/messages/color_picker/color_picker_message_handler.rs b/editor/src/messages/color_picker/color_picker_message_handler.rs index 31ed4ef464..a74ec14cd9 100644 --- a/editor/src/messages/color_picker/color_picker_message_handler.rs +++ b/editor/src/messages/color_picker/color_picker_message_handler.rs @@ -5,7 +5,7 @@ use crate::messages::prelude::*; use graphene_std::Color; use graphene_std::color::SRGBA8; use graphene_std::core_types::misc::parse_css_color; -use graphene_std::vector::style::{FillChoice, Gradient, GradientRamp, GradientSpreadMethod, GradientStops}; +use graphene_std::vector::style::{FillChoice, Gradient, GradientRamp, GradientSpread, GradientStops}; /// Bounds for a midpoint position (relative to the interval between two adjacent gradient stops). const MIN_MIDPOINT: f64 = 0.01; @@ -29,7 +29,7 @@ pub struct ColorPickerMessageHandler { // When set, the picker is editing a gradient: the visual pickers and inputs target the active stop's color. gradient: Option, - spread_method: GradientSpreadMethod, + gradient_spread: GradientSpread, active_marker_index: Option, active_marker_is_midpoint: bool, @@ -51,7 +51,7 @@ impl Default for ColorPickerMessageHandler { old_alpha: 1., old_is_none: true, gradient: None, - spread_method: GradientSpreadMethod::default(), + gradient_spread: GradientSpread::default(), active_marker_index: None, active_marker_is_midpoint: false, allow_none: true, @@ -72,13 +72,13 @@ impl MessageHandler for ColorPickerMessageHandler { FillChoice::None => { self.set_new_hsva(0., 0., 0., 1., true); self.gradient = None; - self.spread_method = GradientSpreadMethod::default(); + self.gradient_spread = GradientSpread::default(); self.active_marker_index = None; self.active_marker_is_midpoint = false; } FillChoice::Solid(color) => { self.gradient = None; - self.spread_method = GradientSpreadMethod::default(); + self.gradient_spread = GradientSpread::default(); self.active_marker_index = None; self.active_marker_is_midpoint = false; self.adopt_color(color); @@ -86,7 +86,7 @@ impl MessageHandler for ColorPickerMessageHandler { FillChoice::Gradient(ramp) => { self.active_marker_index = Some(0); self.active_marker_is_midpoint = false; - self.spread_method = ramp.spread_method; + self.gradient_spread = ramp.gradient_spread; let gradient = Gradient::from(ramp); let first_color = gradient.color(0).unwrap_or(Color::BLACK); self.gradient = Some(gradient); @@ -192,13 +192,13 @@ impl MessageHandler for ColorPickerMessageHandler { self.send_layouts(responses); } ColorPickerMessage::GradientUpdate { update } => self.apply_gradient_update(update, responses), - ColorPickerMessage::SetSpreadMethod { spread_method } => { + ColorPickerMessage::SetGradientSpread { gradient_spread } => { let Some(gradient) = &self.gradient else { return }; responses.add(FrontendMessage::ColorPickerStartHistoryTransaction); - self.spread_method = spread_method; + self.gradient_spread = gradient_spread; responses.add(FrontendMessage::ColorPickerColorChanged { value: FillChoice::Gradient(GradientRamp { - spread_method, + gradient_spread, ..GradientRamp::from(gradient) }), }); @@ -289,7 +289,7 @@ impl ColorPickerMessageHandler { gradient.set_color(active_index as usize, color); responses.add(FrontendMessage::ColorPickerColorChanged { value: FillChoice::Gradient(GradientRamp { - spread_method: self.spread_method, + gradient_spread: self.gradient_spread, ..GradientRamp::from(&*gradient) }), }); @@ -419,7 +419,7 @@ impl ColorPickerMessageHandler { responses.add(FrontendMessage::ColorPickerColorChanged { value: FillChoice::Gradient(GradientRamp { - spread_method: self.spread_method, + gradient_spread: self.gradient_spread, ..GradientRamp::from(&gradient) }), }); @@ -621,21 +621,21 @@ impl ColorPickerMessageHandler { .widget_instance(), ])); - // Gradient ends spread method (only present when the picker is in gradient mode) + // Gradient spread (only present when the picker is in gradient mode) if self.gradient.is_some() { - let entries = [GradientSpreadMethod::Pad, GradientSpreadMethod::Reflect, GradientSpreadMethod::Repeat] + let entries = [GradientSpread::Pad, GradientSpread::Reflect, GradientSpread::Repeat] .into_iter() - .map(|spread_method| { - RadioEntryData::new(format!("{spread_method:?}")) - .label(spread_method.to_string()) - .on_update(move |_| ColorPickerMessage::SetSpreadMethod { spread_method }.into()) + .map(|gradient_spread| { + RadioEntryData::new(format!("{gradient_spread:?}")) + .label(gradient_spread.to_string()) + .on_update(move |_| ColorPickerMessage::SetGradientSpread { gradient_spread }.into()) }) .collect(); groups.push(LayoutGroup::row(vec![ - TextLabel::new("Ends").tooltip_label("Spread Method").tooltip_description(ENDS_DESCRIPTION).widget_instance(), + TextLabel::new("Ends").tooltip_label("Gradient Spread").tooltip_description(ENDS_DESCRIPTION).widget_instance(), Separator::new(SeparatorStyle::Related).widget_instance(), - RadioInput::new(entries).selected_index(Some(self.spread_method as u32)).disabled(self.disabled).widget_instance(), + RadioInput::new(entries).selected_index(Some(self.gradient_spread as u32)).disabled(self.disabled).widget_instance(), ])); } diff --git a/editor/src/messages/portfolio/document/data_panel/data_panel_message_handler.rs b/editor/src/messages/portfolio/document/data_panel/data_panel_message_handler.rs index d33e6f2754..54215d72df 100644 --- a/editor/src/messages/portfolio/document/data_panel/data_panel_message_handler.rs +++ b/editor/src/messages/portfolio/document/data_panel/data_panel_message_handler.rs @@ -23,7 +23,7 @@ use graphene_std::transform::{ReferencePoint, ScaleType}; use graphene_std::vector::misc::{ ArcType, BooleanOperation, BoxCorners, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType, }; -use graphene_std::vector::style::{DashPattern, FillChoice, GradientRamp, GradientSpreadMethod, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin}; +use graphene_std::vector::style::{DashPattern, FillChoice, GradientRamp, GradientSpread, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin}; use graphene_std::vector::{QRCodeErrorCorrectionLevel, Vector}; use graphene_std::{Artboard, Color, Graphic}; use std::any::Any; @@ -217,7 +217,7 @@ fn generate_layout(introspected_data: &Arc, List, List, - List, + List, List, List, List, @@ -270,7 +270,7 @@ fn generate_layout(introspected_data: &Arc, data: &mut Lay } /// Type-dispatched recursion into an attribute value for the Data panel breadcrumb navigation. -/// Mirrors [`dispatch_value_widget`] but routes to [`TableItemLayout::layout_with_breadcrumb`]. +/// Mirrors [`dispatch_value_widgets`] but routes to [`TableItemLayout::layout_with_breadcrumb`]. /// Returns `None` for unrecognized types. fn drilldown_attribute_layout(any: &dyn Any, data: &mut LayoutData) -> Option> { // `List` is interpreted as a path (e.g. the `editor:layer_path` attribute), so each item's NodeId value diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs index 8ef3f3827e..131a8036fe 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs @@ -10,7 +10,7 @@ use graphene_std::raster::BlendMode; use graphene_std::raster_types::Image; use graphene_std::subpath::Subpath; use graphene_std::text::{Font, TypesettingConfig}; -use graphene_std::vector::style::{GradientSpreadMethod, GradientType, Stroke}; +use graphene_std::vector::style::{GradientSpread, GradientType, Stroke}; use graphene_std::vector::{Gradient, PointId, VectorModificationType}; #[impl_message(Message, DocumentMessage, GraphOperation)] @@ -25,7 +25,7 @@ pub enum GraphOperationMessage { #[serde(skip)] gradient: Gradient, gradient_type: GradientType, - spread_method: GradientSpreadMethod, + gradient_spread: GradientSpread, transform: DAffine2, }, BlendingFillSet { @@ -53,9 +53,9 @@ pub enum GraphOperationMessage { layer: LayerNodeIdentifier, gradient_type: GradientType, }, - GradientSpreadMethodSet { + GradientSpreadSet { layer: LayerNodeIdentifier, - spread_method: GradientSpreadMethod, + gradient_spread: GradientSpread, }, OpacitySet { layer: LayerNodeIdentifier, diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index 7711987f45..cb95d9f955 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -14,7 +14,7 @@ use graph_craft::document::{NodeId, NodeInput}; use graphene_std::list::List; use graphene_std::renderer::convert_usvg_path::convert_usvg_path; use graphene_std::text::{Font, TypesettingConfig}; -use graphene_std::vector::style::{Gradient, GradientSpreadMethod, GradientStop, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin}; +use graphene_std::vector::style::{Gradient, GradientSpread, GradientStop, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin}; use graphene_std::{Artboard, Color}; #[derive(ExtractField)] @@ -44,11 +44,11 @@ impl MessageHandler> for layer, gradient, gradient_type, - spread_method, + gradient_spread, transform, } => { if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { - modify_inputs.fill_gradient_set(gradient, gradient_type, spread_method, transform); + modify_inputs.fill_gradient_set(gradient, gradient_type, gradient_spread, transform); } } GraphOperationMessage::BlendingFillSet { layer, fill } => { @@ -81,9 +81,9 @@ impl MessageHandler> for modify_inputs.gradient_type_set(gradient_type); } } - GraphOperationMessage::GradientSpreadMethodSet { layer, spread_method } => { + GraphOperationMessage::GradientSpreadSet { layer, gradient_spread } => { if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) { - modify_inputs.gradient_spread_method_set(spread_method); + modify_inputs.gradient_spread_set(gradient_spread); } } GraphOperationMessage::OpacitySet { layer, opacity } => { @@ -806,11 +806,11 @@ fn apply_usvg_stroke(stroke: &usvg::Stroke, modify_inputs: &mut ModifyInputsCont } } -fn convert_spread_method(spread_method: usvg::SpreadMethod) -> GradientSpreadMethod { +fn convert_gradient_spread(spread_method: usvg::SpreadMethod) -> GradientSpread { match spread_method { - usvg::SpreadMethod::Pad => GradientSpreadMethod::Pad, - usvg::SpreadMethod::Reflect => GradientSpreadMethod::Reflect, - usvg::SpreadMethod::Repeat => GradientSpreadMethod::Repeat, + usvg::SpreadMethod::Pad => GradientSpread::Pad, + usvg::SpreadMethod::Reflect => GradientSpread::Reflect, + usvg::SpreadMethod::Repeat => GradientSpread::Repeat, } } @@ -837,8 +837,8 @@ fn apply_usvg_fill(fill: &usvg::Fill, modify_inputs: &mut ModifyInputsContext, g Gradient::new(stops) } }; - let spread_method = convert_spread_method(linear.spread_method()); - modify_inputs.fill_gradient_set(gradient, gradient_type, spread_method, transform); + let gradient_spread = convert_gradient_spread(linear.spread_method()); + modify_inputs.fill_gradient_set(gradient, gradient_type, gradient_spread, transform); } usvg::Paint::RadialGradient(radial) => { let gradient_transform = usvg_transform(radial.transform()); @@ -861,9 +861,9 @@ fn apply_usvg_fill(fill: &usvg::Fill, modify_inputs: &mut ModifyInputsContext, g Gradient::new(stops) } }; - let spread_method = convert_spread_method(radial.spread_method()); + let gradient_spread = convert_gradient_spread(radial.spread_method()); - modify_inputs.fill_gradient_set(gradient, gradient_type, spread_method, transform); + modify_inputs.fill_gradient_set(gradient, gradient_type, gradient_spread, transform); } usvg::Paint::Pattern(_) => warn!("SVG patterns are not currently supported"), }; diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index 9e5948eeb7..781409a368 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -17,7 +17,7 @@ use graphene_std::raster::BlendMode; use graphene_std::raster_types::Image; use graphene_std::subpath::Subpath; use graphene_std::text::{Font, TypesettingConfig}; -use graphene_std::vector::style::{GradientSpreadMethod, GradientType, Stroke}; +use graphene_std::vector::style::{GradientSpread, GradientType, Stroke}; use graphene_std::vector::{Gradient, GradientRamp, PointId, Vector, VectorModification, VectorModificationType}; use graphene_std::{Artboard, Color, Graphic}; @@ -404,14 +404,14 @@ impl<'a> ModifyInputsContext<'a> { self.set_input_with_refresh(input_connector, NodeInput::value(fill_value, false), false); } - pub fn fill_gradient_set(&mut self, gradient: Gradient, gradient_type: GradientType, spread_method: GradientSpreadMethod, transform: DAffine2) { + pub fn fill_gradient_set(&mut self, gradient: Gradient, gradient_type: GradientType, gradient_spread: GradientSpread, transform: DAffine2) { let Some(fill_node_id) = self.existing_proto_node_id(graphene_std::vector_nodes::fill::IDENTIFIER, true) else { return; }; let backup_input_connector = InputConnector::node(fill_node_id, graphene_std::vector::fill::BackupGradientInput); let ramp = GradientRamp::from(gradient); - let ramp = GradientRamp { spread_method, ..ramp }; + let ramp = GradientRamp { gradient_spread, ..ramp }; self.set_input_with_refresh(backup_input_connector, NodeInput::value(TaggedValue::GradientRamp(ramp.clone()), false), true); // Skip the rerender on all but the last input so the whole update triggers a single graph run @@ -677,20 +677,20 @@ impl<'a> ModifyInputsContext<'a> { self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientType(gradient_type), false), false); } - /// Write the spread method to the last 'Spread Method' node in the chain, inserting one only when the value differs + /// Write the gradient spread to the last 'Gradient Spread' node in the chain, inserting one only when the value differs /// from the default (`Pad`). - pub fn gradient_spread_method_set(&mut self, spread_method: GradientSpreadMethod) { + pub fn gradient_spread_set(&mut self, gradient_spread: GradientSpread) { let Some(output_layer) = self.get_output_layer() else { return }; let target_input = gradient_chain_target_input(output_layer, self.network_interface); - let identifier = graphene_std::math_nodes::spread_method::IDENTIFIER; - let create_if_nonexistent = spread_method != GradientSpreadMethod::default(); + let identifier = graphene_std::math_nodes::gradient_spread::IDENTIFIER; + let create_if_nonexistent = gradient_spread != GradientSpread::default(); let Some(node_id) = self.existing_proto_node_id_at(&target_input, identifier, create_if_nonexistent) else { return; }; - let input_connector = InputConnector::node(node_id, graphene_std::math_nodes::spread_method::SpreadMethodInput); - self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientSpreadMethod(spread_method), false), false); + let input_connector = InputConnector::node(node_id, graphene_std::math_nodes::gradient_spread::GradientSpreadInput); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientSpread(gradient_spread), false), false); } pub fn clip_mode_toggle(&mut self, clip_mode: Option) { 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 ad48a5b395..c1206bfbd7 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -34,7 +34,7 @@ use graphene_std::vector::misc::{ ArcType, BoxCorners, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType, }; use graphene_std::vector::style::{ - FillChoice, Gradient, GradientRamp, GradientSpreadMethod, GradientStops, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin, build_transform_with_y_preservation, + FillChoice, Gradient, GradientRamp, GradientSpread, GradientStops, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin, build_transform_with_y_preservation, }; use graphene_std::vector::{QRCodeErrorCorrectionLevel, VectorModification}; use graphene_std::{NodeParameter, ParameterRef}; @@ -293,7 +293,7 @@ pub(crate) fn property_from_type( // AUTO-GENERATED ENUM TYPES // ========================= Some(x) if id_is::(x) => enum_choice::().for_socket(default_info).property_row(), - Some(x) if id_is::(x) => enum_choice::().for_socket(default_info).property_row(), + Some(x) if id_is::(x) => enum_choice::().for_socket(default_info).property_row(), Some(x) if id_is::(x) => enum_choice::().for_socket(default_info).property_row(), Some(x) if id_is::(x) => enum_choice::().for_socket(default_info).property_row(), Some(x) if id_is::(x) => enum_choice::().for_socket(default_info).property_row(), @@ -2403,7 +2403,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte Gradient { gradient: Gradient, gradient_type: GradientType, - spread_method: GradientSpreadMethod, + gradient_spread: GradientSpread, transform: DAffine2, /// Whether the transform input holds a plain value (so the "Reverse Direction" button may write to it) rather than a wire. transform_is_value: bool, @@ -2433,7 +2433,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte Some(gradient) => ResolvedFill::Gradient { gradient: gradient.stops, gradient_type: gradient.gradient_type, - spread_method: gradient.spread_method, + gradient_spread: gradient.gradient_spread, transform: gradient.transform, transform_is_value: gradient.transform_is_value, }, @@ -2461,9 +2461,9 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte }; match &fill { - ResolvedFill::Gradient { gradient: stops, spread_method, .. } => { + ResolvedFill::Gradient { gradient: stops, gradient_spread, .. } => { let stops = stops.clone(); - let spread_method = *spread_method; + let gradient_spread = *gradient_spread; let reverse_button = IconButton::new("Reverse", 24) .tooltip_label("Reverse Stops") @@ -2471,7 +2471,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte .on_update(update_value( move |_| { TaggedValue::GradientRamp(GradientRamp { - spread_method, + gradient_spread, ..GradientRamp::from(stops.reversed()) }) }, @@ -2493,8 +2493,8 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte FillChoice::::None } } - ResolvedFill::Gradient { gradient: stops, spread_method, .. } => FillChoice::::Gradient(GradientRamp { - spread_method: *spread_method, + ResolvedFill::Gradient { gradient: stops, gradient_spread, .. } => FillChoice::::Gradient(GradientRamp { + gradient_spread: *gradient_spread, ..GradientRamp::from(stops) }), ResolvedFill::Other => FillChoice::::None, diff --git a/editor/src/messages/portfolio/document/storage_tests/round_trip_tests.rs b/editor/src/messages/portfolio/document/storage_tests/round_trip_tests.rs index ae8d37126b..edb6ee2523 100644 --- a/editor/src/messages/portfolio/document/storage_tests/round_trip_tests.rs +++ b/editor/src/messages/portfolio/document/storage_tests/round_trip_tests.rs @@ -813,11 +813,11 @@ async fn legacy_four_input_fill_migrates_to_the_split_transform_shape() { } #[tokio::test] -async fn eight_input_fill_migrates_spread_method_into_the_ramp() { +async fn eight_input_fill_migrates_the_spread_input_into_the_ramp() { use graph_craft::document::value::TaggedValue; - use graphene_std::vector::style::GradientSpreadMethod; + use graphene_std::vector::style::GradientSpread; - // A minimal document from the era when spread method was the Fill node's own sixth input, here set to Repeat + // A minimal document from the era when the gradient spread was the Fill node's own sixth input (tagged `GradientSpreadMethod`), here set to Repeat const EIGHT_INPUT_DOCUMENT: &str = r#"{"network_interface":{"network":{"exports":[{"Node":{"node_id":1,"output_index":0,"lambda":false}}],"nodes":[[1,{"inputs":[{"Value":{"tagged_value":{"GraphicGroup":{"instance":[],"transform":[],"alpha_blending":[],"source_node_id":[]}},"exposed":true}},{"Value":{"tagged_value":{"GradientRamp":{"stops":{"color":[{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]}}},"exposed":false}},{"Value":{"tagged_value":{"Color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}},"exposed":false}},{"Value":{"tagged_value":{"GradientRamp":{"stops":{"color":[{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},{"red":1.0,"green":1.0,"blue":1.0,"alpha":1.0}]}}},"exposed":false}},{"Value":{"tagged_value":{"GradientType":"Linear"},"exposed":false}},{"Value":{"tagged_value":{"GradientSpreadMethod":"Repeat"},"exposed":false}},{"Value":{"tagged_value":{"Bool":false},"exposed":false}},{"Value":{"tagged_value":{"DAffine2":[1.0,0.0,0.0,1.0,0.0,0.0]},"exposed":false}}],"manual_composition":{"Concrete":{"name":"core::option::Option>","alias":null}},"implementation":{"ProtoNode":{"name":"graphene_core::vector::FillNode"}},"visible":true,"skip_deduplication":false}]],"scope_injections":[]},"network_metadata":{"persistent_metadata":{"node_metadata":[[1,{"persistent_metadata":{"reference":"Fill","display_name":"","input_properties":[{"input_data":{"input_name":"Content"},"widget_override":null},{"input_data":{"input_name":"Fill"},"widget_override":null},{"input_data":{"input_name":"Backup Color"},"widget_override":null},{"input_data":{"input_name":"Backup Gradient"},"widget_override":null},{"input_data":{"input_name":"Gradient Type"},"widget_override":null},{"input_data":{"input_name":"Spread Method"},"widget_override":null},{"input_data":{"input_name":"Has Transform"},"widget_override":null},{"input_data":{"input_name":"Transform"},"widget_override":null}],"output_names":[""],"has_primary_output":true,"locked":false,"pinned":false,"node_type_metadata":{"Node":{"position":{"Absolute":[0,0]}}},"network_metadata":null}}]],"previewing":"No","navigation_metadata":{"node_graph_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"node_graph_to_viewport":[1.0,0.0,0.0,1.0,0.0,0.0],"node_graph_top_right":[0.0,0.0]},"selection_undo_history":[],"selection_redo_history":[]}}},"collapsed":[],"name":"eight_input_fill.graphite","commit_hash":"0000000000000000000000000000000000000000","document_ptz":{"pan":[0.0,0.0],"tilt":0.0,"zoom":1.0,"flip":false},"document_mode":"DesignMode","view_mode":"Normal","overlays_visibility_settings":{"all":true,"artboard_name":true,"compass_rose":true,"quick_measurement":true,"transform_measurement":true,"transform_cage":true,"hover_outline":true,"selection_outline":true,"pivot":true,"path":true,"anchors":true,"handles":true},"rulers_visible":true,"snapping_state":{"snapping_enabled":true,"grid_snapping":false,"artboards":true,"tolerance":8.0,"bounding_box":{"center_point":true,"corner_point":true,"edge_midpoint":true,"align_with_edges":true,"distribute_evenly":true},"path":{"anchor_point":true,"line_midpoint":true,"along_path":true,"normal_to_path":true,"tangent_to_path":true,"path_intersection_point":true,"align_with_anchor_point":true,"perpendicular_from_endpoint":true},"grid":{"origin":[0.0,0.0],"grid_type":{"Rectangular":{"spacing":[1.0,1.0]}},"grid_color":{"red":0.6,"green":0.6,"blue":0.6,"alpha":1.0},"dot_display":false}},"graph_view_overlay_open":false,"graph_fade_artwork_percentage":80.0}"#; // Deserializing alone must succeed, so a failure below is attributable to the migrations @@ -843,17 +843,13 @@ async fn eight_input_fill_migrates_spread_method_into_the_ramp() { let Some(TaggedValue::GradientRamp(ramp)) = paint else { panic!("the fill input should keep its gradient ramp value, but became {paint:?}"); }; - assert_eq!(ramp.spread_method, GradientSpreadMethod::Repeat, "the spread method input's value should fold into the fill ramp"); + assert_eq!(ramp.gradient_spread, GradientSpread::Repeat, "the spread input's value should fold into the fill ramp"); let backup = fill_node.input_value(graphene_std::vector::fill::BackupGradientInput); let Some(TaggedValue::GradientRamp(backup_ramp)) = backup else { panic!("the backup gradient input should keep its gradient ramp value, but became {backup:?}"); }; - assert_eq!( - backup_ramp.spread_method, - GradientSpreadMethod::Repeat, - "the spread method input's value should fold into the backup ramp" - ); + assert_eq!(backup_ramp.gradient_spread, GradientSpread::Repeat, "the spread input's value should fold into the backup ramp"); let has_transform = fill_node.input_value(graphene_std::vector::fill::HasTransformInput); assert!( diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index d835f5ccfb..addfd420ae 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -17,7 +17,7 @@ use graphene_std::text::{TextAlign, TypesettingConfig}; use graphene_std::transform::ScaleType; use graphene_std::uuid::NodeId; use graphene_std::vector::graphic_types; -use graphene_std::vector::style::{GradientRamp, GradientSpreadMethod, PaintOrder, StrokeAlign}; +use graphene_std::vector::style::{GradientRamp, GradientSpread, PaintOrder, StrokeAlign}; use std::collections::HashMap; use std::f64::consts::PI; use std::ops::Range; @@ -168,6 +168,10 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ "graphic_nodes::graphic::ItemAtIndexNode", ], }, + NodeReplacement { + node: graphene_std::graphic::read_gradient_spread_attribute::IDENTIFIER, + aliases: &["graphic_nodes::graphic::ReadAttributeSpreadMethodNode", "graphic_nodes::graphic::ReadSpreadMethodAttributeNode"], + }, NodeReplacement { node: graphene_std::list::remove_at_index::IDENTIFIER, aliases: &["graphic_nodes::graphic::OmitElementNode", "graphic_nodes::graphic::RemoveAtIndexNode"], @@ -265,6 +269,10 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ node: graphene_std::math_nodes::footprint_value::IDENTIFIER, aliases: &["graphene_math_nodes::FootprintValueNode", "graphene_core::ops::FootprintValueNode"], }, + NodeReplacement { + node: graphene_std::math_nodes::gradient_spread::IDENTIFIER, + aliases: &["math_nodes::SpreadMethodNode"], + }, NodeReplacement { node: graphene_std::math_nodes::gradient_value::IDENTIFIER, aliases: &[ @@ -1413,10 +1421,10 @@ fn migrate_corner_radius_input(input: &NodeInput) -> Option { Some(NodeInput::value(TaggedValue::BoxCorners(values), *exposed)) } -/// Rewrites a gradient ramp value input to carry the given spread method, which used to live in the Fill node's retired `_spread_method` input. -fn fold_spread_method_into_ramp_input(input: &NodeInput, spread_method: GradientSpreadMethod) -> NodeInput { +/// Rewrites a gradient ramp value input to carry the given gradient spread, which used to live in the Fill node's retired `_spread_method` input. +fn fold_gradient_spread_into_ramp_input(input: &NodeInput, gradient_spread: GradientSpread) -> NodeInput { match input.as_value() { - Some(TaggedValue::GradientRamp(ramp)) => NodeInput::value(TaggedValue::GradientRamp(GradientRamp { spread_method, ..ramp.clone() }), input.is_exposed()), + Some(TaggedValue::GradientRamp(ramp)) => NodeInput::value(TaggedValue::GradientRamp(GradientRamp { gradient_spread, ..ramp.clone() }), input.is_exposed()), _ => input.clone(), } } @@ -1682,7 +1690,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], graphic_types::migrations::legacy::LegacyFill::None => TaggedValue::no_paint(), graphic_types::migrations::legacy::LegacyFill::Solid(color) => TaggedValue::Color(*color), graphic_types::migrations::legacy::LegacyFill::Gradient(gradient) => TaggedValue::GradientRamp(GradientRamp { - spread_method: gradient.spread_method, + gradient_spread: gradient.spread_method, ..gradient.stops.clone() }), }; @@ -1729,7 +1737,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], &InputConnector::node_at_index(*node_id, 3), NodeInput::value( TaggedValue::GradientRamp(GradientRamp { - spread_method: g.spread_method, + gradient_spread: g.spread_method, ..g.stops.clone() }), false, @@ -1770,20 +1778,20 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], // Fill split its `Option` placement into a `_has_transform` bool immediately before the `_transform` matrix. The modern // shape is also 7 inputs, so this era is identified by its `_spread_method` input at 5 or its optional transform at 6. let is_pre_transform_split_fill = inputs_count == 7 - && (matches!(node.inputs.get(5).and_then(|input| input.as_value()), Some(TaggedValue::GradientSpreadMethod(_))) + && (matches!(node.inputs.get(5).and_then(|input| input.as_value()), Some(TaggedValue::GradientSpread(_))) || matches!(node.inputs.get(6).and_then(|input| input.as_value()), Some(TaggedValue::LegacyOptionalDAffine2(_)))); if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER) && is_pre_transform_split_fill { let mut node_template = resolve_document_node_type(&reference)?.default_node_template(); let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; - let spread_method = match old_inputs.get(5).and_then(|input| input.as_value()) { - Some(&TaggedValue::GradientSpreadMethod(value)) => value, - _ => GradientSpreadMethod::default(), + let gradient_spread = match old_inputs.get(5).and_then(|input| input.as_value()) { + Some(&TaggedValue::GradientSpread(value)) => value, + _ => GradientSpread::default(), }; for (index, input) in old_inputs.iter().enumerate().take(5) { let input = if index == 1 || index == 3 { - fold_spread_method_into_ramp_input(input, spread_method) + fold_gradient_spread_into_ramp_input(input, gradient_spread) } else { input.clone() }; @@ -1814,19 +1822,19 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], inputs_count = 7; } - // The Fill node's `_spread_method` input moved into the `GradientRamp` value's own `spread_method` field + // The Fill node's `_spread_method` input moved into the `GradientRamp` value's own `gradient_spread` field if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER) && inputs_count == 8 { let mut node_template = resolve_document_node_type(&reference)?.default_node_template(); let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; - let spread_method = match old_inputs.get(5).and_then(|input| input.as_value()) { - Some(&TaggedValue::GradientSpreadMethod(value)) => value, - _ => GradientSpreadMethod::default(), + let gradient_spread = match old_inputs.get(5).and_then(|input| input.as_value()) { + Some(&TaggedValue::GradientSpread(value)) => value, + _ => GradientSpread::default(), }; for (index, input) in old_inputs.iter().enumerate().take(5) { let input = if index == 1 || index == 3 { - fold_spread_method_into_ramp_input(input, spread_method) + fold_gradient_spread_into_ramp_input(input, gradient_spread) } else { input.clone() }; diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index e66b4c7a23..8d4df8d4da 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -14,7 +14,7 @@ use graphene_std::subpath::Subpath; use graphene_std::text::{Font, TypesettingConfig}; use graphene_std::vector::misc::ManipulatorPointId; use graphene_std::vector::style::{FillChoice, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin, initial_gradient_transform_for_bounding_box}; -use graphene_std::vector::{Gradient, GradientSpreadMethod, GradientType, PointId, SegmentId, VectorModificationType}; +use graphene_std::vector::{Gradient, GradientSpread, GradientType, PointId, SegmentId, VectorModificationType}; use graphene_std::{NodeParameter, ParameterRef}; use std::collections::VecDeque; @@ -660,7 +660,7 @@ pub fn set_stroke_weight_for_selected_layers(weight: f64, document: &DocumentMes pub struct FillNodeGradient { pub stops: Gradient, pub gradient_type: GradientType, - pub spread_method: GradientSpreadMethod, + pub gradient_spread: GradientSpread, pub transform: DAffine2, /// Whether the transform input holds a plain value (so it may be written to) rather than a wire. pub transform_is_value: bool, @@ -673,7 +673,7 @@ pub fn read_fill_node_gradient(fill_node: &DocumentNode, bounding_box: impl FnOn let TaggedValue::GradientRamp(ramp) = fill_node.input(fill::FillInput)?.as_value()? else { return None; }; - let spread_method = ramp.spread_method; + let gradient_spread = ramp.gradient_spread; let stops = Gradient::from(ramp); let gradient_type = match fill_node.input(fill::GradientTypeInput).and_then(|input| input.as_value()) { Some(&TaggedValue::GradientType(value)) => value, @@ -690,7 +690,7 @@ pub fn read_fill_node_gradient(fill_node: &DocumentNode, bounding_box: impl FnOn Some(FillNodeGradient { stops, gradient_type, - spread_method, + gradient_spread, transform, transform_is_value: transform_input.is_some(), }) @@ -839,7 +839,7 @@ pub fn set_fill_for_selected_layers(fill_choice: FillChoice, document: &Document layer, gradient: Gradient::from(ramp), gradient_type, - spread_method: ramp.spread_method, + gradient_spread: ramp.gradient_spread, transform, }); } diff --git a/editor/src/messages/tool/tool_messages/gradient_tool.rs b/editor/src/messages/tool/tool_messages/gradient_tool.rs index d502cb76f7..e63ae69344 100644 --- a/editor/src/messages/tool/tool_messages/gradient_tool.rs +++ b/editor/src/messages/tool/tool_messages/gradient_tool.rs @@ -16,7 +16,7 @@ use glam::DMat2; use graph_craft::document::value::TaggedValue; use graphene_std::color::SRGBA8; use graphene_std::raster::color::Color; -use graphene_std::vector::style::{FillChoice, Gradient, GradientRamp, GradientSpreadMethod, GradientStop, GradientType, build_transform_with_y_preservation}; +use graphene_std::vector::style::{FillChoice, Gradient, GradientRamp, GradientSpread, GradientStop, GradientType, build_transform_with_y_preservation}; #[derive(Default, ExtractField)] pub struct GradientTool { @@ -28,7 +28,7 @@ pub struct GradientTool { #[derive(Default)] pub struct GradientOptions { gradient_type: GradientType, - spread_method: GradientSpreadMethod, + gradient_spread: GradientSpread, } #[impl_message(Message, ToolMessage, Gradient)] @@ -136,8 +136,8 @@ impl<'a> MessageHandler> for Grad } ToolMessage::Gradient(GradientToolMessage::UpdateRamp { ramp }) => { let ramp = GradientRamp::from(&ramp); - self.options.spread_method = ramp.spread_method; - apply_stops_update(&mut self.data, context, responses, Gradient::from(&ramp), ramp.spread_method); + self.options.gradient_spread = ramp.gradient_spread; + apply_stops_update(&mut self.data, context, responses, Gradient::from(&ramp), ramp.gradient_spread); } ToolMessage::Gradient(GradientToolMessage::CloseStopColorPicker) => { if self.data.color_picker_transaction_open { @@ -171,8 +171,8 @@ impl<'a> MessageHandler> for Grad self.options.gradient_type = appearance.gradient_type; needs_refresh = true; } - if self.options.spread_method != appearance.spread_method { - self.options.spread_method = appearance.spread_method; + if self.options.gradient_spread != appearance.gradient_spread { + self.options.gradient_spread = appearance.gradient_spread; needs_refresh = true; } } @@ -263,7 +263,7 @@ impl LayoutHolder for GradientTool { ]) }); let stops_widget = ColorInput::new(FillChoice::Gradient(GradientRamp { - spread_method: self.options.spread_method, + gradient_spread: self.options.gradient_spread, ..GradientRamp::from(&stops_value) })) .allow_none(false) @@ -363,7 +363,7 @@ fn resolve_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI gradient.stops, GradientAppearance { gradient_type: gradient.gradient_type, - spread_method: gradient.spread_method, + gradient_spread: gradient.gradient_spread, transform: gradient.transform, }, GradientSource::Direct, @@ -382,22 +382,22 @@ fn resolve_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI struct GradientAppearance { transform: DAffine2, gradient_type: GradientType, - spread_method: GradientSpreadMethod, + gradient_spread: GradientSpread, } -/// Resolve the gradient transform, type, and spread method by walking the chain feeding the layer. Transform composes all -/// 'Transform' nodes. Type and spread method come from the closest-to-layer node of each kind, or the type default. +/// Resolve the gradient transform, type, and gradient spread by walking the chain feeding the layer. Transform composes all +/// 'Transform' nodes. Type and gradient spread come from the closest-to-layer node of each kind, or the type default. fn read_gradient_chain_state(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> GradientAppearance { let target_input = gradient_chain_target_input(layer, network_interface); let walk_from = network_interface.upstream_output_connector(&target_input, &[]).and_then(|out| out.node_id()).unwrap_or(layer.to_node()); let transform_reference = DefinitionIdentifier::ProtoNode(graphene_std::transform_nodes::transform::IDENTIFIER); let gradient_type_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::gradient_type::IDENTIFIER); - let spread_method_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::spread_method::IDENTIFIER); + let gradient_spread_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::gradient_spread::IDENTIFIER); let mut transforms_downstream_to_upstream: Vec = Vec::new(); let mut gradient_type: Option = None; - let mut spread_method: Option = None; + let mut gradient_spread: Option = None; for node_id in network_interface .upstream_flow_back_from_nodes(vec![walk_from], &[], FlowType::HorizontalFlow) @@ -416,11 +416,11 @@ fn read_gradient_chain_state(layer: LayerNodeIdentifier, network_interface: &Nod && let Some(TaggedValue::GradientType(value)) = document_node.inputs.get(1).and_then(|input| input.as_value()) { gradient_type = Some(*value); - } else if reference == spread_method_reference - && spread_method.is_none() - && let Some(TaggedValue::GradientSpreadMethod(value)) = document_node.inputs.get(1).and_then(|input| input.as_value()) + } else if reference == gradient_spread_reference + && gradient_spread.is_none() + && let Some(TaggedValue::GradientSpread(value)) = document_node.inputs.get(1).and_then(|input| input.as_value()) { - spread_method = Some(*value); + gradient_spread = Some(*value); } } @@ -430,7 +430,7 @@ fn read_gradient_chain_state(layer: LayerNodeIdentifier, network_interface: &Nod GradientAppearance { transform: composed_transform, gradient_type: gradient_type.unwrap_or_default(), - spread_method: spread_method.unwrap_or_default(), + gradient_spread: gradient_spread.unwrap_or_default(), } } @@ -766,7 +766,7 @@ impl SelectedGradient { layer, gradient: self.gradient.clone(), gradient_type: self.appearance.gradient_type, - spread_method: self.appearance.spread_method, + gradient_spread: self.appearance.gradient_spread, transform: self.appearance.transform, }); } @@ -801,9 +801,9 @@ fn dispatch_gradient_chain_writes(layer: LayerNodeIdentifier, gradient: &Gradien layer, gradient_type: appearance.gradient_type, }); - responses.add(GraphOperationMessage::GradientSpreadMethodSet { + responses.add(GraphOperationMessage::GradientSpreadSet { layer, - spread_method: appearance.spread_method, + gradient_spread: appearance.gradient_spread, }); } @@ -1483,7 +1483,7 @@ impl Fsm for GradientToolFsmState { GradientAppearance { transform: DAffine2::IDENTITY, gradient_type: tool_options.gradient_type, - spread_method: tool_options.spread_method, + gradient_spread: tool_options.gradient_spread, }, GradientSource::Direct, ), @@ -1836,7 +1836,7 @@ fn apply_gradient_update( layer, gradient, gradient_type: appearance.gradient_type, - spread_method: appearance.spread_method, + gradient_spread: appearance.gradient_spread, transform: appearance.transform, }); } @@ -1860,7 +1860,7 @@ fn apply_gradient_update( /// Set new gradient stops on every selected layer's gradient. Unlike `apply_gradient_update`, this doesn't open its own /// transaction so it can be called repeatedly during a color picker drag and have all the changes coalesced into a /// single undo entry by the surrounding 'on_commit' callback. -fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessageContext, responses: &mut VecDeque, new_gradient: Gradient, spread_method: GradientSpreadMethod) { +fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessageContext, responses: &mut VecDeque, new_gradient: Gradient, gradient_spread: GradientSpread) { let selected_layers: Vec<_> = context .document .network_interface @@ -1876,14 +1876,14 @@ fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessa if get_upstream_gradient_value_node_id(layer, &context.document.network_interface).is_some() { responses.add(GraphOperationMessage::GradientStopsSet { layer, stops: new_gradient.clone() }); - responses.add(GraphOperationMessage::GradientSpreadMethodSet { layer, spread_method }); + responses.add(GraphOperationMessage::GradientSpreadSet { layer, gradient_spread }); updated_any_layer = true; } else if let Some((_gradient, appearance, _source)) = resolve_gradient(layer, &context.document.network_interface) { responses.add(GraphOperationMessage::FillGradientSet { layer, gradient: new_gradient.clone(), gradient_type: appearance.gradient_type, - spread_method, + gradient_spread, transform: appearance.transform, }); updated_any_layer = true; @@ -1892,7 +1892,7 @@ fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessa if let Some(selected_gradient) = &mut data.selected_gradient { selected_gradient.gradient = new_gradient.clone(); - selected_gradient.appearance.spread_method = spread_method; + selected_gradient.appearance.gradient_spread = gradient_spread; } // When no selected layer had a gradient to update, the user is editing the tool's default gradient instead. @@ -1989,14 +1989,14 @@ mod test_gradient { use graph_craft::document::NodeInput; use graph_craft::document::value::TaggedValue; use graphene_std::color::SRGBA8; - use graphene_std::vector::style::{GradientSpreadMethod, build_transform_with_y_preservation}; + use graphene_std::vector::style::{GradientSpread, build_transform_with_y_preservation}; use graphene_std::vector::{Gradient, GradientRamp, GradientStop, fill}; use super::gradient_space_transform; struct ResolvedGradient { stops: Gradient, - spread_method: GradientSpreadMethod, + gradient_spread: GradientSpread, transform: DAffine2, } @@ -2004,7 +2004,7 @@ mod test_gradient { fn new(stops: Gradient, appearance: super::GradientAppearance) -> Self { Self { stops, - spread_method: appearance.spread_method, + gradient_spread: appearance.gradient_spread, transform: appearance.transform, } } @@ -2032,8 +2032,8 @@ mod test_gradient { let fill_node_id = get_fill_node_id_with_direct_fill_input(layer, &document.network_interface)?; let fill_node = document.network_interface.document_network().nodes.get(&fill_node_id)?; - let (stops, spread_method) = match fill_node.input(fill::FillInput)?.as_value()? { - TaggedValue::GradientRamp(ramp) => (Gradient::from(ramp), ramp.spread_method), + let (stops, gradient_spread) = match fill_node.input(fill::FillInput)?.as_value()? { + TaggedValue::GradientRamp(ramp) => (Gradient::from(ramp), ramp.gradient_spread), _ => return None, }; @@ -2045,7 +2045,7 @@ mod test_gradient { let gradient = ResolvedGradient { stops, - spread_method, + gradient_spread, transform: local_transform, }; @@ -2573,77 +2573,77 @@ mod test_gradient { assert_eq!(editor.active_document().metadata().all_layers().count(), 0, "Expected the layer to be deleted after drawing a gradient"); } - /// Build the JS-boundary ramp the stops swatch's picker would send when choosing a new spread method. - fn ramp_with_spread(stops: &Gradient, spread_method: GradientSpreadMethod) -> GradientRamp { + /// Build the JS-boundary ramp the stops swatch's picker would send when choosing a new gradient spread. + fn ramp_with_spread(stops: &Gradient, gradient_spread: GradientSpread) -> GradientRamp { GradientRamp::::from(&GradientRamp { - spread_method, + gradient_spread, ..GradientRamp::from(stops) }) } #[tokio::test] - async fn change_spread_method() { + async fn change_gradient_spread() { let mut editor = EditorTestUtils::create(); editor.new_document().await; editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).await; editor.drag_tool(ToolType::Gradient, 10., 10., 90., 90., ModifierKeys::empty()).await; - // Verify default spread method is Pad + // Verify default gradient spread is Pad let (gradient, _) = get_gradient_from_fill(&mut editor).await; - assert_eq!(gradient.spread_method, GradientSpreadMethod::Pad); + assert_eq!(gradient.gradient_spread, GradientSpread::Pad); - // Update spread method to Repeat + // Update the gradient spread to Repeat editor .handle_message(GradientToolMessage::UpdateRamp { - ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Repeat), + ramp: ramp_with_spread(&gradient.stops, GradientSpread::Repeat), }) .await; let (gradient, _) = get_gradient_from_fill(&mut editor).await; - assert_eq!(gradient.spread_method, GradientSpreadMethod::Repeat); + assert_eq!(gradient.gradient_spread, GradientSpread::Repeat); - // Update spread method to Reflect + // Update the gradient spread to Reflect editor .handle_message(GradientToolMessage::UpdateRamp { - ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Reflect), + ramp: ramp_with_spread(&gradient.stops, GradientSpread::Reflect), }) .await; let (gradient, _) = get_gradient_from_fill(&mut editor).await; - assert_eq!(gradient.spread_method, GradientSpreadMethod::Reflect); + assert_eq!(gradient.gradient_spread, GradientSpread::Reflect); } #[tokio::test] - async fn change_spread_method_chain() { + async fn change_gradient_spread_chain() { let mut editor = EditorTestUtils::create(); editor.new_document().await; let layer = create_fill_gradient_chain_layer(&mut editor).await; editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }).await; editor.select_tool(ToolType::Gradient).await; - // Verify default spread method is Pad + // Verify default gradient spread is Pad let (gradient, _) = get_gradient_from_chain(&mut editor).await; - assert_eq!(gradient.spread_method, GradientSpreadMethod::Pad); + assert_eq!(gradient.gradient_spread, GradientSpread::Pad); - // Update spread method to Repeat + // Update the gradient spread to Repeat editor .handle_message(GradientToolMessage::UpdateRamp { - ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Repeat), + ramp: ramp_with_spread(&gradient.stops, GradientSpread::Repeat), }) .await; let (gradient, _) = get_gradient_from_chain(&mut editor).await; - assert_eq!(gradient.spread_method, GradientSpreadMethod::Repeat); + assert_eq!(gradient.gradient_spread, GradientSpread::Repeat); - // Update spread method to Reflect + // Update the gradient spread to Reflect editor .handle_message(GradientToolMessage::UpdateRamp { - ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Reflect), + ramp: ramp_with_spread(&gradient.stops, GradientSpread::Reflect), }) .await; let (gradient, _) = get_gradient_from_chain(&mut editor).await; - assert_eq!(gradient.spread_method, GradientSpreadMethod::Reflect); + assert_eq!(gradient.gradient_spread, GradientSpread::Reflect); } #[tokio::test] @@ -2795,7 +2795,7 @@ mod test_gradient { // graph space rather than stranded at the origin. #[tokio::test] async fn gradient_chain_node_on_fill_secondary_input_takes_feeder_slot() { - use graphene_std::vector::style::GradientSpreadMethod; + use graphene_std::vector::style::GradientSpread; let mut editor = EditorTestUtils::create(); editor.new_document().await; @@ -2852,17 +2852,17 @@ mod test_gradient { .await; let feeder_position = editor.active_document_mut().network_interface.position(&gradient_value_id, &[]).expect("Gradient Value position"); - // Set the spread method through the tool, which splices a 'Spread Method' node onto the Fill's fill input wire. + // Set the gradient spread through the tool, which splices a 'Gradient Spread' node onto the Fill's fill input wire. editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }).await; editor.select_tool(ToolType::Gradient).await; let stops = get_gradient_stops(layer, &editor.active_document().network_interface).expect("the chain layer should resolve its gradient stops"); editor .handle_message(GradientToolMessage::UpdateRamp { - ramp: ramp_with_spread(&stops, GradientSpreadMethod::Reflect), + ramp: ramp_with_spread(&stops, GradientSpread::Reflect), }) .await; - let spread_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::spread_method::IDENTIFIER); + let spread_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::gradient_spread::IDENTIFIER); let spread_node_id = { let network_interface = &editor.active_document().network_interface; network_interface @@ -2871,10 +2871,10 @@ mod test_gradient { .keys() .copied() .find(|node_id| network_interface.reference(node_id, &[]).as_ref() == Some(&spread_reference)) - .expect("Spread Method node should have been inserted") + .expect("Gradient Spread node should have been inserted") }; - let spread_position = editor.active_document_mut().network_interface.position(&spread_node_id, &[]).expect("Spread Method position"); + let spread_position = editor.active_document_mut().network_interface.position(&spread_node_id, &[]).expect("Gradient Spread position"); let feeder_position_after = editor.active_document_mut().network_interface.position(&gradient_value_id, &[]).expect("Gradient Value position after"); assert_eq!(spread_position, feeder_position, "the inserted node should occupy the feeder's former slot, not the graph origin"); diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 5e10981d1c..642934fb66 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -168,11 +168,11 @@ macro_rules! tagged_value { Self::BoxCorners(values) => Box::new(BoxCorners::from(values)), Self::Color(color) => Box::new(List::::new_from_element(color)), Self::GradientRamp(ramp) => { - // The ramp's spread method rides the served list as its attribute, as `Item::from` does on master. - let spread_method = ramp.spread_method; + // The ramp's gradient spread rides the served list as its attribute, as `Item::from` does on master. + let gradient_spread = ramp.gradient_spread; let mut list = List::::new_from_element(Gradient::from(ramp)); - if !spread_method.is_default() { - list.set_attribute(graphic_types::vector_types::ATTR_SPREAD_METHOD, 0, spread_method); + if !gradient_spread.is_default() { + list.set_attribute(graphic_types::vector_types::ATTR_GRADIENT_SPREAD, 0, gradient_spread); } Box::new(list) } @@ -222,11 +222,11 @@ macro_rules! tagged_value { Self::BoxCorners(values) => Arc::new(BoxCorners::from(values)), Self::Color(color) => Arc::new(List::::new_from_element(color)), Self::GradientRamp(ramp) => { - // The ramp's spread method rides the served list as its attribute, as `Item::from` does on master. - let spread_method = ramp.spread_method; + // The ramp's gradient spread rides the served list as its attribute, as `Item::from` does on master. + let gradient_spread = ramp.gradient_spread; let mut list = List::::new_from_element(Gradient::from(ramp)); - if !spread_method.is_default() { - list.set_attribute(graphic_types::vector_types::ATTR_SPREAD_METHOD, 0, spread_method); + if !gradient_spread.is_default() { + list.set_attribute(graphic_types::vector_types::ATTR_GRADIENT_SPREAD, 0, gradient_spread); } Arc::new(list) } @@ -627,7 +627,8 @@ tagged_value! { StrokeAlign(vector::style::StrokeAlign), PaintOrder(vector::style::PaintOrder), GradientType(vector::style::GradientType), - GradientSpreadMethod(vector::style::GradientSpreadMethod), + #[serde(alias = "GradientSpreadMethod")] // TODO: Eventually remove this document upgrade code + GradientSpread(vector::style::GradientSpread), ReferencePoint(vector::ReferencePoint), CentroidType(vector::misc::CentroidType), BooleanOperation(vector::misc::BooleanOperation), @@ -1102,7 +1103,7 @@ mod paint_default_parsing { #[cfg(test)] mod gradient_shape_migration { - use graphic_types::vector_types::GradientSpreadMethod; + use graphic_types::vector_types::GradientSpread; use super::*; @@ -1123,7 +1124,7 @@ mod gradient_shape_migration { let mut gradient = Gradient::from(vec![Color::BLACK, Color::WHITE]); gradient.set_positions(&[0.2, 0.9]); let value = TaggedValue::GradientRamp(GradientRamp { - spread_method: GradientSpreadMethod::Reflect, + gradient_spread: GradientSpread::Reflect, ..GradientRamp::from(gradient) }); diff --git a/node-graph/libraries/core-types/src/list.rs b/node-graph/libraries/core-types/src/list.rs index 1e5bd838f6..0a696519dc 100644 --- a/node-graph/libraries/core-types/src/list.rs +++ b/node-graph/libraries/core-types/src/list.rs @@ -1164,7 +1164,7 @@ impl CacheHash for List { self.element.cache_hash(state); // Hash every attribute attribute (key + values) rather than just the well-known ones, so changes to user-defined keys - // (e.g., gradient_type, spread_method) invalidate downstream graph caches as expected + // (e.g., gradient_type, gradient_spread) invalidate downstream graph caches as expected for (key, attribute) in &self.attributes.attributes { std::hash::Hash::hash(key.as_str(), state); attribute.cache_hash_dyn(state); diff --git a/node-graph/libraries/graphic-types/src/lib.rs b/node-graph/libraries/graphic-types/src/lib.rs index 9cc9f97cf5..b393c7ca8a 100644 --- a/node-graph/libraries/graphic-types/src/lib.rs +++ b/node-graph/libraries/graphic-types/src/lib.rs @@ -36,7 +36,7 @@ pub mod migrations { pub start: DVec2, pub end: DVec2, #[serde(default)] - pub spread_method: vector::style::GradientSpreadMethod, + pub spread_method: vector::style::GradientSpread, #[serde(default)] pub absolute: bool, #[serde(default)] diff --git a/node-graph/libraries/rendering/src/render_ext.rs b/node-graph/libraries/rendering/src/render_ext.rs index d6074c0e89..116e625f02 100644 --- a/node-graph/libraries/rendering/src/render_ext.rs +++ b/node-graph/libraries/rendering/src/render_ext.rs @@ -8,11 +8,11 @@ use core_types::uuid::generate_uuid; use glam::{DAffine2, DVec2}; use graphic_types::Graphic; use graphic_types::vector_types::gradient::GradientType; -use graphic_types::vector_types::markers::{GradientType as GradientTypeAttr, SpreadMethod}; +use graphic_types::vector_types::markers::{GradientSpread as GradientSpreadAttr, GradientType as GradientTypeAttr}; use graphic_types::vector_types::vector::style::{PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin}; use std::fmt::Write; use vector_types::Gradient; -use vector_types::gradient::GradientSpreadMethod; +use vector_types::gradient::GradientSpread; #[derive(Copy, Clone, PartialEq)] pub enum PaintTarget { @@ -110,7 +110,7 @@ pub fn render_gradient_paint let Some(stops) = source.element(0) else { return 0 }; let gradient_type: GradientType = source.attr::(0); let local_gradient_transform: DAffine2 = source.attr::(0); - let spread_method: GradientSpreadMethod = source.attr::(0); + let gradient_spread: GradientSpread = source.attr::(0); for (position, color, original_midpoint) in stops.interpolated_samples() { stop.push_str(" format!(r#" gradientTransform="{gradient_transform}""#) }; - let spread_method = if spread_method == GradientSpreadMethod::Pad { + let gradient_spread = if gradient_spread == GradientSpread::Pad { String::new() } else { - format!(r#" spreadMethod="{}""#, spread_method.svg_name()) + format!(r#" spreadMethod="{}""#, gradient_spread.svg_name()) }; let gradient_id = generate_uuid(); @@ -161,14 +161,14 @@ pub fn render_gradient_paint GradientType::Linear => { let _ = write!( svg_defs, - r#"{}"#, + r#"{}"#, gradient_id, stop ); } GradientType::Radial => { let _ = write!( svg_defs, - r#"{}"#, + r#"{}"#, gradient_id, stop ); } diff --git a/node-graph/libraries/rendering/src/renderer.rs b/node-graph/libraries/rendering/src/renderer.rs index 9b3438c3d4..3cad9baa34 100644 --- a/node-graph/libraries/rendering/src/renderer.rs +++ b/node-graph/libraries/rendering/src/renderer.rs @@ -27,7 +27,7 @@ use graphic_types::graphic::{PaintColumns, PaintOverlay, PaintReach, has_paint, use graphic_types::markers::{EditorMergedLayers, Fill, Stroke}; use graphic_types::raster_types::{BitmapMut, CPU, GPU, Image, Raster, Texture}; use graphic_types::vector_types::gradient::{Gradient, GradientType}; -use graphic_types::vector_types::markers::{GradientType as GradientTypeAttr, SpreadMethod}; +use graphic_types::vector_types::markers::{GradientSpread as GradientSpreadAttr, GradientType as GradientTypeAttr}; use graphic_types::vector_types::subpath::Subpath; use graphic_types::vector_types::vector::click_target::{ClickTarget, FreePoint}; use graphic_types::vector_types::vector::style::{PaintOrder, RenderMode, StrokeAlign, StrokeCap, StrokeJoin}; @@ -44,7 +44,7 @@ use std::hash::Hash; use std::ops::Deref; use std::sync::{Arc, LazyLock}; use text_nodes::markers::{Font, TextAlign}; -use vector_types::gradient::GradientSpreadMethod; +use vector_types::gradient::GradientSpread; use vector_types::markers::EditorClickTarget; use vello::*; @@ -430,7 +430,7 @@ fn create_peniko_gradient_brush>(gradient_list let gradient_type: GradientType = gradient_list.attr::(0); let gradient_transform: DAffine2 = gradient_list.attr::(0); - let spread_method: GradientSpreadMethod = gradient_list.attr::(0); + let gradient_spread: GradientSpread = gradient_list.attr::(0); let peniko_stops = peniko_color_stops(stops); @@ -452,10 +452,10 @@ fn create_peniko_gradient_brush>(gradient_list } .into(), }, - extend: match spread_method { - GradientSpreadMethod::Pad => peniko::Extend::Pad, - GradientSpreadMethod::Reflect => peniko::Extend::Reflect, - GradientSpreadMethod::Repeat => peniko::Extend::Repeat, + extend: match gradient_spread { + GradientSpread::Pad => peniko::Extend::Pad, + GradientSpread::Reflect => peniko::Extend::Reflect, + GradientSpread::Repeat => peniko::Extend::Repeat, }, stops: peniko_stops, interpolation_alpha_space: peniko::InterpolationAlphaSpace::Premultiplied, @@ -2327,7 +2327,7 @@ fn render_gradient_svg>(source: &S, render: &m let blend_mode: BlendMode = source.attr::(index); let opacity_attr: f64 = source.attr::(index); let opacity_fill_attr: f64 = source.attr::(index); - let spread_method: GradientSpreadMethod = source.attr::(index); + let gradient_spread: GradientSpread = source.attr::(index); let gradient_type: GradientType = source.attr::(index); let tag = if thumbnail_rect.is_some() { "rect" } else { "polyline" }; render.leaf_tag(tag, |attributes| { @@ -2366,10 +2366,10 @@ fn render_gradient_svg>(source: &S, render: &m }; let gradient_id = generate_uuid(); - let spread_method_attribute = if spread_method == GradientSpreadMethod::Pad { + let spread_method_attribute = if gradient_spread == GradientSpread::Pad { String::new() } else { - format!(r#" spreadMethod="{}""#, spread_method.svg_name()) + format!(r#" spreadMethod="{}""#, gradient_spread.svg_name()) }; // The unit gradient line is the +X unit vector in local space, before the item's transform is applied @@ -2411,7 +2411,7 @@ fn render_gradient_vello>(source: &S, scene: & for index in 0..source.lane_count() { let Some(gradient) = source.element(index) else { continue }; - let spread_method: GradientSpreadMethod = source.attr::(index); + let gradient_spread: GradientSpread = source.attr::(index); let gradient_type: GradientType = source.attr::(index); let transform: DAffine2 = source.attr::(index); let blend_mode_attr: BlendMode = source.attr::(index); @@ -2424,10 +2424,10 @@ fn render_gradient_vello>(source: &S, scene: & let stops = peniko_color_stops(gradient); - let extend = match spread_method { - GradientSpreadMethod::Pad => peniko::Extend::Pad, - GradientSpreadMethod::Reflect => peniko::Extend::Reflect, - GradientSpreadMethod::Repeat => peniko::Extend::Repeat, + let extend = match gradient_spread { + GradientSpread::Pad => peniko::Extend::Pad, + GradientSpread::Reflect => peniko::Extend::Reflect, + GradientSpread::Repeat => peniko::Extend::Repeat, }; // The unit gradient line is the +X unit vector in local space, before the item's transform is applied. diff --git a/node-graph/libraries/vector-types/src/gradient.rs b/node-graph/libraries/vector-types/src/gradient.rs index aff4d3fe29..a273cb101c 100644 --- a/node-graph/libraries/vector-types/src/gradient.rs +++ b/node-graph/libraries/vector-types/src/gradient.rs @@ -1,4 +1,4 @@ -use crate::ATTR_SPREAD_METHOD; +use crate::markers::ATTR_GRADIENT_SPREAD; use core_types::Color; use core_types::color::SRGBA8; use core_types::list::{ATTR_MIDPOINT, ATTR_POSITION, Item, List}; @@ -103,9 +103,9 @@ impl GradientStops { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct GradientRamp { pub stops: GradientStops, - #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "GradientSpreadMethod::is_default"))] + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "GradientSpread::is_default"))] #[cfg_attr(feature = "wasm", tsify(optional))] - pub spread_method: GradientSpreadMethod, + pub gradient_spread: GradientSpread, } unsafe impl dyn_any::StaticType for GradientRamp { @@ -116,7 +116,7 @@ impl From> for GradientRamp { fn from(stops: GradientStops) -> Self { Self { stops, - spread_method: Default::default(), + gradient_spread: Default::default(), } } } @@ -125,7 +125,7 @@ impl From<&Gradient> for GradientRamp { fn from(gradient: &Gradient) -> Self { Self { stops: gradient.into(), - spread_method: Default::default(), + gradient_spread: Default::default(), } } } @@ -153,8 +153,8 @@ impl From<&GradientRamp> for Gradient { impl From for Item { fn from(ramp: GradientRamp) -> Self { let mut item = Item::new_from_element(Gradient::from(ramp.stops)); - if !ramp.spread_method.is_default() { - item.set_attribute(ATTR_SPREAD_METHOD, ramp.spread_method); + if !ramp.gradient_spread.is_default() { + item.set_attribute(ATTR_GRADIENT_SPREAD, ramp.gradient_spread); } item } @@ -164,7 +164,7 @@ impl From<&Item> for GradientRamp { fn from(item: &Item) -> Self { Self { stops: item.element().into(), - spread_method: item.attribute_cloned_or_default(ATTR_SPREAD_METHOD), + gradient_spread: item.attribute_cloned_or_default(ATTR_GRADIENT_SPREAD), } } } @@ -190,7 +190,7 @@ impl From<&GradientRamp> for GradientRamp { fn from(ramp: &GradientRamp) -> Self { Self { stops: ramp.into(), - spread_method: ramp.spread_method, + gradient_spread: ramp.gradient_spread, } } } @@ -199,7 +199,7 @@ impl From<&Gradient> for GradientRamp { fn from(gradient: &Gradient) -> Self { Self { stops: gradient.into(), - spread_method: Default::default(), + gradient_spread: Default::default(), } } } @@ -207,7 +207,7 @@ impl From<&Gradient> for GradientRamp { impl From<&GradientRamp> for GradientRamp { fn from(ramp: &GradientRamp) -> Self { Self { - spread_method: ramp.spread_method, + gradient_spread: ramp.gradient_spread, ..Self::from(&ramp.stops) } } @@ -601,12 +601,12 @@ impl Gradient { stops } - /// Samples the gradient's color at `t`. Given a `t` outside the 0 to 1 range, the `spread_method` determines how the gradient extends. - pub fn evaluate(&self, t: f64, spread_method: GradientSpreadMethod) -> Color { - let t = match spread_method { - GradientSpreadMethod::Pad => t.clamp(0., 1.), - GradientSpreadMethod::Repeat => t.rem_euclid(1.), - GradientSpreadMethod::Reflect => { + /// Samples the gradient's color at `t`. Given a `t` outside the 0 to 1 range, the `gradient_spread` determines how the gradient extends. + pub fn evaluate(&self, t: f64, gradient_spread: GradientSpread) -> Color { + let t = match gradient_spread { + GradientSpread::Pad => t.clamp(0., 1.), + GradientSpread::Repeat => t.rem_euclid(1.), + GradientSpread::Reflect => { let cycle = t.rem_euclid(2.); if cycle > 1. { 2. - cycle } else { cycle } } @@ -785,7 +785,7 @@ impl Gradient { #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, graphene_hash::CacheHash, DynAny, node_macro::ChoiceType)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[widget(Radio)] -pub enum GradientSpreadMethod { +pub enum GradientSpread { /// Extends the end colors outward. #[default] Pad, @@ -796,12 +796,12 @@ pub enum GradientSpreadMethod { // TODO: Add a "Clear" variant that returns transparent black outside the gradient's range } -impl GradientSpreadMethod { +impl GradientSpread { pub fn svg_name(&self) -> &'static str { match self { - GradientSpreadMethod::Pad => "pad", - GradientSpreadMethod::Reflect => "reflect", - GradientSpreadMethod::Repeat => "repeat", + GradientSpread::Pad => "pad", + GradientSpread::Reflect => "reflect", + GradientSpread::Repeat => "repeat", } } @@ -906,39 +906,39 @@ mod tests { } #[test] - fn spread_method_serializes_only_when_not_default() { + fn gradient_spread_serializes_only_when_not_default() { let default_spread = GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE])); let json = serde_json::to_string(&default_spread).unwrap(); - assert!(!json.contains("spread_method"), "the default Pad spread method must not serialize: {json}"); + assert!(!json.contains("gradient_spread"), "the default Pad gradient spread must not serialize: {json}"); assert_eq!(serde_json::from_str::(&json).unwrap(), default_spread); let repeating = GradientRamp { - spread_method: GradientSpreadMethod::Repeat, + gradient_spread: GradientSpread::Repeat, ..default_spread.clone() }; let json = serde_json::to_string(&repeating).unwrap(); - assert!(json.contains(r#""spread_method":"Repeat""#), "a non-default spread method must serialize: {json}"); + assert!(json.contains(r#""gradient_spread":"Repeat""#), "a non-default gradient spread must serialize: {json}"); assert_eq!(serde_json::from_str::(&json).unwrap(), repeating); } #[test] - fn spread_method_round_trips_through_the_item_attribute() { + fn gradient_spread_round_trips_through_the_item_attribute() { let ramp = GradientRamp { - spread_method: GradientSpreadMethod::Repeat, + gradient_spread: GradientSpread::Repeat, ..GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE])) }; let item = Item::::from(ramp.clone()); assert_eq!( - item.attribute_cloned_or_default::(ATTR_SPREAD_METHOD), - GradientSpreadMethod::Repeat, - "the runtime item should carry the spread method as its attribute" + item.attribute_cloned_or_default::(ATTR_GRADIENT_SPREAD), + GradientSpread::Repeat, + "the runtime item should carry the gradient spread as its attribute" ); assert_eq!(GradientRamp::from(&item), ramp); let padded = Item::::from(GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE]))); assert!( - padded.attribute::(ATTR_SPREAD_METHOD).is_none(), + padded.attribute::(ATTR_GRADIENT_SPREAD).is_none(), "the default Pad must stay absent rather than materialize" ); } diff --git a/node-graph/libraries/vector-types/src/lib.rs b/node-graph/libraries/vector-types/src/lib.rs index 9d821e0d39..1ef07f6b41 100644 --- a/node-graph/libraries/vector-types/src/lib.rs +++ b/node-graph/libraries/vector-types/src/lib.rs @@ -9,8 +9,8 @@ pub mod vector; // Re-export commonly used types at the crate root pub use core_types as gcore; -pub use gradient::{Gradient, GradientRamp, GradientSpreadMethod, GradientStop, GradientType}; -pub use markers::{ATTR_EDITOR_CLICK_TARGET, ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD}; +pub use gradient::{Gradient, GradientRamp, GradientSpread, GradientStop, GradientType}; +pub use markers::{ATTR_EDITOR_CLICK_TARGET, ATTR_GRADIENT_SPREAD, ATTR_GRADIENT_TYPE}; pub use math::{QuadExt, RectExt}; pub use subpath::Subpath; pub use vector::Vector; diff --git a/node-graph/libraries/vector-types/src/markers.rs b/node-graph/libraries/vector-types/src/markers.rs index 54d3779e9e..f5e2d4d15f 100644 --- a/node-graph/libraries/vector-types/src/markers.rs +++ b/node-graph/libraries/vector-types/src/markers.rs @@ -5,7 +5,7 @@ use core_types::attribute::Attribute; core_types::attribute! { /// Gradient's spread behavior past its endpoints (`Pad`, `Reflect`, or `Repeat`). - pub SpreadMethod("spread_method"): crate::gradient::GradientSpreadMethod; + pub GradientSpread("gradient_spread"): crate::gradient::GradientSpread; /// Gradient's shape (`Linear` or `Radial`). pub GradientType("gradient_type"): crate::gradient::GradientType; /// Optional `Vector` that overrides the item's own geometry for click-target generation. @@ -18,11 +18,11 @@ core_types::attribute! { // The value types a name-generic attribute can name here, so a compile-time // named write or read reaches this crate's enums like any other plain value. core_types::named_value! { - for crate::gradient::GradientSpreadMethod; + for crate::gradient::GradientSpread; for crate::gradient::GradientType; } -pub const ATTR_SPREAD_METHOD: &str = SpreadMethod::NAME; +pub const ATTR_GRADIENT_SPREAD: &str = GradientSpread::NAME; pub const ATTR_GRADIENT_TYPE: &str = GradientType::NAME; pub const ATTR_EDITOR_CLICK_TARGET: &str = EditorClickTarget::NAME; @@ -35,7 +35,7 @@ mod tests { #[test] fn the_census_carries_this_crates_names() { assert_eq!(info("gradient_type").unwrap().value_type, TypeId::of::()); - assert_eq!(info("spread_method").unwrap().value_type, TypeId::of::()); + assert_eq!(info("gradient_spread").unwrap().value_type, TypeId::of::()); assert_eq!(info("editor:click_target").unwrap().value_type, TypeId::of::>()); } diff --git a/node-graph/nodes/graphic/src/graphic.rs b/node-graph/nodes/graphic/src/graphic.rs index 376bf69988..c9744bcc2e 100644 --- a/node-graph/nodes/graphic/src/graphic.rs +++ b/node-graph/nodes/graphic/src/graphic.rs @@ -14,7 +14,7 @@ use graphic_types::graphic::{Graphic, GraphicLevel, RowStep, TryFromGraphic, wal use graphic_types::markers::{EditorMergedLayers, Fill, Stroke as StrokeAttr}; use graphic_types::{ATTR_FILL, ATTR_STROKE, Vector}; use raster_types::{CPU, GPU, Raster}; -use vector_types::gradient::{GradientSpreadMethod, GradientType as GradientTypeValue}; +use vector_types::gradient::{GradientSpread, GradientType as GradientTypeValue}; use vector_types::{Gradient, ReferencePoint}; fn arena_exhausted() -> Interrupt { @@ -255,8 +255,8 @@ attribute_reads! { read_blend_mode_attribute: core_types::blending::BlendMode => core_types::blending::BlendMode; /// Reads a named gradient-shape attribute, such as `gradient_type`. read_gradient_type_attribute: GradientTypeValue => GradientTypeValue; - /// Reads a named gradient-spread attribute, such as `spread_method`. - read_spread_method_attribute: GradientSpreadMethod => GradientSpreadMethod; + /// Reads a named gradient-spread attribute, such as `gradient_spread`. + read_gradient_spread_attribute: GradientSpread => GradientSpread; } /// Nests the input graphical content in a wrapper graphic. This essentially "groups" the input. diff --git a/node-graph/nodes/math/src/lib.rs b/node-graph/nodes/math/src/lib.rs index 0cc9287114..f960a9cbf4 100644 --- a/node-graph/nodes/math/src/lib.rs +++ b/node-graph/nodes/math/src/lib.rs @@ -11,7 +11,7 @@ use math_parser::value::{Number, Value}; use rand::{Rng, SeedableRng}; use std::ops::{Add, Mul, Rem, Sub}; use vector_types::Gradient; -use vector_types::markers::{GradientType as GradientTypeAttr, SpreadMethod as SpreadMethodAttr}; +use vector_types::markers::{GradientSpread as GradientSpreadAttr, GradientType as GradientTypeAttr}; /// The struct that stores the context for the maths parser. /// This is currently just limited to supplying `a` and `b` until we add better node graph support and UI for variadic inputs. @@ -1210,8 +1210,8 @@ fn gradient_type(_: impl Ctx, gradient: Gradient, gradient_type: vector_types::G /// Sets how each gradient in the input list extends past its endpoints: Pad, Reflect, or Repeat. #[node_macro::node(category("Gradient"))] -fn spread_method(_: impl Ctx, gradient: Gradient, spread_method: vector_types::GradientSpreadMethod) -> (Gradient, Attr) { - (gradient, Attr(spread_method)) +fn gradient_spread(_: impl Ctx, gradient: Gradient, gradient_spread: vector_types::GradientSpread) -> (Gradient, Attr) { + (gradient, Attr(gradient_spread)) } /// Sets the position of each of a gradient's stops, a factor from 0 to 1 along the gradient. @@ -1236,7 +1236,7 @@ fn gradient_midpoints(_: impl Ctx, mut gradient: Gradient, midpoints: IList gradient } -/// Evaluates the color at the specified position along the gradient, given a position from 0 (left) to 1 (right). Positions beyond that range follow the gradient's `spread_method` attribute: Pad (default), Reflect, or Repeat. +/// Evaluates the color at the specified position along the gradient, given a position from 0 (left) to 1 (right). Positions beyond that range follow the gradient's `gradient_spread` attribute: Pad (default), Reflect, or Repeat. #[node_macro::node(category("Color"))] fn sample_gradient( ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, @@ -1249,7 +1249,7 @@ fn sample_gradient( return Err(GraphError::past_end().into()); } - let spread_method = gradient.lane(0).attr::(); + let spread_method = gradient.lane(0).attr::(); Ok(gradient.element_ref(0).evaluate(position, spread_method)) } diff --git a/node-graph/nodes/path-bool/src/lib.rs b/node-graph/nodes/path-bool/src/lib.rs index adaf08b2af..8eba616fa3 100644 --- a/node-graph/nodes/path-bool/src/lib.rs +++ b/node-graph/nodes/path-bool/src/lib.rs @@ -8,11 +8,11 @@ use graphic_types::graphic::{GraphicLevel, PaintColumns, PaintReach, bake_paint_ use graphic_types::markers::{EditorMergedLayers, Fill, Stroke}; use graphic_types::raster_types::{CPU, GPU, Raster}; use graphic_types::vector_types::Gradient; -use graphic_types::vector_types::gradient::{GradientSpreadMethod, GradientType}; +use graphic_types::vector_types::gradient::{GradientSpread, GradientType}; use graphic_types::vector_types::subpath::{ManipulatorGroup, Subpath}; use graphic_types::vector_types::vector::PointId; use graphic_types::vector_types::vector::algorithms::merge_by_distance::MergeByDistanceExt; -use graphic_types::vector_types::{ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD}; +use graphic_types::vector_types::{ATTR_GRADIENT_SPREAD, ATTR_GRADIENT_TYPE}; use graphic_types::{ATTR_FILL, ATTR_STROKE, Graphic, IntoGraphicList, Vector}; use linesweeper::topology::Topology; use linesweeper::{BinaryOp, FillRule, binary_op}; @@ -291,8 +291,8 @@ fn gradient_paint_row(stops: Gradient, mut attributes: core_types::list::ItemAtt if let Some(gradient_type) = attributes.remove::(ATTR_GRADIENT_TYPE) { gradient_paint.set_attribute(ATTR_GRADIENT_TYPE, 0, gradient_type); } - if let Some(spread_method) = attributes.remove::(ATTR_SPREAD_METHOD) { - gradient_paint.set_attribute(ATTR_SPREAD_METHOD, 0, spread_method); + if let Some(spread_method) = attributes.remove::(ATTR_GRADIENT_SPREAD) { + gradient_paint.set_attribute(ATTR_GRADIENT_SPREAD, 0, spread_method); } attributes.insert(ATTR_FILL, Some(gradient_paint)); diff --git a/node-graph/nodes/raster/src/gradient_map.rs b/node-graph/nodes/raster/src/gradient_map.rs index ee33e02872..acba0906c0 100644 --- a/node-graph/nodes/raster/src/gradient_map.rs +++ b/node-graph/nodes/raster/src/gradient_map.rs @@ -23,13 +23,13 @@ fn gradient_map + Clone + Send + Sync + core_types::CacheHash + if gradient.is_empty() { return image; } - let spread_method = gradient.lane(0).attr::(); + let gradient_spread = gradient.lane(0).attr::(); let gradient = gradient.element_ref(0); image.adjust(|color| { let intensity = color.luminance_rec_709(); let intensity = if reverse { 1. - intensity } else { intensity }; - gradient.evaluate(intensity as f64, spread_method) + gradient.evaluate(intensity as f64, gradient_spread) }); image