Perceptual Color

chromahuediagram.h
1// SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR MIT
3
4#ifndef CHROMAHUEDIAGRAM_H
5#define CHROMAHUEDIAGRAM_H
6
7#include "abstractdiagram.h"
8#include "constpropagatinguniquepointer.h"
9#include "genericcolor.h"
10#include "importexport.h"
11#include <qglobal.h>
12#include <qsharedpointer.h>
13#include <qsize.h>
14
15#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
16#include <qtmetamacros.h>
17#else
18#include <qobjectdefs.h>
19#include <qstring.h>
20class QObject;
21#endif
22
23class QKeyEvent;
24class QMouseEvent;
25class QPaintEvent;
26class QResizeEvent;
27class QWheelEvent;
28class QWidget;
29
30namespace PerceptualColor
31{
32class ChromaHueDiagramPrivate;
33}
34namespace PerceptualColor
35{
36class RgbColorSpace;
37}
38
39namespace PerceptualColor
40{
41/** @brief A widget for selecting chroma and hue in LCH color space
42 *
43 * This widget displays the plan of chroma and hue
44 * (that means a diagram of the radius and the angle of the
45 * LCH color space respectively the a axis and the b axis of the
46 * <a href="https://en.wikipedia.org/wiki/CIELAB_color_space">
47 * Lab color model</a>) at a given lightness.
48 *
49 * @image html ChromaHueDiagram.png "ChromaHueDiagram" width=250
50 *
51 * The widget allows the user to select a color (chroma and hue) within the
52 * specified gamut at a given lightness. It reacts on mouse events and on
53 * keyboard events (see @ref keyPressEvent() for details).
54 *
55 * The form of the selection handle (that always indicates the distance from
56 * the center of the diagram) and the circular form of the widget, all this
57 * helps the user to understand intuitively that he is moving within a
58 * polar coordinate system and to capture easily the current radius
59 * and angle.
60 *
61 * Usage example: @snippet testchromahuediagram.cpp instantiate
62 *
63 * @note This widget <em>always</em> accepts focus by a mouse click within
64 * the circle. This happens regardless of the <tt>QWidget::focusPolicy</tt>
65 * property:
66 * - If you set the <tt>QWidget::focusPolicy</tt> property to a
67 * value that does not accept focus by mouse click, the focus
68 * will nevertheless be accepted for clicks within the actual circle.
69 * (This is the default behavior.)
70 * - If you set the <tt>QWidget::focusPolicy</tt> property to a
71 * value that accepts focus by mouse click, the focus will not only be
72 * accepted for clicks within the actual circle, but also for clicks
73 * anywhere within the (rectangular) widget.
74 *
75 * @internal
76 *
77 * @todo BUG Left-click in the gray area inside the wheel but outside
78 * the displayed gamut; maintain the click button and do not move the
79 * mouse. Actual behavior: Mouse cursor is invisible. Expected behaviour:
80 * Mouse cursor stays visible (as it would be anyway after moving the mouse).
81 *
82 * @todo BUG Click on the wheel. Actual behaviour: Nothing. Expected behavior:
83 * The selected color follows the cursor.
84 *
85 * @todo BUG Wide gamut RGB: RGB 51 255 51. Chroma-Hue-Diagram: The handle
86 * is drawn outside the circle. This should never happen! See also
87 * @ref PerceptualColor::CielchD50Values::maximumChroma
88 *
89 * @todo The hue circle around chroma-hue diagram might be confusing because
90 * it is colored, but it is not a usable slider like all other colored
91 * elements. We could remove it. But on the other hand, it is also useful
92 * to have it. Maybe make it look different than for @ref WheelColorPicker,
93 * for instance make it thinner and make it touch the gray diagram area?
94 * Maybe make it react on mouse events just like the inner part of the diagram.
95 *
96 * @todo Add a circular indicator to the handle, indicating the values
97 * with identical chroma? Only during mouse dragging? Or always? Or never?
98 *
99 * @todo Example code: How to create the widget at a given
100 * lightness.
101 *
102 * @todo Allow to touch the widget on the color wheel (and have a reaction).
103 *
104 * @todo Use a cross cursor for better usability: The cross cursor indicates
105 * to the user that an area can be clicked in. Do it only within the gamut
106 * (where the color handle can actually go) or in the hole gray circle,
107 * which is the mouse sensitive area (but out of the gamut the color
108 * handle cannot follow)?
109 *
110 * @todo Support additional mouse buttons. For example, “forward” and
111 * “backward” could be used to increase or decrease the radius.
112 *
113 * @todo What if black or white are out of gamut on L=0.1 or L=99.9? Where
114 * are the handles placed? Visible or invisible? How to react? Should
115 * there be always a physical pixel in the middle that is visible (black
116 * or white) even when out of gamut?
117 *
118 * @todo Optimization: It might be possible to <em>not</em> store
119 * both, @ref ChromaHueDiagramPrivate::m_chromaHueImage and
120 * a @ref ChromaHueDiagramPrivate::m_wheelImage. Instead, both could
121 * be combined into one single image. As long as there is a (big enough)
122 * safety margin between the color wheel and the inner (circular) diagram
123 * surface, it should be possible to erase the original data and paint
124 * new data above without rendering artefacts for each of these two elements
125 * of the image. */
127{
128 Q_OBJECT
129
130 /** @brief Currently selected color
131 *
132 * The widget allows the user to change the LCH chroma and the LCH hue
133 * values. However, the LCH lightness value cannot be changed by the
134 * user, but only by the programmer through this property.
135 *
136 * The programmer can set this property to out-of-gamut values; the
137 * user cannot.
138 *
139 * @sa READ @ref currentColorCielchD50() const
140 * @sa WRITE @ref setCurrentColorCielchD50()
141 * @sa NOTIFY @ref currentColorCielchD50Changed() */
142 Q_PROPERTY(GenericColor currentColorCielchD50 READ currentColorCielchD50 WRITE setCurrentColorCielchD50 NOTIFY currentColorCielchD50Changed)
143
144public:
145 Q_INVOKABLE explicit ChromaHueDiagram(const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace, QWidget *parent = nullptr);
146 virtual ~ChromaHueDiagram() noexcept override;
147 /** @brief Getter for property @ref currentColorCielchD50
148 * @returns the property @ref currentColorCielchD50 */
149 [[nodiscard]] GenericColor currentColorCielchD50() const;
150 [[nodiscard]] virtual QSize minimumSizeHint() const override;
151 [[nodiscard]] virtual QSize sizeHint() const override;
152
153public Q_SLOTS:
154 void setCurrentColorCielchD50(const PerceptualColor::GenericColor &newCurrentColorCielchD50);
155
156Q_SIGNALS:
157 /** @brief Notify signal for property @ref currentColorCielchD50.
158 * @param newCurrentColorCielchD50 the new current color */
159 void currentColorCielchD50Changed(const PerceptualColor::GenericColor &newCurrentColorCielchD50);
160
161protected:
162 virtual void keyPressEvent(QKeyEvent *event) override;
163 virtual void mouseMoveEvent(QMouseEvent *event) override;
164 virtual void mousePressEvent(QMouseEvent *event) override;
165 virtual void mouseReleaseEvent(QMouseEvent *event) override;
166 virtual void paintEvent(QPaintEvent *event) override;
167 virtual void resizeEvent(QResizeEvent *event) override;
168 virtual void wheelEvent(QWheelEvent *event) override;
169
170private:
171 Q_DISABLE_COPY(ChromaHueDiagram)
172
173 /** @internal
174 *
175 * @brief Declare the private implementation as friend class.
176 *
177 * This allows the private class to access the protected members and
178 * functions of instances of <em>this</em> class. */
179 friend class ChromaHueDiagramPrivate;
180 /** @brief Pointer to implementation (pimpl) */
181 ConstPropagatingUniquePointer<ChromaHueDiagramPrivate> d_pointer;
182
183 /** @internal @brief Only for unit tests. */
184 friend class TestChromaHueDiagram;
185};
186
187} // namespace PerceptualColor
188
189#endif // CHROMAHUEDIAGRAM_H
Base class for LCH diagrams.
A widget for selecting chroma and hue in LCH color space.
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 Sat Dec 21 2024 16:57:17 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.