From d37c68321ed1301defcdb9e19da5540ec6c98825 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 18 Feb 2022 17:57:41 +0200 Subject: [PATCH] Z value change for a layout piece. --- ChangeLog.txt | 3 + .../puzzle/carousel/vpcarrouselpiecelist.cpp | 1 + src/app/puzzle/layout/vplayout.h | 1 + src/app/puzzle/layout/vppiece.h | 17 + src/app/puzzle/layout/vpsheet.cpp | 2 + src/app/puzzle/puzzle.pri | 2 + src/app/puzzle/scene/vpgraphicspiece.cpp | 33 +- src/app/puzzle/scene/vpgraphicspiece.h | 1 + src/app/puzzle/scene/vpmaingraphicsview.cpp | 57 ++ src/app/puzzle/scene/vpmaingraphicsview.h | 2 + src/app/puzzle/undocommands/vpundocommand.cpp | 5 + src/app/puzzle/undocommands/vpundocommand.h | 22 +- .../undocommands/vpundopiecezvaluemove.cpp | 513 +++++++++++++++++ .../undocommands/vpundopiecezvaluemove.h | 99 ++++ src/app/puzzle/vpmainwindow.cpp | 45 ++ src/app/puzzle/vpmainwindow.h | 2 + src/app/puzzle/vpmainwindow.ui | 57 +- src/app/puzzle/xml/vplayoutfilereader.cpp | 1 + src/app/puzzle/xml/vplayoutfilewriter.cpp | 4 +- src/app/puzzle/xml/vplayoutliterals.cpp | 1 + src/app/puzzle/xml/vplayoutliterals.h | 1 + src/libs/ifc/schema.qrc | 1 + src/libs/ifc/schema/layout/v0.1.1.xsd | 522 ++++++++++++++++++ src/libs/ifc/xml/vlayoutconverter.cpp | 24 +- src/libs/ifc/xml/vlayoutconverter.h | 32 +- 25 files changed, 1417 insertions(+), 31 deletions(-) create mode 100644 src/app/puzzle/undocommands/vpundopiecezvaluemove.cpp create mode 100644 src/app/puzzle/undocommands/vpundopiecezvaluemove.h create mode 100644 src/libs/ifc/schema/layout/v0.1.1.xsd diff --git a/ChangeLog.txt b/ChangeLog.txt index ff98424a4..6829cde9f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,6 @@ +# Valentina 0.7.51 (unreleased) +- Z value change for a layout piece. + # Valentina 0.7.50 February 14, 2022 - Fix regression. Minimal seam allowance width is less than the point accuracy values. - Call autosave only in GUI mode. diff --git a/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp b/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp index a8fa089e2..9e22971b8 100644 --- a/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp +++ b/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp @@ -250,6 +250,7 @@ void VPCarrouselPieceList::contextMenuEvent(QContextMenuEvent *event) piece->ClearTransformations(); QRectF rect = sheet->GetMarginsRect(); piece->SetPosition(QPointF(rect.topLeft().x() + 1, rect.topLeft().y() + 1)); + piece->SetZValue(1.0); auto *command = new VPUndoMovePieceOnSheet(layout->GetFocusedSheet(), piece); layout->UndoStack()->push(command); } diff --git a/src/app/puzzle/layout/vplayout.h b/src/app/puzzle/layout/vplayout.h index 24b0daeae..7bd2e50a8 100644 --- a/src/app/puzzle/layout/vplayout.h +++ b/src/app/puzzle/layout/vplayout.h @@ -106,6 +106,7 @@ signals: void PieceSheetChanged(const VPPiecePtr &piece); void ActiveSheetChanged(const VPSheetPtr &focusedSheet); void PieceTransformationChanged(const VPPiecePtr &piece); + void PieceZValueChanged(const VPPiecePtr &piece); void TransformationOriginChanged(); void SheetListChanged(); void PieceSelectionChanged(const VPPiecePtr &piece); diff --git a/src/app/puzzle/layout/vppiece.h b/src/app/puzzle/layout/vppiece.h index 55a3f7b8f..c1037bad8 100644 --- a/src/app/puzzle/layout/vppiece.h +++ b/src/app/puzzle/layout/vppiece.h @@ -128,6 +128,9 @@ public: auto CopyNumber() const -> quint16; void SetCopyNumber(quint16 newCopyNumber); + auto ZValue() const -> qreal; + void SetZValue(qreal newZValue); + private: Q_DISABLE_COPY_MOVE(VPPiece) // NOLINT @@ -140,6 +143,8 @@ private: bool m_hasSuperpositionWithPieces{false}; quint16 m_copyNumber{1}; + + qreal m_zValue{1.0}; }; //--------------------------------------------------------------------------------------------------------------------- @@ -203,6 +208,18 @@ inline void VPPiece::SetHasSuperpositionWithPieces(bool newHasSuperpositionWithP m_hasSuperpositionWithPieces = newHasSuperpositionWithPieces; } +//--------------------------------------------------------------------------------------------------------------------- +inline auto VPPiece::ZValue() const -> qreal +{ + return m_zValue; +} + +//--------------------------------------------------------------------------------------------------------------------- +inline void VPPiece::SetZValue(qreal newZValue) +{ + m_zValue = newZValue; +} + Q_DECLARE_METATYPE(VPPiecePtr) // NOLINT #endif // VPPIECE_H diff --git a/src/app/puzzle/layout/vpsheet.cpp b/src/app/puzzle/layout/vpsheet.cpp index dce19f0db..ac57aaa08 100644 --- a/src/app/puzzle/layout/vpsheet.cpp +++ b/src/app/puzzle/layout/vpsheet.cpp @@ -305,6 +305,8 @@ void VPSheetSceneData::ConnectPiece(VPGraphicsPiece *piece) QObject::connect(layout.data(), &VPLayout::PieceTransformationChanged, piece, &VPGraphicsPiece::on_RefreshPiece); + QObject::connect(layout.data(), &VPLayout::PieceZValueChanged, piece, + &VPGraphicsPiece::PieceZValueChanged); QObject::connect(layout.data(), &VPLayout::PieceSelectionChanged, m_rotationControls, &VPGraphicsPieceControls::on_UpdateControls); QObject::connect(layout.data(), &VPLayout::PiecePositionValidityChanged, diff --git a/src/app/puzzle/puzzle.pri b/src/app/puzzle/puzzle.pri index 2129fab00..36f38d1eb 100644 --- a/src/app/puzzle/puzzle.pri +++ b/src/app/puzzle/puzzle.pri @@ -15,6 +15,7 @@ SOURCES += \ $$PWD/undocommands/vpundooriginmove.cpp \ $$PWD/undocommands/vpundopiecemove.cpp \ $$PWD/undocommands/vpundopiecerotate.cpp \ + $$PWD/undocommands/vpundopiecezvaluemove.cpp \ $$PWD/undocommands/vpundoremovesheet.cpp \ $$PWD/vpapplication.cpp \ $$PWD/carousel/vpcarrousel.cpp \ @@ -57,6 +58,7 @@ HEADERS += \ $$PWD/undocommands/vpundooriginmove.h \ $$PWD/undocommands/vpundopiecemove.h \ $$PWD/undocommands/vpundopiecerotate.h \ + $$PWD/undocommands/vpundopiecezvaluemove.h \ $$PWD/undocommands/vpundoremovesheet.h \ $$PWD/vpapplication.h \ $$PWD/carousel/vpcarrousel.h \ diff --git a/src/app/puzzle/scene/vpgraphicspiece.cpp b/src/app/puzzle/scene/vpgraphicspiece.cpp index 817bf532b..1e97fe524 100644 --- a/src/app/puzzle/scene/vpgraphicspiece.cpp +++ b/src/app/puzzle/scene/vpgraphicspiece.cpp @@ -72,6 +72,11 @@ VPGraphicsPiece::VPGraphicsPiece(const VPPiecePtr &piece, QGraphicsItem *parent) setAcceptHoverEvents(true); setCursor(Qt::OpenHandCursor); + if (not piece.isNull()) + { + setZValue(piece->ZValue()); + } + PaintPiece(); InitLabels(); } @@ -666,8 +671,19 @@ auto VPGraphicsPiece::PieceColor() const -> QColor //--------------------------------------------------------------------------------------------------------------------- void VPGraphicsPiece::on_RefreshPiece(const VPPiecePtr &piece) { - if (m_piece == piece) + VPPiecePtr p = m_piece.toStrongRef(); + if (p.isNull()) { + return; + } + + if (p->GetUniqueID() == piece->GetUniqueID()) + { + if (not piece.isNull()) + { + setZValue(piece->ZValue()); + } + prepareGeometryChange(); PaintPiece(); // refresh shapes InitLabels(); @@ -675,6 +691,21 @@ void VPGraphicsPiece::on_RefreshPiece(const VPPiecePtr &piece) } } +//--------------------------------------------------------------------------------------------------------------------- +void VPGraphicsPiece::PieceZValueChanged(const VPPiecePtr &piece) +{ + VPPiecePtr p = m_piece.toStrongRef(); + if (p.isNull() || piece.isNull()) + { + return; + } + + if (p->GetUniqueID() == piece->GetUniqueID()) + { + setZValue(piece->ZValue()); + } +} + //--------------------------------------------------------------------------------------------------------------------- auto VPGraphicsPiece::itemChange(GraphicsItemChange change, const QVariant &value) -> QVariant { diff --git a/src/app/puzzle/scene/vpgraphicspiece.h b/src/app/puzzle/scene/vpgraphicspiece.h index 6a2556c41..3fdcd80d9 100644 --- a/src/app/puzzle/scene/vpgraphicspiece.h +++ b/src/app/puzzle/scene/vpgraphicspiece.h @@ -63,6 +63,7 @@ signals: public slots: void on_RefreshPiece(const VPPiecePtr &piece); + void PieceZValueChanged(const VPPiecePtr &piece); protected: auto boundingRect() const -> QRectF override; diff --git a/src/app/puzzle/scene/vpmaingraphicsview.cpp b/src/app/puzzle/scene/vpmaingraphicsview.cpp index 31c28824c..32630e505 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.cpp +++ b/src/app/puzzle/scene/vpmaingraphicsview.cpp @@ -40,6 +40,7 @@ #include "../layout/vpsheet.h" #include "../layout/vppiece.h" #include "../vwidgets/vmaingraphicsscene.h" +#include "undocommands/vpundopiecezvaluemove.h" #include "vptilefactory.h" #include "vpgraphicspiece.h" #include "vpgraphicspiececontrols.h" @@ -193,6 +194,7 @@ void VPMainGraphicsView::dropEvent(QDropEvent *event) piece->ClearTransformations(); piece->SetPosition(mapToScene(event->pos())); + piece->SetZValue(1.0); auto *command = new VPUndoMovePieceOnSheet(layout->GetFocusedSheet(), piece); layout->UndoStack()->push(command); @@ -311,6 +313,22 @@ void VPMainGraphicsView::keyPressEvent(QKeyEvent *event) RotatePiecesByAngle(-15); } } + else if (event->key() == Qt::Key_Home) + { + ZValueMove(static_cast(ML::ZValueMove::Top)); + } + else if (event->key() == Qt::Key_PageUp) + { + ZValueMove(static_cast(ML::ZValueMove::Up)); + } + else if (event->key() == Qt::Key_PageDown) + { + ZValueMove(static_cast(ML::ZValueMove::Down)); + } + else if (event->key() == Qt::Key_End) + { + ZValueMove(static_cast(ML::ZValueMove::Bottom)); + } } //--------------------------------------------------------------------------------------------------------------------- @@ -666,6 +684,45 @@ void VPMainGraphicsView::ClearSelection() } } +//--------------------------------------------------------------------------------------------------------------------- +void VPMainGraphicsView::ZValueMove(int move) +{ + VPLayoutPtr layout = m_layout.toStrongRef(); + if (layout.isNull()) + { + return; + } + + VPSheetPtr sheet = layout->GetFocusedSheet(); + if (sheet.isNull()) + { + return; + } + + QList selectedPieces = sheet->GetSelectedPieces(); + if (selectedPieces.isEmpty()) + { + return; + } + + QList allPieces = sheet->GetPieces(); + if (allPieces.isEmpty() || (allPieces.size() == selectedPieces.size())) + { + return; + } + + auto zMove = static_cast(move); + + if (selectedPieces.size() == 1) + { + layout->UndoStack()->push(new VPUndoPieceZValueMove(ConstFirst(selectedPieces), zMove)); + } + else if (selectedPieces.size() > 1) + { + layout->UndoStack()->push(new VPUndoPiecesZValueMove(allPieces, zMove)); + } +} + //--------------------------------------------------------------------------------------------------------------------- void VPMainGraphicsView::on_PieceSheetChanged(const VPPiecePtr &piece) { diff --git a/src/app/puzzle/scene/vpmaingraphicsview.h b/src/app/puzzle/scene/vpmaingraphicsview.h index 3fe8d9f3b..19d552923 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.h +++ b/src/app/puzzle/scene/vpmaingraphicsview.h @@ -108,6 +108,8 @@ private: void SwitchScene(const VPSheetPtr &sheet); void ClearSelection(); + + void ZValueMove(int move); }; #endif // VPMAINGRAPHICSVIEW_H diff --git a/src/app/puzzle/undocommands/vpundocommand.cpp b/src/app/puzzle/undocommands/vpundocommand.cpp index d3b18baee..fa6774290 100644 --- a/src/app/puzzle/undocommands/vpundocommand.cpp +++ b/src/app/puzzle/undocommands/vpundocommand.cpp @@ -29,6 +29,11 @@ Q_LOGGING_CATEGORY(vpUndo, "vp.undo") +//--------------------------------------------------------------------------------------------------------------------- +VPUndoCommand::VPUndoCommand(QUndoCommand *parent) + : QUndoCommand(parent) +{} + //--------------------------------------------------------------------------------------------------------------------- VPUndoCommand::VPUndoCommand(bool allowMerge, QUndoCommand *parent) : QUndoCommand(parent), diff --git a/src/app/puzzle/undocommands/vpundocommand.h b/src/app/puzzle/undocommands/vpundocommand.h index 967e0b9e2..19c2dc917 100644 --- a/src/app/puzzle/undocommands/vpundocommand.h +++ b/src/app/puzzle/undocommands/vpundocommand.h @@ -32,6 +32,10 @@ #include #include +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + namespace ML { enum class UndoCommand: qint8 @@ -44,25 +48,27 @@ enum class UndoCommand: qint8 MoveOnSheet = 5, AddSheet = 6, RemoveSheet = 7, + ZValueMovePiece = 8, + ZValueMovePieces = 9, }; -} +} // namespace ML -Q_DECLARE_LOGGING_CATEGORY(vpUndo) +Q_DECLARE_LOGGING_CATEGORY(vpUndo) // NOLINT class VPUndoCommand : public QObject, public QUndoCommand { - Q_OBJECT + Q_OBJECT // NOLINT public: + explicit VPUndoCommand(QUndoCommand *parent = nullptr); explicit VPUndoCommand(bool allowMerge = false, QUndoCommand *parent = nullptr); - virtual ~VPUndoCommand() =default; + ~VPUndoCommand() override =default; auto AllowMerge() const -> bool; -protected: - bool m_allowMerge; - private: - Q_DISABLE_COPY(VPUndoCommand) + Q_DISABLE_COPY_MOVE(VPUndoCommand) // NOLINT + + bool m_allowMerge{false}; }; diff --git a/src/app/puzzle/undocommands/vpundopiecezvaluemove.cpp b/src/app/puzzle/undocommands/vpundopiecezvaluemove.cpp new file mode 100644 index 000000000..1d6ca0a84 --- /dev/null +++ b/src/app/puzzle/undocommands/vpundopiecezvaluemove.cpp @@ -0,0 +1,513 @@ +/************************************************************************ + ** + ** @file vpundopiecezvaluemove.cpp + ** @author Roman Telezhynskyi + ** @date 18 2, 2022 + ** + ** @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) 2022 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 "vpundopiecezvaluemove.h" +#include "../layout/vppiece.h" +#include "../layout/vplayout.h" +#include "../layout/vpsheet.h" +#include "undocommands/vpundocommand.h" + +namespace +{ +//--------------------------------------------------------------------------------------------------------------------- +auto CorrectedZValues(const QList> &order) -> QHash +{ + QHash correctedZValues; + + qreal step = 0; + if (not order.isEmpty()) + { + step = 1.0/order.size(); + } + + for (int i = 0; i < order.size(); ++i) + { + const QVector &level = order.at(i); + for (const auto &pieceId : level) + { + correctedZValues.insert(pieceId, i*step); + } + } + + return correctedZValues; +} +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- +VPUndoPieceZValueMove::VPUndoPieceZValueMove(const VPPiecePtr &piece, ML::ZValueMove move, QUndoCommand *parent) + : VPUndoCommand(parent), + m_piece(piece), + m_move(move) +{ + setText(QObject::tr("z value move piece")); + + VPSheetPtr sheet = Sheet(); + if (not sheet.isNull()) + { + const QList pieces = sheet->GetPieces(); + for(const auto& p : pieces) + { + if (not p.isNull()) + { + m_oldValues.insert(p->GetUniqueID(), p->ZValue()); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPieceZValueMove::undo() +{ + VPPiecePtr piece = Piece(); + if (piece.isNull()) + { + return; + } + + VPLayoutPtr layout = piece->Layout(); + if (layout.isNull()) + { + return; + } + + VPSheetPtr sheet = Sheet(); + if (sheet.isNull()) + { + return; + } + + if (layout->GetFocusedSheet() != sheet) + { + layout->SetFocusedSheet(sheet); + } + + const QList pieces = sheet->GetPieces(); + + for (const auto &p: pieces) + { + if (not p.isNull()) + { + if (m_oldValues.contains(p->GetUniqueID())) + { + p->SetZValue(m_oldValues.value(p->GetUniqueID())); + emit layout->PieceZValueChanged(p); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPieceZValueMove::redo() +{ + VPPiecePtr piece = Piece(); + if (piece.isNull()) + { + return; + } + + VPLayoutPtr layout = piece->Layout(); + if (layout.isNull()) + { + return; + } + + VPSheetPtr sheet = Sheet(); + if (sheet.isNull()) + { + return; + } + + if (layout->GetFocusedSheet() != sheet) + { + layout->SetFocusedSheet(sheet); + } + + const QList pieces = sheet->GetPieces(); + + QList> order; + + if (m_move == ML::ZValueMove::Top) + { + order = Levels(pieces, true); + order.append({piece->GetUniqueID()}); + } + else if (m_move == ML::ZValueMove::Up) + { + const qreal step = LevelStep(pieces); + for (const auto &p: pieces) + { + if (p->GetUniqueID() != piece->GetUniqueID()) + { + p->SetZValue(p->ZValue() - step); + } + } + + order = Levels(pieces, false); + } + else if (m_move == ML::ZValueMove::Down) + { + const qreal step = LevelStep(pieces); + for (const auto &p: pieces) + { + if (p->GetUniqueID() != piece->GetUniqueID()) + { + p->SetZValue(p->ZValue() + step); + } + } + + order = Levels(pieces, false); + } + else if (m_move == ML::ZValueMove::Bottom) + { + order = Levels(pieces, true); + order.prepend({piece->GetUniqueID()}); + } + + QHash correctedZValues = CorrectedZValues(order); + for (const auto &p: pieces) + { + if (not p.isNull()) + { + p->SetZValue(correctedZValues.value(p->GetUniqueID(), p->ZValue())); + emit layout->PieceZValueChanged(p); + } + } + + emit layout->LayoutChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPieceZValueMove::id() const -> int +{ + return static_cast(ML::UndoCommand::ZValueMovePiece); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPieceZValueMove::Piece() const -> VPPiecePtr +{ + return m_piece; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPieceZValueMove::Sheet() const -> VPSheetPtr +{ + VPPiecePtr p = Piece(); + if (not p.isNull()) + { + return p->Sheet(); + } + + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPieceZValueMove::Levels(const QList &pieces, bool skip) const -> QList > +{ + VPPiecePtr piece = Piece(); + if (piece.isNull()) + { + return {}; + } + + QMap> levels; + + for (const auto &p: pieces) + { + if (p.isNull() || (skip && p->GetUniqueID() == piece->GetUniqueID())) + { + continue; + } + + if (levels.contains(p->ZValue())) + { + QVector lavel_images = levels.value(p->ZValue()); + lavel_images.append(p->GetUniqueID()); + levels[p->ZValue()] = lavel_images; + } + else + { + levels[p->ZValue()] = {p->GetUniqueID()}; + } + } + + return levels.values(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPieceZValueMove::LevelStep(const QList &pieces) const -> qreal +{ + QList> levels = Levels(pieces, false); + if (levels.isEmpty()) + { + return 0; + } + + return 1.0/levels.size(); +} + +//--------------------------------------------------------------------------------------------------------------------- +// Z value pieces +VPUndoPiecesZValueMove::VPUndoPiecesZValueMove(const QList &pieces, ML::ZValueMove move, + QUndoCommand *parent) + : VPUndoCommand(parent), + m_move(move) +{ + setText(QObject::tr("z value move pieces")); + + m_pieces.reserve(pieces.size()); + for(const auto& p : pieces) + { + m_pieces.append(p); + } + + VPSheetPtr sheet = Sheet(); + if (not sheet.isNull()) + { + const QList pieces = sheet->GetPieces(); + for(const auto& p : pieces) + { + if (not p.isNull()) + { + m_oldValues.insert(p->GetUniqueID(), p->ZValue()); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPiecesZValueMove::undo() +{ + if (m_pieces.isEmpty()) + { + return; + } + + VPLayoutPtr layout = Layout(); + if (layout.isNull()) + { + return; + } + + VPSheetPtr sheet = Sheet(); + if (sheet.isNull()) + { + return; + } + + if (layout->GetFocusedSheet() != sheet) + { + layout->SetFocusedSheet(sheet); + } + + const QList pieces = sheet->GetPieces(); + + for (const auto &p: pieces) + { + if (not p.isNull()) + { + if (m_oldValues.contains(p->GetUniqueID())) + { + p->SetZValue(m_oldValues.value(p->GetUniqueID())); + emit layout->PieceZValueChanged(p); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPUndoPiecesZValueMove::redo() +{ + if (m_pieces.isEmpty()) + { + return; + } + + VPLayoutPtr layout = Layout(); + if (layout.isNull()) + { + return; + } + + VPSheetPtr sheet = Sheet(); + if (sheet.isNull()) + { + return; + } + + if (layout->GetFocusedSheet() != sheet) + { + layout->SetFocusedSheet(sheet); + } + + const QList allPieces = sheet->GetPieces(); + QVector ids = PieceIds(); + + QList> order; + + if (m_move == ML::ZValueMove::Top) + { + order = Levels(allPieces, ids, true); + order.append(ids); + } + else if (m_move == ML::ZValueMove::Up) + { + const qreal step = LevelStep(allPieces); + for (const auto &p: allPieces) + { + if (not ids.contains(p->GetUniqueID())) + { + p->SetZValue(p->ZValue() - step); + } + } + + order = Levels(allPieces, ids, false); + } + else if (m_move == ML::ZValueMove::Down) + { + const qreal step = LevelStep(allPieces); + for (const auto &p: allPieces) + { + if (not ids.contains(p->GetUniqueID())) + { + p->SetZValue(p->ZValue() + step); + } + } + + order = Levels(allPieces, ids, false); + } + else if (m_move == ML::ZValueMove::Bottom) + { + order = Levels(allPieces, ids, true); + order.prepend(ids); + } + + QHash correctedZValues = CorrectedZValues(order); + for (const auto &p: allPieces) + { + if (not p.isNull()) + { + p->SetZValue(correctedZValues.value(p->GetUniqueID(), p->ZValue())); + emit layout->PieceZValueChanged(p); + } + } + + emit layout->LayoutChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesZValueMove::id() const -> int +{ + return static_cast(ML::UndoCommand::ZValueMovePieces); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesZValueMove::Layout() const -> VPLayoutPtr +{ + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + return p->Layout(); + } + } + + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesZValueMove::Sheet() const -> VPSheetPtr +{ + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + return p->Sheet(); + } + } + + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesZValueMove::PieceIds() const -> QVector +{ + QVector ids; + ids.reserve(m_pieces.size()); + + for (const auto& piece : m_pieces) + { + VPPiecePtr p = piece.toStrongRef(); + if (not p.isNull()) + { + ids.append(p->GetUniqueID()); + } + } + + return ids; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesZValueMove::Levels(const QList &allPieces, const QVector &skipPieces, + bool skip) -> QList > +{ + QMap> levels; + + for (const auto &p: allPieces) + { + if (p.isNull() || (skip && skipPieces.contains(p->GetUniqueID()))) + { + continue; + } + + if (levels.contains(p->ZValue())) + { + QVector lavel_images = levels.value(p->ZValue()); + lavel_images.append(p->GetUniqueID()); + levels[p->ZValue()] = lavel_images; + } + else + { + levels[p->ZValue()] = {p->GetUniqueID()}; + } + } + + return levels.values(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VPUndoPiecesZValueMove::LevelStep(const QList &pieces) const -> qreal +{ + QList> levels = Levels(pieces, QVector(), false); + if (levels.isEmpty()) + { + return 0; + } + + return 1.0/levels.size(); +} diff --git a/src/app/puzzle/undocommands/vpundopiecezvaluemove.h b/src/app/puzzle/undocommands/vpundopiecezvaluemove.h new file mode 100644 index 000000000..55a86b84a --- /dev/null +++ b/src/app/puzzle/undocommands/vpundopiecezvaluemove.h @@ -0,0 +1,99 @@ +/************************************************************************ + ** + ** @file vpundopiecezvaluemove.h + ** @author Roman Telezhynskyi + ** @date 18 2, 2022 + ** + ** @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) 2022 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 VPUNDOPIECEZVALUEMOVE_H +#define VPUNDOPIECEZVALUEMOVE_H + +#include "vpundocommand.h" +#include "../layout/layoutdef.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + +namespace ML +{ +enum class ZValueMove +{ + Top, + Up, + Down, + Bottom +}; +} + +class VPUndoPieceZValueMove : public VPUndoCommand +{ +public: + VPUndoPieceZValueMove(const VPPiecePtr &piece, ML::ZValueMove move, QUndoCommand *parent = nullptr); + ~VPUndoPieceZValueMove() override =default; + + void undo() override; + void redo() override; + auto id() const -> int override; + +private: + Q_DISABLE_COPY_MOVE(VPUndoPieceZValueMove) // NOLINT + + VPPieceWeakPtr m_piece; + ML::ZValueMove m_move; + QHash m_oldValues{}; + + auto Piece() const -> VPPiecePtr; + auto Sheet() const -> VPSheetPtr; + + auto Levels(const QList &pieces, bool skip) const -> QList>; + auto LevelStep(const QList &pieces) const -> qreal; +}; + +class VPUndoPiecesZValueMove : public VPUndoCommand +{ +public: + VPUndoPiecesZValueMove(const QList &pieces, ML::ZValueMove move, QUndoCommand *parent = nullptr); + ~VPUndoPiecesZValueMove() override =default; + + void undo() override; + void redo() override; + auto id() const -> int override; + +private: + Q_DISABLE_COPY_MOVE(VPUndoPiecesZValueMove) // NOLINT + + QList m_pieces{}; + ML::ZValueMove m_move; + QHash m_oldValues{}; + + auto Layout() const -> VPLayoutPtr; + auto Sheet() const -> VPSheetPtr; + + auto PieceIds() const -> QVector; + static auto Levels(const QList &allPieces, const QVector &skipPieces, + bool skip) -> QList>; + auto LevelStep(const QList &pieces) const -> qreal; +}; + +#endif // VPUNDOPIECEZVALUEMOVE_H diff --git a/src/app/puzzle/vpmainwindow.cpp b/src/app/puzzle/vpmainwindow.cpp index 716be7f92..4d22b7132 100644 --- a/src/app/puzzle/vpmainwindow.cpp +++ b/src/app/puzzle/vpmainwindow.cpp @@ -58,6 +58,7 @@ #include "undocommands/vpundoaddsheet.h" #include "undocommands/vpundopiecerotate.h" #include "undocommands/vpundopiecemove.h" +#include "undocommands/vpundopiecezvaluemove.h" #include "dialogs/dialogsavemanuallayout.h" #include "../vdxf/libdxfrw/drw_base.h" #include "../vmisc/dialogs/dialogselectlanguage.h" @@ -688,6 +689,16 @@ void VPMainWindow::SetupMenu() ui->menuSheet->addAction(redoAction); ui->toolBarUndoCommands->addAction(redoAction); + // Z value + connect(ui->actionZValueBottom, &QAction::triggered, this, + [this](){ZValueMove(static_cast(ML::ZValueMove::Bottom));}); + connect(ui->actionZValueDown, &QAction::triggered, this, + [this](){ZValueMove(static_cast(ML::ZValueMove::Down));}); + connect(ui->actionZValueUp, &QAction::triggered, this, + [this](){ZValueMove(static_cast(ML::ZValueMove::Up));}); + connect(ui->actionZValueTop, &QAction::triggered, this, + [this](){ZValueMove(static_cast(ML::ZValueMove::Top));}); + // Watermark connect(ui->actionWatermarkEditor, &QAction::triggered, this, &VPMainWindow::CreateWatermark); connect(ui->actionEditCurrentWatermark, &QAction::triggered, this, &VPMainWindow::EditCurrentWatermark); @@ -3149,6 +3160,39 @@ void VPMainWindow::PrintLayoutTiledSheets(QPrinter *printer, const QListGetFocusedSheet(); + if (sheet.isNull()) + { + return; + } + + QList selectedPieces = sheet->GetSelectedPieces(); + if (selectedPieces.isEmpty()) + { + return; + } + + QList allPieces = sheet->GetPieces(); + if (allPieces.isEmpty() || (allPieces.size() == selectedPieces.size())) + { + return; + } + + auto zMove = static_cast(move); + + if (selectedPieces.size() == 1) + { + m_layout->UndoStack()->push(new VPUndoPieceZValueMove(ConstFirst(selectedPieces), zMove)); + } + else if (selectedPieces.size() > 1) + { + m_layout->UndoStack()->push(new VPUndoPiecesZValueMove(allPieces, zMove)); + } +} + //--------------------------------------------------------------------------------------------------------------------- void VPMainWindow::on_actionNew_triggered() { @@ -3664,6 +3708,7 @@ void VPMainWindow::ToolBarStyles() ToolBarStyle(ui->mainToolBar); ToolBarStyle(ui->toolBarZoom); ToolBarStyle(ui->toolBarUndoCommands); + ToolBarStyle(ui->toolBarZValue); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/puzzle/vpmainwindow.h b/src/app/puzzle/vpmainwindow.h index 039dbcc01..bb9a01bad 100644 --- a/src/app/puzzle/vpmainwindow.h +++ b/src/app/puzzle/vpmainwindow.h @@ -479,6 +479,8 @@ private: void PrintLayoutSheets(QPrinter *printer, const QList &sheets); void PrintLayoutTiledSheets(QPrinter *printer, const QList &sheets); + + void ZValueMove(int move); }; #endif // VPMAINWINDOW_H diff --git a/src/app/puzzle/vpmainwindow.ui b/src/app/puzzle/vpmainwindow.ui index a86a8e019..d845231b8 100644 --- a/src/app/puzzle/vpmainwindow.ui +++ b/src/app/puzzle/vpmainwindow.ui @@ -1973,6 +1973,27 @@ false + + + true + + + Z value + + + Qt::ToolButtonTextUnderIcon + + + TopToolBarArea + + + false + + + + + + @@ -2337,6 +2358,38 @@ QAction::ApplicationSpecificRole + + + + + + Bottom + + + + + + + + Down + + + + + + + + Up + + + + + + + + Top + + @@ -2364,8 +2417,8 @@ - - + + diff --git a/src/app/puzzle/xml/vplayoutfilereader.cpp b/src/app/puzzle/xml/vplayoutfilereader.cpp index a6e25a4e2..5d9d1fcc3 100644 --- a/src/app/puzzle/xml/vplayoutfilereader.cpp +++ b/src/app/puzzle/xml/vplayoutfilereader.cpp @@ -471,6 +471,7 @@ void VPLayoutFileReader::ReadPiece(const VPPiecePtr &piece) piece->SetHideMainPath(not ReadAttributeBool(attribs, ML::AttrShowSeamline, trueStr)); piece->SetXScale(ReadAttributeDouble(attribs, ML::AttrXScale, QChar('1'))); piece->SetYScale(ReadAttributeDouble(attribs, ML::AttrYScale, QChar('1'))); + piece->SetZValue(ReadAttributeDouble(attribs, ML::AttrZValue, QChar('1'))); bool pieceMirrored = ReadAttributeBool(attribs, ML::AttrMirrored, falseStr); piece->SetMirror(pieceMirrored); diff --git a/src/app/puzzle/xml/vplayoutfilewriter.cpp b/src/app/puzzle/xml/vplayoutfilewriter.cpp index 8c2e88882..aeb58bb80 100644 --- a/src/app/puzzle/xml/vplayoutfilewriter.cpp +++ b/src/app/puzzle/xml/vplayoutfilewriter.cpp @@ -153,7 +153,7 @@ void VPLayoutFileWriter::WriteFile(const VPLayoutPtr &layout, QIODevice *file) void VPLayoutFileWriter::WriteLayout(const VPLayoutPtr &layout) { writeStartElement(ML::TagLayout); - SetAttribute(ML::AttrVersion, VLayoutConverter::LayoutMaxVerStr); + SetAttribute(AttrLayoutVersion, VLayoutConverter::LayoutMaxVerStr); WriteLayoutProperties(layout); WritePieceList(layout->GetUnplacedPieces(), ML::TagUnplacedPieces); WriteSheets(layout); @@ -273,6 +273,8 @@ void VPLayoutFileWriter::WritePiece(const VPPiecePtr &piece) [](qreal xs) noexcept {return VFuzzyComparePossibleNulls(xs, 1.0);}); SetAttributeOrRemoveIf(ML::AttrYScale, piece->GetYScale(), [](qreal ys) noexcept {return VFuzzyComparePossibleNulls(ys, 1.0);}); + SetAttributeOrRemoveIf(ML::AttrZValue, piece->ZValue(), + [](qreal z) noexcept {return VFuzzyComparePossibleNulls(z, 1.0);}); writeStartElement(ML::TagSeamLine); writeCharacters(PathToString(piece->GetContourPoints())); diff --git a/src/app/puzzle/xml/vplayoutliterals.cpp b/src/app/puzzle/xml/vplayoutliterals.cpp index e31b5d67e..19d811117 100644 --- a/src/app/puzzle/xml/vplayoutliterals.cpp +++ b/src/app/puzzle/xml/vplayoutliterals.cpp @@ -105,6 +105,7 @@ const QString AttrIgnoreMargins = QStringLiteral("ignoreMargins"); const QString AttrShowPreview = QStringLiteral("showPreview"); const QString AttrPrintScheme = QStringLiteral("printScheme"); const QString AttrTileNumber = QStringLiteral("tileNumber"); +const QString AttrZValue = QStringLiteral("zValue"); const QString atFrontStr = QStringLiteral("atFront"); const QString atRearStr = QStringLiteral("atRear"); diff --git a/src/app/puzzle/xml/vplayoutliterals.h b/src/app/puzzle/xml/vplayoutliterals.h index aa6b0e460..13645c170 100644 --- a/src/app/puzzle/xml/vplayoutliterals.h +++ b/src/app/puzzle/xml/vplayoutliterals.h @@ -110,6 +110,7 @@ extern const QString AttrIgnoreMargins; extern const QString AttrShowPreview; extern const QString AttrPrintScheme; extern const QString AttrTileNumber; +extern const QString AttrZValue; extern const QString atFrontStr; extern const QString atRearStr; diff --git a/src/libs/ifc/schema.qrc b/src/libs/ifc/schema.qrc index fec6becc2..3b0a486f0 100644 --- a/src/libs/ifc/schema.qrc +++ b/src/libs/ifc/schema.qrc @@ -89,5 +89,6 @@ schema/watermark/v1.0.0.xsd schema/watermark/v1.1.0.xsd schema/layout/v0.1.0.xsd + schema/layout/v0.1.1.xsd diff --git a/src/libs/ifc/schema/layout/v0.1.1.xsd b/src/libs/ifc/schema/layout/v0.1.1.xsd new file mode 100644 index 000000000..f97f66a70 --- /dev/null +++ b/src/libs/ifc/schema/layout/v0.1.1.xsd @@ -0,0 +1,522 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/ifc/xml/vlayoutconverter.cpp b/src/libs/ifc/xml/vlayoutconverter.cpp index 9772638b7..b5326df30 100644 --- a/src/libs/ifc/xml/vlayoutconverter.cpp +++ b/src/libs/ifc/xml/vlayoutconverter.cpp @@ -38,8 +38,8 @@ */ const QString VLayoutConverter::LayoutMinVerStr = QStringLiteral("0.1.0"); -const QString VLayoutConverter::LayoutMaxVerStr = QStringLiteral("0.1.0"); -const QString VLayoutConverter::CurrentSchema = QStringLiteral("://schema/layout/v0.1.0.xsd"); +const QString VLayoutConverter::LayoutMaxVerStr = QStringLiteral("0.1.1"); +const QString VLayoutConverter::CurrentSchema = QStringLiteral("://schema/layout/v0.1.1.xsd"); //VLayoutConverter::LayoutMinVer; // <== DON'T FORGET TO UPDATE TOO!!!! //VLayoutConverter::LayoutMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!! @@ -88,7 +88,8 @@ auto VLayoutConverter::XSDSchema(unsigned ver) const -> QString { QHash schemas = { - std::make_pair(FormatVersion(0, 1, 0), CurrentSchema), + std::make_pair(FormatVersion(0, 1, 0), QStringLiteral("://schema/layout/v0.1.0.xsd")), + std::make_pair(FormatVersion(0, 1, 1), CurrentSchema), }; if (schemas.contains(ver)) @@ -105,6 +106,10 @@ void VLayoutConverter::ApplyPatches() switch (m_ver) { case (FormatVersion(0, 1, 0)): + ToV0_1_1(); + ValidateXML(XSDSchema(FormatVersion(0, 1, 1))); + Q_FALLTHROUGH(); + case (FormatVersion(0, 1, 1)): break; default: InvalidVersion(m_ver); @@ -119,7 +124,18 @@ void VLayoutConverter::DowngradeToCurrentMaxVersion() } //--------------------------------------------------------------------------------------------------------------------- -bool VLayoutConverter::IsReadOnly() const +auto VLayoutConverter::IsReadOnly() const -> bool { return false; } + +//--------------------------------------------------------------------------------------------------------------------- +void VLayoutConverter::ToV0_1_1() +{ + // TODO. Delete if minimal supported version is 0.1.1 + Q_STATIC_ASSERT_X(VLayoutConverter::LayoutMinVer < FormatVersion(0, 1, 1), + "Time to refactor the code."); + + SetVersion(QStringLiteral("0.1.1")); + Save(); +} diff --git a/src/libs/ifc/xml/vlayoutconverter.h b/src/libs/ifc/xml/vlayoutconverter.h index 956e5aeeb..3cac97f81 100644 --- a/src/libs/ifc/xml/vlayoutconverter.h +++ b/src/libs/ifc/xml/vlayoutconverter.h @@ -37,29 +37,31 @@ class VLayoutConverter : public VAbstractConverter { public: explicit VLayoutConverter(const QString &fileName); - virtual ~VLayoutConverter() Q_DECL_EQ_DEFAULT; + ~VLayoutConverter() override =default; - virtual QString GetFormatVersionStr() const override; + auto GetFormatVersionStr() const -> QString override; static const QString LayoutMaxVerStr; static const QString CurrentSchema; static Q_DECL_CONSTEXPR const unsigned LayoutMinVer = FormatVersion(0, 1, 0); - static Q_DECL_CONSTEXPR const unsigned LayoutMaxVer = FormatVersion(0, 1, 0); + static Q_DECL_CONSTEXPR const unsigned LayoutMaxVer = FormatVersion(0, 1, 1); protected: void SetVersion(const QString &version) override; - virtual unsigned MinVer() const override; - virtual unsigned MaxVer() const override; + auto MinVer() const -> unsigned override; + auto MaxVer() const -> unsigned override; - virtual QString MinVerStr() const override; - virtual QString MaxVerStr() const override; + auto MinVerStr() const -> QString override; + auto MaxVerStr() const -> QString override; - virtual QString XSDSchema(unsigned ver) const override; - virtual void ApplyPatches() override; - virtual void DowngradeToCurrentMaxVersion() override; + auto XSDSchema(unsigned ver) const -> QString override; + void ApplyPatches() override; + void DowngradeToCurrentMaxVersion() override; - virtual bool IsReadOnly() const override; + auto IsReadOnly() const -> bool override; + + void ToV0_1_1(); private: Q_DISABLE_COPY(VLayoutConverter) @@ -67,25 +69,25 @@ private: }; //--------------------------------------------------------------------------------------------------------------------- -inline unsigned VLayoutConverter::MinVer() const +inline auto VLayoutConverter::MinVer() const -> unsigned { return LayoutMinVer; } //--------------------------------------------------------------------------------------------------------------------- -inline unsigned VLayoutConverter::MaxVer() const +inline auto VLayoutConverter::MaxVer() const -> unsigned { return LayoutMaxVer; } //--------------------------------------------------------------------------------------------------------------------- -inline QString VLayoutConverter::MinVerStr() const +inline auto VLayoutConverter::MinVerStr() const -> QString { return LayoutMinVerStr; } //--------------------------------------------------------------------------------------------------------------------- -inline QString VLayoutConverter::MaxVerStr() const +inline auto VLayoutConverter::MaxVerStr() const -> QString { return LayoutMaxVerStr; }