diff --git a/app/src/actioncommands.cpp b/app/src/actioncommands.cpp index da25a05b9e..d899ff6e3f 100644 --- a/app/src/actioncommands.cpp +++ b/app/src/actioncommands.cpp @@ -32,6 +32,7 @@ GNU General Public License for more details. #include "soundmanager.h" #include "playbackmanager.h" #include "preferencemanager.h" +#include "backupmanager.h" #include "selectionmanager.h" #include "util.h" #include "app_util.h" @@ -85,10 +86,12 @@ Status ActionCommands::importSound() QString strLayerName = QInputDialog::getText(mParent, tr("Layer Properties", "Dialog title on creating a sound layer"), tr("Layer name:"), QLineEdit::Normal, tr("Sound Layer", "Default name on creating a sound layer"), &ok); + mEditor->backups()->saveStates(); if (ok && !strLayerName.isEmpty()) { Layer* newLayer = mEditor->layers()->createSoundLayer(strLayerName); mEditor->layers()->setCurrentLayer(newLayer); + mEditor->backups()->layerAdded(); } else { @@ -120,6 +123,7 @@ Status ActionCommands::importSound() layer->addKeyFrame(currentFrame, key); } + mEditor->backups()->saveStates(); FileDialog fileDialog(mParent); QString strSoundFile = fileDialog.openFile(FileType::SOUND); @@ -129,6 +133,7 @@ Status ActionCommands::importSound() } Status st = mEditor->sound()->loadSound(key, strSoundFile); + mEditor->backups()->keyAdded(); if (!st.ok()) { @@ -155,7 +160,7 @@ Status ActionCommands::exportMovie(bool isGif) OnScopeExit(dialog->deleteLater()); dialog->init(); - + std::vector< std::pair > camerasInfo; auto cameraLayers = mEditor->object()->getLayersByType< LayerCamera >(); for (LayerCamera* i : cameraLayers) @@ -185,7 +190,7 @@ Status ActionCommands::exportMovie(bool isGif) dialog->setDefaultRange(1, length, lengthWithSounds); dialog->exec(); - + if (dialog->result() == QDialog::Rejected) { return Status::SAFE; @@ -269,7 +274,7 @@ Status ActionCommands::exportImageSequence() { auto dialog = new ExportImageDialog(mParent, FileType::IMAGE_SEQUENCE); OnScopeExit(dialog->deleteLater()); - + dialog->init(); std::vector< std::pair > camerasInfo; @@ -410,58 +415,128 @@ Status ActionCommands::exportImage() void ActionCommands::flipSelectionX() { + mEditor->backups()->saveStates(); bool flipVertical = false; mEditor->flipSelection(flipVertical); + mEditor->backups()->transform(tr("Flip Selection X")); } void ActionCommands::flipSelectionY() { + mEditor->backups()->saveStates(); bool flipVertical = true; mEditor->flipSelection(flipVertical); + mEditor->backups()->transform(tr("Flip Selection Y")); } void ActionCommands::selectAll() { + mEditor->backups()->saveStates(); mEditor->selectAll(); + mEditor->backups()->selection(); } void ActionCommands::deselectAll() { + if (!mEditor->select()->somethingSelected()) { return; } + + mEditor->backups()->saveStates(); mEditor->deselectAll(); + mEditor->backups()->deselect(); +} + +void ActionCommands::resetView() +{ + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::CAMERA) { + mEditor->backups()->saveStates(); + mEditor->view()->resetView(); + mEditor->backups()->cameraMotion(tr("Camera: reset view")); + } else { + mEditor->view()->resetView(); + } +} + +void ActionCommands::zoomTo(const float value) +{ + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::CAMERA) { + mEditor->backups()->saveStates(); + mEditor->view()->scale(value); + mEditor->backups()->cameraMotion(tr("Camera: zoom view")); + } else { + mEditor->view()->scale(value); + } } void ActionCommands::ZoomIn() { - mEditor->view()->scaleUp(); + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::CAMERA) { + mEditor->backups()->saveStates(); + mEditor->view()->scaleUp(); + mEditor->backups()->cameraMotion(tr("Camera: zoom view")); + } else { + mEditor->view()->scaleUp(); + } } void ActionCommands::ZoomOut() { - mEditor->view()->scaleDown(); + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::CAMERA) { + mEditor->backups()->saveStates(); + mEditor->view()->scaleDown(); + mEditor->backups()->cameraMotion(tr("Camera: zoom view")); + } else { + mEditor->view()->scaleDown(); + } } void ActionCommands::rotateClockwise() { float currentRotation = mEditor->view()->rotation(); - mEditor->view()->rotate(currentRotation + 15.f); + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::CAMERA) { + mEditor->backups()->saveStates(); + mEditor->view()->rotate(currentRotation + 15.f); + mEditor->backups()->cameraMotion(tr("Camera: rotate view")); + } else { + mEditor->view()->rotate(currentRotation + 15.f); + } } void ActionCommands::rotateCounterClockwise() { float currentRotation = mEditor->view()->rotation(); - mEditor->view()->rotate(currentRotation - 15.f); + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::CAMERA) { + mEditor->backups()->saveStates(); + mEditor->view()->rotate(currentRotation - 15.f); + mEditor->backups()->cameraMotion(tr("Camera: rotate view")); + } else { + mEditor->view()->rotate(currentRotation - 15.f); + } } void ActionCommands::toggleMirror() { - bool flipX = mEditor->view()->isFlipHorizontal(); - mEditor->view()->flipHorizontal(!flipX); + BackupManager* backup = mEditor->backups(); + + bool flipX = !mEditor->view()->isFlipHorizontal(); + mEditor->view()->flipHorizontal(flipX); + + backup->flipView(flipX, DIRECTION::HORIZONTAL); } void ActionCommands::toggleMirrorV() { - bool flipY = mEditor->view()->isFlipVertical(); - mEditor->view()->flipVertical(!flipY); + BackupManager* backup = mEditor->backups(); + + bool flipY = !mEditor->view()->isFlipVertical(); + mEditor->view()->flipVertical(flipY); + + backup->flipView(flipY, DIRECTION::VERTICAL); } void ActionCommands::showGrid(bool bShow) @@ -508,8 +583,11 @@ void ActionCommands::GotoPrevKeyFrame() Status ActionCommands::addNewKey() { + BackupManager* backups = mEditor->backups(); + KeyFrame* key = mEditor->addNewKey(); + backups->saveStates(); SoundClip* clip = dynamic_cast(key); if (clip) { @@ -535,6 +613,7 @@ Status ActionCommands::addNewKey() mEditor->view()->updateViewTransforms(); } + backups->keyAdded(); mEditor->layers()->notifyAnimationLengthChanged(); return Status::OK; @@ -542,17 +621,25 @@ Status ActionCommands::addNewKey() void ActionCommands::removeKey() { - mEditor->removeKey(); + BackupManager* backups = mEditor->backups(); Layer* layer = mEditor->layers()->currentLayer(); - if (layer->keyFrameCount() == 0) - { - layer->addNewKeyFrameAt(1); + + backups->saveStates(); + + // sound layer can as the only layer type, have no keyframes... + if (layer->keyFrameCount() == 1 && layer->type() != Layer::SOUND) { + mEditor->clearCurrentFrame(); + } else { + mEditor->removeCurrentKey(); + backups->keyRemoved(); } } void ActionCommands::duplicateKey() { + BackupManager* backups = mEditor->backups(); + Layer* layer = mEditor->layers()->currentLayer(); if (layer == nullptr) return; if (!layer->visible()) @@ -574,6 +661,7 @@ void ActionCommands::duplicateKey() layer->addKeyFrame(nextEmptyFrame, dupKey); mEditor->scrubTo(nextEmptyFrame); + backups->saveStates(); if (layer->type() == Layer::SOUND) { @@ -584,19 +672,31 @@ void ActionCommands::duplicateKey() dupKey->setFileName(""); // don't share filename dupKey->modification(); } + backups->keyAdded(layer->description() + tr(": Duplicate key")); mEditor->layers()->notifyAnimationLengthChanged(); } void ActionCommands::moveFrameForward() { + int frameIndex = mEditor->currentFrame(); Layer* layer = mEditor->layers()->currentLayer(); if (layer) { - if (layer->moveKeyFrameForward(mEditor->currentFrame())) + auto backupMan = mEditor->backups(); + if (!layer->getSelectedFrameIndexes().isEmpty()) { - mEditor->scrubForward(); + layer->deselectAll(); + backupMan->frameDeselected(QList({frameIndex}), frameIndex); } + + backupMan->saveStates(); + if (layer->moveKeyFrameForward(frameIndex)) + { + backupMan->frameMoved(1); + } + + mEditor->scrubTo(frameIndex+1); } mEditor->layers()->notifyAnimationLengthChanged(); @@ -604,38 +704,59 @@ void ActionCommands::moveFrameForward() void ActionCommands::moveFrameBackward() { + int frameIndex = mEditor->currentFrame(); Layer* layer = mEditor->layers()->currentLayer(); if (layer) { - if (layer->moveKeyFrameBackward(mEditor->currentFrame())) + auto backupMan = mEditor->backups(); + if (!layer->getSelectedFrameIndexes().isEmpty()) + { + layer->deselectAll(); + backupMan->frameDeselected(QList({frameIndex}), frameIndex); + } + + backupMan->saveStates(); + if (layer->moveKeyFrameBackward(frameIndex)) { - mEditor->scrubBackward(); + backupMan->frameMoved(-1); } + + mEditor->scrubTo(frameIndex-1); } } Status ActionCommands::addNewBitmapLayer() { bool ok; + + BackupManager* backups = mEditor->backups(); + backups->saveStates(); + QString text = QInputDialog::getText(nullptr, tr("Layer Properties"), tr("Layer name:"), QLineEdit::Normal, nameSuggest(tr("Bitmap Layer")), &ok); if (ok && !text.isEmpty()) { mEditor->layers()->createBitmapLayer(text); + backups->layerAdded(); } + return Status::OK; } Status ActionCommands::addNewVectorLayer() { bool ok; + BackupManager* backups = mEditor->backups(); + backups->saveStates(); + QString text = QInputDialog::getText(nullptr, tr("Layer Properties"), tr("Layer name:"), QLineEdit::Normal, nameSuggest(tr("Vector Layer")), &ok); if (ok && !text.isEmpty()) { mEditor->layers()->createVectorLayer(text); + backups->layerAdded(); } return Status::OK; } @@ -643,12 +764,16 @@ Status ActionCommands::addNewVectorLayer() Status ActionCommands::addNewCameraLayer() { bool ok; + BackupManager* backups = mEditor->backups(); + backups->saveStates(); + QString text = QInputDialog::getText(nullptr, tr("Layer Properties"), tr("Layer name:"), QLineEdit::Normal, nameSuggest(tr("Camera Layer")), &ok); if (ok && !text.isEmpty()) { mEditor->layers()->createCameraLayer(text); + backups->layerAdded(); } return Status::OK; } @@ -656,6 +781,9 @@ Status ActionCommands::addNewCameraLayer() Status ActionCommands::addNewSoundLayer() { bool ok = false; + BackupManager* backups = mEditor->backups(); + backups->saveStates(); + QString strLayerName = QInputDialog::getText(nullptr, tr("Layer Properties"), tr("Layer name:"), QLineEdit::Normal, nameSuggest(tr("Sound Layer")), &ok); @@ -663,32 +791,77 @@ Status ActionCommands::addNewSoundLayer() { Layer* layer = mEditor->layers()->createSoundLayer(strLayerName); mEditor->layers()->setCurrentLayer(layer); - } - return Status::OK; + + backups->layerAdded(); + return Status::OK; + } + return Status::FAIL; } Status ActionCommands::deleteCurrentLayer() { LayerManager* layerMgr = mEditor->layers(); - QString strLayerName = layerMgr->currentLayer()->name(); + BackupManager* backups = mEditor->backups(); + Layer* layer = mEditor->layers()->currentLayer(); + QString layerName = layer->name(); + int layerIndex = mEditor->currentLayerIndex(); + + backups->saveStates(); + std::map> keyFrames; + for(auto map : layer->getKeysInLayer()) + { + keyFrames.insert(std::make_pair(map.first, map.second->clone())); + } int ret = QMessageBox::warning(mParent, tr("Delete Layer", "Windows title of Delete current layer pop-up."), - tr("Are you sure you want to delete layer: ") + strLayerName + " ?", + tr("Are you sure you want to delete layer: ") + layerName + " ?", QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); if (ret == QMessageBox::Ok) { - Status st = layerMgr->deleteLayer(mEditor->currentLayerIndex()); + Status st = layerMgr->deleteLayer(layerIndex); if (st == Status::ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER) { QMessageBox::information(mParent, "", tr("Please keep at least one camera layer in project", "text when failed to delete camera layer")); + return Status::CANCELED; } + backups->layerDeleted(keyFrames); } return Status::OK; } +void ActionCommands::editCameraProperties() +{ + CameraPropertiesDialog* dialog = nullptr; + LayerCamera* layer = static_cast(mEditor->layers()->currentLayer()); + + const QRect currentViewRect = layer->getViewRect(); + mEditor->backups()->saveStates(); + + if ( dialog == NULL ) + { + dialog = new CameraPropertiesDialog(layer->name(), currentViewRect.width(), currentViewRect.height()); + } + dialog->setName(layer->name()); + dialog->setWidth(currentViewRect.width()); + dialog->setHeight(currentViewRect.height()); + int result = dialog->exec(); + if (result == QDialog::Accepted) + { + + layer->setName(dialog->getName()); + QSettings settings (PENCIL2D, PENCIL2D); + settings.setValue(SETTING_FIELD_W, dialog->getWidth()); + settings.setValue(SETTING_FIELD_H, dialog->getHeight()); + QRect newViewRect = QRect(-dialog->getWidth()/2, -dialog->getHeight()/2, dialog->getWidth(), dialog->getHeight()); + layer->setViewRect(newViewRect); + + mEditor->backups()->cameraProperties(currentViewRect); + } +} + QString ActionCommands::nameSuggest(QString s) { LayerManager* layerMgr = mEditor->layers(); diff --git a/app/src/actioncommands.h b/app/src/actioncommands.h index f357995cad..aa12b9e374 100644 --- a/app/src/actioncommands.h +++ b/app/src/actioncommands.h @@ -51,6 +51,8 @@ class ActionCommands : public QObject // view void ZoomIn(); void ZoomOut(); + void zoomTo(const float value); + void resetView(); void rotateClockwise(); void rotateCounterClockwise(); void toggleMirror(); @@ -63,18 +65,20 @@ class ActionCommands : public QObject void GotoPrevFrame(); void GotoNextKeyFrame(); void GotoPrevKeyFrame(); - Status addNewKey(); void removeKey(); void duplicateKey(); void moveFrameForward(); void moveFrameBackward(); + Status addNewKey(); + // Layer Status addNewBitmapLayer(); Status addNewVectorLayer(); Status addNewCameraLayer(); Status addNewSoundLayer(); Status deleteCurrentLayer(); + void editCameraProperties(); QString nameSuggest(QString s); // Help diff --git a/app/src/displayoptionwidget.cpp b/app/src/displayoptionwidget.cpp index 1b7a374e1b..f455514978 100644 --- a/app/src/displayoptionwidget.cpp +++ b/app/src/displayoptionwidget.cpp @@ -21,10 +21,13 @@ GNU General Public License for more details. #include #include "preferencemanager.h" +#include "backupmanager.h" #include "viewmanager.h" #include "scribblearea.h" + #include "editor.h" #include "util.h" +#include "direction.h" DisplayOptionWidget::DisplayOptionWidget(QWidget *parent) : @@ -108,34 +111,57 @@ void DisplayOptionWidget::updateUI() void DisplayOptionWidget::onionPrevButtonClicked(bool isOn) { +// BackupManager* backup = editor()->backups(); + PreferenceManager* prefs = editor()->preference(); prefs->set(SETTING::PREV_ONION, isOn); + +// backup->toggleSetting(isOn, SETTING::PREV_ONION); + } void DisplayOptionWidget::onionNextButtonClicked(bool isOn) { +// BackupManager* backup = editor()->backups(); + PreferenceManager* prefs = editor()->preference(); prefs->set(SETTING::NEXT_ONION, isOn); + +// backup->toggleSetting(isOn, SETTING::NEXT_ONION); } void DisplayOptionWidget::onionBlueButtonClicked(bool isOn) { +// BackupManager* backup = editor()->backups(); + PreferenceManager* prefs = editor()->preference(); prefs->set(SETTING::ONION_BLUE, isOn); + +// backup->toggleSetting(isOn, SETTING::ONION_BLUE); } void DisplayOptionWidget::onionRedButtonClicked(bool isOn) { +// BackupManager* backup = editor()->backups(); + PreferenceManager* prefs = editor()->preference(); prefs->set(SETTING::ONION_RED, isOn); + +// backup->toggleSetting(isOn, SETTING::ONION_RED); } void DisplayOptionWidget::toggleMirror(bool isOn) { +// BackupManager* backup = editor()->backups(); editor()->view()->flipHorizontal(isOn); + +// backup->flipView(isOn, DIRECTION::HORIZONTAL); } void DisplayOptionWidget::toggleMirrorV(bool isOn) { +// BackupManager* backup = editor()->backups(); editor()->view()->flipVertical(isOn); + +// backup->flipView(isOn, DIRECTION::VERTICAL); } diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 54aa10dbf4..5f939b3df4 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -26,9 +26,12 @@ GNU General Public License for more details. #include #include #include +#include #include #include #include +#include +#include // core_lib headers #include "pencildef.h" @@ -39,6 +42,11 @@ GNU General Public License for more details. #include "filemanager.h" #include "colormanager.h" #include "layermanager.h" + +#include "backupmanager.h" +#include "historyviewerwidget.h" +#include "layercamera.h" + #include "toolmanager.h" #include "playbackmanager.h" #include "soundmanager.h" @@ -112,6 +120,23 @@ MainWindow2::MainWindow2(QWidget *parent) : mCommands = new ActionCommands(this); mCommands->setCore(mEditor); + ui->menuEdit->removeAction(ui->actionUndo); + ui->menuEdit->removeAction(ui->actionRedo); + + QIcon undoIcon; + undoIcon.addFile(QStringLiteral(":/icons/undo.png"), QSize(), QIcon::Normal, QIcon::Off); + ui->actionUndo = mEditor->backups()->undoStack()->createUndoAction(this, tr("&Undo")); + ui->actionUndo->setIcon(undoIcon); + + QIcon redoIcon; + redoIcon.addFile(QStringLiteral(":/icons/redo.png"), QSize(), QIcon::Normal, QIcon::Off); + ui->actionRedo = mEditor->backups()->undoStack()->createRedoAction(this, tr("&Redo")); + ui->actionRedo->setIcon(redoIcon); + + ui->menuEdit->insertAction(ui->actionCut, ui->actionUndo); + ui->menuEdit->insertAction(ui->actionCut, ui->actionRedo); + ui->menuEdit->insertSeparator(ui->actionCut); + createDockWidgets(); createMenus(); setupKeyboardShortcuts(); @@ -159,6 +184,9 @@ void MainWindow2::createDockWidgets() mToolBox = new ToolBoxWidget(this); mToolBox->setObjectName("ToolBox"); + mHistoryView = new HistoryViewerWidget(this); + mHistoryView->setObjectName("History"); + /* mTimeline2 = new Timeline2; mTimeline2->setObjectName( "Timeline2" ); @@ -172,7 +200,8 @@ void MainWindow2::createDockWidgets() << mColorPalette << mDisplayOptionWidget << mToolOptions - << mToolBox; + << mToolBox + << mHistoryView; mStartIcon = QIcon(":icons/controls/play.png"); mStopIcon = QIcon(":icons/controls/stop.png"); @@ -196,6 +225,7 @@ void MainWindow2::createDockWidgets() addDockWidget(Qt::LeftDockWidgetArea, mToolOptions); addDockWidget(Qt::LeftDockWidgetArea, mDisplayOptionWidget); addDockWidget(Qt::BottomDockWidgetArea, mTimeLine); + addDockWidget(Qt::RightDockWidgetArea, mHistoryView); setDockNestingEnabled(true); /* @@ -249,9 +279,7 @@ void MainWindow2::createMenus() connect(ui->actionImport_Sound, &QAction::triggered, mCommands, &ActionCommands::importSound); connect(ui->actionImport_Palette, &QAction::triggered, this, &MainWindow2::importPalette); - //--- Edit Menu --- - connect(ui->actionUndo, &QAction::triggered, mEditor, &Editor::undo); - connect(ui->actionRedo, &QAction::triggered, mEditor, &Editor::redo); + /// --- Edit Menu --- connect(ui->actionCut, &QAction::triggered, mEditor, &Editor::cut); connect(ui->actionCopy, &QAction::triggered, mEditor, &Editor::copy); connect(ui->actionPaste, &QAction::triggered, mEditor, &Editor::paste); @@ -275,14 +303,14 @@ void MainWindow2::createMenus() connect(ui->actionZoom_Out, &QAction::triggered, mCommands, &ActionCommands::ZoomOut); connect(ui->actionRotate_Clockwise, &QAction::triggered, mCommands, &ActionCommands::rotateClockwise); connect(ui->actionRotate_Anticlockwise, &QAction::triggered, mCommands, &ActionCommands::rotateCounterClockwise); - connect(ui->actionReset_View, &QAction::triggered, mEditor->view(), &ViewManager::resetView); - connect(ui->actionZoom400, &QAction::triggered, mEditor->view(), &ViewManager::scale400); - connect(ui->actionZoom300, &QAction::triggered, mEditor->view(), &ViewManager::scale300); - connect(ui->actionZoom200, &QAction::triggered, mEditor->view(), &ViewManager::scale200); - connect(ui->actionZoom100, &QAction::triggered, mEditor->view(), &ViewManager::scale100); - connect(ui->actionZoom50, &QAction::triggered, mEditor->view(), &ViewManager::scale50); - connect(ui->actionZoom33, &QAction::triggered, mEditor->view(), &ViewManager::scale33); - connect(ui->actionZoom25, &QAction::triggered, mEditor->view(), &ViewManager::scale25); + connect(ui->actionReset_View, &QAction::triggered, mCommands, &ActionCommands::resetView); + connect(ui->actionZoom400, &QAction::triggered, this, [this]{ mCommands->zoomTo(4); }); + connect(ui->actionZoom300, &QAction::triggered, this, [this]{ mCommands->zoomTo(3); }); + connect(ui->actionZoom200, &QAction::triggered, this, [this]{ mCommands->zoomTo(2); }); + connect(ui->actionZoom100, &QAction::triggered, this, [this]{ mCommands->zoomTo(1); }); + connect(ui->actionZoom50, &QAction::triggered, this, [this]{ mCommands->zoomTo(0.5f); }); + connect(ui->actionZoom33, &QAction::triggered, this, [this]{ mCommands->zoomTo(0.33f); }); + connect(ui->actionZoom25, &QAction::triggered, this, [this]{ mCommands->zoomTo(0.25f); }); connect(ui->actionHorizontal_Flip, &QAction::triggered, mCommands, &ActionCommands::toggleMirror); connect(ui->actionVertical_Flip, &QAction::triggered, mCommands, &ActionCommands::toggleMirrorV); @@ -346,7 +374,8 @@ void MainWindow2::createMenus() mColorPalette->toggleViewAction(), mTimeLine->toggleViewAction(), mDisplayOptionWidget->toggleViewAction(), - mColorInspector->toggleViewAction() + mColorInspector->toggleViewAction(), + mHistoryView->toggleViewAction() }; for (QAction* action : actions) @@ -382,7 +411,6 @@ void MainWindow2::createMenus() connect(mRecentFileMenu, &RecentFileMenu::loadRecentFile, this, &MainWindow2::openFile); - connect(ui->menuEdit, &QMenu::aboutToShow, this, &MainWindow2::undoActSetText); connect(ui->menuEdit, &QMenu::aboutToHide, this, &MainWindow2::undoActSetEnabled); } @@ -400,7 +428,9 @@ void MainWindow2::setOpacity(int opacity) void MainWindow2::updateSaveState() { - setWindowModified(mEditor->currentBackup() != mBackupAtSave); + bool hasBeenModified = mEditor->backups()->currentBackup() != mBackupAtSave; + + setWindowModified(hasBeenModified); } void MainWindow2::clearRecentFilesList() @@ -483,6 +513,9 @@ void MainWindow2::newDocument(bool force) mColorPalette->refreshColorList(); mEditor->color()->setColorNumber(0); + // clear backup stack + mEditor->backups()->undoStack()->clear(); + setWindowTitle(PENCIL_WINDOW_TITLE); updateSaveState(); } @@ -640,6 +673,9 @@ bool MainWindow2::openObject(QString strFilePath, bool checkForChanges) mColorPalette->refreshColorList(); mEditor->layers()->notifyAnimationLengthChanged(); + // clear backup stack + mEditor->backups()->undoStack()->clear(); + progress.setValue(progress.maximum()); updateSaveState(); @@ -706,13 +742,11 @@ bool MainWindow2::saveObject(QString strSavedFileName) mTimeLine->updateContent(); setWindowTitle(strSavedFileName.prepend("[*]")); - mBackupAtSave = mEditor->currentBackup(); + mBackupAtSave = mEditor->backups()->currentBackup(); updateSaveState(); progress.setValue(progress.maximum()); - mEditor->resetAutoSaveCounter(); - return true; } @@ -726,7 +760,7 @@ bool MainWindow2::saveDocument() bool MainWindow2::maybeSave() { - if (mEditor->currentBackup() != mBackupAtSave) + if (mEditor->backups()->currentBackup() != mBackupAtSave) { int ret = QMessageBox::warning(this, tr("Warning"), tr("This animation has been modified.\n Do you want to save your changes?"), @@ -783,7 +817,8 @@ void MainWindow2::importImage() if (strFilePath.isEmpty()) { return; } if (!QFile::exists(strFilePath)) { return; } - bool ok = mEditor->importImage(strFilePath); + bool isSequence = false; + bool ok = mEditor->importImage(strFilePath, isSequence); if (!ok) { QMessageBox::warning(this, @@ -838,7 +873,7 @@ void MainWindow2::importImageSequence() strImgFileLower.endsWith(".tif") || strImgFileLower.endsWith(".tiff")) { - mEditor->importImage(strImgFile); + mEditor->importImage(strImgFile, mIsImportingImageSequence); imagesImportedSoFar++; progress.setValue(imagesImportedSoFar); @@ -961,10 +996,11 @@ void MainWindow2::addLayerByFilename(QString strFilePath) Q_ASSERT(layer != nullptr); LayerManager* lMgr = mEditor->layers(); lMgr->setCurrentLayer(layer); + bool isSequence = true; for (int i = 0; i < finalList.size(); i++) { mEditor->scrubTo(finalList[i].mid(dot - digits, digits).toInt()); - bool ok = mEditor->importImage(path + finalList[i]); + bool ok = mEditor->importImage(path + finalList[i], isSequence); if (!ok) { return;} layer->addNewKeyFrameAt(finalList[i].mid(dot - digits, digits).toInt()); } @@ -1238,35 +1274,6 @@ void MainWindow2::clearKeyboardShortcuts() } } -void MainWindow2::undoActSetText() -{ - if (mEditor->mBackupIndex < 0) - { - ui->actionUndo->setText(tr("Undo", "Menu item text")); - ui->actionUndo->setEnabled(false); - } - else - { - ui->actionUndo->setText(QString("%1 %2 %3").arg(tr("Undo", "Menu item text")) - .arg(QString::number(mEditor->mBackupIndex + 1)) - .arg(mEditor->mBackupList.at(mEditor->mBackupIndex)->undoText)); - ui->actionUndo->setEnabled(true); - } - - if (mEditor->mBackupIndex + 2 < mEditor->mBackupList.size()) - { - ui->actionRedo->setText(QString("%1 %2 %3").arg(tr("Redo", "Menu item text")) - .arg(QString::number(mEditor->mBackupIndex + 2)) - .arg(mEditor->mBackupList.at(mEditor->mBackupIndex + 1)->undoText)); - ui->actionRedo->setEnabled(true); - } - else - { - ui->actionRedo->setText(tr("Redo", "Menu item text")); - ui->actionRedo->setEnabled(false); - } -} - void MainWindow2::undoActSetEnabled() { ui->actionUndo->setEnabled(true); @@ -1297,7 +1304,7 @@ void MainWindow2::importPalette() void MainWindow2::makeConnections(Editor* editor) { - connect(editor, &Editor::updateBackup, this, &MainWindow2::updateSaveState); + connect(editor->backups(), &BackupManager::updateBackup, this, &MainWindow2::updateSaveState); connect(editor, &Editor::needDisplayInfo, this, &MainWindow2::displayMessageBox); connect(editor, &Editor::needDisplayInfoNoTitle, this, &MainWindow2::displayMessageBoxNoTitle); } @@ -1322,6 +1329,8 @@ void MainWindow2::makeConnections(Editor* editor, ScribbleArea* scribbleArea) connect(editor->layers(), &LayerManager::layerDeleted, scribbleArea, &ScribbleArea::updateAllFrames); connect(editor, &Editor::currentFrameChanged, scribbleArea, &ScribbleArea::updateFrame); +// connect(editor, &Editor::deselectAll, scribbleArea, &ScribbleArea::deselectAll); +// connect(editor, &Editor::selectAll, scribbleArea, &ScribbleArea::selectAll); connect(editor->view(), &ViewManager::viewChanged, scribbleArea, &ScribbleArea::updateAllFrames); //connect( editor->preference(), &PreferenceManager::preferenceChanged, scribbleArea, &ScribbleArea::onPreferencedChanged ); @@ -1342,6 +1351,8 @@ void MainWindow2::makeConnections(Editor* pEditor, TimeLine* pTimeline) connect(pTimeline, &TimeLine::newVectorLayer, mCommands, &ActionCommands::addNewVectorLayer); connect(pTimeline, &TimeLine::newSoundLayer, mCommands, &ActionCommands::addNewSoundLayer); connect(pTimeline, &TimeLine::newCameraLayer, mCommands, &ActionCommands::addNewCameraLayer); + connect(pTimeline, &TimeLine::deleteCurrentLayer, mCommands, &ActionCommands::deleteCurrentLayer); + connect(pTimeline, &TimeLine::modifiedCamera, mCommands, &ActionCommands::editCameraProperties); connect(mTimeLine, &TimeLine::playButtonTriggered, mCommands, &ActionCommands::PlayStop); diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index 86841b93b9..e2b9f6bb75 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -43,6 +43,7 @@ class Timeline2; class ActionCommands; class ImportImageSeqDialog; class BackupElement; +class HistoryViewerWidget; @@ -62,7 +63,6 @@ class MainWindow2 : public QMainWindow Editor* mEditor = nullptr; public slots: - void undoActSetText(); void undoActSetEnabled(); void updateSaveState(); void clearRecentFilesList(); @@ -146,12 +146,13 @@ private slots: Timeline2* mTimeline2 = nullptr; RecentFileMenu* mRecentFileMenu = nullptr; PreferencesDialog* mPrefDialog = nullptr; + HistoryViewerWidget* mHistoryView = nullptr; //PreviewWidget* mPreview = nullptr; TimeLine* mTimeLine = nullptr; // be public temporary ColorInspector* mColorInspector = nullptr; // backup - BackupElement* mBackupAtSave = nullptr; + const BackupElement* mBackupAtSave = nullptr; PegBarAlignmentDialog* mPegAlign = nullptr; diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro index 92238c1364..1a0e83394e 100644 --- a/core_lib/core_lib.pro +++ b/core_lib/core_lib.pro @@ -22,6 +22,7 @@ INCLUDEPATH += src \ src/graphics/bitmap \ src/graphics/vector \ src/interface \ + src/managers \ src/structure \ src/tool \ src/util \ @@ -48,7 +49,10 @@ HEADERS += \ src/interface/timelinecells.h \ src/interface/basedockwidget.h \ src/interface/backgroundwidget.h \ + src/interface/historyviewerwidget.h \ src/managers/basemanager.h \ + src/managers/canvasmanager.h \ + src/managers/keyframemanager.h \ src/managers/selectionmanager.h \ src/managers/colormanager.h \ src/managers/layermanager.h \ @@ -57,6 +61,7 @@ HEADERS += \ src/managers/viewmanager.h \ src/managers/preferencemanager.h \ src/managers/soundmanager.h \ + src/managers/backupmanager.h \ src/structure/camera.h \ src/structure/keyframe.h \ src/structure/layer.h \ @@ -91,6 +96,7 @@ HEADERS += \ src/util/pencilsettings.h \ src/util/util.h \ src/util/log.h \ + src/util/direction.h \ src/util/movemode.h \ src/canvaspainter.h \ src/soundplayer.h \ @@ -120,7 +126,11 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/interface/timelinecells.cpp \ src/interface/basedockwidget.cpp \ src/interface/backgroundwidget.cpp \ + src/interface/backupelement.cpp \ + src/interface/historyviewerwidget.cpp \ src/managers/basemanager.cpp \ + src/managers/canvasmanager.cpp \ + src/managers/keyframemanager.cpp \ src/managers/selectionmanager.cpp \ src/managers/colormanager.cpp \ src/managers/layermanager.cpp \ @@ -128,6 +138,7 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/managers/preferencemanager.cpp \ src/managers/playbackmanager.cpp \ src/managers/viewmanager.cpp \ + src/managers/backupmanager.cpp \ src/structure/camera.cpp \ src/structure/keyframe.cpp \ src/structure/layer.cpp \ diff --git a/core_lib/src/external/linux/linux.cpp b/core_lib/src/external/linux/linux.cpp index 10afc73679..041b9e6187 100644 --- a/core_lib/src/external/linux/linux.cpp +++ b/core_lib/src/external/linux/linux.cpp @@ -110,7 +110,8 @@ void Editor::importMovie (QString filePath, int fps) { progress.setValue(50+i*50/nFiles); if(i>1) scrubForward(); - importImage(tempPath+"tmp_import"+frameNumberString+".png"); + bool isSequence = (i > 1) ? true : false; + importImage(tempPath+"tmp_import"+frameNumberString+".png", isSequence); i++; frameNumberString = QString::number(i); while( frameNumberString.length() < 4) frameNumberString.prepend("0"); diff --git a/core_lib/src/external/macosx/macosx.cpp b/core_lib/src/external/macosx/macosx.cpp index a83c44b534..250d547581 100644 --- a/core_lib/src/external/macosx/macosx.cpp +++ b/core_lib/src/external/macosx/macosx.cpp @@ -133,7 +133,8 @@ void Editor::importMovie(QString filePath, int fps) { progress.setValue(50+i*50/nFiles); if(i>1) scrubForward(); - importImage(tempPath+"tmp_import"+frameNumberString+".png"); + bool isSequence = (i > 1) ? true : false; + importImage(tempPath+"tmp_import"+frameNumberString+".png", isSequence); i++; frameNumberString = QString::number(i); while( frameNumberString.length() < 4) frameNumberString.prepend("0"); diff --git a/core_lib/src/external/win32/win32.cpp b/core_lib/src/external/win32/win32.cpp index fd30ece39e..29a0625c0e 100644 --- a/core_lib/src/external/win32/win32.cpp +++ b/core_lib/src/external/win32/win32.cpp @@ -84,7 +84,8 @@ void Editor::importMovie( QString filePath, int fps ) { progress.setValue( 50 + i * 50 / nFiles ); if ( i>1 ) scrubForward(); - importImage( tempPath + "tmp_import" + frameNumberString + ".png" ); + bool isSequence = (i > 1) ? true : false; + importImage( tempPath + "tmp_import" + frameNumberString + ".png", isSequence); i++; frameNumberString = QString::number( i ); while ( frameNumberString.length() < 4 ) frameNumberString.prepend( "0" ); diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 693033a63b..fce66cd3d5 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -83,7 +83,7 @@ BitmapImage& BitmapImage::operator=(const BitmapImage& a) return *this; } -BitmapImage* BitmapImage::clone() +BitmapImage* BitmapImage::clone() const { return new BitmapImage(*this); } diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index b902103481..5876b490de 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -34,7 +34,7 @@ class BitmapImage : public KeyFrame ~BitmapImage(); BitmapImage& operator=(const BitmapImage& a); - BitmapImage* clone() override; + BitmapImage* clone() const override; void loadFile() override; void unloadFile() override; bool isLoaded() override; diff --git a/core_lib/src/graphics/vector/beziercurve.cpp b/core_lib/src/graphics/vector/beziercurve.cpp index 1ede94fca7..67068d705a 100644 --- a/core_lib/src/graphics/vector/beziercurve.cpp +++ b/core_lib/src/graphics/vector/beziercurve.cpp @@ -152,7 +152,7 @@ void BezierCurve::loadDomElement(QDomElement element) colourNumber = element.attribute("colourNumber").toInt(); origin = QPointF( element.attribute("originX").toFloat(), element.attribute("originY").toFloat() ); pressure.append( element.attribute("originPressure").toFloat() ); - selected.append(false); + mVertSelected.append(false); QDomNode segmentTag = element.firstChild(); while (!segmentTag.isNull()) @@ -183,7 +183,7 @@ void BezierCurve::setOrigin(const QPointF& point, const qreal& pressureValue, co { origin = point; pressure[0] = pressureValue; - selected[0] = trueOrFalse; + mVertSelected[0] = trueOrFalse; } void BezierCurve::setC1(int i, const QPointF& point) @@ -259,9 +259,20 @@ void BezierCurve::setInvisibility(bool YesOrNo) invisible = YesOrNo; } -void BezierCurve::setSelected(int i, bool YesOrNo) +void BezierCurve::setVertexSelected(int i, bool YesOrNo) { - selected[i+1] = YesOrNo; + mVertSelected[i+1] = YesOrNo; +} + +/** + * @brief BezierCurve::setSelected + * Set selection state of the curve + * @param YesOrNo + */ +void BezierCurve::setSelected(const bool YesOrNo) +{ + mIsSelected = YesOrNo; + setVertexSelected(YesOrNo); } /** @@ -296,14 +307,14 @@ BezierCurve BezierCurve::transformed(QTransform transformation) QPointF newC1 = c1.at(i); QPointF newC2 = c2.at(i); QPointF newVertex = vertex.at(i); - if (isSelected(i-1)) { newC1 = transformation.map(newC1); } - if (isSelected(i)) { newC2 = transformation.map(newC2); newVertex = transformation.map(newVertex); } + if (isSelected(i-1)) { newC1 = transformation.map(newC1); } + if (isSelected(i)) { newC2 = transformation.map(newC2); newVertex = transformation.map(newVertex); } transformedCurve.appendCubic( newC1, newC2, newVertex, pressure.at(i) ); - if (isSelected(i)) { transformedCurve.setSelected(i, true); } + if (isSelected(i)) { transformedCurve.setSelected(i, true); } } transformedCurve.setWidth( width); transformedCurve.setVariableWidth( variableWidth ); - //transformedCurve.setSelected(true); // or select only the selected elements of the orginal curve? + //transformedCurve.setSelected(true); // or select only the mVertSelected elements of the orginal curve? */ return transformedCurve; } @@ -329,7 +340,7 @@ void BezierCurve::appendCubic(const QPointF& c1Point, const QPointF& c2Point, co c2.append(c2Point); vertex.append(vertexPoint); pressure.append(pressureValue); - selected.append(false); + mVertSelected.append(false); } void BezierCurve::addPoint(int position, const QPointF point) @@ -348,7 +359,7 @@ void BezierCurve::addPoint(int position, const QPointF point) c2.insert(position, point - 0.2*(v2-v1)); vertex.insert(position, point); pressure.insert(position, getPressure(position)); - selected.insert(position, isSelected(position) && isSelected(position-1)); + mVertSelected.insert(position, isSelected(position) && isSelected(position-1)); //smoothCurve(); } @@ -383,7 +394,7 @@ void BezierCurve::addPoint(int position, const qreal fraction) // fraction is wh c2.insert(position, cA2); vertex.insert(position, vM); pressure.insert(position, getPressure(position)); - selected.insert(position, isSelected(position) && isSelected(position-1)); + mVertSelected.insert(position, isSelected(position) && isSelected(position-1)); //smoothCurve(); } @@ -405,14 +416,14 @@ void BezierCurve::removeVertex(int i) c1.removeAt(0); c2.removeAt(0); pressure.removeAt(0); - selected.removeAt(0); + mVertSelected.removeAt(0); } else { vertex.removeAt(i); c2.removeAt(i); pressure.removeAt(i+1); - selected.removeAt(i+1); + mVertSelected.removeAt(i+1); if ( i != n-1 ) { c1.removeAt(i+1); @@ -480,13 +491,13 @@ void BezierCurve::drawPath(QPainter& painter, Object* object, QTransform transfo if (!simplified) { - // highlight the selected elements + // highlight the mVertSelected elements colour = QColor(100,150,255); // highlight colour painter.setBrush(Qt::NoBrush); qreal lineWidth = 1.5/painter.matrix().m11(); lineWidth = fabs(lineWidth); // make sure line width is positive, otherwise nothing is drawn painter.setPen(QPen(QBrush(colour), lineWidth, Qt::SolidLine, Qt::RoundCap,Qt::RoundJoin)); - if (isSelected()) painter.drawPath(myCurve.getSimplePath()); + if (mIsSelected) painter.drawPath(myCurve.getSimplePath()); for(int i=-1; i< vertex.size(); i++) @@ -629,11 +640,11 @@ void BezierCurve::createCurve(const QList& pointList, const QList0) c1.removeAt(0); while (c2.size()>0) c2.removeAt(0); while (vertex.size()>0) vertex.removeAt(0); - while (selected.size()>0) selected.removeAt(0); + while (mVertSelected.size()>0) mVertSelected.removeAt(0); while (pressure.size()>0) pressure.removeAt(0); setOrigin( pointList.at(0) ); - selected.append(false); + mVertSelected.append(false); pressure.append(pressureList.at(0)); for(p=1; p& pointList, const QListcolourNumber = colourNumber; } - void setSelected(bool YesOrNo) { for(int i=0; i selected; // this list has one more element than the other list (the first element is for the origin) + bool mIsSelected = false; // whether the curve itself is selected + QList mVertSelected; // this list has one more element than the other list (the first element is for the origin) }; #endif diff --git a/core_lib/src/graphics/vector/vectorimage.cpp b/core_lib/src/graphics/vector/vectorimage.cpp index a66648d5c5..263f5d9647 100644 --- a/core_lib/src/graphics/vector/vectorimage.cpp +++ b/core_lib/src/graphics/vector/vectorimage.cpp @@ -38,7 +38,7 @@ VectorImage::~VectorImage() { } -VectorImage* VectorImage::clone() +VectorImage* VectorImage::clone() const { return new VectorImage(*this); } @@ -594,8 +594,9 @@ void VectorImage::setSelected(int curveNumber, bool YesOrNo) { if (mCurves.isEmpty()) return; + mCurves[curveNumber].setVertexSelected(YesOrNo); mCurves[curveNumber].setSelected(YesOrNo); - + if (YesOrNo) mSelectionRect |= mCurves[curveNumber].getBoundingRect(); modification(); @@ -610,7 +611,8 @@ void VectorImage::setSelected(int curveNumber, bool YesOrNo) void VectorImage::setSelected(int curveNumber, int vertexNumber, bool YesOrNo) { if (mCurves.isEmpty()) return; - mCurves[curveNumber].setSelected(vertexNumber, YesOrNo); + mCurves[curveNumber].setVertexSelected(vertexNumber, YesOrNo); + mCurves[curveNumber].setSelected(YesOrNo); QPointF vertex = getVertex(curveNumber, vertexNumber); if (YesOrNo) mSelectionRect |= QRectF(vertex.x(), vertex.y(), 0.0, 0.0); @@ -636,7 +638,7 @@ void VectorImage::setSelected(QList curveList, bool YesOrNo) { for (int i = 0; i < curveList.size(); i++) { - setSelected(curveList.at(i), YesOrNo); + setSelected(curveList.at(i), YesOrNo); } } @@ -645,11 +647,21 @@ void VectorImage::setSelected(QList curveList, bool YesOrNo) * @param QList vertexList * @param YesOrNo: bool */ -void VectorImage::setSelected(QList vertexList, bool YesOrNo) +void VectorImage::setSelected(const QList curveList, const QList vertexList, const bool YesOrNo) { - for (int i = 0; i < vertexList.size(); i++) - { - setSelected(vertexList.at(i), YesOrNo); + for (int curveI = 0; curveI < curveList.size(); curveI++) { + int curveNumber = curveList.at(curveI); + + if (!vertexList.isEmpty()) { + for (int i = 0; i < vertexList.size(); i++) + { + setSelected(curveNumber, vertexList.at(i).vertexNumber, YesOrNo); + } + } else { + mCurves[curveNumber].setSelected(YesOrNo); + mSelectionRect |= mCurves[curveNumber].getBoundingRect(); + modification(); + } } } @@ -705,6 +717,18 @@ bool VectorImage::isSelected(int curveNumber) return mCurves[curveNumber].isSelected(); } +bool VectorImage::isSelected() +{ + bool anySelected = false; + for (BezierCurve curve : mCurves) { + anySelected = curve.isCurveSelected(); + if (anySelected) { + break; + } + } + return anySelected; +} + /** * @brief VectorImage::isSelected * @param curveNumber: The curve you wish to check @@ -743,15 +767,18 @@ bool VectorImage::isSelected(QList curveList) /** * @brief VectorImage::isSelected + * Is any point selected from the input list * @param vertexList: list of vertices you wish to check * @return bool */ bool VectorImage::isSelected(QList vertexList) { - bool result = true; + bool result = false; for (int i = 0; i < vertexList.size(); i++) { - result &= isSelected(vertexList.at(i)); + if (isSelected(vertexList.at(i))) { + return true; + } } return result; } @@ -791,7 +818,12 @@ void VectorImage::selectAll() { for (int i = 0; i < mCurves.size(); i++) { - setSelected(i, true); + BezierCurve bCurve = mCurves[i]; + for (int vertex = 0; vertex < bCurve.getVertexSize(); vertex++) { + + setSelected(i, vertex, true); + } + mSelectionRect |= mCurves[i].getBoundingRect(); } mSelectionTransformation.reset(); } @@ -810,6 +842,15 @@ bool VectorImage::isAnyCurveSelected() return false; } + +bool VectorImage::transformModified(const QTransform newTransform) +{ + if (mSelectionTransformation != newTransform) { + return true; + } + return false; +} + /** * @brief VectorImage::deselectAll */ @@ -819,6 +860,7 @@ void VectorImage::deselectAll() for (int i = 0; i < mCurves.size(); i++) { mCurves[i].setSelected(false); + mCurves[i].setVertexSelected(false); } for (int i = 0; i < mArea.size(); i++) { @@ -989,8 +1031,9 @@ void VectorImage::removeVertex(int curve, int vertex) /** * @brief VectorImage::deleteSelectedPoints */ -void VectorImage::deleteSelectedPoints() +bool VectorImage::deleteSelectedPoints() { + bool deleted = false; for (int i = 0; i < mCurves.size(); i++) { for (int m = -1; m < getCurveSize(i); m++) @@ -998,10 +1041,12 @@ void VectorImage::deleteSelectedPoints() if (mCurves.at(i).isSelected(m)) // point m of curve i is selected { removeVertex(i, m); + deleted = true; } } } modification(); + return deleted; } /** diff --git a/core_lib/src/graphics/vector/vectorimage.h b/core_lib/src/graphics/vector/vectorimage.h index 7ec14be6e4..459b6ed62c 100644 --- a/core_lib/src/graphics/vector/vectorimage.h +++ b/core_lib/src/graphics/vector/vectorimage.h @@ -37,7 +37,7 @@ class VectorImage : public KeyFrame VectorImage(const VectorImage&); virtual ~VectorImage(); - VectorImage* clone() override; + VectorImage* clone() const override; void setObject(Object* pObj) { mObject = pObj; } @@ -57,13 +57,16 @@ class VectorImage : public KeyFrame void setSelected(int curveNumber, int vertexNumber, bool YesOrNo); 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(); bool isSelected(int curveNumber); bool isSelected(int curveNumber, int vertexNumber); bool isSelected(VertexRef vertexRef); bool isSelected(QList curveList); bool isSelected(QList vertexList); bool isAnyCurveSelected(); + bool isAnyVertexSelected(); + bool transformModified(const QTransform newTransform); void setAreaSelected(int areaNumber, bool YesOrNo); bool isAreaSelected(int areaNumber); bool isPathFilled(); @@ -77,7 +80,7 @@ class VectorImage : public KeyFrame void setSelectionRect(QRectF rectange); void calculateSelectionRect(); void deleteSelection(); - void deleteSelectedPoints(); + bool deleteSelectedPoints(); void removeVertex(int curve, int vertex); void paste(VectorImage&); diff --git a/core_lib/src/graphics/vector/vectorselection.cpp b/core_lib/src/graphics/vector/vectorselection.cpp index e23f7dc608..2648ee2ca1 100644 --- a/core_lib/src/graphics/vector/vectorselection.cpp +++ b/core_lib/src/graphics/vector/vectorselection.cpp @@ -23,27 +23,34 @@ VectorSelection::VectorSelection() void VectorSelection::clear() { - vertex.clear(); - curve.clear(); + vertices.clear(); + curves.clear(); } void VectorSelection::add(int curveNumber) { - curve << curveNumber; + curves.append(curveNumber); } void VectorSelection::add(QList list) { - if (list.size() > 0) add(list[0]); + if (list.size() > 0) + + for (int num : list) { + add(num); + } } void VectorSelection::add(VertexRef point) { - vertex << point; + vertices << point; add(point.curveNumber); } void VectorSelection::add(QList list) { - if (list.size() > 0) add(list[0]); + if (list.size() > 0) + for (VertexRef ref : list) { + add(ref); + } } diff --git a/core_lib/src/graphics/vector/vectorselection.h b/core_lib/src/graphics/vector/vectorselection.h index 488995dde4..72a8c55942 100644 --- a/core_lib/src/graphics/vector/vectorselection.h +++ b/core_lib/src/graphics/vector/vectorselection.h @@ -33,8 +33,10 @@ class VectorSelection void add(VertexRef point); void add(QList points); - QList vertex; - QList curve; + bool isEmpty() const { return vertices.isEmpty() && curves.isEmpty(); } + + QList vertices; + QList curves; }; #endif // VECTORSELECTION_H diff --git a/core_lib/src/interface/backupelement.cpp b/core_lib/src/interface/backupelement.cpp new file mode 100755 index 0000000000..4d5262b25d --- /dev/null +++ b/core_lib/src/interface/backupelement.cpp @@ -0,0 +1,1439 @@ +/* + +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 +#include "QProgressDialog" + +#include "layermanager.h" +#include "backupmanager.h" +#include "viewmanager.h" +#include "selectionmanager.h" +#include "keyframemanager.h" +#include "canvasmanager.h" + +#include "layersound.h" +#include "layerbitmap.h" +#include "layervector.h" +#include "layercamera.h" + +#include "editor.h" +#include "backupelement.h" + +#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() +{ +} + +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(); + if (selectMan->somethingSelected()) { + BitmapImage selectionBitmap = newBitmap->transformed(selectMan->mySelectionRect().toRect(), + selectMan->selectionTransform(), + false); + + newBitmap->clear(selectMan->mySelectionRect().toRect()); + newBitmap->paste(&selectionBitmap, QPainter::CompositionMode_SourceOver); + } + + 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()->scrubTo(oldLayerId, oldFrameIndex); +} + +void AddBitmapElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + const TransformElement* childElem = static_cast(this->child(0)); + if (childElem) + { + redoTransform(childElem); + } + else + { + 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) ? true : false; + + if (description.isEmpty() && !isSequence) + { + switch (layer->type()) + { + 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 AddKeyFrameElement::undo() +{ + qDebug() << "key remove triggered"; + bool isSequence = (oldKeySpacing > 1) ? true : false; + 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) ? true : false; + + 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) ? true : false; + + 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.curves, oldVectorSelection.vertices, true); + selectMan->setSelection(vectorImage->getSelectionRect()); + selectMan->setVectorSelection(oldVectorSelection); + } + + KeyFrame* cKeyFrame = editor()->keyframes()->currentKeyFrame(layer); + 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.curves, oldVectorSelection.vertices, true); + selectMan->setVectorSelection(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.curves, newVectorSelection.vertices, true); + selectMan->setSelection(vectorImage->getSelectionRect()); + selectMan->setVectorSelection(newVectorSelection); + } +} + +void SelectionElement::redoDeselection() +{ + auto selectMan = editor()->select(); + + Layer* layer = editor()->layers()->findLayerById(layerId); + KeyFrame* cKeyFrame = editor()->keyframes()->currentKeyFrame(layer); + editor()->canvas()->applyTransformedSelection(layer, + cKeyFrame, + selectMan->selectionTransform(), + selectMan->mySelectionRect()); + + if (layer->type() == Layer::VECTOR) { + VectorImage* vectorImage = static_cast(layer)->getVectorImageAtFrame(frameIndex); + vectorImage->setSelected(newVectorSelection.curves, newVectorSelection.vertices, true); + selectMan->setVectorSelection(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->setVectorSelection(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(); + 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(isSelected); + selectMan->setScale(scaleX, scaleY); + + switch(layer->type()) + { + case Layer::BITMAP: + { + if (bitmapImage->isMinimallyBounded()) { + static_cast(layer)->replaceLastBitmapAtFrame(bitmapImage); + KeyFrame* cKeyFrame = editor()->keyframes()->currentKeyFrame(layer); + editor()->canvas()->paintTransformedSelection(layer, + cKeyFrame, + transform, + selectionRect); + } + break; + } + case Layer::VECTOR: + { + static_cast(layer)->replaceLastVectorAtFrame(vectorImage); + VectorImage* vecImage = editor()->keyframes()->currentVectorImage(layer); + 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(); + + importedKeyFrames = backupImportedKeyFrames; + oldKeyFrames = backupCanvasKeyFrames; + + setText(QObject::tr("Import images/s")); +} + +void ImportBitmapElement::undo() +{ + Editor* _editor = editor(); + for (auto key : importedKeyFrames) + { + _editor->removeKeyAtLayerId(oldLayerId,key.second->pos()); + } + + Layer* layer = _editor->layers()->findLayerById(oldLayerId); + int layerIndex = _editor->layers()->getLayerIndex(layer); + + // 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->addKeyFrameToLayer(layer, layerIndex, key.first, true); + layerBitmap->putBitmapIntoFrame(key.second, key.second->pos()); + } + _editor->updateCurrentFrame(); +} + +void ImportBitmapElement::redo() +{ + Editor* _editor = editor(); + if (isFirstRedo) + { + isFirstRedo = false; + return; + } + + Layer* layer = _editor->layers()->findLayerById(newLayerId); + int layerIndex = _editor->layers()->getLayerIndex(layer); + + LayerBitmap* layerBitmap = static_cast(layer); + for (auto key : importedKeyFrames) + { + _editor->addKeyFrameToLayer(layer, layerIndex, 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()) + { + case Layer::BITMAP: + { + newLayer = new LayerBitmap(layer->object()); + break; + } + case Layer::VECTOR: + { + newLayer = new LayerVector(layer->object()); + break; + } + case Layer::SOUND: + { + newLayer = new LayerSound(layer->object()); + break; + } + case Layer::CAMERA: + { + newLayer = new LayerCamera(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, newLayerType); + +} + +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, oldLayerType); + +} + +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)->getSelectedFrameIndexes(); + + 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); + layer->offsetSelectedFrames(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 FlipViewElement::undo() +{ + if (direction == DIRECTION::VERTICAL) + { + editor()->view()->flipVertical(!isFlipped); + } + else + { + editor()->view()->flipHorizontal(!isFlipped); + } +} + +void FlipViewElement::redo() +{ + + if (isFirstRedo) { isFirstRedo = false; return; } + + if (direction == DIRECTION::VERTICAL) + { + 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()->moveLayers(newLayerIndex, oldLayerIndex); + editor()->layers()->setCurrentLayer(oldLayerIndex); +} + +void MoveLayerElement::redo() +{ + if (isFirstRedo) { isFirstRedo = false; return; } + + editor()->moveLayers(oldLayerIndex, newLayerIndex); + editor()->layers()->setCurrentLayer(newLayerIndex); + +} diff --git a/core_lib/src/interface/backupelement.h b/core_lib/src/interface/backupelement.h old mode 100644 new mode 100755 index 31aea159d1..31a6a295f1 --- a/core_lib/src/interface/backupelement.h +++ b/core_lib/src/interface/backupelement.h @@ -19,62 +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 QUndoCommand +{ +public: + explicit BackupElement(Editor* editor, QUndoCommand* parent = nullptr); + virtual ~BackupElement(); + + Editor* editor() { return mEditor; } + + 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 TransformElement; + +class AddBitmapElement : public BackupElement +{ +public: + AddBitmapElement(const BitmapImage* backupBitmap, + const int& backupLayerId, + const DrawOnEmptyFrameAction& frameAction, + QString description, + Editor* editor, + QUndoCommand* parent = nullptr); + + 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; -class BackupElement : public QObject + 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; +}; + +class QProgressDialog; +class ImportBitmapElement : public BackupElement { - Q_OBJECT + public: - enum types { UNDEFINED, BITMAP_MODIF, VECTOR_MODIF, SOUND_MODIF }; + 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 CameraMotionElement : public BackupElement +{ +public: + + 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); + - QString undoText; - bool somethingSelected; - qreal rotationAngle; - QRectF mySelection, myTransformedSelection, myTempTransformedSelection; + QPointF oldTranslation = QPointF(0,0); + float oldRotation = 0.0f; + float oldScale = 0.0f; - virtual int type() { return UNDEFINED; } - virtual void restore(Editor*) { qDebug() << "Wrong"; } + QPointF newTranslation = QPointF(0,0); + float newRotation = 0.0f; + float newScale = 0.0f; + + int frameIndex = 0; + int layerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; + bool mergeWith(const QUndoCommand *other) override; + int id() const override { return Id; } }; -class BackupBitmapElement : public BackupElement +class AddLayerElement : public BackupElement { - Q_OBJECT public: - BackupBitmapElement(BitmapImage* bi) { bitmapImage = bi->copy(); } + AddLayerElement(Layer* backupLayer, + Editor* editor, + QUndoCommand* parent = nullptr); + + Layer* oldLayer; + Layer* newLayer; + + QString newLayerName; + + Layer::LAYER_TYPE newLayerType = Layer::UNDEFINED; - int layer, frame; - BitmapImage bitmapImage; - int type() { return BackupElement::BITMAP_MODIF; } - void restore(Editor*); + int newLayerId = 0; + int oldLayerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; }; -class BackupVectorElement : public BackupElement +class DeleteLayerElement : public BackupElement { - Q_OBJECT public: - BackupVectorElement(VectorImage* vi) { vectorImage = *vi; } - int layer, frame; - VectorImage vectorImage; + 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 type() { return BackupElement::VECTOR_MODIF; } - void restore(Editor*); + int oldLayerIndex = 0; + int oldFrameIndex = 0; + int oldLayerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; }; -class BackupSoundElement : public BackupElement +class RenameLayerElement : public BackupElement { - Q_OBJECT public: - BackupSoundElement(SoundClip* sound) { clip = *sound; } - int layer, frame; - SoundClip clip; - QString fileName; + RenameLayerElement(const QString& backupLayerName, + const int& backupLayerId, + Editor* editor, + QUndoCommand* parent = nullptr); + + QString oldLayerName; + QString newLayerName; + + int oldLayerIndex = 0; + int newLayerIndex = 0; + + int oldLayerId = 0; + int newLayerId = 0; + + bool isFirstRedo = true; + + void undo() override; + void redo() override; +}; + +class CameraPropertiesElement : public BackupElement +{ +public: + 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; + + 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() { return BackupElement::SOUND_MODIF; } - void restore( Editor* ); + 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 22802a594c..17227d8f8d 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -30,11 +30,12 @@ GNU General Public License for more details. #include "objectdata.h" #include "vectorimage.h" #include "bitmapimage.h" +#include "camera.h" #include "soundclip.h" #include "layerbitmap.h" #include "layervector.h" #include "layercamera.h" -#include "backupelement.h" +#include "activeframepool.h" #include "colormanager.h" #include "toolmanager.h" @@ -44,6 +45,9 @@ GNU General Public License for more details. #include "preferencemanager.h" #include "soundmanager.h" #include "selectionmanager.h" +#include "backupmanager.h" +#include "keyframemanager.h" +#include "canvasmanager.h" #include "scribblearea.h" #include "timeline.h" @@ -59,7 +63,6 @@ static VectorImage g_clipboardVectorImage; Editor::Editor(QObject* parent) : QObject(parent) { - mBackupIndex = -1; clipboardBitmapOk = false; clipboardVectorOk = false; clipboardSoundClipOk = false; @@ -68,7 +71,6 @@ Editor::Editor(QObject* parent) : QObject(parent) Editor::~Editor() { // a lot more probably needs to be cleaned here... - clearUndoStack(); } bool Editor::init() @@ -82,6 +84,9 @@ bool Editor::init() mPreferenceManager = new PreferenceManager(this); mSoundManager = new SoundManager(this); mSelectionManager = new SelectionManager(this); + mBackupManager = new BackupManager(this); + mKeyFrameManager = new KeyFrameManager(this); + mCanvasManager = new CanvasManager(this); mAllManagers = { @@ -92,7 +97,10 @@ bool Editor::init() mViewManager, mPreferenceManager, mSoundManager, - mSelectionManager + mSelectionManager, + mBackupManager, + mKeyFrameManager, + mCanvasManager }; for (BaseManager* pManager : mAllManagers) @@ -141,7 +149,8 @@ void Editor::dropEvent(QDropEvent* event) QString filePath = url.toLocalFile(); if (filePath.endsWith(".png") || filePath.endsWith(".jpg") || filePath.endsWith(".jpeg")) { - importImage(filePath); + bool isSequence = (i > 1) ? true : false; + importImage(filePath, isSequence); } //if ( filePath.endsWith( ".aif" ) || filePath.endsWith( ".mp3" ) || filePath.endsWith( ".wav" ) ) //importSound( filePath ); @@ -171,354 +180,24 @@ void Editor::settingUpdated(SETTING setting) } } -BackupElement* Editor::currentBackup() -{ - if (mBackupIndex >= 0) - { - return mBackupList[mBackupIndex]; - } - else - { - return nullptr; - } -} - -void Editor::backup(QString undoText) -{ - KeyFrame* frame = nullptr; - if (mLastModifiedLayer > -1 && mLastModifiedFrame > 0) - { - if (layers()->currentLayer()->type() == Layer::SOUND) - { - frame = layers()->currentLayer()->getKeyFrameWhichCovers(mLastModifiedFrame); - if (frame != nullptr) - { - backup(mLastModifiedLayer, frame->pos(), undoText); - } - } - else - { - backup(mLastModifiedLayer, mLastModifiedFrame, undoText); - } - } - if (mLastModifiedLayer != layers()->currentLayerIndex() || mLastModifiedFrame != currentFrame()) - { - if (layers()->currentLayer()->type() == Layer::SOUND) - { - frame = layers()->currentLayer()->getKeyFrameWhichCovers(currentFrame()); - - if (frame != nullptr) - { - backup(layers()->currentLayerIndex(), frame->pos(), undoText); - } - } - else - { - backup(layers()->currentLayerIndex(), currentFrame(), undoText); - } - } -} - -void Editor::backup(int backupLayer, int backupFrame, QString undoText) -{ - while (mBackupList.size() - 1 > mBackupIndex && mBackupList.size() > 0) - { - delete mBackupList.takeLast(); - } - while (mBackupList.size() > 19) // we authorize only 20 levels of cancellation - { - delete mBackupList.takeFirst(); - mBackupIndex--; - } - - Layer* layer = mObject->getLayer(backupLayer); - if (layer != nullptr) - { - if (layer->type() == Layer::BITMAP) - { - BitmapImage* bitmapImage = static_cast(layer)->getLastBitmapImageAtFrame(backupFrame, 0); - if (currentFrame() == 1) { - int previous = layer->getPreviousKeyFramePosition(backupFrame); - bitmapImage = static_cast(layer)->getBitmapImageAtFrame(previous); - } - if (bitmapImage != nullptr) - { - BackupBitmapElement* element = new BackupBitmapElement(bitmapImage); - element->layer = backupLayer; - element->frame = backupFrame; - element->undoText = undoText; - element->somethingSelected = select()->somethingSelected(); - element->mySelection = select()->mySelectionRect(); - element->myTransformedSelection = select()->myTransformedSelectionRect(); - element->myTempTransformedSelection = select()->myTempTransformedSelectionRect(); - element->rotationAngle = select()->myRotation(); - mBackupList.append(element); - mBackupIndex++; - } - } - else if (layer->type() == Layer::VECTOR) - { - VectorImage* vectorImage = static_cast(layer)->getLastVectorImageAtFrame(backupFrame, 0); - if (vectorImage != nullptr) - { - BackupVectorElement* element = new BackupVectorElement(vectorImage); - element->layer = backupLayer; - element->frame = backupFrame; - element->undoText = undoText; - element->somethingSelected = select()->somethingSelected(); - element->mySelection = select()->mySelectionRect(); - element->myTransformedSelection = select()->myTransformedSelectionRect(); - element->myTempTransformedSelection = select()->myTempTransformedSelectionRect(); - element->rotationAngle = select()->myRotation(); - mBackupList.append(element); - mBackupIndex++; - } - } - else if (layer->type() == Layer::SOUND) - { - int previous = layer->getPreviousKeyFramePosition(backupFrame); - KeyFrame* key = layer->getLastKeyFrameAtPosition(backupFrame); - - // in case tracks overlap, get previous frame - if (key == nullptr) - { - KeyFrame* previousKey = layer->getKeyFrameAt(previous); - key = previousKey; - } - if (key != nullptr) { - SoundClip* clip = static_cast(key); - if (clip) - { - BackupSoundElement* element = new BackupSoundElement(clip); - element->layer = backupLayer; - element->frame = backupFrame; - element->undoText = undoText; - element->fileName = clip->fileName(); - mBackupList.append(element); - mBackupIndex++; - } - } - } - } - - updateAutoSaveCounter(); - - emit updateBackup(); -} - -void Editor::restoreKey() -{ - BackupElement* lastBackupElement = mBackupList[mBackupIndex]; - - Layer* layer = nullptr; - int frame = 0; - int layerIndex = 0; - if (lastBackupElement->type() == BackupElement::BITMAP_MODIF) - { - BackupBitmapElement* lastBackupBitmapElement = static_cast(lastBackupElement); - layerIndex = lastBackupBitmapElement->layer; - frame = lastBackupBitmapElement->frame; - layer = object()->getLayer(layerIndex); - addKeyFrame(layerIndex, frame); - dynamic_cast(layer)->getBitmapImageAtFrame(frame)->paste(&lastBackupBitmapElement->bitmapImage); - } - if (lastBackupElement->type() == BackupElement::VECTOR_MODIF) - { - BackupVectorElement* lastBackupVectorElement = static_cast(lastBackupElement); - layerIndex = lastBackupVectorElement->layer; - frame = lastBackupVectorElement->frame; - layer = object()->getLayer(layerIndex); - addKeyFrame(layerIndex, frame); - dynamic_cast(layer)->getVectorImageAtFrame(frame)->paste(lastBackupVectorElement->vectorImage); - } - if (lastBackupElement->type() == BackupElement::SOUND_MODIF) - { - QString strSoundFile; - BackupSoundElement* lastBackupSoundElement = static_cast(lastBackupElement); - layerIndex = lastBackupSoundElement->layer; - frame = lastBackupSoundElement->frame; - - strSoundFile = lastBackupSoundElement->fileName; - KeyFrame* key = addKeyFrame(layerIndex, frame); - SoundClip* clip = dynamic_cast(key); - if (clip) - { - if (strSoundFile.isEmpty()) - { - return; - } - else - { - //Status st = sound()->pasteSound(clip, strSoundFile); - //Q_ASSERT(st.ok()); - } - } - } -} - -void BackupBitmapElement::restore(Editor* editor) -{ - Layer* layer = editor->object()->getLayer(this->layer); - auto selectMan = editor->select(); - selectMan->setSelection(mySelection); - selectMan->setTransformedSelectionRect(myTransformedSelection); - selectMan->setTempTransformedSelectionRect(myTempTransformedSelection); - selectMan->setRotation(rotationAngle); - selectMan->setSomethingSelected(somethingSelected); - - editor->updateFrame(this->frame); - editor->scrubTo(this->frame); - - if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) - { - editor->restoreKey(); - } - else - { - if (layer != nullptr) - { - if (layer->type() == Layer::BITMAP) - { - auto pLayerBitmap = static_cast(layer); - *pLayerBitmap->getLastBitmapImageAtFrame(this->frame, 0) = this->bitmapImage; // restore the image - } - } - } -} - -void BackupVectorElement::restore(Editor* editor) -{ - Layer* layer = editor->object()->getLayer(this->layer); - auto selectMan = editor->select(); - selectMan->setSelection(mySelection); - selectMan->setTransformedSelectionRect(myTransformedSelection); - selectMan->setTempTransformedSelectionRect(myTempTransformedSelection); - selectMan->setRotation(rotationAngle); - selectMan->setSomethingSelected(somethingSelected); - - editor->updateFrameAndVector(this->frame); - editor->scrubTo(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()->getLayer(this->layer); - editor->updateFrame(this->frame); - editor->scrubTo(this->frame); - - // TODO: soundclip won't restore if overlapping on first frame - if (this->frame > 0 && layer->getKeyFrameAt(this->frame) == nullptr) - { - editor->restoreKey(); - } -} - -void Editor::undo() -{ - if (mBackupList.size() > 0 && mBackupIndex > -1) - { - if (mBackupIndex == mBackupList.size() - 1) - { - BackupElement* lastBackupElement = mBackupList[mBackupIndex]; - if (lastBackupElement->type() == BackupElement::BITMAP_MODIF) - { - BackupBitmapElement* lastBackupBitmapElement = static_cast(lastBackupElement); - backup(lastBackupBitmapElement->layer, lastBackupBitmapElement->frame, "NoOp"); - mBackupIndex--; - } - if (lastBackupElement->type() == BackupElement::VECTOR_MODIF) - { - BackupVectorElement* lastBackupVectorElement = static_cast(lastBackupElement); - backup(lastBackupVectorElement->layer, lastBackupVectorElement->frame, "NoOp"); - mBackupIndex--; - } - if (lastBackupElement->type() == BackupElement::SOUND_MODIF) - { - BackupSoundElement* lastBackupSoundElement = static_cast(lastBackupElement); - backup(lastBackupSoundElement->layer, lastBackupSoundElement->frame, "NoOp"); - mBackupIndex--; - } - } - - mBackupList[mBackupIndex]->restore(this); - mBackupIndex--; - mScribbleArea->cancelTransformedSelection(); - - Layer* layer = layers()->currentLayer(); - if (layer == nullptr) { return; } - - select()->resetSelectionTransform(); - if (layer->type() == Layer::VECTOR) { - VectorImage *vectorImage = static_cast(layer)->getVectorImageAtFrame(mFrame); - vectorImage->calculateSelectionRect(); - select()->setSelection(vectorImage->getSelectionRect()); - } - emit updateBackup(); - } -} - -void Editor::redo() +void Editor::cut() { - if (mBackupList.size() > 0 && mBackupIndex < mBackupList.size() - 2) - { - mBackupIndex++; - - mBackupList[mBackupIndex + 1]->restore(this); - emit updateBackup(); - } -} + backups()->saveStates(); + copy(); -void Editor::clearUndoStack() -{ - mBackupIndex = -1; - while (!mBackupList.isEmpty()) - { - delete mBackupList.takeLast(); + Layer* layer = layers()->currentLayer(); + if (layer->type() == Layer::VECTOR) { + keyframes()->currentVectorImage(layer)->deleteSelection(); + deselectAll(); + backups()->vector("Vector: Cut"); } - mLastModifiedLayer = -1; - mLastModifiedFrame = -1; -} - -void Editor::updateAutoSaveCounter() -{ - if (mIsAutosave == false) - return; - - mAutosaveCounter++; - if (mAutosaveCounter >= mAutosaveNumber) - { - resetAutoSaveCounter(); - emit needSave(); + if (layer->type() == Layer::BITMAP) { + keyframes()->currentBitmapImage(layer)->clear(select()->mySelectionRect()); + deselectAll(); + backups()->bitmap("Bitmap: Cut"); } } -void Editor::resetAutoSaveCounter() -{ - mAutosaveCounter = 0; -} - -void Editor::cut() -{ - copy(); - mScribbleArea->deleteSelection(); - deselectAll(); -} - void Editor::copy() { Layer* layer = mObject->getLayer(layers()->currentLayerIndex()); @@ -554,11 +233,12 @@ void Editor::paste() Layer* layer = mObject->getLayer(layers()->currentLayerIndex()); if (layer != nullptr) { + backups()->saveStates(); if (layer->type() == Layer::BITMAP && g_clipboardBitmapImage.image() != nullptr) { - backup(tr("Paste")); - BitmapImage tobePasted = g_clipboardBitmapImage.copy(); + + // TODO: paste doesn't remember location, will always paste on top of old image. qDebug() << "to be pasted --->" << tobePasted.image()->size(); if (select()->somethingSelected()) { @@ -574,14 +254,16 @@ void Editor::paste() } auto pLayerBitmap = static_cast(layer); pLayerBitmap->getLastBitmapImageAtFrame(currentFrame(), 0)->paste(&tobePasted); // paste the clipboard + + backups()->bitmap(tr("Bitmap: Paste")); } else if (layer->type() == Layer::VECTOR && clipboardVectorOk) { - backup(tr("Paste")); deselectAll(); VectorImage* vectorImage = (static_cast(layer))->getLastVectorImageAtFrame(currentFrame(), 0); vectorImage->paste(g_clipboardVectorImage); // paste the clipboard select()->setSelection(vectorImage->getSelectionRect()); + backups()->vector(tr("Vector: Paste")); } } mScribbleArea->updateCurrentFrame(); @@ -592,6 +274,18 @@ void Editor::flipSelection(bool flipVertical) mScribbleArea->flipSelection(flipVertical); } +void Editor::deselectAllSelections() +{ + backups()->deselect(); + emit deselectAll(); +} + +void Editor::deselectAllAndCancelTransform() +{ + backups()->deselect(); + emit deselectAll(); +} + void Editor::clipboardChanged() { if (clipboardBitmapOk == false) @@ -647,7 +341,6 @@ Status Editor::setObject(Object* newObject) return Status::SAFE; } - clearUndoStack(); mObject.reset(newObject); for (BaseManager* m : mAllManagers) @@ -788,24 +481,48 @@ bool Editor::importBitmapImage(QString filePath, int space) return false; } + backups()->saveStates(); + + std::map> canvasKeyFrames; + + for(auto map : layer->getKeysInLayer()) + { + // make sure file is loaded when trying to get bitmap from layer... + map.second->loadFile(); + canvasKeyFrames.insert(std::make_pair(map.first, map.second->clone())); + } + + std::map> importedKeyFrames; while (reader.read(&img)) { - if (!layer->keyExists(currentFrame())) + bool keyExisted = layer->keyExists(currentFrame()); + bool keyAdded = false; + KeyFrame* newKey = nullptr; + if (!keyExisted) { - addNewKey(); + newKey = addNewKey(); + keyAdded = true; } - BitmapImage* bitmapImage = layer->getBitmapImageAtFrame(currentFrame()); + BitmapImage* bitmapImage = layer->getBitmapImageAtFrame(currentFrame()); BitmapImage importedBitmapImage(mScribbleArea->getCentralPoint().toPoint() - QPoint(img.width() / 2, img.height() / 2), img); bitmapImage->paste(&importedBitmapImage); - if (space > 1) { + newKey = bitmapImage; + if (newKey != nullptr) { + newKey = newKey->clone(); + } + importedKeyFrames.insert(std::make_pair(newKey->pos(), newKey)); + + if (space > 1) + { scrubTo(currentFrame() + space); - } else { + } + else + { scrubTo(currentFrame() + 1); } - backup(tr("Import Image")); // Workaround for tiff import getting stuck in this loop if (!reader.supportsAnimation()) @@ -813,16 +530,18 @@ bool Editor::importBitmapImage(QString filePath, int space) break; } } + backups()->importBitmap(canvasKeyFrames, importedKeyFrames); return true; } -bool Editor::importVectorImage(QString filePath) +bool Editor::importVectorImage(QString filePath, bool /*isSequence*/) { Q_ASSERT(layers()->currentLayer()->type() == Layer::VECTOR); auto layer = static_cast(layers()->currentLayer()); + backups()->saveStates(); VectorImage* vectorImage = (static_cast(layer))->getVectorImageAtFrame(currentFrame()); if (vectorImage == nullptr) { @@ -837,23 +556,23 @@ bool Editor::importVectorImage(QString filePath) importedVectorImage.selectAll(); vectorImage->paste(importedVectorImage); - backup(tr("Import Image")); + backups()->vector(tr("Vector: Import")); } return ok; } -bool Editor::importImage(QString filePath) +bool Editor::importImage(QString filePath, bool isSequence) { Layer* layer = layers()->currentLayer(); switch (layer->type()) { case Layer::BITMAP: - return importBitmapImage(filePath); + return importBitmapImage(filePath, isSequence); case Layer::VECTOR: - return importVectorImage(filePath); + return importVectorImage(filePath, isSequence); default: { @@ -878,11 +597,22 @@ qreal Editor::viewScaleInversed() return view()->getViewInverse().m11(); } +void Editor::updateView() +{ + view()->updateViewTransforms(); + emit needPaint(); +} + void Editor::selectAll() { Layer* layer = layers()->currentLayer(); QRectF rect; + + canvas()->applyTransformedSelection(layer, + keyframes()->currentKeyFrame(layer), + select()->selectionTransform(), + select()->mySelectionRect()); if (layer->type() == Layer::BITMAP) { // Selects the drawn area (bigger or smaller than the screen). It may be more accurate to select all this way @@ -895,6 +625,7 @@ void Editor::selectAll() VectorImage *vectorImage = static_cast(layer)->getLastVectorImageAtFrame(mFrame,0); vectorImage->selectAll(); rect = vectorImage->getSelectionRect(); + select()->addCurvesToVectorSelection(vectorImage->getSelectedCurveNumbers()); } select()->setSelection(rect); emit updateCurrentFrame(); @@ -911,11 +642,12 @@ void Editor::deselectAll() } select()->resetSelectionProperties(); + emit needPaint(); } void Editor::updateFrame(int frameNumber) { - mScribbleArea->updateFrame(frameNumber); + emit needPaintAtFrame(frameNumber); } void Editor::updateFrameAndVector(int frameNumber) @@ -925,7 +657,7 @@ void Editor::updateFrameAndVector(int frameNumber) void Editor::updateCurrentFrame() { - mScribbleArea->updateCurrentFrame(); + emit needPaint(); } void Editor::setCurrentLayerIndex(int i) @@ -939,6 +671,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; } @@ -976,9 +720,21 @@ KeyFrame* Editor::addNewKey() return addKeyFrame(layers()->currentLayerIndex(), currentFrame()); } -KeyFrame* Editor::addKeyFrame(int layerNumber, int frameIndex) +KeyFrame* Editor::addKeyFrame(int layerIndex, int frameIndex) { - Layer* layer = mObject->getLayer(layerNumber); + return addKeyFrame(layerIndex, frameIndex, false); +} + +/** + * @brief Editor::addKeyFrame + * @param layerIndex + * @param frameIndex + * @param isLastFrame Set true if no more frames will be added, otherwise false. + * @return KeyFrame* + */ +KeyFrame* Editor::addKeyFrame(int layerIndex, int frameIndex, bool ignoreKeyExists) +{ + Layer* layer = mObject->getLayer(layerIndex); if (layer == nullptr) { Q_ASSERT(false); @@ -991,9 +747,12 @@ KeyFrame* Editor::addKeyFrame(int layerNumber, int frameIndex) return nullptr; } - while (layer->keyExists(frameIndex)) + if (!ignoreKeyExists) { - frameIndex += 1; + while (layer->keyExists(frameIndex)) + { + frameIndex += 1; + } } bool ok = layer->addNewKeyFrameAt(frameIndex); @@ -1001,13 +760,116 @@ KeyFrame* Editor::addKeyFrame(int layerNumber, int frameIndex) { scrubTo(frameIndex); // currentFrameChanged() emit inside. } + + if (layerIndex != currentLayerIndex()) + { + setCurrentLayerIndex(layerIndex); + } + return layer->getKeyFrameAt(frameIndex); } -void Editor::removeKey() +KeyFrame* Editor::addKeyFrameToLayerId(int layerId, int frameIndex) { - Layer* layer = layers()->currentLayer(); - Q_ASSERT(layer != nullptr); + return addKeyFrameToLayerId(layerId,frameIndex, false); +} + +KeyFrame* Editor::addKeyFrameToLayer(Layer* layer, const int layerIndex, int frameIndex, const bool ignoreKeyExists) +{ + if (layer == NULL) + { + Q_ASSERT(false); + return nullptr; + } + + if (!ignoreKeyExists) + { + while (layer->keyExists(frameIndex) && frameIndex > 1) + { + frameIndex += 1; + } + } + + bool ok = layer->addNewKeyFrameAt(frameIndex); + if (ok) + { + scrubTo(frameIndex); // currentFrameChanged() emit inside. + } + + if (layerIndex != currentLayerIndex()) + { + setCurrentLayerIndex(layerIndex); + } + + return layer->getKeyFrameAt(frameIndex); +} + +KeyFrame* Editor::addKeyFrameToLayerId(int layerId, int frameIndex, bool ignoreKeyExists) +{ + Layer* layer = layers()->findLayerById(layerId); + int layerIndex = layers()->getLayerIndex(layer); + if (layer == NULL) + { + Q_ASSERT(false); + return nullptr; + } + + if (!ignoreKeyExists) + { + while (layer->keyExists(frameIndex) && frameIndex > 1) + { + frameIndex += 1; + } + } + + bool ok = layer->addNewKeyFrameAt(frameIndex); + if (ok) + { + scrubTo(frameIndex); // currentFrameChanged() emit inside. + } + + if (layerIndex != currentLayerIndex()) + { + setCurrentLayerIndex(layerIndex); + } + + return layer->getKeyFrameAt(frameIndex); +} + + +/** + * @brief Editor::addKeyContaining + * Add a keyframe to the timeline which contains a keyframe + * @param layerIndex + * @param frameIndex + * @param key + * + */ +void Editor::addKeyContaining(int layerId, int frameIndex, KeyFrame* key) +{ + Layer* layer = layers()->findLayerById(layerId); + int layerIndex = layers()->getLayerIndex(layer); + while (layer->keyExistsWhichCovers(frameIndex)) + { + frameIndex += 1; + } + + bool ok = layer->addKeyFrame(frameIndex, key); + if (ok) + { + scrubTo(frameIndex); // currentFrameChanged() emit inside. + } + + if (layerIndex != currentLayerIndex()) + { + setCurrentLayerIndex(layerIndex); + } + +} + +void Editor::removeKeyAt(int layerIndex, int frameIndex) +{ + Layer* layer = layers()->getLayer(layerIndex); if (!layer->visible()) { @@ -1015,18 +877,53 @@ void Editor::removeKey() return; } - if (!layer->keyExistsWhichCovers(currentFrame())) + if (!layer->keyExistsWhichCovers(frameIndex)) { return; } - backup(tr("Remove frame")); + layer->removeKeyFrame(frameIndex); - deselectAll(); - layer->removeKeyFrame(currentFrame()); + if (!layer->keyExists(frameIndex) && frameIndex > 1) + { + frameIndex -= 1; + } + + scrubTo(frameIndex); + + if (layerIndex != currentLayerIndex()) + { + setCurrentLayerIndex(layerIndex); + } +} + +void Editor::removeKeyAtLayerId(int layerId, int frameIndex) +{ + Layer* layer = layers()->findLayerById(layerId); + int layerIndex = layers()->getLayerIndex(layer); + if (!layer->keyExistsWhichCovers(frameIndex)) + { + return; + } + + layer->removeKeyFrame(frameIndex); + + while (!layer->keyExists(frameIndex) && frameIndex > 1) + { + frameIndex -= 1; + } + + scrubTo(frameIndex); - scrubBackward(); - Q_EMIT layers()->currentLayerChanged(layers()->currentLayerIndex()); // trigger timeline repaint. + if (layerIndex != currentLayerIndex()) + { + setCurrentLayerIndex(layerIndex); + } +} + +void Editor::removeCurrentKey() +{ + removeKeyAt(currentLayerIndex(), currentFrame()); } void Editor::scrubNextKeyFrame() @@ -1061,16 +958,17 @@ void Editor::showLayerNotVisibleWarning() return mScribbleArea->showLayerNotVisibleWarning(); } -void Editor::swapLayers(int i, int j) +void Editor::moveLayers(const int& fromIndex, const int& toIndex) { - mObject->swapLayers(i, j); - if (j < i) + if (toIndex < fromIndex) // bubble up { - layers()->setCurrentLayer(j + 1); + for (int i = fromIndex - 1; i >= toIndex; i--) + mObject->swapLayers(i, i + 1); } - else + else // bubble down { - layers()->setCurrentLayer(j - 1); + for (int i = fromIndex + 1; i <= toIndex; i++) + mObject->swapLayers(i, i - 1); } emit updateTimeLine(); mScribbleArea->updateAllFrames(); @@ -1133,7 +1031,29 @@ void Editor::prepareSave() } } +/** + * @brief Editor::clearCurrentFrame + * Depending no the context, this will clear the keyframe.. + * for bitmap and vector that means wiping the canvas + * for camera it will reset the view + */ void Editor::clearCurrentFrame() { - mScribbleArea->clearImage(); + Layer* layer = layers()->currentLayer(); + switch(layer->type()) { + case Layer::BITMAP: + case Layer::VECTOR: { + mScribbleArea->clearImage(); + break; + } + case Layer::CAMERA: { + Camera* camera = static_cast(layer)->getCameraAtFrame(currentFrame()); + camera->reset(); + backups()->cameraMotion(tr("Camera: reset view")); + updateView(); + break; + } + default: + break; + } } diff --git a/core_lib/src/interface/editor.h b/core_lib/src/interface/editor.h index a315051272..add05b3995 100644 --- a/core_lib/src/interface/editor.h +++ b/core_lib/src/interface/editor.h @@ -38,12 +38,18 @@ class PlaybackManager; class ViewManager; class PreferenceManager; class SelectionManager; +class KeyFrameManager; +class CanvasManager; class SoundManager; class ScribbleArea; class TimeLine; class BackupElement; +class Layer; + +class BackupManager; class ActiveFramePool; + enum class SETTING; @@ -59,6 +65,9 @@ class Editor : public QObject Q_PROPERTY(PreferenceManager* preference READ preference) Q_PROPERTY(SoundManager* sound READ sound) Q_PROPERTY(SelectionManager* select READ select) + Q_PROPERTY(BackupManager* backups READ backups) + Q_PROPERTY(KeyFrameManager* keyframes READ keyframes) + Q_PROPERTY(CanvasManager* canvas READ canvas) public: explicit Editor(QObject* parent = nullptr); @@ -77,6 +86,9 @@ class Editor : public QObject PreferenceManager* preference() const { return mPreferenceManager; } SoundManager* sound() const { return mSoundManager; } SelectionManager* select() const { return mSelectionManager; } + BackupManager* backups() const { return mBackupManager; } + KeyFrameManager* keyframes() const { return mKeyFrameManager; } + CanvasManager* canvas() const { return mCanvasManager; } Object* object() const { return mObject.get(); } Status setObject(Object* object); @@ -93,6 +105,8 @@ class Editor : public QObject void setCurrentLayerIndex(int i); void scrubTo(int frameNumber); + void scrubTo(Layer* layer, const int frameIndex); + void scrubTo(const int layerId, const int frameIndex); int allLayers(); bool exportSeqCLI(QString filePath, LayerCamera* cameraLayer, QString format = "PNG", int width = -1, int height = -1, int startFrame = 1, int endFrame = -1, bool transparency = false, bool antialias = true); @@ -106,15 +120,9 @@ class Editor : public QObject void importMovie(QString filePath, int fps); - // backup - int mBackupIndex; - BackupElement* currentBackup(); - QList mBackupList; - Q_SIGNALS: void updateTimeLine(); void updateLayerCount(); - void updateBackup(); void objectLoaded(); @@ -130,7 +138,9 @@ class Editor : public QObject void cut(); - bool importImage(QString filePath); + void deselectAllSelections(); + void deselectAllAndCancelTransform(); + bool importImage(QString filePath, bool isSequence); bool importGIF(QString filePath, int numOfImages = 0); void updateFrame(int frameNumber); void restoreKey(); @@ -142,22 +152,30 @@ class Editor : public QObject void scrubPreviousKeyFrame(); void scrubForward(); void scrubBackward(); + void updateView(); KeyFrame* addNewKey(); + KeyFrame* addKeyFrame(int layerIndex, int frameIndex); + KeyFrame* addKeyFrame(int layerIndex, int frameIndex, bool ignoreKeyExists); + KeyFrame* addKeyFrameToLayerId(int layerId, int frameIndex, bool ignoreKeyExists); + KeyFrame* addKeyFrameToLayerId(int layerId, int frameIndex); + KeyFrame* addKeyFrameToLayer(Layer* layer, const int layerIndex, int frameIndex, const bool ignoreKeyExists); + void addKeyContaining(int layerId, int frameIndex, KeyFrame* key); + + void removeKey(); + void removeCurrentKey(); + void removeKeyAt(int layerIndex, int frameIndex); + void removeKeyAtLayerId(int layerId, int frameIndex); void switchVisibilityOfLayer(int layerNumber); void showLayerNotVisibleWarning(); - void swapLayers(int i, int j); + void moveLayers(const int& fromIndex, const int& toIndex); Status::StatusInt pegBarAlignment(QStringList layers); - void backup(QString undoText); - void backup(int layerNumber, int frameNumber, QString undoText); - void undo(); - void redo(); void copy(); - void paste(); + void clipboardChanged(); void toggleShowAllLayers(); void flipSelection(bool flipVertical); @@ -170,14 +188,18 @@ class Editor : public QObject bool autoSaveNeverAskAgain() { return mAutosaveNeverAskAgain; } void resetAutoSaveCounter(); +signals: + void needPaint(); + void needPaintAtFrame(int frameIndex); + protected: // Need to move to somewhere... void dragEnterEvent(QDragEnterEvent*); void dropEvent(QDropEvent*); private: - bool importBitmapImage(QString, int space = 0); - bool importVectorImage(QString); + bool importBitmapImage(QString, int space); + bool importVectorImage(QString, bool); // the object to be edited by the editor std::shared_ptr mObject = nullptr; @@ -195,6 +217,9 @@ class Editor : public QObject PreferenceManager* mPreferenceManager = nullptr; SoundManager* mSoundManager = nullptr; SelectionManager* mSelectionManager = nullptr; + BackupManager* mBackupManager = nullptr; + KeyFrameManager* mKeyFrameManager = nullptr; + CanvasManager* mCanvasManager = nullptr; std::vector< BaseManager* > mAllManagers; @@ -206,13 +231,6 @@ class Editor : public QObject bool mAutosaveNeverAskAgain = false; void makeConnections(); - KeyFrame* addKeyFrame(int layerNumber, int frameNumber); - - // backup - void clearUndoStack(); - void updateAutoSaveCounter(); - int mLastModifiedFrame = -1; - int mLastModifiedLayer = -1; // clipboard bool clipboardBitmapOk = true; diff --git a/core_lib/src/interface/historyviewerwidget.cpp b/core_lib/src/interface/historyviewerwidget.cpp new file mode 100644 index 0000000000..72fb666510 --- /dev/null +++ b/core_lib/src/interface/historyviewerwidget.cpp @@ -0,0 +1,27 @@ +#include "historyviewerwidget.h" +#include "editor.h" +#include "backupmanager.h" + +HistoryViewerWidget::HistoryViewerWidget( QWidget* parent ) : BaseDockWidget( parent ) +{ + setWindowTitle(tr("History", "HistoryViewerWidget window title")); + undoView = new QUndoView(); + undoView->setAttribute(Qt::WA_QuitOnClose, false); + undoView->setEmptyLabel("New canvas"); + setWidget(undoView); +} + +HistoryViewerWidget::~HistoryViewerWidget() +{ +} + +void HistoryViewerWidget::initUI() +{ + BackupManager* manager = editor()->backups(); + undoView->setStack(manager->undoStack()); +} + +void HistoryViewerWidget::updateUI() +{ + +} diff --git a/core_lib/src/interface/historyviewerwidget.h b/core_lib/src/interface/historyviewerwidget.h new file mode 100644 index 0000000000..1d03e6fa93 --- /dev/null +++ b/core_lib/src/interface/historyviewerwidget.h @@ -0,0 +1,20 @@ +#ifndef BACKUPCONTENTVIEWER_H +#define BACKUPCONTENTVIEWER_H + +#include +#include "basedockwidget.h" + +class HistoryViewerWidget : public BaseDockWidget +{ +public: + explicit HistoryViewerWidget( QWidget* parent ); + virtual ~HistoryViewerWidget(); + + QUndoView* undoView; + + void initUI() override; + void updateUI() override; + +}; + +#endif // BACKUPCONTENTVIEWER_H diff --git a/core_lib/src/interface/scribblearea.cpp b/core_lib/src/interface/scribblearea.cpp index daa4dd7584..9637e790f6 100644 --- a/core_lib/src/interface/scribblearea.cpp +++ b/core_lib/src/interface/scribblearea.cpp @@ -36,8 +36,11 @@ GNU General Public License for more details. #include "strokemanager.h" #include "layermanager.h" #include "playbackmanager.h" +#include "backupmanager.h" #include "viewmanager.h" #include "selectionmanager.h" +#include "keyframemanager.h" +#include "canvasmanager.h" ScribbleArea::ScribbleArea(QWidget* parent) : QWidget(parent), @@ -68,6 +71,9 @@ bool ScribbleArea::init() connect(mEditor->select(), &SelectionManager::selectionChanged, this, &ScribbleArea::updateCurrentFrame); connect(mEditor->select(), &SelectionManager::needPaintAndApply, this, &ScribbleArea::applySelectionChanges); connect(mEditor->select(), &SelectionManager::needDeleteSelection, this, &ScribbleArea::deleteSelection); + connect(mEditor->canvas(), &CanvasManager::needPaint, this, &ScribbleArea::updateCurrentFrame); + connect(mEditor, &Editor::needPaint, this, &ScribbleArea::updateCurrentFrame); + connect(mEditor, &Editor::needPaintAtFrame, this, &ScribbleArea::updateFrame); mDoubleClickTimer->setInterval(50); @@ -175,16 +181,20 @@ void ScribbleArea::updateCurrentFrame() void ScribbleArea::updateFrame(int frame) { - int frameNumber = mEditor->layers()->LastFrameAtFrame(frame); + Status::StatusInt status = mEditor->layers()->LastFrameAtLayer(frame); + int frameNumber = status.value; Q_ASSERT(frame >= 0); - if (mPixmapCacheKeys.size() <= static_cast(frame)) - { - mPixmapCacheKeys.resize(static_cast(frame + 10)); // a buffer - } - QPixmapCache::remove(mPixmapCacheKeys[static_cast(frameNumber)]); - mPixmapCacheKeys[static_cast(frameNumber)] = QPixmapCache::Key(); + if (status.errorcode == Status::OK) { + if (mPixmapCacheKeys.size() <= static_cast(frame)) + { + mPixmapCacheKeys.resize(static_cast(frame + 10)); // a buffer + } + + QPixmapCache::remove(mPixmapCacheKeys[static_cast(frameNumber)]); + mPixmapCacheKeys[static_cast(frameNumber)] = QPixmapCache::Key(); + } update(); } @@ -210,7 +220,10 @@ void ScribbleArea::updateAllVectorLayersAt(int frameNumber) Layer* layer = mEditor->object()->getLayer(i); if (layer->type() == Layer::VECTOR) { - currentVectorImage(layer)->modification(); + VectorImage* vectorImage = mEditor->keyframes()->currentVectorImage(layer); + if (vectorImage) { + vectorImage->modification(); + } } } updateFrame(frameNumber); @@ -267,35 +280,42 @@ void ScribbleArea::keyPressEvent(QKeyEvent *event) void ScribbleArea::keyEventForSelection(QKeyEvent* event) { auto selectMan = mEditor->select(); + auto backupMan = mEditor->backups(); + backupMan->saveStates(); switch (event->key()) { case Qt::Key_Right: selectMan->translate(QPointF(1, 0)); paintTransformedSelection(); + backupMan->transform(tr("Transform right")); break; case Qt::Key_Left: selectMan->translate(QPointF(-1, 0)); paintTransformedSelection(); + backupMan->transform(tr("Transform left")); break; case Qt::Key_Up: selectMan->translate(QPointF(0, -1)); paintTransformedSelection(); + backupMan->transform(tr("Transform up")); break; case Qt::Key_Down: selectMan->translate(QPointF(0, 1)); paintTransformedSelection(); + backupMan->transform(tr("Transform down")); break; case Qt::Key_Return: applyTransformedSelection(); mEditor->deselectAll(); + backupMan->transform("Deselect all"); break; case Qt::Key_Escape: mEditor->deselectAll(); cancelTransformedSelection(); + backupMan->transform("Cancel transformation"); break; case Qt::Key_Backspace: deleteSelection(); - mEditor->deselectAll(); break; case Qt::Key_Space: setTemporaryTool(HAND); // just call "setTemporaryTool()" to activate temporarily any tool @@ -369,10 +389,16 @@ void ScribbleArea::wheelEvent(QWheelEvent* event) if (mMouseInUse) return; Layer* layer = mEditor->layers()->currentLayer(); - if (layer->type() == Layer::CAMERA && !layer->visible()) + if (layer->type() == Layer::CAMERA) { - showLayerNotVisibleWarning(); // FIXME: crash when using tablets - return; + if (!layer->visible()) { + showLayerNotVisibleWarning(); // FIXME: crash when using tablets + return; + } + + BackupManager* backups = mEditor->backups(); + backups->saveStates(); + backups->cameraMotion(); } const QPoint pixels = event->pixelDelta(); @@ -570,6 +596,19 @@ bool ScribbleArea::isLayerPaintable() const return layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR; } +//bool ScribbleArea::isKeySane() const +//{ +// Layer* layer = mEditor->layers()->currentLayer(); +// if (!layer->keyExists(mEditor->currentFrame())) +// { +// return false; +// } +// else +// { +// return true; +// } +//} + bool ScribbleArea::allowSmudging() { ToolType toolType = currentTool()->type(); @@ -701,7 +740,7 @@ void ScribbleArea::paintBitmapBuffer() } // Clear the temporary pixel path - BitmapImage* targetImage = currentBitmapImage(layer); + BitmapImage* targetImage = mEditor->keyframes()->currentBitmapImage(layer); if (targetImage != nullptr) { QPainter::CompositionMode cm = QPainter::CompositionMode_SourceOver; @@ -730,9 +769,14 @@ void ScribbleArea::paintBitmapBuffer() update(rect); // Update the cache for the last key-frame. - auto lastKeyFramePosition = mEditor->layers()->LastFrameAtFrame(frameNumber); - QPixmapCache::remove(mPixmapCacheKeys[static_cast(lastKeyFramePosition)]); - mPixmapCacheKeys[static_cast(lastKeyFramePosition)] = QPixmapCache::Key(); + auto status = mEditor->layers()->LastFrameAtLayer(frameNumber); + + int lastKeyFramePosition = status.value; + + if (status.errorcode == Status::OK) { + QPixmapCache::remove(mPixmapCacheKeys[static_cast(lastKeyFramePosition)]); + mPixmapCacheKeys[static_cast(lastKeyFramePosition)] = QPixmapCache::Key(); + } layer->setModified(frameNumber, true); mBufferImg->clear(); @@ -745,7 +789,7 @@ void ScribbleArea::paintBitmapBufferRect(const QRect& rect) Layer* layer = mEditor->layers()->currentLayer(); Q_ASSERT(layer); - BitmapImage* targetImage = currentBitmapImage(layer); + BitmapImage* targetImage = mEditor->keyframes()->currentBitmapImage(layer); if (targetImage != nullptr) { @@ -883,6 +927,8 @@ void ScribbleArea::handleDrawingOnEmptyFrame() if (layer->getKeyFrameAt(frameNumber) == nullptr) { + + mEditor->backups()->saveStates(); // Drawing on an empty frame; take action based on preference. int action = mPrefs->getInt(SETTING::DRAW_ON_EMPTY_FRAME_ACTION); @@ -892,6 +938,7 @@ void ScribbleArea::handleDrawingOnEmptyFrame() { if (previousKeyFrame == nullptr) { mEditor->addNewKey(); + mEditor->backups()->keyAdded(); } break; } @@ -901,7 +948,8 @@ void ScribbleArea::handleDrawingOnEmptyFrame() { KeyFrame* dupKey = previousKeyFrame->clone(); layer->addKeyFrame(frameNumber, dupKey); - mEditor->scrubTo(frameNumber); + mEditor->scrubTo(frameNumber); // Refresh timeline. + mEditor->backups()->keyAdded(layer->description() + tr(": Duplicate key")); break; } // if the previous keyframe doesn't exist, @@ -909,6 +957,7 @@ void ScribbleArea::handleDrawingOnEmptyFrame() } case CREATE_NEW_KEY: mEditor->addNewKey(); + mEditor->backups()->keyAdded(); // Refresh canvas drawCanvas(frameNumber, mCanvas.rect()); @@ -921,20 +970,25 @@ void ScribbleArea::handleDrawingOnEmptyFrame() void ScribbleArea::paintEvent(QPaintEvent* event) { + if (!mMouseInUse || currentTool()->type() == MOVE || currentTool()->type() == HAND || mMouseRightButtonInUse) { // --- we retrieve the canvas from the cache; we create it if it doesn't exist int curIndex = mEditor->currentFrame(); - int frameNumber = mEditor->layers()->LastFrameAtFrame(curIndex); + Status::StatusInt status = mEditor->layers()->LastFrameAtLayer(curIndex); - QPixmapCache::Key cachedKey = mPixmapCacheKeys[static_cast(frameNumber)]; + int frameNumber = status.value; - if (!QPixmapCache::find(cachedKey, &mCanvas)) - { - drawCanvas(mEditor->currentFrame(), event->rect()); + if (status.errorcode == Status::OK) { + QPixmapCache::Key cachedKey = mPixmapCacheKeys[static_cast(frameNumber)]; - mPixmapCacheKeys[static_cast(frameNumber)] = QPixmapCache::insert(mCanvas); - //qDebug() << "Repaint canvas!"; + if (!QPixmapCache::find(cachedKey, &mCanvas)) + { + drawCanvas(mEditor->currentFrame(), event->rect()); + + mPixmapCacheKeys[static_cast(frameNumber)] = QPixmapCache::insert(mCanvas); + //qDebug() << "Repaint canvas!"; + } } } @@ -944,7 +998,7 @@ void ScribbleArea::paintEvent(QPaintEvent* event) Q_CHECK_PTR(layer); if (layer->type() == Layer::VECTOR) { - currentVectorImage(layer)->setModified(true); + mEditor->keyframes()->currentVectorImage(layer)->setModified(true); } } @@ -960,7 +1014,7 @@ void ScribbleArea::paintEvent(QPaintEvent* event) { if (layer->type() == Layer::VECTOR) { - VectorImage* vectorImage = currentVectorImage(layer); + VectorImage* vectorImage = mEditor->keyframes()->currentVectorImage(layer); switch (currentTool()->type()) { case SMUDGE: @@ -977,10 +1031,10 @@ void ScribbleArea::paintEvent(QPaintEvent* event) // ------------ vertices of the edited curves colour = QColor(200, 200, 200); painter.setBrush(colour); - VectorSelection vectorSelection = selectMan->vectorSelection; - for (int k = 0; k < vectorSelection.curve.size(); k++) + VectorSelection vectorSelection = selectMan->vectorSelection(); + for (int k = 0; k < vectorSelection.curves.size(); k++) { - int curveNumber = vectorSelection.curve.at(k); + int curveNumber = vectorSelection.curves.at(k); for (int vertexNumber = -1; vertexNumber < vectorImage->getCurveSize(curveNumber); vertexNumber++) { @@ -995,9 +1049,9 @@ void ScribbleArea::paintEvent(QPaintEvent* event) // ------------ selected vertices of the edited curves colour = QColor(100, 100, 255); painter.setBrush(colour); - for (int k = 0; k < vectorSelection.vertex.size(); k++) + for (int k = 0; k < vectorSelection.vertices.size(); k++) { - VertexRef vertexRef = vectorSelection.vertex.at(k); + VertexRef vertexRef = vectorSelection.vertices.at(k); QPointF vertexPoint = vectorImage->getVertex(vertexRef); QRectF rectangle0 = QRectF(mEditor->view()->mapCanvasToScreen(vertexPoint) - QPointF(3.0, 3.0), QSizeF(7, 7)); painter.drawRect(rectangle0); @@ -1006,7 +1060,7 @@ void ScribbleArea::paintEvent(QPaintEvent* event) colour = QColor(255, 0, 0); painter.setBrush(colour); QList closestVertices = selectMan->closestVertices(); - if (vectorSelection.curve.size() > 0) + if (vectorSelection.curves.size() > 0) { for (int k = 0; k < closestVertices.size(); k++) { @@ -1047,7 +1101,7 @@ void ScribbleArea::paintEvent(QPaintEvent* event) paintCanvasCursor(painter); } - mCanvasPainter.renderGrid(painter); + mEditor->canvas()->canvasPainter()->renderGrid(painter); // paints the selection outline if (mEditor->select()->somethingSelected()) @@ -1086,20 +1140,6 @@ void ScribbleArea::paintSelectionVisuals() mSelectionPainter.paint(painter, object, mEditor->currentLayerIndex(), currentTool(), params); } -BitmapImage* ScribbleArea::currentBitmapImage(Layer* layer) const -{ - Q_ASSERT(layer->type() == Layer::BITMAP); - auto bitmapLayer = static_cast(layer); - return bitmapLayer->getLastBitmapImageAtFrame(mEditor->currentFrame()); -} - -VectorImage* ScribbleArea::currentVectorImage(Layer* layer) const -{ - Q_ASSERT(layer->type() == Layer::VECTOR); - auto vectorLayer = (static_cast(layer)); - return vectorLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); -} - void ScribbleArea::drawCanvas(int frame, QRect rect) { Object* object = mEditor->object(); @@ -1125,14 +1165,14 @@ void ScribbleArea::drawCanvas(int frame, QRect rect) o.scaling = mEditor->view()->scaling(); o.onionWhilePlayback = mPrefs->getInt(SETTING::ONION_WHILE_PLAYBACK); o.isPlaying = mEditor->playback()->isPlaying() ? true : false; - mCanvasPainter.setOptions(o); - mCanvasPainter.setCanvas(&mCanvas); + auto canvasMan = mEditor->canvas(); + canvasMan->canvasPainter()->setOptions(o); + canvasMan->canvasPainter()->setCanvas(&mCanvas); ViewManager* vm = mEditor->view(); - mCanvasPainter.setViewTransform(vm->getView(), vm->getViewInverse()); - - mCanvasPainter.paint(object, mEditor->layers()->currentLayerIndex(), frame, rect); + canvasMan->canvasPainter()->setViewTransform(vm->getView(), vm->getViewInverse()); + canvasMan->canvasPainter()->paint(object, mEditor->layers()->currentLayerIndex(), frame, rect); } void ScribbleArea::setGaussianGradient(QGradient &gradient, QColor colour, qreal opacity, qreal offset) @@ -1279,7 +1319,7 @@ void ScribbleArea::drawPolyline(QPainterPath path, QPen pen, bool useAA) QRectF ScribbleArea::getCameraRect() { - return mCanvasPainter.getCameraRect(); + return mEditor->canvas()->canvasPainter()->getCameraRect(); } QPointF ScribbleArea::getCentralPoint() @@ -1298,17 +1338,11 @@ void ScribbleArea::paintTransformedSelection() auto selectMan = mEditor->select(); if (selectMan->somethingSelected()) // there is something selected { - if (layer->type() == Layer::BITMAP) - { - mCanvasPainter.setTransformedSelection(selectMan->mySelectionRect().toRect(), selectMan->selectionTransform()); - } - else if (layer->type() == Layer::VECTOR) - { - // vector transformation - VectorImage* vectorImage = currentVectorImage(layer); - vectorImage->setSelectionTransformation(selectMan->selectionTransform()); - - } + KeyFrame* cKeyFrame = mEditor->keyframes()->currentKeyFrame(layer); + mEditor->canvas()->paintTransformedSelection(layer, + cKeyFrame, + selectMan->selectionTransform(), + selectMan->mySelectionRect()); setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); } update(); @@ -1341,8 +1375,6 @@ void ScribbleArea::applySelectionChanges() void ScribbleArea::applyTransformedSelection() { - mCanvasPainter.ignoreTransformedSelection(); - Layer* layer = mEditor->layers()->currentLayer(); if (layer == nullptr) { @@ -1352,22 +1384,11 @@ void ScribbleArea::applyTransformedSelection() auto selectMan = mEditor->select(); if (selectMan->somethingSelected()) { - if (selectMan->mySelectionRect().isEmpty()) { return; } - - if (layer->type() == Layer::BITMAP) - { - BitmapImage* bitmapImage = currentBitmapImage(layer); - BitmapImage transformedImage = bitmapImage->transformed(selectMan->mySelectionRect().toRect(), selectMan->selectionTransform(), true); - - bitmapImage->clear(selectMan->mySelectionRect()); - bitmapImage->paste(&transformedImage, QPainter::CompositionMode_SourceOver); - } - else if (layer->type() == Layer::VECTOR) - { - VectorImage* vectorImage = currentVectorImage(layer); - vectorImage->applySelectionTransformation(); - - } + KeyFrame* cKeyFrame = mEditor->keyframes()->currentKeyFrame(layer); + mEditor->canvas()->applyTransformedSelection(layer, + cKeyFrame, + selectMan->selectionTransform(), + selectMan->mySelectionRect()); setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); } @@ -1377,24 +1398,16 @@ void ScribbleArea::applyTransformedSelection() void ScribbleArea::cancelTransformedSelection() { - mCanvasPainter.ignoreTransformedSelection(); + mEditor->canvas()->ignoreTransformedSelection(); auto selectMan = mEditor->select(); if (selectMan->somethingSelected()) { Layer* layer = mEditor->layers()->currentLayer(); - if (layer == nullptr) { return; } - - if (layer->type() == Layer::VECTOR) { - - VectorImage* vectorImage = currentVectorImage(layer); - vectorImage->setSelectionTransformation(QTransform()); - } - + KeyFrame* cKeyFrame = mEditor->keyframes()->currentKeyFrame(layer); + mEditor->canvas()->cancelTransformedSelection(layer, cKeyFrame); mEditor->select()->setSelection(selectMan->mySelectionRect()); - selectMan->resetSelectionProperties(); - updateCurrentFrame(); } } @@ -1405,7 +1418,7 @@ void ScribbleArea::displaySelectionProperties() if (layer == nullptr) { return; } if (layer->type() == Layer::VECTOR) { - VectorImage* vectorImage = currentVectorImage(layer); + VectorImage* vectorImage = mEditor->keyframes()->currentVectorImage(layer); //vectorImage->applySelectionTransformation(); if (currentTool()->type() == MOVE) { @@ -1430,14 +1443,20 @@ void ScribbleArea::displaySelectionProperties() void ScribbleArea::toggleThinLines() { - bool previousValue = mPrefs->isOn(SETTING::INVISIBLE_LINES); - setEffect(SETTING::INVISIBLE_LINES, !previousValue); +// BackupManager* backup = editor()->backups(); + + bool previousValue = !mPrefs->isOn(SETTING::INVISIBLE_LINES); + setEffect(SETTING::INVISIBLE_LINES, previousValue); +// backup->toggleSetting(previousValue, SETTING::INVISIBLE_LINES); } void ScribbleArea::toggleOutlines() { +// BackupManager* backup = editor()->backups(); mIsSimplified = !mIsSimplified; setEffect(SETTING::OUTLINES, mIsSimplified); + +// backup->toggleSetting(mIsSimplified, SETTING::OUTLINES); } void ScribbleArea::toggleShowAllLayers() @@ -1515,11 +1534,18 @@ void ScribbleArea::deleteSelection() Layer* layer = mEditor->layers()->currentLayer(); if (layer == nullptr) { return; } - mEditor->backup(tr("Delete Selection", "Undo Step: clear the selection area.")); + mEditor->backups()->saveStates(); selectMan->clearCurves(); - if (layer->type() == Layer::VECTOR) { currentVectorImage(layer)->deleteSelection(); } - if (layer->type() == Layer::BITMAP) { currentBitmapImage(layer)->clear(selectMan->mySelectionRect()); } + auto keyframeMan = mEditor->keyframes(); + if (layer->type() == Layer::VECTOR) { + keyframeMan->currentVectorImage(layer)->deleteSelection(); + mEditor->backups()->vector("Vector: Clear Selection"); + } + if (layer->type() == Layer::BITMAP) { + keyframeMan->currentBitmapImage(layer)->clear(selectMan->mySelectionRect()); + mEditor->backups()->bitmap("Bitmap: Clear Selection"); + } updateAllFrames(); } } @@ -1529,18 +1555,19 @@ void ScribbleArea::clearImage() Layer* layer = mEditor->layers()->currentLayer(); if (layer == nullptr) { return; } + mEditor->backups()->saveStates(); if (layer->type() == Layer::VECTOR) { - mEditor->backup(tr("Clear Image", "Undo step text")); - - currentVectorImage(layer)->clear(); + mEditor->keyframes()->currentVectorImage(layer)->clear(); mEditor->select()->clearCurves(); mEditor->select()->clearVertices(); + + mEditor->backups()->vector(tr("Vector: Clear frame")); } else if (layer->type() == Layer::BITMAP) { - mEditor->backup(tr("Clear Image", "Undo step text")); - currentBitmapImage(layer)->clear(); + mEditor->keyframes()->currentBitmapImage(layer)->clear(); + mEditor->backups()->bitmap(tr("Bitmap: Clear frame")); } else { diff --git a/core_lib/src/interface/scribblearea.h b/core_lib/src/interface/scribblearea.h index f445fafd05..5ad3189a60 100644 --- a/core_lib/src/interface/scribblearea.h +++ b/core_lib/src/interface/scribblearea.h @@ -186,9 +186,6 @@ public slots: void settingUpdated(SETTING setting); void paintSelectionVisuals(); - BitmapImage* currentBitmapImage(Layer* layer) const; - VectorImage* currentVectorImage(Layer* layer) const; - MoveMode mMoveMode = MoveMode::NONE; ToolType mPrevTemporalToolType = ERASER; ToolType mPrevToolType = PEN; // previous tool (except temporal) @@ -236,7 +233,6 @@ public slots: PreferenceManager* mPrefs = nullptr; QPixmap mCanvas; - CanvasPainter mCanvasPainter; SelectionPainter mSelectionPainter; // Pixmap Cache keys diff --git a/core_lib/src/interface/timeline.cpp b/core_lib/src/interface/timeline.cpp index 76d15faa47..c19d1e0406 100644 --- a/core_lib/src/interface/timeline.cpp +++ b/core_lib/src/interface/timeline.cpp @@ -216,9 +216,10 @@ void TimeLine::initUI() connect(newCameraLayerAct, &QAction::triggered, this, &TimeLine::newCameraLayer); connect(removeLayerButton, &QPushButton::clicked, this, &TimeLine::deleteCurrentLayer); - connect(mLayerList, &TimeLineCells::mouseMovedY, mLayerList, &TimeLineCells::setMouseMoveY); - connect(mLayerList, &TimeLineCells::mouseMovedY, mTracks, &TimeLineCells::setMouseMoveY); - connect(mTracks, &TimeLineCells::lengthChanged, this, &TimeLine::updateLength); + connect( mLayerList, &TimeLineCells::mouseMovedY, mLayerList, &TimeLineCells::setMouseMoveY ); + connect( mLayerList, &TimeLineCells::mouseMovedY, mTracks, &TimeLineCells::setMouseMoveY ); + connect( mLayerList, &TimeLineCells::modifiedCamera, this, &TimeLine::modifiedCamera ); + connect( mTracks, &TimeLineCells::lengthChanged, this, &TimeLine::updateLength ); connect(editor(), &Editor::currentFrameChanged, this, &TimeLine::updateFrame); @@ -281,28 +282,7 @@ void TimeLine::wheelEvent(QWheelEvent* event) } } -void TimeLine::deleteCurrentLayer() -{ - LayerManager* layerMgr = editor()->layers(); - QString strLayerName = layerMgr->currentLayer()->name(); - - int ret = QMessageBox::warning(this, - tr("Delete Layer", "Windows title of Delete current layer pop-up."), - tr("Are you sure you want to delete layer: ") + strLayerName + " ?", - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Ok); - if (ret == QMessageBox::Ok) - { - Status st = layerMgr->deleteLayer(editor()->currentLayerIndex()); - if (st == Status::ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER) - { - QMessageBox::information(this, "", - tr("Please keep at least one camera layer in project")); - } - } -} - -void TimeLine::updateFrame(int frameNumber) +void TimeLine::updateFrame( int frameNumber ) { Q_ASSERT(mTracks); diff --git a/core_lib/src/interface/timeline.h b/core_lib/src/interface/timeline.h index a120da7850..8522cd1d73 100644 --- a/core_lib/src/interface/timeline.h +++ b/core_lib/src/interface/timeline.h @@ -65,12 +65,16 @@ class TimeLine : public BaseDockWidget void newSoundLayer(); void newCameraLayer(); + void deleteCurrentLayer(); + void soundClick( bool ); void fpsChanged( int ); void onionPrevClick(); void onionNextClick(); void playButtonTriggered(); + void modifiedCamera(); + public: bool scrubbing = false; @@ -79,7 +83,6 @@ class TimeLine : public BaseDockWidget void wheelEvent( QWheelEvent* ) override; private: - void deleteCurrentLayer(); QScrollBar* mHScrollbar = nullptr; diff --git a/core_lib/src/interface/timelinecells.cpp b/core_lib/src/interface/timelinecells.cpp index 7e422544ad..d132cae979 100644 --- a/core_lib/src/interface/timelinecells.cpp +++ b/core_lib/src/interface/timelinecells.cpp @@ -27,6 +27,7 @@ GNU General Public License for more details. #include "layermanager.h" #include "playbackmanager.h" #include "preferencemanager.h" +#include "backupmanager.h" #include "toolmanager.h" @@ -461,6 +462,15 @@ void TimeLineCells::resizeEvent(QResizeEvent* event) void TimeLineCells::mousePressEvent(QMouseEvent* event) { + if ( primaryButton != Qt::NoButton ) return; + + // a right-click simulated by control-click does not always trigger a move nor release event + // this causes primary button to be in a wrong state until the same key is pressed again + // workaround is to simply ignore right-click + if (eventIsControlClick(event->modifiers())) { + return; + } + int frameNumber = getFrameNumber(event->pos().x()); int layerNumber = getLayerNumber(event->pos().y()); mFromLayer = mToLayer = layerNumber; @@ -485,6 +495,8 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) bool switchLayer = mEditor->tools()->currentTool()->switchingLayer(); if (!switchLayer) { return; } + mEditor->backups()->saveStates(); + switch (mType) { case TIMELINE_CELL_TYPE::Layers: @@ -494,8 +506,12 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) { mEditor->switchVisibilityOfLayer(layerNumber); } - else + else // Clicked on another layer { + Layer* currentLayer = mEditor->layers()->currentLayer(); + if (!currentLayer->getSelectedFrameIndexes().isEmpty()) { + currentLayer->deselectAll(); + } mEditor->layers()->setCurrentLayer(layerNumber); } } @@ -508,6 +524,8 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) } break; case TIMELINE_CELL_TYPE::Tracks: + + auto backupMan = mEditor->backups(); if (event->button() == Qt::MidButton) { mLastFrameNumber = getFrameNumber(event->pos().x()); @@ -520,7 +538,13 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) { mEditor->playback()->stop(); } - mTimeLine->scrubbing = true; + + if (!mEditor->layers()->currentLayer()->isFrameSelected(frameNumber)) { + mTimeLine->scrubbing = true; + mCanMoveFrame = false; + } else { + mCanMoveFrame = true; + } } else { @@ -530,8 +554,11 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) if (previousLayerNumber != layerNumber) { Layer *previousLayer = mEditor->object()->getLayer(previousLayerNumber); - previousLayer->deselectAll(); + if (!previousLayer->getSelectedFrameIndexes().isEmpty()) { + previousLayer->deselectAll(); + backupMan->frameDeselected(QList(), frameNumber); + } mEditor->layers()->setCurrentLayer(layerNumber); } @@ -542,9 +569,9 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) { // If it is the case, we select everything that is after the selected frame mClickSelecting = true; - mCanMoveFrame = true; currentLayer->selectAllFramesAfter(frameNumber); + mDidExtendSelection = true; } // Check if we are clicking on a non selected frame else if (!currentLayer->isFrameSelected(frameNumber)) @@ -556,17 +583,22 @@ void TimeLineCells::mousePressEvent(QMouseEvent* event) if (event->modifiers() == Qt::ControlModifier) { // Add/remove from already selected - currentLayer->toggleFrameSelected(frameNumber, true); + Q_UNUSED(currentLayer->toggleFrameSelected(frameNumber, true)) + mDidExtendSelection = true; } else if (event->modifiers() == Qt::ShiftModifier) { - // Select a range from the last selected - currentLayer->extendSelectionTo(frameNumber); + Q_UNUSED(currentLayer->toggleFrameSelected(frameNumber)) + mDidExtendSelection = true; } else { + if (!currentLayer->getSelectedFrameIndexes().isEmpty()) { + currentLayer->deselectAll(); + } currentLayer->toggleFrameSelected(frameNumber, false); } + } else { @@ -636,7 +668,9 @@ void TimeLineCells::mouseMoveEvent(QMouseEvent* event) mMovingFrames = true; int offset = frameNumber - mLastFrameNumber; - currentLayer->moveSelectedFrames(offset); + + mNumOfFramesOffset += offset; + currentLayer->offsetSelectedFrames(offset); mEditor->layers()->notifyAnimationLengthChanged(); mEditor->updateCurrentFrame(); } @@ -646,8 +680,9 @@ void TimeLineCells::mouseMoveEvent(QMouseEvent* event) mBoxSelecting = true; currentLayer->deselectAll(); - currentLayer->setFrameSelected(mStartFrameNumber, true); - currentLayer->extendSelectionTo(frameNumber); + if (currentLayer->setFrameSelected(mStartFrameNumber, true)) { + currentLayer->extendSelectionTo(frameNumber); + } } mLastFrameNumber = frameNumber; } @@ -665,39 +700,55 @@ void TimeLineCells::mouseReleaseEvent(QMouseEvent* event) primaryButton = Qt::NoButton; mEndY = mStartY; mTimeLine->scrubbing = false; - int frameNumber = getFrameNumber(event->pos().x()); - if (frameNumber < 1) frameNumber = -1; - int layerNumber = getLayerNumber(event->pos().y()); + + int frameNumber = mStartFrameNumber; + int layerNumber = mStartLayerNumber; if (mType == TIMELINE_CELL_TYPE::Tracks && primaryButton != Qt::MidButton && layerNumber != -1 && layerNumber < mEditor->object()->getLayerCount()) { Layer *currentLayer = mEditor->object()->getLayer(layerNumber); + // clicking on a frame already selected if (!mTimeLine->scrubbing && !mMovingFrames && !mClickSelecting && !mBoxSelecting) { // De-selecting if we didn't move, scrub nor select anything - bool multipleSelection = (event->modifiers() == Qt::ControlModifier); + bool multipleSelection = (event->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier)); + + if (!currentLayer->getSelectedFrameIndexes().isEmpty()) { + if (event->modifiers() == Qt::NoModifier) { + currentLayer->deselectAll(); + } + } // Add/remove from already selected - currentLayer->toggleFrameSelected(frameNumber, multipleSelection); + Q_UNUSED(currentLayer->toggleFrameSelected(frameNumber, multipleSelection)) } + + // mouse was moved away from the start pos, this not intended to select. + const int numOfSelectedFrames = currentLayer->getSelectedFrameIndexes().count(); + if ((numOfSelectedFrames == 1 && mStartFrameNumber != frameNumber) && mNumOfFramesOffset == 0) { + currentLayer->deselectAll(); + } + + const QList selectedFrameIndexes = currentLayer->getSelectedFrameIndexes(); + if ((mClickSelecting || mBoxSelecting || mDidExtendSelection) && !mMovingFrames) { + mDidExtendSelection = false; + } + else if (mMovingFrames && mNumOfFramesOffset != 0) + { + mEditor->backups()->framesMoved(mNumOfFramesOffset, frameNumber); + mEditor->updateView(); + } + mNumOfFramesOffset = 0; } if (mType == TIMELINE_CELL_TYPE::Layers && layerNumber != mStartLayerNumber && mStartLayerNumber != -1 && layerNumber != -1) { mToLayer = getInbetweenLayerNumber(event->pos().y()); if (mToLayer != mFromLayer && mToLayer > -1 && mToLayer < mEditor->layers()->count()) { - // Bubble the from layer up or down to the to layer - if (mToLayer < mFromLayer) // bubble up - { - for (int i = mFromLayer - 1; i >= mToLayer; i--) - mEditor->swapLayers(i, i + 1); - } - else // bubble down - { - for (int i = mFromLayer + 1; i <= mToLayer; i++) - mEditor->swapLayers(i, i - 1); - } + mEditor->moveLayers(mFromLayer, mToLayer); } + mEditor->layers()->setCurrentLayer(mToLayer); + mEditor->backups()->layerMoved(mToLayer); } emit mouseMovedY(0); mTimeLine->updateContent(); @@ -726,10 +777,11 @@ void TimeLineCells::mouseDoubleClickEvent(QMouseEvent* event) { if (layer->type() == Layer::CAMERA) { - layer->editProperties(); + emit modifiedCamera(); } else { + mEditor->backups()->saveStates(); QRegExp regex("([\\xFFEF-\\xFFFF])+"); bool ok; @@ -738,8 +790,10 @@ void TimeLineCells::mouseDoubleClickEvent(QMouseEvent* event) layer->name(), &ok); if (ok && !text.isEmpty()) { + text.replace(regex, ""); mEditor->layers()->renameLayer(layer, text); + mEditor->backups()->layerRenamed(); } } } @@ -766,3 +820,26 @@ void TimeLineCells::setMouseMoveY(int x) update(); } } + +/// Simulated right-click event +/// does not cause mouse nor release event on some operation systems +bool TimeLineCells::eventIsControlClick(const Qt::KeyboardModifiers keyMod) +{ +#ifdef __APPLE__ + + // META acts as CTRL on mac... + // control is mapped to CMD + if (keyMod == Qt::MetaModifier) { + primaryButton = Qt::NoButton; + return true; + } + return false; +#else + if (keyMod == Qt::ControlModifier) + { + primaryButton = Qt::NoButton; + return true; + } + return false; +#endif +} diff --git a/core_lib/src/interface/timelinecells.h b/core_lib/src/interface/timelinecells.h index 163adb006d..4805f26d56 100644 --- a/core_lib/src/interface/timelinecells.h +++ b/core_lib/src/interface/timelinecells.h @@ -67,6 +67,7 @@ class TimeLineCells : public QWidget void mouseMovedY(int); void lengthChanged(int); void offsetChanged(int); + void modifiedCamera(); public slots: void updateContent(); @@ -89,6 +90,9 @@ private slots: void loadSetting(SETTING setting); private: + + bool eventIsControlClick(const Qt::KeyboardModifiers keyMod); + TimeLine* mTimeLine; Editor* mEditor; // the editor for which this timeLine operates PreferenceManager* mPrefs; @@ -98,6 +102,7 @@ private slots: QPixmap* mCache = nullptr; bool mDrawFrameNumber = true; bool mbShortScrub = false; + bool mDidExtendSelection = false; int mFrameLength = 1; int mFrameSize = 0; int mFontSize = 10; @@ -127,6 +132,9 @@ private slots: const static int mOffsetX = 0; const static int mOffsetY = 20; + + int mNumOfFramesOffset = 0; + const static int mLayerDetatchThreshold = 5; }; diff --git a/core_lib/src/managers/backupmanager.cpp b/core_lib/src/managers/backupmanager.cpp new file mode 100755 index 0000000000..8f9c7b6cf8 --- /dev/null +++ b/core_lib/src/managers/backupmanager.cpp @@ -0,0 +1,601 @@ +/* + +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 "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) +{ + 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->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) { 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) { 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->createSoundLayerContaining(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); + } + + 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 == NULL) { 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->getSelectedFrameIndexes(); + + 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 100755 index 0000000000..7e2484cd8c --- /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..87147c6f74 --- /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), 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/keyframemanager.cpp b/core_lib/src/managers/keyframemanager.cpp new file mode 100644 index 0000000000..6f80182ae2 --- /dev/null +++ b/core_lib/src/managers/keyframemanager.cpp @@ -0,0 +1,56 @@ +#include "keyframemanager.h" + +#include "editor.h" + +#include "vectorimage.h" +#include "bitmapimage.h" +#include "layer.h" +#include "layerbitmap.h" +#include "layervector.h" + +KeyFrameManager::KeyFrameManager(Editor* editor) : BaseManager(editor), mEditor(editor) +{ + +} + +KeyFrameManager::~KeyFrameManager() +{ + // TODO: cleanup stuff here... +} + +bool KeyFrameManager::init() +{ + return true; +} + +Status KeyFrameManager::load(Object* o) +{ + Q_UNUSED(o); + return Status::OK; +} + +Status KeyFrameManager::save(Object* o) +{ + Q_UNUSED(o); + return Status::OK; +} + +KeyFrame* KeyFrameManager::currentKeyFrame(Layer* layer) const +{ +// Q_ASSERT(layer->type() == Layer::Undefined); + return layer->getLastKeyFrameAtPosition(mEditor->currentFrame()); +} + +BitmapImage* KeyFrameManager::currentBitmapImage(Layer* layer) const +{ + Q_ASSERT(layer->type() == Layer::BITMAP); + auto bitmapLayer = static_cast(layer); + return bitmapLayer->getLastBitmapImageAtFrame(mEditor->currentFrame()); +} + +VectorImage* KeyFrameManager::currentVectorImage(Layer* layer) const +{ + Q_ASSERT(layer->type() == Layer::VECTOR); + auto vectorLayer = (static_cast(layer)); + return vectorLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); +} diff --git a/core_lib/src/managers/keyframemanager.h b/core_lib/src/managers/keyframemanager.h new file mode 100644 index 0000000000..6ef1dad845 --- /dev/null +++ b/core_lib/src/managers/keyframemanager.h @@ -0,0 +1,30 @@ +#ifndef KEYFRAMEMANAGER_H +#define KEYFRAMEMANAGER_H + +#include "basemanager.h" + +class Layer; +class BitmapImage; +class VectorImage; +class KeyFrame; + +class KeyFrameManager : public BaseManager +{ + Q_OBJECT +public: + explicit KeyFrameManager(Editor* editor); + ~KeyFrameManager() override; + + bool init() override; + Status load(Object* o) override; + Status save(Object* o) override; + + KeyFrame* currentKeyFrame(Layer* layer) const; + BitmapImage* currentBitmapImage(Layer* layer) const; + VectorImage* currentVectorImage(Layer* layer) const; + +private: + Editor* mEditor; +}; + +#endif // KEYFRAMEMANAGER_H diff --git a/core_lib/src/managers/layermanager.cpp b/core_lib/src/managers/layermanager.cpp index 31e75f6525..463cac45f7 100644 --- a/core_lib/src/managers/layermanager.cpp +++ b/core_lib/src/managers/layermanager.cpp @@ -17,6 +17,7 @@ GNU General Public License for more details. #include "layermanager.h" +#include #include "object.h" #include "editor.h" @@ -88,6 +89,11 @@ Layer* LayerManager::getLayer(int index) return object()->getLayer(index); } +Layer* LayerManager::findLayerById(int layerId) +{ + return object()->findLayerById(layerId); +} + Layer* LayerManager::findLayerByName(QString sName, Layer::LAYER_TYPE type) { return object()->findLayerByName(sName, type); @@ -123,6 +129,11 @@ void LayerManager::setCurrentLayer(int layerIndex) } } +void LayerManager::setCurrentLayerFromId(const int layerId) +{ + setCurrentLayer(findLayerById(layerId)); +} + void LayerManager::setCurrentLayer(Layer* layer) { setCurrentLayer(getIndex(layer)); @@ -149,46 +160,181 @@ void LayerManager::gotoPreviouslayer() LayerBitmap* LayerManager::createBitmapLayer(const QString& strLayerName) { LayerBitmap* layer = object()->addNewBitmapLayer(); - layer->setName(strLayerName); - Q_EMIT layerCountChanged(count()); + layer->setName( strLayerName ); + if (editor()->currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(editor()->object()->getLastLayerIndex()); + } + + Q_EMIT layerCountChanged( count() ); + return layer; } -LayerVector* LayerManager::createVectorLayer(const QString& strLayerName) +LayerBitmap* LayerManager::createBitmapLayerContaining(const int layerId, + const int layerIndex, + const QString& strLayerName) { - LayerVector* layer = object()->addNewVectorLayer(); - layer->setName(strLayerName); + LayerBitmap* newLayer = object()->bitmapLayerContaining(layerId, layerIndex); + newLayer->setName( strLayerName ); - Q_EMIT layerCountChanged(count()); + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + +void LayerManager::createBitmapLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + KeyFrame* keyframe = nullptr; + Layer* layer = createBitmapLayerContaining(layerId, layerIndex, strLayerName); + for(auto& map : keyFrames) + { + keyframe = map.second; + int frameIndex = keyframe->pos(); + + editor()->addKeyFrameToLayerId(layerId, frameIndex); + static_cast(layer)->putBitmapIntoFrame(keyframe, frameIndex); + } +} + +void LayerManager::createVectorLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + KeyFrame* keyframe = nullptr; + Layer* layer = createVectorLayerContaining(layerId, layerIndex, strLayerName); + for(auto& map : keyFrames) + { + keyframe = map.second; + int frameIndex = keyframe->pos(); + + editor()->addKeyFrameToLayerId(layerId, frameIndex); + static_cast(layer)->putVectorImageIntoFrame(keyframe, frameIndex); + } +} + +void LayerManager::createCameraLayerContainingKeyFrames(const std::map> keyFrames, + const int layerId, + const int layerIndex, + const QString& strLayerName) +{ + Layer* layer = createCameraLayerContaining(layerId, layerIndex, strLayerName); + + KeyFrame* keyframe = nullptr; + for (auto map : keyFrames) + { + keyframe = map.second; + int frameIndex = map.second->pos(); + editor()->addKeyFrameToLayerId(layerId, frameIndex); + static_cast(layer)->putCameraIntoFrame(keyframe, frameIndex); + } +} + +LayerVector* LayerManager::createVectorLayer( const QString& strLayerName ) +{ + LayerVector* layer = object()->addNewVectorLayer(); + layer->setName( strLayerName ); + if (editor()->currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(editor()->object()->getLastLayerIndex()); + } + + Q_EMIT layerCountChanged( count() ); + return layer; } -LayerCamera* LayerManager::createCameraLayer(const QString& strLayerName) +LayerVector* LayerManager::createVectorLayerContaining(const int layerId, + const int layerIndex, + const QString& strLayerName) { - LayerCamera* layer = object()->addNewCameraLayer(); - layer->setName(strLayerName); + LayerVector* newLayer = object()->vectorLayerContaining(layerId, layerIndex); + newLayer->setName( strLayerName ); - Q_EMIT layerCountChanged(count()); + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + +LayerCamera* LayerManager::createCameraLayer( const QString& strLayerName ) +{ + LayerCamera* layer = object()->addNewCameraLayer(); + layer->setName( strLayerName ); + + if (editor()->currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(editor()->object()->getLastLayerIndex()); + } + + Q_EMIT layerCountChanged( count() ); + return layer; } -LayerSound* LayerManager::createSoundLayer(const QString& strLayerName) +LayerCamera* LayerManager::createCameraLayerContaining(const int layerId, const int layerIndex, const QString& strLayerName) +{ + LayerCamera* newLayer = object()->addCameraLayerContaining(layerId, layerIndex); + newLayer->setName( strLayerName ); + + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + +LayerSound* LayerManager::createSoundLayer( const QString& strLayerName ) { LayerSound* layer = object()->addNewSoundLayer(); - layer->setName(strLayerName); + layer->setName( strLayerName ); - Q_EMIT layerCountChanged(count()); + setCurrentLayer(editor()->object()->getLastLayerIndex()); + + Q_EMIT layerCountChanged( count() ); return layer; } -int LayerManager::LastFrameAtFrame(int frameIndex) +LayerSound* LayerManager::createSoundLayerContaining(const int layerId, const int layerIndex, const QString& strLayerName) +{ + LayerSound* newLayer = object()->addSoundLayerContaining(layerId, layerIndex); + newLayer->setName( strLayerName ); + + if (currentLayerIndex() != editor()->object()->getLastLayerIndex()) + { + setCurrentLayer(layerIndex); + } + + Q_EMIT layerCountChanged( count() ); + + return newLayer; +} + + +Status::StatusInt LayerManager::LastFrameAtLayer(int frameIndex) { Object* o = object(); + Status::StatusInt status; for (int i = frameIndex; i >= 0; i -= 1) { for (int layerIndex = 0; layerIndex < o->getLayerCount(); ++layerIndex) @@ -196,11 +342,15 @@ int LayerManager::LastFrameAtFrame(int frameIndex) auto pLayer = o->getLayer(layerIndex); if (pLayer->keyExists(i)) { - return i; + status.value = i; + status.errorcode = Status::OK; + return status; } } } - return -1; + status.value = -1; + status.errorcode = Status::FAIL; + return status; } int LayerManager::firstKeyFrameIndex() @@ -253,7 +403,7 @@ Status LayerManager::deleteLayer(int index) return Status::ERROR_NEED_AT_LEAST_ONE_CAMERA_LAYER; } - object()->deleteLayer(layer); + object()->deleteLayer( index ); // current layer is the last layer && we are deleting it if (index == object()->getLayerCount() && @@ -273,6 +423,37 @@ Status LayerManager::deleteLayer(int index) return Status::OK; } +/** + * @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 layer + * @param layerIndex + * @param layerId + * @return Status + */ +Status LayerManager::deleteLayerWithId(int layerId, Layer::LAYER_TYPE layerType) +{ + if (layerType == Layer::CAMERA) + { + qDebug() << "camera layer"; + 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; diff --git a/core_lib/src/managers/layermanager.h b/core_lib/src/managers/layermanager.h index 1af2d8a8c8..15ee3a2c51 100644 --- a/core_lib/src/managers/layermanager.h +++ b/core_lib/src/managers/layermanager.h @@ -43,26 +43,51 @@ 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(); void setCurrentLayer(int nIndex); void setCurrentLayer(Layer* layer); + void setCurrentLayerFromId(const int layerId); int count(); Status deleteLayer(int index); + Status deleteLayerWithId(int layerId, Layer::LAYER_TYPE layerType); Status renameLayer(Layer*, const QString& newName); void notifyLayerChanged(Layer*); void gotoNextLayer(); void gotoPreviouslayer(); + int getLayerIndex(Layer* layer) const { return getIndex(layer); } LayerBitmap* createBitmapLayer(const QString& strLayerName); LayerVector* createVectorLayer(const QString& strLayerName); LayerCamera* createCameraLayer(const QString& strLayerName); LayerSound* createSoundLayer(const QString& strLayerName); + LayerBitmap* createBitmapLayerContaining(const int layerId, const int layerIndex, 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); + + LayerVector* createVectorLayerContaining(const int layerId, const int layerIndex, const QString& strLayerName); + LayerSound* createSoundLayerContaining(const int layerId, const int layerIndex, const QString& strLayerName); + LayerCamera* createCameraLayerContaining(const int layerId, const int layerIndex, const QString& strLayerName); + + // KeyFrame Management - int LastFrameAtFrame(int frameIndex); + Status::StatusInt LastFrameAtLayer(int frameIndex); int firstKeyFrameIndex(); int lastKeyFrameIndex(); diff --git a/core_lib/src/managers/preferencemanager.h b/core_lib/src/managers/preferencemanager.h index 5a9c114448..4d166e9014 100644 --- a/core_lib/src/managers/preferencemanager.h +++ b/core_lib/src/managers/preferencemanager.h @@ -104,6 +104,7 @@ class PreferenceManager : public BaseManager QString getString(SETTING option); int getInt(SETTING option); + Q_SIGNALS: void optionChanged(SETTING e); diff --git a/core_lib/src/managers/selectionmanager.cpp b/core_lib/src/managers/selectionmanager.cpp index 04e412823c..e9f77f3f43 100644 --- a/core_lib/src/managers/selectionmanager.cpp +++ b/core_lib/src/managers/selectionmanager.cpp @@ -18,6 +18,8 @@ SelectionManager::SelectionManager(Editor* editor) : BaseManager(editor), mTempTransformedSelection(QRectF()), mTransformedSelection(QRectF()), mRotatedAngle(0), + mScaleX(1), + mScaleY(1), mSomethingSelected(false), mLastSelectionPolygonF(QPolygonF()), mCurrentSelectionPolygonF(QPolygonF()), @@ -53,9 +55,20 @@ void SelectionManager::resetSelectionTransformProperties() { mOffset = QPointF(0, 0); mRotatedAngle = 0; + mScaleX = 1; + mScaleY = 1; mSelectionTransform.reset(); } +/** + * @brief SelectionManager::sync + * Sync the selection properties + */ +void SelectionManager::sync() +{ + setSelection(myTransformedSelectionRect()); +} + void SelectionManager::updatePolygons() { mCurrentSelectionPolygonF = mTempTransformedSelection; @@ -257,11 +270,16 @@ void SelectionManager::adjustSelection(const QPointF& currentPoint, qreal offset } } -int SelectionManager::constrainRotationToAngle(const qreal& rotatedAngle, const int& rotationIncrement) const +int SelectionManager::constrainRotationToAngle(const qreal rotatedAngle, const int rotationIncrement) const { return qRound(rotatedAngle / rotationIncrement) * rotationIncrement; } +bool SelectionManager::selectionMoved() const +{ + return !mSelectionTransform.isIdentity(); +} + void SelectionManager::setSelection(QRectF rect) { resetSelectionTransformProperties(); @@ -282,12 +300,21 @@ void SelectionManager::calculateSelectionTransformation() mSelectionTransform.translate(centerPoints[0].x(), centerPoints[0].y()); mSelectionTransform.rotate(mRotatedAngle); - if (mSelection.width() > 0 && mSelection.height() > 0) // can't divide by 0 + if (mSelection.isValid()) { qreal scaleX = mTempTransformedSelection.width() / mSelection.width(); qreal scaleY = mTempTransformedSelection.height() / mSelection.height(); + + if (mScaleX < 0) { + scaleX = -scaleX; + } + if (mScaleY < 0) { + scaleY = -scaleY; + } mSelectionTransform.scale(scaleX, scaleY); } + mSelectionTransform.fromScale(mScaleX,mScaleY); + mSelectionTransform.translate(-centerPoints[1].x(), -centerPoints[1].y()); } @@ -341,24 +368,23 @@ QPointF SelectionManager::offsetFromAspectRatio(qreal offsetX, qreal offsetY) */ void SelectionManager::flipSelection(bool flipVertical) { - qreal scaleX = mTempTransformedSelection.width() / mSelection.width(); - qreal scaleY = mTempTransformedSelection.height() / mSelection.height(); QVector centerPoints = calcSelectionCenterPoints(); QTransform translate = QTransform::fromTranslate(centerPoints[0].x(), centerPoints[0].y()); QTransform _translate = QTransform::fromTranslate(-centerPoints[1].x(), -centerPoints[1].y()); - QTransform scale = QTransform::fromScale(-scaleX, scaleY); + + QTransform scale = QTransform::fromScale(-mScaleX, mScaleY); if (flipVertical) { - scale = QTransform::fromScale(scaleX, -scaleY); + scale = QTransform::fromScale(mScaleX, -mScaleY); } // reset transformation for vector selections mSelectionTransform.reset(); mSelectionTransform *= _translate * scale * translate; - - emit needPaintAndApply(); + mScaleX = scale.m11(); + mScaleY = scale.m22(); } void SelectionManager::translate(QPointF point) @@ -378,6 +404,17 @@ void SelectionManager::resetSelectionProperties() mLastSelectionPolygonF = QPolygonF(); mSomethingSelected = false; - vectorSelection.clear(); + mVectorSelection.clear(); +} + +void SelectionManager::addCurvesAndVerticesToVectorSelection(const QList curves, const QList vertices) +{ + mVectorSelection.add(curves); + mVectorSelection.add(vertices); +} + +void SelectionManager::addCurvesToVectorSelection(const QList curves) +{ + mVectorSelection.add(curves); } diff --git a/core_lib/src/managers/selectionmanager.h b/core_lib/src/managers/selectionmanager.h index 2c2a3345c5..b58490fc94 100644 --- a/core_lib/src/managers/selectionmanager.h +++ b/core_lib/src/managers/selectionmanager.h @@ -30,6 +30,7 @@ class SelectionManager : public BaseManager void updatePolygons(); void updateTransformedSelection() { mTransformedSelection = mTempTransformedSelection; } + void sync(); QRectF mappedSelection(); @@ -62,6 +63,11 @@ class SelectionManager : public BaseManager const QList closestCurves() { return mClosestCurves; } const QList closestVertices() { return mClosestVertices; } + const VectorSelection vectorSelection() { return mVectorSelection; } + void setVectorSelection(const VectorSelection& vectorSelection) { mVectorSelection = vectorSelection; } + void addCurvesAndVerticesToVectorSelection(const QList curves, const QList vertices); + void addCurvesToVectorSelection(const QList curves); + QTransform selectionTransform() { return mSelectionTransform; } void setSelectionTransform(QTransform transform) { mSelectionTransform = transform; } void resetSelectionTransform(); @@ -88,17 +94,20 @@ class SelectionManager : public BaseManager void setSomethingSelected(bool selected) { mSomethingSelected = selected; } - 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; } void setTransformedSelectionRect(const QRectF& rect) { mTransformedSelection = rect; } - void setRotation(const qreal& rotation) { mRotatedAngle = rotation; } + void setRotation(const qreal rotation) { mRotatedAngle = rotation; } + void setScale(const qreal scaleX, const qreal scaleY) { mScaleX = scaleX; mScaleY = scaleY; } + + bool selectionMoved() const; signals: @@ -108,12 +117,15 @@ class SelectionManager : public BaseManager private: - int constrainRotationToAngle(const qreal& rotatedAngle, const int& rotationIncrement) const; + int constrainRotationToAngle(const qreal rotatedAngle, const int rotationIncrement) const; + VectorSelection mVectorSelection; QRectF mSelection; QRectF mTempTransformedSelection; QRectF mTransformedSelection; qreal mRotatedAngle; + qreal mScaleX; + qreal mScaleY; bool mSomethingSelected; QPolygonF mLastSelectionPolygonF; diff --git a/core_lib/src/managers/viewmanager.cpp b/core_lib/src/managers/viewmanager.cpp index 3c6edd44ae..ca4a54c616 100644 --- a/core_lib/src/managers/viewmanager.cpp +++ b/core_lib/src/managers/viewmanager.cpp @@ -235,41 +235,6 @@ void ViewManager::scaleDown() scale(scaling() * 0.8333f); } -void ViewManager::scale100() -{ - scale(1.0f); -} - -void ViewManager::scale400() -{ - scale(4.0f); -} - -void ViewManager::scale300() -{ - scale(3.0f); -} - -void ViewManager::scale200() -{ - scale(2.0f); -} - -void ViewManager::scale50() -{ - scale(0.5f); -} - -void ViewManager::scale33() -{ - scale(0.33f); -} - -void ViewManager::scale25() -{ - scale(0.25f); -} - void ViewManager::scale(float scaleValue) { if (scaleValue < mMinScale) diff --git a/core_lib/src/managers/viewmanager.h b/core_lib/src/managers/viewmanager.h index 21da72fc23..99a6344116 100644 --- a/core_lib/src/managers/viewmanager.h +++ b/core_lib/src/managers/viewmanager.h @@ -65,13 +65,6 @@ class ViewManager : public BaseManager void scale(float scaleValue); void scaleUp(); void scaleDown(); - void scale400(); - void scale300(); - void scale200(); - void scale100(); - void scale50(); - void scale33(); - void scale25(); void flipHorizontal(bool b); void flipVertical(bool b); diff --git a/core_lib/src/structure/camera.cpp b/core_lib/src/structure/camera.cpp index 345e0c1605..4691e9e688 100644 --- a/core_lib/src/structure/camera.cpp +++ b/core_lib/src/structure/camera.cpp @@ -41,7 +41,7 @@ Camera::~Camera() { } -Camera* Camera::clone() +Camera* Camera::clone() const { return new Camera(*this); } @@ -51,6 +51,7 @@ void Camera::assign(const Camera& rhs) mTranslate = rhs.mTranslate; mRotate = rhs.mRotate; mScale = rhs.mScale; + mNeedUpdateView = true; updateViewTransform(); modification(); } diff --git a/core_lib/src/structure/camera.h b/core_lib/src/structure/camera.h index a312e2389f..66768c25b9 100644 --- a/core_lib/src/structure/camera.h +++ b/core_lib/src/structure/camera.h @@ -29,7 +29,7 @@ class Camera : public KeyFrame explicit Camera(const Camera&); ~Camera() override; - Camera* clone() override; + Camera* clone() const override; QTransform getView(); void reset(); diff --git a/core_lib/src/structure/keyframe.h b/core_lib/src/structure/keyframe.h index 0124a88e19..f72cce0b95 100644 --- a/core_lib/src/structure/keyframe.h +++ b/core_lib/src/structure/keyframe.h @@ -52,7 +52,7 @@ class KeyFrame void addEventListener(KeyFrameEventListener*); void removeEventListner(KeyFrameEventListener*); - virtual KeyFrame* clone() { return nullptr; } + virtual KeyFrame* clone() const { return nullptr; } virtual void loadFile() {} virtual void unloadFile() {} virtual bool isLoaded() { return true; } diff --git a/core_lib/src/structure/layer.cpp b/core_lib/src/structure/layer.cpp index 798c34a1b8..08db2445ef 100644 --- a/core_lib/src/structure/layer.cpp +++ b/core_lib/src/structure/layer.cpp @@ -211,9 +211,31 @@ bool Layer::moveKeyFrameBackward(int position) { if (position != 1) { - return swapKeyFrames(position, position - 1); + int newPos = position - 1; + return swapKeyFrames(position, newPos); } - return true; + return false; +} + +void Layer::moveFrame(const int oldPosition, const int newPosition) +{ + KeyFrame* keyframe = mKeyFrames.at(oldPosition); + keyframe->setPos(newPosition); + mKeyFrames.insert(std::make_pair(newPosition, keyframe)); + mKeyFrames.erase(oldPosition); +} + +bool Layer::swapKeyFrames(const QList oldFrameIndexes, const QList newFrameIndexes) +{ + bool swapped = false; + for (int i = 0; i < oldFrameIndexes.count(); i++) { + + Q_ASSERT(oldFrameIndexes != newFrameIndexes); + int oldFrame = oldFrameIndexes[i]; + int newFrame = newFrameIndexes[i]; + swapped = swapKeyFrames(oldFrame, newFrame); + } + return swapped; } bool Layer::swapKeyFrames(int position1, int position2) //Current behaviour, need to refresh the swapped cels @@ -223,6 +245,7 @@ bool Layer::swapKeyFrames(int position1, int position2) //Current behaviour, nee KeyFrame* pFirstFrame = nullptr; KeyFrame* pSecondFrame = nullptr; + bool exists = false; if (keyExists(position1)) { auto firstFrame = mKeyFrames.find(position1); @@ -231,6 +254,7 @@ bool Layer::swapKeyFrames(int position1, int position2) //Current behaviour, nee mKeyFrames.erase(position1); keyPosition1 = true; + exists = true; } if (keyExists(position2)) @@ -241,6 +265,11 @@ bool Layer::swapKeyFrames(int position1, int position2) //Current behaviour, nee mKeyFrames.erase(position2); keyPosition2 = true; + exists = true; + } + + if (!exists) { + return false; } if (keyPosition2) @@ -462,7 +491,30 @@ bool Layer::isFrameSelected(int position) const return false; } -void Layer::setFrameSelected(int position, bool isSelected) +int Layer::getFirstFrameInSelection() +{ + return mSelectedFrames_byPosition.last(); +} + +int Layer::getLastFrameInSelection() +{ + return mSelectedFrames_byPosition.first(); +} + +void Layer::setFramesSelected(QList frameIndexes, const bool selected) +{ + for (int frame : frameIndexes) + { + setFrameSelected(frame, selected); + } +} + +void Layer::setFramesSelected(QList frameIndexes) +{ + setFramesSelected(frameIndexes, true); +} + +bool Layer::setFrameSelected(int position, bool isSelected) { KeyFrame* keyFrame = getKeyFrameWhichCovers(position); if (keyFrame != nullptr) @@ -489,23 +541,37 @@ void Layer::setFrameSelected(int position, bool isSelected) mSelectedFrames_byPosition.removeAt(iPos); } keyFrame->setSelected(isSelected); + return true; } + return false; } -void Layer::toggleFrameSelected(int position, bool allowMultiple) +Status::StatusBool Layer::toggleFrameSelected(int position, bool allowMultiple) { bool wasSelected = isFrameSelected(position); - + Status::StatusBool status; if (!allowMultiple) { deselectAll(); } - setFrameSelected(position, !wasSelected); + bool success = setFrameSelected(position, !wasSelected); + + status.value = !wasSelected; + + qDebug() << "isSelected: " << status.value; + + if (success) { + status.errorcode = Status::OK; + } else { + status.errorcode = Status::FAIL; + } + return status; } -void Layer::extendSelectionTo(int position) +QList Layer::selectionExtendedTo(int position) { + QList selection; if (mSelectedFrames_byLast.count() > 0) { int lastSelected = mSelectedFrames_byLast[0]; @@ -526,28 +592,47 @@ void Layer::extendSelectionTo(int position) int i = startPos; while (i <= endPos) { - setFrameSelected(i, true); + bool success = setFrameSelected(i, true); + + if (success) { + selection.append(i); + } + i++; } } + return selection; } -void Layer::selectAllFramesAfter(int position) +void Layer::extendSelectionTo(int position) +{ + Q_UNUSED(selectionExtendedTo(position)); +} + +QList Layer::selectionOfAllFramesAfter(const int position) { int startPosition = position; int endPosition = getMaxKeyFramePosition(); + QList selection; if (!keyExists(startPosition)) { startPosition = getNextKeyFramePosition(startPosition); } + selection.append(startPosition); if (startPosition > 0 && startPosition <= endPosition) { deselectAll(); setFrameSelected(startPosition, true); - extendSelectionTo(endPosition); + selection.append(selectionExtendedTo(endPosition)); } + return selection; +} + +void Layer::selectAllFramesAfter(int position) +{ + Q_UNUSED(selectionOfAllFramesAfter(position)); } void Layer::deselectAll() @@ -561,7 +646,7 @@ void Layer::deselectAll() } } -bool Layer::moveSelectedFrames(int offset) +bool Layer::offsetSelectedFrames(int offset) { if (offset != 0 && mSelectedFrames_byPosition.count() > 0) { @@ -629,21 +714,25 @@ bool Layer::moveSelectedFrames(int offset) } indexInSelection = indexInSelection + step; } - - // Update selection lists - for (int i = 0; i < mSelectedFrames_byPosition.count(); i++) - { - mSelectedFrames_byPosition[i] = mSelectedFrames_byPosition[i] + offset; - } - for (int i = 0; i < mSelectedFrames_byLast.count(); i++) - { - mSelectedFrames_byLast[i] = mSelectedFrames_byLast[i] + offset; - } + updateSelectedFrames(offset); return true; } return false; } +void Layer::updateSelectedFrames(const int offset) +{ + // Update selection lists + for (int i = 0; i < mSelectedFrames_byPosition.count(); i++) + { + mSelectedFrames_byPosition[i] = mSelectedFrames_byPosition[i] + offset; + } + for (int i = 0; i < mSelectedFrames_byLast.count(); i++) + { + mSelectedFrames_byLast[i] = mSelectedFrames_byLast[i] + offset; + } +} + bool Layer::isPaintable() const { return (type() == BITMAP || type() == VECTOR); diff --git a/core_lib/src/structure/layer.h b/core_lib/src/structure/layer.h index 2b076bd41c..eca3e4a933 100644 --- a/core_lib/src/structure/layer.h +++ b/core_lib/src/structure/layer.h @@ -85,8 +85,9 @@ class Layer : public QObject bool addKeyFrame(int position, KeyFrame*); bool removeKeyFrame(int position); bool swapKeyFrames(int position1, int position2); - bool moveKeyFrameForward(int position); - bool moveKeyFrameBackward(int position); + bool swapKeyFrames(const QList oldFrameIndexes, const QList newFrameIndexes); + bool moveKeyFrameForward(const int frameIndex); + bool moveKeyFrameBackward(const int frameIndex); bool loadKey(KeyFrame*); KeyFrame* getKeyFrameAt(int position) const; KeyFrame* getLastKeyFrameAtPosition(int position) const; @@ -94,19 +95,32 @@ class Layer : public QObject KeyFrame *getKeyFrameWhichCovers(int frameNumber) const; bool getVisibility() { return mVisible; } + std::map> getKeysInLayer() { return mKeyFrames; } void foreachKeyFrame(std::function); void setModified(int position, bool isModified); // Handle selection + int getFirstFrameInSelection(); + int getLastFrameInSelection(); bool isFrameSelected(int position) const; - void setFrameSelected(int position, bool isSelected); - void toggleFrameSelected(int position, bool allowMultiple = false); + bool setFrameSelected(int position, bool isSelected); + void setFramesSelected(QList frameIndexes); + void setFramesSelected(QList frameIndexes, const bool selected); + Status::StatusBool toggleFrameSelected(int position, bool allowMultiple = false); + + QList selectionExtendedTo(const int position); + QList selectionOfAllFramesAfter(const int position); void extendSelectionTo(int position); void selectAllFramesAfter(int position); + void deselectAll(); - bool moveSelectedFrames(int offset); + void moveFrame(const int oldPosition, const int newPosition); + void moveFrames(const QList oldIndexes, const QList newIndexes); + + bool offsetSelectedFrames(int offset); + QList getSelectedFrameIndexes() { return mSelectedFrames_byPosition; } Status save(const QString& sDataFolder, QStringList& attachedFiles, ProgressCallback progressStep); virtual Status presave(const QString& sDataFolder) { Q_UNUSED(sDataFolder); return Status::SAFE; } @@ -122,11 +136,26 @@ class Layer : public QObject bool isPaintable() const; + QString description() const { + switch(meType) + { + case LAYER_TYPE::BITMAP: { return tr("Bitmap"); } + case LAYER_TYPE::VECTOR: { return tr("Vector"); } + case LAYER_TYPE::SOUND: { return tr("Sound"); } + case LAYER_TYPE::CAMERA: { return tr("Camera"); } + default: + return ""; + } + } + protected: void setId(int LayerId) { mId = LayerId; } virtual KeyFrame* createKeyFrame(int position, Object*) = 0; private: + + void updateSelectedFrames(const int offset); + LAYER_TYPE meType = UNDEFINED; Object* mObject = nullptr; int mId = 0; diff --git a/core_lib/src/structure/layerbitmap.cpp b/core_lib/src/structure/layerbitmap.cpp index 999cf5160c..4104842e9b 100644 --- a/core_lib/src/structure/layerbitmap.cpp +++ b/core_lib/src/structure/layerbitmap.cpp @@ -30,6 +30,20 @@ LayerBitmap::LayerBitmap(Object* object) : Layer(object, Layer::BITMAP) setName(tr("Bitmap Layer")); } +/** + * @brief LayerBitmap::LayerBitmap + * @param layer + * @param object + * + * 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) : Layer(object, Layer::BITMAP) +{ + setName(tr("Bitmap Layer")); + setId(id); +} + LayerBitmap::~LayerBitmap() { } @@ -46,6 +60,11 @@ BitmapImage* LayerBitmap::getLastBitmapImageAtFrame(int frameNumber, int increme return static_cast(getLastKeyFrameAtPosition(frameNumber + increment)); } +void LayerBitmap::replaceLastBitmapAtFrame(const BitmapImage* replaceWithImage) +{ + *static_cast(getLastKeyFrameAtPosition(replaceWithImage->pos())) = *replaceWithImage; +} + void LayerBitmap::loadImageAtFrame(QString path, QPoint topLeft, int frameNumber) { BitmapImage* pKeyFrame = new BitmapImage(topLeft, path); @@ -54,6 +73,14 @@ void LayerBitmap::loadImageAtFrame(QString path, QPoint topLeft, int frameNumber loadKey(pKeyFrame); } +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 d380f8c4d7..a2f31d353e 100644 --- a/core_lib/src/structure/layerbitmap.h +++ b/core_lib/src/structure/layerbitmap.h @@ -28,6 +28,7 @@ class LayerBitmap : public Layer public: LayerBitmap(Object* object); + LayerBitmap(int id, Object* object); ~LayerBitmap(); QDomElement createDomElement(QDomDocument& doc) override; @@ -37,6 +38,9 @@ class LayerBitmap : public Layer BitmapImage* getBitmapImageAtFrame(int frameNumber); BitmapImage* getLastBitmapImageAtFrame(int frameNumber, int increment = 0); + void putBitmapIntoFrame(KeyFrame* keyframe, const int& frameIndex); + void replaceLastBitmapAtFrame(const BitmapImage* replaceWithImage); + protected: Status saveKeyFrameFile(KeyFrame*, QString strPath) override; KeyFrame* createKeyFrame(int position, Object*) override; diff --git a/core_lib/src/structure/layercamera.cpp b/core_lib/src/structure/layercamera.cpp index afe7aa46d5..51d673c2c5 100644 --- a/core_lib/src/structure/layercamera.cpp +++ b/core_lib/src/structure/layercamera.cpp @@ -78,6 +78,23 @@ void CameraPropertiesDialog::setHeight(int height) LayerCamera::LayerCamera( Object* object ) : Layer( object, Layer::CAMERA ) { setName(tr("Camera Layer")); + + // TODO: remove duplicate code + QSettings settings (PENCIL2D, PENCIL2D); + mFieldW = settings.value("FieldW").toInt(); + mFieldH = settings.value("FieldH").toInt(); + if (mFieldW < 2 || mFieldH < 2) + { + mFieldW = 800; + mFieldH = 600; + } + viewRect = QRect(QPoint(-mFieldW/2, -mFieldH/2), QSize(mFieldW, mFieldH)); +} + +LayerCamera::LayerCamera(const int layerId, Object* object ) : Layer( object, Layer::CAMERA ) +{ + setName(tr("Camera Layer")); + setId(layerId); QSettings settings (PENCIL2D, PENCIL2D); mFieldW = settings.value("FieldW").toInt(); mFieldH = settings.value("FieldH").toInt(); @@ -87,7 +104,6 @@ LayerCamera::LayerCamera( Object* object ) : Layer( object, Layer::CAMERA ) mFieldH = 600; } viewRect = QRect(QPoint(-mFieldW/2, -mFieldH/2), QSize(mFieldW, mFieldH)); - dialog = nullptr; } LayerCamera::~LayerCamera() @@ -99,6 +115,12 @@ Camera* LayerCamera::getCameraAtFrame(int frameNumber) return static_cast< Camera* >( getKeyFrameAt( frameNumber ) ); } +void LayerCamera::putCameraIntoFrame(KeyFrame *keyframe, int frameIndex) +{ + Camera* oldCamera = static_cast(keyframe); + getCameraAtFrame(frameIndex)->assign(*oldCamera); +} + Camera* LayerCamera::getLastCameraAtFrame(int frameNumber, int increment) { return static_cast< Camera* >( getLastKeyFrameAtPosition( frameNumber + increment ) ); @@ -114,7 +136,7 @@ QTransform LayerCamera::getViewAtFrame(int frameNumber) Camera* camera1 = static_cast< Camera* >( getLastKeyFrameAtPosition( frameNumber ) ); int nextFrame = getNextKeyFramePosition( frameNumber ); - Camera* camera2 = static_cast< Camera* >( getLastKeyFrameAtPosition( nextFrame ) ); + Camera* camera2 = static_cast< Camera* >( getLastKeyFrameAtPosition( nextFrame ) ); if (camera1 == nullptr && camera2 == nullptr) { @@ -129,10 +151,10 @@ QTransform LayerCamera::getViewAtFrame(int frameNumber) return camera1->view; } - if ( camera1 == camera2 ) - { - return camera1->view; - } + if ( camera1 == camera2 ) + { + return camera1->view; + } double frame1 = camera1->pos(); double frame2 = camera2->pos(); @@ -239,28 +261,6 @@ KeyFrame* LayerCamera::createKeyFrame(int position, Object*) return c; } -void LayerCamera::editProperties() -{ - if ( dialog == nullptr ) - { - dialog = new CameraPropertiesDialog( name(), viewRect.width(), viewRect.height() ); - } - dialog->setName( name() ); - dialog->setWidth(viewRect.width()); - dialog->setHeight(viewRect.height()); - int result = dialog->exec(); - if (result == QDialog::Accepted) - { - setName( dialog->getName() ); - QSettings settings (PENCIL2D, PENCIL2D); - settings.setValue(SETTING_FIELD_W, dialog->getWidth()); - settings.setValue(SETTING_FIELD_H, dialog->getHeight()); - viewRect = QRect(-dialog->getWidth()/2, -dialog->getHeight()/2, dialog->getWidth(), dialog->getHeight()); - - emit resolutionChanged(); - } -} - QDomElement LayerCamera::createDomElement( QDomDocument& doc ) { QDomElement layerTag = doc.createElement("layer"); diff --git a/core_lib/src/structure/layercamera.h b/core_lib/src/structure/layercamera.h index c2768c78f4..b22bc096c1 100644 --- a/core_lib/src/structure/layercamera.h +++ b/core_lib/src/structure/layercamera.h @@ -51,13 +51,14 @@ class LayerCamera : public Layer public: LayerCamera(Object* object); + LayerCamera(const int layerId, Object *object); ~LayerCamera(); void loadImageAtFrame(int frame, qreal dx, qreal dy, qreal rotate, qreal scale); - void editProperties() override; QDomElement createDomElement(QDomDocument& doc) override; void loadDomElement(QDomElement element, QString dataDirPath, ProgressCallback progressStep) override; + void putCameraIntoFrame(KeyFrame* keyframe, int frameIndex); Camera* getCameraAtFrame(int frameNumber); Camera* getLastCameraAtFrame(int frameNumber, int increment); @@ -66,6 +67,7 @@ class LayerCamera : public Layer QRect getViewRect(); QSize getViewSize(); + void setViewRect(QRect newRect) {viewRect = newRect; } signals: void resolutionChanged(); @@ -79,7 +81,6 @@ class LayerCamera : public Layer int mFieldW = 800; int mFieldH = 600; QRect viewRect; - CameraPropertiesDialog* dialog = nullptr; }; #endif diff --git a/core_lib/src/structure/layersound.cpp b/core_lib/src/structure/layersound.cpp index 7e203f1fa9..171d8a27b2 100644 --- a/core_lib/src/structure/layersound.cpp +++ b/core_lib/src/structure/layersound.cpp @@ -29,6 +29,13 @@ LayerSound::LayerSound(Object* object) : Layer(object, Layer::SOUND) setName(tr("Sound Layer")); } +LayerSound::LayerSound(const int layerId, Object* object) : Layer(object, Layer::SOUND) +{ + setName(tr("Sound Layer")); + setId(layerId); +} + + LayerSound::~LayerSound() { } diff --git a/core_lib/src/structure/layersound.h b/core_lib/src/structure/layersound.h index 86229e640d..e7d8e460a7 100644 --- a/core_lib/src/structure/layersound.h +++ b/core_lib/src/structure/layersound.h @@ -28,6 +28,7 @@ class LayerSound : public Layer public: LayerSound( Object* object ); + LayerSound(const int layerId, Object* object); ~LayerSound(); QDomElement createDomElement(QDomDocument& doc) override; void loadDomElement(QDomElement element, QString dataDirPath, ProgressCallback progressStep) override; diff --git a/core_lib/src/structure/layervector.cpp b/core_lib/src/structure/layervector.cpp index 7df584e9e7..037bde6a10 100644 --- a/core_lib/src/structure/layervector.cpp +++ b/core_lib/src/structure/layervector.cpp @@ -24,6 +24,12 @@ LayerVector::LayerVector(Object* object) : Layer(object, Layer::VECTOR) setName(tr("Vector Layer")); } +LayerVector::LayerVector(int layerId, Object* object) : Layer(object, Layer::VECTOR) +{ + setName(tr("Vector Layer")); + setId(layerId); +} + LayerVector::~LayerVector() { } @@ -188,3 +194,16 @@ VectorImage* LayerVector::getLastVectorImageAtFrame(int frameNumber, int increme { return static_cast(getLastKeyFrameAtPosition(frameNumber + increment)); } + +void LayerVector::putVectorImageIntoFrame(KeyFrame *keyframe, const int frameIndex) +{ + VectorImage* currentVectorImg = getVectorImageAtFrame(frameIndex); + + VectorImage newVectorImg = *static_cast(keyframe); + static_cast(currentVectorImg)->paste(newVectorImg); +} + +void LayerVector::replaceLastVectorAtFrame(const VectorImage *replaceWithVector) +{ + *static_cast(getLastKeyFrameAtPosition(replaceWithVector->pos())) = *replaceWithVector; +} diff --git a/core_lib/src/structure/layervector.h b/core_lib/src/structure/layervector.h index 0779fcf55f..f8eb46f29f 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(const int layerId, Object* object); ~LayerVector(); // method from layerImage @@ -39,6 +40,9 @@ class LayerVector : public Layer VectorImage* getVectorImageAtFrame(int frameNumber) const; VectorImage* getLastVectorImageAtFrame(int frameNumber, int increment) const; + void putVectorImageIntoFrame(KeyFrame* keyframe, const int frameIndex); + void replaceLastVectorAtFrame(const VectorImage* replaceWithVector); + bool usesColour(int index); void removeColour(int index); diff --git a/core_lib/src/structure/object.cpp b/core_lib/src/structure/object.cpp index 74733583ca..0de3e07402 100644 --- a/core_lib/src/structure/object.cpp +++ b/core_lib/src/structure/object.cpp @@ -116,6 +116,15 @@ LayerBitmap* Object::addNewBitmapLayer() return layerBitmap; } +LayerBitmap* Object::bitmapLayerContaining(const int layerId, const int layerIndex) +{ + LayerBitmap* layerBitmap = new LayerBitmap(layerId, this); + mLayers.insert(layerIndex, layerBitmap); + + layerBitmap->addNewKeyFrameAt(1); + return layerBitmap; +} + LayerVector* Object::addNewVectorLayer() { LayerVector* layerVector = new LayerVector(this); @@ -126,6 +135,15 @@ LayerVector* Object::addNewVectorLayer() return layerVector; } +LayerVector* Object::vectorLayerContaining(const int layerId, const int layerIndex) +{ + LayerVector* layerVector = new LayerVector(layerId, this); + mLayers.insert(layerIndex, layerVector); + + layerVector->addNewKeyFrameAt(1); + return layerVector; +} + LayerSound* Object::addNewSoundLayer() { LayerSound* layerSound = new LayerSound(this); @@ -136,6 +154,14 @@ LayerSound* Object::addNewSoundLayer() return layerSound; } +LayerSound* Object::addSoundLayerContaining(const int layerId, const int layerIndex) +{ + LayerSound* layerSound = new LayerSound(layerId, this); + mLayers.insert(layerIndex, layerSound); + + return layerSound; +} + LayerCamera* Object::addNewCameraLayer() { LayerCamera* layerCamera = new LayerCamera(this); @@ -148,6 +174,15 @@ LayerCamera* Object::addNewCameraLayer() return layerCamera; } +LayerCamera* Object::addCameraLayerContaining(const int layerId, const int layerIndex) +{ + LayerCamera* layerCamera = new LayerCamera(layerId, this); + mLayers.insert(layerIndex, layerCamera); + + layerCamera->addNewKeyFrameAt(1); + return layerCamera; +} + void Object::createWorkingDir() { QString strFolderName; @@ -227,6 +262,24 @@ 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) + { + if (layer->id() == layerId) + { + return layer; + } + } + return nullptr; +} + + Layer* Object::findLayerByName(QString strName, Layer::LAYER_TYPE type) const { bool bCheckType = (type != Layer::UNDEFINED); @@ -270,15 +323,18 @@ void Object::deleteLayer(int i) } } -void Object::deleteLayer(Layer* layer) +void Object::deleteLayerWithId(int layerId) { - auto it = std::find(mLayers.begin(), mLayers.end(), layer); - - if (it != mLayers.end()) + for (int index = 0; index < mLayers.size(); index++) { - delete layer; - mLayers.erase(it); + if (mLayers.at(index)->id() == layerId) + { + disconnect(mLayers[index], 0, 0, 0); + delete mLayers.takeAt(index); + break; + } } + } ColourRef Object::getColour(int index) const diff --git a/core_lib/src/structure/object.h b/core_lib/src/structure/object.h index 22070968a5..fe7d40594d 100644 --- a/core_lib/src/structure/object.h +++ b/core_lib/src/structure/object.h @@ -110,26 +110,33 @@ class Object : public QObject LayerSound* addNewSoundLayer(); LayerCamera* addNewCameraLayer(); - int getLayerCount() const; + LayerBitmap* bitmapLayerContaining(const int layerId, const int layerIndex); + LayerVector* vectorLayerContaining(const int layerId, const int layerIndex); + LayerSound* addSoundLayerContaining(const int layerId, const int layerIndex); + LayerCamera* addCameraLayerContaining(const int layerId, const int layerIndex); + + int getLayerCount() const; + int getLastLayerIndex() const; Layer* getLayer(int i) const; - Layer* findLayerByName(QString strName, Layer::LAYER_TYPE type = Layer::UNDEFINED) const; + Layer* findLayerByName( QString strName, Layer::LAYER_TYPE type = Layer::UNDEFINED ) const; + Layer* findLayerById(int layerId) const; bool swapLayers(int i, int j); void deleteLayer(int i); - void deleteLayer(Layer*); - - template - std::vector getLayersByType() const - { - std::vector result; - for (Layer* layer : mLayers) - { - T* t = dynamic_cast(layer); - if (t) - result.push_back(t); - } - return result; - } + void deleteLayerWithId(int layerId); + + template< typename T > + std::vector< T* > getLayersByType() const + { + std::vector< T* > result; + for ( Layer* layer : mLayers) + { + T* t = dynamic_cast(layer); + if ( t ) + result.push_back(t); + } + return result; + } // these functions need to be moved to somewhere... bool exportFrames(int frameStart, int frameEnd, LayerCamera* cameraLayer, QSize exportSize, QString filePath, QString format, diff --git a/core_lib/src/structure/soundclip.cpp b/core_lib/src/structure/soundclip.cpp index cde265d6e0..bd9dfa3ded 100644 --- a/core_lib/src/structure/soundclip.cpp +++ b/core_lib/src/structure/soundclip.cpp @@ -36,7 +36,7 @@ SoundClip::~SoundClip() //QFile::remove( fileName() ); } -SoundClip* SoundClip::clone() +SoundClip* SoundClip::clone() const { return new SoundClip(*this); } diff --git a/core_lib/src/structure/soundclip.h b/core_lib/src/structure/soundclip.h index b2ee7dd85c..0fee6031e3 100644 --- a/core_lib/src/structure/soundclip.h +++ b/core_lib/src/structure/soundclip.h @@ -31,7 +31,7 @@ class SoundClip : public KeyFrame explicit SoundClip(const SoundClip&); ~SoundClip() override; - SoundClip* clone() override; + SoundClip* clone() const override; Status init(const QString& strSoundFile); bool isValid() const; diff --git a/core_lib/src/tool/brushtool.cpp b/core_lib/src/tool/brushtool.cpp index 631b2c00c5..3ed62b1305 100644 --- a/core_lib/src/tool/brushtool.cpp +++ b/core_lib/src/tool/brushtool.cpp @@ -17,7 +17,6 @@ GNU General Public License for more details. #include "brushtool.h" -#include #include #include #include @@ -29,6 +28,7 @@ GNU General Public License for more details. #include "colormanager.h" #include "strokemanager.h" #include "layermanager.h" +#include "backupmanager.h" #include "viewmanager.h" #include "selectionmanager.h" #include "scribblearea.h" @@ -185,7 +185,6 @@ void BrushTool::pointerMoveEvent(PointerEvent* event) void BrushTool::pointerReleaseEvent(PointerEvent*) { Layer* layer = mEditor->layers()->currentLayer(); - mEditor->backup(typeName()); qreal distance = QLineF(getCurrentPoint(), mMouseDownPoint).length(); if (distance < 1) @@ -197,10 +196,16 @@ void BrushTool::pointerReleaseEvent(PointerEvent*) drawStroke(); } + mEditor->backups()->saveStates(); if (layer->type() == Layer::BITMAP) + { paintBitmapStroke(); - else if (layer->type() == Layer::VECTOR) + mEditor->backups()->bitmap(tr("Bitmap: Brush")); + } + else if (layer->type() == Layer::VECTOR) { paintVectorStroke(); + mEditor->backups()->vector(tr("Vector: Brush")); + } endStroke(); } @@ -362,8 +367,6 @@ void BrushTool::paintVectorStroke() mEditor->deselectAll(); } - vectorImage->setSelected(vectorImage->getLastCurveNumber(), true); - mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); } diff --git a/core_lib/src/tool/buckettool.cpp b/core_lib/src/tool/buckettool.cpp index a41aba2b28..d0827c4c4b 100644 --- a/core_lib/src/tool/buckettool.cpp +++ b/core_lib/src/tool/buckettool.cpp @@ -23,10 +23,13 @@ GNU General Public License for more details. #include "layer.h" #include "layervector.h" #include "layerbitmap.h" + #include "layermanager.h" #include "colormanager.h" #include "strokemanager.h" +#include "backupmanager.h" #include "viewmanager.h" + #include "vectorimage.h" #include "editor.h" #include "scribblearea.h" @@ -106,7 +109,6 @@ void BucketTool::setTolerance(const int tolerance) void BucketTool::pointerPressEvent(PointerEvent* event) { - startStroke(); if (event->button() == Qt::LeftButton) { mScribbleArea->setAllDirty(); @@ -133,14 +135,15 @@ void BucketTool::pointerReleaseEvent(PointerEvent* event) if (event->button() == Qt::LeftButton) { - mEditor->backup(typeName()); - - switch (layer->type()) + mEditor->backups()->saveStates(); + if ( layer->type() == Layer::BITMAP ) { - case Layer::BITMAP: paintBitmap(layer); break; - case Layer::VECTOR: paintVector(layer); break; - default: - break; + paintBitmap(layer); + mEditor->backups()->bitmap(tr("Bitmap: Bucket")); + } + else if (layer->type() == Layer::VECTOR ) + { + paintVector(layer); } } endStroke(); @@ -184,6 +187,10 @@ void BucketTool::paintVector(Layer* layer) mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); + + if (vectorImage->isSelected()) { + mEditor->backups()->vector(tr("Vector: Bucket")); + } } void BucketTool::applyChanges() diff --git a/core_lib/src/tool/erasertool.cpp b/core_lib/src/tool/erasertool.cpp index 022eb82d37..41e8e7525c 100644 --- a/core_lib/src/tool/erasertool.cpp +++ b/core_lib/src/tool/erasertool.cpp @@ -25,7 +25,11 @@ GNU General Public License for more details. #include "scribblearea.h" #include "strokemanager.h" #include "layermanager.h" +#include "backupmanager.h" #include "viewmanager.h" +#include "colormanager.h" +#include "selectionmanager.h" + #include "layervector.h" #include "vectorimage.h" #include "pointerevent.h" @@ -116,6 +120,7 @@ QCursor EraserTool::cursor() void EraserTool::pointerPressEvent(PointerEvent*) { + mEditor->backups()->saveStates(); mScribbleArea->setAllDirty(); startStroke(); @@ -136,9 +141,8 @@ void EraserTool::pointerMoveEvent(PointerEvent* event) void EraserTool::pointerReleaseEvent(PointerEvent*) { - mEditor->backup(typeName()); + qreal distance = QLineF( getCurrentPoint(), mMouseDownPoint ).length(); - qreal distance = QLineF(getCurrentPoint(), mMouseDownPoint).length(); if (distance < 1) { paintAt(mMouseDownPoint); @@ -279,6 +283,7 @@ void EraserTool::removeVectorPaint() mScribbleArea->paintBitmapBuffer(); mScribbleArea->setAllDirty(); mScribbleArea->clearBitmapBuffer(); + mEditor->backups()->bitmap(tr("Bitmap: Eraser")); } else if (layer->type() == Layer::VECTOR) { @@ -287,10 +292,11 @@ void EraserTool::removeVectorPaint() //vectorImage->removeArea(lastPoint); // Clear the temporary pixel path mScribbleArea->clearBitmapBuffer(); - vectorImage->deleteSelectedPoints(); - mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); - mScribbleArea->setAllDirty(); + if (vectorImage->deleteSelectedPoints()) { + mScribbleArea->setAllDirty(); + mEditor->backups()->vector(tr("Vector: Eraser")); + } } } diff --git a/core_lib/src/tool/handtool.cpp b/core_lib/src/tool/handtool.cpp index e137e7b2a3..41e6fead00 100644 --- a/core_lib/src/tool/handtool.cpp +++ b/core_lib/src/tool/handtool.cpp @@ -22,11 +22,15 @@ GNU General Public License for more details. #include #include +#include "viewmanager.h" +#include "layermanager.h" +#include "backupmanager.h" +#include "strokemanager.h" + #include "layer.h" #include "layercamera.h" + #include "editor.h" -#include "strokemanager.h" -#include "viewmanager.h" #include "scribblearea.h" #include "mathutils.h" @@ -55,6 +59,7 @@ void HandTool::pointerPressEvent(PointerEvent*) mIsHeld = true; mScribbleArea->updateToolCursor(); + mEditor->backups()->saveStates(); } void HandTool::pointerMoveEvent(PointerEvent* event) @@ -78,6 +83,13 @@ void HandTool::pointerReleaseEvent(PointerEvent* event) } mIsHeld = false; mScribbleArea->updateToolCursor(); + + Layer* layer = mEditor->layers()->currentLayer(); + if (layer->type() == Layer::CAMERA) + { + BackupManager* backup = mEditor->backups(); + backup->cameraMotion(); + } } void HandTool::pointerDoubleClickEvent(PointerEvent* event) diff --git a/core_lib/src/tool/movetool.cpp b/core_lib/src/tool/movetool.cpp index 93fa190b9c..6c313f3e4d 100644 --- a/core_lib/src/tool/movetool.cpp +++ b/core_lib/src/tool/movetool.cpp @@ -22,16 +22,20 @@ GNU General Public License for more details. #include "pointerevent.h" #include "editor.h" + #include "toolmanager.h" #include "viewmanager.h" #include "strokemanager.h" #include "selectionmanager.h" +#include "backupmanager.h" +#include "layermanager.h" #include "scribblearea.h" #include "layervector.h" -#include "layermanager.h" -#include "mathutils.h" #include "vectorimage.h" +#include "mathutils.h" +#include "bitmapimage.h" +#include "layerbitmap.h" MoveTool::MoveTool(QObject* parent) : BaseTool(parent) { @@ -121,14 +125,26 @@ void MoveTool::pointerReleaseEvent(PointerEvent*) updateTransformation(); Layer* layer = mEditor->layers()->currentLayer(); + + if (selectMan->selectionMoved()) { + mEditor->backups()->transform(tr("Transformed image")); + } else { + if (selectMan->somethingSelected()) { + mEditor->backups()->selection(); + } + } + if (layer->type() == Layer::VECTOR) { applyTransformation(); + selectMan->sync(); } selectMan->updatePolygons(); mScribbleArea->updateToolCursor(); mScribbleArea->updateCurrentFrame(); + + mScribbleArea->setModified(mEditor->currentLayerIndex(), mEditor->currentFrame()); } void MoveTool::updateTransformation() @@ -186,15 +202,18 @@ void MoveTool::beginInteraction(Qt::KeyboardModifiers keyMod, Layer* layer) QRectF selectionRect = selectMan->myTransformedSelectionRect(); if (!selectionRect.isNull()) { - mEditor->backup(typeName()); + mEditor->backups()->saveStates(); } - if (keyMod != Qt::ShiftModifier) - { - if (selectMan->isOutsideSelectionArea(getCurrentPoint())) + if (selectMan->somethingSelected()) { + if (keyMod != Qt::ShiftModifier) { - applyTransformation(); - mEditor->deselectAll(); + if (selectMan->isOutsideSelectionArea(getCurrentPoint())) + { + applyTransformation(); + mEditor->deselectAll(); + mEditor->backups()->deselect(); + } } } @@ -229,7 +248,8 @@ void MoveTool::createVectorSelection(Qt::KeyboardModifiers keyMod, Layer* layer) LayerVector* vecLayer = static_cast(layer); VectorImage* vectorImage = vecLayer->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); - if (!mEditor->select()->closestCurves().empty()) // the user clicks near a curve + auto selectMan = mEditor->select(); + if (!selectMan->closestCurves().empty()) // the user clicks near a curve { setCurveSelected(vectorImage, keyMod); } @@ -243,14 +263,17 @@ void MoveTool::createVectorSelection(Qt::KeyboardModifiers keyMod, Layer* layer) void MoveTool::setCurveSelected(VectorImage* vectorImage, Qt::KeyboardModifiers keyMod) { auto selectMan = mEditor->select(); - if (!vectorImage->isSelected(selectMan->closestCurves())) + QList selectedCurves = selectMan->closestCurves(); + if (!vectorImage->isSelected(selectedCurves)) { - if (keyMod != Qt::ShiftModifier) - { - applyTransformation(); + if (keyMod != Qt::ShiftModifier) { + vectorImage->deselectAll(); } - vectorImage->setSelected(selectMan->closestCurves(), true); + applyTransformation(); + + vectorImage->setSelected(selectedCurves, true); selectMan->setSelection(vectorImage->getSelectionRect()); + selectMan->addCurvesToVectorSelection(selectedCurves); } } @@ -287,10 +310,12 @@ void MoveTool::setAnchorToLastPoint() void MoveTool::cancelChanges() { + mEditor->backups()->saveStates(); auto selectMan = mEditor->select(); mScribbleArea->cancelTransformedSelection(); selectMan->resetSelectionProperties(); mEditor->deselectAll(); + mEditor->backups()->deselect(); } void MoveTool::applySelectionChanges() @@ -313,15 +338,23 @@ void MoveTool::paintTransformedSelection() bool MoveTool::leavingThisTool() { - if (mCurrentLayer) - { - switch (mCurrentLayer->type()) + mEditor->backups()->saveStates(); + if (mEditor->select()->transformHasBeenModified()) { + if (mCurrentLayer) { - case Layer::BITMAP: applySelectionChanges(); break; - case Layer::VECTOR: applyTransformation(); break; - default: break; + switch (mCurrentLayer->type()) + { + case Layer::BITMAP: applySelectionChanges(); break; + case Layer::VECTOR: applyTransformation(); break; + default: break; + } } } + + if (mEditor->select()->somethingSelected()) { + mEditor->deselectAll(); + mEditor->backups()->deselect(); + } return true; } @@ -340,10 +373,9 @@ bool MoveTool::switchingLayer() { if (mCurrentLayer->type() == Layer::BITMAP) { - applySelectionChanges(); - } - else if (mCurrentLayer->type() == Layer::VECTOR) - { + applyTransformation(); + + } else if (mCurrentLayer->type() == Layer::VECTOR) { applyTransformation(); } diff --git a/core_lib/src/tool/penciltool.cpp b/core_lib/src/tool/penciltool.cpp index d7871a5344..d774d07149 100644 --- a/core_lib/src/tool/penciltool.cpp +++ b/core_lib/src/tool/penciltool.cpp @@ -21,6 +21,11 @@ GNU General Public License for more details. #include "pointerevent.h" #include "layermanager.h" + +#include "layervector.h" +#include "layerbitmap.h" + +#include "backupmanager.h" #include "colormanager.h" #include "strokemanager.h" #include "viewmanager.h" @@ -173,7 +178,8 @@ void PencilTool::pointerMoveEvent(PointerEvent* event) void PencilTool::pointerReleaseEvent(PointerEvent*) { - mEditor->backup(typeName()); + Layer* layer = mEditor->layers()->currentLayer(); + qreal distance = QLineF(getCurrentPoint(), mMouseDownPoint).length(); if (distance < 1) { @@ -183,12 +189,18 @@ void PencilTool::pointerReleaseEvent(PointerEvent*) { drawStroke(); } - - Layer* layer = mEditor->layers()->currentLayer(); - if (layer->type() == Layer::BITMAP) - paintBitmapStroke(); - else if (layer->type() == Layer::VECTOR) - paintVectorStroke(layer); + + mEditor->backups()->saveStates(); + if ( layer->type() == Layer::BITMAP ) + { + paintBitmapStroke(); + mEditor->backups()->bitmap(tr("Bitmap: Pencil")); + } + else if (layer->type() == Layer::VECTOR ) + { + paintVectorStroke(layer); + mEditor->backups()->vector(tr("Vector: Pencil")); + } endStroke(); } @@ -328,11 +340,6 @@ void PencilTool::paintVectorStroke(Layer* layer) mEditor->deselectAll(); } - // select last/newest curve - vectorImage->setSelected(vectorImage->getLastCurveNumber(), true); - - // TODO: selection doesn't apply on enter - mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); } diff --git a/core_lib/src/tool/pentool.cpp b/core_lib/src/tool/pentool.cpp index fd861cb07f..e92a2e9289 100644 --- a/core_lib/src/tool/pentool.cpp +++ b/core_lib/src/tool/pentool.cpp @@ -23,8 +23,10 @@ GNU General Public License for more details. #include "colormanager.h" #include "strokemanager.h" #include "layermanager.h" +#include "backupmanager.h" #include "viewmanager.h" #include "selectionmanager.h" + #include "editor.h" #include "scribblearea.h" #include "blitrect.h" @@ -136,8 +138,6 @@ void PenTool::pointerMoveEvent(PointerEvent* event) void PenTool::pointerReleaseEvent(PointerEvent*) { - mEditor->backup(typeName()); - Layer* layer = mEditor->layers()->currentLayer(); qreal distance = QLineF(getCurrentPoint(), mMouseDownPoint).length(); @@ -150,10 +150,15 @@ void PenTool::pointerReleaseEvent(PointerEvent*) drawStroke(); } - if (layer->type() == Layer::BITMAP) + mEditor->backups()->saveStates(); + if (layer->type() == Layer::BITMAP) { paintBitmapStroke(); - else if (layer->type() == Layer::VECTOR) + mEditor->backups()->bitmap(tr("Bitmap: Pen")); + } + else if (layer->type() == Layer::VECTOR) { paintVectorStroke(layer); + mEditor->backups()->vector(tr("Vector: Pen")); + } endStroke(); } @@ -288,8 +293,6 @@ void PenTool::paintVectorStroke(Layer* layer) mEditor->deselectAll(); } - vectorImage->setSelected(vectorImage->getLastCurveNumber(), true); - mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); mScribbleArea->setAllDirty(); } diff --git a/core_lib/src/tool/polylinetool.cpp b/core_lib/src/tool/polylinetool.cpp index bbe055105f..ab7bc7e997 100644 --- a/core_lib/src/tool/polylinetool.cpp +++ b/core_lib/src/tool/polylinetool.cpp @@ -23,6 +23,7 @@ GNU General Public License for more details. #include "strokemanager.h" #include "layermanager.h" +#include "backupmanager.h" #include "colormanager.h" #include "viewmanager.h" #include "pointerevent.h" @@ -142,9 +143,7 @@ void PolylineTool::pointerDoubleClickEvent(PointerEvent*) // include the current point before ending the line. mPoints << getCurrentPoint(); - mEditor->backup(typeName()); - - endPolyline(mPoints); + endPolyline( mPoints ); clearToolData(); } @@ -235,7 +234,8 @@ void PolylineTool::endPolyline(QList points) { Layer* layer = mEditor->layers()->currentLayer(); - if (layer->type() == Layer::VECTOR) + mEditor->backups()->saveStates(); + if ( layer->type() == Layer::VECTOR ) { BezierCurve curve = BezierCurve(points); if (mScribbleArea->makeInvisible() == true) @@ -250,13 +250,15 @@ void PolylineTool::endPolyline(QList points) curve.setVariableWidth(false); curve.setInvisibility(mScribbleArea->makeInvisible()); - ((LayerVector *)layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->addCurve(curve, mEditor->view()->scaling()); + ( ( LayerVector * )layer )->getLastVectorImageAtFrame( mEditor->currentFrame(), 0 )->addCurve( curve, mEditor->view()->scaling() ); + mEditor->backups()->vector(tr("Vector: Polyline")); } if (layer->type() == Layer::BITMAP) { - drawPolyline(points, points.last()); - BitmapImage *bitmapImage = ((LayerBitmap *)layer)->getLastBitmapImageAtFrame(mEditor->currentFrame(), 0); - bitmapImage->paste(mScribbleArea->mBufferImg); + drawPolyline( points, points.last() ); + BitmapImage *bitmapImage = ( ( LayerBitmap * )layer )->getLastBitmapImageAtFrame( mEditor->currentFrame(), 0 ); + bitmapImage->paste( mScribbleArea->mBufferImg ); + mEditor->backups()->bitmap(tr("Bitmap: Polyline")); } mScribbleArea->mBufferImg->clear(); mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); diff --git a/core_lib/src/tool/selecttool.cpp b/core_lib/src/tool/selecttool.cpp index 2cd31056ed..87d5e230f1 100644 --- a/core_lib/src/tool/selecttool.cpp +++ b/core_lib/src/tool/selecttool.cpp @@ -21,6 +21,7 @@ GNU General Public License for more details. #include "strokemanager.h" #include "layervector.h" #include "scribblearea.h" +#include "backupmanager.h" #include "layermanager.h" #include "toolmanager.h" #include "selectionmanager.h" @@ -49,6 +50,26 @@ void SelectTool::beginSelection() mAnchorOriginPoint = getLastPoint(); auto selectMan = mEditor->select(); + + // checks whether anchorPoint and selection is still valid + // otherwise make sure selection will be deselected on release + if (selectMan->somethingSelected()) { + if (maybeDeselect()) { + mDeselectSelection = true; + } + } + + QPointF lastPoint = getLastPoint(); + QPointF currentPoint = getCurrentPoint(); + + if (mCurrentLayer->type() == Layer::BITMAP) { + lastPoint = lastPoint.toPoint(); + mAnchorOriginPoint = lastPoint; + currentPoint = currentPoint.toPoint(); + } + + mEditor->backups()->saveStates(); + selectMan->calculateSelectionTransformation(); // paint and apply the transformation @@ -57,23 +78,26 @@ void SelectTool::beginSelection() if (selectMan->somethingSelected()) // there is something selected { + if (!selectMan->myTempTransformedSelectionRect().contains(getCurrentPoint())) { + mPointOutsideSelection = true; + } if (mCurrentLayer->type() == Layer::VECTOR) { static_cast(mCurrentLayer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0)->deselectAll(); } - mAnchorOriginPoint = selectMan->whichAnchorPoint(getLastPoint()); + mAnchorOriginPoint = selectMan->whichAnchorPoint(lastPoint); // the user did not click on one of the corners - if (selectMan->validateMoveMode(getLastPoint()) == MoveMode::NONE) + if (selectMan->validateMoveMode(lastPoint) == MoveMode::NONE) { - const QRectF& newRect = QRectF(getLastPoint(), getLastPoint()); + QRectF newRect = QRectF(lastPoint, lastPoint); selectMan->setSelection(newRect); } } else { - selectMan->setSelection(QRectF(getCurrentPoint().x(), getCurrentPoint().y(),1,1)); + selectMan->setSelection(QRectF(currentPoint.x(), currentPoint.y(),1,1)); mMoveMode = MoveMode::NONE; } mScribbleArea->update(); @@ -103,13 +127,19 @@ void SelectTool::pointerMoveEvent(PointerEvent* event) if (!selectMan->somethingSelected()) { return; } + QPointF currentPoint = getCurrentPoint(); + + if (mCurrentLayer->type() == Layer::BITMAP) { + currentPoint = currentPoint.toPoint(); + } + selectMan->updatePolygons(); mScribbleArea->updateToolCursor(); if (mScribbleArea->isPointerInUse()) { - controlOffsetOrigin(getCurrentPoint(), mAnchorOriginPoint); + controlOffsetOrigin(currentPoint, mAnchorOriginPoint); if (mCurrentLayer->type() == Layer::VECTOR) { @@ -120,6 +150,7 @@ void SelectTool::pointerMoveEvent(PointerEvent* event) } mScribbleArea->updateCurrentFrame(); + } void SelectTool::pointerReleaseEvent(PointerEvent* event) @@ -129,16 +160,23 @@ void SelectTool::pointerReleaseEvent(PointerEvent* event) if (event->button() != Qt::LeftButton) return; auto selectMan = mEditor->select(); + mMoveMode = MoveMode::NONE; + // if there's a small very small distance between current and last point // discard the selection... // TODO: improve by adding a timer to check if the user is deliberately selecting if (QLineF(mAnchorOriginPoint, getCurrentPoint()).length() < 5.0) { mEditor->deselectAll(); + mDeselectSelection = false; + // no backup here, since we didn't intend to make a selection in the first place } - if (maybeDeselect()) + + if (mDeselectSelection) { mEditor->deselectAll(); + mEditor->backups()->deselect(); + mDeselectSelection = false; } else { @@ -149,12 +187,13 @@ void SelectTool::pointerReleaseEvent(PointerEvent* event) mScribbleArea->updateToolCursor(); mScribbleArea->updateCurrentFrame(); -// mScribbleArea->setAllDirty(); + //mScribbleArea->setAllDirty(); } bool SelectTool::maybeDeselect() { - return (!isSelectionPointValid() && mEditor->select()->validateMoveMode(getLastPoint()) == MoveMode::NONE); + return (!isSelectionPointValid() && + mEditor->select()->validateMoveMode(getLastPoint()) == MoveMode::NONE); } /** @@ -178,7 +217,10 @@ void SelectTool::keepSelection() { VectorImage* vectorImage = static_cast(mCurrentLayer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); selectMan->setSelection(vectorImage->getSelectionRect()); + selectMan->addCurvesToVectorSelection(vectorImage->getSelectedCurveNumbers()); } + + mEditor->backups()->selection(); } void SelectTool::controlOffsetOrigin(QPointF currentPoint, QPointF anchorPoint) @@ -187,13 +229,14 @@ void SelectTool::controlOffsetOrigin(QPointF currentPoint, QPointF anchorPoint) if (mMoveMode != MoveMode::NONE) { + QPointF currentPoint = getCurrentPoint(); if (editor()->layers()->currentLayer()->type() == Layer::BITMAP) { offset = QPointF(offset).toPoint(); - } + currentPoint = currentPoint.toPoint(); + auto selectMan = mEditor->select(); - auto selectMan = mEditor->select(); - - selectMan->adjustSelection(getCurrentPoint(), offset.x(), offset.y(), selectMan->myRotation(), 0); + selectMan->adjustSelection(currentPoint, offset.x(), offset.y(), selectMan->myRotation(), 0); + } } else { diff --git a/core_lib/src/tool/selecttool.h b/core_lib/src/tool/selecttool.h index 61b22ad806..a979c71970 100644 --- a/core_lib/src/tool/selecttool.h +++ b/core_lib/src/tool/selecttool.h @@ -57,6 +57,9 @@ class SelectTool : public BaseTool QPointF mAnchorOriginPoint; MoveMode mMoveMode; Layer* mCurrentLayer = nullptr; + + bool mPointOutsideSelection = false; + bool mDeselectSelection = false; }; #endif diff --git a/core_lib/src/tool/smudgetool.cpp b/core_lib/src/tool/smudgetool.cpp index 1b8a911ee1..f212e971fa 100644 --- a/core_lib/src/tool/smudgetool.cpp +++ b/core_lib/src/tool/smudgetool.cpp @@ -23,6 +23,9 @@ GNU General Public License for more details. #include "scribblearea.h" #include "layermanager.h" +#include "colormanager.h" +#include "backupmanager.h" +#include "strokemanager.h" #include "strokemanager.h" #include "viewmanager.h" #include "selectionmanager.h" @@ -132,6 +135,7 @@ bool SmudgeTool::keyReleaseEvent(QKeyEvent*) void SmudgeTool::pointerPressEvent(PointerEvent* event) { //qDebug() << "smudgetool: mousePressEvent"; + mEditor->backups()->saveStates(); Layer* layer = mEditor->layers()->currentLayer(); auto selectMan = mEditor->select(); @@ -148,12 +152,12 @@ void SmudgeTool::pointerPressEvent(PointerEvent* event) else if (layer->type() == Layer::VECTOR) { const int currentFrame = mEditor->currentFrame(); - const float distanceFrom = selectMan->selectionTolerance(); + const qreal distanceFrom = selectMan->selectionTolerance(); VectorImage* vectorImage = static_cast(layer)->getLastVectorImageAtFrame(currentFrame, 0); + selectMan->setCurves(vectorImage->getCurvesCloseTo(getCurrentPoint(), distanceFrom)); selectMan->setVertices(vectorImage->getVerticesCloseTo(getCurrentPoint(), distanceFrom)); -; - if (selectMan->closestCurves().size() > 0 || selectMan->closestCurves().size() > 0) // the user clicks near a vertex or a curve + if (selectMan->closestCurves().size() > 0 || selectMan->closestVertices().size() > 0) // the user clicks near a vertex or a curve { // Since startStroke() isn't called, handle empty frame behaviour here. // Commented out for now - leads to segfault on mouse-release event. @@ -162,22 +166,39 @@ void SmudgeTool::pointerPressEvent(PointerEvent* event) // mScribbleArea->handleDrawingOnEmptyFrame(); // } + //qDebug() << "closestCurves:" << closestCurves << " | closestVertices" << closestVertices; - if (event->modifiers() != Qt::ShiftModifier && !vectorImage->isSelected(selectMan->closestVertices())) + mNumberOfCurvesSelected = selectMan->vectorSelection().curves.count(); + if (event->modifiers() != Qt::ShiftModifier) { mScribbleArea->paintTransformedSelection(); mEditor->deselectAll(); + mNumberOfCurvesSelected = 0; } - vectorImage->setSelected(selectMan->closestVertices(), true); - selectMan->vectorSelection.add(selectMan->closestCurves()); - selectMan->vectorSelection.add(selectMan->closestVertices()); + selectMan->addCurvesAndVerticesToVectorSelection(selectMan->closestCurves(), + selectMan->closestVertices()); + + vectorImage->setSelected(selectMan->closestCurves(), selectMan->closestVertices(), true); + + if (!mDeselection || mNumberOfCurvesSelected != mPreviousNumberOfCurvesSelected) { + mEditor->backups()->selection(); + mDeselection = true; + } + mPreviousNumberOfCurvesSelected = mNumberOfCurvesSelected; mScribbleArea->update(); } else { - mEditor->deselectAll(); + if (vectorImage->isSelected()) { + mNumberOfCurvesSelected = 0; + mPreviousNumberOfCurvesSelected = 0; + + mEditor->deselectAll(); + mEditor->backups()->deselect(); + mDeselection = false; + } } } } @@ -207,8 +228,11 @@ void SmudgeTool::pointerMoveEvent(PointerEvent* event) VectorImage* vectorImage = static_cast(layer)->getLastVectorImageAtFrame(mEditor->currentFrame(), 0); // transforms the selection - selectMan->setSelectionTransform(QTransform().translate(offsetFromPressPos().x(), offsetFromPressPos().y())); - vectorImage->setSelectionTransformation(selectMan->selectionTransform()); + if (vectorImage->isSelected(selectMan->vectorSelection().vertices)) { + selectMan->setSelectionTransform(QTransform().translate(offsetFromPressPos().x(), offsetFromPressPos().y())); + vectorImage->setSelectionTransformation(selectMan->selectionTransform()); + mTransformModified = true; + } } } } @@ -232,13 +256,12 @@ void SmudgeTool::pointerReleaseEvent(PointerEvent* event) if (event->button() == Qt::LeftButton) { - mEditor->backup(typeName()); - if (layer->type() == Layer::BITMAP) { drawStroke(); mScribbleArea->setAllDirty(); endStroke(); + mEditor->backups()->bitmap(tr("Bitmap: Smudge")); } else if (layer->type() == Layer::VECTOR) { @@ -247,12 +270,17 @@ void SmudgeTool::pointerReleaseEvent(PointerEvent* event) auto selectMan = mEditor->select(); selectMan->resetSelectionTransform(); - for (int k = 0; k < selectMan->vectorSelection.curve.size(); k++) + for (int k = 0; k < selectMan->vectorSelection().curves.size(); k++) { - int curveNumber = selectMan->vectorSelection.curve.at(k); + int curveNumber = selectMan->vectorSelection().curves.at(k); vectorImage->curve(curveNumber).smoothCurve(); } mScribbleArea->setModified(mEditor->layers()->currentLayerIndex(), mEditor->currentFrame()); + + if (mTransformModified) { + mEditor->backups()->vector(tr("Vector: Smudge")); + mTransformModified = false; + } } } } @@ -343,6 +371,22 @@ void SmudgeTool::drawStroke() } } +bool SmudgeTool::leavingThisTool() +{ + if (mEditor->layers()->currentLayer()->type() == Layer::VECTOR) + { + if (!mEditor->select()->vectorSelection().isEmpty()) { + mNumberOfCurvesSelected = 0; + mPreviousNumberOfCurvesSelected = 0; + + mEditor->deselectAll(); + mEditor->backups()->deselect(); + mDeselection = false; + } + } + return true; +} + QPointF SmudgeTool::offsetFromPressPos() { return getCurrentPoint() - getCurrentPressPoint(); diff --git a/core_lib/src/tool/smudgetool.h b/core_lib/src/tool/smudgetool.h index da2c9d1142..4b6883101e 100644 --- a/core_lib/src/tool/smudgetool.h +++ b/core_lib/src/tool/smudgetool.h @@ -44,6 +44,8 @@ class SmudgeTool : public StrokeTool void setFeather( const qreal feather ) override; void setPressure( const bool pressure ) override; + bool leavingThisTool() override; + protected: bool emptyFrameActionEnabled() override; @@ -52,6 +54,11 @@ class SmudgeTool : public StrokeTool QPointF offsetFromPressPos(); QPointF mLastBrushPoint; + bool mTransformModified = false; + bool mDeselection = false; + + int mNumberOfCurvesSelected = 0; + int mPreviousNumberOfCurvesSelected = 0; }; #endif // SMUDGETOOL_H diff --git a/core_lib/src/util/direction.h b/core_lib/src/util/direction.h new file mode 100644 index 0000000000..bb06916138 --- /dev/null +++ b/core_lib/src/util/direction.h @@ -0,0 +1,27 @@ +/* + +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 9bce0d16a7..a004fe6ac8 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -53,6 +53,11 @@ enum ToolType : int TOOL_TYPE_COUNT }; +enum SelectionType { + SELECTION, + DESELECT +}; + enum ToolPropertyType { WIDTH, diff --git a/core_lib/src/util/pencilerror.h b/core_lib/src/util/pencilerror.h index 8ecc6e7843..b49cd9ef07 100644 --- a/core_lib/src/util/pencilerror.h +++ b/core_lib/src/util/pencilerror.h @@ -76,6 +76,11 @@ class Status ErrorCode errorcode = Status::OK; }; + struct StatusBool { + bool value = false; + ErrorCode errorcode = Status::OK; + }; + Status(ErrorCode code); Status(ErrorCode code, const DebugDetails& detailsList, QString title = "", QString description = ""); diff --git a/tests/src/test_backupmanager.cpp b/tests/src/test_backupmanager.cpp new file mode 100644 index 0000000000..877adcd441 --- /dev/null +++ b/tests/src/test_backupmanager.cpp @@ -0,0 +1,54 @@ +/* + +Pencil - Traditional Animation Software +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. + +*/ + +// test header +#include "catch.hpp" + +// required qt headers... +#include "QDebug" + + +// pencil2d headers +#include "editor.h" +#include "bitmapimage.h" +#include "layerbitmap.h" +#include "backupmanager.h" +#include "backupelement.h" +#include "object.h" + +class QUndoStack; + +TEST_CASE("Backupmanager setup") +{ + Object* object = new Object; + Editor* editor = new Editor; + editor->setObject(object); + + BackupManager* backups = new BackupManager(editor); + SECTION("Init Undostack") + { + + REQUIRE(editor != nullptr); + object->init(); + backups->init(); + } + + // Doesn't work because of scribblearea... +// SECTION("Try saveStates") +// { +// backups->saveStates(); +// } +} diff --git a/tests/src/test_filemanager.cpp b/tests/src/test_filemanager.cpp index af269788f2..197823e31f 100644 --- a/tests/src/test_filemanager.cpp +++ b/tests/src/test_filemanager.cpp @@ -298,7 +298,7 @@ TEST_CASE("FileManager File-saving") for (int i = 100; i < 150; ++i) layer->setFrameSelected(i, true); - layer->moveSelectedFrames(-55); + layer->offsetSelectedFrames(-55); fm.save(o2, animationPath); delete o2; diff --git a/tests/tests.pro b/tests/tests.pro index 7f57bfe735..d96f0be0d6 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -39,7 +39,8 @@ SOURCES += \ src/test_object.cpp \ src/test_filemanager.cpp \ src/test_bitmapimage.cpp \ - src/test_viewmanager.cpp + src/test_viewmanager.cpp \ + src/test_backupmanager.cpp # --- CoreLib --- win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../core_lib/release/ -lcore_lib