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() )
344 if ( dynamic_cast<const QgsLayoutItemPage *>( currentItem ) )
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 : qgis::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() != QStringLiteral(
"Snapper" ) )
439 element = element.firstChildElement( QStringLiteral(
"Snapper" ) );
442 if ( element.nodeName() != QStringLiteral(
"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" );
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.
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.