QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
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 &&
102 ( mSize != mMarkerSymbolLayer->size() || mMarkerOffset != mMarkerSymbolLayer->offset() ) )
103 mMarker->setDataDefinedSize( mDDSize );
104 if ( mDDAngle &&
105 mAngle != mMarkerSymbolLayer->angle() )
106 mMarker->setDataDefinedAngle( mDDAngle );
107 }
108 else if ( mLine )
109 {
110 if ( mDDWidth &&
111 ( mWidth != mLineSymbolLayer->width() || mLineOffset != mLineSymbolLayer->offset() ) )
112 mLine->setDataDefinedWidth( mDDWidth );
113 }
114 save();
115}
116
117// Hybrid item which may represent a symbol or a layer
118// Check using item->isLayer()
119class SymbolLayerItem : public QStandardItem
120{
121 public:
122 explicit SymbolLayerItem( QgsSymbolLayer *layer, Qgis::SymbolType symbolType, QgsVectorLayer *vectorLayer, QScreen *screen )
123 : mVectorLayer( vectorLayer )
124 , mScreen( screen )
125 {
126 setLayer( layer, symbolType );
127 }
128
129 explicit SymbolLayerItem( QgsSymbol *symbol, QgsVectorLayer *vectorLayer, QScreen *screen )
130 : mVectorLayer( vectorLayer )
131 , mScreen( screen )
132 {
133 setSymbol( symbol );
134 }
135
136 void setLayer( QgsSymbolLayer *layer, Qgis::SymbolType symbolType )
137 {
138 mLayer = layer;
139 mIsLayer = true;
140 mSymbol = nullptr;
141 mSymbolType = symbolType;
142 updatePreview();
143 }
144
145 void setSymbol( QgsSymbol *symbol )
146 {
147 mSymbol = symbol;
148 mIsLayer = false;
149 mLayer = nullptr;
150 updatePreview();
151 }
152
153 void updatePreview()
154 {
155 if ( !mSize.isValid() )
156 {
157 const int size = QgsGuiUtils::scaleIconSize( 16 );
158 mSize = QSize( size, size );
159 }
160 QIcon icon;
161 if ( mIsLayer )
162 icon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( mLayer, Qgis::RenderUnit::Millimeters, mSize, QgsMapUnitScale(), mSymbol ? mSymbol->type() : mSymbolType, mVectorLayer, QgsScreenProperties( mScreen.data() ) );
163 else
164 {
165 QgsExpressionContext expContext;
167 icon = QIcon( QgsSymbolLayerUtils::symbolPreviewPixmap( mSymbol, mSize, 0, nullptr, false, &expContext, nullptr, QgsScreenProperties( mScreen.data() ) ) );
168 }
169 setIcon( icon );
170
171 if ( auto *lParent = parent() )
172 static_cast<SymbolLayerItem *>( lParent )->updatePreview();
173 }
174
175 int type() const override { return SYMBOL_LAYER_ITEM_TYPE; }
176 bool isLayer() { return mIsLayer; }
177
178 // returns the symbol pointer; helpful in determining a layer's parent symbol
179 QgsSymbol *symbol()
180 {
181 return mSymbol;
182 }
183
184 QgsSymbolLayer *layer()
185 {
186 return mLayer;
187 }
188
189 QVariant data( int role ) const override
190 {
191 if ( role == Qt::DisplayRole || role == Qt::EditRole )
192 {
193 if ( mIsLayer )
194 {
196 if ( m )
197 return m->visibleName();
198 else
199 return QString();
200 }
201 else
202 {
203 switch ( mSymbol->type() )
204 {
206 return QCoreApplication::translate( "SymbolLayerItem", "Marker" );
208 return QCoreApplication::translate( "SymbolLayerItem", "Fill" );
210 return QCoreApplication::translate( "SymbolLayerItem", "Line" );
211 default:
212 return "Symbol";
213 }
214 }
215 }
216 else if ( role == Qt::ForegroundRole && mIsLayer )
217 {
218 if ( !mLayer->enabled() )
219 {
220 QPalette pal = qApp->palette();
221 QBrush brush = QStandardItem::data( role ).value< QBrush >();
222 brush.setColor( pal.color( QPalette::Disabled, QPalette::WindowText ) );
223 return brush;
224 }
225 else
226 {
227 return QVariant();
228 }
229 }
230
231// if ( role == Qt::SizeHintRole )
232// return QVariant( QSize( 32, 32 ) );
233 if ( role == Qt::CheckStateRole )
234 return QVariant(); // could be true/false
235 return QStandardItem::data( role );
236 }
237
238 protected:
239 QgsSymbolLayer *mLayer = nullptr;
240 QgsSymbol *mSymbol = nullptr;
241 QPointer< QgsVectorLayer > mVectorLayer;
242 bool mIsLayer = false;
243 QSize mSize;
245 QPointer< QScreen > mScreen;
246};
247
249
251
253 : QgsPanelWidget( parent )
254 , mStyle( style )
255 , mSymbol( symbol )
256 , mVectorLayer( vl )
257{
258#ifdef Q_OS_MAC
259 setWindowModality( Qt::WindowModal );
260#endif
261
262 setupUi( this );
263 this->layout()->setContentsMargins( 0, 0, 0, 0 );
264
265 layersTree->setMaximumHeight( static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 7 ) );
266 layersTree->setMinimumHeight( layersTree->maximumHeight() );
267 lblPreview->setMaximumWidth( layersTree->maximumHeight() );
268
269 // setup icons
270 btnAddLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
271 btnRemoveLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
272 QIcon iconLock;
273 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
274 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
275 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
276 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
277
278 QIcon iconColorLock;
279 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorLocked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
280 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorLocked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
281 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorUnlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
282 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorUnlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
283
284 mLockColorAction = new QAction( tr( "Lock Color" ), this );
285 mLockColorAction->setToolTip( tr( "Avoid changing the color of the layer when the symbol color is changed" ) );
286 mLockColorAction->setCheckable( true );
287 mLockColorAction->setIcon( iconColorLock );
288
289 QIcon iconSelectLock;
290 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectLocked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
291 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectLocked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
292 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectUnlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
293 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectUnlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
294
295 mLockSelectionColorAction = new QAction( tr( "Lock Color When Selected" ), this );
296 mLockSelectionColorAction->setToolTip( tr( "Avoid changing the color of the layer when a feature is selected" ) );
297 mLockSelectionColorAction->setCheckable( true );
298 mLockSelectionColorAction->setIcon( iconSelectLock );
299
300 QMenu *lockMenu = new QMenu( this );
301 lockMenu->addAction( mLockColorAction );
302 lockMenu->addAction( mLockSelectionColorAction );
303 btnLock->setMenu( lockMenu );
304 btnLock->setPopupMode( QToolButton::InstantPopup );
305
306 btnDuplicate->setIcon( QIcon( QgsApplication::iconPath( "mActionDuplicateLayer.svg" ) ) );
307 btnUp->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowUp.svg" ) ) );
308 btnDown->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowDown.svg" ) ) );
309
310 mSymbolLayersModel = new QStandardItemModel( layersTree );
311 // Set the symbol
312 layersTree->setModel( mSymbolLayersModel );
313 layersTree->setHeaderHidden( true );
314
315 //get first feature from layer for previews
316 if ( mVectorLayer )
317 {
318#if 0 // this is too expensive to do for many providers. TODO revisit when support for connection timeouts is complete across all providers
319 // short timeout for request - it doesn't really matter if we don't get the feature, and this call is blocking UI
320 QgsFeatureIterator it = mVectorLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ).setConnectionTimeout( 100 ) );
321 it.nextFeature( mPreviewFeature );
322#endif
323 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mVectorLayer ) );
324#if 0
325 mPreviewExpressionContext.setFeature( mPreviewFeature );
326#endif
327 }
328 else
329 {
330 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
331 }
332
333 QItemSelectionModel *selModel = layersTree->selectionModel();
334 connect( selModel, &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
335
336 loadSymbol( mSymbol, static_cast<SymbolLayerItem *>( mSymbolLayersModel->invisibleRootItem() ) );
338
339 connect( btnUp, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerUp );
340 connect( btnDown, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerDown );
341 connect( btnAddLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::addLayer );
342 connect( btnRemoveLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::removeLayer );
343 connect( mLockColorAction, &QAction::toggled, this, &QgsSymbolSelectorWidget::lockLayer );
344 connect( mLockSelectionColorAction, &QAction::toggled, this, [ = ]( bool checked )
345 {
346 QgsSymbolLayer *layer = currentLayer();
347 if ( !layer )
348 return;
349
350 Qgis::SymbolLayerUserFlags flags = layer->userFlags();
352 layer->setUserFlags( flags );
353 updateLockButtonIcon();
354 emit symbolModified();
355 } );
356 connect( btnDuplicate, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::duplicateLayer );
358
359 updateLockButtonIcon();
360
361 updateUi();
362
363 // set symbol as active item in the tree
364 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
365 layersTree->setCurrentIndex( newIndex );
366
367 setPanelTitle( tr( "Symbol Selector" ) );
368
369 // when a remote svg has been fetched, update the widget's previews
370 // this is required if the symbol utilizes remote svgs, and the current previews
371 // have been generated using the temporary "downloading" svg. In this case
372 // we require the preview to be regenerated to use the correct fetched
373 // svg
374 connect( QgsApplication::svgCache(), &QgsSvgCache::remoteSvgFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
375
376 // when a remote image has been fetched, update the widget's previews
377 // this is required if the symbol utilizes remote images, and the current previews
378 // have been generated using the temporary "downloading" image. In this case
379 // we require the preview to be regenerated to use the correct fetched
380 // image
381 connect( QgsApplication::imageCache(), &QgsImageCache::remoteImageFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
382
383 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
384 // need updating to reflect the new colors
385 connect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsSymbolSelectorWidget::projectDataChanged );
386
387 connect( QgsProject::instance(), static_cast < void ( QgsProject::* )( const QList<QgsMapLayer *>& layers ) > ( &QgsProject::layersWillBeRemoved ), this, &QgsSymbolSelectorWidget::layersAboutToBeRemoved );
388}
389
390QgsSymbolSelectorWidget *QgsSymbolSelectorWidget::createWidgetWithSymbolOwnership( std::unique_ptr<QgsSymbol> symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent )
391{
392 QgsSymbolSelectorWidget *widget = new QgsSymbolSelectorWidget( symbol.get(), style, vl, parent );
393 // transfer ownership of symbol to widget, so that we are guaranteed it will last for the duration of the widget
394 widget->mOwnedSymbol = std::move( symbol );
395 return widget;
396}
397
399{
400 if ( !mAdvancedMenu )
401 {
402 mAdvancedMenu = new QMenu( this );
403 // Brute force method to activate the Advanced menu
404 layerChanged();
405 }
406 return mAdvancedMenu;
407}
408
410{
411 mContext = context;
412
413 if ( auto *lExpressionContext = mContext.expressionContext() )
414 {
415 mPreviewExpressionContext = *lExpressionContext;
416 if ( mVectorLayer )
417 mPreviewExpressionContext.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer ) );
418
419 mPreviewExpressionContext.setFeature( mPreviewFeature );
420 }
421
422 QWidget *widget = stackedWidget->currentWidget();
423 if ( QgsLayerPropertiesWidget *layerProp = qobject_cast< QgsLayerPropertiesWidget * >( widget ) )
424 layerProp->setContext( context );
425 else if ( QgsSymbolsListWidget *listWidget = qobject_cast< QgsSymbolsListWidget * >( widget ) )
426 listWidget->setContext( context );
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
677 ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedSize()
678 : QgsProperty() );
679 const QgsProperty ddAngle( parentSymbol->type() == Qgis::SymbolType::Marker
680 ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedAngle()
681 : QgsProperty() );
682 const QgsProperty ddWidth( parentSymbol->type() == Qgis::SymbolType::Line
683 ? static_cast<QgsLineSymbol *>( parentSymbol )->dataDefinedWidth()
684 : QgsProperty() );
685
687 if ( insertIdx == -1 )
688 parentSymbol->appendSymbolLayer( newLayer );
689 else
690 parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );
691
692 // restore data-defined values at marker level
693 if ( ddSize )
694 static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedSize( ddSize );
695 if ( ddAngle )
696 static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedAngle( ddAngle );
697 if ( ddWidth )
698 static_cast<QgsLineSymbol *>( parentSymbol )->setDataDefinedWidth( ddWidth );
699
700 SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer, parentSymbol->type(), mVectorLayer, screen() );
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 mContext = context;
886}
887
889{
890 return mContext;
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:844
@ 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:5627
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.
This class 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:209
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 a 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.
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.
QgsSymbolLayerAbstractMetadata * symbolLayerMetadata(const QString &name) const
Returns metadata for specified symbol layer. Returns nullptr if not found.
static QgsSymbolLayer * defaultSymbolLayer(Qgis::SymbolType type)
create a new instance of symbol layer for specified symbol type with default settings
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.
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:352
Qgis::SymbolType type() const
Returns the symbol's type.
Definition qgssymbol.h:293
void changed()
Emitted when the symbol is modified in the widget.
Represents a vector layer which manages a vector based data sets.
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:6494
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6493