aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMorteza Jamshidi <morteza.jamshidi@qt.io>2025-12-05 14:59:23 +0100
committerMorteza Jamshidi <morteza.jamshidi@qt.io>2025-12-18 14:08:35 +0100
commiteaebe6716d0bc7aea7503048e243d269837411c8 (patch)
treeafa1c7512669891b47f405f5646453387ea45b9a /src
parent70b885d2cd4eff2aa1ee08368893105666d5a92b (diff)
ColorDialog: use canvas to draw color picker for software renderer
When backend renderer is software ShaderEffect doesn't render anything, so we use canvas renderer as a fallback. Fixes: QTBUG-139362 Change-Id: Id22305ab48d52f9bf2373c88f87cbb10c115999c Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt4
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml10
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp169
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h26
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/shaders/SaturationLightness.vert18
5 files changed, 219 insertions, 8 deletions
diff --git a/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt b/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt
index 4bb0812239..2c6d8fc5a1 100644
--- a/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt
+++ b/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt
@@ -279,9 +279,13 @@ qt_internal_add_resource(QuickDialogs2QuickImpl "QuickDialogs2QuickImpl"
)
qt_internal_add_shaders(QuickDialogs2QuickImpl "QuickDialogs2QuickImplShaders"
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
PREFIX
"/qt-project.org/imports/QtQuick/Dialogs/quickimpl"
FILES
+ "shaders/SaturationLightness.vert"
"shaders/SaturationLightness.frag"
SILENT
)
diff --git a/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml b/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml
index 5ad394657e..bef30ce3a8 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml
+++ b/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml
@@ -18,15 +18,9 @@ SaturationLightnessPickerImpl {
border.color: "#353637"
}
- contentItem: ShaderEffect {
- scale: contentItem.width / width
- layer.enabled: true
- layer.smooth: true
+ contentItem: SaturationLightnessPickerCanvas {
anchors.fill: parent
-
- property alias hue: control.hue
-
- fragmentShader: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.frag.qsb"
+ hue: control.hue
}
handle: PickerHandle {
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp
index 02aad6198c..1969a4f548 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp
@@ -4,6 +4,8 @@
#include "qquicksaturationlightnesspicker_p.h"
#include "qquickabstractcolorpicker_p_p.h"
+#include "qsgsimpletexturenode.h"
+#include "qsgtexture.h"
#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
#include <QtQuickTemplates2/private/qquickdeferredexecute_p_p.h>
@@ -22,6 +24,173 @@ QQuickSaturationLightnessPickerPrivate::QQuickSaturationLightnessPickerPrivate()
m_hsl = true;
}
+class QQuickSaturationLightnessPickerMaterialShader : public QSGMaterialShader
+{
+public:
+ QQuickSaturationLightnessPickerMaterialShader() {
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.vert.qsb"));
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.frag.qsb"));
+ }
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+};
+
+class QQuickSaturationLightnessPickerMaterial : public QSGMaterial
+{
+public:
+ QQuickSaturationLightnessPickerMaterial() { setFlag(Blending, true); }
+ QSGMaterialType* type() const override { static QSGMaterialType t; return &t; }
+ QSGMaterialShader* createShader(QSGRendererInterface::RenderMode renderMode) const override{
+ Q_UNUSED(renderMode);
+ return new QQuickSaturationLightnessPickerMaterialShader();
+ }
+ float hue = 0.0f;
+};
+
+bool QQuickSaturationLightnessPickerMaterialShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ Q_ASSERT(!oldMaterial || newMaterial->type() == oldMaterial->type());
+
+ QQuickSaturationLightnessPickerMaterial *mat =
+ static_cast<QQuickSaturationLightnessPickerMaterial*>(newMaterial);
+ QQuickSaturationLightnessPickerMaterial *oldMat =
+ static_cast<QQuickSaturationLightnessPickerMaterial*>(oldMaterial);
+
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+
+ if (state.isMatrixDirty()) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ changed = true;
+ }
+
+ if (state.isOpacityDirty() || !oldMat) {
+ float opacity = state.opacity();
+ memcpy(buf->data() + 64, &opacity, sizeof(float));
+ changed = true;
+ }
+
+ if (!oldMat || mat->hue != oldMat->hue) {
+ float hue = mat->hue;
+ memcpy(buf->data() + 64 + 4, &hue, sizeof(float));
+ changed = true;
+ }
+
+ return changed;
+}
+
+QQuickSaturationLightnessPickerCanvas::QQuickSaturationLightnessPickerCanvas(QQuickItem *parent)
+ : QQuickItem(parent), m_hue(0) {
+ setFlag(ItemHasContents, true);
+}
+
+void QQuickSaturationLightnessPickerCanvas::setHue(qreal h)
+{
+ if (h == m_hue)
+ return;
+ m_hue = h;
+ m_image = QImage();
+ emit hueChanged();
+ update();
+}
+
+QSGNode *QQuickSaturationLightnessPickerCanvas::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ QSGGeometryNode *node = nullptr;
+
+ bool shaderSupported = false;
+ if (window()) {
+ QSGRendererInterface::GraphicsApi api = window()->rendererInterface()->graphicsApi();
+ switch (api) {
+ case QSGRendererInterface::OpenGL:
+ case QSGRendererInterface::Vulkan:
+ case QSGRendererInterface::Metal:
+ case QSGRendererInterface::Direct3D11:
+ shaderSupported = true;
+ break;
+ default:
+ shaderSupported = false;
+ }
+ }
+ if (shaderSupported) {
+ // GPU path
+ QSGGeometryNode* geomNode = static_cast<QSGGeometryNode*>(oldNode);
+ QSGGeometry* geom;
+ if (!geomNode) {
+ geomNode = new QSGGeometryNode();
+ geom = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
+ geom->setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ geomNode->setGeometry(geom);
+ geomNode->setFlag(QSGNode::OwnsGeometry);
+
+ auto* mat = new QQuickSaturationLightnessPickerMaterial();
+ geomNode->setMaterial(mat);
+ geomNode->setFlag(QSGNode::OwnsMaterial);
+ }
+ else {
+ geom = geomNode->geometry();
+ }
+
+ if (m_lastSize != size()) {
+ m_lastSize = size();
+
+ auto *v = geom->vertexDataAsTexturedPoint2D();
+ v[0].set(0, 0, 0, 0);
+ v[1].set(width(), 0, 1, 0);
+ v[2].set(0, height(), 0, 1);
+ v[3].set(width(), height(), 1, 1);
+
+ geomNode->markDirty(QSGNode::DirtyGeometry);
+ }
+
+ auto* mat = static_cast<QQuickSaturationLightnessPickerMaterial*>(geomNode->material());
+ if (mat->hue != m_hue) {
+ mat->hue = m_hue;
+ geomNode->markDirty(QSGNode::DirtyMaterial);
+ }
+ node = geomNode;
+
+ } else {
+ // CPU path
+ QSGSimpleTextureNode *texNode = static_cast<QSGSimpleTextureNode*>(oldNode);
+ if (!texNode) texNode = new QSGSimpleTextureNode();
+ if (m_image.size().isNull() || m_image.size() != QSize(width(), height()))
+ m_image = generateImage(width(), height(), m_hue);
+ QSGTexture *tex = window()->createTextureFromImage(m_image);
+ texNode->setTexture(tex);
+ texNode->setOwnsTexture(true);
+ texNode->setRect(0,0,width(),height());
+ node = texNode;
+ }
+ return node;
+}
+
+QImage QQuickSaturationLightnessPickerCanvas::generateImage(int width, int height, double hue01) const
+{
+ QImage img(width, height, QImage::Format_RGB32);
+ QRgb* bits = reinterpret_cast<QRgb*>(img.bits());
+ double hue = hue01 * 360.0;
+
+ // Pre-calculate RGB values for each saturation-lightness pair
+ std::vector<QRgb> lut(256 * 256);
+ for (int s = 0; s < 256; ++s) {
+ for (int l = 0; l < 256; ++l) {
+ lut[s * 256 + l] = QColor::fromHsl(hue, s, l).rgb();
+ }
+ }
+
+ for (int y = 0; y < height; ++y) {
+ int saturation = static_cast<int>((1.0 - double(y) / (height - 1)) * 255);
+ QRgb* row = bits + y * width;
+ for (int x = 0; x < width; ++x) {
+ int lightness = static_cast<int>(double(x) / (width - 1) * 255);
+ row[x] = lut[saturation * 256 + lightness];
+ }
+ }
+ return img;
+}
+
QQuickSaturationLightnessPicker::QQuickSaturationLightnessPicker(QQuickItem *parent)
: QQuickAbstractColorPicker(*(new QQuickSaturationLightnessPickerPrivate), parent)
{
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h
index bf651bffe8..8ab801b4a4 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h
+++ b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h
@@ -23,6 +23,32 @@ QT_BEGIN_NAMESPACE
class QQuickSaturationLightnessPickerPrivate;
+class Q_QUICKDIALOGS2QUICKIMPL_EXPORT QQuickSaturationLightnessPickerCanvas : public QQuickItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(SaturationLightnessPickerCanvas)
+ Q_PROPERTY(qreal hue READ hue WRITE setHue NOTIFY hueChanged FINAL)
+
+public:
+ QQuickSaturationLightnessPickerCanvas(QQuickItem *parent = nullptr);
+
+ qreal hue() const { return m_hue; }
+ void setHue(qreal h);
+
+signals:
+ void hueChanged();
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+
+private:
+ qreal m_hue;
+ QImage m_image;
+ QSizeF m_lastSize;
+
+ QImage generateImage(int width, int height, double hue01) const;
+};
+
class Q_QUICKDIALOGS2QUICKIMPL_EXPORT QQuickSaturationLightnessPicker
: public QQuickAbstractColorPicker
{
diff --git a/src/quickdialogs/quickdialogsquickimpl/shaders/SaturationLightness.vert b/src/quickdialogs/quickdialogsquickimpl/shaders/SaturationLightness.vert
new file mode 100644
index 0000000000..cbae4d98a1
--- /dev/null
+++ b/src/quickdialogs/quickdialogsquickimpl/shaders/SaturationLightness.vert
@@ -0,0 +1,18 @@
+#version 440
+
+layout(location = 0) in vec4 qt_VertexPosition;
+layout(location = 1) in vec2 qt_VertexTexCoord;
+
+layout(location = 0) out vec2 qt_TexCoord0;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ float hue;
+};
+
+void main()
+{
+ qt_TexCoord0 = qt_VertexTexCoord;
+ gl_Position = qt_Matrix * qt_VertexPosition;
+}