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 )
288 double diff = std::fabs( p - guidePos );
289 if ( diff < smallestDiff )
292 bestDelta = guidePos - p;
297 if ( smallestDiff <= alignThreshold )
309 QGraphicsLineItem *snapLine )
const 311 double delta =
snapPointsToItems( QList< double >() << original, orientation, scaleFactor, ignoreItems, snapped, snapLine );
312 return original + delta;
315 double QgsLayoutSnapper::snapPointsToItems(
const QList<double> &points, Qt::Orientation orientation,
double scaleFactor,
const QList<QgsLayoutItem *> &ignoreItems,
bool &snapped, QGraphicsLineItem *snapLine )
const 318 if ( !mLayout || !mSnapToItems )
321 snapLine->setVisible(
false );
325 double alignThreshold = mTolerance / scaleFactor;
327 double bestDelta = 0;
328 double smallestDiff = std::numeric_limits<double>::max();
330 const QList<QGraphicsItem *> itemList = mLayout->items();
331 QList< double > currentCoords;
332 for ( QGraphicsItem *item : itemList )
335 if ( !currentItem || ignoreItems.contains( currentItem ) )
339 if ( !currentItem->isVisible() )
343 if ( dynamic_cast<const QgsLayoutItemPage *>( currentItem ) )
347 itemRect = currentItem->mapRectToScene( currentItem->rect() );
351 itemRect = currentItem->mapRectToScene( currentItem->
rectWithFrame() );
354 currentCoords.clear();
355 switch ( orientation )
359 currentCoords << itemRect.left();
360 currentCoords << itemRect.right();
361 currentCoords << itemRect.center().x();
367 currentCoords << itemRect.top();
368 currentCoords << itemRect.center().y();
369 currentCoords << itemRect.bottom();
374 for (
double val : qgis::as_const( currentCoords ) )
376 for (
double p : points )
378 double dist = std::fabs( p - val );
379 if ( dist <= alignThreshold && dist < smallestDiff )
394 snapLine->setVisible(
true );
395 switch ( orientation )
399 snapLine->setLine( QLineF( -100000, closest, 100000, closest ) );
405 snapLine->setLine( QLineF( closest, -100000, closest, 100000 ) );
412 snapLine->setVisible(
false );
422 QDomElement element = document.createElement( QStringLiteral(
"Snapper" ) );
424 element.setAttribute( QStringLiteral(
"tolerance" ), mTolerance );
425 element.setAttribute( QStringLiteral(
"snapToGrid" ), mSnapToGrid );
426 element.setAttribute( QStringLiteral(
"snapToGuides" ), mSnapToGuides );
427 element.setAttribute( QStringLiteral(
"snapToItems" ), mSnapToItems );
429 parentElement.appendChild( element );
435 QDomElement element = e;
436 if ( element.nodeName() != QStringLiteral(
"Snapper" ) )
438 element = element.firstChildElement( QStringLiteral(
"Snapper" ) );
441 if ( element.nodeName() != QStringLiteral(
"Snapper" ) )
446 mTolerance = element.attribute( QStringLiteral(
"tolerance" ), QStringLiteral(
"5" ) ).toInt();
447 mSnapToGrid = element.attribute( QStringLiteral(
"snapToGrid" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
448 mSnapToGuides = element.attribute( QStringLiteral(
"snapToGuides" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
449 mSnapToItems = element.attribute( QStringLiteral(
"snapToItems" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
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.
void setSnapToGrid(bool enabled)
Sets whether snapping to grid is enabled.
The class is used as a container of context for various read/write operations on other objects...
QgsLayoutGuideCollection & guides()
Returns a reference to the layout's guide collection, which manages page snap guides.
QgsLayoutSnapper(QgsLayout *layout)
Constructor for QgsLayoutSnapper, attached to the specified layout.
Base class for graphical items within a QgsLayout.
int type() const override
Returns a unique graphics item type identifier.
This class is a composition of two QSettings instances:
int pageNumberForPoint(QPointF point) const
Returns the page number corresponding to a point in the layout (in layout units). ...
virtual QRectF rectWithFrame() const
Returns the item's rectangular bounds, including any bleed caused by the item's frame.
Contains the configuration for a single snap guide used by a layout.
double snapPointsToGuides(const QList< double > &points, Qt::Orientation orientation, double scaleFactor, bool &snapped) const
Snaps a set of points to the guides.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QPointF snapPointToGrid(QPointF point, double scaleFactor, bool &snappedX, bool &snappedY) const
Snaps a layout coordinate point to the grid.
double layoutPosition() const
Returns the guide's position in absolute layout units.
void setSnapToGuides(bool enabled)
Sets whether snapping to guides is enabled.
QgsLayoutItemPage * page(int pageNumber)
Returns a specific page (by pageNumber) from the collection.
bool writeXml(QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores the snapper's state in a DOM element.
QgsLayoutMeasurement resolution() const
Returns the page/snap grid resolution.
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout...
QgsLayoutGridSettings & gridSettings()
Returns a reference to the layout's grid settings, which stores settings relating to grid appearance...
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.
QPointF snapPointsToGrid(const QList< QPointF > &points, double scaleFactor, bool &snappedX, bool &snappedY) const
Snaps a set of points to the grid.
QgsLayout * layout() override
Returns the layout the object belongs to.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Contains settings relating to the appearance, spacing and offset for layout grids.
bool readXml(const QDomElement &gridElement, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets the snapper's state from a DOM element.
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.
QPointF positionOnPage(QPointF point) const
Returns the position within a page of a point in the layout (in layout units).
QList< QgsLayoutGuide *> guides()
Returns a list of all guides contained in the collection.
QgsLayoutPoint offset() const
Returns the offset of the page/snap grid.
double length() const
Returns the length of the measurement.
double snapPointToGuides(double original, Qt::Orientation orientation, double scaleFactor, bool &snapped) const
Snaps an original layout coordinate to the guides.
void setSnapTolerance(int snapTolerance)
Sets the snap tolerance (in pixels) to use when snapping.
int snapTolerance() const
Returns the snap tolerance (in pixels) to use when snapping.
double convertToLayoutUnits(QgsLayoutMeasurement measurement) const
Converts a measurement into the layout's native units.
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.
void setSnapToItems(bool enabled)
Sets whether snapping to items is enabled.