Add comments to history-related messages and handlers

This commit is contained in:
Keavon Chambers
2026-01-12 02:10:07 -08:00
parent 6d13a2556e
commit 30b000aac7
2 changed files with 48 additions and 25 deletions
@@ -49,8 +49,6 @@ pub enum DocumentMessage {
}, },
DeleteSelectedLayers, DeleteSelectedLayers,
DeselectAllLayers, DeselectAllLayers,
DocumentHistoryBackward,
DocumentHistoryForward,
DocumentStructureChanged, DocumentStructureChanged,
DrawArtboardOverlays { DrawArtboardOverlays {
context: OverlayContext, context: OverlayContext,
@@ -110,7 +108,6 @@ pub enum DocumentMessage {
mouse: Option<(f64, f64)>, mouse: Option<(f64, f64)>,
parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>, parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>,
}, },
Redo,
RenameDocument { RenameDocument {
new_name: String, new_name: String,
}, },
@@ -179,10 +176,23 @@ pub enum DocumentMessage {
SetRenderMode { SetRenderMode {
render_mode: RenderMode, render_mode: RenderMode,
}, },
Undo,
Redo,
DocumentHistoryBackward,
DocumentHistoryForward,
// TODO: Rename to HistoryStepPush
/// Create a snapshot of the document at this point in time, by immediately starting and committing a transaction.
AddTransaction, AddTransaction,
// TODO: Rename to HistoryTransactionStart
/// Take a snapshot of the document to an intermediate state, and then depending on what we do next, we might either commit or abort it.
StartTransaction, StartTransaction,
// TODO: Rename to HistoryTransactionEnd
/// Either commit (creating a new history step) or cancel (removing the last history step, as if it never happened) the last transaction started with `StartTransaction`.
EndTransaction, EndTransaction,
/// Cause the document to revert back to the state when the transaction was started. For example, the user may be dragging
/// something around and hits Escape to abort the drag. This jumps the document back to the point before the drag began.
AbortTransaction, AbortTransaction,
/// The same as `AbortTransaction` with one step back, but it can also be called with multiple steps back in the history of undos.
RepeatedAbortTransaction { RepeatedAbortTransaction {
undo_count: usize, undo_count: usize,
}, },
@@ -206,7 +216,6 @@ pub enum DocumentMessage {
UpdateClipTargets { UpdateClipTargets {
clip_targets: HashSet<NodeId>, clip_targets: HashSet<NodeId>,
}, },
Undo,
UngroupSelectedLayers, UngroupSelectedLayers,
UngroupLayer { UngroupLayer {
layer: LayerNodeIdentifier, layer: LayerNodeIdentifier,
@@ -372,8 +372,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] }); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
self.layer_range_selection_reference = None; self.layer_range_selection_reference = None;
} }
DocumentMessage::DocumentHistoryBackward => self.undo_with_history(viewport, responses),
DocumentMessage::DocumentHistoryForward => self.redo_with_history(viewport, responses),
DocumentMessage::DocumentStructureChanged => { DocumentMessage::DocumentStructureChanged => {
if layers_panel_open { if layers_panel_open {
self.network_interface.load_structure(); self.network_interface.load_structure();
@@ -953,15 +951,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
responses.add(ToolMessage::ActivateTool { tool_type: ToolType::Select }); responses.add(ToolMessage::ActivateTool { tool_type: ToolType::Select });
} }
DocumentMessage::Redo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(SelectToolMessage::Abort);
responses.add(DocumentMessage::DocumentHistoryForward);
responses.add(ToolMessage::Redo);
responses.add(OverlaysMessage::Draw);
}
DocumentMessage::RenameDocument { new_name } => { DocumentMessage::RenameDocument { new_name } => {
self.name = new_name.clone(); self.name = new_name.clone();
@@ -1291,6 +1280,27 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
self.render_mode = render_mode; self.render_mode = render_mode;
responses.add_front(NodeGraphMessage::RunDocumentGraph); responses.add_front(NodeGraphMessage::RunDocumentGraph);
} }
DocumentMessage::Undo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(ToolMessage::PreUndo);
responses.add(DocumentMessage::DocumentHistoryBackward);
responses.add(OverlaysMessage::Draw);
responses.add(ToolMessage::Undo);
}
DocumentMessage::Redo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(SelectToolMessage::Abort);
responses.add(DocumentMessage::DocumentHistoryForward);
responses.add(ToolMessage::Redo);
responses.add(OverlaysMessage::Draw);
}
DocumentMessage::DocumentHistoryBackward => self.undo_with_history(viewport, responses),
DocumentMessage::DocumentHistoryForward => self.redo_with_history(viewport, responses),
// Create a snapshot of the document at this point in time, by immediately starting and committing a transaction.
DocumentMessage::AddTransaction => { DocumentMessage::AddTransaction => {
self.start_transaction(responses); self.start_transaction(responses);
self.commit_transaction(responses); self.commit_transaction(responses);
@@ -1299,37 +1309,50 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
DocumentMessage::StartTransaction => { DocumentMessage::StartTransaction => {
self.start_transaction(responses); self.start_transaction(responses);
} }
// Commits the transaction if the network was mutated since the transaction started, otherwise it cancels the transaction // Either commit (creating a new history step) or cancel (removing the last history step, as if it never happened) the last transaction started with `StartTransaction`.
DocumentMessage::EndTransaction => match self.network_interface.transaction_status() { DocumentMessage::EndTransaction => match self.network_interface.transaction_status() {
// This is used if, between the start and end of the transaction, the changes were undone by the user.
// For example, dragging something around and then dropping it back at its exact original position.
// So we cancel the transaction to return to the point before the transaction was started.
TransactionStatus::Started => { TransactionStatus::Started => {
self.network_interface.finish_transaction(); self.network_interface.finish_transaction();
self.document_undo_history.pop_back(); self.document_undo_history.pop_back();
} }
// This is used if, between the start and end of the transaction, actual changes did occur and we want to keep them as part of a history step that the user can undo/redo.
TransactionStatus::Modified => { TransactionStatus::Modified => {
self.commit_transaction(responses); self.commit_transaction(responses);
} }
TransactionStatus::Finished => {} TransactionStatus::Finished => {}
}, },
DocumentMessage::AbortTransaction => match self.network_interface.transaction_status() { DocumentMessage::AbortTransaction => match self.network_interface.transaction_status() {
// If we abort a transaction without any changes having been made, we simply remove the transaction as if it never occurred.
TransactionStatus::Started => { TransactionStatus::Started => {
self.network_interface.finish_transaction(); self.network_interface.finish_transaction();
self.document_undo_history.pop_back(); self.document_undo_history.pop_back();
} }
// If we abort a transaction after changes have been made, we need to undo those changes.
TransactionStatus::Modified => { TransactionStatus::Modified => {
responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: 1 }); responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: 1 });
} }
// This is an erroneous state indicating that a transaction is being aborted without having ever been started.
TransactionStatus::Finished => {} TransactionStatus::Finished => {}
}, },
// The same as `AbortTransaction` with one step back, but it can also be called with multiple steps back in the history of undos.
DocumentMessage::RepeatedAbortTransaction { undo_count } => { DocumentMessage::RepeatedAbortTransaction { undo_count } => {
// This prevents us from aborting a transaction multiple times in a row, which would be erroneous.
if self.network_interface.transaction_status() == TransactionStatus::Finished { if self.network_interface.transaction_status() == TransactionStatus::Finished {
return; return;
} }
// Sometimes (like successive G/R/S transformations) we may need to undo multiple steps to fully abort the transaction, before we finish.
for _ in 0..undo_count { for _ in 0..undo_count {
self.undo(viewport, responses); self.undo(viewport, responses);
} }
// Finally finish the transaction, ensuring that any future operations are not erroneously redone as part of this aborted transaction.
self.network_interface.finish_transaction(); self.network_interface.finish_transaction();
// Refresh state
responses.add(OverlaysMessage::Draw); responses.add(OverlaysMessage::Draw);
responses.add(PortfolioMessage::UpdateOpenDocumentsList); responses.add(PortfolioMessage::UpdateOpenDocumentsList);
} }
@@ -1401,15 +1424,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
DocumentMessage::UpdateClipTargets { clip_targets } => { DocumentMessage::UpdateClipTargets { clip_targets } => {
self.network_interface.update_clip_targets(clip_targets); self.network_interface.update_clip_targets(clip_targets);
} }
DocumentMessage::Undo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(ToolMessage::PreUndo);
responses.add(DocumentMessage::DocumentHistoryBackward);
responses.add(OverlaysMessage::Draw);
responses.add(ToolMessage::Undo);
}
DocumentMessage::UngroupSelectedLayers => { DocumentMessage::UngroupSelectedLayers => {
if !self.selection_network_path.is_empty() { if !self.selection_network_path.is_empty() {
log::error!("Ungrouping selected layers is only supported for the Document Network"); log::error!("Ungrouping selected layers is only supported for the Document Network");