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