QGIS API Documentation  3.0.2-Girona (307d082)
qgscompoundcolorwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscompoundcolorwidget.cpp
3  --------------------------
4  begin : April 2016
5  copyright : (C) 2016 by Nyall Dawson
6  email : nyall dot dawson 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 
16 #include "qgscompoundcolorwidget.h"
17 #include "qgscolorscheme.h"
18 #include "qgscolorschemeregistry.h"
19 #include "qgssymbollayerutils.h"
20 #include "qgsapplication.h"
21 #include "qgssettings.h"
22 
23 #include <QHeaderView>
24 #include <QPushButton>
25 #include <QMenu>
26 #include <QToolButton>
27 #include <QFileDialog>
28 #include <QMessageBox>
29 #include <QDesktopWidget>
30 #include <QMouseEvent>
31 #include <QScreen>
32 #include <QInputDialog>
33 #include <QVBoxLayout>
34 
35 QgsCompoundColorWidget::QgsCompoundColorWidget( QWidget *parent, const QColor &color, Layout widgetLayout )
36  : QgsPanelWidget( parent )
37 {
38  setupUi( this );
39  connect( mHueRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mHueRadio_toggled );
40  connect( mSaturationRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mSaturationRadio_toggled );
41  connect( mValueRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mValueRadio_toggled );
42  connect( mRedRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mRedRadio_toggled );
43  connect( mGreenRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mGreenRadio_toggled );
44  connect( mBlueRadio, &QRadioButton::toggled, this, &QgsCompoundColorWidget::mBlueRadio_toggled );
45  connect( mAddColorToSchemeButton, &QPushButton::clicked, this, &QgsCompoundColorWidget::mAddColorToSchemeButton_clicked );
46  connect( mAddCustomColorButton, &QPushButton::clicked, this, &QgsCompoundColorWidget::mAddCustomColorButton_clicked );
47  connect( mSampleButton, &QPushButton::clicked, this, &QgsCompoundColorWidget::mSampleButton_clicked );
48  connect( mTabWidget, &QTabWidget::currentChanged, this, &QgsCompoundColorWidget::mTabWidget_currentChanged );
49  connect( mActionShowInButtons, &QAction::toggled, this, &QgsCompoundColorWidget::mActionShowInButtons_toggled );
50 
51  if ( widgetLayout == LayoutVertical )
52  {
53  // shuffle stuff around
54  QVBoxLayout *newLayout = new QVBoxLayout();
55  newLayout->setMargin( 0 );
56  newLayout->setContentsMargins( 0, 0, 0, 0 );
57  newLayout->addWidget( mTabWidget );
58  newLayout->addWidget( mSlidersWidget );
59  newLayout->addWidget( mPreviewWidget );
60  newLayout->addWidget( mSwatchesWidget );
61  delete layout();
62  setLayout( newLayout );
63  }
64 
65  QgsSettings settings;
66 
67  mSchemeList->header()->hide();
68  mSchemeList->setColumnWidth( 0, 44 );
69 
70  //get schemes with ShowInColorDialog set
71  refreshSchemeComboBox();
72  QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorDialog );
73 
74  //choose a reasonable starting scheme
75  int activeScheme = settings.value( QStringLiteral( "Windows/ColorDialog/activeScheme" ), 0 ).toInt();
76  activeScheme = activeScheme >= mSchemeComboBox->count() ? 0 : activeScheme;
77 
78  mSchemeList->setScheme( schemeList.at( activeScheme ) );
79 
80  mSchemeComboBox->setCurrentIndex( activeScheme );
81  updateActionsForCurrentScheme();
82 
83  //listen out for selection changes in list, so we can enable/disable the copy colors option
84  connect( mSchemeList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsCompoundColorWidget::listSelectionChanged );
85  //copy action defaults to disabled
86  mActionCopyColors->setEnabled( false );
87 
88  connect( mActionCopyColors, &QAction::triggered, mSchemeList, &QgsColorSchemeList::copyColors );
89  connect( mActionPasteColors, &QAction::triggered, mSchemeList, &QgsColorSchemeList::pasteColors );
90  connect( mActionExportColors, &QAction::triggered, mSchemeList, &QgsColorSchemeList::showExportColorsDialog );
91  connect( mActionImportColors, &QAction::triggered, mSchemeList, &QgsColorSchemeList::showImportColorsDialog );
92  connect( mActionImportPalette, &QAction::triggered, this, &QgsCompoundColorWidget::importPalette );
93  connect( mActionRemovePalette, &QAction::triggered, this, &QgsCompoundColorWidget::removePalette );
94  connect( mActionNewPalette, &QAction::triggered, this, &QgsCompoundColorWidget::newPalette );
95  connect( mRemoveColorsFromSchemeButton, &QAbstractButton::clicked, mSchemeList, &QgsColorSchemeList::removeSelection );
96 
97  QMenu *schemeMenu = new QMenu( mSchemeToolButton );
98  schemeMenu->addAction( mActionCopyColors );
99  schemeMenu->addAction( mActionPasteColors );
100  schemeMenu->addSeparator();
101  schemeMenu->addAction( mActionImportColors );
102  schemeMenu->addAction( mActionExportColors );
103  schemeMenu->addSeparator();
104  schemeMenu->addAction( mActionNewPalette );
105  schemeMenu->addAction( mActionImportPalette );
106  schemeMenu->addAction( mActionRemovePalette );
107  schemeMenu->addAction( mActionShowInButtons );
108  mSchemeToolButton->setMenu( schemeMenu );
109 
110  connect( mSchemeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsCompoundColorWidget::schemeIndexChanged );
112 
113  mOldColorLabel->hide();
114 
115  mVerticalRamp->setOrientation( QgsColorRampWidget::Vertical );
116  mVerticalRamp->setInteriorMargin( 2 );
117  mVerticalRamp->setShowFrame( true );
118 
119  mRedSlider->setComponent( QgsColorWidget::Red );
120  mGreenSlider->setComponent( QgsColorWidget::Green );
121  mBlueSlider->setComponent( QgsColorWidget::Blue );
122  mHueSlider->setComponent( QgsColorWidget::Hue );
123  mSaturationSlider->setComponent( QgsColorWidget::Saturation );
124  mValueSlider->setComponent( QgsColorWidget::Value );
125  mAlphaSlider->setComponent( QgsColorWidget::Alpha );
126 
127  mSwatchButton1->setShowMenu( false );
128  mSwatchButton1->setBehavior( QgsColorButton::SignalOnly );
129  mSwatchButton2->setShowMenu( false );
130  mSwatchButton2->setBehavior( QgsColorButton::SignalOnly );
131  mSwatchButton3->setShowMenu( false );
132  mSwatchButton3->setBehavior( QgsColorButton::SignalOnly );
133  mSwatchButton4->setShowMenu( false );
134  mSwatchButton4->setBehavior( QgsColorButton::SignalOnly );
135  mSwatchButton5->setShowMenu( false );
136  mSwatchButton5->setBehavior( QgsColorButton::SignalOnly );
137  mSwatchButton6->setShowMenu( false );
138  mSwatchButton6->setBehavior( QgsColorButton::SignalOnly );
139  mSwatchButton7->setShowMenu( false );
140  mSwatchButton7->setBehavior( QgsColorButton::SignalOnly );
141  mSwatchButton8->setShowMenu( false );
142  mSwatchButton8->setBehavior( QgsColorButton::SignalOnly );
143  mSwatchButton9->setShowMenu( false );
144  mSwatchButton9->setBehavior( QgsColorButton::SignalOnly );
145  mSwatchButton10->setShowMenu( false );
146  mSwatchButton10->setBehavior( QgsColorButton::SignalOnly );
147  mSwatchButton11->setShowMenu( false );
148  mSwatchButton11->setBehavior( QgsColorButton::SignalOnly );
149  mSwatchButton12->setShowMenu( false );
150  mSwatchButton12->setBehavior( QgsColorButton::SignalOnly );
151  mSwatchButton13->setShowMenu( false );
152  mSwatchButton13->setBehavior( QgsColorButton::SignalOnly );
153  mSwatchButton14->setShowMenu( false );
154  mSwatchButton14->setBehavior( QgsColorButton::SignalOnly );
155  mSwatchButton15->setShowMenu( false );
156  mSwatchButton15->setBehavior( QgsColorButton::SignalOnly );
157  mSwatchButton16->setShowMenu( false );
158  mSwatchButton16->setBehavior( QgsColorButton::SignalOnly );
159  //restore custom colors
160  mSwatchButton1->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor1" ), QVariant( QColor() ) ).value<QColor>() );
161  mSwatchButton2->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor2" ), QVariant( QColor() ) ).value<QColor>() );
162  mSwatchButton3->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor3" ), QVariant( QColor() ) ).value<QColor>() );
163  mSwatchButton4->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor4" ), QVariant( QColor() ) ).value<QColor>() );
164  mSwatchButton5->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor5" ), QVariant( QColor() ) ).value<QColor>() );
165  mSwatchButton6->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor6" ), QVariant( QColor() ) ).value<QColor>() );
166  mSwatchButton7->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor7" ), QVariant( QColor() ) ).value<QColor>() );
167  mSwatchButton8->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor8" ), QVariant( QColor() ) ).value<QColor>() );
168  mSwatchButton9->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor9" ), QVariant( QColor() ) ).value<QColor>() );
169  mSwatchButton10->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor10" ), QVariant( QColor() ) ).value<QColor>() );
170  mSwatchButton11->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor11" ), QVariant( QColor() ) ).value<QColor>() );
171  mSwatchButton12->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor12" ), QVariant( QColor() ) ).value<QColor>() );
172  mSwatchButton13->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor13" ), QVariant( QColor() ) ).value<QColor>() );
173  mSwatchButton14->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor14" ), QVariant( QColor() ) ).value<QColor>() );
174  mSwatchButton15->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor15" ), QVariant( QColor() ) ).value<QColor>() );
175  mSwatchButton16->setColor( settings.value( QStringLiteral( "Windows/ColorDialog/customColor16" ), QVariant( QColor() ) ).value<QColor>() );
176 
177  //restore sample radius
178  mSpinBoxRadius->setValue( settings.value( QStringLiteral( "Windows/ColorDialog/sampleRadius" ), 1 ).toInt() );
179  mSamplePreview->setColor( QColor() );
180 
181  if ( color.isValid() )
182  {
183  setColor( color );
184  }
185 
186  //restore active component radio button
187  int activeRadio = settings.value( QStringLiteral( "Windows/ColorDialog/activeComponent" ), 2 ).toInt();
188  switch ( activeRadio )
189  {
190  case 0:
191  mHueRadio->setChecked( true );
192  break;
193  case 1:
194  mSaturationRadio->setChecked( true );
195  break;
196  case 2:
197  mValueRadio->setChecked( true );
198  break;
199  case 3:
200  mRedRadio->setChecked( true );
201  break;
202  case 4:
203  mGreenRadio->setChecked( true );
204  break;
205  case 5:
206  mBlueRadio->setChecked( true );
207  break;
208  }
209  int currentTab = settings.value( QStringLiteral( "Windows/ColorDialog/activeTab" ), 0 ).toInt();
210  mTabWidget->setCurrentIndex( currentTab );
211 
212  //setup connections
213  connect( mColorBox, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
214  connect( mColorWheel, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
215  connect( mColorText, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
216  connect( mVerticalRamp, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
217  connect( mRedSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
218  connect( mGreenSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
219  connect( mBlueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
220  connect( mHueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
221  connect( mValueSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
222  connect( mSaturationSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
223  connect( mAlphaSlider, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
224  connect( mColorPreview, &QgsColorWidget::colorChanged, this, &QgsCompoundColorWidget::setColor );
225  connect( mSwatchButton1, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
226  connect( mSwatchButton2, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
227  connect( mSwatchButton3, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
228  connect( mSwatchButton4, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
229  connect( mSwatchButton5, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
230  connect( mSwatchButton6, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
231  connect( mSwatchButton7, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
232  connect( mSwatchButton8, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
233  connect( mSwatchButton9, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
234  connect( mSwatchButton10, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
235  connect( mSwatchButton11, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
236  connect( mSwatchButton12, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
237  connect( mSwatchButton13, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
238  connect( mSwatchButton14, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
239  connect( mSwatchButton15, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
240  connect( mSwatchButton16, &QgsColorButton::colorClicked, this, &QgsCompoundColorWidget::setColor );
241 }
242 
244 {
245  saveSettings();
246  if ( !mDiscarded )
247  {
249  }
250 }
251 
253 {
254  //all widgets should have the same color, so it shouldn't matter
255  //which we fetch it from
256  return mColorPreview->color();
257 }
258 
259 void QgsCompoundColorWidget::setAllowOpacity( const bool allowOpacity )
260 {
261  mAllowAlpha = allowOpacity;
262  mAlphaLabel->setVisible( allowOpacity );
263  mAlphaSlider->setVisible( allowOpacity );
264  if ( !allowOpacity )
265  {
266  mAlphaLayout->setContentsMargins( 0, 0, 0, 0 );
267  mAlphaLayout->setSpacing( 0 );
268  }
269 }
270 
271 void QgsCompoundColorWidget::refreshSchemeComboBox()
272 {
273  mSchemeComboBox->blockSignals( true );
274  mSchemeComboBox->clear();
275  QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorDialog );
276  QList<QgsColorScheme *>::const_iterator schemeIt = schemeList.constBegin();
277  for ( ; schemeIt != schemeList.constEnd(); ++schemeIt )
278  {
279  mSchemeComboBox->addItem( ( *schemeIt )->schemeName() );
280  }
281  mSchemeComboBox->blockSignals( false );
282 }
283 
284 void QgsCompoundColorWidget::importPalette()
285 {
286  QgsSettings s;
287  QString lastDir = s.value( QStringLiteral( "/UI/lastGplPaletteDir" ), QDir::homePath() ).toString();
288  QString filePath = QFileDialog::getOpenFileName( this, tr( "Select Palette File" ), lastDir, QStringLiteral( "GPL (*.gpl);;All files (*.*)" ) );
289  activateWindow();
290  if ( filePath.isEmpty() )
291  {
292  return;
293  }
294 
295  //check if file exists
296  QFileInfo fileInfo( filePath );
297  if ( !fileInfo.exists() || !fileInfo.isReadable() )
298  {
299  QMessageBox::critical( nullptr, tr( "Import Color Palette" ), tr( "Error, file does not exist or is not readable." ) );
300  return;
301  }
302 
303  s.setValue( QStringLiteral( "/UI/lastGplPaletteDir" ), fileInfo.absolutePath() );
304  QFile file( filePath );
305 
306  QgsNamedColorList importedColors;
307  bool ok = false;
308  QString paletteName;
309  importedColors = QgsSymbolLayerUtils::importColorsFromGpl( file, ok, paletteName );
310  if ( !ok )
311  {
312  QMessageBox::critical( nullptr, tr( "Import Color Palette" ), tr( "Palette file is not readable." ) );
313  return;
314  }
315 
316  if ( importedColors.length() == 0 )
317  {
318  //no imported colors
319  QMessageBox::critical( nullptr, tr( "Import Color Palette" ), tr( "No colors found in palette file." ) );
320  return;
321  }
322 
323  //TODO - handle conflicting file names, name for new palette
324  QgsUserColorScheme *importedScheme = new QgsUserColorScheme( fileInfo.fileName() );
325  importedScheme->setName( paletteName );
326  importedScheme->setColors( importedColors );
327 
329 
330  //refresh combobox
331  refreshSchemeComboBox();
332  mSchemeComboBox->setCurrentIndex( mSchemeComboBox->count() - 1 );
333 }
334 
335 void QgsCompoundColorWidget::removePalette()
336 {
337  //get current scheme
338  QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorDialog );
339  int prevIndex = mSchemeComboBox->currentIndex();
340  if ( prevIndex >= schemeList.length() )
341  {
342  return;
343  }
344 
345  //make user scheme is a user removable scheme
346  QgsUserColorScheme *userScheme = dynamic_cast<QgsUserColorScheme *>( schemeList.at( prevIndex ) );
347  if ( !userScheme )
348  {
349  return;
350  }
351 
352  if ( QMessageBox::question( this, tr( "Remove Color Palette" ),
353  QString( tr( "Are you sure you want to remove %1?" ) ).arg( userScheme->schemeName() ),
354  QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
355  {
356  //user canceled
357  return;
358  }
359 
360  //remove palette and associated gpl file
361  if ( !userScheme->erase() )
362  {
363  //something went wrong
364  return;
365  }
366 
367  //remove scheme from registry
369  refreshSchemeComboBox();
370  prevIndex = std::max( std::min( prevIndex, mSchemeComboBox->count() - 1 ), 0 );
371  mSchemeComboBox->setCurrentIndex( prevIndex );
372 }
373 
374 void QgsCompoundColorWidget::newPalette()
375 {
376  bool ok = false;
377  QString name = QInputDialog::getText( this, tr( "Create New Palette" ), tr( "Enter a name for the new palette:" ),
378  QLineEdit::Normal, tr( "New palette" ), &ok );
379 
380  if ( !ok || name.isEmpty() )
381  {
382  //user canceled
383  return;
384  }
385 
386  //generate file name for new palette
387  QDir palettePath( gplFilePath() );
388  QRegExp badChars( "[,^@={}\\[\\]~!?:&*\"|#%<>$\"'();`' /\\\\]" );
389  QString filename = name.simplified().toLower().replace( badChars, QStringLiteral( "_" ) );
390  if ( filename.isEmpty() )
391  {
392  filename = tr( "new_palette" );
393  }
394  QFileInfo destFileInfo( palettePath.filePath( filename + ".gpl" ) );
395  int fileNumber = 1;
396  while ( destFileInfo.exists() )
397  {
398  //try to generate a unique file name
399  destFileInfo = QFileInfo( palettePath.filePath( filename + QStringLiteral( "%1.gpl" ).arg( fileNumber ) ) );
400  fileNumber++;
401  }
402 
403  QgsUserColorScheme *newScheme = new QgsUserColorScheme( destFileInfo.fileName() );
404  newScheme->setName( name );
405 
407 
408  //refresh combobox and set new scheme as active
409  refreshSchemeComboBox();
410  mSchemeComboBox->setCurrentIndex( mSchemeComboBox->count() - 1 );
411 }
412 
413 QString QgsCompoundColorWidget::gplFilePath()
414 {
415  QString palettesDir = QgsApplication::qgisSettingsDirPath() + "/palettes";
416 
417  QDir localDir;
418  if ( !localDir.mkpath( palettesDir ) )
419  {
420  return QString();
421  }
422 
423  return palettesDir;
424 }
425 
426 void QgsCompoundColorWidget::schemeIndexChanged( int index )
427 {
428  //save changes to scheme
429  if ( mSchemeList->isDirty() )
430  {
431  mSchemeList->saveColorsToScheme();
432  }
433 
434  //get schemes with ShowInColorDialog set
435  QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorDialog );
436  if ( index >= schemeList.length() )
437  {
438  return;
439  }
440 
441  QgsColorScheme *scheme = schemeList.at( index );
442  mSchemeList->setScheme( scheme );
443 
444  updateActionsForCurrentScheme();
445 
446  //copy action defaults to disabled
447  mActionCopyColors->setEnabled( false );
448 }
449 
450 void QgsCompoundColorWidget::listSelectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
451 {
452  Q_UNUSED( deselected );
453  mActionCopyColors->setEnabled( selected.length() > 0 );
454 }
455 
456 void QgsCompoundColorWidget::mAddCustomColorButton_clicked()
457 {
458  switch ( mLastCustomColorIndex )
459  {
460  case 0:
461  mSwatchButton1->setColor( mColorPreview->color() );
462  break;
463  case 1:
464  mSwatchButton2->setColor( mColorPreview->color() );
465  break;
466  case 2:
467  mSwatchButton3->setColor( mColorPreview->color() );
468  break;
469  case 3:
470  mSwatchButton4->setColor( mColorPreview->color() );
471  break;
472  case 4:
473  mSwatchButton5->setColor( mColorPreview->color() );
474  break;
475  case 5:
476  mSwatchButton6->setColor( mColorPreview->color() );
477  break;
478  case 6:
479  mSwatchButton7->setColor( mColorPreview->color() );
480  break;
481  case 7:
482  mSwatchButton8->setColor( mColorPreview->color() );
483  break;
484  case 8:
485  mSwatchButton9->setColor( mColorPreview->color() );
486  break;
487  case 9:
488  mSwatchButton10->setColor( mColorPreview->color() );
489  break;
490  case 10:
491  mSwatchButton11->setColor( mColorPreview->color() );
492  break;
493  case 11:
494  mSwatchButton12->setColor( mColorPreview->color() );
495  break;
496  case 12:
497  mSwatchButton13->setColor( mColorPreview->color() );
498  break;
499  case 13:
500  mSwatchButton14->setColor( mColorPreview->color() );
501  break;
502  case 14:
503  mSwatchButton15->setColor( mColorPreview->color() );
504  break;
505  case 15:
506  mSwatchButton16->setColor( mColorPreview->color() );
507  break;
508  }
509  mLastCustomColorIndex++;
510  if ( mLastCustomColorIndex >= 16 )
511  {
512  mLastCustomColorIndex = 0;
513  }
514 }
515 
516 void QgsCompoundColorWidget::mSampleButton_clicked()
517 {
518  //activate picker color
519  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Sampler ) );
520  grabMouse();
521  grabKeyboard();
522  mPickingColor = true;
523  setMouseTracking( true );
524 }
525 
526 void QgsCompoundColorWidget::mTabWidget_currentChanged( int index )
527 {
528  //disable radio buttons if not using the first tab, as they have no meaning for other tabs
529  bool enabled = index == 0;
530  mRedRadio->setEnabled( enabled );
531  mBlueRadio->setEnabled( enabled );
532  mGreenRadio->setEnabled( enabled );
533  mHueRadio->setEnabled( enabled );
534  mSaturationRadio->setEnabled( enabled );
535  mValueRadio->setEnabled( enabled );
536 }
537 
538 void QgsCompoundColorWidget::mActionShowInButtons_toggled( bool state )
539 {
540  QgsUserColorScheme *scheme = dynamic_cast< QgsUserColorScheme * >( mSchemeList->scheme() );
541  if ( scheme )
542  {
543  scheme->setShowSchemeInMenu( state );
544  }
545 }
546 
547 QScreen *QgsCompoundColorWidget::findScreenAt( QPoint pos )
548 {
549  for ( QScreen *screen : QGuiApplication::screens() )
550  {
551  if ( screen->geometry().contains( pos ) )
552  {
553  return screen;
554  }
555  }
556  return nullptr;
557 }
558 
559 void QgsCompoundColorWidget::saveSettings()
560 {
561  //save changes to scheme
562  if ( mSchemeList->isDirty() )
563  {
564  mSchemeList->saveColorsToScheme();
565  }
566 
567  QgsSettings settings;
568 
569  //record active component
570  int activeRadio = 0;
571  if ( mHueRadio->isChecked() )
572  activeRadio = 0;
573  if ( mSaturationRadio->isChecked() )
574  activeRadio = 1;
575  if ( mValueRadio->isChecked() )
576  activeRadio = 2;
577  if ( mRedRadio->isChecked() )
578  activeRadio = 3;
579  if ( mGreenRadio->isChecked() )
580  activeRadio = 4;
581  if ( mBlueRadio->isChecked() )
582  activeRadio = 5;
583  settings.setValue( QStringLiteral( "Windows/ColorDialog/activeComponent" ), activeRadio );
584 
585  //record current scheme
586  settings.setValue( QStringLiteral( "Windows/ColorDialog/activeScheme" ), mSchemeComboBox->currentIndex() );
587 
588  //record current tab
589  settings.setValue( QStringLiteral( "Windows/ColorDialog/activeTab" ), mTabWidget->currentIndex() );
590 
591  //record custom colors
592  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor1" ), QVariant( mSwatchButton1->color() ) );
593  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor2" ), QVariant( mSwatchButton2->color() ) );
594  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor3" ), QVariant( mSwatchButton3->color() ) );
595  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor4" ), QVariant( mSwatchButton4->color() ) );
596  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor5" ), QVariant( mSwatchButton5->color() ) );
597  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor6" ), QVariant( mSwatchButton6->color() ) );
598  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor7" ), QVariant( mSwatchButton7->color() ) );
599  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor8" ), QVariant( mSwatchButton8->color() ) );
600  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor9" ), QVariant( mSwatchButton9->color() ) );
601  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor10" ), QVariant( mSwatchButton10->color() ) );
602  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor11" ), QVariant( mSwatchButton11->color() ) );
603  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor12" ), QVariant( mSwatchButton12->color() ) );
604  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor13" ), QVariant( mSwatchButton13->color() ) );
605  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor14" ), QVariant( mSwatchButton14->color() ) );
606  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor15" ), QVariant( mSwatchButton15->color() ) );
607  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor16" ), QVariant( mSwatchButton16->color() ) );
608 
609  //sample radius
610  settings.setValue( QStringLiteral( "Windows/ColorDialog/sampleRadius" ), mSpinBoxRadius->value() );
611 }
612 
613 void QgsCompoundColorWidget::stopPicking( QPoint eventPos, const bool takeSample )
614 {
615  //release mouse and keyboard, and reset cursor
616  releaseMouse();
617  releaseKeyboard();
618  unsetCursor();
619  setMouseTracking( false );
620  mPickingColor = false;
621 
622  if ( !takeSample )
623  {
624  //not sampling color, nothing more to do
625  return;
626  }
627 
628  //grab snapshot of pixel under mouse cursor
629  QColor snappedColor = sampleColor( eventPos );
630  mSamplePreview->setColor( snappedColor );
631  mColorPreview->setColor( snappedColor, true );
632 }
633 
635 {
636  if ( !color.isValid() )
637  {
638  return;
639  }
640 
641  QColor fixedColor = QColor( color );
642  if ( !mAllowAlpha )
643  {
644  //opacity disallowed, so don't permit transparent colors
645  fixedColor.setAlpha( 255 );
646  }
647  QList<QgsColorWidget *> colorWidgets = this->findChildren<QgsColorWidget *>();
648  Q_FOREACH ( QgsColorWidget *widget, colorWidgets )
649  {
650  if ( widget == mSamplePreview )
651  {
652  continue;
653  }
654  widget->blockSignals( true );
655  widget->setColor( fixedColor );
656  widget->blockSignals( false );
657  }
658  emit currentColorChanged( fixedColor );
659 }
660 
662 {
663  mOldColorLabel->setVisible( color.isValid() );
664  mColorPreview->setColor2( color );
665 }
666 
668 {
669  if ( mPickingColor )
670  {
671  //don't show dialog if in color picker mode
672  e->accept();
673  return;
674  }
675 
676  QWidget::mousePressEvent( e );
677 }
678 
679 QColor QgsCompoundColorWidget::averageColor( const QImage &image ) const
680 {
681  QRgb tmpRgb;
682  int colorCount = 0;
683  int sumRed = 0;
684  int sumBlue = 0;
685  int sumGreen = 0;
686  //scan through image and sum rgb components
687  for ( int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
688  {
689  QRgb *scanLine = ( QRgb * )image.constScanLine( heightIndex );
690  for ( int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
691  {
692  tmpRgb = scanLine[widthIndex];
693  sumRed += qRed( tmpRgb );
694  sumBlue += qBlue( tmpRgb );
695  sumGreen += qGreen( tmpRgb );
696  colorCount++;
697  }
698  }
699  //calculate average components as floats
700  double avgRed = ( double )sumRed / ( 255.0 * colorCount );
701  double avgGreen = ( double )sumGreen / ( 255.0 * colorCount );
702  double avgBlue = ( double )sumBlue / ( 255.0 * colorCount );
703 
704  //create a new color representing the average
705  return QColor::fromRgbF( avgRed, avgGreen, avgBlue );
706 }
707 
708 QColor QgsCompoundColorWidget::sampleColor( QPoint point ) const
709 {
710  int sampleRadius = mSpinBoxRadius->value() - 1;
711  QScreen *screen = findScreenAt( point );
712  if ( ! screen )
713  {
714  return QColor();
715  }
716  QPixmap snappedPixmap = screen->grabWindow( QApplication::desktop()->winId(),
717  point.x() - sampleRadius,
718  point.y() - sampleRadius,
719  1 + sampleRadius * 2,
720  1 + sampleRadius * 2 );
721  QImage snappedImage = snappedPixmap.toImage();
722  //scan all pixels and take average color
723  return averageColor( snappedImage );
724 }
725 
727 {
728  if ( mPickingColor )
729  {
730  //currently in color picker mode
731  //sample color under cursor update preview widget to give feedback to user
732  QColor hoverColor = sampleColor( e->globalPos() );
733  mSamplePreview->setColor( hoverColor );
734 
735  e->accept();
736  return;
737  }
738 
739  QWidget::mouseMoveEvent( e );
740 }
741 
743 {
744  if ( mPickingColor )
745  {
746  //end color picking operation by sampling the color under cursor
747  stopPicking( e->globalPos() );
748  e->accept();
749  return;
750  }
751 
752  QWidget::mouseReleaseEvent( e );
753 }
754 
756 {
757  if ( !mPickingColor )
758  {
759  //if not picking a color, use default tool button behavior
761  return;
762  }
763 
764  //cancel picking, sampling the color if space was pressed
765  stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
766 }
767 
768 void QgsCompoundColorWidget::mHueRadio_toggled( bool checked )
769 {
770  if ( checked )
771  {
772  mColorBox->setComponent( QgsColorWidget::Hue );
773  mVerticalRamp->setComponent( QgsColorWidget::Hue );
774  }
775 }
776 
777 void QgsCompoundColorWidget::mSaturationRadio_toggled( bool checked )
778 {
779  if ( checked )
780  {
781  mColorBox->setComponent( QgsColorWidget::Saturation );
782  mVerticalRamp->setComponent( QgsColorWidget::Saturation );
783  }
784 }
785 
786 void QgsCompoundColorWidget::mValueRadio_toggled( bool checked )
787 {
788  if ( checked )
789  {
790  mColorBox->setComponent( QgsColorWidget::Value );
791  mVerticalRamp->setComponent( QgsColorWidget::Value );
792  }
793 }
794 
795 void QgsCompoundColorWidget::mRedRadio_toggled( bool checked )
796 {
797  if ( checked )
798  {
799  mColorBox->setComponent( QgsColorWidget::Red );
800  mVerticalRamp->setComponent( QgsColorWidget::Red );
801  }
802 }
803 
804 void QgsCompoundColorWidget::mGreenRadio_toggled( bool checked )
805 {
806  if ( checked )
807  {
808  mColorBox->setComponent( QgsColorWidget::Green );
809  mVerticalRamp->setComponent( QgsColorWidget::Green );
810  }
811 }
812 
813 void QgsCompoundColorWidget::mBlueRadio_toggled( bool checked )
814 {
815  if ( checked )
816  {
817  mColorBox->setComponent( QgsColorWidget::Blue );
818  mVerticalRamp->setComponent( QgsColorWidget::Blue );
819  }
820 }
821 
822 void QgsCompoundColorWidget::mAddColorToSchemeButton_clicked()
823 {
824  mSchemeList->addColor( mColorPreview->color(), QgsSymbolLayerUtils::colorToName( mColorPreview->color() ) );
825 }
826 
827 void QgsCompoundColorWidget::updateActionsForCurrentScheme()
828 {
829  QgsColorScheme *scheme = mSchemeList->scheme();
830 
831  mActionImportColors->setEnabled( scheme->isEditable() );
832  mActionPasteColors->setEnabled( scheme->isEditable() );
833  mAddColorToSchemeButton->setEnabled( scheme->isEditable() );
834  mRemoveColorsFromSchemeButton->setEnabled( scheme->isEditable() );
835 
836  QgsUserColorScheme *userScheme = dynamic_cast<QgsUserColorScheme *>( scheme );
837  mActionRemovePalette->setEnabled( static_cast< bool >( userScheme ) );
838  if ( userScheme )
839  {
840  mActionShowInButtons->setEnabled( true );
841  whileBlocking( mActionShowInButtons )->setChecked( userScheme->flags() & QgsColorScheme::ShowInColorButtonMenu );
842  }
843  else
844  {
845  whileBlocking( mActionShowInButtons )->setChecked( false );
846  mActionShowInButtons->setEnabled( false );
847  }
848 }
A color scheme which stores its colors in a gpl palette file within the "palettes" subfolder off the ...
void setName(const QString &name)
Sets the name for the scheme.
A base class for interactive color widgets.
void colorSelected(const QColor &color)
Emitted when a color is selected from the list.
Emit colorClicked signal only, no dialog.
Value component of color (based on HSV model)
bool erase()
Erases the associated gpl palette file from the users "palettes" folder.
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user&#39;s home dir.
void removeSelection()
Removes any selected colors from the list.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:57
void mouseMoveEvent(QMouseEvent *e) override
Abstract base class for color schemes.
bool setColors(const QgsNamedColorList &colors, const QString &context=QString(), const QColor &baseColor=QColor()) override
Sets the colors for the scheme.
void colorClicked(const QColor &color)
Emitted when the button is clicked, if the button&#39;s behavior is set to SignalOnly.
QgsColorScheme::SchemeFlags flags() const override
Returns the current flags for the color scheme.
Base class for any widget that can be shown as a inline panel.
void pasteColors()
Pastes colors from clipboard to the list.
Show scheme in color button drop-down menu.
bool removeColorScheme(QgsColorScheme *scheme)
Removes all matching color schemes from the registry.
void mousePressEvent(QMouseEvent *e) override
Green component of color.
QList< QgsColorScheme * > schemes() const
Returns all color schemes in the registry.
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void setColor(const QColor &color)
Sets the current color for the dialog.
void showExportColorsDialog()
Displays a file picker dialog allowing users to export colors from the list into a file...
Red component of color.
static QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok, QString &name)
Imports colors from a gpl GIMP palette file.
void setShowSchemeInMenu(bool show)
Sets whether a this scheme should be shown in color button menus.
void showImportColorsDialog()
Displays a file picker dialog allowing users to import colors into the list from a file...
Alpha component (opacity) of color.
static QString colorToName(const QColor &color)
Returns a friendly display name for a color.
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
Blue component of color.
Hue component of color (based on HSV model)
void keyPressEvent(QKeyEvent *e) override
void addColorScheme(QgsColorScheme *scheme)
Adds a color scheme to the registry.
static void addRecentColor(const QColor &color)
Adds a color to the list of recent colors.
void keyPressEvent(QKeyEvent *event) override
Overridden key press event to handle the esc event on the widget.
Show scheme in color picker dialog.
void setPreviousColor(const QColor &color)
Sets the color to show in an optional "previous color" section.
QColor color() const
Returns the current color for the dialog.
void setAllowOpacity(const bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color dialog.
virtual bool isEditable() const
Returns whether the color scheme is editable.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application&#39;s color scheme registry, used for managing color schemes. ...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:224
Saturation component of color (based on HSV model)
QString schemeName() const override
Gets the name for the color scheme.
void copyColors()
Copies colors from the list to the clipboard.
QgsCompoundColorWidget(QWidget *parent=nullptr, const QColor &color=QColor(), Layout layout=LayoutDefault)
Constructor for QgsCompoundColorWidget.
void currentColorChanged(const QColor &color)
Emitted when the dialog&#39;s color changes.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
void colorChanged(const QColor &color)
Emitted when the widget&#39;s color changes.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
void mouseReleaseEvent(QMouseEvent *e) override
Use a narrower, vertically stacked layout.
virtual void setColor(const QColor &color, const bool emitSignals=false)
Sets the color for the widget.