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