diff --git a/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.cpp b/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.cpp
index 42544049d..08a140fb2 100644
--- a/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.cpp
+++ b/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.cpp
@@ -119,6 +119,7 @@ auto PuzzlePreferencesLayoutPage::Apply() -> QStringList
settings->SetLayoutSheetMargins(GetSheetMargins());
settings->SetLayoutTileShowTiles(ui->checkBoxTileShowTiles->isChecked());
+ settings->SetLayoutTileShowWatermark(ui->checkBoxTileShowWatermark->isChecked());
settings->SetLayoutTilePaperHeight(
UnitConvertor(ui->doubleSpinBoxTilePaperHeight->value(), m_oldLayoutUnit, Unit::Px));
@@ -602,6 +603,7 @@ void PuzzlePreferencesLayoutPage::ReadSettings()
TileSize(QSizeF(tileWidth, tileHeight));
ui->checkBoxTileShowTiles->setChecked(settings->GetLayoutTileShowTiles());
+ ui->checkBoxTileShowWatermark->setChecked(settings->GetLayoutTileShowWatermark());
ui->checkBoxTileIgnoreFileds->setChecked(settings->GetLayoutTileIgnoreMargins());
SetTileMargins(settings->GetLayoutSheetMargins());
diff --git a/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.ui b/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.ui
index 02593bac5..cc67e52e8 100644
--- a/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.ui
+++ b/src/app/puzzle/dialogs/configpages/puzzlepreferenceslayoutpage.ui
@@ -374,6 +374,16 @@
+ -
+
+
+ Show watermark preview
+
+
+ Show watermark
+
+
+
-
diff --git a/src/app/puzzle/layout/vplayout.cpp b/src/app/puzzle/layout/vplayout.cpp
index ad540597e..71e1ec335 100644
--- a/src/app/puzzle/layout/vplayout.cpp
+++ b/src/app/puzzle/layout/vplayout.cpp
@@ -31,9 +31,13 @@
#include "vpsheet.h"
#include "../vpapplication.h"
#include "../vptilefactory.h"
+#include "../ifc/xml/vwatermarkconverter.h"
+#include "../vformat/vwatermark.h"
+#include "../ifc/exception/vexception.h"
#include
#include
+#include
Q_LOGGING_CATEGORY(pLayout, "p.layout")
@@ -63,6 +67,7 @@ auto VPLayout::CreateLayout(QUndoStack *undoStack) -> VPLayoutPtr
layout->LayoutSettings().SetUnit(settings->LayoutUnit());
layout->LayoutSettings().SetShowTiles(settings->GetLayoutTileShowTiles());
+ layout->LayoutSettings().SetShowWatermark(settings->GetLayoutTileShowWatermark());
layout->LayoutSettings().SetTilesSize(QSizeF(settings->GetLayoutTilePaperWidth(),
settings->GetLayoutTilePaperHeight()));
layout->LayoutSettings().SetIgnoreTilesMargins(settings->GetLayoutTileIgnoreMargins());
@@ -138,6 +143,33 @@ void VPLayout::RefreshScenePieces() const
}
}
+//---------------------------------------------------------------------------------------------------------------------
+auto VPLayout::WatermarkData() const -> VWatermarkData
+{
+ VWatermarkData data;
+ if (not m_layoutSettings.WatermarkPath().isEmpty())
+ {
+ try
+ {
+ VWatermarkConverter converter(m_layoutSettings.WatermarkPath());
+ VWatermark watermark;
+ watermark.setXMLContent(converter.Convert());
+ data = watermark.GetWatermark();
+ }
+ catch (VException &e)
+ {
+ data.invalidFile = true;
+ data.opacity = 20;
+ data.showImage = true;
+ data.path = "fake.png";
+ data.showText = false;
+ return data;
+ }
+ }
+
+ return data;
+}
+
//---------------------------------------------------------------------------------------------------------------------
auto VPLayout::GetPieces() const -> QList
{
diff --git a/src/app/puzzle/layout/vplayout.h b/src/app/puzzle/layout/vplayout.h
index 114448f64..08f358336 100644
--- a/src/app/puzzle/layout/vplayout.h
+++ b/src/app/puzzle/layout/vplayout.h
@@ -39,6 +39,7 @@ class VPPiece;
class VPSheet;
class QUndoStack;
class VPTileFactory;
+struct VWatermarkData;
class VPLayout : public QObject
{
@@ -93,6 +94,8 @@ public:
void RefreshScenePieces() const;
+ auto WatermarkData() const -> VWatermarkData;
+
signals:
void PieceSheetChanged(const VPPiecePtr &piece);
void ActiveSheetChanged(const VPSheetPtr &focusedSheet);
diff --git a/src/app/puzzle/layout/vplayoutsettings.cpp b/src/app/puzzle/layout/vplayoutsettings.cpp
index aaba53418..fca313794 100644
--- a/src/app/puzzle/layout/vplayoutsettings.cpp
+++ b/src/app/puzzle/layout/vplayoutsettings.cpp
@@ -330,7 +330,7 @@ void VPLayoutSettings::SetIgnoreTilesMargins(bool newIgnoreTilesMargins)
}
//---------------------------------------------------------------------------------------------------------------------
-qreal VPLayoutSettings::HorizontalScale() const
+auto VPLayoutSettings::HorizontalScale() const -> qreal
{
return m_horizontalScale;
}
@@ -342,7 +342,7 @@ void VPLayoutSettings::SetHorizontalScale(qreal newHorizontalScale)
}
//---------------------------------------------------------------------------------------------------------------------
-qreal VPLayoutSettings::VerticalScale() const
+auto VPLayoutSettings::VerticalScale() const -> qreal
{
return m_verticalScale;
}
@@ -352,3 +352,27 @@ void VPLayoutSettings::SetVerticalScale(qreal newVerticalScale)
{
m_verticalScale = newVerticalScale;
}
+
+//---------------------------------------------------------------------------------------------------------------------
+auto VPLayoutSettings::WatermarkPath() const -> const QString &
+{
+ return m_watermarkPath;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPLayoutSettings::SetWatermarkPath(const QString &newWatermarkPath)
+{
+ m_watermarkPath = newWatermarkPath;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+auto VPLayoutSettings::GetShowWatermark() const -> bool
+{
+ return m_showWatermark;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPLayoutSettings::SetShowWatermark(bool newShowWatermark)
+{
+ m_showWatermark = newShowWatermark;
+}
diff --git a/src/app/puzzle/layout/vplayoutsettings.h b/src/app/puzzle/layout/vplayoutsettings.h
index 0d7f58806..d0ba7b33f 100644
--- a/src/app/puzzle/layout/vplayoutsettings.h
+++ b/src/app/puzzle/layout/vplayoutsettings.h
@@ -306,6 +306,12 @@ public:
auto VerticalScale() const -> qreal;
void SetVerticalScale(qreal newVerticalScale);
+ auto WatermarkPath() const -> const QString &;
+ void SetWatermarkPath(const QString &newWatermarkPath);
+
+ auto GetShowWatermark() const -> bool;
+ void SetShowWatermark(bool newShowWatermark);
+
private:
Unit m_unit{Unit::Cm};
@@ -329,6 +335,7 @@ private:
bool m_ignoreTilesMargins{false};
bool m_showTiles{false};
+ bool m_showWatermark{false};
// control
bool m_followGrainLine{false};
@@ -357,6 +364,8 @@ private:
qreal m_horizontalScale{1.0};
qreal m_verticalScale{1.0};
+
+ QString m_watermarkPath{};
};
#endif // VPLAYOUTSETTINGS_H
diff --git a/src/app/puzzle/layout/vpsheet.cpp b/src/app/puzzle/layout/vpsheet.cpp
index e369c6df2..9d25ef565 100644
--- a/src/app/puzzle/layout/vpsheet.cpp
+++ b/src/app/puzzle/layout/vpsheet.cpp
@@ -263,6 +263,9 @@ void VPSheetSceneData::PrepareTilesScheme()
{
m_showTilesSchemeTmp = layout->LayoutSettings().GetShowTiles();
layout->LayoutSettings().SetShowTiles(true);
+
+ m_showTilesWatermarkSchemeTmp = layout->LayoutSettings().GetShowWatermark();
+ layout->LayoutSettings().SetShowWatermark(false);
}
RefreshLayout();
@@ -275,6 +278,7 @@ void VPSheetSceneData::ClearTilesScheme()
if (not layout.isNull())
{
layout->LayoutSettings().SetShowTiles(m_showTilesSchemeTmp);
+ layout->LayoutSettings().SetShowWatermark(m_showTilesWatermarkSchemeTmp);
}
RefreshLayout();
@@ -379,7 +383,7 @@ auto VPSheet::GetAsLayoutPieces() const -> QVector
QVector details;
details.reserve(pieces.size());
- for (auto piece : pieces)
+ for (const auto& piece : pieces)
{
if (not piece.isNull())
{
@@ -421,7 +425,7 @@ void VPSheet::SetVisible(bool visible)
}
//---------------------------------------------------------------------------------------------------------------------
-GrainlineType VPSheet::GrainlineOrientation() const
+auto VPSheet::GrainlineOrientation() const -> GrainlineType
{
if (m_grainlineType == GrainlineType::NotFixed)
{
@@ -694,7 +698,7 @@ void VPSheet::ClearSelection() const
}
//---------------------------------------------------------------------------------------------------------------------
-QPageLayout::Orientation VPSheet::GetSheetOrientation() const
+auto VPSheet::GetSheetOrientation() const -> QPageLayout::Orientation
{
return m_size.height() >= m_size.width() ? QPageLayout::Portrait : QPageLayout::Landscape;
}
diff --git a/src/app/puzzle/layout/vpsheet.h b/src/app/puzzle/layout/vpsheet.h
index fc9c758a8..8a138ff98 100644
--- a/src/app/puzzle/layout/vpsheet.h
+++ b/src/app/puzzle/layout/vpsheet.h
@@ -111,6 +111,7 @@ private:
bool m_showTilesTmp{false};
bool m_showTilesSchemeTmp{false};
+ bool m_showTilesWatermarkSchemeTmp{false};
/**
* variable to hold temporarly hte value of the show grid
diff --git a/src/app/puzzle/puzzle.pro b/src/app/puzzle/puzzle.pro
index a2a9a1dce..10ed4c8be 100644
--- a/src/app/puzzle/puzzle.pro
+++ b/src/app/puzzle/puzzle.pro
@@ -189,15 +189,6 @@ noRunPath{ # For enable run qmake with CONFIG+=noRunPath
#win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vtools/$${DESTDIR}/vtools.lib
#else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vtools/$${DESTDIR}/libvtools.a
-#VWidgets static library
-unix|win32: LIBS += -L$$OUT_PWD/../../libs/vwidgets/$${DESTDIR}/ -lvwidgets
-
-INCLUDEPATH += $$PWD/../../libs/vwidgets
-DEPENDPATH += $$PWD/../../libs/vwidgets
-
-win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vwidgets/$${DESTDIR}/vwidgets.lib
-else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vwidgets/$${DESTDIR}/libvwidgets.a
-
# VLayout static library (depend on VGeometry, VFormat)
unix|win32: LIBS += -L$$OUT_PWD/../../libs/vlayout/$${DESTDIR}/ -lvlayout
@@ -243,6 +234,15 @@ DEPENDPATH += $$PWD/../../libs/ifc
win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/ifc/$${DESTDIR}/ifc.lib
else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/ifc/$${DESTDIR}/libifc.a
+#VWidgets static library
+unix|win32: LIBS += -L$$OUT_PWD/../../libs/vwidgets/$${DESTDIR}/ -lvwidgets
+
+INCLUDEPATH += $$PWD/../../libs/vwidgets
+DEPENDPATH += $$PWD/../../libs/vwidgets
+
+win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vwidgets/$${DESTDIR}/vwidgets.lib
+else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vwidgets/$${DESTDIR}/libvwidgets.a
+
#VMisc static library
unix|win32: LIBS += -L$$OUT_PWD/../../libs/vmisc/$${DESTDIR}/ -lvmisc
diff --git a/src/app/puzzle/scene/vpgraphicstilegrid.cpp b/src/app/puzzle/scene/vpgraphicstilegrid.cpp
index 75f45a500..102951dad 100644
--- a/src/app/puzzle/scene/vpgraphicstilegrid.cpp
+++ b/src/app/puzzle/scene/vpgraphicstilegrid.cpp
@@ -4,10 +4,15 @@
#include "../layout/vplayout.h"
#include "../layout/vpsheet.h"
+#include
+#include
+#include
+#include
+
namespace
{
constexpr qreal penWidth = 1;
-}
+} // namespace
//---------------------------------------------------------------------------------------------------------------------
VPGraphicsTileGrid::VPGraphicsTileGrid(const VPLayoutPtr &layout, const QUuid &sheetUuid, QGraphicsItem *parent):
@@ -82,18 +87,44 @@ void VPGraphicsTileGrid::paint(QPainter *painter, const QStyleOptionGraphicsItem
const int nbCol = layout->TileFactory()->ColNb(sheet);
const int nbRow = layout->TileFactory()->RowNb(sheet);
- for(int i=0;i<=nbCol;++i)
- {
- // vertical lines
- painter->drawLine(QPointF(sheetMargins.left()+i*width, sheetMargins.top()),
- QPointF(sheetMargins.left()+i*width, sheetMargins.top() + nbRow*height));
- }
+ VWatermarkData watermarkData = layout->TileFactory()->WatermarkData();
for(int j=0;j<=nbRow;++j)
{
// horizontal lines
painter->drawLine(QPointF(sheetMargins.left(), sheetMargins.top()+j*height),
QPointF(sheetMargins.left()+nbCol*width, sheetMargins.top()+j*height));
+
+ for(int i=0;i<=nbCol;++i)
+ {
+ // vertical lines
+ painter->drawLine(QPointF(sheetMargins.left()+i*width, sheetMargins.top()),
+ QPointF(sheetMargins.left()+i*width, sheetMargins.top() + nbRow*height));
+
+ if (j < nbRow && i < nbCol)
+ {
+ QRectF img(sheetMargins.left()+i*width, sheetMargins.top()+j*height,
+ width, height);
+
+ if (not layout->LayoutSettings().WatermarkPath().isEmpty() &&
+ layout->LayoutSettings().GetShowWatermark())
+ {
+ if (watermarkData.opacity > 0)
+ {
+ if (watermarkData.showImage && not watermarkData.path.isEmpty())
+ {
+ VPTileFactory::PaintWatermarkImage(painter, img, watermarkData,
+ layout->LayoutSettings().WatermarkPath());
+ }
+
+ if (watermarkData.showText && not watermarkData.text.isEmpty())
+ {
+ VPTileFactory::PaintWatermarkText(painter, img, watermarkData);
+ }
+ }
+ }
+ }
+ }
}
}
}
diff --git a/src/app/puzzle/scene/vpgraphicstilegrid.h b/src/app/puzzle/scene/vpgraphicstilegrid.h
index df3931da0..b53980fb3 100644
--- a/src/app/puzzle/scene/vpgraphicstilegrid.h
+++ b/src/app/puzzle/scene/vpgraphicstilegrid.h
@@ -38,6 +38,7 @@
class VPTileFactory;
class VPLayout;
+struct VWatermarkData;
class VPGraphicsTileGrid : public QGraphicsItem
{
diff --git a/src/app/puzzle/share/resources/puzzleicon.qrc b/src/app/puzzle/share/resources/puzzleicon.qrc
index b99ed6215..712fccda6 100644
--- a/src/app/puzzle/share/resources/puzzleicon.qrc
+++ b/src/app/puzzle/share/resources/puzzleicon.qrc
@@ -20,5 +20,6 @@
puzzleicon/32X32/horizontal_grainline@2x.png
puzzleicon/32X32/vertical_grainline.png
puzzleicon/32X32/vertical_grainline@2x.png
+ puzzleicon/svg/no_watermark_image.svg
diff --git a/src/app/puzzle/share/resources/puzzleicon/svg/no_watermark_image.svg b/src/app/puzzle/share/resources/puzzleicon/svg/no_watermark_image.svg
new file mode 100644
index 000000000..3cafa6dbf
--- /dev/null
+++ b/src/app/puzzle/share/resources/puzzleicon/svg/no_watermark_image.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/app/puzzle/vpmainwindow.cpp b/src/app/puzzle/vpmainwindow.cpp
index f5e0be6b3..b65a9cce0 100644
--- a/src/app/puzzle/vpmainwindow.cpp
+++ b/src/app/puzzle/vpmainwindow.cpp
@@ -43,6 +43,7 @@
#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"
@@ -63,6 +64,8 @@
#endif
#include
+#include
+#include
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes")
@@ -167,7 +170,8 @@ VPMainWindow::VPMainWindow(const VPCommandLinePtr &cmd, QWidget *parent) :
m_undoStack(new QUndoStack(this)),
m_layout{VPLayout::CreateLayout(m_undoStack)},
m_statusLabel(new QLabel(this)),
- m_layoutWatcher(new QFileSystemWatcher(this))
+ m_layoutWatcher(new QFileSystemWatcher(this)),
+ m_watermarkWatcher(new QFileSystemWatcher(this))
{
ui->setupUi(this);
@@ -220,7 +224,49 @@ VPMainWindow::VPMainWindow(const VPCommandLinePtr &cmd, QWidget *parent) :
{
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);
}
});
@@ -331,6 +377,14 @@ auto VPMainWindow::LoadFile(QString path) -> bool
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;
}
@@ -527,6 +581,12 @@ void VPMainWindow::SetupMenu()
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]()
{
@@ -882,6 +942,17 @@ void VPMainWindow::InitPropertyTabTiles()
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);
+ }
+ });
}
//---------------------------------------------------------------------------------------------------------------------
@@ -1287,6 +1358,7 @@ void VPMainWindow::SetPropertyTabTilesData()
ui->groupBoxTilesControl->setDisabled(false);
SetCheckBoxValue(ui->checkBoxTilesShowTiles, m_layout->LayoutSettings().GetShowTiles());
+ SetCheckBoxValue(ui->checkBoxTilesShowWatermark, m_layout->LayoutSettings().GetShowWatermark());
}
else
{
@@ -2586,8 +2658,9 @@ void VPMainWindow::GeneratePdfTiledFile(const VPSheetPtr &sheet, bool showTilesS
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 source = QRectF(sheetRect.topLeft(),
+ QSizeF(nbCol * ((width - VPTileFactory::tileStripeWidth) / xScale),
+ nbRow * ((height - VPTileFactory::tileStripeWidth) / yScale)));
QRectF target;
if (tileOrientation != sheetOrientation)
@@ -2610,6 +2683,25 @@ void VPMainWindow::GeneratePdfTiledFile(const VPSheetPtr &sheet, bool showTilesS
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,
+ layout->LayoutSettings().WatermarkPath(),
+ layout->LayoutSettings().HorizontalScale(),
+ layout->LayoutSettings().VerticalScale());
+ }
+
+ if (watermarkData.showText && not watermarkData.text.isEmpty())
+ {
+ VPTileFactory::PaintWatermarkText(painter, target, watermarkData,
+ layout->LayoutSettings().HorizontalScale(),
+ layout->LayoutSettings().VerticalScale());
+ }
+ }
+
sheet->SceneData()->ClearTilesScheme();
firstPage = false;
@@ -2648,6 +2740,42 @@ void VPMainWindow::UpdateScaleConnection() const
ui->toolButtonScaleConnected->setIcon(icon);
}
+//---------------------------------------------------------------------------------------------------------------------
+void VPMainWindow::OpenWatermark(const QString &path)
+{
+ QList>::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> i(m_watermarkEditors);
+ while (i.hasNext())
+ {
+ QPointer watermarkEditor = i.next();
+ if (watermarkEditor.isNull())
+ {
+ i.remove();
+ }
+ }
+}
+
//---------------------------------------------------------------------------------------------------------------------
void VPMainWindow::on_actionNew_triggered()
{
@@ -3715,6 +3843,67 @@ void VPMainWindow::on_actionPrintPreviewTiledSheet_triggered()
}
+//---------------------------------------------------------------------------------------------------------------------
+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()
diff --git a/src/app/puzzle/vpmainwindow.h b/src/app/puzzle/vpmainwindow.h
index e0b43ad16..8f06c816e 100644
--- a/src/app/puzzle/vpmainwindow.h
+++ b/src/app/puzzle/vpmainwindow.h
@@ -55,6 +55,7 @@ class QFileSystemWatcher;
template class QSharedPointer;
class DialogPuzzlePreferences;
struct VPExportData;
+class WatermarkWindow;
class VPMainWindow : public VAbstractMainWindow
{
@@ -273,6 +274,11 @@ private slots:
void on_actionPrintTiledSheet_triggered();
void on_actionPrintPreviewTiledSheet_triggered();
+ void CreateWatermark();
+ void EditCurrentWatermark();
+ void LoadWatermark();
+ void RemoveWatermark();
+
#if defined(Q_OS_MAC)
void AboutToShowDockMenu();
#endif //defined(Q_OS_MAC)
@@ -318,6 +324,10 @@ private:
bool m_scaleConnected{true};
+ QList> m_watermarkEditors{};
+
+ QFileSystemWatcher *m_watermarkWatcher{nullptr};
+
/**
* @brief InitMenuBar Inits the menu bar (File, Edit, Help ...)
*/
@@ -451,6 +461,9 @@ private:
bool &firstPage);
void UpdateScaleConnection() const;
+
+ void OpenWatermark(const QString &path = QString());
+ void CleanWaterkmarkEditors();
};
#endif // VPMAINWINDOW_H
diff --git a/src/app/puzzle/vpmainwindow.ui b/src/app/puzzle/vpmainwindow.ui
index c52e42942..901464d48 100644
--- a/src/app/puzzle/vpmainwindow.ui
+++ b/src/app/puzzle/vpmainwindow.ui
@@ -95,9 +95,20 @@
+
+
@@ -208,7 +219,7 @@
QTabWidget::Rounded
- 3
+ 2
@@ -1520,6 +1531,16 @@
+ -
+
+
+ Show watermark preview
+
+
+ Show watermark
+
+
+
@@ -2243,6 +2264,59 @@
QAction::ApplicationSpecificRole
+
+
+
+
+
+ Editor
+
+
+ Create or edit a watermark
+
+
+ QAction::ApplicationSpecificRole
+
+
+
+
+ false
+
+
+ Edit current
+
+
+ QAction::ApplicationSpecificRole
+
+
+
+
+ true
+
+
+
+
+
+ Load
+
+
+ QAction::ApplicationSpecificRole
+
+
+
+
+ false
+
+
+
+
+
+ Remove
+
+
+ QAction::ApplicationSpecificRole
+
+
@@ -2270,8 +2344,8 @@
+
-
diff --git a/src/app/puzzle/vpsettings.cpp b/src/app/puzzle/vpsettings.cpp
index af9f5787b..f7da12b33 100644
--- a/src/app/puzzle/vpsettings.cpp
+++ b/src/app/puzzle/vpsettings.cpp
@@ -43,6 +43,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingLayoutTileMargins, (QLatin1Strin
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingLayoutSheetIgnoreMargins, (QLatin1String("layout/sheetIgnoreMargins")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingLayoutTileIgnoreMargins, (QLatin1String("layout/tileIgnoreMargins")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingLayoutTileShowTiles, (QLatin1String("layout/tileShowTiles")))
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingLayoutTileShowWatermark, (QLatin1String("layout/tileShowWatermark")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingLayoutWarningPiecesSuperposition,
(QLatin1String("layout/warningPiecesSuperposition")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingLayoutStickyEdges, (QLatin1String("layout/stickyEdges")))
@@ -226,6 +227,18 @@ auto VPSettings::GetLayoutTileShowTiles() const -> bool
return value(*settingLayoutTileShowTiles, true).toBool();
}
+//---------------------------------------------------------------------------------------------------------------------
+void VPSettings::SetLayoutTileShowWatermark(bool value)
+{
+ setValue(*settingLayoutTileShowWatermark, value);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+auto VPSettings::GetLayoutTileShowWatermark() const -> bool
+{
+ return value(*settingLayoutTileShowWatermark, false).toBool();
+}
+
//---------------------------------------------------------------------------------------------------------------------
void VPSettings::SetLayoutWarningPiecesSuperposition(bool value)
{
diff --git a/src/app/puzzle/vpsettings.h b/src/app/puzzle/vpsettings.h
index 75f589b6d..032f86a7f 100644
--- a/src/app/puzzle/vpsettings.h
+++ b/src/app/puzzle/vpsettings.h
@@ -78,6 +78,9 @@ public:
void SetLayoutTileShowTiles(bool value);
auto GetLayoutTileShowTiles() const -> bool;
+ void SetLayoutTileShowWatermark(bool value);
+ auto GetLayoutTileShowWatermark() const -> bool;
+
void SetLayoutWarningPiecesSuperposition(bool value);
auto GetLayoutWarningPiecesSuperposition() const -> bool;
diff --git a/src/app/puzzle/vptilefactory.cpp b/src/app/puzzle/vptilefactory.cpp
index e17a3784e..7de5e03f3 100644
--- a/src/app/puzzle/vptilefactory.cpp
+++ b/src/app/puzzle/vptilefactory.cpp
@@ -12,8 +12,78 @@
namespace
{
const QColor tileColor(180, 180, 180);
+
+//---------------------------------------------------------------------------------------------------------------------
+auto Grayscale(QImage image) -> QImage
+{
+ for (int ii = 0; ii < image.height(); ii++)
+ {
+ uchar* scan = image.scanLine(ii);
+ int depth = 4;
+ for (int jj = 0; jj < image.width(); jj++)
+ {
+ QRgb* rgbpixel = reinterpret_cast(scan + jj * depth);
+ int gray = qGray(*rgbpixel);
+ *rgbpixel = QColor(gray, gray, gray, qAlpha(*rgbpixel)).rgba();
+ }
+ }
+
+ return image;
}
+//---------------------------------------------------------------------------------------------------------------------
+auto WatermarkImageFromCache(const VWatermarkData &watermarkData, const QString &watermarkPath, qreal xScale,
+ qreal yScale, QString &error) -> QPixmap
+{
+ const qreal opacity = watermarkData.opacity/100.;
+ QPixmap pixmap;
+ QString imagePath = AbsoluteMPath(watermarkPath, watermarkData.path);
+ QString imageCacheKey = QString("puzzle=path%1+opacity%2+rotation%3+grayscale%4+xscale%5+yxcale%6")
+ .arg(imagePath, QString::number(opacity), QString::number(watermarkData.imageRotation),
+ watermarkData.grayscale ? trueStr : falseStr ).arg(xScale).arg(yScale);
+
+ if (not QPixmapCache::find(imageCacheKey, &pixmap))
+ {
+ QImageReader imageReader(imagePath);
+ QImage watermark = imageReader.read();
+ if (watermark.isNull())
+ {
+ error = imageReader.errorString();
+ return pixmap;
+ }
+
+ if (watermarkData.grayscale)
+ {
+ watermark = Grayscale(watermark);
+ }
+
+ // Workaround for QGraphicsPixmapItem opacity problem.
+ // Opacity applied only if use a cached pixmap and only after first draw. First image always has opacity 1.
+ // Preparing an image manually allows to avoid the problem.
+ QSize scaledSize(qRound(watermark.width() * xScale), qRound(watermark.height() * yScale));
+ QImage tmp(scaledSize, watermark.format());
+ tmp = tmp.convertToFormat(QImage::Format_ARGB32);
+ tmp.fill(Qt::transparent);
+
+ QPainter p(&tmp);
+ p.setOpacity(opacity);
+
+ QTransform t;
+ t.translate(tmp.width()/2., tmp.height()/2.);
+ t.rotate(-watermarkData.imageRotation);
+ t.translate(-tmp.width()/2., -tmp.height()/2.);
+ p.setTransform(t);
+
+ p.drawImage(QRectF(QPointF(), scaledSize), watermark);
+
+ pixmap = QPixmap::fromImage(tmp);
+
+ QPixmapCache::insert(imageCacheKey, pixmap);
+ }
+ return pixmap;
+}
+} // namespace
+
//---------------------------------------------------------------------------------------------------------------------
VPTileFactory::VPTileFactory(const VPLayoutPtr &layout, VCommonSettings *commonSettings):
m_layout(layout),
@@ -45,6 +115,8 @@ void VPTileFactory::refreshTileInfos()
{
m_drawingAreaWidth -= tilesMargins.left() + tilesMargins.right();
}
+
+ m_watermarkData = layout->WatermarkData();
}
}
@@ -229,6 +301,7 @@ void VPTileFactory::drawTile(QPainter *painter, QPrinter *printer, const VPSheet
}
DrawRuler(painter);
+ DrawWatermark(painter);
if(col < nbCol-1)
{
@@ -357,6 +430,12 @@ auto VPTileFactory::DrawingAreaWidth() const -> qreal
return m_drawingAreaWidth;
}
+//---------------------------------------------------------------------------------------------------------------------
+auto VPTileFactory::WatermarkData() const -> const VWatermarkData &
+{
+ return m_watermarkData;
+}
+
//---------------------------------------------------------------------------------------------------------------------
void VPTileFactory::DrawRuler(QPainter *painter)
{
@@ -410,3 +489,143 @@ void VPTileFactory::DrawRuler(QPainter *painter)
painter->restore();
}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPTileFactory::DrawWatermark(QPainter *painter)
+{
+ SCASSERT(painter != nullptr)
+
+ VPLayoutPtr layout = m_layout.toStrongRef();
+ if(layout.isNull())
+ {
+ return;
+ }
+
+ if (m_watermarkData.opacity > 0)
+ {
+ QRectF img(0, 0,
+ m_drawingAreaWidth - tileStripeWidth,
+ m_drawingAreaHeight - tileStripeWidth);
+
+ if (m_watermarkData.showImage && not m_watermarkData.path.isEmpty())
+ {
+ PaintWatermarkImage(painter, img, m_watermarkData,
+ layout->LayoutSettings().WatermarkPath(),
+ layout->LayoutSettings().HorizontalScale(),
+ layout->LayoutSettings().VerticalScale());
+ }
+
+ if (m_watermarkData.showText && not m_watermarkData.text.isEmpty())
+ {
+ PaintWatermarkText(painter, img, m_watermarkData,
+ layout->LayoutSettings().HorizontalScale(),
+ layout->LayoutSettings().VerticalScale());
+ }
+ }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPTileFactory::PaintWatermarkText(QPainter *painter, const QRectF &img, const VWatermarkData &watermarkData,
+ qreal xScale, qreal yScale)
+{
+ SCASSERT(painter != nullptr)
+
+ painter->save();
+
+ painter->setOpacity(watermarkData.opacity/100.);
+
+ QPen pen = painter->pen();
+ pen.setWidth(1);
+ pen.setColor(watermarkData.textColor);
+ pen.setStyle(Qt::SolidLine);
+ painter->setPen(pen);
+
+ painter->setBrush(watermarkData.textColor);
+
+ QTransform t;
+ t.translate(img.center().x(), img.center().y());
+ t.rotate(-watermarkData.textRotation);
+ t.translate(-img.center().x(), -img.center().y());
+ t.scale(xScale, yScale);
+
+ QPainterPath text;
+ text.addText(img.center(), watermarkData.font, watermarkData.text);
+
+ text = t.map(text);
+
+ QPointF center = img.center() - text.boundingRect().center();
+ t = QTransform();
+ t.translate(center.x(), center.y());
+
+ text = t.map(text);
+
+ painter->drawPath(text);
+
+ painter->restore();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VPTileFactory::PaintWatermarkImage(QPainter *painter, const QRectF &img, const VWatermarkData &watermarkData,
+ const QString &watermarkPath, qreal xScale, qreal yScale)
+{
+ SCASSERT(painter != nullptr)
+
+ auto BrokenImage = [img, watermarkData, watermarkPath]()
+ {
+ const qreal opacity = watermarkData.opacity/100.;
+ QPixmap watermark;
+ QString imagePath = QString("puzzle=path%1+opacity%2_broken")
+ .arg(AbsoluteMPath(watermarkPath, watermarkData.path), QString::number(opacity));
+
+ if (not QPixmapCache::find(imagePath, &watermark))
+ {
+ QScopedPointer svgRenderer(new QSvgRenderer());
+
+ QRect imageRect(0, 0, qRound(img.width()/4.), qRound(img.width()/4.));
+ watermark = QPixmap(imageRect.size());
+ watermark.fill(Qt::transparent);
+
+ QPainter imagePainter(&watermark);
+ imagePainter.setOpacity(opacity);
+
+ svgRenderer->load(QStringLiteral("://puzzleicon/svg/no_watermark_image.svg"));
+ svgRenderer->render(&imagePainter, imageRect);
+
+ QPixmapCache::insert(imagePath, watermark);
+
+ return watermark;
+ }
+
+ return watermark;
+ };
+
+ QPixmap watermark;
+ QFileInfo f(watermarkData.path);
+ if (f.suffix() == "png" || f.suffix() == "jpg" || f.suffix() == "jpeg" || f.suffix() == "bmp")
+ {
+ QString error;
+ watermark = WatermarkImageFromCache(watermarkData, watermarkPath, xScale, yScale, error);
+
+ if (watermark.isNull())
+ {
+ watermark = BrokenImage();
+ }
+ }
+ else
+ {
+ watermark = BrokenImage();
+ }
+
+ if (watermark.width() < img.width() && watermark.height() < img.height())
+ {
+ QRect imagePosition(0, 0, watermark.width(), watermark.height());
+ imagePosition.translate(img.center().toPoint() - imagePosition.center());
+
+ painter->drawPixmap(imagePosition, watermark);
+ }
+ else
+ {
+ painter->drawPixmap(img.toRect(), watermark);
+ }
+}
diff --git a/src/app/puzzle/vptilefactory.h b/src/app/puzzle/vptilefactory.h
index 263504629..55484e2a6 100644
--- a/src/app/puzzle/vptilefactory.h
+++ b/src/app/puzzle/vptilefactory.h
@@ -33,6 +33,7 @@
#include
#include "layout/vplayout.h"
+#include "../ifc/ifcdef.h"
class QGraphicsScene;
class VCommonSettings;
@@ -90,6 +91,13 @@ public:
*/
static constexpr qreal tileStripeWidth = UnitConvertor(1, Unit::Cm, Unit::Px);
+ auto WatermarkData() const -> const VWatermarkData &;
+
+ static void PaintWatermarkText(QPainter *painter, const QRectF &img, const VWatermarkData &watermarkData,
+ qreal xScale = 1.0, qreal yScale = 1.0);
+ static void PaintWatermarkImage(QPainter *painter, const QRectF &img, const VWatermarkData &watermarkData,
+ const QString &watermarkPath, qreal xScale = 1.0, qreal yScale = 1.0);
+
private:
Q_DISABLE_COPY(VPTileFactory)
@@ -106,8 +114,10 @@ private:
*/
qreal m_drawingAreaWidth{0};
- void DrawRuler(QPainter *painter);
+ VWatermarkData m_watermarkData{};
+ void DrawRuler(QPainter *painter);
+ void DrawWatermark(QPainter *painter);
};
#endif // VPTILEFACTORY_H
diff --git a/src/app/puzzle/xml/vplayoutfilereader.cpp b/src/app/puzzle/xml/vplayoutfilereader.cpp
index 3e39667ab..a7e277cba 100644
--- a/src/app/puzzle/xml/vplayoutfilereader.cpp
+++ b/src/app/puzzle/xml/vplayoutfilereader.cpp
@@ -243,7 +243,8 @@ void VPLayoutFileReader::ReadProperties(const VPLayoutPtr &layout)
ML::TagDescription, // 2
ML::TagControl, // 3
ML::TagTiles, // 4
- ML::TagScale // 5
+ ML::TagScale, // 5
+ ML::TagWatermark // 6
};
while (readNextStartElement())
@@ -276,6 +277,10 @@ void VPLayoutFileReader::ReadProperties(const VPLayoutPtr &layout)
qDebug("read scale");
ReadScale(layout);
break;
+ case 6: // watermark
+ qDebug("read watermark");
+ ReadWatermark(layout);
+ break;
default:
qCDebug(MLReader, "Ignoring tag %s", qUtf8Printable(name().toString()));
skipCurrentElement();
@@ -818,6 +823,16 @@ auto VPLayoutFileReader::ReadLabelLine() -> TextLine
return line;
}
+//---------------------------------------------------------------------------------------------------------------------
+void VPLayoutFileReader::ReadWatermark(const VPLayoutPtr &layout)
+{
+ AssertRootTag(ML::TagWatermark);
+
+ QXmlStreamAttributes attribs = attributes();
+ layout->LayoutSettings().SetShowWatermark(ReadAttributeBool(attribs, ML::AttrShowPreview, falseStr));
+ layout->LayoutSettings().SetWatermarkPath(readElementText());
+}
+
//---------------------------------------------------------------------------------------------------------------------
void VPLayoutFileReader::ReadLayoutMargins(const VPLayoutPtr &layout)
{
diff --git a/src/app/puzzle/xml/vplayoutfilereader.h b/src/app/puzzle/xml/vplayoutfilereader.h
index f87a9f855..e2a25b5c6 100644
--- a/src/app/puzzle/xml/vplayoutfilereader.h
+++ b/src/app/puzzle/xml/vplayoutfilereader.h
@@ -75,6 +75,7 @@ private:
void ReadPatternLabel(const VPPiecePtr &piece);
auto ReadLabelLines() -> VTextManager;
auto ReadLabelLine() -> TextLine;
+ void ReadWatermark(const VPLayoutPtr &layout);
void ReadLayoutMargins(const VPLayoutPtr &layout);
void ReadSheetMargins(const VPSheetPtr &sheet);
diff --git a/src/app/puzzle/xml/vplayoutfilewriter.cpp b/src/app/puzzle/xml/vplayoutfilewriter.cpp
index 7a174d8f9..b5adcbd37 100644
--- a/src/app/puzzle/xml/vplayoutfilewriter.cpp
+++ b/src/app/puzzle/xml/vplayoutfilewriter.cpp
@@ -184,6 +184,12 @@ void VPLayoutFileWriter::WriteLayoutProperties(const VPLayoutPtr &layout)
SetAttribute(ML::AttrYScale, layout->LayoutSettings().VerticalScale());
writeEndElement(); // scale
+ writeStartElement(ML::TagWatermark);
+ SetAttributeOrRemoveIf(ML::AttrShowPreview, layout->LayoutSettings().GetShowWatermark(),
+ [](bool show){return not show;});
+ writeCharacters(layout->LayoutSettings().WatermarkPath());
+ writeEndElement(); // watermark
+
writeEndElement(); // properties
}
diff --git a/src/app/puzzle/xml/vplayoutliterals.cpp b/src/app/puzzle/xml/vplayoutliterals.cpp
index e1266931d..addd45cb5 100644
--- a/src/app/puzzle/xml/vplayoutliterals.cpp
+++ b/src/app/puzzle/xml/vplayoutliterals.cpp
@@ -59,6 +59,7 @@ const QString TagPatternLabel = QStringLiteral("patternLabel");
const QString TagLines = QStringLiteral("lines");
const QString TagLine = QStringLiteral("line");
const QString TagScale = QStringLiteral("scale");
+const QString TagWatermark = QStringLiteral("watermark");
const QString AttrVersion = QStringLiteral("version");
const QString AttrWarningSuperposition = QStringLiteral("warningSuperposition");
@@ -102,6 +103,7 @@ const QString AttrGrainlineType = QStringLiteral("grainlineType");
const QString AttrXScale = QStringLiteral("xScale");
const QString AttrYScale = QStringLiteral("yScale");
const QString AttrIgnoreMargins = QStringLiteral("ignoreMargins");
+const QString AttrShowPreview = QStringLiteral("showPreview");
const QString atFrontStr = QStringLiteral("atFront");
const QString atRearStr = QStringLiteral("atRear");
diff --git a/src/app/puzzle/xml/vplayoutliterals.h b/src/app/puzzle/xml/vplayoutliterals.h
index be1cea44f..7a05f7020 100644
--- a/src/app/puzzle/xml/vplayoutliterals.h
+++ b/src/app/puzzle/xml/vplayoutliterals.h
@@ -64,6 +64,7 @@ extern const QString TagPatternLabel;
extern const QString TagLines;
extern const QString TagLine;
extern const QString TagScale;
+extern const QString TagWatermark;
extern const QString AttrVersion;
extern const QString AttrWarningSuperposition;
@@ -107,6 +108,7 @@ extern const QString AttrGrainlineType;
extern const QString AttrXScale;
extern const QString AttrYScale;
extern const QString AttrIgnoreMargins;
+extern const QString AttrShowPreview;
extern const QString atFrontStr;
extern const QString atRearStr;
diff --git a/src/app/valentina/mainwindow.cpp b/src/app/valentina/mainwindow.cpp
index 05f0e8971..65f611438 100644
--- a/src/app/valentina/mainwindow.cpp
+++ b/src/app/valentina/mainwindow.cpp
@@ -65,7 +65,7 @@
#include "../qmuparser/qmuparsererror.h"
#include "../vtools/dialogs/support/dialogeditlabel.h"
#include "../vformat/vpatternrecipe.h"
-#include "watermarkwindow.h"
+#include "../vlayout/dialogs/watermarkwindow.h"
#include "../vmisc/backport/qoverload.h"
#include "../vlayout/vlayoutexporter.h"
#include "../vwidgets/vgraphicssimpletextitem.h"
diff --git a/src/app/valentina/mainwindow.ui b/src/app/valentina/mainwindow.ui
index 4e7b7b612..21deed217 100644
--- a/src/app/valentina/mainwindow.ui
+++ b/src/app/valentina/mainwindow.ui
@@ -1119,7 +1119,7 @@
0
- -53
+ 0
126
237
@@ -1713,7 +1713,7 @@
0
0
1100
- 21
+ 22
@@ -245,8 +262,11 @@
°
+
+ -360
+
- 100
+ 360
@@ -365,8 +385,15 @@
+
+
+ QtColorPicker
+ QPushButton
+
+
+
-
+
diff --git a/src/libs/vlayout/vposter.cpp b/src/libs/vlayout/vposter.cpp
index dab321692..3decf6ec4 100644
--- a/src/libs/vlayout/vposter.cpp
+++ b/src/libs/vlayout/vposter.cpp
@@ -95,7 +95,6 @@ QPixmap WatermarkImageFromCache(const VWatermarkData &watermarkData, const QStri
if (watermarkData.grayscale)
{
watermark = Grayscale(watermark);
- watermark.save("/home/dismine/grayscale.png", "PNG");
}
// Workaround for QGraphicsPixmapItem opacity problem.
@@ -272,6 +271,11 @@ QVector VPoster::TextWatermark(QGraphicsItem *parent, const Pos
QGraphicsSimpleTextItem *text = new QGraphicsSimpleTextItem(watermarkData.text, parent);
text->setFont(watermarkData.font);
+
+ QPen pen = text->pen();
+ pen.setColor(watermarkData.textColor);
+ text->setPen(pen);
+
text->setOpacity(watermarkData.opacity/100.);
text->setTransformOriginPoint(text->boundingRect().center());
text->setRotation(-watermarkData.textRotation);
diff --git a/src/libs/vmisc/vcommonsettings.cpp b/src/libs/vmisc/vcommonsettings.cpp
index 3d2e54a0f..2609b26d3 100644
--- a/src/libs/vmisc/vcommonsettings.cpp
+++ b/src/libs/vmisc/vcommonsettings.cpp
@@ -42,6 +42,7 @@
#include
#include
#include
+#include
#include "../vmisc/def.h"
#include "../vmisc/vmath.h"
@@ -141,6 +142,9 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingScrollingAcceleration, (QLatin1S
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingTiledPDFMargins, (QLatin1String("tiledPDF/margins")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingTiledPDFOrientation, (QLatin1String("tiledPDF/orientation")))
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingWatermarkEditorSize, (QLatin1String("watermarkEditorSize")))
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingWatermarkCustomColors, (QLatin1String("watermarkCustomColors")))
+
// Reading settings file is very expensive, cache curve approximation to speed up getting value
qreal curveApproximationCached = -1;
Q_GLOBAL_STATIC(QString, localeCached)
@@ -1431,3 +1435,63 @@ void VCommonSettings::SetTiledPDFOrientation(PageOrientation value)
{
setValue(*settingTiledPDFOrientation, static_cast (value));
}
+
+//---------------------------------------------------------------------------------------------------------------------
+QSize VCommonSettings::GetWatermarkEditorSize() const
+{
+ return value(*settingWatermarkEditorSize, QSize(0, 0)).toSize();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VCommonSettings::SetWatermarkEditorSize(const QSize &sz)
+{
+ setValue(*settingWatermarkEditorSize, sz);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QVector VCommonSettings::GetWatermarkCustomColors() const
+{
+ QSettings settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
+ QStringList colors = settings.value(*settingPatternGraphicalOutput, 1).toStringList();
+
+ QVector customColors;
+ customColors.reserve(colors.size());
+
+ for (auto color : colors)
+ {
+ QColor c(color);
+ if (c.isValid())
+ {
+ customColors.append(c);
+ }
+ }
+
+ if (customColors.count() > 7)
+ {
+ customColors.remove(0, customColors.count() - 7);
+ }
+
+ return customColors;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void VCommonSettings::SetWatermarkCustomColors(QVector colors)
+{
+ QSettings settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
+
+ if (colors.count() > 7)
+ {
+ colors.remove(0, colors.count() - 7);
+ }
+
+ QStringList customColors;
+ customColors.reserve(colors.size());
+
+ for (auto color : colors)
+ {
+ customColors.append(color.name());
+ }
+
+ settings.setValue(*settingWatermarkCustomColors, customColors);
+ settings.sync();
+}
diff --git a/src/libs/vmisc/vcommonsettings.h b/src/libs/vmisc/vcommonsettings.h
index 8f4a049d3..53293db6b 100644
--- a/src/libs/vmisc/vcommonsettings.h
+++ b/src/libs/vmisc/vcommonsettings.h
@@ -277,6 +277,12 @@ public:
bool GetGraphicalOutput() const;
void SetGraphicalOutput(const bool &value);
+ auto GetWatermarkEditorSize() const -> QSize;
+ void SetWatermarkEditorSize(const QSize& sz);
+
+ auto GetWatermarkCustomColors() const -> QVector;
+ void SetWatermarkCustomColors(QVector colors);
+
protected:
template
diff --git a/src/libs/vmisc/vvalentinasettings.cpp b/src/libs/vmisc/vvalentinasettings.cpp
index 4b93ad90f..6aa8baa18 100644
--- a/src/libs/vmisc/vvalentinasettings.cpp
+++ b/src/libs/vmisc/vvalentinasettings.cpp
@@ -93,8 +93,6 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingDockWidgetToolOptionsActive,
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingDockWidgetPatternMessagesActive,
(QLatin1String("dockWidget/patternMessagesActive")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternMessagesFontSize, (QLatin1String("font/patternMessagesSize")))
-
-Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingWatermarkEditorSize, (QLatin1String("watermarkEditorSize")))
}
//---------------------------------------------------------------------------------------------------------------------
@@ -619,18 +617,6 @@ void VValentinaSettings::SetAutoRefreshPatternMessage(bool value)
setValue(*settingAutoRefreshPatternMessage, value);
}
-//---------------------------------------------------------------------------------------------------------------------
-QSize VValentinaSettings::GetWatermarkEditorSize() const
-{
- return value(*settingWatermarkEditorSize, QSize(0, 0)).toSize();
-}
-
-//---------------------------------------------------------------------------------------------------------------------
-void VValentinaSettings::SetWatermarkEditorSize(const QSize &sz)
-{
- setValue(*settingWatermarkEditorSize, sz);
-}
-
//---------------------------------------------------------------------------------------------------------------------
bool VValentinaSettings::GetToolPanelScaling() const
{
diff --git a/src/libs/vmisc/vvalentinasettings.h b/src/libs/vmisc/vvalentinasettings.h
index c5f222259..1a79d33d7 100644
--- a/src/libs/vmisc/vvalentinasettings.h
+++ b/src/libs/vmisc/vvalentinasettings.h
@@ -161,9 +161,6 @@ public:
bool GetAutoRefreshPatternMessage() const;
void SetAutoRefreshPatternMessage(bool value);
- QSize GetWatermarkEditorSize() const;
- void SetWatermarkEditorSize(const QSize& sz);
-
bool GetToolPanelScaling() const;
void SetToolPanelScaling(const bool &value);
diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp
index b8087d2e6..a6ac6a4be 100644
--- a/src/libs/vtools/tools/vtoolseamallowance.cpp
+++ b/src/libs/vtools/tools/vtoolseamallowance.cpp
@@ -1021,7 +1021,7 @@ void VToolSeamAllowance::RefreshDataInFile()
// Refresh only parts that we possibly need to update
{
// TODO. Delete if minimal supported version is 0.4.0
- Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FORMAT_VERSION(0, 4, 0),
+ Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FormatVersion(0, 4, 0),
"Time to refactor the code.");
const uint version = doc->GetParametrUInt(domElement, AttrVersion, QChar('1'));
diff --git a/src/libs/vtools/tools/vtooluniondetails.cpp b/src/libs/vtools/tools/vtooluniondetails.cpp
index 5c5bfd8c2..f3c14902d 100644
--- a/src/libs/vtools/tools/vtooluniondetails.cpp
+++ b/src/libs/vtools/tools/vtooluniondetails.cpp
@@ -1339,7 +1339,7 @@ void UpdateUnitedNodes(const VToolUnionDetailsInitData &initData, qreal dx, qrea
{
// This check need for backward compatibility
// Remove check and "else" part if min version is 0.3.2
- Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FORMAT_VERSION(0, 3, 2),
+ Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FormatVersion(0, 3, 2),
"Time to refactor the code.");
if (children.size() == countNodeD1 + countNodeD2-1)
{
@@ -1396,7 +1396,7 @@ void UpdateUnitedNodes(const VToolUnionDetailsInitData &initData, qreal dx, qrea
QVector FixChildren(QVector records, QVector children, VContainer *data)
{
// TODO. Delete if minimal supported version is 0.7.0
- Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FORMAT_VERSION(0, 7, 0),
+ Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FormatVersion(0, 7, 0),
"Time to refactor the code.");
SCASSERT(data != nullptr)
@@ -1434,7 +1434,7 @@ void UpdateUnitedDetailPaths(const VToolUnionDetailsInitData &initData, qreal dx
if (initData.version == 1)
{
// TODO. Delete if minimal supported version is 0.7.0
- Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FORMAT_VERSION(0, 7, 0),
+ Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FormatVersion(0, 7, 0),
"Time to refactor the code.");
// Fixing bug in first version of the tool. Mostly for backward compatibility.
children = FixChildren(records, children, initData.data);
@@ -1447,7 +1447,7 @@ void UpdateUnitedDetailPaths(const VToolUnionDetailsInitData &initData, qreal dx
if (initData.version == 1)
{
// TODO. Delete if minimal supported version is 0.7.0
- Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FORMAT_VERSION(0, 7, 0),
+ Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FormatVersion(0, 7, 0),
"Time to refactor the code.");
const quint32 updatedId = TakeNextId(children);
diff --git a/src/libs/vwidgets/qtcolorpicker.cpp b/src/libs/vwidgets/qtcolorpicker.cpp
new file mode 100644
index 000000000..4d77c6edf
--- /dev/null
+++ b/src/libs/vwidgets/qtcolorpicker.cpp
@@ -0,0 +1,1274 @@
+/****************************************************************************
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of a Qt Solutions component.
+**
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Solutions Commercial License Agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** Please note Third Party Software included with Qt Solutions may impose
+** additional restrictions and it is the user's responsibility to ensure
+** that they have met the licensing requirements of the GPL, LGPL, or Qt
+** Solutions Commercial license and the relevant license of the Third
+** Party Software they are using.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact Nokia at qt-info@nokia.com.
+**
+****************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "qtcolorpicker.h"
+
+/*! \class QtColorPicker
+
+ \brief The QtColorPicker class provides a widget for selecting
+ colors from a popup color grid.
+
+ Users can invoke the color picker by clicking on it, or by
+ navigating to it and pressing Space. They can use the mouse or
+ arrow keys to navigate between colors on the grid, and select a
+ color by clicking or by pressing Enter or Space. The
+ colorChanged() signal is emitted whenever the color picker's color
+ changes.
+
+ The widget also supports negative selection: Users can click and
+ hold the mouse button on the QtColorPicker widget, then move the
+ mouse over the color grid and release the mouse button over the
+ color they wish to select.
+
+ The color grid shows a customized selection of colors. An optional
+ ellipsis "..." button (signifying "more") can be added at the
+ bottom of the grid; if the user presses this, a QColorDialog pops
+ up and lets them choose any color they like. This button is made
+ available by using setColorDialogEnabled().
+
+ When a color is selected, the QtColorPicker widget shows the color
+ and its name. If the name cannot be determined, the translatable
+ name "Custom" is used.
+
+ The QtColorPicker object is optionally initialized with the number
+ of columns in the color grid. Colors are then added left to right,
+ top to bottom using insertColor(). If the number of columns is not
+ set, QtColorPicker calculates the number of columns and rows that
+ will make the grid as square as possible.
+
+ \code
+ DrawWidget::DrawWidget(QWidget *parent, const char *name)
+ {
+ QtColorPicker *picker = new QtColorPicker(this);
+ picker->insertColor(red, "Red"));
+ picker->insertColor(QColor("green"), "Green"));
+ picker->insertColor(QColor(0, 0, 255), "Blue"));
+ picker->insertColor(white);
+
+ connect(colors, SIGNAL(colorChanged(const QColor &)), SLOT(setCurrentColor(const QColor &)));
+ }
+ \endcode
+
+ An alternative to adding colors manually is to initialize the grid
+ with QColorDialog's standard colors using setStandardColors().
+
+ QtColorPicker also provides a the static function getColor(),
+ which pops up the grid of standard colors at any given point.
+
+ \img colorpicker1.png
+ \img colorpicker2.png
+
+ \sa QColorDialog
+*/
+
+/*! \fn QtColorPicker::colorChanged(const QColor &color)
+
+ This signal is emitted when the QtColorPicker's color is changed.
+ \a color is the new color.
+
+ To obtain the color's name, use text().
+*/
+
+/*
+ A class that acts very much like a QPushButton. It's not styled,
+ so we can expect the exact same look, feel and geometry
+ everywhere. Also, this button always emits clicked on
+ mouseRelease, even if the mouse button was not pressed inside the
+ widget.
+*/
+class ColorPickerButton : public QFrame
+{
+ Q_OBJECT
+
+public:
+ explicit ColorPickerButton(QWidget *parent);
+
+signals:
+ void clicked();
+
+protected:
+ void mousePressEvent(QMouseEvent *e) override;
+ void mouseMoveEvent(QMouseEvent *e) override;
+ void mouseReleaseEvent(QMouseEvent *e) override;
+ void keyPressEvent(QKeyEvent *e) override;
+ void keyReleaseEvent(QKeyEvent *e) override;
+ void paintEvent(QPaintEvent *e) override;
+ void focusInEvent(QFocusEvent *e) override;
+ void focusOutEvent(QFocusEvent *e) override;
+};
+
+/*
+ This class represents each "color" or item in the color grid.
+*/
+class ColorPickerItem : public QFrame
+{
+ Q_OBJECT
+
+public:
+ ColorPickerItem(const QColor &color = Qt::white, const QString &text = QString(),
+ QWidget *parent = 0);
+ ~ColorPickerItem();
+
+ QColor color() const;
+ QString text() const;
+
+ void setSelected(bool);
+ bool isSelected() const;
+signals:
+ void clicked();
+ void selected();
+
+public slots:
+ void setColor(const QColor &color, const QString &text = QString());
+
+protected:
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void paintEvent(QPaintEvent *e);
+
+private:
+ QColor c;
+ QString t;
+ bool sel;
+};
+
+/*
+
+*/
+class ColorPickerPopup : public QFrame
+{
+ Q_OBJECT
+
+public:
+ ColorPickerPopup(int width, bool withColorDialog,
+ QWidget *parent = nullptr);
+ ~ColorPickerPopup();
+
+ void insertColor(const QColor &col, const QString &text, int index);
+ void exec();
+
+ void setExecFlag();
+
+ QColor lastSelected() const;
+
+ ColorPickerItem *find(const QColor &col) const;
+ QColor color(int index) const;
+
+ auto CustomItems() const -> QVector;
+
+signals:
+ void selected(const QColor &);
+ void hid();
+
+public slots:
+ void getColorFromDialog();
+
+protected slots:
+ void updateSelected();
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+ void showEvent(QShowEvent *e);
+ void hideEvent(QHideEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+
+ void regenerateGrid();
+
+private:
+ Q_DISABLE_COPY(ColorPickerPopup)
+ QMap > widgetAt{};
+ QList items{};
+ QGridLayout *grid{nullptr};
+ ColorPickerButton *moreButton{nullptr};
+ QEventLoop *eventLoop{nullptr};
+
+ int lastPos{0};
+ int cols;
+ QColor lastSel{};
+};
+
+/*!
+ Constructs a QtColorPicker widget. The popup will display a grid
+ with \a cols columns, or if \a cols is -1, the number of columns
+ will be calculated automatically.
+
+ If \a enableColorDialog is true, the popup will also have a "More"
+ button (signified by an ellipsis "...") that presents a
+ QColorDialog when clicked.
+
+ After constructing a QtColorPicker, call insertColor() to add
+ individual colors to the popup grid, or call setStandardColors()
+ to add all the standard colors in one go.
+
+ The \a parent argument is passed to QFrame's constructor.
+
+ \sa QFrame
+*/
+QtColorPicker::QtColorPicker(QWidget *parent,
+ int cols, bool enableColorDialog)
+ : QPushButton(parent), popup(0), withColorDialog(enableColorDialog)
+{
+ setFocusPolicy(Qt::StrongFocus);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ setAutoDefault(false);
+ setAutoFillBackground(true);
+ setCheckable(true);
+
+ // Set text
+ setText(tr("Black"));
+ firstInserted = false;
+
+ // Create and set icon
+ col = Qt::black;
+ dirty = true;
+
+ // Create color grid popup and connect to it.
+ popup = new ColorPickerPopup(cols, withColorDialog, this);
+ connect(popup, SIGNAL(selected(const QColor &)),
+ SLOT(setCurrentColor(const QColor &)));
+ connect(popup, SIGNAL(hid()), SLOT(popupClosed()));
+
+ // Connect this push button's pressed() signal.
+ connect(this, SIGNAL(toggled(bool)), SLOT(buttonPressed(bool)));
+}
+
+/*!
+ Destructs the QtColorPicker.
+*/
+QtColorPicker::~QtColorPicker()
+{
+}
+
+/*! \internal
+
+ Pops up the color grid, and makes sure the status of
+ QtColorPicker's button is right.
+*/
+void QtColorPicker::buttonPressed(bool toggled)
+{
+ if (!toggled)
+ return;
+
+ const QRect desktop = this->parentWidget()->geometry();
+ // Make sure the popup is inside the desktop.
+ QPoint pos = rect().bottomLeft();
+ if (pos.x() < desktop.left())
+ pos.setX(desktop.left());
+ if (pos.y() < desktop.top())
+ pos.setY(desktop.top());
+
+ if ((pos.x() + popup->sizeHint().width()) > desktop.width())
+ pos.setX(desktop.width() - popup->sizeHint().width());
+ if ((pos.y() + popup->sizeHint().height()) > desktop.bottom())
+ pos.setY(desktop.bottom() - popup->sizeHint().height());
+ popup->move(mapToGlobal(pos));
+
+ if (ColorPickerItem *item = popup->find(col))
+ item->setSelected(true);
+
+ // Remove focus from this widget, preventing the focus rect
+ // from showing when the popup is shown. Order an update to
+ // make sure the focus rect is cleared.
+ clearFocus();
+ update();
+
+ // Allow keyboard navigation as soon as the popup shows.
+ popup->setFocus();
+
+ // Execute the popup. The popup will enter the event loop.
+ popup->show();
+}
+
+/*!
+ \internal
+*/
+void QtColorPicker::paintEvent(QPaintEvent *e)
+{
+ if (dirty) {
+ int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize);
+ QPixmap pix(iconSize, iconSize);
+ pix.fill(palette().button().color());
+
+ QPainter p(&pix);
+
+ int w = pix.width(); // width of cell in pixels
+ int h = pix.height(); // height of cell in pixels
+ p.setPen(QPen(Qt::gray));
+ p.setBrush(col);
+ p.drawRect(2, 2, w - 5, h - 5);
+ setIcon(QIcon(pix));
+
+ dirty = false;
+ }
+ QPushButton::paintEvent(e);
+}
+
+/*! \internal
+
+ Makes sure the button isn't pressed when the popup hides.
+*/
+void QtColorPicker::popupClosed()
+{
+ setChecked(false);
+ setFocus();
+}
+
+/*!
+ Returns the currently selected color.
+
+ \sa text()
+*/
+QColor QtColorPicker::currentColor() const
+{
+ return col;
+}
+
+/*!
+ Returns the color at position \a index.
+*/
+QColor QtColorPicker::color(int index) const
+{
+ return popup->color(index);
+}
+
+/*!
+ Adds the 17 predefined colors from the Qt namespace.
+
+ (The names given to the colors, "Black", "White", "Red", etc., are
+ all translatable.)
+
+ \sa insertColor()
+*/
+void QtColorPicker::setStandardColors()
+{
+ insertColor(Qt::black, tr("Black"));
+ insertColor(Qt::white, tr("White"));
+ insertColor(Qt::red, tr("Red"));
+ insertColor(Qt::darkRed, tr("Dark red"));
+ insertColor(Qt::green, tr("Green"));
+ insertColor(Qt::darkGreen, tr("Dark green"));
+ insertColor(Qt::blue, tr("Blue"));
+ insertColor(Qt::darkBlue, tr("Dark blue"));
+ insertColor(Qt::cyan, tr("Cyan"));
+ insertColor(Qt::darkCyan, tr("Dark cyan"));
+ insertColor(Qt::magenta, tr("Magenta"));
+ insertColor(Qt::darkMagenta, tr("Dark magenta"));
+ insertColor(Qt::yellow, tr("Yellow"));
+ insertColor(Qt::darkYellow, tr("Dark yellow"));
+ insertColor(Qt::gray, tr("Gray"));
+ insertColor(Qt::darkGray, tr("Dark gray"));
+ insertColor(Qt::lightGray, tr("Light gray"));
+}
+
+auto QtColorPicker::CustomColors() const -> QVector
+{
+ QVector customColor;
+ if (popup != nullptr)
+ {
+ QVector items = popup->CustomItems();
+ customColor.reserve(items.size());
+
+ for (auto *item : items)
+ {
+ if (item != nullptr)
+ {
+ customColor.append(item->color());
+ }
+ }
+ }
+ return customColor;
+}
+
+
+/*!
+ Makes \a color current. If \a color is not already in the color grid, it
+ is inserted with the text "Custom".
+
+ This function emits the colorChanged() signal if the new color is
+ valid, and different from the old one.
+*/
+void QtColorPicker::setCurrentColor(const QColor &color)
+{
+ if (col == color || !color.isValid())
+ return;
+
+ ColorPickerItem *item = popup->find(color);
+ if (!item)
+ {
+ insertColor(color, tr("Custom"));
+ item = popup->find(color);
+ }
+
+ col = color;
+ setText(item->text());
+
+ dirty = true;
+
+ popup->hide();
+ repaint();
+
+ item->setSelected(true);
+ emit colorChanged(color);
+}
+
+/*!
+ Adds the color \a color with the name \a text to the color grid,
+ at position \a index. If index is -1, the color is assigned
+ automatically assigned a position, starting from left to right,
+ top to bottom.
+*/
+void QtColorPicker::insertColor(const QColor &color, const QString &text, int index)
+{
+ popup->insertColor(color, text, index);
+ if (!firstInserted) {
+ col = color;
+ setText(text);
+ firstInserted = true;
+ }
+}
+
+/*! \property QtColorPicker::colorDialog
+ \brief Whether the ellipsis "..." (more) button is available.
+
+ If this property is set to TRUE, the color grid popup will include
+ a "More" button (signified by an ellipsis, "...") which pops up a
+ QColorDialog when clicked. The user will then be able to select
+ any custom color they like.
+*/
+void QtColorPicker::setColorDialogEnabled(bool enabled)
+{
+ withColorDialog = enabled;
+}
+bool QtColorPicker::colorDialogEnabled() const
+{
+ return withColorDialog;
+}
+
+/*!
+ Pops up a color grid with Qt default colors at \a point, using
+ global coordinates. If \a allowCustomColors is true, there will
+ also be a button on the popup that invokes QColorDialog.
+
+ For example:
+
+ \code
+ void Drawer::mouseReleaseEvent(QMouseEvent *e)
+ {
+ if (e->button() & RightButton) {
+ QColor color = QtColorPicker::getColor(mapToGlobal(e->pos()));
+ }
+ }
+ \endcode
+*/
+QColor QtColorPicker::getColor(const QPoint &point, bool allowCustomColors)
+{
+ ColorPickerPopup popup(-1, allowCustomColors);
+
+ popup.insertColor(Qt::black, tr("Black"), 0);
+ popup.insertColor(Qt::white, tr("White"), 1);
+ popup.insertColor(Qt::red, tr("Red"), 2);
+ popup.insertColor(Qt::darkRed, tr("Dark red"), 3);
+ popup.insertColor(Qt::green, tr("Green"), 4);
+ popup.insertColor(Qt::darkGreen, tr("Dark green"), 5);
+ popup.insertColor(Qt::blue, tr("Blue"), 6);
+ popup.insertColor(Qt::darkBlue, tr("Dark blue"), 7);
+ popup.insertColor(Qt::cyan, tr("Cyan"), 8);
+ popup.insertColor(Qt::darkCyan, tr("Dark cyan"), 9);
+ popup.insertColor(Qt::magenta, tr("Magenta"), 10);
+ popup.insertColor(Qt::darkMagenta, tr("Dark magenta"), 11);
+ popup.insertColor(Qt::yellow, tr("Yellow"), 12);
+ popup.insertColor(Qt::darkYellow, tr("Dark yellow"), 13);
+ popup.insertColor(Qt::gray, tr("Gray"), 14);
+ popup.insertColor(Qt::darkGray, tr("Dark gray"), 15);
+ popup.insertColor(Qt::lightGray, tr("Light gray"), 16);
+
+ popup.move(point);
+ popup.exec();
+ return popup.lastSelected();
+}
+
+/*! \internal
+
+ Constructs the popup widget.
+*/
+ColorPickerPopup::ColorPickerPopup(int width, bool withColorDialog, QWidget *parent)
+ : QFrame(parent, Qt::Popup),
+ cols(width)
+{
+ setFrameStyle(QFrame::StyledPanel);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ setFocusPolicy(Qt::StrongFocus);
+ setMouseTracking(true);
+
+ if (withColorDialog)
+ {
+ moreButton = new ColorPickerButton(this);
+ moreButton->setFixedWidth(24);
+ moreButton->setFixedHeight(21);
+ moreButton->setFrameRect(QRect(2, 2, 20, 17));
+ connect(moreButton, SIGNAL(clicked()), SLOT(getColorFromDialog()));
+ }
+ else
+ {
+ moreButton = 0;
+ }
+
+ eventLoop = nullptr;
+ grid = nullptr;
+ regenerateGrid();
+}
+
+
+/*! \internal
+
+ Destructs the popup widget.
+*/
+ColorPickerPopup::~ColorPickerPopup()
+{
+ if (eventLoop != nullptr)
+ {
+ eventLoop->exit();
+ }
+}
+
+/*! \internal
+
+ If there is an item whole color is equal to \a col, returns a
+ pointer to this item; otherwise returns 0.
+*/
+ColorPickerItem *ColorPickerPopup::find(const QColor &col) const
+{
+ for (auto *item : items)
+ {
+ if (item && item->color() == col)
+ {
+ return item;
+ }
+ }
+
+ return nullptr;
+}
+
+/*! \internal
+
+ Adds \a item to the grid. The items are added from top-left to
+ bottom-right.
+*/
+void ColorPickerPopup::insertColor(const QColor &col, const QString &text, int index)
+{
+ // Don't add colors that we have already.
+ ColorPickerItem *existingItem = find(col);
+ ColorPickerItem *lastSelectedItem = find(lastSelected());
+
+ if (existingItem != nullptr)
+ {
+ if (lastSelectedItem && existingItem != lastSelectedItem)
+ {
+ lastSelectedItem->setSelected(false);
+ }
+ existingItem->setFocus();
+ existingItem->setSelected(true);
+ return;
+ }
+
+ auto *item = new ColorPickerItem(col, text, this);
+
+ if (lastSelectedItem)
+ {
+ lastSelectedItem->setSelected(false);
+ }
+ else
+ {
+ item->setSelected(true);
+ lastSel = col;
+ }
+ item->setFocus();
+
+ connect(item, SIGNAL(selected()), SLOT(updateSelected()));
+
+ if (index == -1)
+ {
+ index = items.count();
+ }
+
+ items.insert(index, item);
+ regenerateGrid();
+
+ update();
+}
+
+/*! \internal
+
+*/
+QColor ColorPickerPopup::color(int index) const
+{
+ if (index < 0 || index > static_cast (items.count() - 1))
+ {
+ return QColor();
+ }
+
+ auto *that = const_cast(this);
+ return that->items.at(index)->color();
+}
+
+auto ColorPickerPopup::CustomItems() const ->QVector
+{
+ QVector customItems;
+ customItems.reserve(items.size());
+
+ for (auto *item : items)
+ {
+ if (item!= nullptr && item->text() == tr("Custom"))
+ {
+ customItems.append(item);
+ }
+ }
+
+ return customItems;
+}
+
+/*! \internal
+
+*/
+void ColorPickerPopup::exec()
+{
+ show();
+
+ QEventLoop e;
+ eventLoop = &e;
+ (void) e.exec();
+ eventLoop = nullptr;
+}
+
+/*! \internal
+
+*/
+void ColorPickerPopup::updateSelected()
+{
+ QLayoutItem *layoutItem;
+ int i = 0;
+ while ((layoutItem = grid->itemAt(i)) != 0)
+ {
+ QWidget *w = layoutItem->widget();
+ if (w && w->inherits("ColorPickerItem"))
+ {
+ auto *litem = reinterpret_cast(layoutItem->widget());
+ if (litem != sender())
+ {
+ litem->setSelected(false);
+ }
+ }
+ ++i;
+ }
+
+ if (sender() && sender()->inherits("ColorPickerItem"))
+ {
+ auto *item = static_cast(sender());
+ lastSel = item->color();
+ emit selected(item->color());
+ }
+
+ hide();
+}
+
+/*! \internal
+
+*/
+void ColorPickerPopup::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (!rect().contains(e->pos()))
+ {
+ hide();
+ }
+}
+
+/*! \internal
+
+ Controls keyboard navigation and selection on the color grid.
+*/
+void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
+{
+ int curRow = 0;
+ int curCol = 0;
+
+ bool foundFocus = false;
+ for (int j = 0; !foundFocus && j < grid->rowCount(); ++j)
+ {
+ for (int i = 0; !foundFocus && i < grid->columnCount(); ++i)
+ {
+ if ((widgetAt[j][i] != nullptr) && widgetAt[j][i]->hasFocus())
+ {
+ curRow = j;
+ curCol = i;
+ foundFocus = true;
+ break;
+ }
+ }
+ }
+
+ switch (e->key())
+ {
+ case Qt::Key_Left:
+ if (curCol > 0)
+ {
+ --curCol;
+ }
+ else if (curRow > 0)
+ {
+ --curRow; curCol = grid->columnCount() - 1;
+ }
+ break;
+ case Qt::Key_Right:
+ if (curCol < grid->columnCount() - 1 && widgetAt[curRow][curCol + 1])
+ {
+ ++curCol;
+ }
+ else if (curRow < grid->rowCount() - 1)
+ {
+ ++curRow; curCol = 0;
+ }
+ break;
+ case Qt::Key_Up:
+ if (curRow > 0)
+ {
+ --curRow;
+ }
+ else curCol = 0;
+ break;
+ case Qt::Key_Down:
+ if (curRow < grid->rowCount() - 1)
+ {
+ QWidget *w = widgetAt[curRow + 1][curCol];
+ if (w)
+ {
+ ++curRow;
+ }
+ else for (int i = 1; i < grid->columnCount(); ++i)
+ {
+ if (!widgetAt[curRow + 1][i])
+ {
+ curCol = i - 1;
+ ++curRow;
+ break;
+ }
+ }
+ }
+ break;
+ case Qt::Key_Space:
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ {
+ QWidget *w = widgetAt[curRow][curCol];
+ if ((w != nullptr) && w->inherits("ColorPickerItem"))
+ {
+ ColorPickerItem *wi = reinterpret_cast(w);
+ wi->setSelected(true);
+
+ QLayoutItem *layoutItem;
+ int i = 0;
+ while ((layoutItem = grid->itemAt(i)) != 0)
+ {
+ QWidget *w = layoutItem->widget();
+ if (w && w->inherits("ColorPickerItem"))
+ {
+ ColorPickerItem *litem
+ = reinterpret_cast(layoutItem->widget());
+ if (litem != wi)
+ {
+ litem->setSelected(false);
+ }
+ }
+ ++i;
+ }
+
+ lastSel = wi->color();
+ emit selected(wi->color());
+ hide();
+ }
+ else if (w && w->inherits("QPushButton"))
+ {
+ ColorPickerItem *wi = reinterpret_cast(w);
+ wi->setSelected(true);
+
+ QLayoutItem *layoutItem;
+ int i = 0;
+ while ((layoutItem = grid->itemAt(i)) != 0)
+ {
+ QWidget *w = layoutItem->widget();
+ if (w && w->inherits("ColorPickerItem"))
+ {
+ ColorPickerItem *litem
+ = reinterpret_cast(layoutItem->widget());
+ if (litem != wi)
+ {
+ litem->setSelected(false);
+ }
+ }
+ ++i;
+ }
+
+ lastSel = wi->color();
+ emit selected(wi->color());
+ hide();
+ }
+ break;
+ }
+ case Qt::Key_Escape:
+ hide();
+ break;
+ default:
+ e->ignore();
+ break;
+ }
+
+ widgetAt[curRow][curCol]->setFocus();
+}
+
+/*! \internal
+
+*/
+void ColorPickerPopup::hideEvent(QHideEvent *e)
+{
+ if (eventLoop)
+ {
+ eventLoop->exit();
+ }
+
+ setFocus();
+
+ emit hid();
+ QFrame::hideEvent(e);
+}
+
+/*! \internal
+
+*/
+QColor ColorPickerPopup::lastSelected() const
+{
+ return lastSel;
+}
+
+/*! \internal
+
+ Sets focus on the popup to enable keyboard navigation. Draws
+ focusRect and selection rect.
+*/
+void ColorPickerPopup::showEvent(QShowEvent *)
+{
+ bool foundSelected = false;
+ for (int i = 0; i < grid->columnCount(); ++i)
+ {
+ for (int j = 0; j < grid->rowCount(); ++j)
+ {
+ QWidget *w = widgetAt[j][i];
+ if (w && w->inherits("ColorPickerItem"))
+ {
+ if (static_cast(w)->isSelected())
+ {
+ w->setFocus();
+ foundSelected = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!foundSelected)
+ {
+ if (items.count() == 0)
+ {
+ setFocus();
+ }
+ else
+ {
+ widgetAt[0][0]->setFocus();
+ }
+ }
+}
+
+/*!
+
+*/
+void ColorPickerPopup::regenerateGrid()
+{
+ widgetAt.clear();
+
+ int columns = cols;
+ if (columns == -1)
+ {
+ columns = static_cast(ceil(sqrt(static_cast(items.count()))));
+ }
+
+ // When the number of columns grows, the number of rows will
+ // fall. There's no way to shrink a grid, so we create a new
+ // one.
+ if (grid) delete grid;
+ grid = new QGridLayout(this);
+ grid->setContentsMargins(1, 1, 1, 1);
+ grid->setSpacing(0);
+
+ int ccol = 0, crow = 0;
+ for (int i = 0; i < items.size(); ++i)
+ {
+ if (items.at(i))
+ {
+ widgetAt[crow][ccol] = items.at(i);
+ grid->addWidget(items.at(i), crow, ccol++);
+ if (ccol == columns)
+ {
+ ++crow;
+ ccol = 0;
+ }
+ }
+ }
+
+ if (moreButton)
+ {
+ grid->addWidget(moreButton, crow, ccol);
+ widgetAt[crow][ccol] = moreButton;
+ }
+ updateGeometry();
+}
+
+/*! \internal
+
+ Copies the color dialog's currently selected item and emits
+ itemSelected().
+*/
+void ColorPickerPopup::getColorFromDialog()
+{
+ QColor col = QColorDialog::getColor(lastSel, parentWidget());
+ if (!col.isValid())
+ {
+ return;
+ }
+
+ insertColor(col, tr("Custom"), -1);
+ lastSel = col;
+ emit selected(col);
+}
+
+/*!
+ Constructs a ColorPickerItem whose color is set to \a color, and
+ whose name is set to \a text.
+*/
+ColorPickerItem::ColorPickerItem(const QColor &color, const QString &text,
+ QWidget *parent)
+ : QFrame(parent), c(color), t(text), sel(false)
+{
+ setToolTip(t);
+ setFixedWidth(24);
+ setFixedHeight(21);
+}
+
+/*!
+ Destructs a ColorPickerItem.
+ */
+ColorPickerItem::~ColorPickerItem()
+{
+}
+
+/*!
+ Returns the item's color.
+
+ \sa text()
+*/
+QColor ColorPickerItem::color() const
+{
+ return c;
+}
+
+/*!
+ Returns the item's text.
+
+ \sa color()
+*/
+QString ColorPickerItem::text() const
+{
+ return t;
+}
+
+/*!
+
+*/
+bool ColorPickerItem::isSelected() const
+{
+ return sel;
+}
+
+/*!
+
+*/
+void ColorPickerItem::setSelected(bool selected)
+{
+ sel = selected;
+ update();
+}
+
+/*!
+ Sets the item's color to \a color, and its name to \a text.
+*/
+void ColorPickerItem::setColor(const QColor &color, const QString &text)
+{
+ c = color;
+ t = text;
+ setToolTip(t);
+ update();
+}
+
+/*!
+
+*/
+void ColorPickerItem::mouseMoveEvent(QMouseEvent *)
+{
+ setFocus();
+ update();
+}
+
+/*!
+
+*/
+void ColorPickerItem::mouseReleaseEvent(QMouseEvent *)
+{
+ sel = true;
+ emit selected();
+}
+
+/*!
+
+*/
+void ColorPickerItem::mousePressEvent(QMouseEvent *)
+{
+ setFocus();
+ update();
+}
+
+/*!
+
+*/
+void ColorPickerItem::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ int w = width(); // width of cell in pixels
+ int h = height(); // height of cell in pixels
+
+ p.setPen( QPen( Qt::gray, 0, Qt::SolidLine ) );
+
+ if (sel)
+ {
+ p.drawRect(1, 1, w - 3, h - 3);
+ }
+
+ p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
+ p.drawRect(3, 3, w - 7, h - 7);
+ p.fillRect(QRect(4, 4, w - 8, h - 8), QBrush(c));
+
+ if (hasFocus())
+ {
+ p.drawRect(0, 0, w - 1, h - 1);
+ }
+}
+
+/*!
+
+*/
+ColorPickerButton::ColorPickerButton(QWidget *parent)
+ : QFrame(parent)
+{
+ setFrameStyle(StyledPanel);
+}
+
+/*!
+
+*/
+void ColorPickerButton::mousePressEvent(QMouseEvent *e)
+{
+ Q_UNUSED(e)
+ setFrameShadow(Sunken);
+ update();
+}
+
+/*!
+
+*/
+void ColorPickerButton::mouseMoveEvent(QMouseEvent *e)
+{
+ Q_UNUSED(e)
+ setFocus();
+ update();
+}
+
+/*!
+
+*/
+void ColorPickerButton::mouseReleaseEvent(QMouseEvent *e)
+{
+ Q_UNUSED(e)
+ setFrameShadow(Raised);
+ repaint();
+ emit clicked();
+}
+
+/*!
+
+*/
+void ColorPickerButton::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Up
+ || e->key() == Qt::Key_Down
+ || e->key() == Qt::Key_Left
+ || e->key() == Qt::Key_Right)
+ {
+ QCoreApplication::sendEvent(parent(), e);
+ }
+ else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return)
+ {
+ setFrameShadow(Sunken);
+ update();
+ }
+ else
+ {
+ QFrame::keyPressEvent(e);
+ }
+}
+
+/*!
+
+*/
+void ColorPickerButton::keyReleaseEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Up
+ || e->key() == Qt::Key_Down
+ || e->key() == Qt::Key_Left
+ || e->key() == Qt::Key_Right)
+ {
+ QCoreApplication::sendEvent(parent(), e);
+ }
+ else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return)
+ {
+ setFrameShadow(Raised);
+ repaint();
+ emit clicked();
+ }
+ else
+ {
+ QFrame::keyReleaseEvent(e);
+ }
+
+}
+
+/*!
+
+*/
+void ColorPickerButton::focusInEvent(QFocusEvent *e)
+{
+ setFrameShadow(Raised);
+ update();
+ QFrame::focusOutEvent(e);
+}
+
+/*!
+
+*/
+void ColorPickerButton::focusOutEvent(QFocusEvent *e)
+{
+ setFrameShadow(Raised);
+ update();
+ QFrame::focusOutEvent(e);
+}
+
+/*!
+
+*/
+void ColorPickerButton::paintEvent(QPaintEvent *e)
+{
+ QFrame::paintEvent(e);
+
+ QPainter p(this);
+ p.fillRect(contentsRect(), palette().button());
+
+ QRect r = rect();
+
+ int offset = frameShadow() == Sunken ? 1 : 0;
+
+ QPen pen(palette().buttonText(), 1);
+ p.setPen(pen);
+
+ p.drawRect(r.center().x() + offset - 4, r.center().y() + offset, 1, 1);
+ p.drawRect(r.center().x() + offset , r.center().y() + offset, 1, 1);
+ p.drawRect(r.center().x() + offset + 4, r.center().y() + offset, 1, 1);
+ if (hasFocus())
+ {
+ p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
+ p.drawRect(0, 0, width() - 1, height() - 1);
+ }
+
+ p.end();
+
+}
+
+#include "qtcolorpicker.moc"
diff --git a/src/libs/vwidgets/qtcolorpicker.h b/src/libs/vwidgets/qtcolorpicker.h
new file mode 100644
index 000000000..1ef681886
--- /dev/null
+++ b/src/libs/vwidgets/qtcolorpicker.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of a Qt Solutions component.
+**
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Solutions Commercial License Agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** Please note Third Party Software included with Qt Solutions may impose
+** additional restrictions and it is the user's responsibility to ensure
+** that they have met the licensing requirements of the GPL, LGPL, or Qt
+** Solutions Commercial license and the relevant license of the Third
+** Party Software they are using.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact Nokia at qt-info@nokia.com.
+**
+****************************************************************************/
+
+#ifndef QTCOLORPICKER_H
+#define QTCOLORPICKER_H
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+
+class ColorPickerPopup;
+class ColorPickerItem;
+
+class QtColorPicker : public QPushButton
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool colorDialog READ colorDialogEnabled WRITE setColorDialogEnabled)
+
+public:
+ QtColorPicker(QWidget *parent = 0,
+ int columns = -1, bool enableColorDialog = true);
+
+ ~QtColorPicker();
+
+ void insertColor(const QColor &color, const QString &text = QString(), int index = -1);
+
+ QColor currentColor() const;
+
+ QColor color(int index) const;
+
+ void setColorDialogEnabled(bool enabled);
+ bool colorDialogEnabled() const;
+
+ void setStandardColors();
+
+ auto CustomColors() const -> QVector;
+
+ static QColor getColor(const QPoint &pos, bool allowCustomColors = true);
+
+public Q_SLOTS:
+ void setCurrentColor(const QColor &col);
+
+Q_SIGNALS:
+ void colorChanged(const QColor &);
+
+protected:
+ void paintEvent(QPaintEvent *e);
+
+private Q_SLOTS:
+ void buttonPressed(bool toggled);
+ void popupClosed();
+
+private:
+ Q_DISABLE_COPY(QtColorPicker)
+ ColorPickerPopup *popup{nullptr};
+ QColor col{};
+ bool withColorDialog{false};
+ bool dirty{false};
+ bool firstInserted{false};
+};
+
+#endif
diff --git a/src/libs/vwidgets/vwidgets.pri b/src/libs/vwidgets/vwidgets.pri
index eaf29bd78..023e5efb0 100644
--- a/src/libs/vwidgets/vwidgets.pri
+++ b/src/libs/vwidgets/vwidgets.pri
@@ -2,6 +2,7 @@
# This need for corect working file translations.pro
SOURCES += \
+ $$PWD/qtcolorpicker.cpp \
$$PWD/vcomboboxdelegate.cpp \
$$PWD/vdecorationaligningdelegate.cpp \
$$PWD/velidedlabel.cpp \
@@ -32,6 +33,7 @@ SOURCES += \
*msvc*:SOURCES += $$PWD/stable.cpp
HEADERS += \
+ $$PWD/qtcolorpicker.h \
$$PWD/stable.h \
$$PWD/vcomboboxdelegate.h \
$$PWD/vdecorationaligningdelegate.h \