mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 05:08:13 +08:00
Add Path tool support for the Tab key swapping to dragging the opposite handle (#2058)
* feat: tab alternates between handles * fix: handle hints, remove anchor to handle switch Added specific handle hints, Can no longer switch to handle if just anchor is selected typo fix * fix: no longer deselect on esc/rclick * feat: hides cursor when switching A pointerlock implementation would be ideal in the future to keep the screen from panning, * fix: tidy up dynamic tool hints switch colinear to V * fix: can no longer hide cursor if anchor selected remove debug statement * fix: clippy * Solve some issues and remap V to C to toggle colinear * Cleanup + change equidistant key from Shift to Alt --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
b7ba2c3637
commit
018e9839f8
@@ -4,6 +4,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{Doc
|
||||
use crate::messages::portfolio::document::utility_types::misc::{GeometrySnapSource, SnapSource};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::tool_messages::path_tool::PointSelectState;
|
||||
|
||||
use bezier_rs::{Bezier, BezierHandles, TValue};
|
||||
use graphene_core::transform::Transform;
|
||||
@@ -12,8 +13,9 @@ use graphene_core::vector::{ManipulatorPointId, PointId, VectorData, VectorModif
|
||||
use glam::DVec2;
|
||||
use graphene_std::vector::{HandleId, SegmentId};
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
|
||||
pub enum ManipulatorAngle {
|
||||
#[default]
|
||||
Colinear,
|
||||
Free,
|
||||
Mixed,
|
||||
@@ -161,9 +163,9 @@ impl ClosestSegment {
|
||||
midpoint
|
||||
}
|
||||
|
||||
pub fn adjusted_insert_and_select(&self, shape_editor: &mut ShapeState, responses: &mut VecDeque<Message>, add_to_selection: bool) {
|
||||
pub fn adjusted_insert_and_select(&self, shape_editor: &mut ShapeState, responses: &mut VecDeque<Message>, extend_selection: bool) {
|
||||
let id = self.adjusted_insert(responses);
|
||||
shape_editor.select_anchor_point_by_id(self.layer, id, add_to_selection)
|
||||
shape_editor.select_anchor_point_by_id(self.layer, id, extend_selection)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +223,7 @@ impl ShapeState {
|
||||
|
||||
/// Select/deselect the first point within the selection threshold.
|
||||
/// Returns a tuple of the points if found and the offset, or `None` otherwise.
|
||||
pub fn change_point_selection(&mut self, network_interface: &NodeNetworkInterface, mouse_position: DVec2, select_threshold: f64, add_to_selection: bool) -> Option<Option<SelectedPointsInfo>> {
|
||||
pub fn change_point_selection(&mut self, network_interface: &NodeNetworkInterface, mouse_position: DVec2, select_threshold: f64, extend_selection: bool) -> Option<Option<SelectedPointsInfo>> {
|
||||
if self.selected_shape_state.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@@ -234,14 +236,14 @@ impl ShapeState {
|
||||
let already_selected = selected_shape_state.is_selected(manipulator_point_id);
|
||||
|
||||
// Should we select or deselect the point?
|
||||
let new_selected = if already_selected { !add_to_selection } else { true };
|
||||
let new_selected = if already_selected { !extend_selection } else { true };
|
||||
|
||||
// Offset to snap the selected point to the cursor
|
||||
let offset = mouse_position - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(point_position);
|
||||
|
||||
// This is selecting the manipulator only for now, next to generalize to points
|
||||
if new_selected {
|
||||
let retain_existing_selection = add_to_selection || already_selected;
|
||||
let retain_existing_selection = extend_selection || already_selected;
|
||||
if !retain_existing_selection {
|
||||
self.deselect_all_points();
|
||||
}
|
||||
@@ -267,8 +269,8 @@ impl ShapeState {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn select_anchor_point_by_id(&mut self, layer: LayerNodeIdentifier, id: PointId, add_to_selection: bool) {
|
||||
if !add_to_selection {
|
||||
pub fn select_anchor_point_by_id(&mut self, layer: LayerNodeIdentifier, id: PointId, extend_selection: bool) {
|
||||
if !extend_selection {
|
||||
self.deselect_all_points();
|
||||
}
|
||||
let point = ManipulatorPointId::Anchor(id);
|
||||
@@ -1060,6 +1062,71 @@ impl ShapeState {
|
||||
_ => self.sorted_selected_layers(network_interface.document_metadata()).find_map(closest_seg),
|
||||
}
|
||||
}
|
||||
pub fn get_dragging_state(&self, network_interface: &NodeNetworkInterface) -> PointSelectState {
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in self.selected_points() {
|
||||
if point.as_anchor().is_some() {
|
||||
return PointSelectState::Anchor;
|
||||
}
|
||||
if point.get_handle_pair(&vector_data).is_some() {
|
||||
return PointSelectState::HandleWithPair;
|
||||
}
|
||||
}
|
||||
}
|
||||
PointSelectState::HandleNoPair
|
||||
}
|
||||
|
||||
/// Returns true if at least one handle with pair is selected
|
||||
pub fn handle_with_pair_selected(&mut self, network_interface: &NodeNetworkInterface) -> bool {
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in self.selected_points() {
|
||||
if point.as_anchor().is_some() {
|
||||
return false;
|
||||
}
|
||||
if point.get_handle_pair(&vector_data).is_some() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Alternate selected handles to mirrors
|
||||
pub fn alternate_selected_handles(&mut self, network_interface: &NodeNetworkInterface) {
|
||||
let mut handles_to_update = Vec::new();
|
||||
|
||||
for &layer in self.selected_shape_state.keys() {
|
||||
let Some(vector_data) = network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in self.selected_points() {
|
||||
if point.as_anchor().is_some() {
|
||||
continue;
|
||||
}
|
||||
if let Some(handles) = point.get_handle_pair(&vector_data) {
|
||||
// handle[0] is selected, handle[1] is opposite / mirror handle
|
||||
handles_to_update.push((layer, handles[0].to_manipulator_point(), handles[1].to_manipulator_point()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (layer, handle_to_deselect, handle_to_select) in handles_to_update {
|
||||
if let Some(state) = self.selected_shape_state.get_mut(&layer) {
|
||||
let points = &state.selected_points;
|
||||
let both_selected = points.contains(&handle_to_deselect) && points.contains(&handle_to_select);
|
||||
if both_selected {
|
||||
continue;
|
||||
}
|
||||
|
||||
state.deselect_point(handle_to_deselect);
|
||||
state.select_point(handle_to_select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Selects handles and anchor connected to current handle
|
||||
pub fn select_handles_and_anchor_connected_to_current_handle(&mut self, network_interface: &NodeNetworkInterface) {
|
||||
|
||||
Reference in New Issue
Block a user