29 mTolerance = s.
value( QStringLiteral(
"LayoutDesigner/defaultSnapTolerancePixels" ), 5,
QgsSettings::Gui ).toInt();
44 mSnapToGrid = enabled;
49 mSnapToGuides = enabled;
54 mSnapToItems = enabled;
57QPointF
QgsLayoutSnapper::snapPoint( QPointF point,
double scaleFactor,
bool &snapped, QGraphicsLineItem *horizontalSnapLine, QGraphicsLineItem *verticalSnapLine,
58 const QList< QgsLayoutItem * > *ignoreItems )
const
63 bool snappedXToGuides =
false;
64 double newX =
snapPointToGuides( point.x(), Qt::Vertical, scaleFactor, snappedXToGuides );
65 if ( snappedXToGuides )
69 if ( verticalSnapLine )
70 verticalSnapLine->setVisible(
false );
72 bool snappedYToGuides =
false;
73 double newY =
snapPointToGuides( point.y(), Qt::Horizontal, scaleFactor, snappedYToGuides );
74 if ( snappedYToGuides )
78 if ( horizontalSnapLine )
79 horizontalSnapLine->setVisible(
false );
82 bool snappedXToItems =
false;
83 bool snappedYToItems =
false;
84 if ( !snappedXToGuides )
86 newX =
snapPointToItems( point.x(), Qt::Horizontal, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedXToItems, verticalSnapLine );
87 if ( snappedXToItems )
93 if ( !snappedYToGuides )
95 newY =
snapPointToItems( point.y(), Qt::Vertical, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedYToItems, horizontalSnapLine );
96 if ( snappedYToItems )
103 bool snappedXToGrid =
false;
104 bool snappedYToGrid =
false;
105 QPointF res =
snapPointToGrid( point, scaleFactor, snappedXToGrid, snappedYToGrid );
106 if ( snappedXToGrid && !snappedXToGuides && !snappedXToItems )
109 point.setX( res.x() );
111 if ( snappedYToGrid && !snappedYToGuides && !snappedYToItems )
114 point.setY( res.y() );
120QRectF
QgsLayoutSnapper::snapRect(
const QRectF &rect,
double scaleFactor,
bool &snapped, QGraphicsLineItem *horizontalSnapLine, QGraphicsLineItem *verticalSnapLine,
const QList<QgsLayoutItem *> *ignoreItems )
const
123 QRectF snappedRect = rect;
125 QList< double > xCoords;
126 xCoords << rect.left() << rect.center().x() << rect.right();
127 QList< double > yCoords;
128 yCoords << rect.top() << rect.center().y() << rect.bottom();
131 bool snappedXToGuides =
false;
132 double deltaX =
snapPointsToGuides( xCoords, Qt::Vertical, scaleFactor, snappedXToGuides );
133 if ( snappedXToGuides )
136 snappedRect.translate( deltaX, 0 );
137 if ( verticalSnapLine )
138 verticalSnapLine->setVisible(
false );
140 bool snappedYToGuides =
false;
141 double deltaY =
snapPointsToGuides( yCoords, Qt::Horizontal, scaleFactor, snappedYToGuides );
142 if ( snappedYToGuides )
145 snappedRect.translate( 0, deltaY );
146 if ( horizontalSnapLine )
147 horizontalSnapLine->setVisible(
false );
150 bool snappedXToItems =
false;
151 bool snappedYToItems =
false;
152 if ( !snappedXToGuides )
154 deltaX =
snapPointsToItems( xCoords, Qt::Horizontal, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedXToItems, verticalSnapLine );
155 if ( snappedXToItems )
158 snappedRect.translate( deltaX, 0 );
161 if ( !snappedYToGuides )
163 deltaY =
snapPointsToItems( yCoords, Qt::Vertical, scaleFactor, ignoreItems ? *ignoreItems : QList< QgsLayoutItem * >(), snappedYToItems, horizontalSnapLine );
164 if ( snappedYToItems )
167 snappedRect.translate( 0, deltaY );
171 bool snappedXToGrid =
false;
172 bool snappedYToGrid =
false;
173 QList< QPointF > points;
174 points << rect.topLeft() << rect.topRight() << rect.bottomLeft() << rect.bottomRight();
175 QPointF res =
snapPointsToGrid( points, scaleFactor, snappedXToGrid, snappedYToGrid );
176 if ( snappedXToGrid && !snappedXToGuides && !snappedXToItems )
179 snappedRect.translate( res.x(), 0 );
181 if ( snappedYToGrid && !snappedYToGuides && !snappedYToItems )
184 snappedRect.translate( 0, res.y() );
192 QPointF delta =
snapPointsToGrid( QList< QPointF >() << point, scaleFactor, snappedX, snappedY );
193 return point + delta;
200 if ( !mLayout || !mSnapToGrid )
202 return QPointF( 0, 0 );
206 return QPointF( 0, 0 );
210 double smallestDiffX = std::numeric_limits<double>::max();
211 double smallestDiffY = std::numeric_limits<double>::max();
212 for ( QPointF point : points )
215 QPointF pagePoint = mLayout->pageCollection()->positionOnPage( point );
217 double yPage = pagePoint.y();
218 double yAtTopOfPage = mLayout->pageCollection()->page( mLayout->pageCollection()->pageNumberForPoint( point ) )->pos().y();
221 double gridRes = mLayout->convertToLayoutUnits( grid.
resolution() );
222 QPointF gridOffset = mLayout->convertToLayoutUnits( grid.
offset() );
223 int xRatio =
static_cast< int >( ( point.x() - gridOffset.x() ) / gridRes + 0.5 );
224 int yRatio =
static_cast< int >( ( yPage - gridOffset.y() ) / gridRes + 0.5 );
226 double xSnapped = xRatio * gridRes + gridOffset.x();
227 double ySnapped = yRatio * gridRes + gridOffset.y() + yAtTopOfPage;
229 double currentDiffX = std::fabs( xSnapped - point.x() );
230 if ( currentDiffX < smallestDiffX )
232 smallestDiffX = currentDiffX;
233 deltaX = xSnapped - point.x();
236 double currentDiffY = std::fabs( ySnapped - point.y() );
237 if ( currentDiffY < smallestDiffY )
239 smallestDiffY = currentDiffY;
240 deltaY = ySnapped - point.y();
245 double alignThreshold = mTolerance / scaleFactor;
247 QPointF delta( 0, 0 );
248 if ( smallestDiffX <= alignThreshold )
252 delta.setX( deltaX );
254 if ( smallestDiffY <= alignThreshold )
258 delta.setY( deltaY );
266 double delta =
snapPointsToGuides( QList< double >() << original, orientation, scaleFactor, snapped );
267 return original + delta;
273 if ( !mLayout || !mSnapToGuides )
279 double alignThreshold = mTolerance / scaleFactor;
281 double bestDelta = 0;
282 double smallestDiff = std::numeric_limits<double>::max();
284 for (
double p : points )
286 const auto constGuides = mLayout->guides().guides( orientation );
289 double guidePos = guide->layoutPosition();
290 double diff = std::fabs( p - guidePos );
291 if ( diff < smallestDiff )
294 bestDelta = guidePos - p;
299 if ( smallestDiff <= alignThreshold )
311 QGraphicsLineItem *snapLine )
const
313 double delta =
snapPointsToItems( QList< double >() << original, orientation, scaleFactor, ignoreItems, snapped, snapLine );
314 return original + delta;
317double QgsLayoutSnapper::snapPointsToItems(
const QList<double> &points, Qt::Orientation orientation,
double scaleFactor,
const QList<QgsLayoutItem *> &ignoreItems,
bool &snapped, QGraphicsLineItem *snapLine )
const
320 if ( !mLayout || !mSnapToItems )
323 snapLine->setVisible(
false );
327 double alignThreshold = mTolerance / scaleFactor;
329 double bestDelta = 0;
330 double smallestDiff = std::numeric_limits<double>::max();
332 const QList<QGraphicsItem *> itemList = mLayout->items();
333 QList< double > currentCoords;
334 for ( QGraphicsItem *item : itemList )
337 if ( !currentItem || ignoreItems.contains( currentItem ) )
341 if ( !currentItem->isVisible() )
349 itemRect = currentItem->mapRectToScene( currentItem->rect() );
353 itemRect = currentItem->mapRectToScene( currentItem->
rectWithFrame() );
356 currentCoords.clear();
357 switch ( orientation )
361 currentCoords << itemRect.left();
362 currentCoords << itemRect.right();
363 currentCoords << itemRect.center().x();
369 currentCoords << itemRect.top();
370 currentCoords << itemRect.center().y();
371 currentCoords << itemRect.bottom();
376 for (
double val : std::as_const( currentCoords ) )
378 for (
double p : points )
380 double dist = std::fabs( p - val );
381 if ( dist <= alignThreshold && dist < smallestDiff )
396 snapLine->setVisible(
true );
397 switch ( orientation )
401 snapLine->setLine( QLineF( -100000, closest, 100000, closest ) );
407 snapLine->setLine( QLineF( closest, -100000, closest, 100000 ) );
414 snapLine->setVisible(
false );
424 QDomElement element = document.createElement( QStringLiteral(
"Snapper" ) );
426 element.setAttribute( QStringLiteral(
"tolerance" ), mTolerance );
427 element.setAttribute( QStringLiteral(
"snapToGrid" ), mSnapToGrid );
428 element.setAttribute( QStringLiteral(
"snapToGuides" ), mSnapToGuides );
429 element.setAttribute( QStringLiteral(
"snapToItems" ), mSnapToItems );
431 parentElement.appendChild( element );
437 QDomElement element = e;
438 if ( element.nodeName() != QLatin1String(
"Snapper" ) )
440 element = element.firstChildElement( QStringLiteral(
"Snapper" ) );
443 if ( element.nodeName() != QLatin1String(
"Snapper" ) )
448 mTolerance = element.attribute( QStringLiteral(
"tolerance" ), QStringLiteral(
"5" ) ).toInt();
449 mSnapToGrid = element.attribute( QStringLiteral(
"snapToGrid" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
450 mSnapToGuides = element.attribute( QStringLiteral(
"snapToGuides" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" );
451 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.
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.
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.
A container for the context for various read/write operations on objects.
Stores settings for use within QGIS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.