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.