Skip to content

Commit dd4a97b

Browse files
0HyperCubeKeavon
andauthored
Correctly apply transforms to vector data and strokes (#1977)
* Fix adding a layer to a transformed group * Fix assorted transform issues * Default stroke transform * Fix bench * Transform gradient * Gradient fix * Add gradient reversal buttons to Fill node in the Properties panel --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 2fa8773 commit dd4a97b

File tree

19 files changed

+152
-59
lines changed

19 files changed

+152
-59
lines changed

.vscode/settings.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
},
3434
// Rust Analyzer config
3535
"rust-analyzer.cargo.allTargets": false,
36-
"rust-analyzer.check.command": "clippy",
3736
// ESLint config
3837
"eslint.format.enable": true,
3938
"eslint.workingDirectories": ["./frontend", "./website/other/bezier-rs-demos", "./website"],

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node,
266266

267267
let bounds_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
268268
apply_usvg_fill(path.fill(), modify_inputs, transform * usvg_transform(node.abs_transform()), bounds_transform);
269-
apply_usvg_stroke(path.stroke(), modify_inputs);
269+
apply_usvg_stroke(path.stroke(), modify_inputs, transform * usvg_transform(node.abs_transform()));
270270
}
271271
usvg::Node::Image(_image) => {
272272
warn!("Skip image")
@@ -279,7 +279,7 @@ fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node,
279279
}
280280
}
281281

282-
fn apply_usvg_stroke(stroke: Option<&usvg::Stroke>, modify_inputs: &mut ModifyInputsContext) {
282+
fn apply_usvg_stroke(stroke: Option<&usvg::Stroke>, modify_inputs: &mut ModifyInputsContext, transform: DAffine2) {
283283
if let Some(stroke) = stroke {
284284
if let usvg::Paint::Color(color) = &stroke.paint() {
285285
modify_inputs.stroke_set(Stroke {
@@ -299,6 +299,7 @@ fn apply_usvg_stroke(stroke: Option<&usvg::Stroke>, modify_inputs: &mut ModifyIn
299299
usvg::LineJoin::Bevel => LineJoin::Bevel,
300300
},
301301
line_join_miter_limit: stroke.miterlimit().get() as f64,
302+
transform,
302303
})
303304
} else {
304305
warn!("Skip non-solid stroke")

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

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,7 +2597,28 @@ pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context:
25972597

25982598
let fill_type_switch = {
25992599
let mut row = vec![TextLabel::new("").widget_holder()];
2600-
add_blank_assist(&mut row);
2600+
match fill {
2601+
Fill::Solid(_) | Fill::None => add_blank_assist(&mut row),
2602+
Fill::Gradient(gradient) => {
2603+
let reverse_button = IconButton::new("Reverse", 24)
2604+
.tooltip("Reverse the gradient color stops")
2605+
.on_update(update_value(
2606+
{
2607+
let gradient = gradient.clone();
2608+
move |_| {
2609+
let mut gradient = gradient.clone();
2610+
gradient.stops = gradient.stops.reversed();
2611+
TaggedValue::Fill(Fill::Gradient(gradient))
2612+
}
2613+
},
2614+
node_id,
2615+
fill_index,
2616+
))
2617+
.widget_holder();
2618+
row.push(Separator::new(SeparatorType::Unrelated).widget_holder());
2619+
row.push(reverse_button);
2620+
}
2621+
}
26012622

26022623
let entries = vec![
26032624
RadioEntryData::new("solid")
@@ -2619,9 +2640,35 @@ pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context:
26192640
};
26202641
widgets.push(fill_type_switch);
26212642

2622-
if let Fill::Gradient(gradient) = fill {
2643+
if let Fill::Gradient(gradient) = fill.clone() {
26232644
let mut row = vec![TextLabel::new("").widget_holder()];
2624-
add_blank_assist(&mut row);
2645+
match gradient.gradient_type {
2646+
GradientType::Linear => add_blank_assist(&mut row),
2647+
GradientType::Radial => {
2648+
let orientation = if (gradient.end.x - gradient.start.x).abs() > f64::EPSILON * 1e6 {
2649+
gradient.end.x > gradient.start.x
2650+
} else {
2651+
(gradient.start.x + gradient.start.y) < (gradient.end.x + gradient.end.y)
2652+
};
2653+
let reverse_radial_gradient_button = IconButton::new(if orientation { "ReverseRadialGradientToRight" } else { "ReverseRadialGradientToLeft" }, 24)
2654+
.tooltip("Reverse which end the gradient radiates from")
2655+
.on_update(update_value(
2656+
{
2657+
let gradient = gradient.clone();
2658+
move |_| {
2659+
let mut gradient = gradient.clone();
2660+
std::mem::swap(&mut gradient.start, &mut gradient.end);
2661+
TaggedValue::Fill(Fill::Gradient(gradient))
2662+
}
2663+
},
2664+
node_id,
2665+
fill_index,
2666+
))
2667+
.widget_holder();
2668+
row.push(Separator::new(SeparatorType::Unrelated).widget_holder());
2669+
row.push(reverse_radial_gradient_button);
2670+
}
2671+
}
26252672

26262673
let new_gradient1 = gradient.clone();
26272674
let new_gradient2 = gradient.clone();

editor/src/messages/tool/tool_messages/ellipse_tool.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,16 +206,15 @@ impl Fsm for EllipseToolFsmState {
206206
let nodes = vec![(NodeId(0), node)];
207207

208208
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(true), responses);
209-
tool_options.fill.apply_fill(layer, responses);
210-
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
211-
shape_data.layer = Some(layer);
212-
213209
responses.add(GraphOperationMessage::TransformSet {
214210
layer,
215211
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
216212
transform_in: TransformIn::Viewport,
217213
skip_rerender: false,
218214
});
215+
tool_options.fill.apply_fill(layer, responses);
216+
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
217+
shape_data.layer = Some(layer);
219218

220219
EllipseToolFsmState::Drawing
221220
}

editor/src/messages/tool/tool_messages/freehand_tool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ impl Fsm for FreehandToolFsmState {
233233
tool_options.stroke.apply_stroke(tool_data.weight, layer, responses);
234234
tool_data.layer = Some(layer);
235235

236-
let transform = document.metadata().transform_to_viewport(layer);
236+
let transform = document.metadata().transform_to_viewport(parent);
237237
let position = transform.inverse().transform_point2(input.mouse.position);
238238

239239
extend_path_with_next_segment(tool_data, position, responses);

editor/src/messages/tool/tool_messages/gradient_tool.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ impl LayoutHolder for GradientTool {
8686
let gradient_type = RadioInput::new(vec![
8787
RadioEntryData::new("linear")
8888
.label("Linear")
89-
.tooltip("Linear Gradient")
89+
.tooltip("Linear gradient")
9090
.on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Linear)).into()),
9191
RadioEntryData::new("radial")
9292
.label("Radial")
93-
.tooltip("Radial Gradient")
93+
.tooltip("Radial gradient")
9494
.on_update(move |_| GradientToolMessage::UpdateOptions(GradientOptionsUpdate::Type(GradientType::Radial)).into()),
9595
])
9696
.selected_index(Some((self.selected_gradient().unwrap_or(self.options.gradient_type) == GradientType::Radial) as u32))

editor/src/messages/tool/tool_messages/line_tool.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,14 @@ impl Fsm for LineToolFsmState {
188188
let nodes = vec![(NodeId(0), node)];
189189

190190
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(false), responses);
191-
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
192-
tool_data.layer = Some(layer);
193-
194191
responses.add(GraphOperationMessage::TransformSet {
195192
layer,
196193
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
197194
transform_in: TransformIn::Viewport,
198195
skip_rerender: false,
199196
});
197+
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
198+
tool_data.layer = Some(layer);
200199

201200
tool_data.layer = Some(layer);
202201
tool_data.weight = tool_options.line_weight;

editor/src/messages/tool/tool_messages/polygon_tool.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,16 +265,15 @@ impl Fsm for PolygonToolFsmState {
265265
let nodes = vec![(NodeId(0), node)];
266266

267267
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(false), responses);
268-
tool_options.fill.apply_fill(layer, responses);
269-
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
270-
polygon_data.layer = Some(layer);
271-
272268
responses.add(GraphOperationMessage::TransformSet {
273269
layer,
274270
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
275271
transform_in: TransformIn::Viewport,
276272
skip_rerender: false,
277273
});
274+
tool_options.fill.apply_fill(layer, responses);
275+
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
276+
polygon_data.layer = Some(layer);
278277

279278
PolygonToolFsmState::Drawing
280279
}

editor/src/messages/tool/tool_messages/rectangle_tool.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,16 +212,15 @@ impl Fsm for RectangleToolFsmState {
212212
let nodes = vec![(NodeId(0), node)];
213213

214214
let layer = graph_modification_utils::new_custom(NodeId(generate_uuid()), nodes, document.new_layer_parent(true), responses);
215-
tool_options.fill.apply_fill(layer, responses);
216-
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
217-
shape_data.layer = Some(layer);
218-
219215
responses.add(GraphOperationMessage::TransformSet {
220216
layer,
221217
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
222218
transform_in: TransformIn::Viewport,
223219
skip_rerender: false,
224220
});
221+
tool_options.fill.apply_fill(layer, responses);
222+
tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
223+
shape_data.layer = Some(layer);
225224

226225
RectangleToolFsmState::Drawing
227226
}

editor/src/node_graph_executor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl NodeRuntime {
284284

285285
for monitor_node_path in &self.monitor_nodes {
286286
// The monitor nodes are located within a document node, and are thus children in that network, so this gets the parent document node's ID
287-
let Some(parent_network_node_id) = monitor_node_path.get(monitor_node_path.len() - 2).copied() else {
287+
let Some(parent_network_node_id) = monitor_node_path.len().checked_sub(2).and_then(|index| monitor_node_path.get(index)).copied() else {
288288
warn!("Monitor node has invalid node id");
289289

290290
continue;

0 commit comments

Comments
 (0)