File indexing completed on 2024-10-13 04:16:24
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 #ifndef SCREENCOLORPICKER 0005 #define SCREENCOLORPICKER 0006 0007 #include <optional> 0008 #include <qglobal.h> 0009 #include <qpointer.h> 0010 #include <qstring.h> 0011 #include <qwidget.h> 0012 class QColorDialog; 0013 class QPushButton; 0014 0015 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0016 #include <qcontainerfwd.h> 0017 #include <qtmetamacros.h> 0018 #else 0019 #include <qmetatype.h> 0020 #include <qobjectdefs.h> 0021 class QObject; 0022 #endif 0023 0024 namespace PerceptualColor 0025 { 0026 0027 /** @internal 0028 * 0029 * @brief Pick a color from the screen. 0030 * 0031 * Provides an interface to let the user pick a color from the screen. 0032 * 0033 * This feature is not available on all platforms. Use @ref isAvailable() 0034 * to check it. 0035 * 0036 * @warning On some platforms, QColorDialog is used to perform the color 0037 * picking. This might mix up the default button setting of the parent dialog. 0038 * Workaround: If using default buttons in a parent dialog, reimplement 0039 * <tt>QWidget::setVisible()</tt> in this parent dialog: Call the 0040 * parent’s class implementation, and <em>after</em> that, call 0041 * <tt>QPushButton::setDefault(true)</tt> on the default button. */ 0042 class ScreenColorPicker : public QWidget 0043 { 0044 Q_OBJECT 0045 0046 public: 0047 explicit ScreenColorPicker(QWidget *parent); 0048 virtual ~ScreenColorPicker() override; 0049 [[nodiscard]] bool isAvailable(); 0050 0051 public Q_SLOTS: 0052 void startPicking(quint8 previousColorRed, quint8 previousColorGreen, quint8 previousColorBlue); 0053 0054 Q_SIGNALS: 0055 /** @brief A new color. 0056 * 0057 * Emitted when the user has clicked on the screen to select a new color. 0058 * 0059 * @note On some platforms, furthermore this signal is also emitted while 0060 * the user hovers over the screen with the mouse. Than, if the user 0061 * cancels with the ESC key, a new signal is emitted with the old color 0062 * passed originally to @ref startPicking. 0063 * 0064 * @param red The <em>red</em> component of the new color. 0065 * Range: <tt>[0, 255]</tt> 0066 * @param green Same for green. 0067 * @param blue Same for blue. 0068 * 0069 * @internal 0070 * 0071 * @note This signal uses integers with the range <tt>[0, 255]</tt> as 0072 * return values because this is the maximum precision of the underlying 0073 * implementation: The QColorDialog implementation rounds on this 0074 * precision when the user pushes the ESC key, even if the previous 0075 * value was more exact. */ 0076 // Choosing thre “double” values as return type, as it makes clear 0077 // what data type returns and as “Portal” actually provides 0078 // double-precision in its return values. 0079 void newColor(double red, double green, double blue); 0080 0081 private: 0082 /** @internal @brief Only for unit tests. */ 0083 friend class TestScreenColorPicker; 0084 0085 void pickWithPortal(); 0086 [[nodiscard]] static bool hasPortalSupport(); 0087 void initializeQColorDialogSupport(); 0088 [[nodiscard]] static bool queryPortalSupport(); 0089 [[nodiscard]] static QString translateViaQColorDialog(const char *sourceText); 0090 /** @brief If on the current platform there is support for 0091 * QColorDialog-based screen color picking. 0092 * 0093 * Might hold an empty value if @ref initializeQColorDialogSupport has 0094 * never been called. 0095 * 0096 * @warning The declaration as <tt>static inline</tt> can be problematic: 0097 * At least when linking on MSVC against a shared/static library, 0098 * apparently there are two instances of this variable: One that is used 0099 * within the shared/dynamic library and another one that is used within 0100 * the executable that links against this library. While on GCC and Clang 0101 * this does not happen, maybe this behaviour is implementation-defined. 0102 * And we do not want to rely on implementation-defined behaviour. However, 0103 * because the variable is <tt>private</tt>, this won't make any problems 0104 * under normal circumstances, because it's inaccessible anyway. Only when 0105 * doing a whitebox test and bypass the private access modifier via the 0106 * @ref ScreenColorPicker::TestScreenColorPicker "friend declaration" for 0107 * unit tests, you might see the wrong variable and consequently possibly 0108 * the wrong value. Therefore, unit tests should only access this variable 0109 * when building against the static library. */ 0110 static inline std::optional<bool> m_hasQColorDialogSupport = std::nullopt; 0111 /** @brief The hidden QColorDialog widget (if any). 0112 * 0113 * @sa @ref initializeQColorDialogSupport */ 0114 QPointer<QColorDialog> m_qColorDialog; 0115 /** @brief The screen-color-picker button of the hidden QColorDialog widget 0116 * (if any). 0117 * 0118 * @sa @ref initializeQColorDialogSupport */ 0119 QPointer<QPushButton> m_qColorDialogScreenButton; 0120 0121 private Q_SLOTS: 0122 void getPortalResponse(uint exitCode, const QVariantMap &responseArguments); 0123 }; 0124 0125 } // namespace PerceptualColor 0126 0127 #endif // SCREENCOLORPICKER