Fix undo/redo history related issues with the Path tool (#3111)
* Fix transactions * A little cleanup * Fix bug in delete * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
9a32e79853
commit
09ece9424d
|
|
@ -1383,7 +1383,9 @@ impl ShapeState {
|
|||
}
|
||||
|
||||
/// Dissolve the selected points.
|
||||
pub fn delete_selected_points(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn delete_selected_points(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, start_transaction: bool) {
|
||||
let mut transaction_started = false;
|
||||
|
||||
for (&layer, state) in &mut self.selected_shape_state {
|
||||
let mut missing_anchors = HashMap::new();
|
||||
let mut deleted_anchors = HashSet::new();
|
||||
|
|
@ -1392,6 +1394,11 @@ impl ShapeState {
|
|||
let selected_segments = &state.selected_segments;
|
||||
|
||||
for point in std::mem::take(&mut state.selected_points) {
|
||||
if !transaction_started && start_transaction {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
transaction_started = true;
|
||||
}
|
||||
|
||||
match point {
|
||||
ManipulatorPointId::Anchor(anchor) => {
|
||||
if let Some(handles) = Self::dissolve_anchor(anchor, responses, layer, &vector) {
|
||||
|
|
@ -1488,34 +1495,51 @@ impl ShapeState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn delete_selected_segments(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn delete_selected_segments(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, start_transaction: bool) -> bool {
|
||||
let mut transaction_started = false;
|
||||
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for (segment, _, start, end) in vector.segment_bezier_iter() {
|
||||
if state.selected_segments.contains(&segment) {
|
||||
if start_transaction && !transaction_started {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
transaction_started = true;
|
||||
}
|
||||
self.dissolve_segment(responses, layer, &vector, segment, [start, end]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transaction_started
|
||||
}
|
||||
|
||||
pub fn delete_hanging_selected_anchors(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn delete_hanging_selected_anchors(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, start_transaction: bool) {
|
||||
let mut transaction_started = false;
|
||||
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for point in &state.selected_points {
|
||||
if let ManipulatorPointId::Anchor(anchor) = point {
|
||||
if vector.all_connected(*anchor).all(|segment| state.is_segment_selected(segment.segment)) {
|
||||
let modification_type = VectorModificationType::RemovePoint { id: *anchor };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
if let ManipulatorPointId::Anchor(anchor) = point
|
||||
&& vector.all_connected(*anchor).all(|segment| state.is_segment_selected(segment.segment))
|
||||
{
|
||||
if !transaction_started && start_transaction {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
transaction_started = true
|
||||
}
|
||||
let modification_type = VectorModificationType::RemovePoint { id: *anchor };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: this also adds a history transaction if there is some change in state.
|
||||
pub fn break_path_at_selected_point(&self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
let mut transaction_started = false;
|
||||
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
|
|
@ -1527,6 +1551,11 @@ impl ShapeState {
|
|||
for handle in vector.all_connected(point) {
|
||||
// Disable the g1 continuous
|
||||
for &handles in &vector.colinear_manipulators {
|
||||
if !transaction_started {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
transaction_started = true;
|
||||
}
|
||||
|
||||
if handles.contains(&handle) {
|
||||
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
|
@ -1539,6 +1568,11 @@ impl ShapeState {
|
|||
continue;
|
||||
}
|
||||
|
||||
if !transaction_started {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
transaction_started = true;
|
||||
}
|
||||
|
||||
// Create new point
|
||||
let id = PointId::generate();
|
||||
let modification_type = VectorModificationType::InsertPoint { id, position: pos };
|
||||
|
|
@ -1559,13 +1593,20 @@ impl ShapeState {
|
|||
}
|
||||
|
||||
/// Delete point(s) and adjacent segments.
|
||||
pub fn delete_point_and_break_path(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
/// Note: this also adds a history transaction if there is some change in state, and true is returned if so.
|
||||
pub fn delete_point_and_break_path(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> bool {
|
||||
let mut transaction_started = false;
|
||||
|
||||
for (&layer, state) in &mut self.selected_shape_state {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { continue };
|
||||
|
||||
for delete in std::mem::take(&mut state.selected_points) {
|
||||
let Some(point) = delete.get_anchor(&vector) else { continue };
|
||||
|
||||
if !transaction_started {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
transaction_started = true;
|
||||
}
|
||||
// Delete point
|
||||
let modification_type = VectorModificationType::RemovePoint { id: point };
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
|
|
@ -1577,6 +1618,8 @@ impl ShapeState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
transaction_started
|
||||
}
|
||||
|
||||
/// Disable colinear handles colinear.
|
||||
|
|
|
|||
|
|
@ -2611,17 +2611,15 @@ impl Fsm for PathToolFsmState {
|
|||
// Delete key
|
||||
(_, PathToolMessage::Delete) => {
|
||||
// Delete the selected points and clean up overlays
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
let point_mode = tool_options.path_editing_mode.point_editing_mode;
|
||||
let segment_mode = tool_options.path_editing_mode.segment_editing_mode;
|
||||
|
||||
let only_segment_mode = segment_mode && !point_mode;
|
||||
|
||||
shape_editor.delete_selected_segments(document, responses);
|
||||
let transaction_started = shape_editor.delete_selected_segments(document, responses, true);
|
||||
if only_segment_mode {
|
||||
shape_editor.delete_hanging_selected_anchors(document, responses);
|
||||
shape_editor.delete_hanging_selected_anchors(document, responses, !transaction_started);
|
||||
} else {
|
||||
shape_editor.delete_selected_points(document, responses);
|
||||
shape_editor.delete_selected_points(document, responses, !transaction_started);
|
||||
}
|
||||
responses.add(PathToolMessage::SelectionChanged);
|
||||
|
||||
|
|
@ -2841,8 +2839,8 @@ impl Fsm for PathToolFsmState {
|
|||
}
|
||||
(_, PathToolMessage::DeleteSelected) => {
|
||||
// Delete the selected points and segments
|
||||
shape_editor.delete_point_and_break_path(document, responses);
|
||||
shape_editor.delete_selected_segments(document, responses);
|
||||
let deleted_some_point = shape_editor.delete_point_and_break_path(document, responses);
|
||||
shape_editor.delete_selected_segments(document, responses, !deleted_some_point);
|
||||
|
||||
PathToolFsmState::Ready
|
||||
}
|
||||
|
|
|
|||
|
|
@ -599,7 +599,7 @@ impl PenToolData {
|
|||
self.g1_continuous = true;
|
||||
let document = snap_data.document;
|
||||
self.next_handle_start = self.next_point;
|
||||
let vector = document.network_interface.compute_modified_vector(layer).unwrap();
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
self.update_handle_type(TargetHandle::FuturePreviewOutHandle);
|
||||
self.handle_mode = HandleMode::ColinearLocked;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue