Skip to content

Commit 1ac0b37

Browse files
committed
Add Table<GradientStops> gradient rendering
* Add SVG and Vello renderers for Table<GradientStops> * Add thumbnail rendering for Table<GradientStops> * Use row transform to map (0,0), (1,0) unit line to document space * Set 100px width for the initially created gradient * Add support of table gradients for the gradient tool
1 parent 5edb00b commit 1ac0b37

19 files changed

Lines changed: 511 additions & 71 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ use graphene_std::raster_types::{CPU, Raster};
1111
use graphene_std::subpath::Subpath;
1212
use graphene_std::table::Table;
1313
use graphene_std::text::{Font, TypesettingConfig};
14-
use graphene_std::vector::PointId;
15-
use graphene_std::vector::VectorModificationType;
1614
use graphene_std::vector::style::{Fill, Stroke};
15+
use graphene_std::vector::{GradientStops, PointId, VectorModificationType};
1716

1817
#[impl_message(Message, DocumentMessage, GraphOperation)]
1918
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -26,6 +25,11 @@ pub enum GraphOperationMessage {
2625
layer: LayerNodeIdentifier,
2726
fill: f64,
2827
},
28+
GradientTableSet {
29+
layer: LayerNodeIdentifier,
30+
stops: GradientStops,
31+
transform: DAffine2,
32+
},
2933
OpacitySet {
3034
layer: LayerNodeIdentifier,
3135
opacity: f64,

editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
4545
modify_inputs.blending_fill_set(fill);
4646
}
4747
}
48+
GraphOperationMessage::GradientTableSet { layer, stops, transform } => {
49+
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) {
50+
modify_inputs.gradient_table_set(stops, transform);
51+
}
52+
}
4853
GraphOperationMessage::OpacitySet { layer, opacity } => {
4954
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) {
5055
modify_inputs.opacity_set(opacity);

editor/src/messages/portfolio/document/graph_operation/utility_types.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ use graphene_std::brush::brush_stroke::BrushStroke;
1212
use graphene_std::raster::BlendMode;
1313
use graphene_std::raster_types::{CPU, Raster};
1414
use graphene_std::subpath::Subpath;
15-
use graphene_std::table::Table;
15+
use graphene_std::table::{Table, TableRow};
1616
use graphene_std::text::{Font, TypesettingConfig};
17-
use graphene_std::vector::Vector;
1817
use graphene_std::vector::style::{Fill, Stroke};
19-
use graphene_std::vector::{PointId, VectorModificationType};
18+
use graphene_std::vector::{GradientStops, PointId, Vector, VectorModificationType};
2019
use graphene_std::{Graphic, NodeInputDecleration};
2120

2221
#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
@@ -390,6 +389,20 @@ impl<'a> ModifyInputsContext<'a> {
390389
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(fill * 100.), false), false);
391390
}
392391

392+
pub fn gradient_table_set(&mut self, stops: GradientStops, transform: DAffine2) {
393+
let Some(gradient_node_id) = self.existing_proto_node_id(graphene_std::math_nodes::gradient_value::IDENTIFIER, true) else {
394+
return;
395+
};
396+
397+
let table = Table::new_from_row(TableRow {
398+
element: stops,
399+
transform,
400+
..Default::default()
401+
});
402+
let input_connector = InputConnector::node(gradient_node_id, 1);
403+
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::GradientTable(table), false), false);
404+
}
405+
393406
pub fn clip_mode_toggle(&mut self, clip_mode: Option<bool>) {
394407
let clip = !clip_mode.unwrap_or(false);
395408
let Some(clip_node_id) = self.existing_proto_node_id(graphene_std::blending_nodes::blending::IDENTIFIER, true) else {

editor/src/messages/portfolio/document/node_graph/node_properties.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,20 +1152,37 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button:
11521152
.on_commit(commit_value)
11531153
.widget_instance(),
11541154
),
1155-
TaggedValue::GradientTable(gradient_table) => widgets.push(
1156-
color_button
1157-
.value(match gradient_table.iter().next() {
1158-
Some(row) => FillChoice::Gradient(row.element.clone()),
1159-
None => FillChoice::Gradient(GradientStops::default()),
1160-
})
1161-
.on_update(update_value(
1162-
|input: &ColorInput| TaggedValue::GradientTable(input.value.as_gradient().iter().map(|&gradient| TableRow::new_from_element(gradient.clone())).collect()),
1163-
node_id,
1164-
index,
1165-
))
1166-
.on_commit(commit_value)
1167-
.widget_instance(),
1168-
),
1155+
TaggedValue::GradientTable(gradient_table) => {
1156+
let existing_transform = gradient_table.iter().next().map(|row| *row.transform).unwrap_or_default();
1157+
1158+
widgets.push(
1159+
color_button
1160+
.value(match gradient_table.iter().next() {
1161+
Some(row) => FillChoice::Gradient(row.element.clone()),
1162+
None => FillChoice::Gradient(GradientStops::default()),
1163+
})
1164+
.on_update(update_value(
1165+
move |input: &ColorInput| {
1166+
TaggedValue::GradientTable(
1167+
input
1168+
.value
1169+
.as_gradient()
1170+
.iter()
1171+
.map(|&gradient| TableRow {
1172+
element: gradient.clone(),
1173+
transform: existing_transform,
1174+
..Default::default()
1175+
})
1176+
.collect(),
1177+
)
1178+
},
1179+
node_id,
1180+
index,
1181+
))
1182+
.on_commit(commit_value)
1183+
.widget_instance(),
1184+
)
1185+
}
11691186
x => warn!("Color {x:?}"),
11701187
}
11711188

editor/src/messages/tool/common_functionality/graph_modification_utils.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use graphene_std::table::Table;
1616
use graphene_std::text::{Font, TypesettingConfig};
1717
use graphene_std::vector::misc::ManipulatorPointId;
1818
use graphene_std::vector::style::{Fill, Gradient};
19-
use graphene_std::vector::{PointId, SegmentId, VectorModificationType};
19+
use graphene_std::vector::{GradientStops, PointId, SegmentId, VectorModificationType};
2020
use std::collections::VecDeque;
2121

2222
/// Returns the ID of the first Spline node in the horizontal flow which is not followed by a `Path` node, or `None` if none exists.
@@ -285,6 +285,17 @@ pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI
285285
Some(gradient.clone())
286286
}
287287

288+
/// Get the gradient table of a layer.
289+
pub fn get_gradient_table(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Table<GradientStops>> {
290+
let gradient_table_index = 1;
291+
292+
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::gradient_value::IDENTIFIER))?;
293+
let TaggedValue::GradientTable(gradient_table) = inputs.get(gradient_table_index)?.as_value()? else {
294+
return None;
295+
};
296+
Some(gradient_table.clone())
297+
}
298+
288299
/// Get the current fill of a layer from the closest "Fill" node.
289300
pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Color> {
290301
let fill_index = 1;

0 commit comments

Comments
 (0)