From 3fbe96c2a7175b62573f278e2e6bb0afba360268 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Mon, 9 Aug 2021 15:09:10 +0300 Subject: [PATCH] Piece rotation. --- src/app/puzzle/{ => carousel}/vpcarrousel.cpp | 2 +- src/app/puzzle/{ => carousel}/vpcarrousel.h | 4 +- src/app/puzzle/{ => carousel}/vpcarrousel.ui | 2 +- .../{ => carousel}/vpcarrouselpiece.cpp | 5 +- .../puzzle/{ => carousel}/vpcarrouselpiece.h | 3 +- .../{ => carousel}/vpcarrouselpiecelist.cpp | 7 +- .../{ => carousel}/vpcarrouselpiecelist.h | 0 .../puzzle/{ => carousel}/vpmimedatapiece.cpp | 2 + .../puzzle/{ => carousel}/vpmimedatapiece.h | 3 +- src/app/puzzle/{ => layout}/vplayout.cpp | 1 - src/app/puzzle/{ => layout}/vplayout.h | 0 .../puzzle/{ => layout}/vplayoutsettings.cpp | 0 .../puzzle/{ => layout}/vplayoutsettings.h | 0 src/app/puzzle/layout/vppiece.cpp | 171 ++++ src/app/puzzle/layout/vppiece.h | 96 +++ src/app/puzzle/{ => layout}/vpsheet.cpp | 27 + src/app/puzzle/{ => layout}/vpsheet.h | 19 + src/app/puzzle/puzzle.pri | 53 +- src/app/puzzle/scene/scenedef.h | 38 + .../puzzle/{ => scene}/vpgraphicspiece.cpp | 477 +++++------- src/app/puzzle/{ => scene}/vpgraphicspiece.h | 51 +- .../puzzle/scene/vpgraphicspiececontrols.cpp | 736 ++++++++++++++++++ .../puzzle/scene/vpgraphicspiececontrols.h | 129 +++ .../puzzle/{ => scene}/vpgraphicssheet.cpp | 4 +- src/app/puzzle/{ => scene}/vpgraphicssheet.h | 2 +- .../puzzle/{ => scene}/vpgraphicstilegrid.cpp | 4 +- .../puzzle/{ => scene}/vpgraphicstilegrid.h | 0 .../puzzle/{ => scene}/vpmaingraphicsview.cpp | 190 ++++- .../puzzle/{ => scene}/vpmaingraphicsview.h | 28 +- src/app/puzzle/vpexporter.cpp | 4 +- src/app/puzzle/vpexporter.h | 2 +- src/app/puzzle/vpmainwindow.cpp | 37 +- src/app/puzzle/vpmainwindow.h | 8 +- src/app/puzzle/vpmainwindow.ui | 2 +- src/app/puzzle/vppiece.cpp | 216 ----- src/app/puzzle/vppiece.h | 181 ----- src/app/puzzle/vptilefactory.cpp | 9 +- src/app/puzzle/vptilefactory.h | 7 +- src/app/puzzle/xml/vplayoutfilereader.cpp | 8 +- src/app/puzzle/xml/vplayoutfilereader.h | 4 +- src/app/puzzle/xml/vplayoutfilewriter.cpp | 10 +- src/libs/vlayout/vlayoutpiece.cpp | 8 +- src/libs/vlayout/vlayoutpiece.h | 1 + 43 files changed, 1723 insertions(+), 828 deletions(-) rename src/app/puzzle/{ => carousel}/vpcarrousel.cpp (99%) rename src/app/puzzle/{ => carousel}/vpcarrousel.h (97%) rename src/app/puzzle/{ => carousel}/vpcarrousel.ui (97%) rename src/app/puzzle/{ => carousel}/vpcarrouselpiece.cpp (97%) rename src/app/puzzle/{ => carousel}/vpcarrouselpiece.h (98%) rename src/app/puzzle/{ => carousel}/vpcarrouselpiecelist.cpp (96%) rename src/app/puzzle/{ => carousel}/vpcarrouselpiecelist.h (100%) rename src/app/puzzle/{ => carousel}/vpmimedatapiece.cpp (98%) rename src/app/puzzle/{ => carousel}/vpmimedatapiece.h (98%) rename src/app/puzzle/{ => layout}/vplayout.cpp (99%) rename src/app/puzzle/{ => layout}/vplayout.h (100%) rename src/app/puzzle/{ => layout}/vplayoutsettings.cpp (100%) rename src/app/puzzle/{ => layout}/vplayoutsettings.h (100%) create mode 100644 src/app/puzzle/layout/vppiece.cpp create mode 100644 src/app/puzzle/layout/vppiece.h rename src/app/puzzle/{ => layout}/vpsheet.cpp (75%) rename src/app/puzzle/{ => layout}/vpsheet.h (84%) create mode 100644 src/app/puzzle/scene/scenedef.h rename src/app/puzzle/{ => scene}/vpgraphicspiece.cpp (57%) rename src/app/puzzle/{ => scene}/vpgraphicspiece.h (70%) create mode 100644 src/app/puzzle/scene/vpgraphicspiececontrols.cpp create mode 100644 src/app/puzzle/scene/vpgraphicspiececontrols.h rename src/app/puzzle/{ => scene}/vpgraphicssheet.cpp (98%) rename src/app/puzzle/{ => scene}/vpgraphicssheet.h (99%) rename src/app/puzzle/{ => scene}/vpgraphicstilegrid.cpp (97%) rename src/app/puzzle/{ => scene}/vpgraphicstilegrid.h (100%) rename src/app/puzzle/{ => scene}/vpmaingraphicsview.cpp (55%) rename src/app/puzzle/{ => scene}/vpmaingraphicsview.h (83%) delete mode 100644 src/app/puzzle/vppiece.cpp delete mode 100644 src/app/puzzle/vppiece.h diff --git a/src/app/puzzle/vpcarrousel.cpp b/src/app/puzzle/carousel/vpcarrousel.cpp similarity index 99% rename from src/app/puzzle/vpcarrousel.cpp rename to src/app/puzzle/carousel/vpcarrousel.cpp index 08a13944a..f2c7ab691 100644 --- a/src/app/puzzle/vpcarrousel.cpp +++ b/src/app/puzzle/carousel/vpcarrousel.cpp @@ -33,7 +33,7 @@ #include #include "../vmisc/backport/qoverload.h" -#include "vpsheet.h" +#include "../layout/vpsheet.h" #include #include diff --git a/src/app/puzzle/vpcarrousel.h b/src/app/puzzle/carousel/vpcarrousel.h similarity index 97% rename from src/app/puzzle/vpcarrousel.h rename to src/app/puzzle/carousel/vpcarrousel.h index 304641119..ab8b75886 100644 --- a/src/app/puzzle/vpcarrousel.h +++ b/src/app/puzzle/carousel/vpcarrousel.h @@ -32,8 +32,8 @@ #include #include #include -#include "vplayout.h" -#include "vppiece.h" +#include "../layout/vplayout.h" +#include "../layout/vppiece.h" namespace Ui { diff --git a/src/app/puzzle/vpcarrousel.ui b/src/app/puzzle/carousel/vpcarrousel.ui similarity index 97% rename from src/app/puzzle/vpcarrousel.ui rename to src/app/puzzle/carousel/vpcarrousel.ui index 32e23095e..f0a03552f 100644 --- a/src/app/puzzle/vpcarrousel.ui +++ b/src/app/puzzle/carousel/vpcarrousel.ui @@ -76,7 +76,7 @@ VPCarrouselPieceList QListWidget -
vpcarrouselpiecelist.h
+
carousel/vpcarrouselpiecelist.h
diff --git a/src/app/puzzle/vpcarrouselpiece.cpp b/src/app/puzzle/carousel/vpcarrouselpiece.cpp similarity index 97% rename from src/app/puzzle/vpcarrouselpiece.cpp rename to src/app/puzzle/carousel/vpcarrouselpiece.cpp index bad64e9d3..9732776f0 100644 --- a/src/app/puzzle/vpcarrouselpiece.cpp +++ b/src/app/puzzle/carousel/vpcarrouselpiece.cpp @@ -35,7 +35,8 @@ #include "vpmimedatapiece.h" #include "vpcarrouselpiecelist.h" #include "vpcarrousel.h" -#include "vpsheet.h" +#include "../layout/vpsheet.h" +#include "../layout/vppiece.h" #include @@ -64,7 +65,7 @@ auto VPCarrouselPiece::GetPiece() -> VPPiece * //--------------------------------------------------------------------------------------------------------------------- void VPCarrouselPiece::RefreshSelection() { - setSelected(m_piece->GetIsSelected()); + setSelected(m_piece->IsSelected()); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpcarrouselpiece.h b/src/app/puzzle/carousel/vpcarrouselpiece.h similarity index 98% rename from src/app/puzzle/vpcarrouselpiece.h rename to src/app/puzzle/carousel/vpcarrouselpiece.h index 781d4beef..1e13ea9b3 100644 --- a/src/app/puzzle/vpcarrouselpiece.h +++ b/src/app/puzzle/carousel/vpcarrouselpiece.h @@ -31,8 +31,7 @@ #include #include -#include "vppiece.h" - +class VPPiece; class VPCarrouselPiece : public QListWidgetItem { diff --git a/src/app/puzzle/vpcarrouselpiecelist.cpp b/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp similarity index 96% rename from src/app/puzzle/vpcarrouselpiecelist.cpp rename to src/app/puzzle/carousel/vpcarrouselpiecelist.cpp index 852dfc90e..da13fa8f4 100644 --- a/src/app/puzzle/vpcarrouselpiecelist.cpp +++ b/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp @@ -37,7 +37,7 @@ #include "vpcarrouselpiece.h" #include "../vmisc/backport/qoverload.h" #include "vpmimedatapiece.h" -#include "vpsheet.h" +#include "../layout/vpsheet.h" #include @@ -72,8 +72,7 @@ void VPCarrouselPieceList::Refresh() { // update the label of the piece auto* carrouselpiece = new VPCarrouselPiece(piece, this); - carrouselpiece->setSelected(piece->GetIsSelected()); - connect(piece, &VPPiece::SelectionChanged, this, &VPCarrouselPieceList::on_SelectionChangedExternal); + carrouselpiece->setSelected(piece->IsSelected()); } sortItems(); } @@ -146,7 +145,7 @@ void VPCarrouselPieceList::startDrag(Qt::DropActions supportedActions) if(drag->exec() == Qt::MoveAction) { m_carrousel->Refresh(); - piece->SetIsSelected(true); + piece->SetSelected(true); } } } diff --git a/src/app/puzzle/vpcarrouselpiecelist.h b/src/app/puzzle/carousel/vpcarrouselpiecelist.h similarity index 100% rename from src/app/puzzle/vpcarrouselpiecelist.h rename to src/app/puzzle/carousel/vpcarrouselpiecelist.h diff --git a/src/app/puzzle/vpmimedatapiece.cpp b/src/app/puzzle/carousel/vpmimedatapiece.cpp similarity index 98% rename from src/app/puzzle/vpmimedatapiece.cpp rename to src/app/puzzle/carousel/vpmimedatapiece.cpp index 912aed437..8dbfc53db 100644 --- a/src/app/puzzle/vpmimedatapiece.cpp +++ b/src/app/puzzle/carousel/vpmimedatapiece.cpp @@ -31,6 +31,8 @@ #include #include +#include "../layout/vppiece.h" + const QString VPMimeDataPiece::mineFormatPiecePtr = QStringLiteral("application/vnd.puzzle.piece.ptr"); //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpmimedatapiece.h b/src/app/puzzle/carousel/vpmimedatapiece.h similarity index 98% rename from src/app/puzzle/vpmimedatapiece.h rename to src/app/puzzle/carousel/vpmimedatapiece.h index 207273663..235395f7b 100644 --- a/src/app/puzzle/vpmimedatapiece.h +++ b/src/app/puzzle/carousel/vpmimedatapiece.h @@ -31,7 +31,7 @@ #include -#include "vppiece.h" +class VPPiece; class VPMimeDataPiece : public QMimeData { @@ -65,5 +65,4 @@ private: VPPiece *m_piece{nullptr}; }; - #endif // VPMIMEDATAPIECE_H diff --git a/src/app/puzzle/vplayout.cpp b/src/app/puzzle/layout/vplayout.cpp similarity index 99% rename from src/app/puzzle/vplayout.cpp rename to src/app/puzzle/layout/vplayout.cpp index 9273cc26f..ede2f73e2 100644 --- a/src/app/puzzle/vplayout.cpp +++ b/src/app/puzzle/layout/vplayout.cpp @@ -30,7 +30,6 @@ #include "vppiece.h" #include "vpsheet.h" - #include Q_LOGGING_CATEGORY(pLayout, "p.layout") diff --git a/src/app/puzzle/vplayout.h b/src/app/puzzle/layout/vplayout.h similarity index 100% rename from src/app/puzzle/vplayout.h rename to src/app/puzzle/layout/vplayout.h diff --git a/src/app/puzzle/vplayoutsettings.cpp b/src/app/puzzle/layout/vplayoutsettings.cpp similarity index 100% rename from src/app/puzzle/vplayoutsettings.cpp rename to src/app/puzzle/layout/vplayoutsettings.cpp diff --git a/src/app/puzzle/vplayoutsettings.h b/src/app/puzzle/layout/vplayoutsettings.h similarity index 100% rename from src/app/puzzle/vplayoutsettings.h rename to src/app/puzzle/layout/vplayoutsettings.h diff --git a/src/app/puzzle/layout/vppiece.cpp b/src/app/puzzle/layout/vppiece.cpp new file mode 100644 index 000000000..f5e197c58 --- /dev/null +++ b/src/app/puzzle/layout/vppiece.cpp @@ -0,0 +1,171 @@ +/************************************************************************ + ** + ** @file vppiece.cpp + ** @author Ronan Le Tiec + ** @date 13 4, 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 "vppiece.h" + +#include + +#include "../vmisc/def.h" +#include "vpsheet.h" + +#include +#include +#include + +Q_LOGGING_CATEGORY(pPiece, "p.piece") + +//--------------------------------------------------------------------------------------------------------------------- +VPPiece::VPPiece(const VLayoutPiece &layoutPiece) + : VLayoutPiece(layoutPiece) +{ + ClearTransformations(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::ClearTransformations() +{ + // Reset the piece position to the default state + QTransform matrix; + SetMatrix(matrix); + // translate the piece so that the top left corner of the bouding rect of the piece is at the position + // (0,0) in the sheet coordinate system + const QPointF offset = MappedDetailBoundingRect().topLeft(); + matrix.translate(-offset.x() ,-offset.y()); + SetMatrix(matrix); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::SetPosition(QPointF point) +{ + QTransform matrix = GetMatrix(); + const QPointF offset = MappedDetailBoundingRect().topLeft(); + matrix.translate(point.x() - offset.x(), point.y() - offset.y()); + SetMatrix(matrix); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPPiece::GetPosition() -> QPointF +{ + QTransform matrix = GetMatrix(); + return QPointF(matrix.dx(), matrix.dy()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::RotateToGrainline() +{ + if (not IsGrainlineEnabled() || m_sheet == nullptr) + { + return; + } + + const QVector grainlinePoints = GetMappedGrainline(); + if (grainlinePoints.count() < 2) + { + return; + } + + QLineF grainline(grainlinePoints.first(), grainlinePoints.last()); + + QLineF canonical(grainlinePoints.first().x(), grainlinePoints.first().y(), + grainlinePoints.first().x()+100, grainlinePoints.first().y()); + + GrainlineType grainlineType = m_sheet->GrainlineType(); + + auto DegreesAtFront = [grainline, canonical, grainlineType]() + { + QLineF atFront = canonical; + if (grainlineType == GrainlineType::Vertical) + { + atFront.setAngle(90); + } + + return grainline.angleTo(atFront); + }; + + auto DegreesAtRear = [grainline, canonical, grainlineType]() + { + QLineF atRear = canonical; + atRear.setAngle(grainlineType == GrainlineType::Vertical ? 270 : 180); + + return grainline.angleTo(atRear); + }; + + GrainlineArrowDirection type = GrainlineArrowType(); + qreal degrees = 0; + + if (type == GrainlineArrowDirection::atFront) + { + degrees = DegreesAtFront(); + } + else if (type == GrainlineArrowDirection::atRear) + { + degrees = DegreesAtRear(); + } + else + { + degrees = qMin(DegreesAtFront(), DegreesAtRear()); + } + + Rotate(MappedDetailBoundingRect().center(), degrees); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::SetSelected(bool value) +{ + m_isSelected = value; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPPiece::IsSelected() const -> bool +{ + return m_isSelected; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPPiece::Sheet() const -> VPSheet * +{ + return m_sheet; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::SetSheet(VPSheet *newSheet) +{ + m_sheet = newSheet; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPPiece::Layout() const -> VPLayout * +{ + return m_layout; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPPiece::SetLayout(VPLayout *layout) +{ + SCASSERT(layout != nullptr) + m_layout = layout; +} diff --git a/src/app/puzzle/layout/vppiece.h b/src/app/puzzle/layout/vppiece.h new file mode 100644 index 000000000..a21bea9ad --- /dev/null +++ b/src/app/puzzle/layout/vppiece.h @@ -0,0 +1,96 @@ +/************************************************************************ + ** + ** @file vppiece.h + ** @author Ronan Le Tiec + ** @date 13 4, 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 VPPIECE_H +#define VPPIECE_H + +#include +#include +#include +#include + +#include "../vlayout/vlayoutpiece.h" + +class VPLayout; +class VPSheet; + +class VPPiece : public VLayoutPiece +{ +public: + VPPiece() = default; + explicit VPPiece(const VLayoutPiece &layoutPiece); + + virtual ~VPPiece() = default; + + void ClearTransformations(); + + /** + * @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 + */ + auto GetPosition() -> QPointF; + + /** + * @brief RotateToGrainline rotates the piece to follow the grainline + */ + void RotateToGrainline(); + + /** + * @brief SetSelected Sets wether the piece is selected + * @param value true if the piece is selected + */ + void SetSelected(bool value); + + /** + * @brief IsSelected Returns wether the piece is selected. It emit the signal SelectionChanged + * @return true if the piece is selected + */ + auto IsSelected() const -> bool; + + auto Sheet() const -> VPSheet *; + void SetSheet(VPSheet *newSheet); + + auto Layout() const -> VPLayout *; + void SetLayout(VPLayout *layout); + +private: + Q_DISABLE_COPY(VPPiece) + + VPLayout *m_layout{nullptr}; + + VPSheet *m_sheet{nullptr}; + + bool m_isSelected{false}; +}; + +#endif // VPPIECE_H diff --git a/src/app/puzzle/vpsheet.cpp b/src/app/puzzle/layout/vpsheet.cpp similarity index 75% rename from src/app/puzzle/vpsheet.cpp rename to src/app/puzzle/layout/vpsheet.cpp index 71f6732c6..3eb1fa41d 100644 --- a/src/app/puzzle/vpsheet.cpp +++ b/src/app/puzzle/layout/vpsheet.cpp @@ -85,3 +85,30 @@ void VPSheet::SetVisible(bool visible) { m_visible = visible; } + +//--------------------------------------------------------------------------------------------------------------------- +auto VPSheet::GrainlineType() const -> enum GrainlineType +{ + if (m_layout != nullptr) + { + QSizeF size = m_layout->LayoutSettings().GetSheetSize(); + if (size.height() < size.width()) + { + return GrainlineType::Horizontal; + } + } + + return GrainlineType::Vertical; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPSheet::TransformationOrigin() const -> const VPTransformationOrigon & +{ + return m_transformationOrigin; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPSheet::SetTransformationOrigin(const VPTransformationOrigon &newTransformationOrigin) +{ + m_transformationOrigin = newTransformationOrigin; +} diff --git a/src/app/puzzle/vpsheet.h b/src/app/puzzle/layout/vpsheet.h similarity index 84% rename from src/app/puzzle/vpsheet.h rename to src/app/puzzle/layout/vpsheet.h index 37a4292e3..6c564529b 100644 --- a/src/app/puzzle/vpsheet.h +++ b/src/app/puzzle/layout/vpsheet.h @@ -40,6 +40,18 @@ class VPLayout; class VPPiece; +enum class GrainlineType : qint8 +{ + Vertical, + Horizontal +}; + +struct VPTransformationOrigon +{ + QPointF origin{}; + bool custom{false}; +}; + class VPSheet : public QObject { Q_OBJECT @@ -73,6 +85,11 @@ public: bool IsVisible() const; void SetVisible(bool visible); + auto GrainlineType() const -> GrainlineType; + + auto TransformationOrigin() const -> const VPTransformationOrigon &; + void SetTransformationOrigin(const VPTransformationOrigon &newTransformationOrigin); + private: Q_DISABLE_COPY(VPSheet) @@ -83,6 +100,8 @@ private: QUuid m_uuid{QUuid::createUuid()}; bool m_visible{true}; + + VPTransformationOrigon m_transformationOrigin{}; }; #endif // VPSHEET_H diff --git a/src/app/puzzle/puzzle.pri b/src/app/puzzle/puzzle.pri index 9d00cef70..70ac0e7a3 100644 --- a/src/app/puzzle/puzzle.pri +++ b/src/app/puzzle/puzzle.pri @@ -8,23 +8,24 @@ SOURCES += \ $$PWD/dialogs/vpdialogabout.cpp \ $$PWD/main.cpp \ $$PWD/vpapplication.cpp \ - $$PWD/vpcarrousel.cpp \ - $$PWD/vpcarrouselpiece.cpp \ - $$PWD/vpcarrouselpiecelist.cpp \ + $$PWD/carousel/vpcarrousel.cpp \ + $$PWD/carousel/vpcarrouselpiece.cpp \ + $$PWD/carousel/vpcarrouselpiecelist.cpp \ $$PWD/vpcommandline.cpp \ $$PWD/vpcommands.cpp \ $$PWD/vpexporter.cpp \ - $$PWD/vpgraphicspiece.cpp \ - $$PWD/vpgraphicssheet.cpp \ - $$PWD/vpgraphicstilegrid.cpp \ - $$PWD/vplayout.cpp \ - $$PWD/vplayoutsettings.cpp \ - $$PWD/vpmaingraphicsview.cpp \ + $$PWD/scene/vpgraphicspiece.cpp \ + $$PWD/scene/vpgraphicspiececontrols.cpp \ + $$PWD/scene/vpgraphicssheet.cpp \ + $$PWD/scene/vpgraphicstilegrid.cpp \ + $$PWD/layout/vplayout.cpp \ + $$PWD/layout/vplayoutsettings.cpp \ + $$PWD/scene/vpmaingraphicsview.cpp \ $$PWD/vpmainwindow.cpp \ - $$PWD/vpmimedatapiece.cpp \ - $$PWD/vppiece.cpp \ + $$PWD/carousel/vpmimedatapiece.cpp \ + $$PWD/layout/vppiece.cpp \ $$PWD/vpsettings.cpp \ - $$PWD/vpsheet.cpp \ + $$PWD/layout/vpsheet.cpp \ $$PWD/vptilefactory.cpp \ $$PWD/xml/vplayoutfilereader.cpp \ $$PWD/xml/vplayoutfilewriter.cpp \ @@ -37,25 +38,27 @@ HEADERS += \ $$PWD/dialogs/configpages/puzzlepreferencespathpage.h \ $$PWD/dialogs/dialogpuzzlepreferences.h \ $$PWD/dialogs/vpdialogabout.h \ + $$PWD/scene/scenedef.h \ $$PWD/stable.h \ $$PWD/vpapplication.h \ - $$PWD/vpcarrousel.h \ - $$PWD/vpcarrouselpiece.h \ - $$PWD/vpcarrouselpiecelist.h \ + $$PWD/carousel/vpcarrousel.h \ + $$PWD/carousel/vpcarrouselpiece.h \ + $$PWD/carousel/vpcarrouselpiecelist.h \ $$PWD/vpcommandline.h \ $$PWD/vpcommands.h \ $$PWD/vpexporter.h \ - $$PWD/vpgraphicspiece.h \ - $$PWD/vpgraphicssheet.h \ - $$PWD/vpgraphicstilegrid.h \ - $$PWD/vplayout.h \ - $$PWD/vplayoutsettings.h \ - $$PWD/vpmaingraphicsview.h \ + $$PWD/scene/vpgraphicspiece.h \ + $$PWD/scene/vpgraphicspiececontrols.h \ + $$PWD/scene/vpgraphicssheet.h \ + $$PWD/scene/vpgraphicstilegrid.h \ + $$PWD/layout/vplayout.h \ + $$PWD/layout/vplayoutsettings.h \ + $$PWD/scene/vpmaingraphicsview.h \ $$PWD/vpmainwindow.h \ - $$PWD/vpmimedatapiece.h \ - $$PWD/vppiece.h \ + $$PWD/carousel/vpmimedatapiece.h \ + $$PWD/layout/vppiece.h \ $$PWD/vpsettings.h \ - $$PWD/vpsheet.h \ + $$PWD/layout/vpsheet.h \ $$PWD/vptilefactory.h \ $$PWD/xml/vplayoutfilereader.h \ $$PWD/xml/vplayoutfilewriter.h \ @@ -66,5 +69,5 @@ FORMS += \ $$PWD/dialogs/configpages/puzzlepreferencespathpage.ui \ $$PWD/dialogs/dialogpuzzlepreferences.ui \ $$PWD/dialogs/vpdialogabout.ui \ - $$PWD/vpcarrousel.ui \ + $$PWD/carousel/vpcarrousel.ui \ $$PWD/vpmainwindow.ui diff --git a/src/app/puzzle/scene/scenedef.h b/src/app/puzzle/scene/scenedef.h new file mode 100644 index 000000000..a088b7744 --- /dev/null +++ b/src/app/puzzle/scene/scenedef.h @@ -0,0 +1,38 @@ +/************************************************************************ + ** + ** @file scenedef.h + ** @author Roman Telezhynskyi + ** @date 7 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 SCENEDEF_H +#define SCENEDEF_H + +enum class PGraphicsItem : int +{ + Piece = 1, + Handles = 2, + TransformationOrigin = 3 +}; + +#endif // SCENEDEF_H diff --git a/src/app/puzzle/vpgraphicspiece.cpp b/src/app/puzzle/scene/vpgraphicspiece.cpp similarity index 57% rename from src/app/puzzle/vpgraphicspiece.cpp rename to src/app/puzzle/scene/vpgraphicspiece.cpp index 8f74e7a14..336e2baef 100644 --- a/src/app/puzzle/vpgraphicspiece.cpp +++ b/src/app/puzzle/scene/vpgraphicspiece.cpp @@ -39,9 +39,9 @@ #include #include -#include "vppiece.h" -#include "vplayout.h" -#include "vpsheet.h" +#include "../layout/vppiece.h" +#include "../layout/vplayout.h" +#include "../layout/vpsheet.h" #include "vlayoutpiecepath.h" #include "vplacelabelitem.h" @@ -49,6 +49,11 @@ #include Q_LOGGING_CATEGORY(pGraphicsPiece, "p.graphicsPiece") +namespace +{ +constexpr qreal penWidth = 1; +} + //--------------------------------------------------------------------------------------------------------------------- VPGraphicsPiece::VPGraphicsPiece(VPPiece *piece, QGraphicsItem *parent) : QGraphicsObject(parent), @@ -57,94 +62,12 @@ VPGraphicsPiece::VPGraphicsPiece(VPPiece *piece, QGraphicsItem *parent) : QPixmap cursor_pixmap = QIcon("://puzzleicon/svg/cursor_rotate.svg").pixmap(QSize(32,32)); m_rotateCursor= QCursor(cursor_pixmap, 16, 16); - Init(); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::Init() -{ // set some infos - setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges); + setFlags(ItemIsSelectable | ItemSendsGeometryChanges); setAcceptHoverEvents(true); - setCursor(QCursor(Qt::OpenHandCursor)); + setCursor(Qt::OpenHandCursor); - // initialises the seam line - QVector seamLinePoints = m_piece->GetMappedContourPoints(); - if(!seamLinePoints.isEmpty()) - { - 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->GetMappedSeamAllowancePoints(); - if(!cuttingLinepoints.isEmpty()) - { - m_cuttingLine.moveTo(cuttingLinepoints.first()); - for (int i = 1; i < cuttingLinepoints.size(); i++) - { - m_cuttingLine.lineTo(cuttingLinepoints.at(i)); - } - } - - // initialises the grainline - if(m_piece->IsGrainlineEnabled()) - { - QVector grainLinepoints = m_piece->GetMappedGrainline(); - if(!grainLinepoints.isEmpty()) - { - m_grainline.moveTo(grainLinepoints.first()); - for (int i = 1; i < grainLinepoints.size(); i++) - { - m_grainline.lineTo(grainLinepoints.at(i)); - } - } - } - - // initialises the internal paths - QVector internalPaths = m_piece->GetInternalPaths(); - for (const auto& piecePath : internalPaths) - { - QPainterPath path = m_piece->GetMatrix().map(piecePath.GetPainterPath()); - m_internalPaths.append(path); - m_internalPathsPenStyle.append(piecePath.PenStyle()); - } - - // initialises the passmarks - QVector passmarks = m_piece->GetMappedPassmarks(); - for(auto &passmark : passmarks) - { - for (auto &line : passmark.lines) - { - m_passmarks.moveTo(line.p1()); - m_passmarks.lineTo(line.p2()); - } - } - - // initialises the place labels (buttons etc) - QVector placeLabels = m_piece->GetPlaceLabels(); - for(auto &placeLabel : placeLabels) - { - QPainterPath path = VPlaceLabelItem::LabelShapePath(placeLabel.shape); - m_placeLabels.append(path); - } - - // TODO : initialises the text labels - - - // Init position - on_PiecePositionChanged(); - on_PieceRotationChanged(); - on_PieceSelectionChanged(); - - // Initialises the connectors - connect(m_piece, &VPPiece::SelectionChanged, this, &VPGraphicsPiece::on_PieceSelectionChanged); - connect(m_piece, &VPPiece::PositionChanged, this, &VPGraphicsPiece::on_PiecePositionChanged); - connect(m_piece, &VPPiece::RotationChanged, this, &VPGraphicsPiece::on_PieceRotationChanged); - connect(m_piece, &VPPiece::PropertiesChanged, this, &VPGraphicsPiece::on_PiecePropertiesChanged); + PaintPiece(); } //--------------------------------------------------------------------------------------------------------------------- @@ -153,15 +76,23 @@ auto VPGraphicsPiece::GetPiece() -> VPPiece* return m_piece; } +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPiece::TranslatePiece(const QPointF &p) +{ + m_piece->Translate(p); + prepareGeometryChange(); +} + //--------------------------------------------------------------------------------------------------------------------- auto VPGraphicsPiece::boundingRect() const -> QRectF { + constexpr qreal halfPenWidth = penWidth/2.; if(!m_cuttingLine.isEmpty()) { - return m_cuttingLine.boundingRect(); + return m_cuttingLine.boundingRect().adjusted(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth); } - return m_seamLine.boundingRect(); + return m_seamLine.boundingRect().adjusted(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth); } //--------------------------------------------------------------------------------------------------------------------- @@ -181,170 +112,41 @@ void VPGraphicsPiece::paint(QPainter *painter, const QStyleOptionGraphicsItem *o Q_UNUSED(widget); Q_UNUSED(option); - QPen pen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); - QBrush noBrush(Qt::NoBrush); - QBrush selectionBrush(QColor(255,160,160,60)); - QBrush blackBrush(Qt::black); - + QPen pen(Qt::black, penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); painter->setPen(pen); - // selection - if(isSelected()) - { - painter->setBrush(selectionBrush); - } - else - { - painter->setBrush(noBrush); - } - - // paint the cutting line - if(!m_cuttingLine.isEmpty()) - { - painter->drawPath(m_cuttingLine); - painter->setBrush(noBrush); - } - - // paint the seam line - if(!m_seamLine.isEmpty() && m_piece->GetShowSeamLine()) - { - painter->drawPath(m_seamLine); - } - - painter->setBrush(noBrush); - - // paint the grainline - if(!m_grainline.isEmpty()) - { - // here to fill the grainlines arrow. Not wanted for mvp - // later maybe if it's configurable -// painter->setBrush(blackBrush); - - painter->drawPath(m_grainline); - } - - // paint the internal paths - painter->setBrush(noBrush); - if(!m_internalPaths.isEmpty()) - { - Qt::PenStyle penStyleTmp = pen.style(); - - for (int i = 0; i < m_internalPaths.size(); i++) - { - painter->setPen(m_internalPathsPenStyle.at(i)); - painter->drawPath(m_internalPaths.at(i)); - } - painter->setPen(penStyleTmp); - } - - // paint the passmarks - if(!m_passmarks.isEmpty()) - { - painter->drawPath(m_passmarks); - } - - // paint the place labels (buttons etc) - if(!m_placeLabels.isEmpty()) - { - for(auto &placeLabel : m_placeLabels) - { - painter->drawPath(placeLabel); - } - } - - - // TODO Detail & Piece Label - -// QPointF position = m_piece->GetPatternTextPosition(); -// QStringList texts = m_piece->GetPatternText(); - -// painter->drawText(); - - - - // when using m_piece->GetItem(), the results were quite bad - + PaintPiece(painter); } //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsPiece::mousePressEvent(QGraphicsSceneMouseEvent *event) { - bool selectionState = isSelected(); //perform the default behaviour QGraphicsObject::mousePressEvent(event); // change the cursor when clicking the left button if((event->button() == Qt::LeftButton)) { - if((event->modifiers() & Qt::AltModifier) != 0U) - { - setCursor(m_rotateCursor); - } - else - { - setCursor(Qt::ClosedHandCursor); - } - } + setCursor(Qt::ClosedHandCursor); - // change the selected state when clicking left button - if (event->button() == Qt::LeftButton) - { - setSelected(true); - - if (event->modifiers() & Qt::ControlModifier) - { - setSelected(!selectionState); - } - else - { - setSelected(true); - } - } - - if((event->button() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) - { - m_rotationStartPoint = event->scenePos(); + m_moveStartPoint = event->pos(); + emit HideTransformationHandles(true); } } //--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::mouseMoveEvent(QGraphicsSceneMouseEvent * event) +void VPGraphicsPiece::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - if((event->buttons() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) - { - //FIXME: it flickers between the arrow cursor and the rotate cursor - setCursor(m_rotateCursor); + QGraphicsObject::mouseMoveEvent(event); - QPointF rotationNewPoint = event->scenePos(); - QPointF rotationCenter = sceneBoundingRect().center(); + GroupMove(event->pos()); - // 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); - } + m_moveStartPoint = event->pos(); } - //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - bool selectionState = isSelected(); - //perform the default behaviour QGraphicsItem::mouseReleaseEvent(event); @@ -352,32 +154,8 @@ void VPGraphicsPiece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (event->button() == Qt::LeftButton) { setCursor(Qt::OpenHandCursor); - - setSelected(selectionState); - - if(m_piece->GetPosition() != pos()) - { - m_piece->SetPosition(pos()); - } - } - - if((event->button() == Qt::LeftButton) && (event->modifiers() & Qt::AltModifier)) - { - m_piece->SetRotation(-rotation()); - } -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - if(event->modifiers() & Qt::AltModifier) - { - //FIXME: it flickers between the arrow cursor and the rotate cursor - setCursor(m_rotateCursor); - } - else - { - setCursor(Qt::OpenHandCursor); + GroupMove(event->pos()); + emit HideTransformationHandles(false); } } @@ -421,30 +199,166 @@ void VPGraphicsPiece::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) } //--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::on_PieceSelectionChanged() +void VPGraphicsPiece::PaintPiece(QPainter *painter) { - setSelected(m_piece->GetIsSelected()); -} + QBrush noBrush(Qt::NoBrush); + QBrush selectionBrush(QColor(255,160,160,60)); -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::on_PiecePositionChanged() -{ - setPos(m_piece->GetPosition()); -} + QRectF rect = m_piece->MappedDetailBoundingRect(); + QPointF p = rect.topLeft(); -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::on_PieceRotationChanged() -{ - setTransformOriginPoint(boundingRect().center()); - setRotation(-m_piece->GetRotation()); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPGraphicsPiece::on_PiecePropertiesChanged() -{ - if(scene() != nullptr) + // initialises the seam line + QVector seamLinePoints = m_piece->GetMappedContourPoints(); + if(!seamLinePoints.isEmpty()) { - scene()->update(); + m_seamLine = QPainterPath(); + m_seamLine.moveTo(seamLinePoints.first()); + for (int i = 1; i < seamLinePoints.size(); i++) + { + m_seamLine.lineTo(seamLinePoints.at(i)); + } + + if (painter != nullptr) + { + painter->save(); + painter->setBrush(isSelected() ? selectionBrush : noBrush); + painter->drawPath(m_seamLine); + painter->restore(); + } + } + + // initiliases the cutting line + QVector cuttingLinepoints = m_piece->GetMappedSeamAllowancePoints(); + if(!cuttingLinepoints.isEmpty()) + { + m_cuttingLine = QPainterPath(); + m_cuttingLine.moveTo(cuttingLinepoints.first()); + for (int i = 1; i < cuttingLinepoints.size(); i++) + { + m_cuttingLine.lineTo(cuttingLinepoints.at(i)); + } + + if (painter != nullptr) + { + painter->save(); + painter->setBrush(isSelected() ? selectionBrush : noBrush); + painter->drawPath(m_cuttingLine); + painter->restore(); + } + } + + // initialises the grainline + if(m_piece->IsGrainlineEnabled()) + { + QVector grainLinepoints = m_piece->GetMappedGrainline(); + if(!grainLinepoints.isEmpty()) + { + QPainterPath grainline; + grainline.moveTo(grainLinepoints.first()); + for (int i = 1; i < grainLinepoints.size(); i++) + { + grainline.lineTo(grainLinepoints.at(i)); + } + + if (painter != nullptr) + { + painter->save(); + // here to fill the grainlines arrow. Not wanted for mvp + // later maybe if it's configurable +// painter->setBrush(blackBrush); + + painter->setBrush(noBrush); + painter->drawPath(grainline); + painter->restore(); + } + } + } + + // initialises the internal paths + QVector internalPaths = m_piece->GetInternalPaths(); + for (const auto& piecePath : internalPaths) + { + QPainterPath path = m_piece->GetMatrix().map(piecePath.GetPainterPath()); + + if (painter != nullptr) + { + painter->save(); + painter->setPen(piecePath.PenStyle()); + painter->drawPath(path); + painter->restore(); + } + } + + // initialises the passmarks + QVector passmarks = m_piece->GetMappedPassmarks(); + for(auto &passmark : passmarks) + { + QPainterPath passmarkPath; + for (auto &line : passmark.lines) + { + passmarkPath.moveTo(line.p1()); + passmarkPath.lineTo(line.p2()); + } + + if (painter != nullptr) + { + painter->save(); + painter->setBrush(noBrush); + painter->drawPath(passmarkPath); + painter->restore(); + } + } + + // initialises the place labels (buttons etc) + QVector placeLabels = m_piece->GetPlaceLabels(); + for(auto &placeLabel : placeLabels) + { + QPainterPath path = VPlaceLabelItem::LabelShapePath(placeLabel.shape); + + if (painter != nullptr) + { + painter->save(); + painter->setBrush(noBrush); + painter->drawPath(path); + painter->restore(); + } + } + + // TODO : initialises the text labels + +// QPointF position = m_piece->GetPatternTextPosition(); +// QStringList texts = m_piece->GetPatternText(); + + // painter->drawText(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPiece::GroupMove(const QPointF &pos) +{ + if (scene() != nullptr) + { + QList list = scene()->selectedItems(); + for (auto *item : list) + { + if (item->type() == UserType + static_cast(PGraphicsItem::Piece)) + { + auto *pieceItem = dynamic_cast(item); + pieceItem->TranslatePiece(pos-m_moveStartPoint); + } + } + emit PiecePositionChanged(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPiece::on_Rotate(const QPointF ¢er, qreal angle) +{ + if (isSelected()) + { + prepareGeometryChange(); + m_piece->Rotate(center, angle); + PaintPiece(); // Update shapes + update(); } } @@ -453,21 +367,10 @@ auto VPGraphicsPiece::itemChange(GraphicsItemChange change, const QVariant &valu { if (scene() != nullptr) { - - // we do this in the mouseRelease button to avoid updated this property all the time. -// if(change == ItemPositionHasChanged) -// { -// blockSignals(true); -// m_piece->SetPosition(pos()); -// blockSignals(false); -// } - if(change == ItemSelectedHasChanged) { - if(m_piece->GetIsSelected() != isSelected()) - { - m_piece->SetIsSelected(isSelected()); - } + emit PieceSelectionChanged(); + m_piece->SetSelected(value.toBool()); } } diff --git a/src/app/puzzle/vpgraphicspiece.h b/src/app/puzzle/scene/vpgraphicspiece.h similarity index 70% rename from src/app/puzzle/vpgraphicspiece.h rename to src/app/puzzle/scene/vpgraphicspiece.h index 2e5db17d1..5e683c434 100644 --- a/src/app/puzzle/vpgraphicspiece.h +++ b/src/app/puzzle/scene/vpgraphicspiece.h @@ -32,6 +32,8 @@ #include #include +#include "scenedef.h" + class VPPiece; class VPGraphicsPiece : public QGraphicsObject @@ -41,37 +43,24 @@ public: explicit VPGraphicsPiece(VPPiece *piece, QGraphicsItem *parent = nullptr); ~VPGraphicsPiece() = default; - void Init(); - /** * @brief GetPiece Returns the piece that corresponds to the graphics piece * @return the piece */ auto GetPiece() -> VPPiece*; - virtual int type() const override {return Type;} - enum { Type = UserType + 1}; + void TranslatePiece(const QPointF &p); + + virtual int type() const override {return Type;} + enum { Type = UserType + static_cast(PGraphicsItem::Piece)}; + +signals: + void PieceSelectionChanged(); + void HideTransformationHandles(bool hide); + void PiecePositionChanged(); public slots: - /** - * @brief on_PieceSelectionChanged Slot called when the piece selection was changed - */ - void on_PieceSelectionChanged(); - - /** - * @brief on_PiecePositionChanged Slot called when the piece position was changed - */ - void on_PiecePositionChanged(); - - /** - * @brief on_PieceRotationChanged Slot called when the piece rotation was changed - */ - void on_PieceRotationChanged(); - - /** - * @brief on_PiecePropertiesChanged Slot called when the showSeamline / mirrored was changed - */ - void on_PiecePropertiesChanged(); + void on_Rotate(const QPointF ¢er, qreal angle); protected: auto boundingRect() const -> QRectF override; @@ -79,11 +68,9 @@ protected: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void mousePressEvent(QGraphicsSceneMouseEvent * event) override; - void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; - void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override; - auto itemChange(GraphicsItemChange change, const QVariant &value) -> QVariant override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; @@ -94,17 +81,15 @@ private: QPainterPath m_cuttingLine{}; QPainterPath m_seamLine{}; - QPainterPath m_grainline{}; - QPainterPath m_passmarks{}; - - QVector m_internalPaths{}; - QVector m_internalPathsPenStyle{}; - - QVector m_placeLabels{}; + QPointF m_moveStartPoint{}; QPointF m_rotationStartPoint{}; QCursor m_rotateCursor{}; + + void PaintPiece(QPainter *painter=nullptr); + + void GroupMove(const QPointF &pos); }; #endif // VPGRAPHICSPIECE_H diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.cpp b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp new file mode 100644 index 000000000..acd837449 --- /dev/null +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.cpp @@ -0,0 +1,736 @@ +/************************************************************************ + ** + ** @file vpgraphicspiececontrols.cpp + ** @author Roman Telezhynskyi + ** @date 2 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 "vpgraphicspiececontrols.h" + +#include +#include +#include +#include +#include +#include + +#include "../vmisc/compatibility.h" +#include "../vwidgets/global.h" +#include "../layout/vplayout.h" + +namespace +{ +const qreal arcStartAngle = 105; +const qreal arcAngle = 25; +const qreal arcRadius = 15; + +const qreal arrowTail = 2; +const qreal arrowSide = 2; +const qreal arrowLength = 4; +const qreal arrow1Angle = 13; +const qreal arrow2Angle = 38; + +constexpr qreal penWidth = 2; + +const qreal centerRadius1 = 5; +const qreal centerRadius2 = 10; + +const QColor defaultColor = Qt::black; +const QColor hoverColor = Qt::green; + +enum class HandleCorner : int +{ + Invalid = 0, + TopLeft = 1, + TopRight = 2, + BottomRight = 3, + BottomLeft = 4 +}; + +auto TransformationOrigin(VPLayout *layout, const QRectF &boundingRect) -> QPointF +{ + SCASSERT(layout != nullptr) + VPSheet *sheet = layout->GetFocusedSheet(); + if (sheet != nullptr) + { + VPTransformationOrigon origin = sheet->TransformationOrigin(); + return origin.origin; + } + + return boundingRect.center(); +} +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- +VPGraphicsTransformationOrigin::VPGraphicsTransformationOrigin(VPLayout *layout, QGraphicsItem *parent) + : QGraphicsObject(parent), + m_layout(layout), + m_color(defaultColor) +{ + SCASSERT(m_layout != nullptr) + setCursor(Qt::OpenHandCursor); + setZValue(1); + setAcceptHoverEvents(true); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::SetTransformationOrigin() +{ + prepareGeometryChange(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::on_HideHandles(bool hide) +{ + m_originVisible = not hide; + prepareGeometryChange(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::on_ShowOrigin(bool show) +{ + setVisible(show); +} + +//--------------------------------------------------------------------------------------------------------------------- +QRectF VPGraphicsTransformationOrigin::boundingRect() const +{ + constexpr qreal halfPenWidth = penWidth/2.; + return Center2().boundingRect().adjusted(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPGraphicsTransformationOrigin::shape() const +{ + return Center2(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(widget); + Q_UNUSED(option); + + const qreal scale = SceneScale(scene()); + + QPen pen(m_color, penWidth/scale, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + + painter->setPen(pen); + + if (m_originVisible) + { + painter->save(); + painter->setBrush(QBrush(m_color)); + painter->drawPath(Center1()); + painter->restore(); + + painter->save(); + painter->setBrush(QBrush()); + painter->drawPath(Center2()); + painter->restore(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + // change the cursor when clicking the left button + if((event->button() == Qt::LeftButton)) + { + setCursor(Qt::ClosedHandCursor); + event->accept(); + } + else + { + //perform the default behaviour + QGraphicsObject::mousePressEvent(event); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + VPSheet *sheet = m_layout->GetFocusedSheet(); + if (sheet != nullptr) + { + VPTransformationOrigon origin = sheet->TransformationOrigin(); + origin.origin = event->scenePos(); + origin.custom = true; + sheet->SetTransformationOrigin(origin); + } + prepareGeometryChange(); + + QGraphicsObject::mouseMoveEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + //perform the default behaviour + QGraphicsItem::mouseReleaseEvent(event); + + // change the cursor when clicking left button + if (event->button() == Qt::LeftButton) + { + setCursor(Qt::OpenHandCursor); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + m_color = hoverColor; + QGraphicsObject::hoverEnterEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsTransformationOrigin::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + m_color = defaultColor; + QGraphicsObject::hoverEnterEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsTransformationOrigin::RotationCenter(QPainter *painter) const -> QPainterPath +{ + QPainterPath path; + + const qreal scale = SceneScale(scene()); + qreal radius = centerRadius1/scale; + QPointF transformationOrigin = TransformationOrigin(m_layout, QRectF()); + QRectF rect(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); + + QPainterPath center1; + center1.addEllipse(rect); + + if (painter != nullptr) + { + painter->save(); + painter->setBrush(QBrush(m_color)); + painter->drawPath(Center1()); + painter->restore(); + } + path.addPath(center1); + + radius = centerRadius2/scale; + rect = QRectF(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); + + QPainterPath center2; + center2.addEllipse(rect); + + if (painter != nullptr) + { + painter->save(); + painter->setBrush(QBrush()); + painter->drawPath(Center2()); + painter->restore(); + } + path.addPath(center2); + + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPGraphicsTransformationOrigin::Center1() const +{ + const qreal scale = SceneScale(scene()); + qreal radius = centerRadius1/scale; + QPointF transformationOrigin = TransformationOrigin(m_layout, QRectF()); + QRectF rect(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); + + QPainterPath center1; + center1.addEllipse(rect); + + return center1; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPGraphicsTransformationOrigin::Center2() const +{ + const qreal scale = SceneScale(scene()); + qreal radius = centerRadius2/scale; + QPointF transformationOrigin = TransformationOrigin(m_layout, QRectF()); + QRectF rect = QRectF(transformationOrigin.x()-radius, transformationOrigin.y()-radius, radius*2., radius*2.); + + QPainterPath center2; + center2.addEllipse(rect); + + return center2; +} + +// VPGraphicsPieceControls +//--------------------------------------------------------------------------------------------------------------------- +VPGraphicsPieceControls::VPGraphicsPieceControls(VPLayout *layout, QGraphicsItem *parent) + : QGraphicsObject(parent), + m_layout(layout) +{ + SCASSERT(m_layout != nullptr) + QPixmap cursor_pixmap = QIcon("://puzzleicon/svg/cursor_rotate.svg").pixmap(QSize(32,32)); + setCursor(QCursor(cursor_pixmap, 16, 16)); + setZValue(1); + setAcceptHoverEvents(true); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::on_UpdateControls() +{ + m_pieceRect = PiecesBoundingRect(); + setVisible(not m_pieceRect.isNull()); + + if (not m_pieceRect.isNull()) + { + VPSheet *sheet = m_layout->GetFocusedSheet(); + if (sheet != nullptr) + { + VPTransformationOrigon origin = sheet->TransformationOrigin(); + if (not origin.custom) + { + origin.origin = m_pieceRect.center(); + sheet->SetTransformationOrigin(origin); + emit TransformationOriginChanged(); + } + } + } + + emit ShowOrigin(not m_pieceRect.isNull()); + prepareGeometryChange(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::on_HideHandles(bool hide) +{ + m_controlsVisible = not hide; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::boundingRect() const -> QRectF +{ + constexpr qreal halfPenWidth = penWidth/2.; + return Handles().boundingRect().adjusted(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::shape() const -> QPainterPath +{ + return Handles(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(widget); + Q_UNUSED(option); + + const qreal scale = SceneScale(scene()); + + QPen pen(defaultColor, penWidth/scale, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); + + painter->setPen(pen); + + if (m_controlsVisible) + { + TopLeftControl(painter); + TopRightControl(painter); + BottomLeftControl(painter); + BottomRightControl(painter); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + m_rotationStartPoint = event->scenePos(); + m_controlsVisible = false; + m_handleCorner = HandleCorner(event->scenePos()); + prepareGeometryChange(); + } + else + { + QGraphicsObject::mousePressEvent(event); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if((event->modifiers() & Qt::ShiftModifier) != 0U + && static_cast(m_handleCorner) != HandleCorner::Invalid) + { + if (not m_originSaved) + { + VPSheet *sheet = m_layout->GetFocusedSheet(); + if (sheet != nullptr) + { + m_savedOrigin = sheet->TransformationOrigin(); + m_originSaved = true; + m_pieceRect = PiecesBoundingRect(); + + 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(); + } + + sheet->SetTransformationOrigin(origin); + emit TransformationOriginChanged(); + } + } + } + else + { + if (m_originSaved) + { + VPSheet *sheet = m_layout->GetFocusedSheet(); + if (sheet != nullptr) + { + if (not m_savedOrigin.custom) + { + m_pieceRect = PiecesBoundingRect(); + m_savedOrigin.origin = m_pieceRect.center(); + } + sheet->SetTransformationOrigin(m_savedOrigin); + emit TransformationOriginChanged(); + } + m_originSaved = false; + } + } + + QPointF rotationNewPoint = event->scenePos(); + + // get the angle from the center to the initial click point + QPointF rotationOrigin = TransformationOrigin(m_layout, m_pieceRect); + QLineF initPosition(rotationOrigin, m_rotationStartPoint); + QLineF initRotationPosition(rotationOrigin, rotationNewPoint); + + qreal angle = initPosition.angleTo(initRotationPosition); + + if (not qFuzzyIsNull(angle)) + { + emit Rotate(rotationOrigin, angle); + } + + if (m_originSaved && m_savedOrigin.custom) + { + QLineF line(rotationOrigin, m_savedOrigin.origin); + line.setAngle(line.angle()+angle); + m_savedOrigin.origin = line.p2(); + } + + m_rotationStartPoint = rotationNewPoint; + QGraphicsObject::mouseMoveEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPieceControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + m_controlsVisible = true; + + if (m_originSaved) + { + VPSheet *sheet = m_layout->GetFocusedSheet(); + if (sheet != nullptr) + { + if (not m_savedOrigin.custom) + { + m_pieceRect = PiecesBoundingRect(); + m_savedOrigin.origin = m_pieceRect.center(); + } + sheet->SetTransformationOrigin(m_savedOrigin); + emit TransformationOriginChanged(); + } + m_originSaved = false; + } + + on_UpdateControls(); + } + QGraphicsObject::mouseReleaseEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::TopLeftControl(QPainter *painter) const -> QPainterPath +{ + return Controller(QTransform(), painter); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::TopRightControl(QPainter *painter) const -> QPainterPath +{ + QTransform t; + t.scale(-1, 1); + t.translate(-(m_pieceRect.topLeft().x() * 2. + m_pieceRect.width()), 0); + + return Controller(t, painter); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::BottomLeftControl(QPainter *painter) const -> QPainterPath +{ + QTransform t; + t.scale(1, -1); + t.translate(0, -(m_pieceRect.topLeft().y() * 2. + m_pieceRect.height())); + + return Controller(t, painter); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::BottomRightControl(QPainter *painter) const -> QPainterPath +{ + QTransform t; + t.scale(-1, -1); + t.translate(-(m_pieceRect.topLeft().x() * 2. + m_pieceRect.width()), + -(m_pieceRect.topLeft().y() * 2. + m_pieceRect.height())); + + return Controller(t, painter); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPainterPath VPGraphicsPieceControls::Handles() const +{ + QPainterPath path; + + path.addPath(TopLeftControl()); + path.addPath(TopRightControl()); + path.addPath(BottomLeftControl()); + path.addPath(BottomRightControl()); + + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::Controller(const QTransform &t, QPainter *painter) const -> QPainterPath +{ + if (painter != nullptr) + { + QPen pen = painter->pen(); + pen.setColor(defaultColor); + painter->setPen(pen); + } + + QBrush colorBrush(defaultColor); + + QPainterPath controller = ArrowPath(); + controller = t.map(controller); + + if (painter != nullptr) + { + painter->save(); + painter->setBrush(colorBrush); + painter->drawPath(controller); + painter->restore(); + } + + return controller; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::ControllersRect() const -> QRectF +{ + const qreal scale = SceneScale(scene()); + + const qreal gap = 2; + QRectF rect = m_pieceRect; + const qreal minWidth = arcRadius/scale+gap; + const qreal minHeight = arcRadius/scale+gap; + + if (m_pieceRect.width() < minWidth) + { + qreal diff = minWidth - m_pieceRect.width(); + rect.adjust(-diff/2., 0, diff/2., 0); + } + + if (m_pieceRect.height() < minHeight) + { + qreal diff = minHeight - m_pieceRect.height(); + rect.adjust(0, -diff/2., 0, diff/2.); + } + + return rect; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::ArrowPath() const -> QPainterPath +{ + const qreal scale = SceneScale(scene()); + QPainterPath arrow; + + QRectF pieceRect = ControllersRect(); + + QLineF start(pieceRect.topLeft().x(), pieceRect.topLeft().y(), + pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius+1)/scale); + start.setAngle(arcStartAngle); + + arrow.moveTo(start.p2()); + + QLineF baseLine(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y())); + baseLine.setAngle(arrow1Angle); + arrow.lineTo(baseLine.p2()); + + QLineF leftSide = QLineF(baseLine.p2(), baseLine.p1()); + leftSide.setLength(arrowSide/scale); + leftSide.setAngle(leftSide.angle()-90); + arrow.lineTo(leftSide.p2()); + + start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(), + pieceRect.topLeft().x(), pieceRect.topLeft().y() - arcRadius/scale); + start.setAngle(arcStartAngle); + + baseLine = QLineF(start.p2(), QPointF(start.p2().x()+(arrowTail+arrowLength)/scale, start.p2().y())); + baseLine.setAngle(arrow1Angle); + arrow.lineTo(baseLine.p2()); + + start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(), + pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius-1)/scale); + start.setAngle(arcStartAngle); + + baseLine = QLineF(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y())); + baseLine.setAngle(arrow1Angle); + + QLineF rightSide = QLineF(baseLine.p2(), baseLine.p1()); + rightSide.setLength(arrowSide/scale); + rightSide.setAngle(rightSide.angle()+90); + arrow.lineTo(rightSide.p2()); + + arrow.lineTo(baseLine.p2()); + arrow.lineTo(start.p2()); + + // arc 1 + QRectF arc1Rect(pieceRect.topLeft().x()-(arcRadius-1)/scale, pieceRect.topLeft().y()-(arcRadius-1)/scale, + (arcRadius-1)/scale*2, (arcRadius-1)/scale*2); + arrow.arcTo(arc1Rect, arcStartAngle, arcAngle); + + // arrow 2 + + start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(), + pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius-1)/scale); + start.setAngle(arcStartAngle+arcAngle); + + baseLine = QLineF(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y())); + baseLine.setAngle(arrow2Angle+180); + arrow.lineTo(baseLine.p2()); + + leftSide = QLineF(baseLine.p2(), baseLine.p1()); + leftSide.setLength(arrowSide/scale); + leftSide.setAngle(leftSide.angle()-90); + arrow.lineTo(leftSide.p2()); + + start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(), + pieceRect.topLeft().x(), pieceRect.topLeft().y() - arcRadius/scale); + start.setAngle(arcStartAngle+arcAngle); + + baseLine = QLineF(start.p2(), QPointF(start.p2().x()+(arrowTail+arrowLength)/scale, start.p2().y())); + baseLine.setAngle(arrow2Angle+180); + arrow.lineTo(baseLine.p2()); + + start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(), + pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius+1)/scale); + start.setAngle(arcStartAngle+arcAngle); + + baseLine = QLineF(start.p2(), QPointF(start.p2().x()+arrowTail/scale, start.p2().y())); + baseLine.setAngle(arrow2Angle+180); + + rightSide = QLineF(baseLine.p2(), baseLine.p1()); + rightSide.setLength(arrowSide/scale); + rightSide.setAngle(rightSide.angle()+90); + arrow.lineTo(rightSide.p2()); + + arrow.lineTo(baseLine.p2()); + arrow.lineTo(start.p2()); + + // arc 2 + QRectF arc2Rect(pieceRect.topLeft().x()-(arcRadius+1)/scale, pieceRect.topLeft().y()-(arcRadius+1)/scale, + (arcRadius+1)/scale*2, (arcRadius+1)/scale*2); + QPainterPath arc; + start = QLineF(pieceRect.topLeft().x(), pieceRect.topLeft().y(), + pieceRect.topLeft().x(), pieceRect.topLeft().y() - (arcRadius+1)/scale); + start.setAngle(arcStartAngle); + + arc.moveTo(start.p2()); + arc.arcTo(arc2Rect, arcStartAngle, arcAngle); + arrow.addPath(arc.toReversed()); + + return arrow; +} + +//--------------------------------------------------------------------------------------------------------------------- +QRectF VPGraphicsPieceControls::PiecesBoundingRect() const +{ + QRectF rect; + QGraphicsScene *scene = this->scene(); + if (scene != nullptr) + { + QList list = scene->selectedItems(); + for (auto *item : list) + { + if (item->type() == UserType + static_cast(PGraphicsItem::Piece)) + { + rect = rect.united(item->sceneBoundingRect()); + } + } + } + + return rect; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPGraphicsPieceControls::HandleCorner(const QPointF &pos) const -> int +{ + if (TopLeftControl().boundingRect().contains(pos)) + { + return static_cast(HandleCorner::BottomRight); + } + + if (TopRightControl().boundingRect().contains(pos)) + { + return static_cast(HandleCorner::BottomLeft); + } + + if (BottomLeftControl().boundingRect().contains(pos)) + { + return static_cast(HandleCorner::TopRight); + } + + if (BottomRightControl().boundingRect().contains(pos)) + { + return static_cast(HandleCorner::TopLeft); + } + + return static_cast(HandleCorner::Invalid); +} diff --git a/src/app/puzzle/scene/vpgraphicspiececontrols.h b/src/app/puzzle/scene/vpgraphicspiececontrols.h new file mode 100644 index 000000000..d340c1a3d --- /dev/null +++ b/src/app/puzzle/scene/vpgraphicspiececontrols.h @@ -0,0 +1,129 @@ +/************************************************************************ + ** + ** @file vpgraphicspiececontrols.h + ** @author Roman Telezhynskyi + ** @date 2 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 VPGRAPHICSPIECECONTROLS_H +#define VPGRAPHICSPIECECONTROLS_H + +#include +#include + +#include "scenedef.h" +#include "../layout/vpsheet.h" + +class VPLayout; + +class VPGraphicsTransformationOrigin : public QGraphicsObject +{ + Q_OBJECT +public: + explicit VPGraphicsTransformationOrigin(VPLayout *layout, QGraphicsItem * parent = nullptr); + + virtual int type() const override {return Type;} + enum { Type = UserType + static_cast(PGraphicsItem::TransformationOrigin)}; + +public slots: + void SetTransformationOrigin(); + void on_HideHandles(bool hide); + void on_ShowOrigin(bool show); + +protected: + auto boundingRect() const -> QRectF override; + auto shape() const -> QPainterPath override; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; + + void mousePressEvent(QGraphicsSceneMouseEvent * event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + + void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; + +private: + Q_DISABLE_COPY(VPGraphicsTransformationOrigin) + + bool m_originVisible{true}; + VPLayout *m_layout; + QColor m_color; + + auto RotationCenter(QPainter *painter = nullptr) const -> QPainterPath; + auto Center1() const -> QPainterPath; + auto Center2() const -> QPainterPath; +}; + +class VPGraphicsPieceControls : public QGraphicsObject +{ + Q_OBJECT +public: + explicit VPGraphicsPieceControls(VPLayout *layout, QGraphicsItem * parent = nullptr); + + virtual int type() const override {return Type;} + enum { Type = UserType + static_cast(PGraphicsItem::Handles)}; + +signals: + void Rotate(const QPointF ¢er, qreal angle); + void ShowOrigin(bool show); + void TransformationOriginChanged(); + +public slots: + void on_UpdateControls(); + void on_HideHandles(bool hide); + +protected: + auto boundingRect() const -> QRectF override; + auto shape() const -> QPainterPath override; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; + + void mousePressEvent(QGraphicsSceneMouseEvent * event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + +private: + Q_DISABLE_COPY(VPGraphicsPieceControls) + QRectF m_pieceRect{}; + QPointF m_rotationStartPoint{}; + bool m_controlsVisible{true}; + VPLayout *m_layout; + int m_handleCorner{0}; + VPTransformationOrigon m_savedOrigin{}; + bool m_originSaved{false}; + + auto TopLeftControl(QPainter *painter = nullptr) const -> QPainterPath; + auto TopRightControl(QPainter *painter = nullptr) const -> QPainterPath; + auto BottomLeftControl(QPainter *painter = nullptr) const -> QPainterPath; + auto BottomRightControl(QPainter *painter = nullptr) const -> QPainterPath; + + auto Handles() const -> QPainterPath; + auto Controller(const QTransform &t, QPainter *painter = nullptr) const -> QPainterPath; + auto ControllersRect() const -> QRectF; + + auto ArrowPath() const -> QPainterPath; + + auto PiecesBoundingRect() const -> QRectF; + auto HandleCorner(const QPointF &pos) const -> int; +}; + +#endif // VPGRAPHICSPIECECONTROLS_H diff --git a/src/app/puzzle/vpgraphicssheet.cpp b/src/app/puzzle/scene/vpgraphicssheet.cpp similarity index 98% rename from src/app/puzzle/vpgraphicssheet.cpp rename to src/app/puzzle/scene/vpgraphicssheet.cpp index 1fc91e4e2..2206366f1 100644 --- a/src/app/puzzle/vpgraphicssheet.cpp +++ b/src/app/puzzle/scene/vpgraphicssheet.cpp @@ -27,7 +27,9 @@ *************************************************************************/ #include "vpgraphicssheet.h" -#include "vplayout.h" +#include "../layout/vplayout.h" +#include "../layout/vpsheet.h" + #include //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpgraphicssheet.h b/src/app/puzzle/scene/vpgraphicssheet.h similarity index 99% rename from src/app/puzzle/vpgraphicssheet.h rename to src/app/puzzle/scene/vpgraphicssheet.h index 29e31bf34..d76170953 100644 --- a/src/app/puzzle/vpgraphicssheet.h +++ b/src/app/puzzle/scene/vpgraphicssheet.h @@ -32,7 +32,7 @@ #include #include -#include "vpsheet.h" +class VPSheet; class VPGraphicsSheet : public QGraphicsItem { diff --git a/src/app/puzzle/vpgraphicstilegrid.cpp b/src/app/puzzle/scene/vpgraphicstilegrid.cpp similarity index 97% rename from src/app/puzzle/vpgraphicstilegrid.cpp rename to src/app/puzzle/scene/vpgraphicstilegrid.cpp index 22e4c167e..2fc1ea366 100644 --- a/src/app/puzzle/vpgraphicstilegrid.cpp +++ b/src/app/puzzle/scene/vpgraphicstilegrid.cpp @@ -1,7 +1,7 @@ #include "vpgraphicstilegrid.h" -#include "vptilefactory.h" -#include "vplayout.h" +#include "../vptilefactory.h" +#include "../layout/vplayout.h" //--------------------------------------------------------------------------------------------------------------------- VPGraphicsTileGrid::VPGraphicsTileGrid(VPLayout *layout, VPTileFactory *tileFactory,QGraphicsItem *parent): diff --git a/src/app/puzzle/vpgraphicstilegrid.h b/src/app/puzzle/scene/vpgraphicstilegrid.h similarity index 100% rename from src/app/puzzle/vpgraphicstilegrid.h rename to src/app/puzzle/scene/vpgraphicstilegrid.h diff --git a/src/app/puzzle/vpmaingraphicsview.cpp b/src/app/puzzle/scene/vpmaingraphicsview.cpp similarity index 55% rename from src/app/puzzle/vpmaingraphicsview.cpp rename to src/app/puzzle/scene/vpmaingraphicsview.cpp index bfa413103..140bd6fe4 100644 --- a/src/app/puzzle/vpmaingraphicsview.cpp +++ b/src/app/puzzle/scene/vpmaingraphicsview.cpp @@ -33,16 +33,27 @@ #include #include -#include "vpmimedatapiece.h" -#include "vplayout.h" -#include "vpsheet.h" +#include "../scene/vpgraphicssheet.h" +#include "../scene/vpgraphicspiece.h" +#include "../vptilefactory.h" +#include "../scene/vpgraphicstilegrid.h" +#include "../carousel/vpmimedatapiece.h" +#include "../layout/vplayout.h" +#include "../layout/vpsheet.h" +#include "../layout/vppiece.h" #include "../vwidgets/vmaingraphicsscene.h" #include "vptilefactory.h" +#include "vpgraphicspiececontrols.h" #include Q_LOGGING_CATEGORY(pMainGraphicsView, "p.mainGraphicsView") +namespace +{ +const QKeySequence restoreOriginShortcut = QKeySequence(Qt::ControlModifier + Qt::Key_Asterisk); +} + //--------------------------------------------------------------------------------------------------------------------- VPMainGraphicsView::VPMainGraphicsView(VPLayout *layout, VPTileFactory *tileFactory, QWidget *parent) : @@ -53,17 +64,65 @@ VPMainGraphicsView::VPMainGraphicsView(VPLayout *layout, VPTileFactory *tileFact SCASSERT(m_layout != nullptr) setScene(m_scene); - m_graphicsSheet = new VPGraphicsSheet(layout->GetFocusedSheet()); + m_graphicsSheet = new VPGraphicsSheet(m_layout->GetFocusedSheet()); m_graphicsSheet->setPos(0, 0); m_scene->addItem(m_graphicsSheet); setAcceptDrops(true); - m_graphicsTileGrid = new VPGraphicsTileGrid(layout, tileFactory); + m_graphicsTileGrid = new VPGraphicsTileGrid(m_layout, tileFactory); m_scene->addItem(m_graphicsTileGrid); + m_rotationControls = new VPGraphicsPieceControls(m_layout); + m_rotationControls->setVisible(false); + m_scene->addItem(m_rotationControls); + + m_rotationOrigin = new VPGraphicsTransformationOrigin(m_layout); + m_rotationOrigin->setVisible(false); + m_scene->addItem(m_rotationOrigin); + + connect(m_rotationControls, &VPGraphicsPieceControls::ShowOrigin, + m_rotationOrigin, &VPGraphicsTransformationOrigin::on_ShowOrigin); + connect(m_rotationControls, &VPGraphicsPieceControls::TransformationOriginChanged, + m_rotationOrigin, &VPGraphicsTransformationOrigin::SetTransformationOrigin); + // add the connections connect(m_layout, &VPLayout::PieceSheetChanged, this, &VPMainGraphicsView::on_PieceSheetChanged); + + auto *restoreOrigin = new QAction(this); + 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); } //--------------------------------------------------------------------------------------------------------------------- @@ -94,8 +153,8 @@ void VPMainGraphicsView::RefreshPieces() { auto *graphicsPiece = new VPGraphicsPiece(piece); m_graphicsPieces.append(graphicsPiece); - scene()->addItem(graphicsPiece); + ConnectPiece(graphicsPiece); } } } @@ -180,9 +239,8 @@ void VPMainGraphicsView::dropEvent(QDropEvent *event) qCDebug(pMainGraphicsView(), "element dropped, %s", qUtf8Printable(piece->GetName())); event->acceptProposedAction(); - QPoint point = event->pos(); - piece->SetPosition(mapToScene(point)); - piece->SetRotation(0); + piece->ClearTransformations(); + piece->SetPosition(mapToScene(event->pos())); // change the piecelist of the piece piece->SetSheet(m_layout->GetFocusedSheet()); @@ -192,6 +250,8 @@ void VPMainGraphicsView::dropEvent(QDropEvent *event) scene()->addItem(graphicsPiece); + ConnectPiece(graphicsPiece); + event->acceptProposedAction(); } } @@ -208,9 +268,9 @@ void VPMainGraphicsView::keyPressEvent(QKeyEvent *event) { VPPiece *piece = graphicsPiece->GetPiece(); - if(piece->GetIsSelected()) + if(piece->IsSelected()) { - piece->SetIsSelected(false); + piece->SetSelected(false); piece->SetSheet(nullptr); } } @@ -228,10 +288,14 @@ void VPMainGraphicsView::contextMenuEvent(QContextMenuEvent *event) } QMenu menu; - VPSheet *sheet = m_layout->GetFocusedSheet(); + + QAction *restoreOriginAction = menu.addAction(tr("Restore transformation origin")); + restoreOriginAction->setShortcut(restoreOriginShortcut); + restoreOriginAction->setEnabled(sheet != nullptr && sheet->TransformationOrigin().custom); + QAction *removeSheetAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), tr("Remove sheet")); - removeSheetAction->setEnabled(sheet != nullptr && m_layout->GetSheets().size() > 1); + removeSheetAction->setEnabled(sheet != nullptr && m_layout->GetSheets().size() > 1); QAction *selectedAction = menu.exec(event->globalPos()); if (selectedAction == removeSheetAction) @@ -251,6 +315,104 @@ void VPMainGraphicsView::contextMenuEvent(QContextMenuEvent *event) emit on_SheetRemoved(); RefreshPieces(); } + else if (selectedAction == restoreOriginAction) + { + RestoreOrigin(); + } + +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPMainGraphicsView::RestoreOrigin() const +{ + VPSheet *sheet = m_layout->GetFocusedSheet(); + if (sheet != nullptr) + { + VPTransformationOrigon origin = sheet->TransformationOrigin(); + origin.custom = false; + sheet->SetTransformationOrigin(origin); + m_rotationControls->on_UpdateControls(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +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) +{ + SCASSERT(piece != nullptr) + + connect(piece, &VPGraphicsPiece::PieceSelectionChanged, + m_rotationControls, &VPGraphicsPieceControls::on_UpdateControls); + connect(piece, &VPGraphicsPiece::PiecePositionChanged, + 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, + m_rotationOrigin, &VPGraphicsTransformationOrigin::on_HideHandles); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPMainGraphicsView::RotatePiecesByAngle(qreal angle) const +{ + QGraphicsScene *scene = this->scene(); + if (scene == nullptr) + { + return; + } + + VPSheet *sheet = m_layout->GetFocusedSheet(); + if (sheet == nullptr) + { + return; + } + + VPTransformationOrigon origin = sheet->TransformationOrigin(); + + QList list = scene->selectedItems(); + for (auto *item : list) + { + if (item->type() == VPGraphicsPiece::Type) + { + auto *pieceItem = dynamic_cast(item); + pieceItem->on_Rotate(origin.origin, angle); + } + } } //--------------------------------------------------------------------------------------------------------------------- @@ -279,8 +441,10 @@ void VPMainGraphicsView::on_PieceSheetChanged(VPPiece *piece) { if(_graphicsPiece == nullptr) { + piece->ClearTransformations(); _graphicsPiece = new VPGraphicsPiece(piece); m_graphicsPieces.append(_graphicsPiece); + ConnectPiece(_graphicsPiece); } scene()->addItem(_graphicsPiece); } diff --git a/src/app/puzzle/vpmaingraphicsview.h b/src/app/puzzle/scene/vpmaingraphicsview.h similarity index 83% rename from src/app/puzzle/vpmaingraphicsview.h rename to src/app/puzzle/scene/vpmaingraphicsview.h index 295a1c93e..2bdb0b1af 100644 --- a/src/app/puzzle/vpmaingraphicsview.h +++ b/src/app/puzzle/scene/vpmaingraphicsview.h @@ -29,15 +29,17 @@ #ifndef VPMAINGRAPHICSVIEW_H #define VPMAINGRAPHICSVIEW_H -#include "vpgraphicssheet.h" -#include "vpgraphicspiece.h" -#include "vptilefactory.h" -#include "vpgraphicstilegrid.h" #include "../vwidgets/vmaingraphicsview.h" class VMainGraphicsScene; - +class VPGraphicsPieceControls; +class VPGraphicsTransformationOrigin; class VPTileFactory; +class VPGraphicsPiece; +class VPLayout; +class VPGraphicsTileGrid; +class VPGraphicsSheet; +class VPPiece; class VPMainGraphicsView : public VMainGraphicsView { @@ -92,6 +94,15 @@ protected: void drawTilesLine(); +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) @@ -101,6 +112,9 @@ private: VPGraphicsTileGrid *m_graphicsTileGrid{nullptr}; + VPGraphicsPieceControls *m_rotationControls{nullptr}; + VPGraphicsTransformationOrigin *m_rotationOrigin{nullptr}; + VPLayout *m_layout; QList m_graphicsPieces{}; @@ -115,6 +129,10 @@ private: */ bool m_showGridTmp{false}; + void ConnectPiece(VPGraphicsPiece *piece); + + void RotatePiecesByAngle(qreal angle) const; + }; #endif // VPMAINGRAPHICSVIEW_H diff --git a/src/app/puzzle/vpexporter.cpp b/src/app/puzzle/vpexporter.cpp index 2a6def67e..df4a2d86f 100644 --- a/src/app/puzzle/vpexporter.cpp +++ b/src/app/puzzle/vpexporter.cpp @@ -4,8 +4,8 @@ #include #include "../vwidgets/vmaingraphicsscene.h" -#include "vpsheet.h" -#include "vpmaingraphicsview.h" +#include "layout/vpsheet.h" +#include "scene/vpmaingraphicsview.h" #include "../vobj/vobjpaintdevice.h" #include "../vdxf/vdxfpaintdevice.h" diff --git a/src/app/puzzle/vpexporter.h b/src/app/puzzle/vpexporter.h index 6e87a2aa7..66a2c81eb 100644 --- a/src/app/puzzle/vpexporter.h +++ b/src/app/puzzle/vpexporter.h @@ -3,7 +3,7 @@ #include -#include "vplayout.h" +#include "layout/vplayout.h" #include "../vmisc/def.h" #include "vcommonsettings.h" #include "../vlayout/vlayoutdef.h" diff --git a/src/app/puzzle/vpmainwindow.cpp b/src/app/puzzle/vpmainwindow.cpp index cbdcb24f2..bc50c6b80 100644 --- a/src/app/puzzle/vpmainwindow.cpp +++ b/src/app/puzzle/vpmainwindow.cpp @@ -43,7 +43,7 @@ #include "../ifc/xml/vlayoutconverter.h" #include "../ifc/exception/vexception.h" #include "../vwidgets/vmaingraphicsscene.h" -#include "vpsheet.h" +#include "layout/vpsheet.h" #include "dialogs/dialogpuzzlepreferences.h" #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) @@ -322,11 +322,6 @@ VPPiece* VPMainWindow::CreatePiece(const VLayoutPiece &rawPiece) // TODO : set all the information we need for the piece! - // - connect(piece, &VPPiece::SelectionChanged, this, &VPMainWindow::on_PieceSelectionChanged); - connect(piece, &VPPiece::PositionChanged, this, &VPMainWindow::on_PiecePositionChanged); - connect(piece, &VPPiece::RotationChanged, this, &VPMainWindow::on_PieceRotationChanged); - return piece; } @@ -603,8 +598,8 @@ void VPMainWindow::SetPropertyTabCurrentPieceData() ui->lineEditCurrentPieceName->setText(selectedPiece->GetName()); ui->plainTextEditCurrentPieceUUID->setPlainText(selectedPiece->GetUUID().toString()); - ui->checkBoxCurrentPieceShowSeamline->setChecked(selectedPiece->GetShowSeamLine()); - ui->checkBoxCurrentPieceMirrorPiece->setChecked(selectedPiece->GetPieceMirrored()); +// ui->checkBoxCurrentPieceShowSeamline->setChecked(selectedPiece->GetShowSeamLine()); + ui->checkBoxCurrentPieceMirrorPiece->setChecked(selectedPiece->IsMirror()); QPointF pos = selectedPiece->GetPosition(); SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionX, @@ -612,8 +607,8 @@ void VPMainWindow::SetPropertyTabCurrentPieceData() SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceBoxPositionY, UnitConvertor(pos.y(), Unit::Px, m_layout->LayoutSettings().GetUnit())); - qreal angle = selectedPiece->GetRotation(); - SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); +// qreal angle = selectedPiece->GetRotation(); +// SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); } else { @@ -1694,7 +1689,7 @@ void VPMainWindow::on_checkBoxCurrentPieceShowSeamline_toggled(bool checked) { if(m_selectedPieces.count() == 1) { - m_selectedPieces.first()->SetShowSeamLine(checked); +// m_selectedPieces.first()->SetShowSeamLine(checked); } } @@ -1703,7 +1698,7 @@ void VPMainWindow::on_checkBoxCurrentPieceMirrorPiece_toggled(bool checked) { if(m_selectedPieces.count() == 1) { - m_selectedPieces.first()->SetPieceMirrored(checked); + m_selectedPieces.first()->SetMirror(checked); } } @@ -1712,7 +1707,7 @@ void VPMainWindow::on_pushButtonCurrentPieceRotate90Anticlockwise_clicked() { if(m_selectedPieces.count() == 1) { - m_selectedPieces.first()->RotateBy(90); +// m_selectedPieces.first()->RotateBy(90); } } @@ -1721,7 +1716,7 @@ void VPMainWindow::on_pushButtonCurrentPieceRotate90Clockwise_clicked() { if(m_selectedPieces.count() == 1) { - m_selectedPieces.first()->RotateBy(-90); +// m_selectedPieces.first()->RotateBy(-90); } } @@ -1730,7 +1725,7 @@ void VPMainWindow::on_pushButtonCurrentPieceRotateGrainlineVertical_clicked() { if(m_selectedPieces.count() == 1) { - m_selectedPieces.first()->RotateToGrainline(90, true); +// m_selectedPieces.first()->RotateToGrainline(90, true); } } @@ -1739,7 +1734,7 @@ void VPMainWindow::on_pushButtonCurrentPieceRotateGrainlineHorizontal_clicked() { if(m_selectedPieces.count() == 1) { - m_selectedPieces.first()->RotateToGrainline(0, true); +// m_selectedPieces.first()->RotateToGrainline(0, true); } } @@ -1748,8 +1743,8 @@ void VPMainWindow::on_doubleSpinBoxCurrentPieceAngle_valueChanged(double value) { if(m_selectedPieces.count() == 1) { - VPPiece *piece = m_selectedPieces.first(); - piece->SetRotation(value); +// VPPiece *piece = m_selectedPieces.first(); +// piece->SetRotation(value); } } @@ -1811,10 +1806,10 @@ void VPMainWindow::on_PieceRotationChanged() { if(m_selectedPieces.count() == 1) { - VPPiece *piece = m_selectedPieces.first(); - qreal angle = piece->GetRotation(); +// VPPiece *piece = m_selectedPieces.first(); +// qreal angle = piece->GetRotation(); - SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); +// SetDoubleSpinBoxValue(ui->doubleSpinBoxCurrentPieceAngle, angle); } } diff --git a/src/app/puzzle/vpmainwindow.h b/src/app/puzzle/vpmainwindow.h index 005aa48ef..995b73359 100644 --- a/src/app/puzzle/vpmainwindow.h +++ b/src/app/puzzle/vpmainwindow.h @@ -34,10 +34,10 @@ #include #include "../vmisc/def.h" -#include "vpcarrousel.h" -#include "vpmaingraphicsview.h" -#include "vplayout.h" -#include "vppiece.h" +#include "carousel/vpcarrousel.h" +#include "scene/vpmaingraphicsview.h" +#include "layout/vplayout.h" +#include "layout/vppiece.h" #include "../vlayout/vlayoutpiece.h" #include "vptilefactory.h" #include "vpexporter.h" diff --git a/src/app/puzzle/vpmainwindow.ui b/src/app/puzzle/vpmainwindow.ui index 30f148558..8e5544612 100644 --- a/src/app/puzzle/vpmainwindow.ui +++ b/src/app/puzzle/vpmainwindow.ui @@ -669,7 +669,7 @@ 0 - 0 + -170 342 870 diff --git a/src/app/puzzle/vppiece.cpp b/src/app/puzzle/vppiece.cpp deleted file mode 100644 index d5561c927..000000000 --- a/src/app/puzzle/vppiece.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/************************************************************************ - ** - ** @file vppiece.cpp - ** @author Ronan Le Tiec - ** @date 13 4, 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 "vppiece.h" - -#include - -#include "../vmisc/def.h" - -#include -#include -#include - -Q_LOGGING_CATEGORY(pPiece, "p.piece") - -//--------------------------------------------------------------------------------------------------------------------- -VPPiece::VPPiece(VLayoutPiece layoutPiece): VLayoutPiece(layoutPiece) -{ - // Resets the translation of the matrix - QTransform matrix = GetMatrix(); - matrix.translate(-matrix.dx() ,-matrix.dy()); - SetMatrix(matrix); - - // then translate the piece so that the top left corner of the bouding rect of the piece is at the position - // (0,0) in the sheet coordinate system - QRectF boundingRect = MappedDetailBoundingRect(); - QPointF offset = boundingRect.topLeft(); - matrix = GetMatrix(); - matrix.translate(-offset.x() ,-offset.y()); - SetMatrix(matrix); -} - -//--------------------------------------------------------------------------------------------------------------------- -VPPiece::~VPPiece() -{ - -} - -//--------------------------------------------------------------------------------------------------------------------- -bool VPPiece::GetShowSeamLine() const -{ - return m_showSeamline; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetShowSeamLine(bool value) -{ - m_showSeamline = value; - - emit PropertiesChanged(); -} - -//--------------------------------------------------------------------------------------------------------------------- -bool VPPiece::GetPieceMirrored() const -{ - return m_mirrorPiece; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetPieceMirrored(bool value) -{ - m_mirrorPiece = value; - - emit PropertiesChanged(); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetPosition(QPointF point) -{ - m_transform.translate(point.x() - m_transform.dx(), point.y() - m_transform.dy()); - - emit PositionChanged(); -} - -//--------------------------------------------------------------------------------------------------------------------- -QPointF VPPiece::GetPosition() -{ - return QPointF(m_transform.dx(),m_transform.dy()); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetRotation(qreal angle) -{ - // qreal currentAngle = GetRotation(); - // qreal newAngle = angle - currentAngle; - - // m_transform.rotate(newAngle); - - if(not VFuzzyComparePossibleNulls(m_pieceAngle, angle)) - { - m_pieceAngle = angle; - - // make sure the angle is [0 <= angle < 360] - while(m_pieceAngle >= 360) - { - m_pieceAngle -= 360; - } - - while(m_pieceAngle < 0) - { - m_pieceAngle += 360; - } - - emit RotationChanged(); - } -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::RotateBy(qreal angle) -{ - SetRotation(m_pieceAngle + angle); -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::RotateToGrainline(qreal angleOfGrainline, bool add180IfAlreadyInPosition) -{ - qreal newAngle = -GrainlineAngle() + angleOfGrainline; - if(newAngle < 0) - { - newAngle += 360; - } - - if(not VFuzzyComparePossibleNulls(m_pieceAngle, newAngle)) - { - SetRotation(newAngle); - } - else if(add180IfAlreadyInPosition) - { - newAngle += 180; - SetRotation(newAngle); - } -} - -//--------------------------------------------------------------------------------------------------------------------- -qreal VPPiece::GetRotation() -{ - return m_pieceAngle; - - // We don't use the QTransform vor now because the math behind it to retrieve the angle is not trivial. - // TODO / FIXME: we can use QTransform later for optimization - - -// QTransform tmpTransform = m_transform; -// tmpTransform.translate(-tmpTransform.dx(), -tmpTransform.dy()); // make sure there is only the rotation in the matrix - -// qreal angle = qRadiansToDegrees(qAcos(tmpTransform.m11())); - -// qCDebug(pPiece, "new angle : %f", angle); - -// return angle; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetIsSelected(bool value) -{ - if(m_isSelected != value) - { - m_isSelected = value; - emit SelectionChanged(); - } -} - -//--------------------------------------------------------------------------------------------------------------------- -bool VPPiece::GetIsSelected() -{ - return m_isSelected; -} - -//--------------------------------------------------------------------------------------------------------------------- -auto VPPiece::Sheet() const -> VPSheet * -{ - return m_sheet; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetSheet(VPSheet *newSheet) -{ - m_sheet = newSheet; -} - -//--------------------------------------------------------------------------------------------------------------------- -auto VPPiece::Layout() const -> VPLayout * -{ - return m_layout; -} - -//--------------------------------------------------------------------------------------------------------------------- -void VPPiece::SetLayout(VPLayout *layout) -{ - SCASSERT(layout != nullptr) - m_layout = layout; -} diff --git a/src/app/puzzle/vppiece.h b/src/app/puzzle/vppiece.h deleted file mode 100644 index 6e1e22ffe..000000000 --- a/src/app/puzzle/vppiece.h +++ /dev/null @@ -1,181 +0,0 @@ -/************************************************************************ - ** - ** @file vppiece.h - ** @author Ronan Le Tiec - ** @date 13 4, 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 VPPIECE_H -#define VPPIECE_H - -#include -#include -#include -#include - -#include "../vlayout/vlayoutpiece.h" - -class VPLayout; -class VPSheet; - -class VPPiece : public QObject, public VLayoutPiece -{ - Q_OBJECT -public: - VPPiece() = default; - explicit VPPiece(VLayoutPiece layoutPiece); - - virtual ~VPPiece(); - - /** - * @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 - */ - bool GetShowSeamLine() const; - - /** - * @brief SetShowSeamLine sets wether the seam line of the piece has to be shown or not - * @param value true if the seamline has to be shown - */ - void SetShowSeamLine(bool value); - - /** - * @brief GetMirrorPiece returns wether the piece is mirrored or not - * @return true if the piece is mirrored - */ - bool GetPieceMirrored() const; - - /** - * @brief SetMirrorPiece sets wether the piece is mirrored or not - * @param value true if the piece will be mirrored - */ - void SetPieceMirrored(bool value); - - /** - * @brief SetPosition Sets the position of the piece, in relation to the origin of the scene - * @param point the point where to set the piece - */ - void SetPosition(QPointF point); - - /** - * @brief GetPosition Returns the position of the piece - * @return the position of the piece - */ - QPointF GetPosition(); - - /** - * @brief SetRotation Sets the rotation of the piece to the given angle. - * @param angle the angle of the rotation in degree - */ - void SetRotation(qreal angle); - - /** - * @brief GetRotation Returns the angle of rotation - * @return the angle of rotation - */ - qreal GetRotation(); - - /** - * @brief rotateBy adds the given angle to the current rotation (anti-clockwise) - * @param angle the angle to add - */ - void RotateBy(qreal angle); - - /** - * @brief RotateToGrainline rotates the piece, so that the grainline has - * the given angle - * - * @param angleOfGrainline angle of grainline - * @param add180IfAlreadyInPosition automatically adds 180, if the piece is - * already in the grainline position - */ - void RotateToGrainline(qreal angleOfGrainline, bool add180IfAlreadyInPosition = false); - - /** - * @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(); - - QIcon PieceIcon(const QSize &size) const; - - auto Sheet() const -> VPSheet *; - void SetSheet(VPSheet *newSheet); - - auto Layout() const -> VPLayout *; - void SetLayout(VPLayout *layout); - -signals: - /** - * @brief SelectionChanged emited when the selection of the piece was - * changed through the SetIsSelected function - */ - void SelectionChanged(); - - /** - * @brief PositionChanged emited when the position of the piece was - * changed through the SetPosition function - */ - void PositionChanged(); - - /** - * @brief RotationChanged emited when the position of the piece was - * changed through the function SetRotation - */ - void RotationChanged(); - - /** - * @brief PropertiesChanged emited when of the properties showSemaline - * or mirrorpiece where changed. - */ - void PropertiesChanged(); - -private: - Q_DISABLE_COPY(VPPiece) - - VPLayout *m_layout{nullptr}; - - VPSheet *m_sheet{nullptr}; - - QVector m_grainline{}; - bool m_isGrainlineEnabled{false}; - - // for now separate the position of the piece to the matrix coming from vlayoutpiece - // because it's difficult to have the origin of the piece by (0,0) - QTransform m_transform{}; - // use a separate value for now because it's not easy to get the angle from the transform matrix - qreal m_pieceAngle{0}; - - bool m_showSeamline{true}; - bool m_mirrorPiece{false}; - - bool m_isSelected{false}; -}; - -#endif // VPPIECE_H diff --git a/src/app/puzzle/vptilefactory.cpp b/src/app/puzzle/vptilefactory.cpp index 076102845..b789f5883 100644 --- a/src/app/puzzle/vptilefactory.cpp +++ b/src/app/puzzle/vptilefactory.cpp @@ -3,9 +3,11 @@ #include #include "../vwidgets/vmaingraphicsscene.h" -#include "vpsheet.h" -#include "vpmaingraphicsview.h" - +#include "layout/vpsheet.h" +#include "scene/vpmaingraphicsview.h" +#include "layout/vplayout.h" +#include "../vmisc/def.h" +#include "../vmisc/vcommonsettings.h" //--------------------------------------------------------------------------------------------------------------------- VPTileFactory::VPTileFactory(VPLayout *layout, VCommonSettings *commonSettings): @@ -21,7 +23,6 @@ VPTileFactory::~VPTileFactory() } - //--------------------------------------------------------------------------------------------------------------------- void VPTileFactory::refreshTileInfos() { diff --git a/src/app/puzzle/vptilefactory.h b/src/app/puzzle/vptilefactory.h index 0032f7d9d..b89303d4d 100644 --- a/src/app/puzzle/vptilefactory.h +++ b/src/app/puzzle/vptilefactory.h @@ -32,11 +32,10 @@ #include #include -#include "vplayout.h" -#include "../vmisc/def.h" -#include "vcommonsettings.h" - class VPMainGraphicsView; +class VPLayout; +class VCommonSettings; +class QPainter; class VPTileFactory : QObject { diff --git a/src/app/puzzle/xml/vplayoutfilereader.cpp b/src/app/puzzle/xml/vplayoutfilereader.cpp index 8476ed0b0..6fbbfc3b7 100644 --- a/src/app/puzzle/xml/vplayoutfilereader.cpp +++ b/src/app/puzzle/xml/vplayoutfilereader.cpp @@ -30,7 +30,7 @@ #include "vplayoutfilereader.h" #include "vplayoutfilewriter.h" #include "vplayoutliterals.h" -#include "vpsheet.h" +#include "../layout/vpsheet.h" #include "../ifc/exception/vexception.h" #include "../ifc/exception/vexceptionconversionerror.h" @@ -297,11 +297,11 @@ void VPLayoutFileReader::ReadPiece(VPPiece *piece) QString uuidStr = ReadAttributeString(attribs, ML::AttrID, QUuid::createUuid().toString()); piece->SetUUID(QUuid(uuidStr)); - bool showSeamline = ReadAttributeBool(attribs, ML::AttrShowSeamline, trueStr); - piece->SetShowSeamLine(showSeamline); +// bool showSeamline = ReadAttributeBool(attribs, ML::AttrShowSeamline, trueStr); +// piece->SetShowSeamLine(showSeamline); bool pieceMirrored = ReadAttributeBool(attribs, ML::AttrMirrored, falseStr); - piece->SetPieceMirrored(pieceMirrored); + piece->SetMirror(pieceMirrored); // TODO read the further attributes diff --git a/src/app/puzzle/xml/vplayoutfilereader.h b/src/app/puzzle/xml/vplayoutfilereader.h index fdb8e9f74..92886d741 100644 --- a/src/app/puzzle/xml/vplayoutfilereader.h +++ b/src/app/puzzle/xml/vplayoutfilereader.h @@ -31,8 +31,8 @@ #include #include "../ifc/xml/vabstractconverter.h" -#include "vplayout.h" -#include "vppiece.h" +#include "../layout/vplayout.h" +#include "../layout/vppiece.h" #include diff --git a/src/app/puzzle/xml/vplayoutfilewriter.cpp b/src/app/puzzle/xml/vplayoutfilewriter.cpp index cb008a09d..7bd0aeb34 100644 --- a/src/app/puzzle/xml/vplayoutfilewriter.cpp +++ b/src/app/puzzle/xml/vplayoutfilewriter.cpp @@ -27,9 +27,9 @@ *************************************************************************/ #include "vplayoutfilewriter.h" -#include "vplayout.h" -#include "vpsheet.h" -#include "vppiece.h" +#include "../layout/vplayout.h" +#include "../layout/vpsheet.h" +#include "../layout/vppiece.h" #include "vplayoutliterals.h" #include "../ifc/xml/vlayoutconverter.h" #include "../vmisc/projectversion.h" @@ -142,8 +142,8 @@ void VPLayoutFileWriter::WritePiece(VPPiece *piece) writeStartElement(ML::TagPiece); SetAttribute(ML::AttrID, piece->GetUUID().toString()); SetAttribute(ML::AttrName, piece->GetName()); - SetAttribute(ML::AttrMirrored, piece->GetPieceMirrored()); - SetAttribute(ML::AttrShowSeamline, piece->GetShowSeamLine()); + SetAttribute(ML::AttrMirrored, piece->IsMirror()); +// SetAttribute(ML::AttrShowSeamline, piece->GetShowSeamLine()); SetAttribute(ML::AttrTransform, "string representation of the transformation"); // TODO / Fixme get the right value // TODO cuttingLine diff --git a/src/libs/vlayout/vlayoutpiece.cpp b/src/libs/vlayout/vlayoutpiece.cpp index 58f3092ab..d8124125a 100644 --- a/src/libs/vlayout/vlayoutpiece.cpp +++ b/src/libs/vlayout/vlayoutpiece.cpp @@ -876,9 +876,15 @@ void VLayoutPiece::SetId(vidtype id) //--------------------------------------------------------------------------------------------------------------------- void VLayoutPiece::Translate(qreal dx, qreal dy) +{ + Translate(QPointF(dx, dy)); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VLayoutPiece::Translate(const QPointF &p) { QTransform m; - m.translate(dx, dy); + m.translate(p.x(), p.y()); d->matrix *= m; } diff --git a/src/libs/vlayout/vlayoutpiece.h b/src/libs/vlayout/vlayoutpiece.h index 5012c8392..a8fae0da2 100644 --- a/src/libs/vlayout/vlayoutpiece.h +++ b/src/libs/vlayout/vlayoutpiece.h @@ -128,6 +128,7 @@ public: bool IsMirror() const; void SetMirror(bool value); + void Translate(const QPointF &p); void Translate(qreal dx, qreal dy); void Scale(qreal sx, qreal sy); void Rotate(const QPointF &originPoint, qreal degrees);