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
qquickcolorinputs.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
6
7#include <functional>
8
9#include <QtCore/qloggingcategory.h>
10#include <QtCore/QRegularExpression>
11#include <QtGui/QValidator>
12#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
13
15
16Q_STATIC_LOGGING_CATEGORY(lcColorInputs, "qt.quick.dialogs.colorinputs")
17
19{
20public:
21 Q_DECLARE_PUBLIC(QQuickColorInputs)
22
23 void repopulate();
24 QQuickTextInput *createDelegateTextInputItem(QQmlComponent *component, const QVariantMap &initialProperties);
35
39 bool m_showAlpha = false;
40 bool m_repopulating = false;
41};
42
43QQuickColorInputs::QQuickColorInputs(QQuickItem *parent)
44 : QQuickContainer(*(new QQuickColorInputsPrivate), parent)
45{ }
46
47QColor QQuickColorInputs::color() const
48{
49 Q_D(const QQuickColorInputs);
50 return QColor::fromHsvF(d->m_hsva.h, d->m_hsva.s, d->m_hsva.v, d->m_hsva.a);
51}
52
53void QQuickColorInputs::setColor(const QColor &c)
54{
55 Q_D(QQuickColorInputs);
56 if (color().rgba() == c.rgba())
57 return;
58
59 // If we get a QColor from an Hsv or Hsl color system,
60 // we want to get the raw values without the risk of QColor converting them,
61 // and possible deleting relevant information for achromatic cases.
62 if (c.spec() == QColor::Spec::Hsl) {
63 const auto sv = getSaturationAndValue(c.hslSaturationF(), c.lightnessF());
64 d->m_hsva.h = qBound(.0, c.hslHueF(), 1.0);
65 d->m_hsva.s = qBound(.0, sv.first, 1.0);
66 d->m_hsva.v = qBound(.0, sv.second, 1.0);
67 } else {
68 d->m_hsva.h = qBound(.0, c.hsvHueF(), 1.0);
69 d->m_hsva.s = qBound(.0, c.hsvSaturationF(), 1.0);
70 d->m_hsva.v = qBound(.0, c.valueF(), 1.0);
71 }
72
73 d->m_hsva.a = c.alphaF();
74
75 emit colorChanged(color());
76}
77
78int QQuickColorInputs::red() const
79{
80 return color().red();
81}
82
83int QQuickColorInputs::green() const
84{
85 return color().green();
86}
87
88int QQuickColorInputs::blue() const
89{
90 return color().blue();
91}
92
93qreal QQuickColorInputs::alpha() const
94{
95 Q_D(const QQuickColorInputs);
96 return d->m_hsva.a;
97}
98
99qreal QQuickColorInputs::hue() const
100{
101 Q_D(const QQuickColorInputs);
102 return d->m_hsva.h;
103}
104
105qreal QQuickColorInputs::hslSaturation() const
106{
107 Q_D(const QQuickColorInputs);
108 return getSaturationAndLightness(d->m_hsva.s, d->m_hsva.v).first;
109}
110
111qreal QQuickColorInputs::hsvSaturation() const
112{
113 Q_D(const QQuickColorInputs);
114 return d->m_hsva.s;
115}
116
117qreal QQuickColorInputs::value() const
118{
119 Q_D(const QQuickColorInputs);
120 return d->m_hsva.v;
121}
122
123qreal QQuickColorInputs::lightness() const
124{
125 Q_D(const QQuickColorInputs);
126 return getSaturationAndLightness(d->m_hsva.s, d->m_hsva.v).second;
127}
128
129bool QQuickColorInputs::showAlpha() const
130{
131 Q_D(const QQuickColorInputs);
132 return d->m_showAlpha;
133}
134
135void QQuickColorInputs::setShowAlpha(bool showAlpha)
136{
137 Q_D(QQuickColorInputs);
138 if (d->m_showAlpha == showAlpha)
139 return;
140
141 d->m_showAlpha = showAlpha;
142 d->repopulate();
143
144 emit showAlphaChanged(d->m_showAlpha);
145}
146
147QQuickColorInputs::Mode QQuickColorInputs::currentMode() const
148{
149 Q_D(const QQuickColorInputs);
150 return d->m_currentMode;
151}
152
153void QQuickColorInputs::setCurrentMode(Mode mode)
154{
155 Q_D(QQuickColorInputs);
156 if (d->m_currentMode == mode)
157 return;
158
159 d->m_currentMode = mode;
160 d->repopulate();
161
162 emit currentModeChanged();
163}
164
165QQmlComponent *QQuickColorInputs::delegate() const
166{
167 Q_D(const QQuickColorInputs);
168 return d->m_delegate;
169}
170
171void QQuickColorInputs::setDelegate(QQmlComponent *delegate)
172{
173 Q_D(QQuickColorInputs);
174 if (d->m_delegate == delegate)
175 return;
176 d->m_delegate = delegate;
177 emit delegateChanged();
178}
179
180
181void QQuickColorInputs::componentComplete()
182{
183 Q_D(QQuickColorInputs);
184 QQuickContainer::componentComplete();
185 d->repopulate();
186}
187
188QQuickTextInput *QQuickColorInputsPrivate::createDelegateTextInputItem(QQmlComponent *component, const QVariantMap &initialProperties)
189{
190 Q_Q(QQuickColorInputs);
191 QQmlContext *context = component->creationContext();
192 if (!context)
193 context = qmlContext(q);
194
195 if (!component->isBound() && initialProperties.isEmpty()) {
196 context = new QQmlContext(context, q);
197 context->setContextObject(q);
198 }
199
200 QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(component->createWithInitialProperties(initialProperties, context));
201 if (textInput)
202 QQml_setParent_noEvent(textInput, q);
203 return textInput;
204}
205
206static const QString s_percentage_pattern = QString::fromUtf8("^(\\d+)%?$");
207static const QString s_degree_pattern = QString::fromUtf8("(\\d+)°?$");
208static const QString s_rgba_pattern = QString::fromUtf8("^#[0-9A-f]{6}(?:[0-9A-f]{2})?$");
209static const QString s_rgb_pattern = QString::fromUtf8("^#[0-9A-f]{6}$");
210
211void QQuickColorInputsPrivate::repopulate()
212{
213 Q_Q(QQuickColorInputs);
214
215 if (m_repopulating)
216 return;
217
218 if (!q->delegate() || !q->contentItem()) {
219 qmlWarning(q) << "Both delegate and contentItem must be set before repopulating";
220 return;
221 }
222
223 QScopedValueRollback<bool> repopulateGuard(m_repopulating, true);
224
225 auto removeAllItems = [q](){
226 while (q->count() > 0)
227 q->removeItem(q->itemAt(0));
228 };
229
230 removeAllItems();
231
232 static const QRegularExpressionValidator rgba_validator = QRegularExpressionValidator(QRegularExpression(s_rgba_pattern));
233 static const QRegularExpressionValidator rgb_validator = QRegularExpressionValidator(QRegularExpression(s_rgb_pattern));
234 static const QRegularExpressionValidator percentage_validator = QRegularExpressionValidator(QRegularExpression(s_percentage_pattern));
235 static const QRegularExpressionValidator degree_validator = QRegularExpressionValidator(QRegularExpression(s_degree_pattern));
236 static const QIntValidator intValdator = QIntValidator(0, 255);
237
238 auto addInputField = [this, q, removeAllItems](const QString &name, const QValidator *validator,
239 void (QQuickColorInputsPrivate::*handler)(),
240 std::function<QString()> textConverter) {
241 const int maxLen = m_currentMode == QQuickColorInputs::Hex ? 9 : 4;
242 const QVariantMap properties = {
243 { QStringLiteral("objectName"), QVariant::fromValue(name) },
244 { QStringLiteral("validator"), QVariant::fromValue(validator) },
245 { QStringLiteral("horizontalAlignment"), QVariant::fromValue(
246 m_currentMode == QQuickColorInputs::Hex ? Qt::AlignLeft : Qt::AlignHCenter) },
247 { QStringLiteral("maximumLength"), QVariant::fromValue(maxLen) },
248 { QStringLiteral("text"), QVariant::fromValue(textConverter()) }
249 };
250 if (QQuickTextInput *item = createDelegateTextInputItem(q->delegate(), properties)) {
251 connect(item, &QQuickTextInput::editingFinished, this, handler);
252 QObject::connect(q, &QQuickColorInputs::colorChanged, item, [item, textConverter](const QColor &){ item->setText(textConverter()); });
253
254 insertItem(q->count(), item);
255 } else {
256 qCWarning(lcColorInputs) << "Failed to create delegate for " << name;
257 removeAllItems();
258 }
259 };
260
261 switch (m_currentMode) {
262 case QQuickColorInputs::Hex:
263 addInputField(QStringLiteral("hex"), m_showAlpha ? &rgba_validator : &rgb_validator, &QQuickColorInputsPrivate::handleHexInput,
264 [q](){ return q->color().name(); });
265 break;
266 case QQuickColorInputs::Rgb:
267 addInputField(QStringLiteral("red"), &intValdator, &QQuickColorInputsPrivate::handleRedInput, [q](){ return QString::number(q->red()); });
268 addInputField(QStringLiteral("green"), &intValdator, &QQuickColorInputsPrivate::handleGreenInput, [q](){ return QString::number(q->green()); });
269 addInputField(QStringLiteral("blue"), &intValdator, &QQuickColorInputsPrivate::handleBlueInput, [q](){ return QString::number(q->blue()); });
270 if (m_showAlpha)
271 addInputField(QStringLiteral("alpha"), &percentage_validator, &QQuickColorInputsPrivate::handleAlphaInput,
272 [q](){ return QString::number(qRound(q->alpha() * 100)).append(QStringLiteral("%")); });
273 break;
274 case QQuickColorInputs::Hsv:
275 addInputField(QStringLiteral("hsvHue"), &degree_validator, &QQuickColorInputsPrivate::handleHueInput,
276 [q](){ return QString::number(qRound(q->hue() * 360)).append(QStringLiteral("°")); });
277 addInputField(QStringLiteral("hsvSaturation"), &percentage_validator, &QQuickColorInputsPrivate::handleHsvSaturationInput,
278 [q](){ return QString::number(qRound(q->hsvSaturation() * 100)).append(QStringLiteral("%")); });
279 addInputField(QStringLiteral("value"), &percentage_validator, &QQuickColorInputsPrivate::handleValueInput,
280 [q](){ return QString::number(qRound(q->value() * 100)).append(QStringLiteral("%")); });
281 if (m_showAlpha)
282 addInputField(QStringLiteral("alpha"), &percentage_validator, &QQuickColorInputsPrivate::handleAlphaInput,
283 [q](){ return QString::number(qRound(q->alpha() * 100)).append(QStringLiteral("%")); });
284 break;
285 case QQuickColorInputs::Hsl:
286 addInputField(QStringLiteral("hslHue"), &degree_validator, &QQuickColorInputsPrivate::handleHueInput,
287 [q](){ return QString::number(qRound(q->hue() * 360)).append(QStringLiteral("°")); });
288 addInputField(QStringLiteral("hslSaturation"), &percentage_validator, &QQuickColorInputsPrivate::handleHslSaturationInput,
289 [q](){ return QString::number(qRound(q->hslSaturation() * 100)).append(QStringLiteral("%")); });
290 addInputField(QStringLiteral("lightness"), &percentage_validator, &QQuickColorInputsPrivate::handleLightnessInput,
291 [q](){ return QString::number(qRound(q->lightness() * 100)).append(QStringLiteral("%")); });
292 if (m_showAlpha)
293 addInputField(QStringLiteral("alpha"), &percentage_validator, &QQuickColorInputsPrivate::handleAlphaInput,
294 [q](){ return QString::number(qRound(q->alpha() * 100)).append(QStringLiteral("%")); });
295 break;
296 default:
297 qCDebug(lcColorInputs) << "Unrecognised mode " << m_currentMode;
298 break;
299 }
300
301 updateImplicitContentSize();
302}
303
305{
306 Q_Q(QQuickColorInputs);
307 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender()))
308 emit q->colorModified(QColor::fromString(textInput->text()));
309}
310
312{
313 Q_Q(QQuickColorInputs);
314 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
315 QColor c = q->color();
316 c.setRed(textInput->text().toInt());
317 emit q->colorModified(c);
318 }
319}
320
322{
323 Q_Q(QQuickColorInputs);
324 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
325 QColor c = q->color();
326 c.setGreen(textInput->text().toInt());
327 emit q->colorModified(c);
328 }
329}
330
332{
333 Q_Q(QQuickColorInputs);
334 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
335 QColor c = q->color();
336 c.setBlue(textInput->text().toInt());
337 emit q->colorModified(c);
338 }
339}
340
342{
343 Q_Q(QQuickColorInputs);
344 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
345 static const QRegularExpression pattern(s_degree_pattern);
346 const auto match = pattern.match(textInput->text());
347 if (match.hasMatch()) {
348 const auto substr = match.captured(1);
349 const qreal input = static_cast<qreal>(qBound(0, substr.toInt(), 360)) / static_cast<qreal>(360);
350 const QColor c = m_currentMode == QQuickColorInputs::Hsl ? QColor::fromHslF(input, q->hslSaturation(), q->lightness(), q->alpha())
351 : QColor::fromHsvF(input, q->hsvSaturation(), q->value(), q->alpha());
352 emit q->colorModified(c);
353 }
354 }
355}
356
358{
359 Q_Q(QQuickColorInputs);
360 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
361 static const QRegularExpression pattern(s_percentage_pattern);
362 const auto match = pattern.match(textInput->text());
363 if (match.hasMatch()) {
364 const auto substr = match.captured(1);
365 const qreal input = static_cast<qreal>(qBound(0, substr.toInt(), 100)) / static_cast<qreal>(100);
366 emit q->colorModified(QColor::fromHsvF(q->hue(), input, q->value(), q->alpha()));
367 }
368 }
369}
370
372{
373 Q_Q(QQuickColorInputs);
374 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
375 static const QRegularExpression pattern(s_percentage_pattern);
376 const auto match = pattern.match(textInput->text());
377 if (match.hasMatch()) {
378 const auto substr = match.captured(1);
379 const qreal input = static_cast<qreal>(qBound(0, substr.toInt(), 100)) / static_cast<qreal>(100);
380 emit q->colorModified(QColor::fromHsvF(q->hue(), q->hsvSaturation(), input, q->alpha()));
381 }
382 }
383}
384
386{
387 Q_Q(QQuickColorInputs);
388 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
389 static const QRegularExpression pattern(s_percentage_pattern);
390 const auto match = pattern.match(textInput->text());
391 if (match.hasMatch()) {
392 const auto substr = match.captured(1);
393 const qreal input = static_cast<qreal>(qBound(0, substr.toInt(), 100)) / static_cast<qreal>(100);
394 emit q->colorModified(QColor::fromHslF(q->hue(), input, q->lightness(), q->alpha()));
395 }
396 }
397}
398
400{
401 Q_Q(QQuickColorInputs);
402 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
403 static const QRegularExpression pattern(s_percentage_pattern);
404 const auto match = pattern.match(textInput->text());
405 if (match.hasMatch()) {
406 const auto substr = match.captured(1);
407 const qreal input = static_cast<qreal>(qBound(0, substr.toInt(), 100)) / static_cast<qreal>(100);
408 emit q->colorModified(QColor::fromHslF(q->hue(), q->hslSaturation(), input, q->alpha()));
409 }
410 }
411}
412
414{
415 Q_Q(QQuickColorInputs);
416 if (const auto textInput = qobject_cast<QQuickTextInput *>(q->QObject::sender())) {
417 static const QRegularExpression pattern(s_percentage_pattern);
418 const auto match = pattern.match(textInput->text());
419 if (match.hasMatch()) {
420 QColor c = q->color();
421 const auto substr = match.captured(1);
422 const qreal input = static_cast<qreal>(qBound(0, substr.toInt(), 100)) / static_cast<qreal>(100);
423 c.setAlphaF(input);
424 emit q->colorModified(c);
425 }
426 }
427}
428
429QT_END_NAMESPACE
430
431#include "moc_qquickcolorinputs_p.cpp"
QQuickTextInput * createDelegateTextInputItem(QQmlComponent *component, const QVariantMap &initialProperties)
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
static const QString s_rgba_pattern
static const QString s_rgb_pattern
static const QString s_percentage_pattern
static const QString s_degree_pattern