Revision control

Copy as Markdown

// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qquickabstractcolorpicker_p_p.h"
#include "qquickcolordialogutils_p.h"
#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
#include <QtQuickTemplates2/private/qquickdeferredexecute_p_p.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
QQuickAbstractColorPickerPrivate::QQuickAbstractColorPickerPrivate() = default;
bool QQuickAbstractColorPickerPrivate::handlePress(const QPointF &point, ulong timestamp)
{
Q_Q(QQuickAbstractColorPicker);
QQuickControlPrivate::handlePress(point, timestamp);
m_pressPoint = point;
q->setPressed(true);
q->updateColor(point);
return true;
}
bool QQuickAbstractColorPickerPrivate::handleMove(const QPointF &point, ulong timestamp)
{
Q_Q(QQuickAbstractColorPicker);
QQuickControlPrivate::handleMove(point, timestamp);
if (point != m_pressPoint)
q->updateColor(point);
return true;
}
bool QQuickAbstractColorPickerPrivate::handleRelease(const QPointF &point, ulong timestamp)
{
Q_Q(QQuickAbstractColorPicker);
QQuickControlPrivate::handleRelease(point, timestamp);
m_pressPoint = QPointF();
q->setKeepMouseGrab(false);
q->setKeepTouchGrab(false);
q->setPressed(false);
q->updateColor(point);
return true;
}
void QQuickAbstractColorPickerPrivate::handleUngrab()
{
Q_Q(QQuickAbstractColorPicker);
QQuickControlPrivate::handleUngrab();
m_pressPoint = QPointF();
q->setPressed(false);
}
void QQuickAbstractColorPickerPrivate::cancelHandle()
{
Q_Q(QQuickAbstractColorPicker);
quickCancelDeferred(q, handleName());
}
void QQuickAbstractColorPickerPrivate::executeHandle(bool complete)
{
Q_Q(QQuickAbstractColorPicker);
if (m_handle.wasExecuted())
return;
if (!m_handle || complete)
quickBeginDeferred(q, handleName(), m_handle);
if (complete)
quickCompleteDeferred(q, handleName(), m_handle);
}
void QQuickAbstractColorPickerPrivate::itemImplicitWidthChanged(QQuickItem *item)
{
Q_Q(QQuickAbstractColorPicker);
QQuickControlPrivate::itemImplicitWidthChanged(item);
if (item == m_handle)
emit q->implicitHandleWidthChanged();
}
void QQuickAbstractColorPickerPrivate::itemImplicitHeightChanged(QQuickItem *item)
{
Q_Q(QQuickAbstractColorPicker);
QQuickControlPrivate::itemImplicitHeightChanged(item);
if (item == m_handle)
emit q->implicitHandleHeightChanged();
}
QQuickAbstractColorPicker::QQuickAbstractColorPicker(QQuickAbstractColorPickerPrivate &dd,
QQuickItem *parent)
: QQuickControl(dd, parent)
{
setActiveFocusOnTab(true);
setAcceptedMouseButtons(Qt::LeftButton);
}
QQuickAbstractColorPicker::~QQuickAbstractColorPicker()
{
Q_D(QQuickAbstractColorPicker);
if (d->m_handle)
d->removeImplicitSizeListener(d->m_handle);
}
QColor QQuickAbstractColorPicker::color() const
{
Q_D(const QQuickAbstractColorPicker);
return d->m_hsl ? QColor::fromHslF(d->m_hsva.h, d->m_hsva.s, d->m_hsva.l, d->m_hsva.a)
: QColor::fromHsvF(d->m_hsva.h, d->m_hsva.s, d->m_hsva.v, d->m_hsva.a);
}
void QQuickAbstractColorPicker::setColor(const QColor &c)
{
Q_D(QQuickAbstractColorPicker);
// QColor represents a theoretical color, rather than simply an rgba value.
// Therefore, two QColor objects can be different,
// and yet translate to the same rgba value.
// Since the color picker can reuse the same rgba value for multiple pixels,
// we should not return early if the rgba() values are equal,
// but only if the QColor objects are exactly the same.
if (color() == c)
return;
// When called from QQuickColorDialogImpl, it might not have the same spec as the current color
// picker.
if (d->m_hsl && c.spec() == QColor::Spec::Hsv) {
const auto sl = getSaturationAndLightness(c.hsvSaturationF(), c.valueF());
d->m_hsva.h = qBound(.0, c.hsvHueF(), 1.0);
d->m_hsva.s = qBound(.0, sl.first, 1.0);
d->m_hsva.l = qBound(.0, sl.second, 1.0);
} else if (!d->m_hsl && c.spec() == QColor::Spec::Hsl) {
const auto sv = getSaturationAndValue(c.hslSaturationF(), c.lightnessF());
d->m_hsva.h = qBound(.0, c.hslHueF(), 1.0);
d->m_hsva.s = qBound(.0, sv.first, 1.0);
d->m_hsva.v = qBound(.0, sv.second, 1.0);
} else {
d->m_hsva.h = qBound(.0, d->m_hsl ? c.hslHueF() : c.hsvHueF(), 1.0);
d->m_hsva.s = qBound(.0, d->m_hsl ? c.hslSaturationF() : c.hsvSaturationF(), 1.0);
d->m_hsva.v = qBound(.0, d->m_hsl ? c.lightnessF() : c.valueF(), 1.0);
}
d->m_hsva.a = qBound(.0, c.alphaF(), 1.0);
emit colorChanged(color());
}
qreal QQuickAbstractColorPicker::alpha() const
{
Q_D(const QQuickAbstractColorPicker);
return d->m_hsva.a;
}
void QQuickAbstractColorPicker::setAlpha(qreal alpha)
{
Q_D(QQuickAbstractColorPicker);
if (!qt_is_finite(alpha))
return;
alpha = qBound(.0, alpha, 1.0);
if (qFuzzyCompare(d->m_hsva.a, alpha))
return;
d->m_hsva.a = alpha;
emit colorChanged(color());
}
qreal QQuickAbstractColorPicker::hue() const
{
Q_D(const QQuickAbstractColorPicker);
return d->m_hsva.h;
}
void QQuickAbstractColorPicker::setHue(qreal hue)
{
Q_D(QQuickAbstractColorPicker);
if (!qt_is_finite(hue))
return;
d->m_hsva.h = hue;
emit colorChanged(color());
}
qreal QQuickAbstractColorPicker::saturation() const
{
Q_D(const QQuickAbstractColorPicker);
return d->m_hsva.s;
}
void QQuickAbstractColorPicker::setSaturation(qreal saturation)
{
Q_D(QQuickAbstractColorPicker);
if (!qt_is_finite(saturation))
return;
d->m_hsva.s = saturation;
emit colorChanged(color());
}
qreal QQuickAbstractColorPicker::value() const
{
Q_D(const QQuickAbstractColorPicker);
return d->m_hsl ? getSaturationAndValue(d->m_hsva.s, d->m_hsva.l).second : d->m_hsva.v;
}
void QQuickAbstractColorPicker::setValue(qreal value)
{
Q_D(QQuickAbstractColorPicker);
if (!qt_is_finite(value))
return;
const auto sv = d->m_hsl ? getSaturationAndValue(d->m_hsva.s, d->m_hsva.l)
: std::pair<qreal, qreal>(d->m_hsva.s, value);
d->m_hsva.s = sv.first;
d->m_hsva.v = sv.second;
emit colorChanged(color());
}
qreal QQuickAbstractColorPicker::lightness() const
{
Q_D(const QQuickAbstractColorPicker);
return d->m_hsl ? d->m_hsva.l : getSaturationAndLightness(d->m_hsva.s, d->m_hsva.v).second;
}
void QQuickAbstractColorPicker::setLightness(qreal lightness)
{
Q_D(QQuickAbstractColorPicker);
if (!qt_is_finite(lightness))
return;
const auto sl = !d->m_hsl ? getSaturationAndLightness(d->m_hsva.s, d->m_hsva.v)
: std::pair<qreal, qreal>(d->m_hsva.s, lightness);
d->m_hsva.s = sl.first;
d->m_hsva.l = sl.second;
emit colorChanged(color());
}
/*!
\internal
This property holds whether the slider is pressed.
*/
bool QQuickAbstractColorPicker::isPressed() const
{
Q_D(const QQuickAbstractColorPicker);
return d->m_pressed;
}
void QQuickAbstractColorPicker::setPressed(bool pressed)
{
Q_D(QQuickAbstractColorPicker);
if (pressed == d->m_pressed)
return;
d->m_pressed = pressed;
emit pressedChanged();
}
/*!
\internal
This property holds the handle item.
*/
QQuickItem *QQuickAbstractColorPicker::handle() const
{
QQuickAbstractColorPickerPrivate *d = const_cast<QQuickAbstractColorPickerPrivate *>(d_func());
if (!d->m_handle)
d->executeHandle();
return d->m_handle;
}
void QQuickAbstractColorPicker::setHandle(QQuickItem *handle)
{
Q_D(QQuickAbstractColorPicker);
if (handle == d->m_handle)
return;
if (!d->m_handle.isExecuting())
d->cancelHandle();
const qreal oldImplicitHandleWidth = implicitHandleWidth();
const qreal oldImplicitHandleHeight = implicitHandleHeight();
d->removeImplicitSizeListener(d->m_handle);
QQuickControlPrivate::hideOldItem(d->m_handle);
d->m_handle = handle;
if (handle) {
if (!handle->parentItem())
handle->setParentItem(this);
d->addImplicitSizeListener(handle);
}
if (!qFuzzyCompare(oldImplicitHandleWidth, implicitHandleWidth()))
emit implicitHandleWidthChanged();
if (!qFuzzyCompare(oldImplicitHandleHeight, implicitHandleHeight()))
emit implicitHandleHeightChanged();
if (!d->m_handle.isExecuting())
emit handleChanged();
}
/*!
\internal
\readonly
This property holds the implicit handle width.
The value is equal to \c {handle ? handle.implicitWidth : 0}.
This is typically used, together with \l {Control::}{implicitContentWidth} and
\l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}.
\sa implicitHandleHeight
*/
qreal QQuickAbstractColorPicker::implicitHandleWidth() const
{
Q_D(const QQuickAbstractColorPicker);
if (!d->m_handle)
return 0;
return d->m_handle->implicitWidth();
}
/*!
\internal
\readonly
This property holds the implicit handle height.
The value is equal to \c {handle ? handle.implicitHeight : 0}.
This is typically used, together with \l {Control::}{implicitContentHeight} and
\l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}.
\sa implicitHandleWidth
*/
qreal QQuickAbstractColorPicker::implicitHandleHeight() const
{
Q_D(const QQuickAbstractColorPicker);
if (!d->m_handle)
return 0;
return d->m_handle->implicitHeight();
}
void QQuickAbstractColorPicker::componentComplete()
{
Q_D(QQuickAbstractColorPicker);
d->executeHandle(true);
QQuickControl::componentComplete();
}
void QQuickAbstractColorPicker::updateColor(const QPointF &pos)
{
QColor c = colorAt(pos);
c.setAlphaF(alpha());
setColor(c);
emit colorPicked(c);
}