Implement item size and positioning using layout units

This commit is contained in:
Nyall Dawson 2017-07-10 13:06:27 +10:00
parent 498c4cda16
commit d0c844ed67
6 changed files with 685 additions and 4 deletions

View File

@ -21,7 +21,20 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem
%End
public:
QgsLayoutItem( QgsLayout *layout );
enum ReferencePoint
{
UpperLeft,
UpperMiddle,
UpperRight,
MiddleLeft,
Middle,
MiddleRight,
LowerLeft,
LowerMiddle,
LowerRight,
};
explicit QgsLayoutItem( QgsLayout *layout );
%Docstring
Constructor for QgsLayoutItem, with the specified parent ``layout``.
%End
@ -34,6 +47,72 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem
the pure virtual method QgsLayoutItem.draw.
%End
void setReferencePoint( const ReferencePoint &point );
%Docstring
Sets the reference ``point`` for positioning of the layout item. This point is also
fixed during resizing of the item, and any size changes will be performed
so that the position of the reference point within the layout remains unchanged.
.. seealso:: referencePoint()
%End
ReferencePoint referencePoint() const;
%Docstring
Returns the reference point for positioning of the layout item. This point is also
fixed during resizing of the item, and any size changes will be performed
so that the position of the reference point within the layout remains unchanged.
.. seealso:: setReferencePoint()
:rtype: ReferencePoint
%End
QgsLayoutSize fixedSize() const;
%Docstring
Returns the fixed size of the item, if applicable, or an empty size if item can be freely
resized.
.. seealso:: setFixedSize()
.. seealso:: minimumSize()
:rtype: QgsLayoutSize
%End
virtual QgsLayoutSize minimumSize() const;
%Docstring
Returns the minimum allowed size of the item, if applicable, or an empty size if item can be freely
resized.
.. seealso:: setMinimumSize()
.. seealso:: fixedSize()
:rtype: QgsLayoutSize
%End
virtual void attemptResize( const QgsLayoutSize &size );
%Docstring
Attempts to resize the item to a specified target ``size``. Note that the final size of the
item may not match the specified target size, as items with a fixed or minimum
size will place restrictions on the allowed item size. Data defined item size overrides
will also override the specified target size.
.. seealso:: minimumSize()
.. seealso:: fixedSize()
.. seealso:: attemptMove()
%End
virtual void attemptMove( const QgsLayoutPoint &point );
%Docstring
Attempts to move the item to a specified ``point``. This method respects the item's
reference point, in that the item will be moved so that its current reference
point is placed at the specified target point.
Note that the final position of the item may not match the specified target position,
as data defined item position may override the specified value.
.. seealso:: attemptResize()
.. seealso:: referencePoint()
%End
public slots:
virtual void refresh();
%Docstring
Refreshes the item, causing a recalculation of any property overrides and
recalculation of its position and size.
%End
protected:
virtual void drawDebugRect( QPainter *painter );
@ -48,6 +127,45 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem
Draws the item's contents on a specified ``painter``.
%End
virtual void setFixedSize( const QgsLayoutSize &size );
%Docstring
Sets a fixed ``size`` for the layout item, which prevents it from being freely
resized. Set an empty size if item can be freely resized.
.. seealso:: fixedSize()
.. seealso:: setMinimumSize()
%End
virtual void setMinimumSize( const QgsLayoutSize &size );
%Docstring
Sets the minimum allowed ``size`` for the layout item. Set an empty size if item can be freely
resized.
.. seealso:: minimumSize()
.. seealso:: setFixedSize()
%End
void refreshItemSize();
%Docstring
Refreshes an item's size by rechecking it against any possible item fixed
or minimum sizes.
.. seealso:: setFixedSize()
.. seealso:: setMinimumSize()
.. seealso:: refreshItemPosition()
%End
void refreshItemPosition();
%Docstring
Refreshes an item's position by rechecking it against any possible overrides
such as data defined positioning.
.. seealso:: refreshItemSize()
%End
QPointF adjustPointForReferencePosition( const QPointF &point, const QSizeF &size ) const;
%Docstring
Adjusts the specified ``point`` at which the reference position of the item
sits and returns the top left corner of the item.
:rtype: QPointF
%End
};

View File

@ -78,7 +78,7 @@ class QgsLayoutObject: QObject, QgsExpressionContextGenerator
:rtype: QgsPropertiesDefinition
%End
QgsLayoutObject( QgsLayout *layout );
explicit QgsLayoutObject( QgsLayout *layout );
%Docstring
Constructor for QgsLayoutObject, with the specified parent ``layout``.
.. note::
@ -159,6 +159,13 @@ class QgsLayoutObject: QObject, QgsExpressionContextGenerator
:rtype: QgsExpressionContext
%End
public slots:
virtual void refresh();
%Docstring
Refreshes the object, causing a recalculation of any property overrides.
%End
protected:

View File

@ -23,6 +23,13 @@ QgsLayoutItem::QgsLayoutItem( QgsLayout *layout )
, QGraphicsRectItem( 0 )
{
setCacheMode( QGraphicsItem::DeviceCoordinateCache );
//record initial position
QgsUnitTypes::LayoutUnit initialUnits = layout ? layout->units() : QgsUnitTypes::LayoutMillimeters;
mItemPosition = QgsLayoutPoint( scenePos().x(), scenePos().y(), initialUnits );
mItemSize = QgsLayoutSize( rect().width(), rect().height(), initialUnits );
initConnectionsToLayout();
}
void QgsLayoutItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
@ -48,6 +55,62 @@ void QgsLayoutItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *it
painter->restore();
}
void QgsLayoutItem::setReferencePoint( const QgsLayoutItem::ReferencePoint &point )
{
mReferencePoint = point;
}
void QgsLayoutItem::attemptResize( const QgsLayoutSize &size )
{
if ( !mLayout )
{
mItemSize = size;
setRect( 0, 0, size.width(), size.height() );
return;
}
QSizeF targetSizeLayoutUnits = mLayout->convertToLayoutUnits( size );
QSizeF actualSizeLayoutUnits = applyMinimumSize( targetSizeLayoutUnits );
actualSizeLayoutUnits = applyFixedSize( actualSizeLayoutUnits );
if ( actualSizeLayoutUnits == rect().size() )
{
return;
}
QgsLayoutSize actualSizeTargetUnits = mLayout->convertFromLayoutUnits( actualSizeLayoutUnits, size.units() );
mItemSize = actualSizeTargetUnits;
setRect( 0, 0, actualSizeLayoutUnits.width(), actualSizeLayoutUnits.height() );
}
void QgsLayoutItem::attemptMove( const QgsLayoutPoint &point )
{
if ( !mLayout )
{
mItemPosition = point;
setPos( point.toQPointF() );
return;
}
QPointF targetPointLayoutUnits = mLayout->convertToLayoutUnits( point );
//TODO - apply data defined position here
targetPointLayoutUnits = adjustPointForReferencePosition( targetPointLayoutUnits, rect().size() );
QPointF actualPointLayoutUnits = targetPointLayoutUnits;
QgsLayoutPoint actualPointTargetUnits = mLayout->convertFromLayoutUnits( actualPointLayoutUnits, point.units() );
mItemPosition = actualPointTargetUnits;
setPos( targetPointLayoutUnits );
}
void QgsLayoutItem::refresh()
{
QgsLayoutObject::refresh();
refreshItemSize();
refreshItemPosition();
}
void QgsLayoutItem::drawDebugRect( QPainter *painter )
{
if ( !painter )
@ -63,6 +126,62 @@ void QgsLayoutItem::drawDebugRect( QPainter *painter )
painter->restore();
}
void QgsLayoutItem::setFixedSize( const QgsLayoutSize &size )
{
mFixedSize = size;
refreshItemSize();
}
void QgsLayoutItem::setMinimumSize( const QgsLayoutSize &size )
{
mMinimumSize = size;
refreshItemSize();
}
void QgsLayoutItem::refreshItemSize()
{
attemptResize( mItemSize );
}
void QgsLayoutItem::refreshItemPosition()
{
attemptMove( mItemPosition );
}
QPointF QgsLayoutItem::adjustPointForReferencePosition( const QPointF &position, const QSizeF &size ) const
{
switch ( mReferencePoint )
{
case UpperMiddle:
return QPointF( position.x() - size.width() / 2.0, position.y() );
case UpperRight:
return QPointF( position.x() - size.width(), position.y() );
case MiddleLeft:
return QPointF( position.x(), position.y() - size.height() / 2.0 );
case Middle:
return QPointF( position.x() - size.width() / 2.0, position.y() - size.height() / 2.0 );
case MiddleRight:
return QPointF( position.x() - size.width(), position.y() - size.height() / 2.0 );
case LowerLeft:
return QPointF( position.x(), position.y() - size.height() );
case LowerMiddle:
return QPointF( position.x() - size.width() / 2.0, position.y() - size.height() );
case LowerRight:
return QPointF( position.x() - size.width(), position.y() - size.height() );
case UpperLeft:
return position;
}
// no warnings
return position;
}
void QgsLayoutItem::initConnectionsToLayout()
{
if ( !mLayout )
return;
}
void QgsLayoutItem::preparePainter( QPainter *painter )
{
if ( !painter || !painter->device() )
@ -86,3 +205,23 @@ bool QgsLayoutItem::shouldDrawDebugRect() const
{
return mLayout && mLayout->context().testFlag( QgsLayoutContext::FlagDebug );
}
QSizeF QgsLayoutItem::applyMinimumSize( const QSizeF &targetSize )
{
if ( !mLayout || minimumSize().isEmpty() )
{
return targetSize;
}
QSizeF minimumSizeLayoutUnits = mLayout->convertToLayoutUnits( minimumSize() );
return targetSize.expandedTo( minimumSizeLayoutUnits );
}
QSizeF QgsLayoutItem::applyFixedSize( const QSizeF &targetSize )
{
if ( !mLayout || fixedSize().isEmpty() )
{
return targetSize;
}
QSizeF fixedSizeLayoutUnits = mLayout->convertToLayoutUnits( fixedSize() );
return targetSize.expandedTo( fixedSizeLayoutUnits );
}

View File

@ -19,6 +19,8 @@
#include "qgis_core.h"
#include "qgslayoutobject.h"
#include "qgslayoutsize.h"
#include "qgslayoutpoint.h"
#include <QGraphicsRectItem>
class QgsLayout;
@ -37,10 +39,24 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
public:
//! Fixed position reference point
enum ReferencePoint
{
UpperLeft, //!< Upper left corner of item
UpperMiddle, //!< Upper center of item
UpperRight, //!< Upper right corner of item
MiddleLeft, //!< Middle left of item
Middle, //!< Center of item
MiddleRight, //!< Middle right of item
LowerLeft, //!< Lower left corner of item
LowerMiddle, //!< Lower center of item
LowerRight, //!< Lower right corner of item
};
/**
* Constructor for QgsLayoutItem, with the specified parent \a layout.
*/
QgsLayoutItem( QgsLayout *layout );
explicit QgsLayoutItem( QgsLayout *layout );
/**
* Handles preparing a paint surface for the layout item and painting the item's
@ -49,6 +65,68 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
*/
void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;
/**
* Sets the reference \a point for positioning of the layout item. This point is also
* fixed during resizing of the item, and any size changes will be performed
* so that the position of the reference point within the layout remains unchanged.
* \see referencePoint()
*/
void setReferencePoint( const ReferencePoint &point );
/**
* Returns the reference point for positioning of the layout item. This point is also
* fixed during resizing of the item, and any size changes will be performed
* so that the position of the reference point within the layout remains unchanged.
* \see setReferencePoint()
*/
ReferencePoint referencePoint() const { return mReferencePoint; }
/**
* Returns the fixed size of the item, if applicable, or an empty size if item can be freely
* resized.
* \see setFixedSize()
* \see minimumSize()
*/
QgsLayoutSize fixedSize() const { return mFixedSize; }
/**
* Returns the minimum allowed size of the item, if applicable, or an empty size if item can be freely
* resized.
* \see setMinimumSize()
* \see fixedSize()
*/
virtual QgsLayoutSize minimumSize() const { return mMinimumSize; }
/**
* Attempts to resize the item to a specified target \a size. Note that the final size of the
* item may not match the specified target size, as items with a fixed or minimum
* size will place restrictions on the allowed item size. Data defined item size overrides
* will also override the specified target size.
* \see minimumSize()
* \see fixedSize()
* \see attemptMove()
*/
virtual void attemptResize( const QgsLayoutSize &size );
/**
* Attempts to move the item to a specified \a point. This method respects the item's
* reference point, in that the item will be moved so that its current reference
* point is placed at the specified target point.
* Note that the final position of the item may not match the specified target position,
* as data defined item position may override the specified value.
* \see attemptResize()
* \see referencePoint()
*/
virtual void attemptMove( const QgsLayoutPoint &point );
public slots:
/**
* Refreshes the item, causing a recalculation of any property overrides and
* recalculation of its position and size.
*/
void refresh() override;
protected:
/** Draws a debugging rectangle of the item's current bounds within the specified
@ -62,13 +140,63 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
*/
virtual void draw( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) = 0;
/**
* Sets a fixed \a size for the layout item, which prevents it from being freely
* resized. Set an empty size if item can be freely resized.
* \see fixedSize()
* \see setMinimumSize()
*/
virtual void setFixedSize( const QgsLayoutSize &size );
/**
* Sets the minimum allowed \a size for the layout item. Set an empty size if item can be freely
* resized.
* \see minimumSize()
* \see setFixedSize()
*/
virtual void setMinimumSize( const QgsLayoutSize &size );
/**
* Refreshes an item's size by rechecking it against any possible item fixed
* or minimum sizes.
* \see setFixedSize()
* \see setMinimumSize()
* \see refreshItemPosition()
*/
void refreshItemSize();
/**
* Refreshes an item's position by rechecking it against any possible overrides
* such as data defined positioning.
* \see refreshItemSize()
*/
void refreshItemPosition();
/**
* Adjusts the specified \a point at which the reference position of the item
* sits and returns the top left corner of the item.
*/
QPointF adjustPointForReferencePosition( const QPointF &point, const QSizeF &size ) const;
private:
ReferencePoint mReferencePoint = UpperLeft;
QgsLayoutSize mFixedSize;
QgsLayoutSize mMinimumSize;
QgsLayoutSize mItemSize;
QgsLayoutPoint mItemPosition;
void initConnectionsToLayout();
//! Prepares a painter by setting rendering flags
void preparePainter( QPainter *painter );
bool shouldDrawAntialiased() const;
bool shouldDrawDebugRect() const;
QSizeF applyMinimumSize( const QSizeF &targetSize );
QSizeF applyFixedSize( const QSizeF &targetSize );
friend class TestQgsLayoutItem;
};

View File

@ -103,7 +103,7 @@ class CORE_EXPORT QgsLayoutObject: public QObject, public QgsExpressionContextGe
* classes which are derived from QgsLayoutObject (such as QgsLayoutItem)
* may transfer their ownership to a layout upon construction.
*/
QgsLayoutObject( QgsLayout *layout );
explicit QgsLayoutObject( QgsLayout *layout );
/**
* Returns the layout the object is attached to.
@ -179,6 +179,13 @@ class CORE_EXPORT QgsLayoutObject: public QObject, public QgsExpressionContextGe
*/
QgsExpressionContext createExpressionContext() const override;
public slots:
/**
* Refreshes the object, causing a recalculation of any property overrides.
*/
virtual void refresh() {}
protected:
QgsLayout *mLayout = nullptr;

View File

@ -42,6 +42,11 @@ class TestQgsLayoutItem: public QObject
void preparePainter();
void debugRect();
void draw();
void resize();
void referencePoint();
void fixedSize();
void minSize();
void move();
private:
@ -68,6 +73,53 @@ class TestQgsLayoutItem: public QObject
}
};
//item with minimum size
class MinSizedItem : public TestItem
{
public:
MinSizedItem( QgsLayout *layout ) : TestItem( layout )
{
setMinimumSize( QgsLayoutSize( 5.0, 10.0, QgsUnitTypes::LayoutCentimeters ) );
}
void updateMinSize( QgsLayoutSize size )
{
setMinimumSize( size );
}
~MinSizedItem() {}
};
//item with fixed size
class FixedSizedItem : public TestItem
{
public:
FixedSizedItem( QgsLayout *layout ) : TestItem( layout )
{
setFixedSize( QgsLayoutSize( 2.0, 4.0, QgsUnitTypes::LayoutInches ) );
}
void updateFixedSize( QgsLayoutSize size )
{
setFixedSize( size );
}
~FixedSizedItem() {}
};
//item with both conflicting fixed and minimum size
class FixedMinSizedItem : public TestItem
{
public:
FixedMinSizedItem( QgsLayout *layout ) : TestItem( layout )
{
setFixedSize( QgsLayoutSize( 2.0, 4.0, QgsUnitTypes::LayoutCentimeters ) );
setMinimumSize( QgsLayoutSize( 5.0, 9.0, QgsUnitTypes::LayoutCentimeters ) );
}
~FixedMinSizedItem() {}
};
QString mReport;
bool renderCheck( QString testName, QImage &image, int mismatchCount );
@ -264,5 +316,235 @@ bool TestQgsLayoutItem::renderCheck( QString testName, QImage &image, int mismat
return myResultFlag;
}
void TestQgsLayoutItem::resize()
{
QgsProject p;
QgsLayout l( &p );
//resize test item (no restrictions), same units as layout
l.setUnits( QgsUnitTypes::LayoutMillimeters );
TestItem *item = new TestItem( &l );
item->setRect( 0, 0, 55, 45 );
item->setPos( 27, 29 );
item->attemptResize( QgsLayoutSize( 100.0, 200.0, QgsUnitTypes::LayoutMillimeters ) );
QCOMPARE( item->rect().width(), 100.0 );
QCOMPARE( item->rect().height(), 200.0 );
QCOMPARE( item->pos().x(), 27.0 ); //item should not move
QCOMPARE( item->pos().y(), 29.0 );
//test conversion of units
l.setUnits( QgsUnitTypes::LayoutCentimeters );
item->setRect( 0, 0, 100, 200 );
item->attemptResize( QgsLayoutSize( 0.30, 0.45, QgsUnitTypes::LayoutMeters ) );
QCOMPARE( item->rect().width(), 30.0 );
QCOMPARE( item->rect().height(), 45.0 );
//test pixel -> page conversion
l.setUnits( QgsUnitTypes::LayoutInches );
l.context().setDpi( 100.0 );
item->refresh();
item->setRect( 0, 0, 1, 2 );
item->attemptResize( QgsLayoutSize( 140, 280, QgsUnitTypes::LayoutPixels ) );
QCOMPARE( item->rect().width(), 1.4 );
QCOMPARE( item->rect().height(), 2.8 );
//changing the dpi should resize the item
l.context().setDpi( 200.0 );
item->refresh();
QCOMPARE( item->rect().width(), 0.7 );
QCOMPARE( item->rect().height(), 1.4 );
//test page -> pixel conversion
l.setUnits( QgsUnitTypes::LayoutPixels );
l.context().setDpi( 100.0 );
item->refresh();
item->setRect( 0, 0, 2, 2 );
item->attemptResize( QgsLayoutSize( 1, 3, QgsUnitTypes::LayoutInches ) );
QCOMPARE( item->rect().width(), 100.0 );
QCOMPARE( item->rect().height(), 300.0 );
//changing dpi results in item resize
l.context().setDpi( 200.0 );
item->refresh();
QCOMPARE( item->rect().width(), 200.0 );
QCOMPARE( item->rect().height(), 600.0 );
l.setUnits( QgsUnitTypes::LayoutMillimeters );
}
void TestQgsLayoutItem::referencePoint()
{
QgsProject p;
QgsLayout l( &p );
//test setting/getting reference point
TestItem *item = new TestItem( &l );
item->setReferencePoint( QgsLayoutItem::LowerMiddle );
QCOMPARE( item->referencePoint(), QgsLayoutItem::LowerMiddle );
//test that setting item position is done relative to reference point
l.setUnits( QgsUnitTypes::LayoutMillimeters );
item->attemptResize( QgsLayoutSize( 2, 4 ) );
item->setReferencePoint( QgsLayoutItem::UpperLeft );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), 1.0 );
QCOMPARE( item->pos().y(), 2.0 );
item->setReferencePoint( QgsLayoutItem::UpperMiddle );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), 0.0 );
QCOMPARE( item->pos().y(), 2.0 );
item->setReferencePoint( QgsLayoutItem::UpperRight );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), -1.0 );
QCOMPARE( item->pos().y(), 2.0 );
item->setReferencePoint( QgsLayoutItem::MiddleLeft );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), 1.0 );
QCOMPARE( item->pos().y(), 0.0 );
item->setReferencePoint( QgsLayoutItem::Middle );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), 0.0 );
QCOMPARE( item->pos().y(), 0.0 );
item->setReferencePoint( QgsLayoutItem::MiddleRight );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), -1.0 );
QCOMPARE( item->pos().y(), 0.0 );
item->setReferencePoint( QgsLayoutItem::LowerLeft );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), 1.0 );
QCOMPARE( item->pos().y(), -2.0 );
item->setReferencePoint( QgsLayoutItem::LowerMiddle );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), 0.0 );
QCOMPARE( item->pos().y(), -2.0 );
item->setReferencePoint( QgsLayoutItem::LowerRight );
item->attemptMove( QgsLayoutPoint( 1, 2 ) );
QCOMPARE( item->pos().x(), -1.0 );
QCOMPARE( item->pos().y(), -2.0 );
//test that resizing is done relative to reference point
}
void TestQgsLayoutItem::fixedSize()
{
QgsProject p;
QgsLayout l( &p );
l.setUnits( QgsUnitTypes::LayoutMillimeters );
FixedSizedItem *item = new FixedSizedItem( &l );
QCOMPARE( item->fixedSize().width(), 2.0 );
QCOMPARE( item->fixedSize().height(), 4.0 );
QCOMPARE( item->fixedSize().units(), QgsUnitTypes::LayoutInches );
item->setRect( 0, 0, 5.0, 6.0 ); //temporarily set rect to random size
item->attemptResize( QgsLayoutSize( 7.0, 8.0, QgsUnitTypes::LayoutPoints ) );
//check size matches fixed item size converted to mm
QVERIFY( qgsDoubleNear( item->rect().width(), 2.0 * 25.4 ) );
QVERIFY( qgsDoubleNear( item->rect().height(), 4.0 * 25.4 ) );
//check that setting a fixed size applies this size immediately
item->updateFixedSize( QgsLayoutSize( 150, 250, QgsUnitTypes::LayoutMillimeters ) );
QVERIFY( qgsDoubleNear( item->rect().width(), 150.0 ) );
QVERIFY( qgsDoubleNear( item->rect().height(), 250.0 ) );
}
void TestQgsLayoutItem::minSize()
{
QgsProject p;
QgsLayout l( &p );
l.setUnits( QgsUnitTypes::LayoutMillimeters );
MinSizedItem *item = new MinSizedItem( &l );
QCOMPARE( item->minimumSize().width(), 5.0 );
QCOMPARE( item->minimumSize().height(), 10.0 );
QCOMPARE( item->minimumSize().units(), QgsUnitTypes::LayoutCentimeters );
item->setRect( 0, 0, 9.0, 6.0 ); //temporarily set rect to random size
//try to resize to less than minimum size
item->attemptResize( QgsLayoutSize( 1.0, 0.5, QgsUnitTypes::LayoutPoints ) );
//check size matches min item size converted to mm
QVERIFY( qgsDoubleNear( item->rect().width(), 50.0 ) );
QVERIFY( qgsDoubleNear( item->rect().height(), 100.0 ) );
//check that resize to larger than min size works
item->attemptResize( QgsLayoutSize( 0.1, 0.2, QgsUnitTypes::LayoutMeters ) );
QVERIFY( qgsDoubleNear( item->rect().width(), 100.0 ) );
QVERIFY( qgsDoubleNear( item->rect().height(), 200.0 ) );
//check that setting a minimum size applies this size immediately
item->updateMinSize( QgsLayoutSize( 150, 250, QgsUnitTypes::LayoutMillimeters ) );
QVERIFY( qgsDoubleNear( item->rect().width(), 150.0 ) );
QVERIFY( qgsDoubleNear( item->rect().height(), 250.0 ) );
//also need check that fixed size trumps min size
FixedMinSizedItem *fixedMinItem = new FixedMinSizedItem( &l );
QCOMPARE( fixedMinItem->minimumSize().width(), 5.0 );
QCOMPARE( fixedMinItem->minimumSize().height(), 9.0 );
QCOMPARE( fixedMinItem->minimumSize().units(), QgsUnitTypes::LayoutCentimeters );
QCOMPARE( fixedMinItem->fixedSize().width(), 2.0 );
QCOMPARE( fixedMinItem->fixedSize().height(), 4.0 );
QCOMPARE( fixedMinItem->fixedSize().units(), QgsUnitTypes::LayoutCentimeters );
//try to resize to less than minimum size
fixedMinItem->attemptResize( QgsLayoutSize( 1.0, 0.5, QgsUnitTypes::LayoutPoints ) );
//check size matches fixed item size, not minimum size (converted to mm)
QVERIFY( qgsDoubleNear( fixedMinItem->rect().width(), 50.0 ) );
QVERIFY( qgsDoubleNear( fixedMinItem->rect().height(), 90.0 ) );
}
void TestQgsLayoutItem::move()
{
QgsProject p;
QgsLayout l( &p );
//move test item, same units as layout
l.setUnits( QgsUnitTypes::LayoutMillimeters );
TestItem *item = new TestItem( &l );
item->setRect( 0, 0, 55, 45 );
item->setPos( 27, 29 );
item->attemptMove( QgsLayoutPoint( 60.0, 15.0, QgsUnitTypes::LayoutMillimeters ) );
QCOMPARE( item->rect().width(), 55.0 ); //size should not change
QCOMPARE( item->rect().height(), 45.0 );
QCOMPARE( item->pos().x(), 60.0 );
QCOMPARE( item->pos().y(), 15.0 );
//test conversion of units
l.setUnits( QgsUnitTypes::LayoutCentimeters );
item->setPos( 100, 200 );
item->attemptMove( QgsLayoutPoint( 0.30, 0.45, QgsUnitTypes::LayoutMeters ) );
QCOMPARE( item->pos().x(), 30.0 );
QCOMPARE( item->pos().y(), 45.0 );
//test pixel -> page conversion
l.setUnits( QgsUnitTypes::LayoutInches );
l.context().setDpi( 100.0 );
item->refresh();
item->setPos( 1, 2 );
item->attemptMove( QgsLayoutPoint( 140, 280, QgsUnitTypes::LayoutPixels ) );
QCOMPARE( item->pos().x(), 1.4 );
QCOMPARE( item->pos().y(), 2.8 );
//changing the dpi should move the item
l.context().setDpi( 200.0 );
item->refresh();
QCOMPARE( item->pos().x(), 0.7 );
QCOMPARE( item->pos().y(), 1.4 );
//test page -> pixel conversion
l.setUnits( QgsUnitTypes::LayoutPixels );
l.context().setDpi( 100.0 );
item->refresh();
item->setPos( 2, 2 );
item->attemptMove( QgsLayoutPoint( 1, 3, QgsUnitTypes::LayoutInches ) );
QCOMPARE( item->pos().x(), 100.0 );
QCOMPARE( item->pos().y(), 300.0 );
//changing dpi results in item move
l.context().setDpi( 200.0 );
item->refresh();
QCOMPARE( item->pos().x(), 200.0 );
QCOMPARE( item->pos().y(), 600.0 );
l.setUnits( QgsUnitTypes::LayoutMillimeters );
//TODO - reference points
}
QGSTEST_MAIN( TestQgsLayoutItem )
#include "testqgslayoutitem.moc"