From a35e46f8457c4a0ff2d6482f146a97930d678a37 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Wed, 18 Aug 2021 20:33:47 +0300 Subject: [PATCH] Undo/Redo piece rotate. --- src/app/puzzle/carousel/vpcarrousel.cpp | 71 +++-- src/app/puzzle/carousel/vpcarrousel.h | 16 +- src/app/puzzle/carousel/vpcarrouselpiece.cpp | 20 +- src/app/puzzle/carousel/vpcarrouselpiece.h | 8 +- .../puzzle/carousel/vpcarrouselpiecelist.cpp | 29 +- .../puzzle/carousel/vpcarrouselpiecelist.h | 4 +- src/app/puzzle/layout/layoutdef.h | 45 +++ src/app/puzzle/layout/vplayout.cpp | 163 +++++++---- src/app/puzzle/layout/vplayout.h | 60 ++-- src/app/puzzle/puzzle.pri | 7 + src/app/puzzle/scene/vpgraphicspiece.cpp | 150 ++++++---- src/app/puzzle/scene/vpgraphicspiece.h | 18 +- .../puzzle/scene/vpgraphicspiececontrols.cpp | 223 ++++++++++----- .../puzzle/scene/vpgraphicspiececontrols.h | 32 ++- src/app/puzzle/scene/vpgraphicssheet.cpp | 48 ++-- src/app/puzzle/scene/vpgraphicssheet.h | 12 +- src/app/puzzle/scene/vpgraphicstilegrid.cpp | 8 +- src/app/puzzle/scene/vpgraphicstilegrid.h | 7 +- src/app/puzzle/scene/vpmaingraphicsview.cpp | 153 +++++----- src/app/puzzle/scene/vpmaingraphicsview.h | 8 +- src/app/puzzle/undocommands/vpundocommand.h | 4 +- .../puzzle/undocommands/vpundopiecerotate.cpp | 266 ++++++++++++++++++ .../puzzle/undocommands/vpundopiecerotate.h | 142 ++++++++++ src/app/puzzle/xml/vplayoutfilereader.cpp | 48 ++-- src/libs/vlayout/vabstractpiece.cpp | 6 + src/libs/vlayout/vabstractpiece.h | 6 + 26 files changed, 1152 insertions(+), 402 deletions(-) create mode 100644 src/app/puzzle/layout/layoutdef.h create mode 100644 src/app/puzzle/undocommands/vpundopiecerotate.cpp create mode 100644 src/app/puzzle/undocommands/vpundopiecerotate.h diff --git a/src/app/puzzle/carousel/vpcarrousel.cpp b/src/app/puzzle/carousel/vpcarrousel.cpp index f2c7ab691..96774bfe4 100644 --- a/src/app/puzzle/carousel/vpcarrousel.cpp +++ b/src/app/puzzle/carousel/vpcarrousel.cpp @@ -34,6 +34,7 @@ #include "../vmisc/backport/qoverload.h" #include "../layout/vpsheet.h" +#include "../layout/vplayout.h" #include #include @@ -42,12 +43,12 @@ Q_LOGGING_CATEGORY(pCarrousel, "p.carrousel") //--------------------------------------------------------------------------------------------------------------------- -VPCarrousel::VPCarrousel(VPLayout *layout, QWidget *parent) : +VPCarrousel::VPCarrousel(const VPLayoutPtr &layout, QWidget *parent) : QWidget(parent), ui(new Ui::VPCarrousel), m_layout(layout) { - SCASSERT(m_layout != nullptr) + SCASSERT(not layout.isNull()) ui->setupUi(this); ui->listWidget->SetCarrousel(this); @@ -55,6 +56,8 @@ VPCarrousel::VPCarrousel(VPLayout *layout, QWidget *parent) : connect(ui->comboBoxPieceList, QOverload::of(&QComboBox::currentIndexChanged), this, &VPCarrousel::on_ActivePieceListChanged); + connect(layout.get(), &VPLayout::ActiveSheetChanged, this, &VPCarrousel::on_ActiveSheetChanged); + // ------ then we fill the carrousel with the layout content Refresh(); } @@ -73,26 +76,27 @@ void VPCarrousel::Refresh() // Do not rely on m_layout because we do not control it. m_pieceLists = QList(); - if (m_layout != nullptr) + VPLayoutPtr layout = m_layout.toStrongRef(); + if (not layout.isNull()) { { VPCarrouselSheet carrouselSheet; carrouselSheet.unplaced = true; carrouselSheet.active = false; carrouselSheet.name = tr("Unplaced pieces"); - carrouselSheet.pieces = m_layout->GetUnplacedPieces(); + carrouselSheet.pieces = layout->GetUnplacedPieces(); m_pieceLists.append(carrouselSheet); } - QList sheets = m_layout->GetSheets(); - for (auto *sheet : sheets) + QList sheets = layout->GetSheets(); + for (const auto &sheet : sheets) { - if (sheet->IsVisible()) + if (not sheet.isNull() && sheet->IsVisible()) { VPCarrouselSheet carrouselSheet; carrouselSheet.unplaced = false; - carrouselSheet.active = (sheet == m_layout->GetFocusedSheet()); + carrouselSheet.active = (sheet == layout->GetFocusedSheet()); carrouselSheet.name = sheet->GetName(); carrouselSheet.pieces = sheet->GetPieces(); carrouselSheet.sheetUuid = sheet->Uuid(); @@ -121,18 +125,41 @@ void VPCarrousel::Refresh() RefreshOrientation(); } +//--------------------------------------------------------------------------------------------------------------------- +void VPCarrousel::on_ActiveSheetChanged(const VPSheetPtr &sheet) +{ + if (not sheet.isNull()) + { + int index = ui->comboBoxPieceList->findData(sheet->Uuid()); + if (index != -1) + { + ui->comboBoxPieceList->setCurrentIndex(index); + } + } + else + { + ui->comboBoxPieceList->setCurrentIndex(0); + } +} + //--------------------------------------------------------------------------------------------------------------------- void VPCarrousel::RefreshSheetNames() { + VPLayoutPtr layout = m_layout.toStrongRef(); + if (layout.isNull()) + { + return; + } + for (int i=0; i < m_pieceLists.size(); ++i) { if (not m_pieceLists.at(i).unplaced) { - VPSheet *sheet = m_layout->GetSheet(m_pieceLists.at(i).sheetUuid); - if (sheet != nullptr) + VPSheetPtr sheet = layout->GetSheet(m_pieceLists.at(i).sheetUuid); + if (not sheet.isNull()) { m_pieceLists[i].name = sheet->GetName(); - m_pieceLists[i].active = (sheet == m_layout->GetFocusedSheet()); + m_pieceLists[i].active = (sheet == layout->GetFocusedSheet()); } } else @@ -158,6 +185,12 @@ void VPCarrousel::on_ActivePieceListChanged(int index) { qCDebug(pCarrousel, "index changed %i", index); + VPLayoutPtr layout = m_layout.toStrongRef(); + if (layout.isNull()) + { + return; + } + if (not m_pieceLists.isEmpty() && index >= 0 && index < m_pieceLists.size()) { ui->listWidget->SetCurrentPieceList(m_pieceLists.at(index).pieces); @@ -165,20 +198,22 @@ void VPCarrousel::on_ActivePieceListChanged(int index) if (index > 0) { QUuid sheetUuid = ui->comboBoxPieceList->currentData().toUuid(); - VPSheet *sheet = m_layout->GetSheet(sheetUuid); + VPSheetPtr sheet = layout->GetSheet(sheetUuid); - if (sheet != nullptr) + if (not sheet.isNull()) { - m_layout->SetFocusedSheet(sheet); - emit on_ActiveSheetChanged(); + m_ignoreActiveSheetChange = true; + layout->SetFocusedSheet(sheet); + m_ignoreActiveSheetChange = false; } } } else { - ui->listWidget->SetCurrentPieceList(QList()); - m_layout->SetFocusedSheet(nullptr); - emit on_ActiveSheetChanged(); + ui->listWidget->SetCurrentPieceList(QList()); + m_ignoreActiveSheetChange = true; + layout->SetFocusedSheet(VPSheetPtr()); + m_ignoreActiveSheetChange = false; } RefreshSheetNames(); diff --git a/src/app/puzzle/carousel/vpcarrousel.h b/src/app/puzzle/carousel/vpcarrousel.h index ab8b75886..c3a56b110 100644 --- a/src/app/puzzle/carousel/vpcarrousel.h +++ b/src/app/puzzle/carousel/vpcarrousel.h @@ -32,8 +32,8 @@ #include #include #include -#include "../layout/vplayout.h" #include "../layout/vppiece.h" +#include "../layout/layoutdef.h" namespace Ui { @@ -45,7 +45,7 @@ struct VPCarrouselSheet bool unplaced{true}; bool active{false}; QString name{}; - QList pieces{}; + QList pieces{}; QUuid sheetUuid{}; }; @@ -53,7 +53,7 @@ class VPCarrousel : public QWidget { Q_OBJECT public: - explicit VPCarrousel(VPLayout *layout, QWidget *parent = nullptr); + explicit VPCarrousel(const VPLayoutPtr &layout, QWidget *parent = nullptr); virtual ~VPCarrousel() = default; /** @@ -69,8 +69,6 @@ public: */ void RefreshOrientation(); - - void RefreshSheetNames(); /** @@ -78,14 +76,12 @@ public: */ void Clear(); -signals: - void on_ActiveSheetChanged(); - public slots: /** * @brief Refresh Refreshes the content of the carrousel */ void Refresh(); + void on_ActiveSheetChanged(const VPSheetPtr &sheet); protected: virtual void changeEvent(QEvent* event) override; @@ -102,12 +98,14 @@ private: Q_DISABLE_COPY(VPCarrousel) Ui::VPCarrousel *ui; - VPLayout *m_layout{nullptr}; + VPLayoutWeakPtr m_layout{}; QList m_pieceLists{}; Qt::Orientation m_orientation{Qt::Vertical}; + bool m_ignoreActiveSheetChange{false}; + static auto GetSheetName(const VPCarrouselSheet &sheet) -> QString; }; diff --git a/src/app/puzzle/carousel/vpcarrouselpiece.cpp b/src/app/puzzle/carousel/vpcarrouselpiece.cpp index 9732776f0..bd0af36ad 100644 --- a/src/app/puzzle/carousel/vpcarrouselpiece.cpp +++ b/src/app/puzzle/carousel/vpcarrouselpiece.cpp @@ -44,7 +44,7 @@ Q_LOGGING_CATEGORY(pCarrouselPiece, "p.carrouselPiece") //--------------------------------------------------------------------------------------------------------------------- -VPCarrouselPiece::VPCarrouselPiece(VPPiece *piece, QListWidget* parent) : +VPCarrouselPiece::VPCarrouselPiece(const VPPiecePtr &piece, QListWidget* parent) : QListWidgetItem(parent, Type), m_piece(piece) { @@ -57,7 +57,7 @@ VPCarrouselPiece::VPCarrouselPiece(VPPiece *piece, QListWidget* parent) : } //--------------------------------------------------------------------------------------------------------------------- -auto VPCarrouselPiece::GetPiece() -> VPPiece * +auto VPCarrouselPiece::GetPiece() const -> VPPiecePtr { return m_piece; } @@ -65,13 +65,23 @@ auto VPCarrouselPiece::GetPiece() -> VPPiece * //--------------------------------------------------------------------------------------------------------------------- void VPCarrouselPiece::RefreshSelection() { - setSelected(m_piece->IsSelected()); + VPPiecePtr piece = GetPiece(); + if (not piece.isNull()) + { + setSelected(piece->IsSelected()); + } } //--------------------------------------------------------------------------------------------------------------------- auto VPCarrouselPiece::CreatePieceIcon(const QSize &size, bool isDragIcon) const -> QIcon { - QRectF boundingRect = m_piece->DetailBoundingRect(); + VPPiecePtr piece = GetPiece(); + if (piece.isNull()) + { + return {}; + } + + QRectF boundingRect = piece->DetailBoundingRect(); qreal canvasSize = qMax(boundingRect.height(), boundingRect.width()); QRectF canvas = QRectF(0, 0, canvasSize, canvasSize); @@ -133,7 +143,7 @@ auto VPCarrouselPiece::CreatePieceIcon(const QSize &size, bool isDragIcon) const painter.setBrush(QBrush(Qt::white)); } - m_piece->DrawMiniature(painter); + piece->DrawMiniature(painter); painter.end(); diff --git a/src/app/puzzle/carousel/vpcarrouselpiece.h b/src/app/puzzle/carousel/vpcarrouselpiece.h index 1e13ea9b3..1786a8396 100644 --- a/src/app/puzzle/carousel/vpcarrouselpiece.h +++ b/src/app/puzzle/carousel/vpcarrouselpiece.h @@ -31,21 +31,21 @@ #include #include -class VPPiece; +#include "../layout/layoutdef.h" class VPCarrouselPiece : public QListWidgetItem { public: enum { Type = UserType + 1}; - explicit VPCarrouselPiece(VPPiece *piece, QListWidget* parent); + explicit VPCarrouselPiece(const VPPiecePtr &piece, QListWidget* parent); virtual ~VPCarrouselPiece() = default; /** * @brief GetPiece Returns the corresponding layout piece * @return the corresponding layout piece */ - auto GetPiece() -> VPPiece *; + auto GetPiece() const -> VPPiecePtr; /** * @brief RefreshSelection refreshes the selection of the piece according to the selection information of m_piece @@ -62,7 +62,7 @@ public: private: Q_DISABLE_COPY(VPCarrouselPiece) - VPPiece *m_piece; + VPPieceWeakPtr m_piece; }; #endif // VPCARROUSELPIECE_H diff --git a/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp b/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp index da13fa8f4..c8dc6ac49 100644 --- a/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp +++ b/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp @@ -38,6 +38,7 @@ #include "../vmisc/backport/qoverload.h" #include "vpmimedatapiece.h" #include "../layout/vpsheet.h" +#include "../layout/vplayout.h" #include @@ -68,18 +69,21 @@ void VPCarrouselPieceList::Refresh() if(not m_pieceList.isEmpty()) { // create the corresponding carrousel pieces - for (auto *piece : m_pieceList) + for (auto piece : m_pieceList) { - // update the label of the piece - auto* carrouselpiece = new VPCarrouselPiece(piece, this); - carrouselpiece->setSelected(piece->IsSelected()); + if (not piece.isNull()) + { + // update the label of the piece + auto* carrouselpiece = new VPCarrouselPiece(piece, this); + carrouselpiece->setSelected(piece->IsSelected()); + } } sortItems(); } } //--------------------------------------------------------------------------------------------------------------------- -void VPCarrouselPieceList::SetCurrentPieceList(const QList &pieceList) +void VPCarrouselPieceList::SetCurrentPieceList(const QList &pieceList) { m_pieceList = pieceList; @@ -135,7 +139,7 @@ void VPCarrouselPieceList::startDrag(Qt::DropActions supportedActions) // starts the dragging auto *drag = new QDrag(this); auto *mimeData = new VPMimeDataPiece(); - VPPiece* piece = pieceItem->GetPiece(); + VPPiecePtr piece = pieceItem->GetPiece(); mimeData->SetPiecePtr(piece); QPixmap pixmap = pieceItem->CreatePieceIcon(QSize(120, 120), true).pixmap(QSize(120, 120)); @@ -189,18 +193,23 @@ void VPCarrouselPieceList::contextMenuEvent(QContextMenuEvent *event) QAction *selectedAction = menu.exec(event->globalPos()); - VPPiece *piece = pieceItem->GetPiece(); - VPLayout *layout = piece->Layout(); + VPPiecePtr piece = pieceItem->GetPiece(); + VPLayoutPtr layout = piece->Layout(); + + if (piece.isNull() || layout.isNull()) + { + return; + } if (selectedAction == moveAction) { - VPSheet *sheet = layout->GetFocusedSheet(); + VPSheetPtr sheet = layout->GetFocusedSheet(); piece->SetSheet(sheet); emit layout->PieceSheetChanged(piece); } else if (selectedAction == deleteAction) { - VPSheet *sheet = layout->GetTrashSheet(); + VPSheetPtr sheet = layout->GetTrashSheet(); piece->SetSheet(sheet); emit layout->PieceSheetChanged(piece); } diff --git a/src/app/puzzle/carousel/vpcarrouselpiecelist.h b/src/app/puzzle/carousel/vpcarrouselpiecelist.h index e8fd0b587..75714c7cf 100644 --- a/src/app/puzzle/carousel/vpcarrouselpiecelist.h +++ b/src/app/puzzle/carousel/vpcarrouselpiecelist.h @@ -50,7 +50,7 @@ public: * @brief SetCurrentPieceList Sets the current piece list to the given piece list and redraw * the carrousel. */ - void SetCurrentPieceList(const QList &pieceList); + void SetCurrentPieceList(const QList &pieceList); /** * @brief SetCarrousel Sets the carrousel corresponding to the list @@ -76,7 +76,7 @@ protected: private: Q_DISABLE_COPY(VPCarrouselPieceList) - QList m_pieceList{}; + QList m_pieceList{}; QPoint m_dragStart{}; VPCarrousel *m_carrousel{nullptr}; }; diff --git a/src/app/puzzle/layout/layoutdef.h b/src/app/puzzle/layout/layoutdef.h new file mode 100644 index 000000000..e33db2838 --- /dev/null +++ b/src/app/puzzle/layout/layoutdef.h @@ -0,0 +1,45 @@ +/************************************************************************ + ** + ** @file layoutdef.h + ** @author Roman Telezhynskyi + ** @date 16 8, 2021 + ** + ** @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) 2021 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 LAYOUTDEF_H +#define LAYOUTDEF_H + +#include + +class VPLayout; +using VPLayoutPtr = QSharedPointer; +using VPLayoutWeakPtr = QWeakPointer; + +class VPPiece; +using VPPiecePtr = QSharedPointer; +using VPPieceWeakPtr = QWeakPointer; + +class VPSheet; +using VPSheetPtr = QSharedPointer; +using VPSheetWeakPtr = QWeakPointer; + +#endif // LAYOUTDEF_H diff --git a/src/app/puzzle/layout/vplayout.cpp b/src/app/puzzle/layout/vplayout.cpp index ede2f73e2..beb19b081 100644 --- a/src/app/puzzle/layout/vplayout.cpp +++ b/src/app/puzzle/layout/vplayout.cpp @@ -31,109 +31,118 @@ #include "vpsheet.h" #include +#include Q_LOGGING_CATEGORY(pLayout, "p.layout") //--------------------------------------------------------------------------------------------------------------------- -VPLayout::VPLayout(QObject *parent) : - QObject(parent), - m_trashSheet(new VPSheet(this)) -{} - -//--------------------------------------------------------------------------------------------------------------------- -VPLayout::~VPLayout() +VPLayout::VPLayout(QUndoStack *undoStack) : + m_undoStack(undoStack) { - qDeleteAll(m_pieces); + SCASSERT(m_undoStack != nullptr) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayout::AddPiece(VPPiece *piece) +VPLayoutPtr VPLayout::CreateLayout(QUndoStack *undoStack) { - if ((piece != nullptr) && not m_pieces.contains(piece)) + SCASSERT(undoStack != nullptr) + undoStack->clear(); + VPLayoutPtr layout(new VPLayout(undoStack)); + layout->AddTrashSheet(VPSheetPtr(new VPSheet(layout))); + return layout; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPLayout::AddPiece(const VPLayoutPtr &layout, const VPPiecePtr &piece) +{ + piece->SetLayout(layout); + layout->AddPiece(piece); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPLayout::AddPiece(const VPPiecePtr &piece) +{ + if ((piece != nullptr) && not m_pieces.contains(piece->GetUniqueID())) { - piece->SetLayout(this); - m_pieces.append(piece); + m_pieces.insert(piece->GetUniqueID(), piece); } } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::GetPieces() const -> QList +auto VPLayout::GetPieces() const -> QList { - return m_pieces; + return m_pieces.values(); } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::GetUnplacedPieces() const -> QList +auto VPLayout::GetUnplacedPieces() const -> QList { - return PiecesForSheet(nullptr); + return PiecesForSheet(VPSheetPtr()); } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::GetTrashedPieces() const -> QList +auto VPLayout::GetTrashedPieces() const -> QList { - return PiecesForSheet(m_trashSheet); -} - -//--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::AddSheet() -> VPSheet* -{ - auto *newSheet = new VPSheet(this); - m_sheets.append(newSheet); - return newSheet; -} - -//--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::AddSheet(VPSheet *sheet) -> VPSheet* -{ - if ((sheet != nullptr) && not m_sheets.contains(sheet)) + if (m_trashSheet.isNull()) + { + return {}; + } + return PiecesForSheet(m_trashSheet->Uuid()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPLayout::AddSheet(const VPSheetPtr &sheet) -> VPSheetPtr +{ + if (not sheet.isNull() && GetSheet(sheet->Uuid()).isNull()) { - sheet->setParent(this); m_sheets.append(sheet); } return sheet; } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::GetSheets() -> QList +auto VPLayout::GetSheets() -> QList { return m_sheets; } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::GetSheet(const QUuid &uuid) -> VPSheet * +auto VPLayout::GetSheet(const QUuid &uuid) -> VPSheetPtr { - for (auto *sheet : m_sheets) + auto sheet = std::find_if(m_sheets.begin(), m_sheets.end(), + [uuid](const VPSheetPtr &sheet) { return sheet->Uuid() == uuid; }); + + if (sheet != m_sheets.end()) { - if (sheet->Uuid() == uuid) - { - return sheet; - } + return *sheet; } - return nullptr; + return {}; } //--------------------------------------------------------------------------------------------------------------------- -void VPLayout::SetFocusedSheet(VPSheet *focusedSheet) +void VPLayout::SetFocusedSheet(const VPSheetPtr &focusedSheet) { if (m_sheets.isEmpty()) { - m_focusedSheet = nullptr; + m_focusedSheet = {}; } else { - m_focusedSheet = focusedSheet == nullptr ? m_sheets.first() : focusedSheet; + m_focusedSheet = focusedSheet.isNull() ? m_sheets.first() : focusedSheet; } + + emit ActiveSheetChanged(m_focusedSheet); } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::GetFocusedSheet() -> VPSheet* +auto VPLayout::GetFocusedSheet() -> VPSheetPtr { return m_focusedSheet; } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::GetTrashSheet() -> VPSheet* +auto VPLayout::GetTrashSheet() -> VPSheetPtr { return m_trashSheet; } @@ -145,14 +154,14 @@ auto VPLayout::LayoutSettings() -> VPLayoutSettings & } //--------------------------------------------------------------------------------------------------------------------- -auto VPLayout::PiecesForSheet(const VPSheet *sheet) const -> QList +auto VPLayout::PiecesForSheet(const VPSheetPtr &sheet) const -> QList { - QList list; + QList list; list.reserve(m_pieces.size()); - for (auto *piece : m_pieces) + for (auto piece : m_pieces) { - if ((piece != nullptr) && piece->Sheet() == sheet) + if (not piece.isNull() && piece->Sheet() == sheet) { list.append(piece); } @@ -160,3 +169,57 @@ auto VPLayout::PiecesForSheet(const VPSheet *sheet) const -> QList return list; } + +//--------------------------------------------------------------------------------------------------------------------- +QList VPLayout::PiecesForSheet(const QUuid &uuid) const +{ + QList list; + list.reserve(m_pieces.size()); + + for (auto piece : m_pieces) + { + if (not piece.isNull()) + { + VPSheetPtr sheet = piece->Sheet(); + if (not sheet.isNull() && sheet->Uuid() == uuid) + { + list.append(piece); + } + } + } + + return list; +} + +//--------------------------------------------------------------------------------------------------------------------- +QUndoStack *VPLayout::UndoStack() const +{ + return m_undoStack; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPLayout::SetUndoStack(QUndoStack *newUndoStack) +{ + m_undoStack = newUndoStack; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPLayout::Clear() +{ + if (m_undoStack != nullptr) + { + m_undoStack->clear(); + } + + m_pieces.clear(); + m_trashSheet->Clear(); + m_sheets.clear(); + m_focusedSheet.clear(); + m_layoutSettings = VPLayoutSettings(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPLayout::AddTrashSheet(const VPSheetPtr &sheet) +{ + m_trashSheet = sheet; +} diff --git a/src/app/puzzle/layout/vplayout.h b/src/app/puzzle/layout/vplayout.h index 9a901566d..5f96b732c 100644 --- a/src/app/puzzle/layout/vplayout.h +++ b/src/app/puzzle/layout/vplayout.h @@ -29,64 +29,86 @@ #define VPLAYOUT_H #include +#include #include "def.h" #include "vplayoutsettings.h" +#include "layoutdef.h" class VPPiece; class VPSheet; +class QUndoStack; class VPLayout : public QObject { Q_OBJECT public: - explicit VPLayout(QObject *parent=nullptr); - virtual ~VPLayout(); + virtual ~VPLayout() = default; - void AddPiece(VPPiece *piece); - auto GetPieces() const -> QList; - auto GetUnplacedPieces() const -> QList; - auto GetTrashedPieces() const -> QList; + static auto CreateLayout(QUndoStack *undoStack) -> VPLayoutPtr; + static void AddPiece(const VPLayoutPtr &layout, const VPPiecePtr &piece); - auto AddSheet() -> VPSheet*; - auto AddSheet(VPSheet *sheet) -> VPSheet*; - auto GetSheets() -> QList; - auto GetSheet(const QUuid &uuid) -> VPSheet *; + auto GetPieces() const -> QList; + auto GetUnplacedPieces() const -> QList; + auto GetTrashedPieces() const -> QList; + + auto AddSheet(const VPSheetPtr &sheet) -> VPSheetPtr; + auto GetSheets() -> QList; + auto GetSheet(const QUuid &uuid) -> VPSheetPtr; /** * @brief SetFocusedSheet Sets the focused sheet, to which pieces are added from the carrousel via drag * and drop * @param focusedSheet the new active sheet. If nullptr, then it sets automaticaly the first sheet from m_sheets */ - void SetFocusedSheet(VPSheet *focusedSheet = nullptr); + void SetFocusedSheet(const VPSheetPtr &focusedSheet = VPSheetPtr()); /** * @brief GetFocusedSheet Returns the focused sheet, to which pieces are added from the carrousel via drag * and drop * @return the focused sheet */ - auto GetFocusedSheet() -> VPSheet*; + auto GetFocusedSheet() -> VPSheetPtr; - auto GetTrashSheet() -> VPSheet*; + void AddTrashSheet(const VPSheetPtr &sheet); + auto GetTrashSheet() -> VPSheetPtr; auto LayoutSettings() -> VPLayoutSettings &; - auto PiecesForSheet(const VPSheet* sheet) const -> QList; + auto PiecesForSheet(const VPSheetPtr &sheet) const -> QList; + auto PiecesForSheet(const QUuid &uuid) const -> QList; + + QUndoStack *UndoStack() const; + + void SetUndoStack(QUndoStack *newUndoStack); + + void Clear(); signals: - void PieceSheetChanged(VPPiece *piece); + void PieceSheetChanged(const VPPiecePtr &piece); + void ActiveSheetChanged(const VPSheetPtr &focusedSheet); + void PieceTransformationChanged(const VPPiecePtr &piece); + +protected: + explicit VPLayout(QUndoStack *undoStack); + + void AddPiece(const VPPiecePtr &piece); private: Q_DISABLE_COPY(VPLayout) - QList m_pieces{}; + QMap m_pieces{}; - VPSheet* m_trashSheet; + VPSheetPtr m_trashSheet{}; - QList m_sheets{}; - VPSheet *m_focusedSheet{nullptr}; + QList m_sheets{}; + VPSheetPtr m_focusedSheet{}; VPLayoutSettings m_layoutSettings{}; + + QUndoStack *m_undoStack; }; +Q_DECLARE_METATYPE(VPLayoutPtr) + #endif // VPLAYOUT_H diff --git a/src/app/puzzle/puzzle.pri b/src/app/puzzle/puzzle.pri index 70ac0e7a3..fffdb9748 100644 --- a/src/app/puzzle/puzzle.pri +++ b/src/app/puzzle/puzzle.pri @@ -7,6 +7,9 @@ SOURCES += \ $$PWD/dialogs/dialogpuzzlepreferences.cpp \ $$PWD/dialogs/vpdialogabout.cpp \ $$PWD/main.cpp \ + $$PWD/undocommands/vpundocommand.cpp \ + $$PWD/undocommands/vpundopiecemove.cpp \ + $$PWD/undocommands/vpundopiecerotate.cpp \ $$PWD/vpapplication.cpp \ $$PWD/carousel/vpcarrousel.cpp \ $$PWD/carousel/vpcarrouselpiece.cpp \ @@ -38,8 +41,12 @@ HEADERS += \ $$PWD/dialogs/configpages/puzzlepreferencespathpage.h \ $$PWD/dialogs/dialogpuzzlepreferences.h \ $$PWD/dialogs/vpdialogabout.h \ + $$PWD/layout/layoutdef.h \ $$PWD/scene/scenedef.h \ $$PWD/stable.h \ + $$PWD/undocommands/vpundocommand.h \ + $$PWD/undocommands/vpundopiecemove.h \ + $$PWD/undocommands/vpundopiecerotate.h \ $$PWD/vpapplication.h \ $$PWD/carousel/vpcarrousel.h \ $$PWD/carousel/vpcarrouselpiece.h \ diff --git a/src/app/puzzle/scene/vpgraphicspiece.cpp b/src/app/puzzle/scene/vpgraphicspiece.cpp index 52322a75e..60cc6a9cc 100644 --- a/src/app/puzzle/scene/vpgraphicspiece.cpp +++ b/src/app/puzzle/scene/vpgraphicspiece.cpp @@ -46,6 +46,8 @@ #include "vlayoutpiecepath.h" #include "vplacelabelitem.h" +#include "undocommands/vpundopiecemove.h" + #include Q_LOGGING_CATEGORY(pGraphicsPiece, "p.graphicsPiece") @@ -55,7 +57,7 @@ constexpr qreal penWidth = 1; } //--------------------------------------------------------------------------------------------------------------------- -VPGraphicsPiece::VPGraphicsPiece(VPPiece *piece, QGraphicsItem *parent) : +VPGraphicsPiece::VPGraphicsPiece(const VPPiecePtr &piece, QGraphicsItem *parent) : QGraphicsObject(parent), m_piece(piece) { @@ -71,25 +73,11 @@ VPGraphicsPiece::VPGraphicsPiece(VPPiece *piece, QGraphicsItem *parent) : } //--------------------------------------------------------------------------------------------------------------------- -auto VPGraphicsPiece::GetPiece() -> VPPiece* +auto VPGraphicsPiece::GetPiece() -> VPPiecePtr { return m_piece; } -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::TranslatePiece(qreal dx, qreal dy) -{ - TranslatePiece(QPointF(dx, dy)); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::TranslatePiece(const QPointF &p) -{ - prepareGeometryChange(); - m_piece->Translate(p); - PaintPiece(); // refresh shapes -} - //--------------------------------------------------------------------------------------------------------------------- auto VPGraphicsPiece::boundingRect() const -> QRectF { @@ -149,6 +137,7 @@ void VPGraphicsPiece::mouseMoveEvent(QGraphicsSceneMouseEvent *event) GroupMove(event->pos()); m_moveStartPoint = event->pos(); + allowChangeMerge = true; } //--------------------------------------------------------------------------------------------------------------------- @@ -161,18 +150,29 @@ void VPGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (event->button() == Qt::LeftButton) { setCursor(Qt::OpenHandCursor); - GroupMove(event->pos()); emit HideTransformationHandles(false); + allowChangeMerge = false; } } //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsPiece::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { - QMenu menu; + VPPiecePtr piece = m_piece.toStrongRef(); + if (piece.isNull()) + { + return; + } - QList sheets = m_piece->Layout()->GetSheets(); - sheets.removeAll(m_piece->Sheet()); + VPLayoutPtr layout = piece->Layout(); + if (layout.isNull()) + { + return; + } + + QMenu menu; + QList sheets = layout->GetSheets(); + sheets.removeAll(piece->Sheet()); QVector moveToActions; @@ -180,11 +180,14 @@ void VPGraphicsPiece::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu *moveMenu = menu.addMenu(tr("Move to")); - for (auto *sheet : sheets) + for (const auto &sheet : sheets) { - QAction* moveToSheet = moveMenu->addAction(sheet->GetName()); - moveToSheet->setData(QVariant::fromValue(sheet)); - moveToActions.append(moveToSheet); + if (not sheet.isNull()) + { + QAction* moveToSheet = moveMenu->addAction(sheet->GetName()); + moveToSheet->setData(QVariant::fromValue(sheet)); + moveToActions.append(moveToSheet); + } } } @@ -195,13 +198,13 @@ void VPGraphicsPiece::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) if (moveToActions.contains(selectedAction)) { - m_piece->SetSheet(qvariant_cast(selectedAction->data())); - emit m_piece->Layout()->PieceSheetChanged(m_piece); + piece->SetSheet(qvariant_cast(selectedAction->data())); + emit layout->PieceSheetChanged(piece); } else if (selectedAction == removeAction) { - m_piece->SetSheet(nullptr); - emit m_piece->Layout()->PieceSheetChanged(m_piece); + piece->SetSheet(nullptr); + emit layout->PieceSheetChanged(piece); } } @@ -211,11 +214,14 @@ void VPGraphicsPiece::PaintPiece(QPainter *painter) QBrush noBrush(Qt::NoBrush); QBrush selectionBrush(QColor(255,160,160,60)); - QRectF rect = m_piece->MappedDetailBoundingRect(); - QPointF p = rect.topLeft(); + VPPiecePtr piece = m_piece.toStrongRef(); + if (piece.isNull()) + { + return; + } // initialises the seam line - QVector seamLinePoints = m_piece->GetMappedContourPoints(); + QVector seamLinePoints = piece->GetMappedContourPoints(); if(!seamLinePoints.isEmpty()) { m_seamLine = QPainterPath(); @@ -235,7 +241,7 @@ void VPGraphicsPiece::PaintPiece(QPainter *painter) } // initiliases the cutting line - QVector cuttingLinepoints = m_piece->GetMappedSeamAllowancePoints(); + QVector cuttingLinepoints = piece->GetMappedSeamAllowancePoints(); if(!cuttingLinepoints.isEmpty()) { m_cuttingLine = QPainterPath(); @@ -255,9 +261,9 @@ void VPGraphicsPiece::PaintPiece(QPainter *painter) } // initialises the grainline - if(m_piece->IsGrainlineEnabled()) + if(piece->IsGrainlineEnabled()) { - QVector grainLinepoints = m_piece->GetMappedGrainline(); + QVector grainLinepoints = piece->GetMappedGrainline(); if(!grainLinepoints.isEmpty()) { QPainterPath grainline; @@ -282,10 +288,10 @@ void VPGraphicsPiece::PaintPiece(QPainter *painter) } // initialises the internal paths - QVector internalPaths = m_piece->GetInternalPaths(); + QVector internalPaths = piece->GetInternalPaths(); for (const auto& piecePath : internalPaths) { - QPainterPath path = m_piece->GetMatrix().map(piecePath.GetPainterPath()); + QPainterPath path = piece->GetMatrix().map(piecePath.GetPainterPath()); if (painter != nullptr) { @@ -297,7 +303,7 @@ void VPGraphicsPiece::PaintPiece(QPainter *painter) } // initialises the passmarks - QVector passmarks = m_piece->GetMappedPassmarks(); + QVector passmarks = piece->GetMappedPassmarks(); for(auto &passmark : passmarks) { QPainterPath passmarkPath; @@ -317,7 +323,7 @@ void VPGraphicsPiece::PaintPiece(QPainter *painter) } // initialises the place labels (buttons etc) - QVector placeLabels = m_piece->GetMappedPlaceLabels(); + QVector placeLabels = piece->GetMappedPlaceLabels(); for(auto &placeLabel : placeLabels) { QPainterPath path = VPlaceLabelItem::LabelShapePath(placeLabel.shape); @@ -345,27 +351,63 @@ void VPGraphicsPiece::GroupMove(const QPointF &pos) if (scene() != nullptr) { QList list = scene()->selectedItems(); - for (auto *item : list) + + if (list.isEmpty()) { - if (item->type() == UserType + static_cast(PGraphicsItem::Piece)) - { - auto *pieceItem = dynamic_cast(item); - pieceItem->TranslatePiece(pos-m_moveStartPoint); - } + return; + } + + VPPiecePtr piece = m_piece.toStrongRef(); + if (piece.isNull()) + { + return; + } + + VPLayoutPtr layout = piece->Layout(); + if (layout.isNull()) + { + return; + } + + auto PreparePieces = [list]() + { + QVector pieces; + for (auto *item : list) + { + if (item->type() == VPGraphicsPiece::Type) + { + auto *pieceItem = dynamic_cast(item); + pieces.append(pieceItem->GetPiece()); + } + } + + return pieces; + }; + + QVector pieces = PreparePieces(); + QPointF newPos = pos - m_moveStartPoint; + + if (pieces.size() == 1) + { + auto *command = new VPUndoPieceMove(pieces.first(), newPos.x(), newPos.y(), allowChangeMerge); + layout->UndoStack()->push(command); + } + else if (pieces.size() > 1) + { + auto *command = new VPUndoPiecesMove(pieces, newPos.x(), newPos.y(), allowChangeMerge); + layout->UndoStack()->push(command); } - emit PiecePositionChanged(); } } //--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::on_Rotate(const QPointF ¢er, qreal angle) +void VPGraphicsPiece::on_RefreshPiece(const VPPiecePtr &piece) { - if (isSelected()) + if (m_piece == piece) { prepareGeometryChange(); - m_piece->Rotate(center, angle); - PaintPiece(); // Update shapes - update(); + PaintPiece(); // refresh shapes + emit PieceTransformationChanged(); } } @@ -376,8 +418,12 @@ auto VPGraphicsPiece::itemChange(GraphicsItemChange change, const QVariant &valu { if(change == ItemSelectedHasChanged) { - emit PieceSelectionChanged(); - m_piece->SetSelected(value.toBool()); + VPPiecePtr piece = m_piece.toStrongRef(); + if (not piece.isNull()) + { + emit PieceSelectionChanged(); + piece->SetSelected(value.toBool()); + } } } diff --git a/src/app/puzzle/scene/vpgraphicspiece.h b/src/app/puzzle/scene/vpgraphicspiece.h index f635d9135..ae8db91e7 100644 --- a/src/app/puzzle/scene/vpgraphicspiece.h +++ b/src/app/puzzle/scene/vpgraphicspiece.h @@ -33,24 +33,20 @@ #include #include "scenedef.h" - -class VPPiece; +#include "../layout/layoutdef.h" class VPGraphicsPiece : public QGraphicsObject { Q_OBJECT public: - explicit VPGraphicsPiece(VPPiece *piece, QGraphicsItem *parent = nullptr); + explicit VPGraphicsPiece(const VPPiecePtr &piece, QGraphicsItem *parent = nullptr); ~VPGraphicsPiece() = default; /** * @brief GetPiece Returns the piece that corresponds to the graphics piece * @return the piece */ - auto GetPiece() -> VPPiece*; - - void TranslatePiece(qreal dx, qreal dy); - void TranslatePiece(const QPointF &p); + auto GetPiece() -> VPPiecePtr; virtual int type() const override {return Type;} enum { Type = UserType + static_cast(PGraphicsItem::Piece)}; @@ -58,10 +54,10 @@ public: signals: void PieceSelectionChanged(); void HideTransformationHandles(bool hide); - void PiecePositionChanged(); + void PieceTransformationChanged(); public slots: - void on_Rotate(const QPointF ¢er, qreal angle); + void on_RefreshPiece(const VPPiecePtr &piece); protected: auto boundingRect() const -> QRectF override; @@ -78,7 +74,7 @@ protected: private: Q_DISABLE_COPY(VPGraphicsPiece) - VPPiece *m_piece; + VPPieceWeakPtr m_piece; QPainterPath m_cuttingLine{}; QPainterPath m_seamLine{}; @@ -88,6 +84,8 @@ private: QCursor m_rotateCursor{}; + bool allowChangeMerge{false}; + void PaintPiece(QPainter *painter=nullptr); void GroupMove(const QPointF &pos); diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.cpp b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp index acd837449..c4339b444 100644 --- a/src/app/puzzle/scene/vpgraphicspiececontrols.cpp +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp @@ -37,6 +37,8 @@ #include "../vmisc/compatibility.h" #include "../vwidgets/global.h" #include "../layout/vplayout.h" +#include "../undocommands/vpundopiecerotate.h" +#include "vpgraphicspiece.h" namespace { @@ -67,11 +69,11 @@ enum class HandleCorner : int BottomLeft = 4 }; -auto TransformationOrigin(VPLayout *layout, const QRectF &boundingRect) -> QPointF +auto TransformationOrigin(const VPLayoutPtr &layout, const QRectF &boundingRect) -> QPointF { SCASSERT(layout != nullptr) - VPSheet *sheet = layout->GetFocusedSheet(); - if (sheet != nullptr) + VPSheetPtr sheet = layout->GetFocusedSheet(); + if (not sheet.isNull()) { VPTransformationOrigon origin = sheet->TransformationOrigin(); return origin.origin; @@ -82,7 +84,7 @@ auto TransformationOrigin(VPLayout *layout, const QRectF &boundingRect) -> QPoin } // namespace //--------------------------------------------------------------------------------------------------------------------- -VPGraphicsTransformationOrigin::VPGraphicsTransformationOrigin(VPLayout *layout, QGraphicsItem *parent) +VPGraphicsTransformationOrigin::VPGraphicsTransformationOrigin(const VPLayoutPtr &layout, QGraphicsItem *parent) : QGraphicsObject(parent), m_layout(layout), m_color(defaultColor) @@ -113,14 +115,14 @@ void VPGraphicsTransformationOrigin::on_ShowOrigin(bool show) } //--------------------------------------------------------------------------------------------------------------------- -QRectF VPGraphicsTransformationOrigin::boundingRect() const +auto VPGraphicsTransformationOrigin::boundingRect() const -> QRectF { constexpr qreal halfPenWidth = penWidth/2.; return Center2().boundingRect().adjusted(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth); } //--------------------------------------------------------------------------------------------------------------------- -QPainterPath VPGraphicsTransformationOrigin::shape() const +auto VPGraphicsTransformationOrigin::shape() const -> QPainterPath { return Center2(); } @@ -170,15 +172,19 @@ void VPGraphicsTransformationOrigin::mousePressEvent(QGraphicsSceneMouseEvent *e //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsTransformationOrigin::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - VPSheet *sheet = m_layout->GetFocusedSheet(); - if (sheet != nullptr) + VPLayoutPtr layout = m_layout.toStrongRef(); + if (not layout.isNull()) { - VPTransformationOrigon origin = sheet->TransformationOrigin(); - origin.origin = event->scenePos(); - origin.custom = true; - sheet->SetTransformationOrigin(origin); + VPSheetPtr sheet = layout->GetFocusedSheet(); + if (not sheet.isNull()) + { + VPTransformationOrigon origin = sheet->TransformationOrigin(); + origin.origin = event->scenePos(); + origin.custom = true; + sheet->SetTransformationOrigin(origin); + } + prepareGeometryChange(); } - prepareGeometryChange(); QGraphicsObject::mouseMoveEvent(event); } @@ -251,7 +257,7 @@ auto VPGraphicsTransformationOrigin::RotationCenter(QPainter *painter) const -> } //--------------------------------------------------------------------------------------------------------------------- -QPainterPath VPGraphicsTransformationOrigin::Center1() const +auto VPGraphicsTransformationOrigin::Center1() const -> QPainterPath { const qreal scale = SceneScale(scene()); qreal radius = centerRadius1/scale; @@ -265,7 +271,7 @@ QPainterPath VPGraphicsTransformationOrigin::Center1() const } //--------------------------------------------------------------------------------------------------------------------- -QPainterPath VPGraphicsTransformationOrigin::Center2() const +auto VPGraphicsTransformationOrigin::Center2() const -> QPainterPath { const qreal scale = SceneScale(scene()); qreal radius = centerRadius2/scale; @@ -280,7 +286,7 @@ QPainterPath VPGraphicsTransformationOrigin::Center2() const // VPGraphicsPieceControls //--------------------------------------------------------------------------------------------------------------------- -VPGraphicsPieceControls::VPGraphicsPieceControls(VPLayout *layout, QGraphicsItem *parent) +VPGraphicsPieceControls::VPGraphicsPieceControls(const VPLayoutPtr &layout, QGraphicsItem *parent) : QGraphicsObject(parent), m_layout(layout) { @@ -294,20 +300,30 @@ VPGraphicsPieceControls::VPGraphicsPieceControls(VPLayout *layout, QGraphicsItem //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsPieceControls::on_UpdateControls() { - m_pieceRect = PiecesBoundingRect(); + if (m_ignorePieceTransformation) + { + return; + } + + m_selectedPieces = SelectedPieces(); + m_pieceRect = PiecesBoundingRect(m_selectedPieces); setVisible(not m_pieceRect.isNull()); if (not m_pieceRect.isNull()) { - VPSheet *sheet = m_layout->GetFocusedSheet(); - if (sheet != nullptr) + VPLayoutPtr layout = m_layout.toStrongRef(); + if (not layout.isNull()) { - VPTransformationOrigon origin = sheet->TransformationOrigin(); - if (not origin.custom) + VPSheetPtr sheet = layout->GetFocusedSheet(); + if (not sheet.isNull()) { - origin.origin = m_pieceRect.center(); - sheet->SetTransformationOrigin(origin); - emit TransformationOriginChanged(); + VPTransformationOrigon origin = sheet->TransformationOrigin(); + if (not origin.custom) + { + origin.origin = m_pieceRect.center(); + sheet->SetTransformationOrigin(origin); + emit TransformationOriginChanged(); + } } } } @@ -320,6 +336,7 @@ void VPGraphicsPieceControls::on_UpdateControls() void VPGraphicsPieceControls::on_HideHandles(bool hide) { m_controlsVisible = not hide; + update(); } //--------------------------------------------------------------------------------------------------------------------- @@ -364,6 +381,7 @@ void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event) m_rotationStartPoint = event->scenePos(); m_controlsVisible = false; m_handleCorner = HandleCorner(event->scenePos()); + m_ignorePieceTransformation = true; prepareGeometryChange(); } else @@ -380,35 +398,39 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (not m_originSaved) { - VPSheet *sheet = m_layout->GetFocusedSheet(); - if (sheet != nullptr) + VPLayoutPtr layout = m_layout.toStrongRef(); + if (not layout.isNull()) { - m_savedOrigin = sheet->TransformationOrigin(); - m_originSaved = true; - m_pieceRect = PiecesBoundingRect(); + VPSheetPtr sheet = layout->GetFocusedSheet(); + if (not sheet.isNull()) + { + m_savedOrigin = sheet->TransformationOrigin(); + m_originSaved = true; + m_pieceRect = PiecesBoundingRect(m_selectedPieces); - VPTransformationOrigon origin; - origin.custom = true; + VPTransformationOrigon origin; + origin.custom = true; - if (static_cast(m_handleCorner) == HandleCorner::TopLeft) - { - origin.origin = m_pieceRect.topLeft(); - } - else if (static_cast(m_handleCorner) == HandleCorner::TopRight) - { - origin.origin = m_pieceRect.topRight(); - } - else if (static_cast(m_handleCorner) == HandleCorner::BottomRight) - { - origin.origin = m_pieceRect.bottomRight(); - } - else if (static_cast(m_handleCorner) == HandleCorner::BottomLeft) - { - origin.origin = m_pieceRect.bottomLeft(); - } + if (static_cast(m_handleCorner) == HandleCorner::TopLeft) + { + origin.origin = m_pieceRect.topLeft(); + } + else if (static_cast(m_handleCorner) == HandleCorner::TopRight) + { + origin.origin = m_pieceRect.topRight(); + } + else if (static_cast(m_handleCorner) == HandleCorner::BottomRight) + { + origin.origin = m_pieceRect.bottomRight(); + } + else if (static_cast(m_handleCorner) == HandleCorner::BottomLeft) + { + origin.origin = m_pieceRect.bottomLeft(); + } - sheet->SetTransformationOrigin(origin); - emit TransformationOriginChanged(); + sheet->SetTransformationOrigin(origin); + emit TransformationOriginChanged(); + } } } } @@ -416,18 +438,22 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (m_originSaved) { - VPSheet *sheet = m_layout->GetFocusedSheet(); - if (sheet != nullptr) + VPLayoutPtr layout = m_layout.toStrongRef(); + if (not layout.isNull()) { - if (not m_savedOrigin.custom) + VPSheetPtr sheet = layout->GetFocusedSheet(); + if (sheet != nullptr) { - m_pieceRect = PiecesBoundingRect(); - m_savedOrigin.origin = m_pieceRect.center(); + if (not m_savedOrigin.custom) + { + m_pieceRect = PiecesBoundingRect(m_selectedPieces); + m_savedOrigin.origin = m_pieceRect.center(); + } + sheet->SetTransformationOrigin(m_savedOrigin); + emit TransformationOriginChanged(); } - sheet->SetTransformationOrigin(m_savedOrigin); - emit TransformationOriginChanged(); + m_originSaved = false; } - m_originSaved = false; } } @@ -442,7 +468,33 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if (not qFuzzyIsNull(angle)) { - emit Rotate(rotationOrigin, angle); + auto PreparePieces = [this]() + { + QVector pieces; + for (auto *item : m_selectedPieces) + { + pieces.append(item->GetPiece()); + } + + return pieces; + }; + + QVector pieces = PreparePieces(); + + VPLayoutPtr layout = m_layout.toStrongRef(); + if (not layout.isNull()) + { + if (pieces.size() == 1) + { + auto *command = new VPUndoPieceRotate(pieces.first(), rotationOrigin, angle, allowChangeMerge); + layout->UndoStack()->push(command); + } + else if (pieces.size() > 1) + { + auto *command = new VPUndoPiecesRotate(pieces, rotationOrigin, angle, allowChangeMerge); + layout->UndoStack()->push(command); + } + } } if (m_originSaved && m_savedOrigin.custom) @@ -453,6 +505,7 @@ void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) } m_rotationStartPoint = rotationNewPoint; + allowChangeMerge = true; QGraphicsObject::mouseMoveEvent(event); } @@ -462,28 +515,40 @@ void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if(event->button() == Qt::LeftButton) { m_controlsVisible = true; + m_ignorePieceTransformation = false; if (m_originSaved) { - VPSheet *sheet = m_layout->GetFocusedSheet(); - if (sheet != nullptr) + VPLayoutPtr layout = m_layout.toStrongRef(); + if (not layout.isNull()) { - if (not m_savedOrigin.custom) + VPSheetPtr sheet = layout->GetFocusedSheet(); + if (not sheet.isNull()) { - m_pieceRect = PiecesBoundingRect(); - m_savedOrigin.origin = m_pieceRect.center(); + if (not m_savedOrigin.custom) + { + m_pieceRect = PiecesBoundingRect(m_selectedPieces); + m_savedOrigin.origin = m_pieceRect.center(); + } + sheet->SetTransformationOrigin(m_savedOrigin); + emit TransformationOriginChanged(); } - sheet->SetTransformationOrigin(m_savedOrigin); - emit TransformationOriginChanged(); + m_originSaved = false; } - m_originSaved = false; } on_UpdateControls(); + allowChangeMerge = false; } QGraphicsObject::mouseReleaseEvent(event); } +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::SetIgnorePieceTransformation(bool newIgnorePieceTransformation) +{ + m_ignorePieceTransformation = newIgnorePieceTransformation; +} + //--------------------------------------------------------------------------------------------------------------------- auto VPGraphicsPieceControls::TopLeftControl(QPainter *painter) const -> QPainterPath { @@ -522,7 +587,7 @@ auto VPGraphicsPieceControls::BottomRightControl(QPainter *painter) const -> QPa } //--------------------------------------------------------------------------------------------------------------------- -QPainterPath VPGraphicsPieceControls::Handles() const +auto VPGraphicsPieceControls::Handles() const -> QPainterPath { QPainterPath path; @@ -690,22 +755,38 @@ auto VPGraphicsPieceControls::ArrowPath() const -> QPainterPath } //--------------------------------------------------------------------------------------------------------------------- -QRectF VPGraphicsPieceControls::PiecesBoundingRect() const +auto VPGraphicsPieceControls::SelectedPieces() const -> QVector { - QRectF rect; + QVector pieces; QGraphicsScene *scene = this->scene(); if (scene != nullptr) { QList list = scene->selectedItems(); for (auto *item : list) { - if (item->type() == UserType + static_cast(PGraphicsItem::Piece)) + if (item->type() == VPGraphicsPiece::Type) { - rect = rect.united(item->sceneBoundingRect()); + auto *pieceItem = dynamic_cast(item); + if (pieceItem != nullptr) + { + pieces.append(pieceItem); + } } } } + return pieces; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::PiecesBoundingRect(const QVector &selectedPieces) const -> QRectF +{ + QRectF rect; + for (auto *item : selectedPieces) + { + rect = rect.united(item->sceneBoundingRect()); + } + return rect; } diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.h b/src/app/puzzle/scene/vpgraphicspiececontrols.h index d340c1a3d..1a2561b97 100644 --- a/src/app/puzzle/scene/vpgraphicspiececontrols.h +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.h @@ -35,12 +35,13 @@ #include "../layout/vpsheet.h" class VPLayout; +class VPGraphicsPiece; class VPGraphicsTransformationOrigin : public QGraphicsObject { Q_OBJECT public: - explicit VPGraphicsTransformationOrigin(VPLayout *layout, QGraphicsItem * parent = nullptr); + explicit VPGraphicsTransformationOrigin(const VPLayoutPtr &layout, QGraphicsItem * parent = nullptr); virtual int type() const override {return Type;} enum { Type = UserType + static_cast(PGraphicsItem::TransformationOrigin)}; @@ -65,9 +66,9 @@ protected: private: Q_DISABLE_COPY(VPGraphicsTransformationOrigin) - bool m_originVisible{true}; - VPLayout *m_layout; - QColor m_color; + bool m_originVisible{true}; + VPLayoutWeakPtr m_layout{}; + QColor m_color; auto RotationCenter(QPainter *painter = nullptr) const -> QPainterPath; auto Center1() const -> QPainterPath; @@ -78,13 +79,14 @@ class VPGraphicsPieceControls : public QGraphicsObject { Q_OBJECT public: - explicit VPGraphicsPieceControls(VPLayout *layout, QGraphicsItem * parent = nullptr); + explicit VPGraphicsPieceControls(const VPLayoutPtr &layout, QGraphicsItem * parent = nullptr); virtual int type() const override {return Type;} enum { Type = UserType + static_cast(PGraphicsItem::Handles)}; + void SetIgnorePieceTransformation(bool newIgnorePieceTransformation); + signals: - void Rotate(const QPointF ¢er, qreal angle); void ShowOrigin(bool show); void TransformationOriginChanged(); @@ -103,13 +105,16 @@ protected: private: Q_DISABLE_COPY(VPGraphicsPieceControls) - QRectF m_pieceRect{}; - QPointF m_rotationStartPoint{}; - bool m_controlsVisible{true}; - VPLayout *m_layout; - int m_handleCorner{0}; + QRectF m_pieceRect{}; + QPointF m_rotationStartPoint{}; + bool m_controlsVisible{true}; + VPLayoutWeakPtr m_layout{}; + int m_handleCorner{0}; VPTransformationOrigon m_savedOrigin{}; - bool m_originSaved{false}; + bool m_originSaved{false}; + bool allowChangeMerge{false}; + QVector m_selectedPieces{}; + bool m_ignorePieceTransformation{false}; auto TopLeftControl(QPainter *painter = nullptr) const -> QPainterPath; auto TopRightControl(QPainter *painter = nullptr) const -> QPainterPath; @@ -122,7 +127,8 @@ private: auto ArrowPath() const -> QPainterPath; - auto PiecesBoundingRect() const -> QRectF; + auto SelectedPieces() const -> QVector; + auto PiecesBoundingRect(const QVector &selectedPieces) const -> QRectF; auto HandleCorner(const QPointF &pos) const -> int; }; diff --git a/src/app/puzzle/scene/vpgraphicssheet.cpp b/src/app/puzzle/scene/vpgraphicssheet.cpp index 2839cacff..d4a2e28f3 100644 --- a/src/app/puzzle/scene/vpgraphicssheet.cpp +++ b/src/app/puzzle/scene/vpgraphicssheet.cpp @@ -1,4 +1,4 @@ -/************************************************************************ +/******************************************************************* ** ** @file vpgraphicssheet.cpp ** @author Ronan Le Tiec @@ -33,7 +33,7 @@ #include //--------------------------------------------------------------------------------------------------------------------- -VPGraphicsSheet::VPGraphicsSheet(VPLayout *layout, QGraphicsItem *parent): +VPGraphicsSheet::VPGraphicsSheet(const VPLayoutPtr &layout, QGraphicsItem *parent): QGraphicsItem(parent), m_layout(layout), m_boundingRect(GetSheetRect()) @@ -66,12 +66,14 @@ void VPGraphicsSheet::paint(QPainter *painter, const QStyleOptionGraphicsItem *o painter->drawRect(sheetRect); } - if(m_layout->LayoutSettings().GetShowGrid()) + VPLayoutPtr layout = m_layout.toStrongRef(); + + if(not layout.isNull() && layout->LayoutSettings().GetShowGrid()) { pen.setColor(QColor(204,204,204)); painter->setPen(pen); - qreal colWidth = m_layout->LayoutSettings().GetGridColWidth(); + qreal colWidth = layout->LayoutSettings().GetGridColWidth(); if(colWidth > 0) { qreal colX = colWidth; @@ -83,7 +85,7 @@ void VPGraphicsSheet::paint(QPainter *painter, const QStyleOptionGraphicsItem *o } } - qreal rowHeight = m_layout->LayoutSettings().GetGridRowHeight(); + qreal rowHeight = layout->LayoutSettings().GetGridRowHeight(); if(rowHeight > 0) { qreal rowY = rowHeight; @@ -101,11 +103,17 @@ void VPGraphicsSheet::paint(QPainter *painter, const QStyleOptionGraphicsItem *o } //--------------------------------------------------------------------------------------------------------------------- -QRectF VPGraphicsSheet::GetSheetRect() const +auto VPGraphicsSheet::GetSheetRect() const -> QRectF { + VPLayoutPtr layout = m_layout.toStrongRef(); + if (layout.isNull()) + { + return {}; + } + QPoint topLeft = QPoint(0,0); - QSizeF size = m_layout->LayoutSettings().GetSheetSize(); - if(m_layout->LayoutSettings().GetOrientation() == PageOrientation::Landscape) + QSizeF size = layout->LayoutSettings().GetSheetSize(); + if(layout->LayoutSettings().GetOrientation() == PageOrientation::Landscape) { size.transpose(); } @@ -114,20 +122,24 @@ QRectF VPGraphicsSheet::GetSheetRect() const } //--------------------------------------------------------------------------------------------------------------------- -QRectF VPGraphicsSheet::GetMarginsRect() const +auto VPGraphicsSheet::GetMarginsRect() const -> QRectF { - QMarginsF margins = m_layout->LayoutSettings().GetSheetMargins(); - QSizeF size = m_layout->LayoutSettings().GetSheetSize(); + VPLayoutPtr layout = m_layout.toStrongRef(); + if (layout.isNull()) + { + return {}; + } - if(m_layout->LayoutSettings().GetOrientation() == PageOrientation::Landscape) + QMarginsF margins = layout->LayoutSettings().GetSheetMargins(); + QSizeF size = layout->LayoutSettings().GetSheetSize(); + + if(layout->LayoutSettings().GetOrientation() == PageOrientation::Landscape) { size.transpose(); } - QRectF rect = QRectF( - QPointF(margins.left(),margins.top()), - QPointF(size.width()-margins.right(), size.height()-margins.bottom()) - ); + QRectF rect = QRectF(QPointF(margins.left(),margins.top()), + QPointF(size.width()-margins.right(), size.height()-margins.bottom())); return rect; } @@ -140,11 +152,11 @@ void VPGraphicsSheet::SetShowMargin(bool value) //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsSheet::SetShowBorder(bool value) { - m_showBorder = value; + m_showBorder = value; } //--------------------------------------------------------------------------------------------------------------------- -QRectF VPGraphicsSheet::boundingRect() const +auto VPGraphicsSheet::boundingRect() const -> QRectF { return m_boundingRect; } diff --git a/src/app/puzzle/scene/vpgraphicssheet.h b/src/app/puzzle/scene/vpgraphicssheet.h index ffdd09a07..cfd10fefb 100644 --- a/src/app/puzzle/scene/vpgraphicssheet.h +++ b/src/app/puzzle/scene/vpgraphicssheet.h @@ -32,19 +32,21 @@ #include #include +#include "../layout/layoutdef.h" + class VPLayout; class VPGraphicsSheet : public QGraphicsItem { public: - explicit VPGraphicsSheet(VPLayout *sheet, QGraphicsItem *parent = nullptr); + explicit VPGraphicsSheet(const VPLayoutPtr &layout, QGraphicsItem *parent = nullptr); ~VPGraphicsSheet()=default; - QRectF boundingRect() const override; + auto boundingRect() const -> QRectF override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - QRectF GetSheetRect() const; - QRectF GetMarginsRect() const; + auto GetSheetRect() const -> QRectF; + auto GetMarginsRect() const -> QRectF; /** * @brief SetShowMargin Sets Wether we see the margin @@ -61,7 +63,7 @@ public: private: Q_DISABLE_COPY(VPGraphicsSheet) - VPLayout *m_layout{nullptr}; + VPLayoutWeakPtr m_layout{}; QRectF m_boundingRect; bool m_showMargin{true}; diff --git a/src/app/puzzle/scene/vpgraphicstilegrid.cpp b/src/app/puzzle/scene/vpgraphicstilegrid.cpp index 2fc1ea366..3ce3d539b 100644 --- a/src/app/puzzle/scene/vpgraphicstilegrid.cpp +++ b/src/app/puzzle/scene/vpgraphicstilegrid.cpp @@ -4,7 +4,7 @@ #include "../layout/vplayout.h" //--------------------------------------------------------------------------------------------------------------------- -VPGraphicsTileGrid::VPGraphicsTileGrid(VPLayout *layout, VPTileFactory *tileFactory,QGraphicsItem *parent): +VPGraphicsTileGrid::VPGraphicsTileGrid(const VPLayoutPtr &layout, VPTileFactory *tileFactory, QGraphicsItem *parent): QGraphicsItem(parent), m_tileFactory(tileFactory), m_layout(layout) @@ -21,7 +21,8 @@ VPGraphicsTileGrid::~VPGraphicsTileGrid() //--------------------------------------------------------------------------------------------------------------------- QRectF VPGraphicsTileGrid::boundingRect() const { - if(m_layout->LayoutSettings().GetShowTiles()) + VPLayoutPtr layout = m_layout.toStrongRef(); + if(not layout.isNull() && layout->LayoutSettings().GetShowTiles()) { return QRectF(0, 0, @@ -39,7 +40,8 @@ void VPGraphicsTileGrid::paint(QPainter *painter, const QStyleOptionGraphicsItem Q_UNUSED(widget); Q_UNUSED(option); - if(m_layout->LayoutSettings().GetShowTiles()) + VPLayoutPtr layout = m_layout.toStrongRef(); + if(not layout.isNull() && layout->LayoutSettings().GetShowTiles()) { QPen pen(QColor(255,0,0,127), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); pen.setCosmetic(true); diff --git a/src/app/puzzle/scene/vpgraphicstilegrid.h b/src/app/puzzle/scene/vpgraphicstilegrid.h index 9559f3e55..11fb45b63 100644 --- a/src/app/puzzle/scene/vpgraphicstilegrid.h +++ b/src/app/puzzle/scene/vpgraphicstilegrid.h @@ -33,6 +33,7 @@ #include #include "../vmisc/def.h" +#include "../layout/layoutdef.h" class VPTileFactory; class VPLayout; @@ -40,7 +41,7 @@ class VPLayout; class VPGraphicsTileGrid : public QGraphicsItem { public: - explicit VPGraphicsTileGrid(VPLayout* layout, VPTileFactory *tileFactory, QGraphicsItem *parent = nullptr); + explicit VPGraphicsTileGrid(const VPLayoutPtr &layout, VPTileFactory *tileFactory, QGraphicsItem *parent = nullptr); ~VPGraphicsTileGrid(); QRectF boundingRect() const override; @@ -50,8 +51,8 @@ public: private: Q_DISABLE_COPY(VPGraphicsTileGrid) - VPTileFactory *m_tileFactory{nullptr}; - VPLayout *m_layout{nullptr}; + VPTileFactory * m_tileFactory{nullptr}; + VPLayoutWeakPtr m_layout{}; }; #endif // VPGRAPHICSTILEGRID_H diff --git a/src/app/puzzle/scene/vpmaingraphicsview.cpp b/src/app/puzzle/scene/vpmaingraphicsview.cpp index bcc94bb8e..95c55f583 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.cpp +++ b/src/app/puzzle/scene/vpmaingraphicsview.cpp @@ -46,6 +46,7 @@ #include "vptilefactory.h" #include "vpgraphicspiececontrols.h" #include "../undocommands/vpundopiecemove.h" +#include "../undocommands/vpundopiecerotate.h" #include @@ -95,36 +96,6 @@ VPMainGraphicsView::VPMainGraphicsView(const VPLayoutPtr &layout, VPTileFactory restoreOrigin->setShortcut(restoreOriginShortcut); connect(restoreOrigin, &QAction::triggered, this, &VPMainGraphicsView::RestoreOrigin); this->addAction(restoreOrigin); - - auto *rotateByPlus15 = new QAction(this); - rotateByPlus15->setShortcut(QKeySequence(Qt::Key_BracketLeft)); - connect(rotateByPlus15, &QAction::triggered, this, &VPMainGraphicsView::RotatePiecesByPlus15); - this->addAction(rotateByPlus15); - - auto *rotateByMinus15 = new QAction(this); - rotateByMinus15->setShortcut(QKeySequence(Qt::Key_BracketRight)); - connect(rotateByMinus15, &QAction::triggered, this, &VPMainGraphicsView::RotatePiecesByMinus15); - this->addAction(rotateByMinus15); - - auto *rotateByPlus90 = new QAction(this); - rotateByPlus90->setShortcut(QKeySequence(Qt::ControlModifier + Qt::Key_BracketLeft)); - connect(rotateByPlus90, &QAction::triggered, this, &VPMainGraphicsView::RotatePiecesByPlus90); - this->addAction(rotateByPlus90); - - auto *rotateByMinus90 = new QAction(this); - rotateByMinus90->setShortcut(QKeySequence(Qt::ControlModifier + Qt::Key_BracketRight)); - connect(rotateByMinus90, &QAction::triggered, this, &VPMainGraphicsView::RotatePiecesByMinus90); - this->addAction(rotateByMinus90); - - auto *rotateByPlus1 = new QAction(this); - rotateByPlus1->setShortcut(QKeySequence(Qt::AltModifier + Qt::Key_BracketLeft)); - connect(rotateByPlus1, &QAction::triggered, this, &VPMainGraphicsView::RotatePiecesByPlus1); - this->addAction(rotateByPlus1); - - auto *rotateByMinus1 = new QAction(this); - rotateByMinus1->setShortcut(QKeySequence(Qt::AltModifier + Qt::Key_BracketRight)); - connect(rotateByMinus1, &QAction::triggered, this, &VPMainGraphicsView::RotatePiecesByMinus1); - this->addAction(rotateByMinus1); } //--------------------------------------------------------------------------------------------------------------------- @@ -342,17 +313,62 @@ void VPMainGraphicsView::keyPressEvent(QKeyEvent *event) TranslatePiecesOn(0, 1); } } + else if (event->key() == Qt::Key_BracketLeft) + { + if((event->modifiers() & Qt::ControlModifier) != 0U) + { + RotatePiecesByAngle(90); + } + else if((event->modifiers() & Qt::AltModifier) != 0U) + { + RotatePiecesByAngle(1); + } + else + { + RotatePiecesByAngle(15); + } + } + else if (event->key() == Qt::Key_BracketRight) + { + if((event->modifiers() & Qt::ControlModifier) != 0U) + { + RotatePiecesByAngle(-90); + } + else if((event->modifiers() & Qt::AltModifier) != 0U) + { + RotatePiecesByAngle(-1); + } + else + { + RotatePiecesByAngle(-15); + } + } } //--------------------------------------------------------------------------------------------------------------------- void VPMainGraphicsView::keyReleaseEvent(QKeyEvent *event) { - VMainGraphicsView::keyReleaseEvent(event); - if (event->key() != Qt::Key_Left && event->key() != Qt::Key_Right && event->key() != Qt::Key_Up && - event->key() != Qt::Key_Down) + if (event->key() == Qt::Key_Left || + event->key() == Qt::Key_Right || + event->key() == Qt::Key_Up || + event->key() == Qt::Key_Down || + event->key() == Qt::Key_BracketLeft || + event->key() == Qt::Key_BracketRight) { - m_allowChangeMerge = false; + if (not event->isAutoRepeat()) + { + m_allowChangeMerge = false; + } } + + if (event->key() == Qt::Key_BracketLeft || event->key() == Qt::Key_BracketRight) + { + if (not event->isAutoRepeat()) + { + m_rotationControls->SetIgnorePieceTransformation(false); + } + } + VMainGraphicsView::keyReleaseEvent(event); } //--------------------------------------------------------------------------------------------------------------------- @@ -428,42 +444,6 @@ void VPMainGraphicsView::RestoreOrigin() const } } -//--------------------------------------------------------------------------------------------------------------------- -void VPMainGraphicsView::RotatePiecesByPlus15() const -{ - RotatePiecesByAngle(15); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPMainGraphicsView::RotatePiecesByMinus15() const -{ - RotatePiecesByAngle(-15); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPMainGraphicsView::RotatePiecesByPlus90() const -{ - RotatePiecesByAngle(90); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPMainGraphicsView::RotatePiecesByMinus90() const -{ - RotatePiecesByAngle(-90); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPMainGraphicsView::RotatePiecesByPlus1() const -{ - RotatePiecesByAngle(1); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPMainGraphicsView::RotatePiecesByMinus1() const -{ - RotatePiecesByAngle(-1); -} - //--------------------------------------------------------------------------------------------------------------------- void VPMainGraphicsView::ConnectPiece(VPGraphicsPiece *piece) { @@ -477,7 +457,6 @@ void VPMainGraphicsView::ConnectPiece(VPGraphicsPiece *piece) m_rotationControls, &VPGraphicsPieceControls::on_UpdateControls); connect(piece, &VPGraphicsPiece::PieceTransformationChanged, m_rotationControls, &VPGraphicsPieceControls::on_UpdateControls); - connect(m_rotationControls, &VPGraphicsPieceControls::Rotate, piece, &VPGraphicsPiece::on_Rotate); connect(piece, &VPGraphicsPiece::HideTransformationHandles, m_rotationControls, &VPGraphicsPieceControls::on_HideHandles); connect(piece, &VPGraphicsPiece::HideTransformationHandles, @@ -485,8 +464,10 @@ void VPMainGraphicsView::ConnectPiece(VPGraphicsPiece *piece) } //--------------------------------------------------------------------------------------------------------------------- -void VPMainGraphicsView::RotatePiecesByAngle(qreal angle) const +void VPMainGraphicsView::RotatePiecesByAngle(qreal angle) { + m_rotationControls->SetIgnorePieceTransformation(true); + VPLayoutPtr layout = m_layout.toStrongRef(); if (layout.isNull()) { @@ -501,14 +482,34 @@ void VPMainGraphicsView::RotatePiecesByAngle(qreal angle) const VPTransformationOrigon origin = sheet->TransformationOrigin(); - for(auto *graphicsPiece : m_graphicsPieces) + auto PreparePieces = [this]() { - if (graphicsPiece->isSelected()) + QVector pieces; + for (auto *item : m_graphicsPieces) { - graphicsPiece->on_Rotate(origin.origin, angle); - m_rotationControls->on_UpdateControls(); + if (item->isSelected()) + { + pieces.append(item->GetPiece()); + } } + + return pieces; + }; + + QVector pieces = PreparePieces(); + + if (pieces.size() == 1) + { + auto *command = new VPUndoPieceRotate(pieces.first(), origin.origin, angle, m_allowChangeMerge); + layout->UndoStack()->push(command); } + else if (pieces.size() > 1) + { + auto *command = new VPUndoPiecesRotate(pieces, origin.origin, angle, m_allowChangeMerge); + layout->UndoStack()->push(command); + } + + m_allowChangeMerge = true; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/scene/vpmaingraphicsview.h b/src/app/puzzle/scene/vpmaingraphicsview.h index e1e854d5f..f3b883104 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.h +++ b/src/app/puzzle/scene/vpmaingraphicsview.h @@ -98,12 +98,6 @@ protected: private slots: void RestoreOrigin() const; - void RotatePiecesByPlus15() const; - void RotatePiecesByMinus15() const; - void RotatePiecesByPlus90() const; - void RotatePiecesByMinus90() const; - void RotatePiecesByPlus1() const; - void RotatePiecesByMinus1() const; private: Q_DISABLE_COPY(VPMainGraphicsView) @@ -134,7 +128,7 @@ private: void ConnectPiece(VPGraphicsPiece *piece); - void RotatePiecesByAngle(qreal angle) const; + void RotatePiecesByAngle(qreal angle); void TranslatePiecesOn(qreal dx, qreal dy); }; diff --git a/src/app/puzzle/undocommands/vpundocommand.h b/src/app/puzzle/undocommands/vpundocommand.h index c2665264d..23f8c8e22 100644 --- a/src/app/puzzle/undocommands/vpundocommand.h +++ b/src/app/puzzle/undocommands/vpundocommand.h @@ -37,7 +37,9 @@ namespace ML enum class UndoCommand: qint8 { MovePiece = 0, - MovePieces = 1 + MovePieces = 1, + RotatePiece = 2, + RotatePieces = 3, }; } diff --git a/src/app/puzzle/undocommands/vpundopiecerotate.cpp b/src/app/puzzle/undocommands/vpundopiecerotate.cpp new file mode 100644 index 000000000..21afec0b6 --- /dev/null +++ b/src/app/puzzle/undocommands/vpundopiecerotate.cpp @@ -0,0 +1,266 @@ +/************************************************************************ + ** + ** @file vpundopiecerotate.cpp + ** @author Roman Telezhynskyi + ** @date 18 8, 2021 + ** + ** @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) 2021 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 "vpundopiecerotate.h" +#include "../layout/vppiece.h" +#include "../layout/vplayout.h" + +//--------------------------------------------------------------------------------------------------------------------- +VPUndoPieceRotate::VPUndoPieceRotate(const VPPiecePtr &piece, const QPointF &origin, qreal angle, bool allowMerge, + QUndoCommand *parent) + : VPUndoCommand(parent), + m_piece(piece), + m_origin(origin), + m_angle(angle), + m_allowMerge(allowMerge) +{ + SCASSERT(not piece.isNull()) + + m_oldTransform = piece->GetMatrix(); + + setText(QObject::tr("rotate piece")); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPieceRotate::undo() +{ + VPPiecePtr piece = Piece(); + if (piece.isNull()) + { + return; + } + + VPLayoutPtr layout = piece->Layout(); + if (layout.isNull()) + { + return; + } + + layout->SetFocusedSheet(piece->Sheet()); + + piece->SetMatrix(m_oldTransform); + emit layout->PieceTransformationChanged(piece); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPieceRotate::redo() +{ + VPPiecePtr piece = Piece(); + if (piece.isNull()) + { + return; + } + + VPLayoutPtr layout = piece->Layout(); + if (layout.isNull()) + { + return; + } + + layout->SetFocusedSheet(piece->Sheet()); + + piece->Rotate(m_origin, m_angle); + emit layout->PieceTransformationChanged(piece); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPieceRotate::mergeWith(const QUndoCommand *command) -> bool +{ + if (command->id() != id()) // make sure other is also an VPUndoPieceMove command + { + return false; + } + + const auto *moveCommand = dynamic_cast(command); + SCASSERT(moveCommand != nullptr) + + VPPiecePtr piece = Piece(); + if (not moveCommand->AllowMerge() || (moveCommand->Piece().isNull() || piece.isNull()) || + moveCommand->Piece() != piece || moveCommand->Origin() != m_origin) + { + return false; + } + + m_angle += moveCommand->Angle(); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPieceRotate::id() const -> int +{ + return static_cast(ML::UndoCommand::RotatePiece); +} + +// rotate pieces +//--------------------------------------------------------------------------------------------------------------------- +VPUndoPiecesRotate::VPUndoPiecesRotate(const QVector &pieces, const QPointF &origin, qreal angle, + bool allowMerge, QUndoCommand *parent) + : VPUndoCommand(parent), + m_origin(origin), + m_angle(angle), + m_allowMerge(allowMerge) +{ + setText(QObject::tr("rotate pieces")); + + for (const auto& piece : pieces) + { + if (not piece.isNull()) + { + m_pieces.append(piece); + m_oldTransforms.insert(piece->GetUniqueID(), piece->GetMatrix()); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPiecesRotate::undo() +{ + if (m_pieces.isEmpty()) + { + return; + } + + VPLayoutPtr layout = Layout(); + if (layout.isNull()) + { + return; + } + + layout->SetFocusedSheet(Sheet()); + + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + if (m_oldTransforms.contains(p->GetUniqueID())) + { + p->SetMatrix(m_oldTransforms.value(p->GetUniqueID())); + emit layout->PieceTransformationChanged(p); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPiecesRotate::redo() +{ + if (m_pieces.isEmpty()) + { + return; + } + + VPLayoutPtr layout = Layout(); + if (layout.isNull()) + { + return; + } + + layout->SetFocusedSheet(Sheet()); + + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + p->Rotate(m_origin, m_angle); + emit layout->PieceTransformationChanged(p); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesRotate::mergeWith(const QUndoCommand *command) -> bool +{ + if (command->id() != id()) // make sure other is also an VPUndoPieceMove command + { + return false; + } + + const auto *moveCommand = dynamic_cast(command); + SCASSERT(moveCommand != nullptr) + + if (not moveCommand->AllowMerge() || moveCommand->PieceIds() != PieceIds() || moveCommand->Origin() != m_origin) + { + return false; + } + + m_angle += moveCommand->Angle(); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesRotate::id() const -> int +{ + return static_cast(ML::UndoCommand::RotatePieces); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesRotate::PieceIds() const -> QSet +{ + QSet ids; + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + ids.insert(p->GetUniqueID()); + } + }; + + return ids; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesRotate::Layout() const -> VPLayoutPtr +{ + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + return p->Layout(); + } + } + + return nullptr; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesRotate::Sheet() const -> VPSheetPtr +{ + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + return p->Sheet(); + } + } + + return nullptr; +} diff --git a/src/app/puzzle/undocommands/vpundopiecerotate.h b/src/app/puzzle/undocommands/vpundopiecerotate.h new file mode 100644 index 000000000..1738bfa6e --- /dev/null +++ b/src/app/puzzle/undocommands/vpundopiecerotate.h @@ -0,0 +1,142 @@ +/************************************************************************ + ** + ** @file vpundopiecerotate.h + ** @author Roman Telezhynskyi + ** @date 18 8, 2021 + ** + ** @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) 2021 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 VPUNDOPIECEROTATE_H +#define VPUNDOPIECEROTATE_H + +#include "vpundocommand.h" + +#include + +#include "../layout/layoutdef.h" + +class VPUndoPieceRotate : public VPUndoCommand +{ + Q_OBJECT +public: + VPUndoPieceRotate(const VPPiecePtr &piece, const QPointF &origin, qreal angle, bool allowMerge, + QUndoCommand *parent = nullptr); + + virtual ~VPUndoPieceRotate()=default; + + virtual void undo() override; + virtual void redo() override; + // cppcheck-suppress unusedFunction + virtual auto mergeWith(const QUndoCommand *command) -> bool override; + virtual auto id() const -> int override ; + + auto Piece() const -> VPPiecePtr; + auto Origin() const -> QPointF; + auto Angle() const -> qreal; + auto AllowMerge() const -> bool; + +private: + Q_DISABLE_COPY(VPUndoPieceRotate) + + VPPieceWeakPtr m_piece; + QTransform m_oldTransform{}; + QPointF m_origin; + qreal m_angle; + bool m_allowMerge; +}; + +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPUndoPieceRotate::Piece() const -> VPPiecePtr +{ + return m_piece; +} + +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPUndoPieceRotate::Origin() const -> QPointF +{ + return m_origin; +} + +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPUndoPieceRotate::Angle() const -> qreal +{ + return m_angle; +} + +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPUndoPieceRotate::AllowMerge() const -> bool +{ + return m_allowMerge; +} + +// Rotate pieces +class VPUndoPiecesRotate : public VPUndoCommand +{ + Q_OBJECT +public: + explicit VPUndoPiecesRotate(const QVector &pieces, const QPointF &origin, qreal angle, bool allowMerge, + QUndoCommand *parent = nullptr); + virtual ~VPUndoPiecesRotate()=default; + + virtual void undo() override; + virtual void redo() override; + // cppcheck-suppress unusedFunction + virtual auto mergeWith(const QUndoCommand *command) -> bool override; + virtual auto id() const -> int override ; + + auto PieceIds() const -> QSet; + auto Origin() const -> QPointF; + auto Angle() const -> qreal; + auto AllowMerge() const -> bool; + +private: + Q_DISABLE_COPY(VPUndoPiecesRotate) + + QVector m_pieces{}; + QMap m_oldTransforms{}; + QPointF m_origin; + qreal m_angle; + bool m_allowMerge; + + auto Layout() const -> VPLayoutPtr; + auto Sheet() const -> VPSheetPtr; +}; + +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPUndoPiecesRotate::Origin() const -> QPointF +{ + return m_origin; +} + +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPUndoPiecesRotate::Angle() const -> qreal +{ + return m_angle; +} + +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPUndoPiecesRotate::AllowMerge() const -> bool +{ + return m_allowMerge; +} + +#endif // VPUNDOPIECEROTATE_H diff --git a/src/app/puzzle/xml/vplayoutfilereader.cpp b/src/app/puzzle/xml/vplayoutfilereader.cpp index 496cdc521..a36e7ea3a 100644 --- a/src/app/puzzle/xml/vplayoutfilereader.cpp +++ b/src/app/puzzle/xml/vplayoutfilereader.cpp @@ -179,7 +179,7 @@ auto StringToMarkerShape(const QString &string) -> PlaceLabelImg } // namespace //--------------------------------------------------------------------------------------------------------------------- -auto VPLayoutFileReader::ReadFile(VPLayout *layout, QFile *file) -> bool +auto VPLayoutFileReader::ReadFile(const VPLayoutPtr &layout, QFile *file) -> bool { setDevice(file); @@ -199,7 +199,7 @@ auto VPLayoutFileReader::ReadFile(VPLayout *layout, QFile *file) -> bool } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadLayout(VPLayout *layout) +void VPLayoutFileReader::ReadLayout(const VPLayoutPtr &layout) { AssertRootTag(ML::TagLayout); @@ -232,7 +232,7 @@ void VPLayoutFileReader::ReadLayout(VPLayout *layout) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadProperties(VPLayout *layout) +void VPLayoutFileReader::ReadProperties(const VPLayoutPtr &layout) { AssertRootTag(ML::TagProperties); @@ -288,7 +288,7 @@ void VPLayoutFileReader::ReadProperties(VPLayout *layout) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadControl(VPLayout *layout) +void VPLayoutFileReader::ReadControl(const VPLayoutPtr &layout) { AssertRootTag(ML::TagControl); @@ -304,7 +304,7 @@ void VPLayoutFileReader::ReadControl(VPLayout *layout) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadUnplacedPieces(VPLayout *layout) +void VPLayoutFileReader::ReadUnplacedPieces(const VPLayoutPtr &layout) { AssertRootTag(ML::TagUnplacedPieces); @@ -312,7 +312,7 @@ void VPLayoutFileReader::ReadUnplacedPieces(VPLayout *layout) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadTiles(VPLayout *layout) +void VPLayoutFileReader::ReadTiles(const VPLayoutPtr &layout) { AssertRootTag(ML::TagTiles); @@ -347,7 +347,7 @@ void VPLayoutFileReader::ReadTiles(VPLayout *layout) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadSheets(VPLayout *layout) +void VPLayoutFileReader::ReadSheets(const VPLayoutPtr &layout) { AssertRootTag(ML::TagSheets); @@ -366,7 +366,7 @@ void VPLayoutFileReader::ReadSheets(VPLayout *layout) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadSheet(VPLayout *layout) +void VPLayoutFileReader::ReadSheet(const VPLayoutPtr &layout) { AssertRootTag(ML::TagSheet); @@ -376,7 +376,7 @@ void VPLayoutFileReader::ReadSheet(VPLayout *layout) ML::TagPieces // 1 }; - QScopedPointer sheet (new VPSheet(layout)); + VPSheetPtr sheet(new VPSheet(layout)); while (readNextStartElement()) { @@ -386,11 +386,7 @@ void VPLayoutFileReader::ReadSheet(VPLayout *layout) sheet->SetName(readElementText()); break; case 1: // pieces -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) - ReadPieces(layout, sheet.get()); -#else - ReadPieces(layout, sheet.data()); -#endif + ReadPieces(layout, sheet); break; default: qCDebug(MLReader, "Ignoring tag %s", qUtf8Printable(name().toString())); @@ -401,21 +397,21 @@ void VPLayoutFileReader::ReadSheet(VPLayout *layout) readElementText(); - layout->AddSheet(sheet.take()); + layout->AddSheet(sheet); } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadPieces(VPLayout *layout, VPSheet *sheet) +void VPLayoutFileReader::ReadPieces(const VPLayoutPtr &layout, const VPSheetPtr &sheet) { while (readNextStartElement()) { if (name() == ML::TagPiece) { - QScopedPointerpiece(new VPPiece()); - ReadPiece(piece.data()); + VPPiecePtr piece(new VPPiece()); + ReadPiece(piece); piece->SetSheet(sheet); - layout->AddPiece(piece.take()); + VPLayout::AddPiece(layout, piece); } else { @@ -426,7 +422,7 @@ void VPLayoutFileReader::ReadPieces(VPLayout *layout, VPSheet *sheet) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadPiece(VPPiece *piece) +void VPLayoutFileReader::ReadPiece(const VPPiecePtr &piece) { AssertRootTag(ML::TagPiece); @@ -490,7 +486,7 @@ void VPLayoutFileReader::ReadPiece(VPPiece *piece) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadSeamAllowance(VPPiece *piece) +void VPLayoutFileReader::ReadSeamAllowance(const VPPiecePtr &piece) { AssertRootTag(ML::TagSeamAllowance); @@ -512,7 +508,7 @@ void VPLayoutFileReader::ReadSeamAllowance(VPPiece *piece) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadGrainline(VPPiece *piece) +void VPLayoutFileReader::ReadGrainline(const VPPiecePtr &piece) { AssertRootTag(ML::TagGrainline); @@ -533,7 +529,7 @@ void VPLayoutFileReader::ReadGrainline(VPPiece *piece) } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadNotches(VPPiece *piece) +void VPLayoutFileReader::ReadNotches(const VPPiecePtr &piece) { AssertRootTag(ML::TagNotches); @@ -576,7 +572,7 @@ auto VPLayoutFileReader::ReadNotch() -> VLayoutPassmark } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadInternalPaths(VPPiece *piece) +void VPLayoutFileReader::ReadInternalPaths(const VPPiecePtr &piece) { AssertRootTag(ML::TagInternalPaths); @@ -615,7 +611,7 @@ auto VPLayoutFileReader::ReadInternalPath() -> VLayoutPiecePath } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadMarkers(VPPiece *piece) +void VPLayoutFileReader::ReadMarkers(const VPPiecePtr &piece) { AssertRootTag(ML::TagMarkers); @@ -658,7 +654,7 @@ auto VPLayoutFileReader::ReadMarker() -> VLayoutPlaceLabel } //--------------------------------------------------------------------------------------------------------------------- -void VPLayoutFileReader::ReadLabels(VPPiece *piece) +void VPLayoutFileReader::ReadLabels(const VPPiecePtr &piece) { AssertRootTag(ML::TagLabels); diff --git a/src/libs/vlayout/vabstractpiece.cpp b/src/libs/vlayout/vabstractpiece.cpp index 4752e7376..7a0112880 100644 --- a/src/libs/vlayout/vabstractpiece.cpp +++ b/src/libs/vlayout/vabstractpiece.cpp @@ -1630,6 +1630,12 @@ void VAbstractPiece::SetUUID(const QString &uuid) d->m_uuid = temp.isNull() ? QUuid::createUuid() : temp; } +//--------------------------------------------------------------------------------------------------------------------- +QString VAbstractPiece::GetUniqueID() const +{ + return d->m_uuid.toString(); +} + //--------------------------------------------------------------------------------------------------------------------- qreal VSAPoint::GetSABefore(qreal width) const { diff --git a/src/libs/vlayout/vabstractpiece.h b/src/libs/vlayout/vabstractpiece.h index aa6e7edf7..fbeef6416 100644 --- a/src/libs/vlayout/vabstractpiece.h +++ b/src/libs/vlayout/vabstractpiece.h @@ -96,6 +96,12 @@ public: void SetUUID(const QUuid &uuid); void SetUUID(const QString &uuid); + /** + * @brief GetUniqueID returns unique piece id. Combines UUID and gradation label. + * @return unique piece id. + */ + QString GetUniqueID() const; + static QVector Equidistant(QVector points, qreal width, const QString &name); static qreal SumTrapezoids(const QVector &points); static QVector CheckLoops(const QVector &points);