Skip to content

Commit 5770a93

Browse files
committed
Merge branch 'master' into granular-overlays-settings
2 parents 73d3ea0 + 0a65e57 commit 5770a93

File tree

19 files changed

+663
-239
lines changed

19 files changed

+663
-239
lines changed

editor/src/consts.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ pub const MIN_LENGTH_FOR_SKEW_TRIANGLE_VISIBILITY: f64 = 48.;
9999
pub const MANIPULATOR_GROUP_MARKER_SIZE: f64 = 6.;
100100
pub const SELECTION_THRESHOLD: f64 = 10.;
101101
pub const HIDE_HANDLE_DISTANCE: f64 = 3.;
102-
pub const INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE: f64 = 50.;
103102
pub const HANDLE_ROTATE_SNAP_ANGLE: f64 = 15.;
103+
pub const SEGMENT_INSERTION_DISTANCE: f64 = 7.5;
104+
pub const SEGMENT_OVERLAY_SIZE: f64 = 10.;
104105

105106
// PEN TOOL
106107
pub const CREATE_CURVE_THRESHOLD: f64 = 5.;

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,13 @@ pub fn input_mappings() -> Mapping {
212212
entry!(KeyDown(Delete); modifiers=[Shift], action_dispatch=PathToolMessage::BreakPath),
213213
entry!(KeyDown(Backspace); modifiers=[Shift], action_dispatch=PathToolMessage::BreakPath),
214214
entry!(KeyDownNoRepeat(Tab); action_dispatch=PathToolMessage::SwapSelectedHandles),
215-
entry!(KeyDown(MouseLeft); action_dispatch=PathToolMessage::MouseDown { direct_insert_without_sliding: Control, extend_selection: Shift, lasso_select: Control, handle_drag_from_anchor: Alt }),
215+
entry!(KeyDown(MouseLeft); action_dispatch=PathToolMessage::MouseDown { extend_selection: Shift, lasso_select: Control, handle_drag_from_anchor: Alt }),
216216
entry!(KeyDown(MouseRight); action_dispatch=PathToolMessage::RightClick),
217217
entry!(KeyDown(Escape); action_dispatch=PathToolMessage::Escape),
218218
entry!(KeyDown(KeyG); action_dispatch=PathToolMessage::GRS { key: KeyG }),
219219
entry!(KeyDown(KeyR); action_dispatch=PathToolMessage::GRS { key: KeyR }),
220220
entry!(KeyDown(KeyS); action_dispatch=PathToolMessage::GRS { key: KeyS }),
221-
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control }),
221+
entry!(PointerMove; refresh_keys=[KeyC, Space, Control, Shift, Alt], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space, snap_angle: Shift, lock_angle: Control, delete_segment: Alt }),
222222
entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete),
223223
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=PathToolMessage::SelectAllAnchors),
224224
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], action_dispatch=PathToolMessage::DeselectAllPoints),

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -691,15 +691,17 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
691691
insert_index: calculated_insert_index,
692692
});
693693

694-
let layer_local_transform = self.network_interface.document_metadata().transform_to_viewport(layer_to_move);
695-
let undo_transform = self.network_interface.document_metadata().transform_to_viewport(parent).inverse();
696-
let transform = undo_transform * layer_local_transform;
697-
responses.add(GraphOperationMessage::TransformSet {
698-
layer: layer_to_move,
699-
transform,
700-
transform_in: TransformIn::Local,
701-
skip_rerender: false,
702-
});
694+
if layer_to_move.parent(self.metadata()) != Some(parent) {
695+
let layer_local_transform = self.network_interface.document_metadata().transform_to_viewport(layer_to_move);
696+
let undo_transform = self.network_interface.document_metadata().transform_to_viewport(parent).inverse();
697+
let transform = undo_transform * layer_local_transform;
698+
responses.add(GraphOperationMessage::TransformSet {
699+
layer: layer_to_move,
700+
transform,
701+
transform_in: TransformIn::Local,
702+
skip_rerender: false,
703+
});
704+
}
703705
}
704706

705707
responses.add(NodeGraphMessage::RunDocumentGraph);

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,13 +412,10 @@ impl OverlayContext {
412412
}
413413

414414
pub fn draw_angle(&mut self, pivot: DVec2, radius: f64, arc_radius: f64, offset_angle: f64, angle: f64) {
415-
let color_line = COLOR_OVERLAY_BLUE;
416-
417415
let end_point1 = pivot + radius * DVec2::from_angle(angle + offset_angle);
418416
let end_point2 = pivot + radius * DVec2::from_angle(offset_angle);
419-
self.line(pivot, end_point1, Some(color_line), None);
420-
self.line(pivot, end_point2, Some(color_line), None);
421-
417+
self.line(pivot, end_point1, None, None);
418+
self.dashed_line(pivot, end_point2, None, None, Some(2.), Some(2.), Some(0.5));
422419
self.draw_arc(pivot, arc_radius, offset_angle, (angle) % TAU + offset_angle);
423420
}
424421

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,21 @@ impl LayerNodeIdentifier {
261261
metadata.get_relations(self).and_then(|relations| relations.last_child)
262262
}
263263

264-
/// Does the layer have children? If so, then it is a folder
264+
/// Does the layer have children? If so, then it is a folder.
265265
pub fn has_children(self, metadata: &DocumentMetadata) -> bool {
266266
self.first_child(metadata).is_some()
267267
}
268268

269+
/// Is the layer a child of the given layer?
270+
pub fn is_child_of(self, metadata: &DocumentMetadata, parent: &LayerNodeIdentifier) -> bool {
271+
parent.children(metadata).any(|child| child == self)
272+
}
273+
274+
/// Is the layer an ancestor of the given layer?
275+
pub fn is_ancestor_of(self, metadata: &DocumentMetadata, child: &LayerNodeIdentifier) -> bool {
276+
child.ancestors(metadata).any(|ancestor| ancestor == self)
277+
}
278+
269279
/// Iterator over all direct children (excluding self and recursive children)
270280
pub fn children(self, metadata: &DocumentMetadata) -> AxisIter {
271281
AxisIter {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4198,9 +4198,9 @@ impl NodeNetworkInterface {
41984198
let Some(downstream_nodes) = outward_wires.get(&current_node) else { continue };
41994199
for downstream_node in downstream_nodes {
42004200
if let InputConnector::Node { node_id: downstream_id, .. } = downstream_node {
4201-
let downstream_node_output = OutputConnector::node(*downstream_id, 0);
42024201
if !delete_nodes.contains(downstream_id) {
4203-
stack.push(downstream_node_output);
4202+
can_delete = false;
4203+
break;
42044204
}
42054205
// Continue traversing over the downstream sibling, if the current node is a sibling to a node that will be deleted and it is a layer
42064206
else {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ fn draw_dashed_line(line_start: DVec2, line_end: DVec2, transform: DAffine2, ove
1010

1111
overlay_context.dashed_line(min_viewport, max_viewport, None, None, Some(2.), Some(2.), Some(0.5));
1212
}
13+
1314
/// Draws a solid line with a length annotation between two points transformed by the given affine transformations.
1415
fn draw_line_with_length(line_start: DVec2, line_end: DVec2, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext, label_alignment: LabelAlignment) {
1516
let transform_to_document = document_to_viewport.inverse() * transform;

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

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ impl ClosestSegment {
126126
self.layer
127127
}
128128

129+
pub fn segment(&self) -> SegmentId {
130+
self.segment
131+
}
132+
133+
pub fn points(&self) -> [PointId; 2] {
134+
self.points
135+
}
136+
129137
pub fn closest_point_to_viewport(&self) -> DVec2 {
130138
self.bezier_point_to_viewport
131139
}
@@ -150,9 +158,7 @@ impl ClosestSegment {
150158
pub fn too_far(&self, mouse_position: DVec2, tolerance: f64, document_metadata: &DocumentMetadata) -> bool {
151159
let dist_sq = self.distance_squared(mouse_position);
152160
let stroke_width = document_metadata.document_to_viewport.decompose_scale().x.max(1.) * self.stroke_width;
153-
let stroke_width_sq = stroke_width * stroke_width;
154-
let tolerance_sq = tolerance * tolerance;
155-
(stroke_width_sq + tolerance_sq) < dist_sq
161+
(stroke_width + tolerance).powi(2) < dist_sq
156162
}
157163

158164
pub fn handle_positions(&self, document_metadata: &DocumentMetadata) -> (Option<DVec2>, Option<DVec2>) {
@@ -221,6 +227,28 @@ impl ClosestSegment {
221227
let id = self.adjusted_insert(responses);
222228
shape_editor.select_anchor_point_by_id(self.layer, id, extend_selection)
223229
}
230+
231+
pub fn calculate_perp(&self, document: &DocumentMessageHandler) -> DVec2 {
232+
let tangent = if let (Some(handle1), Some(handle2)) = self.handle_positions(document.metadata()) {
233+
(handle1 - handle2).try_normalize()
234+
} else {
235+
let [first_point, last_point] = self.points();
236+
if let Some(vector_data) = document.network_interface.compute_modified_vector(self.layer()) {
237+
if let (Some(pos1), Some(pos2)) = (
238+
ManipulatorPointId::Anchor(first_point).get_position(&vector_data),
239+
ManipulatorPointId::Anchor(last_point).get_position(&vector_data),
240+
) {
241+
(pos1 - pos2).try_normalize()
242+
} else {
243+
None
244+
}
245+
} else {
246+
None
247+
}
248+
}
249+
.unwrap_or(DVec2::ZERO);
250+
tangent.perp()
251+
}
224252
}
225253

226254
// TODO Consider keeping a list of selected manipulators to minimize traversals of the layers
@@ -978,6 +1006,29 @@ impl ShapeState {
9781006
.collect::<HashMap<_, _>>()
9791007
}
9801008

1009+
pub fn dissolve_segment(&self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData, segment: SegmentId, points: [PointId; 2]) {
1010+
// Checking which point is terminal point
1011+
let is_point1_terminal = vector_data.connected_count(points[0]) == 1;
1012+
let is_point2_terminal = vector_data.connected_count(points[1]) == 1;
1013+
1014+
// Delete the segment and terminal points
1015+
let modification_type = VectorModificationType::RemoveSegment { id: segment };
1016+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
1017+
for &handles in vector_data.colinear_manipulators.iter().filter(|handles| handles.iter().any(|handle| handle.segment == segment)) {
1018+
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
1019+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
1020+
}
1021+
1022+
if is_point1_terminal {
1023+
let modification_type = VectorModificationType::RemovePoint { id: points[0] };
1024+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
1025+
}
1026+
if is_point2_terminal {
1027+
let modification_type = VectorModificationType::RemovePoint { id: points[1] };
1028+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
1029+
}
1030+
}
1031+
9811032
fn dissolve_anchor(anchor: PointId, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData) -> Option<[(HandleId, PointId); 2]> {
9821033
// Delete point
9831034
let modification_type = VectorModificationType::RemovePoint { id: anchor };

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ impl Fsm for ArtboardToolFsmState {
268268
let constrain_square = input.keyboard.get(constrain_axis_or_aspect as usize);
269269
tool_data.resize_artboard(responses, document, input, from_center, constrain_square);
270270

271-
// AutoPanning
271+
// Auto-panning
272272
let messages = [
273273
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
274274
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
@@ -307,7 +307,7 @@ impl Fsm for ArtboardToolFsmState {
307307
bounds.bounds[0] = position.round();
308308
bounds.bounds[1] = position.round() + size.round();
309309

310-
// AutoPanning
310+
// Auto-panning
311311
let messages = [
312312
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
313313
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
@@ -346,7 +346,7 @@ impl Fsm for ArtboardToolFsmState {
346346
})
347347
}
348348

349-
// AutoPanning
349+
// Auto-panning
350350
let messages = [
351351
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
352352
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),
@@ -378,25 +378,25 @@ impl Fsm for ArtboardToolFsmState {
378378
ArtboardToolFsmState::Ready { hovered }
379379
}
380380
(ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
381-
// AutoPanning
381+
// Auto-panning
382382
let _ = tool_data.auto_panning.shift_viewport(input, responses);
383383

384384
ArtboardToolFsmState::ResizingBounds
385385
}
386386
(ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
387-
// AutoPanning
387+
// Auto-panning
388388
tool_data.auto_panning.shift_viewport(input, responses);
389389

390390
ArtboardToolFsmState::Dragging
391391
}
392392
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerOutsideViewport { .. }) => {
393-
// AutoPanning
393+
// Auto-panning
394394
tool_data.auto_panning.shift_viewport(input, responses);
395395

396396
ArtboardToolFsmState::Drawing
397397
}
398398
(state, ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }) => {
399-
// AutoPanning
399+
// Auto-panning
400400
let messages = [
401401
ArtboardToolMessage::PointerOutsideViewport { constrain_axis_or_aspect, center }.into(),
402402
ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }.into(),

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

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ fn generate_line(tool_data: &mut LineToolData, snap_data: SnapData, lock_angle:
394394

395395
let near_point = SnapCandidatePoint::handle_neighbors(document_points[1], [tool_data.drag_start]);
396396
let far_point = SnapCandidatePoint::handle_neighbors(2. * document_points[0] - document_points[1], [tool_data.drag_start]);
397+
let mid_point = SnapCandidatePoint::handle_neighbors((tool_data.drag_start + document_points[1]) / 2., [tool_data.drag_start]);
397398
let config = SnapTypeConfiguration::default();
398399

399400
if constrained {
@@ -410,8 +411,15 @@ fn generate_line(tool_data: &mut LineToolData, snap_data: SnapData, lock_angle:
410411
snap.update_indicator(best);
411412
} else {
412413
let snapped = snap.constrained_snap(&snap_data, &near_point, constraint, config);
413-
document_points[1] = snapped.snapped_point_document;
414-
snap.update_indicator(snapped);
414+
let snapped_mid = snap.constrained_snap(&snap_data, &mid_point, constraint, config);
415+
let best = if snap_data.document.snapping_state.path.line_midpoint && snapped_mid.other_snap_better(&snapped_mid) {
416+
document_points[1] += (snapped_mid.snapped_point_document - mid_point.document_point) * 2.;
417+
snapped_mid
418+
} else {
419+
document_points[1] = snapped.snapped_point_document;
420+
snapped.clone()
421+
};
422+
snap.update_indicator(best);
415423
}
416424
} else if center {
417425
let snapped = snap.free_snap(&snap_data, &near_point, config);
@@ -422,8 +430,15 @@ fn generate_line(tool_data: &mut LineToolData, snap_data: SnapData, lock_angle:
422430
snap.update_indicator(best);
423431
} else {
424432
let snapped = snap.free_snap(&snap_data, &near_point, config);
425-
document_points[1] = snapped.snapped_point_document;
426-
snap.update_indicator(snapped);
433+
let snapped_mid = snap.free_snap(&snap_data, &mid_point, config);
434+
let best = if snap_data.document.snapping_state.path.line_midpoint && snapped_mid.other_snap_better(&snapped_mid) {
435+
document_points[1] += (snapped_mid.snapped_point_document - mid_point.document_point) * 2.;
436+
snapped_mid
437+
} else {
438+
document_points[1] = snapped.snapped_point_document;
439+
snapped.clone()
440+
};
441+
snap.update_indicator(best);
427442
}
428443

429444
// Snapping happens in other space, while document graph renders in another.
@@ -433,7 +448,8 @@ fn generate_line(tool_data: &mut LineToolData, snap_data: SnapData, lock_angle:
433448
#[cfg(test)]
434449
mod test_line_tool {
435450
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
436-
use crate::{messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer, test_utils::test_prelude::*};
451+
use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer;
452+
use crate::test_utils::test_prelude::*;
437453
use glam::DAffine2;
438454
use graph_craft::document::value::TaggedValue;
439455

0 commit comments

Comments
 (0)