Skip to content

feat: Centralised Undo/Redo System via Command Pattern - #1424

Open
anushkagupta200615-jpg wants to merge 2 commits into
invesalius:masterfrom
anushkagupta200615-jpg:feature/centralised-undo-redo
Open

feat: Centralised Undo/Redo System via Command Pattern#1424
anushkagupta200615-jpg wants to merge 2 commits into
invesalius:masterfrom
anushkagupta200615-jpg:feature/centralised-undo-redo

Conversation

@anushkagupta200615-jpg

Copy link
Copy Markdown

This PR implements a robust Centralised Undo/Redo System for InVesalius 3, resolving the "Dual-Stack Problem" encountered in previous attempts (such as PR #1058) and addressing Issue #1062.

By utilizing the standard Command Pattern and unifying the history stack, this PR ensures that all operations (mask creation, duplication, deletion, and importantly, pixel-level voxel editing) are executed and reversed in strictly chronological order.

Changes Included
HistoryManager (Singleton): Tracks all project state modifications in a unified stack, guaranteeing safe memory handling (max 50 operations) and emitting PubSub events to update GUI menu labels dynamically (e.g., "Undo Add Mask", "Undo Mask Edit").
Commands Architecture: Created AddMaskCommand, RemoveMaskCommand, DuplicateMaskCommand, and MaskEditCommand.
Project Re-indexing: Modified Project.RemoveMask with a non-destructive cleanup=False parameter, allowing deleted masks to stay in memory to be seamlessly recovered upon Undo. Introduced Project.InsertMask to restore deleted masks to their exact previous dictionary indices.
Pixel-Level Stack Unification: Instead of isolating mask brushing/painting into an independent EditionHistory stack that desynchronizes with the global state, pixel edits are now wrapped in a MaskEditCommand and dispatched to the global HistoryManager.
This prevents the race-condition bug from previous PRs where pressing Ctrl+Z could accidentally delete an entire mask instead of undoing the latest brush stroke!

Issue Resolved
Closes #1062

@Prat260104

Copy link
Copy Markdown
Contributor

Hi @anushkagupta200615-jpg

I noticed the new files in the PR doesn't include the standard GPL/copyright license header that's present at the top of the other source files in the repository. Could you add the same header here as well for consistency with the rest of the codebase?

Publisher.sendMessage('Remove mask', index=self.index)

def undo(self):
from invesalius.project import Project

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are importing inside methods?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Proposal: Centralised Undo/Redo system

3 participants