diff --git a/src/app/puzzle/puzzle.pri b/src/app/puzzle/puzzle.pri index 4cd78670e..418af8d9d 100644 --- a/src/app/puzzle/puzzle.pri +++ b/src/app/puzzle/puzzle.pri @@ -6,11 +6,17 @@ SOURCES += \ $$PWD/puzzlecommands.cpp \ $$PWD/puzzlemainwindow.cpp \ $$PWD/puzzleapplication.cpp \ + $$PWD/vpiececarrouselpiecepreview.cpp \ $$PWD/vpuzzlecommandline.cpp \ $$PWD/dialogs/dialogaboutpuzzle.cpp \ $$PWD/vpiececarrousel.cpp \ + $$PWD/vpuzzlegraphicslayout.cpp \ + $$PWD/vpuzzlegraphicspiece.cpp \ $$PWD/vpuzzlelayout.cpp \ $$PWD/vpuzzlelayer.cpp \ + $$PWD/vpuzzlemaingraphicsscene.cpp \ + $$PWD/vpuzzlemaingraphicsview.cpp \ + $$PWD/vpuzzlemimedatapiece.cpp \ $$PWD/vpuzzlepiece.cpp \ $$PWD/xml/layoutliterals.cpp \ $$PWD/xml/vpuzzlelayoutfilewriter.cpp \ @@ -25,11 +31,17 @@ HEADERS += \ $$PWD/puzzlemainwindow.h \ $$PWD/stable.h \ $$PWD/puzzleapplication.h \ + $$PWD/vpiececarrouselpiecepreview.h \ $$PWD/vpuzzlecommandline.h \ $$PWD/dialogs/dialogaboutpuzzle.h \ $$PWD/vpiececarrousel.h \ + $$PWD/vpuzzlegraphicslayout.h \ + $$PWD/vpuzzlegraphicspiece.h \ $$PWD/vpuzzlelayout.h \ $$PWD/vpuzzlelayer.h \ + $$PWD/vpuzzlemaingraphicsscene.h \ + $$PWD/vpuzzlemaingraphicsview.h \ + $$PWD/vpuzzlemimedatapiece.h \ $$PWD/vpuzzlepiece.h \ $$PWD/xml/layoutliterals.h \ $$PWD/xml/vpuzzlelayoutfilewriter.h \ diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp index 8f8252a76..b76bcb9b0 100644 --- a/src/app/puzzle/puzzlemainwindow.cpp +++ b/src/app/puzzle/puzzlemainwindow.cpp @@ -59,9 +59,9 @@ PuzzleMainWindow::PuzzleMainWindow(const VPuzzleCommandLinePtr &cmd, QWidget *pa m_layout = new VPuzzleLayout(); // ----- for test purposes, to be removed------------------ - m_layout->SetLayoutMarginsConverted(1.5, 2.00, 4.21, 0.25); - m_layout->SetLayoutSizeConverted(30.0, 29.7); - m_layout->SetPiecesGapConverted(1.27); + m_layout->SetLayoutMarginsConverted(2, 2, 2, 2); + m_layout->SetLayoutSizeConverted(30.0, 45); + m_layout->SetPiecesGapConverted(1); m_layout->SetUnit(Unit::Cm); m_layout->SetWarningSuperpositionOfPieces(true); // -------------------------------------------------------- @@ -71,6 +71,8 @@ PuzzleMainWindow::PuzzleMainWindow(const VPuzzleCommandLinePtr &cmd, QWidget *pa InitMenuBar(); InitProperties(); InitPieceCarrousel(); + InitMainGraphics(); + SetPropertiesData(); } @@ -142,8 +144,22 @@ void PuzzleMainWindow::ImportRawLayouts(const QStringList &rawLayouts) { VLayoutPiece rawPiece = data.pieces.at(i); - // TODO for feature "Update piece" : CreateOrUpdate() function indstead of CreatePiece() + // We translate the piece, so that the origin of the bounding rect of the piece is at (0,0) + // It makes positioning later on easier. + QRectF boundingRect = rawPiece.DetailBoundingRect(); + QPointF topLeft = boundingRect.topLeft(); + rawPiece.Translate(-topLeft.x(), -topLeft.y()); + + + // TODO / FIXME: make a few tests, on the data to check for validity. If not + // + // If seam allowance enabled, but the path is empty — invalid. + // If seam line path not hidden, but the path is empty — invalid. + // If seam allowance is built-in, but the seam line path is empty — invalid. + + + // TODO for feature "Update piece" : CreateOrUpdate() function indstead of CreatePiece() VPuzzlePiece *piece = CreatePiece(rawPiece); m_layout->GetUnplacedPiecesLayer()->AddPiece(piece); } @@ -168,10 +184,25 @@ VPuzzlePiece* PuzzleMainWindow::CreatePiece(const VLayoutPiece &rawPiece) VPuzzlePiece *piece = new VPuzzlePiece(); piece->SetName(rawPiece.GetName()); piece->SetUuid(rawPiece.GetUUID()); + piece->SetCuttingLine(rawPiece.GetMappedSeamAllowancePoints()); + piece->SetSeamLine(rawPiece.GetMappedContourPoints()); + + piece->SetIsGrainlineEnabled(rawPiece.IsGrainlineEnabled()); + if(rawPiece.IsGrainlineEnabled()) + { + piece->SetGrainlineAngle(rawPiece.GrainlineAngle()); + piece->SetGrainline(rawPiece.GetGrainline()); + } // TODO : set all the information we need for the piece! + // + connect(piece, &VPuzzlePiece::SelectionChanged, this, &PuzzleMainWindow::on_PieceSelectionChanged); + connect(piece, &VPuzzlePiece::PositionChanged, this, &PuzzleMainWindow::on_PiecePositionChanged); + connect(piece, &VPuzzlePiece::RotationChanged, this, &PuzzleMainWindow::on_PieceRotationChanged); + + return piece; } @@ -211,9 +242,9 @@ void PuzzleMainWindow::InitPropertyTabCurrentPiece() // ------------------------------ placement ----------------------------------- connect(ui->doubleSpinBoxCurrentPieceBoxPositionX, QOverload::of(&QDoubleSpinBox::valueChanged), this, - &PuzzleMainWindow::on_CurrentPiecePositionChanged); + &PuzzleMainWindow::on_CurrentPiecePositionEdited); connect(ui->doubleSpinBoxCurrentPieceBoxPositionY, QOverload::of(&QDoubleSpinBox::valueChanged), this, - &PuzzleMainWindow::on_CurrentPiecePositionChanged); + &PuzzleMainWindow::on_CurrentPiecePositionEdited); } @@ -293,9 +324,6 @@ void PuzzleMainWindow::InitPieceCarrousel() connect(ui->dockWidgetPieceCarrousel, QOverload::of(&QDockWidget::dockLocationChanged), this, &PuzzleMainWindow::on_PieceCarrouselLocationChanged); - - connect(m_pieceCarrousel, QOverload::of(&VPieceCarrousel::pieceClicked), this, - &PuzzleMainWindow::on_PieceSelected); } @@ -318,31 +346,45 @@ void PuzzleMainWindow::SetPropertiesData() //--------------------------------------------------------------------------------------------------------------------- void PuzzleMainWindow::SetPropertyTabCurrentPieceData() { - if(m_selectedPiece == nullptr) + if(m_selectedPieces.count() == 0) { - if(false) // check for multiple piece selection - { - // TODO in the future - } - else - { - // TODO : update current piece data to show a "no current piece selected" - ui->containerCurrentPieceNoData->setVisible(true); - ui->containerCurrentPieceData->setVisible(false); - } + // show the content "no piece selected" + + ui->containerCurrentPieceNoData->setVisible(true); + ui->containerCurrentPieceData->setVisible(false); + ui->containerCurrentPieceMultipleData->setVisible(false); + } + else if(m_selectedPieces.count() == 1) + { + // show the content "selected piece data" + ui->containerCurrentPieceNoData->setVisible(false); + ui->containerCurrentPieceData->setVisible(true); + ui->containerCurrentPieceMultipleData->setVisible(false); + + VPuzzlePiece *selectedPiece = m_selectedPieces.first(); + + // set the value to the current piece + ui->lineEditCurrentPieceName->setText(selectedPiece->GetName()); + + ui->checkBoxCurrentPieceShowSeamline->setChecked(selectedPiece->GetShowSeamLine()); + ui->checkBoxCurrentPieceMirrorPiece->setChecked(selectedPiece->GetPieceMirrored()); + + QPointF pos = selectedPiece->GetPosition(); + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionX, UnitConvertor(pos.x(), Unit::Px, m_layout->GetUnit())); + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionY, UnitConvertor(pos.y(), Unit::Px, m_layout->GetUnit())); + + qreal angle = selectedPiece->GetRotation(); + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); } else { + // show the content "multiple pieces selected" + ui->containerCurrentPieceNoData->setVisible(false); - ui->containerCurrentPieceData->setVisible(true); + ui->containerCurrentPieceData->setVisible(false); + ui->containerCurrentPieceMultipleData->setVisible(true); - // set the value to the current piece - ui->lineEditCurrentPieceName->setText(m_selectedPiece->GetName()); - - ui->checkBoxCurrentPieceShowSeamline->setChecked(m_selectedPiece->GetShowSeamLine()); - ui->checkBoxCurrentPieceMirrorPiece->setChecked(m_selectedPiece->GetPieceMirrored()); - - // TODO:rotation and placement; + // if needed in the future, we can show some properties that coul be edited for all the pieces } } @@ -401,6 +443,15 @@ void PuzzleMainWindow::SetPropertyTabLayersData() } +//--------------------------------------------------------------------------------------------------------------------- +void PuzzleMainWindow::InitMainGraphics() +{ + m_graphicsView = new VPuzzleMainGraphicsView(m_layout, this); + ui->centralWidget->layout()->addWidget(m_graphicsView); + + m_graphicsView->RefreshLayout(); +} + //--------------------------------------------------------------------------------------------------------------------- void PuzzleMainWindow::SetDoubleSpinBoxValue(QDoubleSpinBox *spinBox, qreal value) @@ -644,7 +695,8 @@ void PuzzleMainWindow::on_LayoutSizeChanged() } // TODO Undo / Redo - // TODO update the QGraphicView + + m_graphicsView->RefreshLayout(); } //--------------------------------------------------------------------------------------------------------------------- @@ -657,8 +709,11 @@ void PuzzleMainWindow::on_LayoutOrientationChanged() SetDoubleSpinBoxValue(ui->doubleSpinBoxLayoutWidth, length_before); SetDoubleSpinBoxValue(ui->doubleSpinBoxLayoutLength, width_before); + m_layout->SetLayoutSizeConverted(ui->doubleSpinBoxLayoutWidth->value(), ui->doubleSpinBoxLayoutLength->value()); + // TODO Undo / Redo - // TODO update the QGraphicView + + m_graphicsView->RefreshLayout(); } //--------------------------------------------------------------------------------------------------------------------- @@ -686,7 +741,8 @@ void PuzzleMainWindow::on_LayoutMarginChanged() ); // TODO Undo / Redo - // TODO update the QGraphicView + + m_graphicsView->RefreshLayout(); } @@ -759,47 +815,42 @@ void PuzzleMainWindow::on_pushButtonLayoutExport_clicked() //--------------------------------------------------------------------------------------------------------------------- void PuzzleMainWindow::on_checkBoxCurrentPieceShowSeamline_toggled(bool checked) { - if(m_selectedPiece != nullptr) + if(m_selectedPieces.count() == 1) { - m_selectedPiece->SetShowSeamLine(checked); + m_selectedPieces.first()->SetShowSeamLine(checked); } } //--------------------------------------------------------------------------------------------------------------------- void PuzzleMainWindow::on_checkBoxCurrentPieceMirrorPiece_toggled(bool checked) { - if(m_selectedPiece != nullptr) + if(m_selectedPieces.count() == 1) { - m_selectedPiece->SetPieceMirrored(checked); + m_selectedPieces.first()->SetPieceMirrored(checked); } } //--------------------------------------------------------------------------------------------------------------------- void PuzzleMainWindow::on_doubleSpinBoxCurrentPieceAngle_valueChanged(double value) { - // just for test purpuses, to be removed: - QMessageBox msgBox; - msgBox.setText("TODO PuzzleMainWindow::CurrentPieceAngleChanged"); - int ret = msgBox.exec(); - - Q_UNUSED(value); - Q_UNUSED(ret); - - // TODO + if(m_selectedPieces.count() == 1) + { + VPuzzlePiece *piece = m_selectedPieces.first(); + piece->SetRotation(value); + } } //--------------------------------------------------------------------------------------------------------------------- -void PuzzleMainWindow::on_CurrentPiecePositionChanged() +void PuzzleMainWindow::on_CurrentPiecePositionEdited() { - // just for test purpuses, to be removed: - QMessageBox msgBox; - msgBox.setText("TODO PuzzleMainWindow::CurrentPiecePositionChanged"); - int ret = msgBox.exec(); - - Q_UNUSED(ret); - - // TODO + if(m_selectedPieces.count() == 1) + { + VPuzzlePiece *piece = m_selectedPieces.first(); + QPointF pos(UnitConvertor(ui->doubleSpinBoxCurrentPieceBoxPositionX->value(), m_layout->GetUnit(), Unit::Px), + UnitConvertor(ui->doubleSpinBoxCurrentPieceBoxPositionY->value(), m_layout->GetUnit(), Unit::Px)); + piece->SetPosition(pos); + } } //--------------------------------------------------------------------------------------------------------------------- @@ -820,17 +871,37 @@ void PuzzleMainWindow::on_PieceCarrouselLocationChanged(Qt::DockWidgetArea area) } //--------------------------------------------------------------------------------------------------------------------- -void PuzzleMainWindow::on_PieceSelected(VPuzzlePiece* piece) +void PuzzleMainWindow::on_PieceSelectionChanged() { - m_selectedPiece = piece; - - // update the state of the piece carrousel - m_pieceCarrousel->SelectPiece(piece); - - // update the Layout - - // TODO + m_selectedPieces = m_layout->GetSelectedPieces(); // update the property of the piece currently selected SetPropertyTabCurrentPieceData(); } + + +//--------------------------------------------------------------------------------------------------------------------- +void PuzzleMainWindow::on_PiecePositionChanged() +{ + + if(m_selectedPieces.count() == 1) + { + VPuzzlePiece *piece = m_selectedPieces.first(); + QPointF pos = piece->GetPosition(); + + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionX, UnitConvertor(pos.x(), Unit::Px, m_layout->GetUnit())); + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionY, UnitConvertor(pos.y(), Unit::Px, m_layout->GetUnit())); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void PuzzleMainWindow::on_PieceRotationChanged() +{ + if(m_selectedPieces.count() == 1) + { + VPuzzlePiece *piece = m_selectedPieces.first(); + qreal angle = piece->GetRotation(); + + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); + } +} diff --git a/src/app/puzzle/puzzlemainwindow.h b/src/app/puzzle/puzzlemainwindow.h index eb8dde989..4ffa3f29c 100644 --- a/src/app/puzzle/puzzlemainwindow.h +++ b/src/app/puzzle/puzzlemainwindow.h @@ -34,6 +34,7 @@ #include "../vmisc/def.h" #include "vpiececarrousel.h" +#include "vpuzzlemaingraphicsview.h" #include "vpuzzlelayout.h" #include "vpuzzlepiece.h" #include "../vlayout/vlayoutpiece.h" @@ -86,12 +87,14 @@ protected: private: Q_DISABLE_COPY(PuzzleMainWindow) Ui::PuzzleMainWindow *ui; + VPieceCarrousel *m_pieceCarrousel{nullptr}; + VPuzzleMainGraphicsView *m_graphicsView{nullptr}; + VPuzzleCommandLinePtr m_cmd; VPuzzleLayout *m_layout{nullptr}; - - VPuzzlePiece *m_selectedPiece{nullptr}; + QListm_selectedPieces{QList()}; /** * @brief CreatePiece creates a piece from the given VLayoutPiece data @@ -134,6 +137,10 @@ private: */ void InitPieceCarrousel(); + /** + * @brief InitMainGraphics Initialises the puzzle main graphics + */ + void InitMainGraphics(); /** * @brief SetPropertiesData Sets the values of UI elements @@ -347,7 +354,7 @@ private slots: * @brief on_CurrentPiecePositionChanged When the positionX or the positionY * is changed in the current piece tab */ - void on_CurrentPiecePositionChanged(); + void on_CurrentPiecePositionEdited(); /** * @brief PieceCarrouselLocationChanged When the piece carrousel's location @@ -357,10 +364,19 @@ private slots: void on_PieceCarrouselLocationChanged(Qt::DockWidgetArea area); /** - * @brief on_PieceSelected When a piece has been selected - * @param piece the piece that was selected + * @brief on_PieceSelectionChanged When the piece selection has changed */ - void on_PieceSelected(VPuzzlePiece* piece); + void on_PieceSelectionChanged(); + + /** + * @brief on_PiecePositionChanged When the current piece position has changed + */ + void on_PiecePositionChanged(); + + /** + * @brief on_PieceRotationChanged When the current piece rotation has changed + */ + void on_PieceRotationChanged(); }; diff --git a/src/app/puzzle/puzzlemainwindow.ui b/src/app/puzzle/puzzlemainwindow.ui index 5f63f8644..79ed17157 100644 --- a/src/app/puzzle/puzzlemainwindow.ui +++ b/src/app/puzzle/puzzlemainwindow.ui @@ -24,9 +24,6 @@ QLayout::SetDefaultConstraint - - - @@ -233,7 +230,7 @@ 0 0 342 - 894 + 1318 @@ -253,31 +250,6 @@ - - - - - 0 - - - - - - 0 - 400 - - - - No piece selected - - - Qt::AlignCenter - - - - - - @@ -361,7 +333,7 @@ 360.000000000000000 - 0.100000000000000 + 1.000000000000000 @@ -383,6 +355,9 @@ + + -10000.000000000000000 + 10000.000000000000000 @@ -400,6 +375,9 @@ + + -10000.000000000000000 + 10000.000000000000000 @@ -414,6 +392,53 @@ + + + + + 0 + + + + + + 0 + 400 + + + + No piece selected + + + Qt::AlignCenter + + + + + + + + + + + + + + 0 + 400 + + + + Multiple pieces selected + + + Qt::AlignCenter + + + + + + @@ -1096,7 +1121,6 @@ - graphicsView scrollAreaLayout doubleSpinBoxLayoutMarginTop doubleSpinBoxLayoutMarginLeft diff --git a/src/app/puzzle/share/resources/puzzleicon.qrc b/src/app/puzzle/share/resources/puzzleicon.qrc index fb33ba546..809e972be 100644 --- a/src/app/puzzle/share/resources/puzzleicon.qrc +++ b/src/app/puzzle/share/resources/puzzleicon.qrc @@ -9,5 +9,6 @@ puzzleicon/64x64/iconPortrait.png puzzleicon/64x64/iconGrainlineVertical.png puzzleicon/64x64/iconGrainlineHorizontal.png + puzzleicon/64x64/cursorRotate.png diff --git a/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate.png b/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate.png new file mode 100644 index 000000000..a9ade2aee Binary files /dev/null and b/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate.png differ diff --git a/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate@2x.png b/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate@2x.png new file mode 100644 index 000000000..0bde89ddb Binary files /dev/null and b/src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate@2x.png differ diff --git a/src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg b/src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg new file mode 100644 index 000000000..f5b2423cb --- /dev/null +++ b/src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg @@ -0,0 +1,67 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/app/puzzle/vpiececarrousel.cpp b/src/app/puzzle/vpiececarrousel.cpp index 06741ffb7..65e46a410 100644 --- a/src/app/puzzle/vpiececarrousel.cpp +++ b/src/app/puzzle/vpiececarrousel.cpp @@ -28,11 +28,11 @@ #include "vpiececarrousel.h" #include #include +#include #include "../vmisc/backport/qoverload.h" #include -#include Q_LOGGING_CATEGORY(pCarrousel, "p.carrousel") @@ -75,8 +75,10 @@ void VPieceCarrousel::Init() QVBoxLayout *layersContainerLayout = new QVBoxLayout(); layersContainerLayout->setMargin(0); m_layersContainer->setLayout(layersContainerLayout); + m_layersContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QSpacerItem *spacer = new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding); + layersContainerWrapperLayout->addWidget(m_layersContainer); layersContainerWrapperLayout->addSpacerItem(spacer); @@ -91,11 +93,8 @@ void VPieceCarrousel::Init() mainLayout->addWidget(m_scrollArea); // ------ then we fill the carrousel with the layout content - Refresh(); - - // ------ and make sure the calculation for the qlayout is right - SetOrientation(Qt::Vertical); -} + Refresh(); + } //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrousel::Refresh() @@ -119,13 +118,11 @@ void VPieceCarrousel::Refresh() VPieceCarrouselLayer *carrouselLayer = new VPieceCarrouselLayer(layer, this); m_carrouselLayers.append(carrouselLayer); m_layersContainer->layout()->addWidget(carrouselLayer); - - connect(carrouselLayer, QOverload::of(&VPieceCarrouselLayer::pieceClicked), this, - &VPieceCarrousel::on_PieceClicked); - } on_ActiveLayerChanged(0); + + RefreshOrientation(); } //--------------------------------------------------------------------------------------------------------------------- @@ -159,20 +156,6 @@ void VPieceCarrousel::Clear() } } -//--------------------------------------------------------------------------------------------------------------------- -void VPieceCarrousel::SelectPiece(VPuzzlePiece* piece) -{ - for (auto layer : m_carrouselLayers) - { - QList carrouselPieces = layer->GetCarrouselPieces(); - for (auto carrouselPiece : carrouselPieces) - { - carrouselPiece->SetIsSelected(carrouselPiece->GetPiece() == piece); - } - } -} - - //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrousel::on_ActiveLayerChanged(int index) { @@ -188,8 +171,14 @@ void VPieceCarrousel::on_ActiveLayerChanged(int index) //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrousel::SetOrientation(Qt::Orientation orientation) { + m_orientation = orientation; + RefreshOrientation(); +} - QBoxLayout::Direction direction = (orientation == Qt::Horizontal)? +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrousel::RefreshOrientation() +{ + QBoxLayout::Direction direction = (m_orientation == Qt::Horizontal)? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom; @@ -207,7 +196,7 @@ void VPieceCarrousel::SetOrientation(Qt::Orientation orientation) } // then update the scrollarea min height / width and scrollbar behaviour - if(orientation == Qt::Horizontal) + if(m_orientation == Qt::Horizontal) { m_comboBoxLayer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -223,7 +212,6 @@ void VPieceCarrousel::SetOrientation(Qt::Orientation orientation) { m_comboBoxLayer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - // scroll bar policy of scroll area m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -232,13 +220,10 @@ void VPieceCarrousel::SetOrientation(Qt::Orientation orientation) m_scrollArea->setMinimumWidth(124 + m_scrollArea->verticalScrollBar()->sizeHint().width()+2); // FIXME: find a nicer way than putting directly the 120 width of the piece } - } //--------------------------------------------------------------------------------------------------------------------- -void VPieceCarrousel::on_PieceClicked(VPieceCarrouselPiece* carrouselPiece) +void VPieceCarrousel::ClearSelection() { - emit pieceClicked(carrouselPiece->GetPiece()); + m_layout->ClearSelection(); } - - diff --git a/src/app/puzzle/vpiececarrousel.h b/src/app/puzzle/vpiececarrousel.h index 9e90c56d7..a781b8ac2 100644 --- a/src/app/puzzle/vpiececarrousel.h +++ b/src/app/puzzle/vpiececarrousel.h @@ -43,8 +43,19 @@ public: explicit VPieceCarrousel(VPuzzleLayout *layout, QWidget *parent = nullptr); virtual ~VPieceCarrousel(); + /** + * @brief SetOrientation Sets the orientation to the given value and refreshes + * the orientation of the carrousel. + * @param orientation the orientation to set the carrousel to. + */ void SetOrientation(Qt::Orientation orientation); + /** + * @brief RefreshOrientation Refreshes the orientation of the carrousel with the + * m_orientation value; + */ + void RefreshOrientation(); + /** * @brief Inits the carroussel */ @@ -61,18 +72,9 @@ public: void Clear(); /** - * @brief SelectPiece Updates the carrousel so that the given piece is selected - * @param piece the piece to select + * @brief ClearSelection Clears the selection of the carrousel. */ - void SelectPiece(VPuzzlePiece* piece); - - -signals: - void pieceClicked(VPuzzlePiece* piece); - -public slots: - void on_PieceClicked(VPieceCarrouselPiece* carrouselPiece); - + void ClearSelection(); private: Q_DISABLE_COPY(VPieceCarrousel) @@ -85,8 +87,15 @@ private: QList m_carrouselLayers; + Qt::Orientation m_orientation{Qt::Vertical}; + private slots: + + /** + * @brief on_ActiveLayerChanged Called when the active layer is changed + * @param index + */ void on_ActiveLayerChanged(int index); }; diff --git a/src/app/puzzle/vpiececarrousellayer.cpp b/src/app/puzzle/vpiececarrousellayer.cpp index 4028ead33..b784a6c52 100644 --- a/src/app/puzzle/vpiececarrousellayer.cpp +++ b/src/app/puzzle/vpiececarrousellayer.cpp @@ -27,6 +27,7 @@ *************************************************************************/ #include "vpiececarrousellayer.h" +#include "vpiececarrousel.h" #include "../vmisc/backport/qoverload.h" #include @@ -36,9 +37,9 @@ Q_LOGGING_CATEGORY(pCarrouselLayer, "p.carrouselLayer") //--------------------------------------------------------------------------------------------------------------------- -VPieceCarrouselLayer::VPieceCarrouselLayer(VPuzzleLayer *layer, QWidget *parent) : - QWidget(parent), +VPieceCarrouselLayer::VPieceCarrouselLayer(VPuzzleLayer *layer, VPieceCarrousel *carrousel) : m_layer(layer), + m_carrousel(carrousel), m_carrouselPieces(QList()) { Init(); @@ -47,7 +48,7 @@ VPieceCarrouselLayer::VPieceCarrouselLayer(VPuzzleLayer *layer, QWidget *parent) //--------------------------------------------------------------------------------------------------------------------- VPieceCarrouselLayer::~VPieceCarrouselLayer() { - // TODO + Clear(); } //--------------------------------------------------------------------------------------------------------------------- @@ -60,13 +61,16 @@ void VPieceCarrouselLayer::Init() // then refresh the content Refresh(); + + // add the connections + connect(m_layer, &VPuzzleLayer::PieceAdded, this, &VPieceCarrouselLayer::on_PieceAdded); + connect(m_layer, &VPuzzleLayer::PieceRemoved, this, &VPieceCarrouselLayer::on_PieceRemoved); } //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrouselLayer::Refresh() { - // remove the existing carrousel pieces - // TODO + Clear(); // Updates the carrousel pieces from the pieces list QList pieces = m_layer->GetPieces(); @@ -77,24 +81,33 @@ void VPieceCarrouselLayer::Refresh() // create the corresponding carrousel pieces + bool _isVisible = isVisible(); + setVisible(true); for (auto piece : pieces) { -// qCDebug(pCarrouselLayer, "piece name : %s", piece->GetName().toStdString().c_str()); - - VPieceCarrouselPiece *carrouselPiece = new VPieceCarrouselPiece(piece); + VPieceCarrouselPiece *carrouselPiece = new VPieceCarrouselPiece(piece, this); m_carrouselPieces.append(carrouselPiece); layout()->addWidget(carrouselPiece); - - // FIXME? the fitInView inside the refresh of the piece doesn't workd properly. - // only by doing the following I did get it to work: - setVisible(true); - carrouselPiece->CleanPreview(); - setVisible(false); - - connect(carrouselPiece, QOverload::of(&VPieceCarrouselPiece::clicked), this, - &VPieceCarrouselLayer::on_PieceClicked); - + carrouselPiece->CleanPreview(); // fitInView only works if the widget is displayed. } + setVisible(_isVisible); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselLayer::Clear() +{ + // Removes and deletes the carrousel pieces from the layer + while (!m_carrouselPieces.isEmpty()) + { + VPieceCarrouselPiece *carrouselPiece = m_carrouselPieces.takeLast(); + + if(carrouselPiece != nullptr) + { + layout()->removeWidget(carrouselPiece); + delete carrouselPiece; + } + } + } //--------------------------------------------------------------------------------------------------------------------- @@ -104,7 +117,39 @@ QList VPieceCarrouselLayer::GetCarrouselPieces() } //--------------------------------------------------------------------------------------------------------------------- -void VPieceCarrouselLayer::on_PieceClicked(VPieceCarrouselPiece* carrouselPiece) +VPieceCarrousel* VPieceCarrouselLayer::GetCarrousel() { - emit pieceClicked(carrouselPiece); + return m_carrousel; +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleLayer* VPieceCarrouselLayer::GetLayer() +{ + return m_layer; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselLayer::on_PieceAdded(VPuzzlePiece* piece) +{ + Q_UNUSED(piece) + + // TODO/ FIXME: see if we find a solution more efficient refreshing the complete layout everytime. + + Refresh(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselLayer::on_PieceRemoved(VPuzzlePiece* piece) +{ + for (auto carrouselPiece : m_carrouselPieces) + { + if(carrouselPiece->GetPiece() == piece) + { + m_carrouselPieces.removeAll(carrouselPiece); + layout()->removeWidget(carrouselPiece); + delete carrouselPiece; + + return; + } + } } diff --git a/src/app/puzzle/vpiececarrousellayer.h b/src/app/puzzle/vpiececarrousellayer.h index aa3bae3a2..4c65455ae 100644 --- a/src/app/puzzle/vpiececarrousellayer.h +++ b/src/app/puzzle/vpiececarrousellayer.h @@ -33,32 +33,52 @@ #include "vpuzzlelayer.h" #include "vpiececarrouselpiece.h" +class VPieceCarrousel; + class VPieceCarrouselLayer : public QWidget { Q_OBJECT public: - explicit VPieceCarrouselLayer(VPuzzleLayer *layer, QWidget *parent = nullptr); + VPieceCarrouselLayer(VPuzzleLayer *layer, VPieceCarrousel *carrousel); ~VPieceCarrouselLayer(); void Init(); void Refresh(); + /** + * @brief Clear it clears the carrousel layer from its pieces + */ + void Clear(); + QList GetCarrouselPieces(); -signals: - void pieceClicked(VPieceCarrouselPiece* carrouselPiece); + VPieceCarrousel* GetCarrousel(); -public slots: - void on_PieceClicked(VPieceCarrouselPiece* carrouselPiece); + /** + * @brief GetPuzzleLayer Returns the corresponding VPuzzleLayer + * @return the VPuzzleLayer + */ + VPuzzleLayer* GetLayer(); private: Q_DISABLE_COPY(VPieceCarrouselLayer) VPuzzleLayer *m_layer; + VPieceCarrousel *m_carrousel; QList m_carrouselPieces; private slots: + /** + * @brief on_PieceUpdated This slot is called when a piece was added + */ + void on_PieceAdded(VPuzzlePiece* piece); + + /** + * @brief on_PieceUpdated This slot is called when a piece was removed + */ + void on_PieceRemoved(VPuzzlePiece* piece); + }; #endif // VPIECECARROUSELLAYER_H diff --git a/src/app/puzzle/vpiececarrouselpiece.cpp b/src/app/puzzle/vpiececarrouselpiece.cpp index 3ce4771a1..3602ce054 100644 --- a/src/app/puzzle/vpiececarrouselpiece.cpp +++ b/src/app/puzzle/vpiececarrouselpiece.cpp @@ -27,19 +27,30 @@ *************************************************************************/ #include "vpiececarrouselpiece.h" + #include #include #include #include +#include +#include +#include +#include + +#include "vpuzzlemimedatapiece.h" +#include "vpiececarrousellayer.h" +#include "vpiececarrousel.h" #include Q_LOGGING_CATEGORY(pCarrouselPiece, "p.carrouselPiece") + //--------------------------------------------------------------------------------------------------------------------- -VPieceCarrouselPiece::VPieceCarrouselPiece(VPuzzlePiece *piece, QWidget *parent) : - QFrame(parent), - m_piece(piece) +VPieceCarrouselPiece::VPieceCarrouselPiece(VPuzzlePiece *piece, VPieceCarrouselLayer *carrouselLayer) : + m_piece(piece), + m_carrouselLayer(carrouselLayer), + m_dragStart(QPoint()) { Init(); } @@ -48,7 +59,7 @@ VPieceCarrouselPiece::VPieceCarrouselPiece(VPuzzlePiece *piece, QWidget *parent) //--------------------------------------------------------------------------------------------------------------------- VPieceCarrouselPiece::~VPieceCarrouselPiece() { - delete m_graphicsView; + delete m_piecePreview; } //--------------------------------------------------------------------------------------------------------------------- @@ -64,14 +75,15 @@ void VPieceCarrouselPiece::Init() setStyleSheet("background-color:white; border: 2px solid transparent;"); // define the preview of the piece - m_graphicsView = new QGraphicsView(this); + m_piecePreview = new VPieceCarrouselPiecePreview(this); // m_graphicsView = new VMainGraphicsView(this); // --> undefined reference to 'VMainGraphicsView::VMainGraphicView(QWidget*)' QGraphicsScene *graphicsScene = new QGraphicsScene(this); - m_graphicsView->setScene(graphicsScene); - m_graphicsView->setFixedSize(120,100); - m_graphicsView->setStyleSheet("border: 4px solid transparent;"); + m_piecePreview->setScene(graphicsScene); + m_piecePreview->setFixedSize(120,100); + m_piecePreview->setStyleSheet("border: 4px solid transparent;"); + m_piecePreview->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // define the label m_label = new QLabel(); @@ -79,10 +91,15 @@ void VPieceCarrouselPiece::Init() m_label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter); m_label->setFixedSize(120,24); m_label->setStyleSheet("border: 0px;"); + m_label->setMouseTracking(false); - pieceLayout->addWidget(m_graphicsView); + pieceLayout->addWidget(m_piecePreview); pieceLayout->addWidget(m_label); + + // connect the signals + connect(m_piece, &VPuzzlePiece::SelectionChanged, this, &VPieceCarrouselPiece::on_PieceSelectionChanged); + // then refresh the data Refresh(); } @@ -90,7 +107,7 @@ void VPieceCarrouselPiece::Init() //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrouselPiece::CleanPreview() { - m_graphicsView->fitInView(m_graphicsView->scene()->sceneRect(), Qt::KeepAspectRatio); + m_piecePreview->fitInView(m_piecePreview->scene()->sceneRect(), Qt::KeepAspectRatio); } //--------------------------------------------------------------------------------------------------------------------- @@ -98,9 +115,11 @@ void VPieceCarrouselPiece::Refresh() { // update the graphic view / the scene - // TODO / FIXME : not perfect and maybe not the right way, still need to work on this - // for instance: use a painter to habve a better quality, less pixeled. - QVector points = m_piece->GetCuttingLine(); + QVector points = m_piece->GetSeamLine(); + if(points.isEmpty()) + { + points = m_piece->GetCuttingLine(); + } QPen pen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); pen.setCosmetic(true); @@ -110,9 +129,9 @@ void VPieceCarrouselPiece::Refresh() path.moveTo(points.first()); for (int i = 1; i < points.size(); ++i) path.lineTo(points.at(i)); - m_graphicsView->scene()->addPath(path, pen, noBrush); + m_piecePreview->scene()->addPath(path, pen, noBrush); - m_graphicsView->fitInView(m_graphicsView->scene()->sceneRect(), Qt::KeepAspectRatio); + m_piecePreview->fitInView(m_piecePreview->scene()->sceneRect(), Qt::KeepAspectRatio); // update the label of the piece QFontMetrics metrix(m_label->font()); @@ -122,6 +141,9 @@ void VPieceCarrouselPiece::Refresh() // set the tooltip setToolTip(m_piece->GetName()); + + // set the selection state correctly. + on_PieceSelectionChanged(); } //--------------------------------------------------------------------------------------------------------------------- @@ -131,11 +153,9 @@ VPuzzlePiece * VPieceCarrouselPiece::GetPiece() } //--------------------------------------------------------------------------------------------------------------------- -void VPieceCarrouselPiece::SetIsSelected(bool value) +void VPieceCarrouselPiece::on_PieceSelectionChanged() { - m_isSelected = value; - - if(value) + if(m_piece->GetIsSelected()) { setStyleSheet("background-color:white; border: 2px solid red;"); } @@ -145,21 +165,121 @@ void VPieceCarrouselPiece::SetIsSelected(bool value) } } -//--------------------------------------------------------------------------------------------------------------------- -bool VPieceCarrouselPiece::GetIsSelected() -{ - return m_isSelected; -} - //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrouselPiece::mousePressEvent(QMouseEvent *event) { + qCDebug(pCarrouselPiece, "mouse pressed"); + + if (event->button() == Qt::LeftButton) { - if(!m_isSelected) + if(!(event->modifiers() & Qt::ControlModifier)) { - emit clicked(this); + m_carrouselLayer->GetCarrousel()->ClearSelection(); + m_piece->SetIsSelected(true); } + else + { + m_piece->SetIsSelected(!m_piece->GetIsSelected()); + } + + m_dragStart = event->pos(); } } + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselPiece::mouseMoveEvent(QMouseEvent *event) +{ + if (!(event->buttons() & Qt::LeftButton)) + { + return; + } + + if(m_piece->GetLayer() != m_piece->GetLayer()->GetLayout()->GetUnplacedPiecesLayer()) + { + return; + } + + if((event->pos() - m_dragStart).manhattanLength() < QApplication::startDragDistance()) + { + return; + } + + // make sure the multiple selection is removed + m_carrouselLayer->GetCarrousel()->ClearSelection(); + m_piece->SetIsSelected(true); + + // starts the dragging + QDrag *drag = new QDrag(this); + VPuzzleMimeDataPiece *mimeData = new VPuzzleMimeDataPiece(); + mimeData->SetPiecePtr(m_piece); + mimeData->setObjectName("piecePointer"); + + // in case we would want to have the pieces original size: + //drag->setHotSpot(QPoint(0,0)); + //QPixmap pixmap(m_piecePreview->sceneRect().size().toSize()); + + QPixmap pixmap(112,92); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + painter.setRenderHint(QPainter::Antialiasing); + m_piecePreview->scene()->render(&painter); + + drag->setPixmap(pixmap); + drag->setMimeData(mimeData); + drag->exec(); +} + + + + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselPiece::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu contextMenu; + + VPuzzleLayer* unplacedLayer = m_piece->GetLayer()->GetLayout()->GetUnplacedPiecesLayer(); + QList layers = m_piece->GetLayer()->GetLayout()->GetLayers(); + + // move to layer actions -- TODO : To be tested properly when we have several layers + layers.removeAll(m_piece->GetLayer()); + if(layers.count() > 0) + { + QMenu *moveMenu = contextMenu.addMenu(tr("Move to")); + + // TODO order in alphabetical order + + for (auto layer : layers) + { + QAction* moveToLayer = moveMenu->addAction(layer->GetName()); + QVariant data = QVariant::fromValue(layer); + moveToLayer->setData(data); + + connect(moveToLayer, &QAction::triggered, this, &VPieceCarrouselPiece::on_ActionPieceMovedToLayer); + } + } + + // remove from layout action + if(m_piece->GetLayer() != unplacedLayer) + { + QAction *removeAction = contextMenu.addAction(tr("Remove from Layout")); + QVariant data = QVariant::fromValue(m_piece->GetLayer()->GetLayout()->GetUnplacedPiecesLayer()); + removeAction->setData(data); + connect(removeAction, &QAction::triggered, this, &VPieceCarrouselPiece::on_ActionPieceMovedToLayer); + } + + contextMenu.exec(event->globalPos()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselPiece::on_ActionPieceMovedToLayer() +{ + QAction *act = qobject_cast(sender()); + QVariant v = act->data(); + VPuzzleLayer *layer = (VPuzzleLayer *) v.value(); + if(layer != nullptr) + { + layer->GetLayout()->MovePieceToLayer(m_piece, layer); + } +} diff --git a/src/app/puzzle/vpiececarrouselpiece.h b/src/app/puzzle/vpiececarrouselpiece.h index 6eb7df138..96264e0d0 100644 --- a/src/app/puzzle/vpiececarrouselpiece.h +++ b/src/app/puzzle/vpiececarrouselpiece.h @@ -34,13 +34,16 @@ #include #include "vpuzzlepiece.h" +#include "vpiececarrouselpiecepreview.h" +class VPieceCarrouselLayer; + class VPieceCarrouselPiece : public QFrame { Q_OBJECT public: - explicit VPieceCarrouselPiece(VPuzzlePiece *piece, QWidget *parent = nullptr); + explicit VPieceCarrouselPiece(VPuzzlePiece *piece, VPieceCarrouselLayer *carrouselLayer); ~VPieceCarrouselPiece(); void Init(); @@ -57,34 +60,34 @@ public: */ VPuzzlePiece * GetPiece(); - /** - * @brief SetSelected sets the selected state to the given value - * @param value the new selected state - */ - void SetIsSelected(bool value); - - /** - * @brief GetSelected Returns wether the piece is selected or not - * @return true if the piece is selected - */ - bool GetIsSelected(); - -signals: - void clicked(VPieceCarrouselPiece* m_piece); - public slots: + void on_PieceSelectionChanged(); protected: void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + + void contextMenuEvent(QContextMenuEvent *event) override; + +private slots: + /** + * @brief on_ActionPieceMovedToLayer Slot called when the piece is moved via the + * context menu to anoter layer + */ + void on_ActionPieceMovedToLayer(); + private: Q_DISABLE_COPY(VPieceCarrouselPiece) VPuzzlePiece *m_piece; - QLabel *m_label{nullptr}; - QGraphicsView *m_graphicsView{nullptr}; - bool m_isSelected = false; + VPieceCarrouselLayer *m_carrouselLayer; + + QLabel *m_label{nullptr}; + VPieceCarrouselPiecePreview *m_piecePreview{nullptr}; + + QPoint m_dragStart; private slots: diff --git a/src/app/puzzle/vpiececarrouselpiecepreview.cpp b/src/app/puzzle/vpiececarrouselpiecepreview.cpp new file mode 100644 index 000000000..f68af933f --- /dev/null +++ b/src/app/puzzle/vpiececarrouselpiecepreview.cpp @@ -0,0 +1,55 @@ +/************************************************************************ + ** + ** @file vpiececarrouselpiecepreview.cpp + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vpiececarrouselpiecepreview.h" + +#include + +//--------------------------------------------------------------------------------------------------------------------- +VPieceCarrouselPiecePreview::VPieceCarrouselPiecePreview(QWidget *parent): + QGraphicsView(parent) +{ + +} +//--------------------------------------------------------------------------------------------------------------------- +VPieceCarrouselPiecePreview::~VPieceCarrouselPiecePreview() +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselPiecePreview::mousePressEvent(QMouseEvent *event) +{ + event->ignore(); +} +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselPiecePreview::mouseMoveEvent(QMouseEvent *event) +{ + event->ignore(); +} + diff --git a/src/app/puzzle/vpiececarrouselpiecepreview.h b/src/app/puzzle/vpiececarrouselpiecepreview.h new file mode 100644 index 000000000..9e3049de1 --- /dev/null +++ b/src/app/puzzle/vpiececarrouselpiecepreview.h @@ -0,0 +1,45 @@ +/************************************************************************ + ** + ** @file vpiececarrouselpiecepreview.h + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VPUZZLEPIECECARROUSELPIECEPREVIEW_H +#define VPUZZLEPIECECARROUSELPIECEPREVIEW_H + +#include + +class VPieceCarrouselPiecePreview: public QGraphicsView +{ +public: + VPieceCarrouselPiecePreview(QWidget *parent = nullptr); + ~VPieceCarrouselPiecePreview(); + +protected: + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; +}; + +#endif // VPUZZLEPIECECARROUSELPIECEPREVIEW_H diff --git a/src/app/puzzle/vpuzzlegraphicslayout.cpp b/src/app/puzzle/vpuzzlegraphicslayout.cpp new file mode 100644 index 000000000..00185b9b5 --- /dev/null +++ b/src/app/puzzle/vpuzzlegraphicslayout.cpp @@ -0,0 +1,92 @@ +/************************************************************************ + ** + ** @file vpuzzlegraphicslayout.cpp + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vpuzzlegraphicslayout.h" + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleGraphicsLayout::VPuzzleGraphicsLayout(VPuzzleLayout *layout, QGraphicsItem *parent): + QGraphicsItem(parent), + m_layout(layout), + m_boundingRect(GetLayoutRect()) +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleGraphicsLayout::~VPuzzleGraphicsLayout() +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsLayout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(widget); + Q_UNUSED(option); + + QPen pen(QColor(0,179,255), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + pen.setCosmetic(true); + QBrush noBrush(Qt::NoBrush); + painter->setPen(pen); + painter->setBrush(noBrush); + + painter->drawRect(GetMarginsRect()); + + pen.setColor(Qt::black); + + painter->setPen(pen); + painter->drawRect(GetLayoutRect()); + + m_boundingRect = GetLayoutRect(); +} + +//--------------------------------------------------------------------------------------------------------------------- +QRectF VPuzzleGraphicsLayout::GetLayoutRect() const +{ + QRectF rect = QRectF(QPointF(0,0), m_layout->GetLayoutSize()); + return rect; +} + +//--------------------------------------------------------------------------------------------------------------------- +QRectF VPuzzleGraphicsLayout::GetMarginsRect() const +{ + QMarginsF margins = m_layout->GetLayoutMargins(); + QSizeF size = m_layout->GetLayoutSize(); + QRectF rect = QRectF( + QPointF(margins.left(),margins.top()), + QPointF(size.width()-margins.right(), size.height()-margins.bottom()) + ); + return rect; +} + + +//--------------------------------------------------------------------------------------------------------------------- +QRectF VPuzzleGraphicsLayout::boundingRect() const +{ + return m_boundingRect; +} diff --git a/src/app/puzzle/vpuzzlegraphicslayout.h b/src/app/puzzle/vpuzzlegraphicslayout.h new file mode 100644 index 000000000..477fcfc75 --- /dev/null +++ b/src/app/puzzle/vpuzzlegraphicslayout.h @@ -0,0 +1,58 @@ +/************************************************************************ + ** + ** @file vpuzzlegraphicslayout.h + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VPUZZLEGRAPHICSLAYOUT_H +#define VPUZZLEGRAPHICSLAYOUT_H + +#include +#include + +#include "vpuzzlelayout.h" + +class VPuzzleGraphicsLayout : public QGraphicsItem +{ +public: + VPuzzleGraphicsLayout(VPuzzleLayout *layout, QGraphicsItem *parent = nullptr); + ~VPuzzleGraphicsLayout(); + + QRectF boundingRect() const override; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override; + + + QRectF GetLayoutRect() const; + QRectF GetMarginsRect() const; + + +private: + Q_DISABLE_COPY(VPuzzleGraphicsLayout) + + VPuzzleLayout *m_layout{nullptr}; + QRectF m_boundingRect; +}; + +#endif // VPUZZLEGRAPHICSLAYOUT_H diff --git a/src/app/puzzle/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp new file mode 100644 index 000000000..3d53423fe --- /dev/null +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -0,0 +1,376 @@ +/************************************************************************ + ** + ** @file vpuzzlegraphicspiece.cpp + ** @author Ronan Le Tiec + ** @date 4 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vpuzzlegraphicspiece.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpuzzlepiece.h" +#include "vpuzzlelayer.h" +#include "vpuzzlelayout.h" + +#include +Q_LOGGING_CATEGORY(pGraphicsPiece, "p.graphicsPiece") + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleGraphicsPiece::VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *parent) : + QGraphicsObject(parent), + m_piece(piece), + m_cuttingLine(QPainterPath()), + m_seamLine(QPainterPath()), + m_grainline(QPainterPath()), + m_rotationStartPoint(QPointF()) +{ + Init(); +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleGraphicsPiece::~VPuzzleGraphicsPiece() +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::Init() +{ + // set some infos + setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges); + setAcceptHoverEvents(true); + setCursor(QCursor(Qt::OpenHandCursor)); + + // initialises the seam line + QVector seamLinePoints = m_piece->GetSeamLine(); + m_seamLine.moveTo(seamLinePoints.first()); + for (int i = 1; i < seamLinePoints.size(); ++i) + m_seamLine.lineTo(seamLinePoints.at(i)); + + // initiliases the cutting line + QVector cuttingLinepoints = m_piece->GetCuttingLine(); + m_cuttingLine.moveTo(cuttingLinepoints.first()); + for (int i = 1; i < cuttingLinepoints.size(); ++i) + m_cuttingLine.lineTo(cuttingLinepoints.at(i)); + + // initialises the grainline + QVector grainLinepoints = m_piece->GetGrainline(); + m_grainline.moveTo(grainLinepoints.first()); + for (int i = 1; i < grainLinepoints.size(); ++i) + m_grainline.lineTo(grainLinepoints.at(i)); + + + // TODO : initialises the other elements labels, passmarks etc. + + // Initialises the connectors + connect(m_piece, &VPuzzlePiece::SelectionChanged, this, &VPuzzleGraphicsPiece::on_PieceSelectionChanged); + connect(m_piece, &VPuzzlePiece::PositionChanged, this, &VPuzzleGraphicsPiece::on_PiecePositionChanged); + connect(m_piece, &VPuzzlePiece::RotationChanged, this, &VPuzzleGraphicsPiece::on_PieceRotationChanged); +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzlePiece* VPuzzleGraphicsPiece::GetPiece() +{ + return m_piece; +} + +//--------------------------------------------------------------------------------------------------------------------- +QRectF VPuzzleGraphicsPiece::boundingRect() const +{ + if(!m_cuttingLine.isEmpty()) + { + return m_cuttingLine.boundingRect(); + } + + return m_seamLine.boundingRect(); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPuzzleGraphicsPiece::shape() const +{ + if(!m_cuttingLine.isEmpty()) + { + return m_cuttingLine; + } + + return m_seamLine; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(widget); + Q_UNUSED(option); + + QPen pen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + QBrush noBrush(Qt::NoBrush); + QBrush selectionBrush(QColor(255,160,160,60)); + + painter->setPen(pen); + + if(isSelected()) + { + painter->setBrush(selectionBrush); + } + else + { + painter->setBrush(noBrush); + } + + // paint the cutting line + if(!m_cuttingLine.isEmpty()) + { + painter->drawPath(m_cuttingLine); + painter->setBrush(noBrush); + } + + // paint the seam line + if(!m_seamLine.isEmpty()) + { + painter->drawPath(m_seamLine); + } + + painter->setBrush(noBrush); + + // paint the grainline + if(!m_grainline.isEmpty()) + { + painter->drawPath(m_grainline); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + bool selectionState = isSelected(); + //perform the default behaviour + QGraphicsItem::mousePressEvent(event); + + // change the cursor when clicking left button + if (event->button() == Qt::LeftButton) + { + setSelected(true); + setCursor(Qt::ClosedHandCursor); + + if (event->modifiers() & Qt::ControlModifier) + { + setSelected(!selectionState); + } + else + { + setSelected(true); + } + } + + if((event->button() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) + { + m_rotationStartPoint = event->scenePos(); + + QPixmap cursor_pixmap = QPixmap(":/cursor_rotate"); + cursor_pixmap = cursor_pixmap.scaledToWidth(32); + QCursor cursor_rotate = QCursor(cursor_pixmap, 16, 16); + + setCursor(cursor_rotate); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::mouseMoveEvent(QGraphicsSceneMouseEvent * event) +{ + if((event->buttons() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) + { + + QPointF rotationNewPoint = event->scenePos(); + QPointF rotationCenter = sceneBoundingRect().center(); + + // get the angle from the center to the initial click point + qreal init_x = m_rotationStartPoint.x() - rotationCenter.x(); + qreal init_y = m_rotationStartPoint.y() - rotationCenter.y(); + qreal initial_angle = qAtan2(init_y, init_x); + + qreal x = rotationNewPoint.x() - rotationCenter.x(); + qreal y = rotationNewPoint.y() - rotationCenter.y(); + qreal mv_angle = qAtan2(y,x); + + qreal angle = (initial_angle-mv_angle)*180/M_PI; + + setTransformOriginPoint(boundingRect().center()); + setRotation(-(angle+m_piece->GetRotation())); + event->accept(); + } + else + { + QGraphicsItem::mouseMoveEvent(event); + } +} + + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + bool selectionState = isSelected(); + + //perform the default behaviour + QGraphicsItem::mouseReleaseEvent(event); + + // change the cursor when clicking left button + if (event->button() == Qt::LeftButton) + { + setCursor(Qt::OpenHandCursor); + + setSelected(selectionState); + + if(m_piece->GetPosition() != pos()) + { + m_piece->SetPosition(pos()); + } + } + + if((event->button() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) + { + m_piece->SetRotation(-rotation()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + + if(event->modifiers() & Qt::AltModifier) + { + // TODO FIXME: find a more efficient way + + QPixmap cursor_pixmap = QPixmap(":/cursor_rotate"); + cursor_pixmap = cursor_pixmap.scaledToWidth(32); + QCursor cursor_rotate = QCursor(cursor_pixmap, 16, 16); + + setCursor(cursor_rotate); + } + else + { + setCursor(QCursor(Qt::OpenHandCursor)); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +{ + QMenu contextMenu; + + // move to layer actions -- TODO : To be tested properly when we have several layers + QList layers = m_piece->GetLayer()->GetLayout()->GetLayers(); + layers.removeAll(m_piece->GetLayer()); + + if(layers.count() > 0) + { + QMenu *moveMenu = contextMenu.addMenu(tr("Move to")); + + // TODO order in alphabetical order + + for (auto layer : layers) + { + QAction* moveToLayer = moveMenu->addAction(layer->GetName()); + QVariant data = QVariant::fromValue(layer); + moveToLayer->setData(data); + + connect(moveToLayer, &QAction::triggered, this, &VPuzzleGraphicsPiece::on_ActionPieceMovedToLayer); + } + } + + // remove from layout action + QAction *removeAction = contextMenu.addAction(tr("Remove from Layout")); + QVariant data = QVariant::fromValue(m_piece->GetLayer()->GetLayout()->GetUnplacedPiecesLayer()); + removeAction->setData(data); + connect(removeAction, &QAction::triggered, this, &VPuzzleGraphicsPiece::on_ActionPieceMovedToLayer); + + contextMenu.exec(event->screenPos()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::on_ActionPieceMovedToLayer() +{ + QAction *act = qobject_cast(sender()); + QVariant v = act->data(); + VPuzzleLayer *layer = v.value(); + if(layer != nullptr) + { + layer->GetLayout()->MovePieceToLayer(m_piece, layer); + } +} + + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::on_PieceSelectionChanged() +{ + setSelected(m_piece->GetIsSelected()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::on_PiecePositionChanged() +{ + setPos(m_piece->GetPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::on_PieceRotationChanged() +{ + setTransformOriginPoint(boundingRect().center()); + setRotation(-m_piece->GetRotation()); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVariant VPuzzleGraphicsPiece::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (scene()) { + + // we do this in the mouseRelease button to avoid updated this property all the time. +// if(change == ItemPositionHasChanged) +// { +// blockSignals(true); +// m_piece->SetPosition(pos()); +// blockSignals(false); +// } + + if(change == ItemSelectedHasChanged) + { + if(m_piece->GetIsSelected() != isSelected()) + { + m_piece->SetIsSelected(isSelected()); + } + } + } + + return QGraphicsObject::itemChange(change, value); +} + diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h new file mode 100644 index 000000000..fee04892f --- /dev/null +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -0,0 +1,100 @@ +/************************************************************************ + ** + ** @file vpuzzlegraphicspiece.h + ** @author Ronan Le Tiec + ** @date 4 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VPUZZLEGRAPHICSPIECE_H +#define VPUZZLEGRAPHICSPIECE_H + +#include + +class VPuzzlePiece; + +class VPuzzleGraphicsPiece : public QGraphicsObject +{ + Q_OBJECT +public: + VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *parent = nullptr); + ~VPuzzleGraphicsPiece(); + void Init(); + + /** + * @brief GetPiece Returns the piece that corresponds to the graphics piece + * @return the piece + */ + VPuzzlePiece* GetPiece(); + +public slots: + /** + * @brief on_PieceSelectionChanged Slot called when the piece selection was changed + */ + void on_PieceSelectionChanged(); + + /** + * @brief on_PiecePositionChanged Slot called when the piece position was changed + */ + void on_PiecePositionChanged(); + + /** + * @brief on_PieceRotationChanged Slot called when the piece rotation was changed + */ + void on_PieceRotationChanged(); + +protected: + QRectF boundingRect() const override; + QPainterPath shape() const override; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override; + + void mousePressEvent(QGraphicsSceneMouseEvent * event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + + void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; + + QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; + +private slots: + /** + * @brief on_ActionPieceMovedToLayer Slot called when the piece is moved via the + * context menu to anoter layer + */ + void on_ActionPieceMovedToLayer(); + +private: + Q_DISABLE_COPY(VPuzzleGraphicsPiece) + VPuzzlePiece *m_piece; + + QPainterPath m_cuttingLine; + QPainterPath m_seamLine; + QPainterPath m_grainline; + + QPointF m_rotationStartPoint; + +}; + +#endif // VPUZZLEGRAPHICSPIECE_H diff --git a/src/app/puzzle/vpuzzlelayer.cpp b/src/app/puzzle/vpuzzlelayer.cpp index e70e33255..efe1ce0dd 100644 --- a/src/app/puzzle/vpuzzlelayer.cpp +++ b/src/app/puzzle/vpuzzlelayer.cpp @@ -27,8 +27,15 @@ *************************************************************************/ #include "vpuzzlelayer.h" +#include "vpuzzlelayout.h" + +#include + +Q_LOGGING_CATEGORY(pLayer, "p.layer") + //--------------------------------------------------------------------------------------------------------------------- -VPuzzleLayer::VPuzzleLayer() +VPuzzleLayer::VPuzzleLayer(VPuzzleLayout *layout): + m_layout(layout) { } @@ -39,22 +46,46 @@ VPuzzleLayer::~VPuzzleLayer() } +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleLayout* VPuzzleLayer::GetLayout() +{ + return m_layout; +} + //--------------------------------------------------------------------------------------------------------------------- QList VPuzzleLayer::GetPieces() { return m_pieces; } + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleLayer::ClearSelection() +{ + for (auto piece: m_pieces) + { + piece->SetIsSelected(false); + } +} + //--------------------------------------------------------------------------------------------------------------------- void VPuzzleLayer::AddPiece(VPuzzlePiece *piece) { + qCDebug(pLayer(), "piece -- %s -- added to %s", qUtf8Printable(piece->GetName()), qUtf8Printable(this->GetName())); + m_pieces.append(piece); + piece->SetLayer(this); + + emit PieceAdded(piece); } //--------------------------------------------------------------------------------------------------------------------- void VPuzzleLayer::RemovePiece(VPuzzlePiece *piece) { m_pieces.removeAll(piece); + piece->SetLayer(nullptr); + + emit PieceRemoved(piece); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpuzzlelayer.h b/src/app/puzzle/vpuzzlelayer.h index 978393e0d..435701eff 100644 --- a/src/app/puzzle/vpuzzlelayer.h +++ b/src/app/puzzle/vpuzzlelayer.h @@ -31,10 +31,13 @@ #include #include "vpuzzlepiece.h" -class VPuzzleLayer +class VPuzzleLayout; + +class VPuzzleLayer : public QObject { + Q_OBJECT public: - VPuzzleLayer(); + VPuzzleLayer(VPuzzleLayout *layout); ~VPuzzleLayer(); QList GetPieces(); @@ -50,10 +53,36 @@ public: void SetIsVisible(bool value); bool GetIsVisible() const; + /** + * @brief GetLayout Returns the layout in which this layer is + * @return the layout of this layer + */ + VPuzzleLayout* GetLayout(); + + /** + * @brief ClearSelection Clears the selection of the pieces in this layer + */ + void ClearSelection(); + +signals: + /** + * @brief PieceAdded The signal is emited when a piece was added + */ + void PieceAdded(VPuzzlePiece *piece); + + /** + * @brief PieceRemoved The signal is emited when a piece was removed + */ + void PieceRemoved(VPuzzlePiece *piece); + private: + Q_DISABLE_COPY(VPuzzleLayer) + QString m_name{}; QList m_pieces{}; + VPuzzleLayout *m_layout{nullptr}; + // control bool m_isVisible{true}; diff --git a/src/app/puzzle/vpuzzlelayout.cpp b/src/app/puzzle/vpuzzlelayout.cpp index 61290add7..9020f3dac 100644 --- a/src/app/puzzle/vpuzzlelayout.cpp +++ b/src/app/puzzle/vpuzzlelayout.cpp @@ -31,14 +31,17 @@ //--------------------------------------------------------------------------------------------------------------------- VPuzzleLayout::VPuzzleLayout() : - m_unplacedPiecesLayer(new VPuzzleLayer()) + m_unplacedPiecesLayer(new VPuzzleLayer(this)) { m_unplacedPiecesLayer->SetName(QObject::tr("Unplaced pieces")); // create a standard default layer: - VPuzzleLayer *layer = new VPuzzleLayer(); + VPuzzleLayer *layer = new VPuzzleLayer(this); layer->SetName(QObject::tr("Layout")); AddLayer(layer); + + // sets the default active layer + SetFocusedLayer(); } //--------------------------------------------------------------------------------------------------------------------- @@ -57,7 +60,7 @@ VPuzzleLayer* VPuzzleLayout::GetUnplacedPiecesLayer() //--------------------------------------------------------------------------------------------------------------------- VPuzzleLayer* VPuzzleLayout::AddLayer() { - VPuzzleLayer *newLayer = new VPuzzleLayer(); + VPuzzleLayer *newLayer = new VPuzzleLayer(this); m_layers.append(newLayer); return newLayer; } @@ -75,6 +78,29 @@ QList VPuzzleLayout::GetLayers() return m_layers; } +//--------------------------------------------------------------------------------------------------------------------- +QList VPuzzleLayout::GetSelectedPieces() +{ + QList result = QList(); + + QList layers = m_layers; + layers.prepend(m_unplacedPiecesLayer); + + for (auto layer : layers) + { + for (auto piece : layer->GetPieces()) + { + if(piece->GetIsSelected()) + { + result.append(piece); + } + } + } + + return result; +} + + //--------------------------------------------------------------------------------------------------------------------- void VPuzzleLayout::SetUnit(Unit unit) { @@ -245,3 +271,48 @@ bool VPuzzleLayout::GetStickyEdges() const { return m_stickyEdges; } + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleLayout::ClearSelection() +{ + m_unplacedPiecesLayer->ClearSelection(); + + for (auto layer : m_layers) + { + layer->ClearSelection(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleLayout::SetFocusedLayer(VPuzzleLayer* focusedLayer) +{ + if(focusedLayer == nullptr) + { + m_focusedLayer = m_layers.first(); + } + else + { + m_focusedLayer = focusedLayer; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleLayer* VPuzzleLayout::GetFocusedLayer() +{ + return m_focusedLayer; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleLayout::MovePieceToLayer(VPuzzlePiece* piece, VPuzzleLayer* layer) +{ + VPuzzleLayer* layerBefore = piece->GetLayer(); + + if(layerBefore != nullptr) + { + piece->GetLayer()->RemovePiece(piece); + } + layer->AddPiece(piece); + + // signal, that a piece was moved + emit PieceMovedToLayer(piece, layerBefore,layer); +} diff --git a/src/app/puzzle/vpuzzlelayout.h b/src/app/puzzle/vpuzzlelayout.h index 436957475..26ab1da3f 100644 --- a/src/app/puzzle/vpuzzlelayout.h +++ b/src/app/puzzle/vpuzzlelayout.h @@ -35,12 +35,14 @@ #include "def.h" class VPuzzleLayer; +class VPuzzlePiece; // is this the right place for the definition? enum class FollowGrainline : qint8 { No = 0, Follow90 = 1, Follow180 = 2}; -class VPuzzleLayout +class VPuzzleLayout : public QObject { + Q_OBJECT public: VPuzzleLayout(); virtual ~VPuzzleLayout(); @@ -51,7 +53,22 @@ public: VPuzzleLayer* AddLayer(VPuzzleLayer *layer); QList GetLayers(); + /** + * @brief GetSelectedPieces Returns the list of the selected pieces + * @return the selected pieces + */ + QList GetSelectedPieces(); + + /** + * @brief SetUnit Sets the unit of the layout to the given unit + * @param unit the new unit + */ void SetUnit(Unit unit); + + /** + * @brief GetUnit Returns the current unit of the layout + * @return the unit + */ Unit GetUnit() const; /** @@ -133,7 +150,16 @@ public: */ QMarginsF GetLayoutMarginsConverted() const; - void SetFollowGrainline(FollowGrainline state); + /** + * @brief SetFollowGrainline Sets the type of grainline for the pieces to follow + * @param state the type of grainline + */ + void SetFollowGrainline(FollowGrainline state); + + /** + * @brief GetFollowGrainline Returns if the layout's pieces follow a grainline or not + * @return wether the pieces follow a grainline and if so, which grainline + */ FollowGrainline GetFollowGrainline() const; /** @@ -169,11 +195,49 @@ public: void SetStickyEdges(bool state); bool GetStickyEdges() const; + /** + * @brief ClearSelection goes through the layers & pieces and calls + * SetIsSelected(false) for the pieces that were selected. + */ + void ClearSelection(); + + /** + * @brief SetFocusedLayer Sets the focused layer, to which pieces are added from the carrousel via drag + * and drop + * @param focusedLayer the new active layer. If nullptr, then it sets automaticaly the first layer from m_layers + */ + void SetFocusedLayer(VPuzzleLayer* focusedLayer = nullptr); + + /** + * @brief GetFocusedLayer Returns the focused layer, to which pieces are added from the carrousel via drag + * and drop + * @return the focused layer + */ + VPuzzleLayer* GetFocusedLayer(); + + /** + * @brief MovePieceToLayer Moves the given piece to the given layer + * @param piece the piece to move + * @param layer the layer to move the piece to + */ + void MovePieceToLayer(VPuzzlePiece* piece, VPuzzleLayer* layer); + +signals: + + void PieceMovedToLayer(VPuzzlePiece *piece, VPuzzleLayer *layerBefore, VPuzzleLayer *layerAfter); + private: Q_DISABLE_COPY(VPuzzleLayout) + VPuzzleLayer *m_unplacedPiecesLayer; QList m_layers{}; + /** + * @brief m_focusedLayer pointer the the focused layer, to which pieces will be + * added via drag and drop, or if no layer is defined. + */ + VPuzzleLayer *m_focusedLayer{nullptr}; + // format Unit m_unit{Unit::Cm}; /** diff --git a/src/app/puzzle/vpuzzlemaingraphicsscene.cpp b/src/app/puzzle/vpuzzlemaingraphicsscene.cpp new file mode 100644 index 000000000..5a4d1d17f --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsscene.cpp @@ -0,0 +1,35 @@ +/************************************************************************ + ** + ** @file vpuzzlemaingraphicsscene.cpp + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vpuzzlemaingraphicsscene.h" + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleMainGraphicsScene::VPuzzleMainGraphicsScene(QObject *parent): QGraphicsScene(parent) +{ + +} diff --git a/src/app/puzzle/vpuzzlemaingraphicsscene.h b/src/app/puzzle/vpuzzlemaingraphicsscene.h new file mode 100644 index 000000000..199ed0e8f --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsscene.h @@ -0,0 +1,44 @@ +/************************************************************************ + ** + ** @file vpuzzlemaingraphicsscene.cpp + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VPUZZLEMAINGRAPHICSSCENE_H +#define VPUZZLEMAINGRAPHICSSCENE_H + +#include + +// TODO: When ready, extend from QGraphicsScene instead + +class VPuzzleMainGraphicsScene : public QGraphicsScene +{ + Q_OBJECT +public: + VPuzzleMainGraphicsScene(QObject *parent = nullptr); + +}; + +#endif // VPUZZLEMAINGRAPHICSSCENE_H diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.cpp b/src/app/puzzle/vpuzzlemaingraphicsview.cpp new file mode 100644 index 000000000..d4740eeb1 --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsview.cpp @@ -0,0 +1,205 @@ +/************************************************************************ + ** + ** @file vpuzzlemaingraphicsview.cpp + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vpuzzlemaingraphicsview.h" + +#include +#include +#include + +#include "vpuzzlemimedatapiece.h" +#include "vpuzzlelayer.h" + +#include + +Q_LOGGING_CATEGORY(pMainGraphicsView, "p.mainGraphicsView") + + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleMainGraphicsView::VPuzzleMainGraphicsView(VPuzzleLayout *layout, QWidget *parent) : + QGraphicsView(parent), + m_layout(layout), + m_graphicsPieces(QList()) +{ + m_scene = new VPuzzleMainGraphicsScene(this); + setScene(m_scene); + + m_graphicsLayout = new VPuzzleGraphicsLayout(layout); + m_graphicsLayout->setPos(0,0); + m_scene->addItem(m_graphicsLayout); + + setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + + setAcceptDrops(true); + + // add the connections + connect(m_layout, &VPuzzleLayout::PieceMovedToLayer, this, &VPuzzleMainGraphicsView::on_PieceMovedToLayer); + connect(m_scene, &VPuzzleMainGraphicsScene::selectionChanged, this, &VPuzzleMainGraphicsView::on_SceneSelectionChanged); +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleMainGraphicsView::~VPuzzleMainGraphicsView() +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::RefreshLayout() +{ + // FIXME: Is that the way to go? + + m_graphicsLayout->update(); + + m_scene->update(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *mime = event->mimeData(); + + if(mime->objectName() == "piecePointer") + { + qCDebug(pMainGraphicsView(), "drag enter"); + event->acceptProposedAction(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::dragMoveEvent(QDragMoveEvent *event) +{ + const QMimeData *mime = event->mimeData(); + + if(mime->objectName() == "piecePointer") + { + event->acceptProposedAction(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::dragLeaveEvent(QDragLeaveEvent *event) +{ + event->accept(); +} + + + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::dropEvent(QDropEvent *event) +{ + const QMimeData *mime = event->mimeData(); + + qCDebug(pMainGraphicsView(), "drop enter , %s", qUtf8Printable(mime->objectName())); + + if(mime->objectName() == "piecePointer") + { + const VPuzzleMimeDataPiece *mimePiece = qobject_cast (mime); + + VPuzzlePiece *piece = mimePiece->GetPiecePtr(); + if(piece != nullptr) + { + qCDebug(pMainGraphicsView(), "element dropped, %s", qUtf8Printable(piece->GetName())); + event->acceptProposedAction(); + + QPoint point = event->pos(); + piece->SetPosition(mapToScene(point)); + + // change the layer of the piece + VPuzzleLayer *focusedLayer = m_layout->GetFocusedLayer(); + if(focusedLayer != nullptr) + { + m_layout->MovePieceToLayer(piece, focusedLayer); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::keyPressEvent(QKeyEvent *event) +{ + if(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) + { + QList tmpGraphicsPieces = m_graphicsPieces; + + for(auto graphicsPiece : tmpGraphicsPieces) + { + VPuzzlePiece *piece = graphicsPiece->GetPiece(); + + if(piece->GetIsSelected()) + { + piece->SetIsSelected(false); + m_layout->MovePieceToLayer(piece, m_layout->GetUnplacedPiecesLayer()); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::on_PieceMovedToLayer(VPuzzlePiece *piece, VPuzzleLayer *layerBefore, VPuzzleLayer *layerAfter) +{ + Q_UNUSED(layerBefore) + + VPuzzleGraphicsPiece *_graphicsPiece = nullptr; + for(auto graphicPiece : m_graphicsPieces) + { + if(graphicPiece->GetPiece() == piece) + { + _graphicsPiece = graphicPiece; + } + } + + if(layerAfter == m_layout->GetUnplacedPiecesLayer() && _graphicsPiece != nullptr) + { + scene()->removeItem(_graphicsPiece); + m_graphicsPieces.removeAll(_graphicsPiece); + } + else if(layerAfter != m_layout->GetUnplacedPiecesLayer()) + { + if(_graphicsPiece == nullptr) + { + _graphicsPiece = new VPuzzleGraphicsPiece(piece); + m_graphicsPieces.append(_graphicsPiece); + } + + scene()->addItem(_graphicsPiece); + // not very clean to directly call slots + _graphicsPiece->on_PieceSelectionChanged(); + _graphicsPiece->on_PiecePositionChanged(); + _graphicsPiece->on_PieceRotationChanged(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::on_SceneSelectionChanged() +{ + // most of the selection behaviour taks place automatically + // but we need to make sure that the unplaced pieces are unselected when the scene selection has changed + // because as they are not part of the scene, they are not updated + + m_layout->GetUnplacedPiecesLayer()->ClearSelection(); +} diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.h b/src/app/puzzle/vpuzzlemaingraphicsview.h new file mode 100644 index 000000000..fea0d7947 --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsview.h @@ -0,0 +1,87 @@ +/************************************************************************ + ** + ** @file vpuzzlemaingraphicsview.h + ** @author Ronan Le Tiec + ** @date 3 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VPUZZLEMAINGRAPHICSVIEW_H +#define VPUZZLEMAINGRAPHICSVIEW_H + +#include + +#include "vpuzzlegraphicslayout.h" +#include "vpuzzlemaingraphicsscene.h" +#include "vpuzzlegraphicspiece.h" + + +// TODO: when ready, extend the VMainGrapchisView instead + +class VPuzzleMainGraphicsView : public QGraphicsView +{ + Q_OBJECT +public: + VPuzzleMainGraphicsView(VPuzzleLayout *layout, QWidget *parent); + ~VPuzzleMainGraphicsView(); + + /** + * @brief RefreshLayout Refreshes the rectangles for the layout border and the margin + */ + void RefreshLayout(); + +protected: + void dragEnterEvent(QDragEnterEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; + void dropEvent(QDropEvent *event) override; + + void keyPressEvent(QKeyEvent *event) override; + +private slots: + /** + * @brief on_PieceMovedToLayer The slot is called when the given piece was moved from the given layer to the other given layer + * @param piece the piece that was moved + * @param layerBefore the layer before the move + * @param layerAfter the layer after the move + */ + void on_PieceMovedToLayer(VPuzzlePiece *piece, VPuzzleLayer *layerBefore, VPuzzleLayer *layerAfter); + + /** + * @brief on_SceneSelectionChanged Slot is called when the scene selection has changed + */ + void on_SceneSelectionChanged(); + +private: + Q_DISABLE_COPY(VPuzzleMainGraphicsView) + + VPuzzleMainGraphicsScene *m_scene{nullptr}; + + VPuzzleGraphicsLayout *m_graphicsLayout{nullptr}; + VPuzzleLayout *m_layout{nullptr}; + + QList m_graphicsPieces; + +}; + +#endif // VPUZZLEMAINGRAPHICVIEW_H diff --git a/src/app/puzzle/vpuzzlemimedatapiece.cpp b/src/app/puzzle/vpuzzlemimedatapiece.cpp new file mode 100644 index 000000000..873d500c8 --- /dev/null +++ b/src/app/puzzle/vpuzzlemimedatapiece.cpp @@ -0,0 +1,53 @@ +/************************************************************************ + ** + ** @file vpuzzlemimedatapiece.cpp + ** @author Ronan Le Tiec + ** @date 4 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "vpuzzlemimedatapiece.h" + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleMimeDataPiece::VPuzzleMimeDataPiece() +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleMimeDataPiece::~VPuzzleMimeDataPiece() +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzlePiece* VPuzzleMimeDataPiece::GetPiecePtr() const +{ + return m_piece; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMimeDataPiece::SetPiecePtr(VPuzzlePiece* piece) +{ + m_piece = piece; +} diff --git a/src/app/puzzle/vpuzzlemimedatapiece.h b/src/app/puzzle/vpuzzlemimedatapiece.h new file mode 100644 index 000000000..8246c604b --- /dev/null +++ b/src/app/puzzle/vpuzzlemimedatapiece.h @@ -0,0 +1,65 @@ +/************************************************************************ + ** + ** @file vpuzzlemimedatapiece.h + ** @author Ronan Le Tiec + ** @date 4 5, 2020 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2020 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef VPUZZLEMIMEDATAPIECE_H +#define VPUZZLEMIMEDATAPIECE_H + +#include + +#include "vpuzzlepiece.h" + +class VPuzzleMimeDataPiece : public QMimeData +{ + Q_OBJECT + +public: + + VPuzzleMimeDataPiece(); + ~VPuzzleMimeDataPiece(); + + /** + * @brief GetPiecePtr Returns the piece pointer of the mime data + * @return piece pointer + */ + VPuzzlePiece* GetPiecePtr() const; + + /** + * @brief SetPiecePtr sets the piece pointer to the given value + * @param piece the piece pointer + */ + void SetPiecePtr(VPuzzlePiece* piece); + +private: + Q_DISABLE_COPY(VPuzzleMimeDataPiece) + + VPuzzlePiece *m_piece{nullptr}; + +}; + + +#endif // VPUZZLEMIMEDATAPIECE_H diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index 5a1bc0d7d..40aeb2f9d 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -27,6 +27,14 @@ *************************************************************************/ #include "vpuzzlepiece.h" +#include + +#include "vpuzzlelayer.h" + +#include + +Q_LOGGING_CATEGORY(pPiece, "p.piece") + //--------------------------------------------------------------------------------------------------------------------- VPuzzlePiece::VPuzzlePiece() { @@ -79,6 +87,17 @@ void VPuzzlePiece::SetCuttingLine(const QVector &cuttingLine) m_cuttingLine = cuttingLine; } +//--------------------------------------------------------------------------------------------------------------------- +QVector VPuzzlePiece::GetSeamLine() const +{ + return m_seamLine; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetSeamLine(const QVector &seamLine) +{ + m_seamLine = seamLine; +} //--------------------------------------------------------------------------------------------------------------------- bool VPuzzlePiece::GetShowSeamLine() const @@ -90,6 +109,8 @@ bool VPuzzlePiece::GetShowSeamLine() const void VPuzzlePiece::SetShowSeamLine(bool value) { m_showSeamline = value; + + emit PropertiesChanged(); } //--------------------------------------------------------------------------------------------------------------------- @@ -102,5 +123,133 @@ bool VPuzzlePiece::GetPieceMirrored() const void VPuzzlePiece::SetPieceMirrored(bool value) { m_mirrorPiece = value; + + emit PropertiesChanged(); } +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetPosition(QPointF point) +{ + m_transform.translate(point.x() - m_transform.dx(), point.y() - m_transform.dy()); + + emit PositionChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPointF VPuzzlePiece::GetPosition() +{ + return QPointF(m_transform.dx(), m_transform.dy()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetRotation(qreal angle) +{ + // qreal currentAngle = GetRotation(); + // qreal newAngle = angle - currentAngle; + + // m_transform.rotate(newAngle); + + if(m_pieceAngle != angle) + { + m_pieceAngle = angle; + + // make sure the angle is [0 <= angle < 360] + while(m_pieceAngle >= 360) + { + m_pieceAngle -= 360; + } + + while(m_pieceAngle < 0) + { + m_pieceAngle += 360; + } + + emit RotationChanged(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPuzzlePiece::GetRotation() +{ + return m_pieceAngle; + + // We don't use the QTransform vor now because the math behind it to retrieve the angle is not trivial. + // TODO / FIXME: we can use QTransform later for optimization + + +// QTransform tmpTransform = m_transform; +// tmpTransform.translate(-tmpTransform.dx(), -tmpTransform.dy()); // make sure there is only the rotation in the matrix + +// qreal angle = qRadiansToDegrees(qAcos(tmpTransform.m11())); + +// qCDebug(pPiece, "new angle : %f", angle); + +// return angle; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetIsSelected(bool value) +{ + if(m_isSelected != value) + { + m_isSelected = value; + emit SelectionChanged(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPuzzlePiece::GetIsSelected() +{ + return m_isSelected; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetIsGrainlineEnabled(bool value) +{ + m_isGrainlineEnabled = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPuzzlePiece::GetIsGrainlineEnabled() +{ + return m_isGrainlineEnabled; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetGrainlineAngle(qreal value) +{ + m_grainlineAngle = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPuzzlePiece::GetGrainlineAngle() +{ + return m_grainlineAngle; +} +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetGrainline(QVector grainline) +{ + m_grainline = grainline; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPuzzlePiece::GetGrainline() +{ + return m_grainline; +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleLayer* VPuzzlePiece::GetLayer() +{ + return m_layer; +} + + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetLayer(VPuzzleLayer* layer) +{ + if(layer != m_layer) + { + m_layer = layer; + } +} diff --git a/src/app/puzzle/vpuzzlepiece.h b/src/app/puzzle/vpuzzlepiece.h index b126deeb2..b55ffeae0 100644 --- a/src/app/puzzle/vpuzzlepiece.h +++ b/src/app/puzzle/vpuzzlepiece.h @@ -31,9 +31,13 @@ #include #include #include +#include -class VPuzzlePiece +class VPuzzleLayer; + +class VPuzzlePiece : public QObject { + Q_OBJECT public: VPuzzlePiece(); ~VPuzzlePiece(); @@ -61,10 +65,30 @@ public: */ void SetUuid(const QUuid &uuid); + /** + * @brief GetCuttingLine Returns the vector points of the cutting line + * @return the vector points of the cutting line + */ QVector GetCuttingLine() const; + /** + * @brief SetCuttingLine Sets the vector points of the cutting line to the given value + * @param cuttingLine the new vector points for the cutting line + */ void SetCuttingLine(const QVector &cuttingLine); + /** + * @brief GetSeamLine Returns the vector points of the seam line + * @return the vector points of the seam line + */ + QVector GetSeamLine() const; + + /** + * @brief SetSeamLine Sets the vector points of the seam line to the given value + * @param seamLine the new vector points for the seam line + */ + void SetSeamLine(const QVector &seamLine); + /** * @brief GetShowSeamLine returns wether the seam line of the piece has to be shown or not * @return true if the seamline has to be shown @@ -89,13 +113,136 @@ public: */ void SetPieceMirrored(bool value); + /** + * @brief SetPosition Sets the position of the piece, in relation to the origin of the scene + * @param point the point where to set the piece + */ + void SetPosition(QPointF point); + + /** + * @brief GetPosition Returns the position of the piece + * @return the position of the piece + */ + QPointF GetPosition(); + + /** + * @brief SetRotation Sets the rotation of the piece to the given angle. + * @param angle the angle of the rotation in degree + */ + void SetRotation(qreal angle); + + /** + * @brief GetRotation Returns the angle of rotation + * @return the angle of rotation + */ + qreal GetRotation(); + + /** + * @brief SetIsGrainlineEnabled Wether the piece has a grainline or not + * @param value true or false + */ + void SetIsGrainlineEnabled(bool value); + + /** + * @brief GetIsGrainlineEnabled Returns wether the grainline is enabled for this piece + * @return true if enabled + */ + bool GetIsGrainlineEnabled(); + + /** + * @brief SetGrainlineAngle Sets the angle of the grainline + * @param value + */ + void SetGrainlineAngle(qreal value); + + /** + * @brief GetGrainlineAngle Returns the angle of the grainline for this piece + * @return the angle + */ + qreal GetGrainlineAngle(); + + /** + * @brief SetGrainline Sets the grainline to the given vector of points + * @param grainline the grainline + */ + void SetGrainline(QVector grainline); + + /** + * @brief GetGrainline Returns the grainline for this piece + * @return the vector + */ + QVector GetGrainline(); + + + /** + * @brief SetIsSelected Sets wether the piece is selected + * @param value true if the piece is selected + */ + void SetIsSelected(bool value); + + /** + * @brief GetIsSelected Returns wether the piece is selected. It emit the signal SelectionChanged + * @return true if the piece is selected + */ + bool GetIsSelected(); + + /** + * @brief GetLayer Returns the layer in which the piece is. + * @return layer of the piece + */ + VPuzzleLayer* GetLayer(); + + /** + * @brief SetLayer Sets the layer of the piece to the given layer + * @param layer + */ + void SetLayer(VPuzzleLayer* layer); + +signals: + /** + * @brief SelectionChanged emited when the selection of the piece was + * changed through the SetIsSelected function + */ + void SelectionChanged(); + + /** + * @brief PositionChanged emited when the position of the piece was + * changed through the SetPosition function + */ + void PositionChanged(); + + /** + * @brief RotationChanged emited when the position of the piece was + * changed through the function SetRotation + */ + void RotationChanged(); + + /** + * @brief PropertiesChanged emited when of the properties showSemaline + * or mirrorpiece where changed. + */ + void PropertiesChanged(); private: + Q_DISABLE_COPY(VPuzzlePiece) QUuid m_uuid{QUuid()}; QString m_name{QString()}; QVector m_cuttingLine{QVector()}; + QVector m_seamLine{QVector()}; + + QVector m_grainline{QVector()}; + bool m_isGrainlineEnabled{false}; + qreal m_grainlineAngle{0}; + + QTransform m_transform{QTransform()}; + // use a separate value for now because it's not easy to get the angle from the transform matrix + qreal m_pieceAngle{0}; + bool m_showSeamline{true}; bool m_mirrorPiece{false}; + + bool m_isSelected{false}; + VPuzzleLayer *m_layer{nullptr}; }; #endif // VPUZZLEPIECE_H