Perceptual Color

colordialog_p.h
1// SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR MIT
3
4#ifndef COLORDIALOG_P_H
5#define COLORDIALOG_P_H
6
7// Include the header of the public class of this private implementation.
8#include "colordialog.h"
9
10#include "constpropagatingrawpointer.h"
11#include "genericcolor.h"
12#include "helper.h"
13#include "helperconversion.h"
14#include "languagechangeeventfilter.h"
15#include "perceptualsettings.h"
16#include "rgbcolor.h"
17#include <lcms2.h>
18#include <optional>
19#include <qbytearray.h>
20#include <qcolor.h>
21#include <qglobal.h>
22#include <qhash.h>
23#include <qobject.h>
24#include <qpointer.h>
25#include <qsharedpointer.h>
26#include <qstring.h>
27#include <qstringliteral.h>
28class QAction;
30class QDoubleSpinBox;
31class QGroupBox;
32class QHBoxLayout;
33class QLabel;
34class QLineEdit;
35class QPushButton;
36class QShortcut;
37class QTabWidget;
38class QToolButton;
39class QWidget;
40
41#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
42#include <qtmetamacros.h>
43#else
44#include <qobjectdefs.h>
45#endif
46
47namespace PerceptualColor
48{
49class ChromaHueDiagram;
50class ColorPatch;
51class GradientSlider;
52class MultiSpinBox;
53class SwatchBook;
54class RgbColorSpace;
55class WheelColorPicker;
56
57/** @internal
58 *
59 * @brief Private implementation within the <em>Pointer to
60 * implementation</em> idiom */
61class ColorDialogPrivate final : public QObject
62{
64public:
65 explicit ColorDialogPrivate(ColorDialog *backLink);
66 /** @brief Default destructor
67 *
68 * The destructor is non-<tt>virtual</tt> because
69 * the class as a whole is <tt>final</tt>. */
70 virtual ~ColorDialogPrivate() noexcept override = default;
71
72 /** @brief @ref GradientSlider widget for the alpha channel. */
73 QPointer<GradientSlider> m_alphaGradientSlider;
74 /** @brief Pointer to the QLabel for the alpha value.
75 *
76 * We store this in a pointer to allow toggle the visibility later. */
77 QPointer<QLabel> m_alphaLabel;
78 /** @brief Spin box for the alpha channel.
79 *
80 * This spin box shows always the value of @ref m_alphaGradientSlider.
81 *
82 * @note It’s value is not set directly, but is updated via signals from
83 * @ref m_alphaGradientSlider. Do not use it directly! */
84 QPointer<QDoubleSpinBox> m_alphaSpinBox;
85 /** @brief Pointer to the QButtonBox of this dialog.
86 *
87 * We store this in a pointer
88 * to allow toggle the visibility later. */
89 QPointer<QDialogButtonBox> m_buttonBox;
90 /** @brief Pointer to the “Cancel” button of @ref m_buttonBox. */
91 QPointer<QPushButton> m_buttonCancel;
92 /** @brief Pointer to the “Ok” button of @ref m_buttonBox. */
93 QPointer<QPushButton> m_buttonOK;
94 /** @brief Pointer to the @ref ChromaHueDiagram. */
95 QPointer<ChromaHueDiagram> m_chromaHueDiagram;
96 /** @brief Pointer to the @ref MultiSpinBox for CIEHLC. */
97 QPointer<MultiSpinBox> m_ciehlcD50SpinBox;
98 /** @brief Pointer to the gamut action for @ref m_ciehlcD50SpinBox. */
99 QPointer<QAction> m_ciehlcD50SpinBoxGamutAction;
100 /** @brief Pointer to the label for @ref m_ciehlcD50SpinBox. */
101 QPointer<QLabel> m_ciehlcD50SpinBoxLabel;
102 /** @brief Pointer to the @ref ColorPatch widget. */
103 QPointer<ColorPatch> m_colorPatch;
104 /** @brief Holds the currently used icon theme.
105 *
106 * Initially this is <tt>std::nullopt</tt>. Once @ref reloadIcons() has
107 * been called, it has an actual value. */
108 std::optional<ColorSchemeType> m_currentIconThemeType = std::nullopt;
109 /** @brief Current color without alpha information
110 *
111 * Holds the color in absolutely defined color models.
112 *
113 * @note This value is considered in-gamut (even thought @ref RgbColor
114 * might tell different because of rounding errors).
115 *
116 * @sa @ref ColorDialog::currentColor()
117 * @sa @ref m_currentOpaqueColorRgb */
118 QHash<ColorModel, GenericColor> m_currentOpaqueColorAbs;
119 /** @brief Current color without alpha information
120 *
121 * Holds the color in the RGB color model and derived color models.
122 *
123 * @note This value is in-gamut by definition.
124 *
125 * @sa @ref ColorDialog::currentColor()
126 * @sa @ref m_currentOpaqueColorAbs */
127 RgbColor m_currentOpaqueColorRgb;
128 /** @brief If @ref q_pointer has ever been shown. */
129 bool everShown = false;
130 /** @brief Pointer to the @ref MultiSpinBox for HSL. */
131 QPointer<MultiSpinBox> m_hslSpinBox;
132 /** @brief Pointer to the label for @ref m_hslSpinBox. */
133 QPointer<QLabel> m_hslSpinBoxLabel;
134 /** @brief Pointer to the @ref MultiSpinBox for HSV. */
135 QPointer<MultiSpinBox> m_hsvSpinBox;
136 /** @brief Pointer to the label for @ref m_hsvSpinBox. */
137 QPointer<QLabel> m_hsvSpinBoxLabel;
138 /** @brief Pointer to the @ref MultiSpinBox for HWB. */
139 QPointer<MultiSpinBox> m_hwbSpinBox;
140 /** @brief Pointer to the label for @ref m_hwbSpinBox. */
141 QPointer<QLabel> m_hwbSpinBoxLabel;
142 /** @brief Shortcut to show the tab with @ref m_hueFirstWrapperWidget. */
143 QPointer<QShortcut> m_hueFirstTabShortcut;
144 /** @brief Pointer to the QWidget wrapper that contains
145 * @ref m_wheelColorPicker. */
146 QPointer<QWidget> m_hueFirstWrapperWidget;
147 /** @brief Holds whether currently a color change is ongoing, or not.
148 *
149 * Used to avoid infinite recursions when updating the different widgets
150 * within this dialog.
151 * @sa @ref setCurrentOpaqueColor() */
152 bool m_isColorChangeInProgress = false;
153 /** @brief Holds whether the current text of @ref m_rgbLineEdit differs
154 * from the value in @ref m_currentOpaqueColorRgb.
155 * @sa @ref readRgbHexValues
156 * @sa @ref updateRgbHexButBlockSignals */
157 bool m_isDirtyRgbLineEdit = false;
158 /** @brief An event filter used for some child widgets. */
159 LanguageChangeEventFilter m_languageChangeEventFilter;
160 /** @brief Internal storage for property
161 * @ref ColorDialog::layoutDimensions */
162 PerceptualColor::ColorDialog::DialogLayoutDimensions m_layoutDimensions =
163 //! [layoutDimensionsDefaultValue]
164 ColorDialog::DialogLayoutDimensions::Collapsed
165 //! [layoutDimensionsDefaultValue]
166 ;
167 /** @brief The <em>effective</em> layout dimensions.
168 *
169 * The property @ref ColorDialog::layoutDimensions has a value
170 * @ref ColorDialog::DialogLayoutDimensions::ScreenSizeDependent.
171 * <em>This</em> variable holds whatever <em>effectively</em>
172 * is applied. So it can only have the values
173 * @ref ColorDialog::DialogLayoutDimensions::Collapsed or
174 * @ref ColorDialog::DialogLayoutDimensions::Expanded. */
175 PerceptualColor::ColorDialog::DialogLayoutDimensions m_layoutDimensionsEffective = m_layoutDimensions;
176 /** @brief Shortcut to show the tab with @ref m_lightnessFirstWrapperWidget. */
177 QPointer<QShortcut> m_lightnessFirstTabShortcut;
178 /** @brief Pointer to the QWidget wrapper that contains
179 * @ref m_lchLightnessSelector and @ref m_chromaHueDiagram. */
180 QPointer<QWidget> m_lightnessFirstWrapperWidget;
181 /** @brief Pointer to the @ref GradientSlider for LCH lightness. */
182 QPointer<GradientSlider> m_lchLightnessSelector;
183 /** @brief Holds the receiver slot (if any) to be disconnected
184 * automatically after closing the dialog.
185 *
186 * Its value is only meaningful if
187 * @ref m_receiverToBeDisconnected is not null.
188 * @sa @ref m_receiverToBeDisconnected
189 * @sa @ref ColorDialog::open() */
190 QByteArray m_memberToBeDisconnected;
191 /** @brief String that is used as separator between two sections
192 * within a @ref MultiSpinBox.
193 *
194 * This string is introduced <em>twice</em> between two sections
195 * within a @ref MultiSpinBox. */
196 static inline const QString m_multispinboxSectionSeparator = QStringLiteral(u" ");
197 /** @brief Shortcut to show the tab with @ref m_numericalWidget. */
198 QPointer<QShortcut> m_numericalTabShortcut;
199 /** @brief Pointer to the widget that holds the numeric color
200 * representation. */
201 QPointer<QWidget> m_numericalWidget;
202 /** @brief Pointer to the @ref MultiSpinBox for CIEHLC. */
203 QPointer<MultiSpinBox> m_oklchSpinBox;
204 /** @brief Pointer to the gamut action for @ref m_oklchSpinBox. */
205 QPointer<QAction> m_oklchSpinBoxGamutAction;
206 /** @brief Pointer to the label for @ref m_oklchSpinBox. */
207 QPointer<QLabel> m_oklchSpinBoxLabel;
208 /** @brief Pointer to the basic colors widget. */
209 QPointer<PerceptualColor::SwatchBook> m_swatchBookBasicColors;
210 /** @brief Shortcut to show the tab with @ref m_swatchBookWrapperWidget. */
211 QPointer<QShortcut> m_swatchBookTabShortcut;
212 /** @brief Pointer to the QWidget wrapper that contains
213 * the swatch books. */
214 QPointer<QWidget> m_swatchBookWrapperWidget;
215 /** @brief Holds the receiver object (if any) to be disconnected
216 * automatically after closing the dialog.
217 *
218 * @sa @ref m_memberToBeDisconnected
219 * @sa @ref ColorDialog::open() */
220 QPointer<QObject> m_receiverToBeDisconnected;
221 /** @brief Internal storage for property @ref ColorDialog::options */
222 ColorDialog::ColorDialogOptions m_options;
223 /** @brief Pointer to the RgbColorSpace object. */
224 QSharedPointer<RgbColorSpace> m_rgbColorSpace;
225 /** @brief Group box that contains all RGB widgets and all widget for
226 * color spaces that are defined with RGB as base (HSV, Hex…). */
227 QPointer<QGroupBox> m_rgbGroupBox;
228 /** @brief Pointer to the QLineEdit that represents the hexadecimal
229 * RGB value. */
230 QPointer<QLineEdit> m_rgbLineEdit;
231 /** @brief Pointer to the label for @ref m_rgbLineEdit. */
232 QPointer<QLabel> m_rgbLineEditLabel;
233 /** @brief Pointer to the @ref MultiSpinBox for RGB. */
234 QPointer<MultiSpinBox> m_rgbSpinBox;
235 /** @brief Pointer to the label for @ref m_rgbSpinBox. */
236 QPointer<QLabel> m_rgbSpinBoxLabel;
237 /** @brief Internal storage for @ref ColorDialog::selectedColor(). */
238 QColor m_selectedColor;
239 /** @brief Layout that holds the graphical and numeric selectors. */
240 QPointer<QHBoxLayout> m_selectorLayout;
241 /** @brief Access to the @ref Settings singleton. */
242 PerceptualSettings &m_settings = PerceptualSettings::instance();
243 /** @brief Button that allows to pick with the mouse a color somewhere
244 * from the screen. */
245 QPointer<QToolButton> m_screenColorPickerButton;
246 /** @brief A row with two columns within a table in Qt’s rich text
247 * formatting.
248 *
249 * To use it, call QString::arg() twice: Once with the content of the
250 * first column and once with the content of the second column. */
251 const QString tableRow = QStringLiteral(u"<tr><td>%1</td><td>%2</td></tr>");
252 /** @brief Table assigning to each tab a value for the @ref Settings.
253 *
254 * This helps to convert from QString values stored in @ref Settings
255 * to the actual tab widgets and vice versa. */
256 QHash<QPointer<QWidget> *, QString> m_tabTable;
257 /** @brief Pointer to the tab widget. */
258 QPointer<QTabWidget> m_tabWidget;
259 /** @brief @ref m_wcsBasicColors for @ref m_rgbColorSpace. */
260 Array2D<QColor> m_wcsBasicColors;
261 /** @brief A default color within @ref m_wcsBasicColors.
262 *
263 * Choosing the blue tone (no tint, no shade). Arguments in favor:
264 *
265 * - Blue seems to be harmonious and integrate well in many designs.
266 * - The blue color is quite chromatic, giving a vivid impression.
267 * - Blue does not “screem” like red.
268 * - Blue is exactly at the middle of the swatch book.
269 * - The tone (no tint, no shade) is exactly at the middle of the
270 * swatch book. */
271 QColor m_wcsBasicDefaultColor;
272 /** @brief Pointer to the @ref WheelColorPicker widget. */
273 QPointer<WheelColorPicker> m_wheelColorPicker;
274
275 /** @brief Number of decimals to for most values.
276 *
277 * @sa @ref okdecimals */
278 static constexpr quint8 decimals = 0;
279 /** @brief Number of decimals to use for the Oklab/Oklch values
280 * L, C, a, b (but not for h!).
281 *
282 * @sa @ref decimals */
283 static constexpr quint8 okdecimals = decimals + 2;
284
285 void applyLayoutDimensions();
286 void initialize(const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace);
287 [[nodiscard]] QWidget *initializeNumericPage();
288 void initializeScreenColorPicker();
289 [[nodiscard]] QString translateColorModel(cmsColorSpaceSignature model);
290
291public Q_SLOTS:
292 void readChromaHueDiagramValue();
293 void readColorPatchValue();
294 void readHlcNumericValues();
295 void readHslNumericValues();
296 void readHsvNumericValues();
297 void readHwbNumericValues();
298 void readLightnessValue();
299 void readOklchNumericValues();
300 void readRgbHexValues();
301 void readRgbNumericValues();
302 void readSwatchBookBasicColorsValue();
303 void readWheelColorPickerValues();
304 void reloadIcons();
305 void retranslateUi();
306 void saveCurrentTab();
307 void setCurrentOpaqueColor(const QHash<PerceptualColor::ColorModel, PerceptualColor::GenericColor> &abs, QWidget *const ignoreWidget);
308 void setCurrentOpaqueColor(const PerceptualColor::RgbColor &rgb, QWidget *const ignoreWidget);
309 void setCurrentOpaqueColor(const QHash<PerceptualColor::ColorModel, PerceptualColor::GenericColor> &abs,
310 const PerceptualColor::RgbColor &rgb,
311 QWidget *const ignoreWidget);
312 void updateColorPatch();
313 void updateHlcButBlockSignals();
314 void updateOklchButBlockSignals();
315 void updateRgbHexButBlockSignals();
316
317private:
318 Q_DISABLE_COPY(ColorDialogPrivate)
319
320 /** @brief Pointer to the object from which <em>this</em> object
321 * is the private implementation. */
322 ConstPropagatingRawPointer<ColorDialog> q_pointer;
323};
324
325} // namespace PerceptualColor
326
327#endif // COLORDIALOG_P_H
The namespace of this library.
ColorSchemeType
Represents the appearance of a theme.
Definition helper.h:33
Q_OBJECTQ_OBJECT
Q_SLOTSQ_SLOTS
QString tr(const char *sourceText, const char *disambiguation, int n)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:36 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.