Skip to content
Permalink
Browse files
[FEATURE]: snap to left/mid/right coordinates of other items when mov…
…ing composer items
  • Loading branch information
mhugent committed Jan 17, 2013
1 parent 0357f0f commit e7e28697b7ac8a2600a2be518dedd6bd8c266407
Showing with 162 additions and 2 deletions.
  1. +5 −2 src/core/composer/qgscomposeritem.cpp
  2. +144 −0 src/core/composer/qgscomposition.cpp
  3. +13 −0 src/core/composer/qgscomposition.h
@@ -503,8 +503,7 @@ void QgsComposerItem::changeItemRectangle( const QPointF& currentPosition,

double mx = 0.0, my = 0.0, rx = 0.0, ry = 0.0;
QPointF snappedPosition = mComposition->snapPointToGrid( currentPosition );
//double diffX = snappedPosition.x() - mouseMoveStartPos.x();
//double diffY = snappedPosition.y() - mouseMoveStartPos.y();

double diffX = 0;
double diffY = 0;

@@ -566,6 +565,10 @@ void QgsComposerItem::changeItemRectangle( const QPointF& currentPosition,
QPointF upperLeftPoint( originalItem->transform().dx() + moveX, originalItem->transform().dy() + moveY );
QPointF snappedLeftPoint = mComposition->snapPointToGrid( upperLeftPoint );

//align item
double alignX = 0;
double alignY = 0;
snappedLeftPoint = mComposition->alignItem( dynamic_cast<const QgsComposerItem*>( originalItem ), alignX, alignY, moveX, moveY );
double moveRectX = snappedLeftPoint.x() - originalItem->transform().dx();
double moveRectY = snappedLeftPoint.y() - originalItem->transform().dy();

@@ -976,6 +976,150 @@ QPointF QgsComposition::snapPointToGrid( const QPointF& scenePoint ) const
return QPointF( xRatio * mSnapGridResolution + mSnapGridOffsetX, yRatio * mSnapGridResolution + mSnapGridOffsetY + yOffset );
}

QPointF QgsComposition::alignItem( const QgsComposerItem* item, double& alignX, double& alignY, double dx, double dy )
{
if ( !item )
{
return QPointF();
}

double left = item->transform().dx() + dx;
double right = left + item->rect().width();
double midH = ( left + right ) / 2.0;
double top = item->transform().dy() + dy;
double bottom = top + item->rect().height();
double midV = ( top + bottom ) / 2.0;

QMap<double, const QgsComposerItem* > xAlignCoordinates;
QMap<double, const QgsComposerItem* > yAlignCoordinates;

QList<QGraphicsItem *> itemList = items();
QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
for ( ; itemIt != itemList.end(); ++itemIt )
{
const QgsComposerItem* currentItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
if ( item )
{
if ( !currentItem || currentItem == item || currentItem->type() == QgsComposerItem::ComposerPaper )
{
continue;
}
xAlignCoordinates.insert( currentItem->transform().dx(), currentItem );
xAlignCoordinates.insert( currentItem->transform().dx() + currentItem->rect().width(), currentItem );
xAlignCoordinates.insert( currentItem->transform().dx() + currentItem->rect().width() / 2.0, currentItem );
yAlignCoordinates.insert( currentItem->rect().top(), currentItem );
yAlignCoordinates.insert( currentItem->rect().center().y(), currentItem );
yAlignCoordinates.insert( currentItem->rect().bottom(), currentItem );
}
}

//find nearest matches x
double xItemLeft = left; //new left coordinate of the item
double xAlignCoord = 0;
double smallestDiffX = DBL_MAX;
double currentX = 0;
double currentDiffX = 0;

currentX = nearestItem( xAlignCoordinates, left );
currentDiffX = abs( left - currentX );
if ( currentDiffX < smallestDiffX )
{
xItemLeft = currentX;
xAlignCoord = currentX;
smallestDiffX = currentDiffX;
}

currentX = nearestItem( xAlignCoordinates, midH );
currentDiffX = abs( midH - currentX );
if ( currentDiffX < smallestDiffX )
{
xItemLeft = currentX - ( right - left ) / 2.0;
xAlignCoord = currentX;
smallestDiffX = currentDiffX;
}

currentX = nearestItem( xAlignCoordinates, right );
currentDiffX = abs( right - currentX );
if ( currentDiffX < smallestDiffX )
{
xItemLeft = currentX - ( right - left );
xAlignCoord = currentX;
smallestDiffX = currentDiffX;
}

//find nearest matches y
double yItemTop = top; //new top coordinate of the item
double yAlignCoord = 0;
double smallestDiffY = DBL_MAX;
double currentY = 0;
double currentDiffY = 0;

currentY = nearestItem( yAlignCoordinates, top );
currentDiffY = abs( top - currentY );
if ( currentDiffY < smallestDiffY )
{
yItemTop = currentY;
yAlignCoord = currentY;
smallestDiffY = currentDiffY;
}

currentY = nearestItem( yAlignCoordinates, midV );
currentDiffY = abs( midV - currentY );
if ( currentDiffY < smallestDiffY )
{
yItemTop = currentY - ( bottom - top ) / 2.0;
yAlignCoord = currentY;
smallestDiffY = currentDiffY;
}

currentY = nearestItem( yAlignCoordinates, bottom );
currentDiffY = abs( bottom - currentY );
if ( currentDiffY < smallestDiffY )
{
yItemTop = currentY - ( bottom - top );
yAlignCoord = currentY;
smallestDiffY = currentDiffY;
}

double xCoord = ( smallestDiffX < 5 ) ? xItemLeft : item->transform().dx() + dx;
alignX = ( smallestDiffX < 5 ) ? xAlignCoord : -1;
double yCoord = ( smallestDiffY < 5 ) ? yItemTop : item->transform().dy() + dy;
alignY = ( smallestDiffY < 5 ) ? yAlignCoord : -1;
return QPointF( xCoord, yCoord );
}

double QgsComposition::nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value )
{
QMap< double, const QgsComposerItem* >::const_iterator it = coords.lowerBound( value );
if ( it == coords.constBegin() ) //value smaller than first map value
{
return it.key();
}
else if ( it == coords.constEnd() ) //value larger than last map value
{
--it;
return it.key();
}
else
{
//get smaller value and larger value and return the closer one
double upperVal = it.key();
--it;
double lowerVal = it.key();

double lowerDiff = value - lowerVal;
double upperDiff = upperVal - value;
if ( lowerDiff < upperDiff )
{
return lowerVal;
}
else
{
return upperVal;
}
}
}

int QgsComposition::boundingRectOfSelectedItems( QRectF& bRect )
{
QList<QgsComposerItem*> selectedItems = selectedComposerItems();
@@ -236,6 +236,19 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Snaps a scene coordinate point to grid*/
QPointF snapPointToGrid( const QPointF& scenePoint ) const;

/**Snaps item position to align with other items (left / middle / right or top / middle / bottom
@param itemRectangle current item rectangle
@param alignX x-coordinate of align or -1 if not aligned to x
@param alignY y-coordinate of align or -1 if not aligned to y
@param dx item shift in x direction
@param dy item shift in y direction
@return new upper left point after the align*/
QPointF alignItem( const QgsComposerItem* item, double& alignX, double& alignY, double dx = 0, double dy = 0 );

//helper functions
/**Returns the nearest double*/
double nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value );

/**Allocates new item command and saves initial state in it
@param item target item
@param commandText descriptive command text

0 comments on commit e7e2869

Please sign in to comment.