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 qDebug() << "UndoRedoManager: destroyed";
57}
58
59bool UndoRedoManager::init()
60{
61 qDebug() << "UndoRedoManager: init";
62
63 mUndoStack.setUndoLimit(editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS));
64 mNewBackupSystemEnabled = editor()->preference()->isOn(SETTING::NEW_UNDO_REDO_SYSTEM_ON);
65
66 return true;
67}
68
69void UndoRedoManager::onSettingChanged(SETTING setting)
70{
71 if (setting == SETTING::UNDO_REDO_MAX_STEPS) {
72 // The stack needs to be cleared in order to change the undo redo limit
73 clearStack();
74 qDebug() << "updated undo stack limit";
75 mUndoStack.setUndoLimit(editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS));
76 }
77}
78
79Status UndoRedoManager::load(Object* /*o*/)
80{
81 clearStack();
82 return Status::OK;
83}
84
85Status UndoRedoManager::save(Object* /*o*/)
86{
87 if (mNewBackupSystemEnabled) {
88 mUndoStack.setClean();
89 } else if (!mLegacyBackupList.isEmpty() && mLegacyBackupIndex < mLegacyBackupList.count()) {
90 mLegacyBackupAtSave = mLegacyBackupList[mLegacyBackupIndex];
91 }
92 return Status::OK;
93}
94
95void UndoRedoManager::record(const UndoSaveState*& undoState, const QString& description)
96{
97 if (!mNewBackupSystemEnabled) {
98 return;
99 }
100
101 if (!undoState) {
102 return;
103 }
104
105 switch (undoState->recordType)
106 {
107 case UndoRedoRecordType::KEYFRAME_MODIFY: {
108 replaceKeyFrame(*undoState, description);
109 break;
110 }
111 default: {
112 QString reason("Unhandled case for: ");
113 reason.append(description);
114 Q_ASSERT_X(false, "UndoRedoManager::record", qPrintable(reason));
115 break;
116 }
117 }
118
119
120 // The save state has now been used and should be invalidated so we can't use it again.
121 delete undoState;
122 undoState = nullptr;
123}
124
125bool UndoRedoManager::hasUnsavedChanges() const
126{
127 if (mNewBackupSystemEnabled) {
128 return !mUndoStack.isClean();
129 } else {
130 if (mLegacyBackupIndex >= 0) {
131 return mLegacyBackupAtSave != mLegacyBackupList[mLegacyBackupIndex];
132 }
133 return false;
134 }
135}
136
137void UndoRedoManager::pushCommand(QUndoCommand* command)
138{
139 mUndoStack.push(command);
140
141 emit didUpdateUndoStack();
142}
143
144void UndoRedoManager::replaceKeyFrame(const UndoSaveState& undoState, const QString& description)
145{
146 if (undoState.layerType == Layer::BITMAP) {
147 replaceBitmap(undoState, description);
148 } else if (undoState.layerType == Layer::VECTOR) {
149 replaceVector(undoState, description);
150 } else {
151 // Implement other cases
152 }
153}
154
155
156void UndoRedoManager::replaceBitmap(const UndoSaveState& undoState, const QString& description)
157{
158 if (undoState.keyframe == nullptr || undoState.layerType != Layer::BITMAP) { return; }
159 BitmapReplaceCommand* element = new BitmapReplaceCommand(static_cast<BitmapImage*>(undoState.keyframe.get()),
160 undoState.layerId,
161 description,
162 editor());
163
164 const SelectionSaveState* selectionState = undoState.selectionState.get();
165 new TransformCommand(selectionState->bounds,
166 selectionState->translation,
167 selectionState->rotationAngle,
168 selectionState->scaleX,
169 selectionState->scaleY,
170 selectionState->anchor,
171 true, // roundPixels
172 description,
173 editor(), element);
174
175 pushCommand(element);
176}
177
178void UndoRedoManager::replaceVector(const UndoSaveState& undoState, const QString& description)
179{
180 if (undoState.keyframe == nullptr || undoState.layerType != Layer::VECTOR) { return; }
181 VectorReplaceCommand* element = new VectorReplaceCommand(static_cast<VectorImage*>(undoState.keyframe.get()),
182 undoState.layerId,
183 description,
184 editor());
185
186 const SelectionSaveState* selectionState = undoState.selectionState.get();
187 new TransformCommand(selectionState->bounds,
188 selectionState->translation,
189 selectionState->rotationAngle,
190 selectionState->scaleX,
191 selectionState->scaleY,
192 selectionState->anchor,
193 false, // Round pixels
194 description,
195 editor(), element);
196 pushCommand(element);
197}
198
199const UndoSaveState* UndoRedoManager::state(UndoRedoRecordType recordType) const
200{
201 if (!mNewBackupSystemEnabled) {
202 return nullptr;
203 }
204
205 switch (recordType)
206 {
207 case UndoRedoRecordType::KEYFRAME_MODIFY: {
208 return savedKeyFrameState();
209 default:
210 return nullptr;
211 }
212 }
213}
214
215const UndoSaveState* UndoRedoManager::savedKeyFrameState() const
216{
217 UndoSaveState* undoSaveState = new UndoSaveState();
218 undoSaveState->recordType = UndoRedoRecordType::KEYFRAME_MODIFY;
219
220 const Layer* layer = editor()->layers()->currentLayer();
221 undoSaveState->layerType = layer->type();
222 undoSaveState->layerId = layer->id();
223
224 if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR) {
225 auto selectMan = editor()->select();
226 undoSaveState->selectionState = std::unique_ptr<SelectionSaveState>( new SelectionSaveState(
227 selectMan->mySelectionRect(),
228 selectMan->myRotation(),
229 selectMan->myScaleX(),
230 selectMan->myScaleY(),
231 selectMan->myTranslation(),
232 selectMan->currentTransformAnchor())
233 );
234 }
235
236 const int frameIndex = editor()->currentFrame();
237 if (layer->keyExists(frameIndex))
238 {
239 undoSaveState->keyframe = std::unique_ptr<KeyFrame>(layer->getLastKeyFrameAtPosition(frameIndex)->clone());
240 }
241 else if (layer->getKeyFrameWhichCovers(frameIndex) != nullptr)
242 {
243 undoSaveState->keyframe = std::unique_ptr<KeyFrame>(layer->getKeyFrameWhichCovers(frameIndex)->clone());
244 }
245
246 return undoSaveState;
247}
248
249QAction* UndoRedoManager::createUndoAction(QObject* parent, const QIcon& icon)
250{
251 QAction* undoAction = nullptr;
252 if (mNewBackupSystemEnabled) {
253 undoAction = mUndoStack.createUndoAction(parent);
254 } else {
255 undoAction = new QAction(parent);
256 undoAction->setText(tr("Undo"));
257 undoAction->setDisabled(true);
258 }
259 undoAction->setIcon(icon);
260
261 if (mNewBackupSystemEnabled) {
262 // The new system takes care of this automatically
263 } else {
264 connect(undoAction, &QAction::triggered, this, &UndoRedoManager::legacyUndo);
265 }
266 return undoAction;
267}
268
269QAction* UndoRedoManager::createRedoAction(QObject* parent, const QIcon& icon)
270{
271 QAction* redoAction = nullptr;
272 if (mNewBackupSystemEnabled) {
273 redoAction = mUndoStack.createRedoAction(parent);
274 } else {
275 redoAction = new QAction(parent);
276 redoAction->setText(tr("Redo"));
277 redoAction->setDisabled(true);
278 }
279 redoAction->setIcon(icon);
280
281 if (mNewBackupSystemEnabled) {
282 // The new system takes care of this automatically
283 } else {
284 connect(redoAction, &QAction::triggered, this, &UndoRedoManager::legacyRedo);
285 }
286 return redoAction;
287}
288
289void UndoRedoManager::updateUndoAction(QAction* undoAction)
290{
291 if (mNewBackupSystemEnabled) {
292 // Not used
293 // function can be removed when we have replaced the legacy system
294 } else {
295 if (mLegacyBackupIndex < 0)
296 {
297 undoAction->setText(tr("Undo", "Menu item text"));
298 undoAction->setEnabled(false);
299 qDebug() << undoAction->text();
300 }
301 else
302 {
303 undoAction->setText(QString("%1 %2 %3").arg(tr("Undo", "Menu item text"))
304 .arg(mLegacyBackupIndex + 1)
305 .arg(mLegacyBackupList.at(mLegacyBackupIndex)->undoText));
306 undoAction->setIconText(QString("%1 %2 %3").arg(tr("Undo", "Menu item text"))
307 .arg(mLegacyBackupIndex + 1)
308 .arg(mLegacyBackupList.at(mLegacyBackupIndex)->undoText));
309 undoAction->setEnabled(true);
310 qDebug() << undoAction->text();
311 }
312 }
313}
314
315void UndoRedoManager::updateRedoAction(QAction* redoAction)
316{
317 if (mNewBackupSystemEnabled) {
318 // Not used
319 // function can be removed when we have replaced the legacy system
320 } else {
321 if (mLegacyBackupIndex + 2 < mLegacyBackupList.size())
322 {
323 redoAction->setText(QString("%1 %2 %3").arg(tr("Redo", "Menu item text"))
324 .arg(mLegacyBackupIndex + 2)
325 .arg(mLegacyBackupList.at(mLegacyBackupIndex + 1)->undoText));
326 redoAction->setEnabled(true);
327 }
328 else
329 {
330 redoAction->setText(tr("Redo", "Menu item text"));
331 redoAction->setEnabled(false);
332 }
333 }
334}
335
336void UndoRedoManager::clearStack()
337{
338 if (mNewBackupSystemEnabled) {
339 mUndoStack.clear();
340 } else {
341 mLegacyBackupIndex = -1;
342 while (!mLegacyBackupList.isEmpty())
343 {
344 delete mLegacyBackupList.takeLast();
345 }
346 mLegacyLastModifiedLayer = -1;
347 mLegacyLastModifiedFrame = -1;
348 }
349}
350
351// Legacy backup system
352
353void UndoRedoManager::legacyBackup(const QString& undoText)
354{
355
356 if (mNewBackupSystemEnabled) {
357 return;
358 }
359
360 KeyFrame* frame = nullptr;
361 int currentFrame = editor()->currentFrame();
362 if (mLegacyLastModifiedLayer > -1 && mLegacyLastModifiedFrame > 0)
363 {
364 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
365 {
366 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(mLegacyLastModifiedFrame);
367 if (frame != nullptr)
368 {
369 legacyBackup(mLegacyLastModifiedLayer, frame->pos(), undoText);
370 }
371 }
372 else
373 {
374 legacyBackup(mLegacyLastModifiedLayer, mLegacyLastModifiedFrame, undoText);
375 }
376 }
377 if (mLegacyLastModifiedLayer != editor()->layers()->currentLayerIndex() || mLegacyLastModifiedFrame != currentFrame)
378 {
379 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
380 {
381 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(currentFrame);
382
383 if (frame != nullptr)
384 {
385 legacyBackup(editor()->layers()->currentLayerIndex(), frame->pos(), undoText);
386 }
387 }
388 else
389 {
390 legacyBackup(editor()->layers()->currentLayerIndex(), currentFrame, undoText);
391 }
392 }
393}
394
395bool UndoRedoManager::legacyBackup(int backupLayer, int backupFrame, const QString& undoText)
396{
397 if (mNewBackupSystemEnabled) {
398 return false;
399 }
400
401 while (mLegacyBackupList.size() - 1 > mLegacyBackupIndex && !mLegacyBackupList.empty())
402 {
403 delete mLegacyBackupList.takeLast();
404 }
405 while (mLegacyBackupList.size() >= editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS))
406 {
407 delete mLegacyBackupList.takeFirst();
408 mLegacyBackupIndex--;
409 }
410
411 Layer* layer = editor()->layers()->getLayer(backupLayer);
412 int currentFrame = editor()->currentFrame();
413 if (layer != nullptr)
414 {
415 if (layer->type() == Layer::BITMAP)
416 {
417 BitmapImage* bitmapImage = static_cast<BitmapImage*>(layer->getLastKeyFrameAtPosition(backupFrame));
418 if (currentFrame == 1)
419 {
420 int previous = layer->getPreviousKeyFramePosition(backupFrame);
421 bitmapImage = static_cast<BitmapImage*>(layer->getKeyFrameAt(previous));
422 }
423 if (bitmapImage != nullptr)
424 {
425 BackupLegacyBitmapElement* element = new BackupLegacyBitmapElement(bitmapImage);
426 element->layerId = layer->id();
427 element->layer = backupLayer;
428 element->frame = bitmapImage->pos();
429 element->undoText = undoText;
430 element->somethingSelected = editor()->select()->somethingSelected();
431 element->mySelection = editor()->select()->mySelectionRect();
432 element->rotationAngle = editor()->select()->myRotation();
433 element->scaleX = editor()->select()->myScaleX();
434 element->scaleY = editor()->select()->myScaleY();
435 element->translation = editor()->select()->myTranslation();
436 element->selectionAnchor = editor()->select()->currentTransformAnchor();
437
438 mLegacyBackupList.append(element);
439 mLegacyBackupIndex++;
440 }
441 else
442 {
443 return false;
444 }
445 }
446 else if (layer->type() == Layer::VECTOR)
447 {
448 VectorImage* vectorImage = static_cast<VectorImage*>(layer->getLastKeyFrameAtPosition(backupFrame));
449 if (vectorImage != nullptr)
450 {
451 BackupLegacyVectorElement* element = new BackupLegacyVectorElement(vectorImage);
452 element->layerId = layer->id();
453 element->layer = backupLayer;
454 element->frame = vectorImage->pos();
455 element->undoText = undoText;
456 element->somethingSelected = editor()->select()->somethingSelected();
457 element->mySelection = editor()->select()->mySelectionRect();
458 element->rotationAngle = editor()->select()->myRotation();
459 element->scaleX = editor()->select()->myScaleX();
460 element->scaleY = editor()->select()->myScaleY();
461 element->translation = editor()->select()->myTranslation();
462 element->selectionAnchor = editor()->select()->currentTransformAnchor();
463 mLegacyBackupList.append(element);
464 mLegacyBackupIndex++;
465 }
466 else
467 {
468 return false;
469 }
470 }
471 else if (layer->type() == Layer::SOUND)
472 {
473 int previous = layer->getPreviousKeyFramePosition(backupFrame);
474 KeyFrame* key = layer->getLastKeyFrameAtPosition(backupFrame);
475
476 // in case tracks overlap, get previous frame
477 if (key == nullptr)
478 {
479 KeyFrame* previousKey = layer->getKeyFrameAt(previous);
480 key = previousKey;
481 }
482 if (key != nullptr) {
483 SoundClip* clip = static_cast<SoundClip*>(key);
484 if (clip)
485 {
486 BackupLegacySoundElement* element = new BackupLegacySoundElement(clip);
487 element->layerId = layer->id();
488 element->layer = backupLayer;
489 element->frame = backupFrame;
490 element->undoText = undoText;
491 element->fileName = clip->fileName();
492 element->originalName = clip->soundClipName();
493 mLegacyBackupList.append(element);
494 mLegacyBackupIndex++;
495 }
496 }
497 else
498 {
499 return false;
500 }
501 }
502 }
503
504 emit didUpdateUndoStack();
505
506 return true;
507}
508
509void UndoRedoManager::sanitizeLegacyBackupElementsAfterLayerDeletion(int layerIndex)
510{
511 if (mNewBackupSystemEnabled) {
512 return;
513 }
514
515 for (int i = 0; i < mLegacyBackupList.size(); i++)
516 {
517 LegacyBackupElement *backupElement = mLegacyBackupList[i];
518 BackupLegacyBitmapElement *bitmapElement;
519 BackupLegacyVectorElement *vectorElement;
520 BackupLegacySoundElement *soundElement;
521 switch (backupElement->type())
522 {
523 case LegacyBackupElement::BITMAP_MODIF:
524 bitmapElement = qobject_cast<BackupLegacyBitmapElement*>(backupElement);
525 Q_ASSERT(bitmapElement);
526 if (bitmapElement->layer > layerIndex)
527 {
528 bitmapElement->layer--;
529 continue;
530 }
531 else if (bitmapElement->layer != layerIndex)
532 {
533 continue;
534 }
535 break;
536 case LegacyBackupElement::VECTOR_MODIF:
537 vectorElement = qobject_cast<BackupLegacyVectorElement*>(backupElement);
538 Q_ASSERT(vectorElement);
539 if (vectorElement->layer > layerIndex)
540 {
541 vectorElement->layer--;
542 continue;
543 }
544 else if (vectorElement->layer != layerIndex)
545 {
546 continue;
547 }
548 break;
549 case LegacyBackupElement::SOUND_MODIF:
550 soundElement = qobject_cast<BackupLegacySoundElement*>(backupElement);
551 Q_ASSERT(soundElement);
552 if (soundElement->layer > layerIndex)
553 {
554 soundElement->layer--;
555 continue;
556 }
557 else if (soundElement->layer != layerIndex)
558 {
559 continue;
560 }
561 break;
562 default:
563 Q_UNREACHABLE();
564 }
565 if (i <= mLegacyBackupIndex)
566 {
567 mLegacyBackupIndex--;
568 }
569 delete mLegacyBackupList.takeAt(i);
570 i--;
571 }
572}
573
574void UndoRedoManager::restoreLegacyKey()
575{
576 if (mNewBackupSystemEnabled) {
577 return;
578 }
579
580 LegacyBackupElement* lastBackupElement = mLegacyBackupList[mLegacyBackupIndex];
581
582 Layer* layer = nullptr;
583 int frame = 0;
584 int layerIndex = 0;
585 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
586 {
587 BackupLegacyBitmapElement* lastBackupBitmapElement = static_cast<BackupLegacyBitmapElement*>(lastBackupElement);
588 layerIndex = lastBackupBitmapElement->layer;
589 frame = lastBackupBitmapElement->frame;
590 layer = object()->findLayerById(lastBackupBitmapElement->layerId);
591 editor()->addKeyFrame(layerIndex, frame);
592 dynamic_cast<LayerBitmap*>(layer)->getBitmapImageAtFrame(frame)->paste(&lastBackupBitmapElement->bitmapImage);
593 editor()->setModified(layerIndex, frame);
594 }
595 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
596 {
597 BackupLegacyVectorElement* lastBackupVectorElement = static_cast<BackupLegacyVectorElement*>(lastBackupElement);
598 layerIndex = lastBackupVectorElement->layer;
599 frame = lastBackupVectorElement->frame;
600 layer = object()->findLayerById(layerIndex);
601 editor()->addKeyFrame(layerIndex, frame);
602 dynamic_cast<LayerVector*>(layer)->getVectorImageAtFrame(frame)->paste(lastBackupVectorElement->vectorImage);
603 editor()->setModified(layerIndex, frame);
604 }
605 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
606 {
607 QString strSoundFile;
608 BackupLegacySoundElement* lastBackupSoundElement = static_cast<BackupLegacySoundElement*>(lastBackupElement);
609 layerIndex = lastBackupSoundElement->layer;
610 frame = lastBackupSoundElement->frame;
611
612 strSoundFile = lastBackupSoundElement->fileName;
613 if (strSoundFile.isEmpty()) return;
614 KeyFrame* key = editor()->addKeyFrame(layerIndex, frame);
615 SoundClip* clip = dynamic_cast<SoundClip*>(key);
616 if (clip)
617 {
618 Status st = editor()->sound()->loadSound(clip, lastBackupSoundElement->fileName);
619 clip->setSoundClipName(lastBackupSoundElement->originalName);
620 if (!st.ok())
621 {
622 editor()->removeKey();
623 emit editor()->layers()->currentLayerChanged(editor()->layers()->currentLayerIndex()); // trigger timeline repaint.
624 }
625 }
626 }
627}
628
629void UndoRedoManager::legacyUndo()
630{
631 if (!mLegacyBackupList.empty() && mLegacyBackupIndex > -1)
632 {
633 if (mLegacyBackupIndex == mLegacyBackupList.size() - 1)
634 {
635 LegacyBackupElement* lastBackupElement = mLegacyBackupList[mLegacyBackupIndex];
636 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
637 {
638 BackupLegacyBitmapElement* lastBackupBitmapElement = static_cast<BackupLegacyBitmapElement*>(lastBackupElement);
639 if (legacyBackup(lastBackupBitmapElement->layer, lastBackupBitmapElement->frame, "NoOp"))
640 {
641 mLegacyBackupIndex--;
642 }
643 }
644 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
645 {
646 BackupLegacyVectorElement* lastBackupVectorElement = static_cast<BackupLegacyVectorElement*>(lastBackupElement);
647 if (legacyBackup(lastBackupVectorElement->layer, lastBackupVectorElement->frame, "NoOp"))
648 {
649 mLegacyBackupIndex--;
650 }
651 }
652 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
653 {
654 BackupLegacySoundElement* lastBackupSoundElement = static_cast<BackupLegacySoundElement*>(lastBackupElement);
655 if (legacyBackup(lastBackupSoundElement->layer, lastBackupSoundElement->frame, "NoOp"))
656 {
657 mLegacyBackupIndex--;
658 }
659 }
660 }
661
662 qDebug() << "Undo" << mLegacyBackupIndex;
663 mLegacyBackupList[mLegacyBackupIndex]->restore(editor());
664 mLegacyBackupIndex--;
665
666 emit didUpdateUndoStack();
667 }
668}
669
670void UndoRedoManager::legacyRedo()
671{
672 if (!mLegacyBackupList.empty() && mLegacyBackupIndex < mLegacyBackupList.size() - 2)
673 {
674 mLegacyBackupIndex++;
675
676 mLegacyBackupList[mLegacyBackupIndex + 1]->restore(editor());
677 emit didUpdateUndoStack();
678 }
679}
680
681void UndoRedoManager::rememberLastModifiedFrame(int layerNumber, int frameNumber)
682{
683 if (mNewBackupSystemEnabled) {
684 // not required
685 } else {
686 mLegacyLastModifiedLayer = layerNumber;
687 mLegacyLastModifiedFrame = frameNumber;
688 }
689}
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:55
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:908
KeyFrame
Definition: keyframe.h:30
LayerBitmap
Definition: layerbitmap.h:26
Layer
Definition: layer.h:33
LayerVector
Definition: layervector.h:26
LegacyBackupElement
Definition: legacybackupelement.h:29
Object
Definition: object.h:42
SoundClip
Definition: soundclip.h:27
Status
Definition: pencilerror.h:40
TransformCommand
Definition: undoredocommand.h:97
UndoRedoManager::record
void record(const UndoSaveState *&undoState, const QString &description)
Records the given save state.
Definition: undoredomanager.cpp:95
UndoRedoManager::hasUnsavedChanges
bool hasUnsavedChanges() const
Checks whether there are unsaved changes.
Definition: undoredomanager.cpp:125
UndoRedoManager::sanitizeLegacyBackupElementsAfterLayerDeletion
void sanitizeLegacyBackupElementsAfterLayerDeletion(int layerIndex)
Restores integrity of the backup elements after a layer has been deleted.
Definition: undoredomanager.cpp:509
UndoRedoManager::clearStack
void clearStack()
Clears the undo stack.
Definition: undoredomanager.cpp:336
UndoRedoManager::state
const UndoSaveState * state(UndoRedoRecordType recordType) const
Prepares and returns a save state with the given scope.
Definition: undoredomanager.cpp:199
VectorImage
Definition: vectorimage.h:32
VectorReplaceCommand
Definition: undoredocommand.h:76
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()
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)
SelectionSaveState
Definition: undoredomanager.h:53
UndoSaveState
This is the main undo/redo state structure which is meant to populate whatever states that needs to b...
Definition: undoredomanager.h:80
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39