QGIS API Documentation 3.99.0-Master (d270888f95f)
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 ) ),
158 mLightnessCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
159 mLightnessCurve->attach( mPlot );
160
161 mHueCurve = new QwtPlotCurve();
162 mHueCurve->setTitle( tr( "Hue" ) );
163 mHueCurve->setPen( QPen( QColor( 255, 215, 70 ), 0.0 ) ),
164 mHueCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
165 mHueCurve->attach( mPlot );
166
167 mSaturationCurve = new QwtPlotCurve();
168 mSaturationCurve->setTitle( tr( "Saturation" ) );
169 mSaturationCurve->setPen( QPen( QColor( 255, 70, 150 ), 0.0 ) ),
170 mSaturationCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
171 mSaturationCurve->attach( mPlot );
172
173 mAlphaCurve = new QwtPlotCurve();
174 mAlphaCurve->setTitle( tr( "Opacity" ) );
175 mAlphaCurve->setPen( QPen( QColor( 50, 50, 50 ), 0.0 ) ),
176 mAlphaCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
177 mAlphaCurve->attach( mPlot );
178
179 mPlotFilter = new QgsGradientPlotEventFilter( mPlot );
180 connect( mPlotFilter, &QgsGradientPlotEventFilter::mousePress, this, &QgsGradientColorRampDialog::plotMousePress );
181 connect( mPlotFilter, &QgsGradientPlotEventFilter::mouseRelease, this, &QgsGradientColorRampDialog::plotMouseRelease );
182 connect( mPlotFilter, &QgsGradientPlotEventFilter::mouseMove, this, &QgsGradientColorRampDialog::plotMouseMove );
183
184 QgsSettings settings;
185 mPlotHueCheckbox->setChecked( settings.value( u"GradientEditor/plotHue"_s, false ).toBool() );
186 mPlotLightnessCheckbox->setChecked( settings.value( u"GradientEditor/plotLightness"_s, true ).toBool() );
187 mPlotSaturationCheckbox->setChecked( settings.value( u"GradientEditor/plotSaturation"_s, false ).toBool() );
188 mPlotAlphaCheckbox->setChecked( settings.value( u"GradientEditor/plotAlpha"_s, false ).toBool() );
189
190 mHueCurve->setVisible( mPlotHueCheckbox->isChecked() );
191 mLightnessCurve->setVisible( mPlotLightnessCheckbox->isChecked() );
192 mSaturationCurve->setVisible( mPlotSaturationCheckbox->isChecked() );
193 mAlphaCurve->setVisible( mPlotAlphaCheckbox->isChecked() );
194
195 connect( mStopEditor, &QgsGradientStopEditor::selectedStopChanged, this, &QgsGradientColorRampDialog::selectedStopChanged );
196 mStopEditor->selectStop( 0 );
197
198 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsGradientColorRampDialog::showHelp );
199}
200
202{
203 QgsSettings settings;
204 settings.setValue( u"GradientEditor/plotHue"_s, mPlotHueCheckbox->isChecked() );
205 settings.setValue( u"GradientEditor/plotLightness"_s, mPlotLightnessCheckbox->isChecked() );
206 settings.setValue( u"GradientEditor/plotSaturation"_s, mPlotSaturationCheckbox->isChecked() );
207 settings.setValue( u"GradientEditor/plotAlpha"_s, mPlotAlphaCheckbox->isChecked() );
208}
209
211{
212 mRamp = ramp;
213
214 updateColorButtons();
215 updateStopEditor();
216 updatePlot();
217
218 emit changed();
219}
220
222{
223 return mButtonBox;
224}
225
226void QgsGradientColorRampDialog::cboType_currentIndexChanged( int index )
227{
228 if ( ( index == 0 && mRamp.isDiscrete() ) || ( index == 1 && !mRamp.isDiscrete() ) )
229 return;
230 mRamp.convertToDiscrete( index == 0 );
231 updateColorButtons();
232 updateStopEditor();
233 updatePlot();
234
235 emit changed();
236}
237
238void QgsGradientColorRampDialog::btnInformation_pressed()
239{
240 if ( mRamp.info().isEmpty() )
241 return;
242
243 QgsDialog *dlg = new QgsDialog( this );
244 QLabel *label = nullptr;
245
246 // information table
247 QTableWidget *tableInfo = new QTableWidget( dlg );
248 tableInfo->verticalHeader()->hide();
249 tableInfo->horizontalHeader()->hide();
250 tableInfo->setRowCount( mRamp.info().count() );
251 tableInfo->setColumnCount( 2 );
252 int i = 0;
253 QgsStringMap rampInfo = mRamp.info();
254 for ( QgsStringMap::const_iterator it = rampInfo.constBegin();
255 it != rampInfo.constEnd(); ++it )
256 {
257 if ( it.key().startsWith( "cpt-city"_L1 ) )
258 continue;
259 tableInfo->setItem( i, 0, new QTableWidgetItem( it.key() ) );
260 tableInfo->setItem( i, 1, new QTableWidgetItem( it.value() ) );
261 tableInfo->resizeRowToContents( i );
262 i++;
263 }
264 tableInfo->resizeColumnToContents( 0 );
265 tableInfo->horizontalHeader()->setStretchLastSection( true );
266 tableInfo->setRowCount( i );
267 tableInfo->setFixedHeight( tableInfo->rowHeight( 0 ) * i + 5 );
268 dlg->layout()->addWidget( tableInfo );
269 dlg->resize( 600, 250 );
270
271 dlg->layout()->addSpacing( 5 );
272
273 // gradient file
274 QString gradientFile = mRamp.info().value( u"cpt-city-gradient"_s );
275 if ( !gradientFile.isNull() )
276 {
277 QString fileName = gradientFile;
278 fileName.replace( "<cpt-city>"_L1, QgsCptCityArchive::defaultBaseDir() );
279 if ( !QFile::exists( fileName ) )
280 {
281 fileName = gradientFile;
282 fileName.replace( "<cpt-city>"_L1, "http://soliton.vm.bytemark.co.uk/pub/cpt-city"_L1 );
283 }
284 label = new QLabel( tr( "Gradient file : %1" ).arg( fileName ), dlg );
285 label->setTextInteractionFlags( Qt::TextBrowserInteraction );
286 dlg->layout()->addSpacing( 5 );
287 dlg->layout()->addWidget( label );
288 }
289
290 // license file
291 QString licenseFile = mRamp.info().value( u"cpt-city-license"_s );
292 if ( !licenseFile.isNull() )
293 {
294 QString fileName = licenseFile;
295 fileName.replace( "<cpt-city>"_L1, QgsCptCityArchive::defaultBaseDir() );
296 if ( !QFile::exists( fileName ) )
297 {
298 fileName = licenseFile;
299 fileName.replace( "<cpt-city>"_L1, "http://soliton.vm.bytemark.co.uk/pub/cpt-city"_L1 );
300 }
301 label = new QLabel( tr( "License file : %1" ).arg( fileName ), dlg );
302 label->setTextInteractionFlags( Qt::TextBrowserInteraction );
303 dlg->layout()->addSpacing( 5 );
304 dlg->layout()->addWidget( label );
305 if ( QFile::exists( fileName ) )
306 {
307 QTextEdit *textEdit = new QTextEdit( dlg );
308 textEdit->setReadOnly( true );
309 QFile file( fileName );
310 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
311 {
312 textEdit->setText( file.readAll() );
313 file.close();
314 dlg->layout()->addSpacing( 5 );
315 dlg->layout()->addWidget( textEdit );
316 dlg->resize( 600, 500 );
317 }
318 }
319 }
320
321 dlg->show(); //non modal
322}
323
324void QgsGradientColorRampDialog::updateColorButtons()
325{
326 btnColor1->blockSignals( true );
327 btnColor1->setColor( mRamp.color1() );
328 btnColor1->blockSignals( false );
329 btnColor2->blockSignals( true );
330 btnColor2->setColor( mRamp.color2() );
331 btnColor2->blockSignals( false );
332}
333
334void QgsGradientColorRampDialog::updateStopEditor()
335{
336 mStopEditor->blockSignals( true );
337 mStopEditor->setGradientRamp( mRamp );
338 mStopEditor->blockSignals( false );
339}
340
341void QgsGradientColorRampDialog::selectedStopChanged( const QgsGradientStop &stop )
342{
343 mBlockChanges++;
344 mColorWidget->blockSignals( true );
345 mColorWidget->setColor( stop.color );
346 mColorWidget->blockSignals( false );
347 mPositionSpinBox->blockSignals( true );
348 mPositionSpinBox->setValue( stop.offset * 100 );
349 mPositionSpinBox->blockSignals( false );
350
351 mStopColorSpec->setCurrentIndex( mStopColorSpec->findData( static_cast<int>( mStopEditor->selectedStop().colorSpec() ) ) );
352 mStopDirection->setCurrentIndex( mStopDirection->findData( static_cast<int>( mStopEditor->selectedStop().direction() ) ) );
353 mBlockChanges--;
354
355 if ( ( stop.offset == 0 && stop.color == mRamp.color1() ) || ( stop.offset == 1.0 && stop.color == mRamp.color2() ) )
356 {
357 //first/last stop can't be repositioned
358 mPositionSpinBox->setDisabled( true );
359 mDeleteStopButton->setDisabled( true );
360 }
361 else
362 {
363 mPositionSpinBox->setDisabled( false );
364 mDeleteStopButton->setDisabled( false );
365 }
366
367 // first stop cannot have color spec or direction set
368 mStopColorSpec->setEnabled( !( stop.offset == 0 && stop.color == mRamp.color1() ) );
369 mStopDirection->setEnabled( !( stop.offset == 0 && stop.color == mRamp.color1() ) && hasDirection( mStopEditor->selectedStop().colorSpec() ) );
370
371 updatePlot();
372}
373
374void QgsGradientColorRampDialog::colorWidgetChanged( const QColor &color )
375{
376 mStopEditor->setSelectedStopColor( color );
377}
378
379void QgsGradientColorRampDialog::mPositionSpinBox_valueChanged( double val )
380{
381 mStopEditor->setSelectedStopOffset( val / 100.0 );
382}
383
384void QgsGradientColorRampDialog::mPlotHueCheckbox_toggled( bool checked )
385{
386 mHueCurve->setVisible( checked );
387 updatePlot();
388}
389
390void QgsGradientColorRampDialog::mPlotLightnessCheckbox_toggled( bool checked )
391{
392 mLightnessCurve->setVisible( checked );
393 updatePlot();
394}
395
396void QgsGradientColorRampDialog::mPlotSaturationCheckbox_toggled( bool checked )
397{
398 mSaturationCurve->setVisible( checked );
399 updatePlot();
400}
401
402void QgsGradientColorRampDialog::mPlotAlphaCheckbox_toggled( bool checked )
403{
404 mAlphaCurve->setVisible( checked );
405 updatePlot();
406}
407
408void QgsGradientColorRampDialog::plotMousePress( QPointF point )
409{
410 //find closest part
411
412 double minDist = 1;
413 mCurrentPlotColorComponent = -1;
414 mCurrentPlotMarkerIndex = -1;
415 // first color
416
417 for ( int i = 0; i < mRamp.count(); ++i )
418 {
419 QColor currentCol;
420 double currentOff = 0.0;
421 if ( i == 0 )
422 {
423 currentOff = 0.0;
424 currentCol = mRamp.color1();
425 }
426 else if ( i == mRamp.count() - 1 )
427 {
428 currentOff = 1.0;
429 currentCol = mRamp.color2();
430 }
431 else
432 {
433 currentOff = mRamp.stops().at( i - 1 ).offset;
434 currentCol = mRamp.stops().at( i - 1 ).color;
435 }
436
437 double currentDist;
438 if ( mPlotHueCheckbox->isChecked() )
439 {
440 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.hslHueF(), 2.0 );
441 if ( currentDist < minDist )
442 {
443 minDist = currentDist;
444 mCurrentPlotColorComponent = 0;
445 mCurrentPlotMarkerIndex = i;
446 }
447 }
448 if ( mPlotLightnessCheckbox->isChecked() )
449 {
450 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.lightnessF(), 2.0 );
451 if ( currentDist < minDist )
452 {
453 minDist = currentDist;
454 mCurrentPlotColorComponent = 1;
455 mCurrentPlotMarkerIndex = i;
456 }
457 }
458 if ( mPlotSaturationCheckbox->isChecked() )
459 {
460 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.hslSaturationF(), 2.0 );
461 if ( currentDist < minDist )
462 {
463 minDist = currentDist;
464 mCurrentPlotColorComponent = 2;
465 mCurrentPlotMarkerIndex = i;
466 }
467 }
468 if ( mPlotAlphaCheckbox->isChecked() )
469 {
470 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.alphaF(), 2.0 );
471 if ( currentDist < minDist )
472 {
473 minDist = currentDist;
474 mCurrentPlotColorComponent = 3;
475 mCurrentPlotMarkerIndex = i;
476 }
477 }
478 }
479
480 // watch out - selected stop index may differ if stops in editor are out of order!!!
481 if ( mCurrentPlotMarkerIndex >= 0 )
482 mStopEditor->selectStop( mCurrentPlotMarkerIndex );
483}
484
485void QgsGradientColorRampDialog::plotMouseRelease( QPointF )
486{
487 mCurrentPlotColorComponent = -1;
488}
489
490void QgsGradientColorRampDialog::plotMouseMove( QPointF point )
491{
492 QColor newColor = mStopEditor->selectedStop().color;
493
494 if ( mCurrentPlotColorComponent == 0 )
495 newColor = QColor::fromHslF( std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ), newColor.hslSaturationF(), newColor.lightnessF(), newColor.alphaF() );
496 else if ( mCurrentPlotColorComponent == 1 )
497 newColor = QColor::fromHslF( newColor.hslHueF(), newColor.hslSaturationF(), std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ), newColor.alphaF() );
498 else if ( mCurrentPlotColorComponent == 2 )
499 newColor = QColor::fromHslF( newColor.hslHueF(), std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ), newColor.lightnessF(), newColor.alphaF() );
500 else if ( mCurrentPlotColorComponent == 3 )
501 newColor = QColor::fromHslF( newColor.hslHueF(), newColor.hslSaturationF(), newColor.lightnessF(), std::clamp( point.y(), qreal( 0.0 ), qreal( 1.0 ) ) );
502
503 mStopEditor->setSelectedStopDetails( newColor, std::clamp( point.x(), qreal( 0.0 ), qreal( 1.0 ) ) );
504}
505
506bool byX( QPointF p1, QPointF p2 )
507{
508 return p1.x() < p2.x();
509}
510
511void QgsGradientColorRampDialog::addPlotMarker( double x, double y, const QColor &color, bool isSelected )
512{
513 QColor borderColor = color.darker( 200 );
514 borderColor.setAlpha( 255 );
515
516 QColor brushColor = color;
517 brushColor.setAlpha( 255 );
518
519 QwtPlotMarker *marker = new QwtPlotMarker();
520 marker->setSymbol( new QwtSymbol( QwtSymbol::Ellipse, QBrush( brushColor ), QPen( borderColor, isSelected ? 2 : 1 ), QSize( 8, 8 ) ) );
521 marker->setValue( x, y );
522 marker->attach( mPlot );
523 marker->setRenderHint( QwtPlotItem::RenderAntialiased, true );
524 mMarkers << marker;
525}
526
527void QgsGradientColorRampDialog::addMarkersForColor( double x, const QColor &color, bool isSelected )
528{
529 if ( mPlotHueCheckbox->isChecked() )
530 addPlotMarker( x, color.hslHueF(), color, isSelected && mCurrentPlotColorComponent == 0 );
531 if ( mPlotLightnessCheckbox->isChecked() )
532 addPlotMarker( x, color.lightnessF(), color, isSelected && mCurrentPlotColorComponent == 1 );
533 if ( mPlotSaturationCheckbox->isChecked() )
534 addPlotMarker( x, color.hslSaturationF(), color, isSelected && mCurrentPlotColorComponent == 2 );
535 if ( mPlotAlphaCheckbox->isChecked() )
536 addPlotMarker( x, color.alphaF(), color, isSelected && mCurrentPlotColorComponent == 3 );
537}
538
539bool QgsGradientColorRampDialog::hasDirection( QColor::Spec colorSpec )
540{
541 switch ( colorSpec )
542 {
543 case QColor::Spec::Rgb:
544 case QColor::Spec::ExtendedRgb:
545 case QColor::Spec::Cmyk:
546 case QColor::Spec::Invalid:
547 return false;
548
549 case QColor::Spec::Hsv:
550 case QColor::Spec::Hsl:
551 return true;
552 }
553
555}
556
557void QgsGradientColorRampDialog::updatePlot()
558{
559 // remove existing markers
560 const auto constMMarkers = mMarkers;
561 for ( QwtPlotMarker *marker : constMMarkers )
562 {
563 marker->detach();
564 delete marker;
565 }
566 mMarkers.clear();
567
568 QPolygonF lightnessPoints;
569 QPolygonF huePoints;
570 QPolygonF saturationPoints;
571 QPolygonF alphaPoints;
572 lightnessPoints << QPointF( 0.0, mRamp.color1().lightnessF() );
573 huePoints << QPointF( 0.0, mRamp.color1().hslHueF() );
574 saturationPoints << QPointF( 0.0, mRamp.color1().hslSaturationF() );
575 alphaPoints << QPointF( 0.0, mRamp.color1().alphaF() );
576 addMarkersForColor( 0, mRamp.color1(), mCurrentPlotMarkerIndex == 0 );
577
578 int i = 1;
579 const auto constStops = mRamp.stops();
580 for ( const QgsGradientStop &stop : constStops )
581 {
582 lightnessPoints << QPointF( stop.offset, stop.color.lightnessF() );
583 huePoints << QPointF( stop.offset, stop.color.hslHueF() );
584 saturationPoints << QPointF( stop.offset, stop.color.hslSaturationF() );
585 alphaPoints << QPointF( stop.offset, stop.color.alphaF() );
586
587 addMarkersForColor( stop.offset, stop.color, mCurrentPlotMarkerIndex == i );
588 i++;
589 }
590
591 //add extra intermediate points
592 for ( double p = 0.001; p < 1.0; p += 0.001 )
593 {
594 QColor c = mRamp.color( p );
595 lightnessPoints << QPointF( p, c.lightnessF() );
596 huePoints << QPointF( p, c.hslHueF() );
597 saturationPoints << QPointF( p, c.hslSaturationF() );
598 alphaPoints << QPointF( p, c.alphaF() );
599 }
600
601 lightnessPoints << QPointF( 1.0, mRamp.color2().lightnessF() );
602 huePoints << QPointF( 1.0, mRamp.color2().hslHueF() );
603 saturationPoints << QPointF( 1.0, mRamp.color2().hslSaturationF() );
604 alphaPoints << QPointF( 1.0, mRamp.color2().alphaF() );
605 addMarkersForColor( 1.0, mRamp.color2(), mCurrentPlotMarkerIndex == i );
606
607 std::sort( lightnessPoints.begin(), lightnessPoints.end(), byX );
608 std::sort( huePoints.begin(), huePoints.end(), byX );
609 std::sort( saturationPoints.begin(), saturationPoints.end(), byX );
610 std::sort( alphaPoints.begin(), alphaPoints.end(), byX );
611
612 mLightnessCurve->setSamples( lightnessPoints );
613 mHueCurve->setSamples( huePoints );
614 mSaturationCurve->setSamples( saturationPoints );
615 mAlphaCurve->setSamples( alphaPoints );
616 mPlot->replot();
617}
618
619void QgsGradientColorRampDialog::updateRampFromStopEditor()
620{
621 mRamp = mStopEditor->gradientRamp();
622
623 mBlockChanges++;
624 mPositionSpinBox->blockSignals( true );
625 mPositionSpinBox->setValue( mStopEditor->selectedStop().offset * 100 );
626 mPositionSpinBox->blockSignals( false );
627 mColorWidget->blockSignals( true );
628 mColorWidget->setColor( mStopEditor->selectedStop().color );
629 mColorWidget->blockSignals( false );
630
631 mStopColorSpec->setCurrentIndex( mStopColorSpec->findData( static_cast<int>( mStopEditor->selectedStop().colorSpec() ) ) );
632 mStopDirection->setCurrentIndex( mStopDirection->findData( static_cast<int>( mStopEditor->selectedStop().direction() ) ) );
633 mBlockChanges--;
634
635 // first stop cannot have color spec or direction set
636 mStopColorSpec->setEnabled( !( mStopEditor->selectedStop().offset == 0 && mStopEditor->selectedStop().color == mRamp.color1() ) );
637 mStopDirection->setEnabled( !( mStopEditor->selectedStop().offset == 0 && mStopEditor->selectedStop().color == mRamp.color1() ) && hasDirection( mStopEditor->selectedStop().colorSpec() ) );
638
639 updateColorButtons();
640 updatePlot();
641
642 emit changed();
643}
644
645void QgsGradientColorRampDialog::setColor1( const QColor &color )
646{
647 mStopEditor->setColor1( color );
648 updateColorButtons();
649}
650
651void QgsGradientColorRampDialog::setColor2( const QColor &color )
652{
653 mStopEditor->setColor2( color );
654 updateColorButtons();
655}
656
657void QgsGradientColorRampDialog::showHelp()
658{
659 QgsHelp::openHelp( u"style_library/style_manager.html#setting-a-color-ramp"_s );
660}
661
662
664
665QgsGradientPlotEventFilter::QgsGradientPlotEventFilter( QwtPlot *plot )
666 : QObject( plot )
667 , mPlot( plot )
668{
669 mPlot->canvas()->installEventFilter( this );
670}
671
672bool QgsGradientPlotEventFilter::eventFilter( QObject *object, QEvent *event )
673{
674 if ( !mPlot->isEnabled() )
675 return QObject::eventFilter( object, event );
676
677 switch ( event->type() )
678 {
679 case QEvent::MouseButtonPress:
680 {
681 const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>( event );
682 if ( mouseEvent->button() == Qt::LeftButton )
683 {
684 emit mousePress( mapPoint( mouseEvent->pos() ) );
685 }
686 break;
687 }
688 case QEvent::MouseMove:
689 {
690 const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>( event );
691 if ( mouseEvent->buttons() & Qt::LeftButton )
692 {
693 // only emit when button pressed
694 emit mouseMove( mapPoint( mouseEvent->pos() ) );
695 }
696 break;
697 }
698 case QEvent::MouseButtonRelease:
699 {
700 const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>( event );
701 if ( mouseEvent->button() == Qt::LeftButton )
702 {
703 emit mouseRelease( mapPoint( mouseEvent->pos() ) );
704 }
705 break;
706 }
707 default:
708 break;
709 }
710
711 return QObject::eventFilter( object, event );
712}
713
714QPointF QgsGradientPlotEventFilter::mapPoint( QPointF point ) const
715{
716 if ( !mPlot )
717 return QPointF();
718
719 return QPointF( mPlot->canvasMap( QwtPlot::xBottom ).invTransform( point.x() ), mPlot->canvasMap( QwtPlot::yLeft ).invTransform( point.y() ) );
720}
721
AngularDirection
Angular directions.
Definition qgis.h:3491
@ CounterClockwise
Counter-clockwise direction.
Definition qgis.h:3493
@ Clockwise
Clockwise direction.
Definition qgis.h:3492
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:43
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:7489
QMap< QString, QString > QgsStringMap
Definition qgis.h:7413
bool byX(QPointF p1, QPointF p2)