valentina/src/app/puzzle/vpmainwindow.cpp

4535 lines
165 KiB
C++

/************************************************************************
**
** @file vpmainwindow.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 16 2, 2020
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2020 Valentina project
** <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 "vpmainwindow.h"
#include <QFileDialog>
#include <QCloseEvent>
#include <QtMath>
#include <QSvgGenerator>
#include <QFileSystemWatcher>
#include <QSaveFile>
#include <QUndoStack>
#include <QPrinterInfo>
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include "ui_vpmainwindow.h"
#include "dialogs/vpdialogabout.h"
#include "xml/vplayoutfilewriter.h"
#include "xml/vplayoutfilereader.h"
#include "vpapplication.h"
#include "../vlayout/vrawlayout.h"
#include "../vlayout/vlayoutexporter.h"
#include "../vlayout/vprintlayout.h"
#include "../vlayout/dialogs/watermarkwindow.h"
#include "../vmisc/vsysexits.h"
#include "../vmisc/projectversion.h"
#include "../ifc/xml/vlayoutconverter.h"
#include "../ifc/exception/vexception.h"
#include "../vwidgets/vmaingraphicsscene.h"
#include "layout/vpsheet.h"
#include "dialogs/dialogpuzzlepreferences.h"
#include "undocommands/vpundoaddsheet.h"
#include "undocommands/vpundopiecerotate.h"
#include "undocommands/vpundopiecemove.h"
#include "dialogs/dialogsavemanuallayout.h"
#include "../vdxf/libdxfrw/drw_base.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
#include "../vmisc/backport/qscopeguard.h"
#else
#include <QScopeGuard>
#endif
#include <QLoggingCategory>
#include <chrono>
#include <thread>
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes")
QT_WARNING_DISABLE_INTEL(1418)
Q_LOGGING_CATEGORY(pWindow, "p.window")
QT_WARNING_POP
namespace
{
//---------------------------------------------------------------------------------------------------------------------
auto CreateLayoutPath(const QString &path) -> bool
{
bool usedNotExistedDir = true;
QDir dir(path);
dir.setPath(path);
if (not dir.exists(path))
{
usedNotExistedDir = dir.mkpath(QChar('.'));
}
return usedNotExistedDir;
}
//---------------------------------------------------------------------------------------------------------------------
void RemoveLayoutPath(const QString &path, bool usedNotExistedDir)
{
if (usedNotExistedDir)
{
QDir dir(path);
dir.rmpath(QChar('.'));
}
}
//---------------------------------------------------------------------------------------------------------------------
void SetDoubleSpinBoxValue(QDoubleSpinBox *spinBox, qreal value)
{
spinBox->blockSignals(true);
spinBox->setValue(value);
spinBox->blockSignals(false);
}
//---------------------------------------------------------------------------------------------------------------------
void SetCheckBoxValue(QCheckBox *checkbox, bool value)
{
checkbox->blockSignals(true);
checkbox->setChecked(value);
checkbox->blockSignals(false);
}
//---------------------------------------------------------------------------------------------------------------------
void SetLineEditValue(QLineEdit *lineEdit, const QString &value)
{
lineEdit->blockSignals(true);
lineEdit->setText(value);
lineEdit->blockSignals(false);
}
//---------------------------------------------------------------------------------------------------------------------
void SetPlainTextEditValue(QPlainTextEdit *textEdit, const QString &value)
{
textEdit->blockSignals(true);
textEdit->setPlainText(value);
textEdit->blockSignals(false);
}
//---------------------------------------------------------------------------------------------------------------------
auto PiecesBoundingRect(const QList<VPPiecePtr> &selectedPieces) -> QRectF
{
QRectF rect;
for (const auto& item : selectedPieces)
{
if (not item.isNull())
{
rect = rect.united(item->MappedDetailBoundingRect());
}
}
return rect;
}
//---------------------------------------------------------------------------------------------------------------------
Q_REQUIRED_RESULT auto PreparePrinter(
const QPrinterInfo &info, QPrinter::PrinterMode mode = QPrinter::ScreenResolution) -> QSharedPointer<QPrinter>;
auto PreparePrinter(const QPrinterInfo &info, QPrinter::PrinterMode mode) -> QSharedPointer<QPrinter>
{
QPrinterInfo tmpInfo = info;
if(tmpInfo.isNull() || tmpInfo.printerName().isEmpty())
{
const QStringList list = QPrinterInfo::availablePrinterNames();
if(list.isEmpty())
{
return QSharedPointer<QPrinter>();
}
tmpInfo = QPrinterInfo::printerInfo(list.first());
}
auto printer = QSharedPointer<QPrinter>(new QPrinter(tmpInfo, mode));
printer->setResolution(static_cast<int>(PrintDPI));
return printer;
}
//---------------------------------------------------------------------------------------------------------------------
void SetPrinterSheetPageSettings(const QSharedPointer<QPrinter> &printer, const VPSheetPtr &sheet, qreal xScale,
qreal yScale)
{
SCASSERT(not printer.isNull())
QMarginsF margins;
if (not sheet->IgnoreMargins())
{
margins = sheet->GetSheetMargins();
}
QPageLayout::Orientation sheetOrientation = sheet->GetSheetOrientation();
QRectF imageRect = sheet->GetMarginsRect();
qreal width = FromPixel(imageRect.width() * xScale + margins.left() + margins.right(), Unit::Mm);
qreal height = FromPixel(imageRect.height() * yScale + margins.top() + margins.bottom(), Unit::Mm);
QSizeF pageSize = sheetOrientation == QPageLayout::Portrait ? QSizeF(width, height) : QSizeF(height, width);
if (not printer->setPageSize(QPageSize(pageSize, QPageSize::Millimeter)))
{
qWarning() << QObject::tr("Cannot set printer page size");
}
printer->setPageOrientation(sheetOrientation);
printer->setFullPage(sheet->IgnoreMargins());
if (not sheet->IgnoreMargins())
{
if (not printer->setPageMargins(UnitConvertor(margins, Unit::Px, Unit::Mm), QPageLayout::Millimeter))
{
qWarning() << QObject::tr("Cannot set printer margins");
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void SetPrinterTiledPageSettings(const QSharedPointer<QPrinter> &printer, const VPLayoutPtr &layout,
const VPSheetPtr &sheet, QPageLayout::Orientation orientation, bool forSheet)
{
SCASSERT(not printer.isNull())
if (layout.isNull() || sheet.isNull())
{
return;
}
QSizeF tileSize = layout->LayoutSettings().GetTilesSize(Unit::Mm);
QSizeF pageSize;
if (not forSheet)
{
pageSize = orientation == QPageLayout::Portrait ? tileSize : tileSize.transposed();
}
else
{
QPageLayout::Orientation tileOrientation = layout->LayoutSettings().GetTilesOrientation();
QPageLayout::Orientation sheetOrientation = sheet->GetSheetOrientation();
if (tileOrientation != sheetOrientation)
{
pageSize = orientation == QPageLayout::Portrait ? tileSize.transposed() : tileSize;
}
else
{
pageSize = orientation == QPageLayout::Portrait ? tileSize : tileSize.transposed();
}
}
if (not printer->setPageSize(QPageSize(pageSize, QPageSize::Millimeter)))
{
qWarning() << QObject::tr("Cannot set printer page size");
}
printer->setPageOrientation(orientation);
printer->setFullPage(layout->LayoutSettings().IgnoreTilesMargins());
if (not layout->LayoutSettings().IgnoreTilesMargins())
{
if (not printer->setPageMargins(layout->LayoutSettings().GetTilesMargins(Unit::Mm),
QPageLayout::Millimeter))
{
qWarning() << QObject::tr("Cannot set printer margins");
}
}
}
} // namespace
struct VPExportData
{
LayoutExportFormats format{LayoutExportFormats::SVG};
QList<VPSheetPtr> sheets{};
QString path{};
QString fileName{};
qreal xScale{1.};
qreal yScale{1.};
bool isBinaryDXF{false};
bool textAsPaths{false};
bool exportUnified{true};
bool showTilesScheme{false};
};
//---------------------------------------------------------------------------------------------------------------------
VPMainWindow::VPMainWindow(const VPCommandLinePtr &cmd, QWidget *parent) :
VAbstractMainWindow(parent),
ui(new Ui::VPMainWindow),
m_cmd(cmd),
m_undoStack(new QUndoStack(this)),
m_layout{VPLayout::CreateLayout(m_undoStack)},
m_statusLabel(new QLabel(this)),
m_layoutWatcher(new QFileSystemWatcher(this)),
m_watermarkWatcher(new QFileSystemWatcher(this))
{
ui->setupUi(this);
connect(m_layout.data(), &VPLayout::PieceSelectionChanged, this, &VPMainWindow::on_PieceSelectionChanged);
connect(m_layout.data(), &VPLayout::LayoutChanged, this, [this]()
{
LayoutWasSaved(false);
});
connect(m_layout.data(), &VPLayout::PieceTransformationChanged, this, [this]()
{
SetPropertyTabCurrentPieceData();
});
connect(m_layout.data(), &VPLayout::ActiveSheetChanged, this, [this]()
{
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
SetPropertyTabSheetData();
});
connect(m_undoStack, &QUndoStack::cleanChanged, this, [this](bool clean)
{
LayoutWasSaved(clean);
});
// init status bar
statusBar()->addPermanentWidget(m_statusLabel, 1);
SetupMenu();
InitProperties();
InitCarrousel();
InitMainGraphics();
InitZoomToolBar();
InitScaleToolBar();
SetPropertiesData();
ReadSettings();
#if defined(Q_OS_MAC)
// Mac OS Dock Menu
QMenu *menu = new QMenu(this);
connect(menu, &QMenu::aboutToShow, this, &VPMainWindow::AboutToShowDockMenu);
AboutToShowDockMenu();
menu->setAsDockMenu();
#endif //defined(Q_OS_MAC)
connect(m_layoutWatcher, &QFileSystemWatcher::fileChanged, this, [this](const QString &path)
{
if (not curFile.isEmpty() && curFile == path)
{
QFileInfo checkFile(path);
if (not checkFile.exists())
{
for(int i=0; i<=1000; i=i+10)
{
if (checkFile.exists())
{
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
UpdateWindowTitle();
if (checkFile.exists())
{
m_layoutWatcher->addPath(path);
}
}
});
connect(m_layoutWatcher, &QFileSystemWatcher::fileChanged, this, [this](const QString &path)
{
QFileInfo checkFile(path);
if (not checkFile.exists())
{
for(int i=0; i<=1000; i=i+10)
{
if (checkFile.exists())
{
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
if (checkFile.exists())
{
m_layoutWatcher->addPath(path);
}
});
m_graphicsView->RefreshLayout();
}
//---------------------------------------------------------------------------------------------------------------------
VPMainWindow::~VPMainWindow()
{
delete m_undoStack;
delete ui;
delete m_carrousel;
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::CurrentFile() const -> QString
{
return curFile;
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::LoadFile(QString path) -> bool
{
if (not QFileInfo::exists(path))
{
qCCritical(pWindow, "%s", qUtf8Printable(tr("File '%1' doesn't exist!").arg(path)));
if (m_cmd->IsTestModeEnabled())
{
qApp->exit(V_EX_NOINPUT);
}
return false;
}
// Check if file already opened
QList<VPMainWindow*> list = VPApplication::VApp()->MainWindows();
auto w = std::find_if(list.begin(), list.end(),
[path](VPMainWindow *window) { return window->CurrentFile() == path; });
if (w != list.end())
{
(*w)->activateWindow();
if (this != *w)
{
close();
return false;
}
return true;
}
VlpCreateLock(lock, path);
if (not lock->IsLocked())
{
if (not IgnoreLocking(lock->GetLockError(), path, m_cmd->IsGuiEnabled()))
{
return false;
}
}
try
{
VLayoutConverter converter(path);
m_curFileFormatVersion = converter.GetCurrentFormatVersion();
m_curFileFormatVersionStr = converter.GetFormatVersionStr();
path = converter.Convert();
}
catch (VException &e)
{
qCCritical(pWindow, "%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")),
qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
lock.reset();
return false;
}
QFile file(path);
file.open(QIODevice::ReadOnly);
VPLayoutFileReader fileReader;
m_layout->Clear();
fileReader.ReadFile(m_layout, &file);
if (fileReader.hasError())
{
qCCritical(pWindow, "%s\n\n%s", qUtf8Printable(tr("File error.")),
qUtf8Printable(tr("Unable to read a layout file. %1").arg(fileReader.errorString())));
lock.reset();
if (m_cmd->IsTestModeEnabled())
{
qApp->exit(V_EX_NOINPUT);
}
return false;
}
SetCurrentFile(path);
m_layout->SetFocusedSheet();
m_oldLayoutUnit = m_layout->LayoutSettings().GetUnit();
// updates the properties with the loaded data
SetPropertiesData();
m_carrousel->Refresh();
m_graphicsView->on_ActiveSheetChanged(m_layout->GetFocusedSheet());
m_layout->TileFactory()->refreshTileInfos();
m_layout->CheckPiecesPositionValidity();
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
ui->actionRemoveWatermark->setEnabled(not m_layout->LayoutSettings().WatermarkPath().isEmpty());
ui->actionEditCurrentWatermark->setEnabled(not m_layout->LayoutSettings().WatermarkPath().isEmpty());
if (not m_layout->LayoutSettings().WatermarkPath().isEmpty())
{
m_layoutWatcher->addPath(m_layout->LayoutSettings().WatermarkPath());
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::LayoutWasSaved(bool saved)
{
setWindowModified(!saved);
not IsLayoutReadOnly() ? ui->actionSave->setEnabled(!saved): ui->actionSave->setEnabled(false);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SetCurrentFile(const QString &fileName)
{
if (not curFile.isEmpty() && m_layoutWatcher->files().contains(curFile))
{
m_layoutWatcher->removePath(curFile);
}
curFile = fileName;
if (not curFile.isEmpty())
{
if (not m_layoutWatcher->files().contains(curFile))
{
m_layoutWatcher->addPath(curFile);
}
auto *settings = VPApplication::VApp()->PuzzleSettings();
QStringList files = settings->GetRecentFileList();
files.removeAll(fileName);
files.prepend(fileName);
while (files.size() > MaxRecentFiles)
{
files.removeLast();
}
settings->SetRecentFileList(files);
UpdateRecentFileActions();
}
UpdateWindowTitle();
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::SaveLayout(const QString &path, QString &error) -> bool
{
bool success = false;
QSaveFile file(path);
if (file.open(QIODevice::WriteOnly))
{
VPLayoutFileWriter fileWriter;
fileWriter.WriteFile(m_layout, &file);
if (fileWriter.hasError())
{
error = tr("Fail to create layout.");
return false;
}
success = file.commit();
}
if (success)
{
SetCurrentFile(path);
LayoutWasSaved(true);
}
else
{
error = file.errorString();
}
return success;
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ImportRawLayouts(const QStringList &rawLayouts)
{
VRawLayout rawLayoutReader;
for(const auto &path : rawLayouts)
{
VRawLayoutData data;
if (rawLayoutReader.ReadFile(path, data))
{
for (const auto& rawPiece : data.pieces)
{
for (quint16 i = 1; i <= rawPiece.GetQuantity(); ++i)
{
VPPiecePtr piece(new VPPiece(rawPiece));
piece->SetCopyNumber(i);
if (not piece->IsValid())
{
qCCritical(pWindow) << qPrintable(tr("Piece %1 invalid.").arg(piece->GetName()));
if (m_cmd != nullptr && not m_cmd->IsGuiEnabled())
{
QGuiApplication::exit(V_EX_DATAERR);
return;
}
}
piece->SetSheet(nullptr); // just in case
VPLayout::AddPiece(m_layout, piece);
}
}
m_carrousel->Refresh();
m_layout->CheckPiecesPositionValidity();
LayoutWasSaved(false);
}
else
{
qCCritical(pWindow, "%s\n", qPrintable(tr("Could not extract data from file '%1'. %2")
.arg(path, rawLayoutReader.ErrorString())));
if (m_cmd != nullptr && not m_cmd->IsGuiEnabled())
{
m_cmd->ShowHelp(V_EX_DATAERR);
}
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitZoom()
{
if (m_graphicsView != nullptr)
{
m_graphicsView->ZoomFitBest();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SetupMenu()
{
// most of the actions are connected through name convention (auto-connection)
// File
// -------------------- connects the actions for the file menu
ui->actionNew->setShortcuts(QKeySequence::New);
ui->actionSave->setShortcuts(QKeySequence::Save);
ui->actionSaveAs->setShortcuts(QKeySequence::SaveAs);
m_recentFileActs.fill(nullptr);
for (auto & recentFileAct : m_recentFileActs)
{
auto *action = new QAction(this);
recentFileAct = action;
connect(action, &QAction::triggered, this, [this]()
{
if (auto *senderAction = qobject_cast<QAction *>(sender()))
{
const QString filePath = senderAction->data().toString();
if (not filePath.isEmpty())
{
LoadFile(filePath);
}
}
});
ui->menuFile->insertAction(ui->actionPreferences, recentFileAct);
recentFileAct->setVisible(false);
}
m_separatorAct = new QAction(this);
m_separatorAct->setSeparator(true);
m_separatorAct->setVisible(false);
ui->menuFile->insertAction(ui->actionPreferences, m_separatorAct);
// Actions for recent files loaded by a puzzle window application.
UpdateRecentFileActions();
connect(ui->actionExit, &QAction::triggered, this, &VPMainWindow::close);
ui->actionExit->setShortcuts(QKeySequence::Quit);
// Layout
connect(ui->actionExportLayout, &QAction::triggered, this, &VPMainWindow::on_ExportLayout);
// Sheet
connect(ui->actionExportSheet, &QAction::triggered, this, &VPMainWindow::on_ExportSheet);
// Add dock properties action
ui->menuSheet->addSeparator();
QAction* actionDockWidgetToolOptions = ui->dockWidgetProperties->toggleViewAction();
ui->menuSheet->addAction(actionDockWidgetToolOptions);
ui->menuSheet->addSeparator();
// Add Undo/Redo actions.
undoAction = m_layout->UndoStack()->createUndoAction(this, tr("&Undo"));
undoAction->setShortcuts(QKeySequence::Undo);
undoAction->setIcon(QIcon::fromTheme("edit-undo"));
ui->menuSheet->addAction(undoAction);
ui->toolBarUndoCommands->addAction(undoAction);
redoAction = m_layout->UndoStack()->createRedoAction(this, tr("&Redo"));
redoAction->setShortcuts(QKeySequence::Redo);
redoAction->setIcon(QIcon::fromTheme("edit-redo"));
ui->menuSheet->addAction(redoAction);
ui->toolBarUndoCommands->addAction(redoAction);
// Watermark
connect(ui->actionWatermarkEditor, &QAction::triggered, this, &VPMainWindow::CreateWatermark);
connect(ui->actionEditCurrentWatermark, &QAction::triggered, this, &VPMainWindow::EditCurrentWatermark);
connect(ui->actionLoadWatermark, &QAction::triggered, this, &VPMainWindow::LoadWatermark);
connect(ui->actionRemoveWatermark, &QAction::triggered, this, &VPMainWindow::RemoveWatermark);
// Window
connect(ui->menuWindow, &QMenu::aboutToShow, this, [this]()
{
ui->menuWindow->clear();
CreateWindowMenu(ui->menuWindow);
});
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitProperties()
{
ui->tabWidgetProperties->setCurrentIndex(0);
VPSettings *settings = VPApplication::VApp()->PuzzleSettings();
m_oldLayoutUnit = settings->LayoutUnit();
InitPropertyTabCurrentPiece();
InitPropertyTabCurrentSheet();
InitPropertyTabTiles();
InitPropertyTabLayout();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitPropertyTabCurrentPiece()
{
connect(ui->checkBoxCurrentPieceShowSeamline, &QCheckBox::toggled, this, [this](bool checked)
{
QList<VPPiecePtr> selectedPieces = SelectedPieces();
if (selectedPieces.size() == 1)
{
VPPiecePtr selectedPiece = selectedPieces.first();
if (not selectedPiece.isNull())
{
selectedPiece->SetHideMainPath(not checked);
LayoutWasSaved(false);
// nothing changed, but will force redraw
emit m_layout->PieceTransformationChanged(selectedPiece);
}
}
});
connect(ui->checkBoxCurrentPieceMirrorPiece, &QCheckBox::toggled, this, [this](bool checked)
{
QList<VPPiecePtr> selectedPieces = SelectedPieces();
if (selectedPieces.size() == 1)
{
VPPiecePtr selectedPiece = selectedPieces.first();
if (not selectedPiece.isNull())
{
if (selectedPiece->IsMirror() != checked)
{
selectedPiece->Flip();
LayoutWasSaved(false);
emit m_layout->PieceTransformationChanged(selectedPiece);
}
}
}
});
// Translate
ui->comboBoxTranslateUnit->addItem(tr("Millimiters"), QVariant(UnitsToStr(Unit::Mm)));
ui->comboBoxTranslateUnit->addItem(tr("Centimeters"), QVariant(UnitsToStr(Unit::Cm)));
ui->comboBoxTranslateUnit->addItem(tr("Inches"), QVariant(UnitsToStr(Unit::Inch)));
ui->comboBoxTranslateUnit->addItem(tr("Pixels"), QVariant(UnitsToStr(Unit::Px)));
m_oldPieceTranslationUnit = Unit::Mm;
ui->comboBoxTranslateUnit->blockSignals(true);
ui->comboBoxTranslateUnit->setCurrentIndex(0);
ui->comboBoxTranslateUnit->blockSignals(false);
const int minTranslate = -1000;
const int maxTranslate = 1000;
ui->doubleSpinBoxCurrentPieceBoxPositionX->setMinimum(
UnitConvertor(minTranslate, Unit::Cm, m_oldPieceTranslationUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionX->setMaximum(
UnitConvertor(maxTranslate, Unit::Cm, m_oldPieceTranslationUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionX->setValue(0);
ui->doubleSpinBoxCurrentPieceBoxPositionY->setMinimum(
UnitConvertor(minTranslate, Unit::Cm, m_oldPieceTranslationUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setMaximum(
UnitConvertor(maxTranslate, Unit::Cm, m_oldPieceTranslationUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setValue(0);
connect(ui->comboBoxTranslateUnit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this]()
{
const Unit newUnit = TranslateUnit();
const qreal oldTranslateX = ui->doubleSpinBoxCurrentPieceBoxPositionX->value();
const qreal oldTranslateY = ui->doubleSpinBoxCurrentPieceBoxPositionY->value();
ui->doubleSpinBoxCurrentPieceBoxPositionX->setMinimum(UnitConvertor(minTranslate, Unit::Cm, newUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionX->setMaximum(UnitConvertor(maxTranslate, Unit::Cm, newUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setMinimum(UnitConvertor(minTranslate, Unit::Cm, newUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setMaximum(UnitConvertor(maxTranslate, Unit::Cm, newUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionX->setValue(
UnitConvertor(oldTranslateX, m_oldPieceTranslationUnit, newUnit));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setValue(
UnitConvertor(oldTranslateY, m_oldPieceTranslationUnit, newUnit));
m_oldPieceTranslationUnit = newUnit;
});
SetCheckBoxValue(ui->checkBoxRelativeTranslation, true);
connect(ui->checkBoxRelativeTranslation, &QCheckBox::toggled, this, &VPMainWindow::on_RelativeTranslationChanged);
// Rotate
ui->doubleSpinBoxCurrentPieceAngle->setValue(0);
ui->toolButtonCurrentPieceRotationAnticlockwise->setChecked(true);
ui->checkBoxTransformSeparately->setChecked(false);
QPushButton *bApply = ui->buttonBox->button(QDialogButtonBox::Apply);
SCASSERT(bApply != nullptr)
connect(bApply, &QPushButton::clicked, this, &VPMainWindow::on_ApplyPieceTransformation);
QPushButton *bReset = ui->buttonBox->button(QDialogButtonBox::Reset);
SCASSERT(bReset != nullptr)
connect(bReset, &QPushButton::clicked, this, &VPMainWindow::on_ResetPieceTransformationSettings);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitPropertyTabCurrentSheet()
{
connect(ui->lineEditSheetName, &QLineEdit::textEdited, this, [this](const QString &text)
{
if (not m_layout.isNull())
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->SetName(text);
LayoutWasSaved(false);
if(m_carrousel != nullptr)
{
m_carrousel->RefreshSheetNames();
}
}
}
});
// -------------------- layout units ---------------------------
ui->comboBoxLayoutUnit->addItem(tr("Millimiters"), QVariant(UnitsToStr(Unit::Mm)));
ui->comboBoxLayoutUnit->addItem(tr("Centimeters"), QVariant(UnitsToStr(Unit::Cm)));
ui->comboBoxLayoutUnit->addItem(tr("Inches"), QVariant(UnitsToStr(Unit::Inch)));
ui->comboBoxLayoutUnit->addItem(tr("Pixels"), QVariant(UnitsToStr(Unit::Px)));
VPSettings *settings = VPApplication::VApp()->PuzzleSettings();
const qint32 indexUnit = ui->comboBoxLayoutUnit->findData(UnitsToStr(settings->LayoutUnit()));
if (indexUnit != -1)
{
ui->comboBoxLayoutUnit->setCurrentIndex(indexUnit);
}
connect(ui->comboBoxLayoutUnit, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &VPMainWindow::on_ConvertPaperSize);
// -------------------- sheet template ---------------------------
VAbstractLayoutDialog::InitTemplates(ui->comboBoxSheetTemplates);
connect(ui->comboBoxSheetTemplates, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this]{SheetSize(SheetTemplate());});
// -------------------- paper size ---------------------------
MinimumSheetPaperSize();
const QString suffix = " " + UnitsToStr(LayoutUnit(), true);
ui->doubleSpinBoxSheetPaperWidth->setSuffix(suffix);
ui->doubleSpinBoxSheetPaperHeight->setSuffix(suffix);
connect(ui->doubleSpinBoxSheetPaperWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_SheetSizeChanged);
connect(ui->doubleSpinBoxSheetPaperHeight, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_SheetSizeChanged);
connect(ui->toolButtonSheetPortraitOritation, &QToolButton::toggled, this,
&VPMainWindow::on_SheetOrientationChanged);
connect(ui->toolButtonSheetLandscapeOrientation, &QToolButton::toggled, this,
&VPMainWindow::on_SheetOrientationChanged);
connect(ui->toolButtonGrainlineHorizontalOrientation, &QToolButton::clicked, this, [this](bool checked)
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
if (checked)
{
sheet->SetGrainlineType(GrainlineType::Horizontal);
ui->toolButtonGrainlineVerticalOrientation->setChecked(false);
}
else
{
sheet->SetGrainlineType(GrainlineType::NotFixed);
}
RotatePiecesToGrainline();
LayoutWasSaved(false);
});
connect(ui->toolButtonGrainlineVerticalOrientation, &QToolButton::clicked, this, [this](bool checked)
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
if (checked)
{
sheet->SetGrainlineType(GrainlineType::Vertical);
ui->toolButtonGrainlineHorizontalOrientation->setChecked(false);
}
else
{
sheet->SetGrainlineType(GrainlineType::NotFixed);
}
RotatePiecesToGrainline();
LayoutWasSaved(false);
});
connect(ui->pushButtonSheetRemoveUnusedLength, &QPushButton::clicked, this, [this]()
{
if (not m_layout.isNull())
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->RemoveUnusedLength();
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
m_graphicsView->RefreshPieces();
SetPropertyTabSheetData();
}
}
});
// -------------------- margins ------------------------
ui->doubleSpinBoxSheetMarginLeft->setSuffix(suffix);
ui->doubleSpinBoxSheetMarginRight->setSuffix(suffix);
ui->doubleSpinBoxSheetMarginTop->setSuffix(suffix);
ui->doubleSpinBoxSheetMarginBottom->setSuffix(suffix);
connect(ui->doubleSpinBoxSheetMarginTop, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_SheetMarginChanged);
connect(ui->doubleSpinBoxSheetMarginRight, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_SheetMarginChanged);
connect(ui->doubleSpinBoxSheetMarginBottom, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_SheetMarginChanged);
connect(ui->doubleSpinBoxSheetMarginLeft, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_SheetMarginChanged);
connect(ui->checkBoxLayoutIgnoreFileds, &QCheckBox::stateChanged, this, [this](int state)
{
if (not m_layout.isNull())
{
ui->doubleSpinBoxSheetMarginLeft->setDisabled(state != 0);
ui->doubleSpinBoxSheetMarginRight->setDisabled(state != 0);
ui->doubleSpinBoxSheetMarginTop->setDisabled(state != 0);
ui->doubleSpinBoxSheetMarginBottom->setDisabled(state != 0);
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->SetIgnoreMargins(state != 0);
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
sheet->ValidatePiecesOutOfBound();
}
}
});
ui->groupBoxSheetGrid->setVisible(false); // temporary hide
connect(ui->pushButtonSheetExport, &QPushButton::clicked, this, &VPMainWindow::on_ExportSheet);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitPropertyTabTiles()
{
// -------------------- tiles template
VAbstractLayoutDialog::InitTileTemplates(ui->comboBoxTileTemplates, true);
connect(ui->comboBoxTileTemplates, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this]{TileSize(TileTemplate());});
// -------------------- paper size ---------------------------
MinimumTilePaperSize();
const QString suffix = " " + UnitsToStr(LayoutUnit(), true);
ui->doubleSpinBoxTilePaperWidth->setSuffix(suffix);
ui->doubleSpinBoxTilePaperHeight->setSuffix(suffix);
connect(ui->doubleSpinBoxTilePaperWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_TilesSizeChanged);
connect(ui->doubleSpinBoxTilePaperHeight, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_TilesSizeChanged);
connect(ui->toolButtonTilePortraitOrientation, &QToolButton::toggled, this,
&VPMainWindow::on_TilesOrientationChanged);
connect(ui->toolButtonTileLandscapeOrientation, &QToolButton::toggled, this,
&VPMainWindow::on_TilesOrientationChanged);
// -------------------- margins ------------------------
ui->doubleSpinBoxTileMarginLeft->setSuffix(suffix);
ui->doubleSpinBoxTileMarginRight->setSuffix(suffix);
ui->doubleSpinBoxTileMarginTop->setSuffix(suffix);
ui->doubleSpinBoxTileMarginBottom->setSuffix(suffix);
connect(ui->doubleSpinBoxTileMarginTop, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_TilesMarginChanged);
connect(ui->doubleSpinBoxTileMarginRight, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_TilesMarginChanged);
connect(ui->doubleSpinBoxTileMarginBottom, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_TilesMarginChanged);
connect(ui->doubleSpinBoxTileMarginLeft, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
&VPMainWindow::on_TilesMarginChanged);
connect(ui->checkBoxTileIgnoreFileds, &QCheckBox::stateChanged, this, [this](int state)
{
if (not m_layout.isNull())
{
ui->doubleSpinBoxTileMarginLeft->setDisabled(state != 0);
ui->doubleSpinBoxTileMarginRight->setDisabled(state != 0);
ui->doubleSpinBoxTileMarginTop->setDisabled(state != 0);
ui->doubleSpinBoxTileMarginBottom->setDisabled(state != 0);
m_layout->LayoutSettings().SetIgnoreTilesMargins(state != 0);
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
}
});
// -------------------- control ------------------------
connect(ui->checkBoxTilesShowTiles, &QCheckBox::toggled, this, [this](bool checked)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetShowTiles(checked);
LayoutWasSaved(false);
m_graphicsView->RefreshLayout();
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
}
});
connect(ui->checkBoxTilesShowWatermark, &QCheckBox::toggled, this, [this](bool checked)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetShowWatermark(checked);
LayoutWasSaved(false);
m_graphicsView->RefreshLayout();
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
}
});
connect(ui->checkBoxPrintTilesScheme, &QCheckBox::toggled, this, [this](bool checked)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetPrintTilesScheme(checked);
LayoutWasSaved(false);
}
});
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitPropertyTabLayout()
{
connect(ui->lineEditLayoutName, &QLineEdit::textEdited, this, [this](const QString &text)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetTitle(text);
LayoutWasSaved(false);
}
});
connect(ui->plainTextEditLayoutDescription, &QPlainTextEdit::textChanged, this, [this]()
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetDescription(ui->plainTextEditLayoutDescription->toPlainText());
LayoutWasSaved(false);
}
});
connect(ui->checkBoxLayoutWarningPiecesSuperposition, &QCheckBox::toggled, this, [this](bool checked)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetWarningSuperpositionOfPieces(checked);
LayoutWasSaved(false);
if (checked)
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->ValidateSuperpositionOfPieces();
}
}
m_graphicsView->RefreshPieces();
}
});
connect(ui->checkBoxLayoutWarningPiecesOutOfBound, &QCheckBox::toggled, this, [this](bool checked)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetWarningPiecesOutOfBound(checked);
LayoutWasSaved(false);
if (checked)
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->ValidatePiecesOutOfBound();
}
}
m_graphicsView->RefreshPieces();
}
});
connect(ui->checkBoxSheetStickyEdges, &QCheckBox::toggled, this, [this](bool checked)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetStickyEdges(checked);
LayoutWasSaved(false);
}
});
connect(ui->checkBoxFollowGainline, &QCheckBox::toggled, this, [this](bool checked)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetFollowGrainline(checked);
if (checked)
{
RotatePiecesToGrainline();
}
LayoutWasSaved(false);
}
});
VPSettings *settings = VPApplication::VApp()->PuzzleSettings();
ui->doubleSpinBoxSheetPiecesGap->setMaximum(
UnitConvertor(VPSettings::GetMaxLayoutPieceGap(), Unit::Px, settings->LayoutUnit()));
ui->doubleSpinBoxSheetPiecesGap->setSuffix(" " + UnitsToStr(LayoutUnit(), true));
connect(ui->doubleSpinBoxSheetPiecesGap, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
[this](double d)
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetPiecesGapConverted(d);
LayoutWasSaved(false);
}
});
connect(ui->toolButtonScaleConnected, &QToolButton::clicked, this, [this]()
{
m_scaleConnected = not m_scaleConnected;
UpdateScaleConnection();
});
connect(ui->doubleSpinBoxHorizontalScale, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this, [this](double d)
{
if (m_layout.isNull())
{
return;
}
m_layout->LayoutSettings().SetHorizontalScale(d / 100.);
if (m_scaleConnected)
{
ui->doubleSpinBoxVerticalScale->blockSignals(true);
ui->doubleSpinBoxVerticalScale->setValue(d);
ui->doubleSpinBoxVerticalScale->blockSignals(false);
m_layout->LayoutSettings().SetVerticalScale(d / 100.);
}
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
});
connect(ui->doubleSpinBoxVerticalScale, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
[this](double d)
{
if (m_layout.isNull())
{
return;
}
m_layout->LayoutSettings().SetVerticalScale(d / 100.);
if (m_scaleConnected)
{
ui->doubleSpinBoxHorizontalScale->blockSignals(true);
ui->doubleSpinBoxHorizontalScale->setValue(d);
ui->doubleSpinBoxHorizontalScale->blockSignals(false);
m_layout->LayoutSettings().SetHorizontalScale(d / 100.);
}
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
});
connect(ui->pushButtonLayoutExport, &QPushButton::clicked, this, &VPMainWindow::on_ExportLayout);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitCarrousel()
{
m_carrousel = new VPCarrousel(m_layout, ui->dockWidgetCarrousel);
ui->dockWidgetCarrousel->setWidget(m_carrousel);
connect(ui->dockWidgetCarrousel, QOverload<Qt::DockWidgetArea>::of(&QDockWidget::dockLocationChanged), this,
&VPMainWindow::on_CarrouselLocationChanged);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SetPropertiesData()
{
SetPropertyTabCurrentPieceData();
SetPropertyTabSheetData();
SetPropertyTabTilesData();
SetPropertyTabLayoutData();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SetPropertyTabCurrentPieceData()
{
QList<VPPiecePtr> selectedPieces = SelectedPieces();
if(selectedPieces.isEmpty())
{
// show the content "no piece selected"
ui->labelCurrentPieceNoPieceSelected->setVisible(true);
ui->groupBoxCurrentPieceInfo->setVisible(false);
ui->groupBoxPieceTransformation->setVisible(false);
ui-> groupBoxCurrentPieceSeamline->setVisible(false);
ui->groupBoxCurrentPieceGeometry->setVisible(false);
}
else if(selectedPieces.count() == 1)
{
ui->labelCurrentPieceNoPieceSelected->setVisible(false);
ui->groupBoxCurrentPieceInfo->setVisible(true);
ui->groupBoxPieceTransformation->setVisible(true);
ui-> groupBoxCurrentPieceSeamline->setVisible(true);
ui->groupBoxCurrentPieceGeometry->setVisible(true);
VPPiecePtr selectedPiece = selectedPieces.first();
// set the value to the current piece
SetLineEditValue(ui->lineEditCurrentPieceName, selectedPiece->GetName());
SetPlainTextEditValue(ui->plainTextEditCurrentPieceUUID, selectedPiece->GetUUID().toString());
SetLineEditValue(ui->lineEditCurrentPieceGradationId, selectedPiece->GetGradationId());
SetCheckBoxValue(ui->checkBoxCurrentPieceShowSeamline, not selectedPiece->IsHideMainPath());
SetCheckBoxValue(ui->checkBoxCurrentPieceMirrorPiece, selectedPiece->IsMirror());
if (not ui->checkBoxRelativeTranslation->isChecked())
{
QRectF rect = PiecesBoundingRect(selectedPieces);
ui->doubleSpinBoxCurrentPieceBoxPositionX->setValue(
UnitConvertor(rect.topLeft().x(), Unit::Px, TranslateUnit()));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setValue(
UnitConvertor(rect.topLeft().y(), Unit::Px, TranslateUnit()));
}
}
else
{
// show the content "multiple pieces selected"
ui->labelCurrentPieceNoPieceSelected->setVisible(true);
ui->groupBoxCurrentPieceInfo->setVisible(false);
ui->groupBoxPieceTransformation->setVisible(true);
ui->groupBoxCurrentPieceSeamline->setVisible(false);
ui->groupBoxCurrentPieceGeometry->setVisible(false);
if (not ui->checkBoxRelativeTranslation->isChecked())
{
QRectF rect = PiecesBoundingRect(selectedPieces);
ui->doubleSpinBoxCurrentPieceBoxPositionX->setValue(
UnitConvertor(rect.topLeft().x(), Unit::Px, TranslateUnit()));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setValue(
UnitConvertor(rect.topLeft().y(), Unit::Px, TranslateUnit()));
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SetPropertyTabSheetData()
{
if (not m_layout.isNull())
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
ui->groupBoxSheetInfos->setDisabled(false);
SetLineEditValue(ui->lineEditSheetName, sheet->GetName());
ui->groupBoxPaperFormat->setDisabled(false);
const qint32 indexUnit = ui->comboBoxLayoutUnit->findData(UnitsToStr(m_layout->LayoutSettings().GetUnit()));
if (indexUnit != -1)
{
ui->comboBoxLayoutUnit->blockSignals(true);
ui->comboBoxLayoutUnit->setCurrentIndex(indexUnit);
ui->comboBoxLayoutUnit->blockSignals(false);
}
else
{
ui->comboBoxLayoutUnit->setCurrentIndex(0);
}
const QString suffix = " " + UnitsToStr(LayoutUnit(), true);
ui->doubleSpinBoxSheetPaperWidth->setSuffix(suffix);
ui->doubleSpinBoxSheetPaperHeight->setSuffix(suffix);
ui->doubleSpinBoxSheetMarginLeft->setSuffix(suffix);
ui->doubleSpinBoxSheetMarginRight->setSuffix(suffix);
ui->doubleSpinBoxSheetMarginTop->setSuffix(suffix);
ui->doubleSpinBoxSheetMarginBottom->setSuffix(suffix);
// set Width / Length
QSizeF size = sheet->GetSheetSizeConverted();
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperWidth, size.width());
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperHeight, size.height());
SheetPaperSizeChanged();
FindSheetTemplate();
// set margins
ui->groupBoxSheetMargin->setDisabled(false);
QMarginsF margins = sheet->GetSheetMarginsConverted();
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginLeft, margins.left());
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginTop, margins.top());
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginRight, margins.right());
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginBottom, margins.bottom());
CorrectSheetMaxMargins();
const bool ignoreMargins = sheet->IgnoreMargins();
SetCheckBoxValue(ui->checkBoxLayoutIgnoreFileds, ignoreMargins);
ui->doubleSpinBoxSheetMarginLeft->setDisabled(ignoreMargins);
ui->doubleSpinBoxSheetMarginRight->setDisabled(ignoreMargins);
ui->doubleSpinBoxSheetMarginTop->setDisabled(ignoreMargins);
ui->doubleSpinBoxSheetMarginBottom->setDisabled(ignoreMargins);
GrainlineType type = sheet->GetGrainlineType();
ui->toolButtonGrainlineHorizontalOrientation->setChecked(type == GrainlineType::Horizontal);
ui->toolButtonGrainlineVerticalOrientation->setChecked(type == GrainlineType::Vertical);
// set placement grid
ui->groupBoxSheetGrid->setDisabled(false);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetGridColWidth,
m_layout->LayoutSettings().GetGridColWidthConverted());
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetGridRowHeight,
m_layout->LayoutSettings().GetGridRowHeightConverted());
SetCheckBoxValue(ui->checkBoxSheetShowGrid, m_layout->LayoutSettings().GetShowGrid());
ui->groupBoxSheetExport->setDisabled(false);
return;
}
}
ui->groupBoxSheetInfos->setDisabled(true);
SetLineEditValue(ui->lineEditSheetName, QString());
ui->groupBoxPaperFormat->setDisabled(true);
ui->comboBoxLayoutUnit->blockSignals(true);
ui->comboBoxLayoutUnit->setCurrentIndex(-1);
ui->comboBoxLayoutUnit->blockSignals(false);
ui->comboBoxSheetTemplates->blockSignals(true);
ui->comboBoxSheetTemplates->setCurrentIndex(-1);
ui->comboBoxSheetTemplates->blockSignals(false);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperWidth, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperHeight, 0);
ui->groupBoxSheetMargin->setDisabled(true);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginLeft, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginTop, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginRight, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginBottom, 0);
SetCheckBoxValue(ui->checkBoxLayoutIgnoreFileds, false);
ui->groupBoxSheetGrid->setDisabled(true);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetGridColWidth, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetGridRowHeight, 0);
SetCheckBoxValue(ui->checkBoxSheetShowGrid, false);
ui->groupBoxSheetExport->setDisabled(true);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SetPropertyTabTilesData()
{
if (not m_layout.isNull())
{
ui->groupBoxTilePaperFormat->setDisabled(false);
// set Width / Length
QSizeF size = m_layout->LayoutSettings().GetTilesSizeConverted();
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperWidth, size.width());
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperHeight, size.height());
TilePaperSizeChanged();
FindTileTemplate();
// set margins
ui->groupBoxTileMargins->setDisabled(false);
QMarginsF margins = m_layout->LayoutSettings().GetTilesMarginsConverted();
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginLeft, margins.left());
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginTop, margins.top());
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginRight, margins.right());
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginBottom, margins.bottom());
CorrectTileMaxMargins();
const bool ignoreMargins = m_layout->LayoutSettings().IgnoreTilesMargins();
SetCheckBoxValue(ui->checkBoxTileIgnoreFileds, ignoreMargins);
ui->doubleSpinBoxTileMarginLeft->setDisabled(ignoreMargins);
ui->doubleSpinBoxTileMarginRight->setDisabled(ignoreMargins);
ui->doubleSpinBoxTileMarginTop->setDisabled(ignoreMargins);
ui->doubleSpinBoxTileMarginBottom->setDisabled(ignoreMargins);
const QString suffix = " " + UnitsToStr(LayoutUnit(), true);
ui->doubleSpinBoxTilePaperWidth->setSuffix(suffix);
ui->doubleSpinBoxTilePaperHeight->setSuffix(suffix);
ui->doubleSpinBoxTileMarginLeft->setSuffix(suffix);
ui->doubleSpinBoxTileMarginRight->setSuffix(suffix);
ui->doubleSpinBoxTileMarginTop->setSuffix(suffix);
ui->doubleSpinBoxTileMarginBottom->setSuffix(suffix);
ui->groupBoxTilesControl->setDisabled(false);
SetCheckBoxValue(ui->checkBoxTilesShowTiles, m_layout->LayoutSettings().GetShowTiles());
SetCheckBoxValue(ui->checkBoxTilesShowWatermark, m_layout->LayoutSettings().GetShowWatermark());
SetCheckBoxValue(ui->checkBoxPrintTilesScheme, m_layout->LayoutSettings().GetPrintTilesScheme());
}
else
{
ui->groupBoxTilePaperFormat->setDisabled(true);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperWidth, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperHeight, 0);
ui->groupBoxTileMargins->setDisabled(true);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginLeft, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginTop, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginRight, 0);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginBottom, 0);
SetCheckBoxValue(ui->checkBoxTileIgnoreFileds, false);
ui->groupBoxTilesControl->setDisabled(true);
SetCheckBoxValue(ui->checkBoxTilesShowTiles, false);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SetPropertyTabLayoutData()
{
if (not m_layout.isNull())
{
// set the title and description
ui->groupBoxLayoutInfos->setDisabled(false);
SetLineEditValue(ui->lineEditLayoutName, m_layout->LayoutSettings().GetTitle());
SetPlainTextEditValue(ui->plainTextEditLayoutDescription, m_layout->LayoutSettings().GetDescription());
// set controls
ui->groupBoxLayoutControl->setDisabled(false);
SetCheckBoxValue(ui->checkBoxLayoutWarningPiecesOutOfBound,
m_layout->LayoutSettings().GetWarningPiecesOutOfBound());
SetCheckBoxValue(ui->checkBoxLayoutWarningPiecesSuperposition,
m_layout->LayoutSettings().GetWarningSuperpositionOfPieces());
SetCheckBoxValue(ui->checkBoxSheetStickyEdges,
m_layout->LayoutSettings().GetStickyEdges());
SetCheckBoxValue(ui->checkBoxFollowGainline,
m_layout->LayoutSettings().GetFollowGrainline());
// set pieces gap
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPiecesGap, m_layout->LayoutSettings().GetPiecesGapConverted());
ui->doubleSpinBoxSheetPiecesGap->setSuffix(" " + UnitsToStr(LayoutUnit(), true));
ui->groupBoxLayoutScale->setDisabled(false);
const qreal xScale = m_layout->LayoutSettings().HorizontalScale();
SetDoubleSpinBoxValue(ui->doubleSpinBoxHorizontalScale, xScale * 100.);
const qreal yScale = m_layout->LayoutSettings().VerticalScale();
SetDoubleSpinBoxValue(ui->doubleSpinBoxVerticalScale, yScale * 100.);
m_scaleConnected = qFuzzyCompare(xScale, yScale);
UpdateScaleConnection();
ui->groupBoxLayoutExport->setDisabled(false);
}
else
{
ui->groupBoxLayoutInfos->setDisabled(true);
SetLineEditValue(ui->lineEditLayoutName, QString());
SetPlainTextEditValue(ui->plainTextEditLayoutDescription, QString());
ui->groupBoxLayoutControl->setDisabled(true);
ui->comboBoxLayoutUnit->blockSignals(true);
ui->comboBoxLayoutUnit->setCurrentIndex(-1);
ui->comboBoxLayoutUnit->blockSignals(false);
// set controls
SetCheckBoxValue(ui->checkBoxLayoutWarningPiecesOutOfBound, false);
SetCheckBoxValue(ui->checkBoxLayoutWarningPiecesSuperposition, false);
SetCheckBoxValue(ui->checkBoxSheetStickyEdges, false);
SetCheckBoxValue(ui->checkBoxFollowGainline, false);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPiecesGap, 0);
ui->groupBoxLayoutScale->setDisabled(true);
ui->groupBoxLayoutExport->setDisabled(true);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitMainGraphics()
{
m_graphicsView = new VPMainGraphicsView(m_layout, this);
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
ui->centralWidget->layout()->addWidget(m_graphicsView);
m_graphicsView->RefreshLayout();
connect(m_graphicsView, &VPMainGraphicsView::ScaleChanged, this, &VPMainWindow::on_ScaleChanged);
connect(m_graphicsView, &VPMainGraphicsView::mouseMove, this, &VPMainWindow::on_MouseMoved);
connect(m_layout.data(), &VPLayout::PieceSheetChanged, m_carrousel, &VPCarrousel::Refresh);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitZoomToolBar()
{
if (not m_doubleSpinBoxScale.isNull())
{
delete m_doubleSpinBoxScale;
}
delete m_mouseCoordinate;
// connect the zoom buttons and shortcuts to the slots
QList<QKeySequence> zoomInShortcuts;
zoomInShortcuts.append(QKeySequence(QKeySequence::ZoomIn));
zoomInShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Plus + Qt::KeypadModifier));
ui->actionZoomIn->setShortcuts(zoomInShortcuts);
connect(ui->actionZoomIn, &QAction::triggered, m_graphicsView, &VPMainGraphicsView::ZoomIn);
QList<QKeySequence> zoomOutShortcuts;
zoomOutShortcuts.append(QKeySequence(QKeySequence::ZoomOut));
zoomOutShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Minus + Qt::KeypadModifier));
ui->actionZoomOut->setShortcuts(zoomOutShortcuts);
connect(ui->actionZoomOut, &QAction::triggered, m_graphicsView, &VPMainGraphicsView::ZoomOut);
QList<QKeySequence> zoomOriginalShortcuts;
zoomOriginalShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_0));
zoomOriginalShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_0 + Qt::KeypadModifier));
ui->actionZoomOriginal->setShortcuts(zoomOriginalShortcuts);
connect(ui->actionZoomOriginal, &QAction::triggered, m_graphicsView, &VPMainGraphicsView::ZoomOriginal);
QList<QKeySequence> zoomFitBestShortcuts;
zoomFitBestShortcuts.append(QKeySequence(Qt::ControlModifier + Qt::Key_Equal));
ui->actionZoomFitBest->setShortcuts(zoomFitBestShortcuts);
connect(ui->actionZoomFitBest, &QAction::triggered, m_graphicsView, &VPMainGraphicsView::ZoomFitBest);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::InitScaleToolBar()
{
auto* zoomScale = new QLabel(tr("Scale:"), this);
ui->toolBarScale->addWidget(zoomScale);
m_doubleSpinBoxScale = new QDoubleSpinBox(this);
m_doubleSpinBoxScale->setDecimals(1);
m_doubleSpinBoxScale->setSuffix(QChar('%'));
on_ScaleChanged(m_graphicsView->transform().m11());
connect(m_doubleSpinBoxScale.data(), QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this, [this](double d){m_graphicsView->Zoom(d/100.0);});
ui->toolBarScale->addWidget(m_doubleSpinBoxScale);
// define the mouse position
ui->toolBarScale->addSeparator();
m_mouseCoordinate = new QLabel(QStringLiteral("0, 0 (%1)")
.arg(UnitsToStr(m_layout->LayoutSettings().GetUnit(), true)));
ui->toolBarScale->addWidget(m_mouseCoordinate);
ui->toolBarScale->addSeparator();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::UpdateWindowTitle()
{
QString showName;
if (not curFile.isEmpty())
{
showName = StrippedName(curFile);
}
else
{
int index = VPApplication::VApp()->MainWindows().indexOf(this);
if (index != -1)
{
showName = tr("untitled %1.vlt").arg(index+1);
}
else
{
showName = tr("untitled.vlt");
}
}
showName += QLatin1String("[*]");
if (IsLayoutReadOnly())
{
showName += QStringLiteral(" (") + tr("read only") + QChar(')');
}
setWindowTitle(showName);
setWindowFilePath(curFile);
#if defined(Q_OS_MAC)
static QIcon fileIcon = QIcon(QCoreApplication::applicationDirPath() +
QLatin1String("/../Resources/layout.icns"));
QIcon icon;
if (not curFile.isEmpty())
{
if (not isWindowModified())
{
icon = fileIcon;
}
else
{
static QIcon darkIcon;
if (darkIcon.isNull())
{
darkIcon = QIcon(darkenPixmap(fileIcon.pixmap(16, 16)));
}
icon = darkIcon;
}
}
setWindowIcon(icon);
#endif //defined(Q_OS_MAC)
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ReadSettings()
{
qCDebug(pWindow, "Reading settings.");
const VPSettings *settings = VPApplication::VApp()->PuzzleSettings();
if (settings->status() == QSettings::NoError)
{
restoreGeometry(settings->GetGeometry());
restoreState(settings->GetWindowState());
restoreState(settings->GetToolbarsState(), APP_VERSION);
// Text under tool buton icon
ToolBarStyles();
ui->dockWidgetProperties->setVisible(settings->IsDockWidgetPropertiesActive());
ui->dockWidgetPropertiesContents->setVisible(settings->IsDockWidgetPropertiesContentsActive());
// Scene antialiasing
m_graphicsView->SetAntialiasing(settings->GetGraphicalOutput());
// Stack limit
m_undoStack->setUndoLimit(settings->GetUndoCount());
}
else
{
qWarning() << tr("Cannot read settings from a malformed .INI file.");
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::WriteSettings()
{
VPSettings *settings = VPApplication::VApp()->PuzzleSettings();
settings->SetGeometry(saveGeometry());
settings->SetWindowState(saveState());
settings->SetToolbarsState(saveState(APP_VERSION));
settings->SetDockWidgetPropertiesActive(ui->dockWidgetProperties->isEnabled());
settings->SetDockWidgetPropertiesContentsActive(ui->dockWidgetPropertiesContents->isEnabled());
settings->sync();
if (settings->status() == QSettings::AccessError)
{
qWarning() << tr("Cannot save settings. Access denied.");
}
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::MaybeSave() -> bool
{
// TODO: Implement maybe save check
if (this->isWindowModified())
{
QScopedPointer<QMessageBox> messageBox(new QMessageBox(tr("Unsaved changes"),
tr("Layout has been modified.\n"
"Do you want to save your changes?"),
QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No,
QMessageBox::Cancel, this, Qt::Sheet));
messageBox->setDefaultButton(QMessageBox::Yes);
messageBox->setEscapeButton(QMessageBox::Cancel);
messageBox->setButtonText(QMessageBox::Yes, curFile.isEmpty() || IsLayoutReadOnly() ? tr("Save…") : tr("Save"));
messageBox->setButtonText(QMessageBox::No, tr("Don't Save"));
messageBox->setWindowModality(Qt::ApplicationModal);
const auto ret = static_cast<QMessageBox::StandardButton>(messageBox->exec());
switch (ret)
{
case QMessageBox::Yes:
if (IsLayoutReadOnly())
{
return on_actionSaveAs_triggered();
}
return on_actionSave_triggered();
case QMessageBox::No:
return true;
case QMessageBox::Cancel:
return false;
default:
break;
}
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::CreateWindowMenu(QMenu *menu)
{
SCASSERT(menu != nullptr)
QAction *action = menu->addAction(tr("&New Window"));
connect(action, &QAction::triggered, this, []()
{
VPApplication::VApp()->NewMainWindow()->activateWindow();
});
action->setMenuRole(QAction::NoRole);
menu->addSeparator();
const QList<VPMainWindow*> windows = VPApplication::VApp()->MainWindows();
for (int i = 0; i < windows.count(); ++i)
{
VPMainWindow *window = windows.at(i);
QString title = QStringLiteral("%1. %2").arg(i+1).arg(window->windowTitle());
const int index = title.lastIndexOf(QLatin1String("[*]"));
if (index != -1)
{
window->isWindowModified() ? title.replace(index, 3, QChar('*')) : title.replace(index, 3, QString());
}
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
QAction *action = menu->addAction(title, this, SLOT(ShowWindow()));
#else
QAction *action = menu->addAction(title, this, &VPMainWindow::ShowWindow);
#endif //QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
action->setData(i);
action->setCheckable(true);
action->setMenuRole(QAction::NoRole);
if (window->isActiveWindow())
{
action->setChecked(true);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::IsLayoutReadOnly() const -> bool
{
if (curFile.isEmpty())
{
return false;
}
QFileInfo f(curFile);
if (not f.exists())
{
return false;
}
#ifdef Q_OS_WIN32
qt_ntfs_permission_lookup++; // turn checking on
#endif /*Q_OS_WIN32*/
bool fileWritable = f.isWritable();
#ifdef Q_OS_WIN32
qt_ntfs_permission_lookup--; // turn it off again
#endif /*Q_OS_WIN32*/
return not fileWritable;
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ConnectToPreferences(const QSharedPointer<DialogPuzzlePreferences> &preferences)
{
// Must be first
connect(preferences.data(), &DialogPuzzlePreferences::UpdateProperties, this, &VPMainWindow::WindowsLocale);
connect(preferences.data(), &DialogPuzzlePreferences::UpdateProperties, this, &VPMainWindow::ToolBarStyles);
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::SelectedPieces() const -> QList<VPPiecePtr>
{
QList<VPPiecePtr> selectedPieces;
if (not m_layout.isNull())
{
VPSheetPtr activeSheet = m_layout->GetFocusedSheet();
if (not activeSheet.isNull())
{
selectedPieces = activeSheet->GetSelectedPieces();
}
}
return selectedPieces;
}
//---------------------------------------------------------------------------------------------------------------------
Unit VPMainWindow::TranslateUnit() const
{
return StrToUnits(ui->comboBoxTranslateUnit->currentData().toString());
}
//---------------------------------------------------------------------------------------------------------------------
Unit VPMainWindow::LayoutUnit() const
{
return StrToUnits(ui->comboBoxLayoutUnit->currentData().toString());
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::Template(VAbstractLayoutDialog::PaperSizeTemplate t) const -> QSizeF
{
const Unit layoutUnit = LayoutUnit();
switch (t)
{
case VAbstractLayoutDialog::PaperSizeTemplate::A0:
case VAbstractLayoutDialog::PaperSizeTemplate::A1:
case VAbstractLayoutDialog::PaperSizeTemplate::A2:
case VAbstractLayoutDialog::PaperSizeTemplate::A3:
case VAbstractLayoutDialog::PaperSizeTemplate::A4:
case VAbstractLayoutDialog::PaperSizeTemplate::Letter:
case VAbstractLayoutDialog::PaperSizeTemplate::Legal:
case VAbstractLayoutDialog::PaperSizeTemplate::Tabloid:
return VAbstractLayoutDialog::GetTemplateSize(t, layoutUnit);
case VAbstractLayoutDialog::PaperSizeTemplate::Roll24in:
case VAbstractLayoutDialog::PaperSizeTemplate::Roll30in:
case VAbstractLayoutDialog::PaperSizeTemplate::Roll36in:
case VAbstractLayoutDialog::PaperSizeTemplate::Roll42in:
case VAbstractLayoutDialog::PaperSizeTemplate::Roll44in:
case VAbstractLayoutDialog::PaperSizeTemplate::Roll48in:
case VAbstractLayoutDialog::PaperSizeTemplate::Roll62in:
case VAbstractLayoutDialog::PaperSizeTemplate::Roll72in:
return VAbstractLayoutDialog::GetTemplateSize(t, layoutUnit);
case VAbstractLayoutDialog::PaperSizeTemplate::Custom:
return VAbstractLayoutDialog::GetTemplateSize(t, layoutUnit);
default:
break;
}
return QSizeF();
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::SheetTemplate() const -> QSizeF
{
auto t = static_cast<VAbstractLayoutDialog::PaperSizeTemplate>(ui->comboBoxSheetTemplates->currentData().toInt());
return Template(t);
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::TileTemplate() const -> QSizeF
{
auto t = static_cast<VAbstractLayoutDialog::PaperSizeTemplate>(ui->comboBoxTileTemplates->currentData().toInt());
return Template(t);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SheetSize(const QSizeF &size)
{
m_oldLayoutUnit = LayoutUnit();
ui->doubleSpinBoxSheetPaperWidth->setMaximum(FromPixel(QIMAGE_MAX, m_oldLayoutUnit));
ui->doubleSpinBoxSheetPaperHeight->setMaximum(FromPixel(QIMAGE_MAX, m_oldLayoutUnit));
ui->doubleSpinBoxSheetPaperWidth->setValue(size.width());
ui->doubleSpinBoxSheetPaperHeight->setValue(size.height());
CorrectPaperDecimals();
SheetPaperSizeChanged();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::TileSize(const QSizeF &size)
{
m_oldLayoutUnit = LayoutUnit();
ui->doubleSpinBoxTilePaperWidth->setMaximum(FromPixel(QIMAGE_MAX, m_oldLayoutUnit));
ui->doubleSpinBoxTilePaperHeight->setMaximum(FromPixel(QIMAGE_MAX, m_oldLayoutUnit));
ui->doubleSpinBoxTilePaperWidth->setValue(size.width());
ui->doubleSpinBoxTilePaperHeight->setValue(size.height());
CorrectPaperDecimals();
TilePaperSizeChanged();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::CorrectPaperDecimals()
{
switch (m_oldLayoutUnit)
{
case Unit::Cm:
case Unit::Mm:
case Unit::Px:
ui->doubleSpinBoxSheetPaperWidth->setDecimals(2);
ui->doubleSpinBoxSheetPaperHeight->setDecimals(2);
ui->doubleSpinBoxTilePaperWidth->setDecimals(2);
ui->doubleSpinBoxTilePaperHeight->setDecimals(2);
ui->doubleSpinBoxSheetMarginLeft->setDecimals(4);
ui->doubleSpinBoxSheetMarginRight->setDecimals(4);
ui->doubleSpinBoxSheetMarginTop->setDecimals(4);
ui->doubleSpinBoxSheetMarginBottom->setDecimals(4);
ui->doubleSpinBoxTileMarginLeft->setDecimals(4);
ui->doubleSpinBoxTileMarginRight->setDecimals(4);
ui->doubleSpinBoxTileMarginTop->setDecimals(4);
ui->doubleSpinBoxTileMarginBottom->setDecimals(4);
ui->doubleSpinBoxSheetPiecesGap->setDecimals(2);
break;
case Unit::Inch:
ui->doubleSpinBoxSheetPaperWidth->setDecimals(5);
ui->doubleSpinBoxSheetPaperHeight->setDecimals(5);
ui->doubleSpinBoxTilePaperWidth->setDecimals(5);
ui->doubleSpinBoxTilePaperHeight->setDecimals(5);
ui->doubleSpinBoxSheetMarginLeft->setDecimals(5);
ui->doubleSpinBoxSheetMarginRight->setDecimals(5);
ui->doubleSpinBoxSheetMarginTop->setDecimals(5);
ui->doubleSpinBoxSheetMarginBottom->setDecimals(5);
ui->doubleSpinBoxTileMarginLeft->setDecimals(5);
ui->doubleSpinBoxTileMarginRight->setDecimals(5);
ui->doubleSpinBoxTileMarginTop->setDecimals(5);
ui->doubleSpinBoxTileMarginBottom->setDecimals(5);
ui->doubleSpinBoxSheetPiecesGap->setDecimals(5);
break;
default:
break;
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::SheetPaperSizeChanged()
{
bool portrait = ui->doubleSpinBoxSheetPaperHeight->value() >= ui->doubleSpinBoxSheetPaperWidth->value();
ui->toolButtonSheetPortraitOritation->blockSignals(true);
ui->toolButtonSheetPortraitOritation->setChecked(portrait);
ui->toolButtonSheetPortraitOritation->blockSignals(false);
ui->toolButtonSheetLandscapeOrientation->blockSignals(true);
ui->toolButtonSheetLandscapeOrientation->setChecked(not portrait);
ui->toolButtonSheetLandscapeOrientation->blockSignals(false);
if (not m_layout.isNull())
{
if (m_layout->LayoutSettings().GetFollowGrainline())
{
RotatePiecesToGrainline();
}
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->ValidatePiecesOutOfBound();
}
}
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::TilePaperSizeChanged()
{
bool portrait = ui->doubleSpinBoxTilePaperHeight->value() >= ui->doubleSpinBoxTilePaperWidth->value();
ui->toolButtonTilePortraitOrientation->blockSignals(true);
ui->toolButtonTilePortraitOrientation->setChecked(portrait);
ui->toolButtonTilePortraitOrientation->blockSignals(false);
ui->toolButtonTileLandscapeOrientation->blockSignals(true);
ui->toolButtonTileLandscapeOrientation->setChecked(not portrait);
ui->toolButtonTileLandscapeOrientation->blockSignals(false);
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::MinimumSheetPaperSize()
{
const qreal value = UnitConvertor(1, Unit::Px, m_oldLayoutUnit);
ui->doubleSpinBoxSheetPaperWidth->setMinimum(value);
ui->doubleSpinBoxSheetPaperHeight->setMinimum(value);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::MinimumTilePaperSize()
{
const qreal value = UnitConvertor(1, Unit::Px, m_oldLayoutUnit);
ui->doubleSpinBoxTilePaperWidth->setMinimum(value);
ui->doubleSpinBoxTilePaperHeight->setMinimum(value);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::FindTemplate(QComboBox *box, qreal width, qreal height)
{
SCASSERT(box != nullptr)
const Unit paperUnit = LayoutUnit();
const int max = static_cast<int>(VAbstractLayoutDialog::PaperSizeTemplate::Custom);
for (int i=0; i < max; ++i)
{
const QSizeF tmplSize = VAbstractLayoutDialog::GetTemplateSize(
static_cast<VAbstractLayoutDialog::PaperSizeTemplate>(i), paperUnit);
if (QSizeF(width, height) == tmplSize || QSizeF(height, width) == tmplSize)
{
box->blockSignals(true);
const int index = box->findData(i);
if (index != -1)
{
box->setCurrentIndex(index);
}
box->blockSignals(false);
return;
}
}
box->blockSignals(true);
const int index = box->findData(max);
if (index != -1)
{
box->setCurrentIndex(index);
}
box->blockSignals(false);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::FindSheetTemplate()
{
const qreal width = ui->doubleSpinBoxSheetPaperWidth->value();
const qreal height = ui->doubleSpinBoxSheetPaperHeight->value();
FindTemplate(ui->comboBoxSheetTemplates, width, height);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::FindTileTemplate()
{
const qreal width = ui->doubleSpinBoxTilePaperWidth->value();
const qreal height = ui->doubleSpinBoxTilePaperHeight->value();
FindTemplate(ui->comboBoxTileTemplates, width, height);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::CorrectTileMaxMargins()
{
const qreal tileWidth = ui->doubleSpinBoxTilePaperWidth->value();
const qreal tileHeight = ui->doubleSpinBoxTilePaperHeight->value();
// 80%/2 of paper size for each field
const qreal tileWidthMargin = (tileWidth*80.0/100.0)/2.0;
const qreal tileHeightMargin = (tileHeight*80.0/100.0)/2.0;
ui->doubleSpinBoxTileMarginLeft->setMaximum(tileWidthMargin);
ui->doubleSpinBoxTileMarginRight->setMaximum(tileWidthMargin);
ui->doubleSpinBoxTileMarginTop->setMaximum(tileHeightMargin);
ui->doubleSpinBoxTileMarginBottom->setMaximum(tileHeightMargin);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::CorrectSheetMaxMargins()
{
const qreal sheetWidth = ui->doubleSpinBoxSheetPaperWidth->value();
const qreal sheetHeight = ui->doubleSpinBoxSheetPaperHeight->value();
// 80%/2 of paper size for each field
const qreal sheetWidthMargin = (sheetWidth*80.0/100.0)/2.0;
const qreal sheetHeightMargin = (sheetHeight*80.0/100.0)/2.0;
ui->doubleSpinBoxSheetMarginLeft->setMaximum(sheetWidthMargin);
ui->doubleSpinBoxSheetMarginRight->setMaximum(sheetWidthMargin);
ui->doubleSpinBoxSheetMarginTop->setMaximum(sheetHeightMargin);
ui->doubleSpinBoxSheetMarginBottom->setMaximum(sheetHeightMargin);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::CorrectMaxMargins()
{
CorrectSheetMaxMargins();
CorrectTileMaxMargins();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::RotatePiecesToGrainline()
{
if (not m_layout->LayoutSettings().GetFollowGrainline())
{
return;
}
QList<VPSheetPtr> sheets = m_layout->GetAllSheets();
for(const auto& sheet : sheets)
{
if (not sheet.isNull())
{
QList<VPPiecePtr> pieces = sheet->GetPieces();
for(const auto& piece : pieces)
{
if (not piece.isNull() && piece->IsGrainlineEnabled())
{
VPTransformationOrigon origin;
origin.custom = true;
piece->RotateToGrainline(origin);
emit m_layout->PieceTransformationChanged(piece);
}
}
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ExportData(const VPExportData &data)
{
if (data.format == LayoutExportFormats::DXF_AC1006_AAMA ||
data.format == LayoutExportFormats::DXF_AC1009_AAMA ||
data.format == LayoutExportFormats::DXF_AC1012_AAMA ||
data.format == LayoutExportFormats::DXF_AC1014_AAMA ||
data.format == LayoutExportFormats::DXF_AC1015_AAMA ||
data.format == LayoutExportFormats::DXF_AC1018_AAMA ||
data.format == LayoutExportFormats::DXF_AC1021_AAMA ||
data.format == LayoutExportFormats::DXF_AC1024_AAMA ||
data.format == LayoutExportFormats::DXF_AC1027_AAMA ||
data.format == LayoutExportFormats::DXF_AC1006_ASTM ||
data.format == LayoutExportFormats::DXF_AC1009_ASTM ||
data.format == LayoutExportFormats::DXF_AC1012_ASTM ||
data.format == LayoutExportFormats::DXF_AC1014_ASTM ||
data.format == LayoutExportFormats::DXF_AC1015_ASTM ||
data.format == LayoutExportFormats::DXF_AC1018_ASTM ||
data.format == LayoutExportFormats::DXF_AC1021_ASTM ||
data.format == LayoutExportFormats::DXF_AC1024_ASTM ||
data.format == LayoutExportFormats::DXF_AC1027_ASTM ||
data.format == LayoutExportFormats::RLD)
{
for (int i = 0; i < data.sheets.size(); ++i)
{
QString name;
if (data.sheets.size() > 1)
{
name = data.path + '/' + data.fileName +
QString::number(i+1) + VLayoutExporter::ExportFormatSuffix(data.format);
}
else
{
name = data.path + '/' + data.fileName + VLayoutExporter::ExportFormatSuffix(data.format);
}
VPSheetPtr sheet = data.sheets.at(i);
ExportApparelLayout(data, sheet->GetAsLayoutPieces(), name, sheet->GetSheetSize().toSize());
}
}
else
{
ExportFlatLayout(data);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ExportApparelLayout(const VPExportData &data, const QVector<VLayoutPiece> &details,
const QString &name, const QSize &size) const
{
const QString path = data.path;
bool usedNotExistedDir = CreateLayoutPath(path);
if (not usedNotExistedDir)
{
qCritical() << tr("Can't create a path");
return;
}
VPApplication::VApp()->PuzzleSettings()->SetPathManualLayouts(path);
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wnoexcept")
VLayoutExporter exporter;
QT_WARNING_POP
exporter.SetFileName(name);
exporter.SetImageRect(QRectF(0, 0, size.width(), size.height()));
exporter.SetXScale(data.xScale);
exporter.SetYScale(data.yScale);
exporter.SetBinaryDxfFormat(data.isBinaryDXF);
switch (data.format)
{
case LayoutExportFormats::DXF_AC1006_ASTM:
exporter.SetDxfVersion(DRW::AC1006);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1009_ASTM:
exporter.SetDxfVersion(DRW::AC1009);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1012_ASTM:
exporter.SetDxfVersion(DRW::AC1012);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1014_ASTM:
exporter.SetDxfVersion(DRW::AC1014);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1015_ASTM:
exporter.SetDxfVersion(DRW::AC1015);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1018_ASTM:
exporter.SetDxfVersion(DRW::AC1018);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1021_ASTM:
exporter.SetDxfVersion(DRW::AC1021);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1024_ASTM:
exporter.SetDxfVersion(DRW::AC1024);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1027_ASTM:
exporter.SetDxfVersion(DRW::AC1027);
exporter.ExportToASTMDXF(details);
break;
case LayoutExportFormats::DXF_AC1006_AAMA:
exporter.SetDxfVersion(DRW::AC1006);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1009_AAMA:
exporter.SetDxfVersion(DRW::AC1009);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1012_AAMA:
exporter.SetDxfVersion(DRW::AC1012);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1014_AAMA:
exporter.SetDxfVersion(DRW::AC1014);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1015_AAMA:
exporter.SetDxfVersion(DRW::AC1015);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1018_AAMA:
exporter.SetDxfVersion(DRW::AC1018);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1021_AAMA:
exporter.SetDxfVersion(DRW::AC1021);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1024_AAMA:
exporter.SetDxfVersion(DRW::AC1024);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::DXF_AC1027_AAMA:
exporter.SetDxfVersion(DRW::AC1027);
exporter.ExportToAAMADXF(details);
break;
case LayoutExportFormats::RLD:
exporter.ExportToRLD(details);
break;
default:
qDebug() << "Can't recognize file type." << Q_FUNC_INFO;
break;
}
RemoveLayoutPath(path, usedNotExistedDir);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ExportFlatLayout(const VPExportData &data)
{
const QString path = data.path;
bool usedNotExistedDir = CreateLayoutPath(path);
if (not usedNotExistedDir)
{
qCritical() << tr("Can't create a path");
return;
}
m_layout->RefreshScenePieces();
VPApplication::VApp()->PuzzleSettings()->SetPathManualLayouts(path);
if (data.format == LayoutExportFormats::PDFTiled)
{
ExportPdfTiledFile(data);
}
else if ((data.format == LayoutExportFormats::PDF || data.format == LayoutExportFormats::PS ||
data.format == LayoutExportFormats::EPS) && data.exportUnified)
{
ExportUnifiedPdfFile(data);
}
else
{
ExportScene(data);
}
RemoveLayoutPath(path, usedNotExistedDir);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ExportScene(const VPExportData &data)
{
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wnoexcept")
VLayoutExporter exporter;
QT_WARNING_POP
exporter.SetXScale(data.xScale);
exporter.SetYScale(data.yScale);
exporter.SetDescription(m_layout->LayoutSettings().GetDescription());
exporter.SetBinaryDxfFormat(data.isBinaryDXF);
QList<VPSheetPtr> sheets = data.sheets;
for (int i=0; i < sheets.size(); ++i)
{
const VPSheetPtr& sheet = sheets.at(i);
if (sheet.isNull())
{
continue;
}
sheet->SceneData()->PrepareForExport();
sheet->SceneData()->SetTextAsPaths(data.textAsPaths);
exporter.SetMargins(sheet->GetSheetMargins());
exporter.SetTitle(sheet->GetName());
exporter.SetIgnorePrinterMargins(sheet->IgnoreMargins());
QString name;
if (sheets.size() > 1)
{
name = data.path + '/' + data.fileName + QString::number(i+1) +
VLayoutExporter::ExportFormatSuffix(data.format);
}
else
{
name = data.path + '/' + data.fileName + VLayoutExporter::ExportFormatSuffix(data.format);
}
exporter.SetFileName(name);
exporter.SetImageRect(sheet->GetMarginsRect());
switch (data.format)
{
case LayoutExportFormats::SVG:
exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
exporter.ExportToSVG(sheet->SceneData()->Scene());
break;
case LayoutExportFormats::PDF:
exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
exporter.ExportToPDF(sheet->SceneData()->Scene());
break;
case LayoutExportFormats::PNG:
exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
exporter.ExportToPNG(sheet->SceneData()->Scene());
break;
case LayoutExportFormats::OBJ:
exporter.ExportToOBJ(sheet->SceneData()->Scene());
break;
case LayoutExportFormats::PS:
exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
exporter.ExportToPS(sheet->SceneData()->Scene());
break;
case LayoutExportFormats::EPS:
exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
exporter.ExportToEPS(sheet->SceneData()->Scene());
break;
case LayoutExportFormats::DXF_AC1006_Flat:
exporter.SetDxfVersion(DRW::AC1006);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1009_Flat:
exporter.SetDxfVersion(DRW::AC1009);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1012_Flat:
exporter.SetDxfVersion(DRW::AC1012);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1014_Flat:
exporter.SetDxfVersion(DRW::AC1014);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1015_Flat:
exporter.SetDxfVersion(DRW::AC1015);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1018_Flat:
exporter.SetDxfVersion(DRW::AC1018);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1021_Flat:
exporter.SetDxfVersion(DRW::AC1021);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1024_Flat:
exporter.SetDxfVersion(DRW::AC1024);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::DXF_AC1027_Flat:
exporter.SetDxfVersion(DRW::AC1027);
exporter.ExportToFlatDXF(sheet->SceneData()->Scene(), sheet->SceneData()->GraphicsPiecesAsItems());
break;
case LayoutExportFormats::TIF:
exporter.SetPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
exporter.ExportToTIF(sheet->SceneData()->Scene());
break;
default:
qDebug() << "Can't recognize file type." << Q_FUNC_INFO;
break;
}
sheet->SceneData()->CleanAfterExport();
sheet->SceneData()->SetTextAsPaths(false);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ExportUnifiedPdfFile(const VPExportData &data)
{
const QString name = data.path + '/' + data.fileName + VLayoutExporter::ExportFormatSuffix(data.format);
if (data.format == LayoutExportFormats::PDF)
{
GenerateUnifiedPdfFile(data, name);
}
else if (data.format == LayoutExportFormats::PS)
{
QTemporaryFile tmp;
if (tmp.open())
{
GenerateUnifiedPdfFile(data, tmp.fileName());
VLayoutExporter::PdfToPs(QStringList{tmp.fileName(), name});
}
}
else if (data.format == LayoutExportFormats::EPS)
{
QTemporaryFile tmp;
if (tmp.open())
{
GenerateUnifiedPdfFile(data, tmp.fileName());
VLayoutExporter::PdfToPs(QStringList{QStringLiteral("-eps"), tmp.fileName(), name});
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::GenerateUnifiedPdfFile(const VPExportData &data, const QString &name)
{
QSharedPointer<QPrinter> printer(new QPrinter());
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
printer->setOutputFormat(QPrinter::PdfFormat);
printer->setOutputFileName(name);
printer->setDocName(QFileInfo(name).fileName());
printer->setResolution(static_cast<int>(PrintDPI));
QPainter painter;
bool firstPage = true;
for (const auto& sheet : data.sheets)
{
if (sheet.isNull())
{
continue;
}
SetPrinterSheetPageSettings(printer, sheet, data.xScale, data.yScale);
if (firstPage)
{
if (not painter.begin(printer.data()))
{ // failed to open file
qCritical() << qUtf8Printable(tr("Can't open file '%1'").arg(name));
return;
}
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
painter.setBrush(QBrush(Qt::NoBrush));
painter.scale(data.xScale, data.yScale);
}
else
{
if (not printer->newPage())
{
qCritical() << tr("Failed in flushing page to disk, disk full?");
return;
}
}
sheet->SceneData()->PrepareForExport();
QRectF imageRect = sheet->GetMarginsRect();
sheet->SceneData()->Scene()->render(&painter, VPrintLayout::SceneTargetRect(printer.data(), imageRect),
imageRect, Qt::IgnoreAspectRatio);
sheet->SceneData()->CleanAfterExport();
firstPage = false;
}
painter.end();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ExportPdfTiledFile(const VPExportData &data)
{
QSharedPointer<QPrinter> printer(new QPrinter());
#ifdef Q_OS_MAC
printer->setOutputFormat(QPrinter::NativeFormat);
#else
printer->setOutputFormat(QPrinter::PdfFormat);
#endif
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
printer->setResolution(static_cast<int>(PrintDPI));
if (data.exportUnified)
{
const QString name = data.path + '/' + data.fileName + VLayoutExporter::ExportFormatSuffix(data.format);
printer->setOutputFileName(name);
printer->setDocName(QFileInfo(name).baseName());
QPainter painter;
bool firstPage = true;
for (const auto& sheet : data.sheets)
{
GeneratePdfTiledFile(sheet, data.showTilesScheme, &painter, printer, firstPage);
}
}
else
{
for (int i = 0; i < data.sheets.size(); ++i)
{
const QString name = data.path + '/' + data.fileName + QString::number(i+1) +
VLayoutExporter::ExportFormatSuffix(data.format);
printer->setOutputFileName(name);
printer->setDocName(QFileInfo(name).baseName());
QPainter painter;
bool firstPage = true;
GeneratePdfTiledFile(data.sheets.at(i), data.showTilesScheme, &painter, printer, firstPage);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::GeneratePdfTiledFile(const VPSheetPtr &sheet, bool showTilesScheme, QPainter *painter,
const QSharedPointer<QPrinter> &printer, bool &firstPage)
{
SCASSERT(not sheet.isNull())
SCASSERT(painter != nullptr)
SCASSERT(not printer.isNull())
sheet->SceneData()->PrepareForExport();
m_layout->TileFactory()->refreshTileInfos();
sheet->SceneData()->SetTextAsPaths(false);
if (showTilesScheme)
{
SetPrinterTiledPageSettings(printer, m_layout, sheet, sheet->GetSheetOrientation(), true);
}
else
{
SetPrinterTiledPageSettings(printer, m_layout, sheet, m_layout->LayoutSettings().GetTilesOrientation(), false);
}
if (firstPage)
{
if (not painter->begin(printer.data()))
{ // failed to open file
qCritical() << tr("Failed to open file, is it writable?");
return;
}
painter->setPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthMainLine(), Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin));
painter->setBrush(QBrush(Qt::NoBrush));
painter->setRenderHint(QPainter::Antialiasing, true);
}
if (showTilesScheme)
{
DrawTilesScheme(printer.data(), painter, sheet, firstPage);
}
for(int row=0; row < m_layout->TileFactory()->RowNb(sheet); row++) // for each row of the tiling grid
{
for(int col=0; col < m_layout->TileFactory()->ColNb(sheet); col++) // for each column of tiling grid
{
if(not firstPage)
{
SetPrinterTiledPageSettings(printer, m_layout, sheet,
m_layout->LayoutSettings().GetTilesOrientation(), false);
if (not printer->newPage())
{
qWarning("failed in flushing page to disk, disk full?");
return;
}
}
m_layout->TileFactory()->drawTile(painter, printer.data(), sheet, row, col);
firstPage = false;
}
}
sheet->SceneData()->CleanAfterExport();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::UpdateScaleConnection() const
{
QIcon icon;
icon.addFile(m_scaleConnected ? QStringLiteral(":/icon/32x32/link.png")
: QStringLiteral(":/icon/32x32/broken_link.png"));
ui->toolButtonScaleConnected->setIcon(icon);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::OpenWatermark(const QString &path)
{
QList<QPointer<WatermarkWindow>>::const_iterator i;
for (i = m_watermarkEditors.begin(); i != m_watermarkEditors.end(); ++i)
{
if (not (*i).isNull() && not (*i)->CurrentFile().isEmpty()
&& (*i)->CurrentFile() == AbsoluteMPath(curFile, path))
{
(*i)->show();
return;
}
}
auto *watermark = new WatermarkWindow(curFile, this);
connect(watermark, &WatermarkWindow::New, this, [this](){OpenWatermark();});
connect(watermark, &WatermarkWindow::OpenAnother, this, [this](const QString &path){OpenWatermark(path);});
m_watermarkEditors.append(watermark);
watermark->show();
watermark->Open(path);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::CleanWaterkmarkEditors()
{
QMutableListIterator<QPointer<WatermarkWindow>> i(m_watermarkEditors);
while (i.hasNext())
{
QPointer<WatermarkWindow> watermarkEditor = i.next();
if (watermarkEditor.isNull())
{
i.remove();
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::DrawTilesScheme(QPrinter *printer, QPainter *painter, const VPSheetPtr &sheet, bool &firstPage)
{
SCASSERT(printer != nullptr)
SCASSERT(painter != nullptr)
if (sheet.isNull())
{
return;
}
if(not firstPage)
{
printer->setPageOrientation(sheet->GetSheetOrientation());
if (not printer->newPage())
{
qWarning("failed in flushing page to disk, disk full?");
return;
}
}
sheet->SceneData()->PrepareTilesScheme();
qreal xScale = m_layout->LayoutSettings().HorizontalScale();
qreal yScale = m_layout->LayoutSettings().VerticalScale();
qreal width = m_layout->TileFactory()->DrawingAreaWidth();
qreal height = m_layout->TileFactory()->DrawingAreaHeight();
QPageLayout::Orientation tileOrientation = m_layout->LayoutSettings().GetTilesOrientation();
QPageLayout::Orientation sheetOrientation = sheet->GetSheetOrientation();
QRectF sheetRect = sheet->GetMarginsRect();
const int nbCol = m_layout->TileFactory()->ColNb(sheet);
const int nbRow = m_layout->TileFactory()->RowNb(sheet);
QRectF source = QRectF(sheetRect.topLeft(),
QSizeF(nbCol * ((width - VPTileFactory::tileStripeWidth) / xScale),
nbRow * ((height - VPTileFactory::tileStripeWidth) / yScale)));
QRectF target;
if (tileOrientation != sheetOrientation)
{
QMarginsF margins;
if (not m_layout->LayoutSettings().IgnoreTilesMargins())
{
margins = m_layout->LayoutSettings().GetTilesMargins();
}
QSizeF tilesSize = m_layout->LayoutSettings().GetTilesSize();
target = QRectF(0, 0,
tilesSize.height() - margins.left() - margins.right(),
tilesSize.width() - margins.top() - margins.bottom());
}
else
{
target = QRectF(0, 0, width, height);
}
sheet->SceneData()->Scene()->render(painter, VPrintLayout::SceneTargetRect(printer, target), source,
Qt::KeepAspectRatio);
VWatermarkData watermarkData = m_layout->TileFactory()->WatermarkData();
if (watermarkData.opacity > 0)
{
if (watermarkData.showImage && not watermarkData.path.isEmpty())
{
VPTileFactory::PaintWatermarkImage(painter, target, watermarkData,
m_layout->LayoutSettings().WatermarkPath(),
m_layout->LayoutSettings().HorizontalScale(),
m_layout->LayoutSettings().VerticalScale());
}
if (watermarkData.showText && not watermarkData.text.isEmpty())
{
VPTileFactory::PaintWatermarkText(painter, target, watermarkData,
m_layout->LayoutSettings().HorizontalScale(),
m_layout->LayoutSettings().VerticalScale());
}
}
sheet->SceneData()->ClearTilesScheme();
firstPage = false;
}
//---------------------------------------------------------------------------------------------------------------------
auto VPMainWindow::AskLayoutIsInvalid(const QList<VPSheetPtr> &sheets) -> bool
{
if (m_layout->LayoutSettings().GetWarningPiecesOutOfBound() ||
m_layout->LayoutSettings().GetWarningSuperpositionOfPieces())
{
for (const auto &sheet : sheets)
{
bool outOfBoundChecked = false;
bool pieceSuperpositionChecked = false;
QList<VPPiecePtr> pieces = sheet->GetPieces();
for (const auto& piece :pieces)
{
if (m_layout->LayoutSettings().GetWarningPiecesOutOfBound())
{
if (not outOfBoundChecked && not piece.isNull() && piece->OutOfBound())
{
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("The layout is invalid."));
msgBox.setText(tr("The layout is invalid. Piece out of bound. Do you want to continue export?"));
msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
const int width = 500;
auto* horizontalSpacer = new QSpacerItem(width, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
auto* layout = qobject_cast<QGridLayout*>(msgBox.layout());
SCASSERT(layout != nullptr)
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
if (msgBox.exec() == QMessageBox::No)
{
return false;
}
outOfBoundChecked = true; // no need to ask more
}
}
if (m_layout->LayoutSettings().GetWarningSuperpositionOfPieces())
{
if (not pieceSuperpositionChecked && not piece.isNull() && piece->HasSuperpositionWithPieces())
{
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("The layout is invalid."));
msgBox.setText(tr("The layout is invalid. Pieces superposition. Do you want to continue "
"export?"));
msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
const int width = 500;
auto* horizontalSpacer = new QSpacerItem(width, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
auto* layout = qobject_cast<QGridLayout*>(msgBox.layout());
SCASSERT(layout != nullptr)
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
if (msgBox.exec() == QMessageBox::No)
{
return false;
}
pieceSuperpositionChecked = true; // no need to ask more
}
}
}
}
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::PrintLayoutSheets(QPrinter *printer, const QList<VPSheetPtr> &sheets)
{
SCASSERT(printer != nullptr)
// Handle the fromPage(), toPage(), supportsMultipleCopies(), and numCopies() values from QPrinter.
int firstPageNumber = printer->fromPage() - 1;
if (firstPageNumber >= sheets.count())
{
return;
}
if (firstPageNumber == -1)
{
firstPageNumber = 0;
}
int lastPageNumber = printer->toPage() - 1;
if (lastPageNumber == -1 || lastPageNumber >= sheets.count())
{
lastPageNumber = sheets.count() - 1;
}
const int numPages = lastPageNumber - firstPageNumber + 1;
int copyCount = 1;
if (not printer->supportsMultipleCopies())
{
copyCount = printer->copyCount();
}
QPainter painter;
bool firstPage = true;
qreal xScale = m_layout->LayoutSettings().HorizontalScale();
qreal yScale = m_layout->LayoutSettings().VerticalScale();
for (int i = 0; i < copyCount; ++i)
{
for (int j = 0; j < numPages; ++j)
{
int index = printer->pageOrder() == QPrinter::FirstPageFirst ? firstPageNumber + j : lastPageNumber - j;
const VPSheetPtr& sheet = sheets.at(index);
if (sheet.isNull())
{
continue;
}
if (firstPage)
{
if (not painter.begin(printer))
{ // failed to open file
qCritical() << tr("Failed to open file, is it writable?");
return;
}
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthHairLine(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
painter.setBrush(QBrush(Qt::NoBrush));
painter.scale(xScale, yScale);
}
else
{
printer->setPageOrientation(sheet->GetSheetOrientation());
printer->setFullPage(sheet->IgnoreMargins());
if (not sheet->IgnoreMargins())
{
QMarginsF margins = sheet->GetSheetMargins();
if (not printer->setPageMargins(UnitConvertor(margins, Unit::Px, Unit::Mm),
QPageLayout::Millimeter))
{
qWarning() << QObject::tr("Cannot set printer margins");
}
}
if (not printer->newPage())
{
qCritical() << tr("Failed in flushing page to disk, disk full?");
return;
}
}
sheet->SceneData()->PrepareForExport();
QRectF imageRect = sheet->GetMarginsRect();
sheet->SceneData()->Scene()->render(&painter, VPrintLayout::SceneTargetRect(printer, imageRect),
imageRect, Qt::IgnoreAspectRatio);
sheet->SceneData()->CleanAfterExport();
firstPage = false;
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::PrintLayoutTiledSheets(QPrinter *printer, const QList<VPSheetPtr> &sheets)
{
SCASSERT(printer != nullptr)
struct VPLayoutPrinterPage
{
VPSheetPtr sheet{};
bool tilesScheme{false};
int tileRow{-1};
int tileCol{-1};
};
QVector<VPLayoutPrinterPage> pages;
for (const auto& sheet : sheets)
{
if (m_layout->LayoutSettings().GetPrintTilesScheme())
{
VPLayoutPrinterPage page;
page.sheet = sheet;
page.tilesScheme = true;
pages.append(page);
}
for(int row=0; row < m_layout->TileFactory()->RowNb(sheet); row++) // for each row of the tiling grid
{
for(int col=0; col < m_layout->TileFactory()->ColNb(sheet); col++) // for each column of tiling grid
{
VPLayoutPrinterPage page;
page.sheet = sheet;
page.tilesScheme = false;
page.tileRow = row;
page.tileCol = col;
pages.append(page);
}
}
}
// Handle the fromPage(), toPage(), supportsMultipleCopies(), and numCopies() values from QPrinter.
int firstPageNumber = printer->fromPage() - 1;
if (firstPageNumber >= pages.count())
{
return;
}
if (firstPageNumber == -1)
{
firstPageNumber = 0;
}
int lastPageNumber = printer->toPage() - 1;
if (lastPageNumber == -1 || lastPageNumber >= pages.count())
{
lastPageNumber = pages.count() - 1;
}
const int numPages = lastPageNumber - firstPageNumber + 1;
int copyCount = 1;
if (not printer->supportsMultipleCopies())
{
copyCount = printer->copyCount();
}
QPainter painter;
bool firstPage = true;
m_layout->TileFactory()->refreshTileInfos();
for (int i = 0; i < copyCount; ++i)
{
for (int j = 0; j < numPages; ++j)
{
int index = printer->pageOrder() == QPrinter::FirstPageFirst ? firstPageNumber + j : lastPageNumber - j;
const VPLayoutPrinterPage &page = pages.at(index);
page.sheet->SceneData()->PrepareForExport();
page.sheet->SceneData()->SetTextAsPaths(false);
if (firstPage)
{
if (page.tilesScheme)
{
printer->setPageOrientation(page.sheet->GetSheetOrientation());
}
else
{
printer->setPageOrientation(m_layout->LayoutSettings().GetTilesOrientation());
}
if (not painter.begin(printer))
{ // failed to open file
qCritical() << tr("Failed to open file, is it writable?");
return;
}
painter.setPen(QPen(Qt::black, VAbstractApplication::VApp()->Settings()->WidthMainLine(), Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin));
painter.setBrush(QBrush(Qt::NoBrush));
painter.setRenderHint(QPainter::Antialiasing, true);
}
if (page.tilesScheme)
{
DrawTilesScheme(printer, &painter, page.sheet, firstPage);
}
else
{
if(not firstPage)
{
printer->setPageOrientation(m_layout->LayoutSettings().GetTilesOrientation());
if (not printer->newPage())
{
qWarning("failed in flushing page to disk, disk full?");
return;
}
}
m_layout->TileFactory()->drawTile(&painter, printer, page.sheet, page.tileRow, page.tileCol);
firstPage = false;
}
page.sheet->SceneData()->CleanAfterExport();
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionNew_triggered()
{
VPApplication::VApp()->NewMainWindow();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ShowToolTip(const QString &toolTip)
{
m_statusLabel->setText(toolTip);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::closeEvent(QCloseEvent *event)
{
#if defined(Q_OS_MAC) && QT_VERSION < QT_VERSION_CHECK(5, 11, 1)
// Workaround for Qt bug https://bugreports.qt.io/browse/QTBUG-43344
static int numCalled = 0;
if (numCalled++ >= 1)
{
return;
}
#endif
if (MaybeSave())
{
WriteSettings();
event->accept();
deleteLater();
}
else
{
event->ignore();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::changeEvent(QEvent *event)
{
if (event->type() == QEvent::LanguageChange)
{
// retranslate designer form (single inheritance approach)
ui->retranslateUi(this);
undoAction->setText(tr("&Undo"));
redoAction->setText(tr("&Redo"));
WindowsLocale();
UpdateWindowTitle();
}
// remember to call base class implementation
QMainWindow::changeEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
QStringList VPMainWindow::RecentFileList() const
{
return VPApplication::VApp()->PuzzleSettings()->GetRecentFileList();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionOpen_triggered()
{
qCDebug(pWindow, "Openning puzzle layout file.");
const QString filter(tr("Layout files") + QLatin1String(" (*.vlt)"));
//Use standard path to individual measurements
const QString pathTo = VPApplication::VApp()->PuzzleSettings()->GetPathManualLayouts();
bool usedNotExistedDir = false;
QDir directory(pathTo);
if (not directory.exists())
{
usedNotExistedDir = directory.mkpath(QChar('.'));
}
const QString mPath = QFileDialog::getOpenFileName(this, tr("Open file"), pathTo, filter, nullptr,
VAbstractApplication::VApp()->NativeFileDialog());
if (not mPath.isEmpty())
{
VPApplication::VApp()->NewMainWindow()->LoadFile(mPath);
}
if (usedNotExistedDir)
{
QDir(pathTo).rmpath(QChar('.'));
}
}
//---------------------------------------------------------------------------------------------------------------------
bool VPMainWindow::on_actionSave_triggered()
{
if (curFile.isEmpty() || IsLayoutReadOnly())
{
return on_actionSaveAs_triggered();
}
if (m_curFileFormatVersion < VLayoutConverter::LayoutMaxVer
&& not ContinueFormatRewrite(m_curFileFormatVersionStr, VLayoutConverter::LayoutMaxVerStr))
{
return false;
}
if (not CheckFilePermissions(curFile, this))
{
return false;
}
QString error;
if (not SaveLayout(curFile, error))
{
QMessageBox messageBox;
messageBox.setIcon(QMessageBox::Warning);
messageBox.setText(tr("Could not save the file"));
messageBox.setDefaultButton(QMessageBox::Ok);
messageBox.setDetailedText(error);
messageBox.setStandardButtons(QMessageBox::Ok);
messageBox.exec();
return false;
}
m_curFileFormatVersion = VLayoutConverter::LayoutMaxVer;
m_curFileFormatVersionStr = VLayoutConverter::LayoutMaxVerStr;
return true;
}
//---------------------------------------------------------------------------------------------------------------------
bool VPMainWindow::on_actionSaveAs_triggered()
{
QString filters = tr("Layout files") + QStringLiteral(" (*.vlt)");
QString suffix = QStringLiteral("vlt");
QString fName = tr("layout") + QChar('.') + suffix;
QString dir;
if (curFile.isEmpty())
{
dir = VPApplication::VApp()->PuzzleSettings()->GetPathManualLayouts();
}
else
{
dir = QFileInfo(curFile).absolutePath();
}
bool usedNotExistedDir = false;
QDir directory(dir);
if (not directory.exists())
{
usedNotExistedDir = directory.mkpath(QChar('.'));
}
QString fileName = QFileDialog::getSaveFileName(this, tr("Save as"), dir + QChar('/') + fName, filters, nullptr,
VAbstractApplication::VApp()->NativeFileDialog());
auto RemoveTempDir = qScopeGuard([usedNotExistedDir, dir]()
{
if (usedNotExistedDir)
{
QDir(dir).rmpath(QChar('.'));
}
});
if (fileName.isEmpty())
{
return false;
}
QFileInfo f( fileName );
if (f.suffix().isEmpty() && f.suffix() != suffix)
{
fileName += QChar('.') + suffix;
}
if (not CheckFilePermissions(fileName, this))
{
return false;
}
if (QFileInfo::exists(fileName) && curFile != fileName)
{
// Temporary try to lock the file before saving
VLockGuard<char> tmp(fileName);
if (not tmp.IsLocked())
{
qCCritical(pWindow, "%s",
qUtf8Printable(tr("Failed to lock. This file already opened in another window.")));
return false;
}
}
QString error;
bool result = SaveLayout(fileName, error);
if (not result)
{
QMessageBox messageBox;
messageBox.setIcon(QMessageBox::Warning);
messageBox.setInformativeText(tr("Could not save file"));
messageBox.setDefaultButton(QMessageBox::Ok);
messageBox.setDetailedText(error);
messageBox.setStandardButtons(QMessageBox::Ok);
messageBox.exec();
return false;
}
m_curFileFormatVersion = VLayoutConverter::LayoutMaxVer;
m_curFileFormatVersionStr = VLayoutConverter::LayoutMaxVerStr;
UpdateWindowTitle();
if (curFile == fileName && not lock.isNull())
{
lock->Unlock();
}
VlpCreateLock(lock, fileName);
if (not lock->IsLocked())
{
qCCritical(pWindow, "%s", qUtf8Printable(tr("Failed to lock. This file already opened in another window. "
"Expect collissions when run 2 copies of the program.")));
return false;
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionImportRawLayout_triggered()
{
const QString filter(tr("Raw Layout files") + QLatin1String(" (*.rld)"));
const QString filePath = QFileDialog::getOpenFileName(this, tr("Open file"), QDir::homePath(), filter, nullptr,
VAbstractApplication::VApp()->NativeFileDialog());
if (not filePath.isEmpty())
{
ImportRawLayouts({filePath});
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionAboutQt_triggered()
{
QMessageBox::aboutQt(this, tr("About Qt"));
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionAboutPuzzle_triggered()
{
auto *aboutDialog = new VPDialogAbout(this);
aboutDialog->setAttribute(Qt::WA_DeleteOnClose, true);
aboutDialog->show();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_LayoutUnitChanged(int index)
{
Q_UNUSED(index);
QVariant comboBoxValue = ui->comboBoxLayoutUnit->currentData();
m_layout->LayoutSettings().SetUnit(StrToUnits(comboBoxValue.toString()));
SetPropertyTabCurrentPieceData();
SetPropertyTabSheetData();
SetPropertyTabTilesData();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_SheetSizeChanged()
{
if (not m_layout.isNull())
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->SetSheetSizeConverted(ui->doubleSpinBoxSheetPaperWidth->value(),
ui->doubleSpinBoxSheetPaperHeight->value());
}
FindSheetTemplate();
SheetPaperSizeChanged();
CorrectMaxMargins();
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_SheetOrientationChanged(bool checked)
{
if (checked && not m_layout.isNull())
{
const qreal width = ui->doubleSpinBoxSheetPaperWidth->value();
const qreal height = ui->doubleSpinBoxSheetPaperHeight->value();
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperWidth, height);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperHeight, width);
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->SetSheetSizeConverted(height, width);
}
SheetPaperSizeChanged();
CorrectMaxMargins();
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_SheetMarginChanged()
{
if (not m_layout.isNull())
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (not sheet.isNull())
{
sheet->SetSheetMarginsConverted(ui->doubleSpinBoxSheetMarginLeft->value(),
ui->doubleSpinBoxSheetMarginTop->value(),
ui->doubleSpinBoxSheetMarginRight->value(),
ui->doubleSpinBoxSheetMarginBottom->value());
LayoutWasSaved(false);
sheet->ValidatePiecesOutOfBound();
}
m_graphicsView->RefreshLayout();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_checkBoxSheetShowGrid_toggled(bool checked)
{
m_layout->LayoutSettings().SetShowGrid(checked);
m_graphicsView->RefreshLayout();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_doubleSpinBoxSheetGridColWidth_valueChanged(double value)
{
m_layout->LayoutSettings().SetGridColWidthConverted(value);
m_graphicsView->RefreshLayout();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_doubleSpinBoxSheetGridRowHeight_valueChanged(double value)
{
m_layout->LayoutSettings().SetGridRowHeightConverted(value);
m_graphicsView->RefreshLayout();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_TilesSizeChanged()
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetTilesSizeConverted(
ui->doubleSpinBoxTilePaperWidth->value(),
ui->doubleSpinBoxTilePaperHeight->value());
FindTileTemplate();
TilePaperSizeChanged();
CorrectMaxMargins();
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_TilesOrientationChanged(bool checked)
{
if (checked && not m_layout.isNull())
{
const qreal width = ui->doubleSpinBoxTilePaperWidth->value();
const qreal height = ui->doubleSpinBoxTilePaperHeight->value();
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperWidth, height);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperHeight, width);
m_layout->LayoutSettings().SetTilesSizeConverted(height, width);
TilePaperSizeChanged();
CorrectMaxMargins();
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_TilesMarginChanged()
{
if (not m_layout.isNull())
{
m_layout->LayoutSettings().SetTilesMarginsConverted(
ui->doubleSpinBoxTileMarginLeft->value(),
ui->doubleSpinBoxTileMarginTop->value(),
ui->doubleSpinBoxTileMarginRight->value(),
ui->doubleSpinBoxTileMarginBottom->value());
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
}
VMainGraphicsView::NewSceneRect(m_graphicsView->scene(), m_graphicsView);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_CarrouselLocationChanged(Qt::DockWidgetArea area)
{
if(area == Qt::BottomDockWidgetArea || area == Qt::TopDockWidgetArea)
{
m_carrousel->SetOrientation(Qt::Horizontal);
}
else if (area == Qt::LeftDockWidgetArea || area == Qt::RightDockWidgetArea)
{
m_carrousel->SetOrientation(Qt::Vertical);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_PieceSelectionChanged()
{
// update the property of the piece currently selected
SetPropertyTabCurrentPieceData();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_ScaleChanged(qreal scale)
{
if (not m_doubleSpinBoxScale.isNull())
{
m_doubleSpinBoxScale->blockSignals(true);
m_doubleSpinBoxScale->setMaximum(qFloor(VPMainGraphicsView::MaxScale()*1000)/10.0);
m_doubleSpinBoxScale->setMinimum(qFloor(VPMainGraphicsView::MinScale()*1000)/10.0);
m_doubleSpinBoxScale->setValue(qFloor(scale*1000)/10.0);
m_doubleSpinBoxScale->setSingleStep(1);
m_doubleSpinBoxScale->blockSignals(false);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_MouseMoved(const QPointF &scenePos)
{
if (m_mouseCoordinate != nullptr)
{
m_mouseCoordinate->setText(QStringLiteral("%1, %2 (%3)")
.arg(static_cast<qint32>(FromPixel(scenePos.x(),
m_layout->LayoutSettings().GetUnit())))
.arg(static_cast<qint32>(FromPixel(scenePos.y(),
m_layout->LayoutSettings().GetUnit())))
.arg(UnitsToStr(m_layout->LayoutSettings().GetUnit(), true)));
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ShowWindow() const
{
if (auto *action = qobject_cast<QAction*>(sender()))
{
const QVariant v = action->data();
if (v.canConvert<int>())
{
const int offset = qvariant_cast<int>(v);
const QList<VPMainWindow*> windows = VPApplication::VApp()->MainWindows();
windows.at(offset)->raise();
windows.at(offset)->activateWindow();
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPreferences_triggered()
{
// Calling constructor of the dialog take some time. Because of this user have time to call the dialog twice.
QSharedPointer<DialogPuzzlePreferences> preferences = VPApplication::VApp()->PreferencesDialog();
if (preferences.isNull())
{
auto CleanAfterDialog = qScopeGuard([&preferences]()
{
preferences.clear();
});
QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
preferences.reset(new DialogPuzzlePreferences());
preferences->setWindowModality(Qt::ApplicationModal);
VPApplication::VApp()->SetPreferencesDialog(preferences);
const QList<VPMainWindow*> windows = VPApplication::VApp()->MainWindows();
for (auto *window : windows)
{
window->ConnectToPreferences(preferences);
}
QGuiApplication::restoreOverrideCursor();
preferences->exec();
}
else
{
preferences->show();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::ToolBarStyles()
{
ToolBarStyle(ui->mainToolBar);
ToolBarStyle(ui->toolBarZoom);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionAddSheet_triggered()
{
VPSheetPtr sheet(new VPSheet(m_layout));
sheet->SetName(tr("Sheet %1").arg(m_layout->GetAllSheets().size()+1));
m_layout->UndoStack()->push(new VPUndoAddSheet(sheet));
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_ApplyPieceTransformation()
{
if (m_layout.isNull())
{
return;
}
const int index = ui->tabWidgetPieceTransformation->currentIndex();
if (ui->tabWidgetPieceTransformation->indexOf(ui->tabTranslate) == index)
{ // translate
const qreal dx = UnitConvertor(ui->doubleSpinBoxCurrentPieceBoxPositionX->value(), TranslateUnit(), Unit::Px);
const qreal dy = UnitConvertor(ui->doubleSpinBoxCurrentPieceBoxPositionY->value(), TranslateUnit(), Unit::Px);
QList<VPPiecePtr> selectedPieces = SelectedPieces();
if (selectedPieces.isEmpty())
{
return;
}
if (ui->checkBoxRelativeTranslation->isChecked())
{
if (ui->checkBoxTransformSeparately->isChecked())
{
if (selectedPieces.size() > 1)
{
m_layout->UndoStack()->beginMacro(tr("translate pieces"));
}
QRectF rect = PiecesBoundingRect(selectedPieces);
for (const auto& piece : selectedPieces)
{
if (not piece.isNull())
{
const QRectF pieceRect = piece->MappedDetailBoundingRect();
qreal pieceDx = dx;
qreal pieceDy = dy;
if (not qFuzzyIsNull(rect.width()))
{
pieceDx += dx*((pieceRect.topLeft().x()-rect.topLeft().x())/rect.width())*2.;
}
if (not qFuzzyIsNull(rect.height()))
{
pieceDy += dy*((pieceRect.topLeft().y()-rect.topLeft().y())/rect.height())*2.;
}
auto *command = new VPUndoPieceMove(piece, pieceDx, pieceDy);
m_layout->UndoStack()->push(command);
if (m_layout->LayoutSettings().GetStickyEdges())
{
qreal stickyTranslateX = 0;
qreal stickyTranslateY = 0;
if (piece->StickyPosition(stickyTranslateX, stickyTranslateY))
{
bool allowMerge = selectedPieces.size() == 1;
auto *stickyCommand = new VPUndoPieceMove(piece, stickyTranslateX, stickyTranslateY,
allowMerge);
m_layout->UndoStack()->push(stickyCommand);
}
}
}
}
if (selectedPieces.size() > 1)
{
m_layout->UndoStack()->endMacro();
}
}
else
{
auto *command = new VPUndoPiecesMove(selectedPieces, dx, dy);
m_layout->UndoStack()->push(command);
}
}
else
{
QRectF rect = PiecesBoundingRect(selectedPieces);
qreal pieceDx = dx - rect.topLeft().x();
qreal pieceDy = dy - rect.topLeft().y();
if (selectedPieces.size() == 1)
{
auto *command = new VPUndoPieceMove(selectedPieces.first(), pieceDx, pieceDy);
m_layout->UndoStack()->push(command);
}
else
{
auto *command = new VPUndoPiecesMove(selectedPieces, pieceDx, pieceDy);
m_layout->UndoStack()->push(command);
}
}
}
else if (ui->tabWidgetPieceTransformation->indexOf(ui->tabRotate) == index)
{ // rotate
qreal angle = ui->doubleSpinBoxCurrentPieceAngle->value();
if (ui->toolButtonCurrentPieceRotationClockwise->isChecked())
{
angle *= -1;
}
QList<VPPiecePtr> selectedPieces = SelectedPieces();
if (selectedPieces.isEmpty())
{
return;
}
if (ui->checkBoxTransformSeparately->isChecked())
{
m_layout->UndoStack()->beginMacro(tr("rotate pieces"));
for (const auto& piece : selectedPieces)
{
if (not piece.isNull())
{
const QRectF rect = piece->MappedDetailBoundingRect();
VPTransformationOrigon origin;
origin.origin = rect.center();
origin.custom = true;
auto *command = new VPUndoPieceRotate(piece, origin, angle, angle);
m_layout->UndoStack()->push(command);
}
}
m_layout->UndoStack()->endMacro();
}
else
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
VPTransformationOrigon origin = sheet->TransformationOrigin();
auto *command = new VPUndoPiecesRotate(selectedPieces, origin, angle, angle);
m_layout->UndoStack()->push(command);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_ResetPieceTransformationSettings()
{
const int index = ui->tabWidgetPieceTransformation->currentIndex();
if (ui->tabWidgetPieceTransformation->indexOf(ui->tabTranslate) == index)
{ // translate
if (ui->checkBoxRelativeTranslation->isChecked())
{
ui->doubleSpinBoxCurrentPieceBoxPositionX->setValue(0);
ui->doubleSpinBoxCurrentPieceBoxPositionY->setValue(0);
}
else
{
int unitIndex = ui->comboBoxTranslateUnit->findData(QVariant(UnitsToStr(Unit::Px)));
if (unitIndex != -1)
{
ui->comboBoxTranslateUnit->setCurrentIndex(unitIndex);
}
}
}
else if (ui->tabWidgetPieceTransformation->indexOf(ui->tabRotate) == index)
{ // rotate
ui->doubleSpinBoxCurrentPieceAngle->setValue(0);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_RelativeTranslationChanged(bool checked)
{
if (checked)
{
ui->doubleSpinBoxCurrentPieceBoxPositionX->setValue(0);
ui->doubleSpinBoxCurrentPieceBoxPositionY->setValue(0);
}
else
{
QRectF rect = PiecesBoundingRect(SelectedPieces());
ui->doubleSpinBoxCurrentPieceBoxPositionX->setValue(
UnitConvertor(rect.topLeft().x(), Unit::Px, TranslateUnit()));
ui->doubleSpinBoxCurrentPieceBoxPositionY->setValue(
UnitConvertor(rect.topLeft().y(), Unit::Px, TranslateUnit()));
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_ConvertPaperSize()
{
const Unit layoutUnit = LayoutUnit();
const qreal sheetWidth = ui->doubleSpinBoxSheetPaperWidth->value();
const qreal sheetHeight = ui->doubleSpinBoxSheetPaperHeight->value();
const qreal sheetLeftMargin = ui->doubleSpinBoxSheetMarginLeft->value();
const qreal sheetRightMargin = ui->doubleSpinBoxSheetMarginRight->value();
const qreal sheetTopMargin = ui->doubleSpinBoxSheetMarginTop->value();
const qreal sheetBottomMargin = ui->doubleSpinBoxSheetMarginBottom->value();
ui->doubleSpinBoxSheetPaperWidth->blockSignals(true);
ui->doubleSpinBoxSheetPaperHeight->blockSignals(true);
ui->doubleSpinBoxSheetPaperWidth->setMaximum(FromPixel(QIMAGE_MAX, layoutUnit));
ui->doubleSpinBoxSheetPaperHeight->setMaximum(FromPixel(QIMAGE_MAX, layoutUnit));
ui->doubleSpinBoxSheetPaperWidth->blockSignals(false);
ui->doubleSpinBoxSheetPaperHeight->blockSignals(false);
const qreal newSheetWidth = UnitConvertor(sheetWidth, m_oldLayoutUnit, layoutUnit);
const qreal newSheetHeight = UnitConvertor(sheetHeight, m_oldLayoutUnit, layoutUnit);
const qreal newSheetLeftMargin = UnitConvertor(sheetLeftMargin, m_oldLayoutUnit, layoutUnit);
const qreal newSheetRightMargin = UnitConvertor(sheetRightMargin, m_oldLayoutUnit, layoutUnit);
const qreal newSheetTopMargin = UnitConvertor(sheetTopMargin, m_oldLayoutUnit, layoutUnit);
const qreal newSheetBottomMargin = UnitConvertor(sheetBottomMargin, m_oldLayoutUnit, layoutUnit);
const qreal tileWidth = ui->doubleSpinBoxTilePaperWidth->value();
const qreal tileHeight = ui->doubleSpinBoxTilePaperHeight->value();
const qreal tileLeftMargin = ui->doubleSpinBoxTileMarginLeft->value();
const qreal tileRightMargin = ui->doubleSpinBoxTileMarginRight->value();
const qreal tileTopMargin = ui->doubleSpinBoxTileMarginTop->value();
const qreal tileBottomMargin = ui->doubleSpinBoxTileMarginBottom->value();
ui->doubleSpinBoxTilePaperWidth->blockSignals(true);
ui->doubleSpinBoxTilePaperHeight->blockSignals(true);
ui->doubleSpinBoxTilePaperWidth->setMaximum(FromPixel(QIMAGE_MAX, layoutUnit));
ui->doubleSpinBoxTilePaperHeight->setMaximum(FromPixel(QIMAGE_MAX, layoutUnit));
ui->doubleSpinBoxTilePaperWidth->blockSignals(false);
ui->doubleSpinBoxTilePaperHeight->blockSignals(false);
const qreal newTileWidth = UnitConvertor(tileWidth, m_oldLayoutUnit, layoutUnit);
const qreal newTileHeight = UnitConvertor(tileHeight, m_oldLayoutUnit, layoutUnit);
const qreal newTileLeftMargin = UnitConvertor(tileLeftMargin, m_oldLayoutUnit, layoutUnit);
const qreal newTileRightMargin = UnitConvertor(tileRightMargin, m_oldLayoutUnit, layoutUnit);
const qreal newTileTopMargin = UnitConvertor(tileTopMargin, m_oldLayoutUnit, layoutUnit);
const qreal newTileBottomMargin = UnitConvertor(tileBottomMargin, m_oldLayoutUnit, layoutUnit);
qreal newGap = UnitConvertor(ui->doubleSpinBoxSheetPiecesGap->value(), m_oldLayoutUnit, layoutUnit);
m_oldLayoutUnit = layoutUnit;
m_layout->LayoutSettings().SetUnit(layoutUnit);
CorrectPaperDecimals();
MinimumSheetPaperSize();
MinimumTilePaperSize();
const QString suffix = " " + UnitsToStr(layoutUnit, true);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperWidth, newSheetWidth);
ui->doubleSpinBoxSheetPaperWidth->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetPaperHeight, newSheetHeight);
ui->doubleSpinBoxSheetPaperHeight->setSuffix(suffix);
on_SheetSizeChanged();
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginLeft, newSheetLeftMargin);
ui->doubleSpinBoxSheetMarginLeft->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginRight, newSheetRightMargin);
ui->doubleSpinBoxSheetMarginRight->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginTop, newSheetTopMargin);
ui->doubleSpinBoxSheetMarginTop->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxSheetMarginBottom, newSheetBottomMargin);
ui->doubleSpinBoxSheetMarginBottom->setSuffix(suffix);
on_SheetMarginChanged();
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperWidth, newTileWidth);
ui->doubleSpinBoxTilePaperWidth->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTilePaperHeight, newTileHeight);
ui->doubleSpinBoxTilePaperHeight->setSuffix(suffix);
on_TilesSizeChanged();
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginLeft, newTileLeftMargin);
ui->doubleSpinBoxTileMarginLeft->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginRight, newTileRightMargin);
ui->doubleSpinBoxTileMarginRight->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginTop, newTileTopMargin);
ui->doubleSpinBoxTileMarginTop->setSuffix(suffix);
SetDoubleSpinBoxValue(ui->doubleSpinBoxTileMarginBottom, newTileBottomMargin);
ui->doubleSpinBoxTileMarginBottom->setSuffix(suffix);
on_TilesMarginChanged();
ui->doubleSpinBoxSheetPiecesGap->setMaximum(
UnitConvertor(VPSettings::GetMaxLayoutPieceGap(), Unit::Cm, layoutUnit));
ui->doubleSpinBoxSheetPiecesGap->setValue(newGap);
ui->doubleSpinBoxSheetPiecesGap->setSuffix(suffix);
CorrectMaxMargins();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_ExportLayout()
{
if (m_layout.isNull())
{
return;
}
QList<VPSheetPtr> sheets = m_layout->GetSheets();
if (sheets.isEmpty())
{
return;
}
if (not AskLayoutIsInvalid(sheets))
{
return;
}
DialogSaveManualLayout dialog(sheets.size(), false, m_layout->LayoutSettings().GetTitle(), this);
if (dialog.exec() == QDialog::Rejected)
{
return;
}
VPExportData data;
data.format = dialog.Format();
data.path = dialog.Path();
data.fileName = dialog.FileName();
data.sheets = sheets;
data.xScale = m_layout->LayoutSettings().HorizontalScale();
data.yScale = m_layout->LayoutSettings().VerticalScale();
data.isBinaryDXF = dialog.IsBinaryDXFFormat();
data.textAsPaths = dialog.IsTextAsPaths();
data.exportUnified = dialog.IsExportUnified();
data.showTilesScheme = dialog.IsTilesScheme();
ExportData(data);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_ExportSheet()
{
if (m_layout.isNull())
{
return;
}
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
if (not AskLayoutIsInvalid(QList<VPSheetPtr>{sheet}))
{
return;
}
if (m_layout->LayoutSettings().GetWarningPiecesOutOfBound() ||
m_layout->LayoutSettings().GetWarningSuperpositionOfPieces())
{
bool outOfBoundChecked = false;
bool pieceSuperpositionChecked = false;
QList<VPPiecePtr> pieces = sheet->GetPieces();
for (const auto& piece :pieces)
{
if (m_layout->LayoutSettings().GetWarningPiecesOutOfBound())
{
if (not outOfBoundChecked && not piece.isNull() && piece->OutOfBound())
{
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("The layout is invalid."));
msgBox.setText(tr("The layout is invalid. Piece out of bound. Do you want to continue export?"));
msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
const int width = 500;
auto* horizontalSpacer = new QSpacerItem(width, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
auto* layout = qobject_cast<QGridLayout*>(msgBox.layout());
SCASSERT(layout != nullptr)
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
if (msgBox.exec() == QMessageBox::No)
{
return;
}
outOfBoundChecked = true; // no need to ask more
}
}
if (m_layout->LayoutSettings().GetWarningSuperpositionOfPieces())
{
if (not pieceSuperpositionChecked && not piece.isNull() && piece->HasSuperpositionWithPieces())
{
QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("The layout is invalid."));
msgBox.setText(tr("The layout is invalid. Pieces superposition. Do you want to continue export?"));
msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
const int width = 500;
auto* horizontalSpacer = new QSpacerItem(width, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
auto* layout = qobject_cast<QGridLayout*>(msgBox.layout());
SCASSERT(layout != nullptr)
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
if (msgBox.exec() == QMessageBox::No)
{
return;
}
pieceSuperpositionChecked = true; // no need to ask more
}
}
}
}
DialogSaveManualLayout dialog(1, false, sheet->GetName(), this);
if (dialog.exec() == QDialog::Rejected)
{
return;
}
VPExportData data;
data.format = dialog.Format();
data.path = dialog.Path();
data.fileName = dialog.FileName();
data.sheets = QList<VPSheetPtr>{sheet};
data.xScale = m_layout->LayoutSettings().HorizontalScale();
data.yScale = m_layout->LayoutSettings().VerticalScale();
data.isBinaryDXF = dialog.IsBinaryDXFFormat();
data.textAsPaths = dialog.IsTextAsPaths();
data.exportUnified = dialog.IsExportUnified();
data.showTilesScheme = dialog.IsTilesScheme();
ExportData(data);
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintLayout_triggered()
{
if (not m_layout->IsSheetsUniform())
{
qCritical()<<tr("For printing multipages document all sheet should have the same size.");
return;
}
if (not AskLayoutIsInvalid(m_layout->GetSheets()))
{
return;
}
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter(), QPrinter::HighResolution);
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
QList<VPSheetPtr> sheets = m_layout->GetSheets();
VPSheetPtr firstSheet = sheets.first();
if (firstSheet.isNull())
{
qCritical() << tr("Unable to sheet page settings");
}
qreal xScale = m_layout->LayoutSettings().HorizontalScale();
qreal yScale = m_layout->LayoutSettings().VerticalScale();
SetPrinterSheetPageSettings(printer, firstSheet, xScale, yScale);
printer->setDocName(m_layout->LayoutSettings().GetTitle());
printer->setOutputFileName(QString());//Disable printing to file if was enabled.
printer->setOutputFormat(QPrinter::NativeFormat);
QPrintDialog dialog(printer.data(), this);
// If only user couldn't change page margins we could use method setMinMax();
dialog.setOption(QPrintDialog::PrintCurrentPage, false);
if (dialog.exec() == QDialog::Accepted)
{
printer->setResolution(static_cast<int>(PrintDPI));
on_printLayoutSheets(printer.data());
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintPreviewLayout_triggered()
{
if (not m_layout->IsSheetsUniform())
{
qCritical()<<tr("For printing multipages document all sheet should have the same size.");
return;
}
if (not AskLayoutIsInvalid(m_layout->GetSheets()))
{
return;
}
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter());
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
QList<VPSheetPtr> sheets = m_layout->GetSheets();
VPSheetPtr firstSheet = sheets.first();
if (firstSheet.isNull())
{
qCritical() << tr("Unable to sheet page settings");
return;
}
qreal xScale = m_layout->LayoutSettings().HorizontalScale();
qreal yScale = m_layout->LayoutSettings().VerticalScale();
SetPrinterSheetPageSettings(printer, firstSheet, xScale, yScale);
printer->setDocName(m_layout->LayoutSettings().GetTitle());
printer->setResolution(static_cast<int>(PrintDPI));
// display print preview dialog
QPrintPreviewDialog preview(printer.data());
connect(&preview, &QPrintPreviewDialog::paintRequested, this, &VPMainWindow::on_printLayoutSheets);
preview.exec();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintTiledLayout_triggered()
{
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter(), QPrinter::HighResolution);
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
QList<VPSheetPtr> sheets = m_layout->GetSheets();
VPSheetPtr firstSheet = sheets.first();
if (firstSheet.isNull())
{
qCritical() << tr("Unable to sheet page settings");
return;
}
SetPrinterTiledPageSettings(printer, m_layout, firstSheet, m_layout->LayoutSettings().GetTilesOrientation(), false);
printer->setDocName(m_layout->LayoutSettings().GetTitle());
printer->setOutputFileName(QString());//Disable printing to file if was enabled.
printer->setOutputFormat(QPrinter::NativeFormat);
QPrintDialog dialog(printer.data(), this);
// If only user couldn't change page margins we could use method setMinMax();
dialog.setOption(QPrintDialog::PrintCurrentPage, false);
if (dialog.exec() == QDialog::Accepted)
{
printer->setResolution(static_cast<int>(PrintDPI));
on_printLayoutTiledPages(printer.data());
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintPreviewTiledLayout_triggered()
{
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter(), QPrinter::HighResolution);
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
QList<VPSheetPtr> sheets = m_layout->GetSheets();
VPSheetPtr firstSheet = sheets.first();
if (firstSheet.isNull())
{
qCritical() << tr("Unable to sheet page settings");
return;
}
SetPrinterTiledPageSettings(printer, m_layout, firstSheet, m_layout->LayoutSettings().GetTilesOrientation(), false);
printer->setDocName(m_layout->LayoutSettings().GetTitle());
printer->setResolution(static_cast<int>(PrintDPI));
// display print preview dialog
QPrintPreviewDialog preview(printer.data());
connect(&preview, &QPrintPreviewDialog::paintRequested, this, &VPMainWindow::on_printLayoutTiledPages);
preview.exec();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_printLayoutSheets(QPrinter *printer)
{
PrintLayoutSheets(printer, m_layout->GetSheets());
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_printLayoutTiledPages(QPrinter *printer)
{
PrintLayoutTiledSheets(printer, m_layout->GetSheets());
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintSheet_triggered()
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
if (not AskLayoutIsInvalid(QList<VPSheetPtr>{sheet}))
{
return;
}
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter(), QPrinter::HighResolution);
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
qreal xScale = m_layout->LayoutSettings().HorizontalScale();
qreal yScale = m_layout->LayoutSettings().VerticalScale();
SetPrinterSheetPageSettings(printer, sheet, xScale, yScale);
printer->setDocName(sheet->GetName());
printer->setOutputFileName(QString());//Disable printing to file if was enabled.
printer->setOutputFormat(QPrinter::NativeFormat);
QPrintDialog dialog(printer.data(), this);
// If only user couldn't change page margins we could use method setMinMax();
dialog.setOption(QPrintDialog::PrintCurrentPage, false);
if (dialog.exec() == QDialog::Accepted)
{
printer->setResolution(static_cast<int>(PrintDPI));
on_printLayoutSheet(printer.data());
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintPreviewSheet_triggered()
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
if (not AskLayoutIsInvalid(QList<VPSheetPtr>{sheet}))
{
return;
}
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter());
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
qreal xScale = m_layout->LayoutSettings().HorizontalScale();
qreal yScale = m_layout->LayoutSettings().VerticalScale();
SetPrinterSheetPageSettings(printer, sheet, xScale, yScale);
printer->setDocName(sheet->GetName());
printer->setResolution(static_cast<int>(PrintDPI));
// display print preview dialog
QPrintPreviewDialog preview(printer.data());
connect(&preview, &QPrintPreviewDialog::paintRequested, this, &VPMainWindow::on_printLayoutSheet);
preview.exec();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintTiledSheet_triggered()
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter(), QPrinter::HighResolution);
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
SetPrinterTiledPageSettings(printer, m_layout, sheet, m_layout->LayoutSettings().GetTilesOrientation(), false);
printer->setDocName(sheet->GetName());
printer->setOutputFileName(QString());//Disable printing to file if was enabled.
printer->setOutputFormat(QPrinter::NativeFormat);
QPrintDialog dialog(printer.data(), this);
// If only user couldn't change page margins we could use method setMinMax();
dialog.setOption(QPrintDialog::PrintCurrentPage, false);
if (dialog.exec() == QDialog::Accepted)
{
printer->setResolution(static_cast<int>(PrintDPI));
on_printLayoutSheetTiledPages(printer.data());
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionPrintPreviewTiledSheet_triggered()
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
QSharedPointer<QPrinter> printer = PreparePrinter(QPrinterInfo::defaultPrinter(), QPrinter::HighResolution);
if (printer.isNull())
{
qCritical("%s\n\n%s", qUtf8Printable(tr("Print error")),
qUtf8Printable(tr("Cannot proceed because there are no available printers in your system.")));
return;
}
printer->setCreator(QGuiApplication::applicationDisplayName() + QChar(QChar::Space) +
QCoreApplication::applicationVersion());
SetPrinterTiledPageSettings(printer, m_layout, sheet, m_layout->LayoutSettings().GetTilesOrientation(), false);
printer->setDocName(sheet->GetName());
printer->setResolution(static_cast<int>(PrintDPI));
// display print preview dialog
QPrintPreviewDialog preview(printer.data());
connect(&preview, &QPrintPreviewDialog::paintRequested, this, &VPMainWindow::on_printLayoutSheetTiledPages);
preview.exec();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_printLayoutSheet(QPrinter *printer)
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
PrintLayoutSheets(printer, QList<VPSheetPtr>{sheet});
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_printLayoutSheetTiledPages(QPrinter *printer)
{
VPSheetPtr sheet = m_layout->GetFocusedSheet();
if (sheet.isNull())
{
return;
}
PrintLayoutTiledSheets(printer, QList<VPSheetPtr>{sheet});
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::CreateWatermark()
{
CleanWaterkmarkEditors();
OpenWatermark();
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::EditCurrentWatermark()
{
CleanWaterkmarkEditors();
QString watermarkFile = m_layout->LayoutSettings().WatermarkPath();
if (not watermarkFile.isEmpty())
{
OpenWatermark(watermarkFile);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::LoadWatermark()
{
const QString filter(tr("Watermark files") + QLatin1String(" (*.vwm)"));
QString dir = QDir::homePath();
qDebug("Run QFileDialog::getOpenFileName: dir = %s.", qUtf8Printable(dir));
const QString filePath = QFileDialog::getOpenFileName(this, tr("Open file"), dir, filter, nullptr,
VAbstractApplication::VApp()->NativeFileDialog());
if (filePath.isEmpty())
{
return;
}
m_layout->LayoutSettings().SetWatermarkPath(filePath);
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
ui->actionRemoveWatermark->setEnabled(true);
ui->actionEditCurrentWatermark->setEnabled(true);
if (not m_layout->LayoutSettings().WatermarkPath().isEmpty())
{
m_layoutWatcher->addPath(m_layout->LayoutSettings().WatermarkPath());
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::RemoveWatermark()
{
m_layout->LayoutSettings().SetWatermarkPath(QString());
LayoutWasSaved(false);
m_layout->TileFactory()->refreshTileInfos();
m_graphicsView->RefreshLayout();
ui->actionRemoveWatermark->setEnabled(false);
ui->actionEditCurrentWatermark->setEnabled(false);
if (not m_layout->LayoutSettings().WatermarkPath().isEmpty())
{
m_layoutWatcher->removePath(m_layout->LayoutSettings().WatermarkPath());
}
}
//---------------------------------------------------------------------------------------------------------------------
#if defined(Q_OS_MAC)
void VPMainWindow::AboutToShowDockMenu()
{
if (QMenu *menu = qobject_cast<QMenu *>(sender()))
{
menu->clear();
CreateWindowMenu(menu);
menu->addSeparator();
QAction *actionPreferences = menu->addAction(tr("Preferences"));
actionPreferences->setMenuRole(QAction::NoRole);
connect(actionPreferences, &QAction::triggered, this, &VPMainWindow::on_actionPreferences_triggered);
}
}
#endif //defined(Q_OS_MAC)