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 QString percentageInSpinbox =
tr(
"%1%");
223 const QString arcDegreeInSpinbox =
tr(
"%1°");
225 QStringList profileInfo;
231 profileInfo.
append(tableRow.arg(
tr(
"Name:"), name));
234 const QString maximumCielchD50Chroma =
235 tr(
"%L1 (estimated)")
236 .
arg(m_rgbColorSpace->profileMaximumCielchD50Chroma(),
243 tableRow.arg(
tr(
"Maximum CIELCh-D50 chroma:"), maximumCielchD50Chroma));
245 const QString maximumOklchChroma =
246 tr(
"%L1 (estimated)")
247 .
arg(m_rgbColorSpace->profileMaximumOklchChroma(),
254 tableRow.arg(
tr(
"Maximum Oklch chroma:"), maximumOklchChroma));
255 QString profileClass;
256 switch (m_rgbColorSpace->profileClass()) {
257 case cmsSigDisplayClass:
259 profileClass =
tr(
"Display profile");
261 case cmsSigAbstractClass:
266 case cmsSigColorSpaceClass:
267 case cmsSigInputClass:
268 case cmsSigLinkClass:
269 case cmsSigNamedColorClass:
270 case cmsSigOutputClass:
278 tableRow.arg(
tr(
"Profile class:"), profileClass));
280 const QString colorModel =
281 translateColorModel(m_rgbColorSpace->profileColorModel());
287 profileInfo.
append(tableRow.arg(
tr(
"Color model:"), colorModel));
289 const QString manufacturer =
290 m_rgbColorSpace->profileManufacturer().toHtmlEscaped();
296 profileInfo.
append(tableRow.arg(
tr(
"Manufacturer:"), manufacturer));
298 const QString model =
299 m_rgbColorSpace->profileModel().toHtmlEscaped();
305 profileInfo.
append(tableRow.arg(
tr(
"Device model:"), (model)));
307 const QDateTime creationDateTime =
308 m_rgbColorSpace->profileCreationDateTime();
309 if (!creationDateTime.
isNull()) {
310 const auto creationDateTimeString = QLocale().toString(
319 tableRow.arg(
tr(
"Created:"), (creationDateTimeString)));
321 const QVersionNumber iccVersion = m_rgbColorSpace->profileIccVersion();
326 tableRow.arg(
tr(
"ICC format:"), (iccVersion.
toString())));
327 const bool hasMatrixShaper =
328 m_rgbColorSpace->profileHasMatrixShaper();
330 m_rgbColorSpace->profileHasClut();
331 if (hasMatrixShaper || hasClut) {
332 const QString matrixShaperString = tableRow.arg(
337 tr(
"Implementation:"));
338 if (hasMatrixShaper && hasClut) {
344 matrixShaperString.
arg(
tr(
"Matrices and color lookup tables")));
345 }
else if (hasMatrixShaper) {
350 profileInfo.
append(matrixShaperString.
arg(
tr(
"Matrices")));
351 }
else if (hasClut) {
357 matrixShaperString.
arg(
tr(
"Color lookup tables")));
360 const QString pcsColorModelText =
361 translateColorModel(m_rgbColorSpace->profilePcsColorModel());
362 if (!pcsColorModelText.
isEmpty()) {
368 tableRow.arg(
tr(
"PCS color model:"), pcsColorModelText));
370 const QString copyright = m_rgbColorSpace->profileCopyright();
375 profileInfo.
append(tableRow.arg(
tr(
"Copyright:"), copyright));
377 const qint64 fileSize =
378 m_rgbColorSpace->profileFileSize();
383 profileInfo.
append(tableRow.arg(
tr(
"File size:"),
384 QLocale().formattedDataSize(fileSize)));
386 const QString fileName =
387 m_rgbColorSpace->profileAbsoluteFilePath();
391 profileInfo.
append(tableRow.arg(
tr(
"File name:"), fileName));
394 m_rgbGroupBox->setToolTip(QString());
396 const QString tableString = QStringLiteral(
398 "<table border=\"0\" cellpadding=\"2\" cellspacing=\"0\">"
401 m_rgbGroupBox->setToolTip(richTextMarker
407 tr(
"Color space information"),
408 profileInfo.
join(QString())));
413 m_cielchD50SpinBoxLabel->setText(
tr(
"&CIELCH D50:"));
417 m_oklchSpinBoxLabel->setText(
tr(
"O&klch:"));
420 m_rgbSpinBoxLabel->setText(
tr(
"&RGB:"));
423 m_rgbLineEditLabel->setText(
tr(
"He&x:"));
425 const int swatchBookIndex = m_tabWidget->indexOf(m_swatchBookWrapperWidget);
426 if (swatchBookIndex >= 0) {
429 const auto mnemonic =
tr(
"&Swatch book");
430 m_tabWidget->setTabToolTip(
432 richTextMarker + fromMnemonicToRichText(mnemonic));
436 const int hueFirstIndex = m_tabWidget->indexOf(m_hueFirstWrapperWidget);
437 if (hueFirstIndex >= 0) {
441 const auto mnemonic =
tr(
"&Hue-based");
442 m_tabWidget->setTabToolTip(
444 richTextMarker + fromMnemonicToRichText(mnemonic));
447 const int lightnessFirstIndex =
448 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget);
449 if (lightnessFirstIndex >= 0) {
455 const auto mnemonic =
tr(
"&Lightness-based");
456 m_tabWidget->setTabToolTip(
458 richTextMarker + fromMnemonicToRichText(mnemonic));
461 const int numericIndex =
462 m_tabWidget->indexOf(m_numericalWidget);
463 if (numericIndex >= 0) {
467 const auto mnemonic =
tr(
"&Numeric");
468 m_tabWidget->setTabToolTip(
470 richTextMarker + fromMnemonicToRichText(mnemonic));
475 m_hslSpinBoxLabel->setText(
tr(
"HS&L:"));
479 m_hsvSpinBoxLabel->setText(
tr(
"HS&V/HSB:"));
482 m_hwbSpinBoxLabel->setText(
tr(
"H&WB:"));
485 m_buttonOK->setText(
tr(
"&OK"));
488 m_buttonCancel->setText(
tr(
"&Cancel"));
490 m_rgbSpinBox->setToolTip(
492 +
tr(
"<p>Red: 0–255</p>"
493 "<p>Green: 0–255</p>"
494 "<p>Blue: 0–255</p>"));
497 m_rgbLineEdit->setToolTip(
499 +
tr(
"<p>Hexadecimal color code, as used in HTML: #RRGGBB</p>"
500 "<p>RR: two-digit code for red: 00–FF</p>"
501 "<p>GG: two-digit code for green: 00–FF</p>"
502 "<p>BB: two-digit code for blue: 00–FF</p>"));
511 m_hslSpinBox->setToolTip(richTextMarker
512 +
tr(
"<p>Hue: 0°–360°</p>"
513 "<p>HSL-Saturation: 0%–100%</p>"
514 "<p>Lightness: 0%–100%</p>"));
525 m_hwbSpinBox->setToolTip(richTextMarker
526 +
tr(
"<p>Hue: 0°–360°</p>"
527 "<p>Whiteness: 0%–100%</p>"
528 "<p>Blackness: 0%–100%</p>"));
538 m_hsvSpinBox->setToolTip(richTextMarker
539 +
tr(
"<p>Hue: 0°–360°</p>"
540 "<p>HSV/HSB-Saturation: 0%–100%</p>"
541 "<p>Brightness/Value: 0%–100%</p>"));
543 const auto myPercentagePrefixSuffix = getPrefixSuffix(percentageInSpinbox);
544 m_alphaSpinBox->setPrefix(myPercentagePrefixSuffix.first);
545 m_alphaSpinBox->setSuffix(myPercentagePrefixSuffix.second);
550 m_lchLightnessSelector->setAccessibleName(
tr(
"Lightness"));
554 m_cielchD50SpinBox->setToolTip(richTextMarker
555 +
tr(
"<p>Lightness: 0%–100%</p>"
556 "<p>Chroma: 0–%L1</p>"
557 "<p>Hue: 0°–360°</p>")
558 .arg(CielchD50Values::maximumChroma));
560 constexpr double maxOklchChroma = OklchValues::maximumChroma;
563 m_oklchSpinBox->setToolTip(richTextMarker
564 +
tr(
"<p>Lightness: %L1–%L2</p>"
565 "<p>Chroma: %L3–%L4</p>"
566 "<p>Hue: 0°–360°</p>"
567 "<p>Whitepoint: D65</p>")
568 .arg(0., 0,
'f', okdecimals)
569 .arg(1., 0,
'f', okdecimals)
570 .arg(0., 0,
'f', okdecimals)
571 .arg(maxOklchChroma, 0,
'f', okdecimals));
577 const QString opacityLabel =
tr(
"Op&acity:");
578 m_alphaGradientSlider->setAccessibleName(opacityLabel);
579 m_alphaLabel->setText(opacityLabel);
582 QList<MultiSpinBoxSection> hslSections =
583 m_hslSpinBox->sectionConfigurations();
584 if (hslSections.
count() != 3) {
586 <<
"Expected 3 sections in HSV MultiSpinBox, but got"
587 << hslSections.
count()
588 <<
"instead. This is a bug in libperceptualcolor.";
590 hslSections[0].setFormatString(
591 arcDegreeInSpinbox + m_multispinboxSectionSeparator);
592 hslSections[1].setFormatString(
593 m_multispinboxSectionSeparator + percentageInSpinbox
594 + m_multispinboxSectionSeparator);
595 hslSections[2].setFormatString(
596 m_multispinboxSectionSeparator + percentageInSpinbox);
597 m_hslSpinBox->setSectionConfigurations(hslSections);
601 QList<MultiSpinBoxSection> hwbSections =
602 m_hwbSpinBox->sectionConfigurations();
603 if (hwbSections.
count() != 3) {
605 <<
"Expected 3 sections in HSV MultiSpinBox, but got"
606 << hwbSections.
count()
607 <<
"instead. This is a bug in libperceptualcolor.";
609 hwbSections[0].setFormatString(
610 arcDegreeInSpinbox + m_multispinboxSectionSeparator);
611 hwbSections[1].setFormatString(
612 m_multispinboxSectionSeparator + percentageInSpinbox
613 + m_multispinboxSectionSeparator);
614 hwbSections[2].setFormatString(
615 m_multispinboxSectionSeparator + percentageInSpinbox);
616 m_hwbSpinBox->setSectionConfigurations(hwbSections);
620 QList<MultiSpinBoxSection> hsvSections =
621 m_hsvSpinBox->sectionConfigurations();
622 if (hsvSections.
count() != 3) {
624 <<
"Expected 3 sections in HSV MultiSpinBox, but got"
625 << hsvSections.
count()
626 <<
"instead. This is a bug in libperceptualcolor.";
628 hsvSections[0].setFormatString(
629 arcDegreeInSpinbox + m_multispinboxSectionSeparator);
630 hsvSections[1].setFormatString(
631 m_multispinboxSectionSeparator
632 + percentageInSpinbox
633 + m_multispinboxSectionSeparator);
634 hsvSections[2].setFormatString(
635 m_multispinboxSectionSeparator + percentageInSpinbox);
636 m_hsvSpinBox->setSectionConfigurations(hsvSections);
640 QList<MultiSpinBoxSection> cielchD50Sections =
641 m_cielchD50SpinBox->sectionConfigurations();
642 if (cielchD50Sections.
count() != 3) {
644 <<
"Expected 3 sections in CIELCH-D50 MultiSpinBox, but got"
645 << cielchD50Sections.
count()
646 <<
"instead. This is a bug in libperceptualcolor.";
648 cielchD50Sections[0].setFormatString(
649 percentageInSpinbox + m_multispinboxSectionSeparator);
650 cielchD50Sections[1].setFormatString(
651 m_multispinboxSectionSeparator
652 + QStringLiteral(
"%1")
653 + m_multispinboxSectionSeparator);
654 cielchD50Sections[2].setFormatString(
655 m_multispinboxSectionSeparator + arcDegreeInSpinbox);
656 m_cielchD50SpinBox->setSectionConfigurations(cielchD50Sections);
660 QList<MultiSpinBoxSection> oklchSections =
661 m_oklchSpinBox->sectionConfigurations();
662 if (oklchSections.
count() != 3) {
664 <<
"Expected 3 sections in Oklch MultiSpinBox, but got"
665 << oklchSections.
count()
666 <<
"instead. This is a bug in libperceptualcolor.";
668 oklchSections[0].setFormatString(
669 QStringLiteral(
"%1") + m_multispinboxSectionSeparator);
670 oklchSections[1].setFormatString(
671 m_multispinboxSectionSeparator + QStringLiteral(
"%1")
672 + m_multispinboxSectionSeparator);
673 oklchSections[2].setFormatString(
674 m_multispinboxSectionSeparator + arcDegreeInSpinbox);
675 m_oklchSpinBox->setSectionConfigurations(oklchSections);
678 if (m_screenColorPickerButton) {
683 const auto mnemonic =
tr(
"&Pick screen color");
684 m_screenColorPickerButton->setToolTip(
685 richTextMarker + fromMnemonicToRichText(mnemonic));
686 m_screenColorPickerButton->setShortcut(
695 const auto gamutMnemonic =
696 tr(
"Click to snap to nearest in-&gamut color");
697 const QString gamutTooltip =
698 richTextMarker + fromMnemonicToRichText(gamutMnemonic);
700 m_cielchD50SpinBoxGamutAction->setToolTip(gamutTooltip);
701 m_cielchD50SpinBoxGamutAction->setShortcut(gamutShortcut);
702 m_oklchSpinBoxGamutAction->setToolTip(gamutTooltip);
703 m_oklchSpinBoxGamutAction->setShortcut(gamutShortcut);
708 m_swatchBookSelector->setItemText(0,
tr(
"Basic colors"));
713 m_swatchBookSelector->setItemText(1,
tr(
"History"));
718 m_swatchBookSelector->setItemText(2,
tr(
"Custom Colors"));
738void ColorDialogPrivate::reloadIcons()
740 m_currentIconThemeType = guessColorSchemeTypeFromWidget(q_pointer);
742 static const QStringList swatchBookIcons
743 {QStringLiteral(
"paint-swatch"),
746 QStringLiteral(
"palette"),
747 QStringLiteral(
"palette-symbolic")};
748 const int swatchBookIndex =
749 m_tabWidget->indexOf(m_swatchBookWrapperWidget);
750 if (swatchBookIndex >= 0) {
751 m_tabWidget->setTabIcon(swatchBookIndex,
752 qIconFromTheme(swatchBookIcons,
753 QStringLiteral(
"color-swatch"),
754 m_currentIconThemeType));
757 static const QStringList hueFirstIcons
759 QStringLiteral(
"color-mode-hue-shift-positive"),
761 const int hueFirstIndex =
762 m_tabWidget->indexOf(m_hueFirstWrapperWidget);
763 if (hueFirstIndex >= 0) {
764 m_tabWidget->setTabIcon(hueFirstIndex,
765 qIconFromTheme(hueFirstIcons,
766 QStringLiteral(
"steering-wheel"),
767 m_currentIconThemeType));
770 static const QStringList lightnessFirstIcons
772 QStringLiteral(
"brightness-high"),
774 const int lightnessFirstIndex =
775 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget);
776 if (lightnessFirstIndex >= 0) {
777 m_tabWidget->setTabIcon(lightnessFirstIndex,
778 qIconFromTheme(lightnessFirstIcons,
779 QStringLiteral(
"brightness-2"),
780 m_currentIconThemeType));
783 static const QStringList numericIcons
785 QStringLiteral(
"black_sum"),
787 const int numericIndex =
788 m_tabWidget->indexOf(m_numericalWidget);
789 if (numericIndex >= 0) {
790 m_tabWidget->setTabIcon(numericIndex,
791 qIconFromTheme(numericIcons,
792 QStringLiteral(
"123"),
793 m_currentIconThemeType));
797 static const QStringList gamutIconNames
799 QStringLiteral(
"data-warning"),
800 QStringLiteral(
"dialog-warning-symbolic"),
802 const QIcon gamutIcon = qIconFromTheme(gamutIconNames,
803 QStringLiteral(
"eye-exclamation"),
804 m_currentIconThemeType);
805 m_cielchD50SpinBoxGamutAction->setIcon(gamutIcon);
806 m_oklchSpinBoxGamutAction->setIcon(gamutIcon);
808 static const QStringList candidates
810 QStringLiteral(
"color-picker"),
811 QStringLiteral(
"gtk-color-picker"),
812 QStringLiteral(
"tool_color_picker"),
814 if (!m_screenColorPickerButton.isNull()) {
815 m_screenColorPickerButton->setIcon(
816 qIconFromTheme(candidates,
817 QStringLiteral(
"color-picker"),
818 m_currentIconThemeType));
834void ColorDialogPrivate::initialize(
const QSharedPointer<PerceptualColor::RgbColorSpace> &colorSpace)
843 m_rgbColorSpace = colorSpace;
845 m_wcsBasicDefaultColor = m_wcsBasicColors.value(4, 2);
848 m_swatchBookBasicColors =
new SwatchBook(m_rgbColorSpace,
850 Qt::Orientation::Horizontal);
851 auto swatchBookBasicColorsLayout =
new QGridLayout();
852 auto swatchBookBasicColorsLayoutWidget =
new QWidget();
853 swatchBookBasicColorsLayoutWidget->setLayout(swatchBookBasicColorsLayout);
854 swatchBookBasicColorsLayoutWidget->setContentsMargins(0, 0, 0, 0);
855 swatchBookBasicColorsLayout->setContentsMargins(0, 0, 0, 0);
856 swatchBookBasicColorsLayout->addWidget(m_swatchBookBasicColors);
857 swatchBookBasicColorsLayout->setRowStretch(1, 1);
858 swatchBookBasicColorsLayout->setColumnStretch(1, 1);
859 m_swatchBookHistory =
new SwatchBook(m_rgbColorSpace,
861 Qt::Orientation::Vertical);
862 auto swatchBookHistoryLayout =
new QGridLayout();
863 auto swatchBookHistoryLayoutWidget =
new QWidget();
864 swatchBookHistoryLayoutWidget->setLayout(swatchBookHistoryLayout);
865 swatchBookHistoryLayoutWidget->setContentsMargins(0, 0, 0, 0);
866 swatchBookHistoryLayout->setContentsMargins(0, 0, 0, 0);
867 swatchBookHistoryLayout->addWidget(m_swatchBookHistory);
868 swatchBookHistoryLayout->setRowStretch(1, 1);
869 swatchBookHistoryLayout->setColumnStretch(1, 1);
870 loadHistoryFromSettingsToSwatchBook();
871 m_swatchBookCustomColors =
new SwatchBook(
874 Qt::Orientation::Horizontal | Qt::Orientation::Vertical);
875 m_swatchBookCustomColors->setEditable(
true);
876 auto swatchBookCustomColorsLayout =
new QGridLayout();
877 auto swatchBookCustomColorsLayoutWidget =
new QWidget();
878 swatchBookCustomColorsLayoutWidget->setLayout(swatchBookCustomColorsLayout);
879 swatchBookCustomColorsLayoutWidget->setContentsMargins(0, 0, 0, 0);
880 swatchBookCustomColorsLayout->setContentsMargins(0, 0, 0, 0);
881 swatchBookCustomColorsLayout->addWidget(m_swatchBookCustomColors);
882 swatchBookCustomColorsLayout->setRowStretch(1, 1);
883 swatchBookCustomColorsLayout->setColumnStretch(1, 1);
884 loadCustomColorsFromSettingsToSwatchBook();
885 connect(m_swatchBookCustomColors,
886 &SwatchBook::swatchGridChanged,
888 [
this](
const Swatches &newSwatches) {
889 m_settings.customColors.setValue(newSwatches.toQList());
891 m_swatchBookStack =
new QStackedLayout();
892 m_swatchBookStack->addWidget(swatchBookBasicColorsLayoutWidget);
893 m_swatchBookStack->addWidget(swatchBookHistoryLayoutWidget);
894 m_swatchBookStack->addWidget(swatchBookCustomColorsLayoutWidget);
895 QHBoxLayout *swatchBookInnerLayout =
new QHBoxLayout();
896 swatchBookInnerLayout->
addLayout(m_swatchBookStack);
898 QVBoxLayout *swatchBookOuterLayout =
new QVBoxLayout();
899 m_swatchBookSelector =
new QComboBox();
900 m_swatchBookSelector->addItem(QString());
901 m_swatchBookSelector->addItem(QString());
902 m_swatchBookSelector->addItem(QString());
909 m_swatchBookStack->setCurrentIndex(0);
910 m_settings.swatchBookPage.setValue(
911 PerceptualSettings::SwatchBookPage::BasicColors);
914 m_swatchBookStack->setCurrentIndex(1);
915 m_settings.swatchBookPage.setValue(
916 PerceptualSettings::SwatchBookPage::History);
919 m_swatchBookStack->setCurrentIndex(2);
920 m_settings.swatchBookPage.setValue(
921 PerceptualSettings::SwatchBookPage::CustomColors);
925 swatchBookOuterLayout->
addWidget(m_swatchBookSelector);
926 swatchBookOuterLayout->
addLayout(swatchBookInnerLayout);
928 m_swatchBookWrapperWidget =
new QWidget();
929 m_swatchBookWrapperWidget->setLayout(swatchBookOuterLayout);
931 &Setting<PerceptualSettings::ColorList>::valueChanged,
933 &ColorDialogPrivate::loadHistoryFromSettingsToSwatchBook);
934 connect(&m_settings.customColors,
935 &Setting<PerceptualSettings::ColorList>::valueChanged,
937 &ColorDialogPrivate::loadCustomColorsFromSettingsToSwatchBook);
938 m_wheelColorPicker =
new WheelColorPicker(m_rgbColorSpace);
939 m_hueFirstWrapperWidget =
new QWidget;
940 QHBoxLayout *tempHueFirstLayout =
new QHBoxLayout;
941 tempHueFirstLayout->
addWidget(m_wheelColorPicker);
942 m_hueFirstWrapperWidget->setLayout(tempHueFirstLayout);
944 m_lchLightnessSelector =
new GradientSlider(m_rgbColorSpace);
945 GenericColor blackCielchD50;
946 blackCielchD50.first = 0;
947 blackCielchD50.second = 0;
948 blackCielchD50.third = 0;
949 blackCielchD50.fourth = 1;
950 GenericColor whiteCielchD50;
951 whiteCielchD50.first = 100;
952 whiteCielchD50.second = 0;
953 whiteCielchD50.third = 0;
954 whiteCielchD50.fourth = 1;
955 m_lchLightnessSelector->setColors(blackCielchD50, whiteCielchD50);
956 m_chromaHueDiagram =
new ChromaHueDiagram(m_rgbColorSpace);
957 QHBoxLayout *tempLightnesFirstLayout =
new QHBoxLayout();
958 tempLightnesFirstLayout->
addWidget(m_lchLightnessSelector);
959 tempLightnesFirstLayout->
addWidget(m_chromaHueDiagram);
960 m_lightnessFirstWrapperWidget =
new QWidget();
961 m_lightnessFirstWrapperWidget->setLayout(tempLightnesFirstLayout);
963 initializeScreenColorPicker();
965 m_tabWidget =
new QTabWidget;
977 m_tabWidget->addTab(m_swatchBookWrapperWidget, QString());
978 m_swatchBookTabShortcut =
new QShortcut(q_pointer);
979 connect(m_swatchBookTabShortcut,
983 m_tabWidget->setCurrentIndex(
984 m_tabWidget->indexOf(m_swatchBookWrapperWidget));
986 connect(m_swatchBookTabShortcut,
990 m_tabWidget->setCurrentIndex(
991 m_tabWidget->indexOf(m_swatchBookWrapperWidget));
994 m_tabWidget->addTab(m_hueFirstWrapperWidget, QString());
995 m_hueFirstTabShortcut =
new QShortcut(q_pointer);
1000 m_tabWidget->setCurrentIndex(
1001 m_tabWidget->indexOf(m_hueFirstWrapperWidget));
1003 connect(m_hueFirstTabShortcut,
1007 m_tabWidget->setCurrentIndex(
1008 m_tabWidget->indexOf(m_hueFirstWrapperWidget));
1011 m_tabWidget->addTab(m_lightnessFirstWrapperWidget, QString());
1012 m_lightnessFirstTabShortcut =
new QShortcut(q_pointer);
1013 connect(m_lightnessFirstTabShortcut,
1017 m_tabWidget->setCurrentIndex(
1018 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget));
1020 connect(m_lightnessFirstTabShortcut,
1024 m_tabWidget->setCurrentIndex(
1025 m_tabWidget->indexOf(m_lightnessFirstWrapperWidget));
1028 m_tabTable.insert(&m_swatchBookWrapperWidget,
1029 QStringLiteral(
"swatch"));
1030 m_tabTable.insert(&m_hueFirstWrapperWidget,
1031 QStringLiteral(
"hue-based"));
1032 m_tabTable.insert(&m_lightnessFirstWrapperWidget,
1033 QStringLiteral(
"lightness-based"));
1034 m_tabTable.insert(&m_numericalWidget,
1035 QStringLiteral(
"numerical"));
1039 &ColorDialogPrivate::saveCurrentTab);
1042 m_colorPatch =
new ColorPatch();
1043 m_colorPatch->setMinimumSize(m_colorPatch->minimumSizeHint() * 1.5);
1045 QHBoxLayout *headerLayout =
new QHBoxLayout();
1046 headerLayout->
addWidget(m_colorPatch, 1);
1049 headerLayout->
addWidget(m_screenColorPickerButton,
1057 m_numericalWidget = initializeNumericPage();
1058 m_numericalTabShortcut =
new QShortcut(q_pointer);
1059 connect(m_numericalTabShortcut,
1063 m_tabWidget->setCurrentIndex(
1064 m_tabWidget->indexOf(m_numericalWidget));
1066 connect(m_numericalTabShortcut,
1070 m_tabWidget->setCurrentIndex(
1071 m_tabWidget->indexOf(m_numericalWidget));
1075 m_selectorLayout =
new QHBoxLayout();
1076 m_selectorLayout->addWidget(m_tabWidget);
1077 m_selectorLayout->addWidget(m_numericalWidget);
1080 QHBoxLayout *m_alphaLayout =
new QHBoxLayout();
1081 m_alphaGradientSlider =
new GradientSlider(m_rgbColorSpace,
1082 Qt::Orientation::Horizontal);
1083 m_alphaGradientSlider->setSingleStep(singleStepAlpha);
1084 m_alphaGradientSlider->setPageStep(pageStepAlpha);
1085 m_alphaSpinBox =
new QDoubleSpinBox();
1086 m_alphaSpinBox->setAlignment(Qt::AlignmentFlag::AlignRight);
1087 m_alphaSpinBox->setMinimum(0);
1088 m_alphaSpinBox->setMaximum(100);
1090 m_alphaSpinBox->setDecimals(decimals);
1091 m_alphaSpinBox->setSingleStep(singleStepAlpha * 100);
1094 m_alphaLabel =
new QLabel();
1095 m_alphaLabel->setBuddy(m_alphaSpinBox);
1097 m_alphaLayout->
addWidget(m_alphaGradientSlider);
1098 m_alphaLayout->
addWidget(m_alphaSpinBox);
1108 m_buttonBox =
new QDialogButtonBox();
1127 m_buttonBox->installEventFilter(&m_languageChangeEventFilter);
1128 m_buttonOK->installEventFilter(&m_languageChangeEventFilter);
1129 m_buttonCancel->installEventFilter(&m_languageChangeEventFilter);
1140 QVBoxLayout *tempMainLayout =
new QVBoxLayout();
1141 tempMainLayout->
addLayout(headerLayout);
1142 tempMainLayout->
addLayout(m_selectorLayout);
1143 tempMainLayout->
addLayout(m_alphaLayout);
1145 q_pointer->setLayout(tempMainLayout);
1151 &ColorDialogPrivate::readColorPatchValue
1153 connect(m_swatchBookBasicColors,
1154 &SwatchBook::currentColorChanged,
1156 &ColorDialogPrivate::readSwatchBookBasicColorsValue
1159 &SwatchBook::currentColorChanged,
1161 &ColorDialogPrivate::readSwatchBookHistoryValue
1163 connect(m_swatchBookCustomColors,
1164 &SwatchBook::currentColorChanged,
1166 &ColorDialogPrivate::readSwatchBookCustomColorsValue
1171 &ColorDialogPrivate::readRgbNumericValues
1176 &ColorDialogPrivate::readRgbHexValues
1181 &ColorDialogPrivate::updateRgbHexButBlockSignals
1186 &ColorDialogPrivate::readHslNumericValues
1191 &ColorDialogPrivate::readHwbNumericValues
1196 &ColorDialogPrivate::readHsvNumericValues
1201 &ColorDialogPrivate::readLchNumericValues
1206 &ColorDialogPrivate::updateLchButBlockSignals
1211 &ColorDialogPrivate::readOklchNumericValues
1216 &ColorDialogPrivate::updateOklchButBlockSignals
1218 connect(m_lchLightnessSelector,
1221 &ColorDialogPrivate::readLightnessValue
1226 &ColorDialogPrivate::readWheelColorPickerValues
1231 &ColorDialogPrivate::readChromaHueDiagramValue
1233 connect(m_alphaGradientSlider,
1236 &ColorDialogPrivate::updateColorPatch
1238 connect(m_alphaGradientSlider,
1241 [
this](
const qreal newFraction) {
1242 const QSignalBlocker blocker(m_alphaSpinBox);
1243 m_alphaSpinBox->setValue(newFraction * 100);
1248 [
this](
const double newValue) {
1251 m_alphaGradientSlider->setValue(newValue / 100);
1255 q_pointer->setOptions(QColorDialog::ColorDialogOption::DontUseNativeDialog);
1263 q_pointer->setWindowTitle(
tr(
"Select color"));
1278 q_pointer->setSizeGripEnabled(
true);
1283 m_cielchD50SpinBoxGamutAction =
new QAction(q_pointer);
1284 connect(m_cielchD50SpinBoxGamutAction,
1287 &ColorDialogPrivate::updateLchButBlockSignals
1289 m_oklchSpinBoxGamutAction =
new QAction(q_pointer);
1290 connect(m_oklchSpinBoxGamutAction,
1293 &ColorDialogPrivate::updateOklchButBlockSignals
1298 m_cielchD50SpinBoxGamutAction->setVisible(
false);
1299 m_cielchD50SpinBox->addActionButton(
1300 m_cielchD50SpinBoxGamutAction,
1301 QLineEdit::ActionPosition::TrailingPosition);
1302 m_oklchSpinBoxGamutAction->setVisible(
false);
1303 m_oklchSpinBox->addActionButton(
1304 m_oklchSpinBoxGamutAction,
1305 QLineEdit::ActionPosition::TrailingPosition);
1312 std::optional<QStringList>());
1316#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
1317 connect(qGuiApp->styleHints(),
1320 &ColorDialogPrivate::reloadIcons);
1330 , d_pointer(new ColorDialogPrivate(this))
1348 , d_pointer(new ColorDialogPrivate(this))
1367 , d_pointer(new ColorDialogPrivate(this))
1369 d_pointer->initialize(colorSpace);
1377QColor ColorDialogPrivate::defaultColor()
const
1379 const auto history = m_settings.history.value();
1380 return history.value(0, m_wcsBasicDefaultColor);
1397 , d_pointer(new ColorDialogPrivate(this))
1399 d_pointer->initialize(colorSpace);
1422ColorDialogPrivate::ColorDialogPrivate(
ColorDialog *backLink)
1423 : q_pointer(backLink)
1431 QColor temp = d_pointer->m_currentOpaqueColorRgb.rgbQColor;
1433 static_cast<QColorFloatType
>(
1434 d_pointer->m_alphaGradientSlider->value()));
1456 temp = color.
toRgb();
1461 if (
testOption(ColorDialog::ColorDialogOption::ShowAlphaChannel)) {
1462 d_pointer->m_alphaGradientSlider->setValue(
1463 static_cast<double>(temp.
alphaF()));
1465 d_pointer->m_alphaGradientSlider->setValue(1);
1469 const RgbColor myRgbColor = RgbColor::fromRgbQColor(temp);
1470 d_pointer->setCurrentOpaqueColor(myRgbColor,
nullptr);
1489 d_pointer->m_receiverToBeDisconnected = receiver;
1490 d_pointer->m_memberToBeDisconnected = member;
1499void ColorDialogPrivate::updateColorPatch()
1501 QColor tempRgbQColor = m_currentOpaqueColorRgb.rgbQColor;
1503 static_cast<QColorFloatType
>(m_alphaGradientSlider->value()));
1504 m_colorPatch->setColor(tempRgbQColor);
1511 const auto rgb1 = m_rgbColorSpace->fromCielchD50ToRgb1(cielchD50);
1512 const auto rgb255 = GenericColor(rgb1.first * 255,
1515 const auto rgbColor = RgbColor::fromRgb255(rgb255);
1516 setCurrentOpaqueColor(abs, rgbColor, ignoreWidget);
1520void ColorDialogPrivate::setCurrentOpaqueColor(
const PerceptualColor::RgbColor &rgb, QWidget *
const ignoreWidget)
1522 const auto temp = rgb.rgb255;
1524 static_cast<QColorFloatType
>(temp.first / 255.),
1525 static_cast<QColorFloatType
>(temp.second / 255.),
1526 static_cast<QColorFloatType
>(temp.third / 255.));
1527 const auto cielchD50 = GenericColor(
1528 m_rgbColorSpace->toCielchD50(myQColor.
rgba64()));
1529 setCurrentOpaqueColor(
1552void ColorDialogPrivate::setCurrentOpaqueColor(
const QHash<PerceptualColor::ColorModel, PerceptualColor::GenericColor> &abs,
1553 const PerceptualColor::RgbColor &rgb,
1554 QWidget *
const ignoreWidget)
1556 const bool isIdentical =
1557 (abs == m_currentOpaqueColorAbs) && (rgb == m_currentOpaqueColorRgb);
1558 if (m_isColorChangeInProgress || isIdentical) {
1565 m_isColorChangeInProgress =
true;
1569 QColor oldQColor = q_pointer->currentColor();
1572 m_currentOpaqueColorAbs = abs;
1573 m_currentOpaqueColorRgb = rgb;
1576 if (m_swatchBookBasicColors != ignoreWidget) {
1577 m_swatchBookBasicColors->setCurrentColor(
1578 m_currentOpaqueColorRgb.rgbQColor);
1582 if (m_swatchBookHistory != ignoreWidget) {
1583 m_swatchBookHistory->setCurrentColor(m_currentOpaqueColorRgb.rgbQColor);
1587 if (m_swatchBookCustomColors != ignoreWidget) {
1588 m_swatchBookCustomColors->setCurrentColor(m_currentOpaqueColorRgb.rgbQColor);
1592 if (m_rgbSpinBox != ignoreWidget) {
1593 m_rgbSpinBox->setSectionValues(
1594 m_currentOpaqueColorRgb.rgb255.toQList3());
1598 if (m_hslSpinBox != ignoreWidget) {
1599 m_hslSpinBox->setSectionValues(
1600 m_currentOpaqueColorRgb.hsl.toQList3());
1604 if (m_hwbSpinBox != ignoreWidget) {
1605 m_hwbSpinBox->setSectionValues(
1606 m_currentOpaqueColorRgb.hwb.toQList3());
1610 if (m_hsvSpinBox != ignoreWidget) {
1611 m_hsvSpinBox->setSectionValues(
1612 m_currentOpaqueColorRgb.hsv.toQList3());
1617 if (m_cielchD50SpinBox != ignoreWidget) {
1618 m_cielchD50SpinBox->setSectionValues(cielchD50.toQList3());
1623 if (m_oklchSpinBox != ignoreWidget) {
1624 m_oklchSpinBox->setSectionValues(oklch.toQList3());
1628 if (m_rgbLineEdit != ignoreWidget) {
1629 updateRgbHexButBlockSignals();
1633 if (m_lchLightnessSelector != ignoreWidget) {
1634 m_lchLightnessSelector->setValue(
1635 cielchD50.first /
static_cast<qreal
>(100));
1639 if (m_chromaHueDiagram != ignoreWidget) {
1640 m_chromaHueDiagram->setCurrentColorCielchD50(cielchD50);
1644 if (m_wheelColorPicker != ignoreWidget) {
1645 m_wheelColorPicker->setCurrentColorCielchD50(cielchD50);
1649 if (m_alphaGradientSlider != ignoreWidget) {
1650 GenericColor tempColor;
1651 tempColor.first = cielchD50.first;
1652 tempColor.second = cielchD50.second;
1653 tempColor.third = cielchD50.third;
1654 tempColor.fourth = 0;
1655 m_alphaGradientSlider->setFirstColorCieLchD50A(tempColor);
1656 tempColor.fourth = 1;
1657 m_alphaGradientSlider->setSecondColorCieLchD50A(tempColor);
1661 if (m_colorPatch != ignoreWidget) {
1666 if (q_pointer->currentColor() != oldQColor) {
1667 Q_EMIT q_pointer->currentColorChanged(q_pointer->currentColor());
1672 m_isColorChangeInProgress =
false;
1677void ColorDialogPrivate::readLightnessValue()
1679 if (m_isColorChangeInProgress) {
1684 cielchD50.first = m_lchLightnessSelector->value() * 100;
1685 cielchD50 = GenericColor(
1686 m_rgbColorSpace->reduceCielchD50ChromaToFitIntoGamut(cielchD50));
1687 setCurrentOpaqueColor(
1689 m_lchLightnessSelector);
1694void ColorDialogPrivate::readHslNumericValues()
1696 if (m_isColorChangeInProgress) {
1700 const auto temp = RgbColor::fromHsl(
1701 GenericColor(m_hslSpinBox->sectionValues()));
1702 setCurrentOpaqueColor(temp, m_hslSpinBox);
1707void ColorDialogPrivate::readHwbNumericValues()
1709 if (m_isColorChangeInProgress) {
1713 const auto temp = RgbColor::fromHwb(
1714 GenericColor(m_hwbSpinBox->sectionValues()));
1715 setCurrentOpaqueColor(temp, m_hwbSpinBox);
1720void ColorDialogPrivate::readHsvNumericValues()
1722 if (m_isColorChangeInProgress) {
1726 const auto temp = RgbColor::fromHsv(
1727 GenericColor(m_hsvSpinBox->sectionValues()));
1728 setCurrentOpaqueColor(temp, m_hsvSpinBox);
1733void ColorDialogPrivate::readRgbNumericValues()
1735 if (m_isColorChangeInProgress) {
1739 const auto temp = RgbColor::fromRgb255(
1740 GenericColor(m_rgbSpinBox->sectionValues()));
1741 setCurrentOpaqueColor(temp, m_rgbSpinBox);
1746void ColorDialogPrivate::readColorPatchValue()
1748 if (m_isColorChangeInProgress) {
1752 const QColor temp = m_colorPatch->color();
1757 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1758 setCurrentOpaqueColor(myRgbColor, m_colorPatch);
1763void ColorDialogPrivate::readSwatchBookBasicColorsValue()
1765 if (m_isColorChangeInProgress) {
1769 const QColor temp = m_swatchBookBasicColors->currentColor();
1774 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1775 setCurrentOpaqueColor(myRgbColor, m_swatchBookBasicColors);
1780void ColorDialogPrivate::readSwatchBookHistoryValue()
1782 if (m_isColorChangeInProgress) {
1786 const QColor temp = m_swatchBookHistory->currentColor();
1791 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1792 setCurrentOpaqueColor(myRgbColor, m_swatchBookHistory);
1799void ColorDialogPrivate::readSwatchBookCustomColorsValue()
1801 if (m_isColorChangeInProgress) {
1805 const QColor temp = m_swatchBookCustomColors->currentColor();
1810 const auto myRgbColor = RgbColor::fromRgbQColor(temp);
1811 setCurrentOpaqueColor(myRgbColor, m_swatchBookCustomColors);
1816void ColorDialogPrivate::readWheelColorPickerValues()
1818 if (m_isColorChangeInProgress) {
1822 const auto cielchD50 = GenericColor(m_wheelColorPicker->currentColorCielchD50());
1823 setCurrentOpaqueColor(
1825 m_wheelColorPicker);
1830void ColorDialogPrivate::readChromaHueDiagramValue()
1832 if (m_isColorChangeInProgress) {
1836 const auto cielchD50 = GenericColor(m_chromaHueDiagram->currentColorCielchD50());
1837 setCurrentOpaqueColor(
1839 m_chromaHueDiagram);
1844void ColorDialogPrivate::readRgbHexValues()
1846 if (m_isColorChangeInProgress) {
1850 QString temp = m_rgbLineEdit->text();
1851 if (!temp.
startsWith(QStringLiteral(u
"#"))) {
1852 temp = QStringLiteral(u
"#") + temp;
1857 const auto myRgbColor = RgbColor::fromRgbQColor(rgb);
1858 setCurrentOpaqueColor(myRgbColor, m_rgbLineEdit);
1860 m_isDirtyRgbLineEdit =
true;
1868void ColorDialogPrivate::updateRgbHexButBlockSignals()
1870 QSignalBlocker mySignalBlocker(m_rgbLineEdit);
1876 const auto &rgbFloat = m_currentOpaqueColorRgb.rgb255;
1888 const QString hexString =
1889 QStringLiteral(u
"#%1%2%3")
1890 .arg(qBound(0, qRound(rgbFloat.first), 255),
1894 .arg(qBound(0, qRound(rgbFloat.second), 255),
1898 .arg(qBound(0, qRound(rgbFloat.third), 255),
1903 m_rgbLineEdit->setText(hexString);
1911void ColorDialogPrivate::updateLchButBlockSignals()
1913 QSignalBlocker mySignalBlocker(m_cielchD50SpinBox);
1915 m_cielchD50SpinBox->setSectionValues(cielchD50.toQList3());
1916 m_cielchD50SpinBoxGamutAction->setVisible(
false);
1924void ColorDialogPrivate::updateOklchButBlockSignals()
1926 QSignalBlocker mySignalBlocker(m_oklchSpinBox);
1928 m_oklchSpinBox->setSectionValues(oklch.toQList3());
1929 m_oklchSpinBoxGamutAction->setVisible(
false);
1934void ColorDialogPrivate::readLchNumericValues()
1936 if (m_isColorChangeInProgress) {
1940 const GenericColor lchValues = GenericColor(m_cielchD50SpinBox->sectionValues());
1941 if (m_rgbColorSpace->isCielchD50InGamut(lchValues)) {
1942 m_cielchD50SpinBoxGamutAction->setVisible(
false);
1944 m_cielchD50SpinBoxGamutAction->setVisible(
true);
1946 const auto myColor = GenericColor(
1947 m_rgbColorSpace->reduceCielchD50ChromaToFitIntoGamut(lchValues));
1948 setCurrentOpaqueColor(
1951 m_cielchD50SpinBox);
1956void ColorDialogPrivate::readOklchNumericValues()
1958 if (m_isColorChangeInProgress) {
1966 GenericColor originalOklch;
1967 originalOklch.first = m_oklchSpinBox->sectionValues().value(0);
1968 originalOklch.second = m_oklchSpinBox->sectionValues().value(1);
1969 originalOklch.third = m_oklchSpinBox->sectionValues().value(2);
1970 if (m_rgbColorSpace->isOklchInGamut(originalOklch)) {
1971 m_oklchSpinBoxGamutAction->setVisible(
false);
1973 m_oklchSpinBoxGamutAction->setVisible(
true);
1975 const auto inGamutOklch = GenericColor(
1976 m_rgbColorSpace->reduceOklchChromaToFitIntoGamut(originalOklch));
1977 const auto inGamutColor =
1979 setCurrentOpaqueColor(inGamutColor,
1988void ColorDialogPrivate::initializeScreenColorPicker()
1990 auto screenPicker =
new ScreenColorPicker(q_pointer);
1991 if (!screenPicker->isAvailable()) {
1994 m_screenColorPickerButton =
new QToolButton;
1995 screenPicker->setParent(m_screenColorPickerButton);
1996 connect(m_screenColorPickerButton,
2000 [&, screenPicker]() {
2001 const auto myColor = q_pointer->currentColor();
2006 screenPicker->startPicking(
2007 fromFloatingToEightBit(myColor.redF()),
2008 fromFloatingToEightBit(myColor.greenF()),
2009 fromFloatingToEightBit(myColor.blueF()));
2012 &ScreenColorPicker::newColor,
2014 [
this](
const double red,
const double green,
const double blue,
const bool isSRgbGuaranteed) {
2015 Q_UNUSED(isSRgbGuaranteed)
2021 const GenericColor rgb255
2022 {qBound<double>(0, red * 255, 255),
2023 qBound<double>(0, green * 255, 255),
2024 qBound<double>(0, blue * 255, 255)};
2025 setCurrentOpaqueColor(RgbColor::fromRgb255(rgb255),
nullptr);
2032QWidget *ColorDialogPrivate::initializeNumericPage()
2036 m_rgbSpinBox =
new MultiSpinBox();
2037 QList<MultiSpinBoxSection> rgbSections;
2038 MultiSpinBoxSection mySection;
2039 mySection.setDecimals(decimals);
2040 mySection.setMinimum(0);
2041 mySection.setMaximum(255);
2043 mySection.setFormatString(
2044 QStringLiteral(
"%1") + m_multispinboxSectionSeparator);
2045 rgbSections.
append(mySection);
2047 mySection.setFormatString(
2048 m_multispinboxSectionSeparator + QStringLiteral(
"%1")
2049 + m_multispinboxSectionSeparator);
2050 rgbSections.
append(mySection);
2052 mySection.setFormatString(
2053 m_multispinboxSectionSeparator + QStringLiteral(
"%1"));
2054 rgbSections.
append(mySection);
2056 m_rgbSpinBox->setSectionConfigurations(rgbSections);
2061 m_rgbLineEdit =
new QLineEdit();
2062 m_rgbLineEdit->setMaxLength(7);
2063 QRegularExpression tempRegularExpression(
2064 QStringLiteral(u
"#?[0-9A-Fa-f]{0,6}"));
2065 QRegularExpressionValidator *validator =
2066 new QRegularExpressionValidator(tempRegularExpression, q_pointer);
2067 m_rgbLineEdit->setValidator(validator);
2072 m_hslSpinBox =
new MultiSpinBox();
2073 QList<MultiSpinBoxSection> hslSections;
2074 MultiSpinBoxSection mySection;
2075 mySection.setDecimals(decimals);
2077 mySection.setMinimum(0);
2078 mySection.setMaximum(360);
2079 mySection.setWrapping(
true);
2080 hslSections.
append(mySection);
2082 mySection.setMinimum(0);
2083 mySection.setMaximum(100);
2084 mySection.setWrapping(
false);
2085 hslSections.
append(mySection);
2087 mySection.setMinimum(0);
2088 mySection.setMaximum(100);
2089 mySection.setWrapping(
false);
2090 hslSections.
append(mySection);
2092 m_hslSpinBox->setSectionConfigurations(hslSections);
2097 m_hwbSpinBox =
new MultiSpinBox();
2098 QList<MultiSpinBoxSection> hwbSections;
2099 MultiSpinBoxSection mySection;
2100 mySection.setDecimals(decimals);
2102 mySection.setMinimum(0);
2103 mySection.setMaximum(360);
2104 mySection.setWrapping(
true);
2105 hwbSections.
append(mySection);
2107 mySection.setMinimum(0);
2108 mySection.setMaximum(100);
2109 mySection.setWrapping(
false);
2110 hwbSections.
append(mySection);
2112 mySection.setMinimum(0);
2113 mySection.setMaximum(100);
2114 mySection.setWrapping(
false);
2115 hwbSections.
append(mySection);
2117 m_hwbSpinBox->setSectionConfigurations(hwbSections);
2122 m_hsvSpinBox =
new MultiSpinBox();
2123 QList<MultiSpinBoxSection> hsvSections;
2124 MultiSpinBoxSection mySection;
2125 mySection.setDecimals(decimals);
2127 mySection.setMinimum(0);
2128 mySection.setMaximum(360);
2129 mySection.setWrapping(
true);
2130 hsvSections.
append(mySection);
2132 mySection.setMinimum(0);
2133 mySection.setMaximum(100);
2134 mySection.setWrapping(
false);
2135 hsvSections.
append(mySection);
2137 mySection.setMinimum(0);
2138 mySection.setMaximum(100);
2139 mySection.setWrapping(
false);
2140 hsvSections.
append(mySection);
2142 m_hsvSpinBox->setSectionConfigurations(hsvSections);
2147 QFormLayout *tempRgbFormLayout =
new QFormLayout();
2148 m_rgbSpinBoxLabel =
new QLabel();
2149 m_rgbSpinBoxLabel->setBuddy(m_rgbSpinBox);
2150 tempRgbFormLayout->
addRow(m_rgbSpinBoxLabel, m_rgbSpinBox);
2151 m_rgbLineEditLabel =
new QLabel();
2152 m_rgbLineEditLabel->setBuddy(m_rgbLineEdit);
2153 tempRgbFormLayout->
addRow(m_rgbLineEditLabel, m_rgbLineEdit);
2154 m_hslSpinBoxLabel =
new QLabel();
2155 m_hslSpinBoxLabel->setBuddy(m_hslSpinBox);
2156 tempRgbFormLayout->
addRow(m_hslSpinBoxLabel, m_hslSpinBox);
2157 m_hwbSpinBoxLabel =
new QLabel();
2158 m_hwbSpinBoxLabel->setBuddy(m_hwbSpinBox);
2159 tempRgbFormLayout->
addRow(m_hwbSpinBoxLabel, m_hwbSpinBox);
2160 m_hsvSpinBoxLabel =
new QLabel();
2161 m_hsvSpinBoxLabel->setBuddy(m_hsvSpinBox);
2162 tempRgbFormLayout->
addRow(m_hsvSpinBoxLabel, m_hsvSpinBox);
2163 m_rgbGroupBox =
new QGroupBox();
2164 m_rgbGroupBox->setLayout(tempRgbFormLayout);
2170 const QFontMetricsF fontMetrics(m_rgbGroupBox->font());
2171 const auto elidedProfileName = fontMetrics.elidedText(
2172 m_rgbColorSpace->profileName(),
2173 Qt::TextElideMode::ElideRight,
2176 m_rgbGroupBox->setTitle(elidedProfileName);
2181 QList<MultiSpinBoxSection> cielchD50Sections;
2182 m_cielchD50SpinBox =
new MultiSpinBox;
2183 MultiSpinBoxSection mySection;
2184 mySection.setDecimals(decimals);
2186 mySection.setMinimum(0);
2187 mySection.setMaximum(100);
2188 mySection.setWrapping(
false);
2189 cielchD50Sections.
append(mySection);
2191 mySection.setMinimum(0);
2192 mySection.setMaximum(CielchD50Values::maximumChroma);
2193 mySection.setWrapping(
false);
2194 cielchD50Sections.
append(mySection);
2196 mySection.setMinimum(0);
2197 mySection.setMaximum(360);
2198 mySection.setWrapping(
true);
2199 cielchD50Sections.
append(mySection);
2201 m_cielchD50SpinBox->setSectionConfigurations(cielchD50Sections);
2206 QList<MultiSpinBoxSection> oklchSections;
2207 MultiSpinBoxSection mySection;
2208 m_oklchSpinBox =
new MultiSpinBox;
2210 mySection.setMinimum(0);
2211 mySection.setMaximum(1);
2212 mySection.setSingleStep(singleStepOklabc);
2213 mySection.setWrapping(
false);
2214 mySection.setDecimals(okdecimals);
2215 oklchSections.
append(mySection);
2217 mySection.setMinimum(0);
2218 mySection.setMaximum(OklchValues::maximumChroma);
2219 mySection.setSingleStep(singleStepOklabc);
2220 mySection.setWrapping(
false);
2221 mySection.setDecimals(okdecimals);
2222 oklchSections.
append(mySection);
2224 mySection.setMinimum(0);
2225 mySection.setMaximum(360);
2226 mySection.setSingleStep(1);
2227 mySection.setWrapping(
true);
2228 mySection.setDecimals(decimals);
2229 oklchSections.
append(mySection);
2231 m_oklchSpinBox->setSectionConfigurations(oklchSections);
2235 QWidget *tempWidget =
new QWidget;
2236 QVBoxLayout *tempMainLayout =
new QVBoxLayout;
2239 QFormLayout *cielabFormLayout =
new QFormLayout;
2240 m_oklchSpinBoxLabel =
new QLabel();
2241 m_oklchSpinBoxLabel->setBuddy(m_oklchSpinBox);
2242 cielabFormLayout->
addRow(m_oklchSpinBoxLabel, m_oklchSpinBox);
2243 m_cielchD50SpinBoxLabel =
new QLabel();
2244 m_cielchD50SpinBoxLabel->setBuddy(m_cielchD50SpinBox);
2245 cielabFormLayout->
addRow(m_cielchD50SpinBoxLabel, m_cielchD50SpinBox);
2246 tempMainLayout->
addLayout(cielabFormLayout);
2247 tempMainLayout->
addWidget(m_rgbGroupBox);
2258 return d_pointer->m_options;
2269 temp.setFlag(option, on);
2279 if (newOptions == d_pointer->m_options) {
2284 d_pointer->m_options = newOptions;
2287 d_pointer->m_options.setFlag(
2288 QColorDialog::ColorDialogOption::DontUseNativeDialog,
2292 const bool alphaVisibility = d_pointer->m_options.testFlag(
2293 QColorDialog::ColorDialogOption::ShowAlphaChannel);
2294 d_pointer->m_alphaLabel->setVisible(alphaVisibility);
2295 d_pointer->m_alphaGradientSlider->setVisible(alphaVisibility);
2296 d_pointer->m_alphaSpinBox->setVisible(alphaVisibility);
2299 d_pointer->m_buttonBox->setVisible(!d_pointer->m_options.testFlag(
2300 QColorDialog::ColorDialogOption::NoButtons));
2315 return d_pointer->m_options.testFlag(option);
2387 return d_pointer->m_selectedColor;
2403 d_pointer->m_selectedColor =
QColor();
2404 d_pointer->applyLayoutDimensions();
2412 d_pointer->m_buttonOK->setDefault(
true);
2421 if (
result == QDialog::DialogCode::Accepted) {
2423 auto history = d_pointer->m_settings.history.value();
2424 const auto maxHistoryLenght = std::max(d_pointer->historySwatchCount,
2427 history.removeAll(d_pointer->m_selectedColor);
2429 history.prepend(d_pointer->m_selectedColor);
2431 while (history.count() > maxHistoryLenght) {
2432 history.removeLast();
2434 d_pointer->m_settings.history.setValue(history);
2437 d_pointer->m_selectedColor =
QColor();
2440 if (d_pointer->m_receiverToBeDisconnected) {
2449 d_pointer->m_receiverToBeDisconnected,
2450 d_pointer->m_memberToBeDisconnected.constData()
2452 d_pointer->m_receiverToBeDisconnected =
nullptr;
2460 return d_pointer->m_layoutDimensions;
2467 if (newLayoutDimensions == d_pointer->m_layoutDimensions) {
2470 d_pointer->m_layoutDimensions = newLayoutDimensions;
2471 d_pointer->applyLayoutDimensions();
2480void ColorDialogPrivate::applyLayoutDimensions()
2485 constexpr auto screenSizeDependent =
2487 int effectivelyAvailableScreenWidth;
2488 int widthThreeshold;
2489 switch (m_layoutDimensions) {
2491 m_layoutDimensionsEffective = collapsed;
2494 m_layoutDimensionsEffective = expanded;
2496 case screenSizeDependent:
2503 effectivelyAvailableScreenWidth = qRound(
2510 widthThreeshold = qMax(
2511 m_wheelColorPicker->sizeHint().width(),
2512 m_lightnessFirstWrapperWidget->sizeHint().width());
2514 widthThreeshold += m_numericalWidget->sizeHint().width();
2516 widthThreeshold = qRound(widthThreeshold * 1.2);
2519 if (effectivelyAvailableScreenWidth < widthThreeshold) {
2520 m_layoutDimensionsEffective = collapsed;
2522 m_layoutDimensionsEffective = expanded;
2531 if (m_layoutDimensionsEffective == collapsed) {
2532 if (m_selectorLayout->indexOf(m_numericalWidget) >= 0) {
2535 const bool oldUpdatesEnabled = m_tabWidget->updatesEnabled();
2536 m_tabWidget->setUpdatesEnabled(
false);
2540 m_tabWidget->addTab(m_numericalWidget, QString());
2541 m_tabWidget->setUpdatesEnabled(oldUpdatesEnabled);
2547 q_pointer->adjustSize();
2550 if (m_selectorLayout->indexOf(m_numericalWidget) < 0) {
2553 m_selectorLayout->addWidget(m_numericalWidget);
2556 m_numericalWidget->show();
2558 q_pointer->adjustSize();
2572 const auto type =
event->type();
2581 d_pointer->retranslateUi();
2586 &eventForSwatchBookBasicColors);
2591 &eventForSwatchBookHistory);
2596 &eventForSwatchBookCustomColors);
2606 &eventForButtonCancel);
2611 d_pointer->reloadIcons();
2629 if (!d_pointer->everShown) {
2631 const bool exp = d_pointer->m_layoutDimensionsEffective == expValue;
2632 const auto tabString = exp
2633 ? d_pointer->m_settings.tabExpanded.value()
2634 : d_pointer->m_settings.tab.value();
2635 const auto key = d_pointer->m_tabTable.key(tabString,
nullptr);
2636 if (key !=
nullptr) {
2637 d_pointer->m_tabWidget->setCurrentWidget(*key);
2644 d_pointer->saveCurrentTab();
2646 switch (d_pointer->m_settings.swatchBookPage.value()) {
2647 case PerceptualSettings::SwatchBookPage::BasicColors:
2649 d_pointer->m_settings.swatchBookPage.setValue(
2650 PerceptualSettings::SwatchBookPage::BasicColors);
2651 d_pointer->m_swatchBookSelector->setCurrentIndex(0);
2652 d_pointer->m_swatchBookStack->setCurrentIndex(0);
2654 case PerceptualSettings::SwatchBookPage::History:
2655 d_pointer->m_settings.swatchBookPage.setValue(
2656 PerceptualSettings::SwatchBookPage::History);
2657 d_pointer->m_swatchBookSelector->setCurrentIndex(1);
2658 d_pointer->m_swatchBookStack->setCurrentIndex(1);
2660 case PerceptualSettings::SwatchBookPage::CustomColors:
2661 d_pointer->m_settings.swatchBookPage.setValue(
2662 PerceptualSettings::SwatchBookPage::History);
2663 d_pointer->m_swatchBookSelector->setCurrentIndex(2);
2664 d_pointer->m_swatchBookStack->setCurrentIndex(2);
2668 d_pointer->everShown =
true;
2674void ColorDialogPrivate::saveCurrentTab()
2676 const auto currentIndex = m_tabWidget->currentIndex();
2677 QWidget const *
const widget = m_tabWidget->widget(currentIndex);
2678 const auto keyList = m_tabTable.
keys();
2679 auto it = std::find_if(
2682 [widget](
const auto &key) {
2683 return ((*key) == widget);
2686 if (it != keyList.end()) {
2687 const auto tabString = m_tabTable.
value(*it);
2689 if (m_layoutDimensionsEffective == expValue) {
2690 m_settings.tabExpanded.setValue(tabString);
2692 m_settings.tab.setValue(tabString);
2699void ColorDialogPrivate::loadHistoryFromSettingsToSwatchBook()
2701 const Swatches historyArray(historyHSwatchCount,
2702 historyVSwatchCount,
2703 m_settings.history.value());
2704 m_swatchBookHistory->setSwatchGrid(historyArray);
2709void ColorDialogPrivate::loadCustomColorsFromSettingsToSwatchBook()
2711 const Swatches customColorsArray(customColorsHSwatchCount,
2712 customColorsVSwatchCount,
2713 m_settings.customColors.value());
2714 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