mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-28 08:48:13 +08:00
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
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
use crate::messages::layout::utility_types::widgets::input_widgets::{SpectrumInputUpdate, VisualColorPickersInputUpdate};
|
use crate::messages::layout::utility_types::widgets::input_widgets::{SpectrumInputUpdate, VisualColorPickersInputUpdate};
|
||||||
use crate::messages::prelude::*;
|
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.
|
/// Identifies which RGB channel a numeric input change targets.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[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.
|
/// `SpectrumInput` change: marker move/insert/delete, midpoint move/reset, or active marker selection changed.
|
||||||
GradientUpdate { update: SpectrumInputUpdate },
|
GradientUpdate { update: SpectrumInputUpdate },
|
||||||
/// Spread method choice from the gradient "Ends" selection.
|
/// Gradient spread choice from the gradient "Ends" selection.
|
||||||
SetSpreadMethod { spread_method: GradientSpreadMethod },
|
SetGradientSpread { gradient_spread: GradientSpread },
|
||||||
|
|
||||||
/// Tell the frontend to start an undo transaction (forwarded as a `FrontendMessage` it bridges out to the picker's parent).
|
/// Tell the frontend to start an undo transaction (forwarded as a `FrontendMessage` it bridges out to the picker's parent).
|
||||||
StartTransaction,
|
StartTransaction,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::messages::prelude::*;
|
|||||||
use graphene_std::Color;
|
use graphene_std::Color;
|
||||||
use graphene_std::color::SRGBA8;
|
use graphene_std::color::SRGBA8;
|
||||||
use graphene_std::core_types::misc::parse_css_color;
|
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).
|
/// Bounds for a midpoint position (relative to the interval between two adjacent gradient stops).
|
||||||
const MIN_MIDPOINT: f64 = 0.01;
|
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.
|
// When set, the picker is editing a gradient: the visual pickers and inputs target the active stop's color.
|
||||||
gradient: Option<Gradient>,
|
gradient: Option<Gradient>,
|
||||||
spread_method: GradientSpreadMethod,
|
gradient_spread: GradientSpread,
|
||||||
active_marker_index: Option<u32>,
|
active_marker_index: Option<u32>,
|
||||||
active_marker_is_midpoint: bool,
|
active_marker_is_midpoint: bool,
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ impl Default for ColorPickerMessageHandler {
|
|||||||
old_alpha: 1.,
|
old_alpha: 1.,
|
||||||
old_is_none: true,
|
old_is_none: true,
|
||||||
gradient: None,
|
gradient: None,
|
||||||
spread_method: GradientSpreadMethod::default(),
|
gradient_spread: GradientSpread::default(),
|
||||||
active_marker_index: None,
|
active_marker_index: None,
|
||||||
active_marker_is_midpoint: false,
|
active_marker_is_midpoint: false,
|
||||||
allow_none: true,
|
allow_none: true,
|
||||||
@@ -72,13 +72,13 @@ impl MessageHandler<ColorPickerMessage, ()> for ColorPickerMessageHandler {
|
|||||||
FillChoice::None => {
|
FillChoice::None => {
|
||||||
self.set_new_hsva(0., 0., 0., 1., true);
|
self.set_new_hsva(0., 0., 0., 1., true);
|
||||||
self.gradient = None;
|
self.gradient = None;
|
||||||
self.spread_method = GradientSpreadMethod::default();
|
self.gradient_spread = GradientSpread::default();
|
||||||
self.active_marker_index = None;
|
self.active_marker_index = None;
|
||||||
self.active_marker_is_midpoint = false;
|
self.active_marker_is_midpoint = false;
|
||||||
}
|
}
|
||||||
FillChoice::Solid(color) => {
|
FillChoice::Solid(color) => {
|
||||||
self.gradient = None;
|
self.gradient = None;
|
||||||
self.spread_method = GradientSpreadMethod::default();
|
self.gradient_spread = GradientSpread::default();
|
||||||
self.active_marker_index = None;
|
self.active_marker_index = None;
|
||||||
self.active_marker_is_midpoint = false;
|
self.active_marker_is_midpoint = false;
|
||||||
self.adopt_color(color);
|
self.adopt_color(color);
|
||||||
@@ -86,7 +86,7 @@ impl MessageHandler<ColorPickerMessage, ()> for ColorPickerMessageHandler {
|
|||||||
FillChoice::Gradient(ramp) => {
|
FillChoice::Gradient(ramp) => {
|
||||||
self.active_marker_index = Some(0);
|
self.active_marker_index = Some(0);
|
||||||
self.active_marker_is_midpoint = false;
|
self.active_marker_is_midpoint = false;
|
||||||
self.spread_method = ramp.spread_method;
|
self.gradient_spread = ramp.gradient_spread;
|
||||||
let gradient = Gradient::from(ramp);
|
let gradient = Gradient::from(ramp);
|
||||||
let first_color = gradient.color(0).unwrap_or(Color::BLACK);
|
let first_color = gradient.color(0).unwrap_or(Color::BLACK);
|
||||||
self.gradient = Some(gradient);
|
self.gradient = Some(gradient);
|
||||||
@@ -192,13 +192,13 @@ impl MessageHandler<ColorPickerMessage, ()> for ColorPickerMessageHandler {
|
|||||||
self.send_layouts(responses);
|
self.send_layouts(responses);
|
||||||
}
|
}
|
||||||
ColorPickerMessage::GradientUpdate { update } => self.apply_gradient_update(update, 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 };
|
let Some(gradient) = &self.gradient else { return };
|
||||||
responses.add(FrontendMessage::ColorPickerStartHistoryTransaction);
|
responses.add(FrontendMessage::ColorPickerStartHistoryTransaction);
|
||||||
self.spread_method = spread_method;
|
self.gradient_spread = gradient_spread;
|
||||||
responses.add(FrontendMessage::ColorPickerColorChanged {
|
responses.add(FrontendMessage::ColorPickerColorChanged {
|
||||||
value: FillChoice::Gradient(GradientRamp {
|
value: FillChoice::Gradient(GradientRamp {
|
||||||
spread_method,
|
gradient_spread,
|
||||||
..GradientRamp::from(gradient)
|
..GradientRamp::from(gradient)
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -289,7 +289,7 @@ impl ColorPickerMessageHandler {
|
|||||||
gradient.set_color(active_index as usize, color);
|
gradient.set_color(active_index as usize, color);
|
||||||
responses.add(FrontendMessage::ColorPickerColorChanged {
|
responses.add(FrontendMessage::ColorPickerColorChanged {
|
||||||
value: FillChoice::Gradient(GradientRamp {
|
value: FillChoice::Gradient(GradientRamp {
|
||||||
spread_method: self.spread_method,
|
gradient_spread: self.gradient_spread,
|
||||||
..GradientRamp::from(&*gradient)
|
..GradientRamp::from(&*gradient)
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -419,7 +419,7 @@ impl ColorPickerMessageHandler {
|
|||||||
|
|
||||||
responses.add(FrontendMessage::ColorPickerColorChanged {
|
responses.add(FrontendMessage::ColorPickerColorChanged {
|
||||||
value: FillChoice::Gradient(GradientRamp {
|
value: FillChoice::Gradient(GradientRamp {
|
||||||
spread_method: self.spread_method,
|
gradient_spread: self.gradient_spread,
|
||||||
..GradientRamp::from(&gradient)
|
..GradientRamp::from(&gradient)
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -621,21 +621,21 @@ impl ColorPickerMessageHandler {
|
|||||||
.widget_instance(),
|
.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() {
|
if self.gradient.is_some() {
|
||||||
let entries = [GradientSpreadMethod::Pad, GradientSpreadMethod::Reflect, GradientSpreadMethod::Repeat]
|
let entries = [GradientSpread::Pad, GradientSpread::Reflect, GradientSpread::Repeat]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|spread_method| {
|
.map(|gradient_spread| {
|
||||||
RadioEntryData::new(format!("{spread_method:?}"))
|
RadioEntryData::new(format!("{gradient_spread:?}"))
|
||||||
.label(spread_method.to_string())
|
.label(gradient_spread.to_string())
|
||||||
.on_update(move |_| ColorPickerMessage::SetSpreadMethod { spread_method }.into())
|
.on_update(move |_| ColorPickerMessage::SetGradientSpread { gradient_spread }.into())
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
groups.push(LayoutGroup::row(vec![
|
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(),
|
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(),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use graphene_std::transform::{ReferencePoint, ScaleType};
|
|||||||
use graphene_std::vector::misc::{
|
use graphene_std::vector::misc::{
|
||||||
ArcType, BooleanOperation, BoxCorners, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType,
|
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::vector::{QRCodeErrorCorrectionLevel, Vector};
|
||||||
use graphene_std::{Artboard, Color, Context, Graphic};
|
use graphene_std::{Artboard, Color, Context, Graphic};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
@@ -213,7 +213,7 @@ fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'st
|
|||||||
List<DAffine2>,
|
List<DAffine2>,
|
||||||
List<BlendMode>,
|
List<BlendMode>,
|
||||||
List<GradientType>,
|
List<GradientType>,
|
||||||
List<GradientSpreadMethod>,
|
List<GradientSpread>,
|
||||||
List<DashPattern>,
|
List<DashPattern>,
|
||||||
List<BoxCorners>,
|
List<BoxCorners>,
|
||||||
List<StrokeJoin>,
|
List<StrokeJoin>,
|
||||||
@@ -266,7 +266,7 @@ fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'st
|
|||||||
Item<DAffine2>,
|
Item<DAffine2>,
|
||||||
Item<BlendMode>,
|
Item<BlendMode>,
|
||||||
Item<GradientType>,
|
Item<GradientType>,
|
||||||
Item<GradientSpreadMethod>,
|
Item<GradientSpread>,
|
||||||
Item<DashPattern>,
|
Item<DashPattern>,
|
||||||
Item<BoxCorners>,
|
Item<BoxCorners>,
|
||||||
Item<StrokeJoin>,
|
Item<StrokeJoin>,
|
||||||
@@ -1002,7 +1002,7 @@ macro_rules! impl_table_item_layout_for_choice_enum {
|
|||||||
impl_table_item_layout_for_choice_enum!(
|
impl_table_item_layout_for_choice_enum!(
|
||||||
BlendMode,
|
BlendMode,
|
||||||
GradientType,
|
GradientType,
|
||||||
GradientSpreadMethod,
|
GradientSpread,
|
||||||
StrokeJoin,
|
StrokeJoin,
|
||||||
StrokeAlign,
|
StrokeAlign,
|
||||||
StrokeCap,
|
StrokeCap,
|
||||||
@@ -1214,7 +1214,7 @@ macro_rules! known_item_types {
|
|||||||
BoxCorners,
|
BoxCorners,
|
||||||
BlendMode,
|
BlendMode,
|
||||||
GradientType,
|
GradientType,
|
||||||
GradientSpreadMethod,
|
GradientSpread,
|
||||||
StrokeJoin,
|
StrokeJoin,
|
||||||
StrokeAlign,
|
StrokeAlign,
|
||||||
StrokeCap,
|
StrokeCap,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use graphene_std::raster::BlendMode;
|
|||||||
use graphene_std::raster_types::Image;
|
use graphene_std::raster_types::Image;
|
||||||
use graphene_std::subpath::Subpath;
|
use graphene_std::subpath::Subpath;
|
||||||
use graphene_std::text::{Font, TypesettingConfig};
|
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};
|
use graphene_std::vector::{Gradient, PointId, VectorModificationType};
|
||||||
|
|
||||||
#[impl_message(Message, DocumentMessage, GraphOperation)]
|
#[impl_message(Message, DocumentMessage, GraphOperation)]
|
||||||
@@ -25,7 +25,7 @@ pub enum GraphOperationMessage {
|
|||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
gradient: Gradient,
|
gradient: Gradient,
|
||||||
gradient_type: GradientType,
|
gradient_type: GradientType,
|
||||||
spread_method: GradientSpreadMethod,
|
gradient_spread: GradientSpread,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
},
|
},
|
||||||
BlendingFillSet {
|
BlendingFillSet {
|
||||||
@@ -53,9 +53,9 @@ pub enum GraphOperationMessage {
|
|||||||
layer: LayerNodeIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
gradient_type: GradientType,
|
gradient_type: GradientType,
|
||||||
},
|
},
|
||||||
GradientSpreadMethodSet {
|
GradientSpreadSet {
|
||||||
layer: LayerNodeIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
spread_method: GradientSpreadMethod,
|
gradient_spread: GradientSpread,
|
||||||
},
|
},
|
||||||
OpacitySet {
|
OpacitySet {
|
||||||
layer: LayerNodeIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
|
|||||||
+13
-13
@@ -13,7 +13,7 @@ use graph_craft::document::{NodeId, NodeInput};
|
|||||||
use graph_craft::list;
|
use graph_craft::list;
|
||||||
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
|
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
|
||||||
use graphene_std::text::{Font, TypesettingConfig};
|
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};
|
use graphene_std::{Artboard, Color};
|
||||||
|
|
||||||
#[derive(ExtractField)]
|
#[derive(ExtractField)]
|
||||||
@@ -43,11 +43,11 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
|
|||||||
layer,
|
layer,
|
||||||
gradient,
|
gradient,
|
||||||
gradient_type,
|
gradient_type,
|
||||||
spread_method,
|
gradient_spread,
|
||||||
transform,
|
transform,
|
||||||
} => {
|
} => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) {
|
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 } => {
|
GraphOperationMessage::BlendingFillSet { layer, fill } => {
|
||||||
@@ -80,9 +80,9 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
|
|||||||
modify_inputs.gradient_type_set(gradient_type);
|
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) {
|
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 } => {
|
GraphOperationMessage::OpacitySet { layer, opacity } => {
|
||||||
@@ -805,11 +805,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 {
|
match spread_method {
|
||||||
usvg::SpreadMethod::Pad => GradientSpreadMethod::Pad,
|
usvg::SpreadMethod::Pad => GradientSpread::Pad,
|
||||||
usvg::SpreadMethod::Reflect => GradientSpreadMethod::Reflect,
|
usvg::SpreadMethod::Reflect => GradientSpread::Reflect,
|
||||||
usvg::SpreadMethod::Repeat => GradientSpreadMethod::Repeat,
|
usvg::SpreadMethod::Repeat => GradientSpread::Repeat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -836,8 +836,8 @@ fn apply_usvg_fill(fill: &usvg::Fill, modify_inputs: &mut ModifyInputsContext, g
|
|||||||
Gradient::new(stops)
|
Gradient::new(stops)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let spread_method = convert_spread_method(linear.spread_method());
|
let gradient_spread = convert_gradient_spread(linear.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::RadialGradient(radial) => {
|
usvg::Paint::RadialGradient(radial) => {
|
||||||
let gradient_transform = usvg_transform(radial.transform());
|
let gradient_transform = usvg_transform(radial.transform());
|
||||||
@@ -860,9 +860,9 @@ fn apply_usvg_fill(fill: &usvg::Fill, modify_inputs: &mut ModifyInputsContext, g
|
|||||||
Gradient::new(stops)
|
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"),
|
usvg::Paint::Pattern(_) => warn!("SVG patterns are not currently supported"),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use graphene_std::raster::BlendMode;
|
|||||||
use graphene_std::raster_types::Image;
|
use graphene_std::raster_types::Image;
|
||||||
use graphene_std::subpath::Subpath;
|
use graphene_std::subpath::Subpath;
|
||||||
use graphene_std::text::{Font, TypesettingConfig};
|
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::vector::{Gradient, GradientRamp, PointId, Vector, VectorModification, VectorModificationType};
|
||||||
use graphene_std::{Artboard, Color, Graphic};
|
use graphene_std::{Artboard, Color, Graphic};
|
||||||
|
|
||||||
@@ -403,14 +403,14 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
self.set_input_with_refresh(input_connector, NodeInput::value(fill_value, false), false);
|
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 {
|
let Some(fill_node_id) = self.existing_proto_node_id(graphene_std::vector_nodes::fill::IDENTIFIER, true) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let backup_input_connector = InputConnector::node(fill_node_id, graphene_std::vector::fill::BackupGradientInput);
|
let backup_input_connector = InputConnector::node(fill_node_id, graphene_std::vector::fill::BackupGradientInput);
|
||||||
|
|
||||||
let ramp = GradientRamp::from(gradient);
|
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);
|
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
|
// Skip the rerender on all but the last input so the whole update triggers a single graph run
|
||||||
@@ -676,20 +676,20 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientType(gradient_type), false), false);
|
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`).
|
/// 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 Some(output_layer) = self.get_output_layer() else { return };
|
||||||
|
|
||||||
let target_input = gradient_chain_target_input(output_layer, self.network_interface);
|
let target_input = gradient_chain_target_input(output_layer, self.network_interface);
|
||||||
let identifier = graphene_std::math_nodes::spread_method::IDENTIFIER;
|
let identifier = graphene_std::math_nodes::gradient_spread::IDENTIFIER;
|
||||||
let create_if_nonexistent = spread_method != GradientSpreadMethod::default();
|
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 {
|
let Some(node_id) = self.existing_proto_node_id_at(&target_input, identifier, create_if_nonexistent) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let input_connector = InputConnector::node(node_id, graphene_std::math_nodes::spread_method::SpreadMethodInput);
|
let input_connector = InputConnector::node(node_id, graphene_std::math_nodes::gradient_spread::GradientSpreadInput);
|
||||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientSpreadMethod(spread_method), false), false);
|
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<bool>) {
|
pub fn clip_mode_toggle(&mut self, clip_mode: Option<bool>) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ use graphene_std::vector::misc::{
|
|||||||
ArcType, BoxCorners, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType,
|
ArcType, BoxCorners, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType,
|
||||||
};
|
};
|
||||||
use graphene_std::vector::style::{
|
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::vector::{QRCodeErrorCorrectionLevel, VectorModification};
|
||||||
use graphene_std::{NodeParameter, ParameterRef};
|
use graphene_std::{NodeParameter, ParameterRef};
|
||||||
@@ -302,7 +302,7 @@ pub(crate) fn property_from_type(
|
|||||||
// AUTO-GENERATED ENUM TYPES
|
// AUTO-GENERATED ENUM TYPES
|
||||||
// =========================
|
// =========================
|
||||||
Some(x) if id_is::<GradientType>(x) => enum_choice::<GradientType>().for_socket(default_info).property_row(),
|
Some(x) if id_is::<GradientType>(x) => enum_choice::<GradientType>().for_socket(default_info).property_row(),
|
||||||
Some(x) if id_is::<GradientSpreadMethod>(x) => enum_choice::<GradientSpreadMethod>().for_socket(default_info).property_row(),
|
Some(x) if id_is::<GradientSpread>(x) => enum_choice::<GradientSpread>().for_socket(default_info).property_row(),
|
||||||
Some(x) if id_is::<RealTimeMode>(x) => enum_choice::<RealTimeMode>().for_socket(default_info).property_row(),
|
Some(x) if id_is::<RealTimeMode>(x) => enum_choice::<RealTimeMode>().for_socket(default_info).property_row(),
|
||||||
Some(x) if id_is::<RedGreenBlue>(x) => enum_choice::<RedGreenBlue>().for_socket(default_info).property_row(),
|
Some(x) if id_is::<RedGreenBlue>(x) => enum_choice::<RedGreenBlue>().for_socket(default_info).property_row(),
|
||||||
Some(x) if id_is::<RedGreenBlueAlpha>(x) => enum_choice::<RedGreenBlueAlpha>().for_socket(default_info).property_row(),
|
Some(x) if id_is::<RedGreenBlueAlpha>(x) => enum_choice::<RedGreenBlueAlpha>().for_socket(default_info).property_row(),
|
||||||
@@ -2401,7 +2401,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
|||||||
Gradient {
|
Gradient {
|
||||||
gradient: Gradient,
|
gradient: Gradient,
|
||||||
gradient_type: GradientType,
|
gradient_type: GradientType,
|
||||||
spread_method: GradientSpreadMethod,
|
gradient_spread: GradientSpread,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
/// Whether the transform input holds a plain value (so the "Reverse Direction" button may write to it) rather than a wire.
|
/// 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,
|
transform_is_value: bool,
|
||||||
@@ -2431,7 +2431,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
|||||||
Some(gradient) => ResolvedFill::Gradient {
|
Some(gradient) => ResolvedFill::Gradient {
|
||||||
gradient: gradient.stops,
|
gradient: gradient.stops,
|
||||||
gradient_type: gradient.gradient_type,
|
gradient_type: gradient.gradient_type,
|
||||||
spread_method: gradient.spread_method,
|
gradient_spread: gradient.gradient_spread,
|
||||||
transform: gradient.transform,
|
transform: gradient.transform,
|
||||||
transform_is_value: gradient.transform_is_value,
|
transform_is_value: gradient.transform_is_value,
|
||||||
},
|
},
|
||||||
@@ -2459,9 +2459,9 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
|||||||
};
|
};
|
||||||
|
|
||||||
match &fill {
|
match &fill {
|
||||||
ResolvedFill::Gradient { gradient: stops, spread_method, .. } => {
|
ResolvedFill::Gradient { gradient: stops, gradient_spread, .. } => {
|
||||||
let stops = stops.clone();
|
let stops = stops.clone();
|
||||||
let spread_method = *spread_method;
|
let gradient_spread = *gradient_spread;
|
||||||
|
|
||||||
let reverse_button = IconButton::new("Reverse", 24)
|
let reverse_button = IconButton::new("Reverse", 24)
|
||||||
.tooltip_label("Reverse Stops")
|
.tooltip_label("Reverse Stops")
|
||||||
@@ -2469,7 +2469,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
|||||||
.on_update(update_value(
|
.on_update(update_value(
|
||||||
move |_| {
|
move |_| {
|
||||||
TaggedValue::GradientRamp(GradientRamp {
|
TaggedValue::GradientRamp(GradientRamp {
|
||||||
spread_method,
|
gradient_spread,
|
||||||
..GradientRamp::from(stops.reversed())
|
..GradientRamp::from(stops.reversed())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -2491,8 +2491,8 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
|
|||||||
FillChoice::<SRGBA8>::None
|
FillChoice::<SRGBA8>::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResolvedFill::Gradient { gradient: stops, spread_method, .. } => FillChoice::<SRGBA8>::Gradient(GradientRamp {
|
ResolvedFill::Gradient { gradient: stops, gradient_spread, .. } => FillChoice::<SRGBA8>::Gradient(GradientRamp {
|
||||||
spread_method: *spread_method,
|
gradient_spread: *gradient_spread,
|
||||||
..GradientRamp::from(stops)
|
..GradientRamp::from(stops)
|
||||||
}),
|
}),
|
||||||
ResolvedFill::Other => FillChoice::<SRGBA8>::None,
|
ResolvedFill::Other => FillChoice::<SRGBA8>::None,
|
||||||
|
|||||||
@@ -813,11 +813,11 @@ async fn legacy_four_input_fill_migrates_to_the_split_transform_shape() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[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 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<alloc::sync::Arc<graphene_core::context::OwnedContextImpl>>","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}"#;
|
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<alloc::sync::Arc<graphene_core::context::OwnedContextImpl>>","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
|
// 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 {
|
let Some(TaggedValue::GradientRamp(ramp)) = paint else {
|
||||||
panic!("the fill input should keep its gradient ramp value, but became {paint:?}");
|
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 backup = fill_node.input_value(graphene_std::vector::fill::BackupGradientInput);
|
||||||
let Some(TaggedValue::GradientRamp(backup_ramp)) = backup else {
|
let Some(TaggedValue::GradientRamp(backup_ramp)) = backup else {
|
||||||
panic!("the backup gradient input should keep its gradient ramp value, but became {backup:?}");
|
panic!("the backup gradient input should keep its gradient ramp value, but became {backup:?}");
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(backup_ramp.gradient_spread, GradientSpread::Repeat, "the spread input's value should fold into the backup ramp");
|
||||||
backup_ramp.spread_method,
|
|
||||||
GradientSpreadMethod::Repeat,
|
|
||||||
"the spread method input's value should fold into the backup ramp"
|
|
||||||
);
|
|
||||||
|
|
||||||
let has_transform = fill_node.input_value(graphene_std::vector::fill::HasTransformInput);
|
let has_transform = fill_node.input_value(graphene_std::vector::fill::HasTransformInput);
|
||||||
assert!(
|
assert!(
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use graphene_std::text::{TextAlign, TypesettingConfig};
|
|||||||
use graphene_std::transform::ScaleType;
|
use graphene_std::transform::ScaleType;
|
||||||
use graphene_std::uuid::NodeId;
|
use graphene_std::uuid::NodeId;
|
||||||
use graphene_std::vector::graphic_types;
|
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::collections::HashMap;
|
||||||
use std::f64::consts::PI;
|
use std::f64::consts::PI;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
@@ -167,6 +167,10 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
|||||||
"graphic_nodes::graphic::ExtractElementNode",
|
"graphic_nodes::graphic::ExtractElementNode",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
NodeReplacement {
|
||||||
|
node: graphene_std::graphic::read_attribute_gradient_spread::IDENTIFIER,
|
||||||
|
aliases: &["graphic_nodes::graphic::ReadAttributeSpreadMethodNode"],
|
||||||
|
},
|
||||||
NodeReplacement {
|
NodeReplacement {
|
||||||
node: graphene_std::graphic::remove_at_index::IDENTIFIER,
|
node: graphene_std::graphic::remove_at_index::IDENTIFIER,
|
||||||
aliases: &["graphic_nodes::graphic::OmitElementNode"],
|
aliases: &["graphic_nodes::graphic::OmitElementNode"],
|
||||||
@@ -262,6 +266,10 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
|||||||
node: graphene_std::math_nodes::footprint_value::IDENTIFIER,
|
node: graphene_std::math_nodes::footprint_value::IDENTIFIER,
|
||||||
aliases: &["graphene_math_nodes::FootprintValueNode", "graphene_core::ops::FootprintValueNode"],
|
aliases: &["graphene_math_nodes::FootprintValueNode", "graphene_core::ops::FootprintValueNode"],
|
||||||
},
|
},
|
||||||
|
NodeReplacement {
|
||||||
|
node: graphene_std::math_nodes::gradient_spread::IDENTIFIER,
|
||||||
|
aliases: &["math_nodes::SpreadMethodNode"],
|
||||||
|
},
|
||||||
NodeReplacement {
|
NodeReplacement {
|
||||||
node: graphene_std::math_nodes::gradient_value::IDENTIFIER,
|
node: graphene_std::math_nodes::gradient_value::IDENTIFIER,
|
||||||
aliases: &[
|
aliases: &[
|
||||||
@@ -1406,10 +1414,10 @@ fn migrate_corner_radius_input(input: &NodeInput) -> Option<NodeInput> {
|
|||||||
Some(NodeInput::value(TaggedValue::BoxCorners(values), *exposed))
|
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.
|
/// 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_spread_method_into_ramp_input(input: &NodeInput, spread_method: GradientSpreadMethod) -> NodeInput {
|
fn fold_gradient_spread_into_ramp_input(input: &NodeInput, gradient_spread: GradientSpread) -> NodeInput {
|
||||||
match input.as_value() {
|
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(),
|
_ => input.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1635,7 +1643,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::None => TaggedValue::no_paint(),
|
||||||
graphic_types::migrations::legacy::LegacyFill::Solid(color) => TaggedValue::Color(*color),
|
graphic_types::migrations::legacy::LegacyFill::Solid(color) => TaggedValue::Color(*color),
|
||||||
graphic_types::migrations::legacy::LegacyFill::Gradient(gradient) => TaggedValue::GradientRamp(GradientRamp {
|
graphic_types::migrations::legacy::LegacyFill::Gradient(gradient) => TaggedValue::GradientRamp(GradientRamp {
|
||||||
spread_method: gradient.spread_method,
|
gradient_spread: gradient.spread_method,
|
||||||
..gradient.stops.clone()
|
..gradient.stops.clone()
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -1682,7 +1690,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
|||||||
&InputConnector::node_at_index(*node_id, 3),
|
&InputConnector::node_at_index(*node_id, 3),
|
||||||
NodeInput::value(
|
NodeInput::value(
|
||||||
TaggedValue::GradientRamp(GradientRamp {
|
TaggedValue::GradientRamp(GradientRamp {
|
||||||
spread_method: g.spread_method,
|
gradient_spread: g.spread_method,
|
||||||
..g.stops.clone()
|
..g.stops.clone()
|
||||||
}),
|
}),
|
||||||
false,
|
false,
|
||||||
@@ -1723,20 +1731,20 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
|||||||
// Fill split its `Option<DAffine2>` placement into a `_has_transform` bool immediately before the `_transform` matrix. The modern
|
// Fill split its `Option<DAffine2>` 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.
|
// 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
|
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(_))));
|
|| 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 {
|
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 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 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()) {
|
let gradient_spread = match old_inputs.get(5).and_then(|input| input.as_value()) {
|
||||||
Some(&TaggedValue::GradientSpreadMethod(value)) => value,
|
Some(&TaggedValue::GradientSpread(value)) => value,
|
||||||
_ => GradientSpreadMethod::default(),
|
_ => GradientSpread::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (index, input) in old_inputs.iter().enumerate().take(5) {
|
for (index, input) in old_inputs.iter().enumerate().take(5) {
|
||||||
let input = if index == 1 || index == 3 {
|
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 {
|
} else {
|
||||||
input.clone()
|
input.clone()
|
||||||
};
|
};
|
||||||
@@ -1767,19 +1775,19 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
|||||||
inputs_count = 7;
|
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 {
|
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 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 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()) {
|
let gradient_spread = match old_inputs.get(5).and_then(|input| input.as_value()) {
|
||||||
Some(&TaggedValue::GradientSpreadMethod(value)) => value,
|
Some(&TaggedValue::GradientSpread(value)) => value,
|
||||||
_ => GradientSpreadMethod::default(),
|
_ => GradientSpread::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (index, input) in old_inputs.iter().enumerate().take(5) {
|
for (index, input) in old_inputs.iter().enumerate().take(5) {
|
||||||
let input = if index == 1 || index == 3 {
|
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 {
|
} else {
|
||||||
input.clone()
|
input.clone()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use graphene_std::subpath::Subpath;
|
|||||||
use graphene_std::text::{Font, TypesettingConfig};
|
use graphene_std::text::{Font, TypesettingConfig};
|
||||||
use graphene_std::vector::misc::ManipulatorPointId;
|
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::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 graphene_std::{NodeParameter, ParameterRef};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
@@ -660,7 +660,7 @@ pub fn set_stroke_weight_for_selected_layers(weight: f64, document: &DocumentMes
|
|||||||
pub struct FillNodeGradient {
|
pub struct FillNodeGradient {
|
||||||
pub stops: Gradient,
|
pub stops: Gradient,
|
||||||
pub gradient_type: GradientType,
|
pub gradient_type: GradientType,
|
||||||
pub spread_method: GradientSpreadMethod,
|
pub gradient_spread: GradientSpread,
|
||||||
pub transform: DAffine2,
|
pub transform: DAffine2,
|
||||||
/// Whether the transform input holds a plain value (so it may be written to) rather than a wire.
|
/// Whether the transform input holds a plain value (so it may be written to) rather than a wire.
|
||||||
pub transform_is_value: bool,
|
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 {
|
let TaggedValue::GradientRamp(ramp) = fill_node.input(fill::FillInput)?.as_value()? else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let spread_method = ramp.spread_method;
|
let gradient_spread = ramp.gradient_spread;
|
||||||
let stops = Gradient::from(ramp);
|
let stops = Gradient::from(ramp);
|
||||||
let gradient_type = match fill_node.input(fill::GradientTypeInput).and_then(|input| input.as_value()) {
|
let gradient_type = match fill_node.input(fill::GradientTypeInput).and_then(|input| input.as_value()) {
|
||||||
Some(&TaggedValue::GradientType(value)) => 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 {
|
Some(FillNodeGradient {
|
||||||
stops,
|
stops,
|
||||||
gradient_type,
|
gradient_type,
|
||||||
spread_method,
|
gradient_spread,
|
||||||
transform,
|
transform,
|
||||||
transform_is_value: transform_input.is_some(),
|
transform_is_value: transform_input.is_some(),
|
||||||
})
|
})
|
||||||
@@ -839,7 +839,7 @@ pub fn set_fill_for_selected_layers(fill_choice: FillChoice, document: &Document
|
|||||||
layer,
|
layer,
|
||||||
gradient: Gradient::from(ramp),
|
gradient: Gradient::from(ramp),
|
||||||
gradient_type,
|
gradient_type,
|
||||||
spread_method: ramp.spread_method,
|
gradient_spread: ramp.gradient_spread,
|
||||||
transform,
|
transform,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use glam::DMat2;
|
|||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graphene_std::color::SRGBA8;
|
use graphene_std::color::SRGBA8;
|
||||||
use graphene_std::raster::color::Color;
|
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)]
|
#[derive(Default, ExtractField)]
|
||||||
pub struct GradientTool {
|
pub struct GradientTool {
|
||||||
@@ -28,7 +28,7 @@ pub struct GradientTool {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct GradientOptions {
|
pub struct GradientOptions {
|
||||||
gradient_type: GradientType,
|
gradient_type: GradientType,
|
||||||
spread_method: GradientSpreadMethod,
|
gradient_spread: GradientSpread,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[impl_message(Message, ToolMessage, Gradient)]
|
#[impl_message(Message, ToolMessage, Gradient)]
|
||||||
@@ -136,8 +136,8 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Grad
|
|||||||
}
|
}
|
||||||
ToolMessage::Gradient(GradientToolMessage::UpdateRamp { ramp }) => {
|
ToolMessage::Gradient(GradientToolMessage::UpdateRamp { ramp }) => {
|
||||||
let ramp = GradientRamp::from(&ramp);
|
let ramp = GradientRamp::from(&ramp);
|
||||||
self.options.spread_method = ramp.spread_method;
|
self.options.gradient_spread = ramp.gradient_spread;
|
||||||
apply_stops_update(&mut self.data, context, responses, Gradient::from(&ramp), ramp.spread_method);
|
apply_stops_update(&mut self.data, context, responses, Gradient::from(&ramp), ramp.gradient_spread);
|
||||||
}
|
}
|
||||||
ToolMessage::Gradient(GradientToolMessage::CloseStopColorPicker) => {
|
ToolMessage::Gradient(GradientToolMessage::CloseStopColorPicker) => {
|
||||||
if self.data.color_picker_transaction_open {
|
if self.data.color_picker_transaction_open {
|
||||||
@@ -171,8 +171,8 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Grad
|
|||||||
self.options.gradient_type = appearance.gradient_type;
|
self.options.gradient_type = appearance.gradient_type;
|
||||||
needs_refresh = true;
|
needs_refresh = true;
|
||||||
}
|
}
|
||||||
if self.options.spread_method != appearance.spread_method {
|
if self.options.gradient_spread != appearance.gradient_spread {
|
||||||
self.options.spread_method = appearance.spread_method;
|
self.options.gradient_spread = appearance.gradient_spread;
|
||||||
needs_refresh = true;
|
needs_refresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +263,7 @@ impl LayoutHolder for GradientTool {
|
|||||||
])
|
])
|
||||||
});
|
});
|
||||||
let stops_widget = ColorInput::new(FillChoice::Gradient(GradientRamp {
|
let stops_widget = ColorInput::new(FillChoice::Gradient(GradientRamp {
|
||||||
spread_method: self.options.spread_method,
|
gradient_spread: self.options.gradient_spread,
|
||||||
..GradientRamp::from(&stops_value)
|
..GradientRamp::from(&stops_value)
|
||||||
}))
|
}))
|
||||||
.allow_none(false)
|
.allow_none(false)
|
||||||
@@ -363,7 +363,7 @@ fn resolve_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI
|
|||||||
gradient.stops,
|
gradient.stops,
|
||||||
GradientAppearance {
|
GradientAppearance {
|
||||||
gradient_type: gradient.gradient_type,
|
gradient_type: gradient.gradient_type,
|
||||||
spread_method: gradient.spread_method,
|
gradient_spread: gradient.gradient_spread,
|
||||||
transform: gradient.transform,
|
transform: gradient.transform,
|
||||||
},
|
},
|
||||||
GradientSource::Direct,
|
GradientSource::Direct,
|
||||||
@@ -382,22 +382,22 @@ fn resolve_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI
|
|||||||
struct GradientAppearance {
|
struct GradientAppearance {
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
gradient_type: GradientType,
|
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
|
/// Resolve the gradient transform, type, and gradient spread 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.
|
/// '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 {
|
fn read_gradient_chain_state(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> GradientAppearance {
|
||||||
let target_input = gradient_chain_target_input(layer, network_interface);
|
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 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 transform_reference = DefinitionIdentifier::ProtoNode(graphene_std::transform_nodes::transform::IDENTIFIER);
|
||||||
let gradient_type_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::gradient_type::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<DAffine2> = Vec::new();
|
let mut transforms_downstream_to_upstream: Vec<DAffine2> = Vec::new();
|
||||||
let mut gradient_type: Option<GradientType> = None;
|
let mut gradient_type: Option<GradientType> = None;
|
||||||
let mut spread_method: Option<GradientSpreadMethod> = None;
|
let mut gradient_spread: Option<GradientSpread> = None;
|
||||||
|
|
||||||
for node_id in network_interface
|
for node_id in network_interface
|
||||||
.upstream_flow_back_from_nodes(vec![walk_from], &[], FlowType::HorizontalFlow)
|
.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())
|
&& let Some(TaggedValue::GradientType(value)) = document_node.inputs.get(1).and_then(|input| input.as_value())
|
||||||
{
|
{
|
||||||
gradient_type = Some(*value);
|
gradient_type = Some(*value);
|
||||||
} else if reference == spread_method_reference
|
} else if reference == gradient_spread_reference
|
||||||
&& spread_method.is_none()
|
&& gradient_spread.is_none()
|
||||||
&& let Some(TaggedValue::GradientSpreadMethod(value)) = document_node.inputs.get(1).and_then(|input| input.as_value())
|
&& 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 {
|
GradientAppearance {
|
||||||
transform: composed_transform,
|
transform: composed_transform,
|
||||||
gradient_type: gradient_type.unwrap_or_default(),
|
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,
|
layer,
|
||||||
gradient: self.gradient.clone(),
|
gradient: self.gradient.clone(),
|
||||||
gradient_type: self.appearance.gradient_type,
|
gradient_type: self.appearance.gradient_type,
|
||||||
spread_method: self.appearance.spread_method,
|
gradient_spread: self.appearance.gradient_spread,
|
||||||
transform: self.appearance.transform,
|
transform: self.appearance.transform,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -801,9 +801,9 @@ fn dispatch_gradient_chain_writes(layer: LayerNodeIdentifier, gradient: &Gradien
|
|||||||
layer,
|
layer,
|
||||||
gradient_type: appearance.gradient_type,
|
gradient_type: appearance.gradient_type,
|
||||||
});
|
});
|
||||||
responses.add(GraphOperationMessage::GradientSpreadMethodSet {
|
responses.add(GraphOperationMessage::GradientSpreadSet {
|
||||||
layer,
|
layer,
|
||||||
spread_method: appearance.spread_method,
|
gradient_spread: appearance.gradient_spread,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1483,7 +1483,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
GradientAppearance {
|
GradientAppearance {
|
||||||
transform: DAffine2::IDENTITY,
|
transform: DAffine2::IDENTITY,
|
||||||
gradient_type: tool_options.gradient_type,
|
gradient_type: tool_options.gradient_type,
|
||||||
spread_method: tool_options.spread_method,
|
gradient_spread: tool_options.gradient_spread,
|
||||||
},
|
},
|
||||||
GradientSource::Direct,
|
GradientSource::Direct,
|
||||||
),
|
),
|
||||||
@@ -1836,7 +1836,7 @@ fn apply_gradient_update(
|
|||||||
layer,
|
layer,
|
||||||
gradient,
|
gradient,
|
||||||
gradient_type: appearance.gradient_type,
|
gradient_type: appearance.gradient_type,
|
||||||
spread_method: appearance.spread_method,
|
gradient_spread: appearance.gradient_spread,
|
||||||
transform: appearance.transform,
|
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
|
/// 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
|
/// 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.
|
/// single undo entry by the surrounding 'on_commit' callback.
|
||||||
fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessageContext, responses: &mut VecDeque<Message>, new_gradient: Gradient, spread_method: GradientSpreadMethod) {
|
fn apply_stops_update(data: &mut GradientToolData, context: &mut ToolActionMessageContext, responses: &mut VecDeque<Message>, new_gradient: Gradient, gradient_spread: GradientSpread) {
|
||||||
let selected_layers: Vec<_> = context
|
let selected_layers: Vec<_> = context
|
||||||
.document
|
.document
|
||||||
.network_interface
|
.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() {
|
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::GradientStopsSet { layer, stops: new_gradient.clone() });
|
||||||
responses.add(GraphOperationMessage::GradientSpreadMethodSet { layer, spread_method });
|
responses.add(GraphOperationMessage::GradientSpreadSet { layer, gradient_spread });
|
||||||
updated_any_layer = true;
|
updated_any_layer = true;
|
||||||
} else if let Some((_gradient, appearance, _source)) = resolve_gradient(layer, &context.document.network_interface) {
|
} else if let Some((_gradient, appearance, _source)) = resolve_gradient(layer, &context.document.network_interface) {
|
||||||
responses.add(GraphOperationMessage::FillGradientSet {
|
responses.add(GraphOperationMessage::FillGradientSet {
|
||||||
layer,
|
layer,
|
||||||
gradient: new_gradient.clone(),
|
gradient: new_gradient.clone(),
|
||||||
gradient_type: appearance.gradient_type,
|
gradient_type: appearance.gradient_type,
|
||||||
spread_method,
|
gradient_spread,
|
||||||
transform: appearance.transform,
|
transform: appearance.transform,
|
||||||
});
|
});
|
||||||
updated_any_layer = true;
|
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 {
|
if let Some(selected_gradient) = &mut data.selected_gradient {
|
||||||
selected_gradient.gradient = new_gradient.clone();
|
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.
|
// 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::NodeInput;
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graphene_std::color::SRGBA8;
|
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 graphene_std::vector::{Gradient, GradientRamp, GradientStop, fill};
|
||||||
|
|
||||||
use super::gradient_space_transform;
|
use super::gradient_space_transform;
|
||||||
|
|
||||||
struct ResolvedGradient {
|
struct ResolvedGradient {
|
||||||
stops: Gradient,
|
stops: Gradient,
|
||||||
spread_method: GradientSpreadMethod,
|
gradient_spread: GradientSpread,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2004,7 +2004,7 @@ mod test_gradient {
|
|||||||
fn new(stops: Gradient, appearance: super::GradientAppearance) -> Self {
|
fn new(stops: Gradient, appearance: super::GradientAppearance) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stops,
|
stops,
|
||||||
spread_method: appearance.spread_method,
|
gradient_spread: appearance.gradient_spread,
|
||||||
transform: appearance.transform,
|
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_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 fill_node = document.network_interface.document_network().nodes.get(&fill_node_id)?;
|
||||||
|
|
||||||
let (stops, spread_method) = match fill_node.input(fill::FillInput)?.as_value()? {
|
let (stops, gradient_spread) = match fill_node.input(fill::FillInput)?.as_value()? {
|
||||||
TaggedValue::GradientRamp(ramp) => (Gradient::from(ramp), ramp.spread_method),
|
TaggedValue::GradientRamp(ramp) => (Gradient::from(ramp), ramp.gradient_spread),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2045,7 +2045,7 @@ mod test_gradient {
|
|||||||
|
|
||||||
let gradient = ResolvedGradient {
|
let gradient = ResolvedGradient {
|
||||||
stops,
|
stops,
|
||||||
spread_method,
|
gradient_spread,
|
||||||
transform: local_transform,
|
transform: local_transform,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2575,77 +2575,77 @@ mod test_gradient {
|
|||||||
assert_eq!(editor.active_document().metadata().all_layers().count(), 0, "Expected the layer to be deleted after drawing a 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.
|
/// Build the JS-boundary ramp the stops swatch's picker would send when choosing a new gradient spread.
|
||||||
fn ramp_with_spread(stops: &Gradient, spread_method: GradientSpreadMethod) -> GradientRamp<SRGBA8> {
|
fn ramp_with_spread(stops: &Gradient, gradient_spread: GradientSpread) -> GradientRamp<SRGBA8> {
|
||||||
GradientRamp::<SRGBA8>::from(&GradientRamp {
|
GradientRamp::<SRGBA8>::from(&GradientRamp {
|
||||||
spread_method,
|
gradient_spread,
|
||||||
..GradientRamp::from(stops)
|
..GradientRamp::from(stops)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn change_spread_method() {
|
async fn change_gradient_spread() {
|
||||||
let mut editor = EditorTestUtils::create();
|
let mut editor = EditorTestUtils::create();
|
||||||
editor.new_document().await;
|
editor.new_document().await;
|
||||||
editor.drag_tool(ToolType::Rectangle, 0., 0., 100., 100., ModifierKeys::empty()).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;
|
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;
|
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
|
editor
|
||||||
.handle_message(GradientToolMessage::UpdateRamp {
|
.handle_message(GradientToolMessage::UpdateRamp {
|
||||||
ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Repeat),
|
ramp: ramp_with_spread(&gradient.stops, GradientSpread::Repeat),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (gradient, _) = get_gradient_from_fill(&mut editor).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
|
editor
|
||||||
.handle_message(GradientToolMessage::UpdateRamp {
|
.handle_message(GradientToolMessage::UpdateRamp {
|
||||||
ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Reflect),
|
ramp: ramp_with_spread(&gradient.stops, GradientSpread::Reflect),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (gradient, _) = get_gradient_from_fill(&mut editor).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]
|
#[tokio::test]
|
||||||
async fn change_spread_method_chain() {
|
async fn change_gradient_spread_chain() {
|
||||||
let mut editor = EditorTestUtils::create();
|
let mut editor = EditorTestUtils::create();
|
||||||
editor.new_document().await;
|
editor.new_document().await;
|
||||||
let layer = create_fill_gradient_chain_layer(&mut editor).await;
|
let layer = create_fill_gradient_chain_layer(&mut editor).await;
|
||||||
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }).await;
|
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }).await;
|
||||||
editor.select_tool(ToolType::Gradient).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;
|
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
|
editor
|
||||||
.handle_message(GradientToolMessage::UpdateRamp {
|
.handle_message(GradientToolMessage::UpdateRamp {
|
||||||
ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Repeat),
|
ramp: ramp_with_spread(&gradient.stops, GradientSpread::Repeat),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (gradient, _) = get_gradient_from_chain(&mut editor).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
|
editor
|
||||||
.handle_message(GradientToolMessage::UpdateRamp {
|
.handle_message(GradientToolMessage::UpdateRamp {
|
||||||
ramp: ramp_with_spread(&gradient.stops, GradientSpreadMethod::Reflect),
|
ramp: ramp_with_spread(&gradient.stops, GradientSpread::Reflect),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (gradient, _) = get_gradient_from_chain(&mut editor).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]
|
#[tokio::test]
|
||||||
@@ -2797,7 +2797,7 @@ mod test_gradient {
|
|||||||
// graph space rather than stranded at the origin.
|
// graph space rather than stranded at the origin.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn gradient_chain_node_on_fill_secondary_input_takes_feeder_slot() {
|
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();
|
let mut editor = EditorTestUtils::create();
|
||||||
editor.new_document().await;
|
editor.new_document().await;
|
||||||
@@ -2855,17 +2855,17 @@ mod test_gradient {
|
|||||||
.await;
|
.await;
|
||||||
let feeder_position = editor.active_document_mut().network_interface.position(&gradient_value_id, &[]).expect("Gradient Value position");
|
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.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }).await;
|
||||||
editor.select_tool(ToolType::Gradient).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");
|
let stops = get_gradient_stops(layer, &editor.active_document().network_interface).expect("the chain layer should resolve its gradient stops");
|
||||||
editor
|
editor
|
||||||
.handle_message(GradientToolMessage::UpdateRamp {
|
.handle_message(GradientToolMessage::UpdateRamp {
|
||||||
ramp: ramp_with_spread(&stops, GradientSpreadMethod::Reflect),
|
ramp: ramp_with_spread(&stops, GradientSpread::Reflect),
|
||||||
})
|
})
|
||||||
.await;
|
.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 spread_node_id = {
|
||||||
let network_interface = &editor.active_document().network_interface;
|
let network_interface = &editor.active_document().network_interface;
|
||||||
network_interface
|
network_interface
|
||||||
@@ -2874,10 +2874,10 @@ mod test_gradient {
|
|||||||
.keys()
|
.keys()
|
||||||
.copied()
|
.copied()
|
||||||
.find(|node_id| network_interface.reference(node_id, &[]).as_ref() == Some(&spread_reference))
|
.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");
|
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");
|
assert_eq!(spread_position, feeder_position, "the inserted node should occupy the feeder's former slot, not the graph origin");
|
||||||
|
|||||||
@@ -552,7 +552,8 @@ tagged_value! {
|
|||||||
StrokeAlign(vector::style::StrokeAlign),
|
StrokeAlign(vector::style::StrokeAlign),
|
||||||
PaintOrder(vector::style::PaintOrder),
|
PaintOrder(vector::style::PaintOrder),
|
||||||
GradientType(vector::style::GradientType),
|
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),
|
ReferencePoint(vector::ReferencePoint),
|
||||||
CentroidType(vector::misc::CentroidType),
|
CentroidType(vector::misc::CentroidType),
|
||||||
BooleanOperation(vector::misc::BooleanOperation),
|
BooleanOperation(vector::misc::BooleanOperation),
|
||||||
@@ -1021,7 +1022,7 @@ mod paint_default_parsing {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod gradient_shape_migration {
|
mod gradient_shape_migration {
|
||||||
use graphic_types::vector_types::GradientSpreadMethod;
|
use graphic_types::vector_types::GradientSpread;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -1042,7 +1043,7 @@ mod gradient_shape_migration {
|
|||||||
let mut gradient = Gradient::from(vec![Color::BLACK, Color::WHITE]);
|
let mut gradient = Gradient::from(vec![Color::BLACK, Color::WHITE]);
|
||||||
gradient.set_positions(&[0.2, 0.9]);
|
gradient.set_positions(&[0.2, 0.9]);
|
||||||
let value = TaggedValue::GradientRamp(GradientRamp {
|
let value = TaggedValue::GradientRamp(GradientRamp {
|
||||||
spread_method: GradientSpreadMethod::Reflect,
|
gradient_spread: GradientSpread::Reflect,
|
||||||
..GradientRamp::from(gradient)
|
..GradientRamp::from(gradient)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use graphene_std::transform::{Footprint, ReferencePoint, ScaleType};
|
|||||||
use graphene_std::vector::misc::{
|
use graphene_std::vector::misc::{
|
||||||
ArcType, BooleanOperation, BoxCorners, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType,
|
ArcType, BooleanOperation, BoxCorners, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType,
|
||||||
};
|
};
|
||||||
use graphene_std::vector::style::{DashPattern, GradientSpreadMethod, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
use graphene_std::vector::style::{DashPattern, GradientSpread, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
use graphene_std::vector::{QRCodeErrorCorrectionLevel, Vector, VectorModification};
|
use graphene_std::vector::{QRCodeErrorCorrectionLevel, Vector, VectorModification};
|
||||||
use graphene_std::{Artboard, Context, Graphic, NodeIO, NodeIOTypes, ProtoNodeIdentifier, concrete, fn_type_fut, future};
|
use graphene_std::{Artboard, Context, Graphic, NodeIO, NodeIOTypes, ProtoNodeIdentifier, concrete, fn_type_fut, future};
|
||||||
use node_registry_macros::async_node;
|
use node_registry_macros::async_node;
|
||||||
@@ -75,7 +75,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<DAffine2>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<DAffine2>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<BlendMode>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<BlendMode>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<GradientType>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<GradientType>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<GradientSpreadMethod>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => List<GradientSpread>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Item<AttributeValueDyn>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Item<AttributeValueDyn>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ListDyn]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ListDyn]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Item<BrushTrace>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Item<BrushTrace>]),
|
||||||
@@ -109,7 +109,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<DAffine2>]),
|
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<DAffine2>]),
|
||||||
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<BlendMode>]),
|
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<BlendMode>]),
|
||||||
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<GradientType>]),
|
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<GradientType>]),
|
||||||
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<GradientSpreadMethod>]),
|
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => List<GradientSpread>]),
|
||||||
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => Item<Artboard>]),
|
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => Item<Artboard>]),
|
||||||
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => Item<Graphic>]),
|
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => Item<Graphic>]),
|
||||||
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => Item<Vector>]),
|
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => Item<Vector>]),
|
||||||
@@ -332,7 +332,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
StrokeCap,
|
StrokeCap,
|
||||||
PaintOrder,
|
PaintOrder,
|
||||||
GradientType,
|
GradientType,
|
||||||
GradientSpreadMethod,
|
GradientSpread,
|
||||||
DashPattern,
|
DashPattern,
|
||||||
BoxCorners,
|
BoxCorners,
|
||||||
MergeByDistanceAlgorithm,
|
MergeByDistanceAlgorithm,
|
||||||
@@ -421,7 +421,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
DAffine2,
|
DAffine2,
|
||||||
BlendMode,
|
BlendMode,
|
||||||
GradientType,
|
GradientType,
|
||||||
GradientSpreadMethod
|
GradientSpread
|
||||||
));
|
));
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
node_types.extend(list_dyn_rows!(Raster<GPU>));
|
node_types.extend(list_dyn_rows!(Raster<GPU>));
|
||||||
@@ -536,7 +536,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
attribute_value_node!(Item<Color>),
|
attribute_value_node!(Item<Color>),
|
||||||
attribute_value_node!(Item<BlendMode>),
|
attribute_value_node!(Item<BlendMode>),
|
||||||
attribute_value_node!(Item<GradientType>),
|
attribute_value_node!(Item<GradientType>),
|
||||||
attribute_value_node!(Item<GradientSpreadMethod>),
|
attribute_value_node!(Item<GradientSpread>),
|
||||||
attribute_value_node!(Item<NodeIdPath>),
|
attribute_value_node!(Item<NodeIdPath>),
|
||||||
attribute_value_node!(List<String>),
|
attribute_value_node!(List<String>),
|
||||||
attribute_value_node!(List<Color>),
|
attribute_value_node!(List<Color>),
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ pub use graphene_hash;
|
|||||||
pub use graphene_hash::CacheHash;
|
pub use graphene_hash::CacheHash;
|
||||||
pub use list::{
|
pub use list::{
|
||||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_END,
|
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_END,
|
||||||
ATTR_FONT, ATTR_FONT_SIZE, ATTR_GRADIENT_TYPE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_NAME, ATTR_OPACITY, ATTR_OPACITY_FILL,
|
ATTR_FONT, ATTR_FONT_SIZE, ATTR_GRADIENT_SPREAD, ATTR_GRADIENT_TYPE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_NAME,
|
||||||
ATTR_SPREAD_METHOD, ATTR_START, ATTR_TEXT_ALIGN, ATTR_TRANSFORM, ATTR_TYPE,
|
ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_START, ATTR_TEXT_ALIGN, ATTR_TRANSFORM, ATTR_TYPE,
|
||||||
};
|
};
|
||||||
pub use memo::MemoHash;
|
pub use memo::MemoHash;
|
||||||
pub use no_std_types::AsU32;
|
pub use no_std_types::AsU32;
|
||||||
|
|||||||
@@ -55,9 +55,9 @@ pub const ATTR_DIMENSIONS: &str = "dimensions";
|
|||||||
pub const ATTR_BACKGROUND: &str = "background";
|
pub const ATTR_BACKGROUND: &str = "background";
|
||||||
/// `bool` for whether an artboard clips content to its bounds.
|
/// `bool` for whether an artboard clips content to its bounds.
|
||||||
pub const ATTR_CLIP: &str = "clip";
|
pub const ATTR_CLIP: &str = "clip";
|
||||||
// TODO: Consider adding "spread_method_left" and "spread_method_right" override attributes to allow setting different spread methods on each side of a gradient
|
// TODO: Consider adding "gradient_spread_left" and "gradient_spread_right" override attributes to allow setting different gradient spreads on each side of a gradient
|
||||||
/// Gradient's `GradientSpreadMethod` (`Pad`, `Reflect`, or `Repeat`).
|
/// Gradient's `GradientSpread` (`Pad`, `Reflect`, or `Repeat`).
|
||||||
pub const ATTR_SPREAD_METHOD: &str = "spread_method";
|
pub const ATTR_GRADIENT_SPREAD: &str = "gradient_spread";
|
||||||
/// Gradient's `GradientType` (`Linear` or `Radial`).
|
/// Gradient's `GradientType` (`Linear` or `Radial`).
|
||||||
pub const ATTR_GRADIENT_TYPE: &str = "gradient_type";
|
pub const ATTR_GRADIENT_TYPE: &str = "gradient_type";
|
||||||
/// Gradient stop's `f64` position from 0 to 1 along the gradient, on the `List<Color>` inside a `Gradient`.
|
/// Gradient stop's `f64` position from 0 to 1 along the gradient, on the `List<Color>` inside a `Gradient`.
|
||||||
@@ -1229,7 +1229,7 @@ impl<T: CacheHash> CacheHash for List<T> {
|
|||||||
self.element.cache_hash(state);
|
self.element.cache_hash(state);
|
||||||
|
|
||||||
// Hash every attribute attribute (key + values) rather than just the well-known ones, so changes to user-defined keys
|
// 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 {
|
for (key, attribute) in &self.attributes.attributes {
|
||||||
std::hash::Hash::hash(key.as_str(), state);
|
std::hash::Hash::hash(key.as_str(), state);
|
||||||
attribute.cache_hash_dyn(state);
|
attribute.cache_hash_dyn(state);
|
||||||
|
|||||||
@@ -666,8 +666,8 @@ mod tests {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod graphic_is_opaque_tests {
|
mod graphic_is_opaque_tests {
|
||||||
use core_types::ATTR_SPREAD_METHOD;
|
use core_types::ATTR_GRADIENT_SPREAD;
|
||||||
use vector_types::{GradientSpreadMethod, GradientStop};
|
use vector_types::{GradientSpread, GradientStop};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ mod graphic_is_opaque_tests {
|
|||||||
|
|
||||||
fn gradient_graphic(gradient: Gradient) -> Graphic {
|
fn gradient_graphic(gradient: Gradient) -> Graphic {
|
||||||
let mut gradient_list = List::new_from_element(gradient);
|
let mut gradient_list = List::new_from_element(gradient);
|
||||||
gradient_list.set_attribute(ATTR_SPREAD_METHOD, 0, GradientSpreadMethod::Pad);
|
gradient_list.set_attribute(ATTR_GRADIENT_SPREAD, 0, GradientSpread::Pad);
|
||||||
Graphic::Gradient(gradient_list)
|
Graphic::Gradient(gradient_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ pub mod migrations {
|
|||||||
pub start: DVec2,
|
pub start: DVec2,
|
||||||
pub end: DVec2,
|
pub end: DVec2,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub spread_method: vector::style::GradientSpreadMethod,
|
pub spread_method: vector::style::GradientSpread,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub absolute: bool,
|
pub absolute: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ use crate::{Render, RenderSvgSegmentList, SvgRender};
|
|||||||
use core_types::color::SRGBA8;
|
use core_types::color::SRGBA8;
|
||||||
use core_types::list::List;
|
use core_types::list::List;
|
||||||
use core_types::uuid::generate_uuid;
|
use core_types::uuid::generate_uuid;
|
||||||
use core_types::{ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD, ATTR_TRANSFORM, Color};
|
use core_types::{ATTR_GRADIENT_SPREAD, ATTR_GRADIENT_TYPE, ATTR_TRANSFORM, Color};
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graphic_types::Graphic;
|
use graphic_types::Graphic;
|
||||||
use graphic_types::vector_types::gradient::GradientType;
|
use graphic_types::vector_types::gradient::GradientType;
|
||||||
use graphic_types::vector_types::vector::style::{PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
use graphic_types::vector_types::vector::style::{PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use vector_types::Gradient;
|
use vector_types::Gradient;
|
||||||
use vector_types::gradient::GradientSpreadMethod;
|
use vector_types::gradient::GradientSpread;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum PaintTarget {
|
pub enum PaintTarget {
|
||||||
@@ -95,7 +95,7 @@ impl RenderExt for List<Gradient> {
|
|||||||
let Some(stops) = self.element(0) else { return 0 };
|
let Some(stops) = self.element(0) else { return 0 };
|
||||||
let gradient_type: GradientType = self.attribute_cloned_or_default(ATTR_GRADIENT_TYPE, 0);
|
let gradient_type: GradientType = self.attribute_cloned_or_default(ATTR_GRADIENT_TYPE, 0);
|
||||||
let local_gradient_transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
let local_gradient_transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||||
let spread_method: GradientSpreadMethod = self.attribute_cloned_or_default(ATTR_SPREAD_METHOD, 0);
|
let gradient_spread: GradientSpread = self.attribute_cloned_or_default(ATTR_GRADIENT_SPREAD, 0);
|
||||||
|
|
||||||
for (position, color, original_midpoint) in stops.interpolated_samples() {
|
for (position, color, original_midpoint) in stops.interpolated_samples() {
|
||||||
stop.push_str("<stop");
|
stop.push_str("<stop");
|
||||||
@@ -134,10 +134,10 @@ impl RenderExt for List<Gradient> {
|
|||||||
format!(r#" gradientTransform="{gradient_transform}""#)
|
format!(r#" gradientTransform="{gradient_transform}""#)
|
||||||
};
|
};
|
||||||
|
|
||||||
let spread_method = if spread_method == GradientSpreadMethod::Pad {
|
let gradient_spread = if gradient_spread == GradientSpread::Pad {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!(r#" spreadMethod="{}""#, spread_method.svg_name())
|
format!(r#" spreadMethod="{}""#, gradient_spread.svg_name())
|
||||||
};
|
};
|
||||||
|
|
||||||
let gradient_id = generate_uuid();
|
let gradient_id = generate_uuid();
|
||||||
@@ -146,14 +146,14 @@ impl RenderExt for List<Gradient> {
|
|||||||
GradientType::Linear => {
|
GradientType::Linear => {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
svg_defs,
|
svg_defs,
|
||||||
r#"<linearGradient id="{}" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0"{spread_method}{gradient_transform}>{}</linearGradient>"#,
|
r#"<linearGradient id="{}" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0"{gradient_spread}{gradient_transform}>{}</linearGradient>"#,
|
||||||
gradient_id, stop
|
gradient_id, stop
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
GradientType::Radial => {
|
GradientType::Radial => {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
svg_defs,
|
svg_defs,
|
||||||
r#"<radialGradient id="{}" gradientUnits="userSpaceOnUse" cx="0" cy="0" r="1"{spread_method}{gradient_transform}>{}</radialGradient>"#,
|
r#"<radialGradient id="{}" gradientUnits="userSpaceOnUse" cx="0" cy="0" r="1"{gradient_spread}{gradient_transform}>{}</radialGradient>"#,
|
||||||
gradient_id, stop
|
gradient_id, stop
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use core_types::transform::Footprint;
|
|||||||
use core_types::uuid::{NodeId, generate_uuid};
|
use core_types::uuid::{NodeId, generate_uuid};
|
||||||
use core_types::{
|
use core_types::{
|
||||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_FONT,
|
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_FONT,
|
||||||
ATTR_FONT_SIZE, ATTR_GRADIENT_TYPE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD,
|
ATTR_FONT_SIZE, ATTR_GRADIENT_SPREAD, ATTR_GRADIENT_TYPE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_OPACITY, ATTR_OPACITY_FILL,
|
||||||
ATTR_TEXT_ALIGN, ATTR_TRANSFORM,
|
ATTR_TEXT_ALIGN, ATTR_TRANSFORM,
|
||||||
};
|
};
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
@@ -39,7 +39,7 @@ use std::fmt::Write;
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
use vector_types::gradient::GradientSpreadMethod;
|
use vector_types::gradient::GradientSpread;
|
||||||
use vello::*;
|
use vello::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
@@ -424,7 +424,7 @@ fn create_peniko_gradient_brush(gradient_list: &List<Gradient>, multiplied_trans
|
|||||||
|
|
||||||
let gradient_type: GradientType = gradient_list.attribute_cloned_or_default(ATTR_GRADIENT_TYPE, 0);
|
let gradient_type: GradientType = gradient_list.attribute_cloned_or_default(ATTR_GRADIENT_TYPE, 0);
|
||||||
let gradient_transform: DAffine2 = gradient_list.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
let gradient_transform: DAffine2 = gradient_list.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||||
let spread_method: GradientSpreadMethod = gradient_list.attribute_cloned_or_default(ATTR_SPREAD_METHOD, 0);
|
let gradient_spread: GradientSpread = gradient_list.attribute_cloned_or_default(ATTR_GRADIENT_SPREAD, 0);
|
||||||
|
|
||||||
let peniko_stops = peniko_color_stops(stops);
|
let peniko_stops = peniko_color_stops(stops);
|
||||||
|
|
||||||
@@ -446,10 +446,10 @@ fn create_peniko_gradient_brush(gradient_list: &List<Gradient>, multiplied_trans
|
|||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
},
|
},
|
||||||
extend: match spread_method {
|
extend: match gradient_spread {
|
||||||
GradientSpreadMethod::Pad => peniko::Extend::Pad,
|
GradientSpread::Pad => peniko::Extend::Pad,
|
||||||
GradientSpreadMethod::Reflect => peniko::Extend::Reflect,
|
GradientSpread::Reflect => peniko::Extend::Reflect,
|
||||||
GradientSpreadMethod::Repeat => peniko::Extend::Repeat,
|
GradientSpread::Repeat => peniko::Extend::Repeat,
|
||||||
},
|
},
|
||||||
stops: peniko_stops,
|
stops: peniko_stops,
|
||||||
interpolation_alpha_space: peniko::InterpolationAlphaSpace::Premultiplied,
|
interpolation_alpha_space: peniko::InterpolationAlphaSpace::Premultiplied,
|
||||||
@@ -2094,7 +2094,7 @@ impl Render for List<Gradient> {
|
|||||||
let blend_mode: BlendMode = self.attribute_cloned_or_default(ATTR_BLEND_MODE, index);
|
let blend_mode: BlendMode = self.attribute_cloned_or_default(ATTR_BLEND_MODE, index);
|
||||||
let opacity_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY, index, 1.);
|
let opacity_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY, index, 1.);
|
||||||
let opacity_fill_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY_FILL, index, 1.);
|
let opacity_fill_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY_FILL, index, 1.);
|
||||||
let spread_method: GradientSpreadMethod = self.attribute_cloned_or_default(ATTR_SPREAD_METHOD, index);
|
let gradient_spread: GradientSpread = self.attribute_cloned_or_default(ATTR_GRADIENT_SPREAD, index);
|
||||||
let gradient_type: GradientType = self.attribute_cloned_or_default(ATTR_GRADIENT_TYPE, index);
|
let gradient_type: GradientType = self.attribute_cloned_or_default(ATTR_GRADIENT_TYPE, index);
|
||||||
let tag = if thumbnail_rect.is_some() { "rect" } else { "polyline" };
|
let tag = if thumbnail_rect.is_some() { "rect" } else { "polyline" };
|
||||||
render.leaf_tag(tag, |attributes| {
|
render.leaf_tag(tag, |attributes| {
|
||||||
@@ -2133,10 +2133,10 @@ impl Render for List<Gradient> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let gradient_id = generate_uuid();
|
let gradient_id = generate_uuid();
|
||||||
let spread_method_attribute = if spread_method == GradientSpreadMethod::Pad {
|
let gradient_spread_attribute = if gradient_spread == GradientSpread::Pad {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} 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
|
// The unit gradient line is the +X unit vector in local space, before the item's transform is applied
|
||||||
@@ -2144,13 +2144,13 @@ impl Render for List<Gradient> {
|
|||||||
GradientType::Linear => {
|
GradientType::Linear => {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
&mut attributes.0.svg_defs,
|
&mut attributes.0.svg_defs,
|
||||||
r#"<linearGradient id="{gradient_id}" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0"{spread_method_attribute}{gradient_transform_attribute}>{stop_string}</linearGradient>"#
|
r#"<linearGradient id="{gradient_id}" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0"{gradient_spread_attribute}{gradient_transform_attribute}>{stop_string}</linearGradient>"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
GradientType::Radial => {
|
GradientType::Radial => {
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
&mut attributes.0.svg_defs,
|
&mut attributes.0.svg_defs,
|
||||||
r#"<radialGradient id="{gradient_id}" gradientUnits="userSpaceOnUse" cx="0" cy="0" r="1"{spread_method_attribute}{gradient_transform_attribute}>{stop_string}</radialGradient>"#
|
r#"<radialGradient id="{gradient_id}" gradientUnits="userSpaceOnUse" cx="0" cy="0" r="1"{gradient_spread_attribute}{gradient_transform_attribute}>{stop_string}</radialGradient>"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2176,10 +2176,10 @@ impl Render for List<Gradient> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (((index, gradient), spread_method), gradient_type) in self
|
for (((index, gradient), gradient_spread), gradient_type) in self
|
||||||
.iter_element_values()
|
.iter_element_values()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.zip(self.iter_attribute_values_or_default::<GradientSpreadMethod>(ATTR_SPREAD_METHOD))
|
.zip(self.iter_attribute_values_or_default::<GradientSpread>(ATTR_GRADIENT_SPREAD))
|
||||||
.zip(self.iter_attribute_values_or_default::<GradientType>(ATTR_GRADIENT_TYPE))
|
.zip(self.iter_attribute_values_or_default::<GradientType>(ATTR_GRADIENT_TYPE))
|
||||||
{
|
{
|
||||||
let transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, index);
|
let transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, index);
|
||||||
@@ -2193,10 +2193,10 @@ impl Render for List<Gradient> {
|
|||||||
|
|
||||||
let stops = peniko_color_stops(gradient);
|
let stops = peniko_color_stops(gradient);
|
||||||
|
|
||||||
let extend = match spread_method {
|
let extend = match gradient_spread {
|
||||||
GradientSpreadMethod::Pad => peniko::Extend::Pad,
|
GradientSpread::Pad => peniko::Extend::Pad,
|
||||||
GradientSpreadMethod::Reflect => peniko::Extend::Reflect,
|
GradientSpread::Reflect => peniko::Extend::Reflect,
|
||||||
GradientSpreadMethod::Repeat => peniko::Extend::Repeat,
|
GradientSpread::Repeat => peniko::Extend::Repeat,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The unit gradient line is the +X unit vector in local space, before the item's transform is applied.
|
// The unit gradient line is the +X unit vector in local space, before the item's transform is applied.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use core_types::Color;
|
use core_types::Color;
|
||||||
use core_types::color::SRGBA8;
|
use core_types::color::SRGBA8;
|
||||||
use core_types::list::{ATTR_MIDPOINT, ATTR_POSITION, ATTR_SPREAD_METHOD, Item, List};
|
use core_types::list::{ATTR_GRADIENT_SPREAD, ATTR_MIDPOINT, ATTR_POSITION, Item, List};
|
||||||
use core_types::render_complexity::RenderComplexity;
|
use core_types::render_complexity::RenderComplexity;
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
@@ -102,9 +102,9 @@ impl GradientStops<SRGBA8> {
|
|||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct GradientRamp<C = Color> {
|
pub struct GradientRamp<C = Color> {
|
||||||
pub stops: GradientStops<C>,
|
pub stops: GradientStops<C>,
|
||||||
#[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))]
|
#[cfg_attr(feature = "wasm", tsify(optional))]
|
||||||
pub spread_method: GradientSpreadMethod,
|
pub gradient_spread: GradientSpread,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<C: dyn_any::StaticTypeSized> dyn_any::StaticType for GradientRamp<C> {
|
unsafe impl<C: dyn_any::StaticTypeSized> dyn_any::StaticType for GradientRamp<C> {
|
||||||
@@ -115,7 +115,7 @@ impl<C> From<GradientStops<C>> for GradientRamp<C> {
|
|||||||
fn from(stops: GradientStops<C>) -> Self {
|
fn from(stops: GradientStops<C>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stops,
|
stops,
|
||||||
spread_method: Default::default(),
|
gradient_spread: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ impl From<&Gradient> for GradientRamp {
|
|||||||
fn from(gradient: &Gradient) -> Self {
|
fn from(gradient: &Gradient) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stops: gradient.into(),
|
stops: gradient.into(),
|
||||||
spread_method: Default::default(),
|
gradient_spread: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,8 +152,8 @@ impl From<&GradientRamp> for Gradient {
|
|||||||
impl From<GradientRamp> for Item<Gradient> {
|
impl From<GradientRamp> for Item<Gradient> {
|
||||||
fn from(ramp: GradientRamp) -> Self {
|
fn from(ramp: GradientRamp) -> Self {
|
||||||
let mut item = Item::new_from_element(Gradient::from(ramp.stops));
|
let mut item = Item::new_from_element(Gradient::from(ramp.stops));
|
||||||
if !ramp.spread_method.is_default() {
|
if !ramp.gradient_spread.is_default() {
|
||||||
item.set_attribute(ATTR_SPREAD_METHOD, ramp.spread_method);
|
item.set_attribute(ATTR_GRADIENT_SPREAD, ramp.gradient_spread);
|
||||||
}
|
}
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ impl From<&Item<Gradient>> for GradientRamp {
|
|||||||
fn from(item: &Item<Gradient>) -> Self {
|
fn from(item: &Item<Gradient>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stops: item.element().into(),
|
stops: item.element().into(),
|
||||||
spread_method: item.attribute_cloned_or_default(ATTR_SPREAD_METHOD),
|
gradient_spread: item.attribute_cloned_or_default(ATTR_GRADIENT_SPREAD),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ impl From<&GradientRamp> for GradientRamp<SRGBA8> {
|
|||||||
fn from(ramp: &GradientRamp) -> Self {
|
fn from(ramp: &GradientRamp) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stops: ramp.into(),
|
stops: ramp.into(),
|
||||||
spread_method: ramp.spread_method,
|
gradient_spread: ramp.gradient_spread,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ impl From<&Gradient> for GradientRamp<SRGBA8> {
|
|||||||
fn from(gradient: &Gradient) -> Self {
|
fn from(gradient: &Gradient) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stops: gradient.into(),
|
stops: gradient.into(),
|
||||||
spread_method: Default::default(),
|
gradient_spread: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,7 +206,7 @@ impl From<&Gradient> for GradientRamp<SRGBA8> {
|
|||||||
impl From<&GradientRamp<SRGBA8>> for GradientRamp {
|
impl From<&GradientRamp<SRGBA8>> for GradientRamp {
|
||||||
fn from(ramp: &GradientRamp<SRGBA8>) -> Self {
|
fn from(ramp: &GradientRamp<SRGBA8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
spread_method: ramp.spread_method,
|
gradient_spread: ramp.gradient_spread,
|
||||||
..Self::from(&ramp.stops)
|
..Self::from(&ramp.stops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -600,12 +600,12 @@ impl Gradient {
|
|||||||
stops
|
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.
|
/// 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, spread_method: GradientSpreadMethod) -> Color {
|
pub fn evaluate(&self, t: f64, gradient_spread: GradientSpread) -> Color {
|
||||||
let t = match spread_method {
|
let t = match gradient_spread {
|
||||||
GradientSpreadMethod::Pad => t.clamp(0., 1.),
|
GradientSpread::Pad => t.clamp(0., 1.),
|
||||||
GradientSpreadMethod::Repeat => t.rem_euclid(1.),
|
GradientSpread::Repeat => t.rem_euclid(1.),
|
||||||
GradientSpreadMethod::Reflect => {
|
GradientSpread::Reflect => {
|
||||||
let cycle = t.rem_euclid(2.);
|
let cycle = t.rem_euclid(2.);
|
||||||
if cycle > 1. { 2. - cycle } else { cycle }
|
if cycle > 1. { 2. - cycle } else { cycle }
|
||||||
}
|
}
|
||||||
@@ -784,7 +784,7 @@ impl Gradient {
|
|||||||
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, graphene_hash::CacheHash, DynAny, node_macro::ChoiceType)]
|
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, graphene_hash::CacheHash, DynAny, node_macro::ChoiceType)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[widget(Radio)]
|
#[widget(Radio)]
|
||||||
pub enum GradientSpreadMethod {
|
pub enum GradientSpread {
|
||||||
/// Extends the end colors outward.
|
/// Extends the end colors outward.
|
||||||
#[default]
|
#[default]
|
||||||
Pad,
|
Pad,
|
||||||
@@ -795,12 +795,12 @@ pub enum GradientSpreadMethod {
|
|||||||
// TODO: Add a "Clear" variant that returns transparent black outside the gradient's range
|
// 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 {
|
pub fn svg_name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
GradientSpreadMethod::Pad => "pad",
|
GradientSpread::Pad => "pad",
|
||||||
GradientSpreadMethod::Reflect => "reflect",
|
GradientSpread::Reflect => "reflect",
|
||||||
GradientSpreadMethod::Repeat => "repeat",
|
GradientSpread::Repeat => "repeat",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,39 +905,39 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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 default_spread = GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE]));
|
||||||
let json = serde_json::to_string(&default_spread).unwrap();
|
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::<GradientRamp>(&json).unwrap(), default_spread);
|
assert_eq!(serde_json::from_str::<GradientRamp>(&json).unwrap(), default_spread);
|
||||||
|
|
||||||
let repeating = GradientRamp {
|
let repeating = GradientRamp {
|
||||||
spread_method: GradientSpreadMethod::Repeat,
|
gradient_spread: GradientSpread::Repeat,
|
||||||
..default_spread.clone()
|
..default_spread.clone()
|
||||||
};
|
};
|
||||||
let json = serde_json::to_string(&repeating).unwrap();
|
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::<GradientRamp>(&json).unwrap(), repeating);
|
assert_eq!(serde_json::from_str::<GradientRamp>(&json).unwrap(), repeating);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn spread_method_round_trips_through_the_item_attribute() {
|
fn gradient_spread_round_trips_through_the_item_attribute() {
|
||||||
let ramp = GradientRamp {
|
let ramp = GradientRamp {
|
||||||
spread_method: GradientSpreadMethod::Repeat,
|
gradient_spread: GradientSpread::Repeat,
|
||||||
..GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE]))
|
..GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE]))
|
||||||
};
|
};
|
||||||
|
|
||||||
let item = Item::<Gradient>::from(ramp.clone());
|
let item = Item::<Gradient>::from(ramp.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
item.attribute_cloned_or_default::<GradientSpreadMethod>(ATTR_SPREAD_METHOD),
|
item.attribute_cloned_or_default::<GradientSpread>(ATTR_GRADIENT_SPREAD),
|
||||||
GradientSpreadMethod::Repeat,
|
GradientSpread::Repeat,
|
||||||
"the runtime item should carry the spread method as its attribute"
|
"the runtime item should carry the gradient spread as its attribute"
|
||||||
);
|
);
|
||||||
assert_eq!(GradientRamp::from(&item), ramp);
|
assert_eq!(GradientRamp::from(&item), ramp);
|
||||||
|
|
||||||
let padded = Item::<Gradient>::from(GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE])));
|
let padded = Item::<Gradient>::from(GradientRamp::from(Gradient::from(vec![Color::BLACK, Color::WHITE])));
|
||||||
assert!(
|
assert!(
|
||||||
padded.attribute::<GradientSpreadMethod>(ATTR_SPREAD_METHOD).is_none(),
|
padded.attribute::<GradientSpread>(ATTR_GRADIENT_SPREAD).is_none(),
|
||||||
"the default Pad must stay absent rather than materialize"
|
"the default Pad must stay absent rather than materialize"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ pub mod vector;
|
|||||||
|
|
||||||
// Re-export commonly used types at the crate root
|
// Re-export commonly used types at the crate root
|
||||||
pub use core_types as gcore;
|
pub use core_types as gcore;
|
||||||
pub use gradient::{Gradient, GradientRamp, GradientSpreadMethod, GradientStop, GradientType};
|
pub use gradient::{Gradient, GradientRamp, GradientSpread, GradientStop, GradientType};
|
||||||
pub use math::{QuadExt, RectExt};
|
pub use math::{QuadExt, RectExt};
|
||||||
pub use subpath::Subpath;
|
pub use subpath::Subpath;
|
||||||
pub use vector::Vector;
|
pub use vector::Vector;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use rand::SeedableRng;
|
|||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use raster_types::{CPU, GPU, Raster};
|
use raster_types::{CPU, GPU, Raster};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use vector_types::gradient::{GradientSpreadMethod, GradientType};
|
use vector_types::gradient::{GradientSpread, GradientType};
|
||||||
use vector_types::{Gradient, ReferencePoint};
|
use vector_types::{Gradient, ReferencePoint};
|
||||||
|
|
||||||
/// Returns the list with the item at the specified index removed.
|
/// Returns the list with the item at the specified index removed.
|
||||||
@@ -568,7 +568,7 @@ async fn write_attribute<T: AnyHash + Clone + Send + Sync + CacheHash>(
|
|||||||
List<Artboard>,
|
List<Artboard>,
|
||||||
List<BlendMode>,
|
List<BlendMode>,
|
||||||
List<GradientType>,
|
List<GradientType>,
|
||||||
List<GradientSpreadMethod>,
|
List<GradientSpread>,
|
||||||
)]
|
)]
|
||||||
content: List<T>,
|
content: List<T>,
|
||||||
/// The attribute name (key) to write or replace.
|
/// The attribute name (key) to write or replace.
|
||||||
@@ -730,18 +730,18 @@ fn read_attribute_gradient_type(
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a named `GradientSpreadMethod` attribute from the input list, outputting each value as an element of a new `GradientSpreadMethod[]`.
|
/// Reads a named `GradientSpread` attribute from the input list, outputting each value as an element of a new `GradientSpread[]`.
|
||||||
#[node_macro::node(category("Attributes: Read"))]
|
#[node_macro::node(category("Attributes: Read"))]
|
||||||
fn read_attribute_spread_method(
|
fn read_attribute_gradient_spread(
|
||||||
_: impl Ctx,
|
_: impl Ctx,
|
||||||
content: ListDyn,
|
content: ListDyn,
|
||||||
/// The attribute name (key) to read.
|
/// The attribute name (key) to read.
|
||||||
name: Item<String>,
|
name: Item<String>,
|
||||||
) -> List<GradientSpreadMethod> {
|
) -> List<GradientSpread> {
|
||||||
let name = name.into_element();
|
let name = name.into_element();
|
||||||
let mut result = List::with_capacity(content.len());
|
let mut result = List::with_capacity(content.len());
|
||||||
for index in 0..content.len() {
|
for index in 0..content.len() {
|
||||||
let Some(value) = content.attribute::<GradientSpreadMethod>(&name, index) else { continue };
|
let Some(value) = content.attribute::<GradientSpread>(&name, index) else { continue };
|
||||||
result.push(Item::new_from_element(*value));
|
result.push(Item::new_from_element(*value));
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
|||||||
@@ -1387,9 +1387,9 @@ fn gradient_type(_: impl Ctx, gradient: Item<Gradient>, gradient_type: Item<vect
|
|||||||
|
|
||||||
/// Sets how each gradient in the input list extends past its endpoints: Pad, Reflect, or Repeat.
|
/// Sets how each gradient in the input list extends past its endpoints: Pad, Reflect, or Repeat.
|
||||||
#[node_macro::node(category("Gradient"))]
|
#[node_macro::node(category("Gradient"))]
|
||||||
fn spread_method(_: impl Ctx, gradient: Item<Gradient>, spread_method: Item<vector_types::GradientSpreadMethod>) -> Item<Gradient> {
|
fn gradient_spread(_: impl Ctx, gradient: Item<Gradient>, gradient_spread: Item<vector_types::GradientSpread>) -> Item<Gradient> {
|
||||||
let mut gradient = gradient;
|
let mut gradient = gradient;
|
||||||
gradient.set_attribute(core_types::ATTR_SPREAD_METHOD, *spread_method.element());
|
gradient.set_attribute(core_types::ATTR_GRADIENT_SPREAD, *gradient_spread.element());
|
||||||
gradient
|
gradient
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1417,11 +1417,11 @@ fn gradient_midpoints(_: impl Ctx, gradient: Item<Gradient>, midpoints: List<f64
|
|||||||
gradient
|
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"))]
|
#[node_macro::node(category("Color"))]
|
||||||
fn sample_gradient(_: impl Ctx, _primary: (), #[default(Color::BLACK, Color::WHITE)] gradient: Item<Gradient>, position: Item<Fraction>) -> Item<Color> {
|
fn sample_gradient(_: impl Ctx, _primary: (), #[default(Color::BLACK, Color::WHITE)] gradient: Item<Gradient>, position: Item<Fraction>) -> Item<Color> {
|
||||||
let spread_method = gradient.attribute_cloned_or_default::<vector_types::GradientSpreadMethod>(core_types::ATTR_SPREAD_METHOD);
|
let gradient_spread = gradient.attribute_cloned_or_default::<vector_types::GradientSpread>(core_types::ATTR_GRADIENT_SPREAD);
|
||||||
let color = gradient.element().evaluate(*position.element(), spread_method);
|
let color = gradient.element().evaluate(*position.element(), gradient_spread);
|
||||||
Item::new_from_element(color)
|
Item::new_from_element(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use core_types::list::{ATTR_FILL, Item, ItemAttributeValues, List};
|
use core_types::list::{ATTR_FILL, Item, ItemAttributeValues, List};
|
||||||
use core_types::{
|
use core_types::{
|
||||||
ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_GRADIENT_TYPE, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD, ATTR_TRANSFORM, Color, Ctx,
|
ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_GRADIENT_SPREAD, ATTR_GRADIENT_TYPE, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, Color, Ctx,
|
||||||
};
|
};
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graphic_types::graphic::{bake_paint_transforms, set_paint_attribute};
|
use graphic_types::graphic::{bake_paint_transforms, set_paint_attribute};
|
||||||
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::subpath::{ManipulatorGroup, Subpath};
|
||||||
use graphic_types::vector_types::vector::PointId;
|
use graphic_types::vector_types::vector::PointId;
|
||||||
use graphic_types::vector_types::vector::algorithms::merge_by_distance::MergeByDistanceExt;
|
use graphic_types::vector_types::vector::algorithms::merge_by_distance::MergeByDistanceExt;
|
||||||
@@ -286,8 +286,8 @@ fn flatten_vector(graphic_list: &List<Graphic>) -> List<Vector> {
|
|||||||
if let Some(gradient_type) = attributes.remove::<GradientType>(ATTR_GRADIENT_TYPE) {
|
if let Some(gradient_type) = attributes.remove::<GradientType>(ATTR_GRADIENT_TYPE) {
|
||||||
gradient_paint.set_attribute(ATTR_GRADIENT_TYPE, 0, gradient_type);
|
gradient_paint.set_attribute(ATTR_GRADIENT_TYPE, 0, gradient_type);
|
||||||
}
|
}
|
||||||
if let Some(spread_method) = attributes.remove::<GradientSpreadMethod>(ATTR_SPREAD_METHOD) {
|
if let Some(gradient_spread) = attributes.remove::<GradientSpread>(ATTR_GRADIENT_SPREAD) {
|
||||||
gradient_paint.set_attribute(ATTR_SPREAD_METHOD, 0, spread_method);
|
gradient_paint.set_attribute(ATTR_GRADIENT_SPREAD, 0, gradient_spread);
|
||||||
}
|
}
|
||||||
set_paint_attribute(&mut attributes, ATTR_FILL, gradient_paint);
|
set_paint_attribute(&mut attributes, ATTR_FILL, gradient_paint);
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ async fn gradient_map<T: Adjust<Color> + Send>(
|
|||||||
reverse: Item<bool>,
|
reverse: Item<bool>,
|
||||||
) -> Item<T> {
|
) -> Item<T> {
|
||||||
let mut image = image;
|
let mut image = image;
|
||||||
let spread_method = gradient.attribute_cloned_or_default::<vector_types::GradientSpreadMethod>(core_types::ATTR_SPREAD_METHOD);
|
let gradient_spread = gradient.attribute_cloned_or_default::<vector_types::GradientSpread>(core_types::ATTR_GRADIENT_SPREAD);
|
||||||
let gradient = gradient.into_element();
|
let gradient = gradient.into_element();
|
||||||
let reverse = reverse.into_element();
|
let reverse = reverse.into_element();
|
||||||
|
|
||||||
image.element_mut().adjust(|color| {
|
image.element_mut().adjust(|color| {
|
||||||
let intensity = color.luminance_rec_709();
|
let intensity = color.luminance_rec_709();
|
||||||
let intensity = if reverse { 1. - intensity } else { intensity };
|
let intensity = if reverse { 1. - intensity } else { intensity };
|
||||||
gradient.evaluate(intensity as f64, spread_method)
|
gradient.evaluate(intensity as f64, gradient_spread)
|
||||||
});
|
});
|
||||||
|
|
||||||
image
|
image
|
||||||
|
|||||||
Reference in New Issue
Block a user