Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_color_selector_ring.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2010 Adam Celarek <kdedev at xibo dot at>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QPainter>
10#include <QMouseEvent>
11
12#include <Eigen/Core>
13#include <cmath>
14
15#include "KoColor.h"
17
18
23
25{
26 return (qMin(width(), height())/2)*m_innerRingRadiusFraction;
27}
28
30{
31 m_innerRingRadiusFraction = newFraction;
32}
33
35{
36 int outerRadiusSquared = qMin(width(), height())/2;
37 int innerRadiusSquared = innerRadius();
38 outerRadiusSquared*=outerRadiusSquared;
39 innerRadiusSquared*=innerRadiusSquared;
40
41
42 Eigen::Vector2i relativeVector(x-width()/2, y-height()/2);
43
44 if(relativeVector.squaredNorm() < outerRadiusSquared
45 && relativeVector.squaredNorm() > innerRadiusSquared) {
46 return true;
47 }
48 return false;
49}
50
51void KisColorSelectorRing::paint(QPainter* painter)
52{
53 qreal devicePixelRatioF = painter->device()->devicePixelRatioF();
54 if(isDirty()) {
56 m_cachedSize=qMin(width(), height());
57 colorCache();
58 paintCache(devicePixelRatioF);
59 }
60
61 int size = qMin(width(), height());
62 if(m_cachedSize!=size) {
63 m_cachedSize=size;
64 paintCache(devicePixelRatioF);
65 }
66
67 QPoint startPoint = QPoint(width()/2 - (m_pixelCache.width()/(2*devicePixelRatioF)),
68 height()/2 - (m_pixelCache.height()/(2*devicePixelRatioF)));
69 painter->drawImage(startPoint, m_pixelCache);
70
71
72 // paint blip
73 if(m_parent->displayBlip()) {
74 qreal angle;
75 int y_start, y_end, x_start, x_end;
76 angle=m_lastHue*2.*M_PI+(M_PI);
77 y_start=innerRadius()*sin(angle)+height()/2;
78 y_end=outerRadius()*sin(angle)+height()/2;
79 x_start=innerRadius()*cos(angle)+width()/2;
80 x_end=outerRadius()*cos(angle)+width()/2;
81
82 painter->setPen(QColor(0,0,0));
83 painter->drawLine(x_start, y_start, x_end, y_end);
84
85 angle+=M_PI/180.;
86 y_start=innerRadius()*sin(angle)+height()/2;
87 y_end=outerRadius()*sin(angle)+height()/2;
88 x_start=innerRadius()*cos(angle)+width()/2;
89 x_end=outerRadius()*cos(angle)+width()/2;
90
91 painter->setPen(QColor(255,255,255));
92 painter->drawLine(x_start, y_start, x_end, y_end);
93 }
94}
95
97{
98 QPoint ringMiddle(width()/2, height()/2);
99 QPoint ringCoord = QPoint(x, y)-ringMiddle;
100 qreal hue = std::atan2(qreal(ringCoord.y()), qreal(ringCoord.x()))+(M_PI);
101 hue/=2.*M_PI;
102 Q_EMIT paramChanged(hue, -1, -1, -1, -1, -1, -1, -1, -1);
103 m_lastHue=hue;
104 Q_EMIT update();
105
107 return m_parent->converter()->fromHsyF(hue, 1.0, 0.55, R, G, B, Gamma);
108 }
109 return m_parent->converter()->fromHsvF(hue, 1.0, 1.0);
110}
111
113{
114 qreal h, s, v;
115 KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector");
116 R = cfg.readEntry("lumaR", 0.2126);
117 G = cfg.readEntry("lumaG", 0.7152);
118 B = cfg.readEntry("lumaB", 0.0722);
119 Gamma = cfg.readEntry("gamma", 2.2);
120
122 m_parent->converter()->getHsyF(color, &h, &s, &v, R, G, B, Gamma);
123 }
124 else {
125 m_parent->converter()->getHsvF(color, &h, &s, &v);
126 }
127
128 Q_EMIT paramChanged(h, -1, -1, -1, -1, -1, -1, -1, -1);
129
130 // selector keeps the position on the ring if hue is undefined (when saturation is 0)
131 if (!qFuzzyCompare(s, 0.0)) {
132 m_lastHue=h;
133 }
134
135 Q_EMIT update();
136
138}
139
140void KisColorSelectorRing::paintCache(qreal devicePixelRatioF)
141{
142 QImage cache(m_cachedSize*devicePixelRatioF, m_cachedSize*devicePixelRatioF, QImage::Format_ARGB32_Premultiplied);
143 cache.setDevicePixelRatio(devicePixelRatioF);
144
145 Eigen::Vector2i center(cache.width()/2., cache.height()/2.);
146
147 int outerRadiusHighDPI = outerRadius()*devicePixelRatioF;
148 int innerRadiusHighDPI = innerRadius()*devicePixelRatioF;
149
150
151 for(int x=0; x<cache.width(); x++) {
152 for(int y=0; y<cache.height(); y++) {
153 Eigen::Vector2i currentPoint((float)x, (float)y);
154 Eigen::Vector2i relativeVector = currentPoint-center;
155
156 qreal currentRadius = relativeVector.squaredNorm();
157 currentRadius=sqrt(currentRadius);
158
159 if(currentRadius < outerRadiusHighDPI+1
160 && currentRadius > innerRadiusHighDPI-1)
161 {
162
163 float angle = std::atan2((float)relativeVector.y(), (float)relativeVector.x())+((float)M_PI);
164 angle/=2*((float)M_PI);
165 angle*=359.f;
166 if(currentRadius < outerRadiusHighDPI
167 && currentRadius > innerRadiusHighDPI) {
168 cache.setPixel(x, y, m_cachedColors.at(angle));
169 }
170 else {
171 // draw antialiased border
172 qreal coef=1.;
173 if(currentRadius > outerRadiusHighDPI) {
174 // outer border
175 coef-=currentRadius;
176 coef+=outerRadiusHighDPI;
177 }
178 else {
179 // inner border
180 coef+=currentRadius;
181 coef-=innerRadiusHighDPI;
182 }
183 coef=qBound(qreal(0.), coef, qreal(1.));
184 int red=qRed(m_cachedColors.at(angle));
185 int green=qGreen(m_cachedColors.at(angle));
186 int blue=qBlue(m_cachedColors.at(angle));
187
188 // the format is premultiplied, so we have to take care of that
189 QRgb color = qRgba(red*coef, green*coef, blue*coef, 255*coef);
190 cache.setPixel(x, y, color);
191 }
192 }
193 else {
194 cache.setPixel(x, y, qRgba(0,0,0,0));
195 }
196 }
197 }
198 m_pixelCache = cache;
199}
200
202{
203 Q_ASSERT(m_cachedColorSpace);
204 m_cachedColors.clear();
205 KoColor koColor;
206 QColor qColor;
207 for(int i=0; i<360; i++) {
209 koColor = m_parent->converter()->fromHsyF(1.0 * i / 360.0, 1.0, 0.55, R, G, B, Gamma);
210 } else {
211 koColor = m_parent->converter()->fromHsvF(1.0 * i / 360.0, 1.0, 1.0);
212 }
213 qColor = m_parent->converter()->toQColor(koColor);
214 m_cachedColors.append(qColor.rgb());
215 }
216}
217
219{
220 return m_cachedSize/2-1;
221}
qreal v
KisDisplayColorConverter * converter() const
const KoColorSpace * colorSpace() const
void update()
request for repaint, for instance, if the hue changes.
bool isDirty() const
returns true, if ether the color space, the size or the parameters have changed since the last paint ...
virtual void setColor(const KoColor &color)
set the color, blibs etc
void paramChanged(qreal hue, qreal hsvSaturation, qreal value, qreal hslSaturation, qreal lightness, qreal hsiSaturation, qreal intensity, qreal hsySaturation, qreal luma)
-1, if unaffected
KisColorSelectorRing(KisColorSelector *parent)
bool containsPointInComponentCoords(int x, int y) const override
void setInnerRingRadiusFraction(qreal newFraction)
void setColor(const KoColor &color) override
set the color, blibs etc
const KoColorSpace * m_cachedColorSpace
void paint(QPainter *) override
KoColor selectColor(int x, int y) override
this method must be overloaded to return the color at position x/y and draw a marker on that position
void paintCache(qreal devicePixelRatioF)
bool displayBlip() const
void getHsyF(const KoColor &srcColor, qreal *h, qreal *s, qreal *y, qreal R=0.2126, qreal G=0.7152, qreal B=0.0722, qreal gamma=2.2)
void getHsvF(const KoColor &srcColor, qreal *h, qreal *s, qreal *v, qreal *a=0)
QColor toQColor(const KoColor &c, bool proofToPaintColors=false) const
KoColor fromHsyF(qreal h, qreal s, qreal y, qreal R=0.2126, qreal G=0.7152, qreal B=0.0722, qreal gamma=2.2)
KoColor fromHsvF(qreal h, qreal s, qreal v, qreal a=1.0)
static bool qFuzzyCompare(half p1, half p2)
unsigned int QRgb
#define M_PI
Definition kis_global.h:111