diff --git a/ACKNOWLEDGEMENTS.html b/ACKNOWLEDGEMENTS.html index 28ebb99e..66518d47 100644 --- a/ACKNOWLEDGEMENTS.html +++ b/ACKNOWLEDGEMENTS.html @@ -1345,4 +1345,22 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode ** $QT_END_LICENSE$ ** ****************************************************************************/ - \ No newline at end of file + + +

Qt-Color-Widgets

+
+    Linking this library statically or dynamically with other modules is making a
+    combined work based on this library. Thus, the terms and conditions of the
+    GNU Lesser General Public License version 3 cover the whole combination.
+
+    As a special exception, the copyright holders of this library give you
+    permission to combine this library with independent
+    modules to produce an executable, and to copy and distribute the resulting
+    executable under terms of any of the GNU General Public licenses, as published
+    by the Free Software Foundation, provided that you also meet,
+    for each linked independent module, the terms and conditions of the license of
+    that module. An independent module is a module which is not derived from or
+    based on this library. If you modify this library, you may extend this
+    exception to your version of the library, but you are not obliged to do so.
+    If you do not wish to do so, delete this exception statement from your version.
+
diff --git a/dust3d.pro b/dust3d.pro index f79619a6..a0b23060 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -132,6 +132,7 @@ DEFINES += NOMINMAX include(thirdparty/QtAwesome/QtAwesome/QtAwesome.pri) include(thirdparty/qtsingleapplication/src/qtsingleapplication.pri) +include(thirdparty/Qt-Color-Widgets/color_widgets.pri) INCLUDEPATH += src @@ -443,8 +444,11 @@ HEADERS += src/intnumberwidget.h SOURCES += src/imagepreviewwidget.cpp HEADERS += src/imagepreviewwidget.h -SOURCES += src/mousepicker.cpp -HEADERS += src/mousepicker.h +SOURCES += src/vertexcolorpainter.cpp +HEADERS += src/vertexcolorpainter.h + +SOURCES += src/voxelgrid.cpp +HEADERS += src/voxelgrid.h SOURCES += src/paintmode.cpp HEADERS += src/paintmode.h diff --git a/shaders/default.core.frag b/shaders/default.core.frag index a4c09eae..5014ea7b 100644 --- a/shaders/default.core.frag +++ b/shaders/default.core.frag @@ -573,16 +573,16 @@ void main() lights[0].type = TYPE_POINT; lights[0].position = firstLightPos; lights[0].color = vec3(1.0, 1.0, 1.0); - lights[0].intensity = 3.0; - lights[0].constantAttenuation = 0.0; + lights[0].intensity = 1.0; + lights[0].constantAttenuation = 1.0; lights[0].linearAttenuation = 0.0; - lights[0].quadraticAttenuation = 0.0; + lights[0].quadraticAttenuation = 0.0025; // Fill light lights[1].type = TYPE_POINT; lights[1].position = secondLightPos; lights[1].color = vec3(1.0, 1.0, 1.0); - lights[1].intensity = 1.0; + lights[1].intensity = 0.1; lights[1].constantAttenuation = 0.0; lights[1].linearAttenuation = 0.0; lights[1].quadraticAttenuation = 0.0; @@ -591,7 +591,7 @@ void main() lights[2].type = TYPE_POINT; lights[2].position = thirdLightPos; lights[2].color = vec3(1.0, 1.0, 1.0); - lights[2].intensity = 0.5; + lights[2].intensity = 0.05; lights[2].constantAttenuation = 0.0; lights[2].linearAttenuation = 0.0; lights[2].quadraticAttenuation = 0.0; @@ -635,8 +635,8 @@ void main() ambientOcclusion = texture(metalnessRoughnessAmbientOcclusionMapId, vertTexCoord).r; } + roughness = min(0.99, roughness); if (environmentIrradianceMapEnabled != 1) { - roughness = min(0.99, roughness); metalness = min(0.99, metalness); } diff --git a/src/document.cpp b/src/document.cpp index 917481bc..32c1c62b 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -17,7 +17,6 @@ #include "motionsgenerator.h" #include "skeletonside.h" #include "scriptrunner.h" -#include "mousepicker.h" #include "imageforever.h" #include "contourtopartconverter.h" @@ -41,10 +40,12 @@ Document::Document() : rigType(RigType::None), weldEnabled(true), polyCount(PolyCount::Original), + brushColor(Qt::white), // private m_isResultMeshObsolete(false), m_meshGenerator(nullptr), m_resultMesh(nullptr), + m_paintedMesh(nullptr), m_resultMeshCutFaceTransforms(nullptr), m_resultMeshNodesCutFaces(nullptr), m_isMeshGenerationSucceed(true), @@ -73,11 +74,12 @@ Document::Document() : m_nextMeshGenerationId(1), m_scriptRunner(nullptr), m_isScriptResultObsolete(false), - m_mousePicker(nullptr), + m_vertexColorPainter(nullptr), m_isMouseTargetResultObsolete(false), m_paintMode(PaintMode::None), - m_mousePickRadius(0.2), - m_saveNextPaintSnapshot(false) + m_mousePickRadius(0.05), + m_saveNextPaintSnapshot(false), + m_vertexColorVoxelGrid(nullptr) { connect(&Preferences::instance(), &Preferences::partColorChanged, this, &Document::applyPreferencePartColorChange); connect(&Preferences::instance(), &Preferences::flatShadingChanged, this, &Document::applyPreferenceFlatShadingChange); @@ -103,6 +105,7 @@ void Document::applyPreferenceTextureSizeChange() Document::~Document() { delete m_resultMesh; + delete m_paintedMesh; delete m_resultMeshCutFaceTransforms; delete m_resultMeshNodesCutFaces; delete m_postProcessedOutcome; @@ -1029,7 +1032,7 @@ void Document::setPaintMode(PaintMode mode) m_paintMode = mode; emit paintModeChanged(); - doPickMouseTarget(); + paintVertexColors(); } void Document::joinNodeAndNeiborsToGroup(std::vector *group, QUuid nodeId, std::set *visitMap, QUuid noUseEdgeId) @@ -1170,6 +1173,10 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId part["color"] = partIt.second.color.name(QColor::HexArgb); if (partIt.second.colorSolubilityAdjusted()) part["colorSolubility"] = QString::number(partIt.second.colorSolubility); + if (partIt.second.metalnessAdjusted()) + part["metalness"] = QString::number(partIt.second.metalness); + if (partIt.second.roughnessAdjusted()) + part["roughness"] = QString::number(partIt.second.roughness); if (partIt.second.deformThicknessAdjusted()) part["deformThickness"] = QString::number(partIt.second.deformThickness); if (partIt.second.deformWidthAdjusted()) @@ -1590,6 +1597,12 @@ void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource sou const auto &colorSolubilityIt = partKv.second.find("colorSolubility"); if (colorSolubilityIt != partKv.second.end()) part.colorSolubility = colorSolubilityIt->second.toFloat(); + const auto &metalnessIt = partKv.second.find("metalness"); + if (metalnessIt != partKv.second.end()) + part.metalness = metalnessIt->second.toFloat(); + const auto &roughnessIt = partKv.second.find("roughness"); + if (roughnessIt != partKv.second.end()) + part.roughness = roughnessIt->second.toFloat(); const auto &deformThicknessIt = partKv.second.find("deformThickness"); if (deformThicknessIt != partKv.second.end()) part.setDeformThickness(deformThicknessIt->second.toFloat()); @@ -1905,6 +1918,14 @@ Model *Document::takeResultMesh() return resultMesh; } +Model *Document::takePaintedMesh() +{ + if (nullptr == m_paintedMesh) + return nullptr; + Model *paintedMesh = new Model(*m_paintedMesh); + return paintedMesh; +} + bool Document::isMeshGenerationSucceed() { return m_isMeshGenerationSucceed; @@ -2205,12 +2226,12 @@ void Document::pickMouseTarget(const QVector3D &nearPosition, const QVector3D &f m_mouseRayNear = nearPosition; m_mouseRayFar = farPosition; - doPickMouseTarget(); + paintVertexColors(); } -void Document::doPickMouseTarget() +void Document::paintVertexColors() { - if (nullptr != m_mousePicker) { + if (nullptr != m_vertexColorPainter) { m_isMouseTargetResultObsolete = true; return; } @@ -2225,44 +2246,41 @@ void Document::doPickMouseTarget() //qDebug() << "Mouse picking.."; QThread *thread = new QThread; - m_mousePicker = new MousePicker(*m_currentOutcome, m_mouseRayNear, m_mouseRayFar); - - std::map paintImages; - for (const auto &it: partMap) { - if (!it.second.deformMapImageId.isNull()) { - paintImages[it.first] = it.second.deformMapImageId; - } - } + m_vertexColorPainter = new VertexColorPainter(*m_currentOutcome, m_mouseRayNear, m_mouseRayFar); + m_vertexColorPainter->setBrushColor(brushColor); + m_vertexColorPainter->setBrushMetalness(brushMetalness); + m_vertexColorPainter->setBrushRoughness(brushRoughness); if (SkeletonDocumentEditMode::Paint == editMode) { - m_mousePicker->setPaintImages(paintImages); - m_mousePicker->setPaintMode(m_paintMode); - m_mousePicker->setRadius(m_mousePickRadius); - m_mousePicker->setMaskNodeIds(m_mousePickMaskNodeIds); + if (nullptr == m_vertexColorVoxelGrid) { + m_vertexColorVoxelGrid = new VoxelGrid(); + } + m_vertexColorPainter->setVoxelGrid(m_vertexColorVoxelGrid); + m_vertexColorPainter->setPaintMode(m_paintMode); + m_vertexColorPainter->setRadius(m_mousePickRadius); + m_vertexColorPainter->setMaskNodeIds(m_mousePickMaskNodeIds); } - m_mousePicker->moveToThread(thread); - connect(thread, &QThread::started, m_mousePicker, &MousePicker::process); - connect(m_mousePicker, &MousePicker::finished, this, &Document::mouseTargetReady); - connect(m_mousePicker, &MousePicker::finished, thread, &QThread::quit); + m_vertexColorPainter->moveToThread(thread); + connect(thread, &QThread::started, m_vertexColorPainter, &VertexColorPainter::process); + connect(m_vertexColorPainter, &VertexColorPainter::finished, this, &Document::vertexColorsReady); + connect(m_vertexColorPainter, &VertexColorPainter::finished, thread, &QThread::quit); connect(thread, &QThread::finished, thread, &QThread::deleteLater); thread->start(); } -void Document::mouseTargetReady() +void Document::vertexColorsReady() { - m_mouseTargetPosition = m_mousePicker->targetPosition(); - const auto &changedPartIds = m_mousePicker->changedPartIds(); - for (const auto &it: m_mousePicker->resultPaintImages()) { - const auto &partId = it.first; - if (changedPartIds.find(partId) == changedPartIds.end()) - continue; - const auto &imageId = it.second; - m_intermediatePaintImageIds.insert(imageId); - setPartDeformMapImageId(partId, imageId); + m_mouseTargetPosition = m_vertexColorPainter->targetPosition(); + + Model *model = m_vertexColorPainter->takePaintedModel(); + if (nullptr != model) { + delete m_paintedMesh; + m_paintedMesh = model; + emit paintedMeshChanged(); } - delete m_mousePicker; - m_mousePicker = nullptr; + delete m_vertexColorPainter; + m_vertexColorPainter = nullptr; if (!m_isMouseTargetResultObsolete && m_saveNextPaintSnapshot) { m_saveNextPaintSnapshot = false; @@ -3064,6 +3082,36 @@ void Document::setPartColorSolubility(QUuid partId, float solubility) emit skeletonChanged(); } +void Document::setPartMetalness(QUuid partId, float metalness) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + if (qFuzzyCompare(part->second.metalness, metalness)) + return; + part->second.metalness = metalness; + part->second.dirty = true; + emit partMetalnessChanged(partId); + emit skeletonChanged(); +} + +void Document::setPartRoughness(QUuid partId, float roughness) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + if (qFuzzyCompare(part->second.roughness, roughness)) + return; + part->second.roughness = roughness; + part->second.dirty = true; + emit partRoughnessChanged(partId); + emit skeletonChanged(); +} + void Document::setPartHollowThickness(QUuid partId, float hollowThickness) { auto part = partMap.find(partId); @@ -4086,19 +4134,11 @@ void Document::startPaint(void) void Document::stopPaint(void) { - if (m_mousePicker || m_isMouseTargetResultObsolete) { + if (m_vertexColorPainter || m_isMouseTargetResultObsolete) { m_saveNextPaintSnapshot = true; return; } - saveSnapshot(); - for (const auto &it: partMap) { - m_intermediatePaintImageIds.erase(it.second.deformMapImageId); - } - for (const auto &it: m_intermediatePaintImageIds) { - //qDebug() << "Remove intermediate image:" << it; - ImageForever::remove(it); - } - m_intermediatePaintImageIds.clear(); + //saveSnapshot(); } void Document::setMousePickMaskNodeIds(const std::set &nodeIds) diff --git a/src/document.h b/src/document.h index 2efd8bc5..30dd674d 100644 --- a/src/document.h +++ b/src/document.h @@ -31,11 +31,12 @@ #include "proceduralanimation.h" #include "componentlayer.h" #include "clothforce.h" +#include "voxelgrid.h" +#include "vertexcolorpainter.h" class MaterialPreviewsGenerator; class MotionsGenerator; class ScriptRunner; -class MousePicker; class HistoryItem { @@ -437,6 +438,7 @@ signals: void edgeReversed(QUuid edgeId); void partPreviewChanged(QUuid partId); void resultMeshChanged(); + void paintedMeshChanged(); void turnaroundChanged(); void editModeChanged(); void paintModeChanged(); @@ -466,6 +468,8 @@ signals: void partChamferStateChanged(QUuid partId); void partTargetChanged(QUuid partId); void partColorSolubilityChanged(QUuid partId); + void partMetalnessChanged(QUuid partId); + void partRoughnessChanged(QUuid partId); void partHollowThicknessChanged(QUuid partId); void partCountershadeStateChanged(QUuid partId); void partGridStateChanged(QUuid partId); @@ -537,6 +541,9 @@ public: // need initialize RigType rigType; bool weldEnabled; PolyCount polyCount; + QColor brushColor; + float brushMetalness = Model::m_defaultMetalness; + float brushRoughness = Model::m_defaultRoughness; public: Document(); ~Document(); @@ -576,6 +583,7 @@ public: const Pose *findPose(QUuid poseId) const; const Motion *findMotion(QUuid motionId) const; Model *takeResultMesh(); + Model *takePaintedMesh(); bool isMeshGenerationSucceed(); Model *takeResultTextureMesh(); Model *takeResultRigWeightMesh(); @@ -646,8 +654,8 @@ public slots: void generateMotions(); void motionsReady(); void pickMouseTarget(const QVector3D &nearPosition, const QVector3D &farPosition); - void doPickMouseTarget(); - void mouseTargetReady(); + void paintVertexColors(); + void vertexColorsReady(); void setPartLockState(QUuid partId, bool locked); void setPartVisibleState(QUuid partId, bool visible); void setPartSubdivState(QUuid partId, bool subdived); @@ -668,6 +676,8 @@ public slots: void setPartChamferState(QUuid partId, bool chamfered); void setPartTarget(QUuid partId, PartTarget target); void setPartColorSolubility(QUuid partId, float solubility); + void setPartMetalness(QUuid partId, float metalness); + void setPartRoughness(QUuid partId, float roughness); void setPartHollowThickness(QUuid partId, float hollowThickness); void setPartCountershaded(QUuid partId, bool countershaded); void setComponentCombineMode(QUuid componentId, CombineMode combineMode); @@ -774,6 +784,7 @@ private: // need initialize bool m_isResultMeshObsolete; MeshGenerator *m_meshGenerator; Model *m_resultMesh; + Model *m_paintedMesh; std::map *m_resultMeshCutFaceTransforms; std::map> *m_resultMeshNodesCutFaces; bool m_isMeshGenerationSucceed; @@ -805,11 +816,12 @@ private: // need initialize std::map> m_mergedVariables; ScriptRunner *m_scriptRunner; bool m_isScriptResultObsolete; - MousePicker *m_mousePicker; + VertexColorPainter *m_vertexColorPainter; bool m_isMouseTargetResultObsolete; PaintMode m_paintMode; float m_mousePickRadius; bool m_saveNextPaintSnapshot; + VoxelGrid *m_vertexColorVoxelGrid; private: static unsigned long m_maxSnapshot; std::deque m_undoItems; @@ -823,7 +835,6 @@ private: QString m_scriptConsoleLog; QString m_script; std::set m_mousePickMaskNodeIds; - std::set m_intermediatePaintImageIds; }; #endif diff --git a/src/documentwindow.cpp b/src/documentwindow.cpp index b80ec8f7..b6e53c40 100644 --- a/src/documentwindow.cpp +++ b/src/documentwindow.cpp @@ -162,7 +162,8 @@ DocumentWindow::DocumentWindow() : m_exportPreviewWidget(nullptr), m_preferencesWidget(nullptr), m_isLastMeshGenerationSucceed(true), - m_currentUpdatedMeshId(0) + m_currentUpdatedMeshId(0), + m_colorWheelWidget(nullptr) { QObject::connect((QtSingleApplication *)QGuiApplication::instance(), &QtSingleApplication::messageReceived, this, [this](const QString &message) { @@ -201,9 +202,9 @@ DocumentWindow::DocumentWindow() : //markerButton->setToolTip(tr("Marker pen")); //Theme::initAwesomeButton(markerButton); - QPushButton *paintButton = new QPushButton(QChar(fa::paintbrush)); - paintButton->setToolTip(tr("Paint brush")); - Theme::initAwesomeButton(paintButton); + //QPushButton *paintButton = new QPushButton(QChar(fa::paintbrush)); + //paintButton->setToolTip(tr("Paint brush")); + //Theme::initAwesomeButton(paintButton); //QPushButton *dragButton = new QPushButton(QChar(fa::handrocko)); //dragButton->setToolTip(tr("Enter drag mode")); @@ -269,6 +270,10 @@ DocumentWindow::DocumentWindow() : updateRegenerateIconAndTips(regenerateButton, m_document->isMeshGenerationSucceed()); generatePartPreviewImages(); }); + connect(m_document, &Document::paintedMeshChanged, [=]() { + auto paintedMesh = m_document->takePaintedMesh(); + m_modelRenderWidget->updateMesh(paintedMesh); + }); connect(m_document, &Document::postProcessing, this, [=]() { regenerateButton->showSpinner(true); }); @@ -287,7 +292,7 @@ DocumentWindow::DocumentWindow() : toolButtonLayout->addWidget(addButton); toolButtonLayout->addWidget(selectButton); //toolButtonLayout->addWidget(markerButton); - toolButtonLayout->addWidget(paintButton); + //toolButtonLayout->addWidget(paintButton); //toolButtonLayout->addWidget(dragButton); toolButtonLayout->addWidget(zoomInButton); toolButtonLayout->addWidget(zoomOutButton); @@ -392,16 +397,80 @@ DocumentWindow::DocumentWindow() : setTabPosition(Qt::RightDockWidgetArea, QTabWidget::East); - QDockWidget *partTreeDocker = new QDockWidget(tr("Parts"), this); - partTreeDocker->setAllowedAreas(Qt::RightDockWidgetArea); - m_partTreeWidget = new PartTreeWidget(m_document, partTreeDocker); - partTreeDocker->setWidget(m_partTreeWidget); - addDockWidget(Qt::RightDockWidgetArea, partTreeDocker); - //connect(partTreeDocker, &QDockWidget::topLevelChanged, [=](bool topLevel) { - // Q_UNUSED(topLevel); - // for (const auto &part: m_document->partMap) - // m_partTreeWidget->partPreviewChanged(part.first); - //}); + QDockWidget *partsDocker = new QDockWidget(tr("Parts"), this); + partsDocker->setAllowedAreas(Qt::RightDockWidgetArea); + m_colorWheelWidget = new color_widgets::ColorWheel(nullptr); + m_colorWheelWidget->setContentsMargins(0, 5, 0, 5); + m_colorWheelWidget->hide(); + m_document->brushColor = m_colorWheelWidget->color(); + connect(m_colorWheelWidget, &color_widgets::ColorWheel::colorChanged, this, [=](QColor color) { + m_document->brushColor = color; + }); + + FloatNumberWidget *metalnessWidget = new FloatNumberWidget; + metalnessWidget->setSliderFixedWidth(Theme::sidebarPreferredWidth * 0.4); + metalnessWidget->setItemName(tr("Metallic")); + metalnessWidget->setRange(0.0, 1.0); + metalnessWidget->setValue(m_document->brushMetalness); + + connect(metalnessWidget, &FloatNumberWidget::valueChanged, [=](float value) { + m_document->brushMetalness = value; + }); + + QPushButton *metalnessEraser = new QPushButton(QChar(fa::eraser)); + Theme::initAwesomeToolButtonWithoutFont(metalnessEraser); + + connect(metalnessEraser, &QPushButton::clicked, [=]() { + metalnessWidget->setValue(Model::m_defaultMetalness); + }); + + QHBoxLayout *metalnessLayout = new QHBoxLayout; + metalnessLayout->addWidget(metalnessEraser); + metalnessLayout->addWidget(metalnessWidget); + + FloatNumberWidget *roughnessWidget = new FloatNumberWidget; + roughnessWidget->setSliderFixedWidth(Theme::sidebarPreferredWidth * 0.35); + roughnessWidget->setItemName(tr("Roughness")); + roughnessWidget->setRange(0.0, 1.0); + roughnessWidget->setValue(m_document->brushRoughness); + + connect(roughnessWidget, &FloatNumberWidget::valueChanged, [=](float value) { + m_document->brushRoughness = value; + }); + + QPushButton *roughnessEraser = new QPushButton(QChar(fa::eraser)); + Theme::initAwesomeToolButtonWithoutFont(roughnessEraser); + + connect(roughnessEraser, &QPushButton::clicked, [=]() { + roughnessWidget->setValue(Model::m_defaultRoughness); + }); + + QHBoxLayout *roughnessLayout = new QHBoxLayout; + roughnessLayout->addWidget(roughnessEraser); + roughnessLayout->addWidget(roughnessWidget); + + QWidget *metalnessAndRoughnessWidget = new QWidget; + QVBoxLayout *metalnessAndRoughnessLayout = new QVBoxLayout; + metalnessAndRoughnessLayout->addLayout(metalnessLayout); + metalnessAndRoughnessLayout->addLayout(roughnessLayout); + metalnessAndRoughnessWidget->setLayout(metalnessAndRoughnessLayout); + metalnessAndRoughnessWidget->hide(); + + connect(m_document, &Document::editModeChanged, this, [=]() { + m_colorWheelWidget->setVisible(SkeletonDocumentEditMode::Paint == m_document->editMode); + metalnessAndRoughnessWidget->setVisible(SkeletonDocumentEditMode::Paint == m_document->editMode); + }); + + m_partTreeWidget = new PartTreeWidget(m_document, nullptr); + QWidget *partsWidget = new QWidget(partsDocker); + QVBoxLayout *partsLayout = new QVBoxLayout; + partsLayout->setContentsMargins(0, 0, 0, 0); + partsLayout->addWidget(m_colorWheelWidget); + partsLayout->addWidget(metalnessAndRoughnessWidget); + partsLayout->addWidget(m_partTreeWidget); + partsWidget->setLayout(partsLayout); + partsDocker->setWidget(partsWidget); + addDockWidget(Qt::RightDockWidgetArea, partsDocker); QDockWidget *materialDocker = new QDockWidget(tr("Materials"), this); materialDocker->setAllowedAreas(Qt::RightDockWidgetArea); @@ -453,13 +522,13 @@ DocumentWindow::DocumentWindow() : scriptDocker->setWidget(scriptWidget); addDockWidget(Qt::RightDockWidgetArea, scriptDocker); - tabifyDockWidget(partTreeDocker, materialDocker); + tabifyDockWidget(partsDocker, materialDocker); tabifyDockWidget(materialDocker, rigDocker); tabifyDockWidget(rigDocker, poseDocker); tabifyDockWidget(poseDocker, motionDocker); tabifyDockWidget(motionDocker, scriptDocker); - partTreeDocker->raise(); + partsDocker->raise(); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->setSpacing(0); @@ -829,8 +898,8 @@ DocumentWindow::DocumentWindow() : m_showPartsListAction = new QAction(tr("Parts"), this); connect(m_showPartsListAction, &QAction::triggered, [=]() { - partTreeDocker->show(); - partTreeDocker->raise(); + partsDocker->show(); + partsDocker->raise(); }); m_windowMenu->addAction(m_showPartsListAction); @@ -955,9 +1024,9 @@ DocumentWindow::DocumentWindow() : // m_document->setEditMode(SkeletonDocumentEditMode::Mark); //}); - connect(paintButton, &QPushButton::clicked, [=]() { - m_document->setEditMode(SkeletonDocumentEditMode::Paint); - }); + //connect(paintButton, &QPushButton::clicked, [=]() { + // m_document->setEditMode(SkeletonDocumentEditMode::Paint); + //}); //connect(dragButton, &QPushButton::clicked, [=]() { // m_document->setEditMode(SkeletonDocumentEditMode::Drag); @@ -992,8 +1061,8 @@ DocumentWindow::DocumentWindow() : m_partListDockerVisibleSwitchConnection = connect(m_document, &Document::skeletonChanged, [=]() { if (m_graphicsWidget->hasItems()) { - if (partTreeDocker->isHidden()) - partTreeDocker->show(); + if (partsDocker->isHidden()) + partsDocker->show(); disconnect(m_partListDockerVisibleSwitchConnection); } }); @@ -1147,6 +1216,8 @@ DocumentWindow::DocumentWindow() : connect(m_document, &Document::partHollowThicknessChanged, m_partTreeWidget, &PartTreeWidget::partHollowThicknessChanged); connect(m_document, &Document::partMaterialIdChanged, m_partTreeWidget, &PartTreeWidget::partMaterialIdChanged); connect(m_document, &Document::partColorSolubilityChanged, m_partTreeWidget, &PartTreeWidget::partColorSolubilityChanged); + connect(m_document, &Document::partMetalnessChanged, m_partTreeWidget, &PartTreeWidget::partMetalnessChanged); + connect(m_document, &Document::partRoughnessChanged, m_partTreeWidget, &PartTreeWidget::partRoughnessChanged); connect(m_document, &Document::partCountershadeStateChanged, m_partTreeWidget, &PartTreeWidget::partCountershadeStateChanged); connect(m_document, &Document::partTargetChanged, m_partTreeWidget, &PartTreeWidget::partXmirrorStateChanged); diff --git a/src/documentwindow.h b/src/documentwindow.h index dc045e73..29c63a7d 100644 --- a/src/documentwindow.h +++ b/src/documentwindow.h @@ -21,6 +21,7 @@ #include "normalanddepthmapsgenerator.h" #include "autosaver.h" #include "partpreviewimagesgenerator.h" +#include "QtColorWidgets/ColorWheel" class SkeletonGraphicsWidget; class PartTreeWidget; @@ -116,6 +117,7 @@ private: bool m_isLastMeshGenerationSucceed; quint64 m_currentUpdatedMeshId; QStringList m_waitingForExportToFilenames; + color_widgets::ColorWheel *m_colorWheelWidget; private: QString m_currentFilename; diff --git a/src/floatnumberwidget.cpp b/src/floatnumberwidget.cpp index 0988fdde..c7284e9c 100644 --- a/src/floatnumberwidget.cpp +++ b/src/floatnumberwidget.cpp @@ -34,6 +34,11 @@ FloatNumberWidget::FloatNumberWidget(QWidget *parent, bool singleLine) : } } +void FloatNumberWidget::setSliderFixedWidth(float width) +{ + m_slider->setFixedWidth(width); +} + void FloatNumberWidget::updateValueLabel(float value) { QString valueString = QString().sprintf("%.2f", value); diff --git a/src/floatnumberwidget.h b/src/floatnumberwidget.h index 1913bc26..7d841a91 100644 --- a/src/floatnumberwidget.h +++ b/src/floatnumberwidget.h @@ -9,10 +9,11 @@ class FloatNumberWidget : public QWidget { Q_OBJECT public: - explicit FloatNumberWidget(QWidget *parent = nullptr, bool singleLine=true); + explicit FloatNumberWidget(QWidget *parent=nullptr, bool singleLine=true); void setRange(float min, float max); float value() const; void setItemName(const QString &name); + void setSliderFixedWidth(float width); public slots: void increaseValue(); diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index 85cda07c..779e8953 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -416,6 +416,16 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString, if (!colorSolubilityString.isEmpty()) colorSolubility = colorSolubilityString.toFloat(); + float metalness = 0; + QString metalnessString = valueOfKeyInMapOrEmpty(part, "metalness"); + if (!metalnessString.isEmpty()) + metalness = metalnessString.toFloat(); + + float roughness = 1.0; + QString roughnessString = valueOfKeyInMapOrEmpty(part, "roughness"); + if (!roughnessString.isEmpty()) + roughness = roughnessString.toFloat(); + QUuid fillMeshFileId; QString fillMeshString = valueOfKeyInMapOrEmpty(part, "fillMesh"); if (!fillMeshString.isEmpty()) { @@ -538,6 +548,8 @@ MeshCombiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdString, outcomeNode.materialId = materialId; outcomeNode.countershaded = countershaded; outcomeNode.colorSolubility = colorSolubility; + outcomeNode.metalness = metalness; + outcomeNode.roughness = roughness; outcomeNode.boneMark = nodeInfo.boneMark; if (!__mirroredByPartId.isEmpty()) outcomeNode.mirroredByPartId = QUuid(__mirroredByPartId); diff --git a/src/model.cpp b/src/model.cpp index cd88b9b6..3a4cc226 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -5,8 +5,6 @@ #include "model.h" #include "version.h" -#define MAX_VERTICES_PER_FACE 100 - float Model::m_defaultMetalness = 0.0; float Model::m_defaultRoughness = 1.0; diff --git a/src/modelmeshbinder.cpp b/src/modelmeshbinder.cpp index 2588bfe5..4eef98f3 100644 --- a/src/modelmeshbinder.cpp +++ b/src/modelmeshbinder.cpp @@ -156,18 +156,22 @@ void ModelMeshBinder::paint(ModelShaderProgram *program) (m_hasMetalnessMap || m_hasRoughnessMap || m_hasAmbientOcclusionMap)) m_metalnessRoughnessAmbientOcclusionMap = new QOpenGLTexture(*m_mesh->metalnessRoughnessAmbientOcclusionImage()); - delete m_environmentIrradianceMap; - m_environmentIrradianceMap = nullptr; - delete m_environmentSpecularMap; - m_environmentSpecularMap = nullptr; + //delete m_environmentIrradianceMap; + //m_environmentIrradianceMap = nullptr; + //delete m_environmentSpecularMap; + //m_environmentSpecularMap = nullptr; if (program->isCoreProfile() && - m_environmentLightEnabled && - (m_hasMetalnessMap || m_hasRoughnessMap)) { - DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds"); - m_environmentIrradianceMap = irradianceFile.createOpenGLTexture(); + m_environmentLightEnabled/* && + (m_hasMetalnessMap || m_hasRoughnessMap)*/) { + if (nullptr == m_environmentIrradianceMap) { + DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds"); + m_environmentIrradianceMap = irradianceFile.createOpenGLTexture(); + } - DdsFileReader specularFile(":/resources/cedar_bridge_specular.dds"); - m_environmentSpecularMap = specularFile.createOpenGLTexture(); + if (nullptr == m_environmentSpecularMap) { + DdsFileReader specularFile(":/resources/cedar_bridge_specular.dds"); + m_environmentSpecularMap = specularFile.createOpenGLTexture(); + } } { diff --git a/src/mousepicker.cpp b/src/mousepicker.cpp deleted file mode 100644 index c6ac617b..00000000 --- a/src/mousepicker.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "mousepicker.h" -#include "util.h" -#include "imageforever.h" - -MousePicker::MousePicker(const Outcome &outcome, const QVector3D &mouseRayNear, const QVector3D &mouseRayFar) : - m_outcome(outcome), - m_mouseRayNear(mouseRayNear), - m_mouseRayFar(mouseRayFar) -{ -} - -const std::set &MousePicker::changedPartIds() -{ - return m_changedPartIds; -} - -void MousePicker::setPaintMode(PaintMode paintMode) -{ - m_paintMode = paintMode; -} - -void MousePicker::setMaskNodeIds(const std::set &nodeIds) -{ - m_mousePickMaskNodeIds = nodeIds; -} - -void MousePicker::setRadius(float radius) -{ - m_radius = radius; -} - -MousePicker::~MousePicker() -{ -} - -bool MousePicker::calculateMouseModelPosition(QVector3D &mouseModelPosition) -{ - bool foundPosition = false; - auto ray = (m_mouseRayNear - m_mouseRayFar).normalized(); - float minDistance2 = std::numeric_limits::max(); - for (size_t i = 0; i < m_outcome.triangles.size(); ++i) { - const auto &triangleIndices = m_outcome.triangles[i]; - std::vector triangle = { - m_outcome.vertices[triangleIndices[0]], - m_outcome.vertices[triangleIndices[1]], - m_outcome.vertices[triangleIndices[2]], - }; - const auto &triangleNormal = m_outcome.triangleNormals[i]; - if (QVector3D::dotProduct(triangleNormal, ray) <= 0) - continue; - QVector3D intersection; - if (intersectSegmentAndTriangle(m_mouseRayNear, m_mouseRayFar, - triangle, - triangleNormal, - &intersection)) { - float distance2 = (intersection - m_mouseRayNear).lengthSquared(); - if (distance2 < minDistance2) { - mouseModelPosition = intersection; - minDistance2 = distance2; - foundPosition = true; - } - } - } - return foundPosition; -} - -void MousePicker::pick() -{ - if (!calculateMouseModelPosition(m_targetPosition)) - return; - - if (PaintMode::None == m_paintMode) - return; - - float distance2 = m_radius * m_radius; - - for (const auto &map: m_outcome.paintMaps) { - for (const auto &node: map.paintNodes) { - if (!m_mousePickMaskNodeIds.empty() && m_mousePickMaskNodeIds.find(node.originNodeId) == m_mousePickMaskNodeIds.end()) - continue; - size_t intersectedNum = 0; - QVector3D sumOfDirection; - QVector3D referenceDirection = (m_targetPosition - node.origin).normalized(); - float sumOfRadius = 0; - for (const auto &vertexPosition: node.vertices) { - // >0.866 = <30 degrees - auto direction = (vertexPosition - node.origin).normalized(); - if (QVector3D::dotProduct(referenceDirection, direction) > 0.866 && - (vertexPosition - m_targetPosition).lengthSquared() <= distance2) { - float distance = vertexPosition.distanceToPoint(m_targetPosition); - float radius = (m_radius - distance) / node.radius; - sumOfRadius += radius; - sumOfDirection += direction * radius; - ++intersectedNum; - } - } - if (intersectedNum > 0) { - float paintRadius = sumOfRadius / intersectedNum; - QVector3D paintDirection = sumOfDirection.normalized(); - float degrees = angleInRangle360BetweenTwoVectors(node.baseNormal, paintDirection, node.direction); - float offset = (float)node.order / map.paintNodes.size(); - m_changedPartIds.insert(map.partId); - paintToImage(map.partId, offset, degrees / 360.0, paintRadius, PaintMode::Push == m_paintMode); - } - } - } -} - -void MousePicker::process() -{ - pick(); - emit finished(); -} - -void MousePicker::paintToImage(const QUuid &partId, float x, float y, float radius, bool inverted) -{ - QUuid oldImageId; - QImage image(72, 36, QImage::Format_Grayscale8); - image.fill(QColor(127, 127, 127)); - const auto &findImageId = m_paintImages.find(partId); - if (findImageId != m_paintImages.end()) { - const QImage *oldImage = ImageForever::get(findImageId->second); - if (nullptr != oldImage) { - if (oldImage->size() == image.size() && - oldImage->format() == image.format()) { - image = *oldImage; - } - } - } - float destX = image.width() * x; - float destY = image.height() * y; - float destRadius = image.height() * radius; - { - QRadialGradient gradient(destX, destY, destRadius / 2); - if (inverted) { - gradient.setColorAt(0, QColor(0, 0, 0, 3)); - gradient.setColorAt(1, Qt::transparent); - } else { - gradient.setColorAt(0, QColor(255, 255, 255, 3)); - gradient.setColorAt(1, Qt::transparent); - } - QBrush brush(gradient); - QPainter paint(&image); - paint.setRenderHint(QPainter::HighQualityAntialiasing); - paint.setBrush(brush); - paint.setPen(Qt::NoPen); - paint.drawEllipse(destX - destRadius / 2, destY - destRadius / 2, destRadius, destRadius); - } - QUuid imageId = ImageForever::add(&image); - m_paintImages[partId] = imageId; -} - -const QVector3D &MousePicker::targetPosition() -{ - return m_targetPosition; -} - -bool MousePicker::intersectSegmentAndPlane(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, - const QVector3D &pointOnPlane, const QVector3D &planeNormal, - QVector3D *intersection) -{ - auto u = segmentPoint1 - segmentPoint0; - auto w = segmentPoint0 - pointOnPlane; - auto d = QVector3D::dotProduct(planeNormal, u); - auto n = QVector3D::dotProduct(-planeNormal, w); - if (qAbs(d) < 0.00000001) - return false; - auto s = n / d; - if (s < 0 || s > 1 || qIsNaN(s) || qIsInf(s)) - return false; - if (nullptr != intersection) - *intersection = segmentPoint0 + s * u; - return true; -} - -bool MousePicker::intersectSegmentAndTriangle(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, - const std::vector &triangle, - const QVector3D &triangleNormal, - QVector3D *intersection) -{ - QVector3D possibleIntersection; - if (!intersectSegmentAndPlane(segmentPoint0, segmentPoint1, - triangle[0], triangleNormal, &possibleIntersection)) { - return false; - } - auto ray = (segmentPoint0 - segmentPoint1).normalized(); - std::vector normals; - for (size_t i = 0; i < 3; ++i) { - size_t j = (i + 1) % 3; - normals.push_back(QVector3D::normal(possibleIntersection, triangle[i], triangle[j])); - } - if (QVector3D::dotProduct(normals[0], ray) <= 0) - return false; - if (QVector3D::dotProduct(normals[0], normals[1]) <= 0) - return false; - if (QVector3D::dotProduct(normals[0], normals[2]) <= 0) - return false; - if (nullptr != intersection) - *intersection = possibleIntersection; - return true; -} - -void MousePicker::setPaintImages(const std::map &paintImages) -{ - m_paintImages = paintImages; -} - -const std::map &MousePicker::resultPaintImages() -{ - return m_paintImages; -} diff --git a/src/mousepicker.h b/src/mousepicker.h deleted file mode 100644 index cda52148..00000000 --- a/src/mousepicker.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef DUST3D_MOUSE_PICKER_H -#define DUST3D_MOUSE_PICKER_H -#include -#include -#include -#include -#include -#include "outcome.h" -#include "paintmode.h" - -class MousePicker : public QObject -{ - Q_OBJECT -public: - MousePicker(const Outcome &outcome, const QVector3D &mouseRayNear, const QVector3D &mouseRayFar); - void setRadius(float radius); - void setPaintImages(const std::map &paintImages); - void setPaintMode(PaintMode paintMode); - void setMaskNodeIds(const std::set &nodeIds); - const std::map &resultPaintImages(); - const std::set &changedPartIds(); - - ~MousePicker(); - const QVector3D &targetPosition(); -signals: - void finished(); -public slots: - void process(); - void pick(); -private: - float m_radius = 0.0; - std::map m_paintImages; - PaintMode m_paintMode = PaintMode::None; - std::set m_changedPartIds; - std::set m_mousePickMaskNodeIds; - bool m_enablePaint = false; - Outcome m_outcome; - QVector3D m_mouseRayNear; - QVector3D m_mouseRayFar; - QVector3D m_targetPosition; - static bool intersectSegmentAndPlane(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, - const QVector3D &pointOnPlane, const QVector3D &planeNormal, - QVector3D *intersection=nullptr); - static bool intersectSegmentAndTriangle(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, - const std::vector &triangle, - const QVector3D &triangleNormal, - QVector3D *intersection=nullptr); - bool calculateMouseModelPosition(QVector3D &mouseModelPosition); - void paintToImage(const QUuid &partId, float x, float y, float radius, bool inverted=false); -}; - -#endif diff --git a/src/outcome.h b/src/outcome.h index d50222e0..59efb178 100644 --- a/src/outcome.h +++ b/src/outcome.h @@ -19,6 +19,8 @@ struct OutcomeNode float radius = 0; QColor color; float colorSolubility = 0; + float metalness = 0; + float roughness = 1.0; QUuid materialId; bool countershaded = false; QUuid mirrorFromPartId; diff --git a/src/partpreviewimagesgenerator.cpp b/src/partpreviewimagesgenerator.cpp index 3ffa2db5..cc8dcbd4 100644 --- a/src/partpreviewimagesgenerator.cpp +++ b/src/partpreviewimagesgenerator.cpp @@ -28,6 +28,7 @@ void PartPreviewImagesGenerator::generate() m_offscreenRender->setZRotation(0); m_offscreenRender->setEyePosition(QVector3D(0, 0, -4.0)); + m_offscreenRender->enableEnvironmentLight(); m_offscreenRender->setRenderPurpose(0); for (auto &it: m_partPreviews) { if (it.second.isCutFace) { diff --git a/src/parttreewidget.cpp b/src/parttreewidget.cpp index 32f3570f..9c4c0511 100644 --- a/src/parttreewidget.cpp +++ b/src/parttreewidget.cpp @@ -1442,6 +1442,28 @@ void PartTreeWidget::partColorSolubilityChanged(QUuid partId) widget->updateColorButton(); } +void PartTreeWidget::partMetalnessChanged(QUuid partId) +{ + auto item = m_partItemMap.find(partId); + if (item == m_partItemMap.end()) { + qDebug() << "Part item not found:" << partId; + return; + } + PartWidget *widget = (PartWidget *)itemWidget(item->second, 0); + widget->updateColorButton(); +} + +void PartTreeWidget::partRoughnessChanged(QUuid partId) +{ + auto item = m_partItemMap.find(partId); + if (item == m_partItemMap.end()) { + qDebug() << "Part item not found:" << partId; + return; + } + PartWidget *widget = (PartWidget *)itemWidget(item->second, 0); + widget->updateColorButton(); +} + void PartTreeWidget::partCountershadeStateChanged(QUuid partId) { auto item = m_partItemMap.find(partId); diff --git a/src/parttreewidget.h b/src/parttreewidget.h index 3fbcf027..9f0d5b7e 100644 --- a/src/parttreewidget.h +++ b/src/parttreewidget.h @@ -79,6 +79,8 @@ public slots: void partHollowThicknessChanged(QUuid partId); void partMaterialIdChanged(QUuid partId); void partColorSolubilityChanged(QUuid partId); + void partMetalnessChanged(QUuid partId); + void partRoughnessChanged(QUuid partId); void partCountershadeStateChanged(QUuid partId); void partChecked(QUuid partId); void partUnchecked(QUuid partId); diff --git a/src/partwidget.cpp b/src/partwidget.cpp index 6e7c0f4d..c2214f61 100644 --- a/src/partwidget.cpp +++ b/src/partwidget.cpp @@ -177,6 +177,8 @@ PartWidget::PartWidget(const Document *document, QUuid partId) : connect(this, &PartWidget::setPartColorState, m_document, &Document::setPartColorState); connect(this, &PartWidget::setPartMaterialId, m_document, &Document::setPartMaterialId); connect(this, &PartWidget::setPartColorSolubility, m_document, &Document::setPartColorSolubility); + connect(this, &PartWidget::setPartMetalness, m_document, &Document::setPartMetalness); + connect(this, &PartWidget::setPartRoughness, m_document, &Document::setPartRoughness); connect(this, &PartWidget::setPartHollowThickness, m_document, &Document::setPartHollowThickness); connect(this, &PartWidget::setPartCountershaded, m_document, &Document::setPartCountershaded); connect(this, &PartWidget::checkPart, m_document, &Document::checkPart); @@ -469,10 +471,57 @@ void PartWidget::showColorSettingPopup(const QPoint &pos) colorSolubilityLayout->addWidget(colorSolubilityEraser); colorSolubilityLayout->addWidget(colorSolubilityWidget); + FloatNumberWidget *metalnessWidget = new FloatNumberWidget; + metalnessWidget->setItemName(tr("Metallic")); + metalnessWidget->setRange(0.0, 1.0); + metalnessWidget->setValue(part->metalness); + + connect(metalnessWidget, &FloatNumberWidget::valueChanged, [=](float value) { + emit setPartMetalness(m_partId, value); + emit groupOperationAdded(); + }); + + QPushButton *metalnessEraser = new QPushButton(QChar(fa::eraser)); + initToolButton(metalnessEraser); + + connect(metalnessEraser, &QPushButton::clicked, [=]() { + metalnessWidget->setValue(0.0); + emit groupOperationAdded(); + }); + + QHBoxLayout *metalnessLayout = new QHBoxLayout; + metalnessLayout->addWidget(metalnessEraser); + metalnessLayout->addWidget(metalnessWidget); + + FloatNumberWidget *roughnessWidget = new FloatNumberWidget; + roughnessWidget->setItemName(tr("Roughness")); + roughnessWidget->setRange(0.0, 1.0); + roughnessWidget->setValue(part->roughness); + + connect(roughnessWidget, &FloatNumberWidget::valueChanged, [=](float value) { + emit setPartRoughness(m_partId, value); + emit groupOperationAdded(); + }); + + QPushButton *roughnessEraser = new QPushButton(QChar(fa::eraser)); + initToolButton(roughnessEraser); + + connect(roughnessEraser, &QPushButton::clicked, [=]() { + roughnessWidget->setValue(1.0); + emit groupOperationAdded(); + }); + + QHBoxLayout *roughnessLayout = new QHBoxLayout; + roughnessLayout->addWidget(roughnessEraser); + roughnessLayout->addWidget(roughnessWidget); + QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(colorLayout); mainLayout->addLayout(colorTransparencyLayout); mainLayout->addLayout(colorSolubilityLayout); + mainLayout->addWidget(Theme::createHorizontalLineWidget()); + mainLayout->addLayout(metalnessLayout); + mainLayout->addLayout(roughnessLayout); if (m_document->materialIdList.empty()) { InfoLabel *infoLabel = new InfoLabel; @@ -861,10 +910,16 @@ void PartWidget::updateColorButton() qDebug() << "Part not found:" << m_partId; return; } - if (part->hasColor || part->materialAdjusted() || part->colorSolubilityAdjusted() || part->countershaded) + if (part->hasColor || + part->materialAdjusted() || + part->colorSolubilityAdjusted() || + part->countershaded || + part->metalnessAdjusted() || + part->roughnessAdjusted()) { updateButton(m_colorButton, QChar(fa::eyedropper), true, part->hasColorFunction()); - else + } else { updateButton(m_colorButton, QChar(fa::eyedropper), false, part->hasColorFunction()); + } } void PartWidget::updateCutRotationButton() diff --git a/src/partwidget.h b/src/partwidget.h index dda750f7..1d703e24 100644 --- a/src/partwidget.h +++ b/src/partwidget.h @@ -28,6 +28,8 @@ signals: void setPartCutFaceLinkedId(QUuid partId, QUuid linkedId); void setPartMaterialId(QUuid partId, QUuid materialId); void setPartColorSolubility(QUuid partId, float colorSolubility); + void setPartMetalness(QUuid partId, float metalness); + void setPartRoughness(QUuid partId, float roughness); void setPartHollowThickness(QUuid partId, float hollowThickness); void setPartCountershaded(QUuid partId, bool countershaded); void movePartUp(QUuid partId); diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp index 5c08cb47..6c60d3b9 100644 --- a/src/shortcuts.cpp +++ b/src/shortcuts.cpp @@ -27,7 +27,7 @@ void initShortCuts(QWidget *widget, SkeletonGraphicsWidget *graphicsWidget) defineKey(Qt::CTRL + Qt::Key_C, &SkeletonGraphicsWidget::shortcutCopy); defineKey(Qt::CTRL + Qt::Key_V, &SkeletonGraphicsWidget::shortcutPaste); defineKey(Qt::Key_S, &SkeletonGraphicsWidget::shortcutSelectMode); - defineKey(Qt::Key_D, &SkeletonGraphicsWidget::shortcutPaintMode); + //defineKey(Qt::Key_D, &SkeletonGraphicsWidget::shortcutPaintMode); defineKey(Qt::ALT + Qt::Key_Minus, &SkeletonGraphicsWidget::shortcutZoomRenderedModelByMinus10); defineKey(Qt::Key_Minus, &SkeletonGraphicsWidget::shortcutZoomSelectedByMinus1); defineKey(Qt::ALT + Qt::Key_Equal, &SkeletonGraphicsWidget::shortcutZoomRenderedModelBy10); diff --git a/src/skeletondocument.h b/src/skeletondocument.h index b269a707..d4be3b16 100644 --- a/src/skeletondocument.h +++ b/src/skeletondocument.h @@ -177,6 +177,8 @@ public: QUuid materialId; PartTarget target; float colorSolubility; + float metalness; + float roughness; float deformMapScale; QUuid deformMapImageId; float hollowThickness; @@ -204,6 +206,8 @@ public: cutFace(CutFace::Quad), target(PartTarget::Model), colorSolubility(0.0), + metalness(0.0), + roughness(1.0), deformMapScale(1.0), hollowThickness(0.0), countershaded(false), @@ -334,6 +338,14 @@ public: { return fabs(colorSolubility - 0.0) >= 0.01; } + bool metalnessAdjusted() const + { + return fabs(metalness - 0.0) >= 0.01; + } + bool roughnessAdjusted() const + { + return fabs(roughness - 1.0) >= 0.01; + } bool cutRotationAdjusted() const { return fabs(cutRotation - 0.0) >= 0.01; diff --git a/src/texturegenerator.cpp b/src/texturegenerator.cpp index e10c6cf9..e79e7562 100644 --- a/src/texturegenerator.cpp +++ b/src/texturegenerator.cpp @@ -248,6 +248,8 @@ void TextureGenerator::generate() std::map partColorMap; std::map, const OutcomeNode *> nodeMap; std::map partColorSolubilityMap; + std::map partMetalnessMap; + std::map partRoughnessMap; for (const auto &item: m_outcome->nodes) { if (!m_hasTransparencySettings) { if (!qFuzzyCompare(1.0, item.color.alphaF())) @@ -256,6 +258,8 @@ void TextureGenerator::generate() nodeMap.insert({{item.partId, item.nodeId}, &item}); partColorMap.insert({item.partId, item.color}); partColorSolubilityMap.insert({item.partId, item.colorSolubility}); + partMetalnessMap.insert({item.partId, item.metalness}); + partRoughnessMap.insert({item.partId, item.roughness}); } auto createImageBeginTime = countTimeConsumed.elapsed(); @@ -339,6 +343,56 @@ void TextureGenerator::generate() } } + for (const auto &it: partUvRects) { + const auto &partId = it.first; + const auto &rects = it.second; + auto findMetalnessResult = partMetalnessMap.find(partId); + if (findMetalnessResult != partMetalnessMap.end()) { + if (qFuzzyCompare(findMetalnessResult->second, (float)0.0)) + continue; + const auto &color = QColor(findMetalnessResult->second * 255, + findMetalnessResult->second * 255, + findMetalnessResult->second * 255); + QBrush brush(color); + float fillExpandSize = 2; + for (const auto &rect: rects) { + QRectF translatedRect = { + rect.left() * TextureGenerator::m_textureSize - fillExpandSize, + rect.top() * TextureGenerator::m_textureSize - fillExpandSize, + rect.width() * TextureGenerator::m_textureSize + fillExpandSize * 2, + rect.height() * TextureGenerator::m_textureSize + fillExpandSize * 2 + }; + textureMetalnessPainter.fillRect(translatedRect, brush); + hasMetalnessMap = true; + } + } + } + + for (const auto &it: partUvRects) { + const auto &partId = it.first; + const auto &rects = it.second; + auto findRoughnessResult = partRoughnessMap.find(partId); + if (findRoughnessResult != partRoughnessMap.end()) { + if (qFuzzyCompare(findRoughnessResult->second, (float)1.0)) + continue; + const auto &color = QColor(findRoughnessResult->second * 255, + findRoughnessResult->second * 255, + findRoughnessResult->second * 255); + QBrush brush(color); + float fillExpandSize = 2; + for (const auto &rect: rects) { + QRectF translatedRect = { + rect.left() * TextureGenerator::m_textureSize - fillExpandSize, + rect.top() * TextureGenerator::m_textureSize - fillExpandSize, + rect.width() * TextureGenerator::m_textureSize + fillExpandSize * 2, + rect.height() * TextureGenerator::m_textureSize + fillExpandSize * 2 + }; + textureRoughnessPainter.fillRect(translatedRect, brush); + hasRoughnessMap = true; + } + } + } + auto drawTexture = [&](const std::map> &map, QPainter &painter, bool useAlpha) { for (const auto &it: partUvRects) { const auto &partId = it.first; @@ -629,8 +683,10 @@ void TextureGenerator::generate() } hasNormalMap = !m_partNormalTextureMap.empty(); - hasMetalnessMap = !m_partMetalnessTextureMap.empty(); - hasRoughnessMap = !m_partRoughnessTextureMap.empty(); + if (!m_partMetalnessTextureMap.empty()) + hasMetalnessMap = true; + if (!m_partRoughnessTextureMap.empty()) + hasRoughnessMap = true; hasAmbientOcclusionMap = !m_partAmbientOcclusionTextureMap.empty(); auto paintTextureEndTime = countTimeConsumed.elapsed(); diff --git a/src/texturetype.h b/src/texturetype.h index 75ae2139..b6b3df14 100644 --- a/src/texturetype.h +++ b/src/texturetype.h @@ -25,7 +25,7 @@ QString TextureTypeToDispName(TextureType type) \ case TextureType::Normal: \ return QObject::tr("Normal Map"); \ case TextureType::Metalness: \ - return QObject::tr("Metalness"); \ + return QObject::tr("Metallic"); \ case TextureType::Roughness: \ return QObject::tr("Roughness"); \ case TextureType::AmbientOcclusion: \ diff --git a/src/util.cpp b/src/util.cpp index b150bcf1..58127c59 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -510,3 +510,87 @@ void saveAsObj(const char *filename, const std::vector &vertices, stream << endl; } } + +bool intersectSegmentAndPlane(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, + const QVector3D &pointOnPlane, const QVector3D &planeNormal, + QVector3D *intersection) +{ + auto u = segmentPoint1 - segmentPoint0; + auto w = segmentPoint0 - pointOnPlane; + auto d = QVector3D::dotProduct(planeNormal, u); + auto n = QVector3D::dotProduct(-planeNormal, w); + if (qAbs(d) < 0.00000001) + return false; + auto s = n / d; + if (s < 0 || s > 1 || qIsNaN(s) || qIsInf(s)) + return false; + if (nullptr != intersection) + *intersection = segmentPoint0 + s * u; + return true; +} + +bool intersectSegmentAndTriangle(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, + const std::vector &triangle, + const QVector3D &triangleNormal, + QVector3D *intersection) +{ + QVector3D possibleIntersection; + if (!intersectSegmentAndPlane(segmentPoint0, segmentPoint1, + triangle[0], triangleNormal, &possibleIntersection)) { + return false; + } + auto ray = (segmentPoint0 - segmentPoint1).normalized(); + std::vector normals; + for (size_t i = 0; i < 3; ++i) { + size_t j = (i + 1) % 3; + normals.push_back(QVector3D::normal(possibleIntersection, triangle[i], triangle[j])); + } + if (QVector3D::dotProduct(normals[0], ray) <= 0) + return false; + if (QVector3D::dotProduct(normals[0], normals[1]) <= 0) + return false; + if (QVector3D::dotProduct(normals[0], normals[2]) <= 0) + return false; + if (nullptr != intersection) + *intersection = possibleIntersection; + return true; +} + +bool intersectRayAndPolyhedron(const QVector3D &rayNear, + const QVector3D &rayFar, + const std::vector &vertices, + const std::vector> &triangles, + const std::vector &triangleNormals, + QVector3D *intersection) +{ + bool foundPosition = false; + auto ray = (rayNear - rayFar).normalized(); + float minDistance2 = std::numeric_limits::max(); + for (size_t i = 0; i < triangles.size(); ++i) { + const auto &triangleIndices = triangles[i]; + std::vector triangle = { + vertices[triangleIndices[0]], + vertices[triangleIndices[1]], + vertices[triangleIndices[2]], + }; + const auto &triangleNormal = triangleNormals[i]; + if (QVector3D::dotProduct(triangleNormal, ray) <= 0) + continue; + QVector3D point; + if (intersectSegmentAndTriangle(rayNear, rayFar, + triangle, + triangleNormal, + &point)) { + float distance2 = (point - rayNear).lengthSquared(); + if (distance2 < minDistance2) { + if (nullptr != intersection) + *intersection = point; + minDistance2 = distance2; + foundPosition = true; + } + } + } + return foundPosition; +} + + diff --git a/src/util.h b/src/util.h index 2b3f0fa3..c511525c 100644 --- a/src/util.h +++ b/src/util.h @@ -47,5 +47,18 @@ void subdivideFace2D(std::vector *face); QVector3D choosenBaseAxis(const QVector3D &layoutDirection); void saveAsObj(const char *filename, const std::vector &vertices, const std::vector> &faces); - +bool intersectSegmentAndPlane(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, + const QVector3D &pointOnPlane, const QVector3D &planeNormal, + QVector3D *intersection=nullptr); +bool intersectSegmentAndTriangle(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1, + const std::vector &triangle, + const QVector3D &triangleNormal, + QVector3D *intersection=nullptr); +bool intersectRayAndPolyhedron(const QVector3D &rayNear, + const QVector3D &rayFar, + const std::vector &vertices, + const std::vector> &triangles, + const std::vector &triangleNormals, + QVector3D *intersection=nullptr); + #endif diff --git a/src/vertexcolorpainter.cpp b/src/vertexcolorpainter.cpp new file mode 100644 index 00000000..e5842ca1 --- /dev/null +++ b/src/vertexcolorpainter.cpp @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include +#include +#include "vertexcolorpainter.h" +#include "util.h" +#include "imageforever.h" + +const int VertexColorPainter::m_gridSize = 4096; + +PaintColor operator+(const PaintColor &first, const PaintColor &second) +{ + float total = first.alphaF() + second.alphaF(); + if (qFuzzyIsNull(total)) + return PaintColor(255, 255, 255, 255); + float remaining = second.alphaF() / total; + float rate = 1.0 - remaining; + PaintColor color(first.red() * rate + second.red() * remaining, + first.green() * rate + second.green() * remaining, + first.blue() * rate + second.blue() * remaining); + color.metalness = first.metalness * rate + second.metalness * remaining; + color.roughness = first.roughness * rate + second.roughness * remaining; + return color; +} + +PaintColor operator-(const PaintColor &first, const PaintColor &second) +{ + PaintColor color = first; + color.setAlphaF(std::max(color.alphaF() - second.alphaF(), 0.0)); + return color; +} + +VertexColorPainter::VertexColorPainter(const Outcome &m_outcome, const QVector3D &mouseRayNear, const QVector3D &mouseRayFar) : + m_outcome(m_outcome), + m_mouseRayNear(mouseRayNear), + m_mouseRayFar(mouseRayFar) +{ +} + +Model *VertexColorPainter::takePaintedModel() +{ + Model *paintedModel = m_model; + m_model = nullptr; + return paintedModel; +} + +void VertexColorPainter::setVoxelGrid(VoxelGrid *voxelGrid) +{ + m_voxelGrid = voxelGrid; + m_voxelGrid->setNullValue(PaintColor(255, 255, 255, 255)); +} + +void VertexColorPainter::setPaintMode(PaintMode paintMode) +{ + m_paintMode = paintMode; +} + +void VertexColorPainter::setMaskNodeIds(const std::set &nodeIds) +{ + m_mousePickMaskNodeIds = nodeIds; +} + +void VertexColorPainter::setRadius(float radius) +{ + m_radius = radius; +} + +void VertexColorPainter::setBrushColor(const QColor &color) +{ + m_brushColor = color; +} + +void VertexColorPainter::setBrushMetalness(float value) +{ + m_brushMetalness = value; +} + +void VertexColorPainter::setBrushRoughness(float value) +{ + m_brushRoughness = value; +} + +VertexColorPainter::~VertexColorPainter() +{ + delete m_model; +} + +bool VertexColorPainter::calculateMouseModelPosition(QVector3D &mouseModelPosition) +{ + return intersectRayAndPolyhedron(m_mouseRayNear, + m_mouseRayFar, + m_outcome.vertices, + m_outcome.triangles, + m_outcome.triangleNormals, + &mouseModelPosition); +} + +void VertexColorPainter::paintToVoxelGrid() +{ + int voxelX = toVoxelLength(m_targetPosition.x()); + int voxelY = toVoxelLength(m_targetPosition.y()); + int voxelZ = toVoxelLength(m_targetPosition.z()); + int voxelRadius = toVoxelLength(m_radius); + int range2 = voxelRadius * voxelRadius; + PaintColor paintColor(m_brushColor); + paintColor.metalness = m_brushMetalness; + paintColor.roughness = m_brushRoughness; + m_voxelGrid->add(voxelX, voxelY, voxelZ, paintColor); + for (int i = -voxelRadius; i <= voxelRadius; ++i) { + qint8 x = voxelX + i; + int i2 = i * i; + for (int j = -voxelRadius; j <= voxelRadius; ++j) { + qint8 y = voxelY + j; + int j2 = j * j; + for (int k = -voxelRadius; k <= voxelRadius; ++k) { + qint8 z = voxelZ + k; + int k2 = k * k; + int dist2 = i2 + j2 + k2; + if (dist2 <= range2) { + int dist = std::sqrt(dist2); + float alpha = 1.0 - (float)dist / voxelRadius; + qDebug() << "alpha:" << alpha; + PaintColor color = paintColor; + color.setAlphaF(alpha); + m_voxelGrid->add(x, y, z, color); + } + } + } + } +} + +void VertexColorPainter::createPaintedModel() +{ + std::vector vertexColors(m_outcome.vertices.size()); + for (size_t i = 0; i < m_outcome.vertices.size(); ++i) { + const auto &position = m_outcome.vertices[i]; + int voxelX = toVoxelLength(position.x()); + int voxelY = toVoxelLength(position.y()); + int voxelZ = toVoxelLength(position.z()); + vertexColors[i] = m_voxelGrid->query(voxelX, voxelY, voxelZ); + } + + int triangleVertexCount = m_outcome.triangles.size() * 3; + ShaderVertex *triangleVertices = new ShaderVertex[triangleVertexCount]; + int destIndex = 0; + const auto triangleVertexNormals = m_outcome.triangleVertexNormals(); + const auto triangleVertexUvs = m_outcome.triangleVertexUvs(); + const auto triangleTangents = m_outcome.triangleTangents(); + const QVector3D defaultNormal = QVector3D(0, 0, 0); + const QVector2D defaultUv = QVector2D(0, 0); + const QVector3D defaultTangent = QVector3D(0, 0, 0); + for (size_t i = 0; i < m_outcome.triangles.size(); ++i) { + for (auto j = 0; j < 3; j++) { + int vertexIndex = m_outcome.triangles[i][j]; + const auto &vertexColor = &vertexColors[vertexIndex]; + const QVector3D *srcVert = &m_outcome.vertices[vertexIndex]; + const QVector3D *srcNormal = &defaultNormal; + if (triangleVertexNormals) + srcNormal = &(*triangleVertexNormals)[i][j]; + const QVector2D *srcUv = &defaultUv; + if (triangleVertexUvs) + srcUv = &(*triangleVertexUvs)[i][j]; + const QVector3D *srcTangent = &defaultTangent; + if (triangleTangents) + srcTangent = &(*triangleTangents)[i]; + ShaderVertex *dest = &triangleVertices[destIndex]; + dest->colorR = vertexColor->redF(); + dest->colorG = vertexColor->greenF(); + dest->colorB = vertexColor->blueF(); + dest->alpha = vertexColor->alphaF(); + dest->posX = srcVert->x(); + dest->posY = srcVert->y(); + dest->posZ = srcVert->z(); + dest->texU = srcUv->x(); + dest->texV = srcUv->y(); + dest->normX = srcNormal->x(); + dest->normY = srcNormal->y(); + dest->normZ = srcNormal->z(); + dest->metalness = vertexColor->metalness; + dest->roughness = vertexColor->roughness; + dest->tangentX = srcTangent->x(); + dest->tangentY = srcTangent->y(); + dest->tangentZ = srcTangent->z(); + destIndex++; + } + } + m_model = new Model(triangleVertices, triangleVertexCount); +} + +int VertexColorPainter::toVoxelLength(float length) +{ + int voxelLength = length * 100; + if (voxelLength > m_gridSize) + voxelLength = m_gridSize; + else if (voxelLength < -m_gridSize) + voxelLength = -m_gridSize; + return voxelLength; +} + +void VertexColorPainter::paint() +{ + if (!calculateMouseModelPosition(m_targetPosition)) + return; + + if (PaintMode::None == m_paintMode) + return; + + if (nullptr == m_voxelGrid) + return; + + paintToVoxelGrid(); + createPaintedModel(); +} + +void VertexColorPainter::process() +{ + paint(); + + emit finished(); +} + +const QVector3D &VertexColorPainter::targetPosition() +{ + return m_targetPosition; +} diff --git a/src/vertexcolorpainter.h b/src/vertexcolorpainter.h new file mode 100644 index 00000000..2ead83ea --- /dev/null +++ b/src/vertexcolorpainter.h @@ -0,0 +1,81 @@ +#ifndef DUST3D_VERTEX_COLOR_PAINTER_H +#define DUST3D_VERTEX_COLOR_PAINTER_H +#include +#include +#include +#include +#include +#include +#include "outcome.h" +#include "paintmode.h" +#include "voxelgrid.h" +#include "model.h" + +class PaintColor : public QColor +{ +public: + float metalness = Model::m_defaultMetalness; + float roughness = Model::m_defaultRoughness; + + PaintColor() : + QColor() + { + } + + PaintColor(int r, int g, int b, int a = 255) : + QColor(r, g, b, a) + { + } + + PaintColor(const QColor &color) : + QColor(color) + { + } +}; + +PaintColor operator+(const PaintColor &first, const PaintColor &second); +PaintColor operator-(const PaintColor &first, const PaintColor &second); + +class VertexColorPainter : public QObject +{ + Q_OBJECT +public: + VertexColorPainter(const Outcome &outcome, const QVector3D &mouseRayNear, const QVector3D &mouseRayFar); + void setRadius(float radius); + void setBrushColor(const QColor &color); + void setBrushMetalness(float value); + void setBrushRoughness(float value); + void setPaintMode(PaintMode paintMode); + void setMaskNodeIds(const std::set &nodeIds); + void setVoxelGrid(VoxelGrid *voxelGrid); + + ~VertexColorPainter(); + Model *takePaintedModel(); + const QVector3D &targetPosition(); +signals: + void finished(); +public slots: + void process(); + void paint(); +private: + float m_radius = 0.0; + PaintMode m_paintMode = PaintMode::None; + std::set m_mousePickMaskNodeIds; + Outcome m_outcome; + QVector3D m_mouseRayNear; + QVector3D m_mouseRayFar; + QVector3D m_targetPosition; + QColor m_brushColor; + float m_brushMetalness = Model::m_defaultMetalness; + float m_brushRoughness = Model::m_defaultRoughness; + VoxelGrid *m_voxelGrid = nullptr; + Model *m_model = nullptr; + bool calculateMouseModelPosition(QVector3D &mouseModelPosition); + void paintToVoxelGrid(); + int toVoxelLength(float length); + void createPaintedModel(); +public: + static const int m_gridSize; +}; + +#endif diff --git a/src/voxelgrid.cpp b/src/voxelgrid.cpp new file mode 100644 index 00000000..35bc5721 --- /dev/null +++ b/src/voxelgrid.cpp @@ -0,0 +1 @@ +#include "voxelgrid.h" diff --git a/src/voxelgrid.h b/src/voxelgrid.h new file mode 100644 index 00000000..e5e3012c --- /dev/null +++ b/src/voxelgrid.h @@ -0,0 +1,85 @@ +#ifndef DUST3D_VOXEL_GRID_H +#define DUST3D_VOXEL_GRID_H +#include +#include + +template +class VoxelGrid +{ +public: + struct Voxel + { + qint16 x; + qint16 y; + qint16 z; + }; + + struct VoxelHash + { + size_t operator()(const Voxel &voxel) const + { + return ((size_t)voxel.x ^ ((size_t)voxel.y << 1)) ^ (size_t)voxel.z; + } + }; + + struct VoxelEqual + { + bool operator()(const Voxel &left, const Voxel &right) const + { + return (left.x == right.x) && + (left.y == right.y) && + (left.z == right.z); + } + }; + + T query(qint16 x, qint16 y, qint16 z) + { + auto findResult = m_grid.find({x, y, z}); + if (findResult == m_grid.end()) + return m_nullValue; + return findResult->second; + } + + T add(qint16 x, qint16 y, qint16 z, T value) + { + auto insertResult = m_grid.insert(std::make_pair(Voxel {x, y, z}, value)); + if (insertResult.second) { + insertResult.first->second = m_nullValue + value; + return insertResult.first->second; + } + insertResult.first->second = insertResult.first->second + value; + return insertResult.first->second; + } + + T sub(qint16 x, qint16 y, qint16 z, T value) + { + auto findResult = m_grid.find({x, y, z}); + if (findResult == m_grid.end()) + return m_nullValue; + findResult->second = findResult->second - value; + if (findResult->second == m_nullValue) { + m_grid.erase(findResult); + return m_nullValue; + } + return findResult->second; + } + + void reset(qint16 x, qint16 y, qint16 z) + { + auto findResult = m_grid.find({x, y, z}); + if (findResult == m_grid.end()) + return; + m_grid.erase(findResult); + } + + void setNullValue(const T &nullValue) + { + m_nullValue = nullValue; + } + +private: + std::unordered_map m_grid; + T m_nullValue = T(); +}; + +#endif diff --git a/thirdparty/Qt-Color-Widgets/.gitignore b/thirdparty/Qt-Color-Widgets/.gitignore new file mode 100644 index 00000000..567609b1 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/thirdparty/Qt-Color-Widgets/CMakeLists.txt b/thirdparty/Qt-Color-Widgets/CMakeLists.txt new file mode 100644 index 00000000..25f65ee6 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/CMakeLists.txt @@ -0,0 +1,171 @@ +# +# Copyright (C) 2013-2020 Mattia Basaglia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# + + +cmake_minimum_required (VERSION 3.1 FATAL_ERROR) + +set(COLORWIDGET_PROJECT_NAME QtColorWidgets) +project(${COLORWIDGET_PROJECT_NAME} CXX) + + +set (CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules + ${CMAKE_CURRENT_LIST_DIR}) + + +include (CheckCXXCompilerFlag) + +include (cmake/install.cmake) +include (cmake/qt-configuration.cmake) +include (cmake/versioning.cmake) + + +SET (${COLORWIDGET_PROJECT_NAME}_VERSION_MAJOR 2) +SET (${COLORWIDGET_PROJECT_NAME}_VERSION_MINOR 1) +SET (${COLORWIDGET_PROJECT_NAME}_VERSION_PATCH 0) +SET (${COLORWIDGET_PROJECT_NAME}_VERSION "${${COLORWIDGET_PROJECT_NAME}_VERSION_MAJOR}.${${COLORWIDGET_PROJECT_NAME}_VERSION_MINOR}.${${COLORWIDGET_PROJECT_NAME}_VERSION_PATCH}") + + +set (QT_SUPPORTED_VERSIONS 5) + +select_qt ( + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + QT_DEFAULT_VERSION 5) + +set (REQUIRED_QT_COMPONENTS + Widgets + ) +find_qt ( + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + REQUIRED_COMPONENTS "${REQUIRED_QT_COMPONENTS}" + OPTIONAL_COMPONENTS "") + +# Auto generate moc files +set(CMAKE_AUTOMOC ON) +# Auto generate moc files +set(CMAKE_AUTOUIC ON) +# Auto generate moc files +set(CMAKE_AUTORCC ON) + + +option(BUILD_SHARED_LIBS "Build the shared library" ON) +option(BUILD_STATIC_LIBS "Build the static library" OFF) + +set (TARGET_NAME ${COLORWIDGET_PROJECT_NAME}) +set (TARGET_OUTPUT_SUFFIX "-Qt${QT_VERSION}${${COLORWIDGET_PROJECT_NAME}_VERSION_MAJOR}") +set (INCLUDE_PREFIX "QtColorWidgets") +set (COLOR_WIDGETS_LIBRARY "${TARGET_NAME}") + +if ( ${BUILD_STATIC_LIBS} ) + add_definitions(-DQTCOLORWIDGETS_STATICALLY_LINKED) +endif() + + +add_library (${TARGET_NAME} "") +set_target_properties(${TARGET_NAME} + PROPERTIES + EXPORT_NAME "${TARGET_NAME}${TARGET_OUTPUT_SUFFIX}") + + +set_target_properties (${TARGET_NAME} + PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + VERSION ${${COLORWIDGET_PROJECT_NAME}_VERSION} + SOVERSION ${${COLORWIDGET_PROJECT_NAME}_VERSION_MAJOR} + "INTERFACE_${COLORWIDGET_PROJECT_NAME}_MAJOR_VERSION" ${${COLORWIDGET_PROJECT_NAME}_VERSION_MAJOR} + COMPATIBLE_INTERFACE_STRING "${COLORWIDGET_PROJECT_NAME}_MAJOR_VERSION" + COMPILE_DEFINITIONS QTCOLORWIDGETS_LIBRARY + OUTPUT_NAME "${TARGET_NAME}${TARGET_OUTPUT_SUFFIX}") + +check_cxx_compiler_flag ("-Wall" Wall_FLAG_SUPPORTED) + +if (Wall_FLAG_SUPPORTED) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") +endif (Wall_FLAG_SUPPORTED) + +check_cxx_compiler_flag ("-pedantic" pedantic_FLAG_SUPPORTED) + +if (pedantic_FLAG_SUPPORTED) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pedantic") +endif (pedantic_FLAG_SUPPORTED) + +check_cxx_compiler_flag ("-Wextra" Wextra_FLAG_SUPPORTED) + +if (Wextra_FLAG_SUPPORTED) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wextra") +endif (Wextra_FLAG_SUPPORTED) + + +set (EXPORT_HEADER "${INCLUDE_PREFIX}/colorwidgets_global.hpp") + + +generate_versioning_information ( + TARGET_NAME ${TARGET_NAME} + EXPORT_HEADER ${EXPORT_HEADER} + EXPORT_MACRO QCP_EXPORT + VERSIONED_ENTITY ${COLORWIDGET_PROJECT_NAME} + INCLUDE_PREFIX ${INCLUDE_PREFIX} + COMPANY_NAME "Mattia Basaglia" + COMPANY_COPYRIGHT "Mattia Basaglia Copyright (C) 2013-2017" + FILE_DESCRIPTION "Color wheel widget and dialog for Qt${QT_VERSION}" +) + + +target_include_directories(${TARGET_NAME} + PUBLIC + $ + $ + PUBLIC + $ + $ + ) + + +add_subdirectory (${CMAKE_CURRENT_SOURCE_DIR}/include/${INCLUDE_PREFIX}) +add_subdirectory (${CMAKE_CURRENT_SOURCE_DIR}/resources/${INCLUDE_PREFIX}) +add_subdirectory (${CMAKE_CURRENT_SOURCE_DIR}/src/${INCLUDE_PREFIX}) + + +use_qt ( + TARGET_NAME ${TARGET_NAME} + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + REQUIRED_COMPONENTS "${REQUIRED_QT_COMPONENTS}" + OPTIONAL_COMPONENTS "") + + +install_project ( + PROJECT_NAME ${COLORWIDGET_PROJECT_NAME} + TARGET_NAME ${TARGET_NAME} + TARGET_OUTPUT_SUFFIX ${TARGET_OUTPUT_SUFFIX} + EXPORT_HEADER ${EXPORT_HEADER} + INCLUDE_PREFIX ${INCLUDE_PREFIX} + HEADER_MATCHING_REGEX "^.*\.h$|^.*\.hpp$|^.*$" + VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/${COLORWIDGET_PROJECT_NAME}_version.h + NAMESPACE "") + + +add_subdirectory (gallery) + +option(QTCOLORWIDGETS_DESIGNER_PLUGIN "Build QtDesigner plugin" ON) +if (${QTCOLORWIDGETS_DESIGNER_PLUGIN}) + find_package (Qt5Designer QUIET) + if (Qt5Designer_FOUND) + add_subdirectory (color_widgets_designer_plugin) + endif(Qt5Designer_FOUND) +endif() diff --git a/thirdparty/Qt-Color-Widgets/COPYING b/thirdparty/Qt-Color-Widgets/COPYING new file mode 100644 index 00000000..65c5ca88 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/thirdparty/Qt-Color-Widgets/LICENSE-EXCEPTION b/thirdparty/Qt-Color-Widgets/LICENSE-EXCEPTION new file mode 100644 index 00000000..06698128 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/LICENSE-EXCEPTION @@ -0,0 +1,14 @@ +Linking this library statically or dynamically with other modules is making a +combined work based on this library. Thus, the terms and conditions of the +GNU Lesser General Public License version 3 cover the whole combination. + +As a special exception, the copyright holders of this library give you +permission to combine this library with independent +modules to produce an executable, and to copy and distribute the resulting +executable under terms of any of the GNU General Public licenses, as published +by the Free Software Foundation, provided that you also meet, +for each linked independent module, the terms and conditions of the license of +that module. An independent module is a module which is not derived from or +based on this library. If you modify this library, you may extend this +exception to your version of the library, but you are not obliged to do so. +If you do not wish to do so, delete this exception statement from your version. diff --git a/thirdparty/Qt-Color-Widgets/QtColorWidgets.pc.in b/thirdparty/Qt-Color-Widgets/QtColorWidgets.pc.in new file mode 100644 index 00000000..701b124d --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/QtColorWidgets.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/include + +Name: QtColorWidgets +Description: Color wheel widget and dialog for Qt +Version: @QtColorWidgets_VERSION@ +Libs: -L${libdir} -l@i_target_name@@i_target_output_suffix@ +Cflags: -I${includedir}/@i_project_name@ -I${includedir} diff --git a/thirdparty/Qt-Color-Widgets/README.md b/thirdparty/Qt-Color-Widgets/README.md new file mode 100644 index 00000000..2c6815ef --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/README.md @@ -0,0 +1,66 @@ +Color Widgets +============= + +Here is a color dialog that is more user-friendly than the default QColorDialog +and several other color-related widgets + +The provided widgets are: + +* ColorWheel, An analog widget used to select a color +* ColorPreview, A simple widget that displays a color +* GradientSlider, A slider that has a gradient background +* HueSlider, A variant of GradientSlider that has a rainbow background +* ColorSelector, A ColorPreview that shows a ColorDialog when clicked +* ColorDialog, A dialog that uses the above widgets to provide a better user experience than QColorDialog +* ColorListWidget, A widget to edit a list of colors +* Swatch, A widget to display a color palette +* ColorPaletteWidget, A widget to use and manage a list of palettes +* Color2DSlider, An analog widget used to select 2 color components +* ColorLineEdit, A widget to manipulate a string representing a color +* HarmonyColorWheel, A ColorWheel which allows defining multiple colors, separated by hue +* GradientListModel, A QAbstractListModel used to list gradients (useful for combo boxes, list views and the like) + +they are all in the color_widgets namespace. + +See [the gallery](gallery/README.md) for more information and screenshots. + + +Using it in a project +--------------------- + +For QMake-based projects, include color_widgets.pri in the QMake project file. +For CMake-based projects, add this as subdirectory, it will be compiled as a +library and you can link the required targets to ColorWidgets. +All the required files are in ./src and ./include. + + +Installing as a Qt Designer/Creator Plugin +------------------------------------------ + +The sources for the designer plugin are in ./color_widgets_designer_plugin + +Compile the library and install in +(Qt SDK)/Tools/QtCreator/bin/designer/ +(Qt SDK)/(Qt Version)/(Toolchain)/plugins/designer + + mkdir build && cd build && cmake .. && make QtColorWidgetsPlugin && make install + + +Latest Version +-------------- + +The latest version of the sources can be found at the following locations: + +* https://gitlab.com/mattia.basaglia/Qt-Color-Widgets +* git://gitlab.com/mattia.basaglia/Qt-Color-Widgets.git + + +License +------- + +LGPLv3+, See COPYING. +As a special exception, this library can be included in any project under the +terms of any of the GNU liceses, distributing the whole project under a +different GNU license, see LICENSE-EXCEPTION for details. + +Copyright (C) 2013-2020 Mattia Basaglia diff --git a/thirdparty/Qt-Color-Widgets/cmake/QtColorWidgets-config.cmake b/thirdparty/Qt-Color-Widgets/cmake/QtColorWidgets-config.cmake new file mode 100644 index 00000000..9072b088 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/QtColorWidgets-config.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/@CMAKE_BASE_FILE_NAME@@CMAKE_FILE_OUTPUT_SUFFIX@-targets.cmake") diff --git a/thirdparty/Qt-Color-Widgets/cmake/install.cmake b/thirdparty/Qt-Color-Widgets/cmake/install.cmake new file mode 100644 index 00000000..cd35415a --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/install.cmake @@ -0,0 +1,88 @@ +function (install_project + PROJECT_NAME i_project_name + TARGET_NAME i_target_name + TARGET_OUTPUT_SUFFIX i_target_output_suffix + EXPORT_HEADER i_export_header + INCLUDE_PREFIX i_include_prefix + HEADER_MATCHING_REGEX i_header_matching_regex + VERSION_HEADER i_version_header + NAMESPACE i_namespace) + install (TARGETS ${i_target_name} + EXPORT ${i_target_name} + RUNTIME DESTINATION bin + INCLUDES DESTINATION include + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib) + + install (DIRECTORY include/ + DESTINATION include + FILES_MATCHING + REGEX ${i_header_matching_regex} + REGEX "CMakeLists\.txt" EXCLUDE) + + install (FILES ${i_version_header} + DESTINATION include/${i_include_prefix} + COMPONENT Devel) + + install (FILES include/${i_export_header} + DESTINATION include/${i_include_prefix} + COMPONENT Devel) + + install( + EXPORT ${i_target_name} + DESTINATION lib/cmake/${i_target_name}${i_target_output_suffix} + FILE "${i_target_name}${i_target_output_suffix}.cmake" + COMPONENT Devel) + + + include(CMakePackageConfigHelpers) + + string (TOLOWER ${i_target_name} CMAKE_BASE_FILE_NAME) + string (TOLOWER ${i_target_output_suffix} CMAKE_FILE_OUTPUT_SUFFIX) + + write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${i_target_name}/${CMAKE_BASE_FILE_NAME}${CMAKE_FILE_OUTPUT_SUFFIX}-config-version.cmake" + VERSION ${${i_project_name}_VERSION} + COMPATIBILITY SameMajorVersion + ) + + export(EXPORT ${i_target_name} + FILE "${CMAKE_CURRENT_BINARY_DIR}/${i_target_name}/${CMAKE_BASE_FILE_NAME}${CMAKE_FILE_OUTPUT_SUFFIX}-targets.cmake" + ) + + configure_file("cmake/${i_project_name}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${i_target_name}/${CMAKE_BASE_FILE_NAME}${CMAKE_FILE_OUTPUT_SUFFIX}-config.cmake" + @ONLY + ) + + set(ConfigPackageLocation "lib/cmake/${i_target_name}${i_target_output_suffix}") + install(EXPORT ${i_target_name} + FILE + "${CMAKE_BASE_FILE_NAME}${CMAKE_FILE_OUTPUT_SUFFIX}-targets.cmake" + NAMESPACE + "${i_namespace}" + DESTINATION + ${ConfigPackageLocation} + ) + install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/${i_target_name}/${CMAKE_BASE_FILE_NAME}${CMAKE_FILE_OUTPUT_SUFFIX}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${i_target_name}/${CMAKE_BASE_FILE_NAME}${CMAKE_FILE_OUTPUT_SUFFIX}-config-version.cmake" + DESTINATION + ${ConfigPackageLocation} + COMPONENT + Devel + ) + + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${i_project_name}.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/${i_target_name}${i_target_output_suffix}.pc + @ONLY + ) + + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/${i_target_name}${i_target_output_suffix}.pc + DESTINATION + lib/pkgconfig + ) +endfunction (install_project) diff --git a/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning.cmake b/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning.cmake new file mode 100644 index 00000000..6975a968 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning.cmake @@ -0,0 +1,80 @@ +define_property (TARGET + PROPERTY GIT_DESCRIBE + BRIEF_DOCS "Advanced version info for developers" + FULL_DOCS "String with information that is important for developers during + development process. This information includes git commit hash, durty status + of repo, distance from the last tag.") + +define_property (TARGET + PROPERTY GIT_UNTRACKED_FILES + BRIEF_DOCS "Information about presence of untracked files" + FULL_DOCS "Used in helper functions generation to add .with-untracked suffix + to version string. Suffix is only added if there are some untracked not + ignored files in repository.") + +set(HERE_DIR ${CMAKE_CURRENT_LIST_DIR}) + + +function (target_version_information + TARGET_NAME i_target_name + EXPORT_HEADER i_export_header + EXPORT_MACRO i_export_macro + VERSIONED_ENTITY i_versioned_entity) + + find_file ( + headerFileTemplate + "ProjectVersioning/version.h.in" + PATHS ${CMAKE_MODULE_PATH}) + + if ( NOT ${headerFileTemplate} ) + set(headerFileTemplate "${HERE_DIR}/ProjectVersioning/version.h.in") + endif() + + find_file ( + sourceFileTemplate + "ProjectVersioning/version.c.in" + PATHS ${CMAKE_MODULE_PATH}) + + if ( NOT ${sourceFileTemplate} ) + set(sourceFileTemplate "${HERE_DIR}/ProjectVersioning/version.c.in") + endif() + + exec_program ( + "git" + ${CMAKE_SOURCE_DIR} + ARGS "describe --always --dirty --long --tags" + OUTPUT_VARIABLE gitDescribe) + + exec_program ( + "git" + ${CMAKE_SOURCE_DIR} + ARGS "ls-files --others --exclude-standard" + OUTPUT_VARIABLE gitUntracked) + + if (gitUntracked) + set (gitUntracked ".with-untracked") + endif (gitUntracked) + + configure_file ( + "${headerFileTemplate}" + "${CMAKE_CURRENT_BINARY_DIR}/${i_versioned_entity}_version.h") + + configure_file( + "${sourceFileTemplate}" + "${CMAKE_BINARY_DIR}/${i_versioned_entity}_version.c") + + target_sources ("${i_target_name}" + PRIVATE + $ + $ + PRIVATE + "${CMAKE_BINARY_DIR}/${i_versioned_entity}_version.c") + + set_target_properties (${i_target_name} + PROPERTIES + GIT_DESCRIBE "${gitDescribe}" + GIT_UNTRACKED_FILES "${gitUntracked}") + + unset (headerFileTemplate PARENT_SCOPE) + unset (sourceFileTemplate PARENT_SCOPE) +endfunction (target_version_information) diff --git a/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning/version.c.in b/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning/version.c.in new file mode 100644 index 00000000..5786e0db --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning/version.c.in @@ -0,0 +1,34 @@ +#include "${i_versioned_entity}_version.h" + + +unsigned int @i_versioned_entity@_versionMajor () { + return ${${i_versioned_entity}_VERSION_MAJOR}; +} + + +unsigned int @i_versioned_entity@_versionMinor () { + return ${${i_versioned_entity}_VERSION_MINOR}; +} + + +unsigned int @i_versioned_entity@_versionPatch () { + return ${${i_versioned_entity}_VERSION_PATCH}; +} + + +const char* @i_versioned_entity@_versionGitInfo () { + return + "${gitDescribe}" + "${gitUntracked}"; +} + + +const char* @i_versioned_entity@_versionFullString () { + return + "${${i_versioned_entity}_VERSION_MAJOR}." + "${${i_versioned_entity}_VERSION_MINOR}." + "${${i_versioned_entity}_VERSION_PATCH}" + "${${i_versioned_entity}_VERSION_PRE_RELEASE}" + "+${gitDescribe}" + "${gitUntracked}"; +} diff --git a/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning/version.h.in b/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning/version.h.in new file mode 100644 index 00000000..c4c57ab0 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/modules/ProjectVersioning/version.h.in @@ -0,0 +1,23 @@ +#ifndef @CMAKE_PROJECT_NAME@_VERSION_H +#define @CMAKE_PROJECT_NAME@_VERSION_H + + +#include "@i_export_header@" + + +@i_export_macro@ unsigned int @i_versioned_entity@_versionMajor (); + + +@i_export_macro@ unsigned int @i_versioned_entity@_versionMinor (); + + +@i_export_macro@ unsigned int @i_versioned_entity@_versionPatch (); + + +@i_export_macro@ const char* @i_versioned_entity@_versionGitInfo (); + + +@i_export_macro@ const char* @i_versioned_entity@_versionFullString (); + + +#endif /* @CMAKE_PROJECT_NAME@_VERSION_H */ diff --git a/thirdparty/Qt-Color-Widgets/cmake/modules/VersionInfo.in b/thirdparty/Qt-Color-Widgets/cmake/modules/VersionInfo.in new file mode 100644 index 00000000..3dfd3510 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/modules/VersionInfo.in @@ -0,0 +1,113 @@ +/* + The MIT License (MIT) + + Copyright (c) 2015, by [halex2005](mailto:akharlov@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + + +#pragma once + +#ifndef PRODUCT_VERSION_MAJOR +#define PRODUCT_VERSION_MAJOR @PRODUCT_VERSION_MAJOR@ +#endif + +#ifndef PRODUCT_VERSION_MINOR +#define PRODUCT_VERSION_MINOR @PRODUCT_VERSION_MINOR@ +#endif + +#ifndef PRODUCT_VERSION_PATCH +#define PRODUCT_VERSION_PATCH @PRODUCT_VERSION_PATCH@ +#endif + +#ifndef PRODUCT_VERSION_BUILD +#define PRODUCT_VERSION_BUILD @PRODUCT_VERSION_REVISION@ +#endif + +#ifndef FILE_VERSION_MAJOR +#define FILE_VERSION_MAJOR @PRODUCT_VERSION_MAJOR@ +#endif + +#ifndef FILE_VERSION_MINOR +#define FILE_VERSION_MINOR @PRODUCT_VERSION_MINOR@ +#endif + +#ifndef FILE_VERSION_PATCH +#define FILE_VERSION_PATCH @PRODUCT_VERSION_PATCH@ +#endif + +#ifndef FILE_VERSION_BUILD +#define FILE_VERSION_BUILD @PRODUCT_VERSION_REVISION@ +#endif + +#ifndef __TO_STRING +#define __TO_STRING_IMPL(x) #x +#define __TO_STRING(x) __TO_STRING_IMPL(x) +#endif + +#define PRODUCT_VERSION_MAJOR_MINOR_STR __TO_STRING(PRODUCT_VERSION_MAJOR) "." __TO_STRING(PRODUCT_VERSION_MINOR) +#define PRODUCT_VERSION_MAJOR_MINOR_PATCH_STR PRODUCT_VERSION_MAJOR_MINOR_STR "." __TO_STRING(PRODUCT_VERSION_PATCH) +#define PRODUCT_VERSION_FULL_STR PRODUCT_VERSION_MAJOR_MINOR_PATCH_STR "." __TO_STRING(PRODUCT_VERSION_BUILD) +#define PRODUCT_VERSION_RESOURCE PRODUCT_VERSION_MAJOR,PRODUCT_VERSION_MINOR,PRODUCT_VERSION_PATCH,PRODUCT_VERSION_BUILD +#define PRODUCT_VERSION_RESOURCE_STR PRODUCT_VERSION_FULL_STR "\0" + +#define FILE_VERSION_MAJOR_MINOR_STR __TO_STRING(FILE_VERSION_MAJOR) "." __TO_STRING(FILE_VERSION_MINOR) +#define FILE_VERSION_MAJOR_MINOR_PATCH_STR FILE_VERSION_MAJOR_MINOR_STR "." __TO_STRING(FILE_VERSION_PATCH) +#define FILE_VERSION_FULL_STR FILE_VERSION_MAJOR_MINOR_PATCH_STR "." __TO_STRING(FILE_VERSION_BUILD) +#define FILE_VERSION_RESOURCE FILE_VERSION_MAJOR,FILE_VERSION_MINOR,FILE_VERSION_PATCH,FILE_VERSION_BUILD +#define FILE_VERSION_RESOURCE_STR FILE_VERSION_FULL_STR "\0" + +#ifndef USE_ICON +#define USE_ICON @USE_ICON@ +#endif + +#if USE_ICON +#ifndef PRODUCT_ICON +#define PRODUCT_ICON "@PRODUCT_ICON@" +#endif +#endif + +#ifndef PRODUCT_COMMENTS +#define PRODUCT_COMMENTS "@PRODUCT_COMMENTS@\0" +#endif + +#ifndef PRODUCT_COMPANY_NAME +#define PRODUCT_COMPANY_NAME "@PRODUCT_COMPANY_NAME@\0" +#endif + +#ifndef PRODUCT_COMPANY_COPYRIGHT +#define PRODUCT_COMPANY_COPYRIGHT "@PRODUCT_COMPANY_COPYRIGHT@\0" +#endif + +#ifndef PRODUCT_FILE_DESCRIPTION +#define PRODUCT_FILE_DESCRIPTION "@PRODUCT_FILE_DESCRIPTION@\0" +#endif + +#ifndef PRODUCT_INTERNAL_NAME +#define PRODUCT_INTERNAL_NAME "@PRODUCT_NAME@\0" +#endif + +#ifndef PRODUCT_ORIGINAL_FILENAME +#define PRODUCT_ORIGINAL_FILENAME "@PRODUCT_ORIGINAL_FILENAME@\0" +#endif + +#ifndef PRODUCT_BUNDLE +#define PRODUCT_BUNDLE "@PRODUCT_BUNDLE@\0" +#endif diff --git a/thirdparty/Qt-Color-Widgets/cmake/modules/VersionResource.rc b/thirdparty/Qt-Color-Widgets/cmake/modules/VersionResource.rc new file mode 100644 index 00000000..838db86b --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/modules/VersionResource.rc @@ -0,0 +1,66 @@ +/* + The MIT License (MIT) + + Copyright (c) 2015, by [halex2005](mailto:akharlov@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#include "VersionInfo.h" +#include "winresrc.h" + +#if USE_ICON +IDI_ICON1 ICON PRODUCT_ICON +#endif + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +VS_VERSION_INFO VERSIONINFO + FILEVERSION FILE_VERSION_RESOURCE + PRODUCTVERSION PRODUCT_VERSION_RESOURCE + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "041904b0" + BEGIN + VALUE "Comments", PRODUCT_COMMENTS + VALUE "CompanyName", PRODUCT_COMPANY_NAME + VALUE "FileDescription", PRODUCT_FILE_DESCRIPTION + VALUE "FileVersion", FILE_VERSION_RESOURCE_STR + VALUE "InternalName", PRODUCT_INTERNAL_NAME + VALUE "LegalCopyright", PRODUCT_COMPANY_COPYRIGHT + VALUE "OriginalFilename", PRODUCT_ORIGINAL_FILENAME + VALUE "ProductName", PRODUCT_BUNDLE + VALUE "ProductVersion", PRODUCT_VERSION_RESOURCE_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x419, 1200 + END +END diff --git a/thirdparty/Qt-Color-Widgets/cmake/modules/generate_product_version.cmake b/thirdparty/Qt-Color-Widgets/cmake/modules/generate_product_version.cmake new file mode 100644 index 00000000..2880f4a0 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/modules/generate_product_version.cmake @@ -0,0 +1,136 @@ +# The MIT License (MIT) + +# Copyright (c) 2015, by [halex2005](mailto:akharlov@gmail.com) + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include (CMakeParseArguments) + +set (GenerateProductVersionCurrentDir ${CMAKE_CURRENT_LIST_DIR}) + +# generate_product_version() function +# +# This function uses VersionInfo.in template file and VersionResource.rc file +# to generate WIN32 resource with version information and general resource strings. +# +# Usage: +# generate_product_version( +# SomeOutputResourceVariable +# NAME MyGreatProject +# ICON ${PATH_TO_APP_ICON} +# VERSION_MAJOR 2 +# VERSION_MINOR 3 +# VERSION_PATH ${BUILD_COUNTER} +# VERSION_REVISION ${BUILD_REVISION} +# ) +# where BUILD_COUNTER and BUILD_REVISION could be values from your CI server. +# +# You can use generated resource for your executable targets: +# add_executable(target-name ${target-files} ${SomeOutputResourceVariable}) +# +# You can specify resource strings in arguments: +# NAME - name of executable (no defaults, ex: Microsoft Word) +# BUNDLE - bundle (${NAME} is default, ex: Microsoft Office) +# USE_ICON - flag that shows whether icon is used or not +# ICON - path to application icon (${CMAKE_SOURCE_DIR}/product.ico by default) +# VERSION_MAJOR - 1 is default +# VERSION_MINOR - 0 is default +# VERSION_PATCH - 0 is default +# VERSION_REVISION - 0 is default +# COMPANY_NAME - your company name (no defaults) +# COMPANY_COPYRIGHT - ${COMPANY_NAME} (C) Copyright ${CURRENT_YEAR} is default +# COMMENTS - ${NAME} v${VERSION_MAJOR}.${VERSION_MINOR} is default +# ORIGINAL_FILENAME - ${NAME} is default +# INTERNAL_NAME - ${NAME} is default +# FILE_DESCRIPTION - ${NAME} is default +function(generate_product_version outfiles) + set (options) + set (oneValueArgs + NAME + BUNDLE + USE_ICON + ICON + VERSION_MAJOR + VERSION_MINOR + VERSION_PATCH + VERSION_REVISION + COMPANY_NAME + COMPANY_COPYRIGHT + COMMENTS + ORIGINAL_FILENAME + INTERNAL_NAME + FILE_DESCRIPTION) + set (multiValueArgs) + cmake_parse_arguments(PRODUCT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT PRODUCT_BUNDLE OR "${PRODUCT_BUNDLE}" STREQUAL "") + set(PRODUCT_BUNDLE "${PRODUCT_NAME}") + endif() + + if (USE_ICON) + if (NOT PRODUCT_ICON OR "${PRODUCT_ICON}" STREQUAL "") + set(PRODUCT_ICON "${CMAKE_SOURCE_DIR}/product.ico") + endif() + else () + set (USE_ICON 0) + endif () + + if (NOT PRODUCT_VERSION_MAJOR EQUAL 0 AND (NOT PRODUCT_VERSION_MAJOR OR "${PRODUCT_VERSION_MAJOR}" STREQUAL "")) + set(PRODUCT_VERSION_MAJOR 1) + endif() + if (NOT PRODUCT_VERSION_MINOR EQUAL 0 AND (NOT PRODUCT_VERSION_MINOR OR "${PRODUCT_VERSION_MINOR}" STREQUAL "")) + set(PRODUCT_VERSION_MINOR 0) + endif() + if (NOT PRODUCT_VERSION_PATCH EQUAL 0 AND (NOT PRODUCT_VERSION_PATCH OR "${PRODUCT_VERSION_PATCH}" STREQUAL "")) + set(PRODUCT_VERSION_PATCH 0) + endif() + if (NOT PRODUCT_VERSION_REVISION EQUAL 0 AND (NOT PRODUCT_VERSION_REVISION OR "${PRODUCT_VERSION_REVISION}" STREQUAL "")) + set(PRODUCT_VERSION_REVISION 0) + endif() + + if (NOT PRODUCT_COMPANY_COPYRIGHT OR "${PRODUCT_COMPANY_COPYRIGHT}" STREQUAL "") + string(TIMESTAMP PRODUCT_CURRENT_YEAR "%Y") + set(PRODUCT_COMPANY_COPYRIGHT "${PRODUCT_COMPANY_NAME} (C) Copyright ${PRODUCT_CURRENT_YEAR}") + endif() + if (NOT PRODUCT_COMMENTS OR "${PRODUCT_COMMENTS}" STREQUAL "") + set(PRODUCT_COMMENTS "${PRODUCT_NAME} v${PRODUCT_VERSION_MAJOR}.${PRODUCT_VERSION_MINOR}") + endif() + if (NOT PRODUCT_ORIGINAL_FILENAME OR "${PRODUCT_ORIGINAL_FILENAME}" STREQUAL "") + set(PRODUCT_ORIGINAL_FILENAME "${PRODUCT_NAME}") + endif() + if (NOT PRODUCT_INTERNAL_NAME OR "${PRODUCT_INTERNAL_NAME}" STREQUAL "") + set(PRODUCT_INTERNAL_NAME "${PRODUCT_NAME}") + endif() + if (NOT PRODUCT_FILE_DESCRIPTION OR "${PRODUCT_FILE_DESCRIPTION}" STREQUAL "") + set(PRODUCT_FILE_DESCRIPTION "${PRODUCT_NAME}") + endif() + + set (_VersionInfoFile ${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.h) + set (_VersionResourceFile ${CMAKE_CURRENT_BINARY_DIR}/VersionResource.rc) + configure_file( + ${GenerateProductVersionCurrentDir}/VersionInfo.in + ${_VersionInfoFile} + @ONLY) + configure_file( + ${GenerateProductVersionCurrentDir}/VersionResource.rc + ${_VersionResourceFile} + COPYONLY) + list(APPEND ${outfiles} ${_VersionInfoFile} ${_VersionResourceFile}) + set (${outfiles} ${${outfiles}} PARENT_SCOPE) +endfunction() diff --git a/thirdparty/Qt-Color-Widgets/cmake/qt-configuration.cmake b/thirdparty/Qt-Color-Widgets/cmake/qt-configuration.cmake new file mode 100644 index 00000000..49c345c2 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/qt-configuration.cmake @@ -0,0 +1,58 @@ +function (select_qt + QT_SUPPORTED_VERSIONS i_qt_supported_versions + QT_DEFAULT_VERSION i_default_qt_version) + set (QT_VERSION ${i_default_qt_version} CACHE STRING + "Qt version to build against") + + set_property ( + CACHE QT_VERSION + PROPERTY STRINGS ${i_qt_supported_versions}) +endfunction (select_qt) + + +macro (find_qt + QT_SUPPORTED_VERSIONS i_qt_supported_versions + REQUIRED_COMPONENTS i_required_components + OPTIONAL_COMPONENTS i_optional_components) + # Auto generate moc files + if (4 EQUAL QT_VERSION) + find_package (Qt4 4.8 REQUIRED + COMPONENTS + ${i_required_components} + OPTIONAL_COMPONENTS + ${i_optional_components}) + elseif (5 EQUAL QT_VERSION) + find_package (Qt5 5.9 REQUIRED + COMPONENTS + ${i_required_components} + OPTIONAL_COMPONENTS + ${i_optional_components}) + else (5 EQUAL QT_VERSION) + message (FATAL_ERROR "Unsupported version of Qt: ${QT_VERSION}") + endif (4 EQUAL QT_VERSION) +endmacro (find_qt) + + +function (use_qt + TARGET_NAME i_target_name + QT_SUPPORTED_VERSIONS i_qt_supported_versions + REQUIRED_COMPONENTS i_required_components + OPTIONAL_COMPONENTS i_optional_components) + if (4 EQUAL QT_VERSION) + foreach (COMPONENT IN LISTS i_required_components, i_optional_components) + target_link_libraries (${i_target_name} + PRIVATE + Qt4::${COMPONENT} + ) + endforeach (COMPONENT IN LISTS i_required_components, i_optional_components) + elseif (5 EQUAL QT_VERSION) + foreach (COMPONENT IN LISTS i_required_components) + target_link_libraries (${i_target_name} + PRIVATE + Qt5::${COMPONENT} + ) + endforeach (COMPONENT IN LISTS i_required_components, i_optional_components) + else (5 EQUAL QT_VERSION) + message (FATAL_ERROR "Unsupported version of Qt: ${QT_VERSION}") + endif (4 EQUAL QT_VERSION) +endfunction (use_qt) diff --git a/thirdparty/Qt-Color-Widgets/cmake/versioning.cmake b/thirdparty/Qt-Color-Widgets/cmake/versioning.cmake new file mode 100644 index 00000000..4a5ccd32 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/cmake/versioning.cmake @@ -0,0 +1,43 @@ +include (ProjectVersioning) + +function (generate_versioning_information + TARGET_NAME i_target_name + EXPORT_HEADER i_export_header + EXPORT_MACRO i_export_macro + VERSIONED_ENTITY i_versioned_entity + INCLUDE_PREFIX i_include_prefix + COMPANY_NAME i_company_name + COMPANY_COPYRIGHT i_company_copyright + FILE_DESCRIPTION i_file_description +) + target_version_information ( + TARGET_NAME ${i_target_name} + EXPORT_HEADER ${i_export_header} + EXPORT_MACRO ${i_export_macro} + VERSIONED_ENTITY ${i_versioned_entity} + ) + + if (WIN32) + include (generate_product_version) + + get_target_property (gitDescribe + ${i_target_name} GIT_DESCRIBE) + + get_target_property (gitUntracked + ${i_target_name} GIT_UNTRACKED_FILES) + + generate_product_version ( + win32VersionInfoFiles + NAME ${i_versioned_entity} + VERSION_MAJOR ${${i_versioned_entity}_VERSION_MAJOR} + VERSION_MINOR ${${i_versioned_entity}_VERSION_MINOR} + VERSION_PATCH ${${i_versioned_entity}_VERSION_PATCH} + COMPANY_NAME ${i_company_name} + COMPANY_COPYRIGHT ${i_company_copyright} + COMMENTS "${gitDescribe}${gitUntracked}" + FILE_DESCRIPTION ${i_file_description} + ) + + target_sources (${i_target_name} PRIVATE ${win32VersionInfoFiles}) + endif (WIN32) +endfunction (generate_versioning_information) diff --git a/thirdparty/Qt-Color-Widgets/color_widgets.pri b/thirdparty/Qt-Color-Widgets/color_widgets.pri new file mode 100644 index 00000000..4f69ec30 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets.pri @@ -0,0 +1,77 @@ +# Copyright (C) 2013-2019 Mattia Basaglia +# +# +# This software is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Color Widgets. If not, see . + +CONFIG += c++11 + +INCLUDEPATH += $$PWD/src $$PWD/include + +SOURCES += \ + $$PWD/src/QtColorWidgets/abstract_widget_list.cpp \ + $$PWD/src/QtColorWidgets/bound_color_selector.cpp \ + $$PWD/src/QtColorWidgets/color_2d_slider.cpp \ + $$PWD/src/QtColorWidgets/color_delegate.cpp \ + $$PWD/src/QtColorWidgets/color_dialog.cpp \ + $$PWD/src/QtColorWidgets/color_line_edit.cpp \ + $$PWD/src/QtColorWidgets/color_list_widget.cpp \ + $$PWD/src/QtColorWidgets/color_names.cpp \ + $$PWD/src/QtColorWidgets/color_palette.cpp \ + $$PWD/src/QtColorWidgets/color_palette_model.cpp \ + $$PWD/src/QtColorWidgets/color_palette_widget.cpp \ + $$PWD/src/QtColorWidgets/color_preview.cpp \ + $$PWD/src/QtColorWidgets/color_selector.cpp \ + $$PWD/src/QtColorWidgets/color_utils.cpp \ + $$PWD/src/QtColorWidgets/color_wheel.cpp \ + $$PWD/src/QtColorWidgets/gradient_editor.cpp \ + $$PWD/src/QtColorWidgets/gradient_list_model.cpp \ + $$PWD/src/QtColorWidgets/gradient_slider.cpp \ + $$PWD/src/QtColorWidgets/harmony_color_wheel.cpp \ + $$PWD/src/QtColorWidgets/hue_slider.cpp \ + $$PWD/src/QtColorWidgets/swatch.cpp + +HEADERS += \ + $$PWD/include/QtColorWidgets/abstract_widget_list.hpp \ + $$PWD/include/QtColorWidgets/bound_color_selector.hpp \ + $$PWD/include/QtColorWidgets/color_2d_slider.hpp \ + $$PWD/include/QtColorWidgets/color_delegate.hpp \ + $$PWD/include/QtColorWidgets/color_dialog.hpp \ + $$PWD/include/QtColorWidgets/color_line_edit.hpp \ + $$PWD/include/QtColorWidgets/color_list_widget.hpp \ + $$PWD/include/QtColorWidgets/color_names.hpp \ + $$PWD/include/QtColorWidgets/color_palette.hpp \ + $$PWD/include/QtColorWidgets/color_palette_model.hpp \ + $$PWD/include/QtColorWidgets/color_palette_widget.hpp \ + $$PWD/include/QtColorWidgets/color_preview.hpp \ + $$PWD/include/QtColorWidgets/color_selector.hpp \ + $$PWD/include/QtColorWidgets/color_utils.hpp \ + $$PWD/include/QtColorWidgets/color_wheel.hpp \ + $$PWD/include/QtColorWidgets/color_wheel_private.hpp \ + $$PWD/include/QtColorWidgets/colorwidgets_global.hpp \ + $$PWD/include/QtColorWidgets/gradient_delegate.hpp \ + $$PWD/include/QtColorWidgets/gradient_editor.hpp \ + $$PWD/include/QtColorWidgets/gradient_helper.hpp \ + $$PWD/include/QtColorWidgets/gradient_list_model.hpp \ + $$PWD/include/QtColorWidgets/gradient_slider.hpp \ + $$PWD/include/QtColorWidgets/harmony_color_wheel.hpp \ + $$PWD/include/QtColorWidgets/hue_slider.hpp \ + $$PWD/include/QtColorWidgets/swatch.hpp + +FORMS += \ + $$PWD/src/QtColorWidgets/color_dialog.ui \ + $$PWD/src/QtColorWidgets/color_palette_widget.ui + +RESOURCES += \ + $$PWD/resources/QtColorWidgets/color_widgets.qrc + diff --git a/thirdparty/Qt-Color-Widgets/color_widgets.pro b/thirdparty/Qt-Color-Widgets/color_widgets.pro new file mode 100644 index 00000000..7969cd93 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets.pro @@ -0,0 +1,53 @@ +# +# Copyright (C) 2013-2020 Mattia Basaglia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +TEMPLATE=lib +CONFIG += dll +QT += core gui widgets +DEFINES += QTCOLORWIDGETS_LIBRARY + +TARGET=QtColorWidgets-Qt5 + +VERSION=2.0.0 + +OBJECTS_DIR = out/obj +MOC_DIR = out/generated +UI_DIR = out/generated +RCC_DIR = out/generated + +include(color_widgets.pri) + +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +unix { + LIB_TARGET = lib$${TARGET}.so +} +win32 { + LIB_TARGET = $${TARGET}.dll +} + +isEmpty(PREFIX) { + PREFIX = /usr/local +} +target.path = $$PREFIX/lib +headers.path = $$PREFIX/include/QtColorWidgets +headers.files = $$HEADERS + +INSTALLS += target headers + diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/CMakeLists.txt b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/CMakeLists.txt new file mode 100644 index 00000000..709eebc3 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/CMakeLists.txt @@ -0,0 +1,178 @@ +# Copyright (C) 2013-2020 Mattia Basaglia +# +# +# This software is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Color Widgets. If not, see . + +cmake_minimum_required (VERSION 3.1 FATAL_ERROR) + +project(QtColorWidgetsPlugin CXX) + + +set (CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + ${CMAKE_SOURCE_DIR}/cmake/modules + ${CMAKE_CURRENT_LIST_DIR}/..) + + +include (CheckCXXCompilerFlag) + +include (../cmake/qt-configuration.cmake) +include (../cmake/versioning.cmake) + + +SET (${PROJECT_NAME}_VERSION_MAJOR 2) +SET (${PROJECT_NAME}_VERSION_MINOR 0) +SET (${PROJECT_NAME}_VERSION_PATCH 0) +SET (${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}") + + +set (QT_SUPPORTED_VERSIONS 5) + +select_qt ( + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + QT_DEFAULT_VERSION 5) + +set (REQUIRED_QT_COMPONENTS + Designer + ) +find_qt ( + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + REQUIRED_COMPONENTS "${REQUIRED_QT_COMPONENTS}" + OPTIONAL_COMPONENTS "") + +# Auto generate moc files +set(CMAKE_AUTOMOC ON) +# Auto generate moc files +set(CMAKE_AUTOUIC ON) +# Auto generate moc files +set(CMAKE_AUTORCC ON) + +check_cxx_compiler_flag ("-Wall" Wall_FLAG_SUPPORTED) + +if (Wall_FLAG_SUPPORTED) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") +endif (Wall_FLAG_SUPPORTED) + +check_cxx_compiler_flag ("-pedantic" pedantic_FLAG_SUPPORTED) + +if (pedantic_FLAG_SUPPORTED) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pedantic") +endif (pedantic_FLAG_SUPPORTED) + +check_cxx_compiler_flag ("-Wextra" Wextra_FLAG_SUPPORTED) + +if (Wextra_FLAG_SUPPORTED) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wextra") +endif (Wextra_FLAG_SUPPORTED) + +# Library +set (TARGET_NAME ${PROJECT_NAME}) +set (TARGET_OUTPUT_SUFFIX "-Qt${QT_VERSION}${${PROJECT_NAME}_VERSION_MAJOR}") + +add_library (${TARGET_NAME} SHARED "") +set_target_properties(${TARGET_NAME} + PROPERTIES + EXPORT_NAME "${TARGET_NAME}${TARGET_OUTPUT_SUFFIX}") + +set_target_properties (${TARGET_NAME} + PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED ON + VERSION ${${PROJECT_NAME}_VERSION} + SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR} + "INTERFACE_${PROJECT_NAME}_MAJOR_VERSION" ${${PROJECT_NAME}_VERSION_MAJOR} + COMPATIBLE_INTERFACE_STRING "${PROJECT_NAME}_MAJOR_VERSION" + OUTPUT_NAME "${TARGET_NAME}${TARGET_OUTPUT_SUFFIX}") + + +target_link_libraries(${TARGET_NAME} + PRIVATE + ${COLOR_WIDGETS_LIBRARY}) + +use_qt ( + TARGET_NAME ${TARGET_NAME} + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + REQUIRED_COMPONENTS "${REQUIRED_QT_COMPONENTS}" + OPTIONAL_COMPONENTS "") + + +# Sources +set(SOURCES + color_preview_plugin.cpp + color_wheel_plugin.cpp + color_widget_plugin_collection.cpp + gradient_slider_plugin.cpp + hue_slider_plugin.cpp + color_selector_plugin.cpp + color_list_plugin.cpp + swatch_plugin.cpp + color_palette_widget_plugin.cpp + color_2d_slider_plugin.cpp + color_line_edit_plugin.cpp + gradient_editor_plugin.cpp + # add new sources above this line + ) + +foreach (SOURCE IN LISTS SOURCES) + target_sources (${TARGET_NAME} + PRIVATE + $) +endforeach (SOURCE IN SOURCES) + +set(HEADERS + color_preview_plugin.hpp + color_wheel_plugin.hpp + color_widget_plugin_collection.hpp + gradient_slider_plugin.hpp + hue_slider_plugin.hpp + color_selector_plugin.hpp + color_list_plugin.hpp + swatch_plugin.hpp + color_palette_widget_plugin.hpp + color_2d_slider_plugin.hpp + color_line_edit_plugin.hpp + gradient_editor_plugin.hpp + # add new headers above this line + ) + +foreach (HEADER IN LISTS HEADERS) + target_sources (${TARGET_NAME} + PRIVATE + $) +endforeach (HEADER IN HEADERS) + + +# install +get_target_property (QT_QMAKE_EXECUTABLE + Qt5::qmake LOCATION) + +execute_process ( + COMMAND ${QT_QMAKE_EXECUTABLE} -query QT_INSTALL_PLUGINS + OUTPUT_VARIABLE QT_INSTALL_PLUGINS + OUTPUT_STRIP_TRAILING_WHITESPACE) + +# install(TARGETS ${COLOR_WIDGETS_PLUGIN} DESTINATION ${QT_INSTALL_PLUGINS}/designer OPTIONAL) + +execute_process ( + COMMAND ${QT_QMAKE_EXECUTABLE} -query QT_INSTALL_LIBS + OUTPUT_VARIABLE QT_INSTALL_LIBS + OUTPUT_STRIP_TRAILING_WHITESPACE) + +# install(TARGETS ${COLOR_WIDGETS_PLUGIN} DESTINATION ${QT_INSTALL_LIBS}/qtcreator/plugins OPTIONAL) + +add_custom_target(${TARGET_NAME}_install + COMMAND cp $ ${QT_INSTALL_PLUGINS}/designer + COMMAND cp $ ${QT_INSTALL_LIBS}/qtcreator/plugins + DEPENDS ${TARGET_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_2d_slider_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_2d_slider_plugin.cpp new file mode 100644 index 00000000..b56503c5 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_2d_slider_plugin.cpp @@ -0,0 +1,90 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_2d_slider_plugin.hpp" +#include "QtColorWidgets/color_2d_slider.hpp" + +Color2DSlider_Plugin::Color2DSlider_Plugin(QObject *parent) : + QObject(parent), initialized(false) +{ +} + +void Color2DSlider_Plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool Color2DSlider_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget *Color2DSlider_Plugin::createWidget(QWidget *parent) +{ + return new color_widgets::Color2DSlider(parent); +} + +QString Color2DSlider_Plugin::name() const +{ + return "color_widgets::Color2DSlider"; +} + +QString Color2DSlider_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon Color2DSlider_Plugin::icon() const +{ + color_widgets::Color2DSlider w; + w.resize(64,64); + QPixmap pix(64,64); + w.render(&pix); + return QIcon(pix); +} + +QString Color2DSlider_Plugin::toolTip() const +{ + return "An analog widget to select 2 color components at the same time"; +} + +QString Color2DSlider_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool Color2DSlider_Plugin::isContainer() const +{ + return false; +} + +QString Color2DSlider_Plugin::domXml() const +{ + return "\n" + " \n" + " \n" + "\n"; +} + +QString Color2DSlider_Plugin::includeFile() const +{ + return "QtColorWidgets/color_2d_slider.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_2d_slider_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_2d_slider_plugin.hpp new file mode 100644 index 00000000..cc360d2e --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_2d_slider_plugin.hpp @@ -0,0 +1,57 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_2D_SLIDER_PLUGIN_HPP +#define COLOR_WIDGETS_COLOR_2D_SLIDER_PLUGIN_HPP + +#include +#include + +class Color2DSlider_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + Color2DSlider_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + + +#endif // COLOR_WIDGETS_COLOR_2D_SLIDER_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_line_edit_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_line_edit_plugin.cpp new file mode 100644 index 00000000..56d7a5a2 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_line_edit_plugin.cpp @@ -0,0 +1,87 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_line_edit_plugin.hpp" +#include "QtColorWidgets/color_line_edit.hpp" + +QWidget* ColorLineEdit_Plugin::createWidget(QWidget *parent) +{ + color_widgets::ColorLineEdit *widget = new color_widgets::ColorLineEdit(parent); + return widget; +} + +QIcon ColorLineEdit_Plugin::icon() const +{ + return QIcon::fromTheme("edit-rename"); +} + +QString ColorLineEdit_Plugin::domXml() const +{ + return "\n" + " \n" + " \n" + "\n"; +} + +bool ColorLineEdit_Plugin::isContainer() const +{ + return false; +} + +ColorLineEdit_Plugin::ColorLineEdit_Plugin(QObject *parent) : + QObject(parent), initialized(false) +{ +} + +void ColorLineEdit_Plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool ColorLineEdit_Plugin::isInitialized() const +{ + return initialized; +} + +QString ColorLineEdit_Plugin::name() const +{ + return "color_widgets::ColorLineEdit"; +} + +QString ColorLineEdit_Plugin::group() const +{ + return "Color Widgets"; +} + +QString ColorLineEdit_Plugin::toolTip() const +{ + return "A widget to manipulate a string representing a color"; +} + +QString ColorLineEdit_Plugin::whatsThis() const +{ + return toolTip(); +} + +QString ColorLineEdit_Plugin::includeFile() const +{ + return "QtColorWidgets/color_line_edit.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_line_edit_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_line_edit_plugin.hpp new file mode 100644 index 00000000..1388b5bd --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_line_edit_plugin.hpp @@ -0,0 +1,58 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_LINE_EDIT_PLUGIN_HPP +#define COLOR_WIDGETS_COLOR_LINE_EDIT_PLUGIN_HPP + +#include +#include + +class ColorLineEdit_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + explicit ColorLineEdit_Plugin(QObject *parent = nullptr); + + void initialize(QDesignerFormEditorInterface *core) Q_DECL_OVERRIDE; + bool isInitialized() const Q_DECL_OVERRIDE; + + QWidget *createWidget(QWidget *parent) Q_DECL_OVERRIDE; + + QString name() const Q_DECL_OVERRIDE; + QString group() const Q_DECL_OVERRIDE; + QIcon icon() const Q_DECL_OVERRIDE; + QString toolTip() const Q_DECL_OVERRIDE; + QString whatsThis() const Q_DECL_OVERRIDE; + bool isContainer() const Q_DECL_OVERRIDE; + + QString domXml() const Q_DECL_OVERRIDE; + + QString includeFile() const Q_DECL_OVERRIDE; + +private: + bool initialized; +}; + + +#endif // COLOR_WIDGETS_COLOR_LINE_EDIT_PLUGIN_HPP + diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_list_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_list_plugin.cpp new file mode 100644 index 00000000..11768811 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_list_plugin.cpp @@ -0,0 +1,88 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_list_plugin.hpp" +#include "QtColorWidgets/color_list_widget.hpp" + +ColorListWidget_Plugin::ColorListWidget_Plugin(QObject *parent) : + QObject(parent) +{ +} + + +void ColorListWidget_Plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool ColorListWidget_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget *ColorListWidget_Plugin::createWidget(QWidget *parent) +{ + return new color_widgets::ColorListWidget(parent); +} + +QString ColorListWidget_Plugin::name() const +{ + return "color_widgets::ColorListWidget"; +} + +QString ColorListWidget_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon ColorListWidget_Plugin::icon() const +{ + return QIcon::fromTheme("format-stroke-color"); +} + +QString ColorListWidget_Plugin::toolTip() const +{ + return "An editable list of colors"; +} + +QString ColorListWidget_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool ColorListWidget_Plugin::isContainer() const +{ + return false; +} + +QString ColorListWidget_Plugin::domXml() const +{ + + return "\n" + " \n" + " \n" + "\n"; +} + +QString ColorListWidget_Plugin::includeFile() const +{ + return "QtColorWidgets/color_list_widget.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_list_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_list_plugin.hpp new file mode 100644 index 00000000..31508d97 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_list_plugin.hpp @@ -0,0 +1,56 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_LIST_PLUGIN_HPP +#define COLOR_LIST_PLUGIN_HPP + +#include + +class ColorListWidget_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + explicit ColorListWidget_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; + +}; + +#endif // COLOR_LIST_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_palette_widget_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_palette_widget_plugin.cpp new file mode 100644 index 00000000..05d80248 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_palette_widget_plugin.cpp @@ -0,0 +1,120 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_palette_widget_plugin.hpp" +#include "QtColorWidgets/color_palette_widget.hpp" + +ColorPaletteWidget_Plugin::ColorPaletteWidget_Plugin(QObject *parent) : + QObject(parent), initialized(false) +{ +} + +void ColorPaletteWidget_Plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool ColorPaletteWidget_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget* ColorPaletteWidget_Plugin::createWidget(QWidget *parent) +{ + color_widgets::ColorPaletteWidget *wid = new color_widgets::ColorPaletteWidget(parent); + + color_widgets::ColorPalette palette1; + color_widgets::ColorPalette palette2; + int columns = 12; + palette1.setName("Palette 1"); + palette2.setName("Palette 2"); + palette1.setColumns(columns); + palette2.setColumns(columns); + for ( int i = 0; i < 6; i++ ) + { + for ( int j = 0; j < columns; j++ ) + { + float f = float(j)/columns; + palette1.appendColor(QColor::fromHsvF(i/8.0,1-f,0.5+f/2)); + palette2.appendColor(QColor::fromHsvF(i/8.0,1-f,1-f)); + } + } + color_widgets::ColorPaletteModel *model = new color_widgets::ColorPaletteModel; + model->setParent(wid); + model->addPalette(palette1, false); + model->addPalette(palette2, false); + wid->setModel(model); + + return wid; +} + +QString ColorPaletteWidget_Plugin::name() const +{ + return "color_widgets::ColorPaletteWidget"; +} + +QString ColorPaletteWidget_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon ColorPaletteWidget_Plugin::icon() const +{ + color_widgets::ColorPalette w; + w.setColumns(6); + for ( int i = 0; i < 4; i++ ) + { + for ( int j = 0; j < w.columns(); j++ ) + { + float f = float(j)/w.columns(); + w.appendColor(QColor::fromHsvF(i/5.0,1-f,0.5+f/2)); + } + } + return QIcon(w.preview(QSize(64,64))); +} + +QString ColorPaletteWidget_Plugin::toolTip() const +{ + return "A widget that displays a color palette"; +} + +QString ColorPaletteWidget_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool ColorPaletteWidget_Plugin::isContainer() const +{ + return false; +} + +QString ColorPaletteWidget_Plugin::domXml() const +{ + return "\n" + " \n" + " \n" + "\n"; +} + +QString ColorPaletteWidget_Plugin::includeFile() const +{ + return "QtColorWidgets/color_palette_widget.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_palette_widget_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_palette_widget_plugin.hpp new file mode 100644 index 00000000..06f6d72c --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_palette_widget_plugin.hpp @@ -0,0 +1,57 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_PALETTE_WIDGET_PLUGIN_HPP +#define COLOR_WIDGETS_COLOR_PALETTE_WIDGET_PLUGIN_HPP + +#include +#include + +class ColorPaletteWidget_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + ColorPaletteWidget_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + + +#endif // COLOR_WIDGETS_COLOR_PALETTE_WIDGET_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_preview_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_preview_plugin.cpp new file mode 100644 index 00000000..1b424659 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_preview_plugin.cpp @@ -0,0 +1,95 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_preview_plugin.hpp" +#include "QtColorWidgets/color_preview.hpp" +#include + + +ColorPreview_Plugin::ColorPreview_Plugin(QObject *parent) + : QObject(parent), initialized(false) +{ +} + + +void ColorPreview_Plugin::initialize(QDesignerFormEditorInterface *) +{ + if (initialized) + return; + + initialized = true; +} + +bool ColorPreview_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget *ColorPreview_Plugin::createWidget(QWidget *parent) +{ + return new color_widgets::ColorPreview(parent); +} + +QString ColorPreview_Plugin::name() const +{ + return "color_widgets::ColorPreview"; +} + +QString ColorPreview_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon ColorPreview_Plugin::icon() const +{ + return QIcon(); +} + +QString ColorPreview_Plugin::toolTip() const +{ + return "Display a color"; +} + +QString ColorPreview_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool ColorPreview_Plugin::isContainer() const +{ + return false; +} + +QString ColorPreview_Plugin::domXml() const +{ + + return "\n" + " \n" + " \n" + "\n"; +} + +QString ColorPreview_Plugin::includeFile() const +{ + return "QtColorWidgets/color_preview.hpp"; +} + +//Q_EXPORT_PLUGIN2(color_widgets, ColorPreview_Plugin); diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_preview_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_preview_plugin.hpp new file mode 100644 index 00000000..e1bd2c42 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_preview_plugin.hpp @@ -0,0 +1,55 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_PREVIEW_PLUGIN_HPP +#define COLOR_PREVIEW_PLUGIN_HPP + +#include + +class ColorPreview_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + ColorPreview_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + +#endif // COLOR_PREVIEW_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_selector_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_selector_plugin.cpp new file mode 100644 index 00000000..24d831f8 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_selector_plugin.cpp @@ -0,0 +1,92 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_selector_plugin.hpp" +#include "QtColorWidgets/color_selector.hpp" +#include + +ColorSelector_Plugin::ColorSelector_Plugin(QObject *parent) + : QObject(parent), initialized(false) +{ +} + + +void ColorSelector_Plugin::initialize(QDesignerFormEditorInterface *) +{ + if (initialized) + return; + + initialized = true; +} + +bool ColorSelector_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget *ColorSelector_Plugin::createWidget(QWidget *parent) +{ + return new color_widgets::ColorSelector(parent); +} + +QString ColorSelector_Plugin::name() const +{ + return "color_widgets::ColorSelector"; +} + +QString ColorSelector_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon ColorSelector_Plugin::icon() const +{ + return QIcon(); +} + +QString ColorSelector_Plugin::toolTip() const +{ + return "Display a color and opens a color dialog on click"; +} + +QString ColorSelector_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool ColorSelector_Plugin::isContainer() const +{ + return false; +} + +QString ColorSelector_Plugin::domXml() const +{ + + return "\n" + " \n" + " \n" + "\n"; +} + +QString ColorSelector_Plugin::includeFile() const +{ + return "QtColorWidgets/color_selector.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_selector_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_selector_plugin.hpp new file mode 100644 index 00000000..a03ab155 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_selector_plugin.hpp @@ -0,0 +1,55 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_SELECTOR_PLUGIN_HPP +#define COLOR_SELECTOR_PLUGIN_HPP + +#include + +class ColorSelector_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + ColorSelector_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + +#endif // COLOR_SELECTOR_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_wheel_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_wheel_plugin.cpp new file mode 100644 index 00000000..1cde3229 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_wheel_plugin.cpp @@ -0,0 +1,97 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_wheel_plugin.hpp" +#include "QtColorWidgets/color_wheel.hpp" + +ColorWheel_Plugin::ColorWheel_Plugin(QObject *parent) : + QObject(parent), initialized(false) +{ +} + +void ColorWheel_Plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool ColorWheel_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget *ColorWheel_Plugin::createWidget(QWidget *parent) +{ + return new color_widgets::ColorWheel(parent); +} + +QString ColorWheel_Plugin::name() const +{ + return "color_widgets::ColorWheel"; +} + +QString ColorWheel_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon ColorWheel_Plugin::icon() const +{ + color_widgets::ColorWheel w; + w.resize(64,64); + w.setWheelWidth(8); + QPixmap pix(64,64); + w.render(&pix); + return QIcon(pix); +} + +QString ColorWheel_Plugin::toolTip() const +{ + return "A widget that allows an intuitive selection of HSL parameters for a QColor"; +} + +QString ColorWheel_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool ColorWheel_Plugin::isContainer() const +{ + return false; +} + +QString ColorWheel_Plugin::domXml() const +{ + return "\n" + " \n" + " \n" + " \n" + " 0\n" + " 0\n" + " \n" + " \n" + " \n" + "\n"; +} + +QString ColorWheel_Plugin::includeFile() const +{ + return "QtColorWidgets/color_wheel.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_wheel_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_wheel_plugin.hpp new file mode 100644 index 00000000..921323f7 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_wheel_plugin.hpp @@ -0,0 +1,57 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WHEEL_PLUGIN_HPP +#define COLOR_WHEEL_PLUGIN_HPP + +#include +#include + +class ColorWheel_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + ColorWheel_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + + +#endif // COLOR_WHEEL_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_widget_plugin_collection.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_widget_plugin_collection.cpp new file mode 100644 index 00000000..10bf5e1a --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_widget_plugin_collection.cpp @@ -0,0 +1,56 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "color_widget_plugin_collection.hpp" +#include "color_preview_plugin.hpp" +#include "color_wheel_plugin.hpp" +#include "gradient_slider_plugin.hpp" +#include "hue_slider_plugin.hpp" +#include "color_selector_plugin.hpp" +#include "color_list_plugin.hpp" +#include "swatch_plugin.hpp" +#include "color_palette_widget_plugin.hpp" +#include "color_2d_slider_plugin.hpp" +#include "color_line_edit_plugin.hpp" +#include "gradient_editor_plugin.hpp" +// add new plugin headers above this line + +ColorWidgets_PluginCollection::ColorWidgets_PluginCollection(QObject *parent) : + QObject(parent) +{ + widgets.push_back(new ColorPreview_Plugin(this)); + widgets.push_back(new ColorWheel_Plugin(this)); + widgets.push_back(new GradientSlider_Plugin(this)); + widgets.push_back(new HueSlider_Plugin(this)); + widgets.push_back(new ColorSelector_Plugin(this)); + widgets.push_back(new ColorListWidget_Plugin(this)); + widgets.push_back(new Swatch_Plugin(this)); + widgets.push_back(new ColorPaletteWidget_Plugin(this)); + widgets.push_back(new Color2DSlider_Plugin(this)); + widgets.push_back(new ColorLineEdit_Plugin(this)); + widgets.push_back(new GradientEditor_Plugin(this)); + // add new plugins above this line +} + +QList ColorWidgets_PluginCollection::customWidgets() const +{ + return widgets; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_widget_plugin_collection.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_widget_plugin_collection.hpp new file mode 100644 index 00000000..d58ca5df --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/color_widget_plugin_collection.hpp @@ -0,0 +1,43 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGET_PLUGIN_COLLECTION_HPP +#define COLOR_WIDGET_PLUGIN_COLLECTION_HPP + +#include + +class ColorWidgets_PluginCollection : public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "mattia.basaglia.ColorWidgetsPlugin") + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit ColorWidgets_PluginCollection(QObject *parent = 0); + + QList customWidgets() const; + + private: + QList widgets; + +}; + +#endif // COLOR_WIDGET_PLUGIN_COLLECTION_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_editor_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_editor_plugin.cpp new file mode 100644 index 00000000..c679eb9c --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_editor_plugin.cpp @@ -0,0 +1,98 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "gradient_editor_plugin.hpp" +#include "QtColorWidgets/gradient_editor.hpp" + +QWidget* GradientEditor_Plugin::createWidget(QWidget *parent) +{ + color_widgets::GradientEditor *widget = new color_widgets::GradientEditor(parent); + return widget; +} + +QIcon GradientEditor_Plugin::icon() const +{ + color_widgets::GradientEditor w; + w.resize(64,16); + QGradientStops cols; + cols.push_back({0.2, Qt::green}); + cols.push_back({0.5, Qt::yellow}); + cols.push_back({0.8, Qt::red}); + w.setStops(cols); + QPixmap pix(64,64); + pix.fill(Qt::transparent); + w.render(&pix, QPoint(0,16)); + return QIcon(pix); +} + +QString GradientEditor_Plugin::domXml() const +{ + return "\n" + " \n" + " \n" + "\n"; +} + +bool GradientEditor_Plugin::isContainer() const +{ + return false; +} + +GradientEditor_Plugin::GradientEditor_Plugin(QObject *parent) : + QObject(parent), initialized(false) +{ +} + +void GradientEditor_Plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool GradientEditor_Plugin::isInitialized() const +{ + return initialized; +} + +QString GradientEditor_Plugin::name() const +{ + return "color_widgets::GradientEditor"; +} + +QString GradientEditor_Plugin::group() const +{ + return "Color Widgets"; +} + +QString GradientEditor_Plugin::toolTip() const +{ + return "Widget to edit gradient stops"; +} + +QString GradientEditor_Plugin::whatsThis() const +{ + return toolTip(); +} + +QString GradientEditor_Plugin::includeFile() const +{ + return "QtColorWidgets/gradient_editor.hpp"; +} + diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_editor_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_editor_plugin.hpp new file mode 100644 index 00000000..77fb19b7 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_editor_plugin.hpp @@ -0,0 +1,58 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_GRADIENT_EDITOR_PLUGIN_HPP +#define COLOR_WIDGETS_GRADIENT_EDITOR_PLUGIN_HPP + +#include +#include + +class GradientEditor_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + explicit GradientEditor_Plugin(QObject *parent = nullptr); + + void initialize(QDesignerFormEditorInterface *core) Q_DECL_OVERRIDE; + bool isInitialized() const Q_DECL_OVERRIDE; + + QWidget *createWidget(QWidget *parent) Q_DECL_OVERRIDE; + + QString name() const Q_DECL_OVERRIDE; + QString group() const Q_DECL_OVERRIDE; + QIcon icon() const Q_DECL_OVERRIDE; + QString toolTip() const Q_DECL_OVERRIDE; + QString whatsThis() const Q_DECL_OVERRIDE; + bool isContainer() const Q_DECL_OVERRIDE; + + QString domXml() const Q_DECL_OVERRIDE; + + QString includeFile() const Q_DECL_OVERRIDE; + +private: + bool initialized; +}; + + +#endif // COLOR_WIDGETS_GRADIENT_EDITOR_PLUGIN_HPP + diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_slider_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_slider_plugin.cpp new file mode 100644 index 00000000..82e43571 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_slider_plugin.cpp @@ -0,0 +1,102 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "gradient_slider_plugin.hpp" +#include "QtColorWidgets/gradient_slider.hpp" +#include + +GradientSlider_Plugin::GradientSlider_Plugin(QObject *parent) + : QObject(parent), initialized(false) +{ +} + + +void GradientSlider_Plugin::initialize(QDesignerFormEditorInterface *) +{ + if (initialized) + return; + + initialized = true; +} + +bool GradientSlider_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget *GradientSlider_Plugin::createWidget(QWidget *parent) +{ + return new color_widgets::GradientSlider(parent); +} + +QString GradientSlider_Plugin::name() const +{ + return "color_widgets::GradientSlider"; +} + +QString GradientSlider_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon GradientSlider_Plugin::icon() const +{ + color_widgets::GradientSlider w; + w.resize(64,16); + QVector cols; + cols.push_back(Qt::green); + cols.push_back(Qt::yellow); + cols.push_back(Qt::red); + w.setColors(cols); + QPixmap pix(64,64); + pix.fill(Qt::transparent); + w.render(&pix,QPoint(0,16)); + return QIcon(pix); +} + +QString GradientSlider_Plugin::toolTip() const +{ + return "Slider over a gradient"; +} + +QString GradientSlider_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool GradientSlider_Plugin::isContainer() const +{ + return false; +} + +QString GradientSlider_Plugin::domXml() const +{ + + return "\n" + " \n" + " \n" + "\n"; +} + +QString GradientSlider_Plugin::includeFile() const +{ + return "QtColorWidgets/gradient_slider.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_slider_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_slider_plugin.hpp new file mode 100644 index 00000000..5d98035c --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/gradient_slider_plugin.hpp @@ -0,0 +1,34 @@ +#ifndef GRADIENT_SLIDER_PLUGIN_HPP +#define GRADIENT_SLIDER_PLUGIN_HPP + +#include + +class GradientSlider_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + GradientSlider_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + +#endif // GRADIENT_SLIDER_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/hue_slider_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/hue_slider_plugin.cpp new file mode 100644 index 00000000..27cd6c6a --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/hue_slider_plugin.cpp @@ -0,0 +1,98 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2014 Calle Laakkonen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "hue_slider_plugin.hpp" +#include "QtColorWidgets/hue_slider.hpp" +#include + +HueSlider_Plugin::HueSlider_Plugin(QObject *parent) + : QObject(parent), initialized(false) +{ +} + + +void HueSlider_Plugin::initialize(QDesignerFormEditorInterface *) +{ + if (initialized) + return; + + initialized = true; +} + +bool HueSlider_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget *HueSlider_Plugin::createWidget(QWidget *parent) +{ + return new color_widgets::HueSlider(parent); +} + +QString HueSlider_Plugin::name() const +{ + return "color_widgets::HueSlider"; +} + +QString HueSlider_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon HueSlider_Plugin::icon() const +{ + color_widgets::HueSlider w; + w.resize(64,16); + QPixmap pix(64,64); + pix.fill(Qt::transparent); + w.render(&pix,QPoint(0,16)); + return QIcon(pix); +} + +QString HueSlider_Plugin::toolTip() const +{ + return "Slider over a hue gradient"; +} + +QString HueSlider_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool HueSlider_Plugin::isContainer() const +{ + return false; +} + +QString HueSlider_Plugin::domXml() const +{ + + return "\n" + " \n" + " \n" + "\n"; +} + +QString HueSlider_Plugin::includeFile() const +{ + return "QtColorWidgets/hue_slider.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/hue_slider_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/hue_slider_plugin.hpp new file mode 100644 index 00000000..78f08ce8 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/hue_slider_plugin.hpp @@ -0,0 +1,34 @@ +#ifndef HUE_SLIDER_PLUGIN_HPP +#define HUE_SLIDER_PLUGIN_HPP + +#include + +class HueSlider_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + HueSlider_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + +#endif // HUE_SLIDER_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/new_plugin b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/new_plugin new file mode 100644 index 00000000..285d8062 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/new_plugin @@ -0,0 +1,236 @@ +#!/bin/bash +# +# Copyright (C) 2013-2020 Mattia Basaglia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +SELFDIR=$(dirname $(readlink -se "${BASH_SOURCE[0]}")) + +function class_to_underscore() +{ + echo "$1" | sed -r -e 's/([a-z])([A-Z])/\1_\L\2/g' -e 's/[A-Z]/\L\0/g' +} + +function class_to_header() +{ + echo "$(class_to_underscore "$1").hpp" +} + +function header_to_source() +{ + echo "$1" | sed -r -e 's/\.h(pp)?$/.cpp/i' +} + +function read_arg() +{ + varname=$1 + prompt="$2" + default="$3" + [ "$default" ] && prompt="${prompt} [$default]" + read -p "$prompt: " -i "$default" $varname + [ -z "${!varname}" ] && eval "$varname=\"$default\"" +} + +function header_to_guard() +{ + echo "$1" | tr [:lower:] [:upper:] | tr /. _ +} + +read_arg class "Class name" +[ -z "$class" ] && exit 1 +read_arg description "Description" +read_arg header "Header" "$(class_to_header "$class")" + +read_arg plugin "Plugin Class" "${class}_Plugin" +read_arg plugin_header "Plugin Header" "$(class_to_header "$plugin")" +read_arg plugin_source "Plugin Source" "$(header_to_source "$plugin_header")" +read_arg plugin_path "Plugin Path" "$SELFDIR" +read_arg plugin_author "Author" "$(git config user.name)" +read_arg plugin_copyright "Copyright" "2013-$(date +%Y) $plugin_author" + +echo "Summary:" +echo " Class: $class" +echo " Description: $description" +echo " Header: $header" +echo " Plugin Class: $plugin" +echo " Plugin Header: $plugin_header" +echo " Plugin Source: $plugin_source" +echo " Plugin Path: $plugin_path" +echo " Author: $plugin_author" +echo " Copyright: $plugin_copyright" + +object_name="$(class_to_underscore $class)" + +cat >"$plugin_path/$plugin_source" <. + * + */ +#include "$plugin_header" +#include "QtColorWidgets/$header" + +QWidget* $plugin::createWidget(QWidget *parent) +{ + color_widgets::$class *widget = new color_widgets::$class(parent); + return widget; +} + +QIcon $plugin::icon() const +{ + return QIcon(); +} + +QString $plugin::domXml() const +{ + return "\n" + " \n" + " \n" + "\n"; +} + +bool $plugin::isContainer() const +{ + return false; +} + +$plugin::$plugin(QObject *parent) : + QObject(parent), initialized(false) +{ +} + +void $plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool $plugin::isInitialized() const +{ + return initialized; +} + +QString $plugin::name() const +{ + return "color_widgets::$class"; +} + +QString $plugin::group() const +{ + return "Color Widgets"; +} + +QString $plugin::toolTip() const +{ + return "$description"; +} + +QString $plugin::whatsThis() const +{ + return toolTip(); +} + +QString $plugin::includeFile() const +{ + return "QtColorWidgets/$header"; +} + +PLUGIN + +header_guard="COLOR_WIDGETS_$(header_to_guard "$plugin_header")" +cat >"$plugin_path/$plugin_header" <. + * + */ +#ifndef $header_guard +#define $header_guard + +#include +#include + +class $plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + explicit $plugin(QObject *parent = nullptr); + + void initialize(QDesignerFormEditorInterface *core) Q_DECL_OVERRIDE; + bool isInitialized() const Q_DECL_OVERRIDE; + + QWidget *createWidget(QWidget *parent) Q_DECL_OVERRIDE; + + QString name() const Q_DECL_OVERRIDE; + QString group() const Q_DECL_OVERRIDE; + QIcon icon() const Q_DECL_OVERRIDE; + QString toolTip() const Q_DECL_OVERRIDE; + QString whatsThis() const Q_DECL_OVERRIDE; + bool isContainer() const Q_DECL_OVERRIDE; + + QString domXml() const Q_DECL_OVERRIDE; + + QString includeFile() const Q_DECL_OVERRIDE; + +private: + bool initialized; +}; + + +#endif // $header_guard + +PLUGIN + +sed -i -r \ + -e "\\~# add new sources above this line~i\\$plugin_source" \ + -e "\\~# add new headers above this line~i\\$plugin_header" \ + "$plugin_path/CMakeLists.txt" + +sed -i -r \ + -e "\\~// add new plugin headers above this line~i#include \"$plugin_header\"" \ + -e "\\~// add new plugins above this line~i\ widgets.push_back(new $plugin(this));" \ + "$plugin_path/color_widget_plugin_collection.cpp" diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/swatch_plugin.cpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/swatch_plugin.cpp new file mode 100644 index 00000000..3c9b465a --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/swatch_plugin.cpp @@ -0,0 +1,106 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "swatch_plugin.hpp" +#include "QtColorWidgets/swatch.hpp" + +Swatch_Plugin::Swatch_Plugin(QObject *parent) : + QObject(parent), initialized(false) +{ +} + +void Swatch_Plugin::initialize(QDesignerFormEditorInterface *) +{ + initialized = true; +} + +bool Swatch_Plugin::isInitialized() const +{ + return initialized; +} + +QWidget* Swatch_Plugin::createWidget(QWidget *parent) +{ + color_widgets::Swatch *wid = new color_widgets::Swatch(parent); + wid->palette().setColumns(12); + for ( int i = 0; i < 6; i++ ) + { + for ( int j = 0; j < wid->palette().columns(); j++ ) + { + float f = float(j)/wid->palette().columns(); + wid->palette().appendColor(QColor::fromHsvF(i/8.0,1-f,0.5+f/2)); + } + } + return wid; +} + +QString Swatch_Plugin::name() const +{ + return "color_widgets::Swatch"; +} + +QString Swatch_Plugin::group() const +{ + return "Color Widgets"; +} + +QIcon Swatch_Plugin::icon() const +{ + color_widgets::ColorPalette w; + w.setColumns(6); + for ( int i = 0; i < 4; i++ ) + { + for ( int j = 0; j < w.columns(); j++ ) + { + float f = float(j)/w.columns(); + w.appendColor(QColor::fromHsvF(i/5.0,1-f,0.5+f/2)); + } + } + return QIcon(w.preview(QSize(64,64))); +} + +QString Swatch_Plugin::toolTip() const +{ + return "A widget that displays a color palette"; +} + +QString Swatch_Plugin::whatsThis() const +{ + return toolTip(); +} + +bool Swatch_Plugin::isContainer() const +{ + return false; +} + +QString Swatch_Plugin::domXml() const +{ + return "\n" + " \n" + " \n" + "\n"; +} + +QString Swatch_Plugin::includeFile() const +{ + return "QtColorWidgets/swatch.hpp"; +} diff --git a/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/swatch_plugin.hpp b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/swatch_plugin.hpp new file mode 100644 index 00000000..4670c60d --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/color_widgets_designer_plugin/swatch_plugin.hpp @@ -0,0 +1,57 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_SWATCH_PLUGIN_HPP +#define COLOR_WIDGETS_SWATCH_PLUGIN_HPP + +#include +#include + +class Swatch_Plugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + Swatch_Plugin(QObject *parent = 0); + + void initialize(QDesignerFormEditorInterface *core); + bool isInitialized() const; + + QWidget *createWidget(QWidget *parent); + + QString name() const; + QString group() const; + QIcon icon() const; + QString toolTip() const; + QString whatsThis() const; + bool isContainer() const; + + QString domXml() const; + + QString includeFile() const; + +private: + bool initialized; +}; + + +#endif // COLOR_WIDGETS_SWATCH_PLUGIN_HPP diff --git a/thirdparty/Qt-Color-Widgets/gallery/CMakeLists.txt b/thirdparty/Qt-Color-Widgets/gallery/CMakeLists.txt new file mode 100644 index 00000000..7ec618c4 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/gallery/CMakeLists.txt @@ -0,0 +1,48 @@ +# +# Copyright (C) 2013-2020 Mattia Basaglia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +set (QT_SUPPORTED_VERSIONS 5) + +select_qt ( + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + QT_DEFAULT_VERSION 5) + +set (REQUIRED_QT_COMPONENTS + Widgets + ) +find_qt ( + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + REQUIRED_COMPONENTS "${REQUIRED_QT_COMPONENTS}" + OPTIONAL_COMPONENTS "") + +set(SCREENSHOT_SOURCES screenshot.cpp) +set(SCREENSHOT_BINARY screenshot_bin) + +add_executable(${SCREENSHOT_BINARY} EXCLUDE_FROM_ALL ${SCREENSHOT_SOURCES}) + +use_qt ( + TARGET_NAME ${SCREENSHOT_BINARY} + QT_SUPPORTED_VERSIONS "${QT_SUPPORTED_VERSIONS}" + REQUIRED_COMPONENTS "${REQUIRED_QT_COMPONENTS}" + OPTIONAL_COMPONENTS "") +target_link_libraries(${SCREENSHOT_BINARY} + PRIVATE + ${COLOR_WIDGETS_LIBRARY}) + +add_custom_target(gallery + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${SCREENSHOT_BINARY} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${SCREENSHOT_BINARY} +) diff --git a/thirdparty/Qt-Color-Widgets/gallery/Color2DSlider.png b/thirdparty/Qt-Color-Widgets/gallery/Color2DSlider.png new file mode 100644 index 00000000..caed3b2b Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/Color2DSlider.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorDialog.png b/thirdparty/Qt-Color-Widgets/gallery/ColorDialog.png new file mode 100644 index 00000000..b28de516 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorDialog.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorLineEdit.png b/thirdparty/Qt-Color-Widgets/gallery/ColorLineEdit.png new file mode 100644 index 00000000..13439a85 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorLineEdit.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorLineEdit_with_color.png b/thirdparty/Qt-Color-Widgets/gallery/ColorLineEdit_with_color.png new file mode 100644 index 00000000..052b0418 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorLineEdit_with_color.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorListWidget.png b/thirdparty/Qt-Color-Widgets/gallery/ColorListWidget.png new file mode 100644 index 00000000..9f43dc70 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorListWidget.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorPaletteWidget.png b/thirdparty/Qt-Color-Widgets/gallery/ColorPaletteWidget.png new file mode 100644 index 00000000..c9a06b3c Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorPaletteWidget.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorPaletteWidget_readonly.png b/thirdparty/Qt-Color-Widgets/gallery/ColorPaletteWidget_readonly.png new file mode 100644 index 00000000..659e7ea8 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorPaletteWidget_readonly.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorPreview.png b/thirdparty/Qt-Color-Widgets/gallery/ColorPreview.png new file mode 100644 index 00000000..0751b3f8 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorPreview.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/ColorWheel.png b/thirdparty/Qt-Color-Widgets/gallery/ColorWheel.png new file mode 100644 index 00000000..49212fc0 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/ColorWheel.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/GradientEditor.png b/thirdparty/Qt-Color-Widgets/gallery/GradientEditor.png new file mode 100644 index 00000000..9a920749 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/GradientEditor.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/GradientListModel_combo.png b/thirdparty/Qt-Color-Widgets/gallery/GradientListModel_combo.png new file mode 100644 index 00000000..417aeb7a Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/GradientListModel_combo.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/GradientListModel_view.png b/thirdparty/Qt-Color-Widgets/gallery/GradientListModel_view.png new file mode 100644 index 00000000..2da2c3ac Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/GradientListModel_view.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/HueSlider.png b/thirdparty/Qt-Color-Widgets/gallery/HueSlider.png new file mode 100644 index 00000000..58261670 Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/HueSlider.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/README.md b/thirdparty/Qt-Color-Widgets/gallery/README.md new file mode 100644 index 00000000..a3a7cb99 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/gallery/README.md @@ -0,0 +1,91 @@ +Color Widgets +============= + +Color2DSlider +------------- +![Color2DSlider](Color2DSlider.png) + +This widget allow the user to select 2 HSV color components at the same time, +by default that is Saturation and Value but they can be changed. + +ColorDialog +----------- +![ColorDialog](ColorDialog.png) + +This is a dialog analogous to QColorDialog but with a much nicer and friendlier +user interface. It uses several of the other widgets. + +ColorLineEdit +------------- +![ColorLineEdit](ColorLineEdit.png) +![ColorLineEdit with color preview](ColorLineEdit_with_color.png) + +This is a QLineEdit intended to be used to edit and display color names. +It accepts several string formats: +* #f00 (3 hexadecimal rgb digits) +* #ff0000 (6 hexadecimal rgb digits) +* rgb(255,0,0) (function-like) +* red (color name) + +It can optionally display the color it represents on its background. + +ColorListWidget +--------------- +![ColorListWidget](ColorListWidget.png) + +It allows to display and edit a list of colors. + +ColorPaletteWidget and Swatch +----------------------------- +These widgets handle color palettes. + +![Swatch](Swatch.png) + +**Swatch** only handles a single palette, can be used to just select colors from the +palette or to modify the palette via drag and drop operations. + +**ColorPaletteModel** is a list model that represents palettes with can be used +with the Qt item view widgets, it provides a name and a preview icon for +each of the stored palettes. +It also has functionality to load and save palettes from the filesystem. + +![Read-only ColorPaletteWidget](ColorPaletteWidget_readonly.png) +![ColorPaletteWidget](ColorPaletteWidget.png) + +**ColorPaletteWidget** manages a list of palettes (via **ColorPaletteModel**). +Has two modes: read-only only allows to select palettes and colors, +otherwise it can be used to modify the list of palettes and the palette itself. + +ColorPreview and ColorSelector +------------------------------ +![ColorPreview](ColorPreview.png) + +**ColorPreview** is a widget that displays a color or compares two colors. + +**ColorSelector** is like **ColorPreview** but when clicked it shows a ColorDialog. + +GradientSlider and HueSlider +---------------------------- +![HueSlider](HueSlider.png) + +**GradientSlider** is a QSlider which uses a gradient as its background. + +**HueSlider** is specifically made to select a hue and has more information +about the represented color. + + +GradientEditor +-------------- +![GradientEditor](GradientEditor.png) + +**GradientEditor** is similar in appearance to **GradientSlider** but it's for editing the gradient. + + +GradientListModel and GradientDelegate +-------------------------------------- +![GradientListModel](GradientListModel_combo.png) +![GradientListModel](GradientListModel_view.png) + +**GradientListModel** is a QAbstractListModel used to list gradients (useful for combo boxes, item views and the like). + +**GradientDelegate** is an item delegate to edit gradients in an item view. diff --git a/thirdparty/Qt-Color-Widgets/gallery/Swatch.png b/thirdparty/Qt-Color-Widgets/gallery/Swatch.png new file mode 100644 index 00000000..68e8d4fd Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/gallery/Swatch.png differ diff --git a/thirdparty/Qt-Color-Widgets/gallery/screenshot.cpp b/thirdparty/Qt-Color-Widgets/gallery/screenshot.cpp new file mode 100644 index 00000000..a322af0f --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/gallery/screenshot.cpp @@ -0,0 +1,213 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include +#include + +#include +#include +#include +#include +#include + +#include "QtColorWidgets/color_2d_slider.hpp" +#include "QtColorWidgets/color_delegate.hpp" /// \todo show it +#include "QtColorWidgets/color_dialog.hpp" +#include "QtColorWidgets/color_line_edit.hpp" +#include "QtColorWidgets/color_list_widget.hpp" +#include "QtColorWidgets/color_palette_widget.hpp" +#include "QtColorWidgets/color_preview.hpp" +#include "QtColorWidgets/color_wheel.hpp" +#include "QtColorWidgets/harmony_color_wheel.hpp" +#include "QtColorWidgets/hue_slider.hpp" +#include "QtColorWidgets/gradient_editor.hpp" +#include "QtColorWidgets/gradient_list_model.hpp" +#include "QtColorWidgets/gradient_delegate.hpp" + +bool run = false; +QStringList just_these; + +void screenshot(QWidget& widget, QString name = QString()) +{ + if ( name.isEmpty() ) + { + name = widget.metaObject()->className(); + name.remove("color_widgets::"); + } + if ( !just_these.isEmpty() && !just_these.contains(name) ) + return; + + widget.setWindowTitle(name); + QPixmap pic(widget.size()); + widget.render(&pic); + name += ".png"; + pic.save(name); + if ( run ) + widget.show(); +} + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QCommandLineParser parser; + parser.addHelpOption(); + parser.addPositionalArgument("just_these", "Only these widgets"); + QCommandLineOption run_option("run", "Show widgets instead of saving to file"); + parser.addOption(run_option); + + parser.process(a); + run = parser.isSet(run_option); + just_these = parser.positionalArguments(); + + QColor demo_color(64,172,143,128); + + color_widgets::ColorPalette palette1; + color_widgets::ColorPalette palette2; + int palette_columns = 12; + palette1.setName("Palette 1"); + palette2.setName("Palette 2"); + palette1.setColumns(palette_columns); + palette2.setColumns(palette_columns); + for ( int i = 0; i < 6; i++ ) + { + for ( int j = 0; j < palette_columns; j++ ) + { + float f = float(j)/palette_columns; + palette1.appendColor(QColor::fromHsvF(i/8.0,1-f,0.5+f/2)); + palette2.appendColor(QColor::fromHsvF(i/8.0,1-f,1-f)); + } + } + color_widgets::ColorPaletteModel palette_model; + palette_model.addPalette(palette1, false); + palette_model.addPalette(palette2, false); + + + color_widgets::ColorPreview preview; + preview.setColor(demo_color); + preview.setDisplayMode(color_widgets::ColorPreview::SplitAlpha); + preview.resize(128,32); + screenshot(preview); + + color_widgets::ColorDialog dialog; + dialog.setColorSpace(color_widgets::ColorWheel::ColorLCH); + dialog.setColor(demo_color); + screenshot(dialog); + + color_widgets::Color2DSlider slider2d; + slider2d.setColor(demo_color); + slider2d.resize(128,192); + screenshot(slider2d); + + color_widgets::ColorLineEdit line_edit; + line_edit.setColor(demo_color); + line_edit.resize(line_edit.sizeHint()); + screenshot(line_edit); + line_edit.setPreviewColor(true); + screenshot(line_edit, "ColorLineEdit_with_color"); + + color_widgets::ColorWheel wheel; + wheel.resize(256, 256); + wheel.setColor(demo_color); + screenshot(wheel); + + color_widgets::HarmonyColorWheel harwheel; + harwheel.resize(256, 256); + harwheel.setColor(demo_color); + harwheel.addHarmony(.333, true); + harwheel.addHarmony(.667, true); + screenshot(harwheel); + + color_widgets::Swatch swatch; + swatch.setPalette(palette1); + swatch.resize(swatch.sizeHint()); + screenshot(swatch); + + color_widgets::ColorPaletteWidget palette_widget; + palette_widget.setModel(&palette_model); + screenshot(palette_widget); + palette_widget.setReadOnly(true); + screenshot(palette_widget, "ColorPaletteWidget_readonly"); + + color_widgets::HueSlider hue_slider; + hue_slider.setColor(demo_color); + hue_slider.resize(192, hue_slider.sizeHint().height()); +// hue_slider.setInvertedAppearance(true); +// hue_slider.setOrientation(Qt::Vertical); + screenshot(hue_slider); + + color_widgets::ColorListWidget list_widget; + list_widget.setColors({ + demo_color, + palette1.colorAt(palette_columns*0), + palette1.colorAt(palette_columns*1), + palette1.colorAt(palette_columns*3), + palette1.colorAt(palette_columns*5), + }); + list_widget.resize(list_widget.sizeHint()); + screenshot(list_widget); + + color_widgets::GradientEditor editor; + QGradientStops gradient_colors; + float n_colors = 4; + for ( int i = 0; i <= n_colors; ++i ) + gradient_colors.append(QGradientStop(i/n_colors, QColor::fromHsvF(i/n_colors, 0.5, 1))); + editor.setStops(gradient_colors); + screenshot(editor); + + QComboBox gradient_list; + color_widgets::GradientListModel gradient_model; + gradient_model.setGradient("Rainbow", gradient_colors); + gradient_model.setGradient("Black to Transparent", QGradientStops{{0, Qt::black}, {1, QColor(0, 0, 0, 0)}}); + gradient_list.setModel(&gradient_model); + gradient_model.setIconSize(QSize(128, 24)); + gradient_list.setIconSize(gradient_model.iconSize()); + QObject::connect(&editor, &color_widgets::GradientEditor::stopsChanged, &gradient_model, + [&gradient_model](const QGradientStops& stops){ gradient_model.setGradient("Rainbow", stops); }); + gradient_list.resize(gradient_list.sizeHint()); + screenshot(gradient_list, "GradientListModel_combo"); + + QListView gradient_view; + color_widgets::GradientDelegate gradient_delegate; + gradient_view.setItemDelegate(&gradient_delegate); + gradient_view.setModel(&gradient_model); +// gradient_model.setEditMode(color_widgets::GradientListModel::EditName); + gradient_model.setEditMode(color_widgets::GradientListModel::EditGradient); + gradient_view.resize(QSize(gradient_view.sizeHintForColumn(0) + 4, gradient_view.sizeHint().height())); + screenshot(gradient_view, "GradientListModel_view"); + + QTableWidget gradient_table; + gradient_table.setItemDelegate(&gradient_delegate); + gradient_table.setRowCount(2); + gradient_table.setColumnCount(2); + gradient_table.setItem(0, 0, new QTableWidgetItem()); + gradient_table.item(0, 0)->setData(Qt::EditRole, QVariant::fromValue(gradient_model.gradientBrush(0))); + gradient_table.setItem(0, 1, new QTableWidgetItem(gradient_model.nameFromIndex(0))); + gradient_table.setItem(1, 0, new QTableWidgetItem()); + gradient_table.item(1, 0)->setData(Qt::EditRole, QVariant::fromValue(gradient_model.gradientBrush(1))); + gradient_table.setItem(1, 1, new QTableWidgetItem(gradient_model.nameFromIndex(1))); + screenshot(gradient_table, "GradientDelegate_table"); + + if ( run ) + return a.exec(); + + return 0; +} diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/AbstractWidgetList b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/AbstractWidgetList new file mode 100644 index 00000000..32d4d0e6 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/AbstractWidgetList @@ -0,0 +1 @@ +#include "abstract_widget_list.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/BoundColorSelector b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/BoundColorSelector new file mode 100644 index 00000000..bd4d6514 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/BoundColorSelector @@ -0,0 +1 @@ +#include "bound_color_selector.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/CMakeLists.txt b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/CMakeLists.txt new file mode 100644 index 00000000..e182d44c --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/CMakeLists.txt @@ -0,0 +1,37 @@ +set (HEADERS +abstract_widget_list.hpp +bound_color_selector.hpp +color_2d_slider.hpp +color_delegate.hpp +color_dialog.hpp +color_line_edit.hpp +color_list_widget.hpp +color_names.hpp +color_palette.hpp +color_palette_model.hpp +color_palette_widget.hpp +color_preview.hpp +color_selector.hpp +color_wheel.hpp +colorwidgets_global.hpp +gradient_slider.hpp +hue_slider.hpp +swatch.hpp +gradient_editor.hpp +harmony_color_wheel.hpp +gradient_list_model.hpp +gradient_delegate.hpp +) + +file(RELATIVE_PATH + PREFIX + ${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_LIST_DIR}) + + +foreach (HEADER IN LISTS HEADERS) + target_sources (${TARGET_NAME} + PRIVATE + $ + $) +endforeach (HEADER IN HEADERS) diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorDelegate b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorDelegate new file mode 100644 index 00000000..0068a341 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorDelegate @@ -0,0 +1 @@ +#include "color_delegate.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorDialog b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorDialog new file mode 100644 index 00000000..ffaa02b9 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorDialog @@ -0,0 +1 @@ +#include "color_dialog.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorListWidget b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorListWidget new file mode 100644 index 00000000..e0d281b4 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorListWidget @@ -0,0 +1 @@ +#include "color_list_widget.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorPreview b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorPreview new file mode 100644 index 00000000..bfd4165e --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorPreview @@ -0,0 +1 @@ +#include "color_preview.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorSelector b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorSelector new file mode 100644 index 00000000..9b09fc8a --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorSelector @@ -0,0 +1 @@ +#include "color_selector.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorWheel b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorWheel new file mode 100644 index 00000000..ed17f683 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/ColorWheel @@ -0,0 +1 @@ +#include "color_wheel.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientEditor b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientEditor new file mode 100644 index 00000000..b90265eb --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientEditor @@ -0,0 +1 @@ +#include "gradient_editor.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientListModel b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientListModel new file mode 100644 index 00000000..b6a5ef7b --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientListModel @@ -0,0 +1 @@ +#include "gradient_list_model.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientSlider b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientSlider new file mode 100644 index 00000000..b8035fda --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/GradientSlider @@ -0,0 +1 @@ +#include "gradient_slider.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/HarmonyColorWheel b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/HarmonyColorWheel new file mode 100644 index 00000000..693e6478 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/HarmonyColorWheel @@ -0,0 +1 @@ +#include "harmony_color_wheel.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/HueSlider b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/HueSlider new file mode 100644 index 00000000..df6786e3 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/HueSlider @@ -0,0 +1 @@ +#include "hue_slider.hpp" diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/abstract_widget_list.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/abstract_widget_list.hpp new file mode 100644 index 00000000..cd8d6f88 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/abstract_widget_list.hpp @@ -0,0 +1,110 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef ABSTRACT_WIDGET_LIST_HPP +#define ABSTRACT_WIDGET_LIST_HPP + +#include "colorwidgets_global.hpp" + +#include +#include + +class QCP_EXPORT AbstractWidgetList : public QWidget +{ + Q_OBJECT +public: + explicit AbstractWidgetList(QWidget *parent = 0); + ~AbstractWidgetList(); + + /** + * \brief Get the number of items + */ + int count() const; + + /** + * \brief Swap row a and row b + */ + virtual void swap(int a, int b) = 0; + + + /// Whether the given row index is valid + bool isValidRow(int i) const { return i >= 0 && i < count(); } + + void setRowHeight(int row, int height); + + +public Q_SLOTS: + /** + * \brief Remove row i + */ + void remove(int i); + + /** + * \brief append a default row + */ + virtual void append() = 0; + +Q_SIGNALS: + void removed(int i); + +protected: + + /** + * \brief Create a new row with the given widget + * + * Must be caled by implementations of append() + */ + void appendWidget(QWidget* w); + + /** + * \brief get the widget found at the given row + */ + QWidget* widget(int i); + + + /** + * \brief get the widget found at the given row + */ + template + T* widget_cast(int i) { return qobject_cast(widget(i)); } + + /** + * \brief clear all rows without emitting signals + * + * May be useful when implementation want to set all values at once + */ + void clear(); + +private Q_SLOTS: + void remove_clicked(QWidget* w); + void up_clicked(QWidget* w); + void down_clicked(QWidget* w); + +private: + class Private; + Private * const p; + + QWidget* create_button(QWidget* data, QSignalMapper*mapper, + QString icon_name, QString text, + QString tooltip = QString()) const; +}; + +#endif // ABSTRACT_WIDGET_LIST_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/bound_color_selector.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/bound_color_selector.hpp new file mode 100644 index 00000000..5d782939 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/bound_color_selector.hpp @@ -0,0 +1,44 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef BOUND_COLOR_SELECTOR_HPP +#define BOUND_COLOR_SELECTOR_HPP + +#include "color_selector.hpp" + +namespace color_widgets { +/** + * \brief A color selector bound to a color reference + * \todo Maybe this can be removed + */ +class QCP_EXPORT BoundColorSelector : public ColorSelector +{ + Q_OBJECT +private: + QColor* ref; +public: + explicit BoundColorSelector(QColor* reference, QWidget *parent = 0); + +private Q_SLOTS: + void update_reference(QColor); +}; +} // namespace color_widgets +#endif // BOUND_COLOR_SELECTOR_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_2d_slider.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_2d_slider.hpp new file mode 100644 index 00000000..51c67d00 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_2d_slider.hpp @@ -0,0 +1,128 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_2D_SLIDER_HPP +#define COLOR_WIDGETS_COLOR_2D_SLIDER_HPP + +#include "colorwidgets_global.hpp" +#include + +namespace color_widgets { + +/** + * \brief A 2D slider that edits 2 color components + */ +class QCP_EXPORT Color2DSlider : public QWidget +{ + Q_OBJECT + + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true STORED false ) + Q_PROPERTY(qreal hue READ hue WRITE setHue DESIGNABLE false ) + Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation DESIGNABLE false ) + Q_PROPERTY(qreal value READ value WRITE setValue DESIGNABLE false ) + /** + * \brief Which color component is used on the x axis + */ + Q_PROPERTY(Component componentX READ componentX WRITE setComponentX NOTIFY componentXChanged) + /** + * \brief Which color component is used on the y axis + */ + Q_PROPERTY(Component componentY READ componentY WRITE setComponentY NOTIFY componentYChanged) + + +public: + enum Component { + Hue, Saturation, Value + }; + Q_ENUMS(Component) + + explicit Color2DSlider(QWidget *parent = nullptr); + ~Color2DSlider(); + + /// Get current color + QColor color() const; + + QSize sizeHint() const Q_DECL_OVERRIDE; + + /// Get current hue in the range [0-1] + qreal hue() const; + + /// Get current saturation in the range [0-1] + qreal saturation() const; + + /// Get current value in the range [0-1] + qreal value() const; + + Component componentX() const; + Component componentY() const; + +public Q_SLOTS: + + /// Set current color + void setColor(const QColor& c); + + /** + * @param h Hue [0-1] + */ + void setHue(qreal h); + + /** + * @param s Saturation [0-1] + */ + void setSaturation(qreal s); + + /** + * @param v Value [0-1] + */ + void setValue(qreal v); + + void setComponentX(Component componentX); + void setComponentY(Component componentY); + +Q_SIGNALS: + /** + * Emitted when the user selects a color or setColor is called + */ + void colorChanged(QColor); + + /** + * Emitted when the user selects a color + */ + void colorSelected(QColor); + + void componentXChanged(Component componentX); + void componentYChanged(Component componentY); + +protected: + void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent* event) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE; + void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE; + +private: + class Private; + Private * const p; +}; + +} // namespace color_widgets + +#endif // COLOR_WIDGETS_COLOR_2D_SLIDER_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_delegate.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_delegate.hpp new file mode 100644 index 00000000..7be2ab78 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_delegate.hpp @@ -0,0 +1,54 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_DELEGATE_HPP +#define COLOR_DELEGATE_HPP + +#include "colorwidgets_global.hpp" + +#include + +namespace color_widgets { + +/** + Delegate to use a ColorSelector in a color list +*/ +class QCP_EXPORT ColorDelegate : public QAbstractItemDelegate +{ + Q_OBJECT +public: + explicit ColorDelegate(QWidget *parent = 0); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const Q_DECL_OVERRIDE; + + bool editorEvent(QEvent* event, + QAbstractItemModel* model, + const QStyleOptionViewItem & option, + const QModelIndex & index) override; + + virtual QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const Q_DECL_OVERRIDE; +}; + +} // namespace color_widgets + +#endif // COLOR_DELEGATE_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_dialog.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_dialog.hpp new file mode 100644 index 00000000..16ac8164 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_dialog.hpp @@ -0,0 +1,162 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_DIALOG_HPP +#define COLOR_DIALOG_HPP + +#include "colorwidgets_global.hpp" +#include "color_preview.hpp" +#include "color_wheel.hpp" + +#include + +class QAbstractButton; + +namespace color_widgets { + +class QCP_EXPORT ColorDialog : public QDialog +{ + Q_OBJECT + Q_ENUMS(ButtonMode) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true) + Q_PROPERTY(ColorWheel::ShapeEnum wheelShape READ wheelShape WRITE setWheelShape NOTIFY wheelShapeChanged) + Q_PROPERTY(ColorWheel::ColorSpaceEnum colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged) + Q_PROPERTY(bool wheelRotating READ wheelRotating WRITE setWheelRotating NOTIFY wheelRotatingChanged) + /** + * \brief whether the color alpha channel can be edited. + * + * If alpha is disabled, the selected color's alpha will always be 255. + */ + Q_PROPERTY(bool alphaEnabled READ alphaEnabled WRITE setAlphaEnabled NOTIFY alphaEnabledChanged) + +public: + enum ButtonMode { + OkCancel, + OkApplyCancel, + Close + }; + + explicit ColorDialog(QWidget *parent = 0, Qt::WindowFlags f = 0); + + ~ColorDialog(); + + /** + * Get currently selected color + */ + QColor color() const; + + /** + * Set the display mode for the color preview + */ + void setPreviewDisplayMode(ColorPreview::DisplayMode mode); + + /** + * Get the color preview diplay mode + */ + ColorPreview::DisplayMode previewDisplayMode() const; + + bool alphaEnabled() const; + + /** + * Select which dialog buttons to show + * + * There are three predefined modes: + * OkCancel - this is useful when the dialog is modal and we just want to return a color + * OkCancelApply - this is for non-modal dialogs + * Close - for non-modal dialogs with direct color updates via colorChanged signal + */ + void setButtonMode(ButtonMode mode); + ButtonMode buttonMode() const; + + QSize sizeHint() const; + + ColorWheel::ShapeEnum wheelShape() const; + ColorWheel::ColorSpaceEnum colorSpace() const; + bool wheelRotating() const; + +public Q_SLOTS: + + /** + * Change color + */ + void setColor(const QColor &c); + + /** + * Set the current color and show the dialog + */ + void showColor(const QColor &oldcolor); + + void setWheelShape(ColorWheel::ShapeEnum shape); + void setColorSpace(ColorWheel::ColorSpaceEnum space); + void setWheelRotating(bool rotating); + + /** + * Set whether the color alpha channel can be edited. + * If alpha is disabled, the selected color's alpha will always be 255. + */ + void setAlphaEnabled(bool a); + +Q_SIGNALS: + /** + * The current color was changed + */ + void colorChanged(QColor); + + /** + * The user selected the new color by pressing Ok/Apply + */ + void colorSelected(QColor); + + void wheelShapeChanged(ColorWheel::ShapeEnum shape); + void colorSpaceChanged(ColorWheel::ColorSpaceEnum space); + void wheelRotatingChanged(bool rotating); + + void alphaEnabledChanged(bool alphaEnabled); + +private Q_SLOTS: + /// Update all the Ui elements to match the selected color + void setColorInternal(const QColor &color); + /// Update from HSV sliders + void set_hsv(); + /// Update from RGB sliders + void set_rgb(); + /// Update from Alpha slider + void set_alpha(); + + void on_edit_hex_colorChanged(const QColor& color); + void on_edit_hex_colorEditingFinished(const QColor& color); + + void on_buttonBox_clicked(QAbstractButton*); + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent * event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + +private: + class Private; + Private * const p; +}; + +} // namespace color_widgets + +#endif // COLOR_DIALOG_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_line_edit.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_line_edit.hpp new file mode 100644 index 00000000..05643adc --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_line_edit.hpp @@ -0,0 +1,98 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_LINE_EDIT_HPP +#define COLOR_WIDGETS_COLOR_LINE_EDIT_HPP + +#include "colorwidgets_global.hpp" +#include +#include + +namespace color_widgets { + +/** + * \brief A line edit used to define a color name + * + * Supported string formats: + * * Short hex strings #f00 + * * Long hex strings #ff0000 + * * Color names red + * * Function-like rgb(255,0,0) + * + * Additional string formats supported when showAlpha is true: + * * Long hex strings #ff0000ff + * * Function like rgba(255,0,0,255) + */ +class QCP_EXPORT ColorLineEdit : public QLineEdit +{ + Q_OBJECT + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + /** + * \brief Whether the widget displays and edits the alpha channel + */ + Q_PROPERTY(bool showAlpha READ showAlpha WRITE setShowAlpha NOTIFY showAlphaChanged) + /** + * \brief If \b true, the background of the widget is changed to show the color + */ + Q_PROPERTY(bool previewColor READ previewColor WRITE setPreviewColor NOTIFY previewColorChanged) + +public: + explicit ColorLineEdit(QWidget* parent = nullptr); + ~ColorLineEdit(); + + QColor color() const; + bool showAlpha() const; + bool previewColor() const; + +public Q_SLOTS: + void setColor(const QColor& color); + void setShowAlpha(bool showAlpha); + void setPreviewColor(bool previewColor); + +Q_SIGNALS: + /** + * \brief Emitted when the color is changed by any means + */ + void colorChanged(const QColor& color); + /** + * \brief Emitted when the user is typing a color but has not finished yet + */ + void colorEdited(const QColor& color); + /** + * \brief Emitted when the user finished to edit a string + */ + void colorEditingFinished(const QColor& color); + + void showAlphaChanged(bool showAlpha); + void previewColorChanged(bool previewColor); + +protected: + void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent * event) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE; + +private: + class Private; + Private* p; +}; + +} // namespace color_widgets +#endif // COLOR_WIDGETS_COLOR_LINE_EDIT_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_list_widget.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_list_widget.hpp new file mode 100644 index 00000000..1f7ca9a2 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_list_widget.hpp @@ -0,0 +1,78 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_LIST_WIDGET_HPP +#define COLOR_LIST_WIDGET_HPP + +#include "abstract_widget_list.hpp" +#include "color_wheel.hpp" + +namespace color_widgets { + +class QCP_EXPORT ColorListWidget : public AbstractWidgetList +{ + Q_OBJECT + + Q_PROPERTY(QList colors READ colors WRITE setColors NOTIFY colorsChanged ) + Q_PROPERTY(ColorWheel::ShapeEnum wheelShape READ wheelShape WRITE setWheelShape NOTIFY wheelShapeChanged) + Q_PROPERTY(ColorWheel::ColorSpaceEnum colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged) + Q_PROPERTY(bool wheelRotating READ wheelRotating WRITE setWheelRotating NOTIFY wheelRotatingChanged) + +public: + explicit ColorListWidget(QWidget *parent = 0); + ~ColorListWidget(); + + QList colors() const; + void setColors(const QList& colors); + + void swap(int a, int b); + + void append(); + + ColorWheel::ShapeEnum wheelShape() const; + ColorWheel::ColorSpaceEnum colorSpace() const; + bool wheelRotating() const; + +Q_SIGNALS: + void colorsChanged(const QList&); + void wheelShapeChanged(ColorWheel::ShapeEnum shape); + void colorSpaceChanged(ColorWheel::ColorSpaceEnum space); + void wheelRotatingChanged(bool rotating); + +public Q_SLOTS: + void setWheelShape(ColorWheel::ShapeEnum shape); + void setColorSpace(ColorWheel::ColorSpaceEnum space); + void setWheelRotating(bool rotating); + +private Q_SLOTS: + void emit_changed(); + void handle_removed(int); + void color_changed(int row); + +private: + class Private; + Private * const p; + void append_widget(int col); +}; + +} // namespace color_widgets + +#endif // COLOR_LIST_WIDGET_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_names.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_names.hpp new file mode 100644 index 00000000..1273999c --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_names.hpp @@ -0,0 +1,57 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_NAMES_HPP +#define COLOR_WIDGETS_COLOR_NAMES_HPP + +#include +#include + +#include + +namespace color_widgets { + +/** + * \brief Convert a string into a color + * + * Supported string formats: + * * Short hex strings #f00 + * * Long hex strings #ff0000 + * * Color names red + * * Function-like rgb(255,0,0) + * + * Additional string formats supported only when \p alpha is true: + * * Long hex strings #ff0000ff + * * Function like rgba(255,0,0,255) + */ +QCP_EXPORT QColor colorFromString(const QString& string, bool alpha = true); + +/** + * \brief Convert a color into a string + * + * Format: + * * If the color has full alpha: #ff0000 + * * If alpha is true and the color has non-full alpha: #ff000088 + */ +QCP_EXPORT QString stringFromColor(const QColor& color, bool alpha = true); + +} // namespace color_widgets +#endif // COLOR_WIDGETS_COLOR_NAMES_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette.hpp new file mode 100644 index 00000000..55797ba8 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette.hpp @@ -0,0 +1,229 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_PALETTE_HPP +#define COLOR_WIDGETS_COLOR_PALETTE_HPP + +#include +#include +#include +#include +#include +#include +#include "colorwidgets_global.hpp" + +namespace color_widgets { + +class QCP_EXPORT ColorPalette : public QObject +{ + Q_OBJECT + + /** + * \brief The list of colors + */ + Q_PROPERTY(QVector colors READ colors WRITE setColors NOTIFY colorsChanged) + /** + * \brief Name of the palette + */ + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + /** + * \brief Number of colors to display in a row, if 0 unspecified + */ + Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged) + /** + * \brief Number of colors + */ + Q_PROPERTY(int count READ count) + /** + * \brief Name of the file the palette has been read from + */ + Q_PROPERTY(QString fileName READ fileName WRITE setFileName NOTIFY fileNameChanged) + /** + * \brief Whether it has been modified and it might be advisable to save it + */ + Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) + +public: + typedef QPair value_type; + + ColorPalette(const QVector& colors, const QString& name = QString(), int columns = 0); + ColorPalette(const QVector >& colors, const QString& name = QString(), int columns = 0); + explicit ColorPalette(const QString& name = QString()); + ColorPalette(const ColorPalette& other); + ColorPalette& operator=(const ColorPalette& other); + ~ColorPalette(); + ColorPalette(ColorPalette&& other); + ColorPalette& operator=(ColorPalette&& other); + + /** + * \brief Color at the given index + */ + Q_INVOKABLE QColor colorAt(int index) const; + + /** + * \brief Color name at the given index + */ + Q_INVOKABLE QString nameAt(int index) const; + + QVector > colors() const; + QVector onlyColors() const; + + int count() const; + int columns(); + + QString name() const; + + /** + * \brief Use a color table to set the colors + */ + Q_INVOKABLE void loadColorTable(const QVector& color_table); + + /** + * \brief Convert to a color table + */ + Q_INVOKABLE QVector colorTable() const; + + /** + * \brief Creates a ColorPalette from a color table + */ + static ColorPalette fromColorTable(const QVector& table); + + /** + * \brief Use the pixels on an image to set the palette colors + */ + Q_INVOKABLE bool loadImage(const QImage& image); + + /** + * \brief Creates a ColorPalette from a Gimp palette (gpl) file + */ + static ColorPalette fromImage(const QImage& image); + + /** + * \brief Load contents from a Gimp palette (gpl) file + * \returns \b true On Success + * \note If this function returns \b false, the palette will become empty + */ + Q_INVOKABLE bool load(const QString& name); + + /** + * \brief Creates a ColorPalette from a Gimp palette (gpl) file + */ + static ColorPalette fromFile(const QString& name); + + QString fileName() const; + + bool dirty() const; + + /** + * \brief Returns a preview image of the colors in the palette + */ + QPixmap preview(const QSize& size, const QColor& background=Qt::transparent) const; + +public Q_SLOTS: + void setColumns(int columns); + + void setColors(const QVector& colors); + void setColors(const QVector >& colors); + + /** + * \brief Change the color at the given index + */ + void setColorAt(int index, const QColor& color); + /** + * \brief Change the color at the given index + */ + void setColorAt(int index, const QColor& color, const QString& name); + /** + * \brief Change the name of a color + */ + void setNameAt(int index, const QString& name = QString()); + /** + * \brief Append a color at the end + */ + void appendColor(const QColor& color, const QString& name = QString()); + /** + * \brief Insert a color in an arbitrary location + */ + void insertColor(int index, const QColor& color, const QString& name = QString()); + /** + * \brief Remove the color at the given index + */ + void eraseColor(int index); + + /** + * \brief Change file name and save + * \returns \b true on success + */ + bool save(const QString& filename); + /** + * \brief save to file, the filename is \c fileName or determined automatically + * \returns \b true on success + */ + bool save(); + + void setName(const QString& name); + void setFileName(const QString& name); + void setDirty(bool dirty); + +Q_SIGNALS: + /** + * \brief Emitted when all the colors have changed + */ + void colorsChanged(const QVector >&); + void columnsChanged(int); + void nameChanged(const QString&); + void fileNameChanged(const QString&); + void dirtyChanged(bool); + /** + * \brief Emitted when the color or the name at the given index has been modified + */ + void colorChanged(int index); + /** + * \brief Emitted when the color at the given index has been removed + */ + void colorRemoved(int index); + /** + * \brief Emitted when a single color has been added + */ + void colorAdded(int index); + /** + * \brief Emitted when the colors have been modified with a simple operation (set, append etc.) + */ + void colorsUpdated(const QVector>&); + +private: + /** + * \brief Returns \c name if it isn't null, otherwise a default value + */ + QString unnamed(const QString& name = QString()) const; + + /** + * \brief Emit all the necessary signals when the palette has been completely overwritten + */ + void emitUpdate(); + + class Private; + Private *p; +}; + +} // namespace color_widgets + +#endif // COLOR_WIDGETS_COLOR_PALETTE_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette_model.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette_model.hpp new file mode 100644 index 00000000..045786b9 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette_model.hpp @@ -0,0 +1,140 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_PALETTE_MODEL_HPP +#define COLOR_WIDGETS_COLOR_PALETTE_MODEL_HPP + +#include +#include "color_palette.hpp" + +namespace color_widgets { + +class QCP_EXPORT ColorPaletteModel : public QAbstractListModel +{ + Q_OBJECT + /** + * \brief List of directories to be scanned for palette files + */ + Q_PROPERTY(QStringList searchPaths READ searchPaths WRITE setSearchPaths NOTIFY searchPathsChanged) + + /** + * \brief Default directory to be used when saving a palette + */ + Q_PROPERTY(QString savePath READ savePath WRITE setSavePath NOTIFY savePathChanged) + + /** + * \brief Size of the icon used for the palette previews + */ + Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged) + + +public: + ColorPaletteModel(); + ~ColorPaletteModel(); + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()) Q_DECL_OVERRIDE; + + QString savePath() const; + QStringList searchPaths() const; + QSize iconSize() const; + + /** + * \brief Number of palettes + */ + int count() const; + + /** + * \brief Returns a reference to the first palette with the given name + * \pre hasPalette(name) + */ + const ColorPalette& palette(const QString& name) const; + + /** + * \brief Whether a palette with the given name exists in the model + */ + bool hasPalette(const QString& name) const; + + /** + * \brief Get the palette at the given index (row) + * \pre 0 <= index < count() + */ + const ColorPalette& palette(int index) const; + + /** + * \brief Updates an existing palette + * \param index Palette index + * \param palette New palette + * \param save Whether to save the palette to the filesystem + * + * Saving will try: (in this order) + * * To overwrite the file pointed by the old palette + * * To write to the new palette file name + * * To create a file in the save path + * If all of the above fail, the palette will be replaced interally + * but not on the filesystem + * + * \returns \b true if the palette has been successfully updated (and saved) + */ + bool updatePalette(int index, const ColorPalette& palette, bool save = true); + + /** + * \brief Remove a palette from the model and optionally from the filesystem + * \returns \b true if the palette has been successfully removed + */ + bool removePalette(int index, bool remove_file = true); + + /** + * \brief Remove a palette to the model and optionally to the filesystem + * \returns \b true if the palette has been successfully added + */ + bool addPalette(const ColorPalette& palette, bool save = true); + + /** + * \brief The index of the palette with the given file name + * \returns -1 if none is found + */ + int indexFromFile(const QString& filename) const; + +public Q_SLOTS: + void setSavePath(const QString& savePath); + void setSearchPaths(const QStringList& searchPaths); + void addSearchPath(const QString& path); + void setIconSize(const QSize& iconSize); + + /** + * \brief Load palettes files found in the search paths + */ + void load(); + +Q_SIGNALS: + void savePathChanged(const QString& savePath); + void searchPathsChanged(const QStringList& searchPaths); + void iconSizeChanged(const QSize& iconSize); + +private: + class Private; + Private* p; +}; + +} // namespace color_widgets + +#endif // COLOR_WIDGETS_COLOR_PALETTE_MODEL_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette_widget.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette_widget.hpp new file mode 100644 index 00000000..34d45de2 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_palette_widget.hpp @@ -0,0 +1,187 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_COLOR_PALETTE_WIDGET_HPP +#define COLOR_WIDGETS_COLOR_PALETTE_WIDGET_HPP + +#include +#include +#include "color_palette_model.hpp" +#include "swatch.hpp" + +namespace color_widgets { + +/** + * \brief A widget to use and modify palettes + */ +class QCP_EXPORT ColorPaletteWidget : public QWidget +{ + Q_OBJECT + + /** + * \brief Model used to store the palettes + */ + Q_PROPERTY(ColorPaletteModel* model READ model WRITE setModel NOTIFY modelChanged) + + /** + * \brief Size of a single color in the swatch widget + */ + Q_PROPERTY(QSize colorSize READ colorSize WRITE setColorSize NOTIFY colorSizeChanged) + /** + * \brief Policy for colorSize + **/ + Q_PROPERTY(color_widgets::Swatch::ColorSizePolicy colorSizePolicy READ colorSizePolicy WRITE setColorSizePolicy NOTIFY colorSizePolicyChanged) + + /** + * \brief Border around the colors + */ + Q_PROPERTY(QPen border READ border WRITE setBorder NOTIFY borderChanged) + + /** + * \brief Forces the Swatch to display that many rows of colors + * + * If there are too few elements, the widget will display less than this + * many rows. + * + * A value of0 means that the number of rows is automatic. + * + * \note Conflicts with forcedColumns + */ + Q_PROPERTY(int forcedRows READ forcedRows WRITE setForcedRows NOTIFY forcedRowsChanged) + + /** + * \brief Forces the Swatch to display that many columns of colors + * + * If there are too few elements, the widget will display less than this + * many columns. + * + * A value of 0 means that the number of columns is automatic. + * + * \note Conflicts with forcedRows + */ + Q_PROPERTY(int forcedColumns READ forcedColumns WRITE setForcedColumns NOTIFY forcedColumnsChanged) + + /** + * \brief Whether the palettes can be modified via user interaction + */ + Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly NOTIFY readOnlyChanged) + + /** + * \brief Currently selected color + */ + Q_PROPERTY(QColor currentColor READ currentColor WRITE setCurrentColor NOTIFY currentColorChanged) + + /** + * \brief Currently selected model row + */ + Q_PROPERTY(int currentRow READ currentRow WRITE setCurrentRow NOTIFY currentRowChanged) + + /** + * \brief Palette shown by the widget + */ + Q_PROPERTY(const ColorPalette& currentPalette READ currentPalette NOTIFY currentPaletteChanged) + +public: + ColorPaletteWidget(QWidget* parent = nullptr); + ~ColorPaletteWidget(); + + ColorPaletteModel* model() const; + + /** + * \brief Currently selected palette + * \pre model() != nullptr and there is a selected palette + */ + const ColorPalette& currentPalette() const; + + QSize colorSize() const; + Swatch::ColorSizePolicy colorSizePolicy() const; + QPen border() const; + + int forcedRows() const; + int forcedColumns() const; + + bool readOnly() const; + QColor currentColor() const; + + int currentRow() const; + +public Q_SLOTS: + void setModel(ColorPaletteModel* model); + void setColorSize(const QSize& colorSize); + void setColorSizePolicy(Swatch::ColorSizePolicy colorSizePolicy); + void setBorder(const QPen& border); + void setForcedRows(int forcedRows); + void setForcedColumns(int forcedColumns); + void setReadOnly(bool readOnly); + /** + * \brief Clear the selected color + */ + void clearCurrentColor(); + /** + * \brief Attempt to select a color + * + * If the given color is available in the current palete, it will be selected + * \return \b true on success + */ + bool setCurrentColor(const QColor& color); + /** + * \brief Attempt to select a color by name + * + * If the given color is available in the current palete, it will be selected + * \return \b true on success + */ + bool setCurrentColor(const QString& name); + /** + * \brief Attempt to select a color by index + * + * If the given color is available in the current palete, it will be selected + * \return \b true on success + */ + bool setCurrentColor(int index); + /** + * \brief Set the selected row in the model + */ + void setCurrentRow(int currentRow); + +Q_SIGNALS: + void modelChanged(ColorPaletteModel* model); + void colorSizeChanged(const QSize& colorSize); + void colorSizePolicyChanged(Swatch::ColorSizePolicy colorSizePolicy); + void forcedRowsChanged(int forcedRows); + void forcedColumnsChanged(int forcedColumns); + void readOnlyChanged(bool readOnly); + void currentColorChanged(const QColor& currentColor); + void currentColorChanged(int index); + void borderChanged(const QPen& border); + void currentRowChanged(int currentRow); + void currentPaletteChanged(const ColorPalette& palette); + +private Q_SLOTS: + void on_palette_list_currentIndexChanged(int index); + void on_swatch_doubleClicked(int index); + +private: + class Private; + std::unique_ptr p; +}; + +} // namespace color_widgets +#endif // COLOR_WIDGETS_COLOR_PALETTE_WIDGET_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_preview.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_preview.hpp new file mode 100644 index 00000000..16060b82 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_preview.hpp @@ -0,0 +1,110 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2014 Calle Laakkonen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_PREVIEW_HPP +#define COLOR_PREVIEW_HPP + +#include "colorwidgets_global.hpp" + +#include + +namespace color_widgets { + +/** + * Simple widget that shows a preview of a color + */ +class QCP_EXPORT ColorPreview : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true) + Q_PROPERTY(QColor comparisonColor READ comparisonColor WRITE setComparisonColor NOTIFY comparisonColorChanged DESIGNABLE true) + Q_PROPERTY(DisplayMode display_mode READ displayMode WRITE setDisplayMode NOTIFY displayModeChanged DESIGNABLE true) + Q_PROPERTY(QBrush background READ background WRITE setBackground NOTIFY backgroundChanged DESIGNABLE true) + Q_ENUMS(DisplayMode) +public: + enum DisplayMode + { + NoAlpha, ///< Show current color with no transparency + AllAlpha, ///< show current color with transparency + SplitAlpha, ///< Show both solid and transparent side by side + SplitColor ///< Show current and comparison colors side by side + }; + Q_ENUMS(DisplayMode) + + explicit ColorPreview(QWidget *parent = 0); + ~ColorPreview(); + + /// Get the background visible under transparent colors + QBrush background() const; + + /// Change the background visible under transparent colors + void setBackground(const QBrush &bk); + + /// Get color display mode + DisplayMode displayMode() const; + + /// Set how transparent colors are handled + void setDisplayMode(DisplayMode dm); + + /// Get current color + QColor color() const; + + /// Get the comparison color + QColor comparisonColor() const; + + QSize sizeHint () const; + + void paint(QPainter &painter, QRect rect) const; + +public Q_SLOTS: + /// Set current color + void setColor(const QColor &c); + + /// Set the comparison color + void setComparisonColor(const QColor &c); + +Q_SIGNALS: + /// Emitted when the user clicks on the widget + void clicked(); + + /// Emitted on setColor + void colorChanged(QColor); + + void comparisonColorChanged(QColor); + void displayModeChanged(DisplayMode); + void backgroundChanged(const QBrush&); + +protected: + void paintEvent(QPaintEvent *); + void resizeEvent(QResizeEvent *); + void mouseReleaseEvent(QMouseEvent *ev); + void mouseMoveEvent(QMouseEvent *ev); + +private: + class Private; + Private * const p; +}; + +} // namespace color_widgets +Q_DECLARE_METATYPE(color_widgets::ColorPreview::DisplayMode) + +#endif // COLOR_PREVIEW_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_selector.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_selector.hpp new file mode 100644 index 00000000..3e84d05f --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_selector.hpp @@ -0,0 +1,97 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_SELECTOR_HPP +#define COLOR_SELECTOR_HPP + +#include "color_preview.hpp" +#include "color_wheel.hpp" + +namespace color_widgets { + +/** + * Color preview that opens a color dialog + */ +class QCP_EXPORT ColorSelector : public ColorPreview +{ + Q_OBJECT + Q_ENUMS(UpdateMode) + Q_PROPERTY(UpdateMode updateMode READ updateMode WRITE setUpdateMode NOTIFY updateModeChanged) + Q_PROPERTY(Qt::WindowModality dialogModality READ dialogModality WRITE setDialogModality NOTIFY dialogModalityChanged) + Q_PROPERTY(ColorWheel::ShapeEnum wheelShape READ wheelShape WRITE setWheelShape NOTIFY wheelShapeChanged) + Q_PROPERTY(ColorWheel::ColorSpaceEnum colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged) + Q_PROPERTY(bool wheelRotating READ wheelRotating WRITE setWheelRotating NOTIFY wheelRotatingChanged) + +public: + enum UpdateMode { + Confirm, ///< Update color only after the dialog has been accepted + Continuous ///< Update color as it's being modified in the dialog + }; + + explicit ColorSelector(QWidget *parent = 0); + ~ColorSelector(); + + void setUpdateMode(UpdateMode m); + UpdateMode updateMode() const; + + Qt::WindowModality dialogModality() const; + void setDialogModality(Qt::WindowModality m); + + ColorWheel::ShapeEnum wheelShape() const; + ColorWheel::ColorSpaceEnum colorSpace() const; + bool wheelRotating() const; + +Q_SIGNALS: + void wheelShapeChanged(ColorWheel::ShapeEnum shape); + void colorSpaceChanged(ColorWheel::ColorSpaceEnum space); + void wheelRotatingChanged(bool rotating); + void updateModeChanged(UpdateMode); + void dialogModalityChanged(Qt::WindowModality); + +public Q_SLOTS: + void showDialog(); + void setWheelShape(ColorWheel::ShapeEnum shape); + void setColorSpace(ColorWheel::ColorSpaceEnum space); + void setWheelRotating(bool rotating); + +private Q_SLOTS: + void accept_dialog(); + void reject_dialog(); + void update_old_color(const QColor &c); + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent * event); + +private: + /// Connect/Disconnect colorChanged based on UpdateMode + void connect_dialog(); + + /// Disconnect from dialog update + void disconnect_dialog(); + + class Private; + Private * const p; +}; + +} // namespace color_widgets + +#endif // COLOR_SELECTOR_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_utils.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_utils.hpp new file mode 100644 index 00000000..62c884a3 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_utils.hpp @@ -0,0 +1,77 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_UTILS_HPP +#define COLOR_UTILS_HPP + +#include +#include + +#include "QtColorWidgets/colorwidgets_global.hpp" + +namespace color_widgets { +namespace detail { + + +inline qreal color_chromaF(const QColor& c) +{ + qreal max = qMax(c.redF(), qMax(c.greenF(), c.blueF())); + qreal min = qMin(c.redF(), qMin(c.greenF(), c.blueF())); + return max - min; +} + +inline qreal color_lumaF(const QColor& c) +{ + return 0.30 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF(); +} +QColor color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha = 1 ); + +inline QColor rainbow_lch(qreal hue) +{ + return color_from_lch(hue,1,1); +} + +inline QColor rainbow_hsv(qreal hue) +{ + return QColor::fromHsvF(hue,1,1); +} + +inline qreal color_lightnessF(const QColor& c) +{ + return ( qMax(c.redF(),qMax(c.greenF(),c.blueF())) + + qMin(c.redF(),qMin(c.greenF(),c.blueF())) ) / 2; +} + +inline qreal color_HSL_saturationF(const QColor& col) +{ + qreal c = color_chromaF(col); + qreal l = color_lightnessF(col); + if ( qFuzzyCompare(l+1,1) || qFuzzyCompare(l+1,2) ) + return 0; + return c / (1-qAbs(2*l-1)); +} + +QCP_EXPORT QColor color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha = 1 ); + +} // namespace detail +} // namespace color_widgets + +#endif // COLOR_UTILS_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_wheel.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_wheel.hpp new file mode 100644 index 00000000..2b6e65e3 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_wheel.hpp @@ -0,0 +1,176 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WHEEL_HPP +#define COLOR_WHEEL_HPP + +#include + +#include "colorwidgets_global.hpp" + + +namespace color_widgets { + +/** + * \brief Display an analog widget that allows the selection of a HSV color + * + * It has an outer wheel to select the Hue and an intenal square to select + * Saturation and Lightness. + */ +class QCP_EXPORT ColorWheel : public QWidget +{ + Q_OBJECT + + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true STORED false ) + Q_PROPERTY(qreal hue READ hue WRITE setHue DESIGNABLE false ) + Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation DESIGNABLE false ) + Q_PROPERTY(qreal value READ value WRITE setValue DESIGNABLE false ) + Q_PROPERTY(unsigned wheelWidth READ wheelWidth WRITE setWheelWidth NOTIFY wheelWidthChanged DESIGNABLE true ) + Q_PROPERTY(ShapeEnum selectorShape READ selectorShape WRITE setSelectorShape NOTIFY selectorShapeChanged DESIGNABLE true ) + Q_PROPERTY(bool rotatingSelector READ rotatingSelector WRITE setRotatingSelector NOTIFY rotatingSelectorChanged DESIGNABLE true ) + Q_PROPERTY(ColorSpaceEnum colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged DESIGNABLE true ) + +public: + enum ShapeEnum + { + ShapeTriangle, ///< A triangle + ShapeSquare, ///< A square + }; + + enum AngleEnum + { + AngleFixed, ///< The inner part doesn't rotate + AngleRotating, ///< The inner part follows the hue selector + }; + + enum ColorSpaceEnum + { + ColorHSV, ///< Use the HSV color space + ColorHSL, ///< Use the HSL color space + ColorLCH, ///< Use Luma Chroma Hue (Y_601') + }; + + Q_ENUM(ShapeEnum); + Q_ENUM(AngleEnum); + Q_ENUM(ColorSpaceEnum); + + explicit ColorWheel(QWidget *parent = 0); + ~ColorWheel(); + + /// Get current color + QColor color() const; + + virtual QSize sizeHint() const Q_DECL_OVERRIDE; + + /// Get current hue in the range [0-1] + qreal hue() const; + + /// Get current saturation in the range [0-1] + qreal saturation() const; + + /// Get current value in the range [0-1] + qreal value() const; + + /// Get the width in pixels of the outer wheel + unsigned int wheelWidth() const; + + /// Set the width in pixels of the outer wheel + void setWheelWidth(unsigned int w); + + /// Shape of the internal selector + ShapeEnum selectorShape() const; + + /// Whether the internal selector should rotare in accordance with the hue + bool rotatingSelector() const; + + /// Color space used to preview/edit the color + ColorSpaceEnum colorSpace() const; + +public Q_SLOTS: + + /// Set current color + void setColor(QColor c); + + /** + * @param h Hue [0-1] + */ + void setHue(qreal h); + + /** + * @param s Saturation [0-1] + */ + void setSaturation(qreal s); + + /** + * @param v Value [0-1] + */ + void setValue(qreal v); + + /// Sets the shape of the internal selector + void setSelectorShape(ShapeEnum shape); + + /// Sets whether the internal selector should rotare in accordance with the hue + void setRotatingSelector(bool rotating); + + /// Sets the color space used to preview/edit the color + void setColorSpace(ColorSpaceEnum space); + +Q_SIGNALS: + /** + * Emitted when the user selects a color or setColor is called + */ + void colorChanged(QColor); + + /** + * Emitted when the user selects a color + */ + void colorSelected(QColor); + + void wheelWidthChanged(unsigned); + + void selectorShapeChanged(ShapeEnum shape); + + void rotatingSelectorChanged(bool rotating); + + void colorSpaceChanged(ColorSpaceEnum space); + +protected: + void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE; + void dragEnterEvent(QDragEnterEvent* event) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent* event) Q_DECL_OVERRIDE; + +protected: + class Private; + ColorWheel(QWidget *parent, Private* data); + Private* data() const { return p; } + +private: + Private * const p; + +}; + +} // namespace color_widgets + +#endif // COLOR_WHEEL_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_wheel_private.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_wheel_private.hpp new file mode 100644 index 00000000..60714cb7 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/color_wheel_private.hpp @@ -0,0 +1,284 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2017 caryoscelus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ + +#include "QtColorWidgets/color_wheel.hpp" +#include "QtColorWidgets/color_utils.hpp" + +#include +#include + +namespace color_widgets { + +enum MouseStatus +{ + Nothing, + DragCircle, + DragSquare +}; + +class ColorWheel::Private +{ +private: + ColorWheel * const w; + +public: + qreal hue, sat, val; + bool backgroundIsDark; + unsigned int wheel_width; + MouseStatus mouse_status; + QPixmap hue_ring; + QImage inner_selector; + std::vector inner_selector_buffer; + ColorSpaceEnum color_space = ColorHSV; + bool rotating_selector = true; + ShapeEnum selector_shape = ShapeTriangle; + QColor (*color_from)(qreal,qreal,qreal,qreal); + QColor (*rainbow_from_hue)(qreal); + int max_size = 128; + + Private(ColorWheel *widget) + : w(widget), hue(0), sat(0), val(0), + wheel_width(20), mouse_status(Nothing), + color_from(&QColor::fromHsvF), rainbow_from_hue(&detail::rainbow_hsv) + { + } + + void setup() + { + qreal backgroundValue = w->palette().background().color().valueF(); + backgroundIsDark = backgroundValue < 0.5; + } + + virtual ~Private(){} + + /// Calculate outer wheel radius from idget center + qreal outer_radius() const + { + return qMin(w->geometry().width(), w->geometry().height())/2; + } + + /// Calculate inner wheel radius from idget center + qreal inner_radius() const + { + return outer_radius()-wheel_width; + } + + /// Calculate the edge length of the inner square + qreal square_size() const + { + return inner_radius()*qSqrt(2); + } + + /// Calculate the height of the inner triangle + qreal triangle_height() const + { + return inner_radius()*3/2; + } + + /// Calculate the side of the inner triangle + qreal triangle_side() const + { + return inner_radius()*qSqrt(3); + } + + /// return line from center to given point + QLineF line_to_point(const QPoint &p) const + { + return QLineF (w->geometry().width()/2, w->geometry().height()/2, p.x(), p.y()); + } + + /** + * Ensures the internal image buffer is the correct size + * and that the QImage is associated to it + */ + void init_buffer(QSize size) + { + std::size_t linear_size = size.width() * size.height(); + if ( inner_selector_buffer.size() == linear_size ) + return; + inner_selector_buffer.resize(linear_size); + inner_selector = QImage( + reinterpret_cast(inner_selector_buffer.data()), + size.width(), + size.height(), + QImage::Format_RGB32 + ); + } + + void render_square() + { + int width = qMin(square_size(), max_size); + init_buffer(QSize(width, width)); + + for ( int y = 0; y < width; ++y ) + { + for ( int x = 0; x < width; ++x ) + { + QRgb color = color_from(hue,double(x)/width,double(y)/width,1).rgb(); + inner_selector_buffer[width * y + x] = color; + } + } + } + + /** + * \brief renders the selector as a triangle + * \note It's the same as a square with the edge with value=0 collapsed to a single point + */ + void render_triangle() + { + QSizeF size = selector_size(); + if ( size.height() > max_size ) + size *= max_size / size.height(); + + qreal ycenter = size.height()/2; + + QSize isize = size.toSize(); + init_buffer(isize); + + for (int x = 0; x < isize.width(); x++ ) + { + qreal pval = x / size.height(); + qreal slice_h = size.height() * pval; + for (int y = 0; y < isize.height(); y++ ) + { + qreal ymin = ycenter-slice_h/2; + qreal psat = qBound(0.0,(y-ymin)/slice_h,1.0); + QRgb color = color_from(hue,psat,pval,1).rgb(); + inner_selector_buffer[isize.width() * y + x] = color; + } + } + } + + /// Updates the inner image that displays the saturation-value selector + void render_inner_selector() + { + if ( selector_shape == ShapeTriangle ) + render_triangle(); + else + render_square(); + } + + /// Offset of the selector image + QPointF selector_image_offset() + { + if ( selector_shape == ShapeTriangle ) + return QPointF(-inner_radius(),-triangle_side()/2); + return QPointF(-square_size()/2,-square_size()/2); + } + + /** + * \brief Size of the selector when rendered to the screen + */ + QSizeF selector_size() + { + if ( selector_shape == ShapeTriangle ) + return QSizeF(triangle_height(), triangle_side()); + return QSizeF(square_size(), square_size()); + } + + + /// Rotation of the selector image + qreal selector_image_angle() + { + if ( selector_shape == ShapeTriangle ) + { + if ( rotating_selector ) + return -hue*360-60; + return -150; + } + else + { + if ( rotating_selector ) + return -hue*360-45; + else + return 180; + } + } + + /// Updates the outer ring that displays the hue selector + void render_ring() + { + hue_ring = QPixmap(outer_radius()*2,outer_radius()*2); + hue_ring.fill(Qt::transparent); + QPainter painter(&hue_ring); + painter.setRenderHint(QPainter::Antialiasing); + painter.setCompositionMode(QPainter::CompositionMode_Source); + + + const int hue_stops = 24; + QConicalGradient gradient_hue(0, 0, 0); + if ( gradient_hue.stops().size() < hue_stops ) + { + for ( double a = 0; a < 1.0; a+=1.0/(hue_stops-1) ) + { + gradient_hue.setColorAt(a,rainbow_from_hue(a)); + } + gradient_hue.setColorAt(1,rainbow_from_hue(0)); + } + + painter.translate(outer_radius(),outer_radius()); + + painter.setPen(Qt::NoPen); + painter.setBrush(QBrush(gradient_hue)); + painter.drawEllipse(QPointF(0,0),outer_radius(),outer_radius()); + + painter.setBrush(Qt::transparent);//palette().background()); + painter.drawEllipse(QPointF(0,0),inner_radius(),inner_radius()); + } + + void set_color(const QColor& c) + { + switch ( color_space ) + { + case ColorHSV: + hue = qMax(0.0, c.hsvHueF()); + sat = c.hsvSaturationF(); + val = c.valueF(); + break; + case ColorHSL: + hue = qMax(0.0, c.hueF()); + sat = detail::color_HSL_saturationF(c); + val = detail::color_lightnessF(c); + break; + case ColorLCH: + hue = qMax(0.0, c.hsvHueF()); + sat = detail::color_chromaF(c); + val = detail::color_lumaF(c); + break; + } + } + + void draw_ring_editor(double editor_hue, QPainter& painter, QColor color) { + painter.setPen(QPen(color,3)); + painter.setBrush(Qt::NoBrush); + QLineF ray(0, 0, outer_radius(), 0); + ray.setAngle(editor_hue*360); + QPointF h1 = ray.p2(); + ray.setLength(inner_radius()); + QPointF h2 = ray.p2(); + painter.drawLine(h1,h2); + } + +}; + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/colorwidgets_global.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/colorwidgets_global.hpp new file mode 100644 index 00000000..58d5fb62 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/colorwidgets_global.hpp @@ -0,0 +1,16 @@ +#ifndef QT_COLOR_WIDGETS_GLOBAL_H +#define QT_COLOR_WIDGETS_GLOBAL_H + +#include + +#define QTCOLORWIDGETS_STATICALLY_LINKED + +#if defined(QTCOLORWIDGETS_STATICALLY_LINKED) +# define QCP_EXPORT +#elif defined(QTCOLORWIDGETS_LIBRARY) +# define QCP_EXPORT Q_DECL_EXPORT +#else +# define QCP_EXPORT Q_DECL_IMPORT +#endif + +#endif // QT_COLOR_WIDGETS_GLOBAL_H diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_delegate.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_delegate.hpp new file mode 100644 index 00000000..7f2940f4 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_delegate.hpp @@ -0,0 +1,103 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ + +#ifndef COLOR_WIDGETS_GRADIENT_DELEGATE_HPP +#define COLOR_WIDGETS_GRADIENT_DELEGATE_HPP + + +#include +#include + +#include "QtColorWidgets/gradient_editor.hpp" + +namespace color_widgets { + +/** + * \brief Item delegate to edits gradients + * + * In order to make it work, return as edit data from the model a QBrush with a gradient + */ +class QCP_EXPORT GradientDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const Q_DECL_OVERRIDE + { + QVariant data = index.data(Qt::EditRole); + if ( data.canConvert() ) + { + QBrush brush = data.value(); + if ( brush.gradient() ) + { + GradientEditor* editor = new GradientEditor(parent); + editor->setStops(brush.gradient()->stops()); + return editor; + } + } + + return QStyledItemDelegate::createEditor(parent, option, index); + } + + void setModelData(QWidget * widget, QAbstractItemModel * model, const QModelIndex & index) const Q_DECL_OVERRIDE + { + if ( GradientEditor* editor = qobject_cast(widget) ) + model->setData(index, QBrush(editor->gradient()), Qt::EditRole); + else + QStyledItemDelegate::setModelData(widget, model, index); + } + + void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const Q_DECL_OVERRIDE + { + QVariant display_data = index.data(Qt::DisplayRole); + QVariant gradient_data = display_data.isValid() ? display_data : index.data(Qt::EditRole); + if ( gradient_data.canConvert() ) + { + QBrush brush = gradient_data.value(); + if ( brush.gradient() ) + { + QBrush background; + background.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png"))); + painter->fillRect(option.rect, background); + + QLinearGradient g(option.rect.topLeft(), option.rect.topRight()); + g.setStops(brush.gradient()->stops()); + painter->fillRect(option.rect, g); + + if ( option.state & QStyle::State_Selected ) + { + int border = 2; + painter->setBrush(Qt::transparent); + painter->setPen(QPen(option.palette.highlight(), border)); + painter->drawRect(option.rect.adjusted(border/2, border/2, -border/2, -border/2)); + } + return; + } + } + + QStyledItemDelegate::paint(painter, option, index); + } +}; + +} // namespace color_widgets + +#endif // COLOR_WIDGETS_GRADIENT_DELEGATE_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_editor.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_editor.hpp new file mode 100644 index 00000000..196f8670 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_editor.hpp @@ -0,0 +1,123 @@ +/** + * \file gradient_editor.hpp + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef GRADIENT_EDITOR_HPP +#define GRADIENT_EDITOR_HPP + +#include "colorwidgets_global.hpp" + +#include +#include + +namespace color_widgets { + +class ColorDialog; + +/** + * \brief A slider that moves on top of a gradient + */ +class QCP_EXPORT GradientEditor : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QBrush background READ background WRITE setBackground NOTIFY backgroundChanged) + Q_PROPERTY(QGradientStops stops READ stops WRITE setStops NOTIFY stopsChanged) + Q_PROPERTY(QLinearGradient gradient READ gradient WRITE setGradient) + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) + Q_PROPERTY(int selectedStop READ selectedStop WRITE setSelectedStop NOTIFY selectedStopChanged) + Q_PROPERTY(QColor selectedColor READ selectedColor WRITE setSelectedColor) + +public: + explicit GradientEditor(QWidget *parent = 0); + explicit GradientEditor(Qt::Orientation orientation, QWidget *parent = 0); + ~GradientEditor(); + + QSize sizeHint() const override; + + /// Get the background, it's visible for transparent gradient stops + QBrush background() const; + /// Set the background, it's visible for transparent gradient stops + void setBackground(const QBrush &bg); + + /// Get the colors that make up the gradient + QGradientStops stops() const; + /// Set the colors that make up the gradient + void setStops(const QGradientStops &colors); + + /// Get the gradient + QLinearGradient gradient() const; + /// Set the gradient + void setGradient(const QLinearGradient &gradient); + + Qt::Orientation orientation() const; + + /** + * \brief Dialog shown when double clicking a stop + */ + ColorDialog* dialog() const; + + /** + * \brief Index of the currently selected gradient stop (or -1 if there is no selection) + */ + int selectedStop() const; + + /** + * \brief Color of the selected stop + */ + QColor selectedColor() const; + +public Q_SLOTS: + void setOrientation(Qt::Orientation); + void setSelectedStop(int stop); + void setSelectedColor(const QColor& color); + void addStop(); + void removeStop(); + +Q_SIGNALS: + void backgroundChanged(const QBrush&); + void stopsChanged(const QGradientStops&); + void selectedStopChanged(int); + +protected: + void paintEvent(QPaintEvent *ev) override; + + void mousePressEvent(QMouseEvent *ev) override; + void mouseMoveEvent(QMouseEvent *ev) override; + void mouseReleaseEvent(QMouseEvent *ev) override; + void leaveEvent(QEvent * event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + + void dragEnterEvent(QDragEnterEvent *event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; + void dropEvent(QDropEvent* event) override; + +private Q_SLOTS: + void dialogUpdate(const QColor& c); + +private: + class Private; + Private * const p; +}; + +} // namespace color_widgets + +#endif // GRADIENT_EDITOR_HPP + diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_helper.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_helper.hpp new file mode 100644 index 00000000..a1a81112 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_helper.hpp @@ -0,0 +1,98 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef GRADIENT_HELPER_HPP +#define GRADIENT_HELPER_HPP + +#include "colorwidgets_global.hpp" + +#include + +namespace color_widgets { + +inline QColor blendColors(const QColor& a, const QColor& b, qreal ratio) +{ + return QColor::fromRgbF( + a.redF() * (1-ratio) + b.redF() * ratio, + a.greenF() * (1-ratio) + b.greenF() * ratio, + a.blueF() * (1-ratio) + b.blueF() * ratio, + a.alphaF() * (1-ratio) + b.alphaF() * ratio + ); +} + + +/** + * \brief Get an insertion point in the gradient + * \param gradient Gradient stops to look into (must be properly set up) + * \param factor Value in [0, 1] to get the color for + * \return A pair whose first element is the index to insert the new value at, and a GradientStop + */ +inline QPair Q_DECL_EXPORT gradientBlendedColorInsert(const QGradientStops& gradient, qreal factor) +{ + if ( gradient.empty() ) + return {0, {0, QColor()}}; + + if ( gradient.size() == 1 || factor <= 0 ) + return {0, gradient.front()}; + + int i = 0; + QGradientStop s1; + for ( auto s2 : gradient ) + { + if ( factor < s2.first ) + { + qreal ratio = (factor - s1.first) / (s2.first - s1.first); + return {i, {factor, blendColors(s1.second, s2.second, ratio)}}; + } + s1 = s2; + ++i; + } + + return {gradient.size(), gradient.back()}; +} + +/** + * \brief Returns a color in the gradient + * \param gradient Gradient stops to look into (must be properly set up) + * \param factor Value in [0, 1] to get the color for + */ +inline QColor Q_DECL_EXPORT gradientBlendedColor(const QGradientStops& gradient, qreal factor) +{ + return gradientBlendedColorInsert(gradient, factor).second.second; +} + +/** + * \brief Returns a color in the gradient + * \param gradient Gradient to look into + * \param factor Value in [0, 1] to get the color for + */ +inline QColor Q_DECL_EXPORT gradientBlendedColor(const QGradient& gradient, qreal factor) +{ + return gradientBlendedColor(gradient.stops(), factor); +} + +} // namespace color_widgets + + + + +#endif // GRADIENT_HELPER_HPP + diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_list_model.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_list_model.hpp new file mode 100644 index 00000000..9c711e09 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_list_model.hpp @@ -0,0 +1,173 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_GRADIENT_LIST_MODEL_HPP +#define COLOR_WIDGETS_GRADIENT_LIST_MODEL_HPP + +#include "colorwidgets_global.hpp" + +#include +#include +#include + +namespace color_widgets { + +class QCP_EXPORT GradientListModel : public QAbstractListModel +{ + Q_OBJECT + + /** + * \brief Size of the icon used for the gradient previews + */ + Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged) + + Q_PROPERTY(ItemEditMode editMode READ editMode WRITE setEditMode NOTIFY editModeChanged) + +public: + enum ItemEditMode + { + EditNone = 0, + EditName, + EditGradient, + }; + + Q_ENUM(ItemEditMode); + + GradientListModel(QObject *parent = nullptr); + ~GradientListModel(); + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + Qt::ItemFlags flags(const QModelIndex & index) const Q_DECL_OVERRIDE; + bool setData(const QModelIndex & index, const QVariant & value, int role) Q_DECL_OVERRIDE; + + QSize iconSize() const; + + /** + * \brief Number of gradients + */ + int count() const; + + /** + * \brief Remove all gradients + */ + void clear(); + + /** + * \brief Returns a reference to the first gradient with the given name + * \pre hasGradient(name) + */ + const QLinearGradient& gradient(const QString& name) const; + + /** + * \brief Returns a reference to the first gradient with the given name + * \pre hasGradient(name) + */ + QGradientStops gradientStops(const QString& name) const; + + /** + * \brief Whether a gradient with the given name exists in the model + */ + bool hasGradient(const QString& name) const; + + /** + * \brief Get the gradient at the given index (row) + * \pre 0 <= index < count() + */ + const QLinearGradient& gradient(int index) const; + + /** + * \brief Get the gradient stops at the given index (row) + * \pre 0 <= index < count() + */ + QGradientStops gradientStops(int index) const; + + /** + * \brief Inserts or updates a gradient + * \returns The index for the new gradient + */ + int setGradient(const QString& name, const QGradient& gradient); + + int setGradient(const QString& name, const QGradientStops& gradient); + + /** + * \brief Updates the gradient at \p index + */ + bool setGradient(int index, const QGradient& gradient); + + bool setGradient(int index, const QGradientStops& gradient); + + /** + * \brief Renames the gradient at \p index + * \returns \b true on success + */ + bool rename(int index, const QString& new_name); + + /** + * \brief Renames a gradient + * \returns \b true on success + */ + bool rename(const QString& old_name, const QString& new_name); + + /** + * \brief Remove a gradient from the model + * \returns \b true if the gradient has been successfully removed + */ + bool removeGradient(const QString& name); + + + bool removeGradient(int index); + + /** + * \brief The index of the gradient with the given name + * \returns -1 if none is found + */ + int indexFromName(const QString& name) const; + + /** + * \brief Name of the gradient at index + */ + QString nameFromIndex(int index) const; + + ItemEditMode editMode() const; + + /** + * \brief Brush for a gradient + * \pre 0 <= \p index < count() + */ + QBrush gradientBrush(int index) const; + +public Q_SLOTS: + void setIconSize(const QSize& iconSize); + void setEditMode(ItemEditMode mode); + +Q_SIGNALS: + void iconSizeChanged(const QSize& iconSize); + void editModeChanged(ItemEditMode mode); + +private: + class Private; + std::unique_ptr d; +}; + +} // namespace color_widgets + +#endif // COLOR_WIDGETS_GRADIENT_LIST_MODEL_HPP + diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_slider.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_slider.hpp new file mode 100644 index 00000000..ef7908dd --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/gradient_slider.hpp @@ -0,0 +1,117 @@ +/** + * \file gradient_slider.hpp + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2014 Calle Laakkonen + * \copyright Copyright (C) 2017 caryoscelus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef GRADIENT_SLIDER_HPP +#define GRADIENT_SLIDER_HPP + +#include "colorwidgets_global.hpp" + +#include +#include + +namespace color_widgets { + +/** + * \brief A slider that moves on top of a gradient + */ +class QCP_EXPORT GradientSlider : public QSlider +{ + Q_OBJECT + Q_PROPERTY(QBrush background READ background WRITE setBackground NOTIFY backgroundChanged) + Q_PROPERTY(QGradientStops colors READ colors WRITE setColors DESIGNABLE false) + Q_PROPERTY(QColor firstColor READ firstColor WRITE setFirstColor STORED false) + Q_PROPERTY(QColor lastColor READ lastColor WRITE setLastColor STORED false) + Q_PROPERTY(QLinearGradient gradient READ gradient WRITE setGradient) + +public: + explicit GradientSlider(QWidget *parent = 0); + explicit GradientSlider(Qt::Orientation orientation, QWidget *parent = 0); + ~GradientSlider(); + + /// Get the background, it's visible for transparent gradient stops + QBrush background() const; + /// Set the background, it's visible for transparent gradient stops + void setBackground(const QBrush &bg); + + /// Get the colors that make up the gradient + QGradientStops colors() const; + /// Set the colors that make up the gradient + void setColors(const QGradientStops &colors); + + /// Get the gradient + QLinearGradient gradient() const; + /// Set the gradient + void setGradient(const QLinearGradient &gradient); + + /** + * Overload: create an evenly distributed gradient of the given colors + */ + void setColors(const QVector &colors); + + /** + * \brief Set the first color of the gradient + * + * If the gradient is currently empty it will create a stop with the given color + */ + void setFirstColor(const QColor &c); + + /** + * \brief Set the last color of the gradient + * + * If the gradient is has less than two colors, + * it will create a stop with the given color + */ + void setLastColor(const QColor &c); + + /** + * \brief Get the first color + * + * \returns QColor() con empty gradient + */ + QColor firstColor() const; + + /** + * \brief Get the last color + * + * \returns QColor() con empty gradient + */ + QColor lastColor() const; + +Q_SIGNALS: + void backgroundChanged(const QBrush&); + +protected: + void paintEvent(QPaintEvent *ev) override; + + void mousePressEvent(QMouseEvent *ev) override; + void mouseMoveEvent(QMouseEvent *ev) override; + void mouseReleaseEvent(QMouseEvent *ev) override; + +private: + class Private; + Private * const p; +}; + +} // namespace color_widgets + +#endif // GRADIENT_SLIDER_HPP diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/harmony_color_wheel.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/harmony_color_wheel.hpp new file mode 100644 index 00000000..72e774eb --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/harmony_color_wheel.hpp @@ -0,0 +1,95 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2017 caryoscelus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef HARMONY_COLOR_WHEEL_HPP +#define HARMONY_COLOR_WHEEL_HPP + + +#include "color_wheel.hpp" + +namespace color_widgets { + +/** + * \brief ColorWheel with color harmonies + */ +class QCP_EXPORT HarmonyColorWheel : public ColorWheel +{ + Q_OBJECT + +public: + explicit HarmonyColorWheel(QWidget *parent = 0); + ~HarmonyColorWheel(); + + /// Get all harmony colors (including main) + QList harmonyColors() const; + + /// Get number of harmony colors (including main) + unsigned int harmonyCount() const; + + /// Clear harmony color scheme + void clearHarmonies(); + + /** + * @brief Add harmony color + * @param hue_diff Initial hue difference (in [0-1) range) + * @param editable Whether this harmony should be editable + * @returns Index of newly added harmony + */ + unsigned addHarmony(double hue_diff, bool editable); + + /** + * @brief Add symmetric harmony color + * @param relative_to Index of other harmony that should be symmetric relative to main hue + * @returns Index of newly added harmony + * Editability is inherited from symmetric editor + */ + unsigned addSymmetricHarmony(unsigned relative_to); + + /** + * @brief Add opposite harmony color + * @param relative_to Index of other harmony that should be opposite to this + * @returns Index of newly added harmony + * Editability is inherited from opposite editor + */ + unsigned addOppositeHarmony(unsigned relative_to); + +Q_SIGNALS: + /** + * Emitted when harmony settings or harmony colors are changed (including due to main hue change) + */ + void harmonyChanged(); + +protected: + void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE; + +private: + class Private; + Private * p; +}; + +} // namespace color_widgets + +#endif // COLOR_WHEEL_HPP + diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/hue_slider.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/hue_slider.hpp new file mode 100644 index 00000000..fd3fc939 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/hue_slider.hpp @@ -0,0 +1,100 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2014 Calle Laakkonen + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef HUE_SLIDER_HPP +#define HUE_SLIDER_HPP + +#include "gradient_slider.hpp" + +namespace color_widgets { + +/** + * \brief A slider for selecting a hue value + */ +class QCP_EXPORT HueSlider : public GradientSlider +{ + Q_OBJECT + /** + * \brief Saturation used in the rainbow gradient, as a [0-1] float + */ + Q_PROPERTY(qreal colorSaturation READ colorSaturation WRITE setColorSaturation NOTIFY colorSaturationChanged) + /** + * \brief Value used in the rainbow gradient, as a [0-1] float + */ + Q_PROPERTY(qreal colorValue READ colorValue WRITE setColorValue NOTIFY colorValueChanged) + /** + * \brief Alpha used in the rainbow gradient, as a [0-1] float + */ + Q_PROPERTY(qreal colorAlpha READ colorAlpha WRITE setColorAlpha NOTIFY colorAlphaChanged) + + /** + * \brief Color with corresponding color* components + */ + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + + /** + * \brief Normalized Hue, as indicated from the slider + */ + Q_PROPERTY(qreal colorHue READ colorHue WRITE setColorHue NOTIFY colorHueChanged) + + +public: + explicit HueSlider(QWidget *parent = nullptr); + explicit HueSlider(Qt::Orientation orientation, QWidget *parent = nullptr); + ~HueSlider(); + + qreal colorSaturation() const; + qreal colorValue() const; + qreal colorAlpha() const; + QColor color() const; + qreal colorHue() const; + +public Q_SLOTS: + void setColorValue(qreal value); + void setColorSaturation(qreal value); + void setColorAlpha(qreal alpha); + void setColorHue(qreal colorHue); + /** + * \brief Set Hue Saturation and ColorValue, ignoring alpha + */ + void setColor(const QColor& color); + /** + * \brief Set Hue Saturation, ColorValue and Alpha + */ + void setFullColor(const QColor& color); + +Q_SIGNALS: + void colorHueChanged(qreal colorHue); + void colorChanged(QColor); + void colorAlphaChanged(qreal v); + void colorSaturationChanged(qreal v); + void colorValueChanged(qreal v); + +private: + class Private; + Private * const p; +}; + +} // namespace color_widgets + +#endif // HUE_SLIDER_HPP + diff --git a/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/swatch.hpp b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/swatch.hpp new file mode 100644 index 00000000..85d49047 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/include/QtColorWidgets/swatch.hpp @@ -0,0 +1,194 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#ifndef COLOR_WIDGETS_SWATCH_HPP +#define COLOR_WIDGETS_SWATCH_HPP + +#include +#include +#include "color_palette.hpp" + +namespace color_widgets { + +/** + * \brief A widget drawing a palette + */ +class QCP_EXPORT Swatch : public QWidget +{ + Q_OBJECT + + /** + * \brief Palette shown by the widget + */ + Q_PROPERTY(const ColorPalette& palette READ palette WRITE setPalette NOTIFY paletteChanged) + /** + * \brief Currently selected color (-1 if no color is selected) + */ + Q_PROPERTY(int selected READ selected WRITE setSelected NOTIFY selectedChanged) + + /** + * \brief Preferred size for a color square + */ + Q_PROPERTY(QSize colorSize READ colorSize WRITE setColorSize NOTIFY colorSizeChanged) + + Q_PROPERTY(ColorSizePolicy colorSizePolicy READ colorSizePolicy WRITE setColorSizePolicy NOTIFY colorSizePolicyChanged) + + /** + * \brief Border around the colors + */ + Q_PROPERTY(QPen border READ border WRITE setBorder NOTIFY borderChanged) + + /** + * \brief Forces the Swatch to display that many rows of colors + * + * If there are too few elements, the widget will display less than this + * many rows. + * + * A value of0 means that the number of rows is automatic. + * + * \note Conflicts with forcedColumns + */ + Q_PROPERTY(int forcedRows READ forcedRows WRITE setForcedRows NOTIFY forcedRowsChanged) + + /** + * \brief Forces the Swatch to display that many columns of colors + * + * If there are too few elements, the widget will display less than this + * many columns. + * + * A value of 0 means that the number of columns is automatic. + * + * \note Conflicts with forcedRows + */ + Q_PROPERTY(int forcedColumns READ forcedColumns WRITE setForcedColumns NOTIFY forcedColumnsChanged) + + /** + * \brief Whether the palette can be modified via user interaction + * \note Even when this is \b false, it can still be altered programmatically + */ + Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly NOTIFY readOnlyChanged) + + +public: + enum ColorSizePolicy + { + Hint, ///< The size is just a hint + Minimum, ///< Can expand but not contract + Fixed ///< Must be exactly as specified + }; + Q_ENUMS(ColorSizePolicy) + + Swatch(QWidget* parent = 0); + ~Swatch(); + + QSize sizeHint() const Q_DECL_OVERRIDE; + QSize minimumSizeHint() const Q_DECL_OVERRIDE; + + const ColorPalette& palette() const; + ColorPalette& palette(); + int selected() const; + /** + * \brief Color at the currently selected index + */ + QColor selectedColor() const; + + /** + * \brief Color index at the given position within the widget + * \param p Point in local coordinates + * \returns -1 if the position doesn't represent any color + */ + int indexAt(const QPoint& p); + + /** + * \brief Color at the given position within the widget + * \param p Point in local coordinates + */ + QColor colorAt(const QPoint& p); + + QSize colorSize() const; + ColorSizePolicy colorSizePolicy() const; + QPen border() const; + + int forcedRows() const; + int forcedColumns() const; + + bool readOnly() const; + +public Q_SLOTS: + void setPalette(const ColorPalette& palette); + void setSelected(int selected); + void clearSelection(); + void setColorSize(const QSize& colorSize); + void setColorSizePolicy(ColorSizePolicy colorSizePolicy); + void setBorder(const QPen& border); + void setForcedRows(int forcedRows); + void setForcedColumns(int forcedColumns); + void setReadOnly(bool readOnly); + /** + * \brief Remove the currently seleceted color + **/ + void removeSelected(); + +Q_SIGNALS: + void paletteChanged(const ColorPalette& palette); + void selectedChanged(int selected); + void colorSelected(const QColor& color); + void colorSizeChanged(const QSize& colorSize); + void colorSizePolicyChanged(ColorSizePolicy colorSizePolicy); + void doubleClicked(int index); + void rightClicked(int index); + void forcedRowsChanged(int forcedRows); + void forcedColumnsChanged(int forcedColumns); + void readOnlyChanged(bool readOnly); + void borderChanged(const QPen& border); + +protected: + bool event(QEvent* event) Q_DECL_OVERRIDE; + + void paintEvent(QPaintEvent* event) Q_DECL_OVERRIDE; + + void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE; + + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void wheelEvent(QWheelEvent* event) Q_DECL_OVERRIDE; + + void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE; + void dragMoveEvent(QDragMoveEvent* event) Q_DECL_OVERRIDE; + void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent* event) Q_DECL_OVERRIDE; + +protected Q_SLOTS: + /** + * \brief Connected to the internal palette object to keep eveything consistent + */ + void paletteModified(); + +private: + class Private; + Private* p; +}; + + +} // namespace color_widgets +#endif // COLOR_WIDGETS_SWATCH_HPP diff --git a/thirdparty/Qt-Color-Widgets/refactor.sh b/thirdparty/Qt-Color-Widgets/refactor.sh new file mode 100644 index 00000000..c44af522 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/refactor.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# +# Copyright (C) 2013-2020 Mattia Basaglia +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +################################################################################ +# This script is to refactor the old class names to the new ones # +# eg: occurrences of Color_Dialog become color_widgets::ColorDialog # +# This script does very simple text replacements and overwrites existing files # +# Use with care # +# Usage: # +# ./refactor.sh /path/to/sources # +# # +################################################################################ + +old_classes=( + Color_Delegate + Color_Dialog + Color_List_Widget + Color_Preview + Color_Selector + Color_Wheel + Gradient_Slider + Hue_Slider +) +old_enums=( + Button_Mode + Display_Mode + Update_Mode + Display_Enum + Display_Flags +) +file_extensions=( + ui + cpp + hpp + C + H + h + cxx + hxx +) + + +function new_class_name() +{ + echo "$1" | sed -e 's/_//g' -r -e 's/^/color_widgets::/' +} + + +function new_enum_name() +{ + echo "$1" | sed -e 's/_//g' +} + +directory="$1" + +if [ -z "$directory" ] +then + echo "Usage: $0 (directory)" + exit 1 +fi + +find_extensions="" +for ext in ${file_extensions[@]} +do + find_extensions="$find_extensions -o -name '*.$ext'" +done +find_extensions="$(echo "$find_extensions" | sed -r 's/ -o //')" +find_command="find \""$directory"\" -type f -a \( $find_extensions \) -print" + +files="$(bash -c "$find_command")" + +replacements="" +for class in ${old_classes[@]} +do + replacements="$replacements $class $(new_class_name $class)" +done +for enum in ${old_enums[@]} +do + replacements="$replacements $enum $(new_enum_name $enum)" +done + +for file in $files +do + replace $replacements -- "$file" +done diff --git a/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/CMakeLists.txt b/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/CMakeLists.txt new file mode 100644 index 00000000..ee533e5e --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/CMakeLists.txt @@ -0,0 +1,16 @@ +set (SOURCES + alphaback.png + color_widgets.qrc + ) + +file(RELATIVE_PATH + PREFIX + ${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_LIST_DIR}) + + +foreach (SOURCE IN LISTS SOURCES) + target_sources (${TARGET_NAME} + PRIVATE + $) +endforeach (SOURCE IN SOURCES) diff --git a/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/alphaback.png b/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/alphaback.png new file mode 100644 index 00000000..b3634a5a Binary files /dev/null and b/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/alphaback.png differ diff --git a/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/color_widgets.qrc b/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/color_widgets.qrc new file mode 100644 index 00000000..7b8cfcd3 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/resources/QtColorWidgets/color_widgets.qrc @@ -0,0 +1,5 @@ + + + alphaback.png + + diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/CMakeLists.txt b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/CMakeLists.txt new file mode 100644 index 00000000..f1a6c1ba --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/CMakeLists.txt @@ -0,0 +1,37 @@ +set (SOURCES +abstract_widget_list.cpp +bound_color_selector.cpp +color_2d_slider.cpp +color_delegate.cpp +color_dialog.cpp +color_dialog.ui +color_line_edit.cpp +color_list_widget.cpp +color_names.cpp +color_palette.cpp +color_palette_model.cpp +color_palette_widget.cpp +color_palette_widget.ui +color_preview.cpp +color_selector.cpp +color_utils.cpp +color_wheel.cpp +gradient_slider.cpp +hue_slider.cpp +swatch.cpp +gradient_editor.cpp +harmony_color_wheel.cpp +gradient_list_model.cpp +) + +file(RELATIVE_PATH + PREFIX + ${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_LIST_DIR}) + + +foreach (SOURCE IN LISTS SOURCES) + target_sources (${TARGET_NAME} + PRIVATE + $) +endforeach (SOURCE IN SOURCES) diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/abstract_widget_list.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/abstract_widget_list.cpp new file mode 100644 index 00000000..7512d0a5 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/abstract_widget_list.cpp @@ -0,0 +1,175 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/abstract_widget_list.hpp" +#include +#include +#include +#include + +class AbstractWidgetList::Private +{ +public: + QList widgets; + QSignalMapper mapper_up; + QSignalMapper mapper_down; + QSignalMapper mapper_remove; + QTableWidget *table; +}; + +AbstractWidgetList::AbstractWidgetList(QWidget *parent) : + QWidget(parent), p(new Private) +{ + connect(&p->mapper_up,SIGNAL(mapped(QWidget*)),SLOT(up_clicked(QWidget*))); + connect(&p->mapper_down,SIGNAL(mapped(QWidget*)),SLOT(down_clicked(QWidget*))); + connect(&p->mapper_remove,SIGNAL(mapped(QWidget*)),SLOT(remove_clicked(QWidget*))); + + + QVBoxLayout *verticalLayout = new QVBoxLayout(this); + verticalLayout->setContentsMargins(0, 0, 0, 0); + p->table = new QTableWidget(this); + verticalLayout->addWidget(p->table); + + + p->table->insertColumn(0); + p->table->insertColumn(1); + p->table->insertColumn(2); + p->table->insertColumn(3); + + p->table->setColumnWidth(0,128); + p->table->setColumnWidth(1,24); + p->table->setColumnWidth(2,24); + p->table->setColumnWidth(3,24); + + p->table->horizontalHeader()->hide(); + p->table->verticalHeader()->hide(); + p->table->setShowGrid(false); + + QPushButton* add_button = new QPushButton(QIcon::fromTheme(QStringLiteral("list-add")), + tr("Add New")); + + verticalLayout->addWidget(add_button); + connect(add_button,&QAbstractButton::clicked,this, &AbstractWidgetList::append); + +} + +AbstractWidgetList::~AbstractWidgetList() +{ + delete p; +} + +int AbstractWidgetList::count() const +{ + return p->widgets.size(); +} + +void AbstractWidgetList::setRowHeight(int row, int height) +{ + p->table->setRowHeight(row,height); +} + +void AbstractWidgetList::clear() +{ + p->widgets.clear(); + while(p->table->rowCount() > 0) + p->table->removeRow(0); +} + + +void AbstractWidgetList::remove(int i) +{ + if ( isValidRow(i) ) + { + p->widgets.removeAt(i); + p->table->removeRow(i); + if ( i == 0 && !p->widgets.isEmpty() ) + p->table->cellWidget(0,1)->setEnabled(false); + else if ( i != 0 && i == count() ) + p->table->cellWidget(count()-1,2)->setEnabled(false); + + Q_EMIT removed(i); + } +} + + +void AbstractWidgetList::appendWidget(QWidget *w) +{ + int row = count(); + p->table->insertRow(row); + + QWidget* b_up = create_button(w,&p->mapper_up,QStringLiteral("go-up"),tr("Move Up")); + QWidget* b_down = create_button(w,&p->mapper_down,QStringLiteral("go-down"),tr("Move Down")); + QWidget* b_remove = create_button(w,&p->mapper_remove,QStringLiteral("list-remove"),tr("Remove")); + if ( row == 0 ) + b_up->setEnabled(false); + else + p->table->cellWidget(row-1,2)->setEnabled(true); + b_down->setEnabled(false); + + p->table->setCellWidget(row,0,w); + p->table->setCellWidget(row,1,b_up); + p->table->setCellWidget(row,2,b_down); + p->table->setCellWidget(row,3,b_remove); + + p->widgets.push_back(w); +} + +QWidget *AbstractWidgetList::widget(int i) +{ + if ( isValidRow(i) ) + return p->widgets[i]; + return 0; +} + + +QWidget *AbstractWidgetList::create_button(QWidget *data, QSignalMapper *mapper, + QString icon_name, + QString text, QString tooltip) const +{ + + QToolButton* btn = new QToolButton; + btn->setIcon(QIcon::fromTheme(icon_name)); + btn->setText(text); + btn->setToolTip(tooltip.isNull() ? btn->text() : tooltip ); + connect(btn,SIGNAL(clicked()),mapper,SLOT(map())); + mapper->setMapping(btn,data); + return btn; +} + +void AbstractWidgetList::remove_clicked(QWidget *w) +{ + int row = p->widgets.indexOf(w); + remove(row); +} + +void AbstractWidgetList::up_clicked(QWidget *w) +{ + int row = p->widgets.indexOf(w); + if ( row > 0 ) + swap(row,row-1); +} + +void AbstractWidgetList::down_clicked(QWidget *w) +{ + int row = p->widgets.indexOf(w); + if ( row+1 < count() ) + swap(row,row+1); +} diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/bound_color_selector.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/bound_color_selector.cpp new file mode 100644 index 00000000..abb801d9 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/bound_color_selector.cpp @@ -0,0 +1,38 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/bound_color_selector.hpp" + +namespace color_widgets { + +BoundColorSelector::BoundColorSelector(QColor* reference, QWidget *parent) : + ColorSelector(parent), ref(reference) +{ + setColor(*reference); + connect(this,&ColorPreview::colorChanged,this, &BoundColorSelector::update_reference); +} + +void BoundColorSelector::update_reference(QColor c) +{ + *ref = c; +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_2d_slider.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_2d_slider.cpp new file mode 100644 index 00000000..892765fb --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_2d_slider.cpp @@ -0,0 +1,267 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_2d_slider.hpp" +#include "QtColorWidgets/color_utils.hpp" +#include +#include +#include +#include + +namespace color_widgets { + +static const double selector_radius = 6; + +class Color2DSlider::Private +{ +public: + qreal hue = 1, sat = 1, val = 1; + Component comp_x = Saturation; + Component comp_y = Value; + QImage square; + + qreal PixHue(float x, float y) + { + if ( comp_x == Hue ) + return x; + if ( comp_y == Hue ) + return y; + return hue; + } + + qreal PixSat(float x, float y) + { + if ( comp_x == Saturation ) + return x; + if ( comp_y == Saturation ) + return y; + return sat; + } + + qreal PixVal(float x, float y) + { + if ( comp_x == Value ) + return x; + if ( comp_y == Value ) + return y; + return val; + } + + void renderSquare(const QSize& size) + { + square = QImage(size, QImage::Format_RGB32); + + for ( int y = 0; y < size.height(); ++y ) + { + qreal yfloat = 1 - qreal(y) / size.height(); + for ( int x = 0; x < size.width(); ++x ) + { + qreal xfloat = qreal(x) / size.width(); + square.setPixel( x, y, QColor::fromHsvF( + PixHue(xfloat, yfloat), + PixSat(xfloat, yfloat), + PixVal(xfloat, yfloat) + ).rgb()); + } + } + } + + QPointF selectorPos(const QSize& size) + { + QPointF pt; + switch ( comp_x ) + { + case Hue: pt.setX(size.width()*hue); break; + case Saturation:pt.setX(size.width()*sat); break; + case Value: pt.setX(size.width()*val); break; + } + switch ( comp_y ) + { + case Hue: pt.setY(size.height()*(1-hue)); break; + case Saturation:pt.setY(size.height()*(1-sat)); break; + case Value: pt.setY(size.height()*(1-val)); break; + } + return pt; + } + + void setColorFromPos(const QPoint& pt, const QSize& size) + { + QPointF ptfloat( + qBound(0.0, qreal(pt.x()) / size.width(), 1.0), + qBound(0.0, 1 - qreal(pt.y()) / size.height(), 1.0) + ); + switch ( comp_x ) + { + case Hue: hue = ptfloat.x(); break; + case Saturation:sat = ptfloat.x(); break; + case Value: val = ptfloat.x(); break; + } + switch ( comp_y ) + { + case Hue: hue = ptfloat.y(); break; + case Saturation:sat = ptfloat.y(); break; + case Value: val = ptfloat.y(); break; + } + } +}; + +Color2DSlider::Color2DSlider(QWidget* parent) + : QWidget(parent), p(new Private) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +Color2DSlider::~Color2DSlider() +{ + delete p; +} + +QColor Color2DSlider::color() const +{ + return QColor::fromHsvF(p->hue, p->sat, p->val); +} + +QSize Color2DSlider::sizeHint() const +{ + return {128, 128}; +} + +qreal Color2DSlider::hue() const +{ + return p->hue; +} + +qreal Color2DSlider::saturation() const +{ + return p->sat; +} + +qreal Color2DSlider::value() const +{ + return p->val; +} + +Color2DSlider::Component Color2DSlider::componentX() const +{ + return p->comp_x; +} + +Color2DSlider::Component Color2DSlider::componentY() const +{ + return p->comp_y; +} + +void Color2DSlider::setColor(const QColor& c) +{ + p->hue = c.hsvHueF(); + p->sat = c.saturationF(); + p->val = c.valueF(); + p->renderSquare(size()); + update(); + Q_EMIT colorChanged(color()); +} + +void Color2DSlider::setHue(qreal h) +{ + p->hue = h; + p->renderSquare(size()); + update(); + Q_EMIT colorChanged(color()); +} + +void Color2DSlider::setSaturation(qreal s) +{ + p->sat = s; + p->renderSquare(size()); + update(); + Q_EMIT colorChanged(color()); +} + +void Color2DSlider::setValue(qreal v) +{ + p->val = v; + p->renderSquare(size()); + update(); + Q_EMIT colorChanged(color()); +} + +void Color2DSlider::setComponentX(Color2DSlider::Component componentX) +{ + if ( componentX != p->comp_x ) + { + p->comp_x = componentX; + p->renderSquare(size()); + update(); + Q_EMIT componentXChanged(p->comp_x); + } +} + +void Color2DSlider::setComponentY(Color2DSlider::Component componentY) +{ + if ( componentY != p->comp_y ) + { + p->comp_y = componentY; + p->renderSquare(size()); + update(); + Q_EMIT componentXChanged(p->comp_y); + } +} + +void Color2DSlider::paintEvent(QPaintEvent*) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.drawImage(0,0,p->square); + + painter.setPen(QPen(p->val > 0.5 ? Qt::black : Qt::white, 3)); + painter.setBrush(Qt::NoBrush); + painter.drawEllipse(p->selectorPos(size()), selector_radius, selector_radius); +} + +void Color2DSlider::mousePressEvent(QMouseEvent* event) +{ + p->setColorFromPos(event->pos(), size()); + Q_EMIT colorChanged(color()); + update(); +} + +void Color2DSlider::mouseMoveEvent(QMouseEvent* event) +{ + p->setColorFromPos(event->pos(), size()); + Q_EMIT colorChanged(color()); + update(); +} + +void Color2DSlider::mouseReleaseEvent(QMouseEvent* event) +{ + p->setColorFromPos(event->pos(), size()); + Q_EMIT colorChanged(color()); + update(); +} + +void Color2DSlider::resizeEvent(QResizeEvent* event) +{ + p->renderSquare(event->size()); + update(); +} + + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_delegate.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_delegate.cpp new file mode 100644 index 00000000..1aa89b26 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_delegate.cpp @@ -0,0 +1,94 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_delegate.hpp" +#include "QtColorWidgets/color_selector.hpp" +#include "QtColorWidgets/color_dialog.hpp" +#include +#include + +namespace color_widgets { + +ColorDelegate::ColorDelegate(QWidget *parent) : + QAbstractItemDelegate(parent) +{ +} + +void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if (index.data().canConvert()) + { + QStyleOptionFrame panel; + panel.initFrom(option.widget); + if (option.widget->isEnabled()) + panel.state = QStyle::State_Enabled; + panel.rect = option.rect; + panel.lineWidth = 2; + panel.midLineWidth = 0; + panel.state |= QStyle::State_Sunken; + option.widget->style()->drawPrimitive(QStyle::PE_Frame, &panel, painter, nullptr); + QRect r = option.widget->style()->subElementRect(QStyle::SE_FrameContents, &panel, nullptr); + painter->setClipRect(r); + painter->fillRect(option.rect, index.data().value()); + } +} + +bool ColorDelegate::editorEvent(QEvent* event, + QAbstractItemModel* model, + const QStyleOptionViewItem& option, + const QModelIndex& index) +{ + + if ( event->type() == QEvent::MouseButtonRelease && index.data().canConvert()) + { + QMouseEvent* mouse_event = static_cast(event); + + if ( mouse_event->button() == Qt::LeftButton && + ( index.flags() & Qt::ItemIsEditable) ) + { + ColorDialog *editor = new ColorDialog(const_cast(option.widget)); + connect(this, &QObject::destroyed, editor, &QObject::deleteLater); + editor->setMinimumSize(editor->sizeHint()); + auto original_color = index.data().value(); + editor->setColor(original_color); + auto set_color = [model, index](const QColor& color){ + model->setData(index, QVariant(color)); + }; + connect(editor, &ColorDialog::colorSelected, this, set_color); + editor->show(); + } + + return true; + } + + return QAbstractItemDelegate::editorEvent(event, model, option, index); +} + + +QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(index) + Q_UNUSED(option) + return QSize(24,16); +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_dialog.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_dialog.cpp new file mode 100644 index 00000000..4ac1f685 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_dialog.cpp @@ -0,0 +1,378 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2014 Calle Laakkonen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_dialog.hpp" +#include "ui_color_dialog.h" + +#include +#include +#include +#include +#include +#include + +namespace color_widgets { + +class ColorDialog::Private +{ +public: + Ui_ColorDialog ui; + ButtonMode button_mode; + bool pick_from_screen; + bool alpha_enabled; + QColor color; + + Private() : pick_from_screen(false), alpha_enabled(true) + {} + +}; + +ColorDialog::ColorDialog(QWidget *parent, Qt::WindowFlags f) : + QDialog(parent, f), p(new Private) +{ + p->ui.setupUi(this); + + setAcceptDrops(true); + + // Add "pick color" button + QPushButton *pickButton = p->ui.buttonBox->addButton(tr("Pick"), QDialogButtonBox::ActionRole); + pickButton->setIcon(QIcon::fromTheme(QStringLiteral("color-picker"))); + + setButtonMode(OkApplyCancel); + + connect(p->ui.wheel, &ColorWheel::colorSpaceChanged, this, &ColorDialog::colorSpaceChanged); + connect(p->ui.wheel, &ColorWheel::selectorShapeChanged, this, &ColorDialog::wheelShapeChanged); + connect(p->ui.wheel, &ColorWheel::rotatingSelectorChanged, this, &ColorDialog::wheelRotatingChanged); +} + +ColorDialog::~ColorDialog() +{ + delete p; +} + +QSize ColorDialog::sizeHint() const +{ + return QSize(400,0); +} + +QColor ColorDialog::color() const +{ + QColor col = p->color; + if ( !p->alpha_enabled ) + col.setAlpha(255); + return col; +} + +void ColorDialog::setColor(const QColor &c) +{ + p->ui.preview->setComparisonColor(c); + p->ui.edit_hex->setModified(false); + setColorInternal(c); +} + +void ColorDialog::showColor(const QColor &c) +{ + setColor(c); + show(); +} + +void ColorDialog::setPreviewDisplayMode(ColorPreview::DisplayMode mode) +{ + p->ui.preview->setDisplayMode(mode); +} + +ColorPreview::DisplayMode ColorDialog::previewDisplayMode() const +{ + return p->ui.preview->displayMode(); +} + +void ColorDialog::setAlphaEnabled(bool a) +{ + if ( a != p->alpha_enabled ) + { + p->alpha_enabled = a; + + p->ui.edit_hex->setShowAlpha(a); + p->ui.line_alpha->setVisible(a); + p->ui.label_alpha->setVisible(a); + p->ui.slide_alpha->setVisible(a); + p->ui.spin_alpha->setVisible(a); + + Q_EMIT alphaEnabledChanged(a); + } +} + +bool ColorDialog::alphaEnabled() const +{ + return p->alpha_enabled; +} + +void ColorDialog::setButtonMode(ButtonMode mode) +{ + p->button_mode = mode; + QDialogButtonBox::StandardButtons btns; + switch(mode) { + case OkCancel: btns = QDialogButtonBox::Ok | QDialogButtonBox::Cancel; break; + case OkApplyCancel: btns = QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply | QDialogButtonBox::Reset; break; + case Close: btns = QDialogButtonBox::Close; + } + p->ui.buttonBox->setStandardButtons(btns); +} + +ColorDialog::ButtonMode ColorDialog::buttonMode() const +{ + return p->button_mode; +} + +void ColorDialog::setColorInternal(const QColor &col) +{ + /** + * \note Unlike setColor, this is used to update the current color which + * migth differ from the final selected color + */ + p->ui.wheel->setColor(col); + + p->color = col; + + bool blocked = signalsBlocked(); + blockSignals(true); + Q_FOREACH(QWidget* w, findChildren()) + w->blockSignals(true); + + + p->ui.slide_red->setValue(col.red()); + p->ui.spin_red->setValue(p->ui.slide_red->value()); + p->ui.slide_red->setFirstColor(QColor(0,col.green(),col.blue())); + p->ui.slide_red->setLastColor(QColor(255,col.green(),col.blue())); + + p->ui.slide_green->setValue(col.green()); + p->ui.spin_green->setValue(p->ui.slide_green->value()); + p->ui.slide_green->setFirstColor(QColor(col.red(),0,col.blue())); + p->ui.slide_green->setLastColor(QColor(col.red(),255,col.blue())); + + p->ui.slide_blue->setValue(col.blue()); + p->ui.spin_blue->setValue(p->ui.slide_blue->value()); + p->ui.slide_blue->setFirstColor(QColor(col.red(),col.green(),0)); + p->ui.slide_blue->setLastColor(QColor(col.red(),col.green(),255)); + + p->ui.slide_hue->setValue(qRound(p->ui.wheel->hue()*360.0)); + p->ui.slide_hue->setColorSaturation(p->ui.wheel->saturation()); + p->ui.slide_hue->setColorValue(p->ui.wheel->value()); + p->ui.spin_hue->setValue(p->ui.slide_hue->value()); + + p->ui.slide_saturation->setValue(qRound(p->ui.wheel->saturation()*255.0)); + p->ui.spin_saturation->setValue(p->ui.slide_saturation->value()); + p->ui.slide_saturation->setFirstColor(QColor::fromHsvF(p->ui.wheel->hue(),0,p->ui.wheel->value())); + p->ui.slide_saturation->setLastColor(QColor::fromHsvF(p->ui.wheel->hue(),1,p->ui.wheel->value())); + + p->ui.slide_value->setValue(qRound(p->ui.wheel->value()*255.0)); + p->ui.spin_value->setValue(p->ui.slide_value->value()); + p->ui.slide_value->setFirstColor(QColor::fromHsvF(p->ui.wheel->hue(), p->ui.wheel->saturation(),0)); + p->ui.slide_value->setLastColor(QColor::fromHsvF(p->ui.wheel->hue(), p->ui.wheel->saturation(),1)); + + + QColor apha_color = col; + apha_color.setAlpha(0); + p->ui.slide_alpha->setFirstColor(apha_color); + apha_color.setAlpha(255); + p->ui.slide_alpha->setLastColor(apha_color); + p->ui.spin_alpha->setValue(col.alpha()); + p->ui.slide_alpha->setValue(col.alpha()); + + if ( !p->ui.edit_hex->isModified() ) + p->ui.edit_hex->setColor(col); + + p->ui.preview->setColor(col); + + blockSignals(blocked); + Q_FOREACH(QWidget* w, findChildren()) + w->blockSignals(false); + + Q_EMIT colorChanged(col); +} + +void ColorDialog::set_hsv() +{ + if ( !signalsBlocked() ) + { + QColor col = QColor::fromHsv( + p->ui.slide_hue->value(), + p->ui.slide_saturation->value(), + p->ui.slide_value->value(), + p->ui.slide_alpha->value() + ); + p->ui.wheel->setColor(col); + setColorInternal(col); + } +} + +void ColorDialog::set_alpha() +{ + if ( !signalsBlocked() ) + { + QColor col = p->color; + col.setAlpha(p->ui.slide_alpha->value()); + setColorInternal(col); + } +} + +void ColorDialog::set_rgb() +{ + if ( !signalsBlocked() ) + { + QColor col( + p->ui.slide_red->value(), + p->ui.slide_green->value(), + p->ui.slide_blue->value(), + p->ui.slide_alpha->value() + ); + if (col.saturation() == 0) + col = QColor::fromHsv(p->ui.slide_hue->value(), 0, col.value()); + p->ui.wheel->setColor(col); + setColorInternal(col); + } +} + +void ColorDialog::on_edit_hex_colorChanged(const QColor& color) +{ + setColorInternal(color); +} + +void ColorDialog::on_edit_hex_colorEditingFinished(const QColor& color) +{ + p->ui.edit_hex->setModified(false); + setColorInternal(color); +} + +void ColorDialog::on_buttonBox_clicked(QAbstractButton *btn) +{ + QDialogButtonBox::ButtonRole role = p->ui.buttonBox->buttonRole(btn); + + switch(role) { + case QDialogButtonBox::AcceptRole: + case QDialogButtonBox::ApplyRole: + // Explicitly select the color + p->ui.preview->setComparisonColor(color()); + Q_EMIT colorSelected(color()); + break; + + case QDialogButtonBox::ActionRole: + // Currently, the only action button is the "pick color" button + grabMouse(Qt::CrossCursor); + p->pick_from_screen = true; + break; + + case QDialogButtonBox::ResetRole: + // Restore old color + setColorInternal(p->ui.preview->comparisonColor()); + break; + + default: break; + } +} + +void ColorDialog::dragEnterEvent(QDragEnterEvent *event) +{ + if ( event->mimeData()->hasColor() || + ( event->mimeData()->hasText() && QColor(event->mimeData()->text()).isValid() ) ) + event->acceptProposedAction(); +} + + +void ColorDialog::dropEvent(QDropEvent *event) +{ + if ( event->mimeData()->hasColor() ) + { + setColorInternal(event->mimeData()->colorData().value()); + event->accept(); + } + else if ( event->mimeData()->hasText() ) + { + QColor col(event->mimeData()->text()); + if ( col.isValid() ) + { + setColorInternal(col); + event->accept(); + } + } +} + +static QColor get_screen_color(const QPoint &global_pos) +{ + int screenNum = QApplication::desktop()->screenNumber(global_pos); + QScreen *screen = QApplication::screens().at(screenNum); + + WId wid = QApplication::desktop()->winId(); + QImage img = screen->grabWindow(wid, global_pos.x(), global_pos.y(), 1, 1).toImage(); + + return img.pixel(0,0); +} + +void ColorDialog::mouseReleaseEvent(QMouseEvent *event) +{ + if (p->pick_from_screen) + { + setColorInternal(get_screen_color(event->globalPos())); + p->pick_from_screen = false; + releaseMouse(); + } +} + +void ColorDialog::mouseMoveEvent(QMouseEvent *event) +{ + if (p->pick_from_screen) + { + setColorInternal(get_screen_color(event->globalPos())); + } +} + +void ColorDialog::setWheelShape(ColorWheel::ShapeEnum shape) +{ + p->ui.wheel->setSelectorShape(shape); +} + +ColorWheel::ShapeEnum ColorDialog::wheelShape() const +{ + return p->ui.wheel->selectorShape(); +} + +void ColorDialog::setColorSpace(ColorWheel::ColorSpaceEnum space) +{ + p->ui.wheel->setColorSpace(space); +} + +ColorWheel::ColorSpaceEnum ColorDialog::colorSpace() const +{ + return p->ui.wheel->colorSpace(); +} + +void ColorDialog::setWheelRotating(bool rotating) +{ + p->ui.wheel->setRotatingSelector(rotating); +} + +bool ColorDialog::wheelRotating() const +{ + return p->ui.wheel->rotatingSelector(); +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_dialog.ui b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_dialog.ui new file mode 100644 index 00000000..bb1bd3a7 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_dialog.ui @@ -0,0 +1,700 @@ + + + ColorDialog + + + + 0 + 0 + 491 + 380 + + + + Select Color + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + color_widgets::ColorPreview::SplitColor + + + + + + + + + + + 255 + + + Qt::Horizontal + + + + + + + Saturation + + + + + + + Hue + + + + + + + 255 + + + Qt::Horizontal + + + + + + + Hex + + + + + + + Blue + + + + + + + 255 + + + Qt::Horizontal + + + + + + + 255 + + + Qt::Horizontal + + + + + + + 255 + + + Qt::Horizontal + + + + + + + Value + + + + + + + Green + + + + + + + Alpha + + + + + + + Red + + + + + + + 255 + + + Qt::Horizontal + + + + + + + true + + + 359 + + + + + + + 255 + + + + + + + 255 + + + + + + + 255 + + + + + + + 255 + + + + + + + 255 + + + + + + + 255 + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + 0 + + + 359 + + + + + + + + Monospace + + + + true + + + + + + + + + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset + + + + + + + + + color_widgets::ColorPreview + QWidget +
QtColorWidgets/color_preview.hpp
+ 1 +
+ + color_widgets::ColorWheel + QWidget +
QtColorWidgets/color_wheel.hpp
+ 1 + + colorSelected(QColor) + setColor(QColor) + +
+ + color_widgets::GradientSlider + QSlider +
QtColorWidgets/gradient_slider.hpp
+
+ + color_widgets::HueSlider + color_widgets::GradientSlider +
QtColorWidgets/hue_slider.hpp
+
+ + color_widgets::ColorLineEdit + QLineEdit +
QtColorWidgets/color_line_edit.hpp
+
+
+ + + + slide_saturation + valueChanged(int) + ColorDialog + set_hsv() + + + 416 + 71 + + + 537 + 54 + + + + + slide_value + valueChanged(int) + ColorDialog + set_hsv() + + + 416 + 109 + + + 537 + 88 + + + + + slide_red + valueChanged(int) + ColorDialog + set_rgb() + + + 416 + 156 + + + 557 + 142 + + + + + slide_green + valueChanged(int) + ColorDialog + set_rgb() + + + 416 + 194 + + + 538 + 166 + + + + + slide_blue + valueChanged(int) + ColorDialog + set_rgb() + + + 416 + 232 + + + 537 + 205 + + + + + slide_alpha + valueChanged(int) + ColorDialog + set_alpha() + + + 416 + 279 + + + 531 + 251 + + + + + wheel + colorSelected(QColor) + ColorDialog + setColorInternal(QColor) + + + 175 + 101 + + + 568 + 106 + + + + + slide_saturation + valueChanged(int) + spin_saturation + setValue(int) + + + 416 + 71 + + + 480 + 62 + + + + + spin_saturation + valueChanged(int) + slide_saturation + setValue(int) + + + 461 + 55 + + + 416 + 71 + + + + + slide_value + valueChanged(int) + spin_value + setValue(int) + + + 416 + 109 + + + 480 + 91 + + + + + spin_value + valueChanged(int) + slide_value + setValue(int) + + + 480 + 91 + + + 416 + 109 + + + + + slide_red + valueChanged(int) + spin_red + setValue(int) + + + 416 + 156 + + + 482 + 162 + + + + + spin_red + valueChanged(int) + slide_red + setValue(int) + + + 482 + 162 + + + 416 + 156 + + + + + slide_green + valueChanged(int) + spin_green + setValue(int) + + + 416 + 194 + + + 482 + 200 + + + + + spin_green + valueChanged(int) + slide_green + setValue(int) + + + 482 + 200 + + + 416 + 194 + + + + + slide_alpha + valueChanged(int) + spin_alpha + setValue(int) + + + 416 + 279 + + + 482 + 285 + + + + + spin_alpha + valueChanged(int) + slide_alpha + setValue(int) + + + 482 + 285 + + + 416 + 279 + + + + + slide_blue + valueChanged(int) + spin_blue + setValue(int) + + + 416 + 232 + + + 482 + 238 + + + + + spin_blue + valueChanged(int) + slide_blue + setValue(int) + + + 482 + 238 + + + 416 + 232 + + + + + slide_hue + valueChanged(int) + spin_hue + setValue(int) + + + 405 + 20 + + + 462 + 26 + + + + + spin_hue + valueChanged(int) + slide_hue + setValue(int) + + + 448 + 18 + + + 388 + 24 + + + + + slide_hue + valueChanged(int) + ColorDialog + set_hsv() + + + 361 + 17 + + + 363 + 8 + + + + + buttonBox + accepted() + ColorDialog + accept() + + + 250 + 373 + + + 430 + 267 + + + + + buttonBox + rejected() + ColorDialog + reject() + + + 183 + 373 + + + 294 + 323 + + + + + + colorChanged(QColor) + set_rgb() + set_hsv() + setColor(QColor) + setColorInternal(QColor) + set_alpha() + +
diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_line_edit.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_line_edit.cpp new file mode 100644 index 00000000..7172253a --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_line_edit.cpp @@ -0,0 +1,211 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2017 caryoscelus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_line_edit.hpp" + +#include +#include +#include +#include +#include +#include + +#include "QtColorWidgets/color_utils.hpp" +#include "QtColorWidgets/color_names.hpp" + +namespace color_widgets { + + +class ColorLineEdit::Private +{ +public: + QColor color; + bool show_alpha = false; + bool preview_color = false; + QBrush background; + + bool customAlpha() + { + return preview_color && show_alpha && color.alpha() < 255; + } + + void setPalette(const QColor& color, ColorLineEdit* parent) + { + if ( preview_color ) + { + QColor bg = customAlpha() ? Qt::transparent : color; + QColor text = detail::color_lumaF(color) > 0.5 || color.alphaF() < 0.2 ? Qt::black : Qt::white; + parent->setStyleSheet( + QString("background-color: %1; color: %2;") + .arg(bg.name()).arg(text.name()) + ); + } + } +}; + +ColorLineEdit::ColorLineEdit(QWidget* parent) + : QLineEdit(parent), p(new Private) +{ + p->background.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png"))); + setColor(Qt::white); + /// \todo determine if having this connection might be useful + /*connect(this, &QLineEdit::textChanged, [this](const QString& text){ + QColor color = p->colorFromString(text); + if ( color.isValid() ) + Q_EMIT colorChanged(color); + });*/ + connect(this, &QLineEdit::textEdited, [this](const QString& text){ + QColor color = color_widgets::colorFromString(text, p->show_alpha); + if ( color.isValid() ) + { + p->color = color; + p->setPalette(color, this); + Q_EMIT colorEdited(color); + Q_EMIT colorChanged(color); + } + }); + connect(this, &QLineEdit::editingFinished, [this](){ + QColor color = color_widgets::colorFromString(text(), p->show_alpha); + if ( color.isValid() ) + { + p->color = color; + Q_EMIT colorEditingFinished(color); + Q_EMIT colorChanged(color); + } + else + { + setText(color_widgets::stringFromColor(p->color, p->show_alpha)); + Q_EMIT colorEditingFinished(p->color); + Q_EMIT colorChanged(color); + } + p->setPalette(p->color, this); + }); +} + +ColorLineEdit::~ColorLineEdit() +{ + delete p; +} + +QColor ColorLineEdit::color() const +{ + return p->color; +} + +void ColorLineEdit::setColor(const QColor& color) +{ + if ( color != p->color ) + { + p->color = color; + p->setPalette(p->color, this); + setText(color_widgets::stringFromColor(p->color, p->show_alpha)); + Q_EMIT colorChanged(p->color); + } +} + +void ColorLineEdit::setShowAlpha(bool showAlpha) +{ + if ( p->show_alpha != showAlpha ) + { + p->show_alpha = showAlpha; + p->setPalette(p->color, this); + setText(color_widgets::stringFromColor(p->color, p->show_alpha)); + Q_EMIT showAlphaChanged(p->show_alpha); + } +} + +bool ColorLineEdit::showAlpha() const +{ + return p->show_alpha; +} + +void ColorLineEdit::dragEnterEvent(QDragEnterEvent *event) +{ + if ( isReadOnly() ) + return; + + if ( event->mimeData()->hasColor() || + ( event->mimeData()->hasText() && + color_widgets::colorFromString(event->mimeData()->text(), p->show_alpha).isValid() ) ) + { + event->acceptProposedAction(); + } +} + + +void ColorLineEdit::dropEvent(QDropEvent *event) +{ + if ( isReadOnly() ) + return; + + if ( event->mimeData()->hasColor() ) + { + setColor(event->mimeData()->colorData().value()); + event->accept(); + } + else if ( event->mimeData()->hasText() ) + { + QColor col = color_widgets::colorFromString(event->mimeData()->text(), p->show_alpha); + if ( col.isValid() ) + { + setColor(col); + event->accept(); + } + } +} + +bool ColorLineEdit::previewColor() const +{ + return p->preview_color; +} + +void ColorLineEdit::setPreviewColor(bool previewColor) +{ + if ( previewColor != p->preview_color ) + { + p->preview_color = previewColor; + + if ( p->preview_color ) + p->setPalette(p->color, this); + else + setPalette(QApplication::palette()); + + Q_EMIT previewColorChanged(p->preview_color); + } +} + +void ColorLineEdit::paintEvent(QPaintEvent* event) +{ + if ( p->customAlpha() ) + { + QPainter painter(this); + QStyleOptionFrame panel; + initStyleOption(&panel); + QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, nullptr); + painter.fillRect(r, p->background); + painter.fillRect(r, p->color); + } + + QLineEdit::paintEvent(event); +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_list_widget.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_list_widget.cpp new file mode 100644 index 00000000..79f88df1 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_list_widget.cpp @@ -0,0 +1,149 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_list_widget.hpp" +#include "QtColorWidgets/color_selector.hpp" + +namespace color_widgets { + +class ColorListWidget::Private +{ +public: + QList colors; + QSignalMapper mapper; + ColorWheel::ShapeEnum wheel_shape = ColorWheel::ShapeTriangle; + ColorWheel::ColorSpaceEnum color_space = ColorWheel::ColorHSV; + bool wheel_rotating = true; +}; + +ColorListWidget::ColorListWidget(QWidget *parent) + : AbstractWidgetList(parent), p(new Private) +{ + connect(this, &AbstractWidgetList::removed, this, &ColorListWidget::handle_removed); + connect(&p->mapper, SIGNAL(mapped(int)), SLOT(color_changed(int))); +} + +ColorListWidget::~ColorListWidget() +{ + delete p; +} + +QList ColorListWidget::colors() const +{ + return p->colors; +} + +void ColorListWidget::setColors(const QList &colors) +{ + clear(); + p->colors = colors; + for(int i = 0;i < colors.size();i++ ) + append_widget(i); + Q_EMIT colorsChanged(colors); +} + +void ColorListWidget::swap(int a, int b) +{ + ColorSelector* sa = widget_cast(a); + ColorSelector* sb = widget_cast(b); + if ( sa && sb ) + { + QColor ca = sa->color(); + sa->setColor(sb->color()); + sb->setColor(ca); + Q_EMIT colorsChanged(p->colors); + } +} + +void ColorListWidget::append() +{ + p->colors.push_back(Qt::black); + append_widget(p->colors.size()-1); + Q_EMIT colorsChanged(p->colors); +} + +void ColorListWidget::emit_changed() +{ + Q_EMIT colorsChanged(p->colors); +} + +void ColorListWidget::handle_removed(int i) +{ + p->colors.removeAt(i); + Q_EMIT colorsChanged(p->colors); +} + +void ColorListWidget::color_changed(int row) +{ + ColorSelector *cs = widget_cast(row); + if ( cs ) + { + p->colors[row] = cs->color(); + Q_EMIT colorsChanged(p->colors); + } +} + +void ColorListWidget::append_widget(int col) +{ + ColorSelector* cbs = new ColorSelector; + cbs->setDisplayMode(ColorPreview::AllAlpha); + cbs->setColor(p->colors[col]); + //connect(cbs,SIGNAL(colorChanged(QColor)),SLOT(emit_changed())); + p->mapper.setMapping(cbs,col); + connect(cbs,SIGNAL(colorChanged(QColor)),&p->mapper,SLOT(map())); + connect(this, &ColorListWidget::wheelRotatingChanged, cbs, &ColorSelector::setWheelRotating); + connect(this, &ColorListWidget::wheelShapeChanged, cbs, &ColorSelector::setWheelShape); + connect(this, &ColorListWidget::colorSpaceChanged, cbs, &ColorSelector::setColorSpace); + appendWidget(cbs); + setRowHeight(count()-1,22); +} + +void ColorListWidget::setWheelShape(ColorWheel::ShapeEnum shape) +{ + Q_EMIT wheelShapeChanged(p->wheel_shape = shape); +} + +ColorWheel::ShapeEnum ColorListWidget::wheelShape() const +{ + return p->wheel_shape; +} + +void ColorListWidget::setColorSpace(ColorWheel::ColorSpaceEnum space) +{ + Q_EMIT colorSpaceChanged(p->color_space = space); +} + +ColorWheel::ColorSpaceEnum ColorListWidget::colorSpace() const +{ + return p->color_space; +} + +void ColorListWidget::setWheelRotating(bool rotating) +{ + Q_EMIT wheelRotatingChanged(p->wheel_rotating = rotating); +} + +bool ColorListWidget::wheelRotating() const +{ + return p->wheel_rotating; +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_names.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_names.cpp new file mode 100644 index 00000000..07d7d225 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_names.cpp @@ -0,0 +1,89 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_names.hpp" +#include + +static QRegularExpression regex_qcolor (QStringLiteral("^(?:(?:#[[:xdigit:]]{3})|(?:#[[:xdigit:]]{6})|(?:[[:alpha:]]+))$")); +static QRegularExpression regex_func_rgb (QStringLiteral(R"(^rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)$)")); +static QRegularExpression regex_hex_rgba (QStringLiteral("^#[[:xdigit:]]{8}$")); +static QRegularExpression regex_func_rgba (QStringLiteral(R"(^rgba?\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)$)")); + +namespace color_widgets { + + +QString stringFromColor(const QColor& color, bool alpha) +{ + if ( !alpha || color.alpha() == 255 ) + return color.name(); + return color.name()+QStringLiteral("%1").arg(color.alpha(), 2, 16, QChar('0')); +} + +QColor colorFromString(const QString& string, bool alpha) +{ + QString xs = string.trimmed(); + QRegularExpressionMatch match; + + match = regex_qcolor.match(xs); + if ( match.hasMatch() ) + { + return QColor(xs); + } + + match = regex_func_rgb.match(xs); + if ( match.hasMatch() ) + { + return QColor( + match.captured(1).toInt(), + match.captured(2).toInt(), + match.captured(3).toInt() + ); + } + + if ( alpha ) + { + match = regex_hex_rgba.match(xs); + if ( match.hasMatch() ) + { + return QColor( + xs.mid(1,2).toInt(nullptr,16), + xs.mid(3,2).toInt(nullptr,16), + xs.mid(5,2).toInt(nullptr,16), + xs.mid(7,2).toInt(nullptr,16) + ); + } + + match = regex_func_rgba.match(xs); + if ( match.hasMatch() ) + { + return QColor( + match.captured(1).toInt(), + match.captured(2).toInt(), + match.captured(3).toInt(), + match.captured(4).toInt() + ); + } + } + + return QColor(); +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette.cpp new file mode 100644 index 00000000..dbb9605e --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette.cpp @@ -0,0 +1,498 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_palette.hpp" +#include +#include +#include +#include +#include +#include + +namespace color_widgets { + +class ColorPalette::Private +{ +public: + QVector > colors; + int columns; + QString name; + QString fileName; + bool dirty; + + bool valid_index(int index) + { + return index >= 0 && index < colors.size(); + } +}; + +ColorPalette::ColorPalette(const QVector& colors, + const QString& name, + int columns) + : p ( new Private ) +{ + setName(name); + setColumns(columns); + setColors(colors); +} + +ColorPalette::ColorPalette(const QString& name) + : p ( new Private ) +{ + setName(name); + p->columns = 0; + p->dirty = false; +} + +ColorPalette::ColorPalette(const QVector >& colors, + const QString& name, + int columns) +{ + setName(name); + setColumns(columns); + setColors(colors); + p->dirty = false; +} + +ColorPalette::ColorPalette(const ColorPalette& other) + : QObject(), p ( new Private(*other.p) ) +{ +} + +ColorPalette& ColorPalette::operator=(const ColorPalette& other) +{ + *p = *other.p; + emitUpdate(); + return *this; +} + +ColorPalette::~ColorPalette() +{ + delete p; +} + +ColorPalette::ColorPalette(ColorPalette&& other) + : QObject(), p ( other.p ) +{ + other.p = nullptr; +} +ColorPalette& ColorPalette::operator=(ColorPalette&& other) +{ + std::swap(p, other.p); + emitUpdate(); + return *this; +} + +void ColorPalette::emitUpdate() +{ + Q_EMIT colorsChanged(p->colors); + Q_EMIT columnsChanged(p->columns); + Q_EMIT nameChanged(p->name); + Q_EMIT fileNameChanged(p->fileName); + Q_EMIT dirtyChanged(p->dirty); +} + +QColor ColorPalette::colorAt(int index) const +{ + return p->valid_index(index) ? p->colors[index].first : QColor(); +} + +QString ColorPalette::nameAt(int index) const +{ + return p->valid_index(index) ? p->colors[index].second : QString(); +} + +QVector > ColorPalette::colors() const +{ + return p->colors; +} + +int ColorPalette::count() const +{ + return p->colors.size(); +} + +int ColorPalette::columns() +{ + return p->columns; +} + +QString ColorPalette::name() const +{ + return p->name; +} + +void ColorPalette::loadColorTable(const QVector& color_table) +{ + p->colors.clear(); + p->colors.reserve(color_table.size()); + for ( QRgb c : color_table ) + { + QColor color ( c ); + color.setAlpha(255); + p->colors.push_back(qMakePair(color,QString())); + } + Q_EMIT colorsChanged(p->colors); + setDirty(true); +} + +bool ColorPalette::loadImage(const QImage& image) +{ + if ( image.isNull() ) + return false; + setColumns(image.width()); + + p->colors.clear(); + p->colors.reserve(image.width()*image.height()); + for ( int y = 0; y < image.height(); y++ ) + { + for ( int x = 0; x < image.width(); x++ ) + { + QColor color ( image.pixel(x, y) ); + color.setAlpha(255); + p->colors.push_back(qMakePair(color,QString())); + } + } + Q_EMIT colorsChanged(p->colors); + setDirty(true); + return true; +} + +ColorPalette ColorPalette::fromImage(const QImage& image) +{ + ColorPalette p; + p.loadImage(image); + return p; +} + +bool ColorPalette::load(const QString& name) +{ + p->fileName = name; + p->colors.clear(); + p->columns = 0; + p->dirty = false; + p->name = QFileInfo(name).baseName(); + + QFile file(name); + + if ( !file.open(QFile::ReadOnly|QFile::Text) ) + { + emitUpdate(); + return false; + } + + QTextStream stream( &file ); + + if ( stream.readLine() != QLatin1String("GIMP Palette") ) + { + emitUpdate(); + return false; + } + + QString line; + + // parse properties + QHash properties; + while( !stream.atEnd() ) + { + line = stream.readLine(); + if ( line.isEmpty() ) + continue; + if ( line[0] == '#' ) + break; + int colon = line.indexOf(':'); + if ( colon == -1 ) + break; + properties[line.left(colon).toLower()] = + line.right(line.size() - colon - 1).trimmed(); + } + /// \todo Store extra properties in the palette object + setName(properties[QStringLiteral("name")]); + setColumns(properties[QStringLiteral("columns")].toInt()); + + // Skip comments + if ( !stream.atEnd() && line[0] == '#' ) + while( !stream.atEnd() ) + { + qint64 pos = stream.pos(); + line = stream.readLine(); + if ( !line.isEmpty() && line[0] != '#' ) + { + stream.seek(pos); + break; + } + } + + while( !stream.atEnd() ) + { + int r = 0, g = 0, b = 0; + stream >> r >> g >> b; + line = stream.readLine().trimmed(); + p->colors.push_back(qMakePair(QColor(r, g, b), line)); + } + + Q_EMIT colorsChanged(p->colors); + setDirty(false); + + return true; +} + +ColorPalette ColorPalette::fromFile(const QString& name) +{ + ColorPalette p; + p.load(name); + return p; +} + +bool ColorPalette::save(const QString& filename) +{ + setFileName(filename); + return save(); +} + +bool ColorPalette::save() +{ + QString filename = p->fileName; + if ( filename.isEmpty() ) + { + filename = unnamed(p->name)+".gpl"; + } + + QFile file(filename); + if ( !file.open(QFile::Text|QFile::WriteOnly) ) + return false; + + QTextStream stream(&file); + + stream << "GIMP Palette\n"; + stream << "Name: " << unnamed(p->name) << '\n'; + if ( p->columns ) + stream << "Columns: " << p->columns << '\n'; + /// \todo Options to add comments + stream << "#\n"; + + for ( int i = 0; i < p->colors.size(); i++ ) + { + stream << qSetFieldWidth(3) << p->colors[i].first.red() << qSetFieldWidth(0) << ' ' + << qSetFieldWidth(3) << p->colors[i].first.green() << qSetFieldWidth(0) << ' ' + << qSetFieldWidth(3) << p->colors[i].first.blue() << qSetFieldWidth(0) << '\t' + << unnamed(p->colors[i].second) << '\n'; + } + + if ( !file.error() ) + { + setDirty(false); + return true; + } + + return false; +} + + +QString ColorPalette::fileName() const +{ + return p->fileName; +} + + +void ColorPalette::setColumns(int columns) +{ + if ( columns <= 0 ) + columns = 0; + + if ( columns != p->columns ) + { + setDirty(true); + Q_EMIT columnsChanged( p->columns = columns ); + } +} + +void ColorPalette::setColors(const QVector& colors) +{ + p->colors.clear(); + Q_FOREACH(const QColor& col, colors) + p->colors.push_back(qMakePair(col,QString())); + setDirty(true); + Q_EMIT colorsChanged(p->colors); +} + +void ColorPalette::setColors(const QVector >& colors) +{ + p->colors = colors; + setDirty(true); + Q_EMIT colorsChanged(p->colors); +} + + +void ColorPalette::setColorAt(int index, const QColor& color) +{ + if ( !p->valid_index(index) ) + return; + + p->colors[index].first = color; + + setDirty(true); + Q_EMIT colorChanged(index); + Q_EMIT colorsUpdated(p->colors); +} + +void ColorPalette::setColorAt(int index, const QColor& color, const QString& name) +{ + if ( !p->valid_index(index) ) + return; + + p->colors[index].first = color; + p->colors[index].second = name; + setDirty(true); + Q_EMIT colorChanged(index); + Q_EMIT colorsUpdated(p->colors); +} + +void ColorPalette::setNameAt(int index, const QString& name) +{ + if ( !p->valid_index(index) ) + return; + + p->colors[index].second = name; + + setDirty(true); + Q_EMIT colorChanged(index); + Q_EMIT colorsUpdated(p->colors); +} + + +void ColorPalette::appendColor(const QColor& color, const QString& name) +{ + p->colors.push_back(qMakePair(color,name)); + setDirty(true); + Q_EMIT colorAdded(p->colors.size()-1); + Q_EMIT colorsUpdated(p->colors); +} + +void ColorPalette::insertColor(int index, const QColor& color, const QString& name) +{ + if ( index < 0 || index > p->colors.size() ) + return; + + p->colors.insert(index, qMakePair(color, name)); + + setDirty(true); + Q_EMIT colorAdded(index); + Q_EMIT colorsUpdated(p->colors); +} + +void ColorPalette::eraseColor(int index) +{ + if ( !p->valid_index(index) ) + return; + + p->colors.remove(index); + + setDirty(true); + Q_EMIT colorRemoved(index); + Q_EMIT colorsUpdated(p->colors); +} + +void ColorPalette::setName(const QString& name) +{ + setDirty(true); + p->name = name; +} + +void ColorPalette::setFileName(const QString& name) +{ + setDirty(true); + p->fileName = name; +} + +QString ColorPalette::unnamed(const QString& name) const +{ + return name.isEmpty() ? tr("Unnamed") : name; +} + + +QPixmap ColorPalette::preview(const QSize& size, const QColor& background) const +{ + if ( !size.isValid() || p->colors.empty() ) + return QPixmap(); + + QPixmap out( size ); + out.fill(background); + QPainter painter(&out); + + int count = p->colors.size(); + int columns = p->columns; + if ( !columns ) + columns = std::ceil( std::sqrt( count * float(size.width()) / size.height() ) ); + int rows = std::ceil( float(count) / columns ); + QSizeF color_size(float(size.width()) / columns, float(size.height()) / rows); + + for ( int y = 0, i = 0; y < rows && i < count; y++ ) + { + for ( int x = 0; x < columns && i < count; x++, i++ ) + { + painter.fillRect(QRectF(x*color_size.width(), y*color_size.height(), + color_size.width(), color_size.height()), + p->colors[i].first + ); + } + } + + return out; +} + +bool ColorPalette::dirty() const +{ + return p->dirty; +} + +void ColorPalette::setDirty(bool dirty) +{ + if ( dirty != p->dirty ) + Q_EMIT dirtyChanged( p->dirty = dirty ); +} + +QVector ColorPalette::onlyColors() const +{ + QVector out; + out.reserve(p->colors.size()); + for ( int i = 0; i < p->colors.size(); i++ ) + out.push_back(p->colors[i].first); + return out; +} + +QVector ColorPalette::colorTable() const +{ + QVector out; + out.reserve(p->colors.size()); + for ( const auto& color_pair : p->colors ) + out.push_back(color_pair.first.rgba()); + return out; +} + +ColorPalette ColorPalette::fromColorTable(const QVector& table) +{ + ColorPalette palette; + palette.loadColorTable(table); + return palette; +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_model.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_model.cpp new file mode 100644 index 00000000..59b1cd87 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_model.cpp @@ -0,0 +1,329 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_palette_model.hpp" +#include +#include +#include + +namespace color_widgets { + +class ColorPaletteModel::Private +{ +public: + /// \todo Keep sorted by name (?) + QList palettes; + QSize icon_size; + QStringList search_paths; + QString save_path; + + Private() + : icon_size(32, 32) + {} + + bool acceptable(const QModelIndex& index) const + { + return acceptable(index.row()); + } + + bool acceptable(int row) const + { + return row >= 0 && row <= palettes.count(); + } + + QList::iterator find(const QString& name) + { + return std::find_if(palettes.begin(), palettes.end(), + [&name](const ColorPalette& palette) { + return palette.name() == name; + }); + } + + bool attemptSave(ColorPalette& palette, const QString& filename) + { + if ( filename.isEmpty() ) + return false; + return palette.save(filename); + } + + void fixUnnamed(ColorPalette& palette) + { + if ( palette.name().isEmpty() ) + palette.setName(ColorPaletteModel::tr("Unnamed")); + } + + bool save(ColorPalette& palette, const QString& suggested_filename = QString()) + { + // Attempt to save with the existing file names + if ( !suggested_filename.isEmpty() && attemptSave(palette, suggested_filename) ) + return true; + if ( attemptSave(palette, palette.fileName()) ) + return true; + + // Set up the save directory + QDir save_dir(save_path); + if ( !save_dir.exists() && !QDir().mkdir(save_path) ) + return false; + + // Attempt to save as (Name).gpl + QString filename = palette.name()+".gpl"; + if ( !save_dir.exists(filename) && + attemptSave(palette, save_dir.absoluteFilePath(filename)) ) + return true; + + // Get all of the files matching the pattern *.gpl + save_dir.setNameFilters(QStringList() << QStringLiteral("*.gpl")); + save_dir.setFilter(QDir::Files); + QStringList existing_files = save_dir.entryList(); + + // For all the files that match (Name)(Number).gpl, find the maximum (Number) + QRegularExpression name_regex(QRegularExpression::escape(palette.name())+"([0-9]+)\\.gpl"); + int max = 0; + for ( const auto& existing_file : existing_files ) + { + QRegularExpressionMatch match = name_regex.match(existing_file); + if ( match.hasMatch() ) + { + int num = match.captured(1).toInt(); + if ( num > max ) + max = num; + } + } + + return attemptSave(palette, + save_dir.absoluteFilePath(QStringLiteral("%1%2.gpl").arg(palette.name()).arg(max+1)) + ); + } +}; + +ColorPaletteModel::ColorPaletteModel() + : p ( new Private ) + {} + +ColorPaletteModel::~ColorPaletteModel() +{ + delete p; +} + +int ColorPaletteModel::rowCount(const QModelIndex &) const +{ + return count(); +} + +QVariant ColorPaletteModel::data(const QModelIndex &index, int role) const +{ + if ( !p->acceptable(index) ) + return QVariant(); + + const ColorPalette& palette = p->palettes[index.row()]; + switch( role ) + { + case Qt::DisplayRole: + return palette.name(); + case Qt::DecorationRole: + return palette.preview(p->icon_size); + case Qt::ToolTipRole: + return tr("%1 (%2 colors)").arg(palette.name()).arg(palette.count()); + } + + return QVariant(); +} + +bool ColorPaletteModel::removeRows(int row, int count, const QModelIndex & parent) +{ + Q_UNUSED(parent) + + if ( !p->acceptable(row) || count <= 0 ) + return false; + + auto begin = p->palettes.begin() + row; + auto end = row + count >= p->palettes.size() ? p->palettes.end() : begin + count; + for ( auto it = begin; it != end; ++it ) + { + if ( !it->fileName().isEmpty() ) + { + QFileInfo file(it->fileName()); + if ( file.isWritable() && file.isFile() ) + QFile::remove(it->fileName()); + } + } + + p->palettes.erase(begin, end); + + return true; +} + +QSize ColorPaletteModel::iconSize() const +{ + return p->icon_size; +} + +void ColorPaletteModel::setIconSize(const QSize& iconSize) +{ + if ( p->icon_size != iconSize ) + Q_EMIT iconSizeChanged( p->icon_size = iconSize ); +} + +QString ColorPaletteModel::savePath() const +{ + return p->save_path; +} + +QStringList ColorPaletteModel::searchPaths() const +{ + return p->search_paths; +} + +void ColorPaletteModel::setSavePath(const QString& savePath) +{ + if ( p->save_path != savePath ) + Q_EMIT savePathChanged( p->save_path = savePath ); +} + +void ColorPaletteModel::setSearchPaths(const QStringList& searchPaths) +{ + if ( p->search_paths != searchPaths ) + Q_EMIT searchPathsChanged( p->search_paths = searchPaths ); +} + +void ColorPaletteModel::addSearchPath(const QString& path) +{ + /// \todo Should compare canonical paths + /// and these checks should also be made in setSearchPaths + if ( !p->search_paths.contains(path) ) + { + p->search_paths.push_back(path); + Q_EMIT searchPathsChanged( p->search_paths ); + } +} + +void ColorPaletteModel::load() +{ + beginResetModel(); + p->palettes.clear(); + QStringList filters; + filters << QStringLiteral("*.gpl"); + for ( const QString& directory_name : p->search_paths ) + { + QDir directory(directory_name); + directory.setNameFilters(filters); + directory.setFilter(QDir::Files|QDir::Readable); + directory.setSorting(QDir::Name); + for ( const QFileInfo& file : directory.entryInfoList() ) + { + ColorPalette palette; + if ( palette.load(file.absoluteFilePath()) ) + { + p->palettes.push_back(palette); + } + } + } + endResetModel(); +} + +bool ColorPaletteModel::hasPalette(const QString& name) const +{ + return p->find(name) != p->palettes.end(); +} + +int ColorPaletteModel::count() const +{ + return p->palettes.size(); +} + +const ColorPalette& ColorPaletteModel::palette(const QString& name) const +{ + return *p->find(name); +} + +const ColorPalette& ColorPaletteModel::palette(int index) const +{ + return p->palettes[index]; +} + +bool ColorPaletteModel::updatePalette(int index, const ColorPalette& palette, bool save) +{ + if ( !p->acceptable(index) ) + return false; + + // Store the old file name + QString filename = p->palettes[index].fileName(); + // Update the palette + ColorPalette& local_palette = p->palettes[index] = palette; + p->fixUnnamed(local_palette); + + if ( save ) + return p->save(local_palette, filename); + + return true; +} + +bool ColorPaletteModel::removePalette(int index, bool remove_file) +{ + if ( !p->acceptable(index) ) + return false; + + QString file_name = p->palettes[index].fileName(); + + beginRemoveRows(QModelIndex(), index, index); + p->palettes.removeAt(index); + endRemoveRows(); + + if ( !file_name.isEmpty() && remove_file ) + { + QFileInfo file(file_name); + if ( file.isWritable() && file.isFile() ) + return QFile::remove(file_name); + return false; + } + + return true; +} + +bool ColorPaletteModel::addPalette(const ColorPalette& palette, bool save) +{ + beginInsertRows(QModelIndex(), p->palettes.size(), p->palettes.size()); + p->palettes.push_back(palette); + p->fixUnnamed(p->palettes.back()); + endInsertRows(); + + if ( save ) + return p->save(p->palettes.back()); + + return true; +} + + +int ColorPaletteModel::indexFromFile(const QString& filename) const +{ + QString canonical = QFileInfo(filename).canonicalFilePath(); + int i = 0; + for ( const auto& pal : p->palettes ) + { + if ( !pal.fileName().isEmpty() && + QFileInfo(pal.fileName()).canonicalFilePath() == canonical ) + return i; + i++; + } + return -1; +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_widget.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_widget.cpp new file mode 100644 index 00000000..15616a42 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_widget.cpp @@ -0,0 +1,416 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_palette_widget.hpp" +#include "ui_color_palette_widget.h" +#include "QtColorWidgets/color_dialog.hpp" +#include +#include +#include +#include + +namespace color_widgets { + +class ColorPaletteWidget::Private : public Ui::ColorPaletteWidget +{ +public: + ColorPaletteModel* model = nullptr; + bool read_only = false; + + bool hasSelectedPalette() + { + return model && palette_list->currentIndex() != -1; + } + + const ColorPalette& selectedPalette() + { + return model->palette(palette_list->currentIndex()); + } + + void addPalette(ColorPalette& palette) + { + bool save = false; + // Save palettes in the savePath + /// \todo This currently breaks opening the right directory + /// ie: the one containing the original file. + if ( !palette.fileName().isEmpty() ) + { + QFileInfo file(palette.fileName()); + if ( file.dir().canonicalPath() != QDir(model->savePath()).canonicalPath() ) + { + palette.setFileName(QString()); + save = true; + } + } + model->addPalette(palette, save); + palette_list->setCurrentIndex(model->count()-1); + } + + bool openImage(const QString& file) + { + QImage image(file); + if ( !image.isNull() ) + { + ColorPalette palette; + palette.loadImage(image); + palette.setName(QFileInfo(file).baseName()); + palette.setFileName(file+".gpl"); + addPalette(palette); + return true; + } + return false; + } + + bool openGpl(const QString& file) + { + int existing = model->indexFromFile(file); + if ( existing != -1 ) + { + palette_list->setCurrentIndex(existing); + return true; + } + + ColorPalette palette; + if ( palette.load(file) ) + { + addPalette(palette); + return true; + } + + return false; + } + + bool openPalette(const QString& file, int type) + { + if ( type == 1 ) + return openImage(file); + return openGpl(file); + } +}; + + +ColorPaletteWidget::ColorPaletteWidget(QWidget* parent) + : QWidget(parent), p(new Private) +{ + p->setupUi(this); + + // Connext Swatch signals + connect(p->swatch, &Swatch::colorSizeChanged, this, &ColorPaletteWidget::colorSizeChanged); + connect(p->swatch, &Swatch::colorSizePolicyChanged, this, &ColorPaletteWidget::colorSizePolicyChanged); + connect(p->swatch, &Swatch::forcedRowsChanged, this, &ColorPaletteWidget::forcedRowsChanged); + connect(p->swatch, &Swatch::forcedColumnsChanged, this, &ColorPaletteWidget::forcedColumnsChanged); + connect(p->swatch, &Swatch::colorSelected, + this, (void (ColorPaletteWidget::*)(const QColor&)) &ColorPaletteWidget::currentColorChanged); + connect(p->swatch, &Swatch::selectedChanged, + this, (void (ColorPaletteWidget::*)(int)) &ColorPaletteWidget::currentColorChanged); + connect(p->swatch, &Swatch::borderChanged, this, &ColorPaletteWidget::borderChanged); + connect(p->swatch, &Swatch::paletteChanged, this, &ColorPaletteWidget::currentPaletteChanged); + + connect(&p->swatch->palette(), &ColorPalette::dirtyChanged, p->button_palette_save, &QWidget::setEnabled); + connect(&p->swatch->palette(), &ColorPalette::dirtyChanged, p->button_palette_revert, &QWidget::setEnabled); + + connect(p->palette_list, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &ColorPaletteWidget::currentRowChanged); + + // Buttons changing the colors in the current palette + connect(p->button_color_add, &QAbstractButton::clicked, [this](){ + if ( !p->read_only && p->hasSelectedPalette() ) + { + ColorDialog dialog(this); + dialog.setAlphaEnabled(false); + if ( p->swatch->selected() != -1 ) + dialog.setColor(p->swatch->selectedColor()); + if ( dialog.exec() ) + { + p->swatch->palette().appendColor(dialog.color()); + p->swatch->setSelected(p->swatch->palette().count()-1); + } + } + }); + connect(p->button_color_remove, &QAbstractButton::clicked, p->swatch, &Swatch::removeSelected); + + // Buttons modifying the current palette file + connect(p->button_palette_delete, &QAbstractButton::clicked, [this]() { + if ( !p->read_only && p->hasSelectedPalette() ) + p->model->removePalette(p->palette_list->currentIndex()); + }); + connect(p->button_palette_save, &QAbstractButton::clicked, [this](){ + if ( !p->read_only && p->hasSelectedPalette() && p->swatch->palette().dirty() ) + if ( p->model->updatePalette( p->palette_list->currentIndex(), p->swatch->palette() ) ) + { + p->swatch->palette().setDirty(false); + } + /// \todo else ask for a file name (?) + }); + connect(p->button_palette_revert, &QAbstractButton::clicked, [this](){ + if ( p->hasSelectedPalette() ) + { + p->swatch->setPalette(p->selectedPalette()); + } + }); + + // Buttons creating new palettes + connect(p->button_palette_duplicate, &QAbstractButton::clicked, [this](){ + if ( p->hasSelectedPalette() ) + { + ColorPalette new_palette = p->selectedPalette(); + new_palette.setFileName(QString()); + bool ok = false; + QString name = QInputDialog::getText(this, tr("New Palette"), + tr("Name"), QLineEdit::Normal, new_palette.name(), &ok); + if ( ok ) + { + new_palette.setName(name); + p->model->addPalette(new_palette); + p->palette_list->setCurrentIndex(p->model->count()-1); + } + } + }); + /// \todo Show a dialog that asks for the number of columns (?) + connect(p->button_palette_new, &QAbstractButton::clicked, [this](){ + if ( p->hasSelectedPalette() ) + { + bool ok = false; + QString name = QInputDialog::getText(this, tr("New Palette"), + tr("Name"), QLineEdit::Normal, QString(), &ok); + if ( ok ) + { + ColorPalette new_palette(name); + p->model->addPalette(new_palette); + p->palette_list->setCurrentIndex(p->model->count()-1); + } + } + }); + + QString image_formats; + Q_FOREACH(QByteArray ba, QImageReader::supportedImageFormats()) + image_formats += " *."+QString(ba); + + connect(p->button_palette_open, &QAbstractButton::clicked, [this, image_formats](){ + if ( p->model ) + { + QString default_dir; + if ( p->hasSelectedPalette() ) + { + const ColorPalette& palette = p->selectedPalette(); + if ( !palette.fileName().isEmpty() ) + default_dir = QFileInfo(palette.fileName()).dir().path(); + } + + QStringList file_formats = QStringList() + << tr("GIMP Palettes (*.gpl)") + << tr("Palette Image (%1)").arg(image_formats) + << tr("All Files (*)"); + QFileDialog open_dialog(this, tr("Open Palette"), default_dir); + open_dialog.setFileMode(QFileDialog::ExistingFile); + open_dialog.setAcceptMode(QFileDialog::AcceptOpen); + open_dialog.setNameFilters(file_formats); + + if ( !open_dialog.exec() ) + return; + + int type = file_formats.indexOf(open_dialog.selectedNameFilter()); + QString file_name = open_dialog.selectedFiles()[0]; + + if ( !p->openPalette( file_name, type ) ) + { + QMessageBox::warning(this, tr("Open Palette"), + tr("Failed to load the palette file\n%1").arg(file_name)); + } + } + }); +} + +ColorPaletteWidget::~ColorPaletteWidget() = default; + +ColorPaletteModel* ColorPaletteWidget::model() const +{ + return p->model; +} + +const ColorPalette& ColorPaletteWidget::currentPalette() const +{ + return p->swatch->palette(); +} + +QSize ColorPaletteWidget::colorSize() const +{ + return p->swatch->colorSize(); +} + +Swatch::ColorSizePolicy ColorPaletteWidget::colorSizePolicy() const +{ + return p->swatch->colorSizePolicy(); +} + +QPen ColorPaletteWidget::border() const +{ + return p->swatch->border(); +} + +int ColorPaletteWidget::forcedRows() const +{ + return p->swatch->forcedRows(); +} +int ColorPaletteWidget::forcedColumns() const +{ + return p->swatch->forcedColumns(); +} + +bool ColorPaletteWidget::readOnly() const +{ + return p->read_only; +} + +QColor ColorPaletteWidget::currentColor() const +{ + return p->swatch->selectedColor(); +} + +void ColorPaletteWidget::setModel(ColorPaletteModel* model) +{ + if ( model == p->model ) + return; + p->model = model; + p->swatch->setPalette(ColorPalette()); + p->palette_list->setModel(model); +} + +void ColorPaletteWidget::setColorSize(const QSize& colorSize) +{ + p->swatch->setColorSize(colorSize); +} + +void ColorPaletteWidget::setColorSizePolicy(Swatch::ColorSizePolicy colorSizePolicy) +{ + p->swatch->setColorSizePolicy(colorSizePolicy); +} + +void ColorPaletteWidget::setBorder(const QPen& border) +{ + p->swatch->setBorder(border); +} + +void ColorPaletteWidget::setForcedRows(int forcedRows) +{ + p->swatch->setForcedRows(forcedRows); +} + +void ColorPaletteWidget::setForcedColumns(int forcedColumns) +{ + p->swatch->setForcedColumns(forcedColumns); +} + +void ColorPaletteWidget::setReadOnly(bool readOnly) +{ + if ( readOnly == p->read_only ) + return; + + p->swatch->setReadOnly(readOnly); + p->group_edit_list->setVisible(!readOnly); + p->group_edit_palette->setVisible(!readOnly); + Q_EMIT readOnlyChanged(p->read_only = readOnly); +} + +bool ColorPaletteWidget::setCurrentColor(const QColor& color) +{ + const auto& palette = p->swatch->palette(); + for ( int i = 0; i < palette.count(); i++ ) + { + if ( palette.colorAt(i) == color ) + { + p->swatch->setSelected(i); + return true; + } + } + + p->swatch->clearSelection(); + return false; +} + +bool ColorPaletteWidget::setCurrentColor(const QString& name) +{ + const auto& palette = p->swatch->palette(); + for ( int i = 0; i < palette.count(); i++ ) + { + if ( palette.nameAt(i) == name ) + { + p->swatch->setSelected(i); + return true; + } + } + + p->swatch->clearSelection(); + return false; +} + +bool ColorPaletteWidget::setCurrentColor(int index) +{ + const auto& palette = p->swatch->palette(); + if ( index >= 0 && index < palette.count() ) + { + p->swatch->setSelected(index); + return true; + } + + p->swatch->clearSelection(); + return false; +} + + +void ColorPaletteWidget::on_palette_list_currentIndexChanged(int index) +{ + if ( !p->model ) + p->swatch->setPalette(ColorPalette()); + else + p->swatch->setPalette(p->model->palette(index)); + + p->swatch->palette().setDirty(false); +} + +void ColorPaletteWidget::on_swatch_doubleClicked(int index) +{ + if ( !p->read_only ) + { + ColorDialog dialog(this); + dialog.setAlphaEnabled(false); + dialog.setColor(p->swatch->palette().colorAt(index)); + if ( dialog.exec() ) + p->swatch->palette().setColorAt(index, dialog.color()); + } +} + +int ColorPaletteWidget::currentRow() const +{ + return p->palette_list->currentIndex(); +} + +void ColorPaletteWidget::setCurrentRow(int row) +{ + p->palette_list->setCurrentIndex(row); +} + +void ColorPaletteWidget::clearCurrentColor() +{ + p->swatch->clearSelection(); +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_widget.ui b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_widget.ui new file mode 100644 index 00000000..f9bd2251 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_palette_widget.ui @@ -0,0 +1,205 @@ + + + color_widgets::ColorPaletteWidget + + + + 0 + 0 + 227 + 186 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Open a new palette from file + + + + + + + + + + + + Create a new palette + + + + + + + + + + + + Duplicate the current palette + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Delete the current palette + + + + + + + + + + + + Revert changes to the current palette + + + + + + + + + + + + Save changes to the current palette + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add a color to the palette + + + + + + + + + + + + Remove the selected color from the palette + + + + + + + + + + + + + + + + color_widgets::Swatch + QWidget +
QtColorWidgets/swatch.hpp
+
+
+ + +
diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_preview.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_preview.cpp new file mode 100644 index 00000000..d9d3dcc4 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_preview.cpp @@ -0,0 +1,185 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2014 Calle Laakkonen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_preview.hpp" + +#include +#include +#include +#include +#include + +namespace color_widgets { + +class ColorPreview::Private +{ +public: + QColor col; ///< color to be viewed + QColor comparison; ///< comparison color + QBrush back;///< Background brush, visible on a transparent color + DisplayMode display_mode; ///< How the color(s) are to be shown + + Private() : col(Qt::red), back(Qt::darkGray, Qt::DiagCrossPattern), display_mode(NoAlpha) + {} +}; + +ColorPreview::ColorPreview(QWidget *parent) : + QWidget(parent), p(new Private) +{ + p->back.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png"))); +} + +ColorPreview::~ColorPreview() +{ + delete p; +} + +void ColorPreview::setBackground(const QBrush &bk) +{ + p->back = bk; + update(); + Q_EMIT backgroundChanged(bk); +} + +QBrush ColorPreview::background() const +{ + return p->back; +} + +ColorPreview::DisplayMode ColorPreview::displayMode() const +{ + return p->display_mode; +} + +void ColorPreview::setDisplayMode(DisplayMode m) +{ + p->display_mode = m; + update(); + Q_EMIT displayModeChanged(m); +} + +QColor ColorPreview::color() const +{ + return p->col; +} + +QColor ColorPreview::comparisonColor() const +{ + return p->comparison; +} + +QSize ColorPreview::sizeHint() const +{ + return QSize(24,24); +} + +void ColorPreview::paint(QPainter &painter, QRect rect) const +{ + QColor c1, c2; + switch(p->display_mode) { + case DisplayMode::NoAlpha: + c1 = c2 = p->col.rgb(); + break; + case DisplayMode::AllAlpha: + c1 = c2 = p->col; + break; + case DisplayMode::SplitAlpha: + c1 = p->col.rgb(); + c2 = p->col; + break; + case DisplayMode::SplitColor: + c1 = p->comparison; + c2 = p->col; + break; + } + + QStyleOptionFrame panel; + panel.initFrom(this); + panel.lineWidth = 2; + panel.midLineWidth = 0; + panel.state |= QStyle::State_Sunken; + style()->drawPrimitive(QStyle::PE_Frame, &panel, &painter, this); + QRect r = style()->subElementRect(QStyle::SE_FrameContents, &panel, this); + painter.setClipRect(r); + + if ( c1.alpha() < 255 || c2.alpha() < 255 ) + painter.fillRect(0, 0, rect.width(), rect.height(), p->back); + + int w = rect.width() / 2; + int h = rect.height(); + painter.fillRect(0, 0, w, h, c1); + painter.fillRect(w, 0, w, h, c2); +} + +void ColorPreview::setColor(const QColor &c) +{ + p->col = c; + update(); + Q_EMIT colorChanged(c); +} + +void ColorPreview::setComparisonColor(const QColor &c) +{ + p->comparison = c; + update(); + Q_EMIT comparisonColorChanged(c); +} + +void ColorPreview::paintEvent(QPaintEvent *) +{ + QStylePainter painter(this); + + paint(painter, geometry()); +} + +void ColorPreview::resizeEvent(QResizeEvent *) +{ + update(); +} + +void ColorPreview::mouseReleaseEvent(QMouseEvent * ev) +{ + if ( QRect(QPoint(0,0),size()).contains(ev->pos()) ) + Q_EMIT clicked(); +} + +void ColorPreview::mouseMoveEvent(QMouseEvent *ev) +{ + + if ( ev->buttons() &Qt::LeftButton && !QRect(QPoint(0,0),size()).contains(ev->pos()) ) + { + QMimeData *data = new QMimeData; + + data->setColorData(p->col); + + QDrag* drag = new QDrag(this); + drag->setMimeData(data); + + QPixmap preview(24,24); + preview.fill(p->col); + drag->setPixmap(preview); + + drag->exec(); + } +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_selector.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_selector.cpp new file mode 100644 index 00000000..ec267d3e --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_selector.cpp @@ -0,0 +1,183 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_selector.hpp" +#include "QtColorWidgets/color_dialog.hpp" +#include +#include +#include + +namespace color_widgets { + +class ColorSelector::Private +{ +public: + UpdateMode update_mode; + ColorDialog *dialog; + QColor old_color; + + Private(QWidget *widget) : dialog(new ColorDialog(widget)) + { + dialog->setButtonMode(ColorDialog::OkCancel); + } +}; + +ColorSelector::ColorSelector(QWidget *parent) : + ColorPreview(parent), p(new Private(this)) +{ + setUpdateMode(Continuous); + p->old_color = color(); + + connect(this,&ColorPreview::clicked,this,&ColorSelector::showDialog); + connect(this,SIGNAL(colorChanged(QColor)),this,SLOT(update_old_color(QColor))); + connect(p->dialog,&QDialog::rejected,this,&ColorSelector::reject_dialog); + connect(p->dialog,&ColorDialog::colorSelected, this, &ColorSelector::accept_dialog); + + connect(p->dialog, &ColorDialog::wheelRotatingChanged, this, &ColorSelector::wheelRotatingChanged); + connect(p->dialog, &ColorDialog::wheelShapeChanged, this, &ColorSelector::wheelShapeChanged); + connect(p->dialog, &ColorDialog::colorSpaceChanged, this, &ColorSelector::colorSpaceChanged); + + setAcceptDrops(true); +} + +ColorSelector::~ColorSelector() +{ + delete p; +} + +ColorSelector::UpdateMode ColorSelector::updateMode() const +{ + return p->update_mode; +} + +void ColorSelector::setUpdateMode(UpdateMode m) +{ + p->update_mode = m; + Q_EMIT updateModeChanged(m); +} + +Qt::WindowModality ColorSelector::dialogModality() const +{ + return p->dialog->windowModality(); +} + +void ColorSelector::setDialogModality(Qt::WindowModality m) +{ + p->dialog->setWindowModality(m); + Q_EMIT dialogModalityChanged(m); +} + +void ColorSelector::setWheelShape(ColorWheel::ShapeEnum shape) +{ + p->dialog->setWheelShape(shape); +} + +ColorWheel::ShapeEnum ColorSelector::wheelShape() const +{ + return p->dialog->wheelShape(); +} + +void ColorSelector::setColorSpace(ColorWheel::ColorSpaceEnum space) +{ + p->dialog->setColorSpace(space); +} + +ColorWheel::ColorSpaceEnum ColorSelector::colorSpace() const +{ + return p->dialog->colorSpace(); +} + +void ColorSelector::setWheelRotating(bool rotating) +{ + p->dialog->setWheelRotating(rotating); +} + +bool ColorSelector::wheelRotating() const +{ + return p->dialog->wheelRotating(); +} + +void ColorSelector::showDialog() +{ + p->old_color = color(); + p->dialog->setColor(color()); + connect_dialog(); + p->dialog->show(); +} + + +void ColorSelector::connect_dialog() +{ + if (p->update_mode == Continuous) + connect(p->dialog, SIGNAL(colorChanged(QColor)), this, SLOT(setColor(QColor)), Qt::UniqueConnection); + else + disconnect_dialog(); +} + +void ColorSelector::disconnect_dialog() +{ + disconnect(p->dialog, SIGNAL(colorChanged(QColor)), this, SLOT(setColor(QColor))); +} + +void ColorSelector::accept_dialog() +{ + setColor(p->dialog->color()); + p->old_color = color(); +} + +void ColorSelector::reject_dialog() +{ + setColor(p->old_color); +} + +void ColorSelector::update_old_color(const QColor &c) +{ + if (!p->dialog->isVisible()) + p->old_color = c; +} + +void ColorSelector::dragEnterEvent(QDragEnterEvent *event) +{ + if ( event->mimeData()->hasColor() || + ( event->mimeData()->hasText() && QColor(event->mimeData()->text()).isValid() ) ) + event->acceptProposedAction(); +} + + +void ColorSelector::dropEvent(QDropEvent *event) +{ + if ( event->mimeData()->hasColor() ) + { + setColor(event->mimeData()->colorData().value()); + event->accept(); + } + else if ( event->mimeData()->hasText() ) + { + QColor col(event->mimeData()->text()); + if ( col.isValid() ) + { + setColor(col); + event->accept(); + } + } +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_utils.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_utils.cpp new file mode 100644 index 00000000..d82e2dae --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_utils.cpp @@ -0,0 +1,83 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_utils.hpp" + +namespace color_widgets { +namespace detail { + +QColor color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha ) +{ + qreal h1 = hue*6; + qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1)); + QColor col; + if ( h1 >= 0 && h1 < 1 ) + col = QColor::fromRgbF(chroma,x,0); + else if ( h1 < 2 ) + col = QColor::fromRgbF(x,chroma,0); + else if ( h1 < 3 ) + col = QColor::fromRgbF(0,chroma,x); + else if ( h1 < 4 ) + col = QColor::fromRgbF(0,x,chroma); + else if ( h1 < 5 ) + col = QColor::fromRgbF(x,0,chroma); + else if ( h1 < 6 ) + col = QColor::fromRgbF(chroma,0,x); + + qreal m = luma - color_lumaF(col); + + return QColor::fromRgbF( + qBound(0.0,col.redF()+m,1.0), + qBound(0.0,col.greenF()+m,1.0), + qBound(0.0,col.blueF()+m,1.0), + alpha); +} + +QColor color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha ) +{ + qreal chroma = (1 - qAbs(2*lig-1))*sat; + qreal h1 = hue*6; + qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1)); + QColor col; + if ( h1 >= 0 && h1 < 1 ) + col = QColor::fromRgbF(chroma,x,0); + else if ( h1 < 2 ) + col = QColor::fromRgbF(x,chroma,0); + else if ( h1 < 3 ) + col = QColor::fromRgbF(0,chroma,x); + else if ( h1 < 4 ) + col = QColor::fromRgbF(0,x,chroma); + else if ( h1 < 5 ) + col = QColor::fromRgbF(x,0,chroma); + else if ( h1 < 6 ) + col = QColor::fromRgbF(chroma,0,x); + + qreal m = lig-chroma/2; + + return QColor::fromRgbF( + qBound(0.0,col.redF()+m,1.0), + qBound(0.0,col.greenF()+m,1.0), + qBound(0.0,col.blueF()+m,1.0), + alpha); +} + +} // namespace detail +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_wheel.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_wheel.cpp new file mode 100644 index 00000000..fd0dcb6d --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/color_wheel.cpp @@ -0,0 +1,364 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_wheel.hpp" +#include "QtColorWidgets/color_wheel_private.hpp" + +#include +#include +#include +#include + +namespace color_widgets { + + +static const double selector_radius = 6; + + +ColorWheel::ColorWheel(QWidget *parent, Private* data) : + QWidget(parent), p(data) +{ + p->setup(); + setAcceptDrops(true); +} + + +ColorWheel::ColorWheel(QWidget *parent) : + ColorWheel(parent, new Private(this)) +{ + +} + + +ColorWheel::~ColorWheel() +{ + delete p; +} + +QColor ColorWheel::color() const +{ + return p->color_from(p->hue, p->sat, p->val, 1); +} + +QSize ColorWheel::sizeHint() const +{ + return QSize(p->wheel_width*5, p->wheel_width*5); +} + +qreal ColorWheel::hue() const +{ + if ( p->color_space == ColorLCH && p->sat > 0.01 ) + return color().hueF(); + return p->hue; +} + +qreal ColorWheel::saturation() const +{ + return color().hsvSaturationF(); +} + +qreal ColorWheel::value() const +{ + return color().valueF(); +} + +unsigned int ColorWheel::wheelWidth() const +{ + return p->wheel_width; +} + +void ColorWheel::setWheelWidth(unsigned int w) +{ + p->wheel_width = w; + p->render_inner_selector(); + update(); + Q_EMIT wheelWidthChanged(w); +} + +void ColorWheel::paintEvent(QPaintEvent * ) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.translate(geometry().width()/2,geometry().height()/2); + + // hue wheel + if(p->hue_ring.isNull()) + p->render_ring(); + + painter.drawPixmap(-p->outer_radius(), -p->outer_radius(), p->hue_ring); + + // hue selector + p->draw_ring_editor(p->hue, painter, Qt::black); + + // lum-sat square + if(p->inner_selector.isNull()) + p->render_inner_selector(); + + painter.rotate(p->selector_image_angle()); + painter.translate(p->selector_image_offset()); + + QPointF selector_position; + if ( p->selector_shape == ShapeSquare ) + { + qreal side = p->square_size(); + selector_position = QPointF(p->sat*side, p->val*side); + } + else if ( p->selector_shape == ShapeTriangle ) + { + qreal side = p->triangle_side(); + qreal height = p->triangle_height(); + qreal slice_h = side * p->val; + qreal ymin = side/2-slice_h/2; + + selector_position = QPointF(p->val*height, ymin + p->sat*slice_h); + QPolygonF triangle; + triangle.append(QPointF(0,side/2)); + triangle.append(QPointF(height,0)); + triangle.append(QPointF(height,side)); + QPainterPath clip; + clip.addPolygon(triangle); + painter.setClipPath(clip); + } + + painter.drawImage(QRectF(QPointF(0, 0), p->selector_size()), p->inner_selector); + painter.setClipping(false); + + // lum-sat selector + // we define the color of the selecto based on the background color of the widget + // in order to improve to contrast + if (p->backgroundIsDark) + { + bool isWhite = (p->val < 0.65 || p->sat > 0.43); + painter.setPen(QPen(isWhite ? Qt::white : Qt::black, 3)); + } + else + { + painter.setPen(QPen(p->val > 0.5 ? Qt::black : Qt::white, 3)); + } + painter.setBrush(Qt::NoBrush); + painter.drawEllipse(selector_position, selector_radius, selector_radius); + +} + +void ColorWheel::mouseMoveEvent(QMouseEvent *ev) +{ + if (p->mouse_status == DragCircle ) + { + auto hue = p->line_to_point(ev->pos()).angle()/360.0; + p->hue = hue; + p->render_inner_selector(); + + Q_EMIT colorSelected(color()); + Q_EMIT colorChanged(color()); + update(); + } + else if(p->mouse_status == DragSquare) + { + QLineF glob_mouse_ln = p->line_to_point(ev->pos()); + QLineF center_mouse_ln ( QPointF(0,0), + glob_mouse_ln.p2() - glob_mouse_ln.p1() ); + + center_mouse_ln.setAngle(center_mouse_ln.angle()+p->selector_image_angle()); + center_mouse_ln.setP2(center_mouse_ln.p2()-p->selector_image_offset()); + + if ( p->selector_shape == ShapeSquare ) + { + p->sat = qBound(0.0, center_mouse_ln.x2()/p->square_size(), 1.0); + p->val = qBound(0.0, center_mouse_ln.y2()/p->square_size(), 1.0); + } + else if ( p->selector_shape == ShapeTriangle ) + { + QPointF pt = center_mouse_ln.p2(); + + qreal side = p->triangle_side(); + p->val = qBound(0.0, pt.x() / p->triangle_height(), 1.0); + qreal slice_h = side * p->val; + + qreal ycenter = side/2; + qreal ymin = ycenter-slice_h/2; + + if ( slice_h > 0 ) + p->sat = qBound(0.0, (pt.y()-ymin)/slice_h, 1.0); + } + + Q_EMIT colorSelected(color()); + Q_EMIT colorChanged(color()); + update(); + } +} + +void ColorWheel::mousePressEvent(QMouseEvent *ev) +{ + if ( ev->buttons() & Qt::LeftButton ) + { + setFocus(); + QLineF ray = p->line_to_point(ev->pos()); + if ( ray.length() <= p->inner_radius() ) + p->mouse_status = DragSquare; + else if ( ray.length() <= p->outer_radius() ) + p->mouse_status = DragCircle; + + // Update the color + mouseMoveEvent(ev); + } +} + +void ColorWheel::mouseReleaseEvent(QMouseEvent *ev) +{ + mouseMoveEvent(ev); + p->mouse_status = Nothing; +} + +void ColorWheel::resizeEvent(QResizeEvent *) +{ + p->render_ring(); + p->render_inner_selector(); +} + +void ColorWheel::setColor(QColor c) +{ + qreal oldh = p->hue; + p->set_color(c); + if (!qFuzzyCompare(oldh+1, p->hue+1)) + p->render_inner_selector(); + update(); + Q_EMIT colorChanged(c); +} + +void ColorWheel::setHue(qreal h) +{ + p->hue = qBound(0.0, h, 1.0); + p->render_inner_selector(); + update(); +} + +void ColorWheel::setSaturation(qreal s) +{ + p->sat = qBound(0.0, s, 1.0); + update(); +} + +void ColorWheel::setValue(qreal v) +{ + p->val = qBound(0.0, v, 1.0); + update(); +} + +color_widgets::ColorWheel::ColorSpaceEnum ColorWheel::colorSpace() const +{ + return p->color_space; +} + +bool ColorWheel::rotatingSelector() const +{ + return p->rotating_selector; +} + +color_widgets::ColorWheel::ShapeEnum ColorWheel::selectorShape() const +{ + return p->selector_shape; +} + + +void ColorWheel::setColorSpace(color_widgets::ColorWheel::ColorSpaceEnum space) +{ + if ( p->color_space != space ) + { + p->color_space = space; + + QColor old_col = color(); + + switch ( space ) + { + case ColorHSL: + p->hue = old_col.hueF(); + p->sat = detail::color_HSL_saturationF(old_col); + p->val = detail::color_lightnessF(old_col); + p->color_from = &detail::color_from_hsl; + p->rainbow_from_hue = &detail::rainbow_hsv; + break; + case ColorHSV: + p->hue = old_col.hsvHueF(); + p->sat = old_col.hsvSaturationF(); + p->val = old_col.valueF(); + p->color_from = &QColor::fromHsvF; + p->rainbow_from_hue = &detail::rainbow_hsv; + break; + case ColorLCH: + p->hue = old_col.hueF(); + p->sat = detail::color_chromaF(old_col); + p->val = detail::color_lumaF(old_col); + p->color_from = &detail::color_from_lch; + p->rainbow_from_hue = &detail::rainbow_lch; + break; + } + + p->render_ring(); + p->render_inner_selector(); + update(); + Q_EMIT colorSpaceChanged(space); + } +} + +void ColorWheel::setRotatingSelector(bool rotating) +{ + p->rotating_selector = rotating; + update(); + Q_EMIT rotatingSelectorChanged(rotating); +} + +void ColorWheel::setSelectorShape(color_widgets::ColorWheel::ShapeEnum shape) +{ + if ( shape != p->selector_shape ) + { + p->selector_shape = shape; + update(); + p->render_inner_selector(); + Q_EMIT selectorShapeChanged(shape); + } +} + +void ColorWheel::dragEnterEvent(QDragEnterEvent* event) +{ + if ( event->mimeData()->hasColor() || + ( event->mimeData()->hasText() && QColor(event->mimeData()->text()).isValid() ) ) + event->acceptProposedAction(); +} + +void ColorWheel::dropEvent(QDropEvent* event) +{ + if ( event->mimeData()->hasColor() ) + { + setColor(event->mimeData()->colorData().value()); + event->accept(); + } + else if ( event->mimeData()->hasText() ) + { + QColor col(event->mimeData()->text()); + if ( col.isValid() ) + { + setColor(col); + event->accept(); + } + } +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_editor.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_editor.cpp new file mode 100644 index 00000000..5390919b --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_editor.cpp @@ -0,0 +1,575 @@ +/** + * \file gradient_editor.cpp + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/gradient_editor.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QtColorWidgets/gradient_helper.hpp" +#include "QtColorWidgets/color_dialog.hpp" + +namespace color_widgets { + +class GradientEditor::Private +{ +public: + QGradientStops stops; + QBrush back; + Qt::Orientation orientation; + int highlighted = -1; + QLinearGradient gradient; + int selected = -1; + int drop_index = -1; + QColor drop_color; + qreal drop_pos = 0; + ColorDialog color_dialog; + int dialog_selected = -1; + + Private() : + back(Qt::darkGray, Qt::DiagCrossPattern) + { + back.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png"))); + gradient.setCoordinateMode(QGradient::StretchToDeviceMode); + gradient.setSpread(QGradient::RepeatSpread); + } + + void refresh_gradient() + { + gradient.setStops(stops); + } + + qreal paint_pos(const QGradientStop& stop, const GradientEditor* owner) + { + return 2.5 + stop.first * (owner->geometry().width() - 5); + } + + int closest(const QPoint& p, GradientEditor* owner) + { + if ( stops.empty() ) + return -1; + if ( stops.size() == 1 || owner->geometry().width() <= 5 ) + return 0; + qreal pos = move_pos(p, owner); + + int i = 1; + for ( ; i < stops.size()-1; i++ ) + if ( stops[i].first >= pos ) + break; + + if ( stops[i].first - pos < pos - stops[i-1].first ) + return i; + return i-1; + } + + qreal move_pos(const QPoint& p, GradientEditor* owner) + { + int width; + qreal x; + if ( orientation == Qt::Horizontal ) + { + width = owner->geometry().width(); + x = p.x(); + } + else + { + width = owner->geometry().height(); + x = p.y(); + } + return (width > 5) ? qMax(qMin((x - 2.5) / (width - 5), 1.0), 0.0) : 0; + } + + void drop_event(QDropEvent* event, GradientEditor* owner) + { + drop_index = closest(event->pos(), owner); + drop_pos = move_pos(event->pos(), owner); + if ( drop_index == -1 ) + drop_index = stops.size(); + + // Gather up the color + if ( event->mimeData()->hasColor() ) + drop_color = event->mimeData()->colorData().value(); + else if ( event->mimeData()->hasText() ) + drop_color = QColor(event->mimeData()->text()); + + owner->update(); + } + + void clear_drop(GradientEditor* owner) + { + drop_index = -1; + drop_color = QColor(); + owner->update(); + } + + void add_stop_data(int& index, qreal& pos, QColor& color) + { + if ( stops.empty() ) + { + index = 0; + pos = 0; + color = Qt::black; + return; + } + if ( stops.size() == 1 ) + { + color = stops[0].second; + if ( stops[0].first == 1 ) + { + index = 0; + pos = 0.5; + } + else + { + index = 1; + pos = (stops[0].first + 1) / 2; + } + return; + } + + int i_before = selected; + if ( i_before == -1 ) + i_before = stops.size() - 1; + + if ( i_before == stops.size() - 1 ) + { + if ( stops[i_before].first < 1 ) + { + color = stops[i_before].second; + pos = (stops[i_before].first + 1) / 2; + index = stops.size(); + return; + } + i_before--; + } + + index = i_before + 1; + pos = (stops[i_before].first + stops[i_before+1].first) / 2; + color = blendColors(stops[i_before].second, stops[i_before+1].second, 0.5); + } +}; + +GradientEditor::GradientEditor(QWidget *parent) : + GradientEditor(Qt::Horizontal, parent) +{} + +GradientEditor::GradientEditor(Qt::Orientation orientation, QWidget *parent) : + QWidget(parent), p(new Private) +{ + p->orientation = orientation; + setMouseTracking(true); + resize(sizeHint()); + setAcceptDrops(true); + + p->color_dialog.setParent(this); + p->color_dialog.setWindowFlags(Qt::Dialog); + p->color_dialog.setWindowModality(Qt::WindowModal); + + connect(&p->color_dialog, &ColorDialog::colorSelected, this, &GradientEditor::dialogUpdate); +} + +GradientEditor::~GradientEditor() +{ + p->color_dialog.setParent(nullptr); + delete p; +} + +void GradientEditor::dialogUpdate(const QColor& c) +{ + if ( p->dialog_selected != -1 ) + { + p->stops[p->dialog_selected].second = c; + p->dialog_selected = -1; + p->refresh_gradient(); + Q_EMIT stopsChanged(p->stops); + update(); + } +} + +void GradientEditor::mouseDoubleClickEvent(QMouseEvent *ev) +{ + if ( ev->button() == Qt::LeftButton ) + { + ev->accept(); + if ( p->highlighted != -1 ) + { + qreal highlighted_pos = p->paint_pos(p->stops[p->highlighted], this); + qreal mouse_pos = orientation() == Qt::Vertical ? ev->pos().y() : ev->pos().x(); + qreal tolerance = 4; + if ( std::abs(mouse_pos - highlighted_pos) <= tolerance ) + { + p->dialog_selected = p->highlighted; + p->color_dialog.setColor(p->stops[p->highlighted].second); + p->color_dialog.show(); + return; + } + } + + qreal pos = p->move_pos(ev->pos(), this); + auto info = gradientBlendedColorInsert(p->stops, pos); + p->stops.insert(info.first, info.second); + p->selected = p->highlighted = info.first; + p->refresh_gradient(); + Q_EMIT selectedStopChanged(p->selected); + update(); + } + else + { + QWidget::mousePressEvent(ev); + } +} + +void GradientEditor::mousePressEvent(QMouseEvent *ev) +{ + if ( ev->button() == Qt::LeftButton ) + { + ev->accept(); + p->selected = p->highlighted = p->closest(ev->pos(), this); + emit selectedStopChanged(p->selected); + update(); + } + else + { + QWidget::mousePressEvent(ev); + } +} + +void GradientEditor::mouseMoveEvent(QMouseEvent *ev) +{ + if ( ev->buttons() & Qt::LeftButton && p->selected != -1 ) + { + ev->accept(); + qreal pos = p->move_pos(ev->pos(), this); + if ( p->selected > 0 && pos < p->stops[p->selected-1].first ) + { + std::swap(p->stops[p->selected], p->stops[p->selected-1]); + p->selected--; + emit selectedStopChanged(p->selected); + } + else if ( p->selected < p->stops.size()-1 && pos > p->stops[p->selected+1].first ) + { + std::swap(p->stops[p->selected], p->stops[p->selected+1]); + p->selected++; + emit selectedStopChanged(p->selected); + } + p->highlighted = p->selected; + p->stops[p->selected].first = pos; + p->refresh_gradient(); + update(); + } + else + { + p->highlighted = p->closest(ev->pos(), this); + update(); + } +} + +void GradientEditor::mouseReleaseEvent(QMouseEvent *ev) +{ + if ( ev->button() == Qt::LeftButton && p->selected != -1 ) + { + ev->accept(); + QRect bound_rect = rect(); + QPoint localpt = ev->localPos().toPoint(); + const int w_margin = 24; + const int h_margin = 8; + if ( !bound_rect.contains(localpt) && p->stops.size() > 1 && ( + localpt.x() < -w_margin || localpt.x() > bound_rect.width() + w_margin || + localpt.y() < -h_margin || localpt.y() > bound_rect.height() + h_margin + ) ) + { + p->stops.remove(p->selected); + p->highlighted = p->selected = p->dialog_selected = -1; + p->refresh_gradient(); + emit selectedStopChanged(p->selected); + } + emit stopsChanged(p->stops); + update(); + } + else + { + QWidget::mousePressEvent(ev); + } +} + +void GradientEditor::leaveEvent(QEvent*) +{ + p->highlighted = -1; + update(); +} + + +QBrush GradientEditor::background() const +{ + return p->back; +} + +void GradientEditor::setBackground(const QBrush &bg) +{ + p->back = bg; + update(); + Q_EMIT backgroundChanged(bg); +} + +QGradientStops GradientEditor::stops() const +{ + return p->stops; +} + +void GradientEditor::setStops(const QGradientStops &colors) +{ + p->selected = p->highlighted = p->dialog_selected = -1; + p->stops = colors; + p->refresh_gradient(); + emit selectedStopChanged(p->selected); + emit stopsChanged(p->stops); + update(); +} + +QLinearGradient GradientEditor::gradient() const +{ + return p->gradient; +} + +void GradientEditor::setGradient(const QLinearGradient &gradient) +{ + setStops(gradient.stops()); +} + +Qt::Orientation GradientEditor::orientation() const +{ + return p->orientation; +} + +void GradientEditor::setOrientation(Qt::Orientation orientation) +{ + p->orientation = orientation; + update(); +} + + +void GradientEditor::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + + QStyleOptionFrame panel; + panel.initFrom(this); + panel.lineWidth = 1; + panel.midLineWidth = 0; + panel.state |= QStyle::State_Sunken; + style()->drawPrimitive(QStyle::PE_Frame, &panel, &painter, this); + QRect r = style()->subElementRect(QStyle::SE_FrameContents, &panel, this); + painter.setClipRect(r); + + + if(orientation() == Qt::Horizontal) + p->gradient.setFinalStop(1, 0); + else + p->gradient.setFinalStop(0, -1); + + painter.setPen(Qt::NoPen); + painter.setBrush(p->back); + painter.drawRect(1,1,geometry().width()-2,geometry().height()-2); + painter.setBrush(p->gradient); + painter.drawRect(1,1,geometry().width()-2,geometry().height()-2); + + /// \todo Take orientation into account + int i = 0; + for ( const QGradientStop& stop : p->stops ) + { + QColor color = stop.second; + Qt::GlobalColor border_color = Qt::black; + Qt::GlobalColor core_color = Qt::white; + + if ( color.valueF() <= 0.5 && color.alphaF() >= 0.5 ) + std::swap(core_color, border_color); + + QPointF p1 = QPointF(p->paint_pos(stop, this), 2.5); + QPointF p2 = p1 + QPointF(0, geometry().height() - 5); + if ( i == p->selected ) + { + painter.setPen(QPen(border_color, 5)); + painter.drawLine(p1, p2); + painter.setPen(QPen(core_color, 3)); + painter.drawLine(p1, p2); + } + else if ( i == p->highlighted ) + { + painter.setPen(QPen(border_color, 3)); + painter.drawLine(p1, p2); + painter.setPen(QPen(core_color, 1)); + painter.drawLine(p1, p2); + } + else + { + painter.setPen(QPen(border_color, 3)); + painter.drawLine(p1, p2); + } + + i++; + } + + if ( p->drop_index != -1 && p->drop_color.isValid() ) + { + qreal pos = p->drop_pos * (geometry().width() - 5); + painter.setPen(QPen(p->drop_color, 3)); + QPointF p1 = QPointF(2.5, 2.5) + QPointF(pos, 0); + QPointF p2 = p1 + QPointF(0, geometry().height() - 5); + painter.drawLine(p1, p2); + } + +} + +QSize GradientEditor::sizeHint() const +{ + QStyleOptionSlider opt; + opt.orientation = p->orientation; + + int w = style()->pixelMetric(QStyle::PM_SliderThickness, &opt, this); + int h = std::max(84, style()->pixelMetric(QStyle::PM_SliderLength, &opt, this)); + if ( p->orientation == Qt::Horizontal ) + { + std::swap(w, h); + } + QSlider s; + return style()->sizeFromContents(QStyle::CT_Slider, &opt, QSize(w, h), &s) + .expandedTo(QApplication::globalStrut()); +} + +int GradientEditor::selectedStop() const +{ + return p->selected; +} + +void GradientEditor::setSelectedStop(int stop) +{ + if ( stop >= -1 && stop < p->stops.size() ) + { + p->selected = stop; + emit selectedStopChanged(p->selected); + } +} + +QColor GradientEditor::selectedColor() const +{ + if ( p->selected != -1 ) + return p->stops[p->selected].second; + return {}; +} + +void GradientEditor::setSelectedColor(const QColor& color) +{ + if ( p->selected != -1 ) + { + p->stops[p->selected].second = color; + p->refresh_gradient(); + update(); + } +} + + +void GradientEditor::dragEnterEvent(QDragEnterEvent *event) +{ + p->drop_event(event, this); + + if ( p->drop_color.isValid() && p->drop_index != -1 ) + { + event->setDropAction(Qt::CopyAction); + event->accept(); + } +} + +void GradientEditor::dragMoveEvent(QDragMoveEvent* event) +{ + p->drop_event(event, this); +} + +void GradientEditor::dragLeaveEvent(QDragLeaveEvent *) +{ + p->clear_drop(this); +} + +void GradientEditor::dropEvent(QDropEvent *event) +{ + p->drop_event(event, this); + + if ( !p->drop_color.isValid() || p->drop_index == -1 ) + return; + + p->stops.insert(p->drop_index, {p->drop_pos, p->drop_color}); + p->refresh_gradient(); + p->selected = p->drop_index; + event->accept(); + p->clear_drop(this); + emit selectedStopChanged(p->selected); +} + +void GradientEditor::addStop() +{ + int index = -1; + qreal pos = 0; + QColor color; + p->add_stop_data(index, pos, color); + p->stops.insert(index, {pos, color}); + p->selected = p->highlighted = index; + p->refresh_gradient(); + update(); + emit selectedStopChanged(p->selected); +} + +void GradientEditor::removeStop() +{ + if ( p->stops.size() < 2 ) + return; + + int selected = p->selected; + if ( selected == -1 ) + selected = p->stops.size() - 1; + p->stops.remove(selected); + p->refresh_gradient(); + + if ( p->selected != -1 ) + { + p->selected = -1; + emit selectedStopChanged(p->selected); + } + + p->dialog_selected = -1; + + update(); + +} + +ColorDialog * GradientEditor::dialog() const +{ + return &p->color_dialog; +} + + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_list_model.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_list_model.cpp new file mode 100644 index 00000000..4186c486 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_list_model.cpp @@ -0,0 +1,319 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ + +#include "QtColorWidgets/gradient_list_model.hpp" + +#include +#include +#include + +using namespace color_widgets; + +class GradientListModel::Private +{ +public: + struct Gradient + { + QLinearGradient gradient; + QString name; + }; + + QVector gradients; + QSize icon_size{48, 32}; + QBrush background; + ItemEditMode edit_mode = EditNone; + + Private() + { + background.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png"))); + } + + int find(const QString& name) + { + for ( int i = 0; i < gradients.size(); i++ ) + if ( gradients[0].name == name ) + return i; + return -1; + } + + bool contains(const QString& name) + { + return find(name) != -1; + } + + bool acceptable(const QModelIndex& index) const + { + return acceptable(index.row()); + } + + bool acceptable(int row) const + { + return row >= 0 && row < gradients.size(); + } + + QPixmap preview(const QLinearGradient& grad) + { + QPixmap out (icon_size); + QPainter painter(&out); + QRect r({0, 0}, icon_size); + painter.fillRect(r, background); + painter.fillRect(r, grad); + return out; + } + + QLinearGradient make_gradient(const QGradientStops& gradient_stops) + { + QLinearGradient gradient(0, 0, 1, 0); + gradient.setCoordinateMode(QGradient::StretchToDeviceMode); + gradient.setSpread(QGradient::RepeatSpread); + gradient.setStops(gradient_stops); + return gradient; + } +}; + +GradientListModel::GradientListModel(QObject *parent) + : QAbstractListModel(parent), d(new Private()) +{ +} + +GradientListModel::~GradientListModel() = default; + + +int color_widgets::GradientListModel::count() const +{ + return d->gradients.size(); +} + +void color_widgets::GradientListModel::clear() +{ + beginResetModel(); + d->gradients.clear(); + endResetModel(); +} + +QSize color_widgets::GradientListModel::iconSize() const +{ + return d->icon_size; +} + +void color_widgets::GradientListModel::setIconSize ( const QSize& iconSize ) +{ + d->icon_size = iconSize; + Q_EMIT iconSizeChanged(d->icon_size); +} + +int color_widgets::GradientListModel::setGradient ( const QString& name, const QGradient& gradient ) +{ + return setGradient(name, gradient.stops()); +} + + +int color_widgets::GradientListModel::setGradient ( const QString& name, const QGradientStops& gradient_stops ) +{ + int index = d->find(name); + if ( index != -1 ) + { + return setGradient(index, gradient_stops); + } + + index = d->gradients.size(); + beginInsertRows(QModelIndex(), index, index); + d->gradients.push_back({d->make_gradient(gradient_stops), name}); + endInsertRows(); + return index; +} + +bool color_widgets::GradientListModel::setGradient(int index, const QGradient& gradient) +{ + return setGradient(index, gradient.stops()); +} + +bool color_widgets::GradientListModel::setGradient(int index, const QGradientStops& gradient_stops) +{ + if ( index < 0 || index > d->gradients.size() ) + return false; + + d->gradients[index].gradient.setStops(gradient_stops); + QModelIndex mindex = createIndex(index, 0); + Q_EMIT dataChanged(mindex, mindex, {Qt::DecorationRole, Qt::ToolTipRole}); + return true; +} + + + +QGradientStops color_widgets::GradientListModel::gradientStops ( const QString& name ) const +{ + auto iter = d->find(name); + if ( iter != -1 ) + return d->gradients[iter].gradient.stops(); + return {}; +} + +QGradientStops color_widgets::GradientListModel::gradientStops ( int index ) const +{ + if ( d->acceptable(index) ) + return d->gradients[index].gradient.stops(); + return {}; +} + +const QLinearGradient & color_widgets::GradientListModel::gradient ( int index ) const +{ + return d->gradients[index].gradient; +} + +const QLinearGradient & color_widgets::GradientListModel::gradient ( const QString& name ) const +{ + return d->gradients[d->find(name)].gradient; +} + +int color_widgets::GradientListModel::indexFromName ( const QString& name ) const +{ + return d->find(name); +} + +int color_widgets::GradientListModel::rowCount ( const QModelIndex& ) const +{ + return d->gradients.size(); +} + +bool color_widgets::GradientListModel::hasGradient ( const QString& name ) const +{ + return d->contains(name); +} + +bool color_widgets::GradientListModel::removeGradient ( int index ) +{ + if ( !d->acceptable(index) ) + return false; + + beginRemoveRows(QModelIndex{}, index, index); + d->gradients.erase(d->gradients.begin() + index); + endRemoveRows(); + return true; +} + +bool color_widgets::GradientListModel::removeGradient ( const QString& name ) +{ + return removeGradient(d->find(name)); +} + +QVariant color_widgets::GradientListModel::data ( const QModelIndex& index, int role ) const +{ + if ( !d->acceptable(index) ) + return QVariant(); + + + const auto& gradient = d->gradients[index.row()]; + switch( role ) + { + case Qt::DisplayRole: + return gradient.name; + case Qt::DecorationRole: + return d->preview(gradient.gradient); + case Qt::ToolTipRole: + return tr("%1 (%2 colors)").arg(gradient.name).arg(gradient.gradient.stops().size()); + case Qt::EditRole: + if ( d->edit_mode == EditGradient ) + return QBrush(gradient.gradient); + else if ( d->edit_mode == EditName ) + return gradient.name; + return {}; + } + + return QVariant(); +} + +bool color_widgets::GradientListModel::rename(int index, const QString& new_name) +{ + if ( !d->acceptable(index) || d->contains(new_name) ) + return false; + + QModelIndex mindex = createIndex(index, 0); + d->gradients[index].name = new_name; + Q_EMIT dataChanged(mindex, mindex, {Qt::DisplayRole, Qt::ToolTipRole}); + return true; +} + +bool color_widgets::GradientListModel::rename(const QString& old_name, const QString& new_name) +{ + return rename(d->find(old_name), new_name); +} + +Qt::ItemFlags color_widgets::GradientListModel::flags(const QModelIndex& index) const +{ + auto flags = QAbstractListModel::flags(index); + if ( d->edit_mode ) + flags |= Qt::ItemIsEditable; + return flags; +} + +bool color_widgets::GradientListModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if ( !d->acceptable(index) ) + return false; + + if ( role == Qt::DisplayRole ) + { + return rename(index.row(), value.toString()); + } + else if ( role == Qt::EditRole ) + { + if ( d->edit_mode == EditName ) + return rename(index.row(), value.toString()); + + if ( d->edit_mode == EditGradient ) + { + const QGradient* grad = value.value().gradient(); + if ( !grad ) + return false; + return setGradient(index.row(), *grad); + } + } + + return false; +} + +color_widgets::GradientListModel::ItemEditMode color_widgets::GradientListModel::editMode() const +{ + return d->edit_mode; +} + +void color_widgets::GradientListModel::setEditMode(color_widgets::GradientListModel::ItemEditMode mode) +{ + d->edit_mode = mode; + Q_EMIT editModeChanged(mode); +} + +QBrush color_widgets::GradientListModel::gradientBrush(int index) const +{ + if ( d->acceptable(index) ) + return QBrush(d->gradients[index].gradient); + return {}; +} + +QString color_widgets::GradientListModel::nameFromIndex(int index) const +{ + if ( d->acceptable(index) ) + return d->gradients[index].name; + return {}; +} + diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_slider.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_slider.cpp new file mode 100644 index 00000000..44f378dd --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/gradient_slider.cpp @@ -0,0 +1,276 @@ +/** + * \file gradient_slider.cpp + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2014 Calle Laakkonen + * \copyright Copyright (C) 2017 caryoscelus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/gradient_slider.hpp" + +#include +#include +#include +#include +#include + +static void loadResource() +{ + static bool loaded = false; + if ( !loaded ) + { + Q_INIT_RESOURCE(color_widgets); + loaded = true; + } +} + +namespace color_widgets { + +class GradientSlider::Private +{ +public: + QLinearGradient gradient; + QBrush back; + + Private() : + back(Qt::darkGray, Qt::DiagCrossPattern) + { + loadResource(); + back.setTexture(QPixmap(QStringLiteral(":/color_widgets/alphaback.png"))); + gradient.setCoordinateMode(QGradient::StretchToDeviceMode); + gradient.setSpread(QGradient::RepeatSpread); + } + + void mouse_event(QMouseEvent *ev, GradientSlider* owner) + { + qreal pos = (owner->geometry().width() > 5) ? + static_cast(ev->pos().x() - 2.5) / (owner->geometry().width() - 5) : 0; + pos = qMax(qMin(pos, 1.0), 0.0); + owner->setSliderPosition(qRound(owner->minimum() + + pos * (owner->maximum() - owner->minimum()))); + } + +}; + +GradientSlider::GradientSlider(QWidget *parent) : + GradientSlider(Qt::Horizontal, parent) +{} + +GradientSlider::GradientSlider(Qt::Orientation orientation, QWidget *parent) : + QSlider(orientation, parent), p(new Private) +{ + setTickPosition(NoTicks); +} + +GradientSlider::~GradientSlider() +{ + delete p; +} + +void GradientSlider::mousePressEvent(QMouseEvent *ev) +{ + if ( ev->button() == Qt::LeftButton ) + { + ev->accept(); + setSliderDown(true); + p->mouse_event(ev, this); + update(); + } + else + { + QSlider::mousePressEvent(ev); + } +} + +void GradientSlider::mouseMoveEvent(QMouseEvent *ev) +{ + if ( ev->buttons() & Qt::LeftButton ) + { + ev->accept(); + p->mouse_event(ev, this); + update(); + } + else + { + QSlider::mouseMoveEvent(ev); + } +} + +void GradientSlider::mouseReleaseEvent(QMouseEvent *ev) +{ + if ( ev->button() == Qt::LeftButton ) + { + ev->accept(); + setSliderDown(false); + update(); + } + else + { + QSlider::mousePressEvent(ev); + } +} + +QBrush GradientSlider::background() const +{ + return p->back; +} + +void GradientSlider::setBackground(const QBrush &bg) +{ + p->back = bg; + update(); + Q_EMIT backgroundChanged(bg); +} + +QGradientStops GradientSlider::colors() const +{ + return p->gradient.stops(); +} + +void GradientSlider::setColors(const QGradientStops &colors) +{ + p->gradient.setStops(colors); + update(); +} + +QLinearGradient GradientSlider::gradient() const +{ + return p->gradient; +} + +void GradientSlider::setGradient(const QLinearGradient &gradient) +{ + p->gradient = gradient; + update(); +} + +void GradientSlider::setColors(const QVector &colors) +{ + QGradientStops stops; + stops.reserve(colors.size()); + + double c = colors.size() - 1; + if(c==0) { + stops.append(QGradientStop(0, colors.at(0))); + + } else { + for(int i=0;igradient.stops(); + if(stops.isEmpty()) + stops.push_back(QGradientStop(0.0, c)); + else + stops.front().second = c; + p->gradient.setStops(stops); + + update(); +} + +void GradientSlider::setLastColor(const QColor &c) +{ + QGradientStops stops = p->gradient.stops(); + if(stops.size()<2) + stops.push_back(QGradientStop(1.0, c)); + else + stops.back().second = c; + p->gradient.setStops(stops); + update(); +} + +QColor GradientSlider::firstColor() const +{ + QGradientStops s = colors(); + return s.empty() ? QColor() : s.front().second; +} + +QColor GradientSlider::lastColor() const +{ + QGradientStops s = colors(); + return s.empty() ? QColor() : s.back().second; +} + +void GradientSlider::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + + QStyleOptionFrame panel; + panel.initFrom(this); + panel.lineWidth = 1; + panel.midLineWidth = 0; + panel.state |= QStyle::State_Sunken; + style()->drawPrimitive(QStyle::PE_Frame, &panel, &painter, this); + QRect r = style()->subElementRect(QStyle::SE_FrameContents, &panel, this); + painter.setClipRect(r); + + qreal gradient_direction = invertedAppearance() ? -1 : 1; + + if(orientation() == Qt::Horizontal) + p->gradient.setFinalStop(gradient_direction, 0); + else + p->gradient.setFinalStop(0, -gradient_direction); + + painter.setPen(Qt::NoPen); + painter.setBrush(p->back); + painter.drawRect(1,1,geometry().width()-2,geometry().height()-2); + painter.setBrush(p->gradient); + painter.drawRect(1,1,geometry().width()-2,geometry().height()-2); + + qreal pos = (maximum() != 0) ? + static_cast(value() - minimum()) / maximum() : 0; + QColor color; + auto stops = p->gradient.stops(); + int i; + for (i = 0; i < stops.size(); i++) { + if (stops[i].first > pos) + break; + } + if (i == 0) { + color = firstColor(); + } if (i == stops.size()) { + color = lastColor(); + } else { + auto &a = stops[i - 1]; + auto &b = stops[i]; + auto c = (b.first - a.first); + qreal q = (c != 0) ? + (pos - a.first) / c : 0; + color = QColor::fromRgbF(b.second.redF() * q + a.second.redF() * (1.0 - q), + b.second.greenF() * q + a.second.greenF() * (1.0 - q), + b.second.blueF() * q + a.second.blueF() * (1.0 - q), + b.second.alphaF() * q + a.second.alphaF() * (1.0 - q)); + } + + pos = pos * (geometry().width() - 5); + if (color.valueF() > 0.5 || color.alphaF() < 0.5) { + painter.setPen(QPen(Qt::black, 3)); + } else { + painter.setPen(QPen(Qt::white, 3)); + } + QPointF p1 = QPointF(2.5, 2.5) + QPointF(pos, 0); + QPointF p2 = p1 + QPointF(0, geometry().height() - 5); + painter.drawLine(p1, p2); +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/harmony_color_wheel.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/harmony_color_wheel.cpp new file mode 100644 index 00000000..f38ab3d9 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/harmony_color_wheel.cpp @@ -0,0 +1,207 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2017 caryoscelus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/color_wheel_private.hpp" +#include "QtColorWidgets/harmony_color_wheel.hpp" + +namespace color_widgets { + +struct RingEditor +{ + double hue_diff; + bool editable; + int symmetric_to; + int opposite_to; + RingEditor(double hue_diff, bool editable, int symmetric_to=-1, int opposite_to=-1) : + hue_diff(hue_diff), + editable(editable), + symmetric_to(symmetric_to), + opposite_to(opposite_to) + { + } +}; + +class HarmonyColorWheel::Private : public ColorWheel::Private +{ +public: + using ColorWheel::Private::Private; + + std::vector ring_editors; + int current_ring_editor = -1; + + /** + * Puts a double into [0; 1) range + */ + static inline double normalize(double angle) + { + return angle - std::floor(angle); + } +}; + + +HarmonyColorWheel::HarmonyColorWheel(QWidget *parent) : + ColorWheel(parent, new Private(this)) +{ + connect(this, SIGNAL(colorChanged(QColor)), this, SIGNAL(harmonyChanged())); + p = static_cast(data()); +} + +HarmonyColorWheel::~HarmonyColorWheel() = default; + +QList HarmonyColorWheel::harmonyColors() const +{ + QList result; + result.push_back(color()); + for (auto const& harmony : p->ring_editors) + { + auto hue = Private::normalize(p->hue+harmony.hue_diff); + result.push_back(p->color_from(hue, p->sat, p->val, 1)); + } + return result; +} + +unsigned int HarmonyColorWheel::harmonyCount() const +{ + return 1 + p->ring_editors.size(); +} + +void HarmonyColorWheel::clearHarmonies() +{ + p->ring_editors.clear(); + p->current_ring_editor = -1; + Q_EMIT harmonyChanged(); + update(); +} + +unsigned HarmonyColorWheel::addHarmony(double hue_diff, bool editable) +{ + auto count = p->ring_editors.size(); + p->ring_editors.emplace_back(Private::normalize(hue_diff), editable, -1, -1); + Q_EMIT harmonyChanged(); + update(); + return count; +} + +unsigned HarmonyColorWheel::addSymmetricHarmony(unsigned relative_to) +{ + auto count = p->ring_editors.size(); + if (relative_to >= count) + throw std::out_of_range("incorrect call to addSymmetricHarmony: harmony number out of range"); + auto& relative = p->ring_editors[relative_to]; + relative.symmetric_to = count; + p->ring_editors.emplace_back(Private::normalize(-relative.hue_diff), relative.editable, relative_to, -1); + Q_EMIT harmonyChanged(); + update(); + return count; +} + +unsigned HarmonyColorWheel::addOppositeHarmony(unsigned relative_to) +{ + auto count = p->ring_editors.size(); + if (relative_to >= count) + throw std::out_of_range("incorrect call to addOppositeHarmony: harmony number out of range"); + auto& relative = p->ring_editors[relative_to]; + relative.opposite_to = count; + p->ring_editors.emplace_back(Private::normalize(0.5+relative.hue_diff), relative.editable, -1, relative_to); + Q_EMIT harmonyChanged(); + update(); + return count; +} + +void HarmonyColorWheel::paintEvent(QPaintEvent * ev) +{ + ColorWheel::paintEvent(ev); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.translate(geometry().width()/2,geometry().height()/2); + + for (auto const& editor : p->ring_editors) + { + auto hue = p->hue+editor.hue_diff; + // TODO: better color for uneditable indicator + auto color = editor.editable ? Qt::white : Qt::gray; + p->draw_ring_editor(hue, painter, color); + } +} + + +void HarmonyColorWheel::mousePressEvent(QMouseEvent *ev) +{ + if ( ev->buttons() & Qt::LeftButton ) + { + QLineF ray = p->line_to_point(ev->pos()); + if ( ray.length() <= p->outer_radius() && ray.length() > p->inner_radius() ) + { + p->mouse_status = DragCircle; + auto hue_diff = Private::normalize(ray.angle()/360 - p->hue); + auto i = 0; + for (auto const& editor : p->ring_editors) + { + const double eps = 1.0/64; + if (editor.editable && + editor.hue_diff <= hue_diff + eps && + editor.hue_diff >= hue_diff - eps) + { + p->current_ring_editor = i; + // no need to update color.. + return; + } + ++i; + } + } + } + ColorWheel::mousePressEvent(ev); +} + + +void HarmonyColorWheel::mouseMoveEvent(QMouseEvent *ev) +{ + if ( p->mouse_status == DragCircle && p->current_ring_editor != -1 ) + { + auto hue = p->line_to_point(ev->pos()).angle()/360.0; + auto& editor = p->ring_editors[p->current_ring_editor]; + editor.hue_diff = Private::normalize(hue - p->hue); + if (editor.symmetric_to != -1) + { + auto& symmetric = p->ring_editors[editor.symmetric_to]; + symmetric.hue_diff = Private::normalize(p->hue - hue); + } + else if (editor.opposite_to != -1) + { + auto& opposite = p->ring_editors[editor.opposite_to]; + opposite.hue_diff = Private::normalize(editor.hue_diff-0.5); + } + Q_EMIT harmonyChanged(); + update(); + return; + } + ColorWheel::mouseMoveEvent(ev); +} + +void HarmonyColorWheel::mouseReleaseEvent(QMouseEvent *ev) +{ + ColorWheel::mouseReleaseEvent(ev); + p->current_ring_editor = -1; +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/hue_slider.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/hue_slider.cpp new file mode 100644 index 00000000..d95aeac6 --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/hue_slider.cpp @@ -0,0 +1,153 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2014 Calle Laakkonen + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * \copyright Copyright (C) 2017 caryoscelus + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/hue_slider.hpp" + +namespace color_widgets { + +class HueSlider::Private +{ +private: + HueSlider *w; + +public: + qreal saturation = 1; + qreal value = 1; + qreal alpha = 1; + + Private(HueSlider *widget) + : w(widget) + { + w->setRange(0, 359); + connect(w, &QSlider::valueChanged, [this]{ + Q_EMIT w->colorHueChanged(w->colorHue()); + Q_EMIT w->colorChanged(w->color()); + }); + updateGradient(); + } + + void updateGradient() + { + static const double n_colors = 6; + QGradientStops colors; + colors.reserve(n_colors+1); + for ( int i = 0; i <= n_colors; ++i ) + colors.append(QGradientStop(i/n_colors, QColor::fromHsvF(i/n_colors, saturation, value))); + w->setColors(colors); + } +}; + +HueSlider::HueSlider(QWidget *parent) : + GradientSlider(parent), p(new Private(this)) +{ +} + +HueSlider::HueSlider(Qt::Orientation orientation, QWidget *parent) : + GradientSlider(orientation, parent), p(new Private(this)) +{ +} + +HueSlider::~HueSlider() +{ + delete p; +} + +qreal HueSlider::colorSaturation() const +{ + return p->saturation; +} + +void HueSlider::setColorSaturation(qreal s) +{ + p->saturation = qBound(0.0, s, 1.0); + p->updateGradient(); + Q_EMIT colorSaturationChanged(s); +} + +qreal HueSlider::colorValue() const +{ + return p->value; +} + +void HueSlider::setColorValue(qreal v) +{ + p->value = qBound(0.0, v, 1.0); + p->updateGradient(); + Q_EMIT colorValueChanged(v); +} + +qreal HueSlider::colorAlpha() const +{ + return p->alpha; +} + +void HueSlider::setColorAlpha(qreal alpha) +{ + p->alpha = alpha; + p->updateGradient(); + Q_EMIT colorAlphaChanged(alpha); +} + +QColor HueSlider::color() const +{ + return QColor::fromHsvF(colorHue(), p->saturation, p->value, p->alpha); +} + +void HueSlider::setColor(const QColor& color) +{ + p->saturation = color.saturationF(); + p->value = color.valueF(); + p->updateGradient(); + setColorHue(color.hueF()); + Q_EMIT colorValueChanged(p->alpha); + Q_EMIT colorSaturationChanged(p->alpha); +} + +void HueSlider::setFullColor(const QColor& color) +{ + p->alpha = color.alphaF(); + setColor(color); + Q_EMIT colorAlphaChanged(p->alpha); +} + +qreal HueSlider::colorHue() const +{ + if (maximum() == minimum()) + return 0; + auto hue = qreal(value() - minimum()) / (maximum() - minimum()); + if (orientation() == Qt::Vertical) + hue = 1 - hue; + return hue; +} + +void HueSlider::setColorHue(qreal colorHue) +{ + // TODO: consider supporting invertedAppearance? + if (orientation() == Qt::Vertical) + colorHue = 1 - colorHue; + setValue(minimum()+colorHue*(maximum()-minimum())); + Q_EMIT colorHueChanged(colorHue); + Q_EMIT colorChanged(color()); +} + +} // namespace color_widgets diff --git a/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/swatch.cpp b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/swatch.cpp new file mode 100644 index 00000000..bc68440d --- /dev/null +++ b/thirdparty/Qt-Color-Widgets/src/QtColorWidgets/swatch.cpp @@ -0,0 +1,792 @@ +/** + * \file + * + * \author Mattia Basaglia + * + * \copyright Copyright (C) 2013-2020 Mattia Basaglia + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ +#include "QtColorWidgets/swatch.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace color_widgets { + +class Swatch::Private +{ +public: + ColorPalette palette; ///< Palette with colors and related metadata + int selected; ///< Current selection index (-1 for no selection) + QSize color_size; ///< Preferred size for the color squares + ColorSizePolicy size_policy; + QPen border; + int forced_rows; + int forced_columns; + bool readonly; ///< Whether the palette can be modified via user interaction + + QPoint drag_pos; ///< Point used to keep track of dragging + int drag_index; ///< Index used by drags + int drop_index; ///< Index for a requested drop + QColor drop_color; ///< Dropped color + bool drop_overwrite; ///< Whether the drop will overwrite an existing color + + Swatch* owner; + + Private(Swatch* owner) + : selected(-1), + color_size(16,16), + size_policy(Hint), + border(Qt::black, 1), + forced_rows(0), + forced_columns(0), + readonly(false), + drag_index(-1), + drop_index(-1), + drop_overwrite(false), + owner(owner) + {} + + /** + * \brief Number of rows/columns in the palette + */ + QSize rowcols() + { + int count = palette.count(); + if ( count == 0 ) + return QSize(); + + if ( forced_rows ) + return QSize(std::ceil( float(count) / forced_rows ), forced_rows); + + int columns = palette.columns(); + + if ( forced_columns ) + columns = forced_columns; + else if ( columns == 0 ) + columns = qMin(palette.count(), owner->width() / color_size.width()); + + int rows = std::ceil( float(count) / columns ); + + return QSize(columns, rows); + } + + /** + * \brief Sets the drop properties + */ + void dropEvent(QDropEvent* event) + { + // Find the output location + drop_index = owner->indexAt(event->pos()); + if ( drop_index == -1 ) + drop_index = palette.count(); + + // Gather up the color + if ( event->mimeData()->hasColor() ) + { + drop_color = event->mimeData()->colorData().value(); + drop_color.setAlpha(255); + } + else if ( event->mimeData()->hasText() ) + { + drop_color = QColor(event->mimeData()->text()); + } + + drop_overwrite = false; + QRectF drop_rect = indexRect(drop_index); + if ( drop_index < palette.count() && drop_rect.isValid() ) + { + // 1 column => vertical style + if ( palette.columns() == 1 || forced_columns == 1 ) + { + // Dragged to the last quarter of the size of the square, add after + if ( event->posF().y() >= drop_rect.top() + drop_rect.height() * 3.0 / 4 ) + drop_index++; + // Dragged to the middle of the square, overwrite existing color + else if ( event->posF().x() > drop_rect.top() + drop_rect.height() / 4 && + ( event->dropAction() != Qt::MoveAction || event->source() != owner ) ) + drop_overwrite = true; + } + else + { + // Dragged to the last quarter of the size of the square, add after + if ( event->posF().x() >= drop_rect.left() + drop_rect.width() * 3.0 / 4 ) + drop_index++; + // Dragged to the middle of the square, overwrite existing color + else if ( event->posF().x() > drop_rect.left() + drop_rect.width() / 4 && + ( event->dropAction() != Qt::MoveAction || event->source() != owner ) ) + drop_overwrite = true; + } + } + + owner->update(); + } + + /** + * \brief Clears drop properties + */ + void clearDrop() + { + drop_index = -1; + drop_color = QColor(); + drop_overwrite = false; + + owner->update(); + } + + /** + * \brief Actual size of a color square + */ + QSizeF actualColorSize() + { + QSize rowcols = this->rowcols(); + if ( !rowcols.isValid() ) + return QSizeF(); + return actualColorSize(rowcols); + } + + /** + * \brief Actual size of a color square + * \pre rowcols.isValid() and obtained via rowcols() + */ + QSizeF actualColorSize(const QSize& rowcols) + { + return QSizeF (float(owner->width()) / rowcols.width(), + float(owner->height()) / rowcols.height()); + } + + + /** + * \brief Rectangle corresponding to the color at the given index + * \pre rowcols.isValid() and obtained via rowcols() + * \pre color_size obtained via rowlcols(rowcols) + */ + QRectF indexRect(int index, const QSize& rowcols, const QSizeF& color_size) + { + if ( index == -1 ) + return QRectF(); + + return QRectF( + index % rowcols.width() * color_size.width(), + index / rowcols.width() * color_size.height(), + color_size.width(), + color_size.height() + ); + } + /** + * \brief Rectangle corresponding to the color at the given index + */ + QRectF indexRect(int index) + { + QSize rc = rowcols(); + if ( index == -1 || !rc.isValid() ) + return QRectF(); + return indexRect(index, rc, actualColorSize(rc)); + } +}; + +Swatch::Swatch(QWidget* parent) + : QWidget(parent), p(new Private(this)) +{ + connect(&p->palette, &ColorPalette::colorsChanged, this, &Swatch::paletteModified); + connect(&p->palette, &ColorPalette::colorAdded, this, &Swatch::paletteModified); + connect(&p->palette, &ColorPalette::colorRemoved, this, &Swatch::paletteModified); + connect(&p->palette, &ColorPalette::columnsChanged, this, (void(QWidget::*)())&QWidget::update); + connect(&p->palette, &ColorPalette::colorsUpdated, this, (void(QWidget::*)())&QWidget::update); + connect(&p->palette, &ColorPalette::colorChanged, [this](int index){ + if ( index == p->selected ) + Q_EMIT colorSelected( p->palette.colorAt(index) ); + }); + setFocusPolicy(Qt::StrongFocus); + setAcceptDrops(true); + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + setAttribute(Qt::WA_Hover, true); +} + +Swatch::~Swatch() +{ + delete p; +} + +QSize Swatch::sizeHint() const +{ + QSize rowcols = p->rowcols(); + + if ( !p->color_size.isValid() || !rowcols.isValid() ) + return QSize(); + + return QSize( + p->color_size.width() * rowcols.width(), + p->color_size.height() * rowcols.height() + ); +} + +QSize Swatch::minimumSizeHint() const +{ + if ( p->size_policy != Hint ) + return sizeHint(); + return QSize(); +} + +const ColorPalette& Swatch::palette() const +{ + return p->palette; +} + +ColorPalette& Swatch::palette() +{ + return p->palette; +} + +int Swatch::selected() const +{ + return p->selected; +} + +QColor Swatch::selectedColor() const +{ + return p->palette.colorAt(p->selected); +} + +int Swatch::indexAt(const QPoint& pt) +{ + QSize rowcols = p->rowcols(); + if ( rowcols.isEmpty() ) + return -1; + + QSizeF color_size = p->actualColorSize(rowcols); + + QPoint point( + qBound(0, pt.x() / color_size.width(), rowcols.width() - 1), + qBound(0, pt.y() / color_size.height(), rowcols.height() - 1) + ); + + int index = point.y() * rowcols.width() + point.x(); + if ( index >= p->palette.count() ) + return -1; + return index; +} + +QColor Swatch::colorAt(const QPoint& pt) +{ + return p->palette.colorAt(indexAt(pt)); +} + +void Swatch::setPalette(const ColorPalette& palette) +{ + clearSelection(); + p->palette = palette; + update(); + Q_EMIT paletteChanged(p->palette); +} + +void Swatch::setSelected(int selected) +{ + if ( selected < 0 || selected >= p->palette.count() ) + selected = -1; + + if ( selected != p->selected ) + { + Q_EMIT selectedChanged( p->selected = selected ); + if ( selected != -1 ) + Q_EMIT colorSelected( p->palette.colorAt(p->selected) ); + update(); + } +} + +void Swatch::clearSelection() +{ + setSelected(-1); +} + +void Swatch::paintEvent(QPaintEvent* event) +{ + Q_UNUSED(event) + QSize rowcols = p->rowcols(); + if ( rowcols.isEmpty() ) + return; + + QSizeF color_size = p->actualColorSize(rowcols); + QPainter painter(this); + + QStyleOptionFrame panel; + panel.initFrom(this); + panel.lineWidth = 1; + panel.midLineWidth = 0; + panel.state |= QStyle::State_Sunken; + style()->drawPrimitive(QStyle::PE_Frame, &panel, &painter, this); + QRect r = style()->subElementRect(QStyle::SE_FrameContents, &panel, this); + painter.setClipRect(r); + + int count = p->palette.count(); + painter.setPen(p->border); + for ( int y = 0, i = 0; i < count; y++ ) + { + for ( int x = 0; x < rowcols.width() && i < count; x++, i++ ) + { + painter.setBrush(p->palette.colorAt(i)); + painter.drawRect(p->indexRect(i, rowcols, color_size)); + } + } + + painter.setClipping(false); + + if ( p->drop_index != -1 ) + { + QRectF drop_area = p->indexRect(p->drop_index, rowcols, color_size); + if ( p->drop_overwrite ) + { + painter.setBrush(p->drop_color); + painter.setPen(QPen(Qt::gray)); + painter.drawRect(drop_area); + } + else if ( rowcols.width() == 1 ) + { + // 1 column => vertical style + painter.setPen(QPen(p->drop_color, 2)); + painter.setBrush(Qt::transparent); + painter.drawLine(drop_area.topLeft(), drop_area.topRight()); + } + else + { + painter.setPen(QPen(p->drop_color, 2)); + painter.setBrush(Qt::transparent); + painter.drawLine(drop_area.topLeft(), drop_area.bottomLeft()); + // Draw also on the previous line when the first item of a line is selected + if ( p->drop_index % rowcols.width() == 0 && p->drop_index != 0 ) + { + drop_area = p->indexRect(p->drop_index-1, rowcols, color_size); + drop_area.translate(color_size.width(), 0); + painter.drawLine(drop_area.topLeft(), drop_area.bottomLeft()); + } + } + } + + if ( p->selected != -1 ) + { + QRectF rect = p->indexRect(p->selected, rowcols, color_size); + painter.setBrush(Qt::transparent); + painter.setPen(QPen(Qt::darkGray, 2)); + painter.drawRect(rect); + painter.setPen(QPen(Qt::gray, 2, Qt::DotLine)); + painter.drawRect(rect); + } +} + +void Swatch::keyPressEvent(QKeyEvent* event) +{ + if ( p->palette.count() == 0 ) + QWidget::keyPressEvent(event); + + int selected = p->selected; + int count = p->palette.count(); + QSize rowcols = p->rowcols(); + int columns = rowcols.width(); + int rows = rowcols.height(); + switch ( event->key() ) + { + default: + QWidget::keyPressEvent(event); + return; + + case Qt::Key_Left: + if ( selected == -1 ) + selected = count - 1; + else if ( selected > 0 ) + selected--; + break; + + case Qt::Key_Right: + if ( selected == -1 ) + selected = 0; + else if ( selected < count - 1 ) + selected++; + break; + + case Qt::Key_Up: + if ( selected == -1 ) + selected = count - 1; + else if ( selected >= columns ) + selected -= columns; + break; + + case Qt::Key_Down: + if ( selected == -1 ) + selected = 0; + else if ( selected < count - columns ) + selected += columns; + break; + + case Qt::Key_Home: + if ( event->modifiers() & Qt::ControlModifier ) + selected = 0; + else + selected -= selected % columns; + break; + + case Qt::Key_End: + if ( event->modifiers() & Qt::ControlModifier ) + selected = count - 1; + else + selected += columns - (selected % columns) - 1; + break; + + case Qt::Key_Delete: + removeSelected(); + return; + + case Qt::Key_Backspace: + if (selected != -1 && !p->readonly ) + { + p->palette.eraseColor(selected); + if ( p->palette.count() == 0 ) + selected = -1; + else + selected = qMax(selected - 1, 0); + } + break; + + case Qt::Key_PageUp: + if ( selected == -1 ) + selected = 0; + else + selected = selected % columns; + break; + case Qt::Key_PageDown: + if ( selected == -1 ) + { + selected = count - 1; + } + else + { + selected = columns * (rows-1) + selected % columns; + if ( selected >= count ) + selected -= columns; + } + break; + } + setSelected(selected); +} + +void Swatch::removeSelected() +{ + if (p->selected != -1 && !p->readonly ) + { + int selected = p->selected; + p->palette.eraseColor(p->selected); + setSelected(qMin(selected, p->palette.count() - 1)); + } +} + +void Swatch::mousePressEvent(QMouseEvent *event) +{ + if ( event->button() == Qt::LeftButton ) + { + setSelected(indexAt(event->pos())); + p->drag_pos = event->pos(); + p->drag_index = indexAt(event->pos()); + } + else if ( event->button() == Qt::RightButton ) + { + int index = indexAt(event->pos()); + if ( index != -1 ) + Q_EMIT rightClicked(index); + } +} + +void Swatch::mouseMoveEvent(QMouseEvent *event) +{ + if ( p->drag_index != -1 && (event->buttons() & Qt::LeftButton) && + (p->drag_pos - event->pos()).manhattanLength() >= QApplication::startDragDistance() ) + { + QColor color = p->palette.colorAt(p->drag_index); + + QPixmap preview(24,24); + preview.fill(color); + + QMimeData *mimedata = new QMimeData; + mimedata->setColorData(color); + mimedata->setText(p->palette.nameAt(p->drag_index)); + + QDrag *drag = new QDrag(this); + drag->setMimeData(mimedata); + drag->setPixmap(preview); + Qt::DropActions actions = Qt::CopyAction; + if ( !p->readonly ) + actions |= Qt::MoveAction; + drag->exec(actions); + } +} + +void Swatch::mouseReleaseEvent(QMouseEvent *event) +{ + if ( event->button() == Qt::LeftButton ) + { + p->drag_index = -1; + } +} + +void Swatch::mouseDoubleClickEvent(QMouseEvent *event) +{ + if ( event->button() == Qt::LeftButton ) + { + int index = indexAt(event->pos()); + if ( index != -1 ) + Q_EMIT doubleClicked(index); + } +} + +void Swatch::wheelEvent(QWheelEvent* event) +{ + if ( event->delta() > 0 ) + p->selected = qMin(p->selected + 1, p->palette.count() - 1); + else if ( p->selected == -1 ) + p->selected = p->palette.count() - 1; + else if ( p->selected > 0 ) + p->selected--; + setSelected(p->selected); +} + +void Swatch::dragEnterEvent(QDragEnterEvent *event) +{ + if ( p->readonly ) + return; + + p->dropEvent(event); + + if ( p->drop_color.isValid() && p->drop_index != -1 ) + { + if ( event->proposedAction() == Qt::MoveAction && event->source() == this ) + event->setDropAction(Qt::MoveAction); + else + event->setDropAction(Qt::CopyAction); + + event->accept(); + } +} + +void Swatch::dragMoveEvent(QDragMoveEvent* event) +{ + if ( p->readonly ) + return; + p->dropEvent(event); +} + +void Swatch::dragLeaveEvent(QDragLeaveEvent *event) +{ + Q_UNUSED(event) + p->clearDrop(); +} + +void Swatch::dropEvent(QDropEvent *event) +{ + if ( p->readonly ) + return; + + QString name; + + // Gather up the color + if ( event->mimeData()->hasColor() && event->mimeData()->hasText() ) + name = event->mimeData()->text(); + + // Not a color, discard + if ( !p->drop_color.isValid() || p->drop_index == -1 ) + return; + + p->dropEvent(event); + + // Move unto self + if ( event->dropAction() == Qt::MoveAction && event->source() == this ) + { + // Not moved => noop + if ( p->drop_index != p->drag_index && p->drop_index != p->drag_index + 1 ) + { + // Erase the old color + p->palette.eraseColor(p->drag_index); + if ( p->drop_index > p->drag_index ) + p->drop_index--; + p->selected = p->drop_index; + // Insert the dropped color + p->palette.insertColor(p->drop_index, p->drop_color, name); + } + } + // Move into a color cell + else if ( p->drop_overwrite ) + { + p->palette.setColorAt(p->drop_index, p->drop_color, name); + } + // Insert the dropped color + else + { + p->palette.insertColor(p->drop_index, p->drop_color, name); + } + + // Finalize + event->accept(); + p->drag_index = -1; + p->clearDrop(); +} + +void Swatch::paletteModified() +{ + if ( p->selected >= p->palette.count() ) + clearSelection(); + + if ( p->size_policy != Hint ) + { + QSize size_hint = sizeHint(); + + if ( size_hint.isValid() ) + { + if ( p->size_policy == Minimum ) + setMinimumSize(size_hint); + else if ( p->size_policy == Fixed ) + setFixedSize(size_hint); + } + } + + update(); +} + +QSize Swatch::colorSize() const +{ + return p->color_size; +} + +void Swatch::setColorSize(const QSize& colorSize) +{ + if ( p->color_size != colorSize ) + Q_EMIT colorSizeChanged(p->color_size = colorSize); +} + +Swatch::ColorSizePolicy Swatch::colorSizePolicy() const +{ + return p->size_policy; +} + +void Swatch::setColorSizePolicy(ColorSizePolicy colorSizePolicy) +{ + if ( p->size_policy != colorSizePolicy ) + { + setMinimumSize(0,0); + setFixedSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX); + Q_EMIT colorSizePolicyChanged(p->size_policy = colorSizePolicy); + paletteModified(); + } +} + +int Swatch::forcedColumns() const +{ + return p->forced_columns; +} + +int Swatch::forcedRows() const +{ + return p->forced_rows; +} + +void Swatch::setForcedColumns(int forcedColumns) +{ + if ( forcedColumns <= 0 ) + forcedColumns = 0; + + if ( forcedColumns != p->forced_columns ) + { + Q_EMIT forcedColumnsChanged(p->forced_columns = forcedColumns); + Q_EMIT forcedRowsChanged(p->forced_rows = 0); + } +} + +void Swatch::setForcedRows(int forcedRows) +{ + if ( forcedRows <= 0 ) + forcedRows = 0; + + if ( forcedRows != p->forced_rows ) + { + Q_EMIT forcedColumnsChanged(p->forced_columns = 0); + Q_EMIT forcedRowsChanged(p->forced_rows = forcedRows); + } +} + +bool Swatch::readOnly() const +{ + return p->readonly; +} + +void Swatch::setReadOnly(bool readOnly) +{ + if ( readOnly != p->readonly ) + { + Q_EMIT readOnlyChanged(p->readonly = readOnly); + setAcceptDrops(!p->readonly); + } +} + +bool Swatch::event(QEvent* event) +{ + if(event->type() == QEvent::ToolTip) + { + QHelpEvent* help_ev = static_cast(event); + int index = indexAt(help_ev->pos()); + if ( index != -1 ) + { + QColor color = p->palette.colorAt(index); + QString name = p->palette.nameAt(index); + QString message = color.name(); + if ( !name.isEmpty() ) + message = tr("%1 (%2)").arg(name).arg(message); + message = "MM "+message.toHtmlEscaped(); + QToolTip::showText(help_ev->globalPos(), message, this, + p->indexRect(index).toRect()); + event->accept(); + } + else + { + QToolTip::hideText(); + event->ignore(); + } + return true; + } + + return QWidget::event(event); +} + +QPen Swatch::border() const +{ + return p->border; +} + +void Swatch::setBorder(const QPen& border) +{ + if ( border != p->border ) + { + p->border = border; + Q_EMIT borderChanged(border); + update(); + } +} + +} // namespace color_widgets