QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 
QgsGradientColorRamp::color1
QColor color1() const
Returns the gradient start color.
Definition: qgscolorrampimpl.h:177
QgsGradientStop::color
QColor color
Gradient color at stop.
Definition: qgscolorrampimpl.h:52
QgsGradientColorRamp
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorrampimpl.h:136
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:161
qgsgui.h
QgsCptCityArchive::defaultBaseDir
static QString defaultBaseDir()
Definition: qgscptcityarchive.cpp:131
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsDialog::layout
QVBoxLayout * layout()
Returns the central layout. Widgets added to it must have this dialog as parent.
Definition: qgsdialog.h:59
QgsGradientColorRampDialog::setColor1
void setColor1(const QColor &color)
Sets the start color for the gradient ramp.
Definition: qgsgradientcolorrampdialog.cpp:620
qgscptcityarchive.h
byX
bool byX(QPointF p1, QPointF p2)
Definition: qgsgradientcolorrampdialog.cpp:499
QgsGradientColorRamp::convertToDiscrete
void convertToDiscrete(bool discrete)
Converts a gradient with existing color stops to or from discrete interpolation.
Definition: qgscolorrampimpl.cpp:485
QgsColorButton::colorChanged
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
QgsGradientColorRamp::stops
QgsGradientStopsList stops() const
Returns the list of intermediate gradient stops for the ramp.
Definition: qgscolorrampimpl.h:240
QgsDialog
A generic dialog with layout and button box.
Definition: qgsdialog.h:33
QgsGradientColorRampDialog::setColor2
void setColor2(const QColor &color)
Sets the end color for the gradient ramp.
Definition: qgsgradientcolorrampdialog.cpp:626
QgsGui::enableAutoGeometryRestore
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:180
QgsCompoundColorWidget::currentColorChanged
void currentColorChanged(const QColor &color)
Emitted when the dialog's color changes.
QgsGradientColorRamp::count
int count() const override
Returns number of defined colors, or -1 if undefined.
Definition: qgscolorrampimpl.h:156
QgsGradientColorRamp::color2
QColor color2() const
Returns the gradient end color.
Definition: qgscolorrampimpl.h:184
qgscolorramp.h
QgsGradientColorRamp::direction
Qgis::AngularDirection direction() const
Returns the direction to traverse the color wheel using when interpolating hue-based color specificat...
Definition: qgscolorrampimpl.h:298
Qgis::AngularDirection::CounterClockwise
@ CounterClockwise
Counter-clockwise direction.
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:279
QgsGradientColorRampDialog::QgsGradientColorRampDialog
QgsGradientColorRampDialog(const QgsGradientColorRamp &ramp, QWidget *parent=nullptr)
Constructor for QgsGradientColorRampDialog.
Definition: qgsgradientcolorrampdialog.cpp:47
QgsGradientColorRampDialog::changed
void changed()
Emitted when the dialog settings change.
Qgis::AngularDirection::Clockwise
@ Clockwise
Clockwise direction.
qgscolordialog.h
QgsGradientStopEditor::changed
void changed()
Emitted when the gradient ramp is changed by a user.
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:2781
QgsGradientStopEditor::selectedStopChanged
void selectedStopChanged(const QgsGradientStop &stop)
Emitted when the current selected stop changes.
QgsGradientColorRampDialog::ramp
QgsGradientColorRamp ramp
Definition: qgsgradientcolorrampdialog.h:41
QgsGradientColorRampDialog::setRamp
void setRamp(const QgsGradientColorRamp &ramp)
Sets the color ramp to show in the dialog.
Definition: qgsgradientcolorrampdialog.cpp:202
QgsGradientStopEditor::deleteSelectedStop
void deleteSelectedStop()
Deletes the current selected stop.
Definition: qgsgradientstopeditor.cpp:267
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
QgsHelp::openHelp
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
qgssettings.h
QgsGradientColorRamp::color
QColor color(double value) const override
Returns the color corresponding to a specified value.
Definition: qgscolorrampimpl.cpp:316
qgsgradientcolorrampdialog.h
qgsdialog.h
QgsGradientColorRamp::colorSpec
QColor::Spec colorSpec() const
Returns the color specification in which the color component interpolation will occur.
Definition: qgscolorrampimpl.h:273
QgsGradientColorRampDialog::buttonBox
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog's button box.
Definition: qgsgradientcolorrampdialog.cpp:213
QgsGradientStop
Represents a color stop within a QgsGradientColorRamp color ramp.
Definition: qgscolorrampimpl.h:38
QgsGradientColorRamp::isDiscrete
bool isDiscrete() const
Returns true if the gradient is using discrete interpolation, rather than smoothly interpolating betw...
Definition: qgscolorrampimpl.h:207
QgsGradientStop::offset
double offset
Relative positional offset, between 0 and 1.
Definition: qgscolorrampimpl.h:50
QgsGradientColorRamp::info
QgsStringMap info() const
Returns any additional info attached to the gradient ramp (e.g., authorship notes)
Definition: qgscolorrampimpl.h:246
QgsGradientColorRampDialog::~QgsGradientColorRampDialog
~QgsGradientColorRampDialog() override
Definition: qgsgradientcolorrampdialog.cpp:192
Qgis::AngularDirection
AngularDirection
Angular directions.
Definition: qgis.h:1635