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 "importexport.h"
10#include "lchadouble.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 firstColor | 80% | 5 | 15° | 0.7 |
59 * | | 70% | 7 | 5° | 0.8 |
60 * | | 60% | 9 | 355° | 0.9 |
61 * | @ref secondColor | 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 firstColor is the colour
68 * at the bottom of the widget and @ref secondColor is the colour at the
69 * top of the widget.
70 * - In the case of horizontal @ref orientation, @ref firstColor is the
71 * colour on the left of the widget and @ref secondColor 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 firstColor() const
107 * @sa WRITE @ref setFirstColor()
108 * @sa NOTIFY @ref firstColorChanged()
109 * @sa @ref secondColor */
110 Q_PROPERTY(PerceptualColor::LchaDouble firstColor READ firstColor WRITE setFirstColor NOTIFY firstColorChanged)
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 secondColor() const
147 * @sa WRITE @ref setSecondColor()
148 * @sa NOTIFY @ref secondColorChanged()
149 * @sa @ref firstColor */
150 Q_PROPERTY(PerceptualColor::LchaDouble secondColor READ secondColor WRITE setSecondColor NOTIFY secondColorChanged)
151
152 /** @brief This property holds the single step.
153 *
154 * The smaller of two natural steps this widget provides.
155 * Corresponds to the user pressing an arrow key.
156 *
157 * The valid range is <tt>[0, 1]</tt>.
158 *
159 * @sa READ @ref singleStep() const
160 * @sa WRITE @ref setSingleStep()
161 * @sa NOTIFY @ref singleStepChanged()
162 * @sa @ref pageStep */
163 Q_PROPERTY(qreal singleStep READ singleStep WRITE setSingleStep NOTIFY singleStepChanged)
164
165 /** @brief The slider’s current value.
166 *
167 *
168 * The valid range is <tt>[0, 1]</tt>.
169 * The slider forces the value to be within the valid range:
170 * <tt>0 <= value <= 1</tt>.
171 * - <tt>0</tt> means: totally firstColor()
172 * - <tt>1</tt> means: totally secondColor()
173 *
174 * @sa READ @ref value() const
175 * @sa WRITE @ref setValue()
176 * @sa NOTIFY @ref valueChanged() */
177 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged USER true)
178
179public:
180 Q_INVOKABLE explicit GradientSlider(const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace, QWidget *parent = nullptr);
181 Q_INVOKABLE explicit GradientSlider(const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace,
182 Qt::Orientation orientation,
183 QWidget *parent = nullptr);
184 virtual ~GradientSlider() noexcept override;
185 /** @brief Getter for property @ref firstColor
186 * @returns the property */
187 [[nodiscard]] PerceptualColor::LchaDouble firstColor() const;
188 [[nodiscard]] virtual QSize minimumSizeHint() const override;
189 /** @brief Getter for property @ref orientation
190 * @returns the property */
191 [[nodiscard]] Qt::Orientation orientation() const;
192 /** @brief Getter for property @ref pageStep
193 * @returns the property */
194 [[nodiscard]] qreal pageStep() const;
195 /** @brief Getter for property @ref secondColor
196 * @returns the property */
197 [[nodiscard]] PerceptualColor::LchaDouble secondColor() const;
198 /** @brief Getter for property @ref singleStep
199 * @returns the property */
200 [[nodiscard]] qreal singleStep() const;
201 [[nodiscard]] virtual QSize sizeHint() const override;
202 /** @brief Getter for property @ref value
203 * @returns the property */
204 [[nodiscard]] qreal value() const;
205
206Q_SIGNALS:
207 /** @brief Signal for @ref firstColor property.
208 * @param newFirstColor the new @ref firstColor */
209 void firstColorChanged(const PerceptualColor::LchaDouble &newFirstColor);
210 /** @brief Signal for @ref orientation property.
211 * @param newOrientation the new @ref orientation */
212 void orientationChanged(const Qt::Orientation newOrientation);
213 /** @brief Signal for @ref pageStep property.
214 * @param newPageStep the new @ref pageStep */
215 void pageStepChanged(const qreal newPageStep);
216 /** @brief Signal for @ref secondColor property.
217 * @param newSecondColor the new @ref secondColor */
218 void secondColorChanged(const PerceptualColor::LchaDouble &newSecondColor);
219 /** @brief Signal for @ref singleStep property.
220 * @param newSingleStep the new @ref singleStep */
221 void singleStepChanged(const qreal newSingleStep);
222 /** @brief Signal for @ref value property.
223 * @param newValue the new @ref value */
224 void valueChanged(const qreal newValue);
225
226public Q_SLOTS:
227 void setColors(const PerceptualColor::LchaDouble &newFirstColor, const PerceptualColor::LchaDouble &newSecondColor);
228 void setFirstColor(const PerceptualColor::LchaDouble &newFirstColor);
229 void setOrientation(const Qt::Orientation newOrientation);
230 void setPageStep(const qreal newPageStep);
231 void setSecondColor(const PerceptualColor::LchaDouble &newSecondColor);
232 void setSingleStep(const qreal newSingleStep);
233 void setValue(const qreal newValue);
234
235protected:
236 virtual void keyPressEvent(QKeyEvent *event) override;
237 virtual void mouseMoveEvent(QMouseEvent *event) override;
238 virtual void mousePressEvent(QMouseEvent *event) override;
239 virtual void mouseReleaseEvent(QMouseEvent *event) override;
240 virtual void paintEvent(QPaintEvent *event) override;
241 virtual void resizeEvent(QResizeEvent *event) override;
242 virtual void wheelEvent(QWheelEvent *event) override;
243
244private:
245 Q_DISABLE_COPY(GradientSlider)
246
247 /** @internal
248 *
249 * @brief Declare the private implementation as friend class.
250 *
251 * This allows the private class to access the protected members and
252 * functions of instances of <em>this</em> class. */
253 friend class GradientSliderPrivate;
254 /** @brief Pointer to implementation (pimpl) */
255 ConstPropagatingUniquePointer<GradientSliderPrivate> d_pointer;
256
257 /** @internal @brief Only for unit tests. */
258 friend class TestGradientSlider;
259};
260
261} // namespace PerceptualColor
262
263Q_DECLARE_METATYPE(Qt::Orientation)
264
265#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.
A LCH color with alpha channel.
Definition lchadouble.h:51
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:50:27 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.