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
This commit is contained in:
Nyall Dawson 2017-07-21 13:49:39 +10:00
parent 3e92e16d76
commit 3021fc86d2
8 changed files with 163 additions and 5 deletions

View File

@ -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
};
/************************************************************************

View File

@ -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:

View File

@ -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() );
}

View File

@ -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

View File

@ -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"

View File

@ -19,6 +19,10 @@
#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgsunittypes.h"
#include <QDoubleSpinBox>
#include <QPointer>
class QgsLayoutMeasurementConverter;
/**
* \ingroup gui
@ -50,6 +54,32 @@ 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:
/**
@ -57,6 +87,17 @@ class GUI_EXPORT QgsLayoutUnitsComboBox : public QComboBox
*/
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

View File

@ -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() )
{

View File

@ -14,9 +14,11 @@ __revision__ = '$Format:%H$'
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 @@ class TestQgsLayoutUnitsComboBox(unittest.TestCase):
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()