Skip to content
Permalink
Browse files

Merge pull request #4899 from nyalldawson/ratio_lock

Allow setting width/height spin boxes to link to QgsRatioLockButton
  • Loading branch information
nyalldawson committed Jul 21, 2017
2 parents eb5ac44 + 38c8268 commit db74133759c50b4a6b28ae55999090053f7879ac
@@ -9,6 +9,7 @@




class QgsRatioLockButton : QToolButton
{
%Docstring
@@ -42,6 +43,30 @@ class QgsRatioLockButton : QToolButton
:rtype: bool
%End

void setWidthSpinBox( QDoubleSpinBox *widget );
%Docstring
Registers a spin box ``widget`` as the linked "width" spin box.

If both a width and height spin box are linked to the button, they will automatically
have their values updates when if the other spin box value is changed. I.e. changing the
width spin box will automatically update the height spin box to a value which keeps the
same locked ratio.

.. seealso:: setHeightSpinBox()
%End

void setHeightSpinBox( QDoubleSpinBox *widget );
%Docstring
Registers a spin box ``widget`` as the linked "height" spin box.

If both a width and height spin box are linked to the button, they will automatically
have their values updates when if the other spin box value is changed. I.e. changing the
width spin box will automatically update the height spin box to a value which keeps the
same locked ratio.

.. seealso:: setWidthSpinBox()
%End

signals:

void lockChanged( const bool locked );
@@ -20,6 +20,7 @@
#include <QPainter>
#include <QPushButton>
#include <QWidget>
#include <QDoubleSpinBox>

QgsRatioLockButton::QgsRatioLockButton( QWidget *parent )
: QToolButton( parent )
@@ -48,6 +49,38 @@ void QgsRatioLockButton::buttonClicked()
drawButton();
}

void QgsRatioLockButton::widthSpinBoxChanged( double value )
{
if ( mUpdatingRatio || qgsDoubleNear( value, 0.0 ) || qgsDoubleNear( mPrevWidth, 0.0 )
|| qgsDoubleNear( mPrevHeight, 0.0 ) || !mHeightSpinBox || !mLocked )
{
mPrevWidth = value;
return;
}

double oldRatio = mPrevHeight / mPrevWidth;
mUpdatingRatio = true;
mHeightSpinBox->setValue( oldRatio * value );
mUpdatingRatio = false;
mPrevWidth = value;
}

void QgsRatioLockButton::heightSpinBoxChanged( double value )
{
if ( mUpdatingRatio || qgsDoubleNear( value, 0.0 ) || qgsDoubleNear( mPrevWidth, 0.0 )
|| qgsDoubleNear( mPrevHeight, 0.0 ) || !mWidthSpinBox || !mLocked )
{
mPrevHeight = value;
return;
}

double oldRatio = mPrevWidth / mPrevHeight;
mUpdatingRatio = true;
mWidthSpinBox->setValue( oldRatio * value );
mUpdatingRatio = false;
mPrevHeight = value;
}

void QgsRatioLockButton::changeEvent( QEvent *e )
{
if ( e->type() == QEvent::EnabledChange )
@@ -108,3 +141,17 @@ void QgsRatioLockButton::drawButton()
setIconSize( currentIconSize );
setIcon( pm );
}

void QgsRatioLockButton::setWidthSpinBox( QDoubleSpinBox *widget )
{
mWidthSpinBox = widget;
mPrevWidth = widget->value();
connect( mWidthSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsRatioLockButton::widthSpinBoxChanged );
}

void QgsRatioLockButton::setHeightSpinBox( QDoubleSpinBox *widget )
{
mHeightSpinBox = widget;
mPrevHeight = widget->value();
connect( mHeightSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsRatioLockButton::heightSpinBoxChanged );
}
@@ -22,6 +22,9 @@
#include "qgis_gui.h"
#include "qgis.h"

#include <QPointer>
class QDoubleSpinBox;

/** \ingroup gui
* \class QgsRatioLockButton
* A cross platform button subclass used to represent a locked / unlocked ratio state.
@@ -51,6 +54,30 @@ class GUI_EXPORT QgsRatioLockButton : public QToolButton
*/
bool locked() const { return mLocked; }

/**
* Registers a spin box \a widget as the linked "width" spin box.
*
* If both a width and height spin box are linked to the button, they will automatically
* have their values updates when if the other spin box value is changed. I.e. changing the
* width spin box will automatically update the height spin box to a value which keeps the
* same locked ratio.
*
* \see setHeightSpinBox()
*/
void setWidthSpinBox( QDoubleSpinBox *widget );

/**
* Registers a spin box \a widget as the linked "height" spin box.
*
* If both a width and height spin box are linked to the button, they will automatically
* have their values updates when if the other spin box value is changed. I.e. changing the
* width spin box will automatically update the height spin box to a value which keeps the
* same locked ratio.
*
* \see setWidthSpinBox()
*/
void setHeightSpinBox( QDoubleSpinBox *widget );

signals:

/** Emitted whenever the lock state changes.
@@ -69,10 +96,19 @@ class GUI_EXPORT QgsRatioLockButton : public QToolButton

bool mLocked = false;

QPointer< QDoubleSpinBox > mWidthSpinBox;
double mPrevWidth = 0;
QPointer< QDoubleSpinBox > mHeightSpinBox;
double mPrevHeight = 0;
bool mUpdatingRatio = false;

private slots:

void buttonClicked();

void widthSpinBoxChanged( double value );
void heightSpinBoxChanged( double value );

};

#endif
@@ -115,6 +115,7 @@ ADD_PYTHON_TEST(PyQgsRasterFileWriter test_qgsrasterfilewriter.py)
ADD_PYTHON_TEST(PyQgsRasterFileWriterTask test_qgsrasterfilewritertask.py)
ADD_PYTHON_TEST(PyQgsRasterLayer test_qgsrasterlayer.py)
ADD_PYTHON_TEST(PyQgsRasterColorRampShader test_qgsrastercolorrampshader.py)
ADD_PYTHON_TEST(PyQgsRatioLockButton test_qgsratiolockbutton.py)
ADD_PYTHON_TEST(PyQgsRectangle test_qgsrectangle.py)
ADD_PYTHON_TEST(PyQgsRelation test_qgsrelation.py)
ADD_PYTHON_TEST(PyQgsRelationManager test_qgsrelationmanager.py)
@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsRatioLockButton
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nyall Dawson'
__date__ = '18/07/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import qgis # NOQA

from qgis.gui import QgsRatioLockButton

from qgis.PyQt.QtWidgets import QDoubleSpinBox

from qgis.testing import start_app, unittest

start_app()


class TestQgsRatioLockButton(unittest.TestCase):

def testLinkedWidgets(self):
""" test linking spin boxes to combobox"""
w = qgis.gui.QgsRatioLockButton()

spin_width = QDoubleSpinBox()
spin_width.setMaximum(100000)
spin_height = QDoubleSpinBox()
spin_height.setMaximum(100000)

w.setWidthSpinBox(spin_width)
spin_width.setValue(1000)
self.assertEqual(spin_width.value(), 1000)

w.setLocked(True)
spin_width.setValue(2000)
self.assertEqual(spin_width.value(), 2000)
w.setLocked(False)

w.setHeightSpinBox(spin_height)
spin_width.setValue(1000)
self.assertEqual(spin_width.value(), 1000)
self.assertEqual(spin_height.value(), 0)

w.setLocked(True)
spin_width.setValue(2000)
self.assertEqual(spin_width.value(), 2000)
self.assertEqual(spin_height.value(), 0)

spin_height.setValue(1000)
self.assertEqual(spin_width.value(), 2000)
self.assertEqual(spin_height.value(), 1000)

# ok, that was all setup tests... let's check the real thing now
spin_width.setValue(1000)
self.assertEqual(spin_width.value(), 1000)
self.assertEqual(spin_height.value(), 500)
spin_height.setValue(1000)
self.assertEqual(spin_width.value(), 2000)
self.assertEqual(spin_height.value(), 1000)

w.setLocked(False)
spin_width.setValue(1000)
self.assertEqual(spin_width.value(), 1000)
self.assertEqual(spin_height.value(), 1000)
spin_height.setValue(2000)
self.assertEqual(spin_width.value(), 1000)
self.assertEqual(spin_height.value(), 2000)

w.setLocked(True)
spin_height.setValue(1000)
self.assertEqual(spin_width.value(), 500)
self.assertEqual(spin_height.value(), 1000)

# setting to 0 should "break" lock
spin_height.setValue(0)
self.assertEqual(spin_width.value(), 500)
self.assertEqual(spin_height.value(), 0)
spin_width.setValue(1000)
self.assertEqual(spin_width.value(), 1000)
self.assertEqual(spin_height.value(), 0)
spin_height.setValue(100)
self.assertEqual(spin_width.value(), 1000)
self.assertEqual(spin_height.value(), 100)

spin_width.setValue(0)
self.assertEqual(spin_width.value(), 0)
self.assertEqual(spin_height.value(), 100)
spin_height.setValue(1000)
self.assertEqual(spin_width.value(), 0)
self.assertEqual(spin_height.value(), 1000)
spin_width.setValue(200)
self.assertEqual(spin_width.value(), 200)
self.assertEqual(spin_height.value(), 1000)


if __name__ == '__main__':
unittest.main()

0 comments on commit db74133

Please sign in to comment.
You can’t perform that action at this time.