6#include "colordialog.h"
8#include "colordialog_p.h"
10#include "absolutecolor.h"
11#include "chromahuediagram.h"
12#include "cielchd50values.h"
13#include "colorpatch.h"
14#include "constpropagatingrawpointer.h"
15#include "constpropagatinguniquepointer.h"
16#include "gradientslider.h"
18#include "helperconstants.h"
19#include "helperconversion.h"
20#include "helperqttypes.h"
21#include "initializetranslation.h"
22#include "multispinbox.h"
23#include "multispinboxsection.h"
24#include "oklchvalues.h"
26#include "rgbcolorspace.h"
27#include "rgbcolorspacefactory.h"
28#include "screencolorpicker.h"
30#include "swatchbook.h"
31#include "wheelcolorpicker.h"
36#include <qapplication.h>
37#include <qboxlayout.h>
38#include <qbytearray.h>
41#include <qcoreapplication.h>
42#include <qcoreevent.h>
45#include <qdialogbuttonbox.h>
46#include <qfontmetrics.h>
47#include <qformlayout.h>
48#include <qgridlayout.h>
50#include <qguiapplication.h>
52#include <qkeysequence.h>
60#include <qpushbutton.h>
61#include <qregularexpression.h>
62#include <qscopedpointer.h>
64#include <qsharedpointer.h>
67#include <qsizepolicy.h>
69#include <qstackedlayout.h>
70#include <qstringbuilder.h>
71#include <qstringliteral.h>
72#include <qtabwidget.h>
73#include <qtoolbutton.h>
74#include <qvalidator.h>
75#include <qversionnumber.h>
80#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
81#include <qcontainerfwd.h>
82#include <qobjectdefs.h>
84#include <qstringlist.h>
87#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
88#include <qstylehints.h>
101QString ColorDialogPrivate::translateColorModel(cmsColorSpaceSignature model)
116 case cmsSigYCbCrData:
137 case cmsSigNamedData:
138 case cmsSig2colorData:
139 case cmsSig3colorData:
140 case cmsSig4colorData:
141 case cmsSig5colorData:
142 case cmsSig6colorData:
143 case cmsSig7colorData:
144 case cmsSig8colorData:
145 case cmsSig9colorData:
146 case cmsSig10colorData:
147 case cmsSig11colorData:
148 case cmsSig12colorData:
149 case cmsSig13colorData:
150 case cmsSig14colorData:
151 case cmsSig15colorData:
154 case cmsSig1colorData:
217void ColorDialogPrivate::retranslateUi()
220 const QPair<QString, QString> percentageInSpinbox =
221 getPrefixSuffix(
tr(
"%1%"));
224 const QPair<QString, QString> arcDegreeInSpinbox =
225 getPrefixSuffix(
tr(
"%1°"));
227 QStringList profileInfo;
233 profileInfo.
append(tableRow.arg(
tr(
"Name:"), name));
236 const QString maximumCielchD50Chroma =
237 tr(
"%L1 (estimated)")
238 .
arg(m_rgbColorSpace->profileMaximumCielchD50Chroma(),
245 tableRow.arg(
tr(
"Maximum CIELCh-D50 chroma:"), maximumCielchD50Chroma));
247 const QString maximumOklchChroma =
248 tr(
"%L1 (estimated)")
249 .
arg(m_rgbColorSpace->profileMaximumOklchChroma(),
256 tableRow.arg(
tr(
"Maximum Oklch chroma:"), maximumOklchChroma));
257 QString profileClass;
258 switch (m_rgbColorSpace->profileClass()) {
259 case cmsSigDisplayClass:
261 profileClass =
tr(
"Display profile");
263 case cmsSigAbstractClass:
268 case cmsSigColorSpaceClass:
269 case cmsSigInputClass:
270 case cmsSigLinkClass:
271 case cmsSigNamedColorClass:
272 case cmsSigOutputClass:
280 tableRow.arg(
tr(
"Profile class:"), profileClass));
282 const QString colorModel =
283 translateColorModel(m_rgbColorSpace->profileColorModel());
289 profileInfo.
append(tableRow.arg(
tr(
"Color model:"), colorModel));
291 const QString manufacturer =
292 m_rgbColorSpace->profileManufacturer().toHtmlEscaped();
298 profileInfo.
append(tableRow.arg(
tr(
"Manufacturer:"), manufacturer));
300 const QString model =
301 m_rgbColorSpace->profileModel().toHtmlEscaped();
307 profileInfo.
append(tableRow.arg(
tr(
"Device model:"), (model)));
309 const QDateTime creationDateTime =
310 m_rgbColorSpace->profileCreationDateTime();
311 if (!creationDateTime.
isNull()) {
312 const auto creationDateTimeString = QLocale().toString(
321 tableRow.arg(
tr(
"Created:"), (creationDateTimeString)));
323 const QVersionNumber iccVersion = m_rgbColorSpace->profileIccVersion();
328 tableRow.arg(
tr(
"ICC format:"), (iccVersion.
toString())));
329 const bool hasMatrixShaper =
330 m_rgbColorSpace->profileHasMatrixShaper();
332 m_rgbColorSpace->profileHasClut();
333 if (hasMatrixShaper || hasClut) {
334 const QString matrixShaperString = tableRow.arg(
339 tr(
"Implementation:"));
340 if (hasMatrixShaper && hasClut) {
346 matrixShaperString.
arg(
tr(
"Matrices and color lookup tables")));
347 }
else if (hasMatrixShaper) {
352 profileInfo.
append(matrixShaperString.
arg(
tr(
"Matrices")));
353 }
else if (hasClut) {
359 matrixShaperString.
arg(
tr(
"Color lookup tables")));
362 const QString pcsColorModelText =
363 translateColorModel(m_rgbColorSpace->profilePcsColorModel());
364 if (!pcsColorModelText.
isEmpty()) {
370 tableRow.arg(
tr(
"PCS color model:"), pcsColorModelText));
372 const QString copyright = m_rgbColorSpace->profileCopyright();
377 profileInfo.
append(tableRow.arg(
tr(
"Copyright:"), copyright));
379 const qint64 fileSize =
380 m_rgbColorSpace->profileFileSize();
385 profileInfo.
append(tableRow.arg(
tr(
"File size:"),
386 QLocale().formattedDataSize(fileSize)));
388 const QString fileName =
389 m_rgbColorSpace->profileAbsoluteFilePath();
393 profileInfo.
append(tableRow.arg(
tr(
"File name:"), fileName));
396 m_rgbGroupBox->setToolTip(QString());
398 const QString tableString = QStringLiteral(
400 "<table border=\"0\" cellpadding=\"2\" cellspacing=\"0\">"
403 m_rgbGroupBox->setToolTip(richTextMarker
409 tr(
"Color space information"),
410 profileInfo.
join(QString())));
415 m_cielchD50SpinBoxLabel->setText(
tr(
"&CIELCH D50:"));
419 m_oklchSpinBoxLabel->setText(
tr(
"O&klch:"));
422 m_rgbSpinBoxLabel->setText(
tr(
"&RGB:"));
425 m_rgbLineEditLabel->setText(
tr(
"He&x:"));
427 const int swatchBookIndex = m_tabWidget->indexOf(m_swatchBookWrapperWidget);
428 if (swatchBookIndex >= 0) {
431 const auto mnemonic =
tr(
"&Swatch book");
432 m_tabWidget->setTabToolTip(
434 richTextMarker + fromMnemonicToRichText(mnemonic));
438 const int hueFirstIndex = m_tabWidget->indexOf(m_hueFirstWrapperWidget);
439 if (hueFirstIndex >= 0) {
443 const auto mnemonic =
tr(
"&Hue-based");
444 m_tabWidget->setTabToolTip(
446 richTextMarker + fromMnemonicToRichText(mnemonic));
449 const int lightnessFirstIndex =
450 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget);
451 if (lightnessFirstIndex >= 0) {
457 const auto mnemonic =
tr(
"&Lightness-based");
458 m_tabWidget->setTabToolTip(
460 richTextMarker + fromMnemonicToRichText(mnemonic));
463 const int numericIndex =
464 m_tabWidget->indexOf(m_numericalWidget);
465 if (numericIndex >= 0) {
469 const auto mnemonic =
tr(
"&Numeric");
470 m_tabWidget->setTabToolTip(
472 richTextMarker + fromMnemonicToRichText(mnemonic));
477 m_hslSpinBoxLabel->setText(
tr(
"HS&L:"));
481 m_hsvSpinBoxLabel->setText(
tr(
"HS&V/HSB:"));
484 m_hwbSpinBoxLabel->setText(
tr(
"H&WB:"));
487 m_buttonOK->setText(
tr(
"&OK"));
490 m_buttonCancel->setText(
tr(
"&Cancel"));
492 m_rgbSpinBox->setToolTip(
494 +
tr(
"<p>Red: 0–255</p>"
495 "<p>Green: 0–255</p>"
496 "<p>Blue: 0–255</p>"));
499 m_rgbLineEdit->setToolTip(
501 +
tr(
"<p>Hexadecimal color code, as used in HTML: #RRGGBB</p>"
502 "<p>RR: two-digit code for red: 00–FF</p>"
503 "<p>GG: two-digit code for green: 00–FF</p>"
504 "<p>BB: two-digit code for blue: 00–FF</p>"));
513 m_hslSpinBox->setToolTip(richTextMarker
514 +
tr(
"<p>Hue: 0°–360°</p>"
515 "<p>HSL-Saturation: 0%–100%</p>"
516 "<p>Lightness: 0%–100%</p>"));
527 m_hwbSpinBox->setToolTip(richTextMarker
528 +
tr(
"<p>Hue: 0°–360°</p>"
529 "<p>Whiteness: 0%–100%</p>"
530 "<p>Blackness: 0%–100%</p>"));
540 m_hsvSpinBox->setToolTip(richTextMarker
541 +
tr(
"<p>Hue: 0°–360°</p>"
542 "<p>HSV/HSB-Saturation: 0%–100%</p>"
543 "<p>Brightness/Value: 0%–100%</p>"));
545 m_alphaSpinBox->setPrefix(percentageInSpinbox.first);
546 m_alphaSpinBox->setSuffix(percentageInSpinbox.second);
551 m_lchLightnessSelector->setAccessibleName(
tr(
"Lightness"));
555 m_cielchD50SpinBox->setToolTip(richTextMarker
556 +
tr(
"<p>Lightness: 0%–100%</p>"
557 "<p>Chroma: 0–%L1</p>"
558 "<p>Hue: 0°–360°</p>")
559 .arg(CielchD50Values::maximumChroma));
561 constexpr double maxOklchChroma = OklchValues::maximumChroma;
564 m_oklchSpinBox->setToolTip(richTextMarker
565 +
tr(
"<p>Lightness: %L1–%L2</p>"
566 "<p>Chroma: %L3–%L4</p>"
567 "<p>Hue: 0°–360°</p>"
568 "<p>Whitepoint: D65</p>")
569 .arg(0., 0,
'f', okdecimals)
570 .arg(1., 0,
'f', okdecimals)
571 .arg(0., 0,
'f', okdecimals)
572 .arg(maxOklchChroma, 0,
'f', okdecimals));
578 const QString opacityLabel =
tr(
"Op&acity:");
579 m_alphaGradientSlider->setAccessibleName(opacityLabel);
580 m_alphaLabel->setText(opacityLabel);
583 QList<MultiSpinBoxSection> hslSections =
584 m_hslSpinBox->sectionConfigurations();
585 if (hslSections.
count() != 3) {
587 <<
"Expected 3 sections in HSV MultiSpinBox, but got"
588 << hslSections.
count()
589 <<
"instead. This is a bug in libperceptualcolor.";
591 hslSections[0].setPrefix(arcDegreeInSpinbox.first);
592 hslSections[0].setSuffix(
593 arcDegreeInSpinbox.second + m_multispinboxSectionSeparator);
594 hslSections[1].setPrefix(
595 m_multispinboxSectionSeparator + percentageInSpinbox.first);
596 hslSections[1].setSuffix(
597 percentageInSpinbox.second + m_multispinboxSectionSeparator);
598 hslSections[2].setPrefix(
599 m_multispinboxSectionSeparator + percentageInSpinbox.first);
600 hslSections[2].setSuffix(percentageInSpinbox.second);
601 m_hslSpinBox->setSectionConfigurations(hslSections);
605 QList<MultiSpinBoxSection> hwbSections =
606 m_hwbSpinBox->sectionConfigurations();
607 if (hwbSections.
count() != 3) {
609 <<
"Expected 3 sections in HSV MultiSpinBox, but got"
610 << hwbSections.
count()
611 <<
"instead. This is a bug in libperceptualcolor.";
613 hwbSections[0].setPrefix(arcDegreeInSpinbox.first);
614 hwbSections[0].setSuffix(
615 arcDegreeInSpinbox.second + m_multispinboxSectionSeparator);
616 hwbSections[1].setPrefix(
617 m_multispinboxSectionSeparator + percentageInSpinbox.first);
618 hwbSections[1].setSuffix(
619 percentageInSpinbox.second + m_multispinboxSectionSeparator);
620 hwbSections[2].setPrefix(
621 m_multispinboxSectionSeparator + percentageInSpinbox.first);
622 hwbSections[2].setSuffix(
623 percentageInSpinbox.second);
624 m_hwbSpinBox->setSectionConfigurations(hwbSections);
628 QList<MultiSpinBoxSection> hsvSections =
629 m_hsvSpinBox->sectionConfigurations();
630 if (hsvSections.
count() != 3) {
632 <<
"Expected 3 sections in HSV MultiSpinBox, but got"
633 << hsvSections.
count()
634 <<
"instead. This is a bug in libperceptualcolor.";
636 hsvSections[0].setPrefix(arcDegreeInSpinbox.first);
637 hsvSections[0].setSuffix(
638 arcDegreeInSpinbox.second + m_multispinboxSectionSeparator);
639 hsvSections[1].setPrefix(
640 m_multispinboxSectionSeparator + percentageInSpinbox.first);
641 hsvSections[1].setSuffix(
642 percentageInSpinbox.second + m_multispinboxSectionSeparator);
643 hsvSections[2].setPrefix(
644 m_multispinboxSectionSeparator + percentageInSpinbox.first);
645 hsvSections[2].setSuffix(percentageInSpinbox.second);
646 m_hsvSpinBox->setSectionConfigurations(hsvSections);
650 QList<MultiSpinBoxSection> cielchD50Sections =
651 m_cielchD50SpinBox->sectionConfigurations();
652 if (cielchD50Sections.
count() != 3) {
654 <<
"Expected 3 sections in CIELCH-D50 MultiSpinBox, but got"
655 << cielchD50Sections.
count()
656 <<
"instead. This is a bug in libperceptualcolor.";
658 cielchD50Sections[0].setPrefix(percentageInSpinbox.first);
659 cielchD50Sections[0].setSuffix(
660 percentageInSpinbox.second + m_multispinboxSectionSeparator);
661 cielchD50Sections[1].setPrefix(m_multispinboxSectionSeparator);
662 cielchD50Sections[1].setSuffix(m_multispinboxSectionSeparator);
663 cielchD50Sections[2].setPrefix(m_multispinboxSectionSeparator + arcDegreeInSpinbox.first);
664 cielchD50Sections[2].setSuffix(arcDegreeInSpinbox.second);
665 m_cielchD50SpinBox->setSectionConfigurations(cielchD50Sections);
669 QList<MultiSpinBoxSection> oklchSections =
670 m_oklchSpinBox->sectionConfigurations();
671 if (oklchSections.
count() != 3) {
673 <<
"Expected 3 sections in Oklch MultiSpinBox, but got"
674 << oklchSections.
count()
675 <<
"instead. This is a bug in libperceptualcolor.";
677 oklchSections[0].setPrefix(QString());
678 oklchSections[0].setSuffix(m_multispinboxSectionSeparator);
679 oklchSections[1].setPrefix(m_multispinboxSectionSeparator);
680 oklchSections[1].setSuffix(m_multispinboxSectionSeparator);
681 oklchSections[2].setPrefix(
682 m_multispinboxSectionSeparator + arcDegreeInSpinbox.first);
683 oklchSections[2].setSuffix(arcDegreeInSpinbox.second);
684 m_oklchSpinBox->setSectionConfigurations(oklchSections);
687 if (m_screenColorPickerButton) {
692 const auto mnemonic =
tr(
"&Pick screen color");
693 m_screenColorPickerButton->setToolTip(
694 richTextMarker + fromMnemonicToRichText(mnemonic));
695 m_screenColorPickerButton->setShortcut(
704 const auto gamutMnemonic =
705 tr(
"Click to snap to nearest in-&gamut color");
706 const QString gamutTooltip =
707 richTextMarker + fromMnemonicToRichText(gamutMnemonic);
709 m_cielchD50SpinBoxGamutAction->setToolTip(gamutTooltip);
710 m_cielchD50SpinBoxGamutAction->setShortcut(gamutShortcut);
711 m_oklchSpinBoxGamutAction->setToolTip(gamutTooltip);
712 m_oklchSpinBoxGamutAction->setShortcut(gamutShortcut);
717 m_swatchBookSelector->setItemText(0,
tr(
"Basic colors"));
722 m_swatchBookSelector->setItemText(1,
tr(
"History"));
727 m_swatchBookSelector->setItemText(2,
tr(
"Custom Colors"));
747void ColorDialogPrivate::reloadIcons()
749 m_currentIconThemeType = guessColorSchemeTypeFromWidget(q_pointer);
751 static const QStringList swatchBookIcons
752 {QStringLiteral(
"paint-swatch"),
755 QStringLiteral(
"palette"),
756 QStringLiteral(
"palette-symbolic")};
757 const int swatchBookIndex =
758 m_tabWidget->indexOf(m_swatchBookWrapperWidget);
759 if (swatchBookIndex >= 0) {
760 m_tabWidget->setTabIcon(swatchBookIndex,
761 qIconFromTheme(swatchBookIcons,
762 QStringLiteral(
"color-swatch"),
763 m_currentIconThemeType));
766 static const QStringList hueFirstIcons
768 QStringLiteral(
"color-mode-hue-shift-positive"),
770 const int hueFirstIndex =
771 m_tabWidget->indexOf(m_hueFirstWrapperWidget);
772 if (hueFirstIndex >= 0) {
773 m_tabWidget->setTabIcon(hueFirstIndex,
774 qIconFromTheme(hueFirstIcons,
775 QStringLiteral(
"steering-wheel"),
776 m_currentIconThemeType));
779 static const QStringList lightnessFirstIcons
781 QStringLiteral(
"brightness-high"),
783 const int lightnessFirstIndex =
784 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget);
785 if (lightnessFirstIndex >= 0) {
786 m_tabWidget->setTabIcon(lightnessFirstIndex,
787 qIconFromTheme(lightnessFirstIcons,
788 QStringLiteral(
"brightness-2"),
789 m_currentIconThemeType));
792 static const QStringList numericIcons
794 QStringLiteral(
"black_sum"),
796 const int numericIndex =
797 m_tabWidget->indexOf(m_numericalWidget);
798 if (numericIndex >= 0) {
799 m_tabWidget->setTabIcon(numericIndex,
800 qIconFromTheme(numericIcons,
801 QStringLiteral(
"123"),
802 m_currentIconThemeType));
806 static const QStringList gamutIconNames
808 QStringLiteral(
"data-warning"),
809 QStringLiteral(
"dialog-warning-symbolic"),
811 const QIcon gamutIcon = qIconFromTheme(gamutIconNames,
812 QStringLiteral(
"eye-exclamation"),
813 m_currentIconThemeType);
814 m_cielchD50SpinBoxGamutAction->setIcon(gamutIcon);
815 m_oklchSpinBoxGamutAction->setIcon(gamutIcon);
817 static const QStringList candidates
819 QStringLiteral(
"color-picker"),
820 QStringLiteral(
"gtk-color-picker"),
821 QStringLiteral(
"tool_color_picker"),
823 if (!m_screenColorPickerButton.isNull()) {
824 m_screenColorPickerButton->setIcon(
825 qIconFromTheme(candidates,
826 QStringLiteral(
"color-picker"),
827 m_currentIconThemeType));
843void ColorDialogPrivate::initialize(
const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace)
852 m_rgbColorSpace = colorSpace;
854 m_wcsBasicDefaultColor = m_wcsBasicColors.value(4, 2);
857 m_swatchBookBasicColors =
new SwatchBook(m_rgbColorSpace,
859 Qt::Orientation::Horizontal);
860 auto swatchBookBasicColorsLayout =
new QGridLayout();
861 auto swatchBookBasicColorsLayoutWidget =
new QWidget();
862 swatchBookBasicColorsLayoutWidget->setLayout(swatchBookBasicColorsLayout);
863 swatchBookBasicColorsLayoutWidget->setContentsMargins(0, 0, 0, 0);
864 swatchBookBasicColorsLayout->setContentsMargins(0, 0, 0, 0);
865 swatchBookBasicColorsLayout->addWidget(m_swatchBookBasicColors);
866 swatchBookBasicColorsLayout->setRowStretch(1, 1);
867 swatchBookBasicColorsLayout->setColumnStretch(1, 1);
868 m_swatchBookHistory =
new SwatchBook(m_rgbColorSpace,
870 Qt::Orientation::Vertical);
871 auto swatchBookHistoryLayout =
new QGridLayout();
872 auto swatchBookHistoryLayoutWidget =
new QWidget();
873 swatchBookHistoryLayoutWidget->setLayout(swatchBookHistoryLayout);
874 swatchBookHistoryLayoutWidget->setContentsMargins(0, 0, 0, 0);
875 swatchBookHistoryLayout->setContentsMargins(0, 0, 0, 0);
876 swatchBookHistoryLayout->addWidget(m_swatchBookHistory);
877 swatchBookHistoryLayout->setRowStretch(1, 1);
878 swatchBookHistoryLayout->setColumnStretch(1, 1);
879 loadHistoryFromSettingsToSwatchBook();
880 m_swatchBookCustomColors =
new SwatchBook(
883 Qt::Orientation::Horizontal | Qt::Orientation::Vertical);
884 m_swatchBookCustomColors->setEditable(
true);
885 auto swatchBookCustomColorsLayout =
new QGridLayout();
886 auto swatchBookCustomColorsLayoutWidget =
new QWidget();
887 swatchBookCustomColorsLayoutWidget->setLayout(swatchBookCustomColorsLayout);
888 swatchBookCustomColorsLayoutWidget->setContentsMargins(0, 0, 0, 0);
889 swatchBookCustomColorsLayout->setContentsMargins(0, 0, 0, 0);
890 swatchBookCustomColorsLayout->addWidget(m_swatchBookCustomColors);
891 swatchBookCustomColorsLayout->setRowStretch(1, 1);
892 swatchBookCustomColorsLayout->setColumnStretch(1, 1);
893 loadCustomColorsFromSettingsToSwatchBook();
894 connect(m_swatchBookCustomColors,
895 &SwatchBook::swatchGridChanged,
897 [
this](
const Swatches &newSwatches) {
898 m_settings.customColors.setValue(newSwatches.toQList());
900 m_swatchBookStack =
new QStackedLayout();
901 m_swatchBookStack->addWidget(swatchBookBasicColorsLayoutWidget);
902 m_swatchBookStack->addWidget(swatchBookHistoryLayoutWidget);
903 m_swatchBookStack->addWidget(swatchBookCustomColorsLayoutWidget);
904 QHBoxLayout *swatchBookInnerLayout =
new QHBoxLayout();
905 swatchBookInnerLayout->
addLayout(m_swatchBookStack);
907 QVBoxLayout *swatchBookOuterLayout =
new QVBoxLayout();
908 m_swatchBookSelector =
new QComboBox();
909 m_swatchBookSelector->addItem(QString());
910 m_swatchBookSelector->addItem(QString());
911 m_swatchBookSelector->addItem(QString());
918 m_swatchBookStack->setCurrentIndex(0);
919 m_settings.swatchBookPage.setValue(
920 PerceptualSettings::SwatchBookPage::BasicColors);
923 m_swatchBookStack->setCurrentIndex(1);
924 m_settings.swatchBookPage.setValue(
925 PerceptualSettings::SwatchBookPage::History);
928 m_swatchBookStack->setCurrentIndex(2);
929 m_settings.swatchBookPage.setValue(
930 PerceptualSettings::SwatchBookPage::CustomColors);
934 swatchBookOuterLayout->
addWidget(m_swatchBookSelector);
935 swatchBookOuterLayout->
addLayout(swatchBookInnerLayout);
937 m_swatchBookWrapperWidget =
new QWidget();
938 m_swatchBookWrapperWidget->setLayout(swatchBookOuterLayout);
940 &Setting<PerceptualSettings::ColorList>::valueChanged,
942 &ColorDialogPrivate::loadHistoryFromSettingsToSwatchBook);
943 connect(&m_settings.customColors,
944 &Setting<PerceptualSettings::ColorList>::valueChanged,
946 &ColorDialogPrivate::loadCustomColorsFromSettingsToSwatchBook);
947 m_wheelColorPicker =
new WheelColorPicker(m_rgbColorSpace);
948 m_hueFirstWrapperWidget =
new QWidget;
949 QHBoxLayout *tempHueFirstLayout =
new QHBoxLayout;
950 tempHueFirstLayout->
addWidget(m_wheelColorPicker);
951 m_hueFirstWrapperWidget->setLayout(tempHueFirstLayout);
953 m_lchLightnessSelector =
new GradientSlider(m_rgbColorSpace);
954 GenericColor blackCielchD50;
955 blackCielchD50.first = 0;
956 blackCielchD50.second = 0;
957 blackCielchD50.third = 0;
958 blackCielchD50.fourth = 1;
959 GenericColor whiteCielchD50;
960 whiteCielchD50.first = 100;
961 whiteCielchD50.second = 0;
962 whiteCielchD50.third = 0;
963 whiteCielchD50.fourth = 1;
964 m_lchLightnessSelector->setColors(blackCielchD50, whiteCielchD50);
965 m_chromaHueDiagram =
new ChromaHueDiagram(m_rgbColorSpace);
966 QHBoxLayout *tempLightnesFirstLayout =
new QHBoxLayout();
967 tempLightnesFirstLayout->
addWidget(m_lchLightnessSelector);
968 tempLightnesFirstLayout->
addWidget(m_chromaHueDiagram);
969 m_lightnessFirstWrapperWidget =
new QWidget();
970 m_lightnessFirstWrapperWidget->setLayout(tempLightnesFirstLayout);
972 initializeScreenColorPicker();
974 m_tabWidget =
new QTabWidget;
986 m_tabWidget->addTab(m_swatchBookWrapperWidget, QString());
987 m_swatchBookTabShortcut =
new QShortcut(q_pointer);
988 connect(m_swatchBookTabShortcut,
992 m_tabWidget->setCurrentIndex(
993 m_tabWidget->indexOf(m_swatchBookWrapperWidget));
995 connect(m_swatchBookTabShortcut,
999 m_tabWidget->setCurrentIndex(
1000 m_tabWidget->indexOf(m_swatchBookWrapperWidget));
1003 m_tabWidget->addTab(m_hueFirstWrapperWidget, QString());
1004 m_hueFirstTabShortcut =
new QShortcut(q_pointer);
1005 connect(m_hueFirstTabShortcut,
1009 m_tabWidget->setCurrentIndex(
1010 m_tabWidget->indexOf(m_hueFirstWrapperWidget));
1012 connect(m_hueFirstTabShortcut,
1016 m_tabWidget->setCurrentIndex(
1017 m_tabWidget->indexOf(m_hueFirstWrapperWidget));
1020 m_tabWidget->addTab(m_lightnessFirstWrapperWidget, QString());
1021 m_lightnessFirstTabShortcut =
new QShortcut(q_pointer);
1022 connect(m_lightnessFirstTabShortcut,
1026 m_tabWidget->setCurrentIndex(
1027 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget));
1029 connect(m_lightnessFirstTabShortcut,
1033 m_tabWidget->setCurrentIndex(
1034 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget));
1037 m_tabTable.insert(&m_swatchBookWrapperWidget,
1038 QStringLiteral(
"swatch"));
1039 m_tabTable.insert(&m_hueFirstWrapperWidget,
1040 QStringLiteral(
"hue-based"));
1041 m_tabTable.insert(&m_lightnessFirstWrapperWidget,
1042 QStringLiteral(
"lightness-based"));
1043 m_tabTable.insert(&m_numericalWidget,
1044 QStringLiteral(
"numerical"));
1048 &ColorDialogPrivate::saveCurrentTab);
1051 m_colorPatch =
new ColorPatch();
1052 m_colorPatch->setMinimumSize(m_colorPatch->minimumSizeHint() * 1.5);
1054 QHBoxLayout *headerLayout =
new QHBoxLayout();
1055 headerLayout->
addWidget(m_colorPatch, 1);
1058 headerLayout->
addWidget(m_screenColorPickerButton,
1066 m_numericalWidget = initializeNumericPage();
1067 m_numericalTabShortcut =
new QShortcut(q_pointer);
1068 connect(m_numericalTabShortcut,
1072 m_tabWidget->setCurrentIndex(
1073 m_tabWidget->indexOf(m_numericalWidget));
1075 connect(m_numericalTabShortcut,
1079 m_tabWidget->setCurrentIndex(
1080 m_tabWidget->indexOf(m_numericalWidget));
1084 m_selectorLayout =
new QHBoxLayout();
1085 m_selectorLayout->addWidget(m_tabWidget);
1086 m_selectorLayout->addWidget(m_numericalWidget);
1089 QHBoxLayout *m_alphaLayout =
new QHBoxLayout();
1090 m_alphaGradientSlider =
new GradientSlider(m_rgbColorSpace,
1091 Qt::Orientation::Horizontal);
1092 m_alphaGradientSlider->setSingleStep(singleStepAlpha);
1093 m_alphaGradientSlider->setPageStep(pageStepAlpha);
1094 m_alphaSpinBox =
new QDoubleSpinBox();
1095 m_alphaSpinBox->setAlignment(Qt::AlignmentFlag::AlignRight);
1096 m_alphaSpinBox->setMinimum(0);
1097 m_alphaSpinBox->setMaximum(100);
1099 m_alphaSpinBox->setDecimals(decimals);
1100 m_alphaSpinBox->setSingleStep(singleStepAlpha * 100);
1103 m_alphaLabel =
new QLabel();
1104 m_alphaLabel->setBuddy(m_alphaSpinBox);
1106 m_alphaLayout->
addWidget(m_alphaGradientSlider);
1107 m_alphaLayout->
addWidget(m_alphaSpinBox);
1117 m_buttonBox =
new QDialogButtonBox();
1136 m_buttonBox->installEventFilter(&m_languageChangeEventFilter);
1137 m_buttonOK->installEventFilter(&m_languageChangeEventFilter);
1138 m_buttonCancel->installEventFilter(&m_languageChangeEventFilter);
1149 QVBoxLayout *tempMainLayout =
new QVBoxLayout();
1150 tempMainLayout->
addLayout(headerLayout);
1151 tempMainLayout->
addLayout(m_selectorLayout);
1152 tempMainLayout->
addLayout(m_alphaLayout);
1154 q_pointer->setLayout(tempMainLayout);
1160 &ColorDialogPrivate::readColorPatchValue
1162 connect(m_swatchBookBasicColors,
1163 &SwatchBook::currentColorChanged,
1165 &ColorDialogPrivate::readSwatchBookBasicColorsValue
1168 &SwatchBook::currentColorChanged,
1170 &ColorDialogPrivate::readSwatchBookHistoryValue
1172 connect(m_swatchBookCustomColors,
1173 &SwatchBook::currentColorChanged,
1175 &ColorDialogPrivate::readSwatchBookCustomColorsValue
1180 &ColorDialogPrivate::readRgbNumericValues
1185 &ColorDialogPrivate::readRgbHexValues
1190 &ColorDialogPrivate::updateRgbHexButBlockSignals
1195 &ColorDialogPrivate::readHslNumericValues
1200 &ColorDialogPrivate::readHwbNumericValues
1205 &ColorDialogPrivate::readHsvNumericValues
1210 &ColorDialogPrivate::readLchNumericValues
1215 &ColorDialogPrivate::updateLchButBlockSignals
1220 &ColorDialogPrivate::readOklchNumericValues
1225 &ColorDialogPrivate::updateOklchButBlockSignals
1227 connect(m_lchLightnessSelector,
1230 &ColorDialogPrivate::readLightnessValue
1235 &ColorDialogPrivate::readWheelColorPickerValues
1240 &ColorDialogPrivate::readChromaHueDiagramValue
1242 connect(m_alphaGradientSlider,
1245 &ColorDialogPrivate::updateColorPatch
1247 connect(m_alphaGradientSlider,
1250 [
this](
const qreal newFraction) {
1251 const QSignalBlocker blocker(m_alphaSpinBox);
1252 m_alphaSpinBox->setValue(newFraction * 100);
1257 [
this](
const double newValue) {
1260 m_alphaGradientSlider->setValue(newValue / 100);
1264 q_pointer->setOptions(QColorDialog::ColorDialogOption::DontUseNativeDialog);
1272 q_pointer->setWindowTitle(
tr(
"Select color"));
1287 q_pointer->setSizeGripEnabled(
true);
1292 m_cielchD50SpinBoxGamutAction =
new QAction(q_pointer);
1293 connect(m_cielchD50SpinBoxGamutAction,
1296 &ColorDialogPrivate::updateLchButBlockSignals
1298 m_oklchSpinBoxGamutAction =
new QAction(q_pointer);
1299 connect(m_oklchSpinBoxGamutAction,
1302 &ColorDialogPrivate::updateOklchButBlockSignals
1307 m_cielchD50SpinBoxGamutAction->setVisible(
false);
1308 m_cielchD50SpinBox->addActionButton(
1309 m_cielchD50SpinBoxGamutAction,
1310 QLineEdit::ActionPosition::TrailingPosition);
1311 m_oklchSpinBoxGamutAction->setVisible(
false);
1312 m_oklchSpinBox->addActionButton(
1313 m_oklchSpinBoxGamutAction,
1314 QLineEdit::ActionPosition::TrailingPosition);
1321 std::optional<QStringList>());
1325#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
1326 connect(qGuiApp->styleHints(),
1329 &ColorDialogPrivate::reloadIcons);
1339 , d_pointer(new ColorDialogPrivate(this))
1357 , d_pointer(new ColorDialogPrivate(this))
1376 , d_pointer(new ColorDialogPrivate(this))
1378 d_pointer->initialize(colorSpace);
1386QColor ColorDialogPrivate::defaultColor()
const
1388 const auto history = m_settings.history.value();
1389 return history.value(0, m_wcsBasicDefaultColor);
1406 , d_pointer(new ColorDialogPrivate(this))
1408 d_pointer->initialize(colorSpace);
1431ColorDialogPrivate::ColorDialogPrivate(
ColorDialog *backLink)
1432 : q_pointer(backLink)
1440 QColor temp = d_pointer->m_currentOpaqueColorRgb.rgbQColor;
1442 static_cast<QColorFloatType
>(
1443 d_pointer->m_alphaGradientSlider->value()));
1465 temp = color.
toRgb();
1470 if (
testOption(ColorDialog::ColorDialogOption::ShowAlphaChannel)) {
1471 d_pointer->m_alphaGradientSlider->setValue(
1472 static_cast<double>(temp.
alphaF()));
1474 d_pointer->m_alphaGradientSlider->setValue(1);
1478 const RgbColor myRgbColor = RgbColor::fromRgbQColor(temp);
1479 d_pointer->setCurrentOpaqueColor(myRgbColor,
nullptr);
1498 d_pointer->m_receiverToBeDisconnected = receiver;
1499 d_pointer->m_memberToBeDisconnected = member;
1508void ColorDialogPrivate::updateColorPatch()
1510 QColor tempRgbQColor = m_currentOpaqueColorRgb.rgbQColor;
1512 static_cast<QColorFloatType
>(m_alphaGradientSlider->value()));
1513 m_colorPatch->setColor(tempRgbQColor);
1520 const auto rgb1 = m_rgbColorSpace->fromCielchD50ToRgb1(cielchD50);
1521 const auto rgb255 = GenericColor(rgb1.first * 255,
1524 const auto rgbColor = RgbColor::fromRgb255(rgb255);
1525 setCurrentOpaqueColor(abs, rgbColor, ignoreWidget);
1529void ColorDialogPrivate::setCurrentOpaqueColor(
const PerceptualColor::RgbColor &rgb, QWidget *
const ignoreWidget)
1531 const auto temp = rgb.rgb255;
1533 static_cast<QColorFloatType
>(temp.first / 255.),
1534 static_cast<QColorFloatType
>(temp.second / 255.),
1535 static_cast<QColorFloatType
>(temp.third / 255.));
1536 const auto cielchD50 = GenericColor(
1537 m_rgbColorSpace->toCielchD50(myQColor.
rgba64()));
1538 setCurrentOpaqueColor(
1561void ColorDialogPrivate::setCurrentOpaqueColor(
const QHash<PerceptualColor::ColorModel, PerceptualColor::GenericColor> &abs,
1562 const PerceptualColor::RgbColor &rgb,
1563 QWidget *
const ignoreWidget)
1565 const bool isIdentical =
1566 (abs == m_currentOpaqueColorAbs) && (rgb == m_currentOpaqueColorRgb);
1567 if (m_isColorChangeInProgress || isIdentical) {
1574 m_isColorChangeInProgress =
true;
1578 QColor oldQColor = q_pointer->currentColor();
1581 m_currentOpaqueColorAbs = abs;
1582 m_currentOpaqueColorRgb = rgb;
1585 if (m_swatchBookBasicColors != ignoreWidget) {
1586 m_swatchBookBasicColors->setCurrentColor(
1587 m_currentOpaqueColorRgb.rgbQColor);
1591 if (m_swatchBookHistory != ignoreWidget) {
1592 m_swatchBookHistory->setCurrentColor(m_currentOpaqueColorRgb.rgbQColor);
1596 if (m_swatchBookCustomColors != ignoreWidget) {
1597 m_swatchBookCustomColors->setCurrentColor(m_currentOpaqueColorRgb.rgbQColor);
1601 if (m_rgbSpinBox != ignoreWidget) {
1602 m_rgbSpinBox->setSectionValues(
1603 m_currentOpaqueColorRgb.rgb255.toQList3());
1607 if (m_hslSpinBox != ignoreWidget) {
1608 m_hslSpinBox->setSectionValues(
1609 m_currentOpaqueColorRgb.hsl.toQList3());
1613 if (m_hwbSpinBox != ignoreWidget) {
1614 m_hwbSpinBox->setSectionValues(
1615 m_currentOpaqueColorRgb.hwb.toQList3());
1619 if (m_hsvSpinBox != ignoreWidget) {
1620 m_hsvSpinBox->setSectionValues(
1621 m_currentOpaqueColorRgb.hsv.toQList3());
1626 if (m_cielchD50SpinBox != ignoreWidget) {
1627 m_cielchD50SpinBox->setSectionValues(cielchD50.toQList3());
1632 if (m_oklchSpinBox != ignoreWidget) {
1633 m_oklchSpinBox->setSectionValues(oklch.toQList3());
1637 if (m_rgbLineEdit != ignoreWidget) {
1638 updateRgbHexButBlockSignals();
1642 if (m_lchLightnessSelector != ignoreWidget) {
1643 m_lchLightnessSelector->setValue(
1644 cielchD50.first /
static_cast<qreal
>(100));
1648 if (m_chromaHueDiagram != ignoreWidget) {
1649 m_chromaHueDiagram->setCurrentColorCielchD50(cielchD50);
1653 if (m_wheelColorPicker != ignoreWidget) {
1654 m_wheelColorPicker->setCurrentColorCielchD50(cielchD50);
1658 if (m_alphaGradientSlider != ignoreWidget) {
1659 GenericColor tempColor;
1660 tempColor.first = cielchD50.first;
1661 tempColor.second = cielchD50.second;
1662 tempColor.third = cielchD50.third;
1663 tempColor.fourth = 0;
1664 m_alphaGradientSlider->setFirstColorCieLchD50A(tempColor);
1665 tempColor.fourth = 1;
1666 m_alphaGradientSlider->setSecondColorCieLchD50A(tempColor);
1670 if (m_colorPatch != ignoreWidget) {
1675 if (q_pointer->currentColor() != oldQColor) {
1676 Q_EMIT q_pointer->currentColorChanged(q_pointer->currentColor());
1681 m_isColorChangeInProgress =
false;
1686void ColorDialogPrivate::readLightnessValue()
1688 if (m_isColorChangeInProgress) {
1693 cielchD50.first = m_lchLightnessSelector->value() * 100;
1694 cielchD50 = GenericColor(
1695 m_rgbColorSpace->reduceCielchD50ChromaToFitIntoGamut(cielchD50));
1696 setCurrentOpaqueColor(
1698 m_lchLightnessSelector);
1703void ColorDialogPrivate::readHslNumericValues()
1705 if (m_isColorChangeInProgress) {
1709 const auto temp = RgbColor::fromHsl(
1710 GenericColor(m_hslSpinBox->sectionValues()));
1711 setCurrentOpaqueColor(temp, m_hslSpinBox);
1716void ColorDialogPrivate::readHwbNumericValues()
1718 if (m_isColorChangeInProgress) {
1722 const auto temp = RgbColor::fromHwb(
1723 GenericColor(m_hwbSpinBox->sectionValues()));
1724 setCurrentOpaqueColor(temp, m_hwbSpinBox);
1729void ColorDialogPrivate::readHsvNumericValues()
1731 if (m_isColorChangeInProgress) {
1735 const auto temp = RgbColor::fromHsv(
1736 GenericColor(m_hsvSpinBox->sectionValues()));
1737 setCurrentOpaqueColor(temp, m_hsvSpinBox);
1742void ColorDialogPrivate::readRgbNumericValues()
1744 if (m_isColorChangeInProgress) {
1748 const auto temp = RgbColor::fromRgb255(
1749 GenericColor(m_rgbSpinBox->sectionValues()));
1750 setCurrentOpaqueColor(temp, m_rgbSpinBox);
1755void ColorDialogPrivate::readColorPatchValue()
1757 if (m_isColorChangeInProgress) {
1761 const QColor temp = m_colorPatch->color();
1766 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1767 setCurrentOpaqueColor(myRgbColor, m_colorPatch);
1772void ColorDialogPrivate::readSwatchBookBasicColorsValue()
1774 if (m_isColorChangeInProgress) {
1778 const QColor temp = m_swatchBookBasicColors->currentColor();
1783 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1784 setCurrentOpaqueColor(myRgbColor, m_swatchBookBasicColors);
1789void ColorDialogPrivate::readSwatchBookHistoryValue()
1791 if (m_isColorChangeInProgress) {
1795 const QColor temp = m_swatchBookHistory->currentColor();
1800 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1801 setCurrentOpaqueColor(myRgbColor, m_swatchBookHistory);
1808void ColorDialogPrivate::readSwatchBookCustomColorsValue()
1810 if (m_isColorChangeInProgress) {
1814 const QColor temp = m_swatchBookCustomColors->currentColor();
1819 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1820 setCurrentOpaqueColor(myRgbColor, m_swatchBookCustomColors);
1825void ColorDialogPrivate::readWheelColorPickerValues()
1827 if (m_isColorChangeInProgress) {
1831 const auto cielchD50 = GenericColor(m_wheelColorPicker->currentColorCielchD50());
1832 setCurrentOpaqueColor(
1834 m_wheelColorPicker);
1839void ColorDialogPrivate::readChromaHueDiagramValue()
1841 if (m_isColorChangeInProgress) {
1845 const auto cielchD50 = GenericColor(m_chromaHueDiagram->currentColorCielchD50());
1846 setCurrentOpaqueColor(
1848 m_chromaHueDiagram);
1853void ColorDialogPrivate::readRgbHexValues()
1855 if (m_isColorChangeInProgress) {
1859 QString temp = m_rgbLineEdit->text();
1860 if (!temp.
startsWith(QStringLiteral(u
"#"))) {
1861 temp = QStringLiteral(u
"#") + temp;
1866 const auto myRgbColor = RgbColor::fromRgbQColor(rgb);
1867 setCurrentOpaqueColor(myRgbColor, m_rgbLineEdit);
1869 m_isDirtyRgbLineEdit =
true;
1877void ColorDialogPrivate::updateRgbHexButBlockSignals()
1879 QSignalBlocker mySignalBlocker(m_rgbLineEdit);
1885 const auto &rgbFloat = m_currentOpaqueColorRgb.rgb255;
1897 const QString hexString =
1898 QStringLiteral(u
"#%1%2%3")
1899 .arg(qBound(0, qRound(rgbFloat.first), 255),
1903 .arg(qBound(0, qRound(rgbFloat.second), 255),
1907 .arg(qBound(0, qRound(rgbFloat.third), 255),
1912 m_rgbLineEdit->setText(hexString);
1920void ColorDialogPrivate::updateLchButBlockSignals()
1922 QSignalBlocker mySignalBlocker(m_cielchD50SpinBox);
1924 m_cielchD50SpinBox->setSectionValues(cielchD50.toQList3());
1925 m_cielchD50SpinBoxGamutAction->setVisible(
false);
1933void ColorDialogPrivate::updateOklchButBlockSignals()
1935 QSignalBlocker mySignalBlocker(m_oklchSpinBox);
1937 m_oklchSpinBox->setSectionValues(oklch.toQList3());
1938 m_oklchSpinBoxGamutAction->setVisible(
false);
1943void ColorDialogPrivate::readLchNumericValues()
1945 if (m_isColorChangeInProgress) {
1949 const GenericColor lchValues = GenericColor(m_cielchD50SpinBox->sectionValues());
1950 if (m_rgbColorSpace->isCielchD50InGamut(lchValues)) {
1951 m_cielchD50SpinBoxGamutAction->setVisible(
false);
1953 m_cielchD50SpinBoxGamutAction->setVisible(
true);
1955 const auto myColor = GenericColor(
1956 m_rgbColorSpace->reduceCielchD50ChromaToFitIntoGamut(lchValues));
1957 setCurrentOpaqueColor(
1960 m_cielchD50SpinBox);
1965void ColorDialogPrivate::readOklchNumericValues()
1967 if (m_isColorChangeInProgress) {
1975 GenericColor originalOklch;
1976 originalOklch.first = m_oklchSpinBox->sectionValues().value(0);
1977 originalOklch.second = m_oklchSpinBox->sectionValues().value(1);
1978 originalOklch.third = m_oklchSpinBox->sectionValues().value(2);
1979 if (m_rgbColorSpace->isOklchInGamut(originalOklch)) {
1980 m_oklchSpinBoxGamutAction->setVisible(
false);
1982 m_oklchSpinBoxGamutAction->setVisible(
true);
1984 const auto inGamutOklch = GenericColor(
1985 m_rgbColorSpace->reduceOklchChromaToFitIntoGamut(originalOklch));
1986 const auto inGamutColor =
1988 setCurrentOpaqueColor(inGamutColor,
1997void ColorDialogPrivate::initializeScreenColorPicker()
1999 auto screenPicker =
new ScreenColorPicker(q_pointer);
2000 if (!screenPicker->isAvailable()) {
2003 m_screenColorPickerButton =
new QToolButton;
2004 screenPicker->setParent(m_screenColorPickerButton);
2005 connect(m_screenColorPickerButton,
2009 [&, screenPicker]() {
2010 const auto myColor = q_pointer->currentColor();
2015 screenPicker->startPicking(
2016 fromFloatingToEightBit(myColor.redF()),
2017 fromFloatingToEightBit(myColor.greenF()),
2018 fromFloatingToEightBit(myColor.blueF()));
2021 &ScreenColorPicker::newColor,
2023 [
this](
const double red,
const double green,
const double blue,
const bool isSRgbGuaranteed) {
2024 Q_UNUSED(isSRgbGuaranteed)
2030 const GenericColor rgb255
2031 {qBound<double>(0, red * 255, 255),
2032 qBound<double>(0, green * 255, 255),
2033 qBound<double>(0, blue * 255, 255)};
2034 setCurrentOpaqueColor(RgbColor::fromRgb255(rgb255),
nullptr);
2041QWidget *ColorDialogPrivate::initializeNumericPage()
2045 m_rgbSpinBox =
new MultiSpinBox();
2046 QList<MultiSpinBoxSection> rgbSections;
2047 MultiSpinBoxSection mySection;
2048 mySection.setDecimals(decimals);
2049 mySection.setMinimum(0);
2050 mySection.setMaximum(255);
2052 mySection.setPrefix(QString());
2053 mySection.setSuffix(m_multispinboxSectionSeparator);
2054 rgbSections.
append(mySection);
2056 mySection.setPrefix(m_multispinboxSectionSeparator);
2057 mySection.setSuffix(m_multispinboxSectionSeparator);
2058 rgbSections.
append(mySection);
2060 mySection.setPrefix(m_multispinboxSectionSeparator);
2061 mySection.setSuffix(QString());
2062 rgbSections.
append(mySection);
2064 m_rgbSpinBox->setSectionConfigurations(rgbSections);
2069 m_rgbLineEdit =
new QLineEdit();
2070 m_rgbLineEdit->setMaxLength(7);
2071 QRegularExpression tempRegularExpression(
2072 QStringLiteral(u
"#?[0-9A-Fa-f]{0,6}"));
2073 QRegularExpressionValidator *validator =
new QRegularExpressionValidator(
2074 tempRegularExpression,
2076 m_rgbLineEdit->setValidator(validator);
2081 m_hslSpinBox =
new MultiSpinBox();
2082 QList<MultiSpinBoxSection> hslSections;
2083 MultiSpinBoxSection mySection;
2084 mySection.setDecimals(decimals);
2086 mySection.setMinimum(0);
2087 mySection.setMaximum(360);
2088 mySection.setWrapping(
true);
2089 hslSections.
append(mySection);
2091 mySection.setMinimum(0);
2092 mySection.setMaximum(100);
2093 mySection.setWrapping(
false);
2094 hslSections.
append(mySection);
2096 mySection.setMinimum(0);
2097 mySection.setMaximum(100);
2098 mySection.setWrapping(
false);
2099 hslSections.
append(mySection);
2101 m_hslSpinBox->setSectionConfigurations(hslSections);
2106 m_hwbSpinBox =
new MultiSpinBox();
2107 QList<MultiSpinBoxSection> hwbSections;
2108 MultiSpinBoxSection mySection;
2109 mySection.setDecimals(decimals);
2111 mySection.setMinimum(0);
2112 mySection.setMaximum(360);
2113 mySection.setWrapping(
true);
2114 hwbSections.
append(mySection);
2116 mySection.setMinimum(0);
2117 mySection.setMaximum(100);
2118 mySection.setWrapping(
false);
2119 hwbSections.
append(mySection);
2121 mySection.setMinimum(0);
2122 mySection.setMaximum(100);
2123 mySection.setWrapping(
false);
2124 hwbSections.
append(mySection);
2126 m_hwbSpinBox->setSectionConfigurations(hwbSections);
2131 m_hsvSpinBox =
new MultiSpinBox();
2132 QList<MultiSpinBoxSection> hsvSections;
2133 MultiSpinBoxSection mySection;
2134 mySection.setDecimals(decimals);
2136 mySection.setMinimum(0);
2137 mySection.setMaximum(360);
2138 mySection.setWrapping(
true);
2139 hsvSections.
append(mySection);
2141 mySection.setMinimum(0);
2142 mySection.setMaximum(100);
2143 mySection.setWrapping(
false);
2144 hsvSections.
append(mySection);
2146 mySection.setMinimum(0);
2147 mySection.setMaximum(100);
2148 mySection.setWrapping(
false);
2149 hsvSections.
append(mySection);
2151 m_hsvSpinBox->setSectionConfigurations(hsvSections);
2156 QFormLayout *tempRgbFormLayout =
new QFormLayout();
2157 m_rgbSpinBoxLabel =
new QLabel();
2158 m_rgbSpinBoxLabel->setBuddy(m_rgbSpinBox);
2159 tempRgbFormLayout->
addRow(m_rgbSpinBoxLabel, m_rgbSpinBox);
2160 m_rgbLineEditLabel =
new QLabel();
2161 m_rgbLineEditLabel->setBuddy(m_rgbLineEdit);
2162 tempRgbFormLayout->
addRow(m_rgbLineEditLabel, m_rgbLineEdit);
2163 m_hslSpinBoxLabel =
new QLabel();
2164 m_hslSpinBoxLabel->setBuddy(m_hslSpinBox);
2165 tempRgbFormLayout->
addRow(m_hslSpinBoxLabel, m_hslSpinBox);
2166 m_hwbSpinBoxLabel =
new QLabel();
2167 m_hwbSpinBoxLabel->setBuddy(m_hwbSpinBox);
2168 tempRgbFormLayout->
addRow(m_hwbSpinBoxLabel, m_hwbSpinBox);
2169 m_hsvSpinBoxLabel =
new QLabel();
2170 m_hsvSpinBoxLabel->setBuddy(m_hsvSpinBox);
2171 tempRgbFormLayout->
addRow(m_hsvSpinBoxLabel, m_hsvSpinBox);
2172 m_rgbGroupBox =
new QGroupBox();
2173 m_rgbGroupBox->setLayout(tempRgbFormLayout);
2179 const QFontMetricsF fontMetrics(m_rgbGroupBox->font());
2180 const auto elidedProfileName = fontMetrics.elidedText(
2181 m_rgbColorSpace->profileName(),
2182 Qt::TextElideMode::ElideRight,
2185 m_rgbGroupBox->setTitle(elidedProfileName);
2190 QList<MultiSpinBoxSection> cielchD50Sections;
2191 m_cielchD50SpinBox =
new MultiSpinBox;
2192 MultiSpinBoxSection mySection;
2193 mySection.setDecimals(decimals);
2195 mySection.setMinimum(0);
2196 mySection.setMaximum(100);
2197 mySection.setWrapping(
false);
2198 cielchD50Sections.
append(mySection);
2200 mySection.setMinimum(0);
2201 mySection.setMaximum(CielchD50Values::maximumChroma);
2202 mySection.setWrapping(
false);
2203 cielchD50Sections.
append(mySection);
2205 mySection.setMinimum(0);
2206 mySection.setMaximum(360);
2207 mySection.setWrapping(
true);
2208 cielchD50Sections.
append(mySection);
2210 m_cielchD50SpinBox->setSectionConfigurations(cielchD50Sections);
2215 QList<MultiSpinBoxSection> oklchSections;
2216 MultiSpinBoxSection mySection;
2217 m_oklchSpinBox =
new MultiSpinBox;
2219 mySection.setMinimum(0);
2220 mySection.setMaximum(1);
2221 mySection.setSingleStep(singleStepOklabc);
2222 mySection.setWrapping(
false);
2223 mySection.setDecimals(okdecimals);
2224 oklchSections.
append(mySection);
2226 mySection.setMinimum(0);
2227 mySection.setMaximum(OklchValues::maximumChroma);
2228 mySection.setSingleStep(singleStepOklabc);
2229 mySection.setWrapping(
false);
2230 mySection.setDecimals(okdecimals);
2231 oklchSections.
append(mySection);
2233 mySection.setMinimum(0);
2234 mySection.setMaximum(360);
2235 mySection.setSingleStep(1);
2236 mySection.setWrapping(
true);
2237 mySection.setDecimals(decimals);
2238 oklchSections.
append(mySection);
2240 m_oklchSpinBox->setSectionConfigurations(oklchSections);
2244 QWidget *tempWidget =
new QWidget;
2245 QVBoxLayout *tempMainLayout =
new QVBoxLayout;
2248 QFormLayout *cielabFormLayout =
new QFormLayout;
2249 m_oklchSpinBoxLabel =
new QLabel();
2250 m_oklchSpinBoxLabel->setBuddy(m_oklchSpinBox);
2251 cielabFormLayout->
addRow(m_oklchSpinBoxLabel, m_oklchSpinBox);
2252 m_cielchD50SpinBoxLabel =
new QLabel();
2253 m_cielchD50SpinBoxLabel->setBuddy(m_cielchD50SpinBox);
2254 cielabFormLayout->
addRow(m_cielchD50SpinBoxLabel, m_cielchD50SpinBox);
2255 tempMainLayout->
addLayout(cielabFormLayout);
2256 tempMainLayout->
addWidget(m_rgbGroupBox);
2267 return d_pointer->m_options;
2278 temp.setFlag(option, on);
2288 if (newOptions == d_pointer->m_options) {
2293 d_pointer->m_options = newOptions;
2296 d_pointer->m_options.setFlag(
2297 QColorDialog::ColorDialogOption::DontUseNativeDialog,
2301 const bool alphaVisibility = d_pointer->m_options.testFlag(
2302 QColorDialog::ColorDialogOption::ShowAlphaChannel);
2303 d_pointer->m_alphaLabel->setVisible(alphaVisibility);
2304 d_pointer->m_alphaGradientSlider->setVisible(alphaVisibility);
2305 d_pointer->m_alphaSpinBox->setVisible(alphaVisibility);
2308 d_pointer->m_buttonBox->setVisible(!d_pointer->m_options.testFlag(
2309 QColorDialog::ColorDialogOption::NoButtons));
2324 return d_pointer->m_options.testFlag(option);
2396 return d_pointer->m_selectedColor;
2412 d_pointer->m_selectedColor =
QColor();
2413 d_pointer->applyLayoutDimensions();
2421 d_pointer->m_buttonOK->setDefault(
true);
2430 if (
result == QDialog::DialogCode::Accepted) {
2432 auto history = d_pointer->m_settings.history.value();
2433 const auto maxHistoryLenght = std::max(d_pointer->historySwatchCount,
2436 history.removeAll(d_pointer->m_selectedColor);
2438 history.prepend(d_pointer->m_selectedColor);
2440 while (history.count() > maxHistoryLenght) {
2441 history.removeLast();
2443 d_pointer->m_settings.history.setValue(history);
2446 d_pointer->m_selectedColor =
QColor();
2449 if (d_pointer->m_receiverToBeDisconnected) {
2458 d_pointer->m_receiverToBeDisconnected,
2459 d_pointer->m_memberToBeDisconnected.constData()
2461 d_pointer->m_receiverToBeDisconnected =
nullptr;
2469 return d_pointer->m_layoutDimensions;
2476 if (newLayoutDimensions == d_pointer->m_layoutDimensions) {
2479 d_pointer->m_layoutDimensions = newLayoutDimensions;
2480 d_pointer->applyLayoutDimensions();
2489void ColorDialogPrivate::applyLayoutDimensions()
2494 constexpr auto screenSizeDependent =
2496 int effectivelyAvailableScreenWidth;
2497 int widthThreeshold;
2498 switch (m_layoutDimensions) {
2500 m_layoutDimensionsEffective = collapsed;
2503 m_layoutDimensionsEffective = expanded;
2505 case screenSizeDependent:
2512 effectivelyAvailableScreenWidth = qRound(
2519 widthThreeshold = qMax(
2520 m_wheelColorPicker->sizeHint().width(),
2521 m_lightnessFirstWrapperWidget->sizeHint().width());
2523 widthThreeshold += m_numericalWidget->sizeHint().width();
2525 widthThreeshold = qRound(widthThreeshold * 1.2);
2528 if (effectivelyAvailableScreenWidth < widthThreeshold) {
2529 m_layoutDimensionsEffective = collapsed;
2531 m_layoutDimensionsEffective = expanded;
2540 if (m_layoutDimensionsEffective == collapsed) {
2541 if (m_selectorLayout->indexOf(m_numericalWidget) >= 0) {
2544 const bool oldUpdatesEnabled = m_tabWidget->updatesEnabled();
2545 m_tabWidget->setUpdatesEnabled(
false);
2549 m_tabWidget->addTab(m_numericalWidget, QString());
2550 m_tabWidget->setUpdatesEnabled(oldUpdatesEnabled);
2556 q_pointer->adjustSize();
2559 if (m_selectorLayout->indexOf(m_numericalWidget) < 0) {
2562 m_selectorLayout->addWidget(m_numericalWidget);
2565 m_numericalWidget->show();
2567 q_pointer->adjustSize();
2581 const auto type =
event->type();
2590 d_pointer->retranslateUi();
2595 &eventForSwatchBookBasicColors);
2600 &eventForSwatchBookHistory);
2605 &eventForSwatchBookCustomColors);
2615 &eventForButtonCancel);
2620 d_pointer->reloadIcons();
2638 if (!d_pointer->everShown) {
2640 const bool exp = d_pointer->m_layoutDimensionsEffective == expValue;
2641 const auto tabString = exp
2642 ? d_pointer->m_settings.tabExpanded.value()
2643 : d_pointer->m_settings.tab.value();
2644 const auto key = d_pointer->m_tabTable.key(tabString,
nullptr);
2645 if (key !=
nullptr) {
2646 d_pointer->m_tabWidget->setCurrentWidget(*key);
2653 d_pointer->saveCurrentTab();
2655 switch (d_pointer->m_settings.swatchBookPage.value()) {
2656 case PerceptualSettings::SwatchBookPage::BasicColors:
2658 d_pointer->m_settings.swatchBookPage.setValue(
2659 PerceptualSettings::SwatchBookPage::BasicColors);
2660 d_pointer->m_swatchBookSelector->setCurrentIndex(0);
2661 d_pointer->m_swatchBookStack->setCurrentIndex(0);
2663 case PerceptualSettings::SwatchBookPage::History:
2664 d_pointer->m_settings.swatchBookPage.setValue(
2665 PerceptualSettings::SwatchBookPage::History);
2666 d_pointer->m_swatchBookSelector->setCurrentIndex(1);
2667 d_pointer->m_swatchBookStack->setCurrentIndex(1);
2669 case PerceptualSettings::SwatchBookPage::CustomColors:
2670 d_pointer->m_settings.swatchBookPage.setValue(
2671 PerceptualSettings::SwatchBookPage::History);
2672 d_pointer->m_swatchBookSelector->setCurrentIndex(2);
2673 d_pointer->m_swatchBookStack->setCurrentIndex(2);
2677 d_pointer->everShown =
true;
2683void ColorDialogPrivate::saveCurrentTab()
2685 const auto currentIndex = m_tabWidget->currentIndex();
2686 QWidget const *
const widget = m_tabWidget->widget(currentIndex);
2687 const auto keyList = m_tabTable.
keys();
2688 auto it = std::find_if(
2691 [widget](
const auto &key) {
2692 return ((*key) == widget);
2695 if (it != keyList.end()) {
2696 const auto tabString = m_tabTable.
value(*it);
2698 if (m_layoutDimensionsEffective == expValue) {
2699 m_settings.tabExpanded.setValue(tabString);
2701 m_settings.tab.setValue(tabString);
2708void ColorDialogPrivate::loadHistoryFromSettingsToSwatchBook()
2710 const Swatches historyArray(historyHSwatchCount,
2711 historyVSwatchCount,
2712 m_settings.history.value());
2713 m_swatchBookHistory->setSwatchGrid(historyArray);
2718void ColorDialogPrivate::loadCustomColorsFromSettingsToSwatchBook()
2720 const Swatches customColorsArray(customColorsHSwatchCount,
2721 customColorsVSwatchCount,
2722 m_settings.customColors.value());
2723 m_swatchBookCustomColors->setSwatchGrid(customColorsArray);
void currentColorCielchD50Changed(const PerceptualColor::GenericColor &newCurrentColorCielchD50)
Notify signal for property currentColorCielchD50.
A perceptually uniform color picker dialog.
void colorSelected(const QColor &color)
This signal is emitted just after the user has clicked OK to select a color to use.
static QColor getColor(const QColor &initial=Qt::white, QWidget *parent=nullptr, const QString &title=QString(), ColorDialogOptions options=ColorDialogOptions())
Pops up a modal color dialog, lets the user choose a color, and returns that color.
virtual void showEvent(QShowEvent *event) override
Handle show events.
virtual void setVisible(bool visible) override
Setter for property visible
Q_INVOKABLE void open(QObject *receiver, const char *member)
Opens the dialog and connects its colorSelected() signal to the slot specified by receiver and member...
QColorDialog::ColorDialogOptions ColorDialogOptions
Local alias for QColorDialog::ColorDialogOptions.
Q_INVOKABLE ColorDialog(QWidget *parent=nullptr)
Constructor.
ColorDialogOptions options
Various options that affect the look and feel of the dialog.
Q_INVOKABLE bool testOption(PerceptualColor::ColorDialog::ColorDialogOption option) const
Getter for KConfig Entry Options.
Q_INVOKABLE void setOption(PerceptualColor::ColorDialog::ColorDialogOption option, bool on=true)
Setter for KConfig Entry Options.
QColor currentColor
Currently selected color in the dialog.
void setCurrentColor(const QColor &color)
Setter for currentColor property.
virtual void done(int result) override
Various updates when closing the dialog.
virtual ~ColorDialog() noexcept override
Destructor.
void optionsChanged(const PerceptualColor::ColorDialog::ColorDialogOptions newOptions)
Notify signal for property KConfig Entry Options.
void setOptions(PerceptualColor::ColorDialog::ColorDialogOptions newOptions)
Setter for KConfig Entry Options.
void setLayoutDimensions(const PerceptualColor::ColorDialog::DialogLayoutDimensions newLayoutDimensions)
Setter for property layoutDimensions.
DialogLayoutDimensions
Layout dimensions.
@ Expanded
Use the large, “expanded” layout of this dialog.
@ Collapsed
Use the small, “collapsed“ layout of this dialog.
@ ScreenSizeDependent
Decide automatically between collapsed and expanded layout: collapsed is used on small screens,...
virtual void changeEvent(QEvent *event) override
Handle state changes.
void layoutDimensionsChanged(const PerceptualColor::ColorDialog::DialogLayoutDimensions newLayoutDimensions)
Notify signal for property layoutDimensions.
Q_INVOKABLE QColor selectedColor() const
The color that was actually selected by the user.
QColorDialog::ColorDialogOption ColorDialogOption
Local alias for QColorDialog::ColorDialogOption.
DialogLayoutDimensions layoutDimensions
Layout dimensions.
void colorChanged(const QColor &color)
Notify signal for property color.
void valueChanged(const qreal newValue)
Signal for value property.
void sectionValuesChanged(const QList< double > &newSectionValues)
Notify signal for property sectionValues.
static QSharedPointer< PerceptualColor::RgbColorSpace > createSrgb()
Create an sRGB color space object.
void currentColorCielchD50Changed(const PerceptualColor::GenericColor &newCurrentColorCielchD50)
Notify signal for property currentColorCielchD50.
QString name(StandardAction id)
The namespace of this library.
Array2D< QColor > Swatches
Swatches organized in a grid.
Swatches wcsBasicColors(const QSharedPointer< PerceptualColor::RgbColorSpace > &colorSpace)
Swatch grid derived from the basic colors as by WCS (World color survey).
@ OklchD65
The absolute Oklch color space, which by definition always and exclusively uses a D65 illuminant.
@ CielchD50
The absolute Cielch color space using a D50 illuminant.
void triggered(bool checked)
void addLayout(QLayout *layout, int stretch)
void addStretch(int stretch)
void setNamedColor(QLatin1StringView name)
float alphaF() const const
QColor fromRgbF(float r, float g, float b, float a)
bool isValid() const const
QRgba64 rgba64() const const
void setAlphaF(float alpha)
QColor toRgb() const const
typedef ColorDialogOptions
void currentIndexChanged(int index)
QCoreApplication * instance()
bool sendEvent(QObject *receiver, QEvent *event)
bool isNull() const const
QDialog(QWidget *parent, Qt::WindowFlags f)
virtual void setVisible(bool visible) override
virtual void showEvent(QShowEvent *event) override
void valueChanged(double d)
QList< Key > keys() const const
T value(const Key &key) const const
QKeySequence mnemonic(const QString &text)
void textChanged(const QString &text)
void append(QList< T > &&value)
qsizetype count() const const
bool isEmpty() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QObject * parent() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
void activatedAmbiguously()
QString arg(Args &&... args) const const
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString toHtmlEscaped() const const
QString join(QChar separator) const const
void colorSchemeChanged(Qt::ColorScheme colorScheme)
WindowContextHelpButtonHint
QString toString() const const