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
4#include "qquickabstractcolorpicker_p_p.h"
5
6#include "qquickcolordialogutils_p.h"
7
8#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
9#include <QtQuickTemplates2/private/qquickdeferredexecute_p_p.h>
10
11#include <qpa/qplatformintegration.h>
12#include <private/qguiapplication_p.h>
13
14QQuickAbstractColorPickerPrivate::QQuickAbstractColorPickerPrivate() = default;
15
16bool QQuickAbstractColorPickerPrivate::handlePress(const QPointF &point, ulong timestamp)
17{
18 Q_Q(QQuickAbstractColorPicker);
19 QQuickControlPrivate::handlePress(point, timestamp);
20 m_pressPoint = point;
21 q->setPressed(true);
22 q->updateColor(pos: point);
23 return true;
24}
25
26bool QQuickAbstractColorPickerPrivate::handleMove(const QPointF &point, ulong timestamp)
27{
28 Q_Q(QQuickAbstractColorPicker);
29 QQuickControlPrivate::handleMove(point, timestamp);
30 if (point != m_pressPoint)
31 q->updateColor(pos: point);
32 return true;
33}
34
35bool QQuickAbstractColorPickerPrivate::handleRelease(const QPointF &point, ulong timestamp)
36{
37 Q_Q(QQuickAbstractColorPicker);
38 QQuickControlPrivate::handleRelease(point, timestamp);
39 m_pressPoint = QPointF();
40 q->setKeepMouseGrab(false);
41 q->setKeepTouchGrab(false);
42 q->setPressed(false);
43 q->updateColor(pos: point);
44 return true;
45}
46
47void QQuickAbstractColorPickerPrivate::handleUngrab()
48{
49 Q_Q(QQuickAbstractColorPicker);
50 QQuickControlPrivate::handleUngrab();
51 m_pressPoint = QPointF();
52 q->setPressed(false);
53}
54
55void QQuickAbstractColorPickerPrivate::cancelHandle()
56{
57 Q_Q(QQuickAbstractColorPicker);
58 quickCancelDeferred(object: q, property: handleName());
59}
60
61void QQuickAbstractColorPickerPrivate::executeHandle(bool complete)
62{
63 Q_Q(QQuickAbstractColorPicker);
64 if (m_handle.wasExecuted())
65 return;
66
67 if (!m_handle || complete)
68 quickBeginDeferred(object: q, property: handleName(), delegate&: m_handle);
69 if (complete)
70 quickCompleteDeferred(object: q, property: handleName(), delegate&: m_handle);
71}
72
73void QQuickAbstractColorPickerPrivate::itemImplicitWidthChanged(QQuickItem *item)
74{
75 Q_Q(QQuickAbstractColorPicker);
76 QQuickControlPrivate::itemImplicitWidthChanged(item);
77 if (item == m_handle)
78 emit q->implicitHandleWidthChanged();
79}
80
81void QQuickAbstractColorPickerPrivate::itemImplicitHeightChanged(QQuickItem *item)
82{
83 Q_Q(QQuickAbstractColorPicker);
84 QQuickControlPrivate::itemImplicitHeightChanged(item);
85 if (item == m_handle)
86 emit q->implicitHandleHeightChanged();
87}
88
89QQuickAbstractColorPicker::QQuickAbstractColorPicker(QQuickAbstractColorPickerPrivate &dd,
90 QQuickItem *parent)
91 : QQuickControl(dd, parent)
92{
93 setActiveFocusOnTab(true);
94 setAcceptedMouseButtons(Qt::LeftButton);
95}
96
97QColor QQuickAbstractColorPicker::color() const
98{
99 Q_D(const QQuickAbstractColorPicker);
100 return d->m_hsl ? QColor::fromHslF(h: d->m_hsva.h, s: d->m_hsva.s, l: d->m_hsva.l, a: d->m_hsva.a)
101 : QColor::fromHsvF(h: d->m_hsva.h, s: d->m_hsva.s, v: d->m_hsva.v, a: d->m_hsva.a);
102}
103
104void QQuickAbstractColorPicker::setColor(const QColor &c)
105{
106 Q_D(QQuickAbstractColorPicker);
107 // QColor represents a theoretical color, rather than simply an rgba value.
108 // Therefore, two QColor objects can be different,
109 // and yet translate to the same rgba value.
110 // Since the color picker can reuse the same rgba value for multiple pixels,
111 // we should not return early if the rgba() values are equal,
112 // but only if the QColor objects are exactly the same.
113
114 if (color() == c)
115 return;
116
117 // When called from QQuickColorDialogImpl, it might not have the same spec as the current color
118 // picker.
119 if (d->m_hsl && c.spec() == QColor::Spec::Hsv) {
120 const auto sl = getSaturationAndLightness(saturation: c.hsvSaturationF(), value: c.valueF());
121 d->m_hsva.h = qBound(min: .0, val: c.hsvHueF(), max: 1.0);
122 d->m_hsva.s = qBound(min: .0, val: sl.first, max: 1.0);
123 d->m_hsva.l = qBound(min: .0, val: sl.second, max: 1.0);
124 } else if (!d->m_hsl && c.spec() == QColor::Spec::Hsl) {
125 const auto sv = getSaturationAndValue(saturation: c.hslSaturationF(), lightness: c.lightnessF());
126 d->m_hsva.h = qBound(min: .0, val: c.hslHueF(), max: 1.0);
127 d->m_hsva.s = qBound(min: .0, val: sv.first, max: 1.0);
128 d->m_hsva.v = qBound(min: .0, val: sv.second, max: 1.0);
129 } else {
130 d->m_hsva.h = qBound(min: .0, val: d->m_hsl ? c.hslHueF() : c.hsvHueF(), max: 1.0);
131 d->m_hsva.s = qBound(min: .0, val: d->m_hsl ? c.hslSaturationF() : c.hsvSaturationF(), max: 1.0);
132 d->m_hsva.v = qBound(min: .0, val: d->m_hsl ? c.lightnessF() : c.valueF(), max: 1.0);
133 }
134
135 d->m_hsva.a = qBound(min: .0, val: c.alphaF(), max: 1.0);
136
137 emit colorChanged(color: color());
138}
139
140qreal QQuickAbstractColorPicker::alpha() const
141{
142 Q_D(const QQuickAbstractColorPicker);
143 return d->m_hsva.a;
144}
145
146void QQuickAbstractColorPicker::setAlpha(qreal alpha)
147{
148 Q_D(QQuickAbstractColorPicker);
149
150 if (!qt_is_finite(d: alpha))
151 return;
152
153 alpha = qBound(min: .0, val: alpha, max: 1.0);
154
155 if (qFuzzyCompare(p1: d->m_hsva.a, p2: alpha))
156 return;
157
158 d->m_hsva.a = alpha;
159
160 emit colorChanged(color: color());
161}
162
163qreal QQuickAbstractColorPicker::hue() const
164{
165 Q_D(const QQuickAbstractColorPicker);
166 return d->m_hsva.h;
167}
168void QQuickAbstractColorPicker::setHue(qreal hue)
169{
170 Q_D(QQuickAbstractColorPicker);
171
172 if (!qt_is_finite(d: hue))
173 return;
174
175 d->m_hsva.h = hue;
176
177 emit colorChanged(color: color());
178}
179
180qreal QQuickAbstractColorPicker::saturation() const
181{
182 Q_D(const QQuickAbstractColorPicker);
183 return d->m_hsva.s;
184}
185
186void QQuickAbstractColorPicker::setSaturation(qreal saturation)
187{
188 Q_D(QQuickAbstractColorPicker);
189 if (!qt_is_finite(d: saturation))
190 return;
191
192 d->m_hsva.s = saturation;
193
194 emit colorChanged(color: color());
195}
196qreal QQuickAbstractColorPicker::value() const
197{
198 Q_D(const QQuickAbstractColorPicker);
199 return d->m_hsl ? getSaturationAndValue(saturation: d->m_hsva.s, lightness: d->m_hsva.l).second : d->m_hsva.v;
200}
201void QQuickAbstractColorPicker::setValue(qreal value)
202{
203 Q_D(QQuickAbstractColorPicker);
204 if (!qt_is_finite(d: value))
205 return;
206
207 const auto sv = d->m_hsl ? getSaturationAndValue(saturation: d->m_hsva.s, lightness: d->m_hsva.l)
208 : std::pair<qreal, qreal>(d->m_hsva.s, value);
209 d->m_hsva.s = sv.first;
210 d->m_hsva.v = sv.second;
211
212 emit colorChanged(color: color());
213}
214
215qreal QQuickAbstractColorPicker::lightness() const
216{
217 Q_D(const QQuickAbstractColorPicker);
218 return d->m_hsl ? d->m_hsva.l : getSaturationAndLightness(saturation: d->m_hsva.s, value: d->m_hsva.v).second;
219}
220void QQuickAbstractColorPicker::setLightness(qreal lightness)
221{
222 Q_D(QQuickAbstractColorPicker);
223 if (!qt_is_finite(d: lightness))
224 return;
225
226 const auto sl = !d->m_hsl ? getSaturationAndLightness(saturation: d->m_hsva.s, value: d->m_hsva.v)
227 : std::pair<qreal, qreal>(d->m_hsva.s, lightness);
228 d->m_hsva.s = sl.first;
229 d->m_hsva.l = sl.second;
230
231 emit colorChanged(color: color());
232}
233
234/*!
235 \internal
236
237 This property holds whether the slider is pressed.
238*/
239bool QQuickAbstractColorPicker::isPressed() const
240{
241 Q_D(const QQuickAbstractColorPicker);
242 return d->m_pressed;
243}
244
245void QQuickAbstractColorPicker::setPressed(bool pressed)
246{
247 Q_D(QQuickAbstractColorPicker);
248 if (pressed == d->m_pressed)
249 return;
250
251 d->m_pressed = pressed;
252 emit pressedChanged();
253}
254
255/*!
256 \internal
257
258 This property holds the handle item.
259*/
260QQuickItem *QQuickAbstractColorPicker::handle() const
261{
262 QQuickAbstractColorPickerPrivate *d = const_cast<QQuickAbstractColorPickerPrivate *>(d_func());
263 if (!d->m_handle)
264 d->executeHandle();
265 return d->m_handle;
266}
267
268void QQuickAbstractColorPicker::setHandle(QQuickItem *handle)
269{
270 Q_D(QQuickAbstractColorPicker);
271 if (handle == d->m_handle)
272 return;
273
274 if (!d->m_handle.isExecuting())
275 d->cancelHandle();
276
277 const qreal oldImplicitHandleWidth = implicitHandleWidth();
278 const qreal oldImplicitHandleHeight = implicitHandleHeight();
279
280 d->removeImplicitSizeListener(item: d->m_handle);
281 QQuickControlPrivate::hideOldItem(item: d->m_handle);
282 d->m_handle = handle;
283
284 if (handle) {
285 if (!handle->parentItem())
286 handle->setParentItem(this);
287 d->addImplicitSizeListener(item: handle);
288 }
289
290 if (!qFuzzyCompare(p1: oldImplicitHandleWidth, p2: implicitHandleWidth()))
291 emit implicitHandleWidthChanged();
292 if (!qFuzzyCompare(p1: oldImplicitHandleHeight, p2: implicitHandleHeight()))
293 emit implicitHandleHeightChanged();
294 if (!d->m_handle.isExecuting())
295 emit handleChanged();
296}
297
298/*!
299 \internal
300 \readonly
301
302 This property holds the implicit handle width.
303
304 The value is equal to \c {handle ? handle.implicitWidth : 0}.
305
306 This is typically used, together with \l {Control::}{implicitContentWidth} and
307 \l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}.
308
309 \sa implicitHandleHeight
310*/
311qreal QQuickAbstractColorPicker::implicitHandleWidth() const
312{
313 Q_D(const QQuickAbstractColorPicker);
314 if (!d->m_handle)
315 return 0;
316 return d->m_handle->implicitWidth();
317}
318
319/*!
320 \internal
321 \readonly
322
323 This property holds the implicit handle height.
324
325 The value is equal to \c {handle ? handle.implicitHeight : 0}.
326
327 This is typically used, together with \l {Control::}{implicitContentHeight} and
328 \l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}.
329
330 \sa implicitHandleWidth
331*/
332qreal QQuickAbstractColorPicker::implicitHandleHeight() const
333{
334 Q_D(const QQuickAbstractColorPicker);
335 if (!d->m_handle)
336 return 0;
337 return d->m_handle->implicitHeight();
338}
339
340void QQuickAbstractColorPicker::componentComplete()
341{
342 Q_D(QQuickAbstractColorPicker);
343 d->executeHandle(complete: true);
344 QQuickControl::componentComplete();
345}
346
347void QQuickAbstractColorPicker::updateColor(const QPointF &pos)
348{
349 QColor c = colorAt(pos);
350 c.setAlphaF(alpha());
351 setColor(c);
352
353 emit colorPicked(color: c);
354}
355

source code of qtdeclarative/src/quickdialogs/quickdialogsquickimpl/qquickabstractcolorpicker.cpp