Perceptual Color

gradientslider.h
1// SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR MIT
3
4#ifndef GRADIENTSLIDER_H
5#define GRADIENTSLIDER_H
6
7#include "abstractdiagram.h"
8#include "constpropagatinguniquepointer.h"
9#include "genericcolor.h"
10#include "importexport.h"
11#include <qglobal.h>
12#include <qmetatype.h>
13#include <qnamespace.h>
14#include <qsharedpointer.h>
15#include <qsize.h>
16class QKeyEvent;
17class QMouseEvent;
18class QPaintEvent;
19class QResizeEvent;
20class QWheelEvent;
21class QWidget;
22
23#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
24#include <qtmetamacros.h>
25#else
26#include <qobjectdefs.h>
27#include <qstring.h>
28class QObject;
29#endif
30
31namespace PerceptualColor
32{
33class GradientSliderPrivate;
34
35class RgbColorSpace;
36
37/** @brief A slider who’s groove displays an LCH color gradient.
38 *
39 * @image html GradientSlider.png "GradientSlider" width=200
40 *
41 * The groove of this slider that displays a gradient between two LCH
42 * colors. The gradient is an equal gradient calculated independently
43 * for each of the four components (lightness, chroma, hue, alpha).
44 *
45 * The hue component is the only one that is circular (0° = 360°): Here,
46 * Here, the path via the shorter side is always chosen. Examples:
47 * @li If the first hue is 182° and the second hue is 1°, than
48 * the hue will increase from 182° up to 359°, than 0° and then 1°.
49 * @li If the first hue is 169° and the second hue is 359°, than
50 * the hue will decrease from 169° down to 0°, and then 359°.
51 *
52 * This widget considers the alpha channel, using a background
53 * of gray squares behind the (semi-)transparent colors.
54 *
55 * Example:
56 * | | L | C | h | alpha |
57 * | :--------------- | --: | -: | ---: | ----: |
58 * | @ref firstColorCieLchD50A | 80% | 5 | 15° | 0.7 |
59 * | | 70% | 7 | 5° | 0.8 |
60 * | | 60% | 9 | 355° | 0.9 |
61 * | @ref secondColorCieLchD50A | 50% | 11 | 345° | 1.0 |
62 *
63 * Note that due to this mathematical model, there might be out-of-gamut colors
64 * within the slider even if both, the first and the second color are in-gamut
65 * colors. Out-of-gamut colors are rendered as nearby in-gamut colors.
66 *
67 * - In the case of vertical @ref orientation, @ref firstColorCieLchD50A is the colour
68 * at the bottom of the widget and @ref secondColorCieLchD50A is the colour at the
69 * top of the widget.
70 * - In the case of horizontal @ref orientation, @ref firstColorCieLchD50A is the
71 * colour on the left of the widget and @ref secondColorCieLchD50A is the colour
72 * on the right of the widget in LTR layout. In RTL layout it is the
73 * other way round.
74 *
75 * @internal
76 *
77 * @todo A better handle for the slider. Currently, the handle is just a
78 * line. At a handle position at the very beginning or end of the slider,
79 * furthermore only half of the line thickness is visible. It might be better
80 * to have arrows outside the slider to mark the position. (On the other
81 * hand, this would be different to the slider handles of the color
82 * wheels…)
83 *
84 * @todo A better focus indicator. Some example code is commented out
85 * in the implementation of @ref paintEvent().
86 *
87 * @todo This class @ref GradientSlider and also the class
88 * @ref ColorWheel could be subclasses of QAbstractSlider. This
89 * might integrate better with the user’s Qt code. On the other hand,
90 * this would mean a lot of work in this library to implement the
91 * complete interface of QAbstractSlider, and probably we would
92 * also need multiple inheritance because this class also depends
93 * on @ref AbstractDiagram which is itself yet a subclass of QWidget.
94 */
95// The API is roughly orientated on QSlider/QAbstractSlider and on
96// KSelecter/KGradientSelector where applicable. Our API is however
97// less complete, and of course also a little bit different, as
98// both, QAbstractSlider and KGradientSelector are not directly
99// comparable to this class.
101{
102 Q_OBJECT
103
104 /** @brief First color (the one corresponding to a low @ref value)
105 *
106 * @sa READ @ref firstColorCieLchD50A() const
107 * @sa WRITE @ref setFirstColorCieLchD50A()
108 * @sa NOTIFY @ref firstColorCieLchD50AChanged()
109 * @sa @ref secondColorCieLchD50A */
110 Q_PROPERTY(PerceptualColor::GenericColor firstColorCieLchD50A READ firstColorCieLchD50A WRITE setFirstColorCieLchD50A NOTIFY firstColorCieLchD50AChanged)
111
112 /** @brief Orientation of the widget.
113 *
114 * By default, the orientation is horizontal. The possible
115 * orientations are <tt>Qt::Horizontal</tt> and <tt>Qt::Vertical</tt>.
116 *
117 * Also, <tt>Qt::Orientation</tt> is declared in this header as type to
118 * Qt’s type system: <tt>Q_DECLARE_METATYPE(Qt::Orientation)</tt>. This
119 * is done because Qt itself does not declare this type as meta type.
120 * Because we use it here in a property including a signal, we have to
121 * declare this type. Depending on your use case (for example if you
122 * want to use it reliably in Qt’s signals and slots), you might consider
123 * calling <tt>qRegisterMetaType()</tt> for this type, once you have
124 * a QApplication object.
125 *
126 * @sa READ @ref orientation() const
127 * @sa WRITE @ref setOrientation()
128 * @sa NOTIFY @ref orientationChanged() */
129 Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
130
131 /** @brief This property holds the page step.
132 *
133 * The larger of two natural steps this widget provides.
134 * Corresponds to the user pressing PageUp or PageDown.
135 *
136 * The valid range is <tt>[0, 1]</tt>.
137 *
138 * @sa READ @ref pageStep() const
139 * @sa WRITE @ref setPageStep()
140 * @sa NOTIFY @ref pageStepChanged()
141 * @sa @ref singleStep */
142 Q_PROPERTY(qreal pageStep READ pageStep WRITE setPageStep NOTIFY pageStepChanged)
143
144 /** @brief Second color (the one corresponding to a high @ref value)
145 *
146 * @sa READ @ref secondColorCieLchD50A() const
147 * @sa WRITE @ref setSecondColorCieLchD50A()
148 * @sa NOTIFY @ref secondColorCieLchD50AChanged()
149 * @sa @ref firstColorCieLchD50A */
150 // The Q_PROPERTY macro must be on a single line for correct compilation.
151 // clang-format is disabled here to prevent automatic line breaks.
152 // clang-format off
153 Q_PROPERTY(PerceptualColor::GenericColor secondColorCieLchD50A READ secondColorCieLchD50A WRITE setSecondColorCieLchD50A NOTIFY secondColorCieLchD50AChanged)
154 // clang-format on
155
156 /** @brief This property holds the single step.
157 *
158 * The smaller of two natural steps this widget provides.
159 * Corresponds to the user pressing an arrow key.
160 *
161 * The valid range is <tt>[0, 1]</tt>.
162 *
163 * @sa READ @ref singleStep() const
164 * @sa WRITE @ref setSingleStep()
165 * @sa NOTIFY @ref singleStepChanged()
166 * @sa @ref pageStep */
167 Q_PROPERTY(qreal singleStep READ singleStep WRITE setSingleStep NOTIFY singleStepChanged)
168
169 /** @brief The slider’s current value.
170 *
171 *
172 * The valid range is <tt>[0, 1]</tt>.
173 * The slider forces the value to be within the valid range:
174 * <tt>0 <= value <= 1</tt>.
175 * - <tt>0</tt> means: totally firstColorCieLchD50A()
176 * - <tt>1</tt> means: totally secondColorCieLchD50A()
177 *
178 * @sa READ @ref value() const
179 * @sa WRITE @ref setValue()
180 * @sa NOTIFY @ref valueChanged() */
181 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged USER true)
182
183public:
184 Q_INVOKABLE explicit GradientSlider(const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace, QWidget *parent = nullptr);
185 Q_INVOKABLE explicit GradientSlider(const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace,
186 Qt::Orientation orientation,
187 QWidget *parent = nullptr);
188 virtual ~GradientSlider() noexcept override;
189 /** @brief Getter for property @ref firstColorCieLchD50A
190 * @returns the property */
191 [[nodiscard]] PerceptualColor::GenericColor firstColorCieLchD50A() const;
192 [[nodiscard]] virtual QSize minimumSizeHint() const override;
193 /** @brief Getter for property @ref orientation
194 * @returns the property */
195 [[nodiscard]] Qt::Orientation orientation() const;
196 /** @brief Getter for property @ref pageStep
197 * @returns the property */
198 [[nodiscard]] qreal pageStep() const;
199 /** @brief Getter for property @ref secondColorCieLchD50A
200 * @returns the property */
201 [[nodiscard]] PerceptualColor::GenericColor secondColorCieLchD50A() const;
202 /** @brief Getter for property @ref singleStep
203 * @returns the property */
204 [[nodiscard]] qreal singleStep() const;
205 [[nodiscard]] virtual QSize sizeHint() const override;
206 /** @brief Getter for property @ref value
207 * @returns the property */
208 [[nodiscard]] qreal value() const;
209
210Q_SIGNALS:
211 /** @brief Signal for @ref firstColorCieLchD50A property.
212 * @param newFirstColorCieLchD50A the new @ref firstColorCieLchD50A */
213 void firstColorCieLchD50AChanged(const PerceptualColor::GenericColor &newFirstColorCieLchD50A);
214 /** @brief Signal for @ref orientation property.
215 * @param newOrientation the new @ref orientation */
216 void orientationChanged(const Qt::Orientation newOrientation);
217 /** @brief Signal for @ref pageStep property.
218 * @param newPageStep the new @ref pageStep */
219 void pageStepChanged(const qreal newPageStep);
220 /** @brief Signal for @ref secondColorCieLchD50A property.
221 * @param newSecondColorCieLchD50A the new @ref secondColorCieLchD50A */
222 void secondColorCieLchD50AChanged(const PerceptualColor::GenericColor &newSecondColorCieLchD50A);
223 /** @brief Signal for @ref singleStep property.
224 * @param newSingleStep the new @ref singleStep */
225 void singleStepChanged(const qreal newSingleStep);
226 /** @brief Signal for @ref value property.
227 * @param newValue the new @ref value */
228 void valueChanged(const qreal newValue);
229
230public Q_SLOTS:
231 void setColors(const PerceptualColor::GenericColor &newFirstColorCieLchD50A, const PerceptualColor::GenericColor &newSecondColorCieLchD50A);
232 void setFirstColorCieLchD50A(const PerceptualColor::GenericColor &newFirstColorCieLchD50A);
233 void setOrientation(const Qt::Orientation newOrientation);
234 void setPageStep(const qreal newPageStep);
235 void setSecondColorCieLchD50A(const PerceptualColor::GenericColor &newSecondColorCieLchD50A);
236 void setSingleStep(const qreal newSingleStep);
237 void setValue(const qreal newValue);
238
239protected:
240 virtual void keyPressEvent(QKeyEvent *event) override;
241 virtual void mouseMoveEvent(QMouseEvent *event) override;
242 virtual void mousePressEvent(QMouseEvent *event) override;
243 virtual void mouseReleaseEvent(QMouseEvent *event) override;
244 virtual void paintEvent(QPaintEvent *event) override;
245 virtual void resizeEvent(QResizeEvent *event) override;
246 virtual void wheelEvent(QWheelEvent *event) override;
247
248private:
249 Q_DISABLE_COPY(GradientSlider)
250
251 /** @internal
252 *
253 * @brief Declare the private implementation as friend class.
254 *
255 * This allows the private class to access the protected members and
256 * functions of instances of <em>this</em> class. */
257 friend class GradientSliderPrivate;
258 /** @brief Pointer to implementation (pimpl) */
259 ConstPropagatingUniquePointer<GradientSliderPrivate> d_pointer;
260
261 /** @internal @brief Only for unit tests. */
262 friend class TestGradientSlider;
263};
264
265} // namespace PerceptualColor
266
267Q_DECLARE_METATYPE(Qt::Orientation)
268
269#endif // GRADIENTSLIDER_H
Base class for LCH diagrams.
A slider who’s groove displays an LCH color gradient.
This file provides support for C++ symbol import and export.
#define PERCEPTUALCOLOR_IMPORTEXPORT
A macro that either exports dynamic library symbols or imports dynamic library symbols or does nothin...
The namespace of this library.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 6 2024 12:12:00 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.