17 #include <QGraphicsView>
18 #include <QGraphicsSceneHoverEvent>
36 , mComposition( composition )
37 , mGraphicsView( nullptr )
38 , mCurrentMouseMoveAction( NoAction )
39 , mBeginHandleWidth( 0 )
40 , mBeginHandleHeight( 0 )
43 , mIsDragging( false )
44 , mIsResizing( false )
45 , mHAlignSnapItem( nullptr )
46 , mVAlignSnapItem( nullptr )
74 mGraphicsView = viewList.
at( 0 );
85 Q_UNUSED( itemStyle );
97 double rectHandlerSize = rectHandlerBorderTolerance();
98 drawHandles( painter, rectHandlerSize );
104 drawSelectedItemBounds( painter );
108 void QgsComposerMouseHandles::drawHandles(
QPainter* painter,
double rectHandlerSize )
113 painter->
setPen( handlePen );
122 painter->
drawRect(
QRectF( 0, 0, rectHandlerSize, rectHandlerSize ) );
124 painter->
drawRect(
QRectF((
rect().width() - rectHandlerSize ) / 2, 0, rectHandlerSize, rectHandlerSize ) );
126 painter->
drawRect(
QRectF(
rect().width() - rectHandlerSize, 0, rectHandlerSize, rectHandlerSize ) );
128 painter->
drawRect(
QRectF( 0, (
rect().height() - rectHandlerSize ) / 2, rectHandlerSize, rectHandlerSize ) );
130 painter->
drawRect(
QRectF(
rect().width() - rectHandlerSize, (
rect().height() - rectHandlerSize ) / 2, rectHandlerSize, rectHandlerSize ) );
132 painter->
drawRect(
QRectF( 0,
rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
134 painter->
drawRect(
QRectF((
rect().width() - rectHandlerSize ) / 2,
rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
136 painter->
drawRect(
QRectF(
rect().width() - rectHandlerSize,
rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
139 void QgsComposerMouseHandles::drawSelectedItemBounds(
QPainter* painter )
154 selectedItemPen.
setStyle( Qt::DashLine );
156 painter->
setPen( selectedItemPen );
160 for ( ; itemIter != selectedItems.
end(); ++itemIter )
164 if ( mIsDragging && !( *itemIter )->positionLock() )
168 QPolygonF itemSceneBounds = ( *itemIter )->mapToScene(( *itemIter )->rectWithFrame() );
175 else if ( mIsResizing && !( *itemIter )->positionLock() )
178 if ( selectedItems.
size() > 1 )
195 itemBounds =
mapRectFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() );
212 for ( ; itemIt != itemList.
end(); ++itemIt )
240 if ( !mIsDragging && !mIsResizing )
249 if ( !mIsDragging && !mIsResizing )
256 void QgsComposerMouseHandles::updateHandles()
262 if ( !selectedItems.
isEmpty() )
268 if ( selectionRotation( rotation ) )
280 QRectF newHandleBounds = selectionBounds();
297 QRectF QgsComposerMouseHandles::selectionBounds()
const
307 for ( ++itemIter; itemIter != selectedItems.
end(); ++itemIter )
315 bool QgsComposerMouseHandles::selectionRotation(
double & rotation )
const
322 double firstItemRotation = ( *itemIter )->itemRotation();
325 for ( ++itemIter; itemIter != selectedItems.
end(); ++itemIter )
327 if ( !
qgsDoubleNear(( *itemIter )->itemRotation(), firstItemRotation ) )
335 rotation = firstItemRotation;
339 double QgsComposerMouseHandles::rectHandlerBorderTolerance()
343 double viewScaleFactor = graphicsView()->
transform().
m11();
346 double rectHandlerSize = 10.0 / viewScaleFactor;
349 if ( rectHandlerSize > (
rect().width() / 3 ) )
353 if ( rectHandlerSize > (
rect().height() / 3 ) )
357 return rectHandlerSize;
360 Qt::CursorShape QgsComposerMouseHandles::cursorForPosition(
QPointF itemCoordPos )
363 switch ( mouseAction )
366 return Qt::ForbiddenCursor;
368 return Qt::SizeAllCursor;
374 return Qt::SizeVerCursor;
378 return Qt::SizeBDiagCursor;
382 return Qt::SizeHorCursor;
386 return Qt::SizeFDiagCursor;
393 return Qt::SizeHorCursor;
397 return Qt::SizeFDiagCursor;
401 return Qt::SizeVerCursor;
405 return Qt::SizeBDiagCursor;
413 return Qt::SizeFDiagCursor;
417 return Qt::SizeVerCursor;
421 return Qt::SizeBDiagCursor;
425 return Qt::SizeHorCursor;
432 return Qt::SizeBDiagCursor;
436 return Qt::SizeHorCursor;
440 return Qt::SizeFDiagCursor;
444 return Qt::SizeVerCursor;
448 return Qt::ArrowCursor;
454 bool nearLeftBorder =
false;
455 bool nearRightBorder =
false;
456 bool nearLowerBorder =
false;
457 bool nearUpperBorder =
false;
459 bool withinWidth =
false;
460 bool withinHeight =
false;
461 if ( itemCoordPos.
x() >= 0 && itemCoordPos.
x() <=
rect().
width() )
465 if ( itemCoordPos.
y() >= 0 && itemCoordPos.
y() <=
rect().
height() )
470 double borderTolerance = rectHandlerBorderTolerance();
472 if ( itemCoordPos.
x() >= 0 && itemCoordPos.
x() < borderTolerance )
474 nearLeftBorder =
true;
476 if ( itemCoordPos.
y() >= 0 && itemCoordPos.
y() < borderTolerance )
478 nearUpperBorder =
true;
480 if ( itemCoordPos.
x() <=
rect().
width() && itemCoordPos.
x() > (
rect().
width() - borderTolerance ) )
482 nearRightBorder =
true;
486 nearLowerBorder =
true;
489 if ( nearLeftBorder && nearUpperBorder )
493 else if ( nearLeftBorder && nearLowerBorder )
497 else if ( nearRightBorder && nearUpperBorder )
501 else if ( nearRightBorder && nearLowerBorder )
505 else if ( nearLeftBorder && withinHeight )
509 else if ( nearRightBorder && withinHeight )
513 else if ( nearUpperBorder && withinWidth )
517 else if ( nearLowerBorder && withinWidth )
525 if ( itemsAtCursorPos.
isEmpty() )
531 for ( ; itemIter != itemsAtCursorPos.
end(); ++itemIter )
549 return mouseActionForPosition( itemPos );
554 setViewportCursor( cursorForPosition( event->
pos() ) );
560 setViewportCursor( Qt::ArrowCursor );
563 void QgsComposerMouseHandles::setViewportCursor( Qt::CursorShape cursor )
581 dragMouseMove( event->
lastScenePos(),
event->modifiers() & Qt::ShiftModifier,
event->modifiers() & Qt::ControlModifier );
583 else if ( mIsResizing )
588 resizeMouseMove( event->
lastScenePos(),
event->modifiers() & Qt::ShiftModifier,
event->modifiers() & Qt::AltModifier );
591 mLastMouseEventPos =
event->lastScenePos();
596 QPointF mouseMoveStopPoint =
event->lastScenePos();
597 double diffX = mouseMoveStopPoint.
x() - mMouseMoveStartPos.
x();
598 double diffY = mouseMoveStopPoint.
y() - mMouseMoveStartPos.
y();
619 for ( ; itemIter != selectedItems.
end(); ++itemIter )
621 if (( *itemIter )->positionLock() || (( *itemIter )->flags() & QGraphicsItem::ItemIsSelectable ) == 0 )
628 ( *itemIter )->move( mEndHandleMovePos.
x() - mBeginHandlePos.
x(), mEndHandleMovePos.
y() - mBeginHandlePos.
y() );
642 for ( ; itemIter != selectedItems.
end(); ++itemIter )
644 if (( *itemIter )->positionLock() || (( *itemIter )->flags() & QGraphicsItem::ItemIsSelectable ) == 0 )
653 if ( selectedItems.
size() == 1 )
656 itemRect = mResizeRect;
661 itemRect =
mapRectFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() );
688 setViewportCursor( Qt::ArrowCursor );
696 void QgsComposerMouseHandles::resetStatusBar()
699 int selectedCount = selectedItems.
size();
700 if ( selectedCount > 1 )
705 else if ( selectedCount == 1 )
720 mMouseMoveStartPos =
event->lastScenePos();
721 mLastMouseEventPos =
event->lastScenePos();
723 mBeginMouseEventPos =
event->lastScenePos();
728 mCurrentMouseMoveAction = mouseActionForPosition( event->
pos() );
742 mResizeRect =
QRectF( 0, 0, mBeginHandleWidth, mBeginHandleHeight );
745 mCursorOffset = calcCursorEdgeOffset( mMouseMoveStartPos );
756 QSizeF QgsComposerMouseHandles::calcCursorEdgeOffset(
QPointF cursorPos )
761 switch ( mCurrentMouseMoveAction )
765 return QSizeF( 0, sceneMousePos.
y() );
772 return QSizeF( sceneMousePos.
x(), 0 );
779 return QSizeF( sceneMousePos.
x(), sceneMousePos.
y() );
796 void QgsComposerMouseHandles::dragMouseMove(
QPointF currentPosition,
bool lockMovement,
bool preventSnap )
804 double moveX = currentPosition.
x() - mBeginMouseEventPos.
x();
805 double moveY = currentPosition.
y() - mBeginMouseEventPos.
y();
808 QPointF upperLeftPoint( mBeginHandlePos.
x() + moveX, mBeginHandlePos.
y() + moveY );
820 snappedLeftPoint = upperLeftPoint;
825 double moveRectX = snappedLeftPoint.x() - mBeginHandlePos.
x();
826 double moveRectY = snappedLeftPoint.y() - mBeginHandlePos.
y();
832 if ( qAbs( moveRectX ) <= qAbs( moveRectY ) )
844 moveTransform.
translate( moveRectX, moveRectY );
850 void QgsComposerMouseHandles::resizeMouseMove(
QPointF currentPosition,
bool lockRatio,
bool fromCenter )
858 double mx = 0.0, my = 0.0, rx = 0.0, ry = 0.0;
879 double diffX = finalPosition.
x() - beginMousePos.
x();
880 double diffY = finalPosition.
y() - beginMousePos.
y();
883 if ( lockRatio && !
qgsDoubleNear( mBeginHandleHeight, 0.0 ) )
885 ratio = mBeginHandleWidth / mBeginHandleHeight;
888 switch ( mCurrentMouseMoveAction )
895 diffX = (( mBeginHandleHeight - diffY ) * ratio ) - mBeginHandleWidth;
915 diffX = (( mBeginHandleHeight + diffY ) * ratio ) - mBeginHandleWidth;
936 diffY = (( mBeginHandleWidth - diffX ) / ratio ) - mBeginHandleHeight;
955 diffY = (( mBeginHandleWidth + diffX ) / ratio ) - mBeginHandleHeight;
976 if (( mBeginHandleWidth - diffX ) / ( mBeginHandleHeight - diffY ) > ratio )
978 diffX = mBeginHandleWidth - (( mBeginHandleHeight - diffY ) * ratio );
982 diffY = mBeginHandleHeight - (( mBeginHandleWidth - diffX ) / ratio );
985 mx = diffX, my = diffY;
996 if (( mBeginHandleWidth + diffX ) / ( mBeginHandleHeight + diffY ) > ratio )
998 diffX = (( mBeginHandleHeight + diffY ) * ratio ) - mBeginHandleWidth;
1002 diffY = (( mBeginHandleWidth + diffX ) / ratio ) - mBeginHandleHeight;
1007 rx = diffX, ry = diffY;
1016 if (( mBeginHandleWidth + diffX ) / ( mBeginHandleHeight - diffY ) > ratio )
1018 diffX = (( mBeginHandleHeight - diffY ) * ratio ) - mBeginHandleWidth;
1022 diffY = mBeginHandleHeight - (( mBeginHandleWidth + diffX ) / ratio );
1026 my = diffY, rx = diffX, ry = -diffY;
1035 if (( mBeginHandleWidth - diffX ) / ( mBeginHandleHeight + diffY ) > ratio )
1037 diffX = mBeginHandleWidth - (( mBeginHandleHeight + diffY ) * ratio );
1041 diffY = (( mBeginHandleWidth - diffX ) / ratio ) - mBeginHandleHeight;
1068 mResizeMoveX = mBeginHandleWidth + rx > 0 ? mx : mx + mBeginHandleWidth + rx;
1069 mResizeMoveY = mBeginHandleHeight + ry > 0 ? my : my + mBeginHandleHeight + ry;
1072 QLineF translateLine =
QLineF( 0, 0, mResizeMoveX, mResizeMoveY );
1074 QPointF sceneTranslate = translateLine.
p2();
1078 itemTransform.
translate( sceneTranslate.
x(), sceneTranslate.
y() );
1082 if ( mBeginHandleWidth + rx >= 0 && mBeginHandleHeight + ry >= 0 )
1084 mResizeRect =
QRectF( 0, 0, mBeginHandleWidth + rx, mBeginHandleHeight + ry );
1086 else if ( mBeginHandleHeight + ry >= 0 )
1088 mResizeRect =
QRectF(
QPointF( -( mBeginHandleWidth + rx ), 0 ),
QPointF( 0, mBeginHandleHeight + ry ) );
1090 else if ( mBeginHandleWidth + rx >= 0 )
1092 mResizeRect =
QRectF(
QPointF( 0, -( mBeginHandleHeight + ry ) ),
QPointF( mBeginHandleWidth + rx, 0 ) );
1096 mResizeRect =
QRectF(
QPointF( -( mBeginHandleWidth + rx ), -( mBeginHandleHeight + ry ) ),
QPointF( 0, 0 ) );
1099 setRect( 0, 0, fabs( mBeginHandleWidth + rx ), fabs( mBeginHandleHeight + ry ) );
1110 if ( snappedPoint != point )
1113 return snappedPoint;
1129 snappedPoint = alignItem( alignX, alignY, point.
x(), point.
y() );
1132 snappedPoint = alignPos( point, alignX, alignY );
1139 int numPages = mComposition->
numPages();
1140 double yLineCoord = 300;
1150 deleteHAlignSnapItem();
1160 deleteVAlignSnapItem();
1162 return snappedPoint;
1167 if ( !mHAlignSnapItem )
1174 return mHAlignSnapItem;
1179 if ( !mVAlignSnapItem )
1186 return mVAlignSnapItem;
1189 void QgsComposerMouseHandles::deleteHAlignSnapItem()
1191 if ( mHAlignSnapItem )
1194 delete mHAlignSnapItem;
1195 mHAlignSnapItem =
nullptr;
1199 void QgsComposerMouseHandles::deleteVAlignSnapItem()
1201 if ( mVAlignSnapItem )
1204 delete mVAlignSnapItem;
1205 mVAlignSnapItem =
nullptr;
1209 void QgsComposerMouseHandles::deleteAlignItems()
1211 deleteHAlignSnapItem();
1212 deleteVAlignSnapItem();
1215 QPointF QgsComposerMouseHandles::alignItem(
double& alignX,
double& alignY,
double unalignedX,
double unalignedY )
1217 double left = unalignedX;
1219 double midH = ( left + right ) / 2.0;
1220 double top = unalignedY;
1222 double midV = ( top + bottom ) / 2.0;
1226 collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates );
1229 double xItemLeft = left;
1230 double xAlignCoord = 0;
1231 double smallestDiffX = DBL_MAX;
1233 checkNearestItem( left, xAlignCoordinates, smallestDiffX, 0, xItemLeft, xAlignCoord );
1234 checkNearestItem( midH, xAlignCoordinates, smallestDiffX, ( left - right ) / 2.0, xItemLeft, xAlignCoord );
1235 checkNearestItem( right, xAlignCoordinates, smallestDiffX, left - right, xItemLeft, xAlignCoord );
1238 double yItemTop = top;
1239 double yAlignCoord = 0;
1240 double smallestDiffY = DBL_MAX;
1242 checkNearestItem( top, yAlignCoordinates, smallestDiffY, 0, yItemTop, yAlignCoord );
1243 checkNearestItem( midV, yAlignCoordinates, smallestDiffY, ( top - bottom ) / 2.0, yItemTop, yAlignCoord );
1244 checkNearestItem( bottom, yAlignCoordinates, smallestDiffY, top - bottom, yItemTop, yAlignCoord );
1246 double xCoord = ( smallestDiffX < 5 ) ? xItemLeft : unalignedX;
1247 alignX = ( smallestDiffX < 5 ) ? xAlignCoord : -1;
1248 double yCoord = ( smallestDiffY < 5 ) ? yItemTop : unalignedY;
1249 alignY = ( smallestDiffY < 5 ) ? yAlignCoord : -1;
1250 return QPointF( xCoord, yCoord );
1253 QPointF QgsComposerMouseHandles::alignPos(
QPointF pos,
double& alignX,
double& alignY )
1257 collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates );
1259 double nearestX = pos.
x();
1260 double nearestY = pos.
y();
1261 if ( !nearestItem( xAlignCoordinates, pos.
x(), nearestX )
1262 || !nearestItem( yAlignCoordinates, pos.
y(), nearestY ) )
1270 double viewScaleFactor = graphicsView()->
transform().
m11();
1271 double alignThreshold = mComposition->
snapTolerance() / viewScaleFactor;
1274 if ( fabs( nearestX - pos.
x() ) < alignThreshold )
1276 result.
setX( nearestX );
1284 if ( fabs( nearestY - pos.
y() ) < alignThreshold )
1286 result.setY( nearestY );
1298 alignCoordsX.
clear();
1299 alignCoordsY.
clear();
1305 for ( ; itemIt != itemList.
end(); ++itemIt )
1316 if ( dynamic_cast<const QgsPaperItem *>( *itemIt ) )
1326 alignCoordsX.
insert( itemRect.
left(), currentItem );
1327 alignCoordsX.
insert( itemRect.
right(), currentItem );
1329 alignCoordsY.
insert( itemRect.
top(), currentItem );
1341 double x = ( *sIt )->line().x1();
1342 double y = ( *sIt )->line().y1();
1345 alignCoordsX.
insert( x,
nullptr );
1349 alignCoordsY.
insert( y,
nullptr );
1355 void QgsComposerMouseHandles::checkNearestItem(
double checkCoord,
const QMap< double, const QgsComposerItem* >& alignCoords,
double& smallestDiff,
double itemCoordOffset,
double& itemCoord,
double& alignCoord )
1357 double currentCoord = 0;
1358 if ( !nearestItem( alignCoords, checkCoord, currentCoord ) )
1363 double currentDiff = fabs( checkCoord - currentCoord );
1365 double viewScaleFactor = graphicsView()->
transform().
m11();
1366 double alignThreshold = mComposition->
snapTolerance() / viewScaleFactor;
1368 if ( currentDiff < alignThreshold && currentDiff < smallestDiff )
1370 itemCoord = currentCoord + itemCoordOffset;
1371 alignCoord = currentCoord;
1372 smallestDiff = currentDiff;
1378 if ( coords.
size() < 1 )
1386 nearestValue = it.
key();
1389 else if ( it == coords.
constEnd() )
1392 nearestValue = it.
key();
1398 double upperVal = it.
key();
1400 double lowerVal = it.
key();
1402 double lowerDiff = value - lowerVal;
1403 double upperDiff = upperVal - value;
1404 if ( lowerDiff < upperDiff )
1406 nearestValue = lowerVal;
1411 nearestValue = upperVal;
QgsComposerMouseHandles::MouseAction mouseActionForScenePos(QPointF sceneCoordPos)
Finds out which mouse move action to choose depending on the scene cursor position.
QRectF mapRectFromItem(const QGraphicsItem *item, const QRectF &rect) const
static void relativeResizeRect(QRectF &rectToResize, const QRectF &boundsBefore, const QRectF &boundsAfter)
Resizes a QRectF relative to a resized bounding rectangle.
QUndoStack * undoStack()
Returns pointer to undo/redo command storage.
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override
double paperWidth() const
Width of paper item.
void setStyle(Qt::PenStyle style)
bool boundingBoxesVisible() const
Returns whether selection bounding boxes should be shown in the composition.
void setCompositionMode(CompositionMode mode)
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
void selectedItemRotationChanged()
Redraws handles when selected item rotation changes.
QPointF snapPointToGrid(QPointF scenePoint) const
Snaps a scene coordinate point to grid.
virtual bool selected() const
Is selected.
QList< QGraphicsItem * > items() const
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
MouseAction
Describes the action (move or resize in different directon) to be done during mouse move...
void setAcceptHoverEvents(bool enabled)
const_iterator constBegin() const
bool smartGuidesEnabled() const
const T & at(int i) const
A item that forms part of a map composition.
bool preventCursorChange() const
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override
void savePreviousState()
Saves current item state as previous state.
void selectedItemSizeChanged()
Redraws handles when selected item size changes.
QRectF mapRectToScene(const QRectF &rect) const
virtual ~QgsComposerMouseHandles()
QGraphicsScene * scene() const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
double spaceBetweenPages() const
Returns the vertical space between pages in a composer view.
bool alignmentSnap() const
void setStatusMessage(const QString &message)
Sets the status bar message for the composer window.
QString tr(const char *sourceText, const char *disambiguation, int n)
int numPages() const
Returns the number of pages in the composition.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
void update(const QRectF &rect)
void setRect(const QRectF &rectangle)
void drawRect(const QRectF &rectangle)
virtual QRectF boundingRect() const
void addPolygon(const QPolygonF &polygon)
void removeItem(QGraphicsItem *item)
void setPen(const QColor &color)
void setPos(const QPointF &pos)
QList< QGraphicsView * > views() const
QRectF normalized() const
void setAngle(qreal angle)
const_iterator constEnd() const
void setLine(const QLineF &line)
QPointF mapFromScene(const QPointF &point) const
void translate(qreal dx, qreal dy)
void setBrush(const QBrush &brush)
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override
QRectF united(const QRectF &rectangle) const
iterator lowerBound(const Key &key)
void selectionChanged()
Sets up listeners to sizeChanged signal for all selected items.
Graphics scene for map printing.
void setPen(const QPen &pen)
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override
virtual QRectF rectWithFrame() const
Returns the item's rectangular bounds, including any bleed caused by the item's frame.
void saveAfterState()
Saves current item state as after state.
QPointF mapToScene(const QPointF &point) const
QgsComposition * composition()
QPointF mapFromItem(const QGraphicsItem *item, const QPointF &point) const
Undo command to undo/redo all composer item related changes.
void drawPath(const QPainterPath &path)
int snapTolerance() const
Returns the snap tolerance to use when automatically snapping items during movement and resizing to g...
static QgsProject * instance()
access to canonical QgsProject instance
double paperHeight() const
Height of paper item.
void setRotation(qreal angle)
iterator insert(const Key &key, const T &value)
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
const_iterator constEnd() const
const_iterator constBegin() const
QgsComposerMouseHandles(QgsComposition *composition)
void addItem(QGraphicsItem *item)
QgsComposition::PlotStyle plotStyle() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void mousePressEvent(QGraphicsSceneMouseEvent *event) override
bool isGroupMember() const
Returns whether this item is part of a group.
void push(QUndoCommand *cmd)
QPointF lastScenePos() const
QList< QgsComposerItem * > selectedComposerItems(const bool includeLockedItems=true)
Returns list of selected composer items.
QList< QGraphicsLineItem * > * snapLines()
Returns pointer to snap lines collection.