File indexing completed on 2024-05-12 04:44:30
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 #ifndef CHROMALIGHTNESSDIAGRAM_P_H 0005 #define CHROMALIGHTNESSDIAGRAM_P_H 0006 0007 // Include the header of the public class of this private implementation. 0008 // #include "chromalightnessdiagram.h" 0009 0010 #include "asyncimageprovider.h" 0011 #include "chromalightnessimageparameters.h" 0012 #include "constpropagatingrawpointer.h" 0013 #include "lchdouble.h" 0014 #include <cmath> 0015 #include <functional> 0016 #include <limits> 0017 #include <optional> 0018 #include <qglobal.h> 0019 #include <qsharedpointer.h> 0020 #include <qsize.h> 0021 class QRect; 0022 class QPoint; 0023 0024 namespace PerceptualColor 0025 { 0026 class ChromaLightnessDiagram; 0027 class RgbColorSpace; 0028 0029 /** @internal 0030 * 0031 * @brief Private implementation within the <em>Pointer to 0032 * implementation</em> idiom */ 0033 class ChromaLightnessDiagramPrivate final 0034 { 0035 public: 0036 explicit ChromaLightnessDiagramPrivate(ChromaLightnessDiagram *backLink); 0037 /** @brief Default destructor 0038 * 0039 * The destructor is non-<tt>virtual</tt> because 0040 * the class as a whole is <tt>final</tt>. */ 0041 ~ChromaLightnessDiagramPrivate() noexcept = default; 0042 0043 // Member variables 0044 /** @brief The image of the chroma-lightness diagram itself. */ 0045 AsyncImageProvider<ChromaLightnessImageParameters> m_chromaLightnessImage; 0046 /** @brief Properties for @ref m_chromaLightnessImage. */ 0047 ChromaLightnessImageParameters m_chromaLightnessImageParameters; 0048 /** @brief Internal storage of 0049 * the @ref ChromaLightnessDiagram::currentColor property */ 0050 LchDouble m_currentColor; 0051 /** @brief Holds if currently a mouse event is active or not. 0052 * 0053 * Default value is <tt>false</tt>. 0054 * - A mouse event gets typically activated on a 0055 * @ref ChromaLightnessDiagram::mousePressEvent() 0056 * done within the gamut diagram. The value is set to <tt>true</tt>. 0057 * - While active, all @ref ChromaLightnessDiagram::mouseMoveEvent() will 0058 * move the diagram’s color handle. 0059 * - Once a @ref ChromaLightnessDiagram::mouseReleaseEvent() occurs, the 0060 * value is set to <tt>false</tt>. Further mouse movements will not 0061 * move the handle anymore. 0062 * 0063 * This is done because Qt’s default mouse tracking reacts on all clicks 0064 * within the (rectangular) widget. However, <em>this</em> widget is meant 0065 * as a circular widget, only reacting on mouse events within the circle; 0066 * this requires this custom implementation. */ 0067 bool m_isMouseEventActive = false; // TODO Remove me! 0068 /** @brief Pointer to RgbColorSpace() object */ 0069 QSharedPointer<RgbColorSpace> m_rgbColorSpace; 0070 0071 // Member functions 0072 [[nodiscard]] QSize calculateImageSizePhysical() const; 0073 [[nodiscard]] int defaultBorderPhysical() const; 0074 /** @internal 0075 * 0076 * @brief Calculate how far a value is from a given range. 0077 * @pre <tt>low</tt> ≤ <tt>high</tt> 0078 * @param low the lower limit 0079 * @param x the value that will be tested 0080 * @param high the higher limit 0081 * @returns <tt>0</tt> if the value is within the range. The distance 0082 * to the nearest border of the range otherwise. */ 0083 template<typename T> 0084 [[nodiscard]] static constexpr T distanceFromRange(const T &low, const T &x, const T &high) 0085 { 0086 if (x < low) { 0087 return low - x; 0088 } 0089 if (x > high) { 0090 return x - high; 0091 } 0092 if constexpr ( // 0093 std::numeric_limits<T>::has_quiet_NaN // 0094 || std::numeric_limits<T>::has_signaling_NaN // 0095 ) { 0096 if (std::isnan(low) || std::isnan(x) || std::isnan(high)) { 0097 return std::numeric_limits<T>::quiet_NaN(); 0098 } 0099 } 0100 return 0; 0101 } 0102 [[nodiscard]] LchDouble fromWidgetPixelPositionToColor(const QPoint widgetPixelPosition) const; 0103 [[nodiscard]] bool isWidgetPixelPositionInGamut(const QPoint widgetPixelPosition) const; 0104 [[nodiscard]] int leftBorderPhysical() const; 0105 [[nodiscard]] PerceptualColor::LchDouble nearestInGamutColorByAdjustingChromaLightness(const double chroma, const double lightness); 0106 [[nodiscard]] std::optional<QPoint> nearestInGamutPixelPosition(const QPoint originalPixelPosition); 0107 [[nodiscard]] static std::optional<QPoint> 0108 nearestNeighborSearch(const QPoint point, const QRect searchRectangle, const std::function<bool(const QPoint)> &doesPointExist); 0109 void setCurrentColorFromWidgetPixelPosition(const QPoint widgetPixelPosition); 0110 0111 private: 0112 Q_DISABLE_COPY(ChromaLightnessDiagramPrivate) 0113 0114 /** @brief Pointer to the object from which <em>this</em> object 0115 * is the private implementation. */ 0116 ConstPropagatingRawPointer<ChromaLightnessDiagram> q_pointer; 0117 }; 0118 0119 } // namespace PerceptualColor 0120 0121 #endif // CHROMALIGHTNESSDIAGRAM_P_H