Fix resizing items with non-top-left reference point using mouse handles

This commit is contained in:
Nyall Dawson 2017-10-10 16:45:20 +10:00
parent 1c735d59ee
commit ab4e6c11ed
8 changed files with 73 additions and 16 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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