22 #include "qgssettings.h"
28 mTolerance = s.value( QStringLiteral(
"LayoutDesigner/defaultSnapTolerancePixels" ), 5, QgsSettings::Gui ).toInt();
43 mSnapToGrid = enabled;
48 mSnapToGuides = enabled;
53 mSnapToItems = enabled;
56 QPointF
QgsLayoutSnapper::snapPoint( QPointF point,
double scaleFactor,
bool &snapped, QGraphicsLineItem *horizontalSnapLine, QGraphicsLineItem *verticalSnapLine,
57 const QList< QgsLayoutItem * > *ignoreItems )
const
62 bool snappedXToGuides =
false;
63 double newX =
snapPointToGuides( point.x(), Qt::Vertical, scaleFactor, snappedXToGuides );
64 if ( snappedXToGuides )
68 if ( verticalSnapLine )
69 verticalSnapLine->setVisible(
false );
71 bool snappedYToGuides =
false;
72 double newY =
snapPointToGuides( point.y(), Qt::Horizontal, scaleFactor, snappedYToGuides );
73 if ( snappedYToGuides )
77 if ( horizontalSnapLine )
78 horizontalSnapLine->setVisible(
false );
81 bool snappedXToItems =
false;
82 bool snappedYToItems =
false;
83 if ( !snappedXToGuides )
85 newX =
snapPointToItems( point.x(), Qt::Horizontal, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedXToItems, verticalSnapLine );
86 if ( snappedXToItems )
92 if ( !snappedYToGuides )
94 newY =
snapPointToItems( point.y(), Qt::Vertical, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedYToItems, horizontalSnapLine );
95 if ( snappedYToItems )
102 bool snappedXToGrid =
false;
103 bool snappedYToGrid =
false;
104 QPointF res =
snapPointToGrid( point, scaleFactor, snappedXToGrid, snappedYToGrid );
105 if ( snappedXToGrid && !snappedXToGuides && !snappedXToItems )
108 point.setX( res.x() );
110 if ( snappedYToGrid && !snappedYToGuides && !snappedYToItems )
113 point.setY( res.y() );
119 QRectF
QgsLayoutSnapper::snapRect(
const QRectF &rect,
double scaleFactor,
bool &snapped, QGraphicsLineItem *horizontalSnapLine, QGraphicsLineItem *verticalSnapLine,
const QList<QgsLayoutItem *> *ignoreItems )
const
122 QRectF snappedRect = rect;
124 QList< double > xCoords;
125 xCoords << rect.left() << rect.center().x() << rect.right();
126 QList< double > yCoords;
127 yCoords << rect.top() << rect.center().y() << rect.bottom();
130 bool snappedXToGuides =
false;
131 double deltaX =
snapPointsToGuides( xCoords, Qt::Vertical, scaleFactor, snappedXToGuides );
132 if ( snappedXToGuides )
135 snappedRect.translate( deltaX, 0 );
136 if ( verticalSnapLine )
137 verticalSnapLine->setVisible(
false );
139 bool snappedYToGuides =
false;
140 double deltaY =
snapPointsToGuides( yCoords, Qt::Horizontal, scaleFactor, snappedYToGuides );
141 if ( snappedYToGuides )
144 snappedRect.translate( 0, deltaY );
145 if ( horizontalSnapLine )
146 horizontalSnapLine->setVisible(
false );
149 bool snappedXToItems =
false;
150 bool snappedYToItems =
false;
151 if ( !snappedXToGuides )
153 deltaX =
snapPointsToItems( xCoords, Qt::Horizontal, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedXToItems, verticalSnapLine );
154 if ( snappedXToItems )
157 snappedRect.translate( deltaX, 0 );
160 if ( !snappedYToGuides )
162 deltaY =
snapPointsToItems( yCoords, Qt::Vertical, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedYToItems, horizontalSnapLine );
163 if ( snappedYToItems )
166 snappedRect.translate( 0, deltaY );
170 bool snappedXToGrid =
false;
171 bool snappedYToGrid =
false;
172 QList< QPointF > points;
173 points << rect.topLeft() << rect.topRight() << rect.bottomLeft() << rect.bottomRight();
174 QPointF res =
snapPointsToGrid( points, scaleFactor, snappedXToGrid, snappedYToGrid );
175 if ( snappedXToGrid && !snappedXToGuides && !snappedXToItems )
178 snappedRect.translate( res.x(), 0 );
180 if ( snappedYToGrid && !snappedYToGuides && !snappedYToItems )
183 snappedRect.translate( 0, res.y() );
191 QPointF delta =
snapPointsToGrid( QList< QPointF >() << point, scaleFactor, snappedX, snappedY );
192 return point + delta;
199 if ( !mLayout || !mSnapToGrid )
201 return QPointF( 0, 0 );
205 return QPointF( 0, 0 );
209 double smallestDiffX = std::numeric_limits<double>::max();
210 double smallestDiffY = std::numeric_limits<double>::max();
211 for ( QPointF point : points )
216 double yPage = pagePoint.y();
222 int xRatio =
static_cast< int >( ( point.x() - gridOffset.x() ) / gridRes + 0.5 );
223 int yRatio =
static_cast< int >( ( yPage - gridOffset.y() ) / gridRes + 0.5 );
225 double xSnapped = xRatio * gridRes + gridOffset.x();
226 double ySnapped = yRatio * gridRes + gridOffset.y() + yAtTopOfPage;
228 double currentDiffX = std::fabs( xSnapped - point.x() );
229 if ( currentDiffX < smallestDiffX )
231 smallestDiffX = currentDiffX;
232 deltaX = xSnapped - point.x();
235 double currentDiffY = std::fabs( ySnapped - point.y() );
236 if ( currentDiffY < smallestDiffY )
238 smallestDiffY = currentDiffY;
239 deltaY = ySnapped - point.y();
244 double alignThreshold = mTolerance / scaleFactor;
246 QPointF delta( 0, 0 );
247 if ( smallestDiffX <= alignThreshold )
251 delta.setX( deltaX );
253 if ( smallestDiffY <= alignThreshold )
257 delta.setY( deltaY );
265 double delta =
snapPointsToGuides( QList< double >() << original, orientation, scaleFactor, snapped );
266 return original + delta;
272 if ( !mLayout || !mSnapToGuides )
278 double alignThreshold = mTolerance / scaleFactor;
280 double bestDelta = 0;
281 double smallestDiff = std::numeric_limits<double>::max();
283 for (
double p : points )
285 const auto constGuides = mLayout->
guides().
guides( orientation );
288 double guidePos = guide->layoutPosition();
289 double diff = std::fabs( p - guidePos );
290 if ( diff < smallestDiff )
293 bestDelta = guidePos - p;
298 if ( smallestDiff <= alignThreshold )
310 QGraphicsLineItem *snapLine )
const
312 double delta =
snapPointsToItems( QList< double >() << original, orientation, scaleFactor, ignoreItems, snapped, snapLine );
313 return original + delta;
316 double QgsLayoutSnapper::snapPointsToItems(
const QList<double> &points, Qt::Orientation orientation,
double scaleFactor,
const QList<QgsLayoutItem *> &ignoreItems,
bool &snapped, QGraphicsLineItem *snapLine )
const
319 if ( !mLayout || !mSnapToItems )
322 snapLine->setVisible(
false );
326 double alignThreshold = mTolerance / scaleFactor;
328 double bestDelta = 0;
329 double smallestDiff = std::numeric_limits<double>::max();
331 const QList<QGraphicsItem *> itemList = mLayout->items();
332 QList< double > currentCoords;
333 for ( QGraphicsItem *item : itemList )
336 if ( !currentItem || ignoreItems.contains( currentItem ) )
340 if ( !currentItem->isVisible() )
348 itemRect = currentItem->mapRectToScene( currentItem->rect() );
352 itemRect = currentItem->mapRectToScene( currentItem->
rectWithFrame() );
355 currentCoords.clear();
356 switch ( orientation )
360 currentCoords << itemRect.left();
361 currentCoords << itemRect.right();
362 currentCoords << itemRect.center().x();
368 currentCoords << itemRect.top();
369 currentCoords << itemRect.center().y();
370 currentCoords << itemRect.bottom();
375 for (
double val : std::as_const( currentCoords ) )
377 for (
double p : points )
379 double dist = std::fabs( p - val );
380 if ( dist <= alignThreshold && dist < smallestDiff )
395 snapLine->setVisible(
true );
396 switch ( orientation )
400 snapLine->setLine( QLineF( -100000, closest, 100000, closest ) );
406 snapLine->setLine( QLineF( closest, -100000, closest, 100000 ) );
413 snapLine->setVisible(
false );
423 QDomElement element = document.createElement( QStringLiteral(
"Snapper" ) );
425 element.setAttribute( QStringLiteral(
"tolerance" ), mTolerance );
426 element.setAttribute( QStringLiteral(
"snapToGrid" ), mSnapToGrid );
427 element.setAttribute( QStringLiteral(
"snapToGuides" ), mSnapToGuides );
428 element.setAttribute( QStringLiteral(
"snapToItems" ), mSnapToItems );
430 parentElement.appendChild( element );
436 QDomElement element = e;
437 if ( element.nodeName() != QLatin1String(
"Snapper" ) )
439 element = element.firstChildElement( QStringLiteral(
"Snapper" ) );
442 if ( element.nodeName() != QLatin1String(
"Snapper" ) )
447 mTolerance = element.attribute( QStringLiteral(
"tolerance" ), QStringLiteral(
"5" ) ).toInt();
448 mSnapToGrid = element.attribute( QStringLiteral(
"snapToGrid" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
449 mSnapToGuides = element.attribute( QStringLiteral(
"snapToGuides" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
450 mSnapToItems = element.attribute( QStringLiteral(
"snapToItems" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
Contains settings relating to the appearance, spacing and offset for layout grids.
QgsLayoutMeasurement resolution() const
Returns the page/snap grid resolution.
QgsLayoutPoint offset() const
Returns the offset of the page/snap grid.
QList< QgsLayoutGuide * > guides()
Returns a list of all guides contained in the collection.
Contains the configuration for a single snap guide used by a layout.
Item representing the paper in a layout.
@ LayoutGroup
Grouped item.
Base class for graphical items within a QgsLayout.
virtual QRectF rectWithFrame() const
Returns the item's rectangular bounds, including any bleed caused by the item's frame.
int type() const override
Returns a unique graphics item type identifier.
double length() const
Returns the length of the measurement.
int pageNumberForPoint(QPointF point) const
Returns the page number corresponding to a point in the layout (in layout units).
QPointF positionOnPage(QPointF point) const
Returns the position within a page of a point in the layout (in layout units).
QgsLayoutItemPage * page(int pageNumber)
Returns a specific page (by pageNumber) from the collection.
QPointF snapPoint(QPointF point, double scaleFactor, bool &snapped, QGraphicsLineItem *horizontalSnapLine=nullptr, QGraphicsLineItem *verticalSnapLine=nullptr, const QList< QgsLayoutItem * > *ignoreItems=nullptr) const
Snaps a layout coordinate point.
void setSnapToItems(bool enabled)
Sets whether snapping to items is enabled.
QPointF snapPointsToGrid(const QList< QPointF > &points, double scaleFactor, bool &snappedX, bool &snappedY) const
Snaps a set of points to the grid.
QRectF snapRect(const QRectF &rect, double scaleFactor, bool &snapped, QGraphicsLineItem *horizontalSnapLine=nullptr, QGraphicsLineItem *verticalSnapLine=nullptr, const QList< QgsLayoutItem * > *ignoreItems=nullptr) const
Snaps a layout coordinate rect.
int snapTolerance() const
Returns the snap tolerance (in pixels) to use when snapping.
double snapPointsToItems(const QList< double > &points, Qt::Orientation orientation, double scaleFactor, const QList< QgsLayoutItem * > &ignoreItems, bool &snapped, QGraphicsLineItem *snapLine=nullptr) const
Snaps a set of points to the item bounds.
bool readXml(const QDomElement &gridElement, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets the snapper's state from a DOM element.
void setSnapToGuides(bool enabled)
Sets whether snapping to guides is enabled.
QgsLayoutSnapper(QgsLayout *layout)
Constructor for QgsLayoutSnapper, attached to the specified layout.
void setSnapTolerance(int snapTolerance)
Sets the snap tolerance (in pixels) to use when snapping.
double snapPointsToGuides(const QList< double > &points, Qt::Orientation orientation, double scaleFactor, bool &snapped) const
Snaps a set of points to the guides.
void setSnapToGrid(bool enabled)
Sets whether snapping to grid is enabled.
QgsLayout * layout() override
Returns the layout the object belongs to.
double snapPointToItems(double original, Qt::Orientation orientation, double scaleFactor, const QList< QgsLayoutItem * > &ignoreItems, bool &snapped, QGraphicsLineItem *snapLine=nullptr) const
Snaps an original layout coordinate to the item bounds.
double snapPointToGuides(double original, Qt::Orientation orientation, double scaleFactor, bool &snapped) const
Snaps an original layout coordinate to the guides.
QPointF snapPointToGrid(QPointF point, double scaleFactor, bool &snappedX, bool &snappedY) const
Snaps a layout coordinate point to the grid.
bool writeXml(QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores the snapper's state in a DOM element.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
QgsLayoutGridSettings & gridSettings()
Returns a reference to the layout's grid settings, which stores settings relating to grid appearance,...
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
QgsLayoutGuideCollection & guides()
Returns a reference to the layout's guide collection, which manages page snap guides.
double convertToLayoutUnits(QgsLayoutMeasurement measurement) const
Converts a measurement into the layout's native units.
The class is used as a container of context for various read/write operations on other objects.