QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgscolorwidgets.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscolorwidgets.cpp - color selection widgets
3  ---------------------
4  begin : September 2014
5  copyright : (C) 2014 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgscolorwidgets.h"
17 #include "qgsapplication.h"
18 #include "qgssymbollayerutils.h"
19 #include "qgssettings.h"
20 #include "qgslogger.h"
21 #include "qgsguiutils.h"
22 
23 #include <QResizeEvent>
24 
25 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
26 #include <QStyleOptionFrameV3>
27 #else
28 #include <QStyleOptionFrame>
29 #endif
30 #include <QPainter>
31 #include <QHBoxLayout>
32 #include <QSpinBox>
33 #include <QLineEdit>
34 #include <QFontMetrics>
35 #include <QToolButton>
36 #include <QMenu>
37 #include <QDrag>
38 #include <QRectF>
39 #include <QLineF>
40 
41 #include <cmath>
42 
43 
44 //
45 // QgsColorWidget
46 //
47 
48 QgsColorWidget::QgsColorWidget( QWidget *parent, const ColorComponent component )
49  : QWidget( parent )
50  , mCurrentColor( Qt::red )
51  , mComponent( component )
52 {
53  setAcceptDrops( true );
54 }
55 
57 {
58  return componentValue( mComponent );
59 }
60 
61 QPixmap QgsColorWidget::createDragIcon( const QColor &color )
62 {
63  //craft a pixmap for the drag icon
64  const int iconSize = QgsGuiUtils::scaleIconSize( 50 );
65  QPixmap pixmap( iconSize, iconSize );
66  pixmap.fill( Qt::transparent );
67  QPainter painter;
68  painter.begin( &pixmap );
69  //start with a light gray background
70  painter.fillRect( QRect( 0, 0, iconSize, iconSize ), QBrush( QColor( 200, 200, 200 ) ) );
71  //draw rect with white border, filled with current color
72  QColor pixmapColor = color;
73  pixmapColor.setAlpha( 255 );
74  painter.setBrush( QBrush( pixmapColor ) );
75  painter.setPen( QPen( Qt::white ) );
76  painter.drawRect( QRect( 1, 1, iconSize - 2, iconSize - 2 ) );
77  painter.end();
78  return pixmap;
79 }
80 
82 {
83  if ( !mCurrentColor.isValid() )
84  {
85  return -1;
86  }
87 
88  switch ( component )
89  {
91  return mCurrentColor.red();
93  return mCurrentColor.green();
95  return mCurrentColor.blue();
97  //hue is treated specially, to avoid -1 hues values from QColor for ambiguous hues
98  return hue();
100  return mCurrentColor.hsvSaturation();
102  return mCurrentColor.value();
104  return mCurrentColor.alpha();
105  default:
106  return -1;
107  }
108 }
109 
111 {
112  return componentRange( mComponent );
113 }
114 
116 {
118  {
119  //no component
120  return -1;
121  }
122 
124  {
125  //hue ranges to 359
126  return 359;
127  }
128  else
129  {
130  //all other components range to 255
131  return 255;
132  }
133 }
134 
136 {
137  if ( mCurrentColor.hue() >= 0 )
138  {
139  return mCurrentColor.hue();
140  }
141  else
142  {
143  return mExplicitHue;
144  }
145 }
146 
147 void QgsColorWidget::alterColor( QColor &color, const QgsColorWidget::ColorComponent component, const int newValue ) const
148 {
149  int h, s, v, a;
150  color.getHsv( &h, &s, &v, &a );
151 
152  //clip value to sensible range
153  const int clippedValue = std::min( std::max( 0, newValue ), componentRange( component ) );
154 
155  switch ( component )
156  {
157  case QgsColorWidget::Red:
158  color.setRed( clippedValue );
159  return;
161  color.setGreen( clippedValue );
162  return;
164  color.setBlue( clippedValue );
165  return;
166  case QgsColorWidget::Hue:
167  color.setHsv( clippedValue, s, v, a );
168  return;
170  color.setHsv( h, clippedValue, v, a );
171  return;
173  color.setHsv( h, s, clippedValue, a );
174  return;
176  color.setAlpha( clippedValue );
177  return;
178  default:
179  return;
180  }
181 }
182 
184 {
185  static QPixmap sTranspBkgrd;
186 
187  if ( sTranspBkgrd.isNull() )
188  sTranspBkgrd = QgsApplication::getThemePixmap( QStringLiteral( "/transp-background_8x8.png" ) );
189 
190  return sTranspBkgrd;
191 }
192 
193 void QgsColorWidget::dragEnterEvent( QDragEnterEvent *e )
194 {
195  //is dragged data valid color data?
196  bool hasAlpha;
197  const QColor mimeColor = QgsSymbolLayerUtils::colorFromMimeData( e->mimeData(), hasAlpha );
198 
199  if ( mimeColor.isValid() )
200  {
201  //if so, we accept the drag
202  e->acceptProposedAction();
203  }
204 }
205 
206 void QgsColorWidget::dropEvent( QDropEvent *e )
207 {
208  //is dropped data valid color data?
209  bool hasAlpha = false;
210  QColor mimeColor = QgsSymbolLayerUtils::colorFromMimeData( e->mimeData(), hasAlpha );
211 
212  if ( mimeColor.isValid() )
213  {
214  //accept drop and set new color
215  e->acceptProposedAction();
216 
217  if ( !hasAlpha )
218  {
219  //mime color has no explicit alpha component, so keep existing alpha
220  mimeColor.setAlpha( mCurrentColor.alpha() );
221  }
222 
223  setColor( mimeColor );
224  emit colorChanged( mCurrentColor );
225  }
226 
227  //could not get color from mime data
228 }
229 
230 void QgsColorWidget::mouseMoveEvent( QMouseEvent *e )
231 {
232  emit hovered();
233  e->accept();
234  //don't pass to QWidget::mouseMoveEvent, causes issues with widget used in QWidgetAction
235 }
236 
237 void QgsColorWidget::mousePressEvent( QMouseEvent *e )
238 {
239  e->accept();
240  //don't pass to QWidget::mousePressEvent, causes issues with widget used in QWidgetAction
241 }
242 
243 void QgsColorWidget::mouseReleaseEvent( QMouseEvent *e )
244 {
245  e->accept();
246  //don't pass to QWidget::mouseReleaseEvent, causes issues with widget used in QWidgetAction
247 }
248 
249 QColor QgsColorWidget::color() const
250 {
251  return mCurrentColor;
252 }
253 
255 {
256  if ( component == mComponent )
257  {
258  return;
259  }
260 
262  update();
263 }
264 
265 void QgsColorWidget::setComponentValue( const int value )
266 {
268  {
269  return;
270  }
271 
272  //clip value to valid range
273  int valueClipped = std::min( value, componentRange() );
274  valueClipped = std::max( valueClipped, 0 );
275 
276  int r, g, b, a;
277  mCurrentColor.getRgb( &r, &g, &b, &a );
278  int h, s, v;
279  mCurrentColor.getHsv( &h, &s, &v );
280  //overwrite hue with explicit hue if required
281  h = hue();
282 
283  switch ( mComponent )
284  {
285  case QgsColorWidget::Red:
286  if ( r == valueClipped )
287  {
288  return;
289  }
290  mCurrentColor.setRed( valueClipped );
291  break;
293  if ( g == valueClipped )
294  {
295  return;
296  }
297  mCurrentColor.setGreen( valueClipped );
298  break;
300  if ( b == valueClipped )
301  {
302  return;
303  }
304  mCurrentColor.setBlue( valueClipped );
305  break;
306  case QgsColorWidget::Hue:
307  if ( h == valueClipped )
308  {
309  return;
310  }
311  mCurrentColor.setHsv( valueClipped, s, v, a );
312  break;
314  if ( s == valueClipped )
315  {
316  return;
317  }
318  mCurrentColor.setHsv( h, valueClipped, v, a );
319  break;
321  if ( v == valueClipped )
322  {
323  return;
324  }
325  mCurrentColor.setHsv( h, s, valueClipped, a );
326  break;
328  if ( a == valueClipped )
329  {
330  return;
331  }
332  mCurrentColor.setAlpha( valueClipped );
333  break;
334  default:
335  return;
336  }
337 
338  //update recorded hue
339  if ( mCurrentColor.hue() >= 0 )
340  {
341  mExplicitHue = mCurrentColor.hue();
342  }
343 
344  update();
345 }
346 
347 void QgsColorWidget::setColor( const QColor &color, const bool emitSignals )
348 {
349  if ( color == mCurrentColor )
350  {
351  return;
352  }
353 
355 
356  //update recorded hue
357  if ( color.hue() >= 0 )
358  {
359  mExplicitHue = color.hue();
360  }
361 
362  if ( emitSignals )
363  {
364  emit colorChanged( mCurrentColor );
365  }
366 
367  update();
368 }
369 
370 
371 //
372 // QgsColorWheel
373 //
374 
376  : QgsColorWidget( parent )
377 {
378  //create wheel hue brush - only do this once
379  QConicalGradient wheelGradient = QConicalGradient( 0, 0, 0 );
380  const int wheelStops = 20;
381  QColor gradColor = QColor::fromHsvF( 1.0, 1.0, 1.0 );
382  for ( int pos = 0; pos <= wheelStops; ++pos )
383  {
384  const double relativePos = static_cast<double>( pos ) / wheelStops;
385  gradColor.setHsvF( relativePos, 1, 1 );
386  wheelGradient.setColorAt( relativePos, gradColor );
387  }
388  mWheelBrush = QBrush( wheelGradient );
389 }
390 
392 {
393  delete mWheelImage;
394  delete mTriangleImage;
395  delete mWidgetImage;
396 }
397 
399 {
400  const int size = Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 22;
401  return QSize( size, size );
402 }
403 
404 void QgsColorWheel::paintEvent( QPaintEvent *event )
405 {
406  Q_UNUSED( event )
407  QPainter painter( this );
408 
409  if ( !mWidgetImage || !mWheelImage || !mTriangleImage )
410  {
411  createImages( size() );
412  }
413 
414  //draw everything in an image
415  mWidgetImage->fill( Qt::transparent );
416  QPainter imagePainter( mWidgetImage );
417  imagePainter.setRenderHint( QPainter::Antialiasing );
418 
419  if ( mWheelDirty )
420  {
421  //need to redraw the wheel image
422  createWheel();
423  }
424 
425  //draw wheel centered on widget
426  const QPointF center = QPointF( width() / 2.0, height() / 2.0 );
427  imagePainter.drawImage( QPointF( center.x() - ( mWheelImage->width() / 2.0 ), center.y() - ( mWheelImage->height() / 2.0 ) ), *mWheelImage );
428 
429  //draw hue marker
430  const int h = hue();
431  const double length = mWheelImage->width() / 2.0;
432  QLineF hueMarkerLine = QLineF( center.x(), center.y(), center.x() + length, center.y() );
433  hueMarkerLine.setAngle( h );
434  imagePainter.save();
435  //use sourceIn mode for nicer antialiasing
436  imagePainter.setCompositionMode( QPainter::CompositionMode_SourceIn );
437  QPen pen;
438  pen.setWidth( 2 );
439  //adapt pen color for hue
440  pen.setColor( h > 20 && h < 200 ? Qt::black : Qt::white );
441  imagePainter.setPen( pen );
442  imagePainter.drawLine( hueMarkerLine );
443  imagePainter.restore();
444 
445  //draw triangle
446  if ( mTriangleDirty )
447  {
448  createTriangle();
449  }
450  imagePainter.drawImage( QPointF( center.x() - ( mWheelImage->width() / 2.0 ), center.y() - ( mWheelImage->height() / 2.0 ) ), *mTriangleImage );
451 
452  //draw current color marker
453  const double triangleRadius = length - mWheelThickness - 1;
454 
455  //adapted from equations at https://github.com/timjb/colortriangle/blob/master/colortriangle.js by Tim Baumann
456  const double lightness = mCurrentColor.lightnessF();
457  const double hueRadians = ( h * M_PI / 180.0 );
458  const double hx = std::cos( hueRadians ) * triangleRadius;
459  const double hy = -std::sin( hueRadians ) * triangleRadius;
460  const double sx = -std::cos( -hueRadians + ( M_PI / 3.0 ) ) * triangleRadius;
461  const double sy = -std::sin( -hueRadians + ( M_PI / 3.0 ) ) * triangleRadius;
462  const double vx = -std::cos( hueRadians + ( M_PI / 3.0 ) ) * triangleRadius;
463  const double vy = std::sin( hueRadians + ( M_PI / 3.0 ) ) * triangleRadius;
464  const double mx = ( sx + vx ) / 2.0;
465  const double my = ( sy + vy ) / 2.0;
466 
467  const double a = ( 1 - 2.0 * std::fabs( lightness - 0.5 ) ) * mCurrentColor.hslSaturationF();
468  const double x = sx + ( vx - sx ) * lightness + ( hx - mx ) * a;
469  const double y = sy + ( vy - sy ) * lightness + ( hy - my ) * a;
470 
471  //adapt pen color for lightness
472  pen.setColor( lightness > 0.7 ? Qt::black : Qt::white );
473  imagePainter.setPen( pen );
474  imagePainter.setBrush( Qt::NoBrush );
475  imagePainter.drawEllipse( QPointF( x + center.x(), y + center.y() ), 4.0, 4.0 );
476  imagePainter.end();
477 
478  //draw image onto widget
479  painter.drawImage( QPoint( 0, 0 ), *mWidgetImage );
480  painter.end();
481 }
482 
483 void QgsColorWheel::setColor( const QColor &color, const bool emitSignals )
484 {
485  if ( color.hue() >= 0 && color.hue() != hue() )
486  {
487  //hue has changed, need to redraw the triangle
488  mTriangleDirty = true;
489  }
490 
491  QgsColorWidget::setColor( color, emitSignals );
492 }
493 
494 void QgsColorWheel::createImages( const QSizeF size )
495 {
496  const double wheelSize = std::min( size.width(), size.height() ) - mMargin * 2.0;
497  mWheelThickness = wheelSize / 15.0;
498 
499  //recreate cache images at correct size
500  delete mWheelImage;
501  mWheelImage = new QImage( wheelSize, wheelSize, QImage::Format_ARGB32 );
502  delete mTriangleImage;
503  mTriangleImage = new QImage( wheelSize, wheelSize, QImage::Format_ARGB32 );
504  delete mWidgetImage;
505  mWidgetImage = new QImage( size.width(), size.height(), QImage::Format_ARGB32 );
506 
507  //trigger a redraw for the images
508  mWheelDirty = true;
509  mTriangleDirty = true;
510 }
511 
512 void QgsColorWheel::resizeEvent( QResizeEvent *event )
513 {
514  //recreate images for new size
515  createImages( event->size() );
516  QgsColorWidget::resizeEvent( event );
517 }
518 
519 void QgsColorWheel::setColorFromPos( const QPointF pos )
520 {
521  const QPointF center = QPointF( width() / 2.0, height() / 2.0 );
522  //line from center to mouse position
523  const QLineF line = QLineF( center.x(), center.y(), pos.x(), pos.y() );
524 
525  QColor newColor = QColor();
526 
527  int h, s, l, alpha;
528  mCurrentColor.getHsl( &h, &s, &l, &alpha );
529  //override hue with explicit hue, so we don't get -1 values from QColor for hue
530  h = hue();
531 
532  if ( mClickedPart == QgsColorWheel::Triangle )
533  {
534  //adapted from equations at https://github.com/timjb/colortriangle/blob/master/colortriangle.js by Tim Baumann
535 
536  //position of event relative to triangle center
537  const double x = pos.x() - center.x();
538  const double y = pos.y() - center.y();
539 
540  double eventAngleRadians = line.angle() * M_PI / 180.0;
541  const double hueRadians = h * M_PI / 180.0;
542  double rad0 = std::fmod( eventAngleRadians + 2.0 * M_PI - hueRadians, 2.0 * M_PI );
543  double rad1 = std::fmod( rad0, ( ( 2.0 / 3.0 ) * M_PI ) ) - ( M_PI / 3.0 );
544  const double length = mWheelImage->width() / 2.0;
545  const double triangleLength = length - mWheelThickness - 1;
546 
547  const double a = 0.5 * triangleLength;
548  double b = std::tan( rad1 ) * a;
549  double r = std::sqrt( x * x + y * y );
550  const double maxR = std::sqrt( a * a + b * b );
551 
552  if ( r > maxR )
553  {
554  const double dx = std::tan( rad1 ) * r;
555  double rad2 = std::atan( dx / maxR );
556  rad2 = std::min( rad2, M_PI / 3.0 );
557  rad2 = std::max( rad2, -M_PI / 3.0 );
558  eventAngleRadians += rad2 - rad1;
559  rad0 = std::fmod( eventAngleRadians + 2.0 * M_PI - hueRadians, 2.0 * M_PI );
560  rad1 = std::fmod( rad0, ( ( 2.0 / 3.0 ) * M_PI ) ) - ( M_PI / 3.0 );
561  b = std::tan( rad1 ) * a;
562  r = std::sqrt( a * a + b * b );
563  }
564 
565  const double triangleSideLength = std::sqrt( 3.0 ) * triangleLength;
566  const double newL = ( ( -std::sin( rad0 ) * r ) / triangleSideLength ) + 0.5;
567  const double widthShare = 1.0 - ( std::fabs( newL - 0.5 ) * 2.0 );
568  const double newS = ( ( ( std::cos( rad0 ) * r ) + ( triangleLength / 2.0 ) ) / ( 1.5 * triangleLength ) ) / widthShare;
569  s = std::min( static_cast< int >( std::round( std::max( 0.0, newS ) * 255.0 ) ), 255 );
570  l = std::min( static_cast< int >( std::round( std::max( 0.0, newL ) * 255.0 ) ), 255 );
571  newColor = QColor::fromHsl( h, s, l );
572  //explicitly set the hue again, so that it's exact
573  newColor.setHsv( h, newColor.hsvSaturation(), newColor.value(), alpha );
574  }
575  else if ( mClickedPart == QgsColorWheel::Wheel )
576  {
577  //use hue angle
578  s = mCurrentColor.hsvSaturation();
579  const int v = mCurrentColor.value();
580  const int newHue = line.angle();
581  newColor = QColor::fromHsv( newHue, s, v, alpha );
582  //hue has changed, need to redraw triangle
583  mTriangleDirty = true;
584  }
585 
586  if ( newColor.isValid() && newColor != mCurrentColor )
587  {
588  //color has changed
589  mCurrentColor = QColor( newColor );
590 
591  if ( mCurrentColor.hue() >= 0 )
592  {
593  //color has a valid hue, so update the QgsColorWidget's explicit hue
594  mExplicitHue = mCurrentColor.hue();
595  }
596 
597  update();
598  emit colorChanged( mCurrentColor );
599  }
600 }
601 
602 void QgsColorWheel::mouseMoveEvent( QMouseEvent *event )
603 {
604  if ( mIsDragging )
605  setColorFromPos( event->pos() );
606 
608 }
609 
610 void QgsColorWheel::mousePressEvent( QMouseEvent *event )
611 {
612  if ( event->button() == Qt::LeftButton )
613  {
614  mIsDragging = true;
615  //calculate where the event occurred -- on the wheel or inside the triangle?
616 
617  //create a line from the widget's center to the event
618  const QLineF line = QLineF( width() / 2.0, height() / 2.0, event->pos().x(), event->pos().y() );
619 
620  const double innerLength = mWheelImage->width() / 2.0 - mWheelThickness;
621  if ( line.length() < innerLength )
622  {
623  mClickedPart = QgsColorWheel::Triangle;
624  }
625  else
626  {
627  mClickedPart = QgsColorWheel::Wheel;
628  }
629  setColorFromPos( event->pos() );
630  }
631  else
632  {
634  }
635 }
636 
637 void QgsColorWheel::mouseReleaseEvent( QMouseEvent *event )
638 {
639  if ( event->button() == Qt::LeftButton )
640  {
641  mIsDragging = false;
642  mClickedPart = QgsColorWheel::None;
643  }
644  else
645  {
647  }
648 }
649 
650 void QgsColorWheel::createWheel()
651 {
652  if ( !mWheelImage )
653  {
654  return;
655  }
656 
657  const int maxSize = std::min( mWheelImage->width(), mWheelImage->height() );
658  const double wheelRadius = maxSize / 2.0;
659 
660  mWheelImage->fill( Qt::transparent );
661  QPainter p( mWheelImage );
662  p.setRenderHint( QPainter::Antialiasing );
663  p.setBrush( mWheelBrush );
664  p.setPen( Qt::NoPen );
665 
666  //draw hue wheel as a circle
667  p.translate( wheelRadius, wheelRadius );
668  p.drawEllipse( QPointF( 0.0, 0.0 ), wheelRadius, wheelRadius );
669 
670  //cut hole in center of circle to make a ring
671  p.setCompositionMode( QPainter::CompositionMode_DestinationOut );
672  p.setBrush( QBrush( Qt::black ) );
673  p.drawEllipse( QPointF( 0.0, 0.0 ), wheelRadius - mWheelThickness, wheelRadius - mWheelThickness );
674  p.end();
675 
676  mWheelDirty = false;
677 }
678 
679 void QgsColorWheel::createTriangle()
680 {
681  if ( !mWheelImage || !mTriangleImage )
682  {
683  return;
684  }
685 
686  const QPointF center = QPointF( mWheelImage->width() / 2.0, mWheelImage->height() / 2.0 );
687  mTriangleImage->fill( Qt::transparent );
688 
689  QPainter imagePainter( mTriangleImage );
690  imagePainter.setRenderHint( QPainter::Antialiasing );
691 
692  const int angle = hue();
693  const double wheelRadius = mWheelImage->width() / 2.0;
694  const double triangleRadius = wheelRadius - mWheelThickness - 1;
695 
696  //pure version of hue (at full saturation and value)
697  const QColor pureColor = QColor::fromHsv( angle, 255, 255 );
698  //create copy of color but with 0 alpha
699  QColor alphaColor = QColor( pureColor );
700  alphaColor.setAlpha( 0 );
701 
702  //some rather ugly shortcuts to obtain corners and midpoints of triangle
703  QLineF line1 = QLineF( center.x(), center.y(), center.x() - triangleRadius * std::cos( M_PI / 3.0 ), center.y() - triangleRadius * std::sin( M_PI / 3.0 ) );
704  QLineF line2 = QLineF( center.x(), center.y(), center.x() + triangleRadius, center.y() );
705  QLineF line3 = QLineF( center.x(), center.y(), center.x() - triangleRadius * std::cos( M_PI / 3.0 ), center.y() + triangleRadius * std::sin( M_PI / 3.0 ) );
706  QLineF line4 = QLineF( center.x(), center.y(), center.x() - triangleRadius * std::cos( M_PI / 3.0 ), center.y() );
707  QLineF line5 = QLineF( center.x(), center.y(), ( line2.p2().x() + line1.p2().x() ) / 2.0, ( line2.p2().y() + line1.p2().y() ) / 2.0 );
708  line1.setAngle( line1.angle() + angle );
709  line2.setAngle( line2.angle() + angle );
710  line3.setAngle( line3.angle() + angle );
711  line4.setAngle( line4.angle() + angle );
712  line5.setAngle( line5.angle() + angle );
713  const QPointF p1 = line1.p2();
714  const QPointF p2 = line2.p2();
715  const QPointF p3 = line3.p2();
716  const QPointF p4 = line4.p2();
717  const QPointF p5 = line5.p2();
718 
719  //inspired by Tim Baumann's work at https://github.com/timjb/colortriangle/blob/master/colortriangle.js
720  QLinearGradient colorGrad = QLinearGradient( p4.x(), p4.y(), p2.x(), p2.y() );
721  colorGrad.setColorAt( 0, alphaColor );
722  colorGrad.setColorAt( 1, pureColor );
723  QLinearGradient whiteGrad = QLinearGradient( p3.x(), p3.y(), p5.x(), p5.y() );
724  whiteGrad.setColorAt( 0, QColor( 255, 255, 255, 255 ) );
725  whiteGrad.setColorAt( 1, QColor( 255, 255, 255, 0 ) );
726 
727  QPolygonF triangle;
728  triangle << p2 << p1 << p3 << p2;
729  imagePainter.setPen( Qt::NoPen );
730  //start with a black triangle
731  imagePainter.setBrush( QBrush( Qt::black ) );
732  imagePainter.drawPolygon( triangle );
733  //draw a gradient from transparent to the pure color at the triangle's tip
734  imagePainter.setBrush( QBrush( colorGrad ) );
735  imagePainter.drawPolygon( triangle );
736  //draw a white gradient using additive composition mode
737  imagePainter.setCompositionMode( QPainter::CompositionMode_Plus );
738  imagePainter.setBrush( QBrush( whiteGrad ) );
739  imagePainter.drawPolygon( triangle );
740 
741  //above process results in some small artifacts on the edge of the triangle. Let's clear these up
742  //use source composition mode and draw an outline using a transparent pen
743  //this clears the edge pixels and leaves a nice smooth image
744  imagePainter.setCompositionMode( QPainter::CompositionMode_Source );
745  imagePainter.setBrush( Qt::NoBrush );
746  imagePainter.setPen( QPen( Qt::transparent ) );
747  imagePainter.drawPolygon( triangle );
748 
749  imagePainter.end();
750  mTriangleDirty = false;
751 }
752 
753 
754 
755 //
756 // QgsColorBox
757 //
758 
759 QgsColorBox::QgsColorBox( QWidget *parent, const ColorComponent component )
760  : QgsColorWidget( parent, component )
761 {
762  setFocusPolicy( Qt::StrongFocus );
763  setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
764 
765  mBoxImage = new QImage( width() - mMargin * 2, height() - mMargin * 2, QImage::Format_RGB32 );
766 }
767 
769 {
770  delete mBoxImage;
771 }
772 
774 {
775  const int size = Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 22;
776  return QSize( size, size );
777 }
778 
779 void QgsColorBox::paintEvent( QPaintEvent *event )
780 {
781  Q_UNUSED( event )
782  QPainter painter( this );
783 
784  QStyleOptionFrame option;
785  option.initFrom( this );
786  option.state = hasFocus() ? QStyle::State_Active : QStyle::State_None;
787  style()->drawPrimitive( QStyle::PE_Frame, &option, &painter );
788 
789  if ( mDirty )
790  {
791  createBox();
792  }
793 
794  //draw background image
795  painter.drawImage( QPoint( mMargin, mMargin ), *mBoxImage );
796 
797  //draw cross lines
798  const double xPos = mMargin + ( width() - 2 * mMargin - 1 ) * static_cast<double>( xComponentValue() ) / static_cast<double>( valueRangeX() );
799  const double yPos = mMargin + ( height() - 2 * mMargin - 1 ) - ( height() - 2 * mMargin - 1 ) * static_cast<double>( yComponentValue() ) / static_cast<double>( valueRangeY() );
800 
801  painter.setBrush( Qt::white );
802  painter.setPen( Qt::NoPen );
803 
804  painter.drawRect( xPos - 1, mMargin, 3, height() - 2 * mMargin - 1 );
805  painter.drawRect( mMargin, yPos - 1, width() - 2 * mMargin - 1, 3 );
806  painter.setPen( Qt::black );
807  painter.drawLine( xPos, mMargin, xPos, height() - mMargin - 1 );
808  painter.drawLine( mMargin, yPos, width() - mMargin - 1, yPos );
809 
810  painter.end();
811 }
812 
814 {
815  if ( component != mComponent )
816  {
817  //need to redraw
818  mDirty = true;
819  }
821 }
822 
823 void QgsColorBox::setColor( const QColor &color, const bool emitSignals )
824 {
825  //check if we need to redraw the box image
826  if ( mComponent == QgsColorWidget::Red && mCurrentColor.red() != color.red() )
827  {
828  mDirty = true;
829  }
830  else if ( mComponent == QgsColorWidget::Green && mCurrentColor.green() != color.green() )
831  {
832  mDirty = true;
833  }
834  else if ( mComponent == QgsColorWidget::Blue && mCurrentColor.blue() != color.blue() )
835  {
836  mDirty = true;
837  }
838  else if ( mComponent == QgsColorWidget::Hue && color.hsvHue() >= 0 && hue() != color.hsvHue() )
839  {
840  mDirty = true;
841  }
842  else if ( mComponent == QgsColorWidget::Saturation && mCurrentColor.hsvSaturation() != color.hsvSaturation() )
843  {
844  mDirty = true;
845  }
846  else if ( mComponent == QgsColorWidget::Value && mCurrentColor.value() != color.value() )
847  {
848  mDirty = true;
849  }
850  QgsColorWidget::setColor( color, emitSignals );
851 }
852 
853 void QgsColorBox::resizeEvent( QResizeEvent *event )
854 {
855  mDirty = true;
856  delete mBoxImage;
857  mBoxImage = new QImage( event->size().width() - mMargin * 2, event->size().height() - mMargin * 2, QImage::Format_RGB32 );
858  QgsColorWidget::resizeEvent( event );
859 }
860 
861 void QgsColorBox::mouseMoveEvent( QMouseEvent *event )
862 {
863  if ( mIsDragging )
864  {
865  setColorFromPoint( event->pos() );
866  }
868 }
869 
870 void QgsColorBox::mousePressEvent( QMouseEvent *event )
871 {
872  if ( event->button() == Qt::LeftButton )
873  {
874  mIsDragging = true;
875  setColorFromPoint( event->pos() );
876  }
877  else
878  {
880  }
881 }
882 
883 void QgsColorBox::mouseReleaseEvent( QMouseEvent *event )
884 {
885  if ( event->button() == Qt::LeftButton )
886  {
887  mIsDragging = false;
888  }
889  else
890  {
892  }
893 }
894 
895 void QgsColorBox::createBox()
896 {
897  const int maxValueX = mBoxImage->width();
898  const int maxValueY = mBoxImage->height();
899 
900  //create a temporary color object
901  QColor currentColor = QColor( mCurrentColor );
902  int colorComponentValue;
903 
904  for ( int y = 0; y < maxValueY; ++y )
905  {
906  QRgb *scanLine = ( QRgb * )mBoxImage->scanLine( y );
907 
908  colorComponentValue = int( valueRangeY() - valueRangeY() * ( double( y ) / maxValueY ) );
909  alterColor( currentColor, yComponent(), colorComponentValue );
910  for ( int x = 0; x < maxValueX; ++x )
911  {
912  colorComponentValue = int( valueRangeX() * ( double( x ) / maxValueX ) );
913  alterColor( currentColor, xComponent(), colorComponentValue );
914  scanLine[x] = currentColor.rgb();
915  }
916  }
917  mDirty = false;
918 }
919 
920 int QgsColorBox::valueRangeX() const
921 {
922  return componentRange( xComponent() );
923 }
924 
925 int QgsColorBox::valueRangeY() const
926 {
927  return componentRange( yComponent() );
928 }
929 
930 QgsColorWidget::ColorComponent QgsColorBox::yComponent() const
931 {
932  switch ( mComponent )
933  {
934  case QgsColorWidget::Red:
935  return QgsColorWidget::Green;
938  return QgsColorWidget::Red;
939  case QgsColorWidget::Hue:
943  return QgsColorWidget::Hue;
944  default:
945  //should not occur
946  return QgsColorWidget::Red;
947  }
948 }
949 
950 int QgsColorBox::yComponentValue() const
951 {
952  return componentValue( yComponent() );
953 }
954 
955 QgsColorWidget::ColorComponent QgsColorBox::xComponent() const
956 {
957  switch ( mComponent )
958  {
959  case QgsColorWidget::Red:
961  return QgsColorWidget::Blue;
963  return QgsColorWidget::Green;
964  case QgsColorWidget::Hue:
966  return QgsColorWidget:: Value;
969  default:
970  //should not occur
971  return QgsColorWidget::Red;
972  }
973 }
974 
975 int QgsColorBox::xComponentValue() const
976 {
977  return componentValue( xComponent() );
978 }
979 
980 void QgsColorBox::setColorFromPoint( QPoint point )
981 {
982  int valX = valueRangeX() * ( point.x() - mMargin ) / ( width() - 2 * mMargin - 1 );
983  valX = std::min( std::max( valX, 0 ), valueRangeX() );
984 
985  int valY = valueRangeY() - valueRangeY() * ( point.y() - mMargin ) / ( height() - 2 * mMargin - 1 );
986  valY = std::min( std::max( valY, 0 ), valueRangeY() );
987 
988  QColor color = QColor( mCurrentColor );
989  alterColor( color, xComponent(), valX );
990  alterColor( color, yComponent(), valY );
991 
992  if ( color == mCurrentColor )
993  {
994  return;
995  }
996 
997  if ( color.hue() >= 0 )
998  {
999  mExplicitHue = color.hue();
1000  }
1001 
1002  mCurrentColor = color;
1003  update();
1004  emit colorChanged( color );
1005 }
1006 
1007 
1008 //
1009 // QgsColorRampWidget
1010 //
1011 
1013  const QgsColorWidget::ColorComponent component,
1014  const Orientation orientation )
1015  : QgsColorWidget( parent, component )
1016 {
1017  setFocusPolicy( Qt::StrongFocus );
1019 
1020  //create triangle polygons
1021  setMarkerSize( 5 );
1022 }
1023 
1025 {
1026  if ( mOrientation == QgsColorRampWidget::Horizontal )
1027  {
1028  //horizontal
1029  return QSize( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 22, Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.3 );
1030  }
1031  else
1032  {
1033  //vertical
1034  return QSize( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.3, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 22 );
1035  }
1036 }
1037 
1038 void QgsColorRampWidget::paintEvent( QPaintEvent *event )
1039 {
1040  Q_UNUSED( event )
1041  QPainter painter( this );
1042 
1043  if ( mShowFrame )
1044  {
1045  //draw frame
1046  QStyleOptionFrame option;
1047  option.initFrom( this );
1048  option.state = hasFocus() ? QStyle::State_KeyboardFocusChange : QStyle::State_None;
1049  style()->drawPrimitive( QStyle::PE_Frame, &option, &painter );
1050  }
1051 
1052  if ( hasFocus() )
1053  {
1054  //draw focus rect
1055  QStyleOptionFocusRect option;
1056  option.initFrom( this );
1057  option.state = QStyle::State_KeyboardFocusChange;
1058  style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, &painter );
1059  }
1060 
1062  {
1063  const int maxValue = ( mOrientation == QgsColorRampWidget::Horizontal ? width() : height() ) - 1 - 2 * mMargin;
1064  QColor color = QColor( mCurrentColor );
1065  color.setAlpha( 255 );
1066  QPen pen;
1067  // we need to set pen width to 1,
1068  // since on retina displays
1069  // pen.setWidth(0) <=> pen.width = 0.5
1070  // see https://github.com/qgis/QGIS/issues/23900
1071  pen.setWidth( 1 );
1072  painter.setPen( pen );
1073  painter.setBrush( Qt::NoBrush );
1074 
1075  //draw background ramp
1076  for ( int c = 0; c <= maxValue; ++c )
1077  {
1078  int colorVal = static_cast<int>( componentRange() * static_cast<double>( c ) / maxValue );
1079  //vertical sliders are reversed
1080  if ( mOrientation == QgsColorRampWidget::Vertical )
1081  {
1082  colorVal = componentRange() - colorVal;
1083  }
1084  alterColor( color, mComponent, colorVal );
1085  if ( color.hue() < 0 )
1086  {
1087  color.setHsv( hue(), color.saturation(), color.value() );
1088  }
1089  pen.setColor( color );
1090  painter.setPen( pen );
1091  if ( mOrientation == QgsColorRampWidget::Horizontal )
1092  {
1093  //horizontal
1094  painter.drawLine( QLineF( c + mMargin, mMargin, c + mMargin, height() - mMargin - 1 ) );
1095  }
1096  else
1097  {
1098  //vertical
1099  painter.drawLine( QLineF( mMargin, c + mMargin, width() - mMargin - 1, c + mMargin ) );
1100  }
1101  }
1102  }
1103  else
1104  {
1105  //alpha ramps are drawn differently
1106  //start with the checkboard pattern
1107  const QBrush checkBrush = QBrush( transparentBackground() );
1108  painter.setBrush( checkBrush );
1109  painter.setPen( Qt::NoPen );
1110  painter.drawRect( QRectF( mMargin, mMargin, width() - 2 * mMargin - 1, height() - 2 * mMargin - 1 ) );
1111  QLinearGradient colorGrad;
1112  if ( mOrientation == QgsColorRampWidget::Horizontal )
1113  {
1114  //horizontal
1115  colorGrad = QLinearGradient( mMargin, 0, width() - mMargin - 1, 0 );
1116  }
1117  else
1118  {
1119  //vertical
1120  colorGrad = QLinearGradient( 0, mMargin, 0, height() - mMargin - 1 );
1121  }
1122  QColor transparent = QColor( mCurrentColor );
1123  transparent.setAlpha( 0 );
1124  colorGrad.setColorAt( 0, transparent );
1125  QColor opaque = QColor( mCurrentColor );
1126  opaque.setAlpha( 255 );
1127  colorGrad.setColorAt( 1, opaque );
1128  const QBrush colorBrush = QBrush( colorGrad );
1129  painter.setBrush( colorBrush );
1130  painter.drawRect( QRectF( mMargin, mMargin, width() - 2 * mMargin - 1, height() - 2 * mMargin - 1 ) );
1131  }
1132 
1133  if ( mOrientation == QgsColorRampWidget::Horizontal )
1134  {
1135  //draw marker triangles for horizontal ramps
1136  painter.setRenderHint( QPainter::Antialiasing );
1137  painter.setBrush( QBrush( Qt::black ) );
1138  painter.setPen( Qt::NoPen );
1139  painter.translate( mMargin + ( width() - 2 * mMargin ) * static_cast<double>( componentValue() ) / componentRange(), mMargin - 1 );
1140  painter.drawPolygon( mTopTriangle );
1141  painter.translate( 0, height() - mMargin - 2 );
1142  painter.setBrush( QBrush( Qt::white ) );
1143  painter.drawPolygon( mBottomTriangle );
1144  painter.end();
1145  }
1146  else
1147  {
1148  //draw cross lines for vertical ramps
1149  const double ypos = mMargin + ( height() - 2 * mMargin - 1 ) - ( height() - 2 * mMargin - 1 ) * static_cast<double>( componentValue() ) / componentRange();
1150  painter.setBrush( Qt::white );
1151  painter.setPen( Qt::NoPen );
1152  painter.drawRect( QRectF( mMargin, ypos - 1, width() - 2 * mMargin - 1, 3 ) );
1153  painter.setPen( Qt::black );
1154  painter.drawLine( QLineF( mMargin, ypos, width() - mMargin - 1, ypos ) );
1155  }
1156 }
1157 
1159 {
1160  mOrientation = orientation;
1162  {
1163  //horizontal
1164  setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
1165  }
1166  else
1167  {
1168  //vertical
1169  setSizePolicy( QSizePolicy::Fixed, QSizePolicy::MinimumExpanding );
1170  }
1171  updateGeometry();
1172 }
1173 
1175 {
1176  if ( margin == mMargin )
1177  {
1178  return;
1179  }
1180  mMargin = margin;
1181  update();
1182 }
1183 
1184 void QgsColorRampWidget::setShowFrame( const bool showFrame )
1185 {
1186  if ( showFrame == mShowFrame )
1187  {
1188  return;
1189  }
1190  mShowFrame = showFrame;
1191  update();
1192 }
1193 
1194 void QgsColorRampWidget::setMarkerSize( const int markerSize )
1195 {
1196  //create triangle polygons
1197  mTopTriangle << QPoint( -markerSize, 0 ) << QPoint( markerSize, 0 ) << QPoint( 0, markerSize );
1198  mBottomTriangle << QPoint( -markerSize, 0 ) << QPoint( markerSize, 0 ) << QPoint( 0, -markerSize );
1199  update();
1200 }
1201 
1202 void QgsColorRampWidget::mouseMoveEvent( QMouseEvent *event )
1203 {
1204  if ( mIsDragging )
1205  {
1206  setColorFromPoint( event->pos() );
1207  }
1208 
1210 }
1211 
1212 void QgsColorRampWidget::wheelEvent( QWheelEvent *event )
1213 {
1214  const int oldValue = componentValue();
1215 
1216  if ( event->angleDelta().y() > 0 )
1217  {
1219  }
1220  else
1221  {
1223  }
1224 
1225  if ( componentValue() != oldValue )
1226  {
1227  //value has changed
1228  emit colorChanged( mCurrentColor );
1229  emit valueChanged( componentValue() );
1230  }
1231 
1232  event->accept();
1233 }
1234 
1235 void QgsColorRampWidget::mousePressEvent( QMouseEvent *event )
1236 {
1237  if ( event->button() == Qt::LeftButton )
1238  {
1239  mIsDragging = true;
1240  setColorFromPoint( event->pos() );
1241  }
1242  else
1243  {
1245  }
1246 }
1247 
1248 void QgsColorRampWidget::mouseReleaseEvent( QMouseEvent *event )
1249 {
1250  if ( event->button() == Qt::LeftButton )
1251  {
1252  mIsDragging = false;
1253  }
1254  else
1255  {
1257  }
1258 }
1259 
1260 void QgsColorRampWidget::keyPressEvent( QKeyEvent *event )
1261 {
1262  const int oldValue = componentValue();
1263  if ( ( mOrientation == QgsColorRampWidget::Horizontal && ( event->key() == Qt::Key_Right || event->key() == Qt::Key_Up ) )
1264  || ( mOrientation == QgsColorRampWidget::Vertical && ( event->key() == Qt::Key_Left || event->key() == Qt::Key_Up ) ) )
1265  {
1267  }
1268  else if ( ( mOrientation == QgsColorRampWidget::Horizontal && ( event->key() == Qt::Key_Left || event->key() == Qt::Key_Down ) )
1269  || ( mOrientation == QgsColorRampWidget::Vertical && ( event->key() == Qt::Key_Right || event->key() == Qt::Key_Down ) ) )
1270  {
1272  }
1273  else if ( ( mOrientation == QgsColorRampWidget::Horizontal && event->key() == Qt::Key_PageDown )
1274  || ( mOrientation == QgsColorRampWidget::Vertical && event->key() == Qt::Key_PageUp ) )
1275  {
1277  }
1278  else if ( ( mOrientation == QgsColorRampWidget::Horizontal && event->key() == Qt::Key_PageUp )
1279  || ( mOrientation == QgsColorRampWidget::Vertical && event->key() == Qt::Key_PageDown ) )
1280  {
1282  }
1283  else if ( ( mOrientation == QgsColorRampWidget::Horizontal && event->key() == Qt::Key_Home )
1284  || ( mOrientation == QgsColorRampWidget::Vertical && event->key() == Qt::Key_End ) )
1285  {
1286  setComponentValue( 0 );
1287  }
1288  else if ( ( mOrientation == QgsColorRampWidget::Horizontal && event->key() == Qt::Key_End )
1289  || ( mOrientation == QgsColorRampWidget::Vertical && event->key() == Qt::Key_Home ) )
1290  {
1291  //set to maximum value
1293  }
1294  else
1295  {
1296  QgsColorWidget::keyPressEvent( event );
1297  return;
1298  }
1299 
1300  if ( componentValue() != oldValue )
1301  {
1302  //value has changed
1303  emit colorChanged( mCurrentColor );
1304  emit valueChanged( componentValue() );
1305  }
1306 }
1307 
1308 void QgsColorRampWidget::setColorFromPoint( QPointF point )
1309 {
1310  const int oldValue = componentValue();
1311  int val;
1312  if ( mOrientation == QgsColorRampWidget::Horizontal )
1313  {
1314  val = componentRange() * ( point.x() - mMargin ) / ( width() - 2 * mMargin );
1315  }
1316  else
1317  {
1318  val = componentRange() - componentRange() * ( point.y() - mMargin ) / ( height() - 2 * mMargin );
1319  }
1320  val = std::max( 0, std::min( val, componentRange() ) );
1321  setComponentValue( val );
1322 
1323  if ( componentValue() != oldValue )
1324  {
1325  //value has changed
1326  emit colorChanged( mCurrentColor );
1327  emit valueChanged( componentValue() );
1328  }
1329 }
1330 
1331 //
1332 // QgsColorSliderWidget
1333 //
1334 
1336  : QgsColorWidget( parent, component )
1337 
1338 {
1339  QHBoxLayout *hLayout = new QHBoxLayout();
1340  hLayout->setContentsMargins( 0, 0, 0, 0 );
1341  hLayout->setSpacing( 5 );
1342 
1343  mRampWidget = new QgsColorRampWidget( nullptr, component );
1344  mRampWidget->setColor( mCurrentColor );
1345  hLayout->addWidget( mRampWidget, 1 );
1346 
1347  mSpinBox = new QSpinBox();
1348  //set spinbox to a reasonable width
1349  const int largestCharWidth = mSpinBox->fontMetrics().horizontalAdvance( QStringLiteral( "888%" ) );
1350  mSpinBox->setMinimumWidth( largestCharWidth + 35 );
1351  mSpinBox->setMinimum( 0 );
1352  mSpinBox->setMaximum( convertRealToDisplay( componentRange() ) );
1353  mSpinBox->setValue( convertRealToDisplay( componentValue() ) );
1354  if ( component == QgsColorWidget::Hue )
1355  {
1356  //degrees suffix for hue
1357  mSpinBox->setSuffix( QChar( 176 ) );
1358  }
1360  {
1361  mSpinBox->setSuffix( tr( "%" ) );
1362  }
1363  hLayout->addWidget( mSpinBox );
1364  setLayout( hLayout );
1365 
1366  connect( mRampWidget, &QgsColorRampWidget::valueChanged, this, &QgsColorSliderWidget::rampChanged );
1367  connect( mRampWidget, &QgsColorWidget::colorChanged, this, &QgsColorSliderWidget::rampColorChanged );
1368  connect( mSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsColorSliderWidget::spinChanged );
1369 }
1370 
1372 {
1374  mRampWidget->setComponent( component );
1375  mSpinBox->setMaximum( convertRealToDisplay( componentRange() ) );
1376  if ( component == QgsColorWidget::Hue )
1377  {
1378  //degrees suffix for hue
1379  mSpinBox->setSuffix( QChar( 176 ) );
1380  }
1382  {
1383  //saturation, value and alpha are in %
1384  mSpinBox->setSuffix( tr( "%" ) );
1385  }
1386  else
1387  {
1388  //clear suffix
1389  mSpinBox->setSuffix( QString() );
1390  }
1391 }
1392 
1394 {
1396  mRampWidget->blockSignals( true );
1397  mRampWidget->setComponentValue( value );
1398  mRampWidget->blockSignals( false );
1399  mSpinBox->blockSignals( true );
1400  mSpinBox->setValue( convertRealToDisplay( value ) );
1401  mSpinBox->blockSignals( false );
1402 }
1403 
1404 void QgsColorSliderWidget::setColor( const QColor &color, bool emitSignals )
1405 {
1406  QgsColorWidget::setColor( color, emitSignals );
1407  mRampWidget->setColor( color );
1408  mSpinBox->blockSignals( true );
1409  mSpinBox->setValue( convertRealToDisplay( componentValue() ) );
1410  mSpinBox->blockSignals( false );
1411 }
1412 
1413 void QgsColorSliderWidget::rampColorChanged( const QColor &color )
1414 {
1415  emit colorChanged( color );
1416 }
1417 
1418 void QgsColorSliderWidget::spinChanged( int value )
1419 {
1420  const int convertedValue = convertDisplayToReal( value );
1421  QgsColorWidget::setComponentValue( convertedValue );
1422  mRampWidget->setComponentValue( convertedValue );
1423  emit colorChanged( mCurrentColor );
1424 }
1425 
1426 void QgsColorSliderWidget::rampChanged( int value )
1427 {
1428  mSpinBox->blockSignals( true );
1429  mSpinBox->setValue( convertRealToDisplay( value ) );
1430  mSpinBox->blockSignals( false );
1431 }
1432 
1433 
1434 int QgsColorSliderWidget::convertRealToDisplay( const int realValue ) const
1435 {
1436  //scale saturation, value or alpha to 0->100 range. This makes more sense for users
1437  //for whom "255" is a totally arbitrary value!
1439  {
1440  return std::round( 100.0 * realValue / 255.0 );
1441  }
1442 
1443  //leave all other values intact
1444  return realValue;
1445 }
1446 
1447 int QgsColorSliderWidget::convertDisplayToReal( const int displayValue ) const
1448 {
1449  //scale saturation, value or alpha from 0->100 range (see note in convertRealToDisplay)
1451  {
1452  return std::round( 255.0 * displayValue / 100.0 );
1453  }
1454 
1455  //leave all other values intact
1456  return displayValue;
1457 }
1458 
1459 //
1460 // QgsColorTextWidget
1461 //
1462 
1464  : QgsColorWidget( parent )
1465 {
1466  QHBoxLayout *hLayout = new QHBoxLayout();
1467  hLayout->setContentsMargins( 0, 0, 0, 0 );
1468  hLayout->setSpacing( 0 );
1469 
1470  mLineEdit = new QLineEdit( nullptr );
1471  hLayout->addWidget( mLineEdit );
1472 
1473  mMenuButton = new QToolButton( mLineEdit );
1474  mMenuButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconDropDownMenu.svg" ) ) );
1475  mMenuButton->setCursor( Qt::ArrowCursor );
1476  mMenuButton->setFocusPolicy( Qt::NoFocus );
1477  mMenuButton->setStyleSheet( QStringLiteral( "QToolButton { border: none; padding: 0px; }" ) );
1478 
1479  setLayout( hLayout );
1480 
1481  const int frameWidth = mLineEdit->style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
1482  mLineEdit->setStyleSheet( QStringLiteral( "QLineEdit { padding-right: %1px; } " )
1483  .arg( mMenuButton->sizeHint().width() + frameWidth + 1 ) );
1484 
1485  connect( mLineEdit, &QLineEdit::editingFinished, this, &QgsColorTextWidget::textChanged );
1486  connect( mMenuButton, &QAbstractButton::clicked, this, &QgsColorTextWidget::showMenu );
1487 
1488  //restore format setting
1489  QgsSettings settings;
1490  mFormat = settings.enumValue( QStringLiteral( "ColorWidgets/textWidgetFormat" ), HexRgb );
1491 
1492  updateText();
1493 }
1494 
1495 void QgsColorTextWidget::setColor( const QColor &color, const bool emitSignals )
1496 {
1497  QgsColorWidget::setColor( color, emitSignals );
1498  updateText();
1499 }
1500 
1501 void QgsColorTextWidget::resizeEvent( QResizeEvent *event )
1502 {
1503  Q_UNUSED( event )
1504  const QSize sz = mMenuButton->sizeHint();
1505  const int frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
1506  mMenuButton->move( mLineEdit->rect().right() - frameWidth - sz.width(),
1507  ( mLineEdit->rect().bottom() + 1 - sz.height() ) / 2 );
1508 }
1509 
1510 void QgsColorTextWidget::updateText()
1511 {
1512  switch ( mFormat )
1513  {
1514  case HexRgb:
1515  mLineEdit->setText( mCurrentColor.name() );
1516  break;
1517  case HexRgbA:
1518  mLineEdit->setText( mCurrentColor.name() + QStringLiteral( "%1" ).arg( mCurrentColor.alpha(), 2, 16, QChar( '0' ) ) );
1519  break;
1520  case Rgb:
1521  mLineEdit->setText( tr( "rgb( %1, %2, %3 )" ).arg( mCurrentColor.red() ).arg( mCurrentColor.green() ).arg( mCurrentColor.blue() ) );
1522  break;
1523  case Rgba:
1524  mLineEdit->setText( tr( "rgba( %1, %2, %3, %4 )" ).arg( mCurrentColor.red() ).arg( mCurrentColor.green() ).arg( mCurrentColor.blue() ).arg( QString::number( mCurrentColor.alphaF(), 'f', 2 ) ) );
1525  break;
1526  }
1527 }
1528 
1529 void QgsColorTextWidget::textChanged()
1530 {
1531  const QString testString = mLineEdit->text();
1532  bool containsAlpha;
1533  QColor color = QgsSymbolLayerUtils::parseColorWithAlpha( testString, containsAlpha );
1534  if ( !color.isValid() )
1535  {
1536  //bad color string
1537  updateText();
1538  return;
1539  }
1540 
1541  //good color string
1542  if ( color != mCurrentColor )
1543  {
1544  //retain alpha if no explicit alpha set
1545  if ( !containsAlpha )
1546  {
1547  color.setAlpha( mCurrentColor.alpha() );
1548  }
1549  //color has changed
1550  mCurrentColor = color;
1551  emit colorChanged( mCurrentColor );
1552  }
1553  updateText();
1554 }
1555 
1556 void QgsColorTextWidget::showMenu()
1557 {
1558  QMenu colorContextMenu;
1559 
1560  QAction *hexRgbAction = new QAction( tr( "#RRGGBB" ), nullptr );
1561  colorContextMenu.addAction( hexRgbAction );
1562  QAction *hexRgbaAction = new QAction( tr( "#RRGGBBAA" ), nullptr );
1563  colorContextMenu.addAction( hexRgbaAction );
1564  QAction *rgbAction = new QAction( tr( "rgb( r, g, b )" ), nullptr );
1565  colorContextMenu.addAction( rgbAction );
1566  QAction *rgbaAction = new QAction( tr( "rgba( r, g, b, a )" ), nullptr );
1567  colorContextMenu.addAction( rgbaAction );
1568 
1569  QAction *selectedAction = colorContextMenu.exec( QCursor::pos() );
1570  if ( selectedAction == hexRgbAction )
1571  {
1572  mFormat = QgsColorTextWidget::HexRgb;
1573  }
1574  else if ( selectedAction == hexRgbaAction )
1575  {
1576  mFormat = QgsColorTextWidget::HexRgbA;
1577  }
1578  else if ( selectedAction == rgbAction )
1579  {
1580  mFormat = QgsColorTextWidget::Rgb;
1581  }
1582  else if ( selectedAction == rgbaAction )
1583  {
1584  mFormat = QgsColorTextWidget::Rgba;
1585  }
1586 
1587  //save format setting
1588  QgsSettings settings;
1589  settings.setEnumValue( QStringLiteral( "ColorWidgets/textWidgetFormat" ), mFormat );
1590 
1591  updateText();
1592 }
1593 
1594 
1595 //
1596 // QgsColorPreviewWidget
1597 //
1598 
1600  : QgsColorWidget( parent )
1601  , mColor2( QColor() )
1602 {
1603 
1604 }
1605 
1606 void QgsColorPreviewWidget::drawColor( const QColor &color, QRect rect, QPainter &painter )
1607 {
1608  painter.setPen( Qt::NoPen );
1609  //if color has an alpha, start with a checkboard pattern
1610  if ( color.alpha() < 255 )
1611  {
1612  const QBrush checkBrush = QBrush( transparentBackground() );
1613  painter.setBrush( checkBrush );
1614  painter.drawRect( rect );
1615 
1616  //draw half of widget showing solid color, the other half showing color with alpha
1617 
1618  //ensure at least a 1px overlap to avoid artifacts
1619  const QBrush colorBrush = QBrush( color );
1620  painter.setBrush( colorBrush );
1621  painter.drawRect( std::floor( rect.width() / 2.0 ) + rect.left(), rect.top(), rect.width() - std::floor( rect.width() / 2.0 ), rect.height() );
1622 
1623  QColor opaqueColor = QColor( color );
1624  opaqueColor.setAlpha( 255 );
1625  const QBrush opaqueBrush = QBrush( opaqueColor );
1626  painter.setBrush( opaqueBrush );
1627  painter.drawRect( rect.left(), rect.top(), std::ceil( rect.width() / 2.0 ), rect.height() );
1628  }
1629  else
1630  {
1631  //no alpha component, just draw a solid rectangle
1632  const QBrush brush = QBrush( color );
1633  painter.setBrush( brush );
1634  painter.drawRect( rect );
1635  }
1636 }
1637 
1638 void QgsColorPreviewWidget::paintEvent( QPaintEvent *event )
1639 {
1640  Q_UNUSED( event )
1641  QPainter painter( this );
1642 
1643  if ( mColor2.isValid() )
1644  {
1645  //drawing with two color sections
1646  const int verticalSplit = std::round( height() / 2.0 );
1647  drawColor( mCurrentColor, QRect( 0, 0, width(), verticalSplit ), painter );
1648  drawColor( mColor2, QRect( 0, verticalSplit, width(), height() - verticalSplit ), painter );
1649  }
1650  else if ( mCurrentColor.isValid() )
1651  {
1652  drawColor( mCurrentColor, QRect( 0, 0, width(), height() ), painter );
1653  }
1654 
1655  painter.end();
1656 }
1657 
1659 {
1660  return QSize( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 22, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 22 * 0.75 );
1661 }
1662 
1663 void QgsColorPreviewWidget::setColor2( const QColor &color )
1664 {
1665  if ( color == mColor2 )
1666  {
1667  return;
1668  }
1669  mColor2 = color;
1670  update();
1671 }
1672 
1674 {
1675  if ( e->button() == Qt::LeftButton )
1676  {
1677  mDragStartPosition = e->pos();
1678  }
1680 }
1681 
1683 {
1684  if ( ( e->pos() - mDragStartPosition ).manhattanLength() >= QApplication::startDragDistance() )
1685  {
1686  //mouse moved, so a drag. nothing to do here
1688  return;
1689  }
1690 
1691  //work out which color was clicked
1692  QColor clickedColor = mCurrentColor;
1693  if ( mColor2.isValid() )
1694  {
1695  //two color sections, check if dragged color was the second color
1696  const int verticalSplit = std::round( height() / 2.0 );
1697  if ( mDragStartPosition.y() >= verticalSplit )
1698  {
1699  clickedColor = mColor2;
1700  }
1701  }
1702  emit colorChanged( clickedColor );
1703 
1704 }
1705 
1707 {
1708  //handle dragging colors from button
1709 
1710  if ( !( e->buttons() & Qt::LeftButton ) )
1711  {
1712  //left button not depressed, so not a drag
1714  return;
1715  }
1716 
1717  if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
1718  {
1719  //mouse not moved, so not a drag
1721  return;
1722  }
1723 
1724  //user is dragging color
1725 
1726  //work out which color is being dragged
1727  QColor dragColor = mCurrentColor;
1728  if ( mColor2.isValid() )
1729  {
1730  //two color sections, check if dragged color was the second color
1731  const int verticalSplit = std::round( height() / 2.0 );
1732  if ( mDragStartPosition.y() >= verticalSplit )
1733  {
1734  dragColor = mColor2;
1735  }
1736  }
1737 
1738  QDrag *drag = new QDrag( this );
1739  drag->setMimeData( QgsSymbolLayerUtils::colorToMimeData( dragColor ) );
1740  drag->setPixmap( createDragIcon( dragColor ) );
1741  drag->exec( Qt::CopyAction );
1742 }
1743 
1744 
1745 //
1746 // QgsColorWidgetAction
1747 //
1748 
1749 QgsColorWidgetAction::QgsColorWidgetAction( QgsColorWidget *colorWidget, QMenu *menu, QWidget *parent )
1750  : QWidgetAction( parent )
1751  , mMenu( menu )
1752  , mColorWidget( colorWidget )
1753  , mSuppressRecurse( false )
1754  , mDismissOnColorSelection( true )
1755 {
1756  setDefaultWidget( mColorWidget );
1757  connect( mColorWidget, &QgsColorWidget::colorChanged, this, &QgsColorWidgetAction::setColor );
1758 
1759  connect( this, &QAction::hovered, this, &QgsColorWidgetAction::onHover );
1760  connect( mColorWidget, &QgsColorWidget::hovered, this, &QgsColorWidgetAction::onHover );
1761 }
1762 
1763 void QgsColorWidgetAction::onHover()
1764 {
1765  //see https://bugreports.qt.io/browse/QTBUG-10427?focusedCommentId=185610&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-185610
1766  if ( mSuppressRecurse )
1767  {
1768  return;
1769  }
1770 
1771  if ( mMenu )
1772  {
1773  mSuppressRecurse = true;
1774  mMenu->setActiveAction( this );
1775  mSuppressRecurse = false;
1776  }
1777 }
1778 
1779 void QgsColorWidgetAction::setColor( const QColor &color )
1780 {
1781  emit colorChanged( color );
1782  if ( mMenu && mDismissOnColorSelection )
1783  {
1784  QAction::trigger();
1785  mMenu->hide();
1786  }
1787 }
QgsColorRampWidget::setInteriorMargin
void setInteriorMargin(int margin)
Sets the margin between the edge of the widget and the ramp.
Definition: qgscolorwidgets.cpp:1174
QgsColorWidget::Value
@ Value
Value component of color (based on HSV model)
Definition: qgscolorwidgets.h:56
QgsColorTextWidget::Rgb
@ Rgb
Rgb( r, g, b ) format.
Definition: qgscolorwidgets.h:694
QgsColorBox::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:861
QgsColorWidget::hue
int hue() const
Returns the hue for the widget.
Definition: qgscolorwidgets.cpp:135
QgsSymbolLayerUtils::colorToMimeData
static QMimeData * colorToMimeData(const QColor &color)
Creates mime data from a color.
Definition: qgssymbollayerutils.cpp:3497
QgsColorPreviewWidget::paintEvent
void paintEvent(QPaintEvent *event) override
Definition: qgscolorwidgets.cpp:1638
QgsColorRampWidget::Horizontal
@ Horizontal
Horizontal ramp.
Definition: qgscolorwidgets.h:495
QgsColorWheel::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:637
QgsColorTextWidget::Rgba
@ Rgba
Rgba( r, g, b, a ) format, with alpha.
Definition: qgscolorwidgets.h:695
QgsColorWheel::resizeEvent
void resizeEvent(QResizeEvent *event) override
Definition: qgscolorwidgets.cpp:512
QgsColorPreviewWidget::sizeHint
QSize sizeHint() const override
Definition: qgscolorwidgets.cpp:1658
QgsColorWidget::Multiple
@ Multiple
Widget alters multiple color components.
Definition: qgscolorwidgets.h:50
QgsColorRampWidget::wheelEvent
void wheelEvent(QWheelEvent *event) override
Definition: qgscolorwidgets.cpp:1212
QgsColorBox::mousePressEvent
void mousePressEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:870
QgsColorWheel::mousePressEvent
void mousePressEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:610
QgsColorWidget::componentValue
int componentValue() const
Returns the current value of the widget's color component.
Definition: qgscolorwidgets.cpp:56
qgssymbollayerutils.h
QgsColorWidget::mComponent
ColorComponent mComponent
Definition: qgscolorwidgets.h:142
QgsColorWheel::sizeHint
QSize sizeHint() const override
Definition: qgscolorwidgets.cpp:398
QgsColorBox::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:883
QgsColorPreviewWidget::setColor2
virtual void setColor2(const QColor &color)
Sets the second color for the widget.
Definition: qgscolorwidgets.cpp:1663
QgsColorWheel::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:602
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsColorPreviewWidget::QgsColorPreviewWidget
QgsColorPreviewWidget(QWidget *parent=nullptr)
Construct a new color preview widget.
Definition: qgscolorwidgets.cpp:1599
qgscolorwidgets.h
QgsColorWidget::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *e) override
Definition: qgscolorwidgets.cpp:243
QgsColorWidget::mExplicitHue
int mExplicitHue
QColor wipes the hue information when it is ambiguous (e.g., for saturation = 0).
Definition: qgscolorwidgets.h:148
QgsColorRampWidget
A color ramp widget. This widget consists of an interactive box filled with a color which varies alon...
Definition: qgscolorwidgets.h:484
QgsColorWidget::setComponent
virtual void setComponent(QgsColorWidget::ColorComponent component)
Sets the color component which the widget controls.
Definition: qgscolorwidgets.cpp:254
QgsColorWidget::QgsColorWidget
QgsColorWidget(QWidget *parent=nullptr, ColorComponent component=Multiple)
Construct a new color widget.
Definition: qgscolorwidgets.cpp:48
QgsColorWidget::setComponentValue
virtual void setComponentValue(int value)
Alters the widget's color by setting the value for the widget's color component.
Definition: qgscolorwidgets.cpp:265
QgsSymbolLayerUtils::colorFromMimeData
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.
Definition: qgssymbollayerutils.cpp:3507
QgsColorWidget::mousePressEvent
void mousePressEvent(QMouseEvent *e) override
Definition: qgscolorwidgets.cpp:237
QgsColorWheel::QgsColorWheel
QgsColorWheel(QWidget *parent=nullptr)
Constructs a new color wheel widget.
Definition: qgscolorwidgets.cpp:375
QgsColorRampWidget::orientation
Orientation orientation() const
Fetches the orientation for the color ramp.
Definition: qgscolorwidgets.h:524
QgsColorWidget::Green
@ Green
Green component of color.
Definition: qgscolorwidgets.h:52
QgsGuiUtils::iconSize
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
Definition: qgsguiutils.cpp:264
QgsApplication::getThemePixmap
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
Definition: qgsapplication.cpp:827
qgsapplication.h
QgsColorRampWidget::sizeHint
QSize sizeHint() const override
Definition: qgscolorwidgets.cpp:1024
QgsColorBox::sizeHint
QSize sizeHint() const override
Definition: qgscolorwidgets.cpp:773
QgsColorSliderWidget::setComponentValue
void setComponentValue(int value) override
Alters the widget's color by setting the value for the widget's color component.
Definition: qgscolorwidgets.cpp:1393
QgsColorWidget::setColor
virtual void setColor(const QColor &color, bool emitSignals=false)
Sets the color for the widget.
Definition: qgscolorwidgets.cpp:347
QgsColorRampWidget::setShowFrame
void setShowFrame(bool showFrame)
Sets whether the ramp should be drawn within a frame.
Definition: qgscolorwidgets.cpp:1184
QgsColorWidget::transparentBackground
static const QPixmap & transparentBackground()
Generates a checkboard pattern pixmap for use as a background to transparent colors.
Definition: qgscolorwidgets.cpp:183
QgsColorWidgetAction::QgsColorWidgetAction
QgsColorWidgetAction(QgsColorWidget *colorWidget, QMenu *menu=nullptr, QWidget *parent=nullptr)
Construct a new color widget action.
Definition: qgscolorwidgets.cpp:1749
QgsColorTextWidget::HexRgb
@ HexRgb
#RRGGBB in hexadecimal
Definition: qgscolorwidgets.h:692
QgsColorWidget::Red
@ Red
Red component of color.
Definition: qgscolorwidgets.h:51
QgsColorPreviewWidget::mousePressEvent
void mousePressEvent(QMouseEvent *e) override
Definition: qgscolorwidgets.cpp:1673
QgsColorWidget::mCurrentColor
QColor mCurrentColor
Definition: qgscolorwidgets.h:140
QgsColorWheel::~QgsColorWheel
~QgsColorWheel() override
Definition: qgscolorwidgets.cpp:391
QgsSettings::setEnumValue
void setEnumValue(const QString &key, const T &value, const Section section=NoSection)
Set the value of a setting based on an enum.
Definition: qgssettings.h:334
QgsColorRampWidget::paintEvent
void paintEvent(QPaintEvent *event) override
Definition: qgscolorwidgets.cpp:1038
QgsColorWidget::component
ColorComponent component() const
Returns the color component which the widget controls.
Definition: qgscolorwidgets.h:79
QgsColorWidget
A base class for interactive color widgets. Widgets can either allow setting a single component of a ...
Definition: qgscolorwidgets.h:39
QgsColorWidget::Alpha
@ Alpha
Alpha component (opacity) of color.
Definition: qgscolorwidgets.h:57
QgsColorWheel::paintEvent
void paintEvent(QPaintEvent *event) override
Definition: qgscolorwidgets.cpp:404
QgsColorBox::~QgsColorBox
~QgsColorBox() override
Definition: qgscolorwidgets.cpp:768
QgsColorWheel::setColor
void setColor(const QColor &color, bool emitSignals=false) override
Definition: qgscolorwidgets.cpp:483
QgsColorRampWidget::showFrame
bool showFrame() const
Fetches whether the ramp is drawn within a frame.
Definition: qgscolorwidgets.h:552
Qgis::UI_SCALE_FACTOR
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:2043
QgsColorRampWidget::QgsColorRampWidget
QgsColorRampWidget(QWidget *parent=nullptr, ColorComponent component=QgsColorWidget::Red, Orientation orientation=QgsColorRampWidget::Horizontal)
Construct a new color ramp widget.
Definition: qgscolorwidgets.cpp:1012
QgsColorRampWidget::Orientation
Orientation
Specifies the orientation of a color ramp.
Definition: qgscolorwidgets.h:493
QgsColorWidget::componentRange
int componentRange() const
Returns the range of valid values for the color widget's component.
Definition: qgscolorwidgets.cpp:110
QgsColorSliderWidget::QgsColorSliderWidget
QgsColorSliderWidget(QWidget *parent=nullptr, ColorComponent component=QgsColorWidget::Red)
Construct a new color slider widget.
Definition: qgscolorwidgets.cpp:1335
QgsColorRampWidget::Vertical
@ Vertical
Vertical ramp.
Definition: qgscolorwidgets.h:496
QgsColorWidget::Blue
@ Blue
Blue component of color.
Definition: qgscolorwidgets.h:53
QgsColorWidget::Hue
@ Hue
Hue component of color (based on HSV model)
Definition: qgscolorwidgets.h:54
QgsColorPreviewWidget::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *e) override
Definition: qgscolorwidgets.cpp:1706
QgsColorBox::setColor
void setColor(const QColor &color, bool emitSignals=false) override
Definition: qgscolorwidgets.cpp:823
QgsColorBox::setComponent
void setComponent(ColorComponent component) override
Sets the color component which the widget controls.
Definition: qgscolorwidgets.cpp:813
QgsColorTextWidget::resizeEvent
void resizeEvent(QResizeEvent *event) override
Definition: qgscolorwidgets.cpp:1501
QgsColorWidget::dropEvent
void dropEvent(QDropEvent *e) override
Definition: qgscolorwidgets.cpp:206
QgsColorTextWidget::HexRgbA
@ HexRgbA
#RRGGBBAA in hexadecimal, with alpha
Definition: qgscolorwidgets.h:693
QgsColorRampWidget::valueChanged
void valueChanged(int value)
Emitted when the widget's color component value changes.
QgsColorWidget::alterColor
void alterColor(QColor &color, QgsColorWidget::ColorComponent component, int newValue) const
Alters a color by modifying the value of a specific color component.
Definition: qgscolorwidgets.cpp:147
QgsColorWidget::ColorComponent
ColorComponent
Specifies the color component which the widget alters.
Definition: qgscolorwidgets.h:48
QgsColorRampWidget::setOrientation
void setOrientation(Orientation orientation)
Sets the orientation for the color ramp.
Definition: qgscolorwidgets.cpp:1158
QgsColorBox::paintEvent
void paintEvent(QPaintEvent *event) override
Definition: qgscolorwidgets.cpp:779
QgsColorWidget::dragEnterEvent
void dragEnterEvent(QDragEnterEvent *e) override
Definition: qgscolorwidgets.cpp:193
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsSymbolLayerUtils::parseColorWithAlpha
static QColor parseColorWithAlpha(const QString &colorStr, bool &containsAlpha, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
Definition: qgssymbollayerutils.cpp:3834
QgsColorWidget::color
QColor color() const
Returns the current color for the widget.
Definition: qgscolorwidgets.cpp:249
qgssettings.h
QgsColorWidget::Saturation
@ Saturation
Saturation component of color (based on HSV model)
Definition: qgscolorwidgets.h:55
QgsColorRampWidget::setMarkerSize
void setMarkerSize(int markerSize)
Sets the size for drawing the triangular markers on the ramp.
Definition: qgscolorwidgets.cpp:1194
QgsColorWidgetAction::colorChanged
void colorChanged(const QColor &color)
Emitted when a color has been selected from the widget.
QgsColorTextWidget::setColor
void setColor(const QColor &color, bool emitSignals=false) override
Sets the color for the widget.
Definition: qgscolorwidgets.cpp:1495
QgsColorRampWidget::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:1202
QgsColorBox::QgsColorBox
QgsColorBox(QWidget *parent=nullptr, ColorComponent component=Value)
Construct a new color box widget.
Definition: qgscolorwidgets.cpp:759
QgsColorPreviewWidget::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *e) override
Definition: qgscolorwidgets.cpp:1682
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsColorRampWidget::keyPressEvent
void keyPressEvent(QKeyEvent *event) override
Definition: qgscolorwidgets.cpp:1260
QgsSettings::enumValue
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
Definition: qgssettings.h:282
QgsColorWidget::colorChanged
void colorChanged(const QColor &color)
Emitted when the widget's color changes.
qgslogger.h
qgsguiutils.h
QgsColorSliderWidget::setColor
void setColor(const QColor &color, bool emitSignals=false) override
Sets the color for the widget.
Definition: qgscolorwidgets.cpp:1404
QgsGuiUtils::scaleIconSize
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
Definition: qgsguiutils.cpp:259
QgsColorWidget::hovered
void hovered()
Emitted when mouse hovers over widget.
QgsColorRampWidget::mousePressEvent
void mousePressEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:1235
QgsColorWidget::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *e) override
Definition: qgscolorwidgets.cpp:230
MathUtils::angle
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QgsColorRampWidget::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event) override
Definition: qgscolorwidgets.cpp:1248
QgsColorBox::resizeEvent
void resizeEvent(QResizeEvent *event) override
Definition: qgscolorwidgets.cpp:853
QgsColorTextWidget::QgsColorTextWidget
QgsColorTextWidget(QWidget *parent=nullptr)
Construct a new color line edit widget.
Definition: qgscolorwidgets.cpp:1463
QgsColorSliderWidget::setComponent
void setComponent(ColorComponent component) override
Sets the color component which the widget controls.
Definition: qgscolorwidgets.cpp:1371
QgsColorWidget::createDragIcon
static QPixmap createDragIcon(const QColor &color)
Create an icon for dragging colors.
Definition: qgscolorwidgets.cpp:61