Krita Source Code Documentation
Loading...
Searching...
No Matches
KisScreenColorSampler.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2016 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include <QScreen>
8#include <QGuiApplication>
9#include <QApplication>
10#include <QScreen>
11#include <QColor>
12#include <QVBoxLayout>
13#include <QLabel>
14#include <QPushButton>
15#include <QWindow>
16#include <QTimer>
17
18#include <kis_canvas2.h>
19
20#include "kis_shared_ptr.h"
21#include "kis_icon.h"
22#include "kis_image.h"
23#include "kis_wrapped_rect.h"
24#include "KisDocument.h"
25#include "KisPart.h"
30#include <KisPortingUtils.h>
31
33
35{
36 QPushButton *screenColorSamplerButton = 0;
37 QLabel *lblScreenColorInfo = 0;
38
41
43
45
46 QWidget *inputGrabberWidget {nullptr};
47
48#ifdef Q_OS_WIN32
49 QTimer *updateTimer = 0;
50 QWindow dummyTransparentWindow;
51#endif
52
54 {
55 inputGrabberWidget = qApp->activeWindow();
56 }
57};
58
59KisScreenColorSampler::KisScreenColorSampler(bool showInfoLabel, QWidget *parent) : KisScreenColorSamplerBase(parent), m_d(new Private)
60{
61 QVBoxLayout *layout = new QVBoxLayout(this);
62 m_d->screenColorSamplerButton = new QPushButton();
63
64 m_d->screenColorSamplerButton->setMinimumHeight(25);
65 layout->addWidget(m_d->screenColorSamplerButton);
66
67 if (showInfoLabel) {
68 m_d->lblScreenColorInfo = new QLabel(QLatin1String("\n"));
69 layout->addWidget(m_d->lblScreenColorInfo);
70 }
71
72 layout->setContentsMargins(0, 0, 0, 0);
73
74 connect(m_d->screenColorSamplerButton, SIGNAL(clicked()), SLOT(sampleScreenColor()));
75
77
78#ifdef Q_OS_WIN32
79 m_d->updateTimer = new QTimer(this);
80 m_d->dummyTransparentWindow.resize(1, 1);
81 m_d->dummyTransparentWindow.setFlags(Qt::Tool | Qt::FramelessWindowHint);
82 connect(m_d->updateTimer, SIGNAL(timeout()), SLOT(updateColorSampling()));
83#endif
84}
85
89
91{
92 m_d->screenColorSamplerButton->setIcon(kisIcon("krita_tool_color_sampler"));
93}
94
96{
97 return m_d->currentColor;
98}
99
101{
102 return m_d->performRealColorSamplingOfCanvas;
103}
104
106{
107 m_d->performRealColorSamplingOfCanvas = enable;
108}
109
111{
112 m_d->updateInputGrabberWidget();
113 if (m_d->inputGrabberWidget == nullptr) {
115 return;
116 }
117
118 if (!m_d->colorSamplingEventFilter) {
119 m_d->colorSamplingEventFilter = new KisScreenColorSamplingEventFilter(this, this);
120 }
121 m_d->inputGrabberWidget->installEventFilter(m_d->colorSamplingEventFilter);
122 // If user pushes Escape, the last color before sampling will be restored.
123 m_d->beforeScreenColorSampling = currentColor();
124 m_d->inputGrabberWidget->grabMouse(Qt::CrossCursor);
125
126#ifdef Q_OS_WIN32 // excludes WinCE and WinRT
127 // On Windows mouse tracking doesn't work over other processes's windows
128 m_d->updateTimer->start(30);
129
130 // HACK: Because mouse grabbing doesn't work across processes, we have to have a dummy,
131 // invisible window to catch the mouse click, otherwise we will click whatever we clicked
132 // and loose focus.
133 m_d->dummyTransparentWindow.show();
134#endif
135 m_d->inputGrabberWidget->grabKeyboard();
136 /* With setMouseTracking(true) the desired color can be more precisely sampled,
137 * and continuously pushing the mouse button is not necessary.
138 */
139 m_d->inputGrabberWidget->setMouseTracking(true);
140
141 m_d->screenColorSamplerButton->setDisabled(true);
142
143 const QPoint globalPos = QCursor::pos();
145 updateColorLabelText(globalPos);
146}
147
149{
150 m_d->currentColor = c;
151}
152
154{
156 setCurrentColor(m_d->beforeScreenColorSampling);
158}
159
161{
162 // First check whether we're clicking on a Krita window for some real color sampling
163 if (m_d->performRealColorSamplingOfCanvas) {
164 Q_FOREACH(KisView *view, KisPart::instance()->views()) {
165 const KisCanvas2 *canvas = view->canvasBase();
166 const QWidget *canvasWidget = canvas->canvasWidget();
167 QPoint widgetPoint = canvasWidget->mapFromGlobal(p);
168
169 if (canvasWidget->visibleRegion().contains(widgetPoint)) {
170 KisImageWSP image = view->image();
171
172 if (image) {
173 QPointF imagePoint = canvas->coordinatesConverter()->widgetToImage(widgetPoint);
174 // sample from reference images first
175 KisSharedPtr<KisReferenceImagesLayer> referenceImageLayer = view->document()->referenceImagesLayer();
176
177 if (referenceImageLayer && canvas->referenceImagesDecoration()->visible()) {
178 QColor color = referenceImageLayer->getPixel(imagePoint);
179 if (color.isValid()) {
180 return KoColor(color, image->colorSpace());
181 }
182 }
183 if (image->wrapAroundModePermitted()) {
184 imagePoint = KisWrappedRect::ptToWrappedPt(imagePoint.toPoint(), image->bounds(), image->wrapAroundModeAxis());
185 }
186 KoColor sampledColor = KoColor();
187 image->projection()->pixel(imagePoint.x(), imagePoint.y(), &sampledColor);
188 return sampledColor;
189 }
190 }
191 }
192 }
193
194 KoColor col = KoColor();
195 QScreen *targetScreen = QGuiApplication::screenAt(p);
196
197 if (targetScreen) {
198 const QPoint screenPos = p - targetScreen->geometry().topLeft();
199
200 QImage grabImage = targetScreen->grabWindow(0, screenPos.x(), screenPos.y(), 1, 1).toImage();
201 col.fromQColor(QColor::fromRgb(grabImage.pixel(0, 0)));
202 }
203
204 return col;
205}
206
208{
209 if (m_d->lblScreenColorInfo) {
210 KoColor col = grabScreenColor(globalPos);
211 QString colname = KoColor::toQString(col);
212 QString location = QString::number(globalPos.x())+QString(", ")+QString::number(globalPos.y());
213 m_d->lblScreenColorInfo->setWordWrap(true);
214 m_d->lblScreenColorInfo->setText(location+QString(": ")+colname);
215 }
216}
217
219{
220 // If the cross is visible the grabbed color will be black most of the times
221 //cp->setCrossVisible(!cp->geometry().contains(e->pos()));
222
223 continueUpdateColorSampling(e->globalPos());
224 return true;
225}
226
228{
229 setCurrentColor(grabScreenColor(e->globalPos()));
232 return true;
233}
234
236{
237 if (e->matches(QKeySequence::Cancel)) {
238 cancel();
239 } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
240 setCurrentColor(grabScreenColor(QCursor::pos()));
243 }
244 e->accept();
245 return true;
246}
247
249{
250 // HACK: see class KisGrabKeyboardFocusRecoveryWorkaround
252
253 m_d->inputGrabberWidget->removeEventFilter(m_d->colorSamplingEventFilter);
254 m_d->inputGrabberWidget->releaseMouse();
255#ifdef Q_OS_WIN32
256 m_d->updateTimer->stop();
257 m_d->dummyTransparentWindow.setVisible(false);
258#endif
259 m_d->inputGrabberWidget->releaseKeyboard();
260 m_d->inputGrabberWidget->setMouseTracking(false);
261
262 if (m_d->lblScreenColorInfo) {
263 m_d->lblScreenColorInfo->setText(QLatin1String("\n"));
264 }
265
266 m_d->screenColorSamplerButton->setDisabled(false);
267}
268
270{
271 QWidget::changeEvent(e);
272}
273
275{
276 static QPoint lastGlobalPos;
277 QPoint newGlobalPos = QCursor::pos();
278 if (lastGlobalPos == newGlobalPos)
279 return;
280 lastGlobalPos = newGlobalPos;
281
282 if (!rect().contains(mapFromGlobal(newGlobalPos))) { // Inside the dialog mouse tracking works, handleColorSamplingMouseMove will be called
283 continueUpdateColorSampling(newGlobalPos);
284#ifdef Q_OS_WIN32
285 m_d->dummyTransparentWindow.setPosition(newGlobalPos);
286#endif
287 }
288}
289
291{
292 const KoColor color = grabScreenColor(globalPos);
293 // QTBUG-39792, do not change standard, custom color selectors while moving as
294 // otherwise it is not possible to preselect a custom cell for assignment.
295 setCurrentColor(color);
297 updateColorLabelText(globalPos);
298}
299
300// Event filter to be installed on the dialog while in color-sampling mode.
302 : QObject(parent)
303 , m_w(w)
304{}
305
307{
308 switch (event->type()) {
309 case QEvent::MouseMove:
310 return m_w->handleColorSamplingMouseMove(static_cast<QMouseEvent *>(event));
311 case QEvent::MouseButtonRelease:
312 return m_w->handleColorSamplingMouseButtonRelease(static_cast<QMouseEvent *>(event));
313 case QEvent::KeyPress:
314 return m_w->handleColorSamplingKeyPress(static_cast<QKeyEvent *>(event));
315 default:
316 break;
317 }
318 return false;
319}
320
321// Register the color sampler factory with the internal color selector
324}
325
const Params2D p
KIS_DECLARE_STATIC_INITIALIZER
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KisReferenceImagesDecorationSP referenceImagesDecoration() const
KisCoordinatesConverter * coordinatesConverter
KisAbstractCanvasWidget * canvasWidget
_Private::Traits< T >::Result widgetToImage(const T &obj) const
static void setScreenColorSamplerFactory(std::function< KisScreenColorSamplerBase *(QWidget *)> f)
static KisGrabKeyboardFocusRecoveryWorkaround * instance()
const KoColorSpace * colorSpace() const
WrapAroundAxis wrapAroundModeAxis() const
KisPaintDeviceSP projection() const
QRect bounds() const override
bool wrapAroundModePermitted() const
bool pixel(qint32 x, qint32 y, QColor *c) const
static KisPart * instance()
Definition KisPart.cpp:131
The KisScreenColorSampler class Based on the original QColorDialog's screen color picker,...
void sigNewColorHovered(KoColor c)
void changeEvent(QEvent *event) override
const QScopedPointer< Private > m_d
void sigNewColorSampled(KoColor c)
void setPerformRealColorSamplingOfCanvas(bool enable)
void updateColorLabelText(const QPoint &globalPos)
KisScreenColorSampler(bool showInfoLabel=false, QWidget *parent=0)
void continueUpdateColorSampling(const QPoint &globalPos)
bool handleColorSamplingMouseMove(QMouseEvent *e)
KoColor grabScreenColor(const QPoint &p)
void updateIcons() override
reloads icon(s) when theme is updated
bool performRealColorSamplingOfCanvas() const
bool handleColorSamplingMouseButtonRelease(QMouseEvent *e)
bool handleColorSamplingKeyPress(QKeyEvent *e)
static KisScreenColorSampler * createScreenColorSampler(QWidget *parent=0)
bool eventFilter(QObject *, QEvent *event) override
KisScreenColorSamplingEventFilter(KisScreenColorSampler *w, QObject *parent=0)
KisCanvas2 * canvasBase() const
Definition KisView.cpp:427
KisImageWSP image() const
Definition KisView.cpp:432
QPointer< KisDocument > document
Definition KisView.cpp:121
static QString toQString(const KoColor &color)
toQString create a user-visible string of the channel names and the channel values
Definition KoColor.cpp:655
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
#define kisIcon(name)
Definition kis_icon.h:26
KisScreenColorSamplingEventFilter * colorSamplingEventFilter
static QPoint ptToWrappedPt(QPoint pt, const QRect &wrapRect, WrapAroundAxis wrapAxis)