25 #include <QColorDialog>
26 #include <QHeaderView>
27 #include <QInputDialog>
29 #include <QTableWidget>
33 #include <qwt_global.h>
34 #include <qwt_plot_canvas.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>
48 , mCurrentPlotColorComponent( -1 )
49 , mCurrentPlotMarkerIndex( 0 )
53 connect( cboType,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsGradientColorRampDialog::cboType_currentIndexChanged );
54 connect( btnInformation, &QPushButton::pressed,
this, &QgsGradientColorRampDialog::btnInformation_pressed );
55 connect( mPositionSpinBox,
static_cast < void ( QDoubleSpinBox::* )(
double )
> ( &QDoubleSpinBox::valueChanged ),
this, &QgsGradientColorRampDialog::mPositionSpinBox_valueChanged );
56 connect( mPlotHueCheckbox, &QCheckBox::toggled,
this, &QgsGradientColorRampDialog::mPlotHueCheckbox_toggled );
57 connect( mPlotLightnessCheckbox, &QCheckBox::toggled,
this, &QgsGradientColorRampDialog::mPlotLightnessCheckbox_toggled );
58 connect( mPlotSaturationCheckbox, &QCheckBox::toggled,
this, &QgsGradientColorRampDialog::mPlotSaturationCheckbox_toggled );
59 connect( mPlotAlphaCheckbox, &QCheckBox::toggled,
this, &QgsGradientColorRampDialog::mPlotAlphaCheckbox_toggled );
61 setWindowModality( Qt::WindowModal );
64 mPositionSpinBox->setShowClearButton(
false );
65 btnColor1->setAllowOpacity(
true );
66 btnColor1->setColorDialogTitle( tr(
"Select Ramp Color" ) );
67 btnColor1->setContext( QStringLiteral(
"symbology" ) );
68 btnColor1->setShowNoColor(
true );
69 btnColor1->setNoColorString( tr(
"Transparent" ) );
70 btnColor2->setAllowOpacity(
true );
71 btnColor2->setColorDialogTitle( tr(
"Select Ramp Color" ) );
72 btnColor2->setContext( QStringLiteral(
"symbology" ) );
73 btnColor2->setShowNoColor(
true );
74 btnColor2->setNoColorString( tr(
"Transparent" ) );
80 cboType->blockSignals(
true );
81 cboType->addItem( tr(
"Discrete" ) );
82 cboType->addItem( tr(
"Continuous" ) );
84 cboType->setCurrentIndex( 0 );
86 cboType->setCurrentIndex( 1 );
87 cboType->blockSignals(
false );
89 if ( mRamp.
info().isEmpty() )
90 btnInformation->setEnabled(
false );
92 mStopEditor->setGradientRamp( mRamp );
99 mPlot->setFrameStyle( QFrame::NoFrame );
100 QFrame *plotCanvasFrame =
dynamic_cast<QFrame *
>( mPlot->canvas() );
101 if ( plotCanvasFrame )
102 plotCanvasFrame->setFrameStyle( QFrame::NoFrame );
104 mPlot->setAxisScale( QwtPlot::yLeft, 0.0, 1.0 );
105 mPlot->enableAxis( QwtPlot::yLeft,
false );
108 QwtPlotGrid *grid =
new QwtPlotGrid();
109 QwtScaleDiv gridDiv( 0.0, 1.0, QList<double>(), QList<double>(), QList<double>() << 0.2 << 0.4 << 0.6 << 0.8 );
110 grid->setXDiv( gridDiv );
111 grid->setYDiv( gridDiv );
112 grid->setPen( QPen( QColor( 0, 0, 0, 50 ) ) );
113 grid->attach( mPlot );
115 mLightnessCurve =
new QwtPlotCurve();
116 mLightnessCurve->setTitle( tr(
"Lightness" ) );
117 mLightnessCurve->setPen( QPen( QColor( 70, 150, 255 ), 0.0 ) ),
118 mLightnessCurve->setRenderHint( QwtPlotItem::RenderAntialiased,
true );
119 mLightnessCurve->attach( mPlot );
121 mHueCurve =
new QwtPlotCurve();
122 mHueCurve->setTitle( tr(
"Hue" ) );
123 mHueCurve->setPen( QPen( QColor( 255, 215, 70 ), 0.0 ) ),
124 mHueCurve->setRenderHint( QwtPlotItem::RenderAntialiased,
true );
125 mHueCurve->attach( mPlot );
127 mSaturationCurve =
new QwtPlotCurve();
128 mSaturationCurve->setTitle( tr(
"Saturation" ) );
129 mSaturationCurve->setPen( QPen( QColor( 255, 70, 150 ), 0.0 ) ),
130 mSaturationCurve->setRenderHint( QwtPlotItem::RenderAntialiased,
true );
131 mSaturationCurve->attach( mPlot );
133 mAlphaCurve =
new QwtPlotCurve();
134 mAlphaCurve->setTitle( tr(
"Opacity" ) );
135 mAlphaCurve->setPen( QPen( QColor( 50, 50, 50 ), 0.0 ) ),
136 mAlphaCurve->setRenderHint( QwtPlotItem::RenderAntialiased,
true );
137 mAlphaCurve->attach( mPlot );
139 mPlotFilter =
new QgsGradientPlotEventFilter( mPlot );
140 connect( mPlotFilter, &QgsGradientPlotEventFilter::mousePress,
this, &QgsGradientColorRampDialog::plotMousePress );
141 connect( mPlotFilter, &QgsGradientPlotEventFilter::mouseRelease,
this, &QgsGradientColorRampDialog::plotMouseRelease );
142 connect( mPlotFilter, &QgsGradientPlotEventFilter::mouseMove,
this, &QgsGradientColorRampDialog::plotMouseMove );
145 mPlotHueCheckbox->setChecked( settings.
value( QStringLiteral(
"GradientEditor/plotHue" ),
false ).toBool() );
146 mPlotLightnessCheckbox->setChecked( settings.
value( QStringLiteral(
"GradientEditor/plotLightness" ),
true ).toBool() );
147 mPlotSaturationCheckbox->setChecked( settings.
value( QStringLiteral(
"GradientEditor/plotSaturation" ),
false ).toBool() );
148 mPlotAlphaCheckbox->setChecked( settings.
value( QStringLiteral(
"GradientEditor/plotAlpha" ),
false ).toBool() );
150 mHueCurve->setVisible( mPlotHueCheckbox->isChecked() );
151 mLightnessCurve->setVisible( mPlotLightnessCheckbox->isChecked() );
152 mSaturationCurve->setVisible( mPlotSaturationCheckbox->isChecked() );
153 mAlphaCurve->setVisible( mPlotAlphaCheckbox->isChecked() );
156 mStopEditor->selectStop( 0 );
158 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsGradientColorRampDialog::showHelp );
164 settings.
setValue( QStringLiteral(
"GradientEditor/plotHue" ), mPlotHueCheckbox->isChecked() );
165 settings.
setValue( QStringLiteral(
"GradientEditor/plotLightness" ), mPlotLightnessCheckbox->isChecked() );
166 settings.
setValue( QStringLiteral(
"GradientEditor/plotSaturation" ), mPlotSaturationCheckbox->isChecked() );
167 settings.
setValue( QStringLiteral(
"GradientEditor/plotAlpha" ), mPlotAlphaCheckbox->isChecked() );
175 updateColorButtons();
187 void QgsGradientColorRampDialog::cboType_currentIndexChanged(
int index )
193 updateColorButtons();
200 void QgsGradientColorRampDialog::btnInformation_pressed()
202 if ( mRamp.
info().isEmpty() )
206 QLabel *label =
nullptr;
209 QTableWidget *tableInfo =
new QTableWidget( dlg );
210 tableInfo->verticalHeader()->hide();
211 tableInfo->horizontalHeader()->hide();
212 tableInfo->setRowCount( mRamp.
info().count() );
213 tableInfo->setColumnCount( 2 );
216 for ( QgsStringMap::const_iterator it = rampInfo.constBegin();
217 it != rampInfo.constEnd(); ++it )
219 if ( it.key().startsWith( QLatin1String(
"cpt-city" ) ) )
221 tableInfo->setItem( i, 0,
new QTableWidgetItem( it.key() ) );
222 tableInfo->setItem( i, 1,
new QTableWidgetItem( it.value() ) );
223 tableInfo->resizeRowToContents( i );
226 tableInfo->resizeColumnToContents( 0 );
227 tableInfo->horizontalHeader()->setStretchLastSection(
true );
228 tableInfo->setRowCount( i );
229 tableInfo->setFixedHeight( tableInfo->rowHeight( 0 ) * i + 5 );
230 dlg->
layout()->addWidget( tableInfo );
231 dlg->resize( 600, 250 );
233 dlg->
layout()->addSpacing( 5 );
236 QString gradientFile = mRamp.
info().value( QStringLiteral(
"cpt-city-gradient" ) );
237 if ( ! gradientFile.isNull() )
239 QString fileName = gradientFile;
241 if ( ! QFile::exists( fileName ) )
243 fileName = gradientFile;
244 fileName.replace( QLatin1String(
"<cpt-city>" ), QLatin1String(
"http://soliton.vm.bytemark.co.uk/pub/cpt-city" ) );
246 label =
new QLabel( tr(
"Gradient file : %1" ).arg( fileName ), dlg );
247 label->setTextInteractionFlags( Qt::TextBrowserInteraction );
248 dlg->
layout()->addSpacing( 5 );
249 dlg->
layout()->addWidget( label );
253 QString licenseFile = mRamp.
info().value( QStringLiteral(
"cpt-city-license" ) );
254 if ( !licenseFile.isNull() )
256 QString fileName = licenseFile;
258 if ( ! QFile::exists( fileName ) )
260 fileName = licenseFile;
261 fileName.replace( QLatin1String(
"<cpt-city>" ), QLatin1String(
"http://soliton.vm.bytemark.co.uk/pub/cpt-city" ) );
263 label =
new QLabel( tr(
"License file : %1" ).arg( fileName ), dlg );
264 label->setTextInteractionFlags( Qt::TextBrowserInteraction );
265 dlg->
layout()->addSpacing( 5 );
266 dlg->
layout()->addWidget( label );
267 if ( QFile::exists( fileName ) )
269 QTextEdit *textEdit =
new QTextEdit( dlg );
270 textEdit->setReadOnly(
true );
271 QFile file( fileName );
272 if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
274 textEdit->setText( file.readAll() );
276 dlg->
layout()->addSpacing( 5 );
277 dlg->
layout()->addWidget( textEdit );
278 dlg->resize( 600, 500 );
286 void QgsGradientColorRampDialog::updateColorButtons()
288 btnColor1->blockSignals(
true );
289 btnColor1->setColor( mRamp.
color1() );
290 btnColor1->blockSignals(
false );
291 btnColor2->blockSignals(
true );
292 btnColor2->setColor( mRamp.
color2() );
293 btnColor2->blockSignals(
false );
296 void QgsGradientColorRampDialog::updateStopEditor()
298 mStopEditor->blockSignals(
true );
299 mStopEditor->setGradientRamp( mRamp );
300 mStopEditor->blockSignals(
false );
303 void QgsGradientColorRampDialog::selectedStopChanged(
const QgsGradientStop &stop )
305 mColorWidget->blockSignals(
true );
306 mColorWidget->setColor( stop.
color );
307 mColorWidget->blockSignals(
false );
308 mPositionSpinBox->blockSignals(
true );
309 mPositionSpinBox->setValue( stop.
offset * 100 );
310 mPositionSpinBox->blockSignals(
false );
315 mPositionSpinBox->setDisabled(
true );
316 mDeleteStopButton->setDisabled(
true );
320 mPositionSpinBox->setDisabled(
false );
321 mDeleteStopButton->setDisabled(
false );
327 void QgsGradientColorRampDialog::colorWidgetChanged(
const QColor &color )
329 mStopEditor->setSelectedStopColor( color );
332 void QgsGradientColorRampDialog::mPositionSpinBox_valueChanged(
double val )
334 mStopEditor->setSelectedStopOffset( val / 100.0 );
337 void QgsGradientColorRampDialog::mPlotHueCheckbox_toggled(
bool checked )
339 mHueCurve->setVisible( checked );
343 void QgsGradientColorRampDialog::mPlotLightnessCheckbox_toggled(
bool checked )
345 mLightnessCurve->setVisible( checked );
349 void QgsGradientColorRampDialog::mPlotSaturationCheckbox_toggled(
bool checked )
351 mSaturationCurve->setVisible( checked );
355 void QgsGradientColorRampDialog::mPlotAlphaCheckbox_toggled(
bool checked )
357 mAlphaCurve->setVisible( checked );
361 void QgsGradientColorRampDialog::plotMousePress( QPointF point )
366 mCurrentPlotColorComponent = -1;
367 mCurrentPlotMarkerIndex = -1;
370 for (
int i = 0; i < mRamp.
count(); ++i )
373 double currentOff = 0.0;
377 currentCol = mRamp.
color1();
379 else if ( i == mRamp.
count() - 1 )
382 currentCol = mRamp.
color2();
386 currentOff = mRamp.
stops().at( i - 1 ).offset;
387 currentCol = mRamp.
stops().at( i - 1 ).color;
391 if ( mPlotHueCheckbox->isChecked() )
393 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.hslHueF(), 2.0 );
394 if ( currentDist < minDist )
396 minDist = currentDist;
397 mCurrentPlotColorComponent = 0;
398 mCurrentPlotMarkerIndex = i;
401 if ( mPlotLightnessCheckbox->isChecked() )
403 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.lightnessF(), 2.0 );
404 if ( currentDist < minDist )
406 minDist = currentDist;
407 mCurrentPlotColorComponent = 1;
408 mCurrentPlotMarkerIndex = i;
411 if ( mPlotSaturationCheckbox->isChecked() )
413 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.hslSaturationF(), 2.0 );
414 if ( currentDist < minDist )
416 minDist = currentDist;
417 mCurrentPlotColorComponent = 2;
418 mCurrentPlotMarkerIndex = i;
421 if ( mPlotAlphaCheckbox->isChecked() )
423 currentDist = std::pow( point.x() - currentOff, 2.0 ) + std::pow( point.y() - currentCol.alphaF(), 2.0 );
424 if ( currentDist < minDist )
426 minDist = currentDist;
427 mCurrentPlotColorComponent = 3;
428 mCurrentPlotMarkerIndex = i;
434 if ( mCurrentPlotMarkerIndex >= 0 )
435 mStopEditor->selectStop( mCurrentPlotMarkerIndex );
438 void QgsGradientColorRampDialog::plotMouseRelease( QPointF )
440 mCurrentPlotColorComponent = -1;
443 void QgsGradientColorRampDialog::plotMouseMove( QPointF point )
445 QColor newColor = mStopEditor->selectedStop().color;
447 if ( mCurrentPlotColorComponent == 0 )
448 newColor = QColor::fromHslF( qBound( qreal( 0.0 ), point.y(), qreal( 1.0 ) ), newColor.hslSaturationF(), newColor.lightnessF(), newColor.alphaF() );
449 else if ( mCurrentPlotColorComponent == 1 )
450 newColor = QColor::fromHslF( newColor.hslHueF(), newColor.hslSaturationF(), qBound( qreal( 0.0 ), point.y(), qreal( 1.0 ) ), newColor.alphaF() );
451 else if ( mCurrentPlotColorComponent == 2 )
452 newColor = QColor::fromHslF( newColor.hslHueF(), qBound( qreal( 0.0 ), point.y(), qreal( 1.0 ) ), newColor.lightnessF(), newColor.alphaF() );
453 else if ( mCurrentPlotColorComponent == 3 )
454 newColor = QColor::fromHslF( newColor.hslHueF(), newColor.hslSaturationF(), newColor.lightnessF(), qBound( qreal( 0.0 ), point.y(), qreal( 1.0 ) ) );
456 mStopEditor->setSelectedStopDetails( newColor, qBound( qreal( 0.0 ), point.x(), qreal( 1.0 ) ) );
459 bool byX( QPointF p1, QPointF p2 )
461 return p1.x() < p2.x();
464 void QgsGradientColorRampDialog::addPlotMarker(
double x,
double y,
const QColor &color,
bool isSelected )
466 QColor borderColor = color.darker( 200 );
467 borderColor.setAlpha( 255 );
469 QColor brushColor = color;
470 brushColor.setAlpha( 255 );
472 QwtPlotMarker *marker =
new QwtPlotMarker();
473 marker->setSymbol(
new QwtSymbol( QwtSymbol::Ellipse, QBrush( brushColor ), QPen( borderColor, isSelected ? 2 : 1 ), QSize( 8, 8 ) ) );
474 marker->setValue( x, y );
475 marker->attach( mPlot );
476 marker->setRenderHint( QwtPlotItem::RenderAntialiased,
true );
480 void QgsGradientColorRampDialog::addMarkersForColor(
double x,
const QColor &color,
bool isSelected )
482 if ( mPlotHueCheckbox->isChecked() )
483 addPlotMarker( x, color.hslHueF(), color, isSelected && mCurrentPlotColorComponent == 0 );
484 if ( mPlotLightnessCheckbox->isChecked() )
485 addPlotMarker( x, color.lightnessF(), color, isSelected && mCurrentPlotColorComponent == 1 );
486 if ( mPlotSaturationCheckbox->isChecked() )
487 addPlotMarker( x, color.hslSaturationF(), color, isSelected && mCurrentPlotColorComponent == 2 );
488 if ( mPlotAlphaCheckbox->isChecked() )
489 addPlotMarker( x, color.alphaF(), color, isSelected && mCurrentPlotColorComponent == 3 );
492 void QgsGradientColorRampDialog::updatePlot()
495 const auto constMMarkers = mMarkers;
496 for ( QwtPlotMarker *marker : constMMarkers )
503 QPolygonF lightnessPoints;
505 QPolygonF saturationPoints;
506 QPolygonF alphaPoints;
507 lightnessPoints << QPointF( 0.0, mRamp.
color1().lightnessF() );
508 huePoints << QPointF( 0.0, mRamp.
color1().hslHueF() );
509 saturationPoints << QPointF( 0.0, mRamp.
color1().hslSaturationF() );
510 alphaPoints << QPointF( 0.0, mRamp.
color1().alphaF() );
511 addMarkersForColor( 0, mRamp.
color1(), mCurrentPlotMarkerIndex == 0 );
514 const auto constStops = mRamp.
stops();
517 lightnessPoints << QPointF( stop.
offset, stop.
color.lightnessF() );
518 huePoints << QPointF( stop.
offset, stop.
color.hslHueF() );
519 saturationPoints << QPointF( stop.
offset, stop.
color.hslSaturationF() );
520 alphaPoints << QPointF( stop.
offset, stop.
color.alphaF() );
522 addMarkersForColor( stop.
offset, stop.
color, mCurrentPlotMarkerIndex == i );
527 for (
double p = 0.001; p < 1.0; p += 0.001 )
529 QColor
c = mRamp.
color( p );
530 lightnessPoints << QPointF( p,
c.lightnessF() );
531 huePoints << QPointF( p,
c.hslHueF() );
532 saturationPoints << QPointF( p,
c.hslSaturationF() );
533 alphaPoints << QPointF( p,
c.alphaF() );
536 lightnessPoints << QPointF( 1.0, mRamp.
color2().lightnessF() );
537 huePoints << QPointF( 1.0, mRamp.
color2().hslHueF() );
538 saturationPoints << QPointF( 1.0, mRamp.
color2().hslSaturationF() );
539 alphaPoints << QPointF( 1.0, mRamp.
color2().alphaF() );
540 addMarkersForColor( 1.0, mRamp.
color2(), mCurrentPlotMarkerIndex == i );
542 std::sort( lightnessPoints.begin(), lightnessPoints.end(),
byX );
543 std::sort( huePoints.begin(), huePoints.end(),
byX );
544 std::sort( saturationPoints.begin(), saturationPoints.end(),
byX );
545 std::sort( alphaPoints.begin(), alphaPoints.end(),
byX );
547 mLightnessCurve->setSamples( lightnessPoints );
548 mHueCurve->setSamples( huePoints );
549 mSaturationCurve->setSamples( saturationPoints );
550 mAlphaCurve->setSamples( alphaPoints );
554 void QgsGradientColorRampDialog::updateRampFromStopEditor()
556 mRamp = mStopEditor->gradientRamp();
557 mPositionSpinBox->blockSignals(
true );
558 mPositionSpinBox->setValue( mStopEditor->selectedStop().offset * 100 );
559 mPositionSpinBox->blockSignals(
false );
560 mColorWidget->blockSignals(
true );
561 mColorWidget->setColor( mStopEditor->selectedStop().color );
562 mColorWidget->blockSignals(
false );
564 updateColorButtons();
572 mStopEditor->setColor1( color );
573 updateColorButtons();
578 mStopEditor->setColor2( color );
579 updateColorButtons();
582 void QgsGradientColorRampDialog::showHelp()
584 QgsHelp::openHelp( QStringLiteral(
"style_library/style_manager.html#setting-a-color-ramp" ) );
590 QgsGradientPlotEventFilter::QgsGradientPlotEventFilter( QwtPlot *plot )
594 mPlot->canvas()->installEventFilter(
this );
597 bool QgsGradientPlotEventFilter::eventFilter( QObject *
object, QEvent *event )
599 if ( !mPlot->isEnabled() )
600 return QObject::eventFilter(
object, event );
602 switch ( event->type() )
604 case QEvent::MouseButtonPress:
606 const QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>( event );
607 if ( mouseEvent->button() == Qt::LeftButton )
609 emit mousePress( mapPoint( mouseEvent->pos() ) );
613 case QEvent::MouseMove:
615 const QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>( event );
616 if ( mouseEvent->buttons() & Qt::LeftButton )
619 emit mouseMove( mapPoint( mouseEvent->pos() ) );
623 case QEvent::MouseButtonRelease:
625 const QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>( event );
626 if ( mouseEvent->button() == Qt::LeftButton )
628 emit mouseRelease( mapPoint( mouseEvent->pos() ) );
636 return QObject::eventFilter(
object, event );
639 QPointF QgsGradientPlotEventFilter::mapPoint( QPointF point )
const
644 return QPointF( mPlot->canvasMap( QwtPlot::xBottom ).invTransform( point.x() ),
645 mPlot->canvasMap( QwtPlot::yLeft ).invTransform( point.y() ) );