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 // KisReferenceImagesLayer::getPixel use document coordinate
175 QPointF docPoint = canvas->coordinatesConverter()->widgetToDocument(widgetPoint);
176 // sample from reference images first
177 KisSharedPtr<KisReferenceImagesLayer> referenceImageLayer = view->document()->referenceImagesLayer();
178
179 if (referenceImageLayer && canvas->referenceImagesDecoration()->visible()) {
180 KoColor color = referenceImageLayer->getPixelForDocPoint(docPoint);
181 if (color.opacityU8() > 0) {
182 return color.convertedTo(image->colorSpace());
183 }
184 }
185 if (image->wrapAroundModePermitted()) {
186 imagePoint = KisWrappedRect::ptToWrappedPt(imagePoint.toPoint(), image->bounds(), image->wrapAroundModeAxis());
187 }
188 KoColor sampledColor = KoColor();
189 image->projection()->pixel(imagePoint.x(), imagePoint.y(), &sampledColor);
190 return sampledColor;
191 }
192 }
193 }
194 }
195
196 KoColor col = KoColor();
197 QScreen *targetScreen = QGuiApplication::screenAt(p);
198
199 if (targetScreen) {
200 const QPoint screenPos = p - targetScreen->geometry().topLeft();
201
202 QImage grabImage = targetScreen->grabWindow(0, screenPos.x(), screenPos.y(), 1, 1).toImage();
203 col.fromQColor(QColor::fromRgb(grabImage.pixel(0, 0)));
204 }
205
206 return col;
207}
208
210{
211 if (m_d->lblScreenColorInfo) {
212 KoColor col = grabScreenColor(globalPos);
213 QString colname = KoColor::toQString(col);
214 QString location = QString::number(globalPos.x())+QString(", ")+QString::number(globalPos.y());
215 m_d->lblScreenColorInfo->setWordWrap(true);
216 m_d->lblScreenColorInfo->setText(location+QString(": ")+colname);
217 }
218}
219
221{
222 // If the cross is visible the grabbed color will be black most of the times
223 //cp->setCrossVisible(!cp->geometry().contains(e->pos()));
224
225 continueUpdateColorSampling(e->globalPos());
226 return true;
227}
228
230{
231 setCurrentColor(grabScreenColor(e->globalPos()));
234 return true;
235}
236
238{
239 if (e->matches(QKeySequence::Cancel)) {
240 cancel();
241 } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
242 setCurrentColor(grabScreenColor(QCursor::pos()));
245 }
246 e->accept();
247 return true;
248}
249
251{
252 // HACK: see class KisGrabKeyboardFocusRecoveryWorkaround
254
255 m_d->inputGrabberWidget->removeEventFilter(m_d->colorSamplingEventFilter);
256 m_d->inputGrabberWidget->releaseMouse();
257#ifdef Q_OS_WIN32
258 m_d->updateTimer->stop();
259 m_d->dummyTransparentWindow.setVisible(false);
260#endif
261 m_d->inputGrabberWidget->releaseKeyboard();
262 m_d->inputGrabberWidget->setMouseTracking(false);
263
264 if (m_d->lblScreenColorInfo) {
265 m_d->lblScreenColorInfo->setText(QLatin1String("\n"));
266 }
267
268 m_d->screenColorSamplerButton->setDisabled(false);
269}
270
272{
273 QWidget::changeEvent(e);
274}
275
277{
278 static QPoint lastGlobalPos;
279 QPoint newGlobalPos = QCursor::pos();
280 if (lastGlobalPos == newGlobalPos)
281 return;
282 lastGlobalPos = newGlobalPos;
283
284 if (!rect().contains(mapFromGlobal(newGlobalPos))) { // Inside the dialog mouse tracking works, handleColorSamplingMouseMove will be called
285 continueUpdateColorSampling(newGlobalPos);
286#ifdef Q_OS_WIN32
287 m_d->dummyTransparentWindow.setPosition(newGlobalPos);
288#endif
289 }
290}
291
293{
294 const KoColor color = grabScreenColor(globalPos);
295 // QTBUG-39792, do not change standard, custom color selectors while moving as
296 // otherwise it is not possible to preselect a custom cell for assignment.
297 setCurrentColor(color);
299 updateColorLabelText(globalPos);
300}
301
302// Event filter to be installed on the dialog while in color-sampling mode.
304 : QObject(parent)
305 , m_w(w)
306{}
307
309{
310 switch (event->type()) {
311 case QEvent::MouseMove:
312 return m_w->handleColorSamplingMouseMove(static_cast<QMouseEvent *>(event));
313 case QEvent::MouseButtonRelease:
314 return m_w->handleColorSamplingMouseButtonRelease(static_cast<QMouseEvent *>(event));
315 case QEvent::KeyPress:
316 return m_w->handleColorSamplingKeyPress(static_cast<QKeyEvent *>(event));
317 default:
318 break;
319 }
320 return false;
321}
322
323// Register the color sampler factory with the internal color selector
326}
327
const Params2D p
KIS_DECLARE_STATIC_INITIALIZER
KisReferenceImagesDecorationSP referenceImagesDecoration() const
KisCoordinatesConverter * coordinatesConverter
KisAbstractCanvasWidget * canvasWidget
_Private::Traits< T >::Result widgetToDocument(const T &obj) const
_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:130
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:431
KisImageWSP image() const
Definition KisView.cpp:436
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:656
KoColor convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
Definition KoColor.cpp:163
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
quint8 opacityU8() const
Definition KoColor.cpp:341
#define kisIcon(name)
Definition kis_icon.h:26
KisScreenColorSamplingEventFilter * colorSamplingEventFilter
static QPoint ptToWrappedPt(QPoint pt, const QRect &wrapRect, WrapAroundAxis wrapAxis)