Skip to content

Commit 5aedda0

Browse files
0SlowPoke0Keavon
andauthored
Add handle visualization during point insertion in the Path tool (#2197)
* added_handle_overlays * changed color to yellow * Rename color parameter * Change the color to blue --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 0a496ee commit 5aedda0

File tree

7 files changed

+37
-15
lines changed

7 files changed

+37
-15
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,16 @@ pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut Shape
4141
bezier_rs::BezierHandles::Quadratic { handle } if not_under_anchor(handle, bezier.start) && not_under_anchor(handle, bezier.end) => {
4242
overlay_context.line(handle, bezier.start, None);
4343
overlay_context.line(handle, bezier.end, None);
44-
overlay_context.manipulator_handle(handle, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)));
44+
overlay_context.manipulator_handle(handle, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
4545
}
4646
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => {
4747
if not_under_anchor(handle_start, bezier.start) {
4848
overlay_context.line(handle_start, bezier.start, None);
49-
overlay_context.manipulator_handle(handle_start, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)));
49+
overlay_context.manipulator_handle(handle_start, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
5050
}
5151
if not_under_anchor(handle_end, bezier.end) {
5252
overlay_context.line(handle_end, bezier.end, None);
53-
overlay_context.manipulator_handle(handle_end, is_selected(selected, ManipulatorPointId::EndHandle(segment_id)));
53+
overlay_context.manipulator_handle(handle_end, is_selected(selected, ManipulatorPointId::EndHandle(segment_id)), None);
5454
}
5555
}
5656
_ => {}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ impl OverlayContext {
127127
}
128128
}
129129

130-
pub fn manipulator_handle(&mut self, position: DVec2, selected: bool) {
130+
pub fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) {
131131
let position = position.round() - DVec2::splat(0.5);
132132

133133
self.render_context.begin_path();
@@ -137,7 +137,7 @@ impl OverlayContext {
137137

138138
let fill = if selected { COLOR_OVERLAY_BLUE } else { COLOR_OVERLAY_WHITE };
139139
self.render_context.set_fill_style_str(fill);
140-
self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE);
140+
self.render_context.set_stroke_style_str(color.unwrap_or(COLOR_OVERLAY_BLUE));
141141
self.render_context.fill();
142142
self.render_context.stroke();
143143
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,20 @@ impl ClosestSegment {
116116
(stroke_width_sq + tolerance_sq) < dist_sq
117117
}
118118

119+
pub fn handle_positions(&self, document_metadata: &DocumentMetadata) -> (Option<DVec2>, Option<DVec2>) {
120+
// Transform to viewport space
121+
let transform = document_metadata.transform_to_viewport(self.layer);
122+
123+
// Split the Bezier at the parameter `t`
124+
let [first, second] = self.bezier.split(TValue::Parametric(self.t));
125+
126+
// Transform the handle positions to viewport space
127+
let first_handle = first.handle_end().map(|handle| transform.transform_point2(handle));
128+
let second_handle = second.handle_start().map(|handle| transform.transform_point2(handle));
129+
130+
(first_handle, second_handle)
131+
}
132+
119133
pub fn adjusted_insert(&self, responses: &mut VecDeque<Message>) -> PointId {
120134
let layer = self.layer;
121135
let [first, second] = self.bezier.split(TValue::Parametric(self.t));

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,10 @@ impl SnapManager {
461461
overlay_context.line(viewport, target, None);
462462
}
463463
for &target in align.iter().flatten() {
464-
overlay_context.manipulator_handle(target, false);
464+
overlay_context.manipulator_handle(target, false, None);
465465
}
466466
if any_align {
467-
overlay_context.manipulator_handle(viewport, false);
467+
overlay_context.manipulator_handle(viewport, false, None);
468468
}
469469

470470
if !any_align && ind.distribution_equal_distance_x.is_none() && ind.distribution_equal_distance_y.is_none() {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,15 @@ impl Fsm for GradientToolFsmState {
257257
let (start, end) = (transform.transform_point2(start), transform.transform_point2(end));
258258

259259
overlay_context.line(start, end, None);
260-
overlay_context.manipulator_handle(start, dragging == Some(GradientDragTarget::Start));
261-
overlay_context.manipulator_handle(end, dragging == Some(GradientDragTarget::End));
260+
overlay_context.manipulator_handle(start, dragging == Some(GradientDragTarget::Start), None);
261+
overlay_context.manipulator_handle(end, dragging == Some(GradientDragTarget::End), None);
262262

263263
for (index, (position, _)) in stops.0.into_iter().enumerate() {
264264
if position.abs() < f64::EPSILON * 1000. || (1. - position).abs() < f64::EPSILON * 1000. {
265265
continue;
266266
}
267267

268-
overlay_context.manipulator_handle(start.lerp(end, position), dragging == Some(GradientDragTarget::Step(index)));
268+
overlay_context.manipulator_handle(start.lerp(end, position), dragging == Some(GradientDragTarget::Step(index)), None);
269269
}
270270
}
271271

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::tool_prelude::*;
2-
use crate::consts::{COLOR_OVERLAY_YELLOW, DRAG_THRESHOLD, HANDLE_ROTATE_SNAP_ANGLE, INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
2+
use crate::consts::{COLOR_OVERLAY_BLUE, DRAG_THRESHOLD, HANDLE_ROTATE_SNAP_ANGLE, INSERT_POINT_ON_SEGMENT_TOO_FAR_DISTANCE, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
33
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
44
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
55
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
@@ -520,6 +520,7 @@ impl PathToolData {
520520
handle_angle
521521
}
522522

523+
#[allow(clippy::too_many_arguments)]
523524
fn apply_snapping(
524525
&mut self,
525526
handle_direction: DVec2,
@@ -549,6 +550,7 @@ impl PathToolData {
549550
document.metadata().document_to_viewport.transform_vector2(snap_result.snapped_point_document - handle_position)
550551
}
551552

553+
#[allow(clippy::too_many_arguments)]
552554
fn drag(
553555
&mut self,
554556
equidistant: bool,
@@ -622,7 +624,13 @@ impl Fsm for PathToolFsmState {
622624
let state = tool_data.update_insertion(shape_editor, document, responses, input);
623625

624626
if let Some(closest_segment) = &tool_data.segment {
625-
overlay_context.manipulator_anchor(closest_segment.closest_point_to_viewport(), false, Some(COLOR_OVERLAY_YELLOW));
627+
overlay_context.manipulator_anchor(closest_segment.closest_point_to_viewport(), false, Some(COLOR_OVERLAY_BLUE));
628+
if let (Some(handle1), Some(handle2)) = closest_segment.handle_positions(document.metadata()) {
629+
overlay_context.line(closest_segment.closest_point_to_viewport(), handle1, Some(COLOR_OVERLAY_BLUE));
630+
overlay_context.line(closest_segment.closest_point_to_viewport(), handle2, Some(COLOR_OVERLAY_BLUE));
631+
overlay_context.manipulator_handle(handle1, false, Some(COLOR_OVERLAY_BLUE));
632+
overlay_context.manipulator_handle(handle2, false, Some(COLOR_OVERLAY_BLUE));
633+
}
626634
}
627635

628636
responses.add(PathToolMessage::SelectedPointUpdated);

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,12 +602,12 @@ impl Fsm for PenToolFsmState {
602602

603603
if self == PenToolFsmState::DraggingHandle && valid(next_anchor, handle_end) {
604604
// Draw the handle circle for the currently-being-dragged-out incoming handle (opposite the one currently being dragged out)
605-
overlay_context.manipulator_handle(handle_end, false);
605+
overlay_context.manipulator_handle(handle_end, false, None);
606606
}
607607

608608
if valid(anchor_start, handle_start) {
609609
// Draw the handle circle for the most recently placed anchor's outgoing handle (which is currently influencing the currently-being-placed segment)
610-
overlay_context.manipulator_handle(handle_start, false);
610+
overlay_context.manipulator_handle(handle_start, false, None);
611611
}
612612
} else {
613613
// Draw the whole path and its manipulators when the user is clicking-and-dragging out from the most recently placed anchor to set its outgoing handle, during which it would otherwise not have its overlays drawn
@@ -616,7 +616,7 @@ impl Fsm for PenToolFsmState {
616616

617617
if self == PenToolFsmState::DraggingHandle && valid(next_anchor, next_handle_start) {
618618
// Draw the handle circle for the currently-being-dragged-out outgoing handle (the one currently being dragged out, under the user's cursor)
619-
overlay_context.manipulator_handle(next_handle_start, false);
619+
overlay_context.manipulator_handle(next_handle_start, false, None);
620620
}
621621

622622
if self == PenToolFsmState::DraggingHandle {

0 commit comments

Comments
 (0)