Skip to content

Commit

Permalink
QgsLayoutUnitComboBox can be linked to spin boxes so that their
Browse files Browse the repository at this point in the history
values are automatically updated when the combo box unit changes

This means that you can flip between units and things like
the existing width and height are converted immediately to the
new unit
  • Loading branch information
nyalldawson committed Jul 25, 2017
1 parent 3e92e16 commit 3021fc8
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 5 deletions.
7 changes: 7 additions & 0 deletions python/gui/layout/qgslayoutnewitempropertiesdialog.sip
Expand Up @@ -69,6 +69,13 @@ class QgsLayoutItemPropertiesDialog : QDialog
.. seealso:: referencePoint()
%End

void setLayout( QgsLayout *layout );
%Docstring
Sets the ``layout`` associated with the dialog. This allows the dialog
to retrieve properties from the layout and perform tasks like automatic
conversion of units.
%End

};

/************************************************************************
Expand Down
28 changes: 28 additions & 0 deletions python/gui/layout/qgslayoutunitscombobox.sip
Expand Up @@ -7,6 +7,7 @@
************************************************************************/



class QgsLayoutUnitsComboBox : QComboBox
{
%Docstring
Expand Down Expand Up @@ -36,6 +37,33 @@ class QgsLayoutUnitsComboBox : QComboBox
%Docstring
Sets the ``unit`` currently selected in the combo box.
.. seealso:: unit()
%End

void linkToWidget( QDoubleSpinBox *widget );
%Docstring
Registers a spin box ``widget`` as linked with the combo box.

Registered spin boxes will automatically be upodated whenever the unit is changed. I.e. a
spin box with a value of 100 will be set to 1 when the unit is changed from centimeters to meters.

A measurement converter() must be set in order for the automatic unit conversion to occur.

.. seealso:: setConverter()
%End

QgsLayoutMeasurementConverter *converter() const;
%Docstring
Returns the converter used when automatically converting units for linked widgets.
.. seealso:: setConverter()
:rtype: QgsLayoutMeasurementConverter
%End

void setConverter( QgsLayoutMeasurementConverter *converter );
%Docstring
Sets a ``converter`` to use when automatically converting units for linked widgets.
The ownership of ``converter`` is not transferred, and converter must exist for the
life of the combo box.
.. seealso:: converter()
%End

signals:
Expand Down
13 changes: 13 additions & 0 deletions src/gui/layout/qgslayoutnewitempropertiesdialog.cpp
Expand Up @@ -15,6 +15,8 @@

#include "qgslayoutnewitempropertiesdialog.h"
#include "qgssettings.h"
#include "qgslayout.h"


QgsLayoutItemPropertiesDialog::QgsLayoutItemPropertiesDialog( QWidget *parent, Qt::WindowFlags flags )
: QDialog( parent, flags )
Expand All @@ -39,6 +41,11 @@ QgsLayoutItemPropertiesDialog::QgsLayoutItemPropertiesDialog( QWidget *parent, Q
double lastHeight = settings.value( QStringLiteral( "LayoutDesigner/lastItemHeight" ), QStringLiteral( "50" ) ).toDouble();
QgsUnitTypes::LayoutUnit lastSizeUnit = static_cast< QgsUnitTypes::LayoutUnit >( settings.value( QStringLiteral( "LayoutDesigner/lastSizeUnit" ) ).toInt() );
setItemSize( QgsLayoutSize( lastWidth, lastHeight, lastSizeUnit ) );

mPosUnitsComboBox->linkToWidget( mXPosSpin );
mPosUnitsComboBox->linkToWidget( mYPosSpin );
mSizeUnitsComboBox->linkToWidget( mWidthSpin );
mSizeUnitsComboBox->linkToWidget( mHeightSpin );
}

void QgsLayoutItemPropertiesDialog::setItemPosition( QgsLayoutPoint position )
Expand Down Expand Up @@ -147,3 +154,9 @@ void QgsLayoutItemPropertiesDialog::setReferencePoint( QgsLayoutItem::ReferenceP
break;
}
}

void QgsLayoutItemPropertiesDialog::setLayout( QgsLayout *layout )
{
mSizeUnitsComboBox->setConverter( &layout->context().measurementConverter() );
mPosUnitsComboBox->setConverter( &layout->context().measurementConverter() );
}
7 changes: 7 additions & 0 deletions src/gui/layout/qgslayoutnewitempropertiesdialog.h
Expand Up @@ -80,6 +80,13 @@ class GUI_EXPORT QgsLayoutItemPropertiesDialog : public QDialog, private Ui::Qgs
*/
void setReferencePoint( QgsLayoutItem::ReferencePoint point );

/**
* Sets the \a layout associated with the dialog. This allows the dialog
* to retrieve properties from the layout and perform tasks like automatic
* conversion of units.
*/
void setLayout( QgsLayout *layout );

};

#endif // QGSLAYOUTNEWITEMPROPERTIESDIALOG_H
36 changes: 32 additions & 4 deletions src/gui/layout/qgslayoutunitscombobox.cpp
Expand Up @@ -14,6 +14,7 @@
***************************************************************************/

#include "qgslayoutunitscombobox.h"
#include "qgslayoutmeasurementconverter.h"

QgsLayoutUnitsComboBox::QgsLayoutUnitsComboBox( QWidget *parent )
: QComboBox( parent )
Expand All @@ -34,10 +35,7 @@ QgsLayoutUnitsComboBox::QgsLayoutUnitsComboBox( QWidget *parent )
setItemData( 6, tr( "Picas" ), Qt::ToolTipRole );
addItem( tr( "px" ), QgsUnitTypes::LayoutPixels );
setItemData( 7, tr( "Pixels" ), Qt::ToolTipRole );
connect( this, static_cast<void ( QgsLayoutUnitsComboBox::* )( int )>( &QgsLayoutUnitsComboBox::currentIndexChanged ), this, [ = ]( int )
{
emit changed( unit() );
} );
connect( this, static_cast<void ( QgsLayoutUnitsComboBox::* )( int )>( &QgsLayoutUnitsComboBox::currentIndexChanged ), this, &QgsLayoutUnitsComboBox::indexChanged );
}

QgsUnitTypes::LayoutUnit QgsLayoutUnitsComboBox::unit() const
Expand All @@ -50,4 +48,34 @@ void QgsLayoutUnitsComboBox::setUnit( QgsUnitTypes::LayoutUnit unit )
setCurrentIndex( findData( unit ) );
}

void QgsLayoutUnitsComboBox::linkToWidget( QDoubleSpinBox *widget )
{
mLinkedSpinBoxes << widget;
}

void QgsLayoutUnitsComboBox::indexChanged( int )
{
QgsUnitTypes::LayoutUnit newUnit = unit();
if ( mConverter )
{
Q_FOREACH ( const QPointer< QDoubleSpinBox > &widget, mLinkedSpinBoxes )
{
if ( widget )
widget->setValue( mConverter->convert( QgsLayoutMeasurement( widget->value(), mOldUnit ), newUnit ).length() );
}
}
emit changed( newUnit );
mOldUnit = newUnit;
}

QgsLayoutMeasurementConverter *QgsLayoutUnitsComboBox::converter() const
{
return mConverter;
}

void QgsLayoutUnitsComboBox::setConverter( QgsLayoutMeasurementConverter *converter )
{
mConverter = converter;
}

#include "qgslayoutunitscombobox.h"
41 changes: 41 additions & 0 deletions src/gui/layout/qgslayoutunitscombobox.h
Expand Up @@ -19,6 +19,10 @@
#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgsunittypes.h"
#include <QDoubleSpinBox>
#include <QPointer>

class QgsLayoutMeasurementConverter;

/**
* \ingroup gui
Expand Down Expand Up @@ -50,13 +54,50 @@ class GUI_EXPORT QgsLayoutUnitsComboBox : public QComboBox
*/
void setUnit( QgsUnitTypes::LayoutUnit unit );

/**
* Registers a spin box \a widget as linked with the combo box.
*
* Registered spin boxes will automatically be upodated whenever the unit is changed. I.e. a
* spin box with a value of 100 will be set to 1 when the unit is changed from centimeters to meters.
*
* A measurement converter() must be set in order for the automatic unit conversion to occur.
*
* \see setConverter()
*/
void linkToWidget( QDoubleSpinBox *widget );

/**
* Returns the converter used when automatically converting units for linked widgets.
* \see setConverter()
*/
QgsLayoutMeasurementConverter *converter() const;

/**
* Sets a \a converter to use when automatically converting units for linked widgets.
* The ownership of \a converter is not transferred, and converter must exist for the
* life of the combo box.
* \see converter()
*/
void setConverter( QgsLayoutMeasurementConverter *converter );

signals:

/**
* Emitted when the \a unit is changed.
*/
void changed( QgsUnitTypes::LayoutUnit unit );

private slots:

void indexChanged( int index );

private:

QgsLayoutMeasurementConverter *mConverter = nullptr;

QgsUnitTypes::LayoutUnit mOldUnit = QgsUnitTypes::LayoutMillimeters;

QList< QPointer< QDoubleSpinBox > > mLinkedSpinBoxes;
};

#endif // QGSLAYOUTUNITSCOMBOBOX_H
1 change: 1 addition & 0 deletions src/gui/layout/qgslayoutviewtooladditem.cpp
Expand Up @@ -90,6 +90,7 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
if ( clickOnly )
{
QgsLayoutItemPropertiesDialog dlg( view() );
dlg.setLayout( layout() );
dlg.setItemPosition( QgsLayoutPoint( event->layoutPoint(), layout()->units() ) );
if ( dlg.exec() )
{
Expand Down
35 changes: 34 additions & 1 deletion tests/src/python/test_qgslayoutunitscombobox.py
Expand Up @@ -14,9 +14,11 @@

import qgis # NOQA

from qgis.core import QgsUnitTypes
from qgis.core import QgsUnitTypes, QgsLayoutMeasurementConverter
from qgis.gui import QgsLayoutUnitsComboBox

from qgis.PyQt.QtWidgets import QDoubleSpinBox

from qgis.PyQt.QtTest import QSignalSpy
from qgis.testing import start_app, unittest

Expand All @@ -42,6 +44,37 @@ def test_ChangedSignals(self):
self.assertEqual(len(spy), 1)
self.assertEqual(spy[0][0], QgsUnitTypes.LayoutPixels)

def testLinkedWidgets(self):
""" test linking spin boxes to combobox"""
w = qgis.gui.QgsLayoutUnitsComboBox()
self.assertFalse(w.converter())
c = QgsLayoutMeasurementConverter()
w.setConverter(c)
self.assertEqual(w.converter(), c)

spin = QDoubleSpinBox()
spin.setMaximum(1000000)
spin.setValue(100)
w.setUnit(QgsUnitTypes.LayoutCentimeters)
w.linkToWidget(spin)
w.setUnit(QgsUnitTypes.LayoutMeters)
self.assertAlmostEqual(spin.value(), 1.0, 2)
w.setUnit(QgsUnitTypes.LayoutMillimeters)
self.assertAlmostEqual(spin.value(), 1000.0, 2)

spin2 = QDoubleSpinBox()
spin2.setValue(50)
spin2.setMaximum(1000000)
w.linkToWidget(spin2)
w.setUnit(QgsUnitTypes.LayoutCentimeters)
self.assertAlmostEqual(spin.value(), 100.0, 2)
self.assertAlmostEqual(spin2.value(), 5.0, 2)

# no crash!
del spin
w.setUnit(QgsUnitTypes.LayoutMeters)
self.assertAlmostEqual(spin2.value(), 0.05, 2)


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

0 comments on commit 3021fc8

Please sign in to comment.