Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions editor/src/messages/input_mapper/input_mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub fn input_mappings() -> Mapping {
//
// SelectToolMessage
entry!(PointerMove; refresh_keys=[Control, Alt, Shift], action_dispatch=SelectToolMessage::PointerMove(SelectToolPointerKeys { axis_align: Shift, snap_angle: Control, center: Alt, duplicate: Alt })),
entry!(KeyDown(MouseLeft); action_dispatch=SelectToolMessage::DragStart { add_to_selection: Shift, select_deepest: Accel }),
entry!(KeyDown(MouseLeft); action_dispatch=SelectToolMessage::DragStart { extend_selection: Shift, select_deepest: Accel }),
entry!(KeyUp(MouseLeft); action_dispatch=SelectToolMessage::DragStop { remove_from_selection: Shift }),
entry!(KeyDown(Enter); action_dispatch=SelectToolMessage::Enter),
entry!(DoubleClick(MouseButton::Left); action_dispatch=SelectToolMessage::EditLayer),
Expand Down Expand Up @@ -204,19 +204,20 @@ pub fn input_mappings() -> Mapping {
entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=PathToolMessage::DeleteAndBreakPath),
entry!(KeyDown(Delete); modifiers=[Accel, Shift], action_dispatch=PathToolMessage::BreakPath),
entry!(KeyDown(Backspace); modifiers=[Accel, Shift], action_dispatch=PathToolMessage::BreakPath),
entry!(KeyDown(MouseLeft); action_dispatch=PathToolMessage::MouseDown { ctrl: Control, shift: Shift }),
entry!(KeyDown(Tab); action_dispatch=PathToolMessage::SwapSelectedHandles),
entry!(KeyDown(MouseLeft); action_dispatch=PathToolMessage::MouseDown { direct_insert_without_sliding: Control, extend_selection: Shift }),
entry!(KeyDown(MouseRight); action_dispatch=PathToolMessage::RightClick),
entry!(KeyDown(Escape); action_dispatch=PathToolMessage::Escape),
entry!(KeyDown(KeyG); action_dispatch=PathToolMessage::GRS { key: KeyG }),
entry!(KeyDown(KeyR); action_dispatch=PathToolMessage::GRS { key: KeyR }),
entry!(KeyDown(KeyS); action_dispatch=PathToolMessage::GRS { key: KeyS }),
entry!(PointerMove; refresh_keys=[Alt, Shift, Space], action_dispatch=PathToolMessage::PointerMove { alt: Alt, shift: Shift, move_anchor_and_handles: Space}),
entry!(PointerMove; refresh_keys=[KeyC, Shift, Alt, Space], action_dispatch=PathToolMessage::PointerMove { toggle_colinear: KeyC, equidistant: Alt, move_anchor_with_handles: Space}),
entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete),
entry!(KeyDown(KeyA); modifiers=[Accel], action_dispatch=PathToolMessage::SelectAllAnchors),
entry!(KeyDown(KeyA); modifiers=[Accel, Shift], action_dispatch=PathToolMessage::DeselectAllPoints),
entry!(KeyDown(Backspace); action_dispatch=PathToolMessage::Delete),
entry!(KeyUp(MouseLeft); action_dispatch=PathToolMessage::DragStop { equidistant: Shift }),
entry!(KeyDown(Enter); action_dispatch=PathToolMessage::Enter { add_to_selection: Shift }),
entry!(KeyUp(MouseLeft); action_dispatch=PathToolMessage::DragStop { extend_selection: Shift }),
entry!(KeyDown(Enter); action_dispatch=PathToolMessage::Enter { extend_selection: Shift }),
entry!(DoubleClick(MouseButton::Left); action_dispatch=PathToolMessage::FlipSmoothSharp),
entry!(KeyDown(ArrowRight); action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: NUDGE_AMOUNT, delta_y: 0. }),
entry!(KeyDown(ArrowRight); modifiers=[Shift], action_dispatch=PathToolMessage::NudgeSelectedPoints { delta_x: BIG_NUDGE_AMOUNT, delta_y: 0. }),
Expand Down
83 changes: 75 additions & 8 deletions editor/src/messages/tool/common_functionality/shape_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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;
}
Expand All @@ -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();
}
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
Loading
Loading