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
  • interface
undoredocommand.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 <QDebug>
20
21#include "layermanager.h"
22#include "selectionmanager.h"
23
24#include "layersound.h"
25#include "layerbitmap.h"
26#include "layervector.h"
27#include "layer.h"
28
29#include "editor.h"
30#include "undoredocommand.h"
31
32UndoRedoCommand::UndoRedoCommand(Editor* editor, QUndoCommand* parent) : QUndoCommand(parent)
33{
34 qDebug() << "backupElement created";
35 mEditor = editor;
36}
37
38KeyFrameRemoveCommand::KeyFrameRemoveCommand(const KeyFrame* undoKeyFrame,
39 int undoLayerId,
40 const QString &description,
41 Editor *editor,
42 QUndoCommand *parent) : UndoRedoCommand(editor, parent)
43{
44 this->undoKeyFrame = undoKeyFrame->clone();
45 this->undoLayerId = undoLayerId;
46
47 this->redoLayerId = editor->layers()->currentLayer()->id();
48 this->redoPosition = editor->currentFrame();
49
50 setText(description);
51}
52
53KeyFrameRemoveCommand::~KeyFrameRemoveCommand()
54{
55 delete undoKeyFrame;
56}
57
58void KeyFrameRemoveCommand::undo()
59{
60 Layer* layer = editor()->layers()->findLayerById(undoLayerId);
61 if (layer == nullptr) {
62 // Until we support layer deletion recovery, we mark the command as
63 // obsolete as soon as it's been
64 return setObsolete(true);
65 }
66
67 UndoRedoCommand::undo();
68
69 layer->addKeyFrame(undoKeyFrame->pos(), undoKeyFrame->clone());
70
71 emit editor()->frameModified(undoKeyFrame->pos());
72 editor()->layers()->notifyAnimationLengthChanged();
73 editor()->scrubTo(undoKeyFrame->pos());
74}
75
76void KeyFrameRemoveCommand::redo()
77{
78 Layer* layer = editor()->layers()->findLayerById(redoLayerId);
79 if (layer == nullptr) {
80 // Until we support layer deletion recovery, we mark the command as
81 // obsolete as soon as it's been
82 return setObsolete(true);
83 }
84
85 UndoRedoCommand::redo();
86
87 if (isFirstRedo()) { setFirstRedo(false); return; }
88
89 layer->removeKeyFrame(redoPosition);
90
91 emit editor()->frameModified(redoPosition);
92 editor()->layers()->notifyAnimationLengthChanged();
93 editor()->scrubTo(redoPosition);
94}
95
96KeyFrameAddCommand::KeyFrameAddCommand(int undoPosition,
97 int undoLayerId,
98 const QString &description,
99 Editor *editor,
100 QUndoCommand *parent)
101 : UndoRedoCommand(editor, parent)
102{
103 this->undoPosition = undoPosition;
104 this->undoLayerId = undoLayerId;
105
106 this->redoLayerId = editor->layers()->currentLayer()->id();
107 this->redoPosition = editor->currentFrame();
108
109 setText(description);
110}
111
112void KeyFrameAddCommand::undo()
113{
114 Layer* layer = editor()->layers()->findLayerById(undoLayerId);
115 if (!layer) {
116 return setObsolete(true);
117 }
118
119 UndoRedoCommand::undo();
120
121 layer->removeKeyFrame(undoPosition);
122
123 emit editor()->frameModified(undoPosition);
124 editor()->layers()->notifyAnimationLengthChanged();
125 editor()->layers()->setCurrentLayer(layer);
126 editor()->scrubTo(undoPosition);
127}
128
129void KeyFrameAddCommand::redo()
130{
131 Layer* layer = editor()->layers()->findLayerById(redoLayerId);
132 if (!layer) {
133 return setObsolete(true);
134 }
135
136 UndoRedoCommand::redo();
137
138 // Ignore automatic redo when added to undo stack
139 if (isFirstRedo()) { setFirstRedo(false); return; }
140
141 layer->addNewKeyFrameAt(redoPosition);
142
143 emit editor()->frameModified(redoPosition);
144 editor()->layers()->notifyAnimationLengthChanged();
145 editor()->layers()->setCurrentLayer(layer);
146 editor()->scrubTo(redoPosition);
147}
148
149MoveKeyFramesCommand::MoveKeyFramesCommand(int offset,
150 QList<int> listOfPositions,
151 int undoLayerId,
152 const QString& description,
153 Editor* editor,
154 QUndoCommand *parent)
155 : UndoRedoCommand(editor, parent)
156{
157 this->frameOffset = offset;
158 this->positions = listOfPositions;
159
160 this->undoLayerId = undoLayerId;
161 this->redoLayerId = editor->layers()->currentLayer()->id();
162
163 setText(description);
164}
165
166void MoveKeyFramesCommand::undo()
167{
168 Layer* undoLayer = editor()->layers()->findLayerById(undoLayerId);
169
170 if (!undoLayer) {
171 return setObsolete(true);
172 }
173
174 UndoRedoCommand::undo();
175
176 for (int position : qAsConst(positions)) {
177 undoLayer->setFrameSelected(position, true);
178 }
179 undoLayer->moveSelectedFrames(-frameOffset);
180
181 emit editor()->framesModified();
182}
183
184void MoveKeyFramesCommand::redo()
185{
186 Layer* redoLayer = editor()->layers()->findLayerById(redoLayerId);
187
188 if (!redoLayer) {
189 return setObsolete(true);
190 }
191
192 UndoRedoCommand::redo();
193
194 // Ignore automatic redo when added to undo stack
195 if (isFirstRedo()) { setFirstRedo(false); return; }
196
197 QList<int> newPositions = positions;
198
199
200 for (int position : qAsConst(newPositions)) {
201 redoLayer->setFrameSelected(position, true);
202 }
203
204 redoLayer->moveSelectedFrames(frameOffset);
205
206 emit editor()->framesModified();
207}
208BitmapReplaceCommand::BitmapReplaceCommand(const BitmapImage* undoBitmap,
209 const int undoLayerId,
210 const QString& description,
211 Editor *editor,
212 QUndoCommand *parent) : UndoRedoCommand(editor, parent)
213{
214
215 this->undoBitmap = *undoBitmap;
216 this->undoLayerId = undoLayerId;
217
218 Layer* layer = editor->layers()->currentLayer();
219 redoLayerId = layer->id();
220 redoBitmap = *static_cast<LayerBitmap*>(layer)->
221 getLastBitmapImageAtFrame(editor->currentFrame());
222
223 setText(description);
224}
225
226void BitmapReplaceCommand::undo()
227{
228 Layer* layer = editor()->layers()->findLayerById(undoLayerId);
229 if (!layer) {
230 return setObsolete(true);
231 }
232
233 UndoRedoCommand::undo();
234
235 static_cast<LayerBitmap*>(layer)->replaceKeyFrame(&undoBitmap);
236
237 editor()->scrubTo(undoBitmap.pos());
238}
239
240void BitmapReplaceCommand::redo()
241{
242 Layer* layer = editor()->layers()->findLayerById(redoLayerId);
243 if (!layer) {
244 return setObsolete(true);
245 }
246
247 UndoRedoCommand::redo();
248
249 // Ignore automatic redo when added to undo stack
250 if (isFirstRedo()) { setFirstRedo(false); return; }
251
252 static_cast<LayerBitmap*>(layer)->replaceKeyFrame(&redoBitmap);
253
254 editor()->scrubTo(redoBitmap.pos());
255}
256
257VectorReplaceCommand::VectorReplaceCommand(const VectorImage* undoVector,
258 const int undoLayerId,
259 const QString& description,
260 Editor* editor,
261 QUndoCommand* parent) : UndoRedoCommand(editor, parent)
262{
263
264 this->undoVector = *undoVector;
265 this->undoLayerId = undoLayerId;
266 Layer* layer = editor->layers()->currentLayer();
267 redoLayerId = layer->id();
268 redoVector = *static_cast<LayerVector*>(layer)->
269 getLastVectorImageAtFrame(editor->currentFrame());
270
271 setText(description);
272}
273
274void VectorReplaceCommand::undo()
275{
276 Layer* layer = editor()->layers()->findLayerById(undoLayerId);
277 if (!layer) {
278 return setObsolete(true);
279 }
280
281 UndoRedoCommand::undo();
282
283 static_cast<LayerVector*>(layer)->replaceKeyFrame(&undoVector);
284
285 editor()->scrubTo(undoVector.pos());
286}
287
288void VectorReplaceCommand::redo()
289{
290 Layer* layer = editor()->layers()->findLayerById(redoLayerId);
291 if (!layer) {
292 return setObsolete(true);
293 }
294
295 UndoRedoCommand::redo();
296
297 // Ignore automatic redo when added to undo stack
298 if (isFirstRedo()) { setFirstRedo(false); return; }
299
300 static_cast<LayerVector*>(layer)->replaceKeyFrame(&redoVector);
301
302 editor()->scrubTo(redoVector.pos());
303}
304
305TransformCommand::TransformCommand(const QRectF& undoSelectionRect,
306 const QPointF& undoTranslation,
307 const qreal undoRotationAngle,
308 const qreal undoScaleX,
309 const qreal undoScaleY,
310 const QPointF& undoTransformAnchor,
311 const bool roundPixels,
312 const QString& description,
313 Editor* editor,
314 QUndoCommand *parent) : UndoRedoCommand(editor, parent)
315{
316 this->roundPixels = roundPixels;
317
318 this->undoSelectionRect = undoSelectionRect;
319 this->undoAnchor = undoTransformAnchor;
320 this->undoTranslation = undoTranslation;
321 this->undoRotationAngle = undoRotationAngle;
322 this->undoScaleX = undoScaleX;
323 this->undoScaleY = undoScaleY;
324
325 auto selectMan = editor->select();
326 redoSelectionRect = selectMan->mySelectionRect();
327 redoAnchor = selectMan->currentTransformAnchor();
328 redoTranslation = selectMan->myTranslation();
329 redoRotationAngle = selectMan->myRotation();
330 redoScaleX = selectMan->myScaleX();
331 redoScaleY = selectMan->myScaleY();
332
333 setText(description);
334}
335
336void TransformCommand::undo()
337{
338 UndoRedoCommand::undo();
339 apply(undoSelectionRect,
340 undoTranslation,
341 undoRotationAngle,
342 undoScaleX,
343 undoScaleY,
344 undoAnchor,
345 roundPixels);
346}
347
348void TransformCommand::redo()
349{
350 UndoRedoCommand::redo();
351
352 // Ignore automatic redo when added to undo stack
353 if (isFirstRedo()) { setFirstRedo(false); return; }
354
355 apply(redoSelectionRect,
356 redoTranslation,
357 redoRotationAngle,
358 redoScaleX,
359 redoScaleY,
360 redoAnchor,
361 roundPixels);
362}
363
364void TransformCommand::apply(const QRectF& selectionRect,
365 const QPointF& translation,
366 const qreal rotationAngle,
367 const qreal scaleX,
368 const qreal scaleY,
369 const QPointF& selectionAnchor,
370 const bool roundPixels)
371{
372 auto selectMan = editor()->select();
373 selectMan->setSelection(selectionRect, roundPixels);
374 selectMan->setTransformAnchor(selectionAnchor);
375 selectMan->setTranslation(translation);
376 selectMan->setRotation(rotationAngle);
377 selectMan->setScale(scaleX, scaleY);
378
379 selectMan->calculateSelectionTransformation();
380}
BitmapImage
Definition: bitmapimage.h:28
Editor
Definition: editor.h:71
Editor::framesModified
void framesModified()
This should be emitted after modifying multiple frames.
Editor::frameModified
void frameModified(int frameNumber)
This should be emitted after modifying the frame content.
KeyFrame
Definition: keyframe.h:30
LayerBitmap
Definition: layerbitmap.h:26
Layer
Definition: layer.h:33
Layer::addNewKeyFrameAt
bool addNewKeyFrameAt(int position)
Creates a new keyframe at the given position, unless one already exists.
Definition: layer.cpp:170
Layer::addKeyFrame
virtual bool addKeyFrame(int position, KeyFrame *pKeyFrame)
Adds a keyframe at the given position, unless one already exists.
Definition: layer.cpp:191
LayerManager::notifyAnimationLengthChanged
void notifyAnimationLengthChanged()
This should be emitted whenever the animation length frames, eg.
Definition: layermanager.cpp:403
LayerVector
Definition: layervector.h:26
SelectionManager::setSelection
void setSelection(QRectF rect, bool roundPixels=false)
Defines the selection area.
Definition: selectionmanager.cpp:273
UndoRedoCommand
Definition: undoredocommand.h:40
VectorImage
Definition: vectorimage.h:32
QList
QPointF
QRectF
QString
QUndoCommand
QUndoCommand::redo
virtual void redo()
QUndoCommand::setObsolete
void setObsolete(bool obsolete)
QUndoCommand::undo
virtual void undo()
Generated on Wed Apr 29 2026 06:05:08 for Pencil2D by doxygen 1.9.6 based on revision 5841f625b8680b86111af64be6a1235440cd8ff2