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