Skip to content

Commit d8ffab1

Browse files
committed
[FEATURE][layouts] Snapping to item bounds when creating new items
Previously snapping to item bounds would only occur when resizing or moving items, now it also applies to item creation
1 parent d950f17 commit d8ffab1

9 files changed

+80
-2
lines changed

python/gui/layout/qgslayoutviewmouseevent.sip

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ class QgsLayoutViewMouseEvent : QMouseEvent
4040
\param snap set to true to snap the point using the layout's snapping settings
4141
%End
4242

43+
void snapPoint( QGraphicsLineItem *horizontalSnapLine = 0, QGraphicsLineItem *verticalSnapLine = 0 );
44+
%Docstring
45+
Manually triggers a snap for the mouse event position using the layout's snapper.
46+
47+
If the ``horizontalSnapLine`` and ``verticalSnapLine`` arguments are specified, then the snapper
48+
will automatically display and position these lines to indicate snapping positions to item bounds.
49+
%End
50+
4351
QPointF layoutPoint() const;
4452
%Docstring
4553
Returns the event point location in layout coordinates.

src/app/layout/qgslayoutdesignerdialog.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
141141

142142
connect( mActionShowGuides, &QAction::triggered, this, &QgsLayoutDesignerDialog::showGuides );
143143
connect( mActionSnapGuides, &QAction::triggered, this, &QgsLayoutDesignerDialog::snapToGuides );
144+
connect( mActionSmartGuides, &QAction::triggered, this, &QgsLayoutDesignerDialog::snapToItems );
144145

145146
connect( mActionShowBoxes, &QAction::triggered, this, &QgsLayoutDesignerDialog::showBoxes );
146147

@@ -344,6 +345,7 @@ void QgsLayoutDesignerDialog::setCurrentLayout( QgsLayout *layout )
344345
mActionSnapGrid->setChecked( mLayout->snapper().snapToGrid() );
345346
mActionShowGuides->setChecked( mLayout->guides().visible() );
346347
mActionSnapGuides->setChecked( mLayout->snapper().snapToGuides() );
348+
mActionSmartGuides->setChecked( mLayout->snapper().snapToItems() );
347349
mActionShowBoxes->setChecked( mLayout->context().boundingBoxesVisible() );
348350

349351
connect( mLayout->undoStack()->stack(), &QUndoStack::canUndoChanged, mActionUndo, &QAction::setEnabled );
@@ -460,6 +462,11 @@ void QgsLayoutDesignerDialog::snapToGuides( bool enabled )
460462
mLayout->snapper().setSnapToGuides( enabled );
461463
}
462464

465+
void QgsLayoutDesignerDialog::snapToItems( bool enabled )
466+
{
467+
mLayout->snapper().setSnapToItems( enabled );
468+
}
469+
463470
void QgsLayoutDesignerDialog::closeEvent( QCloseEvent * )
464471
{
465472
emit aboutToClose();

src/app/layout/qgslayoutdesignerdialog.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
141141
*/
142142
void snapToGuides( bool enabled );
143143

144+
/**
145+
* Toggles whether snapping to the item guides ("smart" guides) is \a enabled.
146+
*/
147+
void snapToItems( bool enabled );
148+
144149
signals:
145150

146151
/**

src/gui/layout/qgslayoutmousehandles.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,10 @@ Qt::CursorShape QgsLayoutMouseHandles::cursorForPosition( QPointF itemCoordPos )
408408
return Qt::SizeVerCursor;
409409
}
410410
case SelectItem:
411-
// default:
412411
return Qt::ArrowCursor;
413412
}
413+
414+
return Qt::ArrowCursor;
414415
}
415416

416417
QgsLayoutMouseHandles::MouseAction QgsLayoutMouseHandles::mouseActionForPosition( QPointF itemCoordPos )

src/gui/layout/qgslayoutview.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ void QgsLayoutView::setCurrentLayout( QgsLayout *layout )
7474
mSnapMarker->hide();
7575
layout->addItem( mSnapMarker.get() );
7676

77+
mHorizontalSnapLine.reset( createSnapLine() );
78+
mHorizontalSnapLine->hide();
79+
layout->addItem( mHorizontalSnapLine.get() );
80+
mVerticalSnapLine.reset( createSnapLine() );
81+
mVerticalSnapLine->hide();
82+
layout->addItem( mVerticalSnapLine.get() );
83+
7784
if ( mHorizontalRuler )
7885
{
7986
connect( &layout->guides(), &QAbstractItemModel::dataChanged, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
@@ -318,7 +325,11 @@ void QgsLayoutView::mouseMoveEvent( QMouseEvent *event )
318325
QPointF cursorPos = mapToScene( mMouseCurrentXY );
319326
if ( mTool )
320327
{
321-
std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, mTool->flags() & QgsLayoutViewTool::FlagSnaps ) );
328+
std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, false ) );
329+
if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
330+
{
331+
me->snapPoint( mHorizontalSnapLine.get(), mVerticalSnapLine.get() );
332+
}
322333
if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
323334
{
324335
//draw snapping point indicator
@@ -494,6 +505,16 @@ void QgsLayoutView::wheelZoom( QWheelEvent *event )
494505
}
495506
}
496507

508+
QGraphicsLineItem *QgsLayoutView::createSnapLine() const
509+
{
510+
std::unique_ptr< QGraphicsLineItem> item( new QGraphicsLineItem( nullptr ) );
511+
QPen pen = QPen( QColor( Qt::blue ) );
512+
pen.setStyle( Qt::DotLine );
513+
pen.setWidthF( 0.0 );
514+
item->setPen( pen );
515+
item->setZValue( QgsLayout::ZSmartGuide );
516+
return item.release();
517+
}
497518

498519
//
499520
// QgsLayoutViewSnapMarker

src/gui/layout/qgslayoutview.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,14 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
300300

301301
std::unique_ptr< QgsLayoutViewSnapMarker > mSnapMarker;
302302

303+
std::unique_ptr< QGraphicsLineItem > mHorizontalSnapLine;
304+
std::unique_ptr< QGraphicsLineItem > mVerticalSnapLine;
305+
303306
int mCurrentPage = 0;
304307

305308
friend class TestQgsLayoutView;
306309

310+
QGraphicsLineItem *createSnapLine() const;
307311
};
308312

309313

src/gui/layout/qgslayoutviewmouseevent.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ QgsLayoutViewMouseEvent::QgsLayoutViewMouseEvent( QgsLayoutView *view, QMouseEve
3333
}
3434
}
3535

36+
void QgsLayoutViewMouseEvent::snapPoint( QGraphicsLineItem *horizontalSnapLine, QGraphicsLineItem *verticalSnapLine )
37+
{
38+
if ( mView->currentLayout() )
39+
{
40+
mSnappedPoint = mView->currentLayout()->snapper().snapPoint( mLayoutPoint, mView->transform().m11(), mSnapped, horizontalSnapLine, verticalSnapLine );
41+
}
42+
}
43+
3644
QPointF QgsLayoutViewMouseEvent::layoutPoint() const
3745
{
3846
return mLayoutPoint;

src/gui/layout/qgslayoutviewmouseevent.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgis_gui.h"
2222

2323
class QgsLayoutView;
24+
class QGraphicsLineItem;
2425

2526
/**
2627
* \ingroup gui
@@ -52,6 +53,14 @@ class GUI_EXPORT QgsLayoutViewMouseEvent : public QMouseEvent
5253
*/
5354
QgsLayoutViewMouseEvent( QgsLayoutView *view, QMouseEvent *event, bool snap = false );
5455

56+
/**
57+
* Manually triggers a snap for the mouse event position using the layout's snapper.
58+
*
59+
* If the \a horizontalSnapLine and \a verticalSnapLine arguments are specified, then the snapper
60+
* will automatically display and position these lines to indicate snapping positions to item bounds.
61+
*/
62+
void snapPoint( QGraphicsLineItem *horizontalSnapLine = nullptr, QGraphicsLineItem *verticalSnapLine = nullptr );
63+
5564
/**
5665
* Returns the event point location in layout coordinates.
5766
* \see pos()

src/ui/layout/qgslayoutdesignerbase.ui

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
<addaction name="separator"/>
128128
<addaction name="mActionShowGuides"/>
129129
<addaction name="mActionSnapGuides"/>
130+
<addaction name="mActionSmartGuides"/>
130131
<addaction name="mActionManageGuides"/>
131132
<addaction name="mActionClearGuides"/>
132133
<addaction name="separator"/>
@@ -451,6 +452,20 @@
451452
<string>Ctrl+Shift+B</string>
452453
</property>
453454
</action>
455+
<action name="mActionSmartGuides">
456+
<property name="checkable">
457+
<bool>true</bool>
458+
</property>
459+
<property name="text">
460+
<string>S&amp;mart Guides</string>
461+
</property>
462+
<property name="toolTip">
463+
<string>Smart guides</string>
464+
</property>
465+
<property name="shortcut">
466+
<string>Ctrl+Alt+;</string>
467+
</property>
468+
</action>
454469
</widget>
455470
<resources>
456471
<include location="../../../images/images.qrc"/>

0 commit comments

Comments
 (0)