Skip to content

Commit 3754701

Browse files
authored
Merge branch 'master' into 2615-fill-tool-on-strokes
2 parents e92f543 + e2117d9 commit 3754701

14 files changed

Lines changed: 224 additions & 53 deletions

File tree

.github/workflows/build.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,21 @@ jobs:
157157
REF="master"
158158
ENVIRONMENT="graphite-dev (Production)"
159159
else
160-
REF="$(git rev-parse HEAD)"
160+
REF="${{ inputs.checkout_ref || github.head_ref || github.ref_name }}"
161161
ENVIRONMENT="graphite-dev (Preview)"
162162
fi
163-
DEPLOY_ID=$(gh api \
164-
-X POST \
165-
-H "Accept: application/vnd.github+json" \
166-
repos/${{ github.repository }}/deployments \
167-
--input - \
168-
--jq '.id' <<EOF
169-
{"ref":"$REF","environment":"$ENVIRONMENT","auto_merge":false,"required_contexts":[]}
163+
create_deployment() {
164+
gh api \
165+
-X POST \
166+
-H "Accept: application/vnd.github+json" \
167+
repos/${{ github.repository }}/deployments \
168+
--input - \
169+
--jq '.id' <<EOF
170+
{"ref":"$1","environment":"$ENVIRONMENT","auto_merge":false,"required_contexts":[]}
170171
EOF
171-
)
172+
}
173+
# Try branch name first (needed for GitHub's PR "View deployment" button), fall back to commit SHA if the branch was deleted
174+
DEPLOY_ID=$(create_deployment "$REF" 2>/dev/null) || DEPLOY_ID=$(create_deployment "$(git rev-parse HEAD)")
172175
gh api \
173176
-X POST \
174177
-H "Accept: application/vnd.github+json" \

editor/src/messages/portfolio/document/data_panel/data_panel_message_handler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ impl TableRowLayout for Raster<CPU> {
497497
"Raster"
498498
}
499499
fn identifier(&self) -> String {
500-
format!("Raster ({}x{})", self.width, self.height)
500+
format!("Raster ({} x {})", self.width, self.height)
501501
}
502502
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
503503
let raster = self.data();
@@ -528,7 +528,7 @@ impl TableRowLayout for Raster<GPU> {
528528
"Raster"
529529
}
530530
fn identifier(&self) -> String {
531-
format!("Raster ({}x{})", self.data().width(), self.data().height())
531+
format!("Raster ({} x {})", self.data().width(), self.data().height())
532532
}
533533
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
534534
let widgets = vec![TextLabel::new("Raster is a texture on the GPU and cannot currently be displayed here").widget_instance()];

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
3434
use graphene_std::math::quad::Quad;
3535
use graphene_std::path_bool_nodes::boolean_intersect;
3636
use graphene_std::raster::BlendMode;
37-
use graphene_std::raster_types::Raster;
3837
use graphene_std::render_node::wgpu_available;
3938
use graphene_std::subpath::Subpath;
40-
use graphene_std::table::Table;
4139
use graphene_std::vector::PointId;
4240
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
4341
use graphene_std::vector::misc::dvec2_to_point;
@@ -696,7 +694,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
696694

697695
responses.add(DocumentMessage::AddTransaction);
698696

699-
let layer = graph_modification_utils::new_image_layer(Table::new_from_element(Raster::new_cpu(image)), layer_node_id, layer_parent, responses);
697+
let layer = graph_modification_utils::new_image_layer(image, layer_node_id, layer_parent, responses);
700698

701699
if let Some(name) = name {
702700
responses.add(NodeGraphMessage::SetDisplayName {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
44
use crate::messages::prelude::*;
55
use glam::{DAffine2, IVec2};
66
use graph_craft::document::NodeId;
7+
use graphene_std::Artboard;
78
use graphene_std::brush::brush_stroke::BrushStroke;
9+
use graphene_std::color::Color;
810
use graphene_std::raster::BlendMode;
9-
use graphene_std::raster_types::{CPU, Raster};
11+
use graphene_std::raster_types::Image;
1012
use graphene_std::subpath::Subpath;
11-
use graphene_std::table::Table;
1213
use graphene_std::text::{Font, TypesettingConfig};
1314
use graphene_std::vector::PointId;
1415
use graphene_std::vector::VectorModificationType;
1516
use graphene_std::vector::style::{Fill, Stroke};
16-
use graphene_std::{Artboard, Color};
1717

1818
#[impl_message(Message, DocumentMessage, GraphOperation)]
1919
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -74,7 +74,7 @@ pub enum GraphOperationMessage {
7474
},
7575
NewBitmapLayer {
7676
id: NodeId,
77-
image_frame: Table<Raster<CPU>>,
77+
image: Image<Color>,
7878
parent: LayerNodeIdentifier,
7979
insert_index: usize,
8080
},

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,10 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
165165
responses.add_front(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });
166166
responses.add(NodeGraphMessage::RunDocumentGraph);
167167
}
168-
GraphOperationMessage::NewBitmapLayer {
169-
id,
170-
image_frame,
171-
parent,
172-
insert_index,
173-
} => {
168+
GraphOperationMessage::NewBitmapLayer { id, image, parent, insert_index } => {
174169
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
175170
let layer = modify_inputs.create_layer(id);
176-
modify_inputs.insert_image_data(image_frame, layer);
171+
modify_inputs.insert_image_data(image, layer);
177172
network_interface.move_layer_to_stack(layer, parent, insert_index, &[]);
178173
responses.add(NodeGraphMessage::RunDocumentGraph);
179174
}

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ use graph_craft::document::{NodeId, NodeInput};
99
use graph_craft::{ProtoNodeIdentifier, concrete};
1010
use graphene_std::brush::brush_stroke::BrushStroke;
1111
use graphene_std::raster::BlendMode;
12-
use graphene_std::raster_types::{CPU, Raster};
12+
use graphene_std::raster_types::Image;
1313
use graphene_std::subpath::Subpath;
1414
use graphene_std::table::Table;
1515
use graphene_std::text::{Font, TypesettingConfig};
1616
use graphene_std::vector::Vector;
1717
use graphene_std::vector::style::{Fill, Stroke};
18-
use graphene_std::vector::{PointId, VectorModificationType};
18+
use graphene_std::vector::{PointId, VectorModification, VectorModificationType};
1919
use graphene_std::{Artboard, Color, Graphic, NodeInputDecleration};
2020

2121
#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
@@ -211,11 +211,13 @@ impl<'a> ModifyInputsContext<'a> {
211211
}
212212

213213
pub fn insert_vector(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {
214-
let vector = Table::new_from_element(Vector::from_subpaths(subpaths, true));
214+
// Build a VectorModification that reproduces the geometry (same format the Pen tool uses)
215+
let vector = Vector::from_subpaths(subpaths, true);
216+
let modification = Box::new(VectorModification::create_from_vector(&vector));
215217

216218
let shape = resolve_network_node_type("Path")
217219
.expect("Path node does not exist")
218-
.node_template_input_override([Some(NodeInput::value(TaggedValue::Vector(vector), false))]);
220+
.node_template_input_override([None, Some(NodeInput::value(TaggedValue::VectorModification(modification), false))]);
219221
let shape_id = NodeId::new();
220222
self.network_interface.insert_node(shape_id, shape, &[]);
221223
self.network_interface.move_node_to_chain_start(&shape_id, layer, &[], self.import);
@@ -301,14 +303,14 @@ impl<'a> ModifyInputsContext<'a> {
301303
self.network_interface.move_node_to_chain_start(&color_value_id, layer, &[], self.import);
302304
}
303305

304-
pub fn insert_image_data(&mut self, image_frame: Table<Raster<CPU>>, layer: LayerNodeIdentifier) {
306+
pub fn insert_image_data(&mut self, image: Image<Color>, layer: LayerNodeIdentifier) {
305307
let transform = resolve_network_node_type("Transform").expect("Transform node does not exist").default_node_template();
306-
let image = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER)
307-
.expect("ImageValue node does not exist")
308-
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::Raster(image_frame), false))]);
308+
let image_node = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
309+
.expect("Image node does not exist")
310+
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::ImageData(image), false))]);
309311

310312
let image_id = NodeId::new();
311-
self.network_interface.insert_node(image_id, image, &[]);
313+
self.network_interface.insert_node(image_id, image_node, &[]);
312314
self.network_interface.move_node_to_chain_start(&image_id, layer, &[], self.import);
313315

314316
let transform_id = NodeId::new();

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ use graphene_std::raster::{
2121
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
2222
SelectiveColorChoice,
2323
};
24+
use graphene_std::raster_types::Image;
2425
use graphene_std::table::{Table, TableRow};
2526
use graphene_std::text::{Font, TextAlign};
2627
use graphene_std::transform::{Footprint, ReferencePoint, ScaleType, Transform};
27-
use graphene_std::vector::QRCodeErrorCorrectionLevel;
2828
use graphene_std::vector::misc::BooleanOperation;
2929
use graphene_std::vector::misc::{ArcType, CentroidType, ExtrudeJoiningAlgorithm, GridType, InterpolationDistribution, MergeByDistanceAlgorithm, PointSpacingType, RowsOrColumns, SpiralType};
3030
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientSpreadMethod, GradientStops, GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
31+
use graphene_std::vector::{QRCodeErrorCorrectionLevel, VectorModification};
3132

3233
pub(crate) fn string_properties(text: &str) -> Vec<LayoutGroup> {
3334
let widget = TextLabel::new(text).widget_instance();
@@ -230,6 +231,8 @@ pub(crate) fn property_from_type(
230231
Some(x) if x == TypeId::of::<Font>() => font_widget(default_info),
231232
Some(x) if x == TypeId::of::<Curve>() => curve_widget(default_info),
232233
Some(x) if x == TypeId::of::<Footprint>() => footprint_widget(default_info, &mut extra_widgets),
234+
Some(x) if x == TypeId::of::<Box<VectorModification>>() => vector_modification_widget(default_info).into(),
235+
Some(x) if x == TypeId::of::<Image<Color>>() => image_data_widget(default_info).into(),
233236
// ===============================
234237
// MANUALLY IMPLEMENTED ENUM TYPES
235238
// ===============================
@@ -398,6 +401,44 @@ pub fn reference_point_widget(parameter_widgets_info: ParameterWidgetsInfo, disa
398401
widgets
399402
}
400403

404+
pub fn vector_modification_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetInstance> {
405+
let ParameterWidgetsInfo { document_node, node_id: _, index, .. } = parameter_widgets_info;
406+
407+
let mut widgets = start_widgets(parameter_widgets_info);
408+
409+
let Some(document_node) = document_node else { return widgets };
410+
let Some(input) = document_node.inputs.get(index) else { return widgets };
411+
412+
if let Some(TaggedValue::VectorModification(modification)) = input.as_non_exposed_value() {
413+
let label = modification.summary_label();
414+
let tooltip = modification.summary_tooltip();
415+
416+
widgets.extend_from_slice(&[
417+
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
418+
TextLabel::new(label).tooltip_label("Summary of Differential Edits").tooltip_description(tooltip).widget_instance(),
419+
]);
420+
}
421+
422+
widgets
423+
}
424+
425+
pub fn image_data_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<WidgetInstance> {
426+
let ParameterWidgetsInfo { document_node, node_id: _, index, .. } = parameter_widgets_info;
427+
428+
let mut widgets = start_widgets(parameter_widgets_info);
429+
430+
let Some(document_node) = document_node else { return widgets };
431+
let Some(input) = document_node.inputs.get(index) else { return widgets };
432+
433+
if let Some(TaggedValue::ImageData(image)) = input.as_non_exposed_value() {
434+
let label = format!("{} x {}", image.width, image.height);
435+
436+
widgets.extend_from_slice(&[Separator::new(SeparatorStyle::Unrelated).widget_instance(), TextLabel::new(label).widget_instance()]);
437+
}
438+
439+
widgets
440+
}
441+
401442
pub fn footprint_widget(parameter_widgets_info: ParameterWidgetsInfo, extra_widgets: &mut Vec<LayoutGroup>) -> LayoutGroup {
402443
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
403444

editor/src/messages/portfolio/document_migration.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use graph_craft::document::DocumentNode;
1010
use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue};
1111
use graphene_std::ProtoNodeIdentifier;
1212
use graphene_std::subpath::Subpath;
13-
use graphene_std::table::Table;
1413
use graphene_std::text::{TextAlign, TypesettingConfig};
1514
use graphene_std::transform::ScaleType;
1615
use graphene_std::uuid::NodeId;
@@ -585,8 +584,9 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
585584
],
586585
},
587586
NodeReplacement {
588-
node: graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER,
587+
node: graphene_std::raster_nodes::std_nodes::image::IDENTIFIER,
589588
aliases: &[
589+
"raster_nodes::std_nodes::ImageValueNode",
590590
"graphene_raster_nodes::std_nodes::ImageValueNode",
591591
"graphene_std::raster::ImageValueNode",
592592
"graphene_std::raster::ImageNode",
@@ -1140,10 +1140,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
11401140
log::error!("Path node does not exist.");
11411141
return None;
11421142
};
1143-
let path_node = path_node_type.node_template_input_override([
1144-
Some(NodeInput::value(TaggedValue::Vector(Table::new_from_element(vector)), true)),
1145-
Some(NodeInput::value(TaggedValue::VectorModification(Default::default()), false)),
1146-
]);
1143+
let modification = Box::new(graphene_std::vector::VectorModification::create_from_vector(&vector));
1144+
let path_node = path_node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::VectorModification(modification), false))]);
11471145

11481146
// Get the "Spline" node definition and wire it up with the "Path" node as input
11491147
let Some(spline_node_type) = resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER) else {
@@ -1387,7 +1385,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
13871385
.set_input(&InputConnector::node(NodeId(0), 1), NodeInput::value(TaggedValue::String(label), false), &[*node_id]);
13881386
}
13891387

1390-
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER) && inputs_count == 1 {
1388+
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER) && inputs_count == 1 {
13911389
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
13921390
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
13931391

@@ -1952,6 +1950,42 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
19521950
.set_input(&InputConnector::node(*node_id, 3), NodeInput::value(TaggedValue::Bool(false), false), network_path);
19531951
}
19541952

1953+
// Migrate Path nodes that stored geometry directly in input 0 (as a Table<Vector>) to instead use a VectorModification in input 1
1954+
if reference == DefinitionIdentifier::Network("Path".into()) {
1955+
let input_0 = node.inputs.first()?;
1956+
if let NodeInput::Value { tagged_value, exposed } = input_0
1957+
&& !exposed
1958+
&& let TaggedValue::Vector(vector_table) = &**tagged_value
1959+
&& !vector_table.is_empty()
1960+
{
1961+
let vector = vector_table.iter().next()?.element;
1962+
let modification = Box::new(graphene_std::vector::VectorModification::create_from_vector(vector));
1963+
1964+
// Reset input 0 to the default exposed state
1965+
document
1966+
.network_interface
1967+
.set_input(&InputConnector::node(*node_id, 0), NodeInput::value(TaggedValue::Vector(Default::default()), true), network_path);
1968+
1969+
// Store the converted VectorModification in input 1
1970+
document
1971+
.network_interface
1972+
.set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::VectorModification(modification), false), network_path);
1973+
}
1974+
}
1975+
1976+
// Migrate Image nodes that stored a Table<Raster<CPU>> in input 1 to instead use bare Image<Color> via TaggedValue::ImageData
1977+
if reference == DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
1978+
&& let Some(NodeInput::Value { tagged_value, .. }) = node.inputs.get(1)
1979+
&& let TaggedValue::Raster(raster_table) = &**tagged_value
1980+
&& let Some(row) = raster_table.iter().next()
1981+
{
1982+
let image = row.element.data().clone();
1983+
1984+
document
1985+
.network_interface
1986+
.set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::ImageData(image), false), network_path);
1987+
}
1988+
19551989
// ==================================
19561990
// PUT ALL MIGRATIONS ABOVE THIS LINE
19571991
// ==================================

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use graph_craft::{ProtoNodeIdentifier, concrete};
1010
use graphene_std::Color;
1111
use graphene_std::NodeInputDecleration;
1212
use graphene_std::raster::BlendMode;
13-
use graphene_std::raster_types::{CPU, GPU, Raster};
13+
use graphene_std::raster_types::{CPU, GPU, Image, Raster};
1414
use graphene_std::subpath::Subpath;
1515
use graphene_std::table::Table;
1616
use graphene_std::text::{Font, TypesettingConfig};
@@ -218,14 +218,9 @@ pub fn new_vector_layer(subpaths: Vec<Subpath<PointId>>, id: NodeId, parent: Lay
218218
}
219219

220220
/// Create a new bitmap layer.
221-
pub fn new_image_layer(image_frame: Table<Raster<CPU>>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
221+
pub fn new_image_layer(image: Image<Color>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
222222
let insert_index = 0;
223-
responses.add(GraphOperationMessage::NewBitmapLayer {
224-
id,
225-
image_frame,
226-
parent,
227-
insert_index,
228-
});
223+
responses.add(GraphOperationMessage::NewBitmapLayer { id, image, parent, insert_index });
229224
LayerNodeIdentifier::new_unchecked(id)
230225
}
231226

frontend/src/components/window/MainWindow.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
{#if $tooltip.visible}
3434
<Tooltip />
3535
{/if}
36-
{#if import.meta.env.MODE === "native" && new Date() > new Date("2026-04-30")}
36+
{#if import.meta.env.MODE === "native" && new Date() > new Date("2026-07-01")}
3737
<LayoutCol class="release-candidate-expiry">
3838
<TextLabel>
3939
<p>

0 commit comments

Comments
 (0)