File indexing completed on 2024-05-12 04:46:55

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Carson Black <uhhadd@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #pragma once
0008 
0009 #include <QColor>
0010 #include <QJSValue>
0011 #include <QObject>
0012 #include <QQuickItem>
0013 
0014 /**
0015  * Utilities for processing items to obtain colors and information useful for
0016  * UIs that need to adjust to variable elements.
0017  */
0018 class ColorUtils : public QObject
0019 {
0020     Q_OBJECT
0021     QML_ELEMENT
0022     QML_SINGLETON
0023 public:
0024     /**
0025      * Describes the contrast of an item.
0026      */
0027     enum Brightness {
0028         Dark, /**< The item is dark and requires a light foreground color to achieve readable contrast. */
0029         Light, /**< The item is light and requires a dark foreground color to achieve readable contrast. */
0030     };
0031     Q_ENUM(Brightness)
0032 
0033     explicit ColorUtils(QObject *parent = nullptr);
0034 
0035     /**
0036      * Returns whether a color is bright or dark.
0037      *
0038      * @code{.qml}
0039      * import QtQuick 2.0
0040      * import org.kde.kirigami 2.12 as Kirigami
0041      *
0042      * Kirigami.Heading {
0043      *     text: {
0044      *         if (Kirigami.ColorUtils.brightnessForColor("pink") == Kirigami.ColorUtils.Light) {
0045      *             return "The color is light"
0046      *         } else {
0047      *             return "The color is dark"
0048      *         }
0049      *     }
0050      * }
0051      * @endcode
0052      *
0053      * @since 5.69
0054      * @since org.kde.kirigami 2.12
0055      */
0056     Q_INVOKABLE ColorUtils::Brightness brightnessForColor(const QColor &color);
0057 
0058     /**
0059      * Same Algorithm as brightnessForColor but returns a 0 to 1 value for an
0060      * estimate of the equivalent gray light value (luma).
0061      * 0 as full black, 1 as full white and 0.5 equivalent to a 50% gray.
0062      *
0063      * @since 5.81
0064      * @since org.kde.kirigami 2.16
0065      */
0066     Q_INVOKABLE qreal grayForColor(const QColor &color);
0067 
0068     /**
0069      * Returns the result of overlaying the foreground color on the background
0070      * color.
0071      *
0072      * @param foreground The color to overlay on the background.
0073      *
0074      * @param background The color to overlay the foreground on.
0075      *
0076      * @code{.qml}
0077      * import QtQuick 2.0
0078      * import org.kde.kirigami 2.12 as Kirigami
0079      *
0080      * Rectangle {
0081      *     color: Kirigami.ColorUtils.alphaBlend(Qt.rgba(0, 0, 0, 0.5), Qt.rgba(1, 1, 1, 1))
0082      * }
0083      * @endcode
0084      *
0085      * @since 5.69
0086      * @since org.kde.kirigami 2.12
0087      */
0088     Q_INVOKABLE QColor alphaBlend(const QColor &foreground, const QColor &background);
0089 
0090     /**
0091      * Returns a linearly interpolated color between color one and color two.
0092      *
0093      * @param one The color to linearly interpolate from.
0094      *
0095      * @param two The color to linearly interpolate to.
0096      *
0097      * @param balance The balance between the two colors. 0.0 will return the
0098      * first color, 1.0 will return the second color. Values beyond these bounds
0099      * are valid, and will result in extrapolation.
0100      *
0101      * @code{.qml}
0102      * import QtQuick 2.0
0103      * import org.kde.kirigami 2.12 as Kirigami
0104      *
0105      * Rectangle {
0106      *     color: Kirigami.ColorUtils.linearInterpolation("black", "white", 0.5)
0107      * }
0108      * @endcode
0109      *
0110      * @since 5.69
0111      * @since org.kde.kirigami 2.12
0112      */
0113     Q_INVOKABLE QColor linearInterpolation(const QColor &one, const QColor &two, double balance);
0114 
0115     /**
0116      * Increases or decreases the properties of `color` by fixed amounts.
0117      *
0118      * @param color The color to adjust.
0119      *
0120      * @param adjustments The adjustments to apply to the color.
0121      *
0122      * @note `value` and `lightness` are aliases for the same value.
0123      *
0124      * @code{.js}
0125      * {
0126      *     red: null, // Range: -255 to 255
0127      *     green: null, // Range: -255 to 255
0128      *     blue: null, // Range: -255 to 255
0129      *     hue: null, // Range: -360 to 360
0130      *     saturation: null, // Range: -255 to 255
0131      *     value: null // Range: -255 to 255
0132      *     lightness: null, // Range: -255 to 255
0133      *     alpha: null, // Range: -255 to 255
0134      * }
0135      * @endcode
0136      *
0137      * @warning It is an error to adjust both RGB and HSL properties.
0138      *
0139      * @since 5.69
0140      * @since org.kde.kirigami 2.12
0141      */
0142     Q_INVOKABLE QColor adjustColor(const QColor &color, const QJSValue &adjustments);
0143 
0144     /**
0145      * Smoothly scales colors.
0146      *
0147      * @param color The color to adjust.
0148      *
0149      * @param adjustments The adjustments to apply to the color. Each value must
0150      * be between `-100.0` and `100.0`. This indicates how far the property should
0151      * be scaled from its original to the maximum if positive or to the minimum if
0152      * negative.
0153      *
0154      * @note `value` and `lightness` are aliases for the same value.
0155      *
0156      * @code{.js}
0157      * {
0158      *     red: null
0159      *     green: null
0160      *     blue: null
0161      *     saturation: null
0162      *     lightness: null
0163      *     value: null
0164      *     alpha: null
0165      * }
0166      * @endcode
0167      *
0168      * @warning It is an error to scale both RGB and HSL properties.
0169      *
0170      * @since 5.69
0171      * @since org.kde.kirigami 2.12
0172      */
0173     Q_INVOKABLE QColor scaleColor(const QColor &color, const QJSValue &adjustments);
0174 
0175     /**
0176      * Tint a color using a separate alpha value.
0177      *
0178      * This does the same as Qt.tint() except that rather than using the tint
0179      * color's alpha value, it uses a separate value that gets multiplied with
0180      * the tint color's alpha. This avoids needing to create a new color just to
0181      * adjust an alpha value.
0182      *
0183      * \param targetColor The color to tint.
0184      * \param tintColor The color to tint with.
0185      * \param alpha The amount of tinting to apply.
0186      *
0187      * \return The tinted color.
0188      *
0189      * \sa Qt.tint()
0190      */
0191     Q_INVOKABLE QColor tintWithAlpha(const QColor &targetColor, const QColor &tintColor, double alpha);
0192 
0193     /**
0194      * Returns the CIELAB chroma of the given color.
0195      *
0196      * CIELAB chroma may give a better quantification of how vibrant a color is compared to HSV saturation.
0197      *
0198      * \sa https://en.wikipedia.org/wiki/Colorfulness
0199      * \sa https://en.wikipedia.org/wiki/CIELAB_color_space
0200      */
0201     Q_INVOKABLE static qreal chroma(const QColor &color);
0202 
0203     struct XYZColor {
0204         qreal x = 0;
0205         qreal y = 0;
0206         qreal z = 0;
0207     };
0208 
0209     struct LabColor {
0210         qreal l = 0;
0211         qreal a = 0;
0212         qreal b = 0;
0213     };
0214 
0215     // Not for QML, returns the comvertion from srgb of a QColor and XYZ colorspace
0216     static ColorUtils::XYZColor colorToXYZ(const QColor &color);
0217 
0218     // Not for QML, returns the comvertion from srgb of a QColor and Lab colorspace
0219     static ColorUtils::LabColor colorToLab(const QColor &color);
0220 
0221     static qreal luminance(const QColor &color);
0222 };