Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new Undo/Redo system #1817

Merged
merged 65 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
d291117
Implement ability to switch between old and new backup system
MrStevns Apr 1, 2024
e755311
Remove anything but the most essential logic
MrStevns Apr 1, 2024
0bc7331
Make it more obvious that we're calling the legacy system
MrStevns Apr 2, 2024
e9ef704
Make sure we always update the save counter
MrStevns Apr 2, 2024
c685bc7
Change feature dialog text
MrStevns Apr 2, 2024
d381cdf
Add another dialog when re-enabling the old system
MrStevns Apr 2, 2024
849e4a1
Apply more cleanup before restructuring
MrStevns Apr 2, 2024
c41802a
Refactor backupManager
MrStevns Apr 4, 2024
aa12b52
Introduce the new backup system to stroke tools and polyline.
MrStevns Apr 4, 2024
f9c93a2
Add backup for smudge tool
MrStevns Apr 8, 2024
28df936
Remove commented code
MrStevns Apr 8, 2024
cb30ce6
Update license snips
MrStevns Apr 8, 2024
255f631
Fix tests crashing
MrStevns Apr 9, 2024
5cdf342
Add missing MOC for backupmanager for Qt 6 compatibility
MrStevns Apr 9, 2024
a52e346
Change argument type for layer bitmap/vector
MrStevns Apr 10, 2024
57e3919
Calling backupmanager backup should be noop for when not activated
MrStevns Apr 10, 2024
9688f4a
Fix vector selection not being painted immediately during undo/redo
MrStevns Apr 10, 2024
d034b64
Simplify CanvasPainter::paintCurrentFrame logic
MrStevns Apr 10, 2024
12a5cfc
Merge branch 'delayed-vector-transformation' into undo-redo-manager-v2
MrStevns Apr 10, 2024
4732037
Fix rotation would jump when using undo/redo and trying to modify again
MrStevns Apr 11, 2024
291dc04
Merge branch 'bug-selection-rotation-offset' into undo-redo-manager-v2
MrStevns Apr 11, 2024
192eba9
Re-enable selection backups
MrStevns Apr 12, 2024
8bf0866
Do some spring cleaning in BackupManager
MrStevns Apr 12, 2024
380ab00
Merge branch 'master' into undo-redo-manager-v2
MrStevns Apr 14, 2024
c370430
Remove use of ptr's, so we don't have to deal with memory freeing.
MrStevns Apr 16, 2024
b4dcd3b
Remove redundant member variables
MrStevns Apr 16, 2024
bcbee06
Replace replaceLastFoo in favour of a generic replaceKeyFrame method
MrStevns Apr 16, 2024
6a1375c
Fix some issues and housekeeping etc.
J5lx Apr 17, 2024
67d9596
Attempt to fix CI-only build failure
J5lx Apr 17, 2024
822de83
Merge pull request #22 from J5lx/MrStevns/undo-redo-manager-v2
MrStevns Apr 17, 2024
e3a9e4b
Fix legacy undo/redo actions being enabled following startup
J5lx Apr 17, 2024
64fbbcf
Remove superfluous delete
J5lx Apr 17, 2024
dc5d40c
Fix undo/redo system being broken
MrStevns Apr 17, 2024
30c6275
Remove redundant methods in backupelement
MrStevns Apr 17, 2024
4fbbc13
Remove id in backupelement
MrStevns Apr 17, 2024
e968d49
Add unreachable check to TransformElement
MrStevns Apr 17, 2024
d5291fa
Use QUndoStack clean instead if checking the backupElement ptr
MrStevns Apr 17, 2024
378d378
Refactor replaceKeyFrame, should use getXAtFrame instead of getLast
MrStevns Apr 22, 2024
1e47ec3
Prevent use of a saved undo state more than once
MrStevns Apr 22, 2024
5ef8398
Rename BackupElements -> old/new to undo/redo
MrStevns Apr 22, 2024
8364074
Refactor Backup terminology to UndoCommand terminology
MrStevns Apr 22, 2024
79ec18b
Remove undo/redo prefix when using new undo/redo system
MrStevns Apr 22, 2024
1857aae
TransformCommand: split undo/redo keyframe resolving
MrStevns Apr 22, 2024
55f2001
Fix old backupmanager references
MrStevns Apr 22, 2024
5da7bf6
Implement ability to set undo/redo steps
MrStevns Apr 24, 2024
71263a8
Merge remote-tracking branch 'pencil2d/master' into undo-redo-manager-v2
MrStevns Apr 24, 2024
1aef143
Change QUndoStack from ptr to object
MrStevns Apr 24, 2024
d107fce
Update core_lib/src/managers/undoredomanager.cpp
MrStevns Apr 25, 2024
c3ed826
Update app/src/generalpage.cpp
MrStevns Apr 25, 2024
7d63d35
Update app/ui/generalpage.ui
MrStevns Apr 25, 2024
b043dd1
Fix changes individual undo/redo setting would disable buttons.
MrStevns Apr 27, 2024
b55228c
Add newline for easier readability
MrStevns Apr 27, 2024
40be1e0
Rework how undo save state should be used
MrStevns Apr 27, 2024
2090e69
Simplify UndoRedoManager::add
MrStevns Apr 27, 2024
97f50f2
Update core_lib/src/managers/undoredomanager.cpp
MrStevns Apr 27, 2024
c795dc8
Fix transform command children would not be called the first time
MrStevns Apr 28, 2024
e629e9c
Rename Undo commands to be more specific
MrStevns Apr 28, 2024
bdd92fd
Rewrite how state is recorded and saved temporarily.
MrStevns Apr 28, 2024
08fbc40
Rename saveStates -> state
MrStevns Apr 28, 2024
5f549c7
Use layerType from save state rather than current layer
MrStevns Apr 28, 2024
7dac960
UndoRedoManager: Improve assert description
MrStevns Apr 28, 2024
c88fb54
Merge branch 'master' into undo-redo-manager-v2
chchwy Jun 4, 2024
ae65a13
Merge remote-tracking branch 'pencil2d/master' into undo-redo-manager-v2
MrStevns Aug 1, 2024
a10d2da
Merge remote-tracking branch 'pencil2d/master' into undo-redo-manager-v2
MrStevns Aug 1, 2024
bab3f1e
Merge branch 'master' into undo-redo-manager-v2
MrStevns Aug 24, 2024
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
90 changes: 90 additions & 0 deletions app/src/generalpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage)
ui->backgroundButtons->setId(ui->dotsBackgroundButton, 4);
ui->backgroundButtons->setId(ui->weaveBackgroundButton, 5);

ui->undoRedoGroupApplyButton->setDisabled(true);
ui->undoRedoGroupCancelButton->setDisabled(true);

auto buttonClicked = static_cast<void (QButtonGroup::*)(QAbstractButton*)>(&QButtonGroup::buttonClicked);
auto curIndexChanged = static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged);
auto spinValueChanged = static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged);
Expand All @@ -122,6 +125,10 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage)
connect(ui->gridCheckBox, &QCheckBox::stateChanged, this, &GeneralPage::gridCheckBoxStateChanged);
connect(ui->framePoolSizeSpin, spinValueChanged, this, &GeneralPage::frameCacheNumberChanged);
connect(ui->invertScrollDirectionBox, &QCheckBox::stateChanged, this, &GeneralPage::invertScrollDirectionBoxStateChanged);
connect(ui->newUndoRedoCheckBox, &QCheckBox::stateChanged, this, &GeneralPage::newUndoRedoCheckBoxStateChanged);
connect(ui->undoStepsBox, spinValueChanged, this, &GeneralPage::undoRedoMaxStepsChanged);
connect(ui->undoRedoGroupApplyButton, &QPushButton::clicked, this, &GeneralPage::undoRedoApplyButtonPressed);
connect(ui->undoRedoGroupCancelButton, &QPushButton::clicked, this, &GeneralPage::undoRedoCancelButtonPressed);
}

GeneralPage::~GeneralPage()
Expand Down Expand Up @@ -181,6 +188,12 @@ void GeneralPage::updateValues()
QSignalBlocker b12(ui->framePoolSizeSpin);
ui->framePoolSizeSpin->setValue(mManager->getInt(SETTING::FRAME_POOL_SIZE));

QSignalBlocker bNewUndoRedoCheckBox(ui->newUndoRedoCheckBox);
ui->newUndoRedoCheckBox->setChecked(mManager->isOn(SETTING::NEW_UNDO_REDO_SYSTEM_ON));

QSignalBlocker bUndoRedoLimitSpinBox(ui->undoStepsBox);
ui->undoStepsBox->setValue(mManager->getInt(SETTING::UNDO_REDO_MAX_STEPS));

int buttonIdx = 1;
if (bgName == "checkerboard") buttonIdx = 1;
else if (bgName == "white") buttonIdx = 2;
Expand Down Expand Up @@ -318,3 +331,80 @@ void GeneralPage::invertScrollDirectionBoxStateChanged(int b)
{
mManager->set(SETTING::INVERT_SCROLL_ZOOM_DIRECTION, b != Qt::Unchecked);
}

void GeneralPage::newUndoRedoCheckBoxStateChanged()
{
ui->undoRedoGroupApplyButton->setEnabled(canApplyOrCancelUndoRedoChanges());
ui->undoRedoGroupCancelButton->setEnabled(canApplyOrCancelUndoRedoChanges());
}

void GeneralPage::undoRedoMaxStepsChanged()
{
ui->undoRedoGroupApplyButton->setEnabled(canApplyOrCancelUndoRedoChanges());
ui->undoRedoGroupCancelButton->setEnabled(canApplyOrCancelUndoRedoChanges());
}

bool GeneralPage::canApplyOrCancelUndoRedoChanges() const
{
const bool newSystemIsOnCurrent = mManager->isOn(SETTING::NEW_UNDO_REDO_SYSTEM_ON);
const int maxUndoRedoStepNumCurrent = mManager->getInt(SETTING::UNDO_REDO_MAX_STEPS);

if (newSystemIsOnCurrent != ui->newUndoRedoCheckBox->isChecked()
|| maxUndoRedoStepNumCurrent != ui->undoStepsBox->value()) {
return true;
} else {
return false;
}
}

void GeneralPage::undoRedoApplyButtonPressed()
{
if (ui->undoStepsBox->value() != mManager->getInt(SETTING::UNDO_REDO_MAX_STEPS)) {
QMessageBox messageBox(this);
messageBox.setIcon(QMessageBox::Warning);
messageBox.setText(tr("Resets your current undo history"));
messageBox.setInformativeText(tr("Changing the maximum number of undo/redo steps resets your current undo/redo history. \n\nAre you sure you want to proceed?"));
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);

if (messageBox.exec() == QMessageBox::Yes) {
mManager->set(SETTING::UNDO_REDO_MAX_STEPS, ui->undoStepsBox->value());
} else {
ui->undoStepsBox->setValue(mManager->getInt(SETTING::UNDO_REDO_MAX_STEPS));
}
}

const bool systemIsOn = mManager->isOn(SETTING::NEW_UNDO_REDO_SYSTEM_ON);
if (ui->newUndoRedoCheckBox->isChecked() != systemIsOn) {
if (ui->newUndoRedoCheckBox->isChecked()) {
QMessageBox messageBox(this);
messageBox.setIcon(QMessageBox::Warning);
messageBox.setText(tr("Experimental feature!"));
messageBox.setInformativeText(tr("This feature is work in progress and may not currently allow for the same features as the current undo/redo system. Once enabled, you'll need to restart the application to start using it. \n\nDo you still want to try?"));
messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);

if (messageBox.exec() == QMessageBox::Yes) {
mManager->set(SETTING::NEW_UNDO_REDO_SYSTEM_ON, true);
} else {
ui->newUndoRedoCheckBox->setCheckState(Qt::Unchecked);
mManager->set(SETTING::NEW_UNDO_REDO_SYSTEM_ON, false);
}
} else {
QMessageBox messageBox(this);
messageBox.setIcon(QMessageBox::Information);
messageBox.setText(tr("The undo/redo system will be changed on the next launch of the application"));
messageBox.exec();
mManager->set(SETTING::NEW_UNDO_REDO_SYSTEM_ON, false);
}
}

ui->undoRedoGroupCancelButton->setDisabled(true);
ui->undoRedoGroupApplyButton->setDisabled(true);
}

void GeneralPage::undoRedoCancelButtonPressed()
{
ui->undoStepsBox->setValue(mManager->getInt(SETTING::UNDO_REDO_MAX_STEPS));
ui->newUndoRedoCheckBox->setCheckState(mManager->isOn(SETTING::NEW_UNDO_REDO_SYSTEM_ON) ? Qt::Checked : Qt::Unchecked);
ui->undoRedoGroupCancelButton->setDisabled(true);
ui->undoRedoGroupApplyButton->setDisabled(true);
}
6 changes: 6 additions & 0 deletions app/src/generalpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,15 @@ private slots:
void backgroundChanged(QAbstractButton* button);
void frameCacheNumberChanged(int value);
void invertScrollDirectionBoxStateChanged(int b);
void newUndoRedoCheckBoxStateChanged();
void undoRedoMaxStepsChanged();

void undoRedoApplyButtonPressed();
void undoRedoCancelButtonPressed();

private:

bool canApplyOrCancelUndoRedoChanges() const;
void updateSafeHelperTextEnabledState();

Ui::GeneralPage* ui = nullptr;
Expand Down
71 changes: 29 additions & 42 deletions app/src/mainwindow2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ GNU General Public License for more details.
#include "soundmanager.h"
#include "viewmanager.h"
#include "selectionmanager.h"
#include "undoredomanager.h"

#include "actioncommands.h"
#include "fileformat.h" //contains constants used by Pencil File Format
#include "util.h"
#include "backupelement.h"
#include "undoredocommand.h"

// app headers
#include "colorbox.h"
Expand Down Expand Up @@ -263,9 +264,7 @@ void MainWindow2::createMenus()
connect(ui->actionImport_Replace_Palette, &QAction::triggered, this, &MainWindow2::openPalette);

//--- Edit Menu ---
connect(mEditor, &Editor::updateBackup, this, &MainWindow2::undoActSetText);
connect(ui->actionUndo, &QAction::triggered, mEditor, &Editor::undo);
connect(ui->actionRedo, &QAction::triggered, mEditor, &Editor::redo);
replaceUndoRedoActions();
connect(ui->actionCut, &QAction::triggered, mEditor, &Editor::copyAndCut);
connect(ui->actionCopy, &QAction::triggered, mEditor, &Editor::copy);
connect(ui->actionPaste_Previous, &QAction::triggered, mEditor, &Editor::pasteFromPreviousFrame);
Expand Down Expand Up @@ -464,6 +463,16 @@ void MainWindow2::createMenus()
connect(mRecentFileMenu, &RecentFileMenu::loadRecentFile, this, &MainWindow2::openFile);
}

void MainWindow2::replaceUndoRedoActions()
{
ui->menuEdit->removeAction(ui->actionUndo);
ui->menuEdit->removeAction(ui->actionRedo);
ui->actionUndo = mEditor->undoRedo()->createUndoAction(this, ui->actionUndo->icon());
ui->actionRedo = mEditor->undoRedo()->createRedoAction(this, ui->actionRedo->icon());
ui->menuEdit->insertAction(ui->actionCut, ui->actionUndo);
ui->menuEdit->insertAction(ui->actionCut, ui->actionRedo);
}

void MainWindow2::setOpacity(int opacity)
{
mEditor->preference()->set(SETTING::WINDOW_OPACITY, 100 - opacity);
Expand All @@ -472,11 +481,17 @@ void MainWindow2::setOpacity(int opacity)

void MainWindow2::updateSaveState()
{
const bool hasUnsavedChanges = mEditor->currentBackup() != mBackupAtSave;
const bool hasUnsavedChanges = mEditor->undoRedo()->hasUnsavedChanges();
setWindowModified(hasUnsavedChanges);
ui->statusBar->updateModifiedStatus(hasUnsavedChanges);
}

void MainWindow2::updateBackupActionState()
{
mEditor->undoRedo()->updateUndoAction(ui->actionUndo);
mEditor->undoRedo()->updateRedoAction(ui->actionRedo);
}

void MainWindow2::openPegAlignDialog()
{
if (mPegAlign != nullptr)
Expand Down Expand Up @@ -697,7 +712,7 @@ bool MainWindow2::openObject(const QString& strFilePath)
progress.setValue(progress.maximum());

updateSaveState();
undoActSetText();
updateBackupActionState();

if (!QFileInfo(strFilePath).isWritable())
{
Expand Down Expand Up @@ -778,7 +793,6 @@ bool MainWindow2::saveObject(QString strSavedFileName)
mTimeLine->updateContent();

setWindowTitle(strSavedFileName.prepend("[*]"));
mBackupAtSave = mEditor->currentBackup();
updateSaveState();

progress.setValue(progress.maximum());
Expand All @@ -798,7 +812,7 @@ bool MainWindow2::saveDocument()

bool MainWindow2::maybeSave()
{
if (mEditor->currentBackup() == mBackupAtSave)
if (!mEditor->undoRedo()->hasUnsavedChanges())
{
return true;
}
Expand Down Expand Up @@ -1045,7 +1059,8 @@ void MainWindow2::newObject()
closeDialogs();

setWindowTitle(PENCIL_WINDOW_TITLE);
undoActSetText();

updateBackupActionState();
}

bool MainWindow2::newObjectFromPresets(int presetIndex)
Expand All @@ -1070,7 +1085,7 @@ bool MainWindow2::newObjectFromPresets(int presetIndex)

setWindowTitle(PENCIL_WINDOW_TITLE);
updateSaveState();
undoActSetText();
updateBackupActionState();

return true;
}
Expand Down Expand Up @@ -1295,35 +1310,6 @@ void MainWindow2::clearKeyboardShortcuts()
}
}

void MainWindow2::undoActSetText()
{
if (mEditor->mBackupIndex < 0)
{
ui->actionUndo->setText(tr("Undo", "Menu item text"));
ui->actionUndo->setEnabled(false);
}
else
{
ui->actionUndo->setText(QString("%1 %2 %3").arg(tr("Undo", "Menu item text"))
.arg(mEditor->mBackupIndex + 1)
.arg(mEditor->mBackupList.at(mEditor->mBackupIndex)->undoText));
ui->actionUndo->setEnabled(true);
}

if (mEditor->mBackupIndex + 2 < mEditor->mBackupList.size())
{
ui->actionRedo->setText(QString("%1 %2 %3").arg(tr("Redo", "Menu item text"))
.arg(mEditor->mBackupIndex + 2)
.arg(mEditor->mBackupList.at(mEditor->mBackupIndex + 1)->undoText));
ui->actionRedo->setEnabled(true);
}
else
{
ui->actionRedo->setText(tr("Redo", "Menu item text"));
ui->actionRedo->setEnabled(false);
}
}

void MainWindow2::exportPalette()
{
QString filePath = FileDialog::getSaveFileName(this, FileType::PALETTE);
Expand Down Expand Up @@ -1379,7 +1365,8 @@ void MainWindow2::openPalette()

void MainWindow2::makeConnections(Editor* editor)
{
connect(editor, &Editor::updateBackup, this, &MainWindow2::updateSaveState);
connect(editor->undoRedo(), &UndoRedoManager::didUpdateUndoStack, this, &MainWindow2::updateSaveState);
connect(editor->undoRedo(), &UndoRedoManager::didUpdateUndoStack, this, &MainWindow2::updateBackupActionState);
connect(editor, &Editor::needDisplayInfo, this, &MainWindow2::displayMessageBox);
connect(editor, &Editor::needDisplayInfoNoTitle, this, &MainWindow2::displayMessageBoxNoTitle);
connect(editor->layers(), &LayerManager::currentLayerChanged, this, &MainWindow2::currentLayerChanged);
Expand Down Expand Up @@ -1607,7 +1594,7 @@ void MainWindow2::startProjectRecovery(int result)
Q_ASSERT(o);
mEditor->setObject(o);
updateSaveState();
undoActSetText();
updateBackupActionState();

const QString title = tr("Recovery Succeeded!");
const QString text = tr("Please save your work immediately to prevent loss of data");
Expand Down Expand Up @@ -1655,7 +1642,7 @@ void MainWindow2::createToolbars()
mOverlayToolbar->setIconSize(QSize(22,22));
mViewToolbar->setIconSize(QSize(22,22));
mMainToolbar->setIconSize(QSize(22,22));

QToolButton* perspectiveLinesAngleButton = new QToolButton(this);
perspectiveLinesAngleButton->setDefaultAction(ui->menuPerspectiveLinesAngle->menuAction());
perspectiveLinesAngleButton->setPopupMode(QToolButton::InstantPopup);
Expand Down
8 changes: 3 additions & 5 deletions app/src/mainwindow2.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class ColorInspector;
class RecentFileMenu;
class ActionCommands;
class ImportImageSeqDialog;
class BackupElement;
class UndoRedoCommand;
class LayerOpacityDialog;
class PegBarAlignmentDialog;
class RepositionFramesDialog;
Expand All @@ -65,7 +65,7 @@ class MainWindow2 : public QMainWindow
Editor* mEditor = nullptr;

public slots:
void undoActSetText();
void updateBackupActionState();
void updateSaveState();
void openPegAlignDialog();
void openRepositionDialog();
Expand Down Expand Up @@ -124,6 +124,7 @@ private slots:

void createDockWidgets();
void createMenus();
void replaceUndoRedoActions();
void setupKeyboardShortcuts();
void clearKeyboardShortcuts();
bool loadMostRecent();
Expand Down Expand Up @@ -167,9 +168,6 @@ private slots:
QToolBar* mViewToolbar = nullptr;
QToolBar* mOverlayToolbar = nullptr;

// backup
BackupElement* mBackupAtSave = nullptr;

PegBarAlignmentDialog* mPegAlign = nullptr;
RepositionFramesDialog* mReposDialog = nullptr;
LayerOpacityDialog* mLayerOpacityDialog = nullptr;
Expand Down
Loading
Loading