Skip to content

Commit

Permalink
Changes in selection behaviour of handles
Browse files Browse the repository at this point in the history
  • Loading branch information
4adex committed Feb 9, 2025
1 parent 5fae520 commit 818b0af
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ pub fn get_selected_segments(document: &DocumentMessageHandler, shape_editor: &m
}
})
.collect();

//TODO: Currently if there are two duplicate layers, both of their segments get overlays
// Segments of which the selected anchors are a part of
// Adding segments which are are connected to selected anchors
for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()) {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
continue;
Expand Down Expand Up @@ -88,6 +89,43 @@ fn overlay_bezier_handles(
}
}

pub fn overlay_bezier_handle_specific_point(
segment_id: SegmentId,
bezier: Bezier,
start: PointId,
end: PointId,
transform: DAffine2,
overlay_context: &mut OverlayContext,
selected: Option<&SelectedLayerState>,
is_selected: impl Fn(Option<&SelectedLayerState>, ManipulatorPointId) -> bool,
point_to_render: PointId,
) {
let bezier = bezier.apply_transformation(|point| transform.transform_point2(point));
let not_under_anchor = |position: DVec2, anchor: DVec2| position.distance_squared(anchor) >= HIDE_HANDLE_DISTANCE * HIDE_HANDLE_DISTANCE;
match bezier.handles {
bezier_rs::BezierHandles::Quadratic { handle } if not_under_anchor(handle, bezier.start) && not_under_anchor(handle, bezier.end) => {
if start == point_to_render {
//what is point of doing this, what have to be done in this?
overlay_context.line(handle, bezier.start, None);
} else {
overlay_context.line(handle, bezier.end, None);
}
overlay_context.manipulator_handle(handle, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
}
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => {
if not_under_anchor(handle_start, bezier.start) && (point_to_render == start) {
overlay_context.line(handle_start, bezier.start, None);
overlay_context.manipulator_handle(handle_start, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
}
if not_under_anchor(handle_end, bezier.end) && (point_to_render == end) {
overlay_context.line(handle_end, bezier.end, None);
overlay_context.manipulator_handle(handle_end, is_selected(selected, ManipulatorPointId::EndHandle(segment_id)), None);
}
}
_ => {}
}
}

pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext, draw_handles: DrawHandles) {
for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()) {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
Expand All @@ -99,7 +137,8 @@ pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut Shape
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));
overlay_context.outline_vector(&vector_data, transform);

//TODO: Here define which handles to show and which handles to not, for path tool selection
let opposite_handles_data: Vec<(PointId, SegmentId)> = shape_editor.selected_points().filter_map(|point_id| vector_data.get_adjacent_segment(point_id)).collect();

match draw_handles {
DrawHandles::All => {
vector_data.segment_bezier_iter().for_each(|(segment_id, bezier, _start, _end)| {
Expand All @@ -113,6 +152,12 @@ pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut Shape
.for_each(|(segment_id, bezier, _start, _end)| {
overlay_bezier_handles(segment_id, bezier, transform, overlay_context, selected, is_selected);
});

for (segment_id, bezier, start, end) in vector_data.segment_bezier_iter() {
if let Some((corresponding_anchor, _)) = opposite_handles_data.iter().find(|(_, adj_segment_id)| adj_segment_id == &segment_id) {
overlay_bezier_handle_specific_point(segment_id, bezier, start, end, transform, overlay_context, selected, is_selected, *corresponding_anchor);
}
}
}

DrawHandles::FrontierHandles(ref segment_endpoints) => {
Expand All @@ -122,29 +167,7 @@ pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut Shape
.for_each(|(segment_id, bezier, start, end)| {
if segment_endpoints.get(&segment_id).unwrap().len() == 1 {
let point_to_render = segment_endpoints.get(&segment_id).unwrap()[0];
let bezier = bezier.apply_transformation(|point| transform.transform_point2(point));
let not_under_anchor = |position: DVec2, anchor: DVec2| position.distance_squared(anchor) >= HIDE_HANDLE_DISTANCE * HIDE_HANDLE_DISTANCE;
match bezier.handles {
bezier_rs::BezierHandles::Quadratic { handle } if not_under_anchor(handle, bezier.start) && not_under_anchor(handle, bezier.end) => {
if start == point_to_render {
overlay_context.line(handle, bezier.start, None);
} else {
overlay_context.line(handle, bezier.end, None);
}
overlay_context.manipulator_handle(handle, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
}
bezier_rs::BezierHandles::Cubic { handle_start, handle_end } => {
if not_under_anchor(handle_start, bezier.start) && (point_to_render == start) {
overlay_context.line(handle_start, bezier.start, None);
overlay_context.manipulator_handle(handle_start, is_selected(selected, ManipulatorPointId::PrimaryHandle(segment_id)), None);
}
if not_under_anchor(handle_end, bezier.end) && (point_to_render == end) {
overlay_context.line(handle_end, bezier.end, None);
overlay_context.manipulator_handle(handle_end, is_selected(selected, ManipulatorPointId::EndHandle(segment_id)), None);
}
}
_ => {}
}
overlay_bezier_handle_specific_point(segment_id, bezier, start, end, transform, overlay_context, selected, is_selected, point_to_render);
} else {
overlay_bezier_handles(segment_id, bezier, transform, overlay_context, selected, is_selected);
}
Expand Down
74 changes: 54 additions & 20 deletions editor/src/messages/tool/tool_messages/path_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ struct PathToolData {
auto_panning: AutoPanning,
saved_points_before_anchor_select_toggle: Vec<ManipulatorPointId>,
select_anchor_toggled: bool,
saved_points_before_handle_drag: Vec<ManipulatorPointId>,
handle_drag_toggle: bool,
dragging_state: DraggingState,
current_selected_handle_id: Option<ManipulatorPointId>,
angle: f64,
Expand Down Expand Up @@ -473,18 +475,38 @@ impl PathToolData {
extend_selection: bool,
direct_insert_without_sliding: bool,
lasso_select: bool,
tool_options: &PathToolOptions,
) -> PathToolFsmState {
self.double_click_handled = false;
self.opposing_handle_lengths = None;

self.drag_start_pos = input.mouse.position;

let old_selection: Vec<ManipulatorPointId> = shape_editor.selected_points().cloned().collect();

// Select the first point within the threshold (in pixels)
if let Some(selected_points) = shape_editor.change_point_selection(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD, extend_selection) {
responses.add(DocumentMessage::StartTransaction);

if let Some(selected_points) = selected_points {
self.drag_start_pos = input.mouse.position;

//While in mode 2 or 3, if selected points contain only handles and there was some selection before then it stores it and restore on release
if !matches!(tool_options.path_overlay_mode, PathOverlayMode::AllHandles) {
let mut dragging_only_handles = true;
for point in &selected_points.points {
if matches!(point.point_id, ManipulatorPointId::Anchor(_)) {
dragging_only_handles = false;
break;
}
}

if dragging_only_handles && !self.handle_drag_toggle && old_selection.len() > 0 {
self.saved_points_before_handle_drag = old_selection;
self.handle_drag_toggle = true;
}
}

self.start_dragging_point(selected_points, input, document, shape_editor);
responses.add(OverlaysMessage::Draw);
}
Expand Down Expand Up @@ -767,29 +789,34 @@ impl Fsm for PathToolFsmState {

PathOverlayMode::FrontierHandles => {
let selected_segments = get_selected_segments(document, shape_editor);
let mut segment_endpoints: HashMap<SegmentId, Vec<PointId>> = HashMap::new();

for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()) {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
continue;
};

//The points which are part of only one segment will be rendered
let mut selected_segments_by_point: HashMap<PointId, Vec<SegmentId>> = HashMap::new();
for (segment_id, _bezier, start, end) in vector_data.segment_bezier_iter() {
if selected_segments.contains(&segment_id) {
selected_segments_by_point.entry(start).or_insert_with(Vec::new).push(segment_id);
selected_segments_by_point.entry(end).or_insert_with(Vec::new).push(segment_id);
//Behaviour like Selectedpointhandles when only one point is selected
if shape_editor.selected_points().count() == 1 {
path_overlays(document, shape_editor, &mut overlay_context, DrawHandles::SelectedAnchors(selected_segments));
} else {
let mut segment_endpoints: HashMap<SegmentId, Vec<PointId>> = HashMap::new();

for layer in document.network_interface.selected_nodes(&[]).unwrap().selected_layers(document.metadata()) {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
continue;
};

//The points which are part of only one segment will be rendered
let mut selected_segments_by_point: HashMap<PointId, Vec<SegmentId>> = HashMap::new();
for (segment_id, _bezier, start, end) in vector_data.segment_bezier_iter() {
if selected_segments.contains(&segment_id) {
selected_segments_by_point.entry(start).or_insert_with(Vec::new).push(segment_id);
selected_segments_by_point.entry(end).or_insert_with(Vec::new).push(segment_id);
}
}
}
for (point, attached_segments) in selected_segments_by_point {
if attached_segments.len() == 1 {
segment_endpoints.entry(attached_segments[0]).or_insert_with(Vec::new).push(point);
for (point, attached_segments) in selected_segments_by_point {
if attached_segments.len() == 1 {
segment_endpoints.entry(attached_segments[0]).or_insert_with(Vec::new).push(point);
}
}
}
//Now frontier anchors can be sent for rendering overlays
path_overlays(document, shape_editor, &mut overlay_context, DrawHandles::FrontierHandles(segment_endpoints));
}
//Now frontier anchors can be sent for rendering overlays
path_overlays(document, shape_editor, &mut overlay_context, DrawHandles::FrontierHandles(segment_endpoints));
}
}

Expand Down Expand Up @@ -873,7 +900,7 @@ impl Fsm for PathToolFsmState {
tool_data.selection_mode = None;
tool_data.lasso_polygon.clear();

tool_data.mouse_down(shape_editor, document, input, responses, extend_selection, direct_insert_without_sliding, lasso_select)
tool_data.mouse_down(shape_editor, document, input, responses, extend_selection, direct_insert_without_sliding, lasso_select, tool_options)
}
(
PathToolFsmState::Drawing { selection_shape },
Expand Down Expand Up @@ -1114,6 +1141,13 @@ impl Fsm for PathToolFsmState {
PathToolFsmState::Ready
}
(_, PathToolMessage::DragStop { extend_selection, .. }) => {
if tool_data.handle_drag_toggle {
shape_editor.deselect_all_points();
shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_handle_drag);
tool_data.saved_points_before_handle_drag.clear();
tool_data.handle_drag_toggle = false;
}

if tool_data.select_anchor_toggled {
shape_editor.deselect_all_points();
shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_anchor_select_toggle);
Expand Down
20 changes: 20 additions & 0 deletions node-graph/gcore/src/vector/vector_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,26 @@ impl VectorData {
None
}
}

pub fn get_adjacent_segment(&self, manipulator_id: &ManipulatorPointId) -> Option<(PointId, SegmentId)> {
match manipulator_id {
ManipulatorPointId::PrimaryHandle(segment_id) => {
// For start handle, find segments ending at our start point
let (start_point_id, _, _) = self.segment_points_from_id(*segment_id)?;
let start_index = self.point_domain.resolve_id(start_point_id)?;

self.segment_domain.end_connected(start_index).find(|&id| id != *segment_id).map(|id| (start_point_id, id))
}
ManipulatorPointId::EndHandle(segment_id) => {
// For end handle, find segments starting at our end point
let (_, end_point_id, _) = self.segment_points_from_id(*segment_id)?;
let end_index = self.point_domain.resolve_id(end_point_id)?;

self.segment_domain.start_connected(end_index).find(|&id| id != *segment_id).map(|id| (end_point_id, id))
}
ManipulatorPointId::Anchor(_) => None,
}
}
}

impl Default for VectorData {
Expand Down

0 comments on commit 818b0af

Please sign in to comment.