From 497cb65cb244fb0bed57881674d292ff06820608 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sat, 2 May 2020 12:17:06 +0200 Subject: [PATCH 01/10] Optimizing the piece carrousel --- src/app/puzzle/puzzlemainwindow.cpp | 10 ++++++++++ src/app/puzzle/vpiececarrousel.cpp | 18 ++++++++++++------ src/app/puzzle/vpiececarrousel.h | 13 +++++++++++++ src/app/puzzle/vpiececarrouselpiece.cpp | 9 ++++++--- src/app/puzzle/vpuzzlepiece.cpp | 11 +++++++++++ src/app/puzzle/vpuzzlepiece.h | 21 +++++++++++++++++++++ 6 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp index 8f8252a76..f318a9a0d 100644 --- a/src/app/puzzle/puzzlemainwindow.cpp +++ b/src/app/puzzle/puzzlemainwindow.cpp @@ -144,6 +144,14 @@ void PuzzleMainWindow::ImportRawLayouts(const QStringList &rawLayouts) // TODO for feature "Update piece" : CreateOrUpdate() function indstead of CreatePiece() + + // 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. + + VPuzzlePiece *piece = CreatePiece(rawPiece); m_layout->GetUnplacedPiecesLayer()->AddPiece(piece); } @@ -165,10 +173,12 @@ void PuzzleMainWindow::ImportRawLayouts(const QStringList &rawLayouts) //--------------------------------------------------------------------------------------------------------------------- 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()); // TODO : set all the information we need for the piece! diff --git a/src/app/puzzle/vpiececarrousel.cpp b/src/app/puzzle/vpiececarrousel.cpp index 06741ffb7..ff659ca80 100644 --- a/src/app/puzzle/vpiececarrousel.cpp +++ b/src/app/puzzle/vpiececarrousel.cpp @@ -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); @@ -92,9 +94,6 @@ void VPieceCarrousel::Init() // ------ then we fill the carrousel with the layout content Refresh(); - - // ------ and make sure the calculation for the qlayout is right - SetOrientation(Qt::Vertical); } //--------------------------------------------------------------------------------------------------------------------- @@ -126,6 +125,8 @@ void VPieceCarrousel::Refresh() } on_ActiveLayerChanged(0); + + RefreshOrientation(); } //--------------------------------------------------------------------------------------------------------------------- @@ -188,8 +189,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 +214,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); @@ -232,7 +239,6 @@ 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 } - } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpiececarrousel.h b/src/app/puzzle/vpiececarrousel.h index 9e90c56d7..54b9e786e 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 */ @@ -85,6 +96,8 @@ private: QList m_carrouselLayers; + Qt::Orientation m_orientation{Qt::Vertical}; + private slots: void on_ActiveLayerChanged(int index); diff --git a/src/app/puzzle/vpiececarrouselpiece.cpp b/src/app/puzzle/vpiececarrouselpiece.cpp index 3ce4771a1..78f02c9e5 100644 --- a/src/app/puzzle/vpiececarrouselpiece.cpp +++ b/src/app/puzzle/vpiececarrouselpiece.cpp @@ -72,6 +72,7 @@ void VPieceCarrouselPiece::Init() m_graphicsView->setScene(graphicsScene); m_graphicsView->setFixedSize(120,100); m_graphicsView->setStyleSheet("border: 4px solid transparent;"); + m_graphicsView->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // define the label m_label = new QLabel(); @@ -98,9 +99,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); diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index 21daa67a2..b01f9b59b 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -79,6 +79,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() diff --git a/src/app/puzzle/vpuzzlepiece.h b/src/app/puzzle/vpuzzlepiece.h index 55d0f3fd8..735707e1c 100644 --- a/src/app/puzzle/vpuzzlepiece.h +++ b/src/app/puzzle/vpuzzlepiece.h @@ -61,10 +61,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 @@ -94,6 +114,7 @@ private: QUuid m_uuid{QUuid()}; QString m_name{QString()}; QVector m_cuttingLine{QVector()}; + QVector m_seamLine{QVector()}; bool m_showSeamline{true}; bool m_mirrorPiece{false}; }; From c4dbea1d56d2987745a9579265ed8cd829cac704 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Tue, 5 May 2020 07:44:20 +0200 Subject: [PATCH 02/10] puzzle main graphics and pieces --- src/app/puzzle/puzzle.pri | 12 ++ src/app/puzzle/puzzlemainwindow.cpp | 37 +++- src/app/puzzle/puzzlemainwindow.h | 9 +- src/app/puzzle/puzzlemainwindow.ui | 4 - src/app/puzzle/vpiececarrousel.cpp | 1 - src/app/puzzle/vpiececarrouselpiece.cpp | 64 +++++-- src/app/puzzle/vpiececarrouselpiece.h | 7 +- .../puzzle/vpiececarrouselpiecepreview.cpp | 55 ++++++ src/app/puzzle/vpiececarrouselpiecepreview.h | 45 +++++ src/app/puzzle/vpuzzlegraphicslayout.cpp | 91 ++++++++++ src/app/puzzle/vpuzzlegraphicslayout.h | 58 +++++++ src/app/puzzle/vpuzzlegraphicspiece.cpp | 158 ++++++++++++++++++ src/app/puzzle/vpuzzlegraphicspiece.h | 61 +++++++ src/app/puzzle/vpuzzlemaingraphicsscene.cpp | 36 ++++ src/app/puzzle/vpuzzlemaingraphicsscene.h | 43 +++++ src/app/puzzle/vpuzzlemaingraphicsview.cpp | 131 +++++++++++++++ src/app/puzzle/vpuzzlemaingraphicsview.h | 67 ++++++++ src/app/puzzle/vpuzzlemimedatapiece.cpp | 53 ++++++ src/app/puzzle/vpuzzlemimedatapiece.h | 65 +++++++ 19 files changed, 972 insertions(+), 25 deletions(-) create mode 100644 src/app/puzzle/vpiececarrouselpiecepreview.cpp create mode 100644 src/app/puzzle/vpiececarrouselpiecepreview.h create mode 100644 src/app/puzzle/vpuzzlegraphicslayout.cpp create mode 100644 src/app/puzzle/vpuzzlegraphicslayout.h create mode 100644 src/app/puzzle/vpuzzlegraphicspiece.cpp create mode 100644 src/app/puzzle/vpuzzlegraphicspiece.h create mode 100644 src/app/puzzle/vpuzzlemaingraphicsscene.cpp create mode 100644 src/app/puzzle/vpuzzlemaingraphicsscene.h create mode 100644 src/app/puzzle/vpuzzlemaingraphicsview.cpp create mode 100644 src/app/puzzle/vpuzzlemaingraphicsview.h create mode 100644 src/app/puzzle/vpuzzlemimedatapiece.cpp create mode 100644 src/app/puzzle/vpuzzlemimedatapiece.h 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 f318a9a0d..21a26d23c 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,7 +144,12 @@ 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 @@ -152,6 +159,7 @@ void PuzzleMainWindow::ImportRawLayouts(const QStringList &rawLayouts) // 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); } @@ -173,7 +181,6 @@ void PuzzleMainWindow::ImportRawLayouts(const QStringList &rawLayouts) //--------------------------------------------------------------------------------------------------------------------- VPuzzlePiece* PuzzleMainWindow::CreatePiece(const VLayoutPiece &rawPiece) { - VPuzzlePiece *piece = new VPuzzlePiece(); piece->SetName(rawPiece.GetName()); piece->SetUuid(rawPiece.GetUUID()); @@ -411,6 +418,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) @@ -654,7 +670,8 @@ void PuzzleMainWindow::on_LayoutSizeChanged() } // TODO Undo / Redo - // TODO update the QGraphicView + + m_graphicsView->RefreshLayout(); } //--------------------------------------------------------------------------------------------------------------------- @@ -667,8 +684,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(); } //--------------------------------------------------------------------------------------------------------------------- @@ -696,7 +716,8 @@ void PuzzleMainWindow::on_LayoutMarginChanged() ); // TODO Undo / Redo - // TODO update the QGraphicView + + m_graphicsView->RefreshLayout(); } diff --git a/src/app/puzzle/puzzlemainwindow.h b/src/app/puzzle/puzzlemainwindow.h index eb8dde989..a51515f21 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,11 +87,13 @@ 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}; /** @@ -134,6 +137,10 @@ private: */ void InitPieceCarrousel(); + /** + * @brief InitMainGraphics Initialises the puzzle main graphics + */ + void InitMainGraphics(); /** * @brief SetPropertiesData Sets the values of UI elements diff --git a/src/app/puzzle/puzzlemainwindow.ui b/src/app/puzzle/puzzlemainwindow.ui index 5f63f8644..22e8d7fbc 100644 --- a/src/app/puzzle/puzzlemainwindow.ui +++ b/src/app/puzzle/puzzlemainwindow.ui @@ -24,9 +24,6 @@ QLayout::SetDefaultConstraint - - - @@ -1096,7 +1093,6 @@ - graphicsView scrollAreaLayout doubleSpinBoxLayoutMarginTop doubleSpinBoxLayoutMarginLeft diff --git a/src/app/puzzle/vpiececarrousel.cpp b/src/app/puzzle/vpiececarrousel.cpp index ff659ca80..03bd866bf 100644 --- a/src/app/puzzle/vpiececarrousel.cpp +++ b/src/app/puzzle/vpiececarrousel.cpp @@ -230,7 +230,6 @@ void VPieceCarrousel::RefreshOrientation() { m_comboBoxLayer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - // scroll bar policy of scroll area m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); diff --git a/src/app/puzzle/vpiececarrouselpiece.cpp b/src/app/puzzle/vpiececarrouselpiece.cpp index 78f02c9e5..3051e2c6c 100644 --- a/src/app/puzzle/vpiececarrouselpiece.cpp +++ b/src/app/puzzle/vpiececarrouselpiece.cpp @@ -27,15 +27,22 @@ *************************************************************************/ #include "vpiececarrouselpiece.h" + #include #include #include #include +#include +#include +#include + +#include "vpuzzlemimedatapiece.h" #include Q_LOGGING_CATEGORY(pCarrouselPiece, "p.carrouselPiece") + //--------------------------------------------------------------------------------------------------------------------- VPieceCarrouselPiece::VPieceCarrouselPiece(VPuzzlePiece *piece, QWidget *parent) : QFrame(parent), @@ -48,7 +55,7 @@ VPieceCarrouselPiece::VPieceCarrouselPiece(VPuzzlePiece *piece, QWidget *parent) //--------------------------------------------------------------------------------------------------------------------- VPieceCarrouselPiece::~VPieceCarrouselPiece() { - delete m_graphicsView; + delete m_piecePreview; } //--------------------------------------------------------------------------------------------------------------------- @@ -64,15 +71,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_graphicsView->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + 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(); @@ -80,8 +87,9 @@ 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); // then refresh the data @@ -91,7 +99,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); } //--------------------------------------------------------------------------------------------------------------------- @@ -113,9 +121,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()); @@ -157,12 +165,48 @@ bool VPieceCarrouselPiece::GetIsSelected() //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrouselPiece::mousePressEvent(QMouseEvent *event) { + qCDebug(pCarrouselPiece, "mouse pressed"); + + if (event->button() == Qt::LeftButton) { if(!m_isSelected) { emit clicked(this); } + m_dragStart = event->pos(); } } + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrouselPiece::mouseMoveEvent(QMouseEvent *event) +{ + if (!(event->buttons() & Qt::LeftButton)) + { + return; + } + if((event->pos() - m_dragStart).manhattanLength() < QApplication::startDragDistance()) + { + return; + } + + 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(); +} diff --git a/src/app/puzzle/vpiececarrouselpiece.h b/src/app/puzzle/vpiececarrouselpiece.h index 6eb7df138..ad7d6a272 100644 --- a/src/app/puzzle/vpiececarrouselpiece.h +++ b/src/app/puzzle/vpiececarrouselpiece.h @@ -34,6 +34,7 @@ #include #include "vpuzzlepiece.h" +#include "vpiececarrouselpiecepreview.h" class VPieceCarrouselPiece : public QFrame @@ -77,15 +78,19 @@ public slots: protected: void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + private: Q_DISABLE_COPY(VPieceCarrouselPiece) VPuzzlePiece *m_piece; QLabel *m_label{nullptr}; - QGraphicsView *m_graphicsView{nullptr}; + VPieceCarrouselPiecePreview *m_piecePreview{nullptr}; bool m_isSelected = false; + 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..51a4b65dd --- /dev/null +++ b/src/app/puzzle/vpuzzlegraphicslayout.cpp @@ -0,0 +1,91 @@ +/************************************************************************ + ** + ** @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..b69332fe6 --- /dev/null +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -0,0 +1,158 @@ +/************************************************************************ + ** + ** @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 + + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleGraphicsPiece::VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *parent) : + QGraphicsItem(parent), + m_piece(piece), + m_cuttingLine(QPainterPath()), + m_seamLine(QPainterPath()) +{ + Init(); +} + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleGraphicsPiece::~VPuzzleGraphicsPiece() +{ + +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::Init() +{ + // set some infos + setFlags(ItemIsSelectable | ItemIsMovable); + setCursor(QCursor(Qt::OpenHandCursor)); + + //setAcceptHoverEvents(true); // maybe we can do some stuff with this + + + // 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)); + + + // TODO : initialises the other elements like grain line, labels, passmarks etc. + + +} + + +//--------------------------------------------------------------------------------------------------------------------- +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); + + QPen pen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + QBrush noBrush(Qt::NoBrush); + + painter->setPen(pen); + painter->setBrush(noBrush); + + if(!m_cuttingLine.isEmpty()) + { + painter->drawPath(m_cuttingLine); + } + + if(!m_seamLine.isEmpty()) + { + painter->drawPath(m_seamLine); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + //perform the default behaviour + QGraphicsItem::mousePressEvent(event); + + // change the cursor when clicking left button + if (!(event->buttons() & Qt::LeftButton)) + { + return; + } + + setCursor(Qt::ClosedHandCursor); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + //perform the default behaviour + QGraphicsItem::mouseReleaseEvent(event); + + // change the cursor when clicking left button + if (!(event->buttons() & Qt::LeftButton)) + { + return; + } + + setCursor(Qt::OpenHandCursor); +} + + + diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h new file mode 100644 index 000000000..89d55b9ef --- /dev/null +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -0,0 +1,61 @@ +/************************************************************************ + ** + ** @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 + +#include "vpuzzlepiece.h" + +class VPuzzleGraphicsPiece : public QGraphicsItem +{ +public: + VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *parent = nullptr); + ~VPuzzleGraphicsPiece(); + void Init(); + +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 mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + + +private: + Q_DISABLE_COPY(VPuzzleGraphicsPiece) + VPuzzlePiece *m_piece; + + QPainterPath m_cuttingLine; + QPainterPath m_seamLine; + +}; + +#endif // VPUZZLEGRAPHICSPIECE_H diff --git a/src/app/puzzle/vpuzzlemaingraphicsscene.cpp b/src/app/puzzle/vpuzzlemaingraphicsscene.cpp new file mode 100644 index 000000000..37c75557e --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsscene.cpp @@ -0,0 +1,36 @@ +/************************************************************************ + ** + ** @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..7fae7da73 --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsscene.h @@ -0,0 +1,43 @@ +/************************************************************************ + ** + ** @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..bdadeb2c8 --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsview.cpp @@ -0,0 +1,131 @@ +/************************************************************************ + ** + ** @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 "vpuzzlemimedatapiece.h" + +#include + +Q_LOGGING_CATEGORY(pMainGraphicsView, "p.mainGraphicsView") + + +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleMainGraphicsView::VPuzzleMainGraphicsView(VPuzzleLayout *layout, QWidget *parent) : + QGraphicsView(parent) +{ + 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); +} + +//--------------------------------------------------------------------------------------------------------------------- +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(); + QPointF scenePos = mapToScene(point); + // todo take the position into account + + VPuzzleGraphicsPiece *item = new VPuzzleGraphicsPiece(piece); + item->setPos(scenePos); + m_scene->addItem(item); + } + } +} diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.h b/src/app/puzzle/vpuzzlemaingraphicsview.h new file mode 100644 index 000000000..9f6fd4aa9 --- /dev/null +++ b/src/app/puzzle/vpuzzlemaingraphicsview.h @@ -0,0 +1,67 @@ +/************************************************************************ + ** + ** @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; + + +private: + Q_DISABLE_COPY(VPuzzleMainGraphicsView) + + VPuzzleGraphicsLayout *m_graphicsLayout{nullptr}; + VPuzzleMainGraphicsScene *m_scene{nullptr}; +}; + +#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 From e2b816f1928678ca0e047e93e0451f9e4ad5bbe7 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Tue, 5 May 2020 17:40:36 +0200 Subject: [PATCH 03/10] work on piece selection and position --- src/app/puzzle/puzzlemainwindow.cpp | 109 +++++++++++++-------- src/app/puzzle/puzzlemainwindow.h | 14 ++- src/app/puzzle/vpiececarrousel.cpp | 28 +----- src/app/puzzle/vpiececarrousel.h | 7 -- src/app/puzzle/vpiececarrousellayer.cpp | 9 -- src/app/puzzle/vpiececarrousellayer.h | 6 -- src/app/puzzle/vpiececarrouselpiece.cpp | 21 ++-- src/app/puzzle/vpiececarrouselpiece.h | 18 +--- src/app/puzzle/vpuzzlegraphicspiece.cpp | 55 ++++++++++- src/app/puzzle/vpuzzlegraphicspiece.h | 18 +++- src/app/puzzle/vpuzzlelayout.cpp | 23 +++++ src/app/puzzle/vpuzzlelayout.h | 27 ++++- src/app/puzzle/vpuzzlemaingraphicsview.cpp | 22 ++++- src/app/puzzle/vpuzzlemaingraphicsview.h | 7 +- src/app/puzzle/vpuzzlepiece.cpp | 50 ++++++++++ src/app/puzzle/vpuzzlepiece.h | 74 +++++++++++++- 16 files changed, 353 insertions(+), 135 deletions(-) diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp index 21a26d23c..7c2571619 100644 --- a/src/app/puzzle/puzzlemainwindow.cpp +++ b/src/app/puzzle/puzzlemainwindow.cpp @@ -189,6 +189,11 @@ VPuzzlePiece* PuzzleMainWindow::CreatePiece(const VLayoutPiece &rawPiece) // 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); + + return piece; } @@ -228,9 +233,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); } @@ -310,9 +315,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); } @@ -335,31 +337,34 @@ 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); - } + // TODO : update current piece data to show a "no current piece selected" + ui->containerCurrentPieceNoData->setVisible(true); + ui->containerCurrentPieceData->setVisible(false); } - else + else if(m_selectedPieces.count() == 1) { + VPuzzlePiece *selectedPiece = m_selectedPieces.first(); + ui->containerCurrentPieceNoData->setVisible(false); ui->containerCurrentPieceData->setVisible(true); // set the value to the current piece - ui->lineEditCurrentPieceName->setText(m_selectedPiece->GetName()); + ui->lineEditCurrentPieceName->setText(selectedPiece->GetName()); - ui->checkBoxCurrentPieceShowSeamline->setChecked(m_selectedPiece->GetShowSeamLine()); - ui->checkBoxCurrentPieceMirrorPiece->setChecked(m_selectedPiece->GetPieceMirrored()); + ui->checkBoxCurrentPieceShowSeamline->setChecked(selectedPiece->GetShowSeamLine()); + ui->checkBoxCurrentPieceMirrorPiece->setChecked(selectedPiece->GetPieceMirrored()); - // TODO:rotation and placement; + 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())); + + // TODO: rotation + } + else + { + // TODO in the future } } @@ -790,18 +795,18 @@ 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); } } @@ -821,16 +826,22 @@ void PuzzleMainWindow::on_doubleSpinBoxCurrentPieceAngle_valueChanged(double val //--------------------------------------------------------------------------------------------------------------------- -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(); +// ui->doubleSpinBoxCurrentPieceBoxPositionX->blockSignals(true); +// ui->doubleSpinBoxCurrentPieceBoxPositionY->blockSignals(true); - Q_UNUSED(ret); + 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); + } + +// ui->doubleSpinBoxCurrentPieceBoxPositionX->blockSignals(false); +// ui->doubleSpinBoxCurrentPieceBoxPositionY->blockSignals(false); - // TODO } //--------------------------------------------------------------------------------------------------------------------- @@ -851,17 +862,35 @@ void PuzzleMainWindow::on_PieceCarrouselLocationChanged(Qt::DockWidgetArea area) } //--------------------------------------------------------------------------------------------------------------------- -void PuzzleMainWindow::on_PieceSelected(VPuzzlePiece* piece) +void PuzzleMainWindow::on_PieceSelectionChanged() { - m_selectedPiece = piece; + // for now we have only single selection + // FIXME / TODO : To be updated when we support multiple selection. - // update the state of the piece carrousel - m_pieceCarrousel->SelectPiece(piece); - - // update the Layout - - // TODO + for (auto piece : m_selectedPieces) + { + if(piece->GetIsSelected()) + { + piece->SetIsSelected(false); + } + } + 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())); + } +} diff --git a/src/app/puzzle/puzzlemainwindow.h b/src/app/puzzle/puzzlemainwindow.h index a51515f21..8d5015a4e 100644 --- a/src/app/puzzle/puzzlemainwindow.h +++ b/src/app/puzzle/puzzlemainwindow.h @@ -94,7 +94,7 @@ private: VPuzzleCommandLinePtr m_cmd; VPuzzleLayout *m_layout{nullptr}; - VPuzzlePiece *m_selectedPiece{nullptr}; + QListm_selectedPieces{QList()}; /** * @brief CreatePiece creates a piece from the given VLayoutPiece data @@ -354,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 @@ -364,10 +364,14 @@ 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(); }; diff --git a/src/app/puzzle/vpiececarrousel.cpp b/src/app/puzzle/vpiececarrousel.cpp index 03bd866bf..224bea4ec 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") @@ -118,10 +118,6 @@ 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); @@ -160,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) { @@ -239,11 +221,3 @@ void VPieceCarrousel::RefreshOrientation() // FIXME: find a nicer way than putting directly the 120 width of the piece } } - -//--------------------------------------------------------------------------------------------------------------------- -void VPieceCarrousel::on_PieceClicked(VPieceCarrouselPiece* carrouselPiece) -{ - emit pieceClicked(carrouselPiece->GetPiece()); -} - - diff --git a/src/app/puzzle/vpiececarrousel.h b/src/app/puzzle/vpiececarrousel.h index 54b9e786e..294db69ba 100644 --- a/src/app/puzzle/vpiececarrousel.h +++ b/src/app/puzzle/vpiececarrousel.h @@ -78,13 +78,6 @@ public: void SelectPiece(VPuzzlePiece* piece); -signals: - void pieceClicked(VPuzzlePiece* piece); - -public slots: - void on_PieceClicked(VPieceCarrouselPiece* carrouselPiece); - - private: Q_DISABLE_COPY(VPieceCarrousel) diff --git a/src/app/puzzle/vpiececarrousellayer.cpp b/src/app/puzzle/vpiececarrousellayer.cpp index d00ed6ecb..36b3b4e0d 100644 --- a/src/app/puzzle/vpiececarrousellayer.cpp +++ b/src/app/puzzle/vpiececarrousellayer.cpp @@ -89,10 +89,6 @@ void VPieceCarrouselLayer::Refresh() setVisible(true); carrouselPiece->CleanPreview(); setVisible(false); - - connect(carrouselPiece, QOverload::of(&VPieceCarrouselPiece::clicked), this, - &VPieceCarrouselLayer::on_PieceClicked); - } } @@ -102,8 +98,3 @@ QList VPieceCarrouselLayer::GetCarrouselPieces() return m_carrouselPieces; } -//--------------------------------------------------------------------------------------------------------------------- -void VPieceCarrouselLayer::on_PieceClicked(VPieceCarrouselPiece* carrouselPiece) -{ - emit pieceClicked(carrouselPiece); -} diff --git a/src/app/puzzle/vpiececarrousellayer.h b/src/app/puzzle/vpiececarrousellayer.h index aa3bae3a2..08d46a093 100644 --- a/src/app/puzzle/vpiececarrousellayer.h +++ b/src/app/puzzle/vpiececarrousellayer.h @@ -45,12 +45,6 @@ public: QList GetCarrouselPieces(); -signals: - void pieceClicked(VPieceCarrouselPiece* carrouselPiece); - -public slots: - void on_PieceClicked(VPieceCarrouselPiece* carrouselPiece); - private: Q_DISABLE_COPY(VPieceCarrouselLayer) diff --git a/src/app/puzzle/vpiececarrouselpiece.cpp b/src/app/puzzle/vpiececarrouselpiece.cpp index 3051e2c6c..27299cdd3 100644 --- a/src/app/puzzle/vpiececarrouselpiece.cpp +++ b/src/app/puzzle/vpiececarrouselpiece.cpp @@ -92,6 +92,11 @@ void VPieceCarrouselPiece::Init() 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(); } @@ -142,11 +147,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;"); } @@ -156,11 +159,7 @@ void VPieceCarrouselPiece::SetIsSelected(bool value) } } -//--------------------------------------------------------------------------------------------------------------------- -bool VPieceCarrouselPiece::GetIsSelected() -{ - return m_isSelected; -} + //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrouselPiece::mousePressEvent(QMouseEvent *event) @@ -170,9 +169,9 @@ void VPieceCarrouselPiece::mousePressEvent(QMouseEvent *event) if (event->button() == Qt::LeftButton) { - if(!m_isSelected) + if(!m_piece->GetIsSelected()) { - emit clicked(this); + m_piece->SetIsSelected(true); } m_dragStart = event->pos(); } diff --git a/src/app/puzzle/vpiececarrouselpiece.h b/src/app/puzzle/vpiececarrouselpiece.h index ad7d6a272..72d75e639 100644 --- a/src/app/puzzle/vpiececarrouselpiece.h +++ b/src/app/puzzle/vpiececarrouselpiece.h @@ -58,22 +58,8 @@ 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; @@ -87,8 +73,6 @@ private: QLabel *m_label{nullptr}; VPieceCarrouselPiecePreview *m_piecePreview{nullptr}; - bool m_isSelected = false; - QPoint m_dragStart; private slots: diff --git a/src/app/puzzle/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp index b69332fe6..70b5d9156 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.cpp +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -33,11 +33,16 @@ #include #include #include +#include +#include "vpuzzlepiece.h" + +#include +Q_LOGGING_CATEGORY(pGraphicsPiece, "p.graphicsPiece") //--------------------------------------------------------------------------------------------------------------------- VPuzzleGraphicsPiece::VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *parent) : - QGraphicsItem(parent), + QGraphicsObject(parent), m_piece(piece), m_cuttingLine(QPainterPath()), m_seamLine(QPainterPath()) @@ -55,7 +60,7 @@ VPuzzleGraphicsPiece::~VPuzzleGraphicsPiece() void VPuzzleGraphicsPiece::Init() { // set some infos - setFlags(ItemIsSelectable | ItemIsMovable); + setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges); setCursor(QCursor(Qt::OpenHandCursor)); //setAcceptHoverEvents(true); // maybe we can do some stuff with this @@ -76,7 +81,9 @@ void VPuzzleGraphicsPiece::Init() // TODO : initialises the other elements like grain line, labels, passmarks etc. - + // Initialises the connectors + connect(m_piece, &VPuzzlePiece::SelectionChanged, this, &VPuzzleGraphicsPiece::on_PieceSelectionChanged); + connect(m_piece, &VPuzzlePiece::PositionChanged, this, &VPuzzleGraphicsPiece::on_PiecePositionChanged); } @@ -106,8 +113,14 @@ QPainterPath VPuzzleGraphicsPiece::shape() const 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); + if(isSelected()) + { + pen.setColor(Qt::red); + } + QBrush noBrush(Qt::NoBrush); painter->setPen(pen); @@ -136,6 +149,8 @@ void VPuzzleGraphicsPiece::mousePressEvent(QGraphicsSceneMouseEvent *event) return; } + setSelected(true); + setCursor(Qt::ClosedHandCursor); } @@ -155,4 +170,38 @@ void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::on_PieceSelectionChanged() +{ + setSelected(m_piece->GetIsSelected()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleGraphicsPiece::on_PiecePositionChanged() +{ + setPos(m_piece->GetPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +QVariant VPuzzleGraphicsPiece::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (scene()) { + 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 index 89d55b9ef..ef585d9cb 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.h +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -31,15 +31,27 @@ #include -#include "vpuzzlepiece.h" +class VPuzzlePiece; -class VPuzzleGraphicsPiece : public QGraphicsItem +class VPuzzleGraphicsPiece : public QGraphicsObject { + Q_OBJECT public: VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *parent = nullptr); ~VPuzzleGraphicsPiece(); void Init(); +public slots: + /** + * @brief on_PieceSelectionChanged When the piece selection was changed + */ + void on_PieceSelectionChanged(); + + /** + * @brief on_PiecePositionChanged When the piece position was changed + */ + void on_PiecePositionChanged(); + protected: QRectF boundingRect() const override; QPainterPath shape() const override; @@ -48,6 +60,7 @@ protected: void mousePressEvent(QGraphicsSceneMouseEvent * event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; private: Q_DISABLE_COPY(VPuzzleGraphicsPiece) @@ -55,7 +68,6 @@ private: QPainterPath m_cuttingLine; QPainterPath m_seamLine; - }; #endif // VPUZZLEGRAPHICSPIECE_H diff --git a/src/app/puzzle/vpuzzlelayout.cpp b/src/app/puzzle/vpuzzlelayout.cpp index 61290add7..49d75a662 100644 --- a/src/app/puzzle/vpuzzlelayout.cpp +++ b/src/app/puzzle/vpuzzlelayout.cpp @@ -75,6 +75,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) { diff --git a/src/app/puzzle/vpuzzlelayout.h b/src/app/puzzle/vpuzzlelayout.h index 436957475..e404f3025 100644 --- a/src/app/puzzle/vpuzzlelayout.h +++ b/src/app/puzzle/vpuzzlelayout.h @@ -35,6 +35,7 @@ #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}; @@ -51,7 +52,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 +149,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; /** diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.cpp b/src/app/puzzle/vpuzzlemaingraphicsview.cpp index bdadeb2c8..9d1a8238f 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.cpp +++ b/src/app/puzzle/vpuzzlemaingraphicsview.cpp @@ -40,7 +40,8 @@ Q_LOGGING_CATEGORY(pMainGraphicsView, "p.mainGraphicsView") //--------------------------------------------------------------------------------------------------------------------- VPuzzleMainGraphicsView::VPuzzleMainGraphicsView(VPuzzleLayout *layout, QWidget *parent) : - QGraphicsView(parent) + QGraphicsView(parent), + m_graphicsPieces(QList()) { m_scene = new VPuzzleMainGraphicsScene(this); setScene(m_scene); @@ -123,9 +124,22 @@ void VPuzzleMainGraphicsView::dropEvent(QDropEvent *event) QPointF scenePos = mapToScene(point); // todo take the position into account - VPuzzleGraphicsPiece *item = new VPuzzleGraphicsPiece(piece); - item->setPos(scenePos); - m_scene->addItem(item); + AddPiece(piece, scenePos); + } } } + + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleMainGraphicsView::AddPiece(VPuzzlePiece *piece, QPointF pos) +{ + VPuzzleGraphicsPiece *item = new VPuzzleGraphicsPiece(piece); + m_scene->addItem(item); + item->setSelected(true); + item->setPos(pos); + + item->blockSignals(true); + piece->SetPosition(pos); + item->blockSignals(false); +} diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.h b/src/app/puzzle/vpuzzlemaingraphicsview.h index 9f6fd4aa9..4bf74cb15 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.h +++ b/src/app/puzzle/vpuzzlemaingraphicsview.h @@ -50,6 +50,8 @@ public: */ void RefreshLayout(); + void AddPiece(VPuzzlePiece *piece, QPointF pos); + protected: void dragEnterEvent(QDragEnterEvent *event) override; void dragMoveEvent(QDragMoveEvent *event) override; @@ -60,8 +62,11 @@ protected: private: Q_DISABLE_COPY(VPuzzleMainGraphicsView) - VPuzzleGraphicsLayout *m_graphicsLayout{nullptr}; VPuzzleMainGraphicsScene *m_scene{nullptr}; + + VPuzzleGraphicsLayout *m_graphicsLayout{nullptr}; + QList m_graphicsPieces; + }; #endif // VPUZZLEMAINGRAPHICVIEW_H diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index b01f9b59b..66b3d377a 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -101,6 +101,8 @@ bool VPuzzlePiece::GetShowSeamLine() void VPuzzlePiece::SetShowSeamLine(bool value) { m_showSeamline = value; + + emit PropertiesChanged(); } //--------------------------------------------------------------------------------------------------------------------- @@ -113,5 +115,53 @@ bool VPuzzlePiece::GetPieceMirrored() 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) +{ + Q_UNUSED(angle); + //TODO + + emit RotationChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +qreal VPuzzlePiece::GetRotation() +{ + // TODO + return 0; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzlePiece::SetIsSelected(bool value) +{ + m_isSelected = value; + + emit SelectionChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VPuzzlePiece::GetIsSelected() +{ + return m_isSelected; +} + + + diff --git a/src/app/puzzle/vpuzzlepiece.h b/src/app/puzzle/vpuzzlepiece.h index 735707e1c..4f5b37b11 100644 --- a/src/app/puzzle/vpuzzlepiece.h +++ b/src/app/puzzle/vpuzzlepiece.h @@ -31,9 +31,11 @@ #include #include #include +#include -class VPuzzlePiece +class VPuzzlePiece : public QObject { + Q_OBJECT public: VPuzzlePiece(); ~VPuzzlePiece(); @@ -109,14 +111,84 @@ 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 + */ + void SetRotation(qreal angle); + + /** + * @brief GetRotation Returns the angle of rotation + * @return the angle of rotation + */ + qreal GetRotation(); + + /** + * @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 + * @return true if the piece is selected + */ + bool GetIsSelected(); + + +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(); + + /** + * @brief LayerChanged emited when the piece's layer was changed. + */ + void LayerChanged(); private: QUuid m_uuid{QUuid()}; QString m_name{QString()}; QVector m_cuttingLine{QVector()}; QVector m_seamLine{QVector()}; + + QTransform m_transform{QTransform()}; + bool m_showSeamline{true}; bool m_mirrorPiece{false}; + bool m_isSelected{false}; }; #endif // VPUZZLEPIECE_H From d72be9029f169788eb80e8d301834653a7a140a1 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Wed, 6 May 2020 15:05:01 +0200 Subject: [PATCH 04/10] improve multiple selection and add grainline to pieces --- src/app/puzzle/puzzlemainwindow.cpp | 36 ++++++---- src/app/puzzle/puzzlemainwindow.ui | 82 +++++++++++++++------- src/app/puzzle/vpiececarrousel.cpp | 6 ++ src/app/puzzle/vpiececarrousel.h | 5 +- src/app/puzzle/vpiececarrousellayer.cpp | 14 +++- src/app/puzzle/vpiececarrousellayer.h | 7 +- src/app/puzzle/vpiececarrouselpiece.cpp | 22 ++++-- src/app/puzzle/vpiececarrouselpiece.h | 7 +- src/app/puzzle/vpuzzlegraphicspiece.cpp | 60 +++++++++++----- src/app/puzzle/vpuzzlegraphicspiece.h | 1 + src/app/puzzle/vpuzzlelayout.cpp | 9 +++ src/app/puzzle/vpuzzlelayout.h | 6 ++ src/app/puzzle/vpuzzlemaingraphicsview.cpp | 3 + src/app/puzzle/vpuzzlepiece.cpp | 41 ++++++++++- src/app/puzzle/vpuzzlepiece.h | 40 +++++++++++ 15 files changed, 266 insertions(+), 73 deletions(-) diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp index 7c2571619..ef3e8d775 100644 --- a/src/app/puzzle/puzzlemainwindow.cpp +++ b/src/app/puzzle/puzzlemainwindow.cpp @@ -184,9 +184,17 @@ 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! // @@ -339,16 +347,20 @@ void PuzzleMainWindow::SetPropertyTabCurrentPieceData() { if(m_selectedPieces.count() == 0) { - // TODO : update current piece data to show a "no current piece selected" + // show the content "no piece selected" + ui->containerCurrentPieceNoData->setVisible(true); ui->containerCurrentPieceData->setVisible(false); + ui->containerCurrentPieceMultipleData->setVisible(false); } else if(m_selectedPieces.count() == 1) { - VPuzzlePiece *selectedPiece = m_selectedPieces.first(); - + // 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()); @@ -364,7 +376,13 @@ void PuzzleMainWindow::SetPropertyTabCurrentPieceData() } else { - // TODO in the future + // show the content "multiple pieces selected" + + ui->containerCurrentPieceNoData->setVisible(false); + ui->containerCurrentPieceData->setVisible(false); + ui->containerCurrentPieceMultipleData->setVisible(true); + + // if needed in the future, we can show some properties that coul be edited for all the pieces } } @@ -864,16 +882,6 @@ void PuzzleMainWindow::on_PieceCarrouselLocationChanged(Qt::DockWidgetArea area) //--------------------------------------------------------------------------------------------------------------------- void PuzzleMainWindow::on_PieceSelectionChanged() { - // for now we have only single selection - // FIXME / TODO : To be updated when we support multiple selection. - - for (auto piece : m_selectedPieces) - { - if(piece->GetIsSelected()) - { - piece->SetIsSelected(false); - } - } m_selectedPieces = m_layout->GetSelectedPieces(); // update the property of the piece currently selected diff --git a/src/app/puzzle/puzzlemainwindow.ui b/src/app/puzzle/puzzlemainwindow.ui index 22e8d7fbc..7d6205696 100644 --- a/src/app/puzzle/puzzlemainwindow.ui +++ b/src/app/puzzle/puzzlemainwindow.ui @@ -228,9 +228,9 @@ 0 - 0 + -542 342 - 894 + 1302 @@ -250,31 +250,6 @@ - - - - - 0 - - - - - - 0 - 400 - - - - No piece selected - - - Qt::AlignCenter - - - - - - @@ -380,6 +355,9 @@ + + -10000.000000000000000 + 10000.000000000000000 @@ -397,6 +375,9 @@ + + -10000.000000000000000 + 10000.000000000000000 @@ -411,6 +392,53 @@ + + + + + 0 + + + + + + 0 + 400 + + + + No piece selected + + + Qt::AlignCenter + + + + + + + + + + + + + + 0 + 400 + + + + Multiple pieces selected + + + Qt::AlignCenter + + + + + + diff --git a/src/app/puzzle/vpiececarrousel.cpp b/src/app/puzzle/vpiececarrousel.cpp index 224bea4ec..991c51100 100644 --- a/src/app/puzzle/vpiececarrousel.cpp +++ b/src/app/puzzle/vpiececarrousel.cpp @@ -221,3 +221,9 @@ void VPieceCarrousel::RefreshOrientation() // FIXME: find a nicer way than putting directly the 120 width of the piece } } + +//--------------------------------------------------------------------------------------------------------------------- +void VPieceCarrousel::ClearSelection() +{ + m_layout->ClearSelection(); +} diff --git a/src/app/puzzle/vpiececarrousel.h b/src/app/puzzle/vpiececarrousel.h index 294db69ba..1459a24a2 100644 --- a/src/app/puzzle/vpiececarrousel.h +++ b/src/app/puzzle/vpiececarrousel.h @@ -72,10 +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); + void ClearSelection(); private: diff --git a/src/app/puzzle/vpiececarrousellayer.cpp b/src/app/puzzle/vpiececarrousellayer.cpp index 36b3b4e0d..d7435af52 100644 --- a/src/app/puzzle/vpiececarrousellayer.cpp +++ b/src/app/puzzle/vpiececarrousellayer.cpp @@ -27,6 +27,8 @@ *************************************************************************/ #include "vpiececarrousellayer.h" +#include "vpiececarrousel.h" + #include @@ -35,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(); @@ -80,7 +82,7 @@ void VPieceCarrouselLayer::Refresh() { // 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); @@ -98,3 +100,9 @@ QList VPieceCarrouselLayer::GetCarrouselPieces() return m_carrouselPieces; } +//--------------------------------------------------------------------------------------------------------------------- +VPieceCarrousel* VPieceCarrouselLayer::GetCarrousel() +{ + return m_carrousel; +} + diff --git a/src/app/puzzle/vpiececarrousellayer.h b/src/app/puzzle/vpiececarrousellayer.h index 08d46a093..07f59eb2d 100644 --- a/src/app/puzzle/vpiececarrousellayer.h +++ b/src/app/puzzle/vpiececarrousellayer.h @@ -33,11 +33,13 @@ #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(); @@ -45,10 +47,13 @@ public: QList GetCarrouselPieces(); + VPieceCarrousel* GetCarrousel(); + private: Q_DISABLE_COPY(VPieceCarrouselLayer) VPuzzleLayer *m_layer; + VPieceCarrousel *m_carrousel; QList m_carrouselPieces; private slots: diff --git a/src/app/puzzle/vpiececarrouselpiece.cpp b/src/app/puzzle/vpiececarrouselpiece.cpp index 27299cdd3..5ce09a63e 100644 --- a/src/app/puzzle/vpiececarrouselpiece.cpp +++ b/src/app/puzzle/vpiececarrouselpiece.cpp @@ -37,6 +37,8 @@ #include #include "vpuzzlemimedatapiece.h" +#include "vpiececarrousellayer.h" +#include "vpiececarrousel.h" #include @@ -44,9 +46,10 @@ 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(); } @@ -169,10 +172,16 @@ void VPieceCarrouselPiece::mousePressEvent(QMouseEvent *event) if (event->button() == Qt::LeftButton) { - if(!m_piece->GetIsSelected()) + if(!(event->modifiers() & Qt::ControlModifier)) { + m_carrouselLayer->GetCarrousel()->ClearSelection(); m_piece->SetIsSelected(true); } + else + { + m_piece->SetIsSelected(!m_piece->GetIsSelected()); + } + m_dragStart = event->pos(); } } @@ -190,6 +199,11 @@ void VPieceCarrouselPiece::mouseMoveEvent(QMouseEvent *event) 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); diff --git a/src/app/puzzle/vpiececarrouselpiece.h b/src/app/puzzle/vpiececarrouselpiece.h index 72d75e639..ecbf24095 100644 --- a/src/app/puzzle/vpiececarrouselpiece.h +++ b/src/app/puzzle/vpiececarrouselpiece.h @@ -37,11 +37,13 @@ #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(); @@ -70,6 +72,9 @@ private: Q_DISABLE_COPY(VPieceCarrouselPiece) VPuzzlePiece *m_piece; + + VPieceCarrouselLayer *m_carrouselLayer; + QLabel *m_label{nullptr}; VPieceCarrouselPiecePreview *m_piecePreview{nullptr}; diff --git a/src/app/puzzle/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp index 70b5d9156..6a9060214 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.cpp +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -45,7 +45,8 @@ VPuzzleGraphicsPiece::VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *p QGraphicsObject(parent), m_piece(piece), m_cuttingLine(QPainterPath()), - m_seamLine(QPainterPath()) + m_seamLine(QPainterPath()), + m_grainline(QPainterPath()) { Init(); } @@ -63,9 +64,6 @@ void VPuzzleGraphicsPiece::Init() setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges); setCursor(QCursor(Qt::OpenHandCursor)); - //setAcceptHoverEvents(true); // maybe we can do some stuff with this - - // initialises the seam line QVector seamLinePoints = m_piece->GetSeamLine(); m_seamLine.moveTo(seamLinePoints.first()); @@ -78,8 +76,14 @@ void VPuzzleGraphicsPiece::Init() 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 like grain line, labels, passmarks etc. + + // TODO : initialises the other elements labels, passmarks etc. // Initialises the connectors connect(m_piece, &VPuzzlePiece::SelectionChanged, this, &VPuzzleGraphicsPiece::on_PieceSelectionChanged); @@ -126,47 +130,69 @@ void VPuzzleGraphicsPiece::paint(QPainter *painter, const QStyleOptionGraphicsIt painter->setPen(pen); painter->setBrush(noBrush); + // paint the cutting line if(!m_cuttingLine.isEmpty()) { painter->drawPath(m_cuttingLine); } + // paint the seam line if(!m_seamLine.isEmpty()) { painter->drawPath(m_seamLine); } + + // 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->buttons() & Qt::LeftButton)) + if (event->button() == Qt::LeftButton) { - return; + setSelected(true); + setCursor(Qt::ClosedHandCursor); + + if (event->modifiers() & Qt::ControlModifier) + { + setSelected(!selectionState); + } + else + { + setSelected(true); + } } - - setSelected(true); - - setCursor(Qt::ClosedHandCursor); } //--------------------------------------------------------------------------------------------------------------------- void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + bool selectionState = isSelected(); + //perform the default behaviour QGraphicsItem::mouseReleaseEvent(event); - // change the cursor when clicking left button - if (!(event->buttons() & Qt::LeftButton)) - { - return; - } + qCDebug(pGraphicsPiece, "piiiiieeece --- mouse release"); - setCursor(Qt::OpenHandCursor); + // change the cursor when clicking left button + + if (event->button() == Qt::LeftButton) + { + setCursor(Qt::OpenHandCursor); + + qCDebug(pGraphicsPiece, "piiiiieeece --- left button"); + + setSelected(selectionState); + } } diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h index ef585d9cb..dd467acfa 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.h +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -68,6 +68,7 @@ private: QPainterPath m_cuttingLine; QPainterPath m_seamLine; + QPainterPath m_grainline; }; #endif // VPUZZLEGRAPHICSPIECE_H diff --git a/src/app/puzzle/vpuzzlelayout.cpp b/src/app/puzzle/vpuzzlelayout.cpp index 49d75a662..51ed0e5ce 100644 --- a/src/app/puzzle/vpuzzlelayout.cpp +++ b/src/app/puzzle/vpuzzlelayout.cpp @@ -268,3 +268,12 @@ bool VPuzzleLayout::GetStickyEdges() const { return m_stickyEdges; } + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleLayout::ClearSelection() +{ + for(auto piece : GetSelectedPieces()) + { + piece->SetIsSelected(false); + } +} diff --git a/src/app/puzzle/vpuzzlelayout.h b/src/app/puzzle/vpuzzlelayout.h index e404f3025..a057b7c62 100644 --- a/src/app/puzzle/vpuzzlelayout.h +++ b/src/app/puzzle/vpuzzlelayout.h @@ -194,6 +194,12 @@ 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(); + private: Q_DISABLE_COPY(VPuzzleLayout) VPuzzleLayer *m_unplacedPiecesLayer; diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.cpp b/src/app/puzzle/vpuzzlemaingraphicsview.cpp index 9d1a8238f..bf620cb9f 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.cpp +++ b/src/app/puzzle/vpuzzlemaingraphicsview.cpp @@ -142,4 +142,7 @@ void VPuzzleMainGraphicsView::AddPiece(VPuzzlePiece *piece, QPointF pos) item->blockSignals(true); piece->SetPosition(pos); item->blockSignals(false); + + + } diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index 66b3d377a..93058c960 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -152,9 +152,11 @@ qreal VPuzzlePiece::GetRotation() //--------------------------------------------------------------------------------------------------------------------- void VPuzzlePiece::SetIsSelected(bool value) { - m_isSelected = value; - - emit SelectionChanged(); + if(m_isSelected != value) + { + m_isSelected = value; + emit SelectionChanged(); + } } //--------------------------------------------------------------------------------------------------------------------- @@ -163,5 +165,38 @@ 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; +} diff --git a/src/app/puzzle/vpuzzlepiece.h b/src/app/puzzle/vpuzzlepiece.h index 4f5b37b11..00e9925b6 100644 --- a/src/app/puzzle/vpuzzlepiece.h +++ b/src/app/puzzle/vpuzzlepiece.h @@ -147,6 +147,42 @@ public: */ bool GetIsSelected(); + /** + * @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(); + signals: /** @@ -184,6 +220,10 @@ private: QVector m_cuttingLine{QVector()}; QVector m_seamLine{QVector()}; + QVector m_grainline{QVector()}; + bool m_isGrainlineEnabled{false}; + qreal m_grainlineAngle{0}; + QTransform m_transform{QTransform()}; bool m_showSeamline{true}; From 6c35dfc78a94ef27f12e6743fda37c688de35c3c Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Fri, 8 May 2020 23:49:41 +0200 Subject: [PATCH 05/10] Work on layer and graphics view behaviour --- src/app/puzzle/vpiececarrousel.cpp | 4 +- src/app/puzzle/vpiececarrousel.h | 6 +- src/app/puzzle/vpiececarrousellayer.cpp | 69 ++++++++++++++++---- src/app/puzzle/vpiececarrousellayer.h | 21 +++++++ src/app/puzzle/vpiececarrouselpiece.cpp | 12 +++- src/app/puzzle/vpuzzlegraphicslayout.cpp | 5 +- src/app/puzzle/vpuzzlegraphicspiece.cpp | 24 +++++-- src/app/puzzle/vpuzzlegraphicspiece.h | 6 ++ src/app/puzzle/vpuzzlelayer.cpp | 23 ++++++- src/app/puzzle/vpuzzlelayer.h | 28 ++++++++- src/app/puzzle/vpuzzlelayout.cpp | 43 ++++++++++++- src/app/puzzle/vpuzzlelayout.h | 35 ++++++++++- src/app/puzzle/vpuzzlemaingraphicsscene.cpp | 1 - src/app/puzzle/vpuzzlemaingraphicsscene.h | 1 + src/app/puzzle/vpuzzlemaingraphicsview.cpp | 70 ++++++++++++++++----- src/app/puzzle/vpuzzlemaingraphicsview.h | 14 ++++- src/app/puzzle/vpuzzlepiece.cpp | 21 +++++++ src/app/puzzle/vpuzzlepiece.h | 46 +++++++++----- 18 files changed, 363 insertions(+), 66 deletions(-) diff --git a/src/app/puzzle/vpiececarrousel.cpp b/src/app/puzzle/vpiececarrousel.cpp index 991c51100..65e46a410 100644 --- a/src/app/puzzle/vpiececarrousel.cpp +++ b/src/app/puzzle/vpiececarrousel.cpp @@ -93,8 +93,8 @@ void VPieceCarrousel::Init() mainLayout->addWidget(m_scrollArea); // ------ then we fill the carrousel with the layout content - Refresh(); -} + Refresh(); + } //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrousel::Refresh() diff --git a/src/app/puzzle/vpiececarrousel.h b/src/app/puzzle/vpiececarrousel.h index 1459a24a2..a781b8ac2 100644 --- a/src/app/puzzle/vpiececarrousel.h +++ b/src/app/puzzle/vpiececarrousel.h @@ -76,7 +76,6 @@ public: */ void ClearSelection(); - private: Q_DISABLE_COPY(VPieceCarrousel) @@ -92,6 +91,11 @@ private: 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 d7435af52..03cdaab45 100644 --- a/src/app/puzzle/vpiececarrousellayer.cpp +++ b/src/app/puzzle/vpiececarrousellayer.cpp @@ -48,7 +48,7 @@ VPieceCarrouselLayer::VPieceCarrouselLayer(VPuzzleLayer *layer, VPieceCarrousel //--------------------------------------------------------------------------------------------------------------------- VPieceCarrouselLayer::~VPieceCarrouselLayer() { - // TODO + Clear(); } //--------------------------------------------------------------------------------------------------------------------- @@ -61,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(); @@ -78,20 +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, 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); + 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; + } + } + } //--------------------------------------------------------------------------------------------------------------------- @@ -106,3 +122,34 @@ VPieceCarrousel* VPieceCarrouselLayer::GetCarrousel() 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 07f59eb2d..4c65455ae 100644 --- a/src/app/puzzle/vpiececarrousellayer.h +++ b/src/app/puzzle/vpiececarrousellayer.h @@ -45,10 +45,21 @@ public: void Init(); void Refresh(); + /** + * @brief Clear it clears the carrousel layer from its pieces + */ + void Clear(); + QList GetCarrouselPieces(); VPieceCarrousel* GetCarrousel(); + /** + * @brief GetPuzzleLayer Returns the corresponding VPuzzleLayer + * @return the VPuzzleLayer + */ + VPuzzleLayer* GetLayer(); + private: Q_DISABLE_COPY(VPieceCarrouselLayer) @@ -58,6 +69,16 @@ private: 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 5ce09a63e..722b5752c 100644 --- a/src/app/puzzle/vpiececarrouselpiece.cpp +++ b/src/app/puzzle/vpiececarrouselpiece.cpp @@ -99,7 +99,6 @@ void VPieceCarrouselPiece::Init() // connect the signals connect(m_piece, &VPuzzlePiece::SelectionChanged, this, &VPieceCarrouselPiece::on_PieceSelectionChanged); - // then refresh the data Refresh(); } @@ -141,6 +140,9 @@ void VPieceCarrouselPiece::Refresh() // set the tooltip setToolTip(m_piece->GetName()); + + // set the selection state correctly. + on_PieceSelectionChanged(); } //--------------------------------------------------------------------------------------------------------------------- @@ -162,8 +164,6 @@ void VPieceCarrouselPiece::on_PieceSelectionChanged() } } - - //--------------------------------------------------------------------------------------------------------------------- void VPieceCarrouselPiece::mousePressEvent(QMouseEvent *event) { @@ -194,6 +194,12 @@ void VPieceCarrouselPiece::mouseMoveEvent(QMouseEvent *event) { return; } + + if(m_piece->GetLayer() != m_piece->GetLayer()->GetLayout()->GetUnplacedPiecesLayer()) + { + return; + } + if((event->pos() - m_dragStart).manhattanLength() < QApplication::startDragDistance()) { return; diff --git a/src/app/puzzle/vpuzzlegraphicslayout.cpp b/src/app/puzzle/vpuzzlegraphicslayout.cpp index 51a4b65dd..00185b9b5 100644 --- a/src/app/puzzle/vpuzzlegraphicslayout.cpp +++ b/src/app/puzzle/vpuzzlegraphicslayout.cpp @@ -31,9 +31,10 @@ //--------------------------------------------------------------------------------------------------------------------- VPuzzleGraphicsLayout::VPuzzleGraphicsLayout(VPuzzleLayout *layout, QGraphicsItem *parent): QGraphicsItem(parent), - m_layout(layout) + m_layout(layout), + m_boundingRect(GetLayoutRect()) { - m_boundingRect = GetLayoutRect(); + } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp index 6a9060214..26b90e42f 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.cpp +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -90,6 +90,11 @@ void VPuzzleGraphicsPiece::Init() connect(m_piece, &VPuzzlePiece::PositionChanged, this, &VPuzzleGraphicsPiece::on_PiecePositionChanged); } +//--------------------------------------------------------------------------------------------------------------------- +VPuzzlePiece* VPuzzleGraphicsPiece::GetPiece() +{ + return m_piece; +} //--------------------------------------------------------------------------------------------------------------------- QRectF VPuzzleGraphicsPiece::boundingRect() const @@ -120,20 +125,25 @@ void VPuzzleGraphicsPiece::paint(QPainter *painter, const QStyleOptionGraphicsIt Q_UNUSED(option); QPen pen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); - if(isSelected()) - { - pen.setColor(Qt::red); - } - QBrush noBrush(Qt::NoBrush); + QBrush selectionBrush(QColor(255,160,160,60)); painter->setPen(pen); - painter->setBrush(noBrush); + + 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 @@ -142,6 +152,8 @@ void VPuzzleGraphicsPiece::paint(QPainter *painter, const QStyleOptionGraphicsIt painter->drawPath(m_seamLine); } + painter->setBrush(noBrush); + // paint the grainline if(!m_grainline.isEmpty()) { diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h index dd467acfa..a7aebe10b 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.h +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -41,6 +41,12 @@ public: ~VPuzzleGraphicsPiece(); void Init(); + /** + * @brief GetPiece Returns the piece that corresponds to the graphics piece + * @return the piece + */ + VPuzzlePiece* GetPiece(); + public slots: /** * @brief on_PieceSelectionChanged When the piece selection was changed diff --git a/src/app/puzzle/vpuzzlelayer.cpp b/src/app/puzzle/vpuzzlelayer.cpp index e70e33255..37a8cdec8 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,6 +46,12 @@ VPuzzleLayer::~VPuzzleLayer() } +//--------------------------------------------------------------------------------------------------------------------- +VPuzzleLayout* VPuzzleLayer::GetLayout() +{ + return m_layout; +} + //--------------------------------------------------------------------------------------------------------------------- QList VPuzzleLayer::GetPieces() { @@ -48,13 +61,21 @@ QList VPuzzleLayer::GetPieces() //--------------------------------------------------------------------------------------------------------------------- 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..b35e9d669 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,31 @@ 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(); + +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 51ed0e5ce..9f18a10d7 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; } @@ -277,3 +280,37 @@ void VPuzzleLayout::ClearSelection() piece->SetIsSelected(false); } } + +//--------------------------------------------------------------------------------------------------------------------- +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 a057b7c62..26ab1da3f 100644 --- a/src/app/puzzle/vpuzzlelayout.h +++ b/src/app/puzzle/vpuzzlelayout.h @@ -40,8 +40,9 @@ 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(); @@ -200,11 +201,43 @@ public: */ 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 index 37c75557e..5a4d1d17f 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsscene.cpp +++ b/src/app/puzzle/vpuzzlemaingraphicsscene.cpp @@ -28,7 +28,6 @@ #include "vpuzzlemaingraphicsscene.h" - //--------------------------------------------------------------------------------------------------------------------- VPuzzleMainGraphicsScene::VPuzzleMainGraphicsScene(QObject *parent): QGraphicsScene(parent) { diff --git a/src/app/puzzle/vpuzzlemaingraphicsscene.h b/src/app/puzzle/vpuzzlemaingraphicsscene.h index 7fae7da73..199ed0e8f 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsscene.h +++ b/src/app/puzzle/vpuzzlemaingraphicsscene.h @@ -38,6 +38,7 @@ 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 index bf620cb9f..75d68e14f 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.cpp +++ b/src/app/puzzle/vpuzzlemaingraphicsview.cpp @@ -30,8 +30,10 @@ #include #include +#include #include "vpuzzlemimedatapiece.h" +#include "vpuzzlelayer.h" #include @@ -41,6 +43,7 @@ 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); @@ -53,6 +56,9 @@ VPuzzleMainGraphicsView::VPuzzleMainGraphicsView(VPuzzleLayout *layout, QWidget setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); setAcceptDrops(true); + + // add the connections + connect(m_layout, &VPuzzleLayout::PieceMovedToLayer, this, &VPuzzleMainGraphicsView::on_PieceMovedToLayer); } //--------------------------------------------------------------------------------------------------------------------- @@ -119,30 +125,66 @@ void VPuzzleMainGraphicsView::dropEvent(QDropEvent *event) qCDebug(pMainGraphicsView(), "element dropped, %s", qUtf8Printable(piece->GetName())); event->acceptProposedAction(); - QPoint point = event->pos(); - QPointF scenePos = mapToScene(point); - // todo take the position into account - - AddPiece(piece, scenePos); + 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) + { + for(auto graphicsPiece : m_graphicsPieces) + { + VPuzzlePiece *piece = graphicsPiece->GetPiece(); + + if(piece->GetIsSelected()) + { + m_layout->MovePieceToLayer(piece, m_layout->GetUnplacedPiecesLayer()); + } + } + } +} //--------------------------------------------------------------------------------------------------------------------- -void VPuzzleMainGraphicsView::AddPiece(VPuzzlePiece *piece, QPointF pos) +void VPuzzleMainGraphicsView::on_PieceMovedToLayer(VPuzzlePiece *piece, VPuzzleLayer *layerBefore, VPuzzleLayer *layerAfter) { - VPuzzleGraphicsPiece *item = new VPuzzleGraphicsPiece(piece); - m_scene->addItem(item); - item->setSelected(true); - item->setPos(pos); - - item->blockSignals(true); - piece->SetPosition(pos); - item->blockSignals(false); + 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); + _graphicsPiece->setPos(_graphicsPiece->GetPiece()->GetPosition()); + _graphicsPiece->setSelected(_graphicsPiece->GetPiece()->GetIsSelected()); + _graphicsPiece->update(); + } } diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.h b/src/app/puzzle/vpuzzlemaingraphicsview.h index 4bf74cb15..623e47d13 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.h +++ b/src/app/puzzle/vpuzzlemaingraphicsview.h @@ -50,14 +50,22 @@ public: */ void RefreshLayout(); - void AddPiece(VPuzzlePiece *piece, QPointF pos); - 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); private: Q_DISABLE_COPY(VPuzzleMainGraphicsView) @@ -65,6 +73,8 @@ private: VPuzzleMainGraphicsScene *m_scene{nullptr}; VPuzzleGraphicsLayout *m_graphicsLayout{nullptr}; + VPuzzleLayout *m_layout{nullptr}; + QList m_graphicsPieces; }; diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index 93058c960..9b2a6908a 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -27,6 +27,12 @@ *************************************************************************/ #include "vpuzzlepiece.h" +#include "vpuzzlelayer.h" + +#include + +Q_LOGGING_CATEGORY(pPiece, "p.piece") + //--------------------------------------------------------------------------------------------------------------------- VPuzzlePiece::VPuzzlePiece() { @@ -200,3 +206,18 @@ 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 00e9925b6..f5dd3ef5f 100644 --- a/src/app/puzzle/vpuzzlepiece.h +++ b/src/app/puzzle/vpuzzlepiece.h @@ -33,6 +33,8 @@ #include #include +class VPuzzleLayer; + class VPuzzlePiece : public QObject { Q_OBJECT @@ -135,18 +137,6 @@ public: */ qreal GetRotation(); - /** - * @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 - * @return true if the piece is selected - */ - bool GetIsSelected(); - /** * @brief SetIsGrainlineEnabled Wether the piece has a grainline or not * @param value true or false @@ -184,6 +174,30 @@ public: 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 @@ -209,12 +223,8 @@ signals: */ void PropertiesChanged(); - /** - * @brief LayerChanged emited when the piece's layer was changed. - */ - void LayerChanged(); - private: + Q_DISABLE_COPY(VPuzzlePiece) QUuid m_uuid{QUuid()}; QString m_name{QString()}; QVector m_cuttingLine{QVector()}; @@ -228,7 +238,9 @@ private: bool m_showSeamline{true}; bool m_mirrorPiece{false}; + bool m_isSelected{false}; + VPuzzleLayer *m_layer{nullptr}; }; #endif // VPUZZLEPIECE_H From f516d80513f6b97fb88396c8c83c1da7cd264793 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sat, 9 May 2020 09:00:27 +0200 Subject: [PATCH 06/10] improve unselect behaviour of unplaced pieces --- src/app/puzzle/vpuzzlelayer.cpp | 10 ++++++++++ src/app/puzzle/vpuzzlelayer.h | 5 +++++ src/app/puzzle/vpuzzlelayout.cpp | 6 ++++-- src/app/puzzle/vpuzzlemaingraphicsview.cpp | 16 +++++++++++++++- src/app/puzzle/vpuzzlemaingraphicsview.h | 5 +++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/app/puzzle/vpuzzlelayer.cpp b/src/app/puzzle/vpuzzlelayer.cpp index 37a8cdec8..efe1ce0dd 100644 --- a/src/app/puzzle/vpuzzlelayer.cpp +++ b/src/app/puzzle/vpuzzlelayer.cpp @@ -58,6 +58,16 @@ QList VPuzzleLayer::GetPieces() return m_pieces; } + +//--------------------------------------------------------------------------------------------------------------------- +void VPuzzleLayer::ClearSelection() +{ + for (auto piece: m_pieces) + { + piece->SetIsSelected(false); + } +} + //--------------------------------------------------------------------------------------------------------------------- void VPuzzleLayer::AddPiece(VPuzzlePiece *piece) { diff --git a/src/app/puzzle/vpuzzlelayer.h b/src/app/puzzle/vpuzzlelayer.h index b35e9d669..435701eff 100644 --- a/src/app/puzzle/vpuzzlelayer.h +++ b/src/app/puzzle/vpuzzlelayer.h @@ -59,6 +59,11 @@ public: */ 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 diff --git a/src/app/puzzle/vpuzzlelayout.cpp b/src/app/puzzle/vpuzzlelayout.cpp index 9f18a10d7..9020f3dac 100644 --- a/src/app/puzzle/vpuzzlelayout.cpp +++ b/src/app/puzzle/vpuzzlelayout.cpp @@ -275,9 +275,11 @@ bool VPuzzleLayout::GetStickyEdges() const //--------------------------------------------------------------------------------------------------------------------- void VPuzzleLayout::ClearSelection() { - for(auto piece : GetSelectedPieces()) + m_unplacedPiecesLayer->ClearSelection(); + + for (auto layer : m_layers) { - piece->SetIsSelected(false); + layer->ClearSelection(); } } diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.cpp b/src/app/puzzle/vpuzzlemaingraphicsview.cpp index 75d68e14f..b8406469a 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.cpp +++ b/src/app/puzzle/vpuzzlemaingraphicsview.cpp @@ -59,6 +59,7 @@ VPuzzleMainGraphicsView::VPuzzleMainGraphicsView(VPuzzleLayout *layout, QWidget // add the connections connect(m_layout, &VPuzzleLayout::PieceMovedToLayer, this, &VPuzzleMainGraphicsView::on_PieceMovedToLayer); + connect(m_scene, &VPuzzleMainGraphicsScene::selectionChanged, this, &VPuzzleMainGraphicsView::on_SceneSelectionChanged); } //--------------------------------------------------------------------------------------------------------------------- @@ -143,12 +144,15 @@ void VPuzzleMainGraphicsView::keyPressEvent(QKeyEvent *event) { if(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) { - for(auto graphicsPiece : m_graphicsPieces) + 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()); } } @@ -188,3 +192,13 @@ void VPuzzleMainGraphicsView::on_PieceMovedToLayer(VPuzzlePiece *piece, VPuzzleL _graphicsPiece->update(); } } + +//--------------------------------------------------------------------------------------------------------------------- +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 index 623e47d13..fea0d7947 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.h +++ b/src/app/puzzle/vpuzzlemaingraphicsview.h @@ -67,6 +67,11 @@ private slots: */ 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) From e72a664c8a3ea475ce77f32b85eef4e19df26365 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sat, 9 May 2020 09:54:56 +0200 Subject: [PATCH 07/10] context menu for carrousel piece and graphics piece --- src/app/puzzle/vpiececarrouselpiece.cpp | 54 ++++++++++++++++++++++++ src/app/puzzle/vpiececarrouselpiece.h | 9 ++++ src/app/puzzle/vpuzzlegraphicspiece.cpp | 55 ++++++++++++++++++++++--- src/app/puzzle/vpuzzlegraphicspiece.h | 9 ++++ 4 files changed, 122 insertions(+), 5 deletions(-) diff --git a/src/app/puzzle/vpiececarrouselpiece.cpp b/src/app/puzzle/vpiececarrouselpiece.cpp index 722b5752c..3602ce054 100644 --- a/src/app/puzzle/vpiececarrouselpiece.cpp +++ b/src/app/puzzle/vpiececarrouselpiece.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "vpuzzlemimedatapiece.h" #include "vpiececarrousellayer.h" @@ -229,3 +230,56 @@ void VPieceCarrouselPiece::mouseMoveEvent(QMouseEvent *event) 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 ecbf24095..96264e0d0 100644 --- a/src/app/puzzle/vpiececarrouselpiece.h +++ b/src/app/puzzle/vpiececarrouselpiece.h @@ -68,6 +68,15 @@ protected: 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) diff --git a/src/app/puzzle/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp index 26b90e42f..6b221427f 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.cpp +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -34,8 +34,12 @@ #include #include #include +#include +#include #include "vpuzzlepiece.h" +#include "vpuzzlelayer.h" +#include "vpuzzlelayout.h" #include Q_LOGGING_CATEGORY(pGraphicsPiece, "p.graphicsPiece") @@ -193,20 +197,61 @@ void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) //perform the default behaviour QGraphicsItem::mouseReleaseEvent(event); - qCDebug(pGraphicsPiece, "piiiiieeece --- mouse release"); - // change the cursor when clicking left button - if (event->button() == Qt::LeftButton) { setCursor(Qt::OpenHandCursor); - qCDebug(pGraphicsPiece, "piiiiieeece --- left button"); - setSelected(selectionState); } } +//--------------------------------------------------------------------------------------------------------------------- +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 = (VPuzzleLayer *) v.value(); + if(layer != nullptr) + { + layer->GetLayout()->MovePieceToLayer(m_piece, layer); + } +} + //--------------------------------------------------------------------------------------------------------------------- void VPuzzleGraphicsPiece::on_PieceSelectionChanged() diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h index a7aebe10b..c11680008 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.h +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -68,6 +68,15 @@ protected: 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; From dc44bef761303be9088d572bffe6831ae04f9fcf Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sat, 9 May 2020 11:13:29 +0200 Subject: [PATCH 08/10] enable rotation --- src/app/puzzle/puzzlemainwindow.cpp | 24 +++++---------- src/app/puzzle/puzzlemainwindow.ui | 6 ++-- src/app/puzzle/vpuzzlegraphicspiece.cpp | 8 +++++ src/app/puzzle/vpuzzlegraphicspiece.h | 9 ++++-- src/app/puzzle/vpuzzlepiece.cpp | 39 ++++++++++++++++++++++--- src/app/puzzle/vpuzzlepiece.h | 4 ++- 6 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp index ef3e8d775..83375cba9 100644 --- a/src/app/puzzle/puzzlemainwindow.cpp +++ b/src/app/puzzle/puzzlemainwindow.cpp @@ -372,7 +372,8 @@ void PuzzleMainWindow::SetPropertyTabCurrentPieceData() SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionX, UnitConvertor(pos.x(), Unit::Px, m_layout->GetUnit())); SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionY, UnitConvertor(pos.y(), Unit::Px, m_layout->GetUnit())); - // TODO: rotation + qreal angle = selectedPiece->GetRotation(); + SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); } else { @@ -831,24 +832,17 @@ void PuzzleMainWindow::on_checkBoxCurrentPieceMirrorPiece_toggled(bool 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_CurrentPiecePositionEdited() { -// ui->doubleSpinBoxCurrentPieceBoxPositionX->blockSignals(true); -// ui->doubleSpinBoxCurrentPieceBoxPositionY->blockSignals(true); - if(m_selectedPieces.count() == 1) { VPuzzlePiece *piece = m_selectedPieces.first(); @@ -856,10 +850,6 @@ void PuzzleMainWindow::on_CurrentPiecePositionEdited() UnitConvertor(ui->doubleSpinBoxCurrentPieceBoxPositionY->value(), m_layout->GetUnit(), Unit::Px)); piece->SetPosition(pos); } - -// ui->doubleSpinBoxCurrentPieceBoxPositionX->blockSignals(false); -// ui->doubleSpinBoxCurrentPieceBoxPositionY->blockSignals(false); - } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/puzzlemainwindow.ui b/src/app/puzzle/puzzlemainwindow.ui index 7d6205696..79ed17157 100644 --- a/src/app/puzzle/puzzlemainwindow.ui +++ b/src/app/puzzle/puzzlemainwindow.ui @@ -228,9 +228,9 @@ 0 - -542 + 0 342 - 1302 + 1318 @@ -333,7 +333,7 @@ 360.000000000000000 - 0.100000000000000 + 1.000000000000000 diff --git a/src/app/puzzle/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp index 6b221427f..fb18783f6 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.cpp +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -92,6 +92,7 @@ void VPuzzleGraphicsPiece::Init() // 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); } //--------------------------------------------------------------------------------------------------------------------- @@ -265,6 +266,13 @@ 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) { diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h index c11680008..496f55e76 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.h +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -49,15 +49,20 @@ public: public slots: /** - * @brief on_PieceSelectionChanged When the piece selection was changed + * @brief on_PieceSelectionChanged Slot called when the piece selection was changed */ void on_PieceSelectionChanged(); /** - * @brief on_PiecePositionChanged When the piece position was changed + * @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; diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index 9b2a6908a..92a42191f 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -27,6 +27,8 @@ *************************************************************************/ #include "vpuzzlepiece.h" +#include + #include "vpuzzlelayer.h" #include @@ -142,8 +144,25 @@ QPointF VPuzzlePiece::GetPosition() //--------------------------------------------------------------------------------------------------------------------- void VPuzzlePiece::SetRotation(qreal angle) { - Q_UNUSED(angle); - //TODO + 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; + } + + +// qreal currentAngle = GetRotation(); +// qreal newAngle = angle - currentAngle; + +// m_transform.rotate(newAngle); + emit RotationChanged(); } @@ -151,8 +170,20 @@ void VPuzzlePiece::SetRotation(qreal angle) //--------------------------------------------------------------------------------------------------------------------- qreal VPuzzlePiece::GetRotation() { - // TODO - return 0; + 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; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpuzzlepiece.h b/src/app/puzzle/vpuzzlepiece.h index f5dd3ef5f..229036139 100644 --- a/src/app/puzzle/vpuzzlepiece.h +++ b/src/app/puzzle/vpuzzlepiece.h @@ -127,7 +127,7 @@ public: /** * @brief SetRotation Sets the rotation of the piece to the given angle. - * @param angle the angle of the rotation + * @param angle the angle of the rotation in degree */ void SetRotation(qreal angle); @@ -235,6 +235,8 @@ private: 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}; From a9d6fae27d3f1d46ca2dc020d34eaef539322522 Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sat, 9 May 2020 14:45:36 +0200 Subject: [PATCH 09/10] optimization angle / rotation --- src/app/puzzle/puzzlemainwindow.cpp | 13 +++ src/app/puzzle/puzzlemainwindow.h | 5 + src/app/puzzle/share/resources/puzzleicon.qrc | 1 + .../puzzleicon/64x64/cursorRotate.png | Bin 0 -> 1635 bytes .../puzzleicon/64x64/cursorRotate@2x.png | Bin 0 -> 2938 bytes .../puzzleicon/svg/cursor_rotate.svg | 67 +++++++++++++ src/app/puzzle/vpuzzlegraphicspiece.cpp | 94 ++++++++++++++++-- src/app/puzzle/vpuzzlegraphicspiece.h | 6 ++ src/app/puzzle/vpuzzlepiece.cpp | 37 +++---- 9 files changed, 197 insertions(+), 26 deletions(-) create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/64x64/cursorRotate@2x.png create mode 100644 src/app/puzzle/share/resources/puzzleicon/svg/cursor_rotate.svg diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp index 83375cba9..b76bcb9b0 100644 --- a/src/app/puzzle/puzzlemainwindow.cpp +++ b/src/app/puzzle/puzzlemainwindow.cpp @@ -200,6 +200,7 @@ VPuzzlePiece* PuzzleMainWindow::CreatePiece(const VLayoutPiece &rawPiece) // 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; @@ -892,3 +893,15 @@ void PuzzleMainWindow::on_PiecePositionChanged() 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 8d5015a4e..4ffa3f29c 100644 --- a/src/app/puzzle/puzzlemainwindow.h +++ b/src/app/puzzle/puzzlemainwindow.h @@ -373,6 +373,11 @@ private slots: */ void on_PiecePositionChanged(); + /** + * @brief on_PieceRotationChanged When the current piece rotation has changed + */ + void on_PieceRotationChanged(); + }; #endif // PUZZLEMAINWINDOW_H 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 0000000000000000000000000000000000000000..a9ade2aee24b7949c0e842cd8722883b286671cd GIT binary patch literal 1635 zcmV-p2AuhcP)i|UK~#90)!S)|B~=x`@!#|`bTgWkWf&Y3!sZM{*+dYXPK*nX zu!SWi1Tg9+!+e0SM-u&@F(w2P{Xh_jf*KQzCaj5)Kv)wN*&-njNEjzGA_fL%rn}$k z>7IrU=RK!s>Q-01s(SDFPi{I>Q+4h+r|vy<@44r#(tkGK3>=4zI27x!fcHCpr|}A& zz;k%M^Y8y#PQcCh59Tli9~MD_jZ z>Z~B6xJ7zOEaEM(=cvp@(%zmEpRYl2xp>vS+`uU6Omo|+{$_l$bLr^!m{-hp#Yv*|BQSfjXL8H<^N0-2W${onJoI2d8t6^OyQ`a4md1veYeQ<4?8a>uCFQT zfQiKQIkC$ccDBlnVdJCt1wOOvKX!^J+2zv-!3+32z9m+J-7IhSM5iSjG~cV{4Kq$G zVS7Eim>15PTGDokmDU2@5t-sa^CK|=vX=0OQLs{et!$gYrA=E_kQ-$uaQ+v-$M7%p z9b+wuz?1rN^qbT&{;8!mO-iqu%eJ-}b8t1VUACToU4G-QRG$iM{IN-EO0u8qbIKO3 zTYmEz{9CoDFpKpK8dR2xMPSZ~Q730T@HM?pg=vwP9479T{X$!EQunt>XIJwA->Z2- z2f#Y%m-%4cgA-zhSH=M?e6;~1s&Iqsn6?uauJrI3ijRV}NIwk|`^!(_6v_$yNiio3 zTi_#JNS5w%V&PYa{l!^(p7Ardx<Mwf{ zdWUQ$wDI-IDszmCMM)1FA}YsH=ND7>L@$C5^ii+Q;jW4bkBRb^-MF`+ti$Zt_ot@n z_p5Ypp$|vZmUNz=2$Nz1);(#i;($}d3rZQ^#^2RY6!tfJN?ot-QN{#r?I^W$h1QD$ z_7R6Nc`MgNQI%Fp&BA(N{5ILC=9M^GWQelj$vq|HtP)3CZ(6you%+gjh40|>lFzIY zHA8u8in|NQIS^OiHN^@l+c>kNuC?=Bdvc6<%HEmr?5LF1Yp`$gCgw9Pw!%9#GXi#rCGNaPZQq1V(#0C3sp~U1Axh$}?8xk; zG=4!C+ZHRlt$0=h)hEPTA9@bJ&xH|r72H|v_XE(kF%H4)%KcpK_5tYGI7f?3PLa>! zZwI7fUpNU5$p5L!Zw97aAK8SbWv>)(9iU!)=bPdbX{jTIso1(NtQNV2H$;56Ww7cD hj=gc29!uD(@&VNnLwq?<1%vwmR zFUh8|vWH}iFr{cVS)v2ds0H+#ARBs&sUblq##A~`O89_@Fw=Mi4H<~Sy};#hPJgU( z;9NNO-m}+lKYow%nOVck<@|oX?_PVKeSUlIwb#y(Ed~N3f#Jn}&jR`ttuJsY&`|dI zS5L4lz)QeCi}o^*_aog6xzGX}GZdHrTvD_lmhb;M@Kn+MT(pChpHah*w*ub+{st60 zTMMulxDFWLxSTc0=m}g8JdgiM@5qh_x;houTU@ma38#iQ+ z{=nV9e!^F-X|J#hxX8XsvOyDYJISl~O11*H(5`#Z%|u`$;VaIj<$(u*vn~25b@T-8 zCwyhOv;)9wpob-&rG^WD7YScMzU*b-GAo`-0aKAlmC%*q+w#Bypm%f^CX;T!eT1)w z(6${IAJLax61S<~X5d%Al@6cr8t@$OcVHXh=v}}*;1Ez({9Ny%4FXO_rjO?YH0?Zz^>Dt z1U`+7B3#l4ycd`c?6h2la@z)saa@)loPxc|KZ-2IyxnI3%IF4M4*U{m>p)`^+Xr0X ztu!9U0S{ouIctd5%-R6pHed&K8^IA^n#XcD_4@ z37;Uk6V?GEd<$370NjX-IBYe7`NVG|R~5sF{`UN9GhzE$* zd5D#udvyT4ab+C(xq?Rm=sm`a4n$RB z69edtGoM87%MS$5OE+M%LTmvE=BRNp-$m!o7w{Lxc8n{PVhh04zQrblMqoWUpMKW2 z*oT!ucL3dei%k%t(M20=!{h2{PxLQ;Gku9nFtgD4_Ih6eKc*B|0N&zDWP)i1wqowv z4S1RyTC5OPKw|Z4REIXA%K6r_2J|z3ce)mrBDw+pz}&}6Tniho5LL2J;oM0@GdIu% z^l>Tb4uz-!GHsdW^?nz0M;CT}UFilc;>g~uylyoTEmWg=4kNh}OqpU^NQow7gQcbi znBhuP${B)00-5;w5by@D-vf+7KZ)}fn?f?g7GSO6HQkZKnbsSCcJpEZN$gld$8QwZ zTnh1N0NasVe>HUcPI1iy+af@}%lA*+WbiV6y@Aig4}!tf|N@d1NGD!a$o1K%0&0ATlJW5gpS8V6_L(Hh>n3 z8nRBS;pdy`k-c~47ynRNmMv!=?SESi(Eebg!$>7wYWVOHZOG|ed&~Z|M|rQTV|rj! zeGWJe_$%>^#C@IPX;RA@V=J<%1yb-<;B&ygy{d~B%P`wccdWt8L?6Wy7n^5L@U-%K z%zV~Xy0C#T$E?}1O-Q6{)>)02-*%N=0uKS7!F(JU2MS2nZ~6k1Mou;S{7EaYvkCug zHnkrb7CO!B#>{umo_K>MWFukdO0Cwm0;ffASeod8x&Kz4I1g|Ti5N{naApDc0_}&7 zSw?g6*p^BYK~Is4q=WYZkB1f!BQ()in>zZB9?0?Np}Y8wYzNWS9@5C&nEUago!xLe z(Xx8Fw8})q-Zaj5!0)We`;#EYS=5=iqf_ zyU}kp$pW`y?$bQ7rCiNq#Y43g+tV*%Kri4`%ze7b#>0Q1c(AEycD!Z@Z4{T46!Lv> zdr)%lH0Lqr40I>3v|=$q)Q1%Usx|L{x3hB%qCniUo#FReanVPj#`FoK)0yQerANUXYFP0OoQ3|SLu{h%*6J_J_Ddyw$>xG)a=*$V|c z2hc262wX)xjy@mBasA5!Ybh}n*}S2x{5`-xpMnP?lQ`81+z$-%DX;O`32xh-c=*pw5k<&QwV`YP6577)+l z(piAZvH-e3e0K}cqp@2E+_RoV=X2EuaWE@Y1rw3|a9uetL<8u9o#Au=_`GNB6}f?q z1>WXa%LvRSQI>kvcPaKl?qU-_lLP+5$pW9j-zk>;f$!7)1usqwpdYXh^L+mu*$WiU z0f-Cd(*6LcHsEa@p4$Z6ivBJ7w~qBSAU&k^RPai+2N>>Hw~A>T7x_)c&&mNGM;9ht zZmv$&sz(xWY>ue!L^}e!-;w6X)FHc2)*~(772}a)S2i4Ky8-k;hP?l>q_5oaNTZ51 z!+{GN-Fq1J-kwWl<3*|)a)8!CqL1l2vuPHzCX#+gW-#p`Rh`*lrKV=!a^MHJ4Vf$1 zHNMPsaFdEl#6YU~tW!!aA=kc0-ai5S;j1@%Dh zqBSGK$-&43*O|!D_4znHfwKdSA{%xW26%QbE=Hz~eSEv(Y%RbCBlp&cF4f6lP{8ByMTMi*l)a+I%K1$%LN}_mA(MUuol-t zxnj*A^vMuHSR1k`co&ksHTH{bN%;+$j0AU{8Cpmg2aw5{4MlqnS+Lq4Qj{r4X#gOZ zE$;-rjQgq4O-MxZQRG{_7x*udB5!B$-|ZyhWR=u$9qKd<=TvOH|)5p_s zckXb$>yOlk17`z|VZR6Xp3g#rB#AvhIh&Dq_$f$6aa$BD-YeE5y#bVX2nju(hn?;_ zGYue(T!IYGqWlCT;n+MYq@@QaXBBc9)~%GCj%`ToB`_rnMbgii_5k;V5F3It_5kI) zgiOhP3OReAS~BwvkoE=uQkjc@(ZJ6QuE_*hXaFU4BDsOCK(>!}My&y)nB_=*qB(Rt zmtT7c%n0uQp6BG3z&RmB`6P=yKsjrXMlgf+%ea~O38-Px#07*qoM6N<$g0#12j{pDw literal 0 HcmV?d00001 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/vpuzzlegraphicspiece.cpp b/src/app/puzzle/vpuzzlegraphicspiece.cpp index fb18783f6..3d53423fe 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.cpp +++ b/src/app/puzzle/vpuzzlegraphicspiece.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "vpuzzlepiece.h" #include "vpuzzlelayer.h" @@ -50,7 +52,8 @@ VPuzzleGraphicsPiece::VPuzzleGraphicsPiece(VPuzzlePiece *piece, QGraphicsItem *p m_piece(piece), m_cuttingLine(QPainterPath()), m_seamLine(QPainterPath()), - m_grainline(QPainterPath()) + m_grainline(QPainterPath()), + m_rotationStartPoint(QPointF()) { Init(); } @@ -66,6 +69,7 @@ void VPuzzleGraphicsPiece::Init() { // set some infos setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges); + setAcceptHoverEvents(true); setCursor(QCursor(Qt::OpenHandCursor)); // initialises the seam line @@ -188,8 +192,50 @@ void VPuzzleGraphicsPiece::mousePressEvent(QGraphicsSceneMouseEvent *event) 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) { @@ -204,6 +250,36 @@ void VPuzzleGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 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)); } } @@ -246,7 +322,7 @@ void VPuzzleGraphicsPiece::on_ActionPieceMovedToLayer() { QAction *act = qobject_cast(sender()); QVariant v = act->data(); - VPuzzleLayer *layer = (VPuzzleLayer *) v.value(); + VPuzzleLayer *layer = v.value(); if(layer != nullptr) { layer->GetLayout()->MovePieceToLayer(m_piece, layer); @@ -277,12 +353,14 @@ void VPuzzleGraphicsPiece::on_PieceRotationChanged() QVariant VPuzzleGraphicsPiece::itemChange(GraphicsItemChange change, const QVariant &value) { if (scene()) { - if(change == ItemPositionHasChanged) - { - blockSignals(true); - m_piece->SetPosition(pos()); - blockSignals(false); - } + + // 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) { diff --git a/src/app/puzzle/vpuzzlegraphicspiece.h b/src/app/puzzle/vpuzzlegraphicspiece.h index 496f55e76..fee04892f 100644 --- a/src/app/puzzle/vpuzzlegraphicspiece.h +++ b/src/app/puzzle/vpuzzlegraphicspiece.h @@ -69,8 +69,11 @@ protected: 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; @@ -89,6 +92,9 @@ private: QPainterPath m_cuttingLine; QPainterPath m_seamLine; QPainterPath m_grainline; + + QPointF m_rotationStartPoint; + }; #endif // VPUZZLEGRAPHICSPIECE_H diff --git a/src/app/puzzle/vpuzzlepiece.cpp b/src/app/puzzle/vpuzzlepiece.cpp index 92a42191f..45e652516 100644 --- a/src/app/puzzle/vpuzzlepiece.cpp +++ b/src/app/puzzle/vpuzzlepiece.cpp @@ -144,27 +144,28 @@ QPointF VPuzzlePiece::GetPosition() //--------------------------------------------------------------------------------------------------------------------- void VPuzzlePiece::SetRotation(qreal angle) { - m_pieceAngle = angle; + // qreal currentAngle = GetRotation(); + // qreal newAngle = angle - currentAngle; - // make sure the angle is [0 <= angle < 360] - while(m_pieceAngle >= 360) + // m_transform.rotate(newAngle); + + if(m_pieceAngle != angle) { - m_pieceAngle -= 360; + 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(); } - - while(m_pieceAngle < 0) - { - m_pieceAngle += 360; - } - - -// qreal currentAngle = GetRotation(); -// qreal newAngle = angle - currentAngle; - -// m_transform.rotate(newAngle); - - - emit RotationChanged(); } //--------------------------------------------------------------------------------------------------------------------- From 0e87b10a668a60a9bf36be39cb16430743d49eaa Mon Sep 17 00:00:00 2001 From: Ronan Le Tiec Date: Sat, 9 May 2020 15:13:00 +0200 Subject: [PATCH 10/10] improvement rotation initialisation --- src/app/puzzle/vpuzzlemaingraphicsview.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/puzzle/vpuzzlemaingraphicsview.cpp b/src/app/puzzle/vpuzzlemaingraphicsview.cpp index b8406469a..d4740eeb1 100644 --- a/src/app/puzzle/vpuzzlemaingraphicsview.cpp +++ b/src/app/puzzle/vpuzzlemaingraphicsview.cpp @@ -187,9 +187,10 @@ void VPuzzleMainGraphicsView::on_PieceMovedToLayer(VPuzzlePiece *piece, VPuzzleL } scene()->addItem(_graphicsPiece); - _graphicsPiece->setPos(_graphicsPiece->GetPiece()->GetPosition()); - _graphicsPiece->setSelected(_graphicsPiece->GetPiece()->GetIsSelected()); - _graphicsPiece->update(); + // not very clean to directly call slots + _graphicsPiece->on_PieceSelectionChanged(); + _graphicsPiece->on_PiecePositionChanged(); + _graphicsPiece->on_PieceRotationChanged(); } }