File indexing completed on 2024-05-05 07:57:38

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      * @code{.js}
0123      * {
0124      *     red: null, // Range: -255 to 255
0125      *     green: null, // Range: -255 to 255
0126      *     blue: null, // Range: -255 to 255
0127      *     hue: null, // Range: -360 to 360
0128      *     saturation: null, // Range: -255 to 255
0129      *     value: null // Range: -255 to 255
0130      *     alpha: null, // Range: -255 to 255
0131      * }
0132      * @endcode
0133      *
0134      * @warning It is an error to adjust both RGB and HSV properties.
0135      *
0136      * @since 5.69
0137      * @since org.kde.kirigami 2.12
0138      */
0139     Q_INVOKABLE QColor adjustColor(const QColor &color, const QJSValue &adjustments);
0140 
0141     /**
0142      * Smoothly scales colors.
0143      *
0144      * @param color The color to adjust.
0145      *
0146      * @param adjustments The adjustments to apply to the color. Each value must
0147      * be between `-100.0` and `100.0`. This indicates how far the property should
0148      * be scaled from its original to the maximum if positive or to the minimum if
0149      * negative.
0150      *
0151      * @code{.js}
0152      * {
0153      *     red: null
0154      *     green: null
0155      *     blue: null
0156      *     saturation: null
0157      *     value: null
0158      *     alpha: null
0159      * }
0160      * @endcode
0161      *
0162      * @warning It is an error to scale both RGB and HSV properties.
0163      *
0164      * @since 5.69
0165      * @since org.kde.kirigami 2.12
0166      */
0167     Q_INVOKABLE QColor scaleColor(const QColor &color, const QJSValue &adjustments);
0168 
0169     /**
0170      * Tint a color using a separate alpha value.
0171      *
0172      * This does the same as Qt.tint() except that rather than using the tint
0173      * color's alpha value, it uses a separate value that gets multiplied with
0174      * the tint color's alpha. This avoids needing to create a new color just to
0175      * adjust an alpha value.
0176      *
0177      * \param targetColor The color to tint.
0178      * \param tintColor The color to tint with.
0179      * \param alpha The amount of tinting to apply.
0180      *
0181      * \return The tinted color.
0182      *
0183      * \sa Qt.tint()
0184      */
0185     Q_INVOKABLE QColor tintWithAlpha(const QColor &targetColor, const QColor &tintColor, double alpha);
0186 
0187     /**
0188      * Returns the CIELAB chroma of the given color.
0189      *
0190      * CIELAB chroma may give a better quantification of how vibrant a color is compared to HSV saturation.
0191      *
0192      * \sa https://en.wikipedia.org/wiki/Colorfulness
0193      * \sa https://en.wikipedia.org/wiki/CIELAB_color_space
0194      */
0195     Q_INVOKABLE static qreal chroma(const QColor &color);
0196 
0197     struct XYZColor {
0198         qreal x = 0;
0199         qreal y = 0;
0200         qreal z = 0;
0201     };
0202 
0203     struct LabColor {
0204         qreal l = 0;
0205         qreal a = 0;
0206         qreal b = 0;
0207     };
0208 
0209     // Not for QML, returns the comvertion from srgb of a QColor and XYZ colorspace
0210     static ColorUtils::XYZColor colorToXYZ(const QColor &color);
0211 
0212     // Not for QML, returns the comvertion from srgb of a QColor and Lab colorspace
0213     static ColorUtils::LabColor colorToLab(const QColor &color);
0214 
0215     static qreal luminance(const QColor &color);
0216 };