diff --git a/app/src/mainwindow2.cpp b/app/src/mainwindow2.cpp index 23e9b42ecd..da8cd8099c 100644 --- a/app/src/mainwindow2.cpp +++ b/app/src/mainwindow2.cpp @@ -450,9 +450,6 @@ void MainWindow2::openPegAlignDialog() mPegAlign = new PegBarAlignmentDialog(mEditor, this); mPegAlign->setAttribute(Qt::WA_DeleteOnClose); - mPegAlign->updatePegRegLayers(); - mPegAlign->setRefLayer(mEditor->layers()->currentLayer()->name()); - mPegAlign->setRefKey(mEditor->currentFrame()); Qt::WindowFlags flags = mPegAlign->windowFlags(); flags |= Qt::WindowStaysOnTopHint; @@ -592,6 +589,8 @@ bool MainWindow2::openObject(const QString& strFilePath) mRecentFileMenu->saveToDisk(); } + closeDialogs(); + setWindowTitle(mEditor->object()->filePath().prepend("[*]")); setWindowModified(false); @@ -986,6 +985,8 @@ void MainWindow2::newObject() object->createDefaultLayers(); mEditor->setObject(object); + closeDialogs(); + setWindowTitle(PENCIL_WINDOW_TITLE); } @@ -1063,6 +1064,13 @@ bool MainWindow2::tryLoadPreset() return true; } +void MainWindow2::closeDialogs() +{ + for (auto dialog : findChildren(QString(), Qt::FindDirectChildrenOnly)) { + dialog->close(); + } +} + void MainWindow2::readSettings() { QSettings settings(PENCIL2D, PENCIL2D); @@ -1332,6 +1340,7 @@ void MainWindow2::makeConnections(Editor* editor, ColorInspector* colorInspector void MainWindow2::makeConnections(Editor* editor, ScribbleArea* scribbleArea) { connect(editor->tools(), &ToolManager::toolChanged, scribbleArea, &ScribbleArea::setCurrentTool); + connect(editor->tools(), &ToolManager::toolChanged, mToolBox, &ToolBoxWidget::onToolSetActive); connect(editor->tools(), &ToolManager::toolPropertyChanged, scribbleArea, &ScribbleArea::updateToolCursor); diff --git a/app/src/mainwindow2.h b/app/src/mainwindow2.h index b8b9d7fdc8..d1a8a86aa8 100644 --- a/app/src/mainwindow2.h +++ b/app/src/mainwindow2.h @@ -113,6 +113,7 @@ public slots: bool newObjectFromPresets(int presetIndex); bool openObject(const QString& strFilename); bool saveObject(QString strFileName); + void closeDialogs(); void createDockWidgets(); void createMenus(); diff --git a/app/src/pegbaralignmentdialog.cpp b/app/src/pegbaralignmentdialog.cpp index 2b84fec8cc..8d13ed2294 100644 --- a/app/src/pegbaralignmentdialog.cpp +++ b/app/src/pegbaralignmentdialog.cpp @@ -20,15 +20,20 @@ GNU General Public License for more details. #include #include #include + +#include "keyframe.h" #include "layermanager.h" #include "selectionmanager.h" +#include "toolmanager.h" +#include "scribblearea.h" + +#include PegBarAlignmentDialog::PegBarAlignmentDialog(Editor *editor, QWidget *parent) : QDialog(parent), - ui(new Ui::PegBarAlignmentDialog) + ui(new Ui::PegBarAlignmentDialog), mEditor(editor) { ui->setupUi(this); - mEditor = editor; connect(ui->btnAlign, &QPushButton::clicked, this, &PegBarAlignmentDialog::alignPegs); connect(ui->btnCancel, &QPushButton::clicked, this, &PegBarAlignmentDialog::closeClicked); connect(ui->lwLayers, &QListWidget::clicked, this, &PegBarAlignmentDialog::updatePegRegDialog); @@ -36,10 +41,19 @@ PegBarAlignmentDialog::PegBarAlignmentDialog(Editor *editor, QWidget *parent) : connect(mEditor->layers(), &LayerManager::layerCountChanged, this, &PegBarAlignmentDialog::updatePegRegLayers); connect(mEditor->select(), &SelectionManager::selectionChanged, this, &PegBarAlignmentDialog::updatePegRegDialog); connect(mEditor, &Editor::scrubbed, this, &PegBarAlignmentDialog::updatePegRegDialog); + connect(mEditor, &Editor::framesModified, this, &PegBarAlignmentDialog::updatePegRegDialog); connect(mEditor->layers(), &LayerManager::currentLayerChanged, this, &PegBarAlignmentDialog::updatePegRegDialog); ui->btnAlign->setEnabled(false); mLayernames.clear(); + + mEditor->tools()->setCurrentTool(SELECT); + + if (!mEditor->select()->somethingSelected()) { + QPoint centralPoint = mEditor->getScribbleArea()->getCentralPoint().toPoint(); + mEditor->select()->setSelection(QRect(centralPoint.x()-100,centralPoint.y()-50,200,100)); + } + updatePegRegLayers(); } PegBarAlignmentDialog::~PegBarAlignmentDialog() @@ -55,6 +69,11 @@ void PegBarAlignmentDialog::setLayerList(QStringList layerList) { ui->lwLayers->addItem(mLayernames.at(i)); } + + // Select the first layer. + if (ui->lwLayers->count() > 0) { + ui->lwLayers->item(0)->setSelected(true); + } } QStringList PegBarAlignmentDialog::getLayerList() @@ -63,46 +82,49 @@ QStringList PegBarAlignmentDialog::getLayerList() selectedLayers.clear(); for (int i = 0; i < ui->lwLayers->count(); i++) { - if (ui->lwLayers->item(i)->isSelected()) - selectedLayers.append(ui->lwLayers->item(i)->text()); + if (!ui->lwLayers->item(i)->isSelected()) { continue; } + + selectedLayers.append(ui->lwLayers->item(i)->text()); } return selectedLayers; } -void PegBarAlignmentDialog::updateRefKeyLabelText() +void PegBarAlignmentDialog::updateRefKeyLabel(QString text) { - ui->labRefKey->setText(QStringLiteral("%1 - %2").arg(mRefLayer).arg(mRefkey)); + ui->labRefKey->setText(text); } void PegBarAlignmentDialog::setAreaSelected(bool b) { mAreaSelected = b; - setBtnAlignEnabled(); + updateAlignButton(); } void PegBarAlignmentDialog::setReferenceSelected(bool b) { mReferenceSelected = b; - setBtnAlignEnabled(); + updateAlignButton(); } void PegBarAlignmentDialog::setLayerSelected(bool b) { mLayerSelected = b; - setBtnAlignEnabled(); + updateAlignButton(); } void PegBarAlignmentDialog::updatePegRegLayers() { QStringList bitmaplayers; - for (int i = 0; i < mEditor->layers()->count(); i++) + auto layerMan = mEditor->layers(); + for (int i = 0; i < layerMan->count(); i++) { - if (mEditor->layers()->getLayer(i)->type() == Layer::BITMAP) - { - bitmaplayers.append(mEditor->layers()->getLayer(i)->name()); - } + const Layer* layer = layerMan->getLayer(i); + if (layer->type() != Layer::BITMAP) { continue; } + + bitmaplayers.append(layer->name()); } setLayerList(bitmaplayers); + updatePegRegDialog(); } void PegBarAlignmentDialog::updatePegRegDialog() @@ -112,28 +134,24 @@ void PegBarAlignmentDialog::updatePegRegDialog() const Layer* currentLayer = mEditor->layers()->currentLayer(); // is the reference key valid? - setRefLayer(currentLayer->name()); - setRefKey(mEditor->currentFrame()); + KeyFrame* key = currentLayer->getLastKeyFrameAtPosition(mEditor->currentFrame()); + + if (key == nullptr) { + updateRefKeyLabel("-"); + setReferenceSelected(false); + return; + } bool isReferenceSelected = (currentLayer->type() == Layer::BITMAP && - currentLayer->keyExists(mEditor->currentFrame())); + key->pos()); setReferenceSelected(isReferenceSelected); // has minimum one layer been selected? const QStringList bitmaplayers = getLayerList(); - if (bitmaplayers.isEmpty()) - { - setLayerSelected(false); - } - else - { - setRefLayer(currentLayer->name()); - setRefKey(mEditor->currentFrame()); - setLayerSelected(true); - } - - setBtnAlignEnabled(); + setLayerSelected(!bitmaplayers.isEmpty()); + updateRefKeyLabel(QString::number(key->pos())); + updateAlignButton(); } void PegBarAlignmentDialog::alignPegs() @@ -147,7 +165,8 @@ void PegBarAlignmentDialog::alignPegs() return; } - Status result = mEditor->pegBarAlignment(bitmaplayers); + + Status result = PegBarAligner(mEditor, mEditor->select()->mySelectionRect().toAlignedRect()).align(bitmaplayers); if (!result.ok()) { QMessageBox::information(this, "Pencil2D", @@ -155,10 +174,12 @@ void PegBarAlignmentDialog::alignPegs() QMessageBox::Ok); return; } + + mEditor->deselectAll(); done(QDialog::Accepted); } -void PegBarAlignmentDialog::setBtnAlignEnabled() +void PegBarAlignmentDialog::updateAlignButton() { if (mAreaSelected && mReferenceSelected && mLayerSelected) ui->btnAlign->setEnabled(true); @@ -166,18 +187,6 @@ void PegBarAlignmentDialog::setBtnAlignEnabled() ui->btnAlign->setEnabled(false); } -void PegBarAlignmentDialog::setRefLayer(QString s) -{ - mRefLayer = s; - updateRefKeyLabelText(); -} - -void PegBarAlignmentDialog::setRefKey(int i) -{ - mRefkey = i; - updateRefKeyLabelText(); -} - void PegBarAlignmentDialog::closeClicked() { done(QDialog::Accepted); diff --git a/app/src/pegbaralignmentdialog.h b/app/src/pegbaralignmentdialog.h index 6749d3ae79..38ffc61206 100644 --- a/app/src/pegbaralignmentdialog.h +++ b/app/src/pegbaralignmentdialog.h @@ -33,26 +33,21 @@ class PegBarAlignmentDialog : public QDialog explicit PegBarAlignmentDialog(Editor* editor, QWidget* parent = nullptr); ~PegBarAlignmentDialog(); - void setLayerList(QStringList layerList); - QStringList getLayerList(); - int getRefKey() { return mRefkey; } - QString getRefLayer() { return mRefLayer; } - void updateRefKeyLabelText(); - - void setAreaSelected(bool b); - void setReferenceSelected(bool b); - void setLayerSelected(bool b); +public slots: + void updateAlignButton(); +private: void updatePegRegLayers(); void updatePegRegDialog(); void alignPegs(); + void setLayerList(QStringList layerList); + void updateRefKeyLabel(QString text); -public slots: - void setBtnAlignEnabled(); - void setRefLayer(QString s); - void setRefKey(int i); + QStringList getLayerList(); -private: + void setAreaSelected(bool b); + void setReferenceSelected(bool b); + void setLayerSelected(bool b); void closeClicked(); Ui::PegBarAlignmentDialog* ui; @@ -61,8 +56,6 @@ public slots: bool mAreaSelected = false; bool mReferenceSelected = false; bool mLayerSelected = false; - QString mRefLayer; - int mRefkey = 0; }; #endif // PEGBARALIGNMENTDIALOG_H diff --git a/app/src/toolbox.cpp b/app/src/toolbox.cpp index 3609518521..6a7b4c73a1 100644 --- a/app/src/toolbox.cpp +++ b/app/src/toolbox.cpp @@ -166,112 +166,101 @@ void ToolBoxWidget::updateUI() { } -void ToolBoxWidget::pencilOn() +void ToolBoxWidget::onToolSetActive(ToolType toolType) { - if (!leavingTool(ui->pencilButton)) { return; } - - editor()->tools()->setCurrentTool(PENCIL); - deselectAllTools(); - ui->pencilButton->setChecked(true); + switch (toolType) { + case ToolType::BRUSH: + ui->brushButton->setChecked(true); + break; + case ToolType::PEN: + ui->penButton->setChecked(true); + break; + case ToolType::PENCIL: + ui->pencilButton->setChecked(true); + break; + case ToolType::SELECT: + ui->selectButton->setChecked(true); + break; + case ToolType::HAND: + ui->handButton->setChecked(true); + break; + case ToolType::MOVE: + ui->moveButton->setChecked(true); + break; + case ToolType::ERASER: + ui->eraserButton->setChecked(true); + break; + case ToolType::POLYLINE: + ui->polylineButton->setChecked(true); + break; + case ToolType::SMUDGE: + ui->smudgeButton->setChecked(true); + break; + case ToolType::BUCKET: + ui->bucketButton->setChecked(true); + break; + case ToolType::EYEDROPPER: + ui->eyedropperButton->setChecked(true); + break; + default: + break; + } } -void ToolBoxWidget::eraserOn() +void ToolBoxWidget::pencilOn() { - if (!leavingTool(ui->eraserButton)) { return; } - - editor()->tools()->setCurrentTool(ERASER); + toolOn(PENCIL, ui->pencilButton); +} - deselectAllTools(); - ui->eraserButton->setChecked(true); +void ToolBoxWidget::eraserOn() +{ + toolOn(ERASER, ui->eraserButton); } void ToolBoxWidget::selectOn() { - if (!leavingTool(ui->selectButton)) { return; } - - editor()->tools()->setCurrentTool(SELECT); - - deselectAllTools(); - ui->selectButton->setChecked(true); + toolOn(SELECT, ui->selectButton); } void ToolBoxWidget::moveOn() { - if (!leavingTool(ui->moveButton)) { return; } - - editor()->tools()->setCurrentTool(MOVE); - - deselectAllTools(); - ui->moveButton->setChecked(true); + toolOn(MOVE, ui->moveButton); } void ToolBoxWidget::penOn() { - if (!leavingTool(ui->penButton)) { return; } - - editor()->tools()->setCurrentTool(PEN); - - deselectAllTools(); - ui->penButton->setChecked(true); + toolOn(PEN, ui->penButton); } void ToolBoxWidget::handOn() { - if (!leavingTool(ui->handButton)) { return; } - - editor()->tools()->setCurrentTool( HAND ); - - deselectAllTools(); - ui->handButton->setChecked(true); + toolOn(HAND, ui->handButton); } void ToolBoxWidget::polylineOn() { - if (!leavingTool(ui->polylineButton)) { return; } - - editor()->tools()->setCurrentTool(POLYLINE); - - deselectAllTools(); - ui->polylineButton->setChecked(true); + toolOn(POLYLINE, ui->polylineButton); } void ToolBoxWidget::bucketOn() { - if (!leavingTool(ui->bucketButton)) { return; } - - editor()->tools()->setCurrentTool(BUCKET); - - deselectAllTools(); - ui->bucketButton->setChecked(true); + toolOn(BUCKET, ui->bucketButton); } void ToolBoxWidget::eyedropperOn() { - if (!leavingTool(ui->eyedropperButton)) { return; } - editor()->tools()->setCurrentTool(EYEDROPPER); - - deselectAllTools(); - ui->eyedropperButton->setChecked(true); + toolOn(EYEDROPPER, ui->eyedropperButton); } void ToolBoxWidget::brushOn() { - if (!leavingTool(ui->brushButton)) { return; } - - editor()->tools()->setCurrentTool( BRUSH ); - - deselectAllTools(); - ui->brushButton->setChecked(true); + toolOn(BRUSH, ui->brushButton); } void ToolBoxWidget::smudgeOn() { - if (!leavingTool(ui->smudgeButton)) { return; } - editor()->tools()->setCurrentTool(SMUDGE); - - deselectAllTools(); - ui->smudgeButton->setChecked(true); + toolOn(SMUDGE, ui->smudgeButton); } int ToolBoxWidget::getMinHeightForWidth(int width) @@ -294,14 +283,13 @@ void ToolBoxWidget::deselectAllTools() ui->smudgeButton->setChecked(false); } -bool ToolBoxWidget::leavingTool(QToolButton* toolButton) +bool ToolBoxWidget::toolOn(ToolType toolType, QToolButton* toolButton) { if (!editor()->tools()->leavingThisTool()) { - if (toolButton->isChecked()) { - toolButton->setChecked(false); - } + toolButton->setChecked(false); return false; } + editor()->tools()->setCurrentTool(toolType); return true; } diff --git a/app/src/toolbox.h b/app/src/toolbox.h index ad29e74f55..7224d65d01 100644 --- a/app/src/toolbox.h +++ b/app/src/toolbox.h @@ -44,6 +44,7 @@ class ToolBoxWidget : public BaseDockWidget void updateUI() override; public slots: + void onToolSetActive(ToolType toolType); void pencilOn(); void eraserOn(); void selectOn(); @@ -64,7 +65,7 @@ public slots: private: void deselectAllTools(); - bool leavingTool(QToolButton*); + bool toolOn(ToolType toolType, QToolButton* toolButton); Ui::ToolBoxWidget* ui = nullptr; }; diff --git a/app/ui/pegbaralignmentdialog.ui b/app/ui/pegbaralignmentdialog.ui index 32495a52f5..5dd372b70c 100644 --- a/app/ui/pegbaralignmentdialog.ui +++ b/app/ui/pegbaralignmentdialog.ui @@ -18,21 +18,11 @@ :/icons/icon.png:/icons/icon.png - - - - - 75 - true - - - - Peg Bar Alignment: - - - + + 2 + @@ -50,21 +40,42 @@ - 1) Select a reference area around center pegs. + 1) A selection should exist - + + + + 0 + 0 + + + + 1 + - 2) Select one reference keyframe from timeline. + 2) The selection be large enough to contain the center pegs of all frames + + + true + + + 0 + + + -1 - 3) Select at least one layer to align. (Bitmaps only!) + 3) At least one layer should be selected (Bitmaps only!) + + + true @@ -76,6 +87,21 @@ Layer selection + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + @@ -151,7 +177,7 @@ - Align Peg Bars + Align true diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro index 055ebc86b4..10a190cc6a 100644 --- a/core_lib/core_lib.pro +++ b/core_lib/core_lib.pro @@ -67,6 +67,7 @@ HEADERS += \ src/structure/layercamera.h \ src/structure/layersound.h \ src/structure/layervector.h \ + src/structure/pegbaraligner.h \ src/structure/soundclip.h \ src/structure/object.h \ src/structure/objectdata.h \ @@ -143,6 +144,7 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/structure/layersound.cpp \ src/structure/layervector.cpp \ src/structure/object.cpp \ + src/structure/pegbaraligner.cpp \ src/structure/soundclip.cpp \ src/structure/objectdata.cpp \ src/structure/filemanager.cpp \ diff --git a/core_lib/src/graphics/bitmap/bitmapimage.cpp b/core_lib/src/graphics/bitmap/bitmapimage.cpp index 5daee5a23e..3c735771fb 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.cpp +++ b/core_lib/src/graphics/bitmap/bitmapimage.cpp @@ -675,54 +675,6 @@ void BitmapImage::drawPath(QPainterPath path, QPen pen, QBrush brush, modification(); } -PegbarResult BitmapImage::findLeft(QRectF rect, int grayValue) -{ - PegbarResult result; - result.value = -1; - result.errorcode = Status::FAIL; - int left = static_cast(rect.left()); - int right = static_cast(rect.right()); - int top = static_cast(rect.top()); - int bottom = static_cast(rect.bottom()); - for (int x = left; x <= right; x++) - { - for (int y = top; y <= bottom; y++) - { - if (qAlpha(constScanLine(x,y)) == 255 && qGray(constScanLine(x,y)) < grayValue) - { - result.value = x; - result.errorcode = Status::OK; - return result; - } - } - } - return result; -} - -PegbarResult BitmapImage::findTop(QRectF rect, int grayValue) -{ - PegbarResult result; - result.value = -1; - result.errorcode = Status::FAIL; - int left = static_cast(rect.left()); - int right = static_cast(rect.right()); - int top = static_cast(rect.top()); - int bottom = static_cast(rect.bottom()); - for (int y = top; y <= bottom; y++) - { - for (int x = left; x <= right; x++) - { - if (qAlpha(constScanLine(x,y)) == 255 && qGray(constScanLine(x,y)) < grayValue) - { - result.value = y; - result.errorcode = Status::OK; - return result; - } - } - } - return result; -} - Status BitmapImage::writeFile(const QString& filename) { if (mImage && !mImage->isNull()) diff --git a/core_lib/src/graphics/bitmap/bitmapimage.h b/core_lib/src/graphics/bitmap/bitmapimage.h index 8d3a71fe02..21c4fcec4c 100644 --- a/core_lib/src/graphics/bitmap/bitmapimage.h +++ b/core_lib/src/graphics/bitmap/bitmapimage.h @@ -94,10 +94,6 @@ class BitmapImage : public KeyFrame int height() { autoCrop(); return mBounds.height(); } QSize size() { autoCrop(); return mBounds.size(); } - // peg bar alignment - PegbarResult findLeft(QRectF rect, int grayValue); - PegbarResult findTop(QRectF rect, int grayValue); - QRect& bounds() { autoCrop(); return mBounds; } diff --git a/core_lib/src/interface/editor.cpp b/core_lib/src/interface/editor.cpp index 5bf1e2e391..f3dbcfb833 100644 --- a/core_lib/src/interface/editor.cpp +++ b/core_lib/src/interface/editor.cpp @@ -1065,52 +1065,6 @@ void Editor::swapLayers(int i, int j) mScribbleArea->onLayerChanged(); } -Status Editor::pegBarAlignment(const QStringList& layers) -{ - PegbarResult retLeft; - PegbarResult retRight; - - LayerBitmap* layerBitmap = static_cast(mLayerManager->currentLayer()); - BitmapImage* img = layerBitmap->getBitmapImageAtFrame(currentFrame()); - QRectF rect = select()->mySelectionRect(); - retLeft = img->findLeft(rect, 121); - retRight = img->findTop(rect, 121); - if (STATUS_FAILED(retLeft.errorcode) || STATUS_FAILED(retRight.errorcode)) - { - return Status(Status::FAIL, "", tr("Peg hole not found!\nCheck selection, and please try again.", "PegBar error message")); - } - const int peg_x = retLeft.value; - const int peg_y = retRight.value; - - // move other layers - for (int i = 0; i < layers.count(); i++) - { - layerBitmap = static_cast(mLayerManager->findLayerByName(layers.at(i))); - for (int k = layerBitmap->firstKeyFramePosition(); k <= layerBitmap->getMaxKeyFramePosition(); k++) - { - if (layerBitmap->keyExists(k)) - { - img = layerBitmap->getBitmapImageAtFrame(k); - retLeft = img->findLeft(rect, 121); - const QString errorDescription = tr("Peg bar not found at %1, %2").arg(layerBitmap->name()).arg(k); - if (STATUS_FAILED(retLeft.errorcode)) - { - return Status(retLeft.errorcode, "", errorDescription); - } - retRight = img->findTop(rect, 121); - if (STATUS_FAILED(retRight.errorcode)) - { - return Status(retRight.errorcode, "", errorDescription); - } - img->moveTopLeft(QPoint(img->left() + (peg_x - retLeft.value), img->top() + (peg_y - retRight.value))); - } - } - } - deselectAll(); - - return retLeft.errorcode; -} - void Editor::prepareSave() { for (auto mgr : mAllManagers) diff --git a/core_lib/src/interface/editor.h b/core_lib/src/interface/editor.h index 2ccc591465..a663b11055 100644 --- a/core_lib/src/interface/editor.h +++ b/core_lib/src/interface/editor.h @@ -163,7 +163,6 @@ class Editor : public QObject void switchVisibilityOfLayer(int layerNumber); void swapLayers(int i, int j); - Status pegBarAlignment(const QStringList& layers); void backup(const QString& undoText); void backup(int layerNumber, int frameNumber, const QString& undoText); diff --git a/core_lib/src/structure/pegbaraligner.cpp b/core_lib/src/structure/pegbaraligner.cpp new file mode 100644 index 0000000000..7bd1ade5a1 --- /dev/null +++ b/core_lib/src/structure/pegbaraligner.cpp @@ -0,0 +1,126 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#include "pegbaraligner.h" + +#include +#include +#include + +#include +#include +#include + +PegStatus::PegStatus(ErrorCode code, QPoint point) + : Status(code), point(point) +{ +} + +PegBarAligner::PegBarAligner(Editor* editor, QRect searchRect) : + mEditor(editor), mPegSearchRect(searchRect) +{ +} + + +Status PegBarAligner::align(const QStringList& layers) +{ + LayerBitmap* layerBitmap = static_cast(mEditor->layers()->currentLayer()); + BitmapImage* img = layerBitmap->getBitmapImageAtFrame(mEditor->currentFrame()); + PegStatus result = findPoint(*img); + + if (!result.ok()) + { + return Status(Status::FAIL, "", tr("Peg hole not found!\nCheck selection, and please try again.", "PegBar error message")); + } + + const int pegX = result.point.x(); + const int pegY = result.point.y(); + + for (int i = 0; i < layers.count(); i++) + { + layerBitmap = static_cast(mEditor->layers()->findLayerByName(layers.at(i))); + for (int k = layerBitmap->firstKeyFramePosition(); k <= layerBitmap->getMaxKeyFramePosition(); k++) + { + if (!layerBitmap->keyExists(k)) { continue; } + + img = layerBitmap->getBitmapImageAtFrame(k); + img->enableAutoCrop(false); + + result = findPoint(*img); + if (!result.ok()) + { + const QString errorDescription = tr("Peg bar not found at %1, %2").arg(layerBitmap->name()).arg(k); + return Status(result.code(), "", errorDescription); + } + img->moveTopLeft(QPoint(img->left() + (pegX - result.point.x()), img->top() + (pegY - result.point.y()))); + + mEditor->frameModified(img->pos()); + } + } + + mEditor->deselectAll(); + + return Status::OK; +} + + +PegStatus PegBarAligner::findPoint(const BitmapImage& image) const +{ + QPoint point; + const int left = mPegSearchRect.left(); + const int right = mPegSearchRect.right(); + const int top = mPegSearchRect.top(); + const int bottom = mPegSearchRect.bottom(); + const int grayValue = mGrayThreshold; + + bool foundX = false; + + for (int x = left; x <= right && !foundX; x++) + { + for (int y = top; y <= bottom; y++) + { + const QRgb& scan = image.constScanLine(x,y); + if (qAlpha(scan) == 255 && qGray(scan) < grayValue) + { + foundX = true; + point.setX(x); + + break; + } + } + } + + bool foundY = false; + for (int y = top; y <= bottom && !foundY; y++) + { + for (int x = left; x <= right; x++) + { + const QRgb& scan = image.constScanLine(x,y); + if (qAlpha(scan) == 255 && qGray(scan) < grayValue) + { + foundY = true; + point.setY(y); + + break; + } + } + } + + if (foundX && foundY) { + return PegStatus(Status::OK, point); + } + return Status::FAIL; +} diff --git a/core_lib/src/structure/pegbaraligner.h b/core_lib/src/structure/pegbaraligner.h new file mode 100644 index 0000000000..eb08e80488 --- /dev/null +++ b/core_lib/src/structure/pegbaraligner.h @@ -0,0 +1,52 @@ +/* + +Pencil2D - Traditional Animation Software +Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon +Copyright (C) 2012-2020 Matthew Chiawen Chang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +*/ +#ifndef PEGBARALIGNER_H +#define PEGBARALIGNER_H + +#include + +#include +#include + +class BitmapImage; +class Editor; + +class PegStatus : public Status +{ +public: + PegStatus(ErrorCode code, QPoint point = {}); + QPoint point; +}; + +class PegBarAligner +{ + Q_DECLARE_TR_FUNCTIONS(PegBarAligner) +public: + PegBarAligner(Editor* editor, QRect searchRect); + + Status align(const QStringList& layers); + +private: + PegStatus findPoint(const BitmapImage& image) const; + + Editor* mEditor = nullptr; + + const int mGrayThreshold = 121; + QRect mPegSearchRect; +}; + +#endif // PEGBARALIGNER_H diff --git a/core_lib/src/util/pencilerror.cpp b/core_lib/src/util/pencilerror.cpp index f7d1935ca1..5b0f18d4dd 100644 --- a/core_lib/src/util/pencilerror.cpp +++ b/core_lib/src/util/pencilerror.cpp @@ -25,10 +25,6 @@ DebugDetails::DebugDetails() { } -DebugDetails::~DebugDetails() -{ -} - void DebugDetails::collect(const DebugDetails& d) { for (const QString& s : d.mDetails) diff --git a/core_lib/src/util/pencilerror.h b/core_lib/src/util/pencilerror.h index 33452359a5..999c78baca 100644 --- a/core_lib/src/util/pencilerror.h +++ b/core_lib/src/util/pencilerror.h @@ -25,7 +25,6 @@ class DebugDetails { public: DebugDetails(); - ~DebugDetails(); void collect(const DebugDetails& d); QString str(); @@ -98,12 +97,6 @@ class Status DebugDetails mDetails; }; -struct PegbarResult -{ - int value = 0; - Status::ErrorCode errorcode = Status::OK; -}; - #ifndef STATUS_CHECK #define STATUS_CHECK( x )\ { Status st = (x); if (!st.ok()) { return st; } }