QGIS API Documentation 3.43.0-Master (b60ef06885e)
qgssymbolselectordialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgssymbolselectordialog.cpp
3 ---------------------
4 begin : November 2009
5 copyright : (C) 2009 by Martin Dobias
6 email : wonder dot sk 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
17#include "moc_qgssymbolselectordialog.cpp"
18
19#include "qgsstyle.h"
20#include "qgssymbol.h"
21#include "qgssymbollayer.h"
22#include "qgssymbollayerutils.h"
25
26// the widgets
29#include "qgsapplication.h"
30#include "qgsvectorlayer.h"
31#include "qgssvgcache.h"
32#include "qgsimagecache.h"
33#include "qgsproject.h"
34#include "qgsguiutils.h"
35#include "qgsgui.h"
36#include "qgsmarkersymbol.h"
37#include "qgslinesymbol.h"
38#include "qscreen.h"
39
40#include <QColorDialog>
41#include <QPainter>
42#include <QStandardItemModel>
43#include <QInputDialog>
44#include <QMessageBox>
45#include <QKeyEvent>
46#include <QMenu>
47
48#include <QWidget>
49#include <QFile>
50#include <QStandardItem>
51
53
54static const int SYMBOL_LAYER_ITEM_TYPE = QStandardItem::UserType + 1;
55
56DataDefinedRestorer::DataDefinedRestorer( QgsSymbol *symbol, const QgsSymbolLayer *symbolLayer )
57
58{
59 if ( symbolLayer->type() == Qgis::SymbolType::Marker && symbol->type() == Qgis::SymbolType::Marker )
60 {
61 Q_ASSERT( symbol->type() == Qgis::SymbolType::Marker );
62 mMarker = static_cast<QgsMarkerSymbol *>( symbol );
63 mMarkerSymbolLayer = static_cast<const QgsMarkerSymbolLayer *>( symbolLayer );
64 mDDSize = mMarker->dataDefinedSize();
65 mDDAngle = mMarker->dataDefinedAngle();
66 // check if restore is actually needed
67 if ( !mDDSize && !mDDAngle )
68 mMarker = nullptr;
69 }
70 else if ( symbolLayer->type() == Qgis::SymbolType::Line && symbol->type() == Qgis::SymbolType::Line )
71 {
72 mLine = static_cast<QgsLineSymbol *>( symbol );
73 mLineSymbolLayer = static_cast<const QgsLineSymbolLayer *>( symbolLayer );
74 mDDWidth = mLine->dataDefinedWidth();
75 // check if restore is actually needed
76 if ( !mDDWidth )
77 mLine = nullptr;
78 }
79 save();
80}
81
82void DataDefinedRestorer::save()
83{
84 if ( mMarker )
85 {
86 mSize = mMarkerSymbolLayer->size();
87 mAngle = mMarkerSymbolLayer->angle();
88 mMarkerOffset = mMarkerSymbolLayer->offset();
89 }
90 else if ( mLine )
91 {
92 mWidth = mLineSymbolLayer->width();
93 mLineOffset = mLineSymbolLayer->offset();
94 }
95}
96
97void DataDefinedRestorer::restore()
98{
99 if ( mMarker )
100 {
101 if ( mDDSize && ( mSize != mMarkerSymbolLayer->size() || mMarkerOffset != mMarkerSymbolLayer->offset() ) )
102 mMarker->setDataDefinedSize( mDDSize );
103 if ( mDDAngle && mAngle != mMarkerSymbolLayer->angle() )
104 mMarker->setDataDefinedAngle( mDDAngle );
105 }
106 else if ( mLine )
107 {
108 if ( mDDWidth && ( mWidth != mLineSymbolLayer->width() || mLineOffset != mLineSymbolLayer->offset() ) )
109 mLine->setDataDefinedWidth( mDDWidth );
110 }
111 save();
112}
113
114// Hybrid item which may represent a symbol or a layer
115// Check using item->isLayer()
116class SymbolLayerItem : public QStandardItem
117{
118 public:
119 explicit SymbolLayerItem( QgsSymbolLayer *layer, Qgis::SymbolType symbolType, QgsVectorLayer *vectorLayer, QScreen *screen )
120 : mVectorLayer( vectorLayer )
121 , mScreen( screen )
122 {
123 setLayer( layer, symbolType );
124 }
125
126 explicit SymbolLayerItem( QgsSymbol *symbol, QgsVectorLayer *vectorLayer, QScreen *screen )
127 : mVectorLayer( vectorLayer )
128 , mScreen( screen )
129 {
130 setSymbol( symbol );
131 }
132
133 void setLayer( QgsSymbolLayer *layer, Qgis::SymbolType symbolType )
134 {
135 mLayer = layer;
136 mIsLayer = true;
137 mSymbol = nullptr;
138 mSymbolType = symbolType;
139 updatePreview();
140 }
141
142 void setSymbol( QgsSymbol *symbol )
143 {
144 mSymbol = symbol;
145 mIsLayer = false;
146 mLayer = nullptr;
147 updatePreview();
148 }
149
150 void updatePreview()
151 {
152 if ( !mSize.isValid() )
153 {
154 const int size = QgsGuiUtils::scaleIconSize( 16 );
155 mSize = QSize( size, size );
156 }
157 QIcon icon;
158 if ( mIsLayer )
159 icon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( mLayer, Qgis::RenderUnit::Millimeters, mSize, QgsMapUnitScale(), mSymbol ? mSymbol->type() : mSymbolType, mVectorLayer, QgsScreenProperties( mScreen.data() ) );
160 else
161 {
162 QgsExpressionContext expContext;
164 icon = QIcon( QgsSymbolLayerUtils::symbolPreviewPixmap( mSymbol, mSize, 0, nullptr, false, &expContext, nullptr, QgsScreenProperties( mScreen.data() ) ) );
165 }
166 setIcon( icon );
167
168 if ( auto *lParent = parent() )
169 static_cast<SymbolLayerItem *>( lParent )->updatePreview();
170 }
171
172 int type() const override { return SYMBOL_LAYER_ITEM_TYPE; }
173 bool isLayer() { return mIsLayer; }
174
175 // returns the symbol pointer; helpful in determining a layer's parent symbol
176 QgsSymbol *symbol()
177 {
178 return mSymbol;
179 }
180
181 QgsSymbolLayer *layer()
182 {
183 return mLayer;
184 }
185
186 QVariant data( int role ) const override
187 {
188 if ( role == Qt::DisplayRole || role == Qt::EditRole )
189 {
190 if ( mIsLayer )
191 {
193 if ( m )
194 return m->visibleName();
195 else
196 return QString();
197 }
198 else
199 {
200 switch ( mSymbol->type() )
201 {
203 return QCoreApplication::translate( "SymbolLayerItem", "Marker" );
205 return QCoreApplication::translate( "SymbolLayerItem", "Fill" );
207 return QCoreApplication::translate( "SymbolLayerItem", "Line" );
208 default:
209 return "Symbol";
210 }
211 }
212 }
213 else if ( role == Qt::ForegroundRole && mIsLayer )
214 {
215 if ( !mLayer->enabled() )
216 {
217 QPalette pal = qApp->palette();
218 QBrush brush = QStandardItem::data( role ).value<QBrush>();
219 brush.setColor( pal.color( QPalette::Disabled, QPalette::WindowText ) );
220 return brush;
221 }
222 else
223 {
224 return QVariant();
225 }
226 }
227
228 // if ( role == Qt::SizeHintRole )
229 // return QVariant( QSize( 32, 32 ) );
230 if ( role == Qt::CheckStateRole )
231 return QVariant(); // could be true/false
232 return QStandardItem::data( role );
233 }
234
235 protected:
236 QgsSymbolLayer *mLayer = nullptr;
237 QgsSymbol *mSymbol = nullptr;
238 QPointer<QgsVectorLayer> mVectorLayer;
239 bool mIsLayer = false;
240 QSize mSize;
242 QPointer<QScreen> mScreen;
243};
244
246
248
250 : QgsPanelWidget( parent )
251 , mStyle( style )
252 , mSymbol( symbol )
253 , mVectorLayer( vl )
254{
255#ifdef Q_OS_MAC
256 setWindowModality( Qt::WindowModal );
257#endif
258
259 setupUi( this );
260 this->layout()->setContentsMargins( 0, 0, 0, 0 );
261
262 layersTree->setMaximumHeight( static_cast<int>( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 7 ) );
263 layersTree->setMinimumHeight( layersTree->maximumHeight() );
264 lblPreview->setMaximumWidth( layersTree->maximumHeight() );
265
266 // setup icons
267 btnAddLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
268 btnRemoveLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
269 QIcon iconLock;
270 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
271 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
272 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
273 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
274
275 QIcon iconColorLock;
276 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorLocked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
277 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorLocked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
278 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorUnlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
279 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorUnlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
280
281 mLockColorAction = new QAction( tr( "Lock Color" ), this );
282 mLockColorAction->setToolTip( tr( "Avoid changing the color of the layer when the symbol color is changed" ) );
283 mLockColorAction->setCheckable( true );
284 mLockColorAction->setIcon( iconColorLock );
285
286 QIcon iconSelectLock;
287 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectLocked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
288 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectLocked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
289 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectUnlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
290 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectUnlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
291
292 mLockSelectionColorAction = new QAction( tr( "Lock Color When Selected" ), this );
293 mLockSelectionColorAction->setToolTip( tr( "Avoid changing the color of the layer when a feature is selected" ) );
294 mLockSelectionColorAction->setCheckable( true );
295 mLockSelectionColorAction->setIcon( iconSelectLock );
296
297 QMenu *lockMenu = new QMenu( this );
298 lockMenu->addAction( mLockColorAction );
299 lockMenu->addAction( mLockSelectionColorAction );
300 btnLock->setMenu( lockMenu );
301 btnLock->setPopupMode( QToolButton::InstantPopup );
302
303 btnDuplicate->setIcon( QIcon( QgsApplication::iconPath( "mActionDuplicateLayer.svg" ) ) );
304 btnUp->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowUp.svg" ) ) );
305 btnDown->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowDown.svg" ) ) );
306
307 mSymbolLayersModel = new QStandardItemModel( layersTree );
308 // Set the symbol
309 layersTree->setModel( mSymbolLayersModel );
310 layersTree->setHeaderHidden( true );
311
312 //get first feature from layer for previews
313 if ( mVectorLayer )
314 {
315#if 0 // this is too expensive to do for many providers. TODO revisit when support for connection timeouts is complete across all providers
316 // short timeout for request - it doesn't really matter if we don't get the feature, and this call is blocking UI
317 QgsFeatureIterator it = mVectorLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ).setConnectionTimeout( 100 ) );
318 it.nextFeature( mPreviewFeature );
319#endif
320 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mVectorLayer ) );
321#if 0
322 mPreviewExpressionContext.setFeature( mPreviewFeature );
323#endif
324 }
325 else
326 {
327 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
328 }
329
330 QItemSelectionModel *selModel = layersTree->selectionModel();
331 connect( selModel, &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
332
333 loadSymbol( mSymbol, static_cast<SymbolLayerItem *>( mSymbolLayersModel->invisibleRootItem() ) );
335
336 connect( btnUp, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerUp );
337 connect( btnDown, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerDown );
338 connect( btnAddLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::addLayer );
339 connect( btnRemoveLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::removeLayer );
340 connect( mLockColorAction, &QAction::toggled, this, &QgsSymbolSelectorWidget::lockLayer );
341 connect( mLockSelectionColorAction, &QAction::toggled, this, [=]( bool checked ) {
342 QgsSymbolLayer *layer = currentLayer();
343 if ( !layer )
344 return;
345
346 Qgis::SymbolLayerUserFlags flags = layer->userFlags();
348 layer->setUserFlags( flags );
349 updateLockButtonIcon();
350 emit symbolModified();
351 } );
352 connect( btnDuplicate, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::duplicateLayer );
354
355 updateLockButtonIcon();
356
357 updateUi();
358
359 // set symbol as active item in the tree
360 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
361 layersTree->setCurrentIndex( newIndex );
362
363 setPanelTitle( tr( "Symbol Selector" ) );
364
365 // when a remote svg has been fetched, update the widget's previews
366 // this is required if the symbol utilizes remote svgs, and the current previews
367 // have been generated using the temporary "downloading" svg. In this case
368 // we require the preview to be regenerated to use the correct fetched
369 // svg
370 connect( QgsApplication::svgCache(), &QgsSvgCache::remoteSvgFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
371
372 // when a remote image has been fetched, update the widget's previews
373 // this is required if the symbol utilizes remote images, and the current previews
374 // have been generated using the temporary "downloading" image. In this case
375 // we require the preview to be regenerated to use the correct fetched
376 // image
377 connect( QgsApplication::imageCache(), &QgsImageCache::remoteImageFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
378
379 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
380 // need updating to reflect the new colors
381 connect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsSymbolSelectorWidget::projectDataChanged );
382
383 connect( QgsProject::instance(), static_cast<void ( QgsProject::* )( const QList<QgsMapLayer *> &layers )>( &QgsProject::layersWillBeRemoved ), this, &QgsSymbolSelectorWidget::layersAboutToBeRemoved );
384}
385
386QgsSymbolSelectorWidget *QgsSymbolSelectorWidget::createWidgetWithSymbolOwnership( std::unique_ptr<QgsSymbol> symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent )
387{
388 QgsSymbolSelectorWidget *widget = new QgsSymbolSelectorWidget( symbol.get(), style, vl, parent );
389 // transfer ownership of symbol to widget, so that we are guaranteed it will last for the duration of the widget
390 widget->mOwnedSymbol = std::move( symbol );
391 return widget;
392}
393
395{
396 if ( !mAdvancedMenu )
397 {
398 mAdvancedMenu = new QMenu( this );
399 // Brute force method to activate the Advanced menu
400 layerChanged();
401 }
402 return mAdvancedMenu;
403}
404
406{
407 mContext = context;
408
409 if ( auto *lExpressionContext = mContext.expressionContext() )
410 {
411 mPreviewExpressionContext = *lExpressionContext;
412 if ( mVectorLayer )
413 mPreviewExpressionContext.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer ) );
414
415 mPreviewExpressionContext.setFeature( mPreviewFeature );
416 }
417
418 QWidget *widget = stackedWidget->currentWidget();
419 if ( QgsLayerPropertiesWidget *layerProp = qobject_cast<QgsLayerPropertiesWidget *>( widget ) )
420 {
421 layerProp->setContext( context );
422 }
423 else if ( QgsSymbolsListWidget *listWidget = qobject_cast<QgsSymbolsListWidget *>( widget ) )
424 {
425 listWidget->setContext( context );
426 }
427
428 layerChanged();
430}
431
433{
434 return mContext;
435}
436
437void QgsSymbolSelectorWidget::loadSymbol( QgsSymbol *symbol, SymbolLayerItem *parent )
438{
439 if ( !symbol )
440 return;
441
442 if ( !parent )
443 {
444 mSymbol = symbol;
445 mSymbolLayersModel->clear();
446 parent = static_cast<SymbolLayerItem *>( mSymbolLayersModel->invisibleRootItem() );
447 }
448
449 SymbolLayerItem *symbolItem = new SymbolLayerItem( symbol, mVectorLayer, screen() );
450 QFont boldFont = symbolItem->font();
451 boldFont.setBold( true );
452 symbolItem->setFont( boldFont );
453 parent->appendRow( symbolItem );
454
455 const int count = symbol->symbolLayerCount();
456 for ( int i = count - 1; i >= 0; i-- )
457 {
458 SymbolLayerItem *layerItem = new SymbolLayerItem( symbol->symbolLayer( i ), symbol->type(), mVectorLayer, screen() );
459 layerItem->setEditable( false );
460 symbolItem->appendRow( layerItem );
461 if ( symbol->symbolLayer( i )->subSymbol() )
462 {
463 loadSymbol( symbol->symbolLayer( i )->subSymbol(), layerItem );
464 }
465 layersTree->setExpanded( layerItem->index(), true );
466 }
467 layersTree->setExpanded( symbolItem->index(), true );
468
469 if ( mSymbol == symbol && !layersTree->currentIndex().isValid() )
470 {
471 // make sure root item for symbol is selected in tree
472 layersTree->setCurrentIndex( symbolItem->index() );
473 }
474}
475
476void QgsSymbolSelectorWidget::reloadSymbol()
477{
478 mSymbolLayersModel->clear();
479 loadSymbol( mSymbol, static_cast<SymbolLayerItem *>( mSymbolLayersModel->invisibleRootItem() ) );
480}
481
482void QgsSymbolSelectorWidget::updateUi()
483{
484 const QModelIndex currentIdx = layersTree->currentIndex();
485 if ( !currentIdx.isValid() )
486 return;
487
488 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( currentIdx ) );
489 if ( !item->isLayer() )
490 {
491 btnUp->setEnabled( false );
492 btnDown->setEnabled( false );
493 btnRemoveLayer->setEnabled( false );
494 btnLock->setEnabled( false );
495 btnDuplicate->setEnabled( false );
496 return;
497 }
498
499 const int rowCount = item->parent()->rowCount();
500 const int currentRow = item->row();
501
502 btnUp->setEnabled( currentRow > 0 );
503 btnDown->setEnabled( currentRow < rowCount - 1 );
504 btnRemoveLayer->setEnabled( rowCount > 1 );
505 btnLock->setEnabled( true );
506 btnDuplicate->setEnabled( true );
507}
508
510{
511 if ( !mSymbol )
512 return;
513
514 std::unique_ptr<QgsSymbol> symbolClone( mSymbol->clone() );
515 const QImage preview = symbolClone->bigSymbolPreviewImage( &mPreviewExpressionContext, Qgis::SymbolPreviewFlag::FlagIncludeCrosshairsForMarkerSymbols, QgsScreenProperties( screen() ) );
516 lblPreview->setPixmap( QPixmap::fromImage( preview ) );
517 // Hope this is a appropriate place
518 if ( !mBlockModified )
519 emit symbolModified();
520}
521
523{
524 // get current layer item and update its icon
525 SymbolLayerItem *item = currentLayerItem();
526 if ( item )
527 item->updatePreview();
528 // update also preview of the whole symbol
530}
531
532SymbolLayerItem *QgsSymbolSelectorWidget::currentLayerItem()
533{
534 const QModelIndex idx = layersTree->currentIndex();
535 if ( !idx.isValid() )
536 return nullptr;
537
538 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
539 if ( !item->isLayer() )
540 return nullptr;
541
542 return item;
543}
544
545QgsSymbolLayer *QgsSymbolSelectorWidget::currentLayer()
546{
547 const QModelIndex idx = layersTree->currentIndex();
548 if ( !idx.isValid() )
549 return nullptr;
550
551 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
552 if ( item->isLayer() )
553 return item->layer();
554
555 return nullptr;
556}
557
559{
560 updateUi();
561
562 SymbolLayerItem *currentItem = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( layersTree->currentIndex() ) );
563 if ( !currentItem )
564 return;
565
566 if ( currentItem->isLayer() )
567 {
568 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( currentItem->parent() );
569 mDataDefineRestorer.reset( new DataDefinedRestorer( parent->symbol(), currentItem->layer() ) );
570 QgsLayerPropertiesWidget *layerProp = new QgsLayerPropertiesWidget( currentItem->layer(), parent->symbol(), mVectorLayer );
571 layerProp->setDockMode( this->dockMode() );
572 layerProp->setContext( mContext );
573 setWidget( layerProp );
574 connect( layerProp, &QgsLayerPropertiesWidget::changed, mDataDefineRestorer.get(), &DataDefinedRestorer::restore );
576 // This connection when layer type is changed
578
579 connectChildPanel( layerProp );
580 }
581 else
582 {
583 // then it must be a symbol
584 mDataDefineRestorer.reset();
586 currentItem->symbol()->setLayer( mVectorLayer );
588 // Now populate symbols of that type using the symbols list widget:
589 QgsSymbolsListWidget *symbolsList = new QgsSymbolsListWidget( currentItem->symbol(), mStyle, mAdvancedMenu, this, mVectorLayer );
590 symbolsList->setContext( mContext );
591
592 setWidget( symbolsList );
594 }
595 updateLockButton();
596}
597
599{
600 SymbolLayerItem *currentItem = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( layersTree->currentIndex() ) );
601 if ( !currentItem || currentItem->isLayer() )
602 return;
603 // disconnect to avoid recreating widget
604 disconnect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
605 if ( currentItem->parent() )
606 {
607 // it is a sub-symbol
608 QgsSymbol *symbol = currentItem->symbol();
609 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( currentItem->parent() );
610 parent->removeRow( 0 );
611 loadSymbol( symbol, parent );
612 layersTree->setCurrentIndex( parent->child( 0 )->index() );
613 parent->updatePreview();
614 }
615 else
616 {
617 //it is the symbol itself
618 reloadSymbol();
619 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
620 layersTree->setCurrentIndex( newIndex );
621 }
623 // connect it back once things are set
624 connect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
625}
626
627void QgsSymbolSelectorWidget::setWidget( QWidget *widget )
628{
629 const int index = stackedWidget->addWidget( widget );
630 stackedWidget->setCurrentIndex( index );
631 if ( mPresentWidget )
632 mPresentWidget->deleteLater();
633 mPresentWidget = widget;
634}
635
636void QgsSymbolSelectorWidget::updateLockButton()
637{
638 QgsSymbolLayer *layer = currentLayer();
639 if ( !layer )
640 return;
641 mLockColorAction->setChecked( layer->isLocked() );
642 mLockSelectionColorAction->setChecked( layer->userFlags() & Qgis::SymbolLayerUserFlag::DisableSelectionRecoloring );
643
644 updateLockButtonIcon();
645}
646
647void QgsSymbolSelectorWidget::updateLockButtonIcon()
648{
649 if ( mLockColorAction->isChecked() && mLockSelectionColorAction->isChecked() )
650 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "locked.svg" ) ) );
651 else if ( mLockColorAction->isChecked() )
652 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconColorLocked.svg" ) ) );
653 else if ( mLockSelectionColorAction->isChecked() )
654 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconSelectLocked.svg" ) ) );
655 else
656 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "unlocked.svg" ) ) );
657}
658
660{
661 const QModelIndex idx = layersTree->currentIndex();
662 if ( !idx.isValid() )
663 return;
664
665 int insertIdx = -1;
666 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
667 if ( item->isLayer() )
668 {
669 insertIdx = item->row();
670 item = static_cast<SymbolLayerItem *>( item->parent() );
671 }
672
673 QgsSymbol *parentSymbol = item->symbol();
674
675 // save data-defined values at marker level
676 const QgsProperty ddSize( parentSymbol->type() == Qgis::SymbolType::Marker ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedSize() : QgsProperty() );
677 const QgsProperty ddAngle( parentSymbol->type() == Qgis::SymbolType::Marker ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedAngle() : QgsProperty() );
678 const QgsProperty ddWidth( parentSymbol->type() == Qgis::SymbolType::Line ? static_cast<QgsLineSymbol *>( parentSymbol )->dataDefinedWidth() : QgsProperty() );
679
680 QgsSymbolLayer *newLayerPtr = nullptr;
681 {
682 std::unique_ptr< QgsSymbolLayer > newLayer = QgsSymbolLayerRegistry::defaultSymbolLayer( parentSymbol->type() );
683 newLayerPtr = newLayer.get();
684 if ( insertIdx == -1 )
685 parentSymbol->appendSymbolLayer( newLayer.release() );
686 else
687 parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer.release() );
688 }
689
690 // restore data-defined values at marker level
691 if ( ddSize )
692 static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedSize( ddSize );
693 if ( ddAngle )
694 static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedAngle( ddAngle );
695 if ( ddWidth )
696 static_cast<QgsLineSymbol *>( parentSymbol )->setDataDefinedWidth( ddWidth );
697
698 // TODO -- using newLayerPtr is not safe in some circumstances here. This needs reworking so that SymbolLayerItem does has
699 // its own owned QgsSymbolLayer clone, and isn't reliant on a pointer to the object owned by parentSymbol.
700 SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayerPtr, parentSymbol->type(), mVectorLayer, screen() ); // cppcheck-suppress invalidLifetime
701 item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
702 item->updatePreview();
703
704 layersTree->setCurrentIndex( mSymbolLayersModel->indexFromItem( newLayerItem ) );
705 updateUi();
707}
708
710{
711 SymbolLayerItem *item = currentLayerItem();
712 const int row = item->row();
713 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );
714
715 const int layerIdx = parent->rowCount() - row - 1; // IMPORTANT
716 QgsSymbol *parentSymbol = parent->symbol();
717 QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
718
719 parent->removeRow( row );
720 parent->updatePreview();
721
722 const QModelIndex newIdx = parent->child( 0 )->index();
723 layersTree->setCurrentIndex( newIdx );
724
725 updateUi();
727 //finally delete the removed layer pointer
728 delete tmpLayer;
729}
730
732{
733 moveLayerByOffset( +1 );
734}
735
737{
738 moveLayerByOffset( -1 );
739}
740
741void QgsSymbolSelectorWidget::moveLayerByOffset( int offset )
742{
743 SymbolLayerItem *item = currentLayerItem();
744 if ( !item )
745 return;
746 const int row = item->row();
747
748 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );
749 QgsSymbol *parentSymbol = parent->symbol();
750
751 const int layerIdx = parent->rowCount() - row - 1;
752 // switch layers
753 QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
754 parentSymbol->insertSymbolLayer( layerIdx - offset, tmpLayer );
755
756 QList<QStandardItem *> rowItems = parent->takeRow( row );
757 parent->insertRows( row + offset, rowItems );
758 parent->updatePreview();
759
760 const QModelIndex newIdx = rowItems[0]->index();
761 layersTree->setCurrentIndex( newIdx );
762
764 updateUi();
765}
766
768{
769 QgsSymbolLayer *layer = currentLayer();
770 if ( !layer )
771 return;
772 layer->setLocked( mLockColorAction->isChecked() );
773 updateLockButtonIcon();
774 emit symbolModified();
775}
776
778{
779 const QModelIndex idx = layersTree->currentIndex();
780 if ( !idx.isValid() )
781 return;
782
783 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
784 if ( !item->isLayer() )
785 return;
786
787 QgsSymbolLayer *source = item->layer();
788
789 const int insertIdx = item->row();
790 item = static_cast<SymbolLayerItem *>( item->parent() );
791
792 QgsSymbol *parentSymbol = item->symbol();
793
794 QgsSymbolLayer *newLayer = source->clone();
796 if ( insertIdx == -1 )
797 parentSymbol->appendSymbolLayer( newLayer );
798 else
799 parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );
800
801 SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer, parentSymbol->type(), mVectorLayer, screen() );
802 item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
803 if ( newLayer->subSymbol() )
804 {
805 loadSymbol( newLayer->subSymbol(), newLayerItem );
806 layersTree->setExpanded( newLayerItem->index(), true );
807 }
808 item->updatePreview();
809
810 layersTree->setCurrentIndex( mSymbolLayersModel->indexFromItem( newLayerItem ) );
811 updateUi();
813}
814
816{
817 SymbolLayerItem *item = currentLayerItem();
818
819 if ( item->rowCount() > 0 )
820 {
821 item->removeRow( 0 );
822 }
823 QgsSymbol *symbol = static_cast<SymbolLayerItem *>( item->parent() )->symbol();
824
825 // update symbol layer item
826 item->setLayer( newLayer, symbol->type() );
827 // When it is a marker symbol
828 if ( newLayer->subSymbol() )
829 {
830 loadSymbol( newLayer->subSymbol(), item );
831 layersTree->setExpanded( item->index(), true );
832 }
833
834 // Change the symbol at last to avoid deleting item's layer
835 const int layerIdx = item->parent()->rowCount() - item->row() - 1;
836 symbol->changeSymbolLayer( layerIdx, newLayer );
837
838 item->updatePreview();
840 // Important: This lets the layer have its own layer properties widget
841 layerChanged();
842}
843
844QgsSymbolSelectorDialog::QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent, bool embedded )
845 : QDialog( parent )
846{
847 setLayout( new QVBoxLayout() );
848
849 mSelectorWidget = new QgsSymbolSelectorWidget( symbol, style, vl, this );
850 mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
851
852 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
853 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
854 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsSymbolSelectorDialog::showHelp );
855
856 layout()->addWidget( mSelectorWidget );
857 layout()->addWidget( mButtonBox );
858
859 connect( mSelectorWidget, &QgsPanelWidget::panelAccepted, this, &QDialog::reject );
860
861 mSelectorWidget->setMinimumSize( 460, 560 );
862 setObjectName( QStringLiteral( "SymbolSelectorDialog" ) );
864
865 // Can be embedded in renderer properties dialog
866 if ( embedded )
867 {
868 mButtonBox->hide();
869 layout()->setContentsMargins( 0, 0, 0, 0 );
870 }
871 else
872 {
873 setWindowTitle( tr( "Symbol Selector" ) );
874 }
875 mSelectorWidget->setDockMode( embedded );
876}
877
879{
880 return mSelectorWidget->advancedMenu();
881}
882
884{
885 mSelectorWidget->setContext( context );
886}
887
889{
890 return mSelectorWidget->context();
891}
892
894{
895 return mSelectorWidget->symbol();
896}
897
899{
900 // Ignore the ESC key to avoid close the dialog without the properties window
901 if ( !isWindow() && e->key() == Qt::Key_Escape )
902 {
903 e->ignore();
904 }
905 else
906 {
907 QDialog::keyPressEvent( e );
908 }
909}
910
911void QgsSymbolSelectorDialog::reloadSymbol()
912{
913 mSelectorWidget->reloadSymbol();
914}
915
916void QgsSymbolSelectorDialog::loadSymbol( QgsSymbol *symbol, SymbolLayerItem *parent )
917{
918 mSelectorWidget->loadSymbol( symbol, parent );
919}
920
921void QgsSymbolSelectorDialog::updateUi()
922{
923 mSelectorWidget->updateUi();
924}
925
926void QgsSymbolSelectorDialog::updateLockButton()
927{
928 mSelectorWidget->updateLockButton();
929}
930
931SymbolLayerItem *QgsSymbolSelectorDialog::currentLayerItem()
932{
933 return mSelectorWidget->currentLayerItem();
934}
935
936QgsSymbolLayer *QgsSymbolSelectorDialog::currentLayer()
937{
938 return mSelectorWidget->currentLayer();
939}
940
941void QgsSymbolSelectorDialog::moveLayerByOffset( int offset )
942{
943 mSelectorWidget->moveLayerByOffset( offset );
944}
945
946void QgsSymbolSelectorDialog::setWidget( QWidget *widget )
947{
948 mSelectorWidget->setWidget( widget );
949}
950
952{
953 mSelectorWidget->moveLayerDown();
954}
955
957{
958 mSelectorWidget->moveLayerUp();
959}
960
962{
963 mSelectorWidget->addLayer();
964}
965
967{
968 mSelectorWidget->removeLayer();
969}
970
972{
973 mSelectorWidget->lockLayer();
974}
975
977{
978 mSelectorWidget->duplicateLayer();
979}
980
982{
983 mSelectorWidget->layerChanged();
984}
985
990
992{
993 mSelectorWidget->updatePreview();
994}
995
997{
998 mSelectorWidget->symbolChanged();
999}
1000
1002{
1003 mSelectorWidget->changeLayer( layer );
1004}
1005
1006QDialogButtonBox *QgsSymbolSelectorDialog::buttonBox() const
1007{
1008 return mButtonBox;
1009}
1010
1011void QgsSymbolSelectorDialog::showHelp()
1012{
1013 QgsHelp::openHelp( QStringLiteral( "style_library/symbol_selector.html" ) );
1014}
1015
1016void QgsSymbolSelectorWidget::projectDataChanged()
1017{
1018 mBlockModified = true;
1019 symbolChanged();
1020 updatePreview();
1021 mBlockModified = false;
1022}
1023
1024void QgsSymbolSelectorWidget::layersAboutToBeRemoved( const QList<QgsMapLayer *> &layers )
1025{
1026 if ( mVectorLayer && layers.contains( mVectorLayer ) )
1027 {
1028 disconnect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsSymbolSelectorWidget::projectDataChanged );
1029 }
1030}
QFlags< SymbolLayerUserFlag > SymbolLayerUserFlags
Symbol layer user flags.
Definition qgis.h:874
@ Millimeters
Millimeters.
@ FlagIncludeCrosshairsForMarkerSymbols
Include a crosshairs reference image in the background of marker symbol previews.
@ DisableSelectionRecoloring
If present, indicates that the symbol layer should not be recolored when rendering selected features.
SymbolType
Symbol types.
Definition qgis.h:574
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:5932
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application's symbol layer registry, used for managing symbol layers.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:210
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:39
void remoteImageFetched(const QString &url)
Emitted when the cache has finished retrieving an image file from a remote url.
A widget which allows configuration of the properties of a single QgsSymbolLayer.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
void changeLayer(QgsSymbolLayer *layer)
Emitted when the symbol layer is changed in the widget.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
void changed()
Emitted when the symbol layer configuration is changed in the widget.
Abstract base class for line symbol layers.
A line symbol type, for rendering LineString and MultiLineString geometries.
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Struct for storing maximum and minimum scales for measurements in map units.
Abstract base class for marker symbol layers.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Base class for any widget that can be shown as an inline panel.
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
void connectChildPanel(QgsPanelWidget *panel)
Connect the given sub panel widgets showPanel signals to this current panels main showPanel event to ...
void widgetChanged()
Emitted when the widget state changes.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
bool dockMode()
Returns the dock mode state.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
static QgsProject * instance()
Returns the QgsProject singleton instance.
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
A store for object properties.
Stores properties relating to a screen.
A database of saved style entities, including symbols, color ramps, text formats and others.
Definition qgsstyle.h:88
void remoteSvgFetched(const QString &url)
Emitted when the cache has finished retrieving an SVG file from a remote url.
Stores metadata about one symbol layer class.
static std::unique_ptr< QgsSymbolLayer > defaultSymbolLayer(Qgis::SymbolType type)
create a new instance of symbol layer for specified symbol type with default settings
QgsSymbolLayerAbstractMetadata * symbolLayerMetadata(const QString &name) const
Returns metadata for specified symbol layer. Returns nullptr if not found.
static QIcon symbolLayerPreviewIcon(const QgsSymbolLayer *layer, Qgis::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::SymbolType parentSymbolType=Qgis::SymbolType::Hybrid, QgsMapLayer *mapLayer=nullptr, const QgsScreenProperties &screen=QgsScreenProperties())
Draws a symbol layer preview to an icon.
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *shape=nullptr, const QgsScreenProperties &screen=QgsScreenProperties())
Returns a pixmap preview for a color ramp.
static void resetSymbolLayerIds(QgsSymbol *symbol)
Regenerate recursively unique id from all symbol symbol layers.
Abstract base class for symbol layers.
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
Qgis::SymbolType type() const
bool isLocked() const
Returns true if the symbol layer colors are locked and the layer will ignore any symbol-level color c...
void setUserFlags(Qgis::SymbolLayerUserFlags flags)
Sets user-controlled flags which control the symbol layer's behavior.
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Qgis::SymbolLayerUserFlags userFlags() const
Returns user-controlled flags which control the symbol layer's behavior.
void setLocked(bool locked)
Sets whether the layer's colors are locked.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsSymbolSelectorDialog(QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr, bool embedded=false)
Constructor for QgsSymbolSelectorDialog.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
QMenu * advancedMenu()
Returns menu for "advanced" button - create it if doesn't exist and show the advanced button.
void symbolChanged()
Slot to update tree when a new symbol from style.
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog's button box.
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
void keyPressEvent(QKeyEvent *e) override
void duplicateLayer()
Duplicates the current symbol layer and places the duplicated layer above the current symbol layer.
void changeLayer(QgsSymbolLayer *layer)
Alters tree and sets proper widget when Layer Type is changed.
void loadSymbol(QgsSymbol *symbol, SymbolLayerItem *parent=nullptr)
Loads the given symbol into the widget.
Symbol selector widget that can be used to select and build a symbol.
void loadSymbol(QgsSymbol *symbol, SymbolLayerItem *parent=nullptr)
Loads the given symbol into the widget.
void symbolChanged()
Slot to update tree when a new symbol from style.
void addLayer()
Add a symbol layer to the bottom of the stack.
QMenu * advancedMenu()
Returns menu for "advanced" button - create it if doesn't exist and show the advanced button.
void layerChanged()
Called when the layer changes in the widget.
void changeLayer(QgsSymbolLayer *layer)
Alters tree and sets proper widget when Layer Type is changed.
void updatePreview()
Update the preview of the whole symbol in the interface.
QgsSymbolSelectorWidget(QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr)
Symbol selector widget that can be used to select and build a symbol.
void removeLayer()
Remove the current active symbol layer.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
void moveLayerDown()
Move the active symbol layer down.
void symbolModified()
Emitted when a symbol is modified in the widget.
void duplicateLayer()
Duplicates the current symbol layer and places the duplicated layer above the current symbol layer.
void lockLayer()
Lock the current active symbol layer.
void updateLayerPreview()
Update the single symbol layer preview in the widget.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
void moveLayerUp()
Move the active symbol layer up.
static QgsSymbolSelectorWidget * createWidgetWithSymbolOwnership(std::unique_ptr< QgsSymbol > symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr)
Creates a QgsSymbolSelectorWidget which takes ownership of a symbol and maintains the ownership for t...
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
bool appendSymbolLayer(QgsSymbolLayer *layer)
Appends a symbol layer at the end of the current symbol layer list.
bool insertSymbolLayer(int index, QgsSymbolLayer *layer)
Inserts a symbol layer to specified index.
bool changeSymbolLayer(int index, QgsSymbolLayer *layer)
Deletes the current layer at the specified index and replaces it with layer.
QgsSymbolLayer * takeSymbolLayer(int index)
Removes a symbol layer from the list and returns a pointer to it.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition qgssymbol.h:353
Qgis::SymbolType type() const
Returns the symbol's type.
Definition qgssymbol.h:294
A widget which presents symbol-level properties (such as size), and allows selection of symbols from ...
void changed()
Emitted when the symbol is modified in the widget.
Represents a vector layer which manages a vector based dataset.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:6819
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6818