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