12#include <QRadialGradient>
13#include <QConicalGradient>
15#include <QResizeEvent>
32 , m_inverseSaturation(false)
33 , m_selectedColor(m_colorConverter)
34 , m_fgColor(m_colorConverter)
35 , m_bgColor(m_colorConverter)
37 , m_gamutMaskOn(false)
38 , m_currentGamutMask(nullptr)
39 , m_maskPreviewActive(true)
40 , m_gamutMaskViewTransform(QTransform())
41 , m_widgetUpdatesSelf(false)
42 , m_isDirtyWheel(false)
43 , m_isDirtyLightStrip(false)
44 , m_isDirtyGamutMask(false)
45 , m_isDirtyColorPreview(false)
55 using namespace std::placeholders;
68#ifdef DEBUG_ARC_SELECTOR
140#ifdef DEBUG_ARC_SELECTOR
141 dbgPlugins <<
"KisColorSelector::setFgColor: m_fgColor set to:"
146 dbgPlugins <<
"KisColorSelector::setFgColor: m_selectedColor set to:"
162#ifdef DEBUG_ARC_SELECTOR
163 dbgPlugins <<
"KisColorSelector::setBgColor: m_bgColor set to:"
192#ifdef DEBUG_ARC_SELECTOR
274 qreal w = viewRect.width() / 2.0;
275 qreal h = viewRect.height() / 2.0;
277 qreal x = pt.x() + 1.0;
278 qreal y = (pt.y()) + 1.0;
280 return QPointF(x*w, y*h);
285 qreal w = viewRect.width() / 2.0;
286 qreal h = viewRect.height() / 2.0;
287 qreal x = pt.x() - (viewRect.x() + w);
288 qreal y = pt.y() - (viewRect.y() + h);
289 return QPointF(x/w, y/h);
296 radius = 1.0 - color.
getS();
298 radius = color.
getS();
302 qreal x = hueCoord.x()*radius;
303 qreal y = hueCoord.y()*radius;
310 qreal angle = std::atan2(-y, -x);
312#ifdef DEBUG_ARC_SELECTOR
313 dbgPlugins <<
"KisColorSelector::mapCoordToAngle: "
316 <<
"angle:" << angle;
324 qreal angle = hue * 2.0 *
M_PI -
M_PI;
325 qreal x = std::cos(angle);
326 qreal y = std::sin(angle);
344 light = qreal(1) - qBound(qreal(0), light, qreal(1));
352 if (clickedLightPiece >= 0) {
372 return hue.
scaled(0.0, 1.0);
377 saturation = qBound(qreal(0), saturation, qreal(1));
379 return qint8(saturation * qreal(
getNumRings() - 1));
384 qreal
length = std::sqrt(pt.x()*pt.x() + pt.y()*pt.y());
396 qreal sat = qreal(saturationIdx) / qreal(
getNumRings()-1);
402 qreal LIGHT_STRIP_RATIO = 0.075;
405 LIGHT_STRIP_RATIO = 0.25;
408 int width = QWidget::width();
409 int height = QWidget::height();
410 int size = qMin(width, height);
411 int stripThick = int(size * LIGHT_STRIP_RATIO);
415 size = qMin(width, height);
417 int x = (width - size) / 2;
418 int y = (height - size) / 2;
420 m_widgetArea = QRect(0, 0, QWidget::width(), QWidget::height());
424 m_renderBuffer = QImage(size*devicePixelRatioF(), size*devicePixelRatioF(), QImage::Format_ARGB32_Premultiplied);
425 m_colorPreviewBuffer = QImage(QWidget::width()*devicePixelRatioF(), QWidget::height()*devicePixelRatioF(), QImage::Format_ARGB32_Premultiplied);
426 m_maskBuffer = QImage(size*devicePixelRatioF(), size*devicePixelRatioF(), QImage::Format_ARGB32_Premultiplied);
427 m_lightStripBuffer = QImage(stripThick*devicePixelRatioF(), QWidget::height()*devicePixelRatioF(), QImage::Format_ARGB32_Premultiplied);
451 for(
int i=0; i<numRings; ++i) {
452 qreal innerRadius = qreal(i) / qreal(numRings);
453 qreal outerRadius = qreal(i+1) / qreal(numRings);
454 qreal saturation = qreal(i) / qreal(numRings-1);
465 int numParts = qMax<int>(numPieces, 1);
469 ring.
pieced.resize(numParts);
471 qreal partSize = 360.0 / qreal(numParts);
472 QRectF outerRect(-outerRadius, -outerRadius, outerRadius*2.0, outerRadius*2.0);
473 QRectF innerRect(-innerRadius, -innerRadius, innerRadius*2.0, innerRadius*2.0);
475 for(
int i=0; i<numParts; ++i) {
476 qreal aBeg = partSize*i;
477 qreal aEnd = aBeg + partSize;
479 aBeg -= partSize / 2.0;
480 aEnd -= partSize / 2.0;
482 ring.
pieced[i] = QPainterPath();
483 ring.
pieced[i].arcMoveTo(innerRect, aBeg);
484 ring.
pieced[i].arcTo(outerRect, aBeg, partSize);
485 ring.
pieced[i].arcTo(innerRect, aEnd,-partSize);
514#ifdef DEBUG_ARC_SELECTOR
515 dbgPlugins <<
"KisColorSelector::requestUpdateColorAndPreview: requesting update to: "
516 <<
"H:" << color.
getH()
517 <<
"S:" << color.
getS()
518 <<
"X:" << color.
getX();
528 if (selectAsFgColor) {
540#ifdef DEBUG_ARC_SELECTOR
541 dbgPlugins <<
"KisColorSelector::slotUpdateColorAndPreview: m_selectedColor set to:"
554 painter.setRenderHint(QPainter::Antialiasing,
true);
555 painter.resetTransform();
556 painter.translate(
rect.width()/2,
rect.height()/2);
558 if (ring.
pieced.size() > 1) {
560 mirror.rotate(180, Qt::YAxis);
561 painter.setTransform(mirror,
true);
562 painter.scale(
rect.width()/2,
rect.height()/2);
565 QBrush brush(Qt::SolidPattern);
567 for(
int i=0; i<ring.
pieced.size(); ++i) {
568 qreal hue = qreal(i) / qreal(ring.
pieced.size());
569 hue = (hue >= 1.0) ? (hue - 1.0) : hue;
570 hue = (hue < 0.0) ? (hue + 1.0) : hue;
577 painter.setPen(clearMaskPen);
579 painter.setPen(normalPen);
587 painter.setBrush(brush);
589 painter.drawPath(ring.
pieced[i]);
603 QConicalGradient gradient(0, 0, 0);
605 for(
int i=0; i<=6; ++i) {
606 qreal hue = qreal(i) / 6.0;
609 gradient.setColorAt(hue, colors[i].toQColor());
612 painter.scale(
rect.width()/2,
rect.height()/2);
613 painter.fillPath(ring.
pieced[0], QBrush(gradient));
623 painter.setRenderHint(QPainter::Antialiasing,
true);
624 painter.resetTransform();
626 painter.scale(
rect.width()/2,
rect.height()/2);
631 painter.setPen(normalPen);
635 painter.resetTransform();
638 mirror.rotate(180, Qt::YAxis);
639 painter.setTransform(mirror,
true);
640 painter.scale(
rect.width()/2,
rect.height()/2);
648 painter.setPen(selectedPen);
655 painter.drawEllipse(QRectF(-rad, -rad, rad*2.0, rad*2.0));
668 painter.setPen(selectedPen);
669 painter.drawEllipse(QRectF(-iRad, -iRad, iRad*2.0, iRad*2.0));
670 painter.drawEllipse(QRectF(-oRad, -oRad, oRad*2.0, oRad*2.0));
673 painter.drawLine(QPointF(lineCoords.x()*iRad, lineCoords.y()*iRad), QPointF(lineCoords.x()*oRad, lineCoords.y()*oRad));
682 qreal penSize = qreal(qMin(QWidget::width(), QWidget::height())) / 200.0;
683 qreal penSizeSmall = penSize / 1.2;
688 int rectSize =
rect.height();
691 painter.resetTransform();
692 painter.setRenderHint(QPainter::Antialiasing,
true);
695 matrix.translate(
rect.x(),
rect.y());
696 matrix.scale(
rect.width(),
rect.height());
698 qreal rectColorLeftX;
699 qreal rectColorWidth;
702 rectColorLeftX = 0.6;
703 rectColorWidth = 0.4;
705 rectColorLeftX = 0.0;
706 rectColorWidth = 1.0;
714 qreal diff = t2 - t1;
716 QRectF rectColor = QRectF(rectColorLeftX, t1, rectColorWidth, diff);
717 rectColor = matrix.mapRect(rectColor);
719 valueScaleColor.
setX(light);
720 painter.fillRect(rectColor, valueScaleColor.
toQColor());
729 painter.setPen(selectedPen);
730 painter.drawRect(rectColor);
734 painter.setRenderHint(QPainter::Antialiasing,
false);
736 for(
int i=0; i<rectSize; ++i) {
737 int y =
rect.y() + i;
738 qreal light = 1.0 - (qreal(i) / qreal(rectSize-1));
739 valueScaleColor.
setX(light);
740 painter.setPen(QPen(QBrush(valueScaleColor.
toQColor()), penSize));
741 painter.drawLine(
rect.left(), y,
rect.right(), y);
746 painter.setRenderHint(QPainter::Antialiasing,
false);
750 int y =
rect.y() + int(rectSize * fgColorValue);
752 painter.drawLine(
rect.left(), y,
rect.right(), y);
754 painter.drawLine(
rect.left(), y+2*penSizeSmall,
rect.right(), y+2*penSizeSmall);
758 painter.setRenderHint(QPainter::Antialiasing,
true);
762 valueScalePieces = 11;
765 QFont font = painter.font();
766 QFontMetrics fm = painter.fontMetrics();
768 while ((retries > 0) && (fm.boundingRect(
"100%").width() >
rect.width()*rectColorLeftX)) {
769 font.setPointSize(font.pointSize() - 1);
770 painter.setFont(font);
771 fm = painter.fontMetrics();
775 for(
int i=0; i<valueScalePieces; ++i) {
776 qreal t1 = qreal(i) / qreal(valueScalePieces);
777 qreal t2 = qreal(i+1) / qreal(valueScalePieces);
778 qreal light = 1.0 - (qreal(i) / qreal(valueScalePieces-1));
779 qreal diff = t2 - t1;
781 grayScaleColor.
setX(light);
783 QRectF rectValue = QRectF(0.0, t1, rectColorLeftX, diff);
784 rectValue = matrix.mapRect(rectValue);
786 painter.fillRect(rectValue, grayScaleColor.
toQColor());
793 valueNumber = 100 - round(pow(pow(grayScaleColor.
getX(),
m_lumaGamma), 1.0/2.2)*100);
795 valueNumber = 100 - grayScaleColor.
getX()*100;
798 if (valueNumber < 55) {
799 painter.setPen(QPen(QBrush(
COLOR_DARK), penSize));
801 painter.setPen(QPen(QBrush(
COLOR_LIGHT), penSize));
804 painter.drawText(rectValue, Qt::AlignRight|Qt::AlignBottom, QString(
"%1%").arg(QString::number(valueNumber)));
816 painter.setRenderHint(QPainter::Antialiasing,
true);
817 painter.resetTransform();
819 painter.scale(
rect.width()/2,
rect.height()/2);
823#ifdef DEBUG_ARC_SELECTOR
826 <<
"-> coord X:" << fgColorPos.x() <<
" Y:" << fgColorPos.y();
830 painter.drawEllipse(fgColorPos, 0.05, 0.05);
833 painter.drawEllipse(fgColorPos, 0.04, 0.04);
841 painter.setRenderHint(QPainter::Antialiasing,
true);
843 painter.resetTransform();
844 painter.translate(
rect.width()/2,
rect.height()/2);
845 painter.scale(
rect.width()/2,
rect.height()/2);
847 painter.setPen(Qt::NoPen);
850 painter.drawEllipse(QPointF(0,0), 1.0, 1.0);
854 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
857 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
866 painter.setRenderHint(QPainter::Antialiasing,
true);
870 int bgSide = qMin(
rect.width()*0.15,
rect.height()*0.15);
873 QPointF bgPolyPoints[3] = {
874 QPointF(
rect.width(),
rect.height()),
875 QPointF(
rect.width()-bgSide,
rect.height()),
876 QPointF(
rect.width(),
rect.height()-bgSide)
881 painter.drawPolygon(bgPolyPoints, 3);
889 QPainter wdgPainter(
this);
951#ifdef DEBUG_ARC_SELECTOR
952 dbgPlugins <<
"KisColorSelector::mousePressEvent: m_widgetUpdatesSelf = true";
963 if (clickedLightPiece >= 0) {
974 color.setHSX(angle.scaled(0.0, 1.0)
979#ifdef DEBUG_ARC_SELECTOR
980 dbgPlugins <<
"KisColorSelector::mousePressEvent: picked color: "
981 <<
"H:" << color.getH()
982 <<
"S:" << color.getS()
983 <<
"X:" << color.getX();
1003 if (clickedLightPiece >= 0) {
1015 color.setHSX(angle.scaled(0.0, 1.0)
1040 color.setH(
getHue(hueIndex));
1042 color.setH(angle.scaled(0.0, 1.0));
1061#ifdef DEBUG_ARC_SELECTOR
1062 dbgPlugins <<
"KisColorSelector::ReleasePressEvent: m_widgetUpdatesSelf = false";
1076#ifdef DEBUG_ARC_SELECTOR
1077 dbgPlugins <<
"KisColorSelector::leaveEvent: m_widgetUpdatesSelf = false";
qreal length(const QPointF &vec)
float value(const T *src, size_t ch)
const KoColorSpace * colorSpace() const
qreal getLight(const QPointF &pt) const
void setColorConverter(KisDisplayColorConverter *colorConverter)
qint8 getLightIndex(const QPointF &pt) const
QPointF mapCoordToUnit(const QPointF &pt, const QRectF &viewRect) const
qint8 getSaturationIndex(const QPointF &pt) const
KisSignalCompressorWithParam< QPair< KisColor, Acs::ColorRole > > ColorCompressorType
void setDefaultSaturationSteps(int num)
qint8 m_selectedLightPiece
void setNumLightPieces(int num)
void drawRing(QPainter &painter, ColorRing &wheel, const QRect &rect)
Radian mapCoordToAngle(qreal x, qreal y) const
qint32 getNumLightPieces() const
void setColorSpace(KisColor::Type type)
QVector< ColorRing > m_colorRings
void drawBlip(QPainter &painter, const QRect &rect)
QPointF mapCoordToView(const QPointF &pt, const QRectF &viewRect) const
void sigFgColorChanged(const KisColor &color)
quint8 m_defaultSaturationSteps
QImage m_lightStripBuffer
void mouseMoveEvent(QMouseEvent *) override
void recalculateRings(quint8 numRings, quint8 numPieces)
void setInverseSaturation(bool inverse)
KoGamutMaskSP gamutMask()
KoGamutMaskSP m_currentGamutMask
Qt::MouseButtons m_pressedButtons
qreal getSaturation(int saturationIdx) const
KisColorSelector(KisColorSelectorConfiguration conf, QWidget *parent=0)
void recalculateAreas(quint8 numLightPieces)
void leaveEvent(QEvent *e) override
void setEnforceGamutMask(bool enforce)
bool m_isDirtyColorPreview
quint8 m_defaultValueScaleSteps
void setGamutMaskOn(bool gamutMaskOn)
qreal getHue(int hueIdx, Radian shift=0.0f) const
void resizeEvent(QResizeEvent *) override
QScopedPointer< ColorCompressorType > m_updateColorCompressor
void setDefaultHueSteps(int num)
void setDefaultValueScaleSteps(int num)
void requestUpdateColorAndPreview(const KisColor &color, Acs::ColorRole role)
QPointF mapHueToAngle(qreal hue) const
void sigBgColorChanged(const KisColor &color)
QTransform m_gamutMaskViewTransform
void setNumPieces(int num)
bool m_showValueScaleNumbers
void setLumaCoefficients(qreal lR, qreal lG, qreal lB, qreal lGamma)
qint32 getNumRings() const
KisColor::Type m_colorSpace
void mousePressEvent(QMouseEvent *) override
bool colorIsClear(const KisColor &color)
void setNumRings(int num)
void selectColor(const KisColor &color)
void setFgColor(const KoColor &fgColor)
void slotUpdateColorAndPreview(QPair< KisColor, Acs::ColorRole > color)
void drawGamutMaskShape(QPainter &painter, const QRect &rect)
QPointF mapColorToUnit(const KisColor &color, bool invertSaturation=true) const
void setBgColor(const KoColor &bgColor)
KisDisplayColorConverter * m_colorConverter
void mouseReleaseEvent(QMouseEvent *) override
void setGamutMask(KoGamutMaskSP gamutMask)
void setShowValueScaleNumbers(bool value)
void drawOutline(QPainter &painter, const QRect &rect)
void setLight(qreal light=0.0f)
void paintEvent(QPaintEvent *) override
void setShowBgColor(bool value)
void createRing(ColorRing &wheel, quint8 numPieces, qreal innerRadius, qreal outerRadius)
qint8 getHueIndex(Radian hue) const
void drawColorPreview(QPainter &painter, const QRect &rect)
void drawLightStrip(QPainter &painter, const QRect &rect)
qint32 getNumPieces() const
KisRadian< qreal > Radian
QImage m_colorPreviewBuffer
void setHSX(qreal h, qreal s, qreal x)
void writeEntry(const QString &name, const T &value)
T readEntry(const QString &name, const T &defaultValue=T())
TReal scaled(const TReal &min, const TReal &max) const
static const int MIN_NUM_SATURATION_RINGS
static const qreal DEFAULT_LUMA_R
static const int MAX_NUM_HUE_PIECES
static const int DEFAULT_VALUE_SCALE_STEPS
static const QColor COLOR_DARK
static const int MAX_NUM_LIGHT_PIECES
static const int MIN_NUM_HUE_PIECES
static const QColor COLOR_MASK_CLEAR
static const int DEFAULT_SATURATION_STEPS
static const QColor COLOR_SELECTED_LIGHT
static const QColor COLOR_LIGHT
static const int MAX_NUM_SATURATION_RINGS
static const qreal DEFAULT_LUMA_GAMMA
static const qreal DEFAULT_LUMA_B
static const int DEFAULT_HUE_STEPS
static const QColor COLOR_MASK_FILL
static const int MIN_NUM_LIGHT_PIECES
static const QColor COLOR_NORMAL_OUTLINE
static const qreal DEFAULT_LUMA_G
static const QColor COLOR_SELECTED_DARK
ColorRole buttonsToRole(Qt::MouseButton button, Qt::MouseButtons buttons)
bool update(QSpinBox *spinBox)
QVector< QPainterPath > pieced