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 %End
QPointF snapPoint( QPointF point, double scaleFactor, bool &snapped /Out/, QGraphicsLineItem *horizontalSnapLine = 0, 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 %Docstring
Snaps a layout coordinate ``point``. If ``point`` was snapped, ``snapped`` will be set to true. 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 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. 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 :rtype: QPointF
%End %End

View File

@ -49,7 +49,8 @@ void QgsLayoutSnapper::setSnapToItems( bool enabled )
mSnapToItems = 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; snapped = false;
@ -77,7 +78,7 @@ QPointF QgsLayoutSnapper::snapPoint( QPointF point, double scaleFactor, bool &sn
bool snappedYToItems = false; bool snappedYToItems = false;
if ( !snappedXToGuides ) 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 ) if ( snappedXToItems )
{ {
snapped = true; snapped = true;
@ -86,7 +87,7 @@ QPointF QgsLayoutSnapper::snapPoint( QPointF point, double scaleFactor, bool &sn
} }
if ( !snappedYToGuides ) 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 ) if ( snappedYToItems )
{ {
snapped = true; 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 * 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. * 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, 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 * Snaps a layout coordinate \a point to the grid. If \a point

View File

@ -24,6 +24,7 @@
#include "qgslayoututils.h" #include "qgslayoututils.h"
#include "qgslayoutview.h" #include "qgslayoutview.h"
#include "qgslayoutviewtoolselect.h" #include "qgslayoutviewtoolselect.h"
#include "qgslayoutsnapper.h"
#include <QGraphicsView> #include <QGraphicsView>
#include <QGraphicsSceneHoverEvent> #include <QGraphicsSceneHoverEvent>
#include <QPainter> #include <QPainter>
@ -41,6 +42,13 @@ QgsLayoutMouseHandles::QgsLayoutMouseHandles( QgsLayout *layout, QgsLayoutView *
//accept hover events, required for changing cursor to resize cursors //accept hover events, required for changing cursor to resize cursors
setAcceptHoverEvents( true ); 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 ) 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 ) void QgsLayoutMouseHandles::mousePressEvent( QGraphicsSceneMouseEvent *event )
{ {
//save current cursor position //save current cursor position
@ -797,9 +857,6 @@ void QgsLayoutMouseHandles::dragMouseMove( QPointF currentPosition, bool lockMov
QPointF snappedLeftPoint; QPointF snappedLeftPoint;
//TODO
snappedLeftPoint = upperLeftPoint;
#if 0
//no snapping for rotated items for now //no snapping for rotated items for now
if ( !preventSnap && qgsDoubleNear( rotation(), 0.0 ) ) if ( !preventSnap && qgsDoubleNear( rotation(), 0.0 ) )
{ {
@ -810,9 +867,11 @@ void QgsLayoutMouseHandles::dragMouseMove( QPointF currentPosition, bool lockMov
{ {
//no snapping //no snapping
snappedLeftPoint = upperLeftPoint; snappedLeftPoint = upperLeftPoint;
#if 0
deleteAlignItems(); deleteAlignItems();
}
#endif #endif
}
//calculate total shift for item from beginning of drag operation to current position //calculate total shift for item from beginning of drag operation to current position
double moveRectX = snappedLeftPoint.x() - mBeginHandlePos.x(); double moveRectX = snappedLeftPoint.x() - mBeginHandlePos.x();
double moveRectY = snappedLeftPoint.y() - mBeginHandlePos.y(); 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 //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 //rather then cursor position
beginMousePos = mapFromScene( QPointF( mBeginMouseEventPos.x() - mCursorOffset.width(), mBeginMouseEventPos.y() - mCursorOffset.height() ) ); 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 ); QPointF snappedPosition = snapPoint( QPointF( currentPosition.x() - mCursorOffset.width(), currentPosition.y() - mCursorOffset.height() ), QgsLayoutMouseHandles::Point );
finalPosition = mapFromScene( snappedPosition ); finalPosition = mapFromScene( snappedPosition );
#endif
finalPosition = mapFromScene( currentPosition );
} }
else else
{ {

View File

@ -22,6 +22,7 @@
#include <QGraphicsRectItem> #include <QGraphicsRectItem>
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <memory>
#include "qgis_gui.h" #include "qgis_gui.h"
@ -157,8 +158,8 @@ class GUI_EXPORT QgsLayoutMouseHandles: public QObject, public QGraphicsRectItem
bool mIsResizing = false; bool mIsResizing = false;
//! Align snap lines //! Align snap lines
QGraphicsLineItem *mHAlignSnapItem = nullptr; std::unique_ptr< QGraphicsLineItem > mHorizontalSnapLine;
QGraphicsLineItem *mVAlignSnapItem = nullptr; std::unique_ptr< QGraphicsLineItem > mVerticalSnapLine;
QSizeF mCursorOffset; QSizeF mCursorOffset;
@ -199,6 +200,10 @@ class GUI_EXPORT QgsLayoutMouseHandles: public QObject, public QGraphicsRectItem
//resets the composer window status bar to the default message //resets the composer window status bar to the default message
void resetStatusBar(); 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 ///@endcond PRIVATE

View File

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

View File

@ -314,6 +314,11 @@ class TestQgsLayoutSnapper(unittest.TestCase):
self.assertTrue(snapped) self.assertTrue(snapped)
self.assertEqual(point, QPointF(0, 1.1)) 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): def testReadWriteXml(self):
p = QgsProject() p = QgsProject()
l = QgsLayout(p) l = QgsLayout(p)