Prevent snapping to selected items when resizing

This commit is contained in:
Nyall Dawson 2017-10-02 17:11:05 +10:00
parent d8ffab1523
commit 051ed1e156
7 changed files with 88 additions and 14 deletions

View File

@ -83,7 +83,8 @@ class QgsLayoutSnapper: QgsLayoutSerializableObject
%End
QPointF snapPoint( QPointF point, double scaleFactor, bool &snapped /Out/, QGraphicsLineItem *horizontalSnapLine = 0,
QGraphicsLineItem *verticalSnapLine = 0 ) const;
QGraphicsLineItem *verticalSnapLine = 0,
const QList< QgsLayoutItem * > *ignoreItems = 0 ) const;
%Docstring
Snaps a layout coordinate ``point``. If ``point`` was snapped, ``snapped`` will be set to true.
@ -95,6 +96,8 @@ class QgsLayoutSnapper: QgsLayoutSerializableObject
If the ``horizontalSnapLine`` and ``verticalSnapLine`` arguments are specified, then the snapper
will automatically display and position these lines to indicate snapping positions to item bounds.
A list of items to ignore during the snapping can be specified via the ``ignoreItems`` list.
:rtype: QPointF
%End

View File

@ -49,7 +49,8 @@ void QgsLayoutSnapper::setSnapToItems( bool enabled )
mSnapToItems = enabled;
}
QPointF QgsLayoutSnapper::snapPoint( QPointF point, double scaleFactor, bool &snapped, QGraphicsLineItem *horizontalSnapLine, QGraphicsLineItem *verticalSnapLine ) const
QPointF QgsLayoutSnapper::snapPoint( QPointF point, double scaleFactor, bool &snapped, QGraphicsLineItem *horizontalSnapLine, QGraphicsLineItem *verticalSnapLine,
const QList< QgsLayoutItem * > *ignoreItems ) const
{
snapped = false;
@ -77,7 +78,7 @@ QPointF QgsLayoutSnapper::snapPoint( QPointF point, double scaleFactor, bool &sn
bool snappedYToItems = false;
if ( !snappedXToGuides )
{
newX = snapPointToItems( point.x(), Qt::Horizontal, scaleFactor, QList< QgsLayoutItem * >(), snappedXToItems, verticalSnapLine );
newX = snapPointToItems( point.x(), Qt::Horizontal, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedXToItems, verticalSnapLine );
if ( snappedXToItems )
{
snapped = true;
@ -86,7 +87,7 @@ QPointF QgsLayoutSnapper::snapPoint( QPointF point, double scaleFactor, bool &sn
}
if ( !snappedYToGuides )
{
newY = snapPointToItems( point.y(), Qt::Vertical, scaleFactor, QList< QgsLayoutItem * >(), snappedYToItems, horizontalSnapLine );
newY = snapPointToItems( point.y(), Qt::Vertical, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedYToItems, horizontalSnapLine );
if ( snappedYToItems )
{
snapped = true;

View File

@ -105,9 +105,12 @@ class CORE_EXPORT QgsLayoutSnapper: public QgsLayoutSerializableObject
*
* If the \a horizontalSnapLine and \a verticalSnapLine arguments are specified, then the snapper
* will automatically display and position these lines to indicate snapping positions to item bounds.
*
* A list of items to ignore during the snapping can be specified via the \a ignoreItems list.
*/
QPointF snapPoint( QPointF point, double scaleFactor, bool &snapped SIP_OUT, QGraphicsLineItem *horizontalSnapLine = nullptr,
QGraphicsLineItem *verticalSnapLine = nullptr ) const;
QGraphicsLineItem *verticalSnapLine = nullptr,
const QList< QgsLayoutItem * > *ignoreItems = nullptr ) const;
/**
* Snaps a layout coordinate \a point to the grid. If \a point

View File

@ -24,6 +24,7 @@
#include "qgslayoututils.h"
#include "qgslayoutview.h"
#include "qgslayoutviewtoolselect.h"
#include "qgslayoutsnapper.h"
#include <QGraphicsView>
#include <QGraphicsSceneHoverEvent>
#include <QPainter>
@ -41,6 +42,13 @@ QgsLayoutMouseHandles::QgsLayoutMouseHandles( QgsLayout *layout, QgsLayoutView *
//accept hover events, required for changing cursor to resize cursors
setAcceptHoverEvents( true );
mHorizontalSnapLine.reset( mView->createSnapLine() );
mHorizontalSnapLine->hide();
layout->addItem( mHorizontalSnapLine.get() );
mVerticalSnapLine.reset( mView->createSnapLine() );
mVerticalSnapLine->hide();
layout->addItem( mVerticalSnapLine.get() );
}
void QgsLayoutMouseHandles::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
@ -697,6 +705,58 @@ void QgsLayoutMouseHandles::resetStatusBar()
}
}
QPointF QgsLayoutMouseHandles::snapPoint( QPointF originalPoint, QgsLayoutMouseHandles::SnapGuideMode mode )
{
//align item
double alignX = 0;
double alignY = 0;
bool snapped = false;
const QList< QgsLayoutItem * > selectedItems = mLayout->selectedLayoutItems();
//depending on the mode, we either snap just the single point, or all the bounds of the selection
QPointF snappedPoint;
switch ( mode )
{
case Item:
//snappedPoint = alignItem( alignX, alignY, point.x(), point.y() );
break;
case Point:
snappedPoint = mLayout->snapper().snapPoint( originalPoint, mView->transform().m11(), snapped, mHorizontalSnapLine.get(), mVerticalSnapLine.get(), &selectedItems );
break;
}
#if 0
if ( !qgsDoubleNear( alignX, -1.0 ) )
{
QGraphicsLineItem *item = hAlignSnapItem();
int numPages = mComposition->numPages();
double yLineCoord = 300; //default in case there is no single page
if ( numPages > 0 )
{
yLineCoord = mComposition->paperHeight() * numPages + mComposition->spaceBetweenPages() * ( numPages - 1 );
}
item->setLine( QLineF( alignX, 0, alignX, yLineCoord ) );
item->show();
}
else
{
deleteHAlignSnapItem();
}
if ( !qgsDoubleNear( alignY, -1.0 ) )
{
QGraphicsLineItem *item = vAlignSnapItem();
item->setLine( QLineF( 0, alignY, mComposition->paperWidth(), alignY ) );
item->show();
}
else
{
deleteVAlignSnapItem();
}
#endif
return snappedPoint;
}
void QgsLayoutMouseHandles::mousePressEvent( QGraphicsSceneMouseEvent *event )
{
//save current cursor position
@ -797,9 +857,6 @@ void QgsLayoutMouseHandles::dragMouseMove( QPointF currentPosition, bool lockMov
QPointF snappedLeftPoint;
//TODO
snappedLeftPoint = upperLeftPoint;
#if 0
//no snapping for rotated items for now
if ( !preventSnap && qgsDoubleNear( rotation(), 0.0 ) )
{
@ -810,9 +867,11 @@ void QgsLayoutMouseHandles::dragMouseMove( QPointF currentPosition, bool lockMov
{
//no snapping
snappedLeftPoint = upperLeftPoint;
#if 0
deleteAlignItems();
}
#endif
}
//calculate total shift for item from beginning of drag operation to current position
double moveRectX = snappedLeftPoint.x() - mBeginHandlePos.x();
double moveRectY = snappedLeftPoint.y() - mBeginHandlePos.y();
@ -859,11 +918,8 @@ void QgsLayoutMouseHandles::resizeMouseMove( QPointF currentPosition, bool lockR
//subtract cursor edge offset from begin mouse event and current cursor position, so that snapping occurs to edge of mouse handles
//rather then cursor position
beginMousePos = mapFromScene( QPointF( mBeginMouseEventPos.x() - mCursorOffset.width(), mBeginMouseEventPos.y() - mCursorOffset.height() ) );
#if 0
QPointF snappedPosition = snapPoint( QPointF( currentPosition.x() - mCursorOffset.width(), currentPosition.y() - mCursorOffset.height() ), QgsLayoutMouseHandles::Point );
finalPosition = mapFromScene( snappedPosition );
#endif
finalPosition = mapFromScene( currentPosition );
}
else
{

View File

@ -22,6 +22,7 @@
#include <QGraphicsRectItem>
#include <QObject>
#include <QPointer>
#include <memory>
#include "qgis_gui.h"
@ -157,8 +158,8 @@ class GUI_EXPORT QgsLayoutMouseHandles: public QObject, public QGraphicsRectItem
bool mIsResizing = false;
//! Align snap lines
QGraphicsLineItem *mHAlignSnapItem = nullptr;
QGraphicsLineItem *mVAlignSnapItem = nullptr;
std::unique_ptr< QGraphicsLineItem > mHorizontalSnapLine;
std::unique_ptr< QGraphicsLineItem > mVerticalSnapLine;
QSizeF mCursorOffset;
@ -199,6 +200,10 @@ class GUI_EXPORT QgsLayoutMouseHandles: public QObject, public QGraphicsRectItem
//resets the composer window status bar to the default message
void resetStatusBar();
//! Snaps an item or point (depending on mode) originating at originalPoint to the grid or align rulers
QPointF snapPoint( QPointF originalPoint, SnapGuideMode mode );
};
///@endcond PRIVATE

View File

@ -306,6 +306,7 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
int mCurrentPage = 0;
friend class TestQgsLayoutView;
friend class QgsLayoutMouseHandles;
QGraphicsLineItem *createSnapLine() const;
};

View File

@ -314,6 +314,11 @@ class TestQgsLayoutSnapper(unittest.TestCase):
self.assertTrue(snapped)
self.assertEqual(point, QPointF(0, 1.1))
# ... unless item is ignored!
point, snapped = s.snapPoint(QPointF(1, 1), 1, None, None, [item1])
self.assertTrue(snapped)
self.assertEqual(point, QPointF(0, 0))
def testReadWriteXml(self):
p = QgsProject()
l = QgsLayout(p)