diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index b87bfb8504..80a70902b7 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -53,6 +53,7 @@ GNU General Public License for more details. #include "fileformat.h" //contains constants used by Pencil File Format #include "util.h" #include "backupelement.h" +#include "legacybackupelement.h" // app headers #include "colorbox.h" diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index 92b799350f..91eaf140a5 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -44,6 +44,7 @@ class Timeline2; class ActionCommands; class ImportImageSeqDialog; class BackupElement; +class LegacyBackupElement; class LayerOpacityDialog; class PegBarAlignmentDialog; class RepositionFramesDialog; @@ -172,7 +173,7 @@ private slots: QToolBar* mOverlayToolbar = nullptr; // backup - BackupElement* mBackupAtSave = nullptr; + LegacyBackupElement* mBackupAtSave = nullptr; PegBarAlignmentDialog* mPegAlign = nullptr; RepositionFramesDialog* mReposDialog = nullptr; diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro index 4239594862..a219708b30 100644 --- a/core_lib/core_lib.pro +++ b/core_lib/core_lib.pro @@ -44,6 +44,7 @@ HEADERS += \ src/interface/camerapropertiesdialog.h \ src/interface/editor.h \ src/interface/flowlayout.h \ + src/interface/legacybackupelement.h \ src/interface/recentfilemenu.h \ src/interface/scribblearea.h \ src/interface/timecontrols.h \ @@ -51,9 +52,11 @@ HEADERS += \ src/interface/timelinecells.h \ src/interface/basedockwidget.h \ src/interface/backgroundwidget.h \ + src/managers/backupmanager.h \ src/managers/basemanager.h \ src/managers/overlaymanager.h \ src/managers/clipboardmanager.h \ + src/managers/canvasmanager.h \ src/managers/selectionmanager.h \ src/managers/colormanager.h \ src/managers/layermanager.h \ @@ -94,6 +97,7 @@ HEADERS += \ src/util/cameraeasingtype.h \ src/util/camerafieldoption.h \ src/util/colordictionary.h \ + src/util/direction.h \ src/util/fileformat.h \ src/util/filetype.h \ src/util/mathutils.h \ @@ -126,6 +130,7 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/interface/camerapropertiesdialog.cpp \ src/interface/editor.cpp \ src/interface/flowlayout.cpp \ + src/interface/legacybackupelement.cpp \ src/interface/recentfilemenu.cpp \ src/interface/scribblearea.cpp \ src/interface/timecontrols.cpp \ @@ -133,9 +138,11 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/interface/timelinecells.cpp \ src/interface/basedockwidget.cpp \ src/interface/backgroundwidget.cpp \ + src/managers/backupmanager.cpp \ src/managers/basemanager.cpp \ src/managers/overlaymanager.cpp \ src/managers/clipboardmanager.cpp \ + src/managers/canvasmanager.cpp \ src/managers/selectionmanager.cpp \ src/managers/colormanager.cpp \ src/managers/layermanager.cpp \ diff --git a/core_lib/src/graphics/vector/vectorimage.cpp b/core_lib/src/graphics/vector/vectorimage.cpp index 3735d39db5..a17fdc43bd 100644 --- a/core_lib/src/graphics/vector/vectorimage.cpp +++ b/core_lib/src/graphics/vector/vectorimage.cpp @@ -24,7 +24,6 @@ GNU General Public License for more details. #include #include "object.h" - VectorImage::VectorImage() { deselectAll(); @@ -677,6 +676,28 @@ void VectorImage::setSelected(QList vertexList, bool YesOrNo) } } +void VectorImage::setSelected(const QList curveList, const QList vertexList, const bool YesOrNo) +{ + for (int curveI = 0; curveI < curveList.size(); curveI++) + { + int curveNumber = curveList.at(curveI); + + if (vertexList.isEmpty()) + { + setSelected(curveNumber, YesOrNo); + } + else + { + for (int i = 0; i < vertexList.size(); i++) + { + setSelected(curveNumber, vertexList.at(i).vertexNumber, YesOrNo); + } + } + } +} + + + /** * @brief VectorImage::setAreaSelected * @param areaNumber: int diff --git a/core_lib/src/graphics/vector/vectorimage.h b/core_lib/src/graphics/vector/vectorimage.h index 0a31cccd98..2c7d104bd4 100644 --- a/core_lib/src/graphics/vector/vectorimage.h +++ b/core_lib/src/graphics/vector/vectorimage.h @@ -58,6 +58,7 @@ class VectorImage : public KeyFrame void setSelected(VertexRef vertexRef, bool YesOrNo); void setSelected(QList curveList, bool YesOrNo); void setSelected(QList vertexList, bool YesOrNo); + void setSelected(const QList curveList, const QList vertexList, const bool YesOrNo); bool isSelected(int curveNumber); bool isSelected(int curveNumber, int vertexNumber); bool isSelected(VertexRef vertexRef); diff --git a/core_lib/src/interface/backupelement.cpp b/core_lib/src/interface/backupelement.cpp index 6e2d6fdf05..5ffa81c637 100644 --- a/core_lib/src/interface/backupelement.cpp +++ b/core_lib/src/interface/backupelement.cpp @@ -1,8 +1,8 @@ /* -Pencil2D - Traditional Animation Software +Pencil - Traditional Animation Software Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon -Copyright (C) 2012-2020 Matthew Chiawen Chang +Copyright (C) 2012-2018 Matthew Chiawen Chang This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -15,102 +15,1422 @@ GNU General Public License for more details. */ -#include "backupelement.h" +#include +#include "QProgressDialog" +#include -#include "editor.h" -#include "layer.h" +#include "layermanager.h" +#include "backupmanager.h" +#include "viewmanager.h" +#include "selectionmanager.h" +#include "canvasmanager.h" + +#include "layersound.h" #include "layerbitmap.h" #include "layervector.h" -#include "object.h" -#include "selectionmanager.h" +#include "layercamera.h" + +#include "editor.h" +#include "backupelement.h" -void BackupBitmapElement::restore(Editor* editor) +#include "vectorimage.h" +#include "bitmapimage.h" +#include "soundclip.h" +#include "camera.h" + +BackupElement::BackupElement(Editor* editor, QUndoCommand* parent) : QUndoCommand(parent) +{ + qDebug() << "backupElement created"; + mEditor = editor; +} + +BackupElement::~BackupElement() { - Layer* layer = editor->object()->findLayerById(this->layerId); +} + +AddBitmapElement::AddBitmapElement(const BitmapImage* backupBitmap, + const int& backupLayerId, + const DrawOnEmptyFrameAction& frameAction, + QString description, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + + oldBitmap = backupBitmap->clone(); + + oldFrameIndex = oldBitmap->pos(); + newLayerIndex = editor->currentLayerIndex(); + oldLayerId = backupLayerId; + + Layer* layer = editor->layers()->currentLayer(); + newLayerId = layer->id(); + + newFrameIndex = editor->currentFrame(); + newFrameIndex = BackupManager::getActiveFrameIndex(layer, newFrameIndex, frameAction); + + newBitmap = static_cast(layer)-> + getBitmapImageAtFrame(newFrameIndex)->clone(); + auto selectMan = editor->select(); - selectMan->setSelection(mySelection, true); - selectMan->setTransformedSelectionRect(myTransformedSelection); - selectMan->setTempTransformedSelectionRect(myTempTransformedSelection); - selectMan->setRotation(rotationAngle); - selectMan->setSomethingSelected(somethingSelected); + if (selectMan->somethingSelected()) { + BitmapImage selectionBitmap = newBitmap->transformed(selectMan->mySelectionRect().toRect(), + selectMan->selectionTransform(), + false); + + newBitmap->clear(selectMan->mySelectionRect().toRect()); + newBitmap->paste(&selectionBitmap, QPainter::CompositionMode_SourceOver); + } - if (editor->currentFrame() != this->frame) { - editor->scrubTo(this->frame); + setText(description); +} + +void AddBitmapElement::undo() +{ + Layer* layer = editor()->layers()->findLayerById(oldLayerId); + + const TransformElement* childElem = static_cast(this->child(0)); + if (childElem) + { + undoTransform(childElem); + } + else + { + static_cast(layer)->replaceLastBitmapAtFrame(oldBitmap); } - editor->frameModified(this->frame); - if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) + editor()->scrubTo(oldLayerId, oldFrameIndex); +} + +void AddBitmapElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + const TransformElement* childElem = static_cast(this->child(0)); + if (childElem) { - editor->restoreKey(); + redoTransform(childElem); } else { - if (layer != nullptr) + Layer* layer = editor()->layers()->findLayerById(newLayerId); + static_cast(layer)->replaceLastBitmapAtFrame(newBitmap); + } + + editor()->scrubTo(newLayerId, newFrameIndex); +} + +void AddBitmapElement::undoTransform(const TransformElement* childElem) +{ + + BitmapImage* oldBitmapClone = oldBitmap->clone(); + + // make the cloned bitmap the new canvas image. + Layer* layer = editor()->layers()->findLayerById(oldLayerId); + static_cast(layer)->replaceLastBitmapAtFrame(oldBitmapClone); + + // set selections so the transform will be correct + auto selectMan = editor()->select(); + + selectMan->setSelectionTransform(childElem->oldTransform); + selectMan->setSelectionRect(childElem->oldSelectionRect); + selectMan->setTempTransformedSelectionRect(childElem->oldSelectionRectTemp); + selectMan->setTransformedSelectionRect(childElem->oldTransformedSelectionRect); + selectMan->setRotation(childElem->oldRotationAngle); + selectMan->setSomethingSelected(childElem->oldIsSelected); + + editor()->canvas()->paintTransformedSelection(layer, oldBitmapClone, childElem->oldTransform, childElem->oldSelectionRect); +} + +void AddBitmapElement::redoTransform(const TransformElement* childElem) +{ + Layer* layer = editor()->layers()->findLayerById(newLayerId); + + BitmapImage* newBitmapClone = newBitmap->clone(); + + static_cast(layer)->replaceLastBitmapAtFrame(newBitmapClone); + + auto selectMan = editor()->select(); + selectMan->setSelectionTransform(childElem->newTransform); + selectMan->setSelectionRect(childElem->newSelectionRect); + selectMan->setTempTransformedSelectionRect(childElem->newSelectionRectTemp); + selectMan->setTransformedSelectionRect(childElem->newTransformedSelectionRect); + selectMan->setRotation(childElem->newRotationAngle); + selectMan->setSomethingSelected(childElem->newIsSelected); + + editor()->canvas()->paintTransformedSelection(layer, newBitmapClone, childElem->oldTransform, childElem->oldSelectionRect); +} + +AddVectorElement::AddVectorElement(const VectorImage* backupVector, + const int& backupLayerId, + const DrawOnEmptyFrameAction& backupFrameAction, + QString description, + Editor* editor, + QUndoCommand* parent) : BackupElement(editor, parent) +{ + + oldVector = backupVector->clone(); + oldFrameIndex = oldVector->pos(); + + newLayerIndex = editor->layers()->currentLayerIndex(); + newFrameIndex = editor->currentFrame(); + + oldLayerId = backupLayerId; + Layer* layer = editor->layers()->currentLayer(); + newLayerId = layer->id(); + + newFrameIndex = BackupManager::getActiveFrameIndex(layer, newFrameIndex, backupFrameAction); + newVector = static_cast(layer)-> + getVectorImageAtFrame(newFrameIndex)->clone(); + + setText(description); +} + +void AddVectorElement::undo() +{ + qDebug() << "BackupVectorElement: undo"; + + Layer* layer = editor()->layers()->findLayerById(oldLayerId); + + *static_cast(layer)-> + getVectorImageAtFrame(oldFrameIndex) = *oldVector; + + editor()->scrubTo(oldLayerId, oldFrameIndex); +} + +void AddVectorElement::redo() +{ + qDebug() << "BackupVectorElement: redo"; + + if (isFirstRedo) { isFirstRedo = false; return; } + + Layer* layer = editor()->layers()->findLayerById(newLayerId); + + *static_cast(layer)-> + getVectorImageAtFrame(newFrameIndex) = *newVector; + + editor()->scrubTo(newLayerId, newFrameIndex); +} + +AddKeyFrameElement::AddKeyFrameElement(const int backupFrameIndex, + const int backupLayerId, + const DrawOnEmptyFrameAction& backupFrameAction, + const int backupKeySpacing, + const bool backupKeyExisted, + QString description, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + + Layer* layer = editor->layers()->currentLayer(); + newLayerIndex = editor->currentLayerIndex(); + newFrameIndex = editor->currentFrame(); + + oldFrameIndex = backupFrameIndex; + + oldLayerId = backupLayerId; + newLayerId = layer->id(); + + oldKeyExisted = backupKeyExisted; + oldKeySpacing = backupKeySpacing; + + emptyFrameSettingVal = editor->preference()-> + getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION); + newFrameIndex = editor->currentFrame(); + newFrameIndex = BackupManager::getActiveFrameIndex(layer, newFrameIndex, backupFrameAction); + + newKey = layer->getLastKeyFrameAtPosition(oldFrameIndex)->clone(); + oldKeyFrames.insert(std::make_pair(oldFrameIndex, newKey)); + + bool isSequence = oldKeySpacing > 1; + + if (description.isEmpty() && !isSequence) + { + switch (layer->type()) { - if (layer->type() == Layer::BITMAP) - { - auto bitmapLayer = static_cast(layer); - *bitmapLayer->getLastBitmapImageAtFrame(this->frame, 0) = bitmapImage; // restore the image - } + case Layer::BITMAP: description = QObject::tr("Bitmap: New key"); break; + case Layer::VECTOR: description = QObject::tr("Vector: New Key"); break; + case Layer::SOUND: description = QObject::tr("Sound: New Key"); break; + case Layer::CAMERA: description = QObject::tr("Camera: New Key"); break; + default: break; + } + } + setText(description); +} + +void AddKeyFrameElement::undoSequence() +{ + qDebug() << "oldKeyFrames: " << oldKeyFrames; + for (auto map : oldKeyFrames) + { + qDebug() << "did A key exist before:" << oldKeyExisted; + if (!oldKeyExisted) { + editor()->removeKeyAtLayerId(oldLayerId, map.first); } } } -void BackupVectorElement::restore(Editor* editor) +void AddKeyFrameElement::undo() { - Layer* layer = editor->object()->findLayerById(this->layerId); + qDebug() << "key remove triggered"; + bool isSequence = oldKeySpacing > 1; + if (isSequence) + { + undoSequence(); + } + else + { + editor()->removeKeyAtLayerId(oldLayerId, oldFrameIndex); + } + editor()->updateCurrentFrame(); +} + +void AddKeyFrameElement::redoSequence() +{ + qDebug() << "nnnew:" << newKeyFrames; + for (auto map : newKeyFrames) + { + newFrameIndex = map.first; + newKey = map.second; + editor()->backups()->restoreKey(this); + } +} + +void AddKeyFrameElement::redo() +{ + qDebug() << "undo: new backup frame " << newFrameIndex; + qDebug() << "undo: newLayer" << newLayerIndex; + + if (isFirstRedo) { isFirstRedo = false; return; } + bool isSequence = oldKeySpacing > 1; + + if (newFrameIndex > 0) + { + if (isSequence) + { + redoSequence(); + } + else + { + qDebug() << "restore Addkey triggered"; + editor()->backups()->restoreKey(this); + } + } + editor()->updateCurrentFrame(); + +} + +bool AddKeyFrameElement::mergeWith(const QUndoCommand *other) +{ + qDebug() << "MERGE CHECK!"; + + qDebug() << "state of frames: old" << oldKeyFrames; + qDebug() << "state of frames:: new" << newKeyFrames; + qDebug() << newKeyFrames; + + bool isSequence = oldKeySpacing > 1; + + if (newKeyFrames.empty()) + { + newKeyFrames.insert(std::make_pair(oldFrameIndex, newKey)); + } + + const AddKeyFrameElement* element = static_cast(other); + + if (!isSequence || element->oldKeySpacing < 2) + { + return false; + } + qDebug() << "MERGING!"; + + oldFrameIndex = element->oldFrameIndex; + newFrameIndex = element->newFrameIndex; + newKey = element->newKey; + oldKeyExisted = element->oldKeyExisted; + + std::mapframes = static_cast(other)->oldKeyFrames; + for (auto map : frames) + { + oldKeyFrames.insert(std::make_pair(map.first, map.second)); + } + + newKeyFrames.insert(std::make_pair(oldFrameIndex, newKey)); + return true; +} + + +RemoveKeyFrameElement::RemoveKeyFrameElement(const KeyFrame* backupKey, + const int& backupLayerId, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + oldFrameIndex = backupKey->pos(); + oldLayerId = backupLayerId; + oldKey = backupKey->clone(); + + Layer* layer = editor->layers()->findLayerById(oldLayerId); + + switch(layer->type()) + { + case Layer::BITMAP: + { + oldBitmap = static_cast(oldKey); + setText(QObject::tr("Remove Bitmap Key")); + break; + } + case Layer::VECTOR: + { + oldVector = static_cast(oldKey); + setText(QObject::tr("Remove Vector Key")); + break; + } + case Layer::SOUND: + { + oldClip = static_cast(oldKey); + setText(QObject::tr("Remove Sound Key")); + break; + } + case Layer::CAMERA: + { + oldCamera = static_cast(oldKey); + setText(QObject::tr("Remove Camera key")); + break; + } + default: + break; + } +} + +void RemoveKeyFrameElement::undo() +{ + qDebug() << "undo: old frame index" << oldFrameIndex; + qDebug() << "restore key"; + editor()->backups()->restoreKey(this); +} + +void RemoveKeyFrameElement::redo() +{ + qDebug() << "redo: old backup frame: " << oldFrameIndex; + + if (isFirstRedo) { isFirstRedo = false; return; } + + + qDebug() << "RemoveKeyFrame triggered"; + editor()->removeKeyAtLayerId(oldLayerId, oldFrameIndex); + editor()->scrubTo(oldLayerId, oldFrameIndex); +} + +SelectionElement::SelectionElement(const int backupLayerId, + const int backupFrameIndex, + const VectorSelection& backupVectorSelection, + const SelectionType& backupSelectionType, + const QRectF& backupSelectionRect, + const qreal& backupRotationAngle, + const bool& backupIsSelected, + Editor* editor, + QUndoCommand* parent) : BackupElement(editor, parent), + layerId(backupLayerId), + frameIndex(backupFrameIndex) +{ + oldSelectionRect = backupSelectionRect; + oldRotationAngle = backupRotationAngle; + oldIsSelected = backupIsSelected; + + oldVectorSelection = backupVectorSelection; + + newSelectionRect = editor->select()->myTransformedSelectionRect(); + newRotationAngle = editor->select()->myRotation(); + newIsSelected = editor->select()->somethingSelected(); + + newVectorSelection = editor->select()->vectorSelection; + + selectionType = backupSelectionType; + + if (selectionType == SelectionType::SELECTION) { + setText(QObject::tr("Select")); + } else { + setText(QObject::tr("Deselect")); + } + +} + +void SelectionElement::undo() +{ + editor()->scrubTo(layerId, frameIndex); + if (selectionType == SelectionType::SELECTION) { + undoSelection(); + } else { + undoDeselection(); + } +} + +void SelectionElement::undoSelection() +{ + auto selectMan = editor()->select(); + + selectMan->setSelection(oldSelectionRect); + selectMan->setRotation(oldRotationAngle); + selectMan->setSomethingSelected(oldIsSelected); + + Layer* layer = editor()->layers()->findLayerById(layerId); + + editor()->deselectAll(); + if (layer->type() == Layer::VECTOR) { + VectorImage* vectorImage = static_cast(layer)->getVectorImageAtFrame(frameIndex); + vectorImage->setSelected(oldVectorSelection.curve, oldVectorSelection.vertex, true); + selectMan->setSelection(vectorImage->getSelectionRect()); + selectMan->vectorSelection = oldVectorSelection; + } + + KeyFrame* cKeyFrame = layer->getLastKeyFrameAtPosition(editor()->currentFrame()); + editor()->canvas()->applyTransformedSelection(layer, + cKeyFrame, + selectMan->selectionTransform(), + oldSelectionRect); +} + +void SelectionElement::undoDeselection() +{ + auto selectMan = editor()->select(); + selectMan->resetSelectionTransform(); + selectMan->setSelection(oldSelectionRect); + selectMan->setRotation(oldRotationAngle); + selectMan->setSomethingSelected(oldIsSelected); + + Layer* layer = editor()->layers()->findLayerById(layerId); + if (layer->type() == Layer::VECTOR) { + VectorImage* vectorImage = static_cast(layer)->getVectorImageAtFrame(frameIndex); + vectorImage->setSelected(oldVectorSelection.curve, oldVectorSelection.vertex, true); + selectMan->vectorSelection = oldVectorSelection; + } +} + +void SelectionElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + editor()->scrubTo(layerId, frameIndex); + if (selectionType == SelectionType::SELECTION) { + redoSelection(); + } else { + redoDeselection(); + } + +} + +void SelectionElement::redoSelection() +{ + auto selectMan = editor()->select(); + + selectMan->setSelection(newSelectionRect); + selectMan->setRotation(newRotationAngle); + selectMan->setSomethingSelected(newIsSelected); + selectMan->calculateSelectionTransformation(); + + Layer* layer = editor()->layers()->findLayerById(layerId); + if (layer->type() == Layer::VECTOR) { + VectorImage* vectorImage = static_cast(layer)->getVectorImageAtFrame(frameIndex); + vectorImage->setSelected(newVectorSelection.curve, newVectorSelection.vertex, true); + selectMan->setSelection(vectorImage->getSelectionRect()); + selectMan->vectorSelection = newVectorSelection; + } +} + +void SelectionElement::redoDeselection() +{ + auto selectMan = editor()->select(); + + Layer* layer = editor()->layers()->findLayerById(layerId); + KeyFrame* cKeyFrame = layer->getLastKeyFrameAtPosition(editor()->currentFrame()); + editor()->canvas()->applyTransformedSelection(layer, + cKeyFrame, + selectMan->selectionTransform(), + selectMan->mySelectionRect()); + + if (layer->type() == Layer::VECTOR) { + VectorImage* vectorImage = static_cast(layer)->getVectorImageAtFrame(frameIndex); + vectorImage->setSelected(newVectorSelection.curve, newVectorSelection.vertex, true); + selectMan->vectorSelection = newVectorSelection; + } + + editor()->deselectAll(); +} + +bool SelectionElement::mergeWith(const QUndoCommand *other) +{ + if (other->id() != id()) + { + return false; + } + + auto otherSelectionElement = static_cast(other); + SelectionType otherType = otherSelectionElement->selectionType; + if (selectionType == SelectionType::SELECTION && otherType == selectionType) { + newSelectionRect = otherSelectionElement->newSelectionRect; + newIsSelected = otherSelectionElement->newIsSelected; + newRotationAngle = otherSelectionElement->newRotationAngle; + newVectorSelection = otherSelectionElement->newVectorSelection; + + auto selectMan = editor()->select(); + selectMan->setSelectionRect(newSelectionRect); + selectMan->setRotation(newRotationAngle); + selectMan->setSomethingSelected(newIsSelected); + selectMan->vectorSelection = newVectorSelection; + + return true; + } else { + return false; + } +} + +TransformElement::TransformElement(const KeyFrame* backupKeyFrame, + const int backupLayerId, + const DrawOnEmptyFrameAction& backupFrameAction, + const QRectF& backupSelectionRect, + const QRectF& backupTempSelectionRect, + const QRectF& backupTransformedSelectionRect, + const qreal backupRotationAngle, + const qreal backupScaleX, + const qreal backupScaleY, + const bool backupIsSelected, + const QTransform& backupTransform, + const QString& description, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + + + oldLayerId = backupLayerId; + oldFrameIndex = backupKeyFrame->pos(); + oldSelectionRect = backupSelectionRect; + oldSelectionRectTemp = backupTempSelectionRect; + oldTransformedSelectionRect = backupTransformedSelectionRect; + oldRotationAngle = backupRotationAngle; + oldIsSelected = backupIsSelected; + + oldTransform = backupTransform; + oldScaleX = backupScaleX; + oldScaleY = backupScaleY; + + Layer* newLayer = editor->layers()->currentLayer(); + newLayerId = newLayer->id(); + newFrameIndex = editor->currentFrame(); + auto selectMan = editor->select(); - selectMan->setSelection(mySelection, false); - selectMan->setTransformedSelectionRect(myTransformedSelection); - selectMan->setTempTransformedSelectionRect(myTempTransformedSelection); + newSelectionRect = selectMan->mySelectionRect(); + newSelectionRectTemp = selectMan->myTempTransformedSelectionRect(); + newTransformedSelectionRect = selectMan->myTransformedSelectionRect(); + newRotationAngle = selectMan->myRotation(); + newIsSelected = selectMan->somethingSelected(); + newTransform = selectMan->selectionTransform(); + newScaleX = selectMan->myScaleX(); + newScaleY = selectMan->myScaleY(); + + Layer* layer = editor->layers()->findLayerById(backupLayerId); + + newFrameIndex = BackupManager::getActiveFrameIndex(layer, newFrameIndex, backupFrameAction); + KeyFrame* oldKeyFrame = backupKeyFrame->clone(); + + switch(layer->type()) + { + case Layer::BITMAP: + { + oldBitmap = static_cast(oldKeyFrame)->clone(); + newBitmap = static_cast(layer)->getBitmapImageAtFrame(newFrameIndex)->clone(); + break; + } + case Layer::VECTOR: + { + oldVector = static_cast(oldKeyFrame)->clone(); + newVector = static_cast(layer)-> + getVectorImageAtFrame(newFrameIndex)->clone(); + break; + } + default: + break; + } + + setText(description); +} + +void TransformElement::undo() +{ + apply(oldBitmap, + oldVector, + oldSelectionRect, + oldSelectionRectTemp, + oldTransformedSelectionRect, + oldRotationAngle, + oldScaleX, + oldScaleY, + oldIsSelected, + oldTransform, + oldLayerId); +} + +void TransformElement::redo() +{ + if (isFirstRedo) { + isFirstRedo = false; return; + } + + apply(newBitmap, + newVector, + newSelectionRect, + newSelectionRectTemp, + newTransformedSelectionRect, + newRotationAngle, + newScaleX, + newScaleY, + newIsSelected, + newTransform, + newLayerId); +} + +void TransformElement::apply(const BitmapImage* bitmapImage, + const VectorImage* vectorImage, + const QRectF& selectionRect, + const QRectF& tempRect, + const QRectF& transformedRect, + const qreal rotationAngle, + const qreal scaleX, + const qreal scaleY, + const bool isSelected, + const QTransform& transform, + const int layerId) +{ + + Layer* layer = editor()->layers()->findLayerById(layerId); + Layer* currentLayer = editor()->layers()->currentLayer(); + + if (layer->type() != currentLayer->type()) + { + editor()->layers()->setCurrentLayer(layer); + } + + auto selectMan = editor()->select(); + selectMan->setSelectionTransform(transform); + selectMan->setSelectionRect(selectionRect); + selectMan->setTempTransformedSelectionRect(tempRect); + selectMan->setTransformedSelectionRect(transformedRect); selectMan->setRotation(rotationAngle); - selectMan->setSomethingSelected(somethingSelected); + selectMan->setSomethingSelected(isSelected); + selectMan->setScale(scaleX, scaleY); - for (int i = 0; i < editor->object()->getLayerCount(); i++) + switch(layer->type()) { - Layer* layer = editor->object()->getLayer(i); - if (layer->type() == Layer::VECTOR) + case Layer::BITMAP: { - VectorImage* vectorImage = static_cast(layer)->getVectorImageAtFrame(this->frame); - if (vectorImage != nullptr) - { - vectorImage->modification(); + if (bitmapImage->isMinimallyBounded()) { + static_cast(layer)->replaceLastBitmapAtFrame(bitmapImage); + KeyFrame* cKeyFrame = layer->getLastKeyFrameAtPosition(editor()->currentFrame()); + editor()->canvas()->paintTransformedSelection(layer, + cKeyFrame, + transform, + selectionRect); } + break; + } + case Layer::VECTOR: + { + LayerVector* vlayer = static_cast(layer); + vlayer->replaceLastVectorAtFrame(vectorImage); + VectorImage* vecImage = vlayer->getLastVectorImageAtFrame(editor()->currentFrame(), 0); + vecImage->setSelectionTransformation(transform); + editor()->updateCurrentFrame(); + break; } + default: + break; + } +} + +ImportBitmapElement::ImportBitmapElement(const std::map>& backupCanvasKeyFrames, + const std::map>& backupImportedKeyFrames, + const int& backupLayerId, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + + oldLayerId = backupLayerId; + newLayerId = editor->layers()->currentLayer()->id(); - if (editor->currentFrame() != this->frame) { - editor->scrubTo(this->frame); + importedKeyFrames = backupImportedKeyFrames; + oldKeyFrames = backupCanvasKeyFrames; + + setText(QObject::tr("Import images/s")); +} + +void ImportBitmapElement::undo() +{ + for (auto key : importedKeyFrames) + { + editor()->removeKeyAtLayerId(oldLayerId,key.second->pos()); } - editor->frameModified(this->frame); - if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) + + Layer* layer = editor()->layers()->findLayerById(oldLayerId); + + // we've removed all keyframes + those that were overwritten + // now re-add the old ones + LayerBitmap* layerBitmap = static_cast(layer); + for (auto key : oldKeyFrames) { - editor->restoreKey(); + editor()->addKeyFrameToLayer(layer, key.first, true); + layerBitmap->putBitmapIntoFrame(key.second, key.second->pos()); } - else + editor()->updateCurrentFrame(); +} + +void ImportBitmapElement::redo() +{ + if (isFirstRedo) + { + isFirstRedo = false; + return; + } + + Layer* layer = editor()->layers()->findLayerById(newLayerId); + + LayerBitmap* layerBitmap = static_cast(layer); + for (auto key : importedKeyFrames) + { + editor()->addKeyFrameToLayer(layer, key.first, true); + layerBitmap->putBitmapIntoFrame(key.second, key.second->pos()); + } + editor()->updateCurrentFrame(); +} + +bool ImportBitmapElement::mergeWith(const QUndoCommand *other) +{ + if (other->id() != id()) { + return false; + } + + auto element = static_cast(other); + newLayerId = element->newLayerId; + + auto importedKeys = element->importedKeyFrames; + importedKeyFrames.insert(importedKeys.begin(), importedKeys.end()); + + return true; +} + +CameraMotionElement::CameraMotionElement(const int backupFrameIndex, + const int backupLayerId, + const QPointF& backupTranslation, + const float backupRotation, + const float backupScale, + const QString& description, + Editor* editor, + QUndoCommand* parent) : BackupElement(editor, parent) +{ + + frameIndex = backupFrameIndex; + layerId = backupLayerId; + + oldTranslation = backupTranslation; + oldRotation = backupRotation; + oldScale = backupScale; + + ViewManager* viewMgr = editor->view(); + newTranslation = viewMgr->translation(); + newRotation = viewMgr->rotation(); + newScale = viewMgr->scaling(); + + if (description.isEmpty()) { + setText(QObject::tr("Camera: New motion")); + } else { + setText(description); + } + +} + +void CameraMotionElement::undo() +{ + ViewManager* viewMgr = editor()->view(); + + Layer* layer = editor()->layers()->findLayerById(layerId); + editor()->scrubTo(layer, frameIndex); + + viewMgr->translate(oldTranslation); + viewMgr->rotate(oldRotation); + viewMgr->scale(oldScale); +} + +void CameraMotionElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + Layer* layer = editor()->layers()->findLayerById(layerId); + editor()->scrubTo(layer, frameIndex); + + ViewManager* viewMgr = editor()->view(); + viewMgr->translate(newTranslation); + viewMgr->rotate(newRotation); + viewMgr->scale(newScale); +} + +bool CameraMotionElement::mergeWith(const QUndoCommand *other) +{ + if (other->id() != id() || other->text() != text()) + { + return false; + } + + newTranslation = static_cast(other)->newTranslation; + newRotation = static_cast(other)->newRotation; + newScale = static_cast(other)->newScale; + + ViewManager* viewMgr = editor()->view(); + viewMgr->translate(newTranslation); + viewMgr->rotate(newRotation); + viewMgr->scale(newScale); + return true; +} + +AddLayerElement::AddLayerElement(Layer* backupLayer, + Editor* editor, + QUndoCommand* parent) : BackupElement(editor, parent) +{ + + + oldLayer = backupLayer; + oldLayerId = backupLayer->id(); + + Layer* layer = editor->layers()->currentLayer(); + newLayerType = layer->type(); + newLayerId = layer->id(); + + switch(layer->type()) { - if (layer != nullptr) + case Layer::BITMAP: { - if (layer->type() == Layer::VECTOR) - { - auto pVectorImage = static_cast(layer); - *pVectorImage->getLastVectorImageAtFrame(this->frame, 0) = this->vectorImage; // restore the image - } + newLayer = new LayerBitmap(newLayerId, layer->object()); + break; + } + case Layer::VECTOR: + { + newLayer = new LayerVector(newLayerId, layer->object()); + break; + } + case Layer::SOUND: + { + newLayer = new LayerSound(newLayerId, layer->object()); + break; + } + case Layer::CAMERA: + { + newLayer = new LayerCamera(newLayerId, layer->object()); + break; + } + default: + Q_ASSERT(false); + } + newLayerName = layer->name(); + + + setText(QObject::tr("New Layer")); +} + +void AddLayerElement::undo() +{ + qDebug() << "undo"; + qDebug() << "oldLayerId:" << oldLayerId; + qDebug() << "newLayerId:" << newLayerId; + editor()->layers()->deleteLayerWithId(newLayerId); + +} + +void AddLayerElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + switch(newLayer->type()) + { + case Layer::BITMAP: + { + editor()->layers()->createBitmapLayer(newLayerName); + break; + } + case Layer::VECTOR: + { + editor()->layers()->createVectorLayer(newLayerName); + break; + } + case Layer::SOUND: + { + editor()->layers()->createSoundLayer(newLayerName); + break; + } + case Layer::CAMERA: + { + editor()->layers()->createCameraLayer(newLayerName); + break; } + default: + break; + } + +} + +DeleteLayerElement::DeleteLayerElement(const QString& backupLayerName, + const Layer::LAYER_TYPE& backupType, + const std::map >& backupLayerKeys, + const int& backupFrameIndex, + const int& backupLayerIndex, + const int& backupLayerId, + Editor* editor, + QUndoCommand* parent) : BackupElement(editor, parent) +{ + + + oldFrameIndex = backupFrameIndex; + oldLayerIndex = backupLayerIndex; + oldLayerName = backupLayerName; + oldLayerKeys = backupLayerKeys; + oldLayerType = backupType; + oldLayerId = backupLayerId; + + switch(oldLayerType) + { + case Layer::BITMAP: + { + setText(QObject::tr("Delete Bitmap Layer")); + break; + } + case Layer::VECTOR: + { + setText(QObject::tr("Delete Vector Layer")); + break; + } + case Layer::SOUND: + { + setText(QObject::tr("Delete Sound Layer")); + break; + } + case Layer::CAMERA: + { + setText(QObject::tr("Delete Camera Layer")); + break; + } + default: + break; + } +} + +void DeleteLayerElement::undo() +{ + editor()->backups()->restoreLayerKeys(this); +} + +void DeleteLayerElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + editor()->layers()->deleteLayerWithId(oldLayerId); + +} + +RenameLayerElement::RenameLayerElement(const QString& backupLayerName, + const int& backupLayerId, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + + oldLayerName = backupLayerName; + oldLayerId = backupLayerId; + + Layer* layer = editor->layers()->currentLayer(); + newLayerId = layer->id(); + newLayerName = layer->name(); + + setText(QObject::tr("Rename layer")); +} + +void RenameLayerElement::undo() +{ + Layer* layer = editor()->layers()->findLayerById(oldLayerId); + editor()->layers()->renameLayer(layer, oldLayerName); +} + +void RenameLayerElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + Layer* layer = editor()->layers()->findLayerById(newLayerId); + editor()->layers()->renameLayer(layer, newLayerName); + +} + +CameraPropertiesElement::CameraPropertiesElement(const QString& backupLayerName, + const QRect& backupViewRect, + const int& backupLayerId, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + + oldLayerId = backupLayerId; + oldViewRect = backupViewRect; + oldLayerName = backupLayerName; + + LayerCamera* layer = static_cast(editor->layers()->currentLayer()); + + newLayerId = layer->id(); + newLayerName = layer->name(); + newViewRect = layer->getViewRect(); + + if (oldViewRect != newViewRect) + { + setText(QObject::tr("Edit Camera Properties")); + } + else + { + setText(QObject::tr("Rename Layer")); + } + +} + +void CameraPropertiesElement::undo() +{ + LayerManager* lmgr = editor()->layers(); + LayerCamera* layer = static_cast(lmgr->findLayerById(oldLayerId)); + + lmgr->renameLayer(layer, oldLayerName); + layer->setViewRect(oldViewRect); + editor()->updateCurrentFrame(); + +} + +void CameraPropertiesElement::redo() +{ + + if (isFirstRedo) { isFirstRedo = false; return; } + + LayerManager* lmgr = editor()->layers(); + LayerCamera* layer = static_cast(lmgr->findLayerById(newLayerId)); + + if (layer->name() != newLayerName) + { + lmgr->renameLayer(layer, newLayerName); + } + if (layer->getViewRect() != newViewRect) + { + layer->setViewRect(newViewRect); + } + editor()->updateCurrentFrame(); +} + +MoveFramesElement::MoveFramesElement(const int backupLayerId, + const int backupScrubberFrameIndex, + const int backupOffset, + const bool wasSelected, + const QList selectedFrameIndexes, + Editor* editor, + QUndoCommand* parent) : BackupElement(editor, parent), + offset(backupOffset) +{ + scrubberIndex = backupScrubberFrameIndex; + + layerId = backupLayerId; + oldSelectedFrameIndexes = selectedFrameIndexes; + newSelectedFrameIndexes = editor->layers()->findLayerById(layerId)->getSelectedFramesByPos(); + + framesSelected = wasSelected; + if (backupOffset < 0) { + setText(QObject::tr("Move frame/s backward")); + } else { + setText(QObject::tr("Move frame/s forward")); + } +} + +void MoveFramesElement::undo() +{ + qDebug() << "UNDO"; + + Layer* layer = editor()->layers()->findLayerById(layerId); + if (!framesSelected) { + qDebug() << "old index: " << scrubberIndex; + qDebug() << "new index: " << scrubberIndex+offset; + applyToSingle(layer, scrubberIndex, scrubberIndex+offset); + editor()->scrubTo(layerId, scrubberIndex); + } else { + applyToMulti(layer, -offset, newSelectedFrameIndexes); + editor()->layers()->setCurrentLayer(layer); + } + + editor()->updateView(); +} + +void MoveFramesElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + Layer* layer = editor()->layers()->findLayerById(layerId); + if (!framesSelected) { + + qDebug() << "old index: " << scrubberIndex; + qDebug() << "new index: " << scrubberIndex+offset; + applyToSingle(layer, scrubberIndex+offset, scrubberIndex); + editor()->scrubTo(layerId, scrubberIndex+offset); + } else { + applyToMulti(layer, offset, oldSelectedFrameIndexes); + editor()->layers()->setCurrentLayer(layer); + } + + editor()->updateView(); +} + + +void MoveFramesElement::applyToSingle(Layer* layer, const int oldFrameIndex, const int newFrameIndex) +{ + layer->swapKeyFrames(oldFrameIndex, newFrameIndex); +} + +void MoveFramesElement::applyToMulti(Layer* layer, const int offset, const QList selectedFrameIndexes) +{ + layer->setFramesSelected(selectedFrameIndexes, true); + layer->moveSelectedFrames(offset); + layer->deselectAll(); +} + +//SelectFramesElement::SelectFramesElement(const SelectionType selectionType, +// const int backupOldLayerId, +// const int backupFrameIndex, +// const QList backupFrameIndexes, +// const QList backupChangedSelectedIndexes, +// const bool backupIsFrameSelected, +// Editor* editor, +// QUndoCommand* parent) : BackupElement (editor, parent), +// oldLayerId(backupOldLayerId), +// frameIndex(backupFrameIndex), +// oldIsSelected(backupIsFrameSelected), +// oldFrameIndexes(backupFrameIndexes), +// selectionType(selectionType) +//{ +// oldChangedIndexes = backupChangedSelectedIndexes; + +// Layer* layer = editor->layers()->currentLayer(); +//// newSelectedFrameIndexes = layer->getSelectedFrameIndexes(); + +// newFrameIndexes = layer->getSelectedFrameIndexes(); +// newChangedIndexes = newFrameIndexes; +// newLayerId = layer->id(); + + +// oldChangedIndexes = getUniqueFrames(oldChangedIndexes, backupFrameIndexes); +//// qDebug() << "old filtered:" << oldChangedIndexes; + +// if (selectionType == SelectionType::SELECTION) { +// setText(QObject::tr("Select frame/s")); +// } else { +// setText(QObject::tr("Deselect frame/s")); +// } +//} + +//QList SelectFramesElement::getUniqueFrames(const QList frameIndexes, const QList compareIndxes) +//{ +// QList filteredFrames; +// for (int i : frameIndexes) { +// if (!compareIndxes.contains(i)) { +// filteredFrames.append(i); +// } +// } + +// if (filteredFrames.count() > 1) { +// moreFramesSelected = true; +// } else { +// moreFramesSelected = false; +// } +// return filteredFrames; +//} + +////void SelectFramesElement::apply(const bool moreFramesSelected, +//// const int layerId, +//// const QList changedFrameIndexes, +//// const QList undoFrameIndexes, +//// const QList redoFrameIndexes, +//// const SelectionType& selectionType) +////{ +//// Layer* layer = editor()->layers()->findLayerById(layerId); + +//// if (selectionType == SelectionType::SELECTION) { + +//// if (moreFramesSelected && changedFrameIndexes != undoFrameIndexes) { +//// layer->setFramesSelected(changedFrameIndexes, false); +//// layer->setFramesSelected(redoFrameIndexes, true); +//// } else { +//// layer->setFramesSelected(redoFrameIndexes, false); +//// } +//// } else { +//// layer->setFramesSelected(undoFrameIndexes, true); +//// } +//// editor()->updateTimeLine(); +//// editor()->layers()->setCurrentLayer(layer); +////} + +//void SelectFramesElement::undo() +//{ + +//// apply(moreFramesSelected, +//// newLayerId, +//// frameIndex, +//// oldNewlyFrameIndexes, +//// oldFrameIndexes, +//// newFrameIndexes, +//// selectionType); +// Layer* layer = editor()->layers()->findLayerById(newLayerId); + +// if (selectionType == SelectionType::SELECTION) { + + +// // FIXME: sometimes (using modifiers presumably) move and selections are not always undo/redo able... +// if (moreFramesSelected && oldChangedIndexes != oldFrameIndexes) { +// layer->deselectAll(); +// layer->setFramesSelected(oldFrameIndexes, true); +// } else { +// qDebug() << " \n newFrameIdx: " << newFrameIndexes; +// qDebug() << "old indexes: " << oldFrameIndexes; +// qDebug() << "oldChangedIndexes: " << oldChangedIndexes; +// qDebug() << "newChanged Indexes" << newChangedIndexes; +//// layer->setFramesSelected(newFrameIndexes, false); +// layer->deselectAll(); +// layer->setFramesSelected(oldFrameIndexes); +// } +// } else { +// layer->setFramesSelected(oldFrameIndexes, true); +// } + +// qDebug() << layer->getSelectedFrameIndexes(); +// editor()->updateTimeLine(); +// editor()->layers()->setCurrentLayer(layer); +//} + +//void SelectFramesElement::redo() +//{ +// if (isFirstRedo) { isFirstRedo = false; return; } + +//// apply(moreFramesSelected, +//// newLayerId, +//// newSelectedFrameIndexes, +//// newFrameIndexes, +//// oldFrameIndexes, +//// selectionType); + +// Layer* layer = editor()->layers()->findLayerById(newLayerId); + +// if (selectionType == SelectionType::SELECTION) { +// if (moreFramesSelected && newChangedIndexes != newFrameIndexes) { +//// layer->setFramesSelected(newChangedIndexes, false); +// layer->deselectAll(); +// layer->setFramesSelected(newFrameIndexes, true); +// } else { +// layer->deselectAll(); +// layer->setFramesSelected(newFrameIndexes, true); +// } +// } else { +// layer->setFramesSelected(newFrameIndexes, true); +// } +// editor()->updateTimeLine(); +// editor()->layers()->setCurrentLayer(layer); +//} + +//bool SelectFramesElement::mergeWith(const QUndoCommand *other) +//{ +// const SelectFramesElement* otherElem = static_cast(other); + +// if (otherElem->id() != id()) { +// return false; +// } + +//// setText(otherElem->text()); +//// oldFrameIndexes = otherElem->oldFrameIndexes; +// newFrameIndexes = otherElem->newFrameIndexes; +// frameIndex = otherElem->frameIndex; +//// oldLayerId = otherElem->oldLayerId; +// newLayerId = otherElem->newLayerId; +//// oldNewlyFrameIndexes = otherElem->oldNewlyFrameIndexes; +// newChangedIndexes = otherElem->newChangedIndexes; +// newChangedIndexes = getUniqueFrames(newChangedIndexes, newFrameIndexes); + +// if (newChangedIndexes.isEmpty() && newFrameIndexes.isEmpty()) { +// setObsolete(true); +////// return false; +// } +//// selectionType = otherElem->selectionType; + +// // TODO: figure out to merge select deselect... +//// oldIsSelected = otherElem->oldIsSelected; +// return true; +//} + +FlipViewElement::FlipViewElement(const bool& backupFlipState, + const Direction& backupFlipDirection, + Editor *editor, + QUndoCommand *parent) : BackupElement(editor, parent) +{ + + + isFlipped = backupFlipState; + direction = backupFlipDirection; + + if (direction == Direction::HORIZONTAL) + { + setText(QObject::tr("Flip View X")); + } + else + { + setText(QObject::tr("Flip View Y")); } } -void BackupSoundElement::restore(Editor* editor) +void FlipViewElement::undo() { - Layer* layer = editor->object()->findLayerById(this->layerId); - if (editor->currentFrame() != this->frame) { - editor->scrubTo(this->frame); + if (direction == Direction::VERTICAL) + { + editor()->view()->flipVertical(!isFlipped); } - editor->frameModified(this->frame); + else + { + editor()->view()->flipHorizontal(!isFlipped); + } +} + +void FlipViewElement::redo() +{ + + if (isFirstRedo) { isFirstRedo = false; return; } - // TODO: soundclip won't restore if overlapping on first frame - if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) + if (direction == Direction::VERTICAL) { - editor->restoreKey(); + editor()->view()->flipVertical(isFlipped); } + else + { + editor()->view()->flipHorizontal(isFlipped); + } +} + +MoveLayerElement::MoveLayerElement(const int& backupOldLayerIndex, + const int& backupNewLayerIndex, + Editor* editor, + QUndoCommand* parent) : BackupElement(editor, parent) +{ + oldLayerIndex = backupOldLayerIndex; + newLayerIndex = backupNewLayerIndex; + + setText(QObject::tr("Move layer")); +} + +void MoveLayerElement::undo() +{ + editor()->swapLayers(newLayerIndex, oldLayerIndex); + editor()->layers()->setCurrentLayer(oldLayerIndex); +} + +void MoveLayerElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + editor()->swapLayers(oldLayerIndex, newLayerIndex); + editor()->layers()->setCurrentLayer(newLayerIndex); + } diff --git a/core_lib/src/interface/backupelement.h b/core_lib/src/interface/backupelement.h index 8d62668451..4d39df3bf1 100644 --- a/core_lib/src/interface/backupelement.h +++ b/core_lib/src/interface/backupelement.h @@ -1,8 +1,8 @@ /* -Pencil2D - Traditional Animation Software +Pencil - Traditional Animation Software Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon -Copyright (C) 2012-2020 Matthew Chiawen Chang +Copyright (C) 2012-2018 Matthew Chiawen Chang This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -19,71 +19,578 @@ GNU General Public License for more details. #define BACKUPELEMENT_H #include -#include "vectorimage.h" -#include "bitmapimage.h" -#include "soundclip.h" +#include +#include +#include + +#include "direction.h" +#include "movemode.h" +#include "pencildef.h" +#include "layer.h" +#include "vectorselection.h" +#include "preferencemanager.h" class Editor; +class BackupManager; +class PreferenceManager; +class BitmapImage; +class VectorImage; +class SoundClip; +class Camera; +class Layer; +class KeyFrame; + +enum types { UNDEFINED, + ADD_KEY_MODIF, + REMOVE_KEY_MODIF + }; -class BackupElement : public QObject +class BackupElement : public QUndoCommand { - Q_OBJECT public: - enum types { UNDEFINED, BITMAP_MODIF, VECTOR_MODIF, SOUND_MODIF }; + explicit BackupElement(Editor* editor, QUndoCommand* parent = nullptr); + virtual ~BackupElement(); - QString undoText; - bool somethingSelected = false; - qreal rotationAngle = 0.0; - QRectF mySelection, myTransformedSelection, myTempTransformedSelection; + Editor* editor() { return mEditor; } - virtual int type() { return UNDEFINED; } - virtual void restore(Editor*) { Q_ASSERT(false); } + virtual int type() const { return UNDEFINED; } + virtual void undo() { Q_ASSUME(true); } // should never end here + virtual void redo() { Q_ASSUME(true); } // should never end here +private: + Editor* mEditor = nullptr; }; -class BackupBitmapElement : public BackupElement +class TransformElement; + +class AddBitmapElement : public BackupElement { - Q_OBJECT public: - explicit BackupBitmapElement(BitmapImage* bi) { bitmapImage = *bi; } + AddBitmapElement(const BitmapImage* backupBitmap, + const int& backupLayerId, + const DrawOnEmptyFrameAction& frameAction, + QString description, + Editor* editor, + QUndoCommand* parent = nullptr); - int layerId = 0; + int oldLayerIndex = 0; + int newLayerIndex = 0; + + int oldFrameIndex = 0; + int newFrameIndex = 0; + int previousFrameIndex = 0; + + int otherFrameIndex = 0; + + int oldLayerId = 0; + int newLayerId = 0; + + int emptyFrameSettingVal = -1; + + BitmapImage* oldBitmap = nullptr; + BitmapImage* newBitmap = nullptr; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; + + void redoTransform(const TransformElement* childElem); + void undoTransform(const TransformElement* childElem); +}; + +class AddVectorElement : public BackupElement +{ +public: + AddVectorElement(const VectorImage* backupVector, + const int& backupLayerId, + const DrawOnEmptyFrameAction& backupFrameAction, + QString description, + Editor* editor, + QUndoCommand* parent = nullptr); + + int newLayerIndex = 0; + int oldFrameIndex = 0; + int newFrameIndex = 0; + + int newLayerId = 0; + int oldLayerId = 0; + int emptyFrameSettingVal = -1; + + VectorImage* oldVector = nullptr; + VectorImage* newVector = nullptr; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; + +}; + +class AddKeyFrameElement : public BackupElement +{ +public: + enum { Id = 5 }; + AddKeyFrameElement(const int backupFrameIndex, + const int backupLayerId, + const DrawOnEmptyFrameAction& backupFrameAction, + const int backupKeySpacing, + const bool backupKeyExisted, + QString description, + Editor* editor, + QUndoCommand* parent = nullptr); + + void undoSequence(); + void redoSequence(); + + + int newLayerIndex = 0; + int newFrameIndex = 0; + + int oldFrameIndex; + int oldLayerId; + int oldKeySpacing; + bool oldKeyExisted; + + int newLayerId; + + std::mapoldKeyFrames; + std::mapnewKeyFrames; + + KeyFrame* newKey = nullptr; + int emptyFrameSettingVal = -1; + + bool isFirstRedo = true; + + int type() const override { return ADD_KEY_MODIF; } + void undo() override; + void redo() override; + int id() const override { return Id; } + bool mergeWith(const QUndoCommand *other) override; +}; + +class RemoveKeyFrameElement : public BackupElement +{ +public: + enum { Id = 4 }; + RemoveKeyFrameElement(const KeyFrame* backupBitmap, + const int& backupLayerId, + Editor* editor, + QUndoCommand* parent = nullptr); + + int oldLayerIndex = 0; + int oldFrameIndex = 0; + int oldLayerId = 0; + + KeyFrame* oldKey = nullptr; + + BitmapImage* oldBitmap = nullptr; + VectorImage* oldVector = nullptr; + SoundClip* oldClip = nullptr; + Camera* oldCamera = nullptr; + + bool isFirstRedo = true; + + int type() const override { return REMOVE_KEY_MODIF; } + void undo() override; + void redo() override; + int id() const override { return Id; } + +}; + +class SelectionElement : public BackupElement +{ +public: + + enum { Id = 1 }; + + SelectionElement(const int backupLayerId, + const int backupFrameIndex, + const VectorSelection& backupVectorSelection, + const SelectionType& backupSelectionType, + const QRectF& backupSelectionRect, + const qreal& backupRotationAngle, + const bool& backupIsSelected, + Editor* editor, + QUndoCommand* parent = nullptr); + + const int layerId; + const int frameIndex; + + VectorSelection oldVectorSelection; + VectorSelection newVectorSelection; + + QRectF oldSelectionRect = QRectF(); + QRectF newSelectionRect = QRectF(); + + qreal oldRotationAngle = 0.0; + qreal newRotationAngle = 0.0; + + bool oldIsSelected = false; + bool newIsSelected = false; + + SelectionType selectionType; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; + bool mergeWith(const QUndoCommand *other) override; + int id() const override { return Id; } + + void redoDeselection(); + void redoSelection(); + void undoDeselection(); + void undoSelection(); +}; + +class TransformElement : public BackupElement + +{ +public: + + enum { Id = 2 }; + TransformElement(const KeyFrame* backupKeyFrame, + const int backupLayerId, + const DrawOnEmptyFrameAction& backupFrameAction, + const QRectF& backupSelectionRect, + const QRectF& backupTempSelectionRect, + const QRectF& backupTransformedSelectionRect, + const qreal backupRotationAngle, + const qreal backupScaleX, + const qreal backupScaleY, + const bool backupIsSelected, + const QTransform& backupTransform, + const QString& description, + Editor* editor, + QUndoCommand* parent = nullptr); + + void undo() override; + void redo() override; + void apply(const BitmapImage* bitmapImage, + const VectorImage* vectorImage, + const QRectF& selectionRect, + const QRectF& tempRect, + const QRectF& transformedRect, + const qreal rotationAngle, + const qreal scaleX, + const qreal scaleY, + const bool isSelected, + const QTransform& transform, + const int layerId); + + int id() const override { return Id; } + + int oldFrameIndex = 0; + int newFrameIndex = 0; + + QRectF oldSelectionRect; + QRectF newSelectionRect; + + QRectF oldSelectionRectTemp; + QRectF newSelectionRectTemp; + + QRectF oldTransformedSelectionRect; + QRectF newTransformedSelectionRect; + + qreal oldRotationAngle; + qreal newRotationAngle; + + qreal oldScaleX; + qreal oldScaleY; + + qreal newScaleX; + qreal newScaleY; + + bool oldIsSelected = false; + bool newIsSelected = false; + + QTransform oldTransform; + QTransform newTransform; + + BitmapImage* oldBitmap = nullptr; + BitmapImage* newBitmap = nullptr; + + VectorImage* oldVector = nullptr; + VectorImage* newVector = nullptr; + + int oldLayerId = 0; + int newLayerId = 0; + + bool isFirstRedo = true; +}; - int layer = 0; - int frame = 0; - BitmapImage bitmapImage; - int type() override { return BackupElement::BITMAP_MODIF; } - void restore(Editor*) override; +class QProgressDialog; +class ImportBitmapElement : public BackupElement +{ + +public: + enum { Id = 7 }; + + ImportBitmapElement(const std::map >& backupCanvasKeyFrames, + const std::map >& backupImportedKeyFrames, + const int& backupLayerId, + Editor* editor, + QUndoCommand* parent = nullptr); + + std::map> oldKeyFrames; + std::map> importedKeyFrames; + + int oldLayerId = 0; + int newLayerId = 0; + + bool isFirstRedo = true; + + QProgressDialog* progress = nullptr; + + void undo() override; + void redo() override; + bool mergeWith(const QUndoCommand *other) override; + int id() const override { return Id; } }; -class BackupVectorElement : public BackupElement +class CameraMotionElement : public BackupElement { - Q_OBJECT public: - explicit BackupVectorElement(VectorImage* vi) { vectorImage = *vi; } + + enum { Id = 3 }; + CameraMotionElement(const int backupFrameIndex, + const int backupLayerId, + const QPointF& backupTranslation, + const float backupRotation, + const float backupScale, + const QString& description, + Editor* editor, + QUndoCommand* parent = nullptr); + + + QPointF oldTranslation = QPointF(0,0); + float oldRotation = 0.0f; + float oldScale = 0.0f; + + QPointF newTranslation = QPointF(0,0); + float newRotation = 0.0f; + float newScale = 0.0f; + + int frameIndex = 0; int layerId = 0; - int layer = 0; - int frame = 0; - VectorImage vectorImage; + bool isFirstRedo = true; + + void undo() override; + void redo() override; + bool mergeWith(const QUndoCommand *other) override; + int id() const override { return Id; } +}; + +class AddLayerElement : public BackupElement +{ +public: + AddLayerElement(Layer* backupLayer, + Editor* editor, + QUndoCommand* parent = nullptr); + + Layer* oldLayer; + Layer* newLayer; + + QString newLayerName; + + Layer::LAYER_TYPE newLayerType = Layer::UNDEFINED; + + int newLayerId = 0; + int oldLayerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; +}; + +class DeleteLayerElement : public BackupElement +{ +public: + DeleteLayerElement(const QString& backupLayerName, + const Layer::LAYER_TYPE& backupType, + const std::map >&, + const int& backupFrameIndex, + const int& backupLayerIndex, + const int& backupLayerId, + Editor* editor, + QUndoCommand* parent = nullptr); + + std::map >oldLayerKeys; + + QString oldLayerName; + + Layer::LAYER_TYPE oldLayerType; + + int oldLayerIndex = 0; + int oldFrameIndex = 0; + int oldLayerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; +}; + +class RenameLayerElement : public BackupElement +{ +public: + RenameLayerElement(const QString& backupLayerName, + const int& backupLayerId, + Editor* editor, + QUndoCommand* parent = nullptr); + + QString oldLayerName; + QString newLayerName; + + int oldLayerIndex = 0; + int newLayerIndex = 0; - int type() override { return BackupElement::VECTOR_MODIF; } - void restore(Editor*) override; + int oldLayerId = 0; + int newLayerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; }; -class BackupSoundElement : public BackupElement +class CameraPropertiesElement : public BackupElement { - Q_OBJECT public: - explicit BackupSoundElement(SoundClip* sound) { clip = *sound; } + CameraPropertiesElement(const QString& backupLayerName, + const QRect& backupViewRect, + const int& backupLayerId, + Editor* editor, + QUndoCommand* parent = nullptr); + + QString oldLayerName; + QString newLayerName; + + int oldLayerIndex = 0; + int newLayerIndex = 0; + + QRect oldViewRect; + QRect newViewRect; + + int oldLayerId = 0; + int newLayerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; +}; + +class MoveFramesElement : public BackupElement +{ +public: + + MoveFramesElement(const int backupLayerId, + const int backupScrubberFrameIndex, + const int backupOffset, + const bool wasSelected, + const QList selectedFrameIndexes, + Editor* editor, + QUndoCommand* parent = nullptr); + int layerId = 0; - int layer = 0; - int frame = 0; - SoundClip clip; - QString fileName, originalName; + const int offset; + + QList oldSelectedFrameIndexes; + QList newSelectedFrameIndexes; + + int scrubberIndex = 0; + + bool isFirstRedo = true; + bool framesSelected = false; + + void undo() override; + void redo() override; + void applyToSingle(Layer* layer, const int oldFrameIndex, const int newFrameIndex); + void applyToMulti(Layer* layer, const int offset, const QList selectedFrameIndexes); +}; + +//class SelectFramesElement : public BackupElement +//{ +//public: +// enum { Id = 8 }; +// SelectFramesElement(const SelectionType selectionType, +// const int backupLayerId, +// const int backupFrameIndex, +// const QList backupFrameIndexes, +// const QList backupChangedSelectedIndexes, +// const bool backupIsFrameSelected, +// Editor* editor, +// QUndoCommand* parent = nullptr); + +// int oldLayerId; +// int newLayerId; + +// int frameIndex; +// bool oldIsSelected; +// bool isFirstRedo = true; + +// QList oldFrameIndexes; +// QList newFrameIndexes; + +// QList oldChangedIndexes; +// QList newChangedIndexes; +// SelectionType selectionType; + +// bool moreFramesSelected = false; + +// void undo() override; +// void redo() override; +// bool mergeWith(const QUndoCommand *other) override; +// int id() const override { return Id; }; + +//private: +// QList getUniqueFrames(const QList frameIndexes, const QList compareIndxes); +// void apply(const bool moreFramesSelected, +// const int layerId, +// const QList additionalFramesIndexes, +// const QList oldFrameIndexes, +// const QList newFrameIndexes, +// const SelectionType& selectionType); +//}; + +class FlipViewElement : public BackupElement +{ +public: + FlipViewElement(const bool& backupFlipEnabled, + const Direction& backupFlipDirection, + Editor* editor, + QUndoCommand* parent = nullptr); + + bool isFlipped = false; + + Direction direction; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; +}; + +class MoveLayerElement : public BackupElement +{ + +public: + MoveLayerElement(const int& backupOldLayerIndex, + const int& backupNewLayerIndex, + Editor* editor, + QUndoCommand* parent = nullptr); + + int oldLayerIndex = 0; + int newLayerIndex = 0; + + bool isFirstRedo = true; - int type() override { return BackupElement::SOUND_MODIF; } - void restore( Editor* ) override; + void undo() override; + void redo() override; }; #endif // BACKUPELEMENT_H diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index b8ab068f59..821b4e88f6 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -33,6 +33,7 @@ GNU General Public License for more details. #include "layervector.h" #include "layercamera.h" #include "backupelement.h" +#include "legacybackupelement.h" #include "colormanager.h" #include "filemanager.h" @@ -45,6 +46,7 @@ GNU General Public License for more details. #include "selectionmanager.h" #include "overlaymanager.h" #include "clipboardmanager.h" +#include "canvasmanager.h" #include "scribblearea.h" #include "timeline.h" @@ -159,7 +161,7 @@ void Editor::onModified(int layer, int frame) mLastModifiedFrame = frame; } -BackupElement* Editor::currentBackup() +LegacyBackupElement* Editor::currentBackup() { if (mBackupIndex >= 0) { @@ -206,6 +208,7 @@ void Editor::backup(const QString& undoText) bool Editor::backup(int backupLayer, int backupFrame, const QString& undoText) { + // TODO: remove me after integrating new backupmanager while (mBackupList.size() - 1 > mBackupIndex && !mBackupList.empty()) { delete mBackupList.takeLast(); @@ -312,15 +315,16 @@ bool Editor::backup(int backupLayer, int backupFrame, const QString& undoText) void Editor::sanitizeBackupElementsAfterLayerDeletion(int layerIndex) { + // TODO: to be removed when integrating new backupmanager for (int i = 0; i < mBackupList.size(); i++) { - BackupElement *backupElement = mBackupList[i]; + LegacyBackupElement *backupElement = mBackupList[i]; BackupBitmapElement *bitmapElement; BackupVectorElement *vectorElement; BackupSoundElement *soundElement; switch (backupElement->type()) { - case BackupElement::BITMAP_MODIF: + case LegacyBackupElement::BITMAP_MODIF: bitmapElement = qobject_cast(backupElement); Q_ASSERT(bitmapElement); if (bitmapElement->layer > layerIndex) @@ -333,7 +337,7 @@ void Editor::sanitizeBackupElementsAfterLayerDeletion(int layerIndex) continue; } break; - case BackupElement::VECTOR_MODIF: + case LegacyBackupElement::VECTOR_MODIF: vectorElement = qobject_cast(backupElement); Q_ASSERT(vectorElement); if (vectorElement->layer > layerIndex) @@ -346,7 +350,7 @@ void Editor::sanitizeBackupElementsAfterLayerDeletion(int layerIndex) continue; } break; - case BackupElement::SOUND_MODIF: + case LegacyBackupElement::SOUND_MODIF: soundElement = qobject_cast(backupElement); Q_ASSERT(soundElement); if (soundElement->layer > layerIndex) @@ -373,12 +377,13 @@ void Editor::sanitizeBackupElementsAfterLayerDeletion(int layerIndex) void Editor::restoreKey() { - BackupElement* lastBackupElement = mBackupList[mBackupIndex]; + // TODO: to be removed when integrating new backupmanager + LegacyBackupElement* lastBackupElement = mBackupList[mBackupIndex]; Layer* layer = nullptr; int frame = 0; int layerIndex = 0; - if (lastBackupElement->type() == BackupElement::BITMAP_MODIF) + if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF) { BackupBitmapElement* lastBackupBitmapElement = static_cast(lastBackupElement); layerIndex = lastBackupBitmapElement->layer; @@ -388,7 +393,7 @@ void Editor::restoreKey() dynamic_cast(layer)->getBitmapImageAtFrame(frame)->paste(&lastBackupBitmapElement->bitmapImage); emit frameModified(frame); } - if (lastBackupElement->type() == BackupElement::VECTOR_MODIF) + if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF) { BackupVectorElement* lastBackupVectorElement = static_cast(lastBackupElement); layerIndex = lastBackupVectorElement->layer; @@ -398,7 +403,7 @@ void Editor::restoreKey() dynamic_cast(layer)->getVectorImageAtFrame(frame)->paste(lastBackupVectorElement->vectorImage); emit frameModified(frame); } - if (lastBackupElement->type() == BackupElement::SOUND_MODIF) + if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF) { QString strSoundFile; BackupSoundElement* lastBackupSoundElement = static_cast(lastBackupElement); @@ -424,12 +429,13 @@ void Editor::restoreKey() void Editor::undo() { + // TODO: to be removed when integrating new backupmanager if (!mBackupList.empty() && mBackupIndex > -1) { if (mBackupIndex == mBackupList.size() - 1) { - BackupElement* lastBackupElement = mBackupList[mBackupIndex]; - if (lastBackupElement->type() == BackupElement::BITMAP_MODIF) + LegacyBackupElement* lastBackupElement = mBackupList[mBackupIndex]; + if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF) { BackupBitmapElement* lastBackupBitmapElement = static_cast(lastBackupElement); if (backup(lastBackupBitmapElement->layer, lastBackupBitmapElement->frame, "NoOp")) @@ -437,7 +443,7 @@ void Editor::undo() mBackupIndex--; } } - if (lastBackupElement->type() == BackupElement::VECTOR_MODIF) + if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF) { BackupVectorElement* lastBackupVectorElement = static_cast(lastBackupElement); if (backup(lastBackupVectorElement->layer, lastBackupVectorElement->frame, "NoOp")) @@ -445,7 +451,7 @@ void Editor::undo() mBackupIndex--; } } - if (lastBackupElement->type() == BackupElement::SOUND_MODIF) + if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF) { BackupSoundElement* lastBackupSoundElement = static_cast(lastBackupElement); if (backup(lastBackupSoundElement->layer, lastBackupSoundElement->frame, "NoOp")) @@ -476,6 +482,7 @@ void Editor::undo() void Editor::redo() { + // TODO: to be removed when integrating new backupmanager if (!mBackupList.empty() && mBackupIndex < mBackupList.size() - 2) { mBackupIndex++; @@ -1001,6 +1008,12 @@ bool Editor::importGIF(const QString& filePath, int numOfImages) return false; } +void Editor::updateView() +{ + view()->forceUpdateViewTransform(); + emit needPaint(); +} + void Editor::selectAll() const { Layer* layer = layers()->currentLayer(); @@ -1070,6 +1083,18 @@ void Editor::setCurrentLayerIndex(int i) } } +void Editor::scrubTo(const int layerId, const int frameIndex) +{ + layers()->setCurrentLayerFromId(layerId); + scrubTo(frameIndex); +} + +void Editor::scrubTo(Layer* layer, const int frameIndex) +{ + layers()->setCurrentLayer(layer); + scrubTo(frameIndex); +} + void Editor::scrubTo(int frame) { if (frame < 1) { frame = 1; } @@ -1108,70 +1133,104 @@ void Editor::scrubBackward() } } -KeyFrame* Editor::addNewKey() +KeyFrame* Editor::addKeyFrameToLayerId(int layerId, int frameIndex, bool ignoreKeyExists) { - return addKeyFrame(layers()->currentLayerIndex(), currentFrame()); + Layer* layer = layers()->findLayerById(layerId); + return addKeyFrameToLayer(layer, frameIndex, ignoreKeyExists); } -KeyFrame* Editor::addKeyFrame(int layerNumber, int frameIndex) +KeyFrame* Editor::addKeyFrameToLayer(Layer* layer, int frameIndex, const bool ignoreKeyExists) { - Layer* layer = mObject->getLayer(layerNumber); - Q_ASSERT(layer); - - if (!layer->visible()) + if (layer == nullptr) { - mScribbleArea->showLayerNotVisibleWarning(); + Q_ASSERT(false); return nullptr; } - // Find next available space for a keyframe (where either no key exists or there is an empty sound key) - while (layer->keyExists(frameIndex)) + if (!ignoreKeyExists) { - if (layer->type() == Layer::SOUND - && layer->getKeyFrameAt(frameIndex)->fileName().isEmpty() - && layer->removeKeyFrame(frameIndex)) + // Find next available space for a keyframe (where either no key exists or there is an empty sound key) + while (layer->keyExists(frameIndex)) { - break; - } - else - { - frameIndex += 1; + if (layer->type() == Layer::SOUND + && layer->getKeyFrameAt(frameIndex)->fileName().isEmpty() + && layer->removeKeyFrame(frameIndex)) + { + break; + } + else + { + frameIndex += 1; + } } } bool ok = layer->addNewKeyFrameAt(frameIndex); if (ok) { - scrubTo(frameIndex); // currentFrameChanged() emit inside. + scrubTo(layer, frameIndex); // currentFrameChanged() and currentLayerChanged() emitted inside. emit frameModified(frameIndex); layers()->notifyAnimationLengthChanged(); } + return layer->getKeyFrameAt(frameIndex); } -void Editor::removeKey() +KeyFrame* Editor::addNewKey() { - Layer* layer = layers()->currentLayer(); - Q_ASSERT(layer != nullptr); + return addKeyFrame(layers()->currentLayerIndex(), currentFrame()); +} +KeyFrame* Editor::addKeyFrame(int layerNumber, int frameIndex) +{ + Layer* layer = mObject->getLayer(layerNumber); if (!layer->visible()) { mScribbleArea->showLayerNotVisibleWarning(); + return nullptr; + } + return addKeyFrameToLayer(layer, frameIndex, false); +} + +void Editor::removeKeyAtLayerId(int layerId, int frameIndex) +{ + Layer* layer = layers()->findLayerById(layerId); + removeKeyAtLayer(layer, frameIndex); +} + +void Editor::removeKeyAtLayer(Layer *layer, int frameIndex, bool shouldBackup) +{ + if (layer == nullptr) + { + Q_ASSERT(false); return; } - if (!layer->keyExistsWhichCovers(currentFrame())) + if (!layer->keyExistsWhichCovers(frameIndex)) { scrubBackward(); return; } - backup(tr("Remove frame")); + if (shouldBackup) + { + backup(tr("Remove frame")); + } deselectAll(); - layer->removeKeyFrame(currentFrame()); + layer->removeKeyFrame(frameIndex); layers()->notifyAnimationLengthChanged(); - emit layers()->currentLayerChanged(layers()->currentLayerIndex()); // trigger timeline repaint. +} + +void Editor::removeKey() +{ + Layer* layer = layers()->currentLayer(); + if (!layer->visible()) + { + mScribbleArea->showLayerNotVisibleWarning(); + return; + } + removeKeyAtLayer(layer, currentFrame(), true); } void Editor::scrubNextKeyFrame() diff --git a/core_lib/src/interface/editor.h b/core_lib/src/interface/editor.h index 7ab2a9f66b..81c26033cf 100644 --- a/core_lib/src/interface/editor.h +++ b/core_lib/src/interface/editor.h @@ -49,6 +49,9 @@ class TimeLine; class BackupElement; class ActiveFramePool; class Layer; +class CanvasManager; +class BackupManager; +class LegacyBackupElement; enum class SETTING; @@ -63,9 +66,11 @@ class Editor : public QObject Q_PROPERTY(ViewManager* view READ view) Q_PROPERTY(PreferenceManager* preference READ preference) Q_PROPERTY(SoundManager* sound READ sound) - Q_PROPERTY(SelectionManager* select READ select) + Q_PROPERTY(SelectionManager* select READ select) Q_PROPERTY(OverlayManager* overlays READ overlays) Q_PROPERTY(ClipboardManager* clipboards READ clipboards) + Q_PROPERTY(CanvasManager* canvas READ canvas) + Q_PROPERTY(BackupManager* backups READ backups) public: explicit Editor(QObject* parent = nullptr); @@ -86,6 +91,8 @@ class Editor : public QObject SelectionManager* select() const { return mSelectionManager; } OverlayManager* overlays() const { return mOverlayManager; } ClipboardManager* clipboards() const { return mClipboardManager; } + CanvasManager* canvas() const { return mCanvasManager; } + BackupManager* backups() const { return mBackupManager; } Object* object() const { return mObject.get(); } Status openObject(const QString& strFilePath, const std::function& progressChanged, const std::function& progressRangeChanged); @@ -103,8 +110,12 @@ class Editor : public QObject int currentLayerIndex() const { return mCurrentLayerIndex; } void setCurrentLayerIndex(int i); + void scrubTo(const int layerId, const int frameIndex); + void scrubTo(Layer* layer, const int frameIndex); void scrubTo(int frameNumber); + void updateView(); + /** * @brief The visibility value should match any of the VISIBILITY enum values */ @@ -119,8 +130,8 @@ class Editor : public QObject // backup int mBackupIndex; - BackupElement* currentBackup(); - QList mBackupList; + LegacyBackupElement* currentBackup(); + QList mBackupList; signals: @@ -149,6 +160,8 @@ class Editor : public QObject void canCopyChanged(bool enabled); void canPasteChanged(bool enabled); + void needPaint(); + public: //slots /** Will call update() and update the canvas @@ -173,7 +186,11 @@ class Editor : public QObject void scrubForward(); void scrubBackward(); + KeyFrame* addKeyFrameToLayerId(int layerId, int frameIndex, bool ignoreKeyExists); + KeyFrame* addKeyFrameToLayer(Layer* layer, int frameIndex, const bool ignoreKeyExists); KeyFrame* addNewKey(); + void removeKeyAtLayerId(int layerId, int frameIndex); + void removeKeyAtLayer(Layer* layer, int frameIndex, bool shouldBackup = false); void removeKey(); void switchVisibilityOfLayer(int layerNumber); @@ -248,6 +265,8 @@ class Editor : public QObject SelectionManager* mSelectionManager = nullptr; OverlayManager* mOverlayManager = nullptr; ClipboardManager* mClipboardManager = nullptr; + CanvasManager* mCanvasManager = nullptr; + BackupManager* mBackupManager = nullptr; std::vector< BaseManager* > mAllManagers; diff --git a/core_lib/src/interface/legacybackupelement.cpp b/core_lib/src/interface/legacybackupelement.cpp new file mode 100644 index 0000000000..c2769d4f18 --- /dev/null +++ b/core_lib/src/interface/legacybackupelement.cpp @@ -0,0 +1,112 @@ +/* +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "legacybackupelement.h" + +#include "editor.h" +#include "layer.h" +#include "layerbitmap.h" +#include "layervector.h" +#include "object.h" +#include "selectionmanager.h" + +void BackupBitmapElement::restore(Editor* editor) +{ + Layer* layer = editor->object()->findLayerById(this->layerId); + auto selectMan = editor->select(); + selectMan->setSelection(mySelection, true); + selectMan->setTransformedSelectionRect(myTransformedSelection); + selectMan->setTempTransformedSelectionRect(myTempTransformedSelection); + selectMan->setRotation(rotationAngle); + selectMan->setSomethingSelected(somethingSelected); + + if (editor->currentFrame() != this->frame) { + editor->scrubTo(this->frame); + } + editor->frameModified(this->frame); + + if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) + { + editor->restoreKey(); + } + else + { + if (layer != nullptr) + { + if (layer->type() == Layer::BITMAP) + { + auto bitmapLayer = static_cast(layer); + *bitmapLayer->getLastBitmapImageAtFrame(this->frame, 0) = bitmapImage; // restore the image + } + } + } +} + +void BackupVectorElement::restore(Editor* editor) +{ + Layer* layer = editor->object()->findLayerById(this->layerId); + auto selectMan = editor->select(); + selectMan->setSelection(mySelection, false); + selectMan->setTransformedSelectionRect(myTransformedSelection); + selectMan->setTempTransformedSelectionRect(myTempTransformedSelection); + selectMan->setRotation(rotationAngle); + selectMan->setSomethingSelected(somethingSelected); + + for (int i = 0; i < editor->object()->getLayerCount(); i++) + { + Layer* layer = editor->object()->getLayer(i); + if (layer->type() == Layer::VECTOR) + { + VectorImage* vectorImage = static_cast(layer)->getVectorImageAtFrame(this->frame); + if (vectorImage != nullptr) + { + vectorImage->modification(); + } + } + } + + if (editor->currentFrame() != this->frame) { + editor->scrubTo(this->frame); + } + editor->frameModified(this->frame); + if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) + { + editor->restoreKey(); + } + else + { + if (layer != nullptr) + { + if (layer->type() == Layer::VECTOR) + { + auto pVectorImage = static_cast(layer); + *pVectorImage->getLastVectorImageAtFrame(this->frame, 0) = this->vectorImage; // restore the image + } + } + } +} + +void BackupSoundElement::restore(Editor* editor) +{ + Layer* layer = editor->object()->findLayerById(this->layerId); + if (editor->currentFrame() != this->frame) { + editor->scrubTo(this->frame); + } + editor->frameModified(this->frame); + + // TODO: soundclip won't restore if overlapping on first frame + if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) + { + editor->restoreKey(); + } +} diff --git a/core_lib/src/interface/legacybackupelement.h b/core_lib/src/interface/legacybackupelement.h new file mode 100644 index 0000000000..96c699229d --- /dev/null +++ b/core_lib/src/interface/legacybackupelement.h @@ -0,0 +1,87 @@ +/* +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef LEGACYBACKUPELEMENT_H +#define LEGACYBACKUPELEMENT_H + +#include +#include "vectorimage.h" +#include "bitmapimage.h" +#include "soundclip.h" + +class Editor; + +class LegacyBackupElement : public QObject +{ + Q_OBJECT +public: + enum types { UNDEFINED, BITMAP_MODIF, VECTOR_MODIF, SOUND_MODIF }; + + QString undoText; + bool somethingSelected = false; + qreal rotationAngle = 0.0; + QRectF mySelection, myTransformedSelection, myTempTransformedSelection; + + virtual int type() { return UNDEFINED; } + virtual void restore(Editor*) { Q_ASSERT(false); } +}; + +class BackupBitmapElement : public LegacyBackupElement +{ + Q_OBJECT +public: + explicit BackupBitmapElement(BitmapImage* bi) { bitmapImage = *bi; } + + int layerId = 0; + + int layer = 0; + int frame = 0; + BitmapImage bitmapImage; + int type() override { return LegacyBackupElement::BITMAP_MODIF; } + void restore(Editor*) override; +}; + +class BackupVectorElement : public LegacyBackupElement +{ + Q_OBJECT +public: + explicit BackupVectorElement(VectorImage* vi) { vectorImage = *vi; } + + int layerId = 0; + + int layer = 0; + int frame = 0; + VectorImage vectorImage; + + int type() override { return LegacyBackupElement::VECTOR_MODIF; } + void restore(Editor*) override; +}; + +class BackupSoundElement : public LegacyBackupElement +{ + Q_OBJECT +public: + explicit BackupSoundElement(SoundClip* sound) { clip = *sound; } + + int layerId = 0; + + int layer = 0; + int frame = 0; + SoundClip clip; + QString fileName, originalName; + + int type() override { return LegacyBackupElement::SOUND_MODIF; } + void restore( Editor* ) override; +}; + +#endif // LEGACYBACKUPELEMENT_H diff --git a/core_lib/src/managers/backupmanager.cpp b/core_lib/src/managers/backupmanager.cpp new file mode 100644 index 0000000000..32a89ed65d --- /dev/null +++ b/core_lib/src/managers/backupmanager.cpp @@ -0,0 +1,604 @@ +/* + +Pencil - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2018 Matthew Chiawen Chang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ + +#include "object.h" +#include "editor.h" + +#include + +#include "layermanager.h" +#include "soundmanager.h" +#include "backupmanager.h" +#include "viewmanager.h" +#include "selectionmanager.h" + +#include "backupelement.h" + +#include "layerbitmap.h" +#include "layercamera.h" +#include "layervector.h" +#include "layersound.h" + +#include "bitmapimage.h" +#include "vectorimage.h" +#include "soundclip.h" +#include "camera.h" + +BackupManager::BackupManager(Editor* editor) : BaseManager(editor, "BackupManager") +{ + qDebug() << "BackupManager: created"; +} + +BackupManager::~BackupManager() +{ + qDebug() << "BackupManager: destroyed"; +} + +bool BackupManager::init() +{ + mUndoStack = new QUndoStack(this); + qDebug() << "BackupManager: init"; + + return true; +} + +Status BackupManager::load(Object* /*o*/) +{ + return Status::OK; +} + +Status BackupManager::save(Object* /*o*/) +{ + return Status::OK; +} + +const BackupElement* BackupManager::currentBackup() +{ + if (mUndoStack->count()) + { + return static_cast(mUndoStack->command(mUndoStack->index()-1)); + } + else + { + return nullptr; + } +} + +void BackupManager::keyAdded(const int& keySpacing, const bool& keyExisted, const QString& description) +{ + if (mLayer == nullptr) { return; } + + AddKeyFrameElement* element = new AddKeyFrameElement(mFrameIndex, + mLayerId, + mEmptyFrameSettingVal, + keySpacing, + keyExisted, + description, + editor()); + mUndoStack->push(element); + + emit updateBackup(); +} + +void BackupManager::keyAdded(const QString& description) +{ + if (mLayer == nullptr) { return; } + + AddKeyFrameElement* element = new AddKeyFrameElement(mFrameIndex, + mLayerId, + mEmptyFrameSettingVal, + false, + false, + description, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::importBitmap(const std::map>& canvasKeys, + const std::map>& importedKeys) +{ + if (mLayer == nullptr) { return; } + if (mLayer->type() != Layer::BITMAP) { return; } + + ImportBitmapElement* element = new ImportBitmapElement(canvasKeys, + importedKeys, + mLayerId, + editor()); + + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::keyRemoved() +{ + if (mLayer == nullptr) { return; } + if (mKeyframe == nullptr) { return; } + + RemoveKeyFrameElement* element = new RemoveKeyFrameElement(mKeyframe, + mLayerId, + editor()); + mUndoStack->push(element); + emit updateBackup(); + +} + +void BackupManager::bitmap(const QString& description) +{ + if (mBitmap == nullptr) { return; } + AddBitmapElement* element = new AddBitmapElement(mBitmap, + mLayerId, + mEmptyFrameSettingVal, + description, + editor()); + + if (mIsSelected) + { + new TransformElement(mKeyframe, + mLayerId, + mEmptyFrameSettingVal, + mSelectionRect, + mTempSelectionRect, + mTransformedSelectionRect, + mSelectionRotationAngle, + mSelectionScaleX, + mSelectionScaleY, + mIsSelected, + mSelectionTransform, + description, + editor(), element); + } + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::vector(const QString& description) +{ + if (mVector == nullptr) { return; } + AddVectorElement* element = new AddVectorElement(mVector, + mLayerId, + mEmptyFrameSettingVal, + description, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::selection() +{ + SelectionElement* element = new SelectionElement(mLayerId, + mFrameIndex, + mVectorSelection, + SelectionType::SELECTION, + mSelectionRect, + mSelectionRotationAngle, + mIsSelected, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::deselect() +{ + SelectionElement* element = new SelectionElement(mLayerId, + mFrameIndex, + mVectorSelection, + SelectionType::DESELECT, + mTransformedSelectionRect, + mSelectionRotationAngle, + mIsSelected, + editor()); + mUndoStack->push(element); + + emit updateBackup(); +} + +void BackupManager::transform(const QString& description) +{ + if (!mIsSelected) { return; } + TransformElement* element = new TransformElement(mKeyframe, + mLayerId, + mEmptyFrameSettingVal, + mSelectionRect, + mTempSelectionRect, + mTransformedSelectionRect, + mSelectionRotationAngle, + mSelectionScaleX, + mSelectionScaleY, + mIsSelected, + mSelectionTransform, + description, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + + +/** + * @brief Get the frame index for the keyframe which is being painted to + * + * @param layer + * @param frameIndex <- current frame + * @param usingPreviousFrameAction <- This is whether DRAW_ON_EMPTY_FRAME_ACTION is active + * @return frameindex + */ +int BackupManager::getActiveFrameIndex(Layer* layer, const int frameIndex, const DrawOnEmptyFrameAction& frameAction) +{ + int activeFrameIndex = frameIndex; + if (!layer->keyExists(frameIndex)) { + if (frameAction == DrawOnEmptyFrameAction::KEEP_DRAWING_ON_PREVIOUS_KEY) + { + activeFrameIndex = layer->getPreviousKeyFramePosition(frameIndex); + } + } + return activeFrameIndex; +} + +void BackupManager::restoreLayerKeys(const BackupElement* backupElement) +{ + + const DeleteLayerElement* lastBackupLayerElem = static_cast(backupElement); + LayerManager* layerMgr = editor()->layers(); + Layer* layer = nullptr; + + int oldFrameIndex = lastBackupLayerElem->oldFrameIndex; + int layerIndex = lastBackupLayerElem->oldLayerIndex; + int layerId = lastBackupLayerElem->oldLayerId; + QString layerName = lastBackupLayerElem->oldLayerName; + + switch(lastBackupLayerElem->oldLayerType) + { + case Layer::BITMAP: + { + layerMgr->createBitmapLayerContainingKeyFrames(lastBackupLayerElem->oldLayerKeys, + layerId, + layerIndex, + layerName); + break; + } + case Layer::VECTOR: + { + + layerMgr->createVectorLayerContainingKeyFrames(lastBackupLayerElem->oldLayerKeys, + layerId, + layerIndex, + layerName); + break; + } + case Layer::SOUND: + { + layer = layerMgr->createSoundLayerAt(layerId, + layerIndex, + layerName); + for (auto map : lastBackupLayerElem->oldLayerKeys) + { + int frameIndex = map.second->pos(); + editor()->sound()->loadSound(layer, frameIndex, map.second->fileName()); + } + break; + } + case Layer::CAMERA: + { + layerMgr->createCameraLayerContainingKeyFrames(lastBackupLayerElem->oldLayerKeys, + layerId, + layerIndex, + layerName); + break; + } + default: + break; + } + editor()->scrubTo(oldFrameIndex); +} + +void BackupManager::restoreKey(const BackupElement* backupElement) +{ + Layer* layer = nullptr; + KeyFrame* keyFrame = nullptr; + int frame = 0; + int layerIndex = 0; + int layerId = 0; + + if (backupElement->type() == ADD_KEY_MODIF) + { + const AddKeyFrameElement* lastBackupElement = static_cast(backupElement); + layerIndex = lastBackupElement->newLayerIndex; + frame = lastBackupElement->newFrameIndex; + layerId = lastBackupElement->newLayerId; + keyFrame = lastBackupElement->newKey; + layer = object()->findLayerById(layerId); + + restoreKey(layerId, frame, keyFrame); + editor()->scrubTo(layerId, frame); + } + else // REMOVE_KEY_MODIF + { + const RemoveKeyFrameElement* lastBackupElement = static_cast(backupElement); + layerIndex = lastBackupElement->oldLayerIndex; + frame = lastBackupElement->oldFrameIndex; + layerId = lastBackupElement->oldLayerId; + keyFrame = lastBackupElement->oldKey; + layer = editor()->layers()->findLayerById(layerId); + + restoreKey(layerId, frame, keyFrame); + editor()->scrubTo(layerId, frame); + } +} + +void BackupManager::restoreKey(const int& layerId, const int& frame, KeyFrame *keyFrame) +{ + Layer* layer = editor()->layers()->findLayerById(layerId); + + if (!layer->keyExists(frame)) + { + editor()->addKeyFrameToLayerId(layerId, frame, true); + } + + switch(layer->type()) + { + case Layer::BITMAP: + { + static_cast(layer)->putBitmapIntoFrame(keyFrame, frame); + break; + } + case Layer::VECTOR: + { + static_cast(layer)->putVectorImageIntoFrame(keyFrame, frame); + break; + } + case Layer::SOUND: + { + editor()->sound()->loadSound(layer, frame, keyFrame->fileName()); + break; + } + case Layer::CAMERA: + { + static_cast(layer)->putCameraIntoFrame(keyFrame, frame); + break; + } + default: + break; + } + editor()->updateView(); +} + +void BackupManager::cameraMotion(const QString& description) +{ + if (mLayer == nullptr) { return; } + + CameraMotionElement* element = new CameraMotionElement(mFrameIndex, + mLayerId, + mTranslation, + mRotation, + mScale, + description, + editor()); + mUndoStack->push(element); + + emit updateBackup(); +} + +void BackupManager::layerAdded() +{ + AddLayerElement* element = new AddLayerElement(mLayer, editor()); + mUndoStack->push(element); + + emit updateBackup(); +} + +void BackupManager::layerDeleted(const std::map >& oldKeys) +{ + + DeleteLayerElement* element = new DeleteLayerElement(mLayerName, + mLayerType, + oldKeys, + mFrameIndex, + mLayerIndex, + mLayerId, + editor()); + mUndoStack->push(element); + + emit updateBackup(); +} + +void BackupManager::layerRenamed() +{ + RenameLayerElement* element = new RenameLayerElement(mLayerName, + mLayerId, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::cameraProperties(const QRect& backupViewRect) +{ + CameraPropertiesElement* element = new CameraPropertiesElement(mLayerName, + backupViewRect, + mLayerId, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::frameDeselected(const int frameIndex) +{ + frameDeselected(QList({frameIndex}), frameIndex); +} + +void BackupManager::frameDeselected(const QList newDeselectedIndexes, const int frameIndex) +{ + +// SelectFramesElement* element = new SelectFramesElement(SelectionType::DESELECT, +// mLayerId, +// frameIndex, +// mFrameIndexes, +// newDeselectedIndexes, +// false, +// editor()); + +// mUndoStack->push(element); +// emit updateBackup(); +} + +void BackupManager::frameSelected(const QList newSelectedIndexes, const int frameIndex, const bool isSelected) +{ + +// SelectFramesElement* element = new SelectFramesElement(SelectionType::SELECTION, +// mLayerId, +// frameIndex, +// mFrameIndexes, +// newSelectedIndexes, +// isSelected, +// editor()); + +// mUndoStack->push(element); +// emit updateBackup(); +} + +void BackupManager::frameMoved(const int offset) +{ + MoveFramesElement* element = new MoveFramesElement(mLayerId, + mFrameIndex, + offset, + false, + QList(), + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::framesMoved(const int offset, + const int scrubberFrameIndex) +{ + MoveFramesElement* element = new MoveFramesElement(mLayerId, + scrubberFrameIndex, + offset, + true, + mFrameIndexes, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::flipView(const bool& backupIsFlipped, const Direction& backupFlipDirection) +{ + FlipViewElement* element = new FlipViewElement(backupIsFlipped, + backupFlipDirection, + editor()); + + mUndoStack->push(element); + emit updateBackup(); +} + +void BackupManager::toggleSetting(bool /*backupToggleState*/, const SETTING& /*backupType*/) +{ +// ToggleSettingElement* element = new ToggleSettingElement(backupToggleState, +// backupType, +// editor()); + +// mUndoStack->push(element); +// emit updateBackup(); +} + +void BackupManager::layerMoved(const int& backupNewLayerIndex) +{ + MoveLayerElement* element = new MoveLayerElement(mLayerIndex, + backupNewLayerIndex, + editor()); + mUndoStack->push(element); + emit updateBackup(); +} + +/** + * @brief BackupManager::saveStates + * This method should be called prior to a backup taking place. + */ +void BackupManager::saveStates() +{ + mBitmap = nullptr; + mVector = nullptr; + mCamera = nullptr; + mClip = nullptr; + mKeyframe = nullptr; + + mLayer = editor()->layers()->currentLayer(); + mLayerId = mLayer->id(); + + mEmptyFrameSettingVal = static_cast(editor()->preference()->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION)); + + mFrameIndex = editor()->currentFrame(); + mFrameIndex = BackupManager::getActiveFrameIndex(mLayer, mFrameIndex, mEmptyFrameSettingVal); + + auto selectMan = editor()->select(); + mIsSelected = selectMan->somethingSelected(); + mSelectionRect = selectMan->mySelectionRect(); + mTempSelectionRect = selectMan->myTempTransformedSelectionRect(); + mTransformedSelectionRect = selectMan->myTransformedSelectionRect(); + mSelectionRotationAngle = selectMan->myRotation(); + mMoveOffset = selectMan->getTransformOffset(); + mSelectionTransform = selectMan->selectionTransform(); + mSelectionScaleX = selectMan->myScaleX(); + mSelectionScaleY = selectMan->myScaleY(); + mMoveMode = selectMan->getMoveMode(); + mVectorSelection = selectMan->vectorSelection; + + mFrameIndexes = mLayer->getSelectedFramesByPos(); + + mLayerName = mLayer->name(); + mLayerIndex = editor()->currentLayerIndex(); + mLayerType = mLayer->type(); + + ViewManager* viewMgr = editor()->view(); + mTranslation = viewMgr->translation(); + mScale = viewMgr->scaling(); + mRotation = viewMgr->rotation(); + + if (mLayer->keyExists(mFrameIndex)) + { + mKeyframe = mLayer->getLastKeyFrameAtPosition(mFrameIndex)->clone(); + } + else if (mLayer->getKeyFrameWhichCovers(mFrameIndex) != nullptr) + { + mKeyframe = mLayer->getKeyFrameWhichCovers(mFrameIndex)->clone(); + } + + switch(mLayer->type()) + { + case Layer::BITMAP: + { + mBitmap = static_cast(mKeyframe); + break; + } + case Layer::VECTOR: + { + mVector = static_cast(mKeyframe); + break; + } + case Layer::SOUND: + { + mClip = static_cast(mKeyframe); + break; + } + case Layer::CAMERA: + { + mCamera = static_cast(mKeyframe); + break; + } + default: + break; + } +} diff --git a/core_lib/src/managers/backupmanager.h b/core_lib/src/managers/backupmanager.h new file mode 100644 index 0000000000..bf58d7ba08 --- /dev/null +++ b/core_lib/src/managers/backupmanager.h @@ -0,0 +1,123 @@ +#ifndef BACKUPMANAGER_H +#define BACKUPMANAGER_H + +#include +#include +#include "basemanager.h" +#include "preferencemanager.h" +#include "layer.h" +#include "direction.h" +#include "movemode.h" +#include "vectorselection.h" + +class BitmapImage; +class VectorImage; +class Camera; +class SoundClip; +class KeyFrame; +class BackupElement; + +class BackupManager : public BaseManager +{ + Q_OBJECT + + friend class RemoveKeyFrameElement; + friend class AddKeyFrameElement; + friend class DeleteLayerElement; + +public: + explicit BackupManager(Editor* editor); + ~BackupManager(); + + bool init() override; + Status load(Object*) override; + Status save(Object*) override; + + void keyAdded(const int& keySpacing, const bool& keyExisted, const QString& description); + void keyAdded(const QString& description = ""); + void keyRemoved(); + void bitmap(const QString& description); + void vector(const QString& description); + void cameraMotion(const QString& description = ""); + void layerAdded(); + void layerDeleted(const std::map>& oldKeys); + void layerRenamed(); + void layerMoved(const int& backupNewLayerIndex); + + void importBitmap(const std::map>& canvasKeys, + const std::map>& importedKeys); + void selection(); + void deselect(); + void transform(const QString& description); + void cameraProperties(const QRect& backupViewRect); + void frameMoved(const int offset); + void framesMoved(const int offset, + const int scrubberFrameIndex); + + void frameSelected(const QList newSelectedIndexes, const int frameIndex, const bool isSelected); + void frameDeselected(const QList newDeselectedIndexes, const int frameIndex); + void frameDeselected(const int frameIndex); + void flipView(const bool& backupIsFlipped, const Direction& backupFlipDirection); + void toggleSetting(bool backupToggleState, const SETTING& backupType); + void saveStates(); + + void restoreKey(const int& layerId, const int& frame, KeyFrame* keyFrame); + + static int getActiveFrameIndex(Layer* layer, const int frameIndex, const DrawOnEmptyFrameAction& frameAction); + + const BackupElement* currentBackup(); + + QUndoStack* undoStack() { return mUndoStack; } + +Q_SIGNALS: + void updateBackup(); + +private: + void restoreKey(const BackupElement* element); + void restoreLayerKeys(const BackupElement* element); + + QUndoStack* mUndoStack; + + int mLayerId = 0; + int mFrameIndex = 0; + int mLayerIndex = 0; + + float mRotation = 0; + float mScale = 0; + + QString mLayerName; + + Layer* mLayer = nullptr; + BitmapImage* mBitmap = nullptr; + VectorImage* mVector = nullptr; + SoundClip* mClip = nullptr; + Camera* mCamera = nullptr; + KeyFrame* mKeyframe = nullptr; + + QList mFrameIndexes; + + bool mIsSelected = false; + + QRectF mSelectionRect = QRectF(); + QRectF mTempSelectionRect = QRectF(); + QRectF mTransformedSelectionRect = QRectF(); + + VectorSelection mVectorSelection; + + qreal mSelectionRotationAngle = 0.0; + qreal mSelectionScaleX = 0.0; + qreal mSelectionScaleY = 0.0; + + QPointF mTranslation = QPointF(0,0); + QPointF mMoveOffset = QPointF(0,0); + QTransform mSelectionTransform; + + MoveMode mMoveMode; + + Layer::LAYER_TYPE mLayerType; + + DrawOnEmptyFrameAction mEmptyFrameSettingVal; + +}; + +#endif // BACKUPMANAGER_H diff --git a/core_lib/src/managers/canvasmanager.cpp b/core_lib/src/managers/canvasmanager.cpp new file mode 100644 index 0000000000..1f7288a865 --- /dev/null +++ b/core_lib/src/managers/canvasmanager.cpp @@ -0,0 +1,96 @@ +#include "canvasmanager.h" + +#include "layer.h" + +#include "bitmapimage.h" +#include "vectorimage.h" +#include "canvaspainter.h" + +CanvasManager::CanvasManager(Editor* editor) : BaseManager(editor, "CanvasManager"), mEditor(editor) +{ + mCanvasPainter = new CanvasPainter(); +} + +CanvasManager::~CanvasManager() +{ + // TODO: cleanup stuff.. +} + +bool CanvasManager::init() +{ + return true; +} + +Status CanvasManager::load(Object* o) +{ + Q_UNUSED(o); + return Status::OK; +} + +Status CanvasManager::save(Object* o) +{ + Q_UNUSED(o); + return Status::OK; +} + +void CanvasManager::paintTransformedSelection(Layer* layer, KeyFrame* keyframe, + const QTransform& selectionTransform, + const QRectF& selectionRect) +{ + if (layer->type() == Layer::BITMAP) + { + mCanvasPainter->setTransformedSelection(selectionRect.toRect(), selectionTransform); + } + else if (layer->type() == Layer::VECTOR) + { + // vector transformation + VectorImage* vectorImage = static_cast(keyframe); + vectorImage->setSelectionTransformation(selectionTransform); + } + + emit needPaint(); +} + +void CanvasManager::applyTransformedSelection(Layer* layer, + KeyFrame* keyframe, + const QTransform& selectionTransform, + const QRectF& selectionRect) +{ + mCanvasPainter->ignoreTransformedSelection(); + + if (selectionRect.isEmpty()) { return; } + + if (layer->type() == Layer::BITMAP) + { + QRect selectionRectAligned = selectionRect.toRect(); + BitmapImage* bitmapImage = static_cast(keyframe); + BitmapImage transformedImage = bitmapImage->transformed(selectionRectAligned, selectionTransform, true); + + bitmapImage->clear(selectionRectAligned); + bitmapImage->paste(&transformedImage, QPainter::CompositionMode_SourceOver); + } + else if (layer->type() == Layer::VECTOR) + { + VectorImage* vectorImage = static_cast(keyframe); + vectorImage->applySelectionTransformation(); + + } + + emit needPaint(); +} + +void CanvasManager::ignoreTransformedSelection() +{ + mCanvasPainter->ignoreTransformedSelection(); +} + +void CanvasManager::cancelTransformedSelection(Layer* layer, KeyFrame* keyframe) +{ + if (layer == nullptr) { return; } + + if (layer->type() == Layer::VECTOR) { + + VectorImage* vectorImage = static_cast(keyframe); + vectorImage->setSelectionTransformation(QTransform()); + } +} diff --git a/core_lib/src/managers/canvasmanager.h b/core_lib/src/managers/canvasmanager.h new file mode 100644 index 0000000000..3026fabcc5 --- /dev/null +++ b/core_lib/src/managers/canvasmanager.h @@ -0,0 +1,45 @@ +#ifndef CANVASMANAGER_H +#define CANVASMANAGER_H + +#include "basemanager.h" + +class Layer; +class KeyFrame; +class CanvasPainter; + +class CanvasManager : public BaseManager +{ + Q_OBJECT +public: + explicit CanvasManager(Editor* editor); + ~CanvasManager() override; + + bool init() override; + Status load(Object* o) override; + Status save(Object* o) override; + + void paintTransformedSelection(Layer* layer, + KeyFrame* keyframe, + const QTransform& selectionTransform, + const QRectF& selectionRect); + void applyTransformedSelection(Layer* layer, + KeyFrame* keyframe, + const QTransform& selectionTransform, + const QRectF& selectionRect); + + void cancelTransformedSelection(Layer* layer, + KeyFrame* keyframe); + + void ignoreTransformedSelection(); + + CanvasPainter* canvasPainter() { return mCanvasPainter; } + +signals: + void needPaint(); + +private: + Editor* mEditor = nullptr; + CanvasPainter* mCanvasPainter = nullptr; +}; + +#endif // CANVASMANAGER_H diff --git a/core_lib/src/managers/layermanager.cpp b/core_lib/src/managers/layermanager.cpp index ecda2d0114..9a4370f857 100644 --- a/core_lib/src/managers/layermanager.cpp +++ b/core_lib/src/managers/layermanager.cpp @@ -95,6 +95,11 @@ Layer* LayerManager::findLayerByName(QString sName, Layer::LAYER_TYPE type) return object()->findLayerByName(sName, type); } +Layer* LayerManager::findLayerById(int layerId) +{ + return object()->findLayerById(layerId); +} + int LayerManager::currentLayerIndex() { return editor()->currentLayerIndex(); @@ -131,6 +136,11 @@ void LayerManager::setCurrentLayer(int layerIndex) } } +void LayerManager::setCurrentLayerFromId(int layerId) +{ + setCurrentLayer(findLayerById(layerId)); +} + void LayerManager::setCurrentLayer(Layer* layer) { setCurrentLayer(getIndex(layer)); @@ -211,6 +221,127 @@ Layer* LayerManager::createLayer(Layer::LAYER_TYPE type, const QString& strLayer return layer; } +void LayerManager::createBitmapLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + KeyFrame* keyframe = nullptr; + LayerBitmap* layer = createBitmapLayerAt(layerId, layerIndex, strLayerName); + for(auto& map : keyFrames) + { + keyframe = map.second; + int frameIndex = keyframe->pos(); + + editor()->addKeyFrameToLayerId(layerId, frameIndex, true); + layer->putBitmapIntoFrame(keyframe, frameIndex); + } +} + +void LayerManager::createVectorLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + KeyFrame* keyframe = nullptr; + LayerVector* layer = createVectorLayerAt(layerId, layerIndex, strLayerName); + for(auto& map : keyFrames) + { + keyframe = map.second; + int frameIndex = keyframe->pos(); + + editor()->addKeyFrameToLayerId(layerId, frameIndex, true); + layer->putVectorImageIntoFrame(keyframe, frameIndex); + } +} + +void LayerManager::createCameraLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + LayerCamera* layer = createCameraLayerAt(layerId, layerIndex, strLayerName); + + KeyFrame* keyframe = nullptr; + for (auto map : keyFrames) + { + keyframe = map.second; + int frameIndex = map.second->pos(); + editor()->addKeyFrameToLayerId(layerId, frameIndex, true); + layer->putCameraIntoFrame(keyframe, frameIndex); + } +} + +LayerBitmap* LayerManager::createBitmapLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + LayerBitmap* newLayer = object()->addBitmapLayerAt(layerId, layerIndex); + newLayer->setName( strLayerName ); + + Q_EMIT layerCountChanged(count()); + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + +LayerVector* LayerManager::createVectorLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + LayerVector* newLayer = object()->addVectorLayerAt(layerId, layerIndex); + newLayer->setName( strLayerName ); + + Q_EMIT layerCountChanged(count()); + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + +LayerSound* LayerManager::createSoundLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + LayerSound* newLayer = object()->addSoundLayerAt(layerId, layerIndex); + newLayer->setName( strLayerName ); + + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + +LayerCamera* LayerManager::createCameraLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + LayerCamera* newLayer = object()->addCameraLayerAt(layerId, layerIndex); + newLayer->setName( strLayerName ); + + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + LayerBitmap* LayerManager::createBitmapLayer(const QString& strLayerName) { LayerBitmap* layer = object()->addNewBitmapLayer(); @@ -342,6 +473,31 @@ Status LayerManager::deleteLayer(int index) return Status::OK; } +Status LayerManager::deleteLayerWithId(int layerId) +{ + Layer* layer = object()->findLayerById(layerId); + if (layer == nullptr) return Status::SAFE; + Layer::LAYER_TYPE layerType = layer->type(); + + if (layerType == Layer::CAMERA) + { + std::vector camLayers = object()->getLayersByType(); + if ( camLayers.size() == 1 ) + return Status::ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER; + } + + object()->deleteLayerWithId(layerId); + + if (currentLayerIndex() > editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(editor()->object()->getLastLayerIndex()); + } + + Q_EMIT layerCountChanged( count() ); + + return Status::OK; +} + Status LayerManager::renameLayer(Layer* layer, const QString& newName) { if (newName.isEmpty()) return Status::FAIL; @@ -399,7 +555,7 @@ void LayerManager::notifyAnimationLengthChanged() emit animationLengthChanged(animationLength(true)); } -int LayerManager::getIndex(Layer* layer) const +int LayerManager::getIndex(const Layer* layer) const { const Object* o = object(); for (int i = 0; i < o->getLayerCount(); ++i) diff --git a/core_lib/src/managers/layermanager.h b/core_lib/src/managers/layermanager.h index 62c4bad981..a723f350c9 100644 --- a/core_lib/src/managers/layermanager.h +++ b/core_lib/src/managers/layermanager.h @@ -43,12 +43,23 @@ class LayerManager : public BaseManager Layer* currentLayer(int offset); Layer* getLayer(int index); Layer* findLayerByName(QString sName, Layer::LAYER_TYPE type = Layer::UNDEFINED); + Layer* findLayerById(int layerId); Layer* getLastCameraLayer(); int currentLayerIndex(); + int getLayerIndex(const Layer* layer) const { return getIndex(layer); } void setCurrentLayer(int nIndex); void setCurrentLayer(Layer* layer); + void setCurrentLayerFromId(int layerId); int count(); + /** + * @brief LayerManager::deleteLayerWithId + * Delete a layer with a given id. This is fitting when you want to + * delete a layer which does not depend on a position. + * @param layerId + * @return Status + */ + Status deleteLayerWithId(int layerId); Status deleteLayer(int index); Status renameLayer(Layer*, const QString& newName); void notifyLayerChanged(Layer*); @@ -58,11 +69,46 @@ class LayerManager : public BaseManager /** Returns a new Layer with the given LAYER_TYPE */ Layer* createLayer(Layer::LAYER_TYPE type, const QString& strLayerName); + + void createBitmapLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName); + void createVectorLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName); + void createCameraLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName); + + void createSoundLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName); + LayerBitmap* createBitmapLayer(const QString& strLayerName); LayerVector* createVectorLayer(const QString& strLayerName); LayerCamera* createCameraLayer(const QString& strLayerName); LayerSound* createSoundLayer(const QString& strLayerName); + LayerBitmap* createBitmapLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName); + + LayerVector* createVectorLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName); + + LayerCamera* createCameraLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName); + + LayerSound* createSoundLayerAt(const int layerId, + const int layerIndex, + const QString& strLayerName); + // KeyFrame Management int lastFrameAtFrame(int frameIndex); int firstKeyFrameIndex(); @@ -83,7 +129,7 @@ class LayerManager : public BaseManager void layerDeleted(int index); private: - int getIndex(Layer*) const; + int getIndex(const Layer *) const; int mLastCameraLayerIdx = 0; }; diff --git a/core_lib/src/managers/selectionmanager.h b/core_lib/src/managers/selectionmanager.h index 216ae74022..021829d22b 100644 --- a/core_lib/src/managers/selectionmanager.h +++ b/core_lib/src/managers/selectionmanager.h @@ -101,13 +101,17 @@ class SelectionManager : public BaseManager QPolygonF lastSelectionPolygonF() const { return mLastSelectionPolygonF; } void setSomethingSelected(bool selected) { mSomethingSelected = selected; } + void setScale(const qreal scaleX, const qreal scaleY) { mScaleX = scaleX; mScaleY = scaleY; } VectorSelection vectorSelection; const QRectF& mySelectionRect() { return mSelection; } const QRectF& myTempTransformedSelectionRect() { return mTempTransformedSelection; } const QRectF& myTransformedSelectionRect() { return mTransformedSelection; } - const qreal& myRotation() { return mRotatedAngle; } + + qreal myRotation() const { return mRotatedAngle; } + qreal myScaleX() const { return mScaleX; } + qreal myScaleY() const { return mScaleY; } void setSelectionRect(const QRectF& rect) { mSelection = rect; } void setTempTransformedSelectionRect(const QRectF& rect) { mTempTransformedSelection = rect; } @@ -127,6 +131,8 @@ class SelectionManager : public BaseManager QRectF mTempTransformedSelection; QRectF mTransformedSelection; qreal mRotatedAngle = 0.0; + qreal mScaleX = .0; + qreal mScaleY = .0; bool mSomethingSelected = false; QPolygonF mLastSelectionPolygonF; diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index b3163d54b0..ce7da57201 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -387,6 +387,14 @@ bool Layer::isFrameSelected(int position) const return frameFound; } +void Layer::setFramesSelected(QList frameIndexes, const bool selected) +{ + for (int frame : frameIndexes) + { + setFrameSelected(frame, selected); + } +} + void Layer::setFrameSelected(int position, bool isSelected) { KeyFrame* keyFrame = getKeyFrameWhichCovers(position); diff --git a/core_lib/src/structure/layer.h b/core_lib/src/structure/layer.h index cc8f217c99..d7cb014eb4 100644 --- a/core_lib/src/structure/layer.h +++ b/core_lib/src/structure/layer.h @@ -115,6 +115,8 @@ class Layer : public QObject // Handle selection bool isFrameSelected(int position) const; + + void setFramesSelected(QList frameIndexes, const bool selected); void setFrameSelected(int position, bool isSelected); void toggleFrameSelected(int position, bool allowMultiple = false); void extendSelectionTo(int position); diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index e81e244770..e38a6ce58e 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -28,6 +28,14 @@ LayerBitmap::LayerBitmap(Object* object) : Layer(object, Layer::BITMAP) setName(tr("Bitmap Layer")); } +/** Add a new layer with a given id + * This should only be used to restore a layer with id + */ +LayerBitmap::LayerBitmap(int id, Object* object) : LayerBitmap(object) +{ + setId(id); +} + LayerBitmap::~LayerBitmap() { } @@ -65,6 +73,19 @@ void LayerBitmap::loadImageAtFrame(QString path, QPoint topLeft, int frameNumber loadKey(pKeyFrame); } +void LayerBitmap::replaceLastBitmapAtFrame(const BitmapImage* replaceWithImage) +{ + *static_cast(getLastKeyFrameAtPosition(replaceWithImage->pos())) = *replaceWithImage; +} + +void LayerBitmap::putBitmapIntoFrame(KeyFrame* keyframe, const int& frameIndex) +{ + BitmapImage* currentBitmap = getBitmapImageAtFrame(frameIndex); + + BitmapImage newBitmap = *static_cast(keyframe); + static_cast(currentBitmap)->paste(&newBitmap); +} + Status LayerBitmap::saveKeyFrameFile(KeyFrame* keyframe, QString path) { QString strFilePath = filePath(keyframe, QDir(path)); diff --git a/core_lib/src/structure/layerbitmap.h b/core_lib/src/structure/layerbitmap.h index 4865dd64a2..dbe0cf5101 100644 --- a/core_lib/src/structure/layerbitmap.h +++ b/core_lib/src/structure/layerbitmap.h @@ -27,6 +27,7 @@ class LayerBitmap : public Layer Q_OBJECT public: + LayerBitmap(int id, Object* object); LayerBitmap(Object* object); ~LayerBitmap() override; @@ -36,6 +37,8 @@ class LayerBitmap : public Layer BitmapImage* getBitmapImageAtFrame(int frameNumber); BitmapImage* getLastBitmapImageAtFrame(int frameNumber, int increment = 0); + void replaceLastBitmapAtFrame(const BitmapImage* replaceWithImage); + void putBitmapIntoFrame(KeyFrame* keyframe, const int& frameIndex); void repositionFrame(QPoint point, int frame); QRect getFrameBounds(int frame); diff --git a/core_lib/src/structure/layercamera.cpp b/core_lib/src/structure/layercamera.cpp index 2d4712ed69..f7ae548535 100644 --- a/core_lib/src/structure/layercamera.cpp +++ b/core_lib/src/structure/layercamera.cpp @@ -39,6 +39,14 @@ LayerCamera::LayerCamera(Object* object) : Layer(object, Layer::CAMERA) viewRect = QRect(QPoint(-mFieldW / 2, -mFieldH / 2), QSize(mFieldW, mFieldH)); } +/** Add a new layer with a given id + * This should only be used to restore a layer with id + */ +LayerCamera::LayerCamera(int layerId, Object* object) : LayerCamera(object) +{ + setId(layerId); +} + LayerCamera::~LayerCamera() { } @@ -53,6 +61,13 @@ Camera* LayerCamera::getLastCameraAtFrame(int frameNumber, int increment) return static_cast(getLastKeyFrameAtPosition(frameNumber + increment)); } +void LayerCamera::putCameraIntoFrame(KeyFrame *keyframe, int frameIndex) +{ + Camera* oldCamera = static_cast(keyframe); + getCameraAtFrame(frameIndex)->assign(*oldCamera); +} + + QTransform LayerCamera::getViewAtFrame(int frameNumber) const { if (keyFrameCount() == 0) diff --git a/core_lib/src/structure/layercamera.h b/core_lib/src/structure/layercamera.h index 9877ea36bb..0568e8ee88 100644 --- a/core_lib/src/structure/layercamera.h +++ b/core_lib/src/structure/layercamera.h @@ -27,6 +27,7 @@ class LayerCamera : public Layer { public: explicit LayerCamera(Object* object); + explicit LayerCamera(int layerId, Object* object); ~LayerCamera() override; void loadImageAtFrame(int frame, qreal dx, qreal dy, qreal rotate, qreal scale, CameraEasingType type); @@ -34,6 +35,8 @@ class LayerCamera : public Layer QDomElement createDomElement(QDomDocument& doc) const override; void loadDomElement(const QDomElement& element, QString dataDirPath, ProgressCallback progressStep) override; + void putCameraIntoFrame(KeyFrame *keyframe, int frameIndex); + Camera* getCameraAtFrame(int frameNumber); Camera* getLastCameraAtFrame(int frameNumber, int increment); QTransform getViewAtFrame(int frameNumber) const; diff --git a/core_lib/src/structure/layersound.cpp b/core_lib/src/structure/layersound.cpp index 83b46bc502..f01174186a 100644 --- a/core_lib/src/structure/layersound.cpp +++ b/core_lib/src/structure/layersound.cpp @@ -29,6 +29,14 @@ LayerSound::LayerSound(Object* object) : Layer(object, Layer::SOUND) setName(tr("Sound Layer")); } +/** Add a new layer with a given id + * This should only be used to restore a layer with id + */ +LayerSound::LayerSound(int layerId, Object* object) : LayerSound(object) +{ + setId(layerId); +} + LayerSound::~LayerSound() { } diff --git a/core_lib/src/structure/layersound.h b/core_lib/src/structure/layersound.h index 718c6fc383..fbf720b7f9 100644 --- a/core_lib/src/structure/layersound.h +++ b/core_lib/src/structure/layersound.h @@ -27,7 +27,8 @@ class LayerSound : public Layer Q_OBJECT public: - LayerSound( Object* object ); + LayerSound(Object* object); + LayerSound(int id, Object* object); ~LayerSound(); QDomElement createDomElement(QDomDocument& doc) const override; void loadDomElement(const QDomElement& element, QString dataDirPath, ProgressCallback progressStep) override; diff --git a/core_lib/src/structure/layervector.cpp b/core_lib/src/structure/layervector.cpp index 57ea14443c..b014c14291 100644 --- a/core_lib/src/structure/layervector.cpp +++ b/core_lib/src/structure/layervector.cpp @@ -27,6 +27,14 @@ LayerVector::LayerVector(Object* object) : Layer(object, Layer::VECTOR) setName(tr("Vector Layer")); } +/** Add a new layer with a given id + * This should only be used to restore a layer with id + */ +LayerVector::LayerVector(int layerId, Object* object) : LayerVector(object) +{ + setId(layerId); +} + LayerVector::~LayerVector() { } @@ -196,3 +204,16 @@ VectorImage* LayerVector::getLastVectorImageAtFrame(int frameNumber, int increme { return static_cast(getLastKeyFrameAtPosition(frameNumber + increment)); } + +void LayerVector::replaceLastVectorAtFrame(const VectorImage *replaceWithVector) +{ + *static_cast(getLastKeyFrameAtPosition(replaceWithVector->pos())) = *replaceWithVector; +} + +void LayerVector::putVectorImageIntoFrame(KeyFrame *keyframe, const int frameIndex) +{ + VectorImage* currentVectorImg = getVectorImageAtFrame(frameIndex); + + VectorImage newVectorImg = *static_cast(keyframe); + static_cast(currentVectorImg)->paste(newVectorImg); +} diff --git a/core_lib/src/structure/layervector.h b/core_lib/src/structure/layervector.h index 563a1800b9..c1a92f6342 100644 --- a/core_lib/src/structure/layervector.h +++ b/core_lib/src/structure/layervector.h @@ -28,6 +28,7 @@ class LayerVector : public Layer public: LayerVector(Object* object); + LayerVector(int id, Object* object); ~LayerVector(); // method from layerImage @@ -38,6 +39,8 @@ class LayerVector : public Layer VectorImage* getVectorImageAtFrame(int frameNumber) const; VectorImage* getLastVectorImageAtFrame(int frameNumber, int increment) const; + void replaceLastVectorAtFrame(const VectorImage *replaceWithVector); + void putVectorImageIntoFrame(KeyFrame *keyframe, const int frameIndex); bool usesColor(int index); void removeColor(int index); diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 3e84df91b1..86c1e774f6 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -116,6 +116,41 @@ bool Object::loadXML(const QDomElement& docElem, ProgressCallback progressForwar return true; } +LayerBitmap* Object::addBitmapLayerAt(const int layerId, const int layerIndex) +{ + LayerBitmap* layerBitmap = new LayerBitmap(layerId, this); + mLayers.insert(layerIndex, layerBitmap); + + layerBitmap->addNewKeyFrameAt(1); + return layerBitmap; +} + +LayerVector* Object::addVectorLayerAt(const int layerId, const int layerIndex) +{ + LayerVector* layerVector = new LayerVector(layerId, this); + mLayers.insert(layerIndex, layerVector); + + layerVector->addNewKeyFrameAt(1); + return layerVector; +} + +LayerSound* Object::addSoundLayerAt(const int layerId, const int layerIndex) +{ + LayerSound* layerSound = new LayerSound(layerId, this); + mLayers.insert(layerIndex, layerSound); + + return layerSound; +} + +LayerCamera* Object::addCameraLayerAt(const int layerId, const int layerIndex) +{ + LayerCamera* layerCamera = new LayerCamera(layerId, this); + mLayers.insert(layerIndex, layerCamera); + + layerCamera->addNewKeyFrameAt(1); + return layerCamera; +} + LayerBitmap* Object::addNewBitmapLayer() { LayerBitmap* layerBitmap = new LayerBitmap(this); @@ -234,6 +269,11 @@ Layer* Object::getLayer(int i) const return mLayers.at(i); } +int Object::getLastLayerIndex() const +{ + return mLayers.indexOf(mLayers.last()); // begin is the highest layer position +} + Layer* Object::findLayerById(int layerId) const { for(Layer* layer : mLayers) @@ -310,6 +350,18 @@ void Object::deleteLayer(int i) } } +void Object::deleteLayerWithId(int layerId) +{ + for (int index = 0; index < mLayers.size(); index++) + { + if (mLayers.at(index)->id() == layerId) + { + delete mLayers.takeAt(index); + break; + } + } +} + void Object::deleteLayer(Layer* layer) { auto it = std::find(mLayers.begin(), mLayers.end(), layer); diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index 9c7c8e1e61..49adbf55a1 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -103,7 +103,13 @@ class Object final LayerSound* addNewSoundLayer(); LayerCamera* addNewCameraLayer(); + LayerBitmap* addBitmapLayerAt(const int layerId, const int layerIndex); + LayerVector* addVectorLayerAt(const int layerId, const int layerIndex); + LayerSound* addSoundLayerAt(const int layerId, const int layerIndex); + LayerCamera* addCameraLayerAt(const int layerId, const int layerIndex); + int getLayerCount() const; + int getLastLayerIndex() const; Layer* getLayer(int i) const; Layer* findLayerByName(const QString& strName, Layer::LAYER_TYPE type = Layer::UNDEFINED) const; Layer* findLayerById(int layerId) const; @@ -112,6 +118,7 @@ class Object final bool swapLayers(int i, int j); void deleteLayer(int i); void deleteLayer(Layer*); + void deleteLayerWithId(int layerId); bool addLayer(Layer* layer); template diff --git a/core_lib/src/util/direction.h b/core_lib/src/util/direction.h new file mode 100644 index 0000000000..1ee449cdb9 --- /dev/null +++ b/core_lib/src/util/direction.h @@ -0,0 +1,25 @@ + +/* +Pencil - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2018 Matthew Chiawen Chang +Copyright (C) 2018 Oliver Stevns Larsen +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#ifndef DIRECTION_H +#define DIRECTION_H + +enum class Direction +{ + HORIZONTAL, + VERTICAL +}; + +#endif // DIRECTION_H diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index a463c301d1..9fcfe667ec 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -79,6 +79,11 @@ enum StabilizationLevel STRONG }; +enum SelectionType { + SELECTION, + DESELECT +}; + enum TimecodeTextLevel { NOTEXT,