Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • core_lib
  • src
  • managers
undoredomanager.cpp
1/*
2
3Pencil2D - Traditional Animation Software
4Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5Copyright (C) 2008-2009 Mj Mendoza IV
6Copyright (C) 2012-2020 Matthew Chiawen Chang
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; version 2 of the License.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17*/
18
19#include "object.h"
20#include "editor.h"
21
22#include <QAction>
23#include <QDebug>
24#include <QSettings>
25
26
27#include "preferencemanager.h"
28#include "layermanager.h"
29#include "soundmanager.h"
30#include "undoredomanager.h"
31#include "selectionmanager.h"
32
33#include "undoredocommand.h"
34#include "legacybackupelement.h"
35
36#include "layerbitmap.h"
37#include "layervector.h"
38#include "layersound.h"
39
40
41#include "bitmapimage.h"
42#include "vectorimage.h"
43#include "soundclip.h"
44
45UndoRedoManager::UndoRedoManager(Editor* editor) : BaseManager(editor, "UndoRedoManager")
46{
47 qDebug() << "UndoRedoManager: created";
48}
49
50UndoRedoManager::~UndoRedoManager()
51{
52 if (!mNewBackupSystemEnabled)
53 {
54 clearStack();
55 }
56 clearSaveStates();
57 qDebug() << "UndoRedoManager: destroyed";
58}
59
60bool UndoRedoManager::init()
61{
62 qDebug() << "UndoRedoManager: init";
63
64 mUndoStack.setUndoLimit(editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS));
65 mNewBackupSystemEnabled = editor()->preference()->isOn(SETTING::NEW_UNDO_REDO_SYSTEM_ON);
66
67 return true;
68}
69
70void UndoRedoManager::onSettingChanged(SETTING setting)
71{
72 if (setting == SETTING::UNDO_REDO_MAX_STEPS) {
73 // The stack needs to be cleared in order to change the undo redo limit
74 clearStack();
75 qDebug() << "updated undo stack limit";
76 mUndoStack.setUndoLimit(editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS));
77 }
78}
79
80Status UndoRedoManager::load(Object* /*o*/)
81{
82 clearStack();
83 return Status::OK;
84}
85
86Status UndoRedoManager::save(Object* /*o*/)
87{
88 if (mNewBackupSystemEnabled) {
89 mUndoStack.setClean();
90 } else if (!mLegacyBackupList.isEmpty() && mLegacyBackupIndex < mLegacyBackupList.count()) {
91 mLegacyBackupAtSave = mLegacyBackupList[mLegacyBackupIndex];
92 }
93 return Status::OK;
94}
95
96void UndoRedoManager::record(SAVESTATE_ID saveStateId, const QString& description)
97{
98 if (!mSaveStates.contains(saveStateId)) {
99 return;
100 }
101
102 UndoSaveState* saveState = mSaveStates.take(saveStateId);
103 if (!saveState) { return; }
104
105 if (!mNewBackupSystemEnabled) {
106 clearState(saveState);
107 return;
108 }
109
110 switch (saveState->recordType)
111 {
112 case UndoRedoRecordType::KEYFRAME_MODIFY: {
113 replaceKeyFrame(*saveState, description);
114 break;
115 }
116 case UndoRedoRecordType::KEYFRAME_REMOVE: {
117 removeKeyFrame(*saveState, description);
118 break;
119 }
120 case UndoRedoRecordType::KEYFRAME_ADD: {
121 addKeyFrame(*saveState, description);
122 break;
123 }
124 case UndoRedoRecordType::KEYFRAME_MOVE: {
125 moveKeyFrames(*saveState, description);
126 break;
127 }
128 default: {
129 QString reason("Unhandled case for: ");
130 reason.append(description);
131 Q_ASSERT_X(false, "UndoRedoManager::record", qPrintable(reason));
132 break;
133 }
134 }
135
136 // The save state has now been used and should be invalidated so we can't use it again.
137 clearState(saveState);
138}
139
140void UndoRedoManager::clearState(UndoSaveState*& state)
141{
142 if (state) {
143 delete state;
144 state = nullptr;
145 }
146}
147
148void UndoRedoManager::clearSaveStates()
149{
150 for (UndoSaveState* saveState : mSaveStates) {
151 if (saveState) {
152 delete saveState;
153 saveState = nullptr;
154 }
155 }
156 mSaveStates.clear();
157}
158
159bool UndoRedoManager::hasUnsavedChanges() const
160{
161 if (mNewBackupSystemEnabled) {
162 return !mUndoStack.isClean();
163 } else {
164 if (mLegacyBackupIndex >= 0) {
165 return mLegacyBackupAtSave != mLegacyBackupList[mLegacyBackupIndex];
166 }
167 return false;
168 }
169}
170
171void UndoRedoManager::pushCommand(QUndoCommand* command)
172{
173 mUndoStack.push(command);
174
175 emit didUpdateUndoStack();
176}
177
178void UndoRedoManager::removeKeyFrame(const UndoSaveState& undoState, const QString& description)
179{
180 KeyFrameRemoveCommand* element = new KeyFrameRemoveCommand(undoState.keyframe.get(),
181 undoState.layerId,
182 description,
183 editor());
184 pushCommand(element);
185}
186
187void UndoRedoManager::addKeyFrame(const UndoSaveState& undoState, const QString& description)
188{
189 KeyFrameAddCommand* element = new KeyFrameAddCommand(undoState.currentFrameIndex,
190 undoState.layerId,
191 description,
192 editor());
193 pushCommand(element);
194}
195
196void UndoRedoManager::replaceKeyFrame(const UndoSaveState& undoState, const QString& description)
197{
198 if (undoState.layerType == Layer::BITMAP) {
199 replaceBitmap(undoState, description);
200 } else if (undoState.layerType == Layer::VECTOR) {
201 replaceVector(undoState, description);
202 } else {
203 // Implement other cases
204 }
205}
206
207void UndoRedoManager::moveKeyFrames(const UndoSaveState& undoState, const QString& description)
208{
209 const MoveFramesSaveState& state = undoState.userState.moveFramesState;
210 MoveKeyFramesCommand* element = new MoveKeyFramesCommand(state.offset,
211 state.positions,
212 undoState.layerId,
213 description,
214 editor());
215 pushCommand(element);
216}
217
218void UndoRedoManager::replaceBitmap(const UndoSaveState& undoState, const QString& description)
219{
220 if (undoState.keyframe == nullptr || undoState.layerType != Layer::BITMAP) { return; }
221 BitmapReplaceCommand* element = new BitmapReplaceCommand(static_cast<BitmapImage*>(undoState.keyframe.get()),
222 undoState.layerId,
223 description,
224 editor());
225
226 const SelectionSaveState& selectionState = undoState.selectionState;
227 new TransformCommand(selectionState.bounds,
228 selectionState.translation,
229 selectionState.rotationAngle,
230 selectionState.scaleX,
231 selectionState.scaleY,
232 selectionState.anchor,
233 true, // roundPixels
234 description,
235 editor(), element);
236
237 pushCommand(element);
238}
239
240void UndoRedoManager::replaceVector(const UndoSaveState& undoState, const QString& description)
241{
242 if (undoState.keyframe == nullptr || undoState.layerType != Layer::VECTOR) { return; }
243 VectorReplaceCommand* element = new VectorReplaceCommand(static_cast<VectorImage*>(undoState.keyframe.get()),
244 undoState.layerId,
245 description,
246 editor());
247
248 const SelectionSaveState& selectionState = undoState.selectionState;
249 new TransformCommand(selectionState.bounds,
250 selectionState.translation,
251 selectionState.rotationAngle,
252 selectionState.scaleX,
253 selectionState.scaleY,
254 selectionState.anchor,
255 false, // Round pixels
256 description,
257 editor(), element);
258 pushCommand(element);
259}
260
261SAVESTATE_ID UndoRedoManager::createState(UndoRedoRecordType recordType)
262{
263 int saveStateId = mSaveStateId;
264 UndoSaveState* state = new UndoSaveState();
265 state->recordType = recordType;
266 initCommonKeyFrameState(state);
267
268 mSaveStates[saveStateId] = state;
269 mSaveStateId += 1;
270
271 return saveStateId;
272}
273
274void UndoRedoManager::addUserState(SAVESTATE_ID saveStateId, const UserSaveState& userState)
275{
276 if (!mSaveStates.contains(saveStateId)) { return; }
277 mSaveStates[saveStateId]->userState = userState;
278}
279
280void UndoRedoManager::initCommonKeyFrameState(UndoSaveState* undoSaveState) const
281{
282 const Layer* layer = editor()->layers()->currentLayer();
283 undoSaveState->layerType = layer->type();
284 undoSaveState->layerId = layer->id();
285 undoSaveState->currentFrameIndex = editor()->currentFrame();
286
287 if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR) {
288 auto selectMan = editor()->select();
289 undoSaveState->selectionState = SelectionSaveState(
290 selectMan->mySelectionRect(),
291 selectMan->myRotation(),
292 selectMan->myScaleX(),
293 selectMan->myScaleY(),
294 selectMan->myTranslation(),
295 selectMan->currentTransformAnchor());
296 }
297
298 const int frameIndex = editor()->currentFrame();
299 if (layer->keyExists(frameIndex))
300 {
301 undoSaveState->keyframe = std::unique_ptr<KeyFrame>(layer->getLastKeyFrameAtPosition(frameIndex)->clone());
302 }
303 else if (layer->getKeyFrameWhichCovers(frameIndex) != nullptr)
304 {
305 undoSaveState->keyframe = std::unique_ptr<KeyFrame>(layer->getKeyFrameWhichCovers(frameIndex)->clone());
306 }
307}
308
309QAction* UndoRedoManager::createUndoAction(QObject* parent, const QIcon& icon)
310{
311 QAction* undoAction = nullptr;
312 if (mNewBackupSystemEnabled) {
313 undoAction = mUndoStack.createUndoAction(parent);
314 } else {
315 undoAction = new QAction(parent);
316 undoAction->setText(tr("Undo"));
317 undoAction->setDisabled(true);
318 }
319 undoAction->setIcon(icon);
320
321 if (mNewBackupSystemEnabled) {
322 // The new system takes care of this automatically
323 } else {
324 connect(undoAction, &QAction::triggered, this, &UndoRedoManager::legacyUndo);
325 }
326 return undoAction;
327}
328
329QAction* UndoRedoManager::createRedoAction(QObject* parent, const QIcon& icon)
330{
331 QAction* redoAction = nullptr;
332 if (mNewBackupSystemEnabled) {
333 redoAction = mUndoStack.createRedoAction(parent);
334 } else {
335 redoAction = new QAction(parent);
336 redoAction->setText(tr("Redo"));
337 redoAction->setDisabled(true);
338 }
339 redoAction->setIcon(icon);
340
341 if (mNewBackupSystemEnabled) {
342 // The new system takes care of this automatically
343 } else {
344 connect(redoAction, &QAction::triggered, this, &UndoRedoManager::legacyRedo);
345 }
346 return redoAction;
347}
348
349void UndoRedoManager::updateUndoAction(QAction* undoAction)
350{
351 if (mNewBackupSystemEnabled) {
352 // Not used
353 // function can be removed when we have replaced the legacy system
354 } else {
355 if (mLegacyBackupIndex < 0)
356 {
357 undoAction->setText(tr("Undo", "Menu item text"));
358 undoAction->setEnabled(false);
359 qDebug() << undoAction->text();
360 }
361 else
362 {
363 undoAction->setText(QString("%1 %2 %3").arg(tr("Undo", "Menu item text"))
364 .arg(mLegacyBackupIndex + 1)
365 .arg(mLegacyBackupList.at(mLegacyBackupIndex)->undoText));
366 undoAction->setIconText(QString("%1 %2 %3").arg(tr("Undo", "Menu item text"))
367 .arg(mLegacyBackupIndex + 1)
368 .arg(mLegacyBackupList.at(mLegacyBackupIndex)->undoText));
369 undoAction->setEnabled(true);
370 qDebug() << undoAction->text();
371 }
372 }
373}
374
375void UndoRedoManager::updateRedoAction(QAction* redoAction)
376{
377 if (mNewBackupSystemEnabled) {
378 // Not used
379 // function can be removed when we have replaced the legacy system
380 } else {
381 if (mLegacyBackupIndex + 2 < mLegacyBackupList.size())
382 {
383 redoAction->setText(QString("%1 %2 %3").arg(tr("Redo", "Menu item text"))
384 .arg(mLegacyBackupIndex + 2)
385 .arg(mLegacyBackupList.at(mLegacyBackupIndex + 1)->undoText));
386 redoAction->setEnabled(true);
387 }
388 else
389 {
390 redoAction->setText(tr("Redo", "Menu item text"));
391 redoAction->setEnabled(false);
392 }
393 }
394}
395
396void UndoRedoManager::clearStack()
397{
398 if (mNewBackupSystemEnabled) {
399 mUndoStack.clear();
400 } else {
401 mLegacyBackupIndex = -1;
402 while (!mLegacyBackupList.isEmpty())
403 {
404 delete mLegacyBackupList.takeLast();
405 }
406 mLegacyLastModifiedLayer = -1;
407 mLegacyLastModifiedFrame = -1;
408 }
409}
410
411// Legacy backup system
412
413void UndoRedoManager::legacyBackup(const QString& undoText)
414{
415
416 if (mNewBackupSystemEnabled) {
417 return;
418 }
419
420 KeyFrame* frame = nullptr;
421 int currentFrame = editor()->currentFrame();
422 if (mLegacyLastModifiedLayer > -1 && mLegacyLastModifiedFrame > 0)
423 {
424 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
425 {
426 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(mLegacyLastModifiedFrame);
427 if (frame != nullptr)
428 {
429 legacyBackup(mLegacyLastModifiedLayer, frame->pos(), undoText);
430 }
431 }
432 else
433 {
434 legacyBackup(mLegacyLastModifiedLayer, mLegacyLastModifiedFrame, undoText);
435 }
436 }
437 if (mLegacyLastModifiedLayer != editor()->layers()->currentLayerIndex() || mLegacyLastModifiedFrame != currentFrame)
438 {
439 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
440 {
441 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(currentFrame);
442
443 if (frame != nullptr)
444 {
445 legacyBackup(editor()->layers()->currentLayerIndex(), frame->pos(), undoText);
446 }
447 }
448 else
449 {
450 legacyBackup(editor()->layers()->currentLayerIndex(), currentFrame, undoText);
451 }
452 }
453}
454
455bool UndoRedoManager::legacyBackup(int backupLayer, int backupFrame, const QString& undoText)
456{
457 if (mNewBackupSystemEnabled) {
458 return false;
459 }
460
461 while (mLegacyBackupList.size() - 1 > mLegacyBackupIndex && !mLegacyBackupList.empty())
462 {
463 delete mLegacyBackupList.takeLast();
464 }
465 while (mLegacyBackupList.size() >= editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS))
466 {
467 delete mLegacyBackupList.takeFirst();
468 mLegacyBackupIndex--;
469 }
470
471 Layer* layer = editor()->layers()->getLayer(backupLayer);
472 int currentFrame = editor()->currentFrame();
473 if (layer != nullptr)
474 {
475 if (layer->type() == Layer::BITMAP)
476 {
477 BitmapImage* bitmapImage = static_cast<BitmapImage*>(layer->getLastKeyFrameAtPosition(backupFrame));
478 if (currentFrame == 1)
479 {
480 int previous = layer->getPreviousKeyFramePosition(backupFrame);
481 bitmapImage = static_cast<BitmapImage*>(layer->getKeyFrameAt(previous));
482 }
483 if (bitmapImage != nullptr)
484 {
485 BackupLegacyBitmapElement* element = new BackupLegacyBitmapElement(bitmapImage);
486 element->layerId = layer->id();
487 element->layer = backupLayer;
488 element->frame = bitmapImage->pos();
489 element->undoText = undoText;
490 element->somethingSelected = editor()->select()->somethingSelected();
491 element->mySelection = editor()->select()->mySelectionRect();
492 element->rotationAngle = editor()->select()->myRotation();
493 element->scaleX = editor()->select()->myScaleX();
494 element->scaleY = editor()->select()->myScaleY();
495 element->translation = editor()->select()->myTranslation();
496 element->selectionAnchor = editor()->select()->currentTransformAnchor();
497
498 mLegacyBackupList.append(element);
499 mLegacyBackupIndex++;
500 }
501 else
502 {
503 return false;
504 }
505 }
506 else if (layer->type() == Layer::VECTOR)
507 {
508 VectorImage* vectorImage = static_cast<VectorImage*>(layer->getLastKeyFrameAtPosition(backupFrame));
509 if (vectorImage != nullptr)
510 {
511 BackupLegacyVectorElement* element = new BackupLegacyVectorElement(vectorImage);
512 element->layerId = layer->id();
513 element->layer = backupLayer;
514 element->frame = vectorImage->pos();
515 element->undoText = undoText;
516 element->somethingSelected = editor()->select()->somethingSelected();
517 element->mySelection = editor()->select()->mySelectionRect();
518 element->rotationAngle = editor()->select()->myRotation();
519 element->scaleX = editor()->select()->myScaleX();
520 element->scaleY = editor()->select()->myScaleY();
521 element->translation = editor()->select()->myTranslation();
522 element->selectionAnchor = editor()->select()->currentTransformAnchor();
523 mLegacyBackupList.append(element);
524 mLegacyBackupIndex++;
525 }
526 else
527 {
528 return false;
529 }
530 }
531 else if (layer->type() == Layer::SOUND)
532 {
533 int previous = layer->getPreviousKeyFramePosition(backupFrame);
534 KeyFrame* key = layer->getLastKeyFrameAtPosition(backupFrame);
535
536 // in case tracks overlap, get previous frame
537 if (key == nullptr)
538 {
539 KeyFrame* previousKey = layer->getKeyFrameAt(previous);
540 key = previousKey;
541 }
542 if (key != nullptr) {
543 SoundClip* clip = static_cast<SoundClip*>(key);
544 if (clip)
545 {
546 BackupLegacySoundElement* element = new BackupLegacySoundElement(clip);
547 element->layerId = layer->id();
548 element->layer = backupLayer;
549 element->frame = backupFrame;
550 element->undoText = undoText;
551 element->fileName = clip->fileName();
552 element->originalName = clip->soundClipName();
553 mLegacyBackupList.append(element);
554 mLegacyBackupIndex++;
555 }
556 }
557 else
558 {
559 return false;
560 }
561 }
562 }
563
564 emit didUpdateUndoStack();
565
566 return true;
567}
568
569void UndoRedoManager::sanitizeLegacyBackupElementsAfterLayerDeletion(int layerIndex)
570{
571 if (mNewBackupSystemEnabled) {
572 return;
573 }
574
575 for (int i = 0; i < mLegacyBackupList.size(); i++)
576 {
577 LegacyBackupElement *backupElement = mLegacyBackupList[i];
578 BackupLegacyBitmapElement *bitmapElement;
579 BackupLegacyVectorElement *vectorElement;
580 BackupLegacySoundElement *soundElement;
581 switch (backupElement->type())
582 {
583 case LegacyBackupElement::BITMAP_MODIF:
584 bitmapElement = qobject_cast<BackupLegacyBitmapElement*>(backupElement);
585 Q_ASSERT(bitmapElement);
586 if (bitmapElement->layer > layerIndex)
587 {
588 bitmapElement->layer--;
589 continue;
590 }
591 else if (bitmapElement->layer != layerIndex)
592 {
593 continue;
594 }
595 break;
596 case LegacyBackupElement::VECTOR_MODIF:
597 vectorElement = qobject_cast<BackupLegacyVectorElement*>(backupElement);
598 Q_ASSERT(vectorElement);
599 if (vectorElement->layer > layerIndex)
600 {
601 vectorElement->layer--;
602 continue;
603 }
604 else if (vectorElement->layer != layerIndex)
605 {
606 continue;
607 }
608 break;
609 case LegacyBackupElement::SOUND_MODIF:
610 soundElement = qobject_cast<BackupLegacySoundElement*>(backupElement);
611 Q_ASSERT(soundElement);
612 if (soundElement->layer > layerIndex)
613 {
614 soundElement->layer--;
615 continue;
616 }
617 else if (soundElement->layer != layerIndex)
618 {
619 continue;
620 }
621 break;
622 default:
623 Q_UNREACHABLE();
624 }
625 if (i <= mLegacyBackupIndex)
626 {
627 mLegacyBackupIndex--;
628 }
629 delete mLegacyBackupList.takeAt(i);
630 i--;
631 }
632}
633
634void UndoRedoManager::restoreLegacyKey()
635{
636 if (mNewBackupSystemEnabled) {
637 return;
638 }
639
640 LegacyBackupElement* lastBackupElement = mLegacyBackupList[mLegacyBackupIndex];
641
642 Layer* layer = nullptr;
643 int frame = 0;
644 int layerIndex = 0;
645 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
646 {
647 BackupLegacyBitmapElement* lastBackupBitmapElement = static_cast<BackupLegacyBitmapElement*>(lastBackupElement);
648 layerIndex = lastBackupBitmapElement->layer;
649 frame = lastBackupBitmapElement->frame;
650 layer = object()->findLayerById(lastBackupBitmapElement->layerId);
651 editor()->addKeyFrame(layerIndex, frame);
652 dynamic_cast<LayerBitmap*>(layer)->getBitmapImageAtFrame(frame)->paste(&lastBackupBitmapElement->bitmapImage);
653 editor()->setModified(layerIndex, frame);
654 }
655 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
656 {
657 BackupLegacyVectorElement* lastBackupVectorElement = static_cast<BackupLegacyVectorElement*>(lastBackupElement);
658 layerIndex = lastBackupVectorElement->layer;
659 frame = lastBackupVectorElement->frame;
660 layer = object()->findLayerById(layerIndex);
661 editor()->addKeyFrame(layerIndex, frame);
662 dynamic_cast<LayerVector*>(layer)->getVectorImageAtFrame(frame)->paste(lastBackupVectorElement->vectorImage);
663 editor()->setModified(layerIndex, frame);
664 }
665 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
666 {
667 QString strSoundFile;
668 BackupLegacySoundElement* lastBackupSoundElement = static_cast<BackupLegacySoundElement*>(lastBackupElement);
669 layerIndex = lastBackupSoundElement->layer;
670 frame = lastBackupSoundElement->frame;
671
672 strSoundFile = lastBackupSoundElement->fileName;
673 if (strSoundFile.isEmpty()) return;
674 KeyFrame* key = editor()->addKeyFrame(layerIndex, frame);
675 SoundClip* clip = dynamic_cast<SoundClip*>(key);
676 if (clip)
677 {
678 Status st = editor()->sound()->loadSound(clip, lastBackupSoundElement->fileName);
679 clip->setSoundClipName(lastBackupSoundElement->originalName);
680 if (!st.ok())
681 {
682 editor()->removeKey();
683 emit editor()->layers()->currentLayerChanged(editor()->layers()->currentLayerIndex()); // trigger timeline repaint.
684 }
685 }
686 }
687}
688
689void UndoRedoManager::legacyUndo()
690{
691 if (!mLegacyBackupList.empty() && mLegacyBackupIndex > -1)
692 {
693 if (mLegacyBackupIndex == mLegacyBackupList.size() - 1)
694 {
695 LegacyBackupElement* lastBackupElement = mLegacyBackupList[mLegacyBackupIndex];
696 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
697 {
698 BackupLegacyBitmapElement* lastBackupBitmapElement = static_cast<BackupLegacyBitmapElement*>(lastBackupElement);
699 if (legacyBackup(lastBackupBitmapElement->layer, lastBackupBitmapElement->frame, "NoOp"))
700 {
701 mLegacyBackupIndex--;
702 }
703 }
704 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
705 {
706 BackupLegacyVectorElement* lastBackupVectorElement = static_cast<BackupLegacyVectorElement*>(lastBackupElement);
707 if (legacyBackup(lastBackupVectorElement->layer, lastBackupVectorElement->frame, "NoOp"))
708 {
709 mLegacyBackupIndex--;
710 }
711 }
712 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
713 {
714 BackupLegacySoundElement* lastBackupSoundElement = static_cast<BackupLegacySoundElement*>(lastBackupElement);
715 if (legacyBackup(lastBackupSoundElement->layer, lastBackupSoundElement->frame, "NoOp"))
716 {
717 mLegacyBackupIndex--;
718 }
719 }
720 }
721
722 qDebug() << "Undo" << mLegacyBackupIndex;
723 mLegacyBackupList[mLegacyBackupIndex]->restore(editor());
724 mLegacyBackupIndex--;
725
726 emit didUpdateUndoStack();
727 }
728}
729
730void UndoRedoManager::legacyRedo()
731{
732 if (!mLegacyBackupList.empty() && mLegacyBackupIndex < mLegacyBackupList.size() - 2)
733 {
734 mLegacyBackupIndex++;
735
736 mLegacyBackupList[mLegacyBackupIndex + 1]->restore(editor());
737 emit didUpdateUndoStack();
738 }
739}
740
741void UndoRedoManager::rememberLastModifiedFrame(int layerNumber, int frameNumber)
742{
743 if (mNewBackupSystemEnabled) {
744 // not required
745 } else {
746 mLegacyLastModifiedLayer = layerNumber;
747 mLegacyLastModifiedFrame = frameNumber;
748 }
749}
BackupLegacyBitmapElement
Definition: legacybackupelement.h:48
BackupLegacySoundElement
Definition: legacybackupelement.h:78
BackupLegacyVectorElement
Definition: legacybackupelement.h:63
BaseManager
Definition: basemanager.h:29
BitmapImage
Definition: bitmapimage.h:28
BitmapReplaceCommand
Definition: undoredocommand.h:123
Editor
Definition: editor.h:71
Editor::addKeyFrame
KeyFrame * addKeyFrame(int layerNumber, int frameIndex)
Attempts to create a new keyframe at the given position and layer.
Definition: editor.cpp:910
KeyFrameAddCommand
Definition: undoredocommand.h:80
KeyFrame
Definition: keyframe.h:30
KeyFrameRemoveCommand
Definition: undoredocommand.h:57
LayerBitmap
Definition: layerbitmap.h:26
Layer
Definition: layer.h:33
LayerVector
Definition: layervector.h:26
LegacyBackupElement
Definition: legacybackupelement.h:29
MoveKeyFramesCommand
Definition: undoredocommand.h:102
Object
Definition: object.h:42
SoundClip
Definition: soundclip.h:27
Status
Definition: pencilerror.h:40
TransformCommand
Definition: undoredocommand.h:165
UndoRedoManager::hasUnsavedChanges
bool hasUnsavedChanges() const
Checks whether there are unsaved changes.
Definition: undoredomanager.cpp:159
UndoRedoManager::sanitizeLegacyBackupElementsAfterLayerDeletion
void sanitizeLegacyBackupElementsAfterLayerDeletion(int layerIndex)
Restores integrity of the backup elements after a layer has been deleted.
Definition: undoredomanager.cpp:569
UndoRedoManager::addUserState
void addUserState(SAVESTATE_ID SaveStateId, const UserSaveState &userState)
Adds userState to the saveState found at SaveStateId If no record is found matching the id,...
Definition: undoredomanager.cpp:274
UndoRedoManager::record
void record(SAVESTATE_ID SaveStateId, const QString &description)
Records the given save state.
Definition: undoredomanager.cpp:96
UndoRedoManager::createState
SAVESTATE_ID createState(UndoRedoRecordType recordType)
Prepares and returns an save state with common data.
Definition: undoredomanager.cpp:261
UndoRedoManager::clearStack
void clearStack()
Clears the undo stack.
Definition: undoredomanager.cpp:396
VectorImage
Definition: vectorimage.h:32
VectorReplaceCommand
Definition: undoredocommand.h:144
QAction
QAction::setEnabled
void setEnabled(bool)
QAction::setIcon
void setIcon(const QIcon &icon)
QAction::setIconText
void setIconText(const QString &text)
QAction::setDisabled
void setDisabled(bool b)
QAction::setText
void setText(const QString &text)
QAction::triggered
void triggered(bool checked)
QIcon
QList::append
void append(const T &value)
QList::at
const T & at(int i) const const
QList::count
int count(const T &value) const const
QList::empty
bool empty() const const
QList::isEmpty
bool isEmpty() const const
QList::size
int size() const const
QList::takeAt
T takeAt(int i)
QList::takeFirst
T takeFirst()
QList::takeLast
T takeLast()
QMap::contains
bool contains(const Key &key) const const
QMap::take
T take(const Key &key)
QObject
QObject::connect
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::parent
QObject * parent() const const
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
QString
QString::append
QString & append(QChar ch)
QString::isEmpty
bool isEmpty() const const
QUndoCommand
QUndoStack::clear
void clear()
QUndoStack::createRedoAction
QAction * createRedoAction(QObject *parent, const QString &prefix) const const
QUndoStack::createUndoAction
QAction * createUndoAction(QObject *parent, const QString &prefix) const const
QUndoStack::isClean
bool isClean() const const
QUndoStack::push
void push(QUndoCommand *cmd)
QUndoStack::setClean
void setClean()
QUndoStack::setUndoLimit
void setUndoLimit(int limit)
MoveFramesSaveState
Definition: undoredomanager.h:81
SelectionSaveState
Definition: undoredomanager.h:55
UndoSaveState
This is the main undo/redo state structure which is meant to populate whatever states that needs to b...
Definition: undoredomanager.h:106
UserSaveState
Use this struct to store user related data that will later be added to the backup This struct is mean...
Definition: undoredomanager.h:100
Generated on Sun Apr 19 2026 11:29:08 for Pencil2D by doxygen 1.9.6 based on revision b701d7965064c33ede63718d846965b58fcaf29b