6#include "chromahuediagram.h"
8#include "chromahuediagram_p.h"
10#include "abstractdiagram.h"
11#include "asyncimageprovider.h"
12#include "chromahueimageparameters.h"
13#include "cielchd50values.h"
14#include "colorwheelimage.h"
15#include "constpropagatingrawpointer.h"
16#include "constpropagatinguniquepointer.h"
18#include "helperconstants.h"
19#include "helperconversion.h"
20#include "polarpointf.h"
21#include "rgbcolorspace.h"
27#include <qnamespace.h>
31#include <qsharedpointer.h>
43 , d_pointer(new ChromaHueDiagramPrivate(this, colorSpace))
47 d_pointer->m_rgbColorSpace = colorSpace;
65 connect(&d_pointer->m_chromaHueImage,
66 &AsyncImageProvider<ChromaHueImageParameters>::interlacingPassCompleted,
86 : m_currentColorCielchD50{0, 0, 0}
87 , m_wheelImage(colorSpace)
114 const bool isWithinCircle =
115 d_pointer->isWidgetPixelPositionWithinMouseSensibleCircle(
event->pos());
116 if (isWithinCircle) {
125 d_pointer->m_isMouseEventActive =
true;
131 d_pointer->setColorFromWidgetPixelPosition(
event->pos());
166 if (d_pointer->m_isMouseEventActive) {
168 const cmsCIELab cielabD50 =
169 d_pointer->fromWidgetPixelPositionToLab(
event->pos());
170 const bool isWithinCircle =
171 d_pointer->isWidgetPixelPositionWithinMouseSensibleCircle(
173 if (isWithinCircle && d_pointer->m_rgbColorSpace->isCielabD50InGamut(cielabD50)) {
178 d_pointer->setColorFromWidgetPixelPosition(
event->pos());
211 if (d_pointer->m_isMouseEventActive) {
214 d_pointer->m_isMouseEventActive =
false;
215 d_pointer->setColorFromWidgetPixelPosition(
event->pos());
242 const bool isWithinCircle =
243 d_pointer->isWidgetPixelPositionWithinMouseSensibleCircle(
244 event->position().toPoint());
248 (!d_pointer->m_isMouseEventActive)
251 && (
event->angleDelta().y() != 0)
264 GenericColor newColor = d_pointer->m_currentColorCielchD50;
265 newColor.third += standardWheelStepCount(
event) * singleStepHue;
267 d_pointer->m_rgbColorSpace->reduceCielchD50ChromaToFitIntoGamut(newColor));
307 switch (
event->key()) {
309 newColor.second += singleStepChroma;
312 newColor.second -= singleStepChroma;
315 newColor.third += singleStepHue;
318 newColor.third -= singleStepHue;
321 newColor.second += pageStepChroma;
324 newColor.second -= pageStepChroma;
327 newColor.third += pageStepHue;
330 newColor.third -= pageStepHue;
349 if (newColor.second < 0) {
355 newColor = d_pointer->m_rgbColorSpace->reduceCielchD50ChromaToFitIntoGamut(newColor);
387 return QSize(mySize, mySize);
394 return d_pointer->m_currentColorCielchD50;
402 if (newCurrentColorCielchD50 == d_pointer->m_currentColorCielchD50) {
406 const GenericColor oldColor = d_pointer->m_currentColorCielchD50;
408 d_pointer->m_currentColorCielchD50 = newCurrentColorCielchD50;
411 if (d_pointer->m_currentColorCielchD50.first != oldColor.first) {
412 const qreal temp = qBound(
static_cast<qreal
>(0),
413 d_pointer->m_currentColorCielchD50.first,
414 static_cast<qreal
>(100));
415 d_pointer->m_chromaHueImageParameters.lightness = temp;
437QPointF ChromaHueDiagramPrivate::diagramCenter()
const
439 const qreal tempOffset{diagramOffset()};
440 return QPointF(tempOffset, tempOffset);
452qreal ChromaHueDiagramPrivate::diagramOffset()
const
454 return q_pointer->maximumWidgetSquareSize() / 2.0;
468 d_pointer->m_chromaHueImageParameters.imageSizePhysical =
491QPointF ChromaHueDiagramPrivate::widgetCoordinatesFromCurrentColorCielchD50()
const
493 const qreal scaleFactor =
494 (q_pointer->maximumWidgetSquareSize() - 2.0 * diagramBorder())
495 / (2.0 * m_rgbColorSpace->profileMaximumCielchD50Chroma());
497 PolarPointF(m_currentColorCielchD50.second, m_currentColorCielchD50.third).toCartesian();
500 currentColor.
x() * scaleFactor + diagramOffset(),
502 diagramOffset() - currentColor.
y() * scaleFactor);
515cmsCIELab ChromaHueDiagramPrivate::fromWidgetPixelPositionToLab(
const QPoint position)
const
517 const qreal scaleFactor =
518 (2.0 * m_rgbColorSpace->profileMaximumCielchD50Chroma())
519 / (q_pointer->maximumWidgetSquareSize() - 2.0 * diagramBorder());
524 constexpr qreal pixelValueShift = 0.5;
526 lab.L = m_currentColorCielchD50.first;
528 (position.
x() + pixelValueShift - diagramOffset()) * scaleFactor;
530 (position.
y() + pixelValueShift - diagramOffset()) * scaleFactor * (-1);
563void ChromaHueDiagramPrivate::setColorFromWidgetPixelPosition(
const QPoint position)
565 const cmsCIELab lab = fromWidgetPixelPositionToLab(position);
567 m_rgbColorSpace->reduceCielchD50ChromaToFitIntoGamut(
568 toGenericColorCielabD50(lab));
569 q_pointer->setCurrentColorCielchD50(myColor);
582bool ChromaHueDiagramPrivate::isWidgetPixelPositionWithinMouseSensibleCircle(
const QPoint position)
const
584 const qreal radius = PolarPointF(
596 const qreal diagramCircleRadius =
597 q_pointer->maximumWidgetSquareSize() / 2.0 - diagramBorder();
599 return (radius <= diagramCircleRadius);
666 const QPointF widgetCoordinatesFromCurrentColorCielchD50
667 {d_pointer->widgetCoordinatesFromCurrentColorCielchD50()};
673 d_pointer->m_chromaHueImageParameters.borderPhysical =
678 d_pointer->m_chromaHueImageParameters.imageSizePhysical =
681 const qreal temp = qBound(
static_cast<qreal
>(0),
682 d_pointer->m_currentColorCielchD50.first,
683 static_cast<qreal
>(100));
684 d_pointer->m_chromaHueImageParameters.lightness = temp;
685 d_pointer->m_chromaHueImageParameters.devicePixelRatioF =
687 d_pointer->m_chromaHueImageParameters.rgbColorSpace =
688 d_pointer->m_rgbColorSpace;
689 d_pointer->m_chromaHueImage.setImageParameters(
690 d_pointer->m_chromaHueImageParameters);
691 d_pointer->m_chromaHueImage.refreshAsync();
692 const qreal circleRadius =
696 bufferPainter.
setBrush(d_pointer->m_chromaHueImage.getCache());
710 d_pointer->m_wheelImage.setBorder(
714 d_pointer->m_wheelImage.setWheelThickness(
718 d_pointer->m_wheelImage.getImage()
723 if (d_pointer->m_isMouseEventActive) {
729 d_pointer->m_currentColorCielchD50.third)
731 myHandleInner.
ry() *= -1;
732 myHandleInner += d_pointer->diagramCenter();
734 PolarPointF(radius, d_pointer->m_currentColorCielchD50.third).toCartesian();
735 myHandleOuter.
ry() *= -1;
736 myHandleOuter += d_pointer->diagramCenter();
745 bufferPainter.
setPen(pen);
747 bufferPainter.
drawLine(myHandleInner, myHandleOuter);
756 bufferPainter.
setPen(pen);
757 bufferPainter.
setBrush(transparentBrush);
758 bufferPainter.
drawEllipse(widgetCoordinatesFromCurrentColorCielchD50,
762 const auto diagramOffset = d_pointer->diagramOffset();
763 const QPointF diagramCartesianCoordinatesFromCurrentColorCielchD50(
765 widgetCoordinatesFromCurrentColorCielchD50.x() - diagramOffset,
767 (widgetCoordinatesFromCurrentColorCielchD50.y() - diagramOffset) * (-1));
768 PolarPointF diagramPolarCoordinatesFromCurrentColorCielchD50(
769 diagramCartesianCoordinatesFromCurrentColorCielchD50);
773 diagramPolarCoordinatesFromCurrentColorCielchD50.radius() -
handleRadius();
774 if (lineRadius > 0) {
775 QPointF lineEndWidgetCoordinates =
780 diagramPolarCoordinatesFromCurrentColorCielchD50.angleDegree()
783 lineEndWidgetCoordinates.
ry() *= (-1);
784 lineEndWidgetCoordinates += d_pointer->diagramCenter();
787 d_pointer->diagramCenter(),
789 lineEndWidgetCoordinates);
826 bufferPainter.
setPen(pen);
827 bufferPainter.
setBrush(transparentBrush);
830 d_pointer->diagramCenter(),
849int ChromaHueDiagramPrivate::diagramBorder()
const
853 q_pointer->spaceForFocusIndicator()
855 + q_pointer->gradientThickness()
857 + 2 * q_pointer->handleOutlineThickness();
Base class for LCH diagrams.
qreal handleRadius() const
The radius of a circular handle.
QColor handleColorFromBackgroundLightness(qreal lightness) const
An appropriate color for a handle, depending on the background lightness.
int gradientMinimumLength() const
The minimum length of a color gradient.
int spaceForFocusIndicator() const
The empty space around diagrams reserved for the focus indicator.
void callUpdate()
An alternative to QWidget::update().
int handleOutlineThickness() const
The outline thickness of a handle.
int gradientThickness() const
The thickness of a color gradient.
QColor focusIndicatorColor() const
The color for painting focus indicators.
int maximumPhysicalSquareSize() const
The maximum possible size of a square within the widget, measured in physical pixels.
qreal maximumWidgetSquareSize() const
The maximum possible size of a square within the widget, measured in device-independent pixels.
A widget for selecting chroma and hue in LCH color space.
virtual void mouseMoveEvent(QMouseEvent *event) override
React on a mouse move event.
virtual void wheelEvent(QWheelEvent *event) override
React on a mouse wheel event.
void currentColorCielchD50Changed(const PerceptualColor::GenericColor &newCurrentColorCielchD50)
Notify signal for property currentColorCielchD50.
virtual QSize minimumSizeHint() const override
Recommended minimum size for the widget.
GenericColor currentColorCielchD50
Currently selected color.
virtual void keyPressEvent(QKeyEvent *event) override
React on key press events.
virtual ~ChromaHueDiagram() noexcept override
Default destructor.
virtual void paintEvent(QPaintEvent *event) override
Paint the widget.
virtual void mousePressEvent(QMouseEvent *event) override
React on a mouse press event.
virtual void mouseReleaseEvent(QMouseEvent *event) override
React on a mouse release event.
virtual void resizeEvent(QResizeEvent *event) override
React on a resize event.
Q_INVOKABLE ChromaHueDiagram(const QSharedPointer< PerceptualColor::RgbColorSpace > &colorSpace, QWidget *parent=nullptr)
The constructor.
virtual QSize sizeHint() const override
Recommended size for the widget.
void setCurrentColorCielchD50(const PerceptualColor::GenericColor &newCurrentColorCielchD50)
Setter for the currentColorCielchD50 property.
The namespace of this library.
void fill(Qt::GlobalColor color)
void setDevicePixelRatio(qreal scaleFactor)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
qreal devicePixelRatioF() const const
void drawEllipse(const QPoint ¢er, int rx, int ry)
void drawImage(const QPoint &point, const QImage &image)
void drawLine(const QLine &line)
void setBrush(Qt::BrushStyle style)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
void setCapStyle(Qt::PenCapStyle style)
void setColor(const QColor &color)