QGIS API Documentation 4.3.0-Master (b46232e4f9a)
Loading...
Searching...
No Matches
qgscolorschemelist.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscolorschemelist.cpp
3 ----------------------
4 Date : August 2014
5 Copyright : (C) 2014 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 "qgscolorschemelist.h"
17
18#include "qgsapplication.h"
19#include "qgscolordialog.h"
20#include "qgslogger.h"
21#include "qgspainting.h"
22#include "qgssettings.h"
23#include "qgssymbollayerutils.h"
24
25#include <QClipboard>
26#include <QColorDialog>
27#include <QFileDialog>
28#include <QKeyEvent>
29#include <QMessageBox>
30#include <QMimeData>
31#include <QPainter>
32#include <QString>
33
34#include "moc_qgscolorschemelist.cpp"
35
36using namespace Qt::StringLiterals;
37
38#ifdef ENABLE_MODELTEST
39#include "modeltest.h"
40#endif
41
42QgsColorSchemeList::QgsColorSchemeList( QWidget *parent, QgsColorScheme *scheme, const QString &context, const QColor &baseColor )
43 : QTreeView( parent )
44 , mScheme( scheme )
45{
46 mModel = new QgsColorSchemeModel( scheme, context, baseColor, this );
47#ifdef ENABLE_MODELTEST
48 new ModelTest( mModel, this );
49#endif
50 setModel( mModel );
51
52 mSwatchDelegate = new QgsColorSwatchDelegate( this );
53 setItemDelegateForColumn( 0, mSwatchDelegate );
54
55 setRootIsDecorated( false );
56 setSelectionMode( QAbstractItemView::ExtendedSelection );
57 setSelectionBehavior( QAbstractItemView::SelectRows );
58 setDragEnabled( true );
59 setAcceptDrops( true );
60 setDragDropMode( QTreeView::DragDrop );
61 setDropIndicatorShown( true );
62 setDefaultDropAction( Qt::CopyAction );
63}
64
65void QgsColorSchemeList::setScheme( QgsColorScheme *scheme, const QString &context, const QColor &baseColor )
66{
67 mScheme = scheme;
68 mModel->setScheme( scheme, context, baseColor );
69}
70
72{
73 if ( !mScheme || !mScheme->isEditable() )
74 {
75 return false;
76 }
77
78 mScheme->setColors( mModel->colors(), mModel->context(), mModel->baseColor() );
79 return true;
80}
81
83{
84 QList<int> rows;
85 const auto constSelectedIndexes = selectedIndexes();
86 for ( const QModelIndex &index : constSelectedIndexes )
87 {
88 rows << index.row();
89 }
90 //remove duplicates
91 QList<int> rowsToRemove = qgis::setToList( qgis::listToSet( rows ) );
92
93 //remove rows in descending order
94 std::sort( rowsToRemove.begin(), rowsToRemove.end(), std::greater<int>() );
95 const auto constRowsToRemove = rowsToRemove;
96 for ( const int row : constRowsToRemove )
97 {
98 mModel->removeRow( row );
99 }
100}
101
102void QgsColorSchemeList::addColor( const QColor &color, const QString &label, bool allowDuplicate )
103{
104 mModel->addColor( color, label, allowDuplicate );
105}
106
108{
109 const QgsNamedColorList pastedColors = QgsSymbolLayerUtils::colorListFromMimeData( QApplication::clipboard()->mimeData() );
110
111 if ( pastedColors.length() == 0 )
112 {
113 //no pasted colors
114 return;
115 }
116
117 //insert pasted colors
118 QgsNamedColorList::const_iterator colorIt = pastedColors.constBegin();
119 for ( ; colorIt != pastedColors.constEnd(); ++colorIt )
120 {
121 mModel->addColor( ( *colorIt ).first, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
122 }
123}
124
126{
127 QList<int> rows;
128 const auto constSelectedIndexes = selectedIndexes();
129 for ( const QModelIndex &index : constSelectedIndexes )
130 {
131 rows << index.row();
132 }
133 //remove duplicates
134 const QList<int> rowsToCopy = qgis::setToList( qgis::listToSet( rows ) );
135
136 QgsNamedColorList colorsToCopy;
137 const auto constRowsToCopy = rowsToCopy;
138 for ( const int row : constRowsToCopy )
139 {
140 colorsToCopy << mModel->colors().at( row );
141 }
142
143 //copy colors
144 std::unique_ptr<QMimeData> mimeData = QgsSymbolLayerUtils::colorListToMimeData( colorsToCopy );
145 QApplication::clipboard()->setMimeData( mimeData.release() );
146}
147
149{
150 QgsSettings s;
151 const QString lastDir = s.value( u"/UI/lastGplPaletteDir"_s, QDir::homePath() ).toString();
152 const QString filePath = QFileDialog::getOpenFileName( this, tr( "Select Palette File" ), lastDir, u"GPL (*.gpl);;All files (*.*)"_s );
153 activateWindow();
154 if ( filePath.isEmpty() )
155 {
156 return;
157 }
158
159 //check if file exists
160 const QFileInfo fileInfo( filePath );
161 if ( !fileInfo.exists() || !fileInfo.isReadable() )
162 {
163 QMessageBox::critical( nullptr, tr( "Import Colors" ), tr( "Error, file does not exist or is not readable." ) );
164 return;
165 }
166
167 s.setValue( u"/UI/lastGplPaletteDir"_s, fileInfo.absolutePath() );
168 QFile file( filePath );
169 const bool importOk = importColorsFromGpl( file );
170 if ( !importOk )
171 {
172 QMessageBox::critical( nullptr, tr( "Import Colors" ), tr( "Error, no colors found in palette file." ) );
173 return;
174 }
175}
176
178{
179 QgsSettings s;
180 const QString lastDir = s.value( u"/UI/lastGplPaletteDir"_s, QDir::homePath() ).toString();
181 QString fileName = QFileDialog::getSaveFileName( this, tr( "Palette file" ), lastDir, u"GPL (*.gpl)"_s );
182 activateWindow();
183 if ( fileName.isEmpty() )
184 {
185 return;
186 }
187
188 // ensure filename contains extension
189 if ( !fileName.endsWith( ".gpl"_L1, Qt::CaseInsensitive ) )
190 {
191 fileName += ".gpl"_L1;
192 }
193
194 const QFileInfo fileInfo( fileName );
195 s.setValue( u"/UI/lastGplPaletteDir"_s, fileInfo.absolutePath() );
196
197 QFile file( fileName );
198 const bool exportOk = exportColorsToGpl( file );
199 if ( !exportOk )
200 {
201 QMessageBox::critical( nullptr, tr( "Export Colors" ), tr( "Error writing palette file." ) );
202 return;
203 }
204}
205
206void QgsColorSchemeList::keyPressEvent( QKeyEvent *event )
207{
208 //listen out for delete/backspace presses and remove selected colors
209 if ( ( event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete ) )
210 {
211 QList<int> rows;
212 const auto constSelectedIndexes = selectedIndexes();
213 for ( const QModelIndex &index : constSelectedIndexes )
214 {
215 rows << index.row();
216 }
217 //remove duplicates
218 QList<int> rowsToRemove = qgis::setToList( qgis::listToSet( rows ) );
219
220 //remove rows in descending order
221 std::sort( rowsToRemove.begin(), rowsToRemove.end(), std::greater<int>() );
222 const auto constRowsToRemove = rowsToRemove;
223 for ( const int row : constRowsToRemove )
224 {
225 mModel->removeRow( row );
226 }
227 return;
228 }
229
230 QTreeView::keyPressEvent( event );
231}
232
233void QgsColorSchemeList::mousePressEvent( QMouseEvent *event )
234{
235 if ( event->button() == Qt::LeftButton )
236 {
237 //record press start position
238 mDragStartPosition = event->pos();
239 }
240 QTreeView::mousePressEvent( event );
241}
242
244{
245 if ( ( event->button() == Qt::LeftButton ) && ( event->pos() - mDragStartPosition ).manhattanLength() <= QApplication::startDragDistance() )
246 {
247 //just a click, not a drag
248
249 //if only one item is selected, emit color changed signal
250 //(if multiple are selected, user probably was interacting with color list rather than trying to pick a color)
251 if ( selectedIndexes().length() == mModel->columnCount() )
252 {
253 const QModelIndex selectedColor = selectedIndexes().at( 0 );
254 emit colorSelected( mModel->colors().at( selectedColor.row() ).first );
255 }
256 }
257
258 QTreeView::mouseReleaseEvent( event );
259}
260
262{
263 QgsNamedColorList importedColors;
264 bool ok = false;
265 QString name;
266 importedColors = QgsSymbolLayerUtils::importColorsFromGpl( file, ok, name );
267 if ( !ok )
268 {
269 return false;
270 }
271
272 if ( importedColors.length() == 0 )
273 {
274 //no imported colors
275 return false;
276 }
277
278 //insert imported colors
279 QgsNamedColorList::const_iterator colorIt = importedColors.constBegin();
280 for ( ; colorIt != importedColors.constEnd(); ++colorIt )
281 {
282 mModel->addColor( ( *colorIt ).first, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
283 }
284
285 return true;
286}
287
289{
290 return QgsSymbolLayerUtils::saveColorsToGpl( file, QString(), mModel->colors() );
291}
292
294{
295 if ( !mModel )
296 {
297 return false;
298 }
299
300 return mModel->isDirty();
301}
302
304{
305 return mScheme;
306}
307
308//
309// QgsColorSchemeModel
310//
311
312QgsColorSchemeModel::QgsColorSchemeModel( QgsColorScheme *scheme, const QString &context, const QColor &baseColor, QObject *parent )
313 : QAbstractItemModel( parent )
314 , mScheme( scheme )
315 , mContext( context )
316 , mBaseColor( baseColor )
317{
318 if ( scheme )
319 {
320 mColors = scheme->fetchColors( context, baseColor );
321 }
322}
323
324QModelIndex QgsColorSchemeModel::index( int row, int column, const QModelIndex &parent ) const
325{
326 if ( column < 0 || column >= columnCount() )
327 {
328 //column out of bounds
329 return QModelIndex();
330 }
331
332 if ( !parent.isValid() && row >= 0 && row < mColors.size() )
333 {
334 //return an index for the color item at this position
335 return createIndex( row, column );
336 }
337
338 //only top level supported
339 return QModelIndex();
340}
341
342QModelIndex QgsColorSchemeModel::parent( const QModelIndex &index ) const
343{
344 Q_UNUSED( index )
345
346 //all items are top level
347 return QModelIndex();
348}
349
350int QgsColorSchemeModel::rowCount( const QModelIndex &parent ) const
351{
352 if ( !parent.isValid() )
353 {
354 return mColors.size();
355 }
356 else
357 {
358 //no children
359 return 0;
360 }
361}
362
363int QgsColorSchemeModel::columnCount( const QModelIndex &parent ) const
364{
365 Q_UNUSED( parent )
366 return 2;
367}
368
369QVariant QgsColorSchemeModel::data( const QModelIndex &index, int role ) const
370{
371 if ( !index.isValid() )
372 return QVariant();
373
374 const QPair<QColor, QString> namedColor = mColors.at( index.row() );
375 switch ( role )
376 {
377 case Qt::DisplayRole:
378 case Qt::EditRole:
379 switch ( index.column() )
380 {
381 case ColorSwatch:
382 return namedColor.first;
383 case ColorLabel:
384 return namedColor.second;
385 default:
386 return QVariant();
387 }
388
389 case Qt::TextAlignmentRole:
390 return static_cast<Qt::Alignment::Int>( Qt::AlignLeft | Qt::AlignVCenter );
391
392 default:
393 return QVariant();
394 }
395}
396
397Qt::ItemFlags QgsColorSchemeModel::flags( const QModelIndex &index ) const
398{
399 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
400
401 if ( !index.isValid() )
402 {
403 return flags | Qt::ItemIsDropEnabled;
404 }
405
406 switch ( index.column() )
407 {
408 case ColorSwatch:
409 case ColorLabel:
410 if ( mScheme && mScheme->isEditable() )
411 {
412 flags = flags | Qt::ItemIsEditable;
413 }
414 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
415 default:
416 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
417 }
418}
419
420bool QgsColorSchemeModel::setData( const QModelIndex &index, const QVariant &value, int role )
421{
422 Q_UNUSED( role )
423
424 if ( !mScheme || !mScheme->isEditable() )
425 return false;
426
427 if ( !index.isValid() )
428 return false;
429
430 if ( index.row() >= mColors.length() )
431 return false;
432
433 switch ( index.column() )
434 {
435 case ColorSwatch:
436 mColors[index.row()].first = value.value<QColor>();
437 emit dataChanged( index, index );
438 mIsDirty = true;
439 return true;
440
441 case ColorLabel:
442 mColors[index.row()].second = value.toString();
443 emit dataChanged( index, index );
444 mIsDirty = true;
445 return true;
446
447 default:
448 return false;
449 }
450}
451
452QVariant QgsColorSchemeModel::headerData( int section, Qt::Orientation orientation, int role ) const
453{
454 switch ( role )
455 {
456 case Qt::DisplayRole:
457 {
458 switch ( section )
459 {
460 case ColorSwatch:
461 return tr( "Color" );
462 case ColorLabel:
463 return tr( "Label" );
464 default:
465 return QVariant();
466 }
467 }
468
469 case Qt::TextAlignmentRole:
470 switch ( section )
471 {
472 case ColorSwatch:
473 return static_cast<Qt::Alignment::Int>( Qt::AlignHCenter | Qt::AlignVCenter );
474 case ColorLabel:
475 return static_cast<Qt::Alignment::Int>( Qt::AlignLeft | Qt::AlignVCenter );
476 default:
477 return QVariant();
478 }
479 default:
480 return QAbstractItemModel::headerData( section, orientation, role );
481 }
482}
483
485{
486 if ( mScheme && mScheme->isEditable() )
487 {
488 return Qt::CopyAction | Qt::MoveAction;
489 }
490 else
491 {
492 return Qt::CopyAction;
493 }
494}
495
497{
498 if ( !mScheme || !mScheme->isEditable() )
499 {
500 return QStringList();
501 }
502
503 QStringList types;
504 types << u"text/xml"_s;
505 types << u"text/plain"_s;
506 types << u"application/x-color"_s;
507 types << u"application/x-colorobject-list"_s;
508 return types;
509}
510
511QMimeData *QgsColorSchemeModel::mimeData( const QModelIndexList &indexes ) const
512{
513 QgsNamedColorList colorList;
514
515 QModelIndexList::const_iterator indexIt = indexes.constBegin();
516 for ( ; indexIt != indexes.constEnd(); ++indexIt )
517 {
518 if ( ( *indexIt ).column() > 0 )
519 continue;
520
521 colorList << qMakePair( mColors[( *indexIt ).row()].first, mColors[( *indexIt ).row()].second );
522 }
523
524 std::unique_ptr<QMimeData> mimeData = QgsSymbolLayerUtils::colorListToMimeData( colorList );
525 return mimeData.release();
526}
527
528bool QgsColorSchemeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
529{
530 Q_UNUSED( column )
531
532 if ( !mScheme || !mScheme->isEditable() )
533 {
534 return false;
535 }
536
537 if ( action == Qt::IgnoreAction )
538 {
539 return true;
540 }
541
542 if ( parent.isValid() )
543 {
544 return false;
545 }
546
547 int beginRow = row != -1 ? row : rowCount( QModelIndex() );
549
550 if ( droppedColors.length() == 0 )
551 {
552 //no dropped colors
553 return false;
554 }
555
556 //any existing colors? if so, remove them first
557 QgsNamedColorList::const_iterator colorIt = droppedColors.constBegin();
558 for ( ; colorIt != droppedColors.constEnd(); ++colorIt )
559 {
560 //dest color
561 const QPair<QColor, QString> color = qMakePair( ( *colorIt ).first, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
562 //if color already exists, remove it
563 const int existingIndex = mColors.indexOf( color );
564 if ( existingIndex >= 0 )
565 {
566 if ( existingIndex < beginRow )
567 {
568 //color is before destination row, so decrease destination row to account for removal
569 beginRow--;
570 }
571
572 beginRemoveRows( parent, existingIndex, existingIndex );
573 mColors.removeAt( existingIndex );
574 endRemoveRows();
575 }
576 }
577
578 //insert dropped colors
579 insertRows( beginRow, droppedColors.length(), QModelIndex() );
580 colorIt = droppedColors.constBegin();
581 for ( ; colorIt != droppedColors.constEnd(); ++colorIt )
582 {
583 const QModelIndex colorIdx = index( beginRow, 0, QModelIndex() );
584 setData( colorIdx, QVariant( ( *colorIt ).first ) );
585 const QModelIndex labelIdx = index( beginRow, 1, QModelIndex() );
586 setData( labelIdx, !( *colorIt ).second.isEmpty() ? ( *colorIt ).second : QgsSymbolLayerUtils::colorToName( ( *colorIt ).first ) );
587 beginRow++;
588 }
589 mIsDirty = true;
590
591 return true;
592}
593
594void QgsColorSchemeModel::setScheme( QgsColorScheme *scheme, const QString &context, const QColor &baseColor )
595{
596 mScheme = scheme;
597 mContext = context;
598 mBaseColor = baseColor;
599 mIsDirty = false;
600 beginResetModel();
601 mColors = scheme->fetchColors( mContext, mBaseColor );
602 endResetModel();
603}
604
605bool QgsColorSchemeModel::removeRows( int row, int count, const QModelIndex &parent )
606{
607 if ( !mScheme || !mScheme->isEditable() )
608 {
609 return false;
610 }
611
612 if ( parent.isValid() )
613 {
614 return false;
615 }
616
617 if ( row >= mColors.count() )
618 {
619 return false;
620 }
621
622 for ( int i = row + count - 1; i >= row; --i )
623 {
624 beginRemoveRows( parent, i, i );
625 mColors.removeAt( i );
626 endRemoveRows();
627 }
628
629 mIsDirty = true;
630 return true;
631}
632
633bool QgsColorSchemeModel::insertRows( int row, int count, const QModelIndex &parent )
634{
635 Q_UNUSED( parent )
636
637 if ( !mScheme || !mScheme->isEditable() )
638 {
639 return false;
640 }
641
642 beginInsertRows( QModelIndex(), row, row + count - 1 );
643 for ( int i = row; i < row + count; ++i )
644 {
645 const QPair<QColor, QString> newColor;
646 mColors.insert( i, newColor );
647 }
648 endInsertRows();
649 mIsDirty = true;
650 return true;
651}
652
653void QgsColorSchemeModel::addColor( const QColor &color, const QString &label, bool allowDuplicate )
654{
655 if ( !mScheme || !mScheme->isEditable() )
656 {
657 return;
658 }
659
660 if ( !allowDuplicate )
661 {
662 //matches existing color? if so, remove it first
663 const QPair<QColor, QString> newColor = qMakePair( color, !label.isEmpty() ? label : QgsSymbolLayerUtils::colorToName( color ) );
664 //if color already exists, remove it
665 const int existingIndex = mColors.indexOf( newColor );
666 if ( existingIndex >= 0 )
667 {
668 beginRemoveRows( QModelIndex(), existingIndex, existingIndex );
669 mColors.removeAt( existingIndex );
670 endRemoveRows();
671 }
672 }
673
674 const int row = rowCount();
675 insertRow( row );
676 const QModelIndex colorIdx = index( row, 0, QModelIndex() );
677 setData( colorIdx, QVariant( color ) );
678 const QModelIndex labelIdx = index( row, 1, QModelIndex() );
679 setData( labelIdx, QVariant( label ) );
680 mIsDirty = true;
681}
682
683
684//
685// QgsColorSwatchDelegate
686//
688 : QAbstractItemDelegate( parent )
689 , mParent( parent )
690{}
691
692void QgsColorSwatchDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
693{
694 if ( option.state & QStyle::State_Selected )
695 {
696 painter->setPen( QPen( Qt::NoPen ) );
697 if ( option.state & QStyle::State_Active )
698 {
699 painter->setBrush( QBrush( option.widget->palette().highlight() ) );
700 }
701 else
702 {
703 painter->setBrush( QBrush( option.widget->palette().color( QPalette::Inactive, QPalette::Highlight ) ) );
704 }
705 painter->drawRect( option.rect );
706 }
707
708 QColor color = index.model()->data( index, Qt::DisplayRole ).value<QColor>();
709 if ( !color.isValid() )
710 {
711 return;
712 }
713
714 QRect rect = option.rect;
715 const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.horizontalAdvance( 'X' ) * 4;
716
717 const int cornerSize = iconSize / 6;
718 //center it
719 rect.setLeft( option.rect.center().x() - iconSize / 2 );
720
721 rect.setSize( QSize( iconSize, iconSize ) );
722 rect.adjust( 0, 1, 0, 1 );
723 //create an icon pixmap
724 const QgsScopedQPainterState painterState( painter );
725 painter->setRenderHint( QPainter::Antialiasing );
726 painter->setPen( Qt::NoPen );
727 if ( color.alpha() < 255 )
728 {
729 //start with checkboard pattern
730 const QBrush checkBrush = QBrush( transparentBackground() );
731 painter->setBrush( checkBrush );
732 painter->drawRoundedRect( rect, cornerSize, cornerSize );
733 //draw semi-transparent color on top
734 painter->setBrush( color );
735 painter->drawRoundedRect( rect, cornerSize, cornerSize );
736 //draw fully opaque color on the left side
737 const QRectF clipRect( rect.left(), rect.top(), static_cast<qreal>( rect.width() ) / 2.0, rect.height() );
738 painter->setClipRect( clipRect );
739 color.setAlpha( 255 );
740 painter->setBrush( color );
741 painter->drawRoundedRect( rect, cornerSize, cornerSize );
742 }
743 else
744 {
745 painter->setBrush( color );
746 painter->drawRoundedRect( rect, cornerSize, cornerSize );
747 }
748}
749
750QPixmap QgsColorSwatchDelegate::transparentBackground() const
751{
752 static QPixmap sTranspBkgrd;
753
754 if ( sTranspBkgrd.isNull() )
755 sTranspBkgrd = QgsApplication::getThemePixmap( u"/transp-background_8x8.png"_s );
756
757 return sTranspBkgrd;
758}
759
760QSize QgsColorSwatchDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const
761{
762 Q_UNUSED( index )
763
764 const int iconSize = Qgis::UI_SCALE_FACTOR * option.fontMetrics.horizontalAdvance( 'X' ) * 4;
765 return QSize( iconSize, iconSize * 32 / 30.0 );
766}
767
768bool QgsColorSwatchDelegate::editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
769{
770 Q_UNUSED( option )
771 if ( event->type() == QEvent::MouseButtonDblClick )
772 {
773 if ( !index.model()->flags( index ).testFlag( Qt::ItemIsEditable ) )
774 {
775 //item not editable
776 return false;
777 }
778
779 const QColor color = index.model()->data( index, Qt::DisplayRole ).value<QColor>();
780
781 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( qobject_cast<QWidget *>( parent() ) );
782 if ( panel && panel->dockMode() )
783 {
785 colorWidget->setPanelTitle( tr( "Select Color" ) );
786 colorWidget->setAllowOpacity( true );
787 colorWidget->setProperty( "index", index );
788 connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, &QgsColorSwatchDelegate::colorChanged );
789 panel->openPanel( colorWidget );
790 return true;
791 }
792
793 const QColor newColor = QgsColorDialog::getColor( color, mParent, tr( "Select color" ), true );
794 if ( !newColor.isValid() )
795 {
796 return false;
797 }
798
799 return model->setData( index, newColor, Qt::EditRole );
800 }
801
802 return false;
803}
804
805void QgsColorSwatchDelegate::colorChanged()
806{
807 if ( QgsCompoundColorWidget *colorWidget = qobject_cast<QgsCompoundColorWidget *>( sender() ) )
808 {
809 const QModelIndex index = colorWidget->property( "index" ).toModelIndex();
810 const_cast<QAbstractItemModel *>( index.model() )->setData( index, colorWidget->color(), Qt::EditRole );
811 }
812}
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:7320
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), bool allowOpacity=false)
Returns a color selection from a color dialog.
bool exportColorsToGpl(QFile &file)
Export colors to a GPL palette file from the list.
void setScheme(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the color scheme to show in the list.
void pasteColors()
Pastes colors from clipboard to the list.
void removeSelection()
Removes any selected colors from the list.
bool importColorsFromGpl(QFile &file)
Import colors from a GPL palette file to the list.
void copyColors()
Copies colors from the list to the clipboard.
bool isDirty() const
Returns whether the color scheme list has been modified.
void mouseReleaseEvent(QMouseEvent *event) override
void mousePressEvent(QMouseEvent *event) override
QgsColorScheme * scheme()
Returns the scheme currently selected in the list.
void addColor(const QColor &color, const QString &label=QString(), bool allowDuplicate=false)
Adds a color to the list.
void showExportColorsDialog()
Displays a file picker dialog allowing users to export colors from the list into a file.
void colorSelected(const QColor &color)
Emitted when a color is selected from the list.
void keyPressEvent(QKeyEvent *event) override
QgsColorSchemeList(QWidget *parent=nullptr, QgsColorScheme *scheme=nullptr, const QString &context=QString(), const QColor &baseColor=QColor())
Construct a new color swatch grid.
bool saveColorsToScheme()
Saves the current colors shown in the list back to a color scheme, if supported by the color scheme.
void showImportColorsDialog()
Displays a file picker dialog allowing users to import colors into the list from a file.
A model for colors in a color scheme.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
void addColor(const QColor &color, const QString &label=QString(), bool allowDuplicate=false)
Add a color to the list.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QColor baseColor() const
Gets the base color for the color scheme used by the model.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Qt::DropActions supportedDropActions() const override
QModelIndex parent(const QModelIndex &index) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
void setScheme(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor())
Sets the color scheme to show in the widget.
bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QMimeData * mimeData(const QModelIndexList &indexes) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
QgsColorSchemeModel(QgsColorScheme *scheme, const QString &context=QString(), const QColor &baseColor=QColor(), QObject *parent=nullptr)
Constructor.
QStringList mimeTypes() const override
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
QString context() const
Gets the current color scheme context for the model.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Abstract base class for color schemes.
virtual QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor())=0
Gets a list of colors from the scheme.
A delegate for showing a color swatch in a list.
QgsColorSwatchDelegate(QWidget *parent=nullptr)
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
A custom QGIS widget for selecting a color, including options for selecting colors via hue wheel,...
@ LayoutVertical
Use a narrower, vertically stacked layout.
void currentColorChanged(const QColor &color)
Emitted when the dialog's color changes.
void setAllowOpacity(bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color dialog.
Base class for any widget that can be shown as an inline panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
Scoped object for saving and restoring a QPainter object's state.
Stores settings for use within QGIS.
Definition qgssettings.h:68
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static bool saveColorsToGpl(QFile &file, const QString &paletteName, const QgsNamedColorList &colors)
Exports colors to a gpl GIMP palette file.
static std::unique_ptr< QMimeData > colorListToMimeData(const QgsNamedColorList &colorList, bool allFormats=true)
Creates mime data from a list of named colors.
static QgsNamedColorList colorListFromMimeData(const QMimeData *data)
Attempts to parse mime data as a list of named colors.
static QgsNamedColorList importColorsFromGpl(QFile &file, bool &ok, QString &name)
Imports colors from a gpl GIMP palette file.
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.