Skip to content

Commit

Permalink
Prevent snapping to selected items when resizing
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Oct 6, 2017
1 parent d8ffab1 commit 051ed1e
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 14 deletions.
5 changes: 4 additions & 1 deletion python/core/layout/qgslayoutsnapper.sip
Original file line number Diff line number Diff line change
Expand Up @@ -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.

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

Expand Down
7 changes: 4 additions & 3 deletions src/core/layout/qgslayoutsnapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion src/core/layout/qgslayoutsnapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 63 additions & 7 deletions src/gui/layout/qgslayoutmousehandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "qgslayoututils.h"
#include "qgslayoutview.h"
#include "qgslayoutviewtoolselect.h"
#include "qgslayoutsnapper.h"
#include <QGraphicsView>
#include <QGraphicsSceneHoverEvent>
#include <QPainter>
Expand All @@ -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 )
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 ) )
{
Expand All @@ -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();
Expand Down Expand Up @@ -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
{
Expand Down
9 changes: 7 additions & 2 deletions src/gui/layout/qgslayoutmousehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <QGraphicsRectItem>
#include <QObject>
#include <QPointer>
#include <memory>

#include "qgis_gui.h"

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/gui/layout/qgslayoutview.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
int mCurrentPage = 0;

friend class TestQgsLayoutView;
friend class QgsLayoutMouseHandles;

QGraphicsLineItem *createSnapLine() const;
};
Expand Down
5 changes: 5 additions & 0 deletions tests/src/python/test_qgslayoutsnapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,11 @@ def testSnapPoint(self):
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)
Expand Down

0 comments on commit 051ed1e

Please sign in to comment.