QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsratiolockbutton.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsratiolockbutton.cpp - Lock button
3 --------------------------------------
4 Date : July, 2017
5 Copyright : (C) 2017 by Mathieu Pellerin
6 Email : nirvn dot asia at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsratiolockbutton.h"
17#include "qgsapplication.h"
18#include "qgssvgcache.h"
19#include "qgis.h"
20
21#include <QApplication>
22#include <QMouseEvent>
23#include <QPainter>
24#include <QPushButton>
25#include <QWidget>
26#include <QDoubleSpinBox>
27
29 : QToolButton( parent )
30{
31 setMinimumSize( QSize( 24, 24 ) );
32 setMaximumWidth( fontMetrics().horizontalAdvance( '0' ) * 3 );
33 setCheckable( true );
34 setAutoRaise( true );
35 connect( this, &QPushButton::clicked, this, &QgsRatioLockButton::buttonClicked );
36}
37
38void QgsRatioLockButton::setLocked( const bool locked )
39{
40 if ( mLocked != locked )
41 buttonClicked();
42}
43
44void QgsRatioLockButton::buttonClicked()
45{
46 mLocked = !mLocked;
47 setDown( mLocked );
48
49 emit lockChanged( mLocked );
50
51 drawButton();
52}
53
54void QgsRatioLockButton::widthSpinBoxChanged( double value )
55{
56 if ( mUpdatingRatio || qgsDoubleNear( value, 0.0 ) || qgsDoubleNear( mPrevWidth, 0.0 )
57 || qgsDoubleNear( mPrevHeight, 0.0 ) || !mHeightSpinBox || !mLocked )
58 {
59 mPrevWidth = value;
60 return;
61 }
62
63 const double oldRatio = mPrevHeight / mPrevWidth;
64 mUpdatingRatio = true;
65 mHeightSpinBox->setValue( oldRatio * value );
66 mUpdatingRatio = false;
67 mPrevWidth = value;
68}
69
70void QgsRatioLockButton::heightSpinBoxChanged( double value )
71{
72 if ( mUpdatingRatio || qgsDoubleNear( value, 0.0 ) || qgsDoubleNear( mPrevWidth, 0.0 )
73 || qgsDoubleNear( mPrevHeight, 0.0 ) || !mWidthSpinBox || !mLocked )
74 {
75 mPrevHeight = value;
76 return;
77 }
78
79 const double oldRatio = mPrevWidth / mPrevHeight;
80 mUpdatingRatio = true;
81 mWidthSpinBox->setValue( oldRatio * value );
82 mUpdatingRatio = false;
83 mPrevHeight = value;
84}
85
87{
88 if ( e->type() == QEvent::EnabledChange )
89 {
90 drawButton();
91 }
92 QToolButton::changeEvent( e );
93}
94
95void QgsRatioLockButton::showEvent( QShowEvent *e )
96{
97 drawButton();
98 QToolButton::showEvent( e );
99}
100
101void QgsRatioLockButton::resizeEvent( QResizeEvent *event )
102{
103 QToolButton::resizeEvent( event );
104 drawButton();
105}
106
107void QgsRatioLockButton::drawButton()
108{
109 QSize currentIconSize;
110
111#ifdef Q_OS_WIN
112 currentIconSize = QSize( width() - 10, height() - 6 );
113#else
114 currentIconSize = QSize( width() - 10, height() - 12 );
115#endif
116
117 if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
118 {
119 return;
120 }
121
122 const double pixelRatio = devicePixelRatioF();
123 QPixmap pm( currentIconSize * pixelRatio );
124 pm.setDevicePixelRatio( pixelRatio );
125 pm.fill( Qt::transparent );
126
127 QPainter painter;
128 QPen pen = QPen( QColor( 136, 136, 136 ) );
129 pen.setWidth( 2 );
130
131 painter.begin( &pm );
132 painter.setRenderHint( QPainter::Antialiasing, true );
133 painter.setPen( pen );
134
135 painter.drawLine( QPointF( 1, 1 ), QPointF( currentIconSize.width() / 2, 1 ) );
136 painter.drawLine( QPointF( currentIconSize.width() / 2, 1 ), QPointF( currentIconSize.width() / 2, currentIconSize.height() / 2 - 13 ) );
137 painter.drawLine( QPointF( currentIconSize.width() / 2, currentIconSize.height() / 2 + 13 ), QPointF( currentIconSize.width() / 2, currentIconSize.height() - 2 ) );
138 painter.drawLine( QPointF( currentIconSize.width() / 2, currentIconSize.height() - 2 ), QPointF( 1, currentIconSize.height() - 2 ) );
139
140 const QString imageSource = mLocked ? QStringLiteral( ":/images/themes/default/lockedGray.svg" ) : QStringLiteral( ":/images/themes/default/unlockedGray.svg" );
141 bool fitsInCache = false;
142 QImage image = QgsApplication::svgCache()->svgAsImage(
143 imageSource, 16 * pixelRatio, QColor(), QColor(), 0, 1, fitsInCache
144 );
145 image.setDevicePixelRatio( pixelRatio );
146 painter.drawImage( QRectF(
147 currentIconSize.width() / 2 - 8,
148 currentIconSize.height() / 2 - 8,
149 16,
150 16 ),
151 image );
152
153 painter.end();
154
155 setIconSize( currentIconSize );
156 setIcon( pm );
157}
158
159void QgsRatioLockButton::setWidthSpinBox( QDoubleSpinBox *widget )
160{
161 mWidthSpinBox = widget;
162 mPrevWidth = widget->value();
163 connect( mWidthSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsRatioLockButton::widthSpinBoxChanged );
164}
165
166void QgsRatioLockButton::setHeightSpinBox( QDoubleSpinBox *widget )
167{
168 mHeightSpinBox = widget;
169 mPrevHeight = widget->value();
170 connect( mHeightSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsRatioLockButton::heightSpinBoxChanged );
171}
172
174{
175 mPrevWidth = mWidthSpinBox ? mWidthSpinBox->value() : 0.0;
176 mPrevHeight = mHeightSpinBox ? mHeightSpinBox->value() : 0.0;
177}
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
void setHeightSpinBox(QDoubleSpinBox *widget)
Registers a spin box widget as the linked "height" spin box.
void setLocked(bool locked)
Sets whether the button state is locked.
void resetRatio()
Resets the current width/height ratio, taking the width and height from the current values of the wid...
void changeEvent(QEvent *e) override
void resizeEvent(QResizeEvent *event) override
QgsRatioLockButton(QWidget *parent=nullptr)
Construct a new ratio lock button.
void showEvent(QShowEvent *e) override
void lockChanged(bool locked)
Emitted whenever the lock state changes.
void setWidthSpinBox(QDoubleSpinBox *widget)
Registers a spin box widget as the linked "width" spin box.
QImage svgAsImage(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > &parameters=QMap< QString, QString >())
Returns an SVG drawing as a QImage.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207