QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgslegendpatchshapebutton.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslegendpatchshapebutton.cpp
3  -----------------
4  Date : April 2020
5  Copyright : (C) 2020 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 
18 #include "qgis.h"
19 #include "qgsguiutils.h"
20 #include "qgsfillsymbol.h"
21 #include "qgsmarkersymbol.h"
22 #include "qgslinesymbol.h"
23 
24 #include <QMenu>
25 #include <QBuffer>
26 
27 QgsLegendPatchShapeButton::QgsLegendPatchShapeButton( QWidget *parent, const QString &dialogTitle )
28  : QToolButton( parent )
29  , mShape( QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) ) )
30  , mDialogTitle( dialogTitle.isEmpty() ? tr( "Legend Patch Shape" ) : dialogTitle )
31 {
32  mPreviewSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
33 
34  connect( this, &QAbstractButton::clicked, this, &QgsLegendPatchShapeButton::showSettingsDialog );
35 
36  //setup dropdown menu
37  mMenu = new QMenu( this );
38  connect( mMenu, &QMenu::aboutToShow, this, &QgsLegendPatchShapeButton::prepareMenu );
39  setMenu( mMenu );
40  setPopupMode( QToolButton::MenuButtonPopup );
41 
42  //make sure height of button looks good under different platforms
43  QSize size = QToolButton::minimumSizeHint();
44  int fontHeight = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2.0 );
45  mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight ) );
46 }
47 
49 
51 {
52  return mSizeHint;
53 }
54 
56 {
57  return mSizeHint;
58 }
59 
61 {
62  if ( mPreviewSymbol->type() != type )
63  {
64  switch ( type )
65  {
67  mPreviewSymbol.reset( QgsMarkerSymbol::createSimple( QVariantMap() ) );
68  break;
69 
71  mPreviewSymbol.reset( QgsLineSymbol::createSimple( QVariantMap() ) );
72  break;
73 
75  mPreviewSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
76  break;
77 
79  break;
80  }
81  }
82 
83  if ( type != mType )
84  {
85  mType = type;
86  setToDefault();
87  }
88 
89  updatePreview();
90 }
91 
93 {
94  mPreviewSymbol.reset( symbol );
95  updatePreview();
96 }
97 
98 void QgsLegendPatchShapeButton::showSettingsDialog()
99 {
101  if ( panel && panel->dockMode() )
102  {
103  QgsLegendPatchShapeWidget *widget = new QgsLegendPatchShapeWidget( this, mShape );
104  connect( widget, &QgsLegendPatchShapeWidget::changed, this, [ = ]
105  {
106  setShape( widget->shape() );
107  } );
108  widget->setPanelTitle( mDialogTitle );
109  panel->openPanel( widget );
110  }
111 }
112 
114 {
115  switch ( mType )
116  {
118  mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
119  break;
120 
122  mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
123  break;
124 
126  mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
127  break;
128 
130  break;
131  }
132  mIsDefault = true;
133  updatePreview();
134  emit changed();
135 }
136 
138 {
139  mMessageBar = bar;
140 }
141 
143 {
144  return mMessageBar;
145 }
146 
148 {
149  mShape = shape.symbolType() == mType ? shape : QgsLegendPatchShape();
150  mIsDefault = mShape.isNull();
151  if ( mIsDefault )
152  {
153  switch ( mType )
154  {
156  mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
157  break;
158 
160  mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
161  break;
162 
164  mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
165  break;
166 
168  break;
169  }
170  }
171 
172  updatePreview();
173  emit changed();
174 }
175 
177 {
178  if ( e->button() == Qt::RightButton )
179  {
180  QToolButton::showMenu();
181  return;
182  }
183  QToolButton::mousePressEvent( e );
184 }
185 
186 void QgsLegendPatchShapeButton::prepareMenu()
187 {
188  mMenu->clear();
189 
190  QAction *configureAction = new QAction( tr( "Configure Patch…" ), this );
191  mMenu->addAction( configureAction );
192  connect( configureAction, &QAction::triggered, this, &QgsLegendPatchShapeButton::showSettingsDialog );
193 
194  QAction *defaultAction = new QAction( tr( "Reset to Default" ), this );
195  mMenu->addAction( defaultAction );
196  connect( defaultAction, &QAction::triggered, this, [ = ] { setToDefault(); emit changed(); } );
197 
198  mMenu->addSeparator();
199 
201  patchNames.sort();
202  const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
203  for ( const QString &name : std::as_const( patchNames ) )
204  {
206  if ( shape.symbolType() == mType )
207  {
208  if ( const QgsSymbol *symbol = QgsStyle::defaultStyle()->previewSymbolForPatchShape( shape ) )
209  {
210  QIcon icon = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol, QSize( iconSize, iconSize ), 1, nullptr, false, nullptr, &shape );
211  QAction *action = new QAction( name, this );
212  action->setIcon( icon );
213  connect( action, &QAction::triggered, this, [ = ] { loadPatchFromStyle( name ); } );
214  mMenu->addAction( action );
215  }
216  }
217  }
218 }
219 
220 void QgsLegendPatchShapeButton::loadPatchFromStyle( const QString &name )
221 {
222  if ( !QgsStyle::defaultStyle()->legendPatchShapeNames().contains( name ) )
223  return;
224 
225  const QgsLegendPatchShape newShape = QgsStyle::defaultStyle()->legendPatchShape( name );
226  setShape( newShape );
227 }
228 
230 {
231  if ( e->type() == QEvent::EnabledChange )
232  {
233  updatePreview();
234  }
235  QToolButton::changeEvent( e );
236 }
237 
239 {
240  updatePreview();
241  QToolButton::showEvent( e );
242 }
243 
244 void QgsLegendPatchShapeButton::resizeEvent( QResizeEvent *event )
245 {
246  QToolButton::resizeEvent( event );
247  //recalculate icon size and redraw icon
248  mIconSize = QSize();
249  updatePreview();
250 }
251 
252 void QgsLegendPatchShapeButton::updatePreview()
253 {
254  QSize currentIconSize;
255  //icon size is button size with a small margin
256  if ( menu() )
257  {
258  if ( !mIconSize.isValid() )
259  {
260  //calculate size of push button part of widget (ie, without the menu dropdown button part)
261  QStyleOptionToolButton opt;
262  initStyleOption( &opt );
263  QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
264  this );
265  //make sure height of icon looks good under different platforms
266 #ifdef Q_OS_WIN
267  mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
268 #else
269  mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
270 #endif
271  }
272  currentIconSize = mIconSize;
273  }
274  else
275  {
276  //no menu
277 #ifdef Q_OS_WIN
278  currentIconSize = QSize( width() - 10, height() - 6 );
279 #else
280  currentIconSize = QSize( width() - 10, height() - 12 );
281 #endif
282  }
283 
284  if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
285  {
286  return;
287  }
288 
289  //create an icon pixmap
290  QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mPreviewSymbol.get(), currentIconSize, currentIconSize.height() / 10, &mShape );
291  setIconSize( currentIconSize );
292  setIcon( icon );
293 
294  // set tooltip
295  // create very large preview image
296 
297  int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 23 );
298  int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
299 
300  QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( mPreviewSymbol.get(), QSize( width, height ), height / 20, nullptr, false, nullptr, &mShape );
301  QByteArray data;
302  QBuffer buffer( &data );
303  pm.save( &buffer, "PNG", 100 );
304  setToolTip( QStringLiteral( "<img src='data:image/png;base64, %3'>" ).arg( QString( data.toBase64() ) ) );
305 }
306 
307 void QgsLegendPatchShapeButton::setDialogTitle( const QString &title )
308 {
309  mDialogTitle = title;
310 }
311 
313 {
314  return mDialogTitle;
315 }
316 
318 {
319  return mIsDefault ? QgsLegendPatchShape() : mShape;
320 }
QgsLegendPatchShapeButton::changed
void changed()
Emitted when the shape's settings are changed.
QgsLegendPatchShapeButton::QgsLegendPatchShapeButton
QgsLegendPatchShapeButton(QWidget *parent=nullptr, const QString &dialogTitle=QString())
Construct a new patch shape button with the specified parent widget.
Definition: qgslegendpatchshapebutton.cpp:27
Qgis::SymbolType::Fill
@ Fill
Fill symbol.
Qgis::SymbolType::Line
@ Line
Line symbol.
QgsPanelWidget::findParentPanel
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
Definition: qgspanelwidget.cpp:54
QgsStyle::symbolsOfFavorite
QStringList symbolsOfFavorite(StyleEntity type) const
Returns the symbol names which are flagged as favorite.
Definition: qgsstyle.cpp:1301
QgsLegendPatchShapeButton::mousePressEvent
void mousePressEvent(QMouseEvent *e) override
Definition: qgslegendpatchshapebutton.cpp:176
QgsLegendPatchShapeButton::showEvent
void showEvent(QShowEvent *e) override
Definition: qgslegendpatchshapebutton.cpp:238
QgsLegendPatchShapeButton::~QgsLegendPatchShapeButton
~QgsLegendPatchShapeButton() override
QgsPanelWidget::openPanel
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
Definition: qgspanelwidget.cpp:84
qgis.h
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:92
QgsStyle::LegendPatchShapeEntity
@ LegendPatchShapeEntity
Legend patch shape (since QGIS 3.14)
Definition: qgsstyle.h:186
QgsLegendPatchShapeButton::setSymbolType
void setSymbolType(Qgis::SymbolType type)
Sets the symbol type which the button requires.
Definition: qgslegendpatchshapebutton.cpp:60
QgsPanelWidget::dockMode
bool dockMode()
Returns the dock mode state.
Definition: qgspanelwidget.h:93
QgsLineSymbol::createSimple
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
Definition: qgslinesymbol.cpp:22
QgsLegendPatchShapeButton::shape
QgsLegendPatchShape shape()
Returns the current shape defined by the button.
Definition: qgslegendpatchshapebutton.cpp:317
QgsLegendPatchShape
Represents a patch shape for use in map legends.
Definition: qgslegendpatchshape.h:33
QgsGuiUtils::iconSize
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
Definition: qgsguiutils.cpp:264
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
QgsLegendPatchShapeButton::minimumSizeHint
QSize minimumSizeHint() const override
Definition: qgslegendpatchshapebutton.cpp:50
QgsSymbolLayerUtils::symbolPreviewIcon
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr)
Returns an icon preview for a color ramp.
Definition: qgssymbollayerutils.cpp:871
QgsPanelWidget
Base class for any widget that can be shown as a inline panel.
Definition: qgspanelwidget.h:29
QgsSymbolLayerUtils::symbolPreviewPixmap
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)
Returns a pixmap preview for a color ramp.
Definition: qgssymbollayerutils.cpp:876
Qgis::SymbolType
SymbolType
Symbol types.
Definition: qgis.h:205
QgsLegendPatchShapeWidget
Widget for configuring a custom legend patch shape.
Definition: qgslegendpatchshapewidget.h:32
QgsLegendPatchShapeWidget::shape
QgsLegendPatchShape shape() const
Returns the legend patch shape as currently defined by the widget.
Definition: qgslegendpatchshapewidget.cpp:43
QgsMessageBar
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:60
QgsLegendPatchShapeButton::messageBar
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
Definition: qgslegendpatchshapebutton.cpp:142
Qgis::UI_SCALE_FACTOR
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:2043
QgsFillSymbol::createSimple
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
Definition: qgsfillsymbol.cpp:20
QgsPanelWidget::setPanelTitle
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
Definition: qgspanelwidget.h:44
QgsLegendPatchShapeButton::setMessageBar
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
Definition: qgslegendpatchshapebutton.cpp:137
QgsLegendPatchShapeWidget::changed
void changed()
Emitted whenever the patch shape defined by the widget is changed.
QgsLegendPatchShapeButton::resizeEvent
void resizeEvent(QResizeEvent *event) override
Definition: qgslegendpatchshapebutton.cpp:244
QgsLegendPatchShapeButton::dialogTitle
QString dialogTitle() const
Returns the title for the symbol settings dialog window.
Definition: qgslegendpatchshapebutton.cpp:312
Qgis::SymbolType::Hybrid
@ Hybrid
Hybrid symbol.
QgsStyle::legendPatchShape
QgsLegendPatchShape legendPatchShape(const QString &name) const
Returns the legend patch shape with the specified name.
Definition: qgsstyle.cpp:2145
QgsStyle
Definition: qgsstyle.h:159
qgsmarkersymbol.h
QgsLegendPatchShapeButton::setToDefault
void setToDefault()
Resets the shape to the default shape.
Definition: qgslegendpatchshapebutton.cpp:113
QgsLegendPatchShapeButton::setPreviewSymbol
void setPreviewSymbol(QgsSymbol *symbol)
Sets the symbol to use for previewing the legend patch shape.
Definition: qgslegendpatchshapebutton.cpp:92
QgsLegendPatchShapeButton::sizeHint
QSize sizeHint() const override
Definition: qgslegendpatchshapebutton.cpp:55
QgsLegendPatchShape::symbolType
Qgis::SymbolType symbolType() const
Returns the symbol type associated with this patch.
Definition: qgslegendpatchshape.cpp:229
QgsStyle::defaultPatch
QgsLegendPatchShape defaultPatch(Qgis::SymbolType type, QSizeF size) const
Returns the default legend patch shape for the given symbol type.
Definition: qgsstyle.cpp:1157
QgsLegendPatchShapeButton::changeEvent
void changeEvent(QEvent *e) override
Definition: qgslegendpatchshapebutton.cpp:229
Qgis
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:71
qgslegendpatchshapebutton.h
qgsguiutils.h
QgsGuiUtils::scaleIconSize
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
Definition: qgsguiutils.cpp:259
QgsMarkerSymbol::createSimple
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgsmarkersymbol.cpp:22
qgsfillsymbol.h
Qgis::SymbolType::Marker
@ Marker
Marker symbol.
QgsLegendPatchShapeButton::setDialogTitle
void setDialogTitle(const QString &title)
Sets the title for the symbol settings dialog window.
Definition: qgslegendpatchshapebutton.cpp:307
qgslinesymbol.h
QgsLegendPatchShapeButton::setShape
void setShape(const QgsLegendPatchShape &shape)
Sets the shape for the button.
Definition: qgslegendpatchshapebutton.cpp:147
qgslegendpatchshapewidget.h
QgsLegendPatchShape::isNull
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
Definition: qgslegendpatchshape.cpp:32