21#include <QApplication>
28#include "moc_qgscolorpickerhelper.cpp"
32 , mSampleTimer( new QTimer( this ) )
36 mSampleTimer->setSingleShot(
true );
37 mSampleTimer->setInterval( 100 );
38 connect( mSampleTimer, &QTimer::timeout,
this, &QgsColorPickerHelper::hoverSampleTimeout );
57 mSampleRadius = sampleRadius;
59 mCurrentPickingColor = QColor();
60 mFinalColor = QColor();
65 const QList<QWidget *> topLevelWidgets = QApplication::topLevelWidgets();
66 for ( QWidget *widget : topLevelWidgets )
68 if ( !widget->hasMouseTracking() )
70 widget->setMouseTracking(
true );
71 mWidgetsToCleanup.append( QPointer( widget ) );
76 qApp->installEventFilter(
this );
83 return QObject::eventFilter( watched, event );
86 switch ( event->type() )
88 case QEvent::MouseMove:
89 case QEvent::HoverMove:
91 const QPoint pos =
static_cast<QSinglePointEvent *
>( event )->position().toPoint();
93 if ( QWidget *target = findEventWindowWidgetAndLocalPos( watched, pos, localPos ) )
95 mPendingTargetWidget = target;
96 mPendingLocalPos = localPos;
98 if ( !mSampleTimer->isActive() )
100 mSampleTimer->start();
108 case QEvent::MouseButtonPress:
110 QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>( event );
111 if ( mouseEvent->button() == Qt::LeftButton )
114 mSampleTimer->stop();
117 if ( QWidget *target = findEventWindowWidgetAndLocalPos( watched, mouseEvent->position(), localPos ) )
119 finalColor = sampleColor( target, localPos );
121 mFinalColor = finalColor.isValid() ? finalColor : mCurrentPickingColor;
124 else if ( mouseEvent->button() == Qt::RightButton )
131 case QEvent::MouseButtonRelease:
133 QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>( event );
134 if ( mouseEvent->button() == Qt::LeftButton )
136 if ( mFinalColor.isValid() )
137 onColorPicked( mFinalColor );
142 else if ( mouseEvent->button() == Qt::RightButton )
151 case QEvent::KeyPress:
153 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>( event );
154 switch ( keyEvent->key() )
163 mSampleTimer->stop();
164 if ( mPendingTargetWidget )
166 const QColor sampled = sampleColor( mPendingTargetWidget, mPendingLocalPos );
167 if ( sampled.isValid() )
168 mCurrentPickingColor = sampled;
170 onColorPicked( mCurrentPickingColor );
175 if ( keyEvent->text().isEmpty() )
186 return QObject::eventFilter( watched, event );
189void QgsColorPickerHelper::hoverSampleTimeout()
191 if ( !mPickingColor || !mPendingTargetWidget )
194 const QColor sampled = sampleColor( mPendingTargetWidget, mPendingLocalPos );
195 if ( sampled.isValid() )
197 mCurrentPickingColor = sampled;
202QWidget *QgsColorPickerHelper::findEventWindowWidgetAndLocalPos( QObject *watched,
const QPointF &eventPos, QPoint &outPos )
205 if ( QWidget *w = qobject_cast<QWidget *>( watched ) )
210 QWidget *topLevel = w->window();
211 outPos = w->mapTo( topLevel, eventPos.toPoint() );
216 if ( QWindow *window = qobject_cast<QWindow *>( watched ) )
218 const QList<QWidget *> topLevelWidgets = QApplication::topLevelWidgets();
219 for ( QWidget *widget : topLevelWidgets )
221 if ( widget->windowHandle() == window )
223 outPos = eventPos.toPoint();
232void QgsColorPickerHelper::onColorPicked(
const QColor &color )
238void QgsColorPickerHelper::cancelPicking()
244void QgsColorPickerHelper::stopPicking()
246 mSampleTimer->stop();
247 mPendingTargetWidget =
nullptr;
249 qApp->removeEventFilter(
this );
251 for (
const QPointer< QWidget > &widget : std::as_const( mWidgetsToCleanup ) )
255 widget->setMouseTracking(
false );
258 mWidgetsToCleanup.clear();
260 QgsApplication::restoreOverrideCursor();
261 mPickingColor =
false;
264QColor QgsColorPickerHelper::sampleColor( QWidget *widget,
const QPoint &pos )
const
269 const int radius = std::max( 0, mSampleRadius );
270 QRect grabRect( pos.x() - radius, pos.y() - radius, 1 + radius * 2, 1 + radius * 2 );
272 grabRect = grabRect.intersected( widget->rect() );
273 if ( grabRect.isEmpty() )
276 const QPixmap pixmap = widget->grab( grabRect );
277 if ( pixmap.isNull() )
280 const QImage image = pixmap.toImage();
283 return image.pixelColor( 0, 0 );
287 return averageColor( image );
291QColor QgsColorPickerHelper::averageColor(
const QImage &image )
297 quint64 sumGreen = 0;
299 for (
int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
301 const QRgb *scanLine =
reinterpret_cast<const QRgb *
>( image.constScanLine( heightIndex ) );
302 for (
int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
304 tmpRgb = scanLine[widthIndex];
305 sumRed += qRed( tmpRgb );
306 sumBlue += qBlue( tmpRgb );
307 sumGreen += qGreen( tmpRgb );
312 const double avgRed =
static_cast<double>( sumRed ) / ( 255.0 * colorCount );
313 const double avgGreen =
static_cast<double>( sumGreen ) / ( 255.0 * colorCount );
314 const double avgBlue =
static_cast<double>( sumBlue ) / ( 255.0 * colorCount );
317 return QColor::fromRgbF( avgRed, avgGreen, avgBlue );
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
@ Sampler
Color/Value picker.
void colorPicked(const QColor &color)
Emitted when the user has finished picking a color from the screen.
~QgsColorPickerHelper() override
void activate(int sampleRadius=0)
Activates the color picking operation.
void colorHovered(const QColor &color)
Emitted when the user hovers over a color from the screen.
QgsColorPickerHelper(QObject *parent)
Constructor for QgsColorPickerHelper for the specified parent widget.
bool eventFilter(QObject *watched, QEvent *event) override
void canceled()
Emitted when the user cancels the picking operation.