diff --git a/python/core/layout/qgslayoutitem.sip b/python/core/layout/qgslayoutitem.sip index 5d3ebb88665..3e54ac8d37a 100644 --- a/python/core/layout/qgslayoutitem.sip +++ b/python/core/layout/qgslayoutitem.sip @@ -235,13 +235,20 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt .. seealso:: sizeWithUnits() %End - virtual void attemptMove( const QgsLayoutPoint &point ); + virtual void attemptMove( const QgsLayoutPoint &point, bool useReferencePoint = true ); %Docstring - Attempts to move the item to a specified ``point``. This method respects the item's + Attempts to move the item to a specified ``point``. + + If ``useReferencePoint`` is true, this method will respect 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. + + If ``useReferencePoint`` is false, the item will be moved so that ``point`` + falls at the top-left corner of the item. + 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() .. seealso:: positionWithUnits() @@ -575,7 +582,7 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt QPointF adjustPointForReferencePosition( const QPointF &point, const QSizeF &size, const ReferencePoint &reference ) const; %Docstring Adjusts the specified ``point`` at which a ``reference`` position of the item - sits and returns the top left corner of the item, if reference point where placed at the specified position. + sits and returns the top left corner of the item, if reference point were placed at the specified position. :rtype: QPointF %End @@ -585,6 +592,13 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt :rtype: QPointF %End + QgsLayoutPoint topLeftToReferencePoint( const QgsLayoutPoint &point ) const; +%Docstring + Returns the position for the reference point of the item, if the top-left of the item + was placed at the specified ``point``. + :rtype: QgsLayoutPoint +%End + virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const; %Docstring Stores item state within an XML DOM element. diff --git a/python/core/layout/qgslayoutitemgroup.sip b/python/core/layout/qgslayoutitemgroup.sip index d20cbc15de3..315f784e4ec 100644 --- a/python/core/layout/qgslayoutitemgroup.sip +++ b/python/core/layout/qgslayoutitemgroup.sip @@ -62,7 +62,7 @@ class QgsLayoutItemGroup: QgsLayoutItem virtual void setVisibility( const bool visible ); - virtual void attemptMove( const QgsLayoutPoint &point ); + virtual void attemptMove( const QgsLayoutPoint &point, bool useReferencePoint = true ); virtual void attemptResize( const QgsLayoutSize &size ); diff --git a/src/core/layout/qgslayoutitem.cpp b/src/core/layout/qgslayoutitem.cpp index b65796e4a51..f360fb55503 100644 --- a/src/core/layout/qgslayoutitem.cpp +++ b/src/core/layout/qgslayoutitem.cpp @@ -351,7 +351,7 @@ void QgsLayoutItem::attemptResize( const QgsLayoutSize &size ) emit sizePositionChanged(); } -void QgsLayoutItem::attemptMove( const QgsLayoutPoint &point ) +void QgsLayoutItem::attemptMove( const QgsLayoutPoint &point, bool useReferencePoint ) { if ( !mLayout ) { @@ -360,7 +360,13 @@ void QgsLayoutItem::attemptMove( const QgsLayoutPoint &point ) return; } - QgsLayoutPoint evaluatedPoint = applyDataDefinedPosition( point ); + QgsLayoutPoint evaluatedPoint = point; + if ( !useReferencePoint ) + { + evaluatedPoint = topLeftToReferencePoint( point ); + } + + evaluatedPoint = applyDataDefinedPosition( evaluatedPoint ); QPointF evaluatedPointLayoutUnits = mLayout->convertToLayoutUnits( evaluatedPoint ); QPointF topLeftPointLayoutUnits = adjustPointForReferencePosition( evaluatedPointLayoutUnits, rect().size(), mReferencePoint ); if ( topLeftPointLayoutUnits == scenePos() && point.units() == mItemPosition.units() ) @@ -737,6 +743,13 @@ QPointF QgsLayoutItem::positionAtReferencePoint( const QgsLayoutItem::ReferenceP return mapToScene( pointWithinItem ); } +QgsLayoutPoint QgsLayoutItem::topLeftToReferencePoint( const QgsLayoutPoint &point ) const +{ + QPointF topLeft = mLayout->convertToLayoutUnits( point ); + QPointF refPoint = topLeft + itemPositionAtReferencePoint( mReferencePoint, rect().size() ); + return mLayout->convertFromLayoutUnits( refPoint, point.units() ); +} + bool QgsLayoutItem::writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const { element.setAttribute( QStringLiteral( "uuid" ), mUuid ); diff --git a/src/core/layout/qgslayoutitem.h b/src/core/layout/qgslayoutitem.h index ee91d02a046..6859ac2048e 100644 --- a/src/core/layout/qgslayoutitem.h +++ b/src/core/layout/qgslayoutitem.h @@ -250,16 +250,23 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt virtual void attemptResize( const QgsLayoutSize &size ); /** - * Attempts to move the item to a specified \a point. This method respects the item's + * Attempts to move the item to a specified \a point. + * + * If \a useReferencePoint is true, this method will respect 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. + * + * If \a useReferencePoint is false, the item will be moved so that \a point + * falls at the top-left corner of the item. + * * 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() * \see positionWithUnits() */ - virtual void attemptMove( const QgsLayoutPoint &point ); + virtual void attemptMove( const QgsLayoutPoint &point, bool useReferencePoint = true ); /** * Returns the item's current position, including units. The position returned @@ -572,7 +579,7 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt /** * Adjusts the specified \a point at which a \a reference position of the item - * sits and returns the top left corner of the item, if reference point where placed at the specified position. + * sits and returns the top left corner of the item, if reference point were placed at the specified position. */ QPointF adjustPointForReferencePosition( const QPointF &point, const QSizeF &size, const ReferencePoint &reference ) const; @@ -581,6 +588,12 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt */ QPointF positionAtReferencePoint( const ReferencePoint &reference ) const; + /** + * Returns the position for the reference point of the item, if the top-left of the item + * was placed at the specified \a point. + */ + QgsLayoutPoint topLeftToReferencePoint( const QgsLayoutPoint &point ) const; + /** * Stores item state within an XML DOM element. * \param element is the DOM element to store the item's properties in diff --git a/src/core/layout/qgslayoutitemgroup.cpp b/src/core/layout/qgslayoutitemgroup.cpp index dbaf8e1464e..d614880e501 100644 --- a/src/core/layout/qgslayoutitemgroup.cpp +++ b/src/core/layout/qgslayoutitemgroup.cpp @@ -127,7 +127,7 @@ void QgsLayoutItemGroup::setVisibility( const bool visible ) mLayout->undoStack()->endMacro(); } -void QgsLayoutItemGroup::attemptMove( const QgsLayoutPoint &point ) +void QgsLayoutItemGroup::attemptMove( const QgsLayoutPoint &point, bool useReferencePoint ) { if ( !mLayout ) return; diff --git a/src/core/layout/qgslayoutitemgroup.h b/src/core/layout/qgslayoutitemgroup.h index 015330c448b..f2cc0863fad 100644 --- a/src/core/layout/qgslayoutitemgroup.h +++ b/src/core/layout/qgslayoutitemgroup.h @@ -69,7 +69,7 @@ class CORE_EXPORT QgsLayoutItemGroup: public QgsLayoutItem void setVisibility( const bool visible ) override; //overridden to move child items - void attemptMove( const QgsLayoutPoint &point ) override; + void attemptMove( const QgsLayoutPoint &point, bool useReferencePoint = true ) override; void attemptResize( const QgsLayoutSize &size ) override; bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const override; diff --git a/src/gui/layout/qgslayoutmousehandles.cpp b/src/gui/layout/qgslayoutmousehandles.cpp index 643997bcd83..fe3c403648d 100644 --- a/src/gui/layout/qgslayoutmousehandles.cpp +++ b/src/gui/layout/qgslayoutmousehandles.cpp @@ -657,13 +657,13 @@ void QgsLayoutMouseHandles::mouseReleaseEvent( QGraphicsSceneMouseEvent *event ) itemRect = itemRect.normalized(); QPointF newPos = mapToScene( itemRect.topLeft() ); - // translate new position to current item units - QgsLayoutPoint itemPos = mLayout->convertFromLayoutUnits( newPos, item->positionWithUnits().units() ); - item->attemptMove( itemPos ); - QgsLayoutSize itemSize = mLayout->convertFromLayoutUnits( itemRect.size(), item->sizeWithUnits().units() ); item->attemptResize( itemSize ); + // translate new position to current item units + QgsLayoutPoint itemPos = mLayout->convertFromLayoutUnits( newPos, item->positionWithUnits().units() ); + item->attemptMove( itemPos, false ); + command->saveAfterState(); mLayout->undoStack()->stack()->push( command.release() ); } diff --git a/tests/src/core/testqgslayoutitem.cpp b/tests/src/core/testqgslayoutitem.cpp index 2cd772af52c..9194577a756 100644 --- a/tests/src/core/testqgslayoutitem.cpp +++ b/tests/src/core/testqgslayoutitem.cpp @@ -1139,7 +1139,24 @@ void TestQgsLayoutItem::move() l.setUnits( QgsUnitTypes::LayoutMillimeters ); - //TODO - reference points + //reference points + item->attemptMove( QgsLayoutPoint( 5, 9 ) ); + item->attemptResize( QgsLayoutSize( 4, 6 ) ); + item->setReferencePoint( QgsLayoutItem::LowerRight ); + QCOMPARE( item->positionWithUnits().x(), 9.0 ); + QCOMPARE( item->positionWithUnits().y(), 15.0 ); + + item->attemptMove( QgsLayoutPoint( 11, 13 ) ); + QCOMPARE( item->positionWithUnits().x(), 11.0 ); + QCOMPARE( item->positionWithUnits().y(), 13.0 ); + QCOMPARE( item->scenePos().x(), 7.0 ); + QCOMPARE( item->scenePos().y(), 7.0 ); + + item->attemptMove( QgsLayoutPoint( 10, 12 ), false ); + QCOMPARE( item->positionWithUnits().x(), 14.0 ); + QCOMPARE( item->positionWithUnits().y(), 18.0 ); + QCOMPARE( item->scenePos().x(), 10.0 ); + QCOMPARE( item->scenePos().y(), 12.0 ); } void TestQgsLayoutItem::rotation()