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

KDE's Doxygen guidelines are available online.