QGIS API Documentation  3.2.0-Bonn (bc43194)
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 
286 {
287  QgsSettings s;
288  QString lastDir = s.value( QStringLiteral( "/UI/lastGplPaletteDir" ), QDir::homePath() ).toString();
289  QString filePath = QFileDialog::getOpenFileName( parent, tr( "Select Palette File" ), lastDir, QStringLiteral( "GPL (*.gpl);;All files (*.*)" ) );
290  if ( parent )
291  parent->activateWindow();
292  if ( filePath.isEmpty() )
293  {
294  return nullptr;
295  }
296 
297  //check if file exists
298  QFileInfo fileInfo( filePath );
299  if ( !fileInfo.exists() || !fileInfo.isReadable() )
300  {
301  QMessageBox::critical( nullptr, tr( "Import Color Palette" ), tr( "Error, file does not exist or is not readable." ) );
302  return nullptr;
303  }
304 
305  s.setValue( QStringLiteral( "/UI/lastGplPaletteDir" ), fileInfo.absolutePath() );
306  QFile file( filePath );
307 
308  QgsNamedColorList importedColors;
309  bool ok = false;
310  QString paletteName;
311  importedColors = QgsSymbolLayerUtils::importColorsFromGpl( file, ok, paletteName );
312  if ( !ok )
313  {
314  QMessageBox::critical( nullptr, tr( "Import Color Palette" ), tr( "Palette file is not readable." ) );
315  return nullptr;
316  }
317 
318  if ( importedColors.length() == 0 )
319  {
320  //no imported colors
321  QMessageBox::critical( nullptr, tr( "Import Color Palette" ), tr( "No colors found in palette file." ) );
322  return nullptr;
323  }
324 
325  //TODO - handle conflicting file names, name for new palette
326  QgsUserColorScheme *importedScheme = new QgsUserColorScheme( fileInfo.fileName() );
327  importedScheme->setName( paletteName );
328  importedScheme->setColors( importedColors );
329 
331  return importedScheme;
332 }
333 
334 void QgsCompoundColorWidget::importPalette()
335 {
336  if ( importUserPaletteFromFile( this ) )
337  {
338  //refresh combobox
339  refreshSchemeComboBox();
340  mSchemeComboBox->setCurrentIndex( mSchemeComboBox->count() - 1 );
341  }
342 }
343 
344 
346 {
347  if ( QMessageBox::question( parent, tr( "Remove Color Palette" ),
348  QString( tr( "Are you sure you want to remove %1?" ) ).arg( scheme->schemeName() ),
349  QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
350  {
351  //user canceled
352  return false;
353  }
354 
355  //remove palette and associated gpl file
356  if ( !scheme->erase() )
357  {
358  //something went wrong
359  return false;
360  }
361 
362  //remove scheme from registry
364  return true;
365 }
366 
367 void QgsCompoundColorWidget::removePalette()
368 {
369  //get current scheme
370  QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorDialog );
371  int prevIndex = mSchemeComboBox->currentIndex();
372  if ( prevIndex >= schemeList.length() )
373  {
374  return;
375  }
376 
377  //make user scheme is a user removable scheme
378  QgsUserColorScheme *userScheme = dynamic_cast<QgsUserColorScheme *>( schemeList.at( prevIndex ) );
379  if ( !userScheme )
380  {
381  return;
382  }
383 
384  if ( removeUserPalette( userScheme, this ) )
385  {
386  refreshSchemeComboBox();
387  prevIndex = std::max( std::min( prevIndex, mSchemeComboBox->count() - 1 ), 0 );
388  mSchemeComboBox->setCurrentIndex( prevIndex );
389  }
390 }
391 
393 {
394  bool ok = false;
395  QString name = QInputDialog::getText( parent, tr( "Create New Palette" ), tr( "Enter a name for the new palette:" ),
396  QLineEdit::Normal, tr( "New palette" ), &ok );
397 
398  if ( !ok || name.isEmpty() )
399  {
400  //user canceled
401  return nullptr;
402  }
403 
404 //generate file name for new palette
405  QDir palettePath( gplFilePath() );
406  QRegExp badChars( "[,^@={}\\[\\]~!?:&*\"|#%<>$\"'();`' /\\\\]" );
407  QString filename = name.simplified().toLower().replace( badChars, QStringLiteral( "_" ) );
408  if ( filename.isEmpty() )
409  {
410  filename = tr( "new_palette" );
411  }
412  QFileInfo destFileInfo( palettePath.filePath( filename + ".gpl" ) );
413  int fileNumber = 1;
414  while ( destFileInfo.exists() )
415  {
416  //try to generate a unique file name
417  destFileInfo = QFileInfo( palettePath.filePath( filename + QStringLiteral( "%1.gpl" ).arg( fileNumber ) ) );
418  fileNumber++;
419  }
420 
421  QgsUserColorScheme *newScheme = new QgsUserColorScheme( destFileInfo.fileName() );
422  newScheme->setName( name );
423 
425  return newScheme;
426 }
427 
428 void QgsCompoundColorWidget::newPalette()
429 {
430  if ( createNewUserPalette( this ) )
431  {
432  //refresh combobox and set new scheme as active
433  refreshSchemeComboBox();
434  mSchemeComboBox->setCurrentIndex( mSchemeComboBox->count() - 1 );
435  }
436 }
437 
438 QString QgsCompoundColorWidget::gplFilePath()
439 {
440  QString palettesDir = QgsApplication::qgisSettingsDirPath() + "palettes";
441 
442  QDir localDir;
443  if ( !localDir.mkpath( palettesDir ) )
444  {
445  return QString();
446  }
447 
448  return palettesDir;
449 }
450 
451 void QgsCompoundColorWidget::schemeIndexChanged( int index )
452 {
453  //save changes to scheme
454  if ( mSchemeList->isDirty() )
455  {
456  mSchemeList->saveColorsToScheme();
457  }
458 
459  //get schemes with ShowInColorDialog set
460  QList<QgsColorScheme *> schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorDialog );
461  if ( index >= schemeList.length() )
462  {
463  return;
464  }
465 
466  QgsColorScheme *scheme = schemeList.at( index );
467  mSchemeList->setScheme( scheme );
468 
469  updateActionsForCurrentScheme();
470 
471  //copy action defaults to disabled
472  mActionCopyColors->setEnabled( false );
473 }
474 
475 void QgsCompoundColorWidget::listSelectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
476 {
477  Q_UNUSED( deselected );
478  mActionCopyColors->setEnabled( selected.length() > 0 );
479 }
480 
481 void QgsCompoundColorWidget::mAddCustomColorButton_clicked()
482 {
483  switch ( mLastCustomColorIndex )
484  {
485  case 0:
486  mSwatchButton1->setColor( mColorPreview->color() );
487  break;
488  case 1:
489  mSwatchButton2->setColor( mColorPreview->color() );
490  break;
491  case 2:
492  mSwatchButton3->setColor( mColorPreview->color() );
493  break;
494  case 3:
495  mSwatchButton4->setColor( mColorPreview->color() );
496  break;
497  case 4:
498  mSwatchButton5->setColor( mColorPreview->color() );
499  break;
500  case 5:
501  mSwatchButton6->setColor( mColorPreview->color() );
502  break;
503  case 6:
504  mSwatchButton7->setColor( mColorPreview->color() );
505  break;
506  case 7:
507  mSwatchButton8->setColor( mColorPreview->color() );
508  break;
509  case 8:
510  mSwatchButton9->setColor( mColorPreview->color() );
511  break;
512  case 9:
513  mSwatchButton10->setColor( mColorPreview->color() );
514  break;
515  case 10:
516  mSwatchButton11->setColor( mColorPreview->color() );
517  break;
518  case 11:
519  mSwatchButton12->setColor( mColorPreview->color() );
520  break;
521  case 12:
522  mSwatchButton13->setColor( mColorPreview->color() );
523  break;
524  case 13:
525  mSwatchButton14->setColor( mColorPreview->color() );
526  break;
527  case 14:
528  mSwatchButton15->setColor( mColorPreview->color() );
529  break;
530  case 15:
531  mSwatchButton16->setColor( mColorPreview->color() );
532  break;
533  }
534  mLastCustomColorIndex++;
535  if ( mLastCustomColorIndex >= 16 )
536  {
537  mLastCustomColorIndex = 0;
538  }
539 }
540 
541 void QgsCompoundColorWidget::mSampleButton_clicked()
542 {
543  //activate picker color
544  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Sampler ) );
545  grabMouse();
546  grabKeyboard();
547  mPickingColor = true;
548  setMouseTracking( true );
549 }
550 
551 void QgsCompoundColorWidget::mTabWidget_currentChanged( int index )
552 {
553  //disable radio buttons if not using the first tab, as they have no meaning for other tabs
554  bool enabled = index == 0;
555  mRedRadio->setEnabled( enabled );
556  mBlueRadio->setEnabled( enabled );
557  mGreenRadio->setEnabled( enabled );
558  mHueRadio->setEnabled( enabled );
559  mSaturationRadio->setEnabled( enabled );
560  mValueRadio->setEnabled( enabled );
561 }
562 
563 void QgsCompoundColorWidget::mActionShowInButtons_toggled( bool state )
564 {
565  QgsUserColorScheme *scheme = dynamic_cast< QgsUserColorScheme * >( mSchemeList->scheme() );
566  if ( scheme )
567  {
568  scheme->setShowSchemeInMenu( state );
569  }
570 }
571 
572 QScreen *QgsCompoundColorWidget::findScreenAt( QPoint pos )
573 {
574  for ( QScreen *screen : QGuiApplication::screens() )
575  {
576  if ( screen->geometry().contains( pos ) )
577  {
578  return screen;
579  }
580  }
581  return nullptr;
582 }
583 
584 void QgsCompoundColorWidget::saveSettings()
585 {
586  //save changes to scheme
587  if ( mSchemeList->isDirty() )
588  {
589  mSchemeList->saveColorsToScheme();
590  }
591 
592  QgsSettings settings;
593 
594  //record active component
595  int activeRadio = 0;
596  if ( mHueRadio->isChecked() )
597  activeRadio = 0;
598  if ( mSaturationRadio->isChecked() )
599  activeRadio = 1;
600  if ( mValueRadio->isChecked() )
601  activeRadio = 2;
602  if ( mRedRadio->isChecked() )
603  activeRadio = 3;
604  if ( mGreenRadio->isChecked() )
605  activeRadio = 4;
606  if ( mBlueRadio->isChecked() )
607  activeRadio = 5;
608  settings.setValue( QStringLiteral( "Windows/ColorDialog/activeComponent" ), activeRadio );
609 
610  //record current scheme
611  settings.setValue( QStringLiteral( "Windows/ColorDialog/activeScheme" ), mSchemeComboBox->currentIndex() );
612 
613  //record current tab
614  settings.setValue( QStringLiteral( "Windows/ColorDialog/activeTab" ), mTabWidget->currentIndex() );
615 
616  //record custom colors
617  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor1" ), QVariant( mSwatchButton1->color() ) );
618  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor2" ), QVariant( mSwatchButton2->color() ) );
619  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor3" ), QVariant( mSwatchButton3->color() ) );
620  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor4" ), QVariant( mSwatchButton4->color() ) );
621  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor5" ), QVariant( mSwatchButton5->color() ) );
622  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor6" ), QVariant( mSwatchButton6->color() ) );
623  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor7" ), QVariant( mSwatchButton7->color() ) );
624  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor8" ), QVariant( mSwatchButton8->color() ) );
625  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor9" ), QVariant( mSwatchButton9->color() ) );
626  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor10" ), QVariant( mSwatchButton10->color() ) );
627  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor11" ), QVariant( mSwatchButton11->color() ) );
628  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor12" ), QVariant( mSwatchButton12->color() ) );
629  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor13" ), QVariant( mSwatchButton13->color() ) );
630  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor14" ), QVariant( mSwatchButton14->color() ) );
631  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor15" ), QVariant( mSwatchButton15->color() ) );
632  settings.setValue( QStringLiteral( "Windows/ColorDialog/customColor16" ), QVariant( mSwatchButton16->color() ) );
633 
634  //sample radius
635  settings.setValue( QStringLiteral( "Windows/ColorDialog/sampleRadius" ), mSpinBoxRadius->value() );
636 }
637 
638 void QgsCompoundColorWidget::stopPicking( QPoint eventPos, const bool takeSample )
639 {
640  //release mouse and keyboard, and reset cursor
641  releaseMouse();
642  releaseKeyboard();
643  unsetCursor();
644  setMouseTracking( false );
645  mPickingColor = false;
646 
647  if ( !takeSample )
648  {
649  //not sampling color, nothing more to do
650  return;
651  }
652 
653  //grab snapshot of pixel under mouse cursor
654  QColor snappedColor = sampleColor( eventPos );
655  mSamplePreview->setColor( snappedColor );
656  mColorPreview->setColor( snappedColor, true );
657 }
658 
660 {
661  if ( !color.isValid() )
662  {
663  return;
664  }
665 
666  QColor fixedColor = QColor( color );
667  if ( !mAllowAlpha )
668  {
669  //opacity disallowed, so don't permit transparent colors
670  fixedColor.setAlpha( 255 );
671  }
672  QList<QgsColorWidget *> colorWidgets = this->findChildren<QgsColorWidget *>();
673  Q_FOREACH ( QgsColorWidget *widget, colorWidgets )
674  {
675  if ( widget == mSamplePreview )
676  {
677  continue;
678  }
679  widget->blockSignals( true );
680  widget->setColor( fixedColor );
681  widget->blockSignals( false );
682  }
683  emit currentColorChanged( fixedColor );
684 }
685 
687 {
688  mOldColorLabel->setVisible( color.isValid() );
689  mColorPreview->setColor2( color );
690 }
691 
693 {
694  if ( mPickingColor )
695  {
696  //don't show dialog if in color picker mode
697  e->accept();
698  return;
699  }
700 
701  QWidget::mousePressEvent( e );
702 }
703 
704 QColor QgsCompoundColorWidget::averageColor( const QImage &image ) const
705 {
706  QRgb tmpRgb;
707  int colorCount = 0;
708  int sumRed = 0;
709  int sumBlue = 0;
710  int sumGreen = 0;
711  //scan through image and sum rgb components
712  for ( int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
713  {
714  QRgb *scanLine = ( QRgb * )image.constScanLine( heightIndex );
715  for ( int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
716  {
717  tmpRgb = scanLine[widthIndex];
718  sumRed += qRed( tmpRgb );
719  sumBlue += qBlue( tmpRgb );
720  sumGreen += qGreen( tmpRgb );
721  colorCount++;
722  }
723  }
724  //calculate average components as floats
725  double avgRed = ( double )sumRed / ( 255.0 * colorCount );
726  double avgGreen = ( double )sumGreen / ( 255.0 * colorCount );
727  double avgBlue = ( double )sumBlue / ( 255.0 * colorCount );
728 
729  //create a new color representing the average
730  return QColor::fromRgbF( avgRed, avgGreen, avgBlue );
731 }
732 
733 QColor QgsCompoundColorWidget::sampleColor( QPoint point ) const
734 {
735  int sampleRadius = mSpinBoxRadius->value() - 1;
736  QScreen *screen = findScreenAt( point );
737  if ( ! screen )
738  {
739  return QColor();
740  }
741  QPixmap snappedPixmap = screen->grabWindow( QApplication::desktop()->winId(),
742  point.x() - sampleRadius,
743  point.y() - sampleRadius,
744  1 + sampleRadius * 2,
745  1 + sampleRadius * 2 );
746  QImage snappedImage = snappedPixmap.toImage();
747  //scan all pixels and take average color
748  return averageColor( snappedImage );
749 }
750 
752 {
753  if ( mPickingColor )
754  {
755  //currently in color picker mode
756  //sample color under cursor update preview widget to give feedback to user
757  QColor hoverColor = sampleColor( e->globalPos() );
758  mSamplePreview->setColor( hoverColor );
759 
760  e->accept();
761  return;
762  }
763 
764  QWidget::mouseMoveEvent( e );
765 }
766 
768 {
769  if ( mPickingColor )
770  {
771  //end color picking operation by sampling the color under cursor
772  stopPicking( e->globalPos() );
773  e->accept();
774  return;
775  }
776 
777  QWidget::mouseReleaseEvent( e );
778 }
779 
781 {
782  if ( !mPickingColor )
783  {
784  //if not picking a color, use default tool button behavior
786  return;
787  }
788 
789  //cancel picking, sampling the color if space was pressed
790  stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
791 }
792 
793 void QgsCompoundColorWidget::mHueRadio_toggled( bool checked )
794 {
795  if ( checked )
796  {
797  mColorBox->setComponent( QgsColorWidget::Hue );
798  mVerticalRamp->setComponent( QgsColorWidget::Hue );
799  }
800 }
801 
802 void QgsCompoundColorWidget::mSaturationRadio_toggled( bool checked )
803 {
804  if ( checked )
805  {
806  mColorBox->setComponent( QgsColorWidget::Saturation );
807  mVerticalRamp->setComponent( QgsColorWidget::Saturation );
808  }
809 }
810 
811 void QgsCompoundColorWidget::mValueRadio_toggled( bool checked )
812 {
813  if ( checked )
814  {
815  mColorBox->setComponent( QgsColorWidget::Value );
816  mVerticalRamp->setComponent( QgsColorWidget::Value );
817  }
818 }
819 
820 void QgsCompoundColorWidget::mRedRadio_toggled( bool checked )
821 {
822  if ( checked )
823  {
824  mColorBox->setComponent( QgsColorWidget::Red );
825  mVerticalRamp->setComponent( QgsColorWidget::Red );
826  }
827 }
828 
829 void QgsCompoundColorWidget::mGreenRadio_toggled( bool checked )
830 {
831  if ( checked )
832  {
833  mColorBox->setComponent( QgsColorWidget::Green );
834  mVerticalRamp->setComponent( QgsColorWidget::Green );
835  }
836 }
837 
838 void QgsCompoundColorWidget::mBlueRadio_toggled( bool checked )
839 {
840  if ( checked )
841  {
842  mColorBox->setComponent( QgsColorWidget::Blue );
843  mVerticalRamp->setComponent( QgsColorWidget::Blue );
844  }
845 }
846 
847 void QgsCompoundColorWidget::mAddColorToSchemeButton_clicked()
848 {
849  mSchemeList->addColor( mColorPreview->color(), QgsSymbolLayerUtils::colorToName( mColorPreview->color() ) );
850 }
851 
852 void QgsCompoundColorWidget::updateActionsForCurrentScheme()
853 {
854  QgsColorScheme *scheme = mSchemeList->scheme();
855 
856  mActionImportColors->setEnabled( scheme->isEditable() );
857  mActionPasteColors->setEnabled( scheme->isEditable() );
858  mAddColorToSchemeButton->setEnabled( scheme->isEditable() );
859  mRemoveColorsFromSchemeButton->setEnabled( scheme->isEditable() );
860 
861  QgsUserColorScheme *userScheme = dynamic_cast<QgsUserColorScheme *>( scheme );
862  mActionRemovePalette->setEnabled( static_cast< bool >( userScheme ) );
863  if ( userScheme )
864  {
865  mActionShowInButtons->setEnabled( true );
866  whileBlocking( mActionShowInButtons )->setChecked( userScheme->flags() & QgsColorScheme::ShowInColorButtonMenu );
867  }
868  else
869  {
870  whileBlocking( mActionShowInButtons )->setChecked( false );
871  mActionShowInButtons->setEnabled( false );
872  }
873 }
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:58
virtual void setColor(const QColor &color, bool emitSignals=false)
Sets the color for the widget.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
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.
static QgsUserColorScheme * importUserPaletteFromFile(QWidget *parent)
Triggers a user prompt for importing a new color scheme from an existing GPL file.
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 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.
static bool removeUserPalette(QgsUserColorScheme *scheme, QWidget *parent)
Triggers a user prompt for removing an existing user color scheme.
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 setAllowOpacity(bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color dialog.
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.
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)
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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.
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.
static QgsUserColorScheme * createNewUserPalette(QWidget *parent)
Triggers a user prompt for creating a new user color scheme.