Z value change for a layout piece.

This commit is contained in:
Roman Telezhynskyi 2022-02-18 17:57:41 +02:00
parent ed910db2c3
commit d37c68321e
25 changed files with 1417 additions and 31 deletions

View file

@ -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.

View file

@ -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);
}

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -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 \

View file

@ -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
{

View file

@ -63,6 +63,7 @@ signals:
public slots:
void on_RefreshPiece(const VPPiecePtr &piece);
void PieceZValueChanged(const VPPiecePtr &piece);
protected:
auto boundingRect() const -> QRectF override;

View file

@ -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<int>(ML::ZValueMove::Top));
}
else if (event->key() == Qt::Key_PageUp)
{
ZValueMove(static_cast<int>(ML::ZValueMove::Up));
}
else if (event->key() == Qt::Key_PageDown)
{
ZValueMove(static_cast<int>(ML::ZValueMove::Down));
}
else if (event->key() == Qt::Key_End)
{
ZValueMove(static_cast<int>(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<VPPiecePtr> selectedPieces = sheet->GetSelectedPieces();
if (selectedPieces.isEmpty())
{
return;
}
QList<VPPiecePtr> allPieces = sheet->GetPieces();
if (allPieces.isEmpty() || (allPieces.size() == selectedPieces.size()))
{
return;
}
auto zMove = static_cast<ML::ZValueMove>(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)
{

View file

@ -108,6 +108,8 @@ private:
void SwitchScene(const VPSheetPtr &sheet);
void ClearSelection();
void ZValueMove(int move);
};
#endif // VPMAINGRAPHICSVIEW_H

View file

@ -29,6 +29,11 @@
Q_LOGGING_CATEGORY(vpUndo, "vp.undo")
//---------------------------------------------------------------------------------------------------------------------
VPUndoCommand::VPUndoCommand(QUndoCommand *parent)
: QUndoCommand(parent)
{}
//---------------------------------------------------------------------------------------------------------------------
VPUndoCommand::VPUndoCommand(bool allowMerge, QUndoCommand *parent)
: QUndoCommand(parent),

View file

@ -32,6 +32,10 @@
#include <QUndoCommand>
#include <QLoggingCategory>
#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};
};

View file

@ -0,0 +1,513 @@
/************************************************************************
**
** @file vpundopiecezvaluemove.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @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
** <https://gitlab.com/smart-pattern/valentina> 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 <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vpundopiecezvaluemove.h"
#include "../layout/vppiece.h"
#include "../layout/vplayout.h"
#include "../layout/vpsheet.h"
#include "undocommands/vpundocommand.h"
namespace
{
//---------------------------------------------------------------------------------------------------------------------
auto CorrectedZValues(const QList<QVector<QString>> &order) -> QHash<QString, qreal>
{
QHash<QString, qreal> correctedZValues;
qreal step = 0;
if (not order.isEmpty())
{
step = 1.0/order.size();
}
for (int i = 0; i < order.size(); ++i)
{
const QVector<QString> &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<VPPiecePtr> 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<VPPiecePtr> 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<VPPiecePtr> pieces = sheet->GetPieces();
QList<QVector<QString>> 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<QString, qreal> 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<int>(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<VPPiecePtr> &pieces, bool skip) const -> QList<QVector<QString> >
{
VPPiecePtr piece = Piece();
if (piece.isNull())
{
return {};
}
QMap<qreal, QVector<QString>> levels;
for (const auto &p: pieces)
{
if (p.isNull() || (skip && p->GetUniqueID() == piece->GetUniqueID()))
{
continue;
}
if (levels.contains(p->ZValue()))
{
QVector<QString> 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<VPPiecePtr> &pieces) const -> qreal
{
QList<QVector<QString>> levels = Levels(pieces, false);
if (levels.isEmpty())
{
return 0;
}
return 1.0/levels.size();
}
//---------------------------------------------------------------------------------------------------------------------
// Z value pieces
VPUndoPiecesZValueMove::VPUndoPiecesZValueMove(const QList<VPPiecePtr> &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<VPPiecePtr> 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<VPPiecePtr> 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<VPPiecePtr> allPieces = sheet->GetPieces();
QVector<QString> ids = PieceIds();
QList<QVector<QString>> 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<QString, qreal> 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<int>(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<QString>
{
QVector<QString> 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<VPPiecePtr> &allPieces, const QVector<QString> &skipPieces,
bool skip) -> QList<QVector<QString> >
{
QMap<qreal, QVector<QString>> levels;
for (const auto &p: allPieces)
{
if (p.isNull() || (skip && skipPieces.contains(p->GetUniqueID())))
{
continue;
}
if (levels.contains(p->ZValue()))
{
QVector<QString> 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<VPPiecePtr> &pieces) const -> qreal
{
QList<QVector<QString>> levels = Levels(pieces, QVector<QString>(), false);
if (levels.isEmpty())
{
return 0;
}
return 1.0/levels.size();
}

View file

@ -0,0 +1,99 @@
/************************************************************************
**
** @file vpundopiecezvaluemove.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @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
** <https://gitlab.com/smart-pattern/valentina> 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 <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#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<QString, qreal> m_oldValues{};
auto Piece() const -> VPPiecePtr;
auto Sheet() const -> VPSheetPtr;
auto Levels(const QList<VPPiecePtr> &pieces, bool skip) const -> QList<QVector<QString>>;
auto LevelStep(const QList<VPPiecePtr> &pieces) const -> qreal;
};
class VPUndoPiecesZValueMove : public VPUndoCommand
{
public:
VPUndoPiecesZValueMove(const QList<VPPiecePtr> &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<VPPieceWeakPtr> m_pieces{};
ML::ZValueMove m_move;
QHash<QString, qreal> m_oldValues{};
auto Layout() const -> VPLayoutPtr;
auto Sheet() const -> VPSheetPtr;
auto PieceIds() const -> QVector<QString>;
static auto Levels(const QList<VPPiecePtr> &allPieces, const QVector<QString> &skipPieces,
bool skip) -> QList<QVector<QString>>;
auto LevelStep(const QList<VPPiecePtr> &pieces) const -> qreal;
};
#endif // VPUNDOPIECEZVALUEMOVE_H

View file

@ -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<int>(ML::ZValueMove::Bottom));});
connect(ui->actionZValueDown, &QAction::triggered, this,
[this](){ZValueMove(static_cast<int>(ML::ZValueMove::Down));});
connect(ui->actionZValueUp, &QAction::triggered, this,
[this](){ZValueMove(static_cast<int>(ML::ZValueMove::Up));});
connect(ui->actionZValueTop, &QAction::triggered, this,
[this](){ZValueMove(static_cast<int>(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 QList<VPSheet
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ZValueMove(int move)
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
QList<VPPiecePtr> selectedPieces = sheet->GetSelectedPieces();
if (selectedPieces.isEmpty())
{
return;
}
QList<VPPiecePtr> allPieces = sheet->GetPieces();
if (allPieces.isEmpty() || (allPieces.size() == selectedPieces.size()))
{
return;
}
auto zMove = static_cast<ML::ZValueMove>(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);
}
//---------------------------------------------------------------------------------------------------------------------

View file

@ -479,6 +479,8 @@ private:
void PrintLayoutSheets(QPrinter *printer, const QList<VPSheetPtr> &sheets);
void PrintLayoutTiledSheets(QPrinter *printer, const QList<VPSheetPtr> &sheets);
void ZValueMove(int move);
};
#endif // VPMAINWINDOW_H

View file

@ -1973,6 +1973,27 @@
<bool>false</bool>
</attribute>
</widget>
<widget class="QToolBar" name="toolBarZValue">
<property name="enabled">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>Z value</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionZValueBottom"/>
<addaction name="actionZValueDown"/>
<addaction name="actionZValueUp"/>
<addaction name="actionZValueTop"/>
</widget>
<action name="actionOpen">
<property name="icon">
<iconset theme="document-open">
@ -2337,6 +2358,38 @@
<enum>QAction::ApplicationSpecificRole</enum>
</property>
</action>
<action name="actionZValueBottom">
<property name="icon">
<iconset theme="go-bottom"/>
</property>
<property name="text">
<string>Bottom</string>
</property>
</action>
<action name="actionZValueDown">
<property name="icon">
<iconset theme="go-down"/>
</property>
<property name="text">
<string>Down</string>
</property>
</action>
<action name="actionZValueUp">
<property name="icon">
<iconset theme="go-up"/>
</property>
<property name="text">
<string>Up</string>
</property>
</action>
<action name="actionZValueTop">
<property name="icon">
<iconset theme="go-top"/>
</property>
<property name="text">
<string>Top</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
@ -2364,8 +2417,8 @@
</resources>
<connections/>
<buttongroups>
<buttongroup name="buttonGroupRotationDirection"/>
<buttongroup name="buttonGroupTileOrientation"/>
<buttongroup name="buttonGroupSheetOrientation"/>
<buttongroup name="buttonGroupTileOrientation"/>
<buttongroup name="buttonGroupRotationDirection"/>
</buttongroups>
</ui>

View file

@ -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);

View file

@ -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<qreal>(ML::AttrYScale, piece->GetYScale(),
[](qreal ys) noexcept {return VFuzzyComparePossibleNulls(ys, 1.0);});
SetAttributeOrRemoveIf<qreal>(ML::AttrZValue, piece->ZValue(),
[](qreal z) noexcept {return VFuzzyComparePossibleNulls(z, 1.0);});
writeStartElement(ML::TagSeamLine);
writeCharacters(PathToString(piece->GetContourPoints()));

View file

@ -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");

View file

@ -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;

View file

@ -89,5 +89,6 @@
<file>schema/watermark/v1.0.0.xsd</file>
<file>schema/watermark/v1.1.0.xsd</file>
<file>schema/layout/v0.1.0.xsd</file>
<file>schema/layout/v0.1.1.xsd</file>
</qresource>
</RCC>

View file

@ -0,0 +1,522 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="layout">
<xs:complexType>
<xs:sequence>
<xs:element name="properties">
<xs:complexType>
<xs:sequence>
<xs:element type="units" name="unit"/>
<xs:element type="xs:string" name="title"/>
<xs:element type="xs:string" name="description"/>
<xs:element name="control">
<xs:complexType>
<xs:attribute type="xs:boolean" name="warningSuperposition"/>
<xs:attribute type="xs:boolean" name="warningOutOfBound"/>
<xs:attribute type="xs:boolean" name="stickyEdges"/>
<xs:attribute type="xs:boolean" name="followGrainline"/>
<xs:attribute type="xs:float" name="piecesGap"/>
</xs:complexType>
</xs:element>
<xs:element name="tiles">
<xs:complexType>
<xs:sequence>
<xs:element name="size">
<xs:complexType>
<xs:attribute type="xs:float" name="width" use="required"/>
<xs:attribute type="xs:float" name="length" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="margin">
<xs:complexType>
<xs:attribute type="xs:float" name="top"/>
<xs:attribute type="xs:float" name="right"/>
<xs:attribute type="xs:float" name="bottom"/>
<xs:attribute type="xs:float" name="left"/>
<xs:attribute type="xs:boolean" name="ignoreMargins"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:boolean" name="visible"/>
<xs:attribute type="xs:string" name="matchingMarks"/>
<xs:attribute type="xs:boolean" name="printScheme"/>
<xs:attribute type="xs:boolean" name="tileNumber"/>
</xs:complexType>
</xs:element>
<xs:element name="scale">
<xs:complexType>
<xs:attribute type="LayoutScale" name="xScale"/>
<xs:attribute type="LayoutScale" name="yScale"/>
</xs:complexType>
</xs:element>
<xs:element name="watermark">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:boolean" name="showPreview" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="unplacedPieces">
<xs:complexType>
<xs:sequence>
<xs:element name="piece" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element type="PathNotEmpty" name="seamLine"/>
<xs:element name="seamAllowance">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="PathOrEmpty">
<xs:attribute type="xs:boolean" name="enabled" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="grainline">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="PathOrEmpty">
<xs:attribute type="xs:boolean" name="enabled" use="optional"/>
<xs:attribute type="xs:float" name="angle" use="optional"/>
<xs:attribute type="ArrowDirection" name="arrowDirection" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="notches">
<xs:complexType>
<xs:sequence>
<xs:element name="notch" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute type="xs:boolean" name="builtIn" use="optional"/>
<xs:attribute type="NotchType" name="type" use="optional"/>
<xs:attribute type="LinePath" name="baseLine" use="optional"/>
<xs:attribute type="LinesPath" name="path" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="internalPaths">
<xs:complexType>
<xs:sequence>
<xs:element name="internalPath" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="PathNotEmpty">
<xs:attribute type="xs:boolean" name="cut" use="optional"/>
<xs:attribute type="CurvePenStyle" name="penStyle" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="markers">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="marker" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="MarkerShapePath">
<xs:attribute type="Transformation" name="transform" use="required"/>
<xs:attribute type="MarkerType" name="type" use="required"/>
<xs:attribute type="PointPath" name="center" use="required"/>
<xs:attribute type="RectPath" name="box" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="labels">
<xs:complexType>
<xs:sequence>
<xs:element name="pieceLabel" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="lines">
<xs:complexType>
<xs:sequence>
<xs:element name="line" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:boolean" name="bold" use="optional"/>
<xs:attribute type="xs:boolean" name="italic" use="optional"/>
<xs:attribute type="xs:unsignedInt" name="alignment" use="optional"/>
<xs:attribute type="xs:unsignedInt" name="fontSize" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="font"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="shape" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="patternLabel" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="lines">
<xs:complexType>
<xs:sequence>
<xs:element name="line" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:boolean" name="bold" use="optional"/>
<xs:attribute type="xs:boolean" name="italic" use="optional"/>
<xs:attribute type="xs:unsignedInt" name="alignment" use="optional"/>
<xs:attribute type="xs:unsignedInt" name="fontSize" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="font"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="shape" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="uuid" use="required"/>
<xs:attribute type="xs:string" name="name"/>
<xs:attribute type="xs:boolean" name="mirrored"/>
<xs:attribute type="Transformation" name="transform"/>
<xs:attribute type="xs:string" name="gradationLabel"/>
<xs:attribute type="xs:unsignedInt" name="copyNumber"/>
<xs:attribute type="xs:boolean" name="showSeamline"/>
<xs:attribute type="xs:float" name="xScale"/>
<xs:attribute type="xs:float" name="yScale"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="sheets">
<xs:complexType>
<xs:sequence>
<xs:element name="sheet" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="name"/>
<xs:element name="size">
<xs:complexType>
<xs:attribute type="xs:float" name="width" use="required"/>
<xs:attribute type="xs:float" name="length" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="margin">
<xs:complexType>
<xs:attribute type="xs:float" name="top"/>
<xs:attribute type="xs:float" name="right"/>
<xs:attribute type="xs:float" name="bottom"/>
<xs:attribute type="xs:float" name="left"/>
<xs:attribute type="xs:boolean" name="ignoreMargins"/>
</xs:complexType>
</xs:element>
<xs:element name="pieces">
<xs:complexType>
<xs:sequence>
<xs:element name="piece" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element type="PathNotEmpty" name="seamLine"/>
<xs:element name="seamAllowance">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="PathOrEmpty">
<xs:attribute type="xs:boolean" name="enabled" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="grainline">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="PathOrEmpty">
<xs:attribute type="xs:boolean" name="enabled" use="optional"/>
<xs:attribute type="xs:float" name="angle" use="optional"/>
<xs:attribute type="ArrowDirection" name="arrowDirection" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="notches">
<xs:complexType>
<xs:sequence>
<xs:element name="notch" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute type="xs:boolean" name="builtIn" use="optional"/>
<xs:attribute type="NotchType" name="type" use="optional"/>
<xs:attribute type="LinePath" name="baseLine" use="optional"/>
<xs:attribute type="LinesPath" name="path" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="internalPaths">
<xs:complexType>
<xs:sequence>
<xs:element name="internalPath" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="PathNotEmpty">
<xs:attribute type="xs:boolean" name="cut" use="optional"/>
<xs:attribute type="CurvePenStyle" name="penStyle" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="markers">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="marker" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="MarkerShapePath">
<xs:attribute type="Transformation" name="transform" use="required"/>
<xs:attribute type="MarkerType" name="type" use="required"/>
<xs:attribute type="PointPath" name="center" use="required"/>
<xs:attribute type="RectPath" name="box" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="labels">
<xs:complexType>
<xs:sequence>
<xs:element name="pieceLabel" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="lines">
<xs:complexType>
<xs:sequence>
<xs:element name="line" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:boolean" name="bold" use="optional"/>
<xs:attribute type="xs:boolean" name="italic" use="optional"/>
<xs:attribute type="AlignmentType" name="alignment" use="optional"/>
<xs:attribute type="xs:unsignedInt" name="fontSize" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="font"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="PathNotEmpty" name="shape" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="patternLabel" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="lines">
<xs:complexType>
<xs:sequence>
<xs:element name="line" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:boolean" name="bold" use="optional"/>
<xs:attribute type="xs:boolean" name="italic" use="optional"/>
<xs:attribute type="AlignmentType" name="alignment" use="optional"/>
<xs:attribute type="xs:unsignedInt" name="fontSize" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="font"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="PathNotEmpty" name="shape" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="uuid" use="required"/>
<xs:attribute type="xs:string" name="name"/>
<xs:attribute type="xs:boolean" name="mirrored"/>
<xs:attribute type="Transformation" name="transform"/>
<xs:attribute type="xs:string" name="gradationLabel"/>
<xs:attribute type="xs:unsignedInt" name="copyNumber"/>
<xs:attribute type="xs:boolean" name="showSeamline"/>
<xs:attribute type="xs:float" name="xScale"/>
<xs:attribute type="xs:float" name="yScale"/>
<xs:attribute type="xs:float" name="zValue"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="GrainlineType" name="grainlineType"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="formatVersion" name="version" use="required"/>
</xs:complexType>
</xs:element>
<!--Types-->
<xs:simpleType name="formatVersion">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="units">
<xs:restriction base="xs:string">
<xs:enumeration value="mm"/>
<xs:enumeration value="cm"/>
<xs:enumeration value="inch"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="uuid">
<xs:restriction base="xs:string">
<xs:pattern value="|\{[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}\}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ArrowDirection">
<xs:restriction base="xs:string">
<xs:enumeration value="atFront"/>
<xs:enumeration value="atRear"/>
<xs:enumeration value="atBoth"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="NotchType">
<xs:restriction base="xs:unsignedInt">
<xs:enumeration value="0"/>
<!--OneLine-->
<xs:enumeration value="1"/>
<!--TwoLines-->
<xs:enumeration value="2"/>
<!--ThreeLines-->
<xs:enumeration value="3"/>
<!--TMark-->
<xs:enumeration value="4"/>
<!--VMark-->
<xs:enumeration value="5"/>
<!--VMark2-->
<xs:enumeration value="6"/>
<!--UMark-->
<xs:enumeration value="7"/>
<!--BoxMark-->
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="CurvePenStyle">
<xs:restriction base="xs:string">
<xs:enumeration value="hair"/>
<xs:enumeration value="dashLine"/>
<xs:enumeration value="dotLine"/>
<xs:enumeration value="dashDotLine"/>
<xs:enumeration value="dashDotDotLine"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="MarkerType">
<xs:restriction base="xs:unsignedInt">
<xs:enumeration value="0"/><!--Segment-->
<xs:enumeration value="1"/><!--Rectangle-->
<xs:enumeration value="2"/><!--Cross-->
<xs:enumeration value="3"/><!--Tshaped-->
<xs:enumeration value="4"/><!--Doubletree-->
<xs:enumeration value="5"/><!--Corner-->
<xs:enumeration value="6"/><!--Triangle-->
<xs:enumeration value="7"/><!--Hshaped-->
<xs:enumeration value="8"/><!--Button-->
<xs:enumeration value="9"/><!--Circle-->
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="AlignmentType">
<xs:restriction base="xs:unsignedInt">
<xs:enumeration value="0"/><!--default (no aligns)-->
<xs:enumeration value="1"/><!--aligns with the left edge-->
<xs:enumeration value="2"/><!--aligns with the right edge-->
<xs:enumeration value="4"/><!--Centers horizontally in the available space-->
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="Transformation">
<xs:restriction base="xs:string">
<xs:pattern value="([-+]?\d+\.?\d*([eE][-+]?\d+)?;){8,}[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PathNotEmpty">
<xs:restriction base="xs:string">
<xs:pattern value="([-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?\s){0,}[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PathOrEmpty">
<xs:restriction base="xs:string">
<xs:pattern value="|([-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?\s){0,}[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="LinePath">
<xs:restriction base="xs:string">
<xs:pattern value="[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?;[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="LinesPath">
<xs:restriction base="xs:string">
<xs:pattern value="([-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?;[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?\*){0,}[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?;[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PointPath">
<xs:restriction base="xs:string">
<xs:pattern value="[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="RectPath">
<xs:restriction base="xs:string">
<xs:pattern value="([-+]?\d+\.?\d*([eE][-+]?\d+)?;){3,}[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="MarkerShapePath">
<xs:restriction base="xs:string">
<xs:pattern value="(([-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?\s){0,}[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?\*){0,}([-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?\s){0,}[-+]?\d+\.?\d*([eE][-+]?\d+)?,[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="GrainlineType">
<xs:restriction base="xs:string">
<xs:enumeration value="horizontal"/>
<xs:enumeration value="vertical"/>
<xs:enumeration value="notFixed"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="LayoutScale">
<xs:restriction base="xs:float">
<xs:minInclusive value="0.01"/>
<xs:maxInclusive value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

View file

@ -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 <unsigned, QString> 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();
}

View file

@ -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;
}