Skip to content
Permalink
Browse files

QgsLayoutUnitComboBox can be linked to spin boxes so that their

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 21, 2017
1 parent 3e92e16 commit 3021fc86d26fdea0c820a84adaeb0b2bcb35d417
@@ -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

};

/************************************************************************
@@ -7,6 +7,7 @@
************************************************************************/



class QgsLayoutUnitsComboBox : QComboBox
{
%Docstring
@@ -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:
@@ -15,6 +15,8 @@

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


QgsLayoutItemPropertiesDialog::QgsLayoutItemPropertiesDialog( QWidget *parent, Qt::WindowFlags flags )
: QDialog( parent, flags )
@@ -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 )
@@ -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() );
}
@@ -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
@@ -14,6 +14,7 @@
***************************************************************************/

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

QgsLayoutUnitsComboBox::QgsLayoutUnitsComboBox( QWidget *parent )
: QComboBox( parent )
@@ -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
@@ -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"
@@ -19,6 +19,10 @@
#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgsunittypes.h"
#include <QDoubleSpinBox>
#include <QPointer>

class QgsLayoutMeasurementConverter;

/**
* \ingroup gui
@@ -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
@@ -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() )
{
@@ -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

@@ -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.
You can’t perform that action at this time.