Restore handle length when Shift is released while dragging opposite handle with Path tool (#1009)

* Restore path handle length to previous length when shift is released while dragging

* Reset previous opposing handle length on Delete and Abort messages

* Move the opposing handle length state to the path tool

* Use MoveManipulatorPoint messages instead of modifying MoveSelectedManipulatorPoints + break handle mirroring on dragging both handles without anchor

* Handle alt + improve reset logic + comments

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Shouvik Ghosh
2023-02-22 05:21:46 +05:30
committed by Keavon Chambers
co-authored by Keavon Chambers
parent 107e55e91d
commit 92cb553961
3 changed files with 126 additions and 0 deletions
@@ -212,6 +212,114 @@ impl ShapeEditor {
}
}
/// The opposing handle lengths.
pub fn opposing_handle_lengths(&self, document: &Document) -> HashMap<Vec<LayerId>, HashMap<u64, f64>> {
self.selected_layers()
.iter()
.filter_map(|path| document.layer(path).ok().map(|layer| (path, layer)))
.filter_map(|(path, shape)| shape.as_subpath().map(|subpath| (path, subpath)))
.map(|(path, shape)| {
let opposing_handle_lengths = shape
.manipulator_groups()
.enumerate()
.filter_map(|(id, manipulator_group)| {
// We will keep track of the opposing handle length when:
// i) Both handles exist and exactly one is selected.
// ii) The anchor is not selected.
// iii) We have to mirror the angle between handles.
if !manipulator_group.editor_state.mirror_angle_between_handles {
return None;
}
let mut selected_handles = manipulator_group.selected_handles();
let handle = selected_handles.next()?;
// Check that handle is the only selected handle.
if selected_handles.next().is_none() {
let opposing_handle_position = manipulator_group.opposing_handle(handle)?.position;
let anchor = manipulator_group.points[ManipulatorType::Anchor].as_ref()?;
if !anchor.is_selected() {
let opposing_handle_length = opposing_handle_position.distance(anchor.position);
Some((*id, opposing_handle_length))
} else {
None
}
} else {
None
}
})
.collect::<HashMap<_, _>>();
(path.clone(), opposing_handle_lengths)
})
.collect::<HashMap<_, _>>()
}
/// Reset the opposing handle lengths.
pub fn reset_opposing_handle_lengths(&self, document: &Document, opposing_handle_lengths: &HashMap<Vec<LayerId>, HashMap<u64, f64>>, responses: &mut VecDeque<Message>) {
self.selected_layers()
.iter()
.filter_map(|path| document.layer(path).ok().map(|layer| (path, layer)))
.filter_map(|(path, shape)| shape.as_subpath().map(|subpath| (path, subpath)))
.filter_map(|(path, shape)| opposing_handle_lengths.get(path).map(|layer_opposing_handle_lengths| (path, shape, layer_opposing_handle_lengths)))
.flat_map(|(path, shape, layer_opposing_handle_lengths)| {
shape
.manipulator_groups()
.enumerate()
.map(move |(id, manipulator_group)| (path, layer_opposing_handle_lengths, id, manipulator_group))
})
.for_each(|(path, layer_opposing_handle_lengths, id, manipulator_group)| {
if !manipulator_group.editor_state.mirror_angle_between_handles {
return;
}
let opposing_handle_length = if let Some(length) = layer_opposing_handle_lengths.get(id) {
length
} else {
return;
};
let mut selected_handles = manipulator_group.selected_handles();
let handle = if let Some(handle) = selected_handles.next() {
handle
} else {
return;
};
// Check that handle is the only selected handle.
if selected_handles.next().is_none() {
let opposing_handle = if let Some(opposing_handle) = manipulator_group.opposing_handle(handle) {
opposing_handle
} else {
return;
};
let anchor = if let Some(anchor) = manipulator_group.points[ManipulatorType::Anchor].as_ref() {
anchor
} else {
return;
};
if anchor.is_selected() {
return;
}
if let Some(offset) = (opposing_handle.position - anchor.position).try_normalize() {
let new_opposing_handle_position = anchor.position + offset * (*opposing_handle_length);
assert!(new_opposing_handle_position.is_finite(), "Opposing handle not finite!");
responses.push_back(
Operation::MoveManipulatorPoint {
layer_path: path.clone(),
id: *id,
manipulator_type: opposing_handle.manipulator_type,
position: new_opposing_handle_position.into(),
}
.into(),
);
}
}
});
}
/// Dissolve the selected points.
pub fn delete_selected_points(&self, responses: &mut VecDeque<Message>) {
responses.push_back(DocumentMessage::DeleteSelectedManipulatorPoints.into());