Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquicksaturationlightnesspicker.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
8#include "qsgtexture.h"
9
10#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
11#include <QtQuickTemplates2/private/qquickdeferredexecute_p_p.h>
12
14
16{
17 Q_DECLARE_PUBLIC(QQuickSaturationLightnessPicker)
18
19public:
21};
22QQuickSaturationLightnessPickerPrivate::QQuickSaturationLightnessPickerPrivate()
23{
24 m_hsl = true;
25}
26
28{
29public:
31 setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.vert.qsb"));
32 setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.frag.qsb"));
33 }
34
35 bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
36};
37
39{
40public:
41 QQuickSaturationLightnessPickerMaterial() { setFlag(Blending, true); }
42 QSGMaterialType* type() const override { static QSGMaterialType t; return &t; }
43 QSGMaterialShader* createShader(QSGRendererInterface::RenderMode renderMode) const override{
44 Q_UNUSED(renderMode);
46 }
47 float hue = 0.0f;
48};
49
50bool QQuickSaturationLightnessPickerMaterialShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
51{
52 Q_ASSERT(!oldMaterial || newMaterial->type() == oldMaterial->type());
53
55 static_cast<QQuickSaturationLightnessPickerMaterial*>(newMaterial);
57 static_cast<QQuickSaturationLightnessPickerMaterial*>(oldMaterial);
58
59 bool changed = false;
60 QByteArray *buf = state.uniformData();
61
62 if (state.isMatrixDirty()) {
63 const QMatrix4x4 m = state.combinedMatrix();
64 memcpy(buf->data(), m.constData(), 64);
65 changed = true;
66 }
67
68 if (state.isOpacityDirty() || !oldMat) {
69 float opacity = state.opacity();
70 memcpy(buf->data() + 64, &opacity, sizeof(float));
71 changed = true;
72 }
73
74 if (!oldMat || mat->hue != oldMat->hue) {
75 float hue = mat->hue;
76 memcpy(buf->data() + 64 + 4, &hue, sizeof(float));
77 changed = true;
78 }
79
80 return changed;
81}
82
83QQuickSaturationLightnessPickerCanvas::QQuickSaturationLightnessPickerCanvas(QQuickItem *parent)
84 : QQuickItem(parent), m_hue(0) {
85 setFlag(ItemHasContents, true);
86}
87
88void QQuickSaturationLightnessPickerCanvas::setHue(qreal h)
89{
90 if (h == m_hue)
91 return;
92 m_hue = h;
93 m_image = QImage();
94 emit hueChanged();
95 update();
96}
97
98QSGNode *QQuickSaturationLightnessPickerCanvas::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
99{
100 QSGGeometryNode *node = nullptr;
101
102 bool shaderSupported = false;
103 if (window()) {
104 QSGRendererInterface::GraphicsApi api = window()->rendererInterface()->graphicsApi();
105 switch (api) {
106 case QSGRendererInterface::OpenGL:
107 case QSGRendererInterface::Vulkan:
108 case QSGRendererInterface::Metal:
109 case QSGRendererInterface::Direct3D11:
110 shaderSupported = true;
111 break;
112 default:
113 shaderSupported = false;
114 }
115 }
116 if (shaderSupported) {
117 // GPU path
118 QSGGeometryNode* geomNode = static_cast<QSGGeometryNode*>(oldNode);
119 QSGGeometry* geom;
120 if (!geomNode) {
121 geomNode = new QSGGeometryNode();
122 geom = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
123 geom->setDrawingMode(QSGGeometry::DrawTriangleStrip);
124 geomNode->setGeometry(geom);
125 geomNode->setFlag(QSGNode::OwnsGeometry);
126
127 auto* mat = new QQuickSaturationLightnessPickerMaterial();
128 geomNode->setMaterial(mat);
129 geomNode->setFlag(QSGNode::OwnsMaterial);
130 m_lastSize = QSize(); //to force it to set vertex positions
131 }
132 else {
133 geom = geomNode->geometry();
134 }
135
136 if (m_lastSize != size()) {
137 m_lastSize = size();
138
139 auto *v = geom->vertexDataAsTexturedPoint2D();
140 v[0].set(0, 0, 0, 0);
141 v[1].set(width(), 0, 1, 0);
142 v[2].set(0, height(), 0, 1);
143 v[3].set(width(), height(), 1, 1);
144
145 geomNode->markDirty(QSGNode::DirtyGeometry);
146 }
147
148 auto* mat = static_cast<QQuickSaturationLightnessPickerMaterial*>(geomNode->material());
149 if (mat->hue != m_hue) {
150 mat->hue = m_hue;
151 geomNode->markDirty(QSGNode::DirtyMaterial);
152 }
153 node = geomNode;
154
155 } else {
156 // CPU path
157 QSGSimpleTextureNode *texNode = static_cast<QSGSimpleTextureNode*>(oldNode);
158 if (!texNode) texNode = new QSGSimpleTextureNode();
159 if (m_image.size().isNull() || m_image.size() != QSize(width(), height()))
160 m_image = generateImage(width(), height(), m_hue);
161 QSGTexture *tex = window()->createTextureFromImage(m_image);
162 texNode->setTexture(tex);
163 texNode->setOwnsTexture(true);
164 texNode->setRect(0,0,width(),height());
165 node = texNode;
166 }
167 return node;
168}
169
170QImage QQuickSaturationLightnessPickerCanvas::generateImage(int width, int height, double hue01) const
171{
172 QImage img(width, height, QImage::Format_RGB32);
173 QRgb* bits = reinterpret_cast<QRgb*>(img.bits());
174 double hue = hue01 * 360.0;
175
176 // Pre-calculate RGB values for each saturation-lightness pair
177 std::vector<QRgb> lut(256 * 256);
178 for (int s = 0; s < 256; ++s) {
179 for (int l = 0; l < 256; ++l) {
180 lut[s * 256 + l] = QColor::fromHsl(hue, s, l).rgb();
181 }
182 }
183
184 for (int y = 0; y < height; ++y) {
185 int saturation = static_cast<int>((1.0 - double(y) / (height - 1)) * 255);
186 QRgb* row = bits + y * width;
187 for (int x = 0; x < width; ++x) {
188 int lightness = static_cast<int>(double(x) / (width - 1) * 255);
189 row[x] = lut[saturation * 256 + lightness];
190 }
191 }
192 return img;
193}
194
195QQuickSaturationLightnessPicker::QQuickSaturationLightnessPicker(QQuickItem *parent)
196 : QQuickAbstractColorPicker(*(new QQuickSaturationLightnessPickerPrivate), parent)
197{
198}
199
200QColor QQuickSaturationLightnessPicker::colorAt(const QPointF &pos)
201{
202 const qreal w = width();
203 const qreal h = height();
204 if (w <= 0 || h <= 0)
205 return color();
206 const qreal x = qBound(.0, pos.x(), w);
207 const qreal y = qBound(.0, pos.y(), h);
208 const qreal saturation = 1.0 - (y / h);
209 const qreal lightness = x / w;
210
211 return QColor::fromHslF(hue(), saturation, lightness);
212}
213
214QT_END_NAMESPACE
bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
This function is called by the scene graph to get the contents of the shader program's uniform buffer...
QSGMaterialType * type() const override
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const override
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
Combined button and popup list for selecting options.