QGIS API Documentation  3.23.0-Master (eb871beae0)
qgsgradientcolorrampdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgradientcolorrampdialog.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk 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 
17 
18 #include "qgscolorramp.h"
19 #include "qgsdialog.h"
20 #include "qgscolordialog.h"
21 #include "qgscptcityarchive.h"
22 #include "qgssettings.h"
23 #include "qgsgui.h"
24 
25 #include <QColorDialog>
26 #include <QHeaderView>
27 #include <QInputDialog>
28 #include <QPainter>
29 #include <QTableWidget>
30 #include <QTextEdit>
31 
32 // QWT Charting widget
33 #include <qwt_global.h>
34 #include <qwt_plot_canvas.h>
35 #include <qwt_plot.h>
36 #include <qwt_plot_curve.h>
37 #include <qwt_plot_grid.h>
38 #include <qwt_plot_marker.h>
39 #include <qwt_plot_picker.h>
40 #include <qwt_picker_machine.h>
41 #include <qwt_plot_layout.h>
42 #include <qwt_symbol.h>
43 #include <qwt_legend.h>
44 #include <qwt_scale_div.h>
45 #include <qwt_scale_map.h>
46 
48  : QDialog( parent )
49  , mRamp( ramp )
50  , mCurrentPlotColorComponent( -1 )
51  , mCurrentPlotMarkerIndex( 0 )
52 {
53  setupUi( this );
55 
56  mStopColorSpec->addItem( tr( "RGB" ), static_cast< int >( QColor::Spec::Rgb ) );
57  mStopColorSpec->addItem( tr( "HSV" ), static_cast< int >( QColor::Spec::Hsv ) );
58  mStopColorSpec->addItem( tr( "HSL" ), static_cast< int >( QColor::Spec::Hsl ) );
59  mStopColorSpec->setCurrentIndex( mStopColorSpec->findData( static_cast< int >( ramp.colorSpec() ) ) );
60 
61  mStopDirection->addItem( tr( "Clockwise" ), static_cast< int >( Qgis::AngularDirection::Clockwise ) );
62  mStopDirection->addItem( tr( "Counterclockwise" ), static_cast< int >( Qgis::AngularDirection::CounterClockwise ) );
63  mStopDirection->setCurrentIndex( mStopColorSpec->findData( static_cast< int >( ramp.direction() ) ) );
64 
65  mStopDirection->setEnabled( static_cast< QColor::Spec>( mStopColorSpec->currentData().toInt() ) != QColor::Spec::Rgb );
66 
67  connect( mStopColorSpec, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, [ = ]
68  {
69  mStopDirection->setEnabled( static_cast< QColor::Spec>( mStopColorSpec->currentData().toInt() ) != QColor::Spec::Rgb );
70 
71  if ( mBlockChanges )
72  return;
73  mStopEditor->setSelectedStopColorSpec( static_cast< QColor::Spec>( mStopColorSpec->currentData().toInt() ) );
74  } );
75 
76  connect( mStopDirection, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, [ = ]
77  {
78  if ( mBlockChanges )
79  return;
80 
81  mStopEditor->setSelectedStopDirection( static_cast< Qgis::AngularDirection >( mStopDirection->currentData().toInt() ) );
82  } );
83 
84  connect( cboType, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsGradientColorRampDialog::cboType_currentIndexChanged );
85  connect( btnInformation, &QPushButton::pressed, this, &QgsGradientColorRampDialog::btnInformation_pressed );
86  connect( mPositionSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsGradientColorRampDialog::mPositionSpinBox_valueChanged );
87  connect( mPlotHueCheckbox, &QCheckBox::toggled, this, &QgsGradientColorRampDialog::mPlotHueCheckbox_toggled );
88  connect( mPlotLightnessCheckbox, &QCheckBox::toggled, this, &QgsGradientColorRampDialog::mPlotLightnessCheckbox_toggled );
89  connect( mPlotSaturationCheckbox, &QCheckBox::toggled, this, &QgsGradientColorRampDialog::mPlotSaturationCheckbox_toggled );
90  connect( mPlotAlphaCheckbox, &QCheckBox::toggled, this, &QgsGradientColorRampDialog::mPlotAlphaCheckbox_toggled );
91 #ifdef Q_OS_MAC
92  setWindowModality( Qt::WindowModal );
93 #endif
94 
95  mPositionSpinBox->setShowClearButton( false );
96  btnColor1->setAllowOpacity( true );
97  btnColor1->setColorDialogTitle( tr( "Select Ramp Color" ) );
98  btnColor1->setContext( QStringLiteral( "symbology" ) );
99  btnColor1->setShowNoColor( true );
100  btnColor1->setNoColorString( tr( "Transparent" ) );
101  btnColor2->setAllowOpacity( true );
102  btnColor2->setColorDialogTitle( tr( "Select Ramp Color" ) );
103  btnColor2->setContext( QStringLiteral( "symbology" ) );
104  btnColor2->setShowNoColor( true );
105  btnColor2->setNoColorString( tr( "Transparent" ) );
106  updateColorButtons();
109 
110  // fill type combobox
111  cboType->blockSignals( true );
112  cboType->addItem( tr( "Discrete" ) );
113  cboType->addItem( tr( "Continuous" ) );
114  if ( mRamp.isDiscrete() )
115  cboType->setCurrentIndex( 0 );
116  else
117  cboType->setCurrentIndex( 1 );
118  cboType->blockSignals( false );
119 
120  if ( mRamp.info().isEmpty() )
121  btnInformation->setEnabled( false );
122 
123  mStopEditor->setGradientRamp( mRamp );
124  connect( mStopEditor, &QgsGradientStopEditor::changed, this, &QgsGradientColorRampDialog::updateRampFromStopEditor );
125 
126  connect( mColorWidget, &QgsCompoundColorWidget::currentColorChanged, this, &QgsGradientColorRampDialog::colorWidgetChanged );
127  connect( mDeleteStopButton, &QAbstractButton::clicked, mStopEditor, &QgsGradientStopEditor::deleteSelectedStop );
128 
129  // hide the ugly canvas frame
130  mPlot->setFrameStyle( QFrame::NoFrame );
131  QFrame *plotCanvasFrame = dynamic_cast<QFrame *>( mPlot->canvas() );
132  if ( plotCanvasFrame )
133  plotCanvasFrame->setFrameStyle( QFrame::NoFrame );
134 
135  mPlot->setAxisScale( QwtPlot::yLeft, 0.0, 1.0 );
136  mPlot->enableAxis( QwtPlot::yLeft, false );
137 
138  // add a grid
139  QwtPlotGrid *grid = new QwtPlotGrid();
140  QwtScaleDiv gridDiv( 0.0, 1.0, QList<double>(), QList<double>(), QList<double>() << 0.2 << 0.4 << 0.6 << 0.8 );
141  grid->setXDiv( gridDiv );
142  grid->setYDiv( gridDiv );
143  grid->setPen( QPen( QColor( 0, 0, 0, 50 ) ) );
144  grid->attach( mPlot );
145 
146  mLightnessCurve = new QwtPlotCurve();
147  mLightnessCurve->setTitle( tr( "Lightness" ) );
148  mLightnessCurve->setPen( QPen( QColor( 70, 150, 255 ), 0.0 ) ),
149  mLightnessCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
150  mLightnessCurve->attach( mPlot );
151 
152  mHueCurve = new QwtPlotCurve();
153  mHueCurve->setTitle( tr( "Hue" ) );
154  mHueCurve->setPen( QPen( QColor( 255, 215, 70 ), 0.0 ) ),
155  mHueCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
156  mHueCurve->attach( mPlot );
157 
158  mSaturationCurve = new QwtPlotCurve();
159  mSaturationCurve->setTitle( tr( "Saturation" ) );
160  mSaturationCurve->setPen( QPen( QColor( 255, 70, 150 ), 0.0 ) ),
161  mSaturationCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
162  mSaturationCurve->attach( mPlot );
163 
164  mAlphaCurve = new QwtPlotCurve();
165  mAlphaCurve->setTitle( tr( "Opacity" ) );
166  mAlphaCurve->setPen( QPen( QColor( 50, 50, 50 ), 0.0 ) ),
167  mAlphaCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
168  mAlphaCurve->attach( mPlot );
169 
170  mPlotFilter = new QgsGradientPlotEventFilter( mPlot );
171  connect( mPlotFilter, &QgsGradientPlotEventFilter::mousePress, this, &QgsGradientColorRampDialog::plotMousePress );
172  connect( mPlotFilter, &QgsGradientPlotEventFilter::mouseRelease, this, &QgsGradientColorRampDialog::plotMouseRelease );
173  connect( mPlotFilter, &QgsGradientPlotEventFilter::mouseMove, this, &QgsGradientColorRampDialog::plotMouseMove );
174 
175  QgsSettings settings;
176  mPlotHueCheckbox->setChecked( settings.value( QStringLiteral( "GradientEditor/plotHue" ), false ).toBool() );
177  mPlotLightnessCheckbox->setChecked( settings.value( QStringLiteral( "GradientEditor/plotLightness" ), true ).toBool() );
178  mPlotSaturationCheckbox->setChecked( settings.value( QStringLiteral( "GradientEditor/plotSaturation" ), false ).toBool() );
179  mPlotAlphaCheckbox->setChecked( settings.value( QStringLiteral( "GradientEditor/plotAlpha" ), false ).toBool() );
180 
181  mHueCurve->setVisible( mPlotHueCheckbox->isChecked() );
182  mLightnessCurve->setVisible( mPlotLightnessCheckbox->isChecked() );
183  mSaturationCurve->setVisible( mPlotSaturationCheckbox->isChecked() );
184  mAlphaCurve->setVisible( mPlotAlphaCheckbox->isChecked() );
185 
186  connect( mStopEditor, &QgsGradientStopEditor::selectedStopChanged, this, &QgsGradientColorRampDialog::selectedStopChanged );
187  mStopEditor->selectStop( 0 );
188 
189  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsGradientColorRampDialog::showHelp );
190 }
191 
193 {
194  QgsSettings settings;
195  settings.setValue( QStringLiteral( "GradientEditor/plotHue" ), mPlotHueCheckbox->isChecked() );
196  settings.setValue( QStringLiteral( "GradientEditor/plotLightness" ), mPlotLightnessCheckbox->isChecked() );
197  settings.setValue( QStringLiteral( "GradientEditor/plotSaturation" ), mPlotSaturationCheckbox->isChecked() );
198  settings.setValue( QStringLiteral( "GradientEditor/plotAlpha" ), mPlotAlphaCheckbox->isChecked() );
199 
200 }
201 
203 {
204  mRamp = ramp;
205 
206  updateColorButtons();
207  updateStopEditor();
208  updatePlot();
209 
210  emit changed();
211 }
212 
213 QDialogButtonBox *QgsGradientColorRampDialog::buttonBox() const
214 {
215  return mButtonBox;
216 }
217 
218 void QgsGradientColorRampDialog::cboType_currentIndexChanged( int index )
219 {
220  if ( ( index == 0 && mRamp.isDiscrete() ) ||
221  ( index == 1 && !mRamp.isDiscrete() ) )
222  return;
223  mRamp.convertToDiscrete( index == 0 );
224  updateColorButtons();
225  updateStopEditor();
226  updatePlot();
227 
228  emit changed();
229 }
230 
231 void QgsGradientColorRampDialog::btnInformation_pressed()
232 {
233  if ( mRamp.info().isEmpty() )
234  return;
235 
236  QgsDialog *dlg = new QgsDialog( this );
237  QLabel *label = nullptr;
238 
239  // information table
240  QTableWidget *tableInfo = new QTableWidget( dlg );
241  tableInfo->verticalHeader()->hide();
242  tableInfo->horizontalHeader()->hide();
243  tableInfo->setRowCount( mRamp.info().count() );
244  tableInfo->setColumnCount( 2 );
245  int i = 0;
246  QgsStringMap rampInfo = mRamp.info();
247  for ( QgsStringMap::const_iterator it = rampInfo.constBegin();
248  it != rampInfo.constEnd(); ++it )
249  {
250  if ( it.key().startsWith( QLatin1String( "cpt-city" ) ) )
251  continue;
252  tableInfo->setItem( i, 0, new QTableWidgetItem( it.key() ) );
253  tableInfo->setItem( i, 1, new QTableWidgetItem( it.value() ) );
254  tableInfo->resizeRowToContents( i );
255  i++;
256  }
257  tableInfo->resizeColumnToContents( 0 );
258  tableInfo->horizontalHeader()->setStretchLastSection( true );
259  tableInfo->setRowCount( i );
260  tableInfo->setFixedHeight( tableInfo->rowHeight( 0 ) * i + 5 );
261  dlg->layout()->addWidget( tableInfo );
262  dlg->resize( 600, 250 );
263 
264  dlg->layout()->addSpacing( 5 );
265 
266  // gradient file
267  QString gradientFile = mRamp.info().value( QStringLiteral( "cpt-city-gradient" ) );
268  if ( ! gradientFile.isNull() )
269  {
270  QString fileName = gradientFile;
271  fileName.replace( QLatin1String( "<cpt-city>" ), QgsCptCityArchive::defaultBaseDir() );
272  if ( ! QFile::exists( fileName ) )
273  {
274  fileName = gradientFile;
275  fileName.replace( QLatin1String( "<cpt-city>" ), QLatin1String( "http://soliton.vm.bytemark.co.uk/pub/cpt-city" ) );
276  }
277  label = new QLabel( tr( "Gradient file : %1" ).arg( fileName ), dlg );
278  label->setTextInteractionFlags( Qt::TextBrowserInteraction );
279  dlg->layout()->addSpacing( 5 );
280  dlg->layout()->addWidget( label );
281  }
282 
283  // license file
284  QString licenseFile = mRamp.info().value( QStringLiteral( "cpt-city-license" ) );
285  if ( !licenseFile.isNull() )
286  {
287  QString fileName = licenseFile;
288  fileName.replace( QLatin1String( "<cpt-city>" ), QgsCptCityArchive::defaultBaseDir() );
289  if ( ! QFile::exists( fileName ) )
290  {
291  fileName = licenseFile;
292  fileName.replace( QLatin1String( "<cpt-city>" ), QLatin1String( "http://soliton.vm.bytemark.co.uk/pub/cpt-city" ) );
293  }
294  label = new QLabel( tr( "License file : %1" ).arg( fileName ), dlg );
295  label->setTextInteractionFlags( Qt::TextBrowserInteraction );
296  dlg->layout()->addSpacing( 5 );
297  dlg->layout()->addWidget( label );
298  if ( QFile::exists( fileName ) )
299  {
300  QTextEdit *textEdit = new QTextEdit( dlg );
301  textEdit->setReadOnly( true );
302  QFile file( fileName );
303  if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
304  {
305  textEdit->setText( file.readAll() );
306  file.close();
307  dlg->layout()->addSpacing( 5 );
308  dlg->layout()->addWidget( textEdit );
309  dlg->resize( 600, 500 );
310  }
311  }
312  }
313 
314  dlg->show(); //non modal
315 }
316 
317 void QgsGradientColorRampDialog::updateColorButtons()
318 {
319  btnColor1->blockSignals( true );
320  btnColor1->setColor( mRamp.color1() );
321  btnColor1->blockSignals( false );
322  btnColor2->blockSignals( true );
323  btnColor2->setColor( mRamp.color2() );
324  btnColor2->blockSignals( false );
325 }
326 
327 void QgsGradientColorRampDialog::updateStopEditor()
328 {
329  mStopEditor->blockSignals( true );
330  mStopEditor->setGradientRamp( mRamp );
331  mStopEditor->blockSignals( false );
332 }
333 
334 void QgsGradientColorRampDialog::selectedStopChanged( const QgsGradientStop &stop )
335 {
336  mBlockChanges++;
337  mColorWidget->blockSignals( true );
338  mColorWidget->setColor( stop.color );
339  mColorWidget->blockSignals( false );
340  mPositionSpinBox->blockSignals( true );
341  mPositionSpinBox->setValue( stop.offset * 100 );
342  mPositionSpinBox->blockSignals( false );
343 
344  mStopColorSpec->setCurrentIndex( mStopColorSpec->findData( static_cast< int >( mStopEditor->selectedStop().colorSpec() ) ) );
345  mStopDirection->setCurrentIndex( mStopDirection->findData( static_cast< int >( mStopEditor->selectedStop().direction() ) ) );
346  mBlockChanges--;
347 
348  if ( ( stop.offset == 0 && stop.color == mRamp.color1() ) || ( stop.offset == 1.0 && stop.color == mRamp.color2() ) )
349  {
350  //first/last stop can't be repositioned
351  mPositionSpinBox->setDisabled( true );
352  mDeleteStopButton->setDisabled( true );
353  }
354  else
355  {
356  mPositionSpinBox->setDisabled( false );
357  mDeleteStopButton->setDisabled( false );
358  }
359 
360  // first stop cannot have color spec or direction set
361  mStopColorSpec->setEnabled( !( stop.offset == 0 && stop.color == mRamp.color1() ) );
362  mStopDirection->setEnabled( !( stop.offset == 0 && stop.color == mRamp.color1() ) && mStopEditor->selectedStop().colorSpec() != QColor::Rgb );
363 
364  updatePlot();
365 }
366 
367 void QgsGradientColorRampDialog::colorWidgetChanged( const QColor &color )
368 {
369  mStopEditor->setSelectedStopColor( color );
370 }
371 
372 void QgsGradientColorRampDialog::mPositionSpinBox_valueChanged( double val )
373 {
374  mStopEditor->setSelectedStopOffset( val / 100.0 );
375 }
376 
377 void QgsGradientColorRampDialog::mPlotHueCheckbox_toggled( bool checked )
378 {
379  mHueCurve->setVisible( checked );
380  updatePlot();
381 }
382 
383 void QgsGradientColorRampDialog::mPlotLightnessCheckbox_toggled( bool checked )
384 {
385  mLightnessCurve->setVisible( checked );
386  updatePlot();
387 }
388 
389 void QgsGradientColorRampDialog::mPlotSaturationCheckbox_toggled( bool checked )
390 {
391  mSaturationCurve->setVisible( checked );
392  updatePlot();
393 }
394 
395 void QgsGradientColorRampDialog::mPlotAlphaCheckbox_toggled( bool checked )
396 {
397  mAlphaCurve->setVisible( checked );
398  updatePlot();
399 }
400 
401 void QgsGradientColorRampDialog::plotMousePress( QPointF point )
402 {
403  //find closest part
404 
405  double minDist = 1;
406  mCurrentPlotColorComponent = -1;
407  mCurrentPlotMarkerIndex = -1;
408  // first color
409 
410  for ( int i = 0; i < mRamp.count(); ++i )
411  {
412  QColor currentCol;
413  double currentOff = 0.0;
414  if ( i == 0 )
415  {
416  currentOff = 0.0;
417  currentCol = mRamp.color1();
418  }
419  else if ( i == mRamp.count() - 1 )
420  {
421  currentOff = 1.0;
422  currentCol = mRamp.color2();
423  }
424  else
425  {
426  currentOff = mRamp.stops().at( i - 1 ).offset;
427  currentCol = mRamp.stops().at( i - 1 ).color;
428  }
429 
430  double currentDist;
431  if ( mPlotHueCheckbox->isChecked() )
432  {
433  currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.hslHueF(), 2.0 );
434  if ( currentDist < minDist )
435  {
436  minDist = currentDist;
437  mCurrentPlotColorComponent = 0;
438  mCurrentPlotMarkerIndex = i;
439  }
440  }
441  if ( mPlotLightnessCheckbox->isChecked() )
442  {
443  currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.lightnessF(), 2.0 );
444  if ( currentDist < minDist )
445  {
446  minDist = currentDist;
447  mCurrentPlotColorComponent = 1;
448  mCurrentPlotMarkerIndex = i;
449  }
450  }
451  if ( mPlotSaturationCheckbox->isChecked() )
452  {
453  currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.hslSaturationF(), 2.0 );
454  if ( currentDist < minDist )
455  {
456  minDist = currentDist;
457  mCurrentPlotColorComponent = 2;
458  mCurrentPlotMarkerIndex = i;
459  }
460  }
461  if ( mPlotAlphaCheckbox->isChecked() )
462  {
463  currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.alphaF(), 2.0 );
464  if ( currentDist < minDist )
465  {
466  minDist = currentDist;
467  mCurrentPlotColorComponent = 3;
468  mCurrentPlotMarkerIndex = i;
469  }
470  }
471  }
472 
473  // watch out - selected stop index may differ if stops in editor are out of order!!!
474  if ( mCurrentPlotMarkerIndex >= 0 )
475  mStopEditor->selectStop( mCurrentPlotMarkerIndex );
476 }
477 
478 void QgsGradientColorRampDialog::plotMouseRelease( QPointF )
479 {
480  mCurrentPlotColorComponent = -1;
481 }
482 
483 void QgsGradientColorRampDialog::plotMouseMove( QPointF point )
484 {
485  QColor newColor = mStopEditor->selectedStop().color;
486 
487  if ( mCurrentPlotColorComponent == 0 )
488  newColor = QColor::fromHslF( std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ), newColor.hslSaturationF(), newColor.lightnessF(), newColor.alphaF() );
489  else if ( mCurrentPlotColorComponent == 1 )
490  newColor = QColor::fromHslF( newColor.hslHueF(), newColor.hslSaturationF(), std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ), newColor.alphaF() );
491  else if ( mCurrentPlotColorComponent == 2 )
492  newColor = QColor::fromHslF( newColor.hslHueF(), std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ), newColor.lightnessF(), newColor.alphaF() );
493  else if ( mCurrentPlotColorComponent == 3 )
494  newColor = QColor::fromHslF( newColor.hslHueF(), newColor.hslSaturationF(), newColor.lightnessF(), std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ) );
495 
496  mStopEditor->setSelectedStopDetails( newColor, std::clamp( point.x(), qreal( 0.0 ), qreal( 1.0 ) ) );
497 }
498 
499 bool byX( QPointF p1, QPointF p2 )
500 {
501  return p1.x() < p2.x();
502 }
503 
504 void QgsGradientColorRampDialog::addPlotMarker( double x, double y, const QColor &color, bool isSelected )
505 {
506  QColor borderColor = color.darker( 200 );
507  borderColor.setAlpha( 255 );
508 
509  QColor brushColor = color;
510  brushColor.setAlpha( 255 );
511 
512  QwtPlotMarker *marker = new QwtPlotMarker();
513  marker->setSymbol( new QwtSymbol( QwtSymbol::Ellipse, QBrush( brushColor ), QPen( borderColor, isSelected ? 2 : 1 ), QSize( 8, 8 ) ) );
514  marker->setValue( x, y );
515  marker->attach( mPlot );
516  marker->setRenderHint( QwtPlotItem::RenderAntialiased, true );
517  mMarkers << marker;
518 }
519 
520 void QgsGradientColorRampDialog::addMarkersForColor( double x, const QColor &color, bool isSelected )
521 {
522  if ( mPlotHueCheckbox->isChecked() )
523  addPlotMarker( x, color.hslHueF(), color, isSelected && mCurrentPlotColorComponent == 0 );
524  if ( mPlotLightnessCheckbox->isChecked() )
525  addPlotMarker( x, color.lightnessF(), color, isSelected && mCurrentPlotColorComponent == 1 );
526  if ( mPlotSaturationCheckbox->isChecked() )
527  addPlotMarker( x, color.hslSaturationF(), color, isSelected && mCurrentPlotColorComponent == 2 );
528  if ( mPlotAlphaCheckbox->isChecked() )
529  addPlotMarker( x, color.alphaF(), color, isSelected && mCurrentPlotColorComponent == 3 );
530 }
531 
532 void QgsGradientColorRampDialog::updatePlot()
533 {
534  // remove existing markers
535  const auto constMMarkers = mMarkers;
536  for ( QwtPlotMarker *marker : constMMarkers )
537  {
538  marker->detach();
539  delete marker;
540  }
541  mMarkers.clear();
542 
543  QPolygonF lightnessPoints;
544  QPolygonF huePoints;
545  QPolygonF saturationPoints;
546  QPolygonF alphaPoints;
547  lightnessPoints << QPointF( 0.0, mRamp.color1().lightnessF() );
548  huePoints << QPointF( 0.0, mRamp.color1().hslHueF() );
549  saturationPoints << QPointF( 0.0, mRamp.color1().hslSaturationF() );
550  alphaPoints << QPointF( 0.0, mRamp.color1().alphaF() );
551  addMarkersForColor( 0, mRamp.color1(), mCurrentPlotMarkerIndex == 0 );
552 
553  int i = 1;
554  const auto constStops = mRamp.stops();
555  for ( const QgsGradientStop &stop : constStops )
556  {
557  lightnessPoints << QPointF( stop.offset, stop.color.lightnessF() );
558  huePoints << QPointF( stop.offset, stop.color.hslHueF() );
559  saturationPoints << QPointF( stop.offset, stop.color.hslSaturationF() );
560  alphaPoints << QPointF( stop.offset, stop.color.alphaF() );
561 
562  addMarkersForColor( stop.offset, stop.color, mCurrentPlotMarkerIndex == i );
563  i++;
564  }
565 
566  //add extra intermediate points
567  for ( double p = 0.001; p < 1.0; p += 0.001 )
568  {
569  QColor c = mRamp.color( p );
570  lightnessPoints << QPointF( p, c.lightnessF() );
571  huePoints << QPointF( p, c.hslHueF() );
572  saturationPoints << QPointF( p, c.hslSaturationF() );
573  alphaPoints << QPointF( p, c.alphaF() );
574  }
575 
576  lightnessPoints << QPointF( 1.0, mRamp.color2().lightnessF() );
577  huePoints << QPointF( 1.0, mRamp.color2().hslHueF() );
578  saturationPoints << QPointF( 1.0, mRamp.color2().hslSaturationF() );
579  alphaPoints << QPointF( 1.0, mRamp.color2().alphaF() );
580  addMarkersForColor( 1.0, mRamp.color2(), mCurrentPlotMarkerIndex == i );
581 
582  std::sort( lightnessPoints.begin(), lightnessPoints.end(), byX );
583  std::sort( huePoints.begin(), huePoints.end(), byX );
584  std::sort( saturationPoints.begin(), saturationPoints.end(), byX );
585  std::sort( alphaPoints.begin(), alphaPoints.end(), byX );
586 
587  mLightnessCurve->setSamples( lightnessPoints );
588  mHueCurve->setSamples( huePoints );
589  mSaturationCurve->setSamples( saturationPoints );
590  mAlphaCurve->setSamples( alphaPoints );
591  mPlot->replot();
592 }
593 
594 void QgsGradientColorRampDialog::updateRampFromStopEditor()
595 {
596  mRamp = mStopEditor->gradientRamp();
597 
598  mBlockChanges++;
599  mPositionSpinBox->blockSignals( true );
600  mPositionSpinBox->setValue( mStopEditor->selectedStop().offset * 100 );
601  mPositionSpinBox->blockSignals( false );
602  mColorWidget->blockSignals( true );
603  mColorWidget->setColor( mStopEditor->selectedStop().color );
604  mColorWidget->blockSignals( false );
605 
606  mStopColorSpec->setCurrentIndex( mStopColorSpec->findData( static_cast< int >( mStopEditor->selectedStop().colorSpec() ) ) );
607  mStopDirection->setCurrentIndex( mStopDirection->findData( static_cast< int >( mStopEditor->selectedStop().direction() ) ) );
608  mBlockChanges--;
609 
610  // first stop cannot have color spec or direction set
611  mStopColorSpec->setEnabled( !( mStopEditor->selectedStop().offset == 0 && mStopEditor->selectedStop().color == mRamp.color1() ) );
612  mStopDirection->setEnabled( !( mStopEditor->selectedStop().offset == 0 && mStopEditor->selectedStop().color == mRamp.color1() ) && mStopEditor->selectedStop().colorSpec() != QColor::Rgb );
613 
614  updateColorButtons();
615  updatePlot();
616 
617  emit changed();
618 }
619 
620 void QgsGradientColorRampDialog::setColor1( const QColor &color )
621 {
622  mStopEditor->setColor1( color );
623  updateColorButtons();
624 }
625 
626 void QgsGradientColorRampDialog::setColor2( const QColor &color )
627 {
628  mStopEditor->setColor2( color );
629  updateColorButtons();
630 }
631 
632 void QgsGradientColorRampDialog::showHelp()
633 {
634  QgsHelp::openHelp( QStringLiteral( "style_library/style_manager.html#setting-a-color-ramp" ) );
635 }
636 
637 
639 
640 QgsGradientPlotEventFilter::QgsGradientPlotEventFilter( QwtPlot *plot )
641  : QObject( plot )
642  , mPlot( plot )
643 {
644  mPlot->canvas()->installEventFilter( this );
645 }
646 
647 bool QgsGradientPlotEventFilter::eventFilter( QObject *object, QEvent *event )
648 {
649  if ( !mPlot->isEnabled() )
650  return QObject::eventFilter( object, event );
651 
652  switch ( event->type() )
653  {
654  case QEvent::MouseButtonPress:
655  {
656  const QMouseEvent *mouseEvent = static_cast<QMouseEvent * >( event );
657  if ( mouseEvent->button() == Qt::LeftButton )
658  {
659  emit mousePress( mapPoint( mouseEvent->pos() ) );
660  }
661  break;
662  }
663  case QEvent::MouseMove:
664  {
665  const QMouseEvent *mouseEvent = static_cast<QMouseEvent * >( event );
666  if ( mouseEvent->buttons() & Qt::LeftButton )
667  {
668  // only emit when button pressed
669  emit mouseMove( mapPoint( mouseEvent->pos() ) );
670  }
671  break;
672  }
673  case QEvent::MouseButtonRelease:
674  {
675  const QMouseEvent *mouseEvent = static_cast<QMouseEvent * >( event );
676  if ( mouseEvent->button() == Qt::LeftButton )
677  {
678  emit mouseRelease( mapPoint( mouseEvent->pos() ) );
679  }
680  break;
681  }
682  default:
683  break;
684  }
685 
686  return QObject::eventFilter( object, event );
687 }
688 
689 QPointF QgsGradientPlotEventFilter::mapPoint( QPointF point ) const
690 {
691  if ( !mPlot )
692  return QPointF();
693 
694  return QPointF( mPlot->canvasMap( QwtPlot::xBottom ).invTransform( point.x() ),
695  mPlot->canvasMap( QwtPlot::yLeft ).invTransform( point.y() ) );
696 }
697 
AngularDirection
Angular directions.
Definition: qgis.h:1245
@ CounterClockwise
Counter-clockwise direction.
@ Clockwise
Clockwise direction.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
void currentColorChanged(const QColor &color)
Emitted when the dialog's color changes.
static QString defaultBaseDir()
A generic dialog with layout and button box.
Definition: qgsdialog.h:34
QVBoxLayout * layout()
Returns the central layout. Widgets added to it must have this dialog as parent.
Definition: qgsdialog.h:46
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog's button box.
void setColor2(const QColor &color)
Sets the end color for the gradient ramp.
void setRamp(const QgsGradientColorRamp &ramp)
Sets the color ramp to show in the dialog.
QgsGradientColorRampDialog(const QgsGradientColorRamp &ramp, QWidget *parent=nullptr)
Constructor for QgsGradientColorRampDialog.
void setColor1(const QColor &color)
Sets the start color for the gradient ramp.
void changed()
Emitted when the dialog settings change.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
bool isDiscrete() const
Returns true if the gradient is using discrete interpolation, rather than smoothly interpolating betw...
int count() const override
Returns number of defined colors, or -1 if undefined.
QgsStringMap info() const
Returns any additional info attached to the gradient ramp (e.g., authorship notes)
void convertToDiscrete(bool discrete)
Converts a gradient with existing color stops to or from discrete interpolation.
QColor::Spec colorSpec() const
Returns the color specification in which the color component interpolation will occur.
QColor color(double value) const override
Returns the color corresponding to a specified value.
QColor color1() const
Returns the gradient start color.
Qgis::AngularDirection direction() const
Returns the direction to traverse the color wheel using when interpolating hue-based color specificat...
QgsGradientStopsList stops() const
Returns the list of intermediate gradient stops for the ramp.
QColor color2() const
Returns the gradient end color.
void changed()
Emitted when the gradient ramp is changed by a user.
void deleteSelectedStop()
Deletes the current selected stop.
void selectedStopChanged(const QgsGradientStop &stop)
Emitted when the current selected stop changes.
Represents a color stop within a QgsGradientColorRamp color ramp.
double offset
Relative positional offset, between 0 and 1.
QColor color
Gradient color at stop.
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:67
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:168
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
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
QMap< QString, QString > QgsStringMap
Definition: qgis.h:1961
bool byX(QPointF p1, QPointF p2)