Skip to content

Commit 391ed34

Browse files
4adexKeavon
andauthored
Add segment editing mode to the Path tool (#2712)
* Segment select mode upto dragging * Lasso select for segment editing * Formatting * Compatibility with point selection mode * Add delete segment support and drawing from inside of shape * Add GRS support for selected segments * Cleanup and add dynamic hints * Fix double click behaviour and overlays * Format code * Fix merge * Fix Lint * Fix formatting * Fix lasso bug * Code review --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent a4fbea9 commit 391ed34

File tree

13 files changed

+613
-187
lines changed

13 files changed

+613
-187
lines changed

editor/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ thiserror = { workspace = true }
3636
serde = { workspace = true }
3737
serde_json = { workspace = true }
3838
bezier-rs = { workspace = true }
39+
kurbo = { workspace = true }
3940
futures = { workspace = true }
4041
glam = { workspace = true }
41-
kurbo = { workspace = true }
4242
derivative = { workspace = true }
4343
specta = { workspace = true }
4444
dyn-any = { workspace = true }

editor/src/consts.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub const MANIPULATOR_GROUP_MARKER_SIZE: f64 = 6.;
102102
pub const SELECTION_THRESHOLD: f64 = 10.;
103103
pub const HIDE_HANDLE_DISTANCE: f64 = 3.;
104104
pub const HANDLE_ROTATE_SNAP_ANGLE: f64 = 15.;
105-
pub const SEGMENT_INSERTION_DISTANCE: f64 = 8.;
105+
pub const SEGMENT_INSERTION_DISTANCE: f64 = 5.;
106106
pub const SEGMENT_OVERLAY_SIZE: f64 = 10.;
107107
pub const HANDLE_LENGTH_FACTOR: f64 = 0.5;
108108

@@ -133,6 +133,7 @@ pub const SCALE_EFFECT: f64 = 0.5;
133133

134134
// COLORS
135135
pub const COLOR_OVERLAY_BLUE: &str = "#00a8ff";
136+
pub const COLOR_OVERLAY_BLUE_50: &str = "rgba(0, 168, 255, 0.5)";
136137
pub const COLOR_OVERLAY_YELLOW: &str = "#ffc848";
137138
pub const COLOR_OVERLAY_GREEN: &str = "#63ce63";
138139
pub const COLOR_OVERLAY_RED: &str = "#ef5454";

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ 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 { extend_selection: Shift, lasso_select: Control, handle_drag_from_anchor: Alt, drag_restore_handle: Control }),
215+
entry!(KeyDown(MouseLeft); action_dispatch=PathToolMessage::MouseDown { extend_selection: Shift, lasso_select: Control, handle_drag_from_anchor: Alt, drag_restore_handle: Control, molding_in_segment_edit: KeyA }),
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 }),

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,19 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
124124
overlay_context.outline_vector(&vector_data, transform);
125125
}
126126

127+
// Get the selected segments and then add a bold line overlay on them
128+
for (segment_id, bezier, _, _) in vector_data.segment_bezier_iter() {
129+
let Some(selected_shape_state) = shape_editor.selected_shape_state.get_mut(&layer) else {
130+
continue;
131+
};
132+
133+
if selected_shape_state.is_segment_selected(segment_id) {
134+
overlay_context.outline_select_bezier(bezier, transform);
135+
}
136+
}
137+
127138
let selected = shape_editor.selected_shape_state.get(&layer);
128-
let is_selected = |point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));
139+
let is_selected = |point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_point_selected(point));
129140

130141
if display_handles {
131142
let opposite_handles_data: Vec<(PointId, SegmentId)> = shape_editor.selected_points().filter_map(|point_id| vector_data.adjacent_segment(point_id)).collect();
@@ -187,7 +198,7 @@ pub fn path_endpoint_overlays(document: &DocumentMessageHandler, shape_editor: &
187198
//let document_to_viewport = document.navigation_handler.calculate_offset_transform(overlay_context.size / 2., &document.document_ptz);
188199
let transform = document.metadata().transform_to_viewport(layer);
189200
let selected = shape_editor.selected_shape_state.get(&layer);
190-
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));
201+
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_point_selected(point));
191202

192203
for point in vector_data.extendable_points(preferences.vector_meshes) {
193204
let Some(position) = vector_data.point_domain.position_from_id(point) else { continue };

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::utility_functions::overlay_canvas_context;
22
use crate::consts::{
3-
COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER,
4-
COMPASS_ROSE_RING_INNER_DIAMETER, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER,
3+
COLOR_OVERLAY_BLUE, COLOR_OVERLAY_BLUE_50, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER,
4+
COMPASS_ROSE_MAIN_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER, MANIPULATOR_GROUP_MARKER_SIZE, PIVOT_CROSSHAIR_LENGTH, PIVOT_CROSSHAIR_THICKNESS, PIVOT_DIAMETER,
55
};
66
use crate::messages::prelude::Message;
77
use bezier_rs::{Bezier, Subpath};
@@ -581,6 +581,35 @@ impl OverlayContext {
581581
self.end_dpi_aware_transform();
582582
}
583583

584+
/// Used by the path tool segment mode in order to show the selected segments.
585+
pub fn outline_select_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
586+
self.start_dpi_aware_transform();
587+
588+
self.render_context.begin_path();
589+
self.bezier_command(bezier, transform, true);
590+
self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE);
591+
self.render_context.set_line_width(4.);
592+
self.render_context.stroke();
593+
594+
self.render_context.set_line_width(1.);
595+
596+
self.end_dpi_aware_transform();
597+
}
598+
599+
pub fn outline_overlay_bezier(&mut self, bezier: Bezier, transform: DAffine2) {
600+
self.start_dpi_aware_transform();
601+
602+
self.render_context.begin_path();
603+
self.bezier_command(bezier, transform, true);
604+
self.render_context.set_stroke_style_str(COLOR_OVERLAY_BLUE_50);
605+
self.render_context.set_line_width(4.);
606+
self.render_context.stroke();
607+
608+
self.render_context.set_line_width(1.);
609+
610+
self.end_dpi_aware_transform();
611+
}
612+
584613
fn bezier_command(&self, bezier: Bezier, transform: DAffine2, move_to: bool) {
585614
self.start_dpi_aware_transform();
586615

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ impl OriginalTransforms {
8888
let Some(selected_points) = shape_editor.selected_points_in_layer(layer) else {
8989
continue;
9090
};
91+
let Some(selected_segments) = shape_editor.selected_segments_in_layer(layer) else {
92+
continue;
93+
};
94+
95+
let mut selected_points = selected_points.clone();
96+
97+
for (segment_id, _, start, end) in vector_data.segment_bezier_iter() {
98+
if selected_segments.contains(&segment_id) {
99+
selected_points.insert(ManipulatorPointId::Anchor(start));
100+
selected_points.insert(ManipulatorPointId::Anchor(end));
101+
}
102+
}
91103

92104
// Anchors also move their handles
93105
let anchor_ids = selected_points.iter().filter_map(|point| point.as_anchor());

0 commit comments

Comments
 (0)