QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposermousehandles.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposermousehandles.cpp
3  -------------------
4  begin : September 2013
5  copyright : (C) 2013 by Nyall Dawson, Radim Blazek
6  email : nyall.dawson@gmail.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include <QPainter>
18 #include <QWidget>
19 
20 #include <limits>
21 
23 #include "qgscomposeritem.h"
24 #include "qgscomposition.h"
25 #include "qgspaperitem.h"
26 #include "qgis.h"
27 #include "qgslogger.h"
28 
30  QGraphicsRectItem( 0 ),
31  mComposition( composition ),
32  mGraphicsView( 0 ),
33  mBeginHandleWidth( 0 ),
34  mBeginHandleHeight( 0 ),
35  mResizeMoveX( 0 ),
36  mResizeMoveY( 0 ),
37  mIsDragging( false ),
38  mIsResizing( false ),
39  mHAlignSnapItem( 0 ),
40  mVAlignSnapItem( 0 )
41 {
42  //listen for selection changes, and update handles accordingly
43  QObject::connect( mComposition, SIGNAL( selectionChanged() ), this, SLOT( selectionChanged() ) );
44 
45  //accept hover events, required for changing cursor to resize cursors
46  setAcceptsHoverEvents( true );
47 }
48 
50 {
51 
52 }
53 
55 {
56  //have we already found the current view?
57  if ( mGraphicsView )
58  {
59  return mGraphicsView;
60  }
61 
62  //otherwise, try and find current view attached to composition
63  if ( scene() )
64  {
65  QList<QGraphicsView*> viewList = scene()->views();
66  if ( viewList.size() > 0 )
67  {
68  mGraphicsView = viewList.at( 0 );
69  return mGraphicsView;
70  }
71  }
72 
73  //no view attached to composition
74  return 0;
75 }
76 
77 void QgsComposerMouseHandles::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
78 {
79  Q_UNUSED( itemStyle );
80  Q_UNUSED( pWidget );
81 
83  {
84  //don't draw selection handles in composition outputs
85  return;
86  }
87 
88  //draw resize handles around bounds of entire selection
89  double rectHandlerSize = rectHandlerBorderTolerance();
90  drawHandles( painter, rectHandlerSize );
91 
92  //draw dotted boxes around selected items
93  drawSelectedItemBounds( painter );
94 }
95 
96 void QgsComposerMouseHandles::drawHandles( QPainter* painter, double rectHandlerSize )
97 {
98  //blue, zero width cosmetic pen for outline
99  QPen handlePen = QPen( QColor( 55, 140, 195, 255 ) );
100  handlePen.setWidth( 0 );
101  painter->setPen( handlePen );
102 
103  //draw box around entire selection bounds
104  painter->setBrush( Qt::NoBrush );
105  painter->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
106 
107  //draw resize handles, using a filled white box
108  painter->setBrush( QColor( 255, 255, 255, 255 ) );
109  //top left
110  painter->drawRect( QRectF( 0, 0, rectHandlerSize, rectHandlerSize ) );
111  //mid top
112  painter->drawRect( QRectF(( rect().width() - rectHandlerSize ) / 2, 0, rectHandlerSize, rectHandlerSize ) );
113  //top right
114  painter->drawRect( QRectF( rect().width() - rectHandlerSize, 0, rectHandlerSize, rectHandlerSize ) );
115  //mid left
116  painter->drawRect( QRectF( 0, ( rect().height() - rectHandlerSize ) / 2, rectHandlerSize, rectHandlerSize ) );
117  //mid right
118  painter->drawRect( QRectF( rect().width() - rectHandlerSize, ( rect().height() - rectHandlerSize ) / 2, rectHandlerSize, rectHandlerSize ) );
119  //bottom left
120  painter->drawRect( QRectF( 0, rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
121  //mid bottom
122  painter->drawRect( QRectF(( rect().width() - rectHandlerSize ) / 2, rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
123  //bottom right
124  painter->drawRect( QRectF( rect().width() - rectHandlerSize, rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
125 }
126 
128 {
129  //draw dotted border around selected items to give visual feedback which items are selected
130  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
131  if ( selectedItems.size() == 0 )
132  {
133  return;
134  }
135 
136  //use difference mode so that they are visible regardless of item colors
137  painter->save();
138  painter->setCompositionMode( QPainter::CompositionMode_Difference );
139 
140  // use a grey dashed pen - in difference mode this should always be visible
141  QPen selectedItemPen = QPen( QColor( 144, 144, 144, 255 ) );
142  selectedItemPen.setStyle( Qt::DashLine );
143  selectedItemPen.setWidth( 0 );
144  painter->setPen( selectedItemPen );
145  painter->setBrush( Qt::NoBrush );
146 
147  QList<QgsComposerItem*>::iterator itemIter = selectedItems.begin();
148  for ( ; itemIter != selectedItems.end(); ++itemIter )
149  {
150  //get bounds of selected item
151  QPolygonF itemBounds;
152  if ( mIsDragging && !( *itemIter )->positionLock() )
153  {
154  //if currently dragging, draw selected item bounds relative to current mouse position
155  //first, get bounds of current item in scene coordinates
156  QPolygonF itemSceneBounds = ( *itemIter )->mapToScene(( *itemIter )->rectWithFrame() );
157  //now, translate it by the current movement amount
158  //IMPORTANT - this is done in scene coordinates, since we don't want any rotation/non-translation transforms to affect the movement
159  itemSceneBounds.translate( transform().dx(), transform().dy() );
160  //finally, remap it to the mouse handle item's coordinate system so it's ready for drawing
161  itemBounds = mapFromScene( itemSceneBounds );
162  }
163  else if ( mIsResizing && !( *itemIter )->positionLock() )
164  {
165  //if currently resizing, calculate relative resize of this item
166  if ( selectedItems.size() > 1 )
167  {
168  //get item bounds in mouse handle item's coordinate system
169  QRectF itemRect = mapRectFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() );
170  //now, resize it relative to the current resized dimensions of the mouse handles
172  itemBounds = QPolygonF( itemRect );
173  }
174  else
175  {
176  //single item selected
177  itemBounds = rect();
178  }
179  }
180  else
181  {
182  //not resizing or moving, so just map from scene bounds
183  itemBounds = mapRectFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() );
184  }
185  painter->drawPolygon( itemBounds );
186  }
187  painter->restore();
188 }
189 
191 {
192  //listen out for selected items' size and rotation changed signals
193  QList<QGraphicsItem *> itemList = composition()->items();
194  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
195  for ( ; itemIt != itemList.end(); ++itemIt )
196  {
197  QgsComposerItem* item = dynamic_cast<QgsComposerItem *>( *itemIt );
198  if ( item )
199  {
200  if ( item->selected() )
201  {
202  QObject::connect( item, SIGNAL( sizeChanged() ), this, SLOT( selectedItemSizeChanged() ) );
203  QObject::connect( item, SIGNAL( itemRotationChanged( double ) ), this, SLOT( selectedItemRotationChanged() ) );
204  QObject::connect( item, SIGNAL( frameChanged( ) ), this, SLOT( selectedItemSizeChanged() ) );
205  }
206  else
207  {
208  QObject::disconnect( item, SIGNAL( sizeChanged() ), this, 0 );
209  QObject::disconnect( item, SIGNAL( itemRotationChanged( double ) ), this, 0 );
210  QObject::disconnect( item, SIGNAL( frameChanged( ) ), this, 0 );
211  }
212  }
213  }
214 
215  resetStatusBar();
216  updateHandles();
217 }
218 
220 {
221  if ( !mIsDragging && !mIsResizing )
222  {
223  //only required for non-mouse initiated size changes
224  updateHandles();
225  }
226 }
227 
229 {
230  if ( !mIsDragging && !mIsResizing )
231  {
232  //only required for non-mouse initiated rotation changes
233  updateHandles();
234  }
235 }
236 
238 {
239  //recalculate size and position of handle item
240 
241  //first check to see if any items are selected
242  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
243  if ( selectedItems.size() > 0 )
244  {
245  //one or more items are selected, get bounds of all selected items
246 
247  //update rotation of handle object
248  double rotation;
249  if ( selectionRotation( rotation ) )
250  {
251  //all items share a common rotation value, so we rotate the mouse handles to match
252  setRotation( rotation );
253  }
254  else
255  {
256  //items have varying rotation values - we can't rotate the mouse handles to match
257  setRotation( 0 );
258  }
259 
260  //get bounds of all selected items
261  QRectF newHandleBounds = selectionBounds();
262 
263  //update size and position of handle object
264  setRect( 0, 0, newHandleBounds.width(), newHandleBounds.height() );
265  setPos( mapToScene( newHandleBounds.topLeft() ) );
266 
267  show();
268  }
269  else
270  {
271  //no items selected, hide handles
272  hide();
273  }
274  //force redraw
275  update();
276 }
277 
279 {
280  //calculate bounds of all currently selected items in mouse handle coordinate system
281  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
282  QList<QgsComposerItem*>::iterator itemIter = selectedItems.begin();
283 
284  //start with handle bounds of first selected item
285  QRectF bounds = mapFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() ).boundingRect();
286 
287  //iterate through remaining items, expanding the bounds as required
288  for ( ++itemIter; itemIter != selectedItems.end(); ++itemIter )
289  {
290  bounds = bounds.united( mapFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() ).boundingRect() );
291  }
292 
293  return bounds;
294 }
295 
296 bool QgsComposerMouseHandles::selectionRotation( double & rotation ) const
297 {
298  //check if all selected items have same rotation
299  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
300  QList<QgsComposerItem*>::iterator itemIter = selectedItems.begin();
301 
302  //start with rotation of first selected item
303  double firstItemRotation = ( *itemIter )->itemRotation();
304 
305  //iterate through remaining items, checking if they have same rotation
306  for ( ++itemIter; itemIter != selectedItems.end(); ++itemIter )
307  {
308  if (( *itemIter )->itemRotation() != firstItemRotation )
309  {
310  //item has a different rotation, so return false
311  return false;
312  }
313  }
314 
315  //all items have the same rotation, so set the rotation variable and return true
316  rotation = firstItemRotation;
317  return true;
318 }
319 
321 {
322  //calculate size for resize handles
323  //get view scale factor
324  double viewScaleFactor = graphicsView()->transform().m11();
325 
326  //size of handle boxes depends on zoom level in composer view
327  double rectHandlerSize = 10.0 / viewScaleFactor;
328 
329  //make sure the boxes don't get too large
330  if ( rectHandlerSize > ( rect().width() / 3 ) )
331  {
332  rectHandlerSize = rect().width() / 3;
333  }
334  if ( rectHandlerSize > ( rect().height() / 3 ) )
335  {
336  rectHandlerSize = rect().height() / 3;
337  }
338  return rectHandlerSize;
339 }
340 
341 Qt::CursorShape QgsComposerMouseHandles::cursorForPosition( const QPointF& itemCoordPos )
342 {
343  QgsComposerMouseHandles::MouseAction mouseAction = mouseActionForPosition( itemCoordPos );
344  switch ( mouseAction )
345  {
346  case NoAction:
347  return Qt::ForbiddenCursor;
348  case MoveItem:
349  return Qt::SizeAllCursor;
350  case ResizeUp:
351  case ResizeDown:
352  //account for rotation
353  if (( rotation() <= 22.5 || rotation() >= 337.5 ) || ( rotation() >= 157.5 && rotation() <= 202.5 ) )
354  {
355  return Qt::SizeVerCursor;
356  }
357  else if (( rotation() >= 22.5 && rotation() <= 67.5 ) || ( rotation() >= 202.5 && rotation() <= 247.5 ) )
358  {
359  return Qt::SizeBDiagCursor;
360  }
361  else if (( rotation() >= 67.5 && rotation() <= 112.5 ) || ( rotation() >= 247.5 && rotation() <= 292.5 ) )
362  {
363  return Qt::SizeHorCursor;
364  }
365  else
366  {
367  return Qt::SizeFDiagCursor;
368  }
369  case ResizeLeft:
370  case ResizeRight:
371  //account for rotation
372  if (( rotation() <= 22.5 || rotation() >= 337.5 ) || ( rotation() >= 157.5 && rotation() <= 202.5 ) )
373  {
374  return Qt::SizeHorCursor;
375  }
376  else if (( rotation() >= 22.5 && rotation() <= 67.5 ) || ( rotation() >= 202.5 && rotation() <= 247.5 ) )
377  {
378  return Qt::SizeFDiagCursor;
379  }
380  else if (( rotation() >= 67.5 && rotation() <= 112.5 ) || ( rotation() >= 247.5 && rotation() <= 292.5 ) )
381  {
382  return Qt::SizeVerCursor;
383  }
384  else
385  {
386  return Qt::SizeBDiagCursor;
387  }
388 
389  case ResizeLeftUp:
390  case ResizeRightDown:
391  //account for rotation
392  if (( rotation() <= 22.5 || rotation() >= 337.5 ) || ( rotation() >= 157.5 && rotation() <= 202.5 ) )
393  {
394  return Qt::SizeFDiagCursor;
395  }
396  else if (( rotation() >= 22.5 && rotation() <= 67.5 ) || ( rotation() >= 202.5 && rotation() <= 247.5 ) )
397  {
398  return Qt::SizeVerCursor;
399  }
400  else if (( rotation() >= 67.5 && rotation() <= 112.5 ) || ( rotation() >= 247.5 && rotation() <= 292.5 ) )
401  {
402  return Qt::SizeBDiagCursor;
403  }
404  else
405  {
406  return Qt::SizeHorCursor;
407  }
408  case ResizeRightUp:
409  case ResizeLeftDown:
410  //account for rotation
411  if (( rotation() <= 22.5 || rotation() >= 337.5 ) || ( rotation() >= 157.5 && rotation() <= 202.5 ) )
412  {
413  return Qt::SizeBDiagCursor;
414  }
415  else if (( rotation() >= 22.5 && rotation() <= 67.5 ) || ( rotation() >= 202.5 && rotation() <= 247.5 ) )
416  {
417  return Qt::SizeHorCursor;
418  }
419  else if (( rotation() >= 67.5 && rotation() <= 112.5 ) || ( rotation() >= 247.5 && rotation() <= 292.5 ) )
420  {
421  return Qt::SizeFDiagCursor;
422  }
423  else
424  {
425  return Qt::SizeVerCursor;
426  }
427  case SelectItem:
428  default:
429  return Qt::ArrowCursor;
430  }
431 }
432 
434 {
435  bool nearLeftBorder = false;
436  bool nearRightBorder = false;
437  bool nearLowerBorder = false;
438  bool nearUpperBorder = false;
439 
440  double borderTolerance = rectHandlerBorderTolerance();
441 
442  if ( itemCoordPos.x() >= 0 && itemCoordPos.x() < borderTolerance )
443  {
444  nearLeftBorder = true;
445  }
446  if ( itemCoordPos.y() >= 0 && itemCoordPos.y() < borderTolerance )
447  {
448  nearUpperBorder = true;
449  }
450  if ( itemCoordPos.x() <= rect().width() && itemCoordPos.x() > ( rect().width() - borderTolerance ) )
451  {
452  nearRightBorder = true;
453  }
454  if ( itemCoordPos.y() <= rect().height() && itemCoordPos.y() > ( rect().height() - borderTolerance ) )
455  {
456  nearLowerBorder = true;
457  }
458 
459  if ( nearLeftBorder && nearUpperBorder )
460  {
462  }
463  else if ( nearLeftBorder && nearLowerBorder )
464  {
466  }
467  else if ( nearRightBorder && nearUpperBorder )
468  {
470  }
471  else if ( nearRightBorder && nearLowerBorder )
472  {
474  }
475  else if ( nearLeftBorder )
476  {
478  }
479  else if ( nearRightBorder )
480  {
482  }
483  else if ( nearUpperBorder )
484  {
486  }
487  else if ( nearLowerBorder )
488  {
490  }
491 
492  //find out if cursor position is over a selected item
493  QPointF scenePoint = mapToScene( itemCoordPos );
494  QList<QGraphicsItem *> itemsAtCursorPos = mComposition->items( scenePoint );
495  if ( itemsAtCursorPos.size() == 0 )
496  {
497  //no items at cursor position
499  }
500  QList<QGraphicsItem*>::iterator itemIter = itemsAtCursorPos.begin();
501  for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
502  {
503  QgsComposerItem* item = dynamic_cast<QgsComposerItem *>(( *itemIter ) );
504  if ( item && item->selected() )
505  {
506  //cursor is over a selected composer item
508  }
509  }
510 
511  //default
513 }
514 
516 {
517  // convert sceneCoordPos to item coordinates
518  QPointF itemPos = mapFromScene( sceneCoordPos );
519  return mouseActionForPosition( itemPos );
520 }
521 
522 void QgsComposerMouseHandles::hoverMoveEvent( QGraphicsSceneHoverEvent * event )
523 {
524  setViewportCursor( cursorForPosition( event->pos() ) );
525 }
526 
527 void QgsComposerMouseHandles::hoverLeaveEvent( QGraphicsSceneHoverEvent * event )
528 {
529  Q_UNUSED( event );
530  setViewportCursor( Qt::ArrowCursor );
531 }
532 
533 void QgsComposerMouseHandles::setViewportCursor( Qt::CursorShape cursor )
534 {
535  //workaround qt bug #3732 by setting cursor for QGraphicsView viewport,
536  //rather then setting it directly here
537 
539  {
540  graphicsView()->viewport()->setCursor( cursor );
541  }
542 }
543 
544 void QgsComposerMouseHandles::mouseMoveEvent( QGraphicsSceneMouseEvent* event )
545 {
546  bool shiftModifier = false;
547  bool controlModifier = false;
548  if ( event->modifiers() & Qt::ShiftModifier )
549  {
550  //shift key depressed
551  shiftModifier = true;
552  }
553  if ( event->modifiers() & Qt::ControlModifier )
554  {
555  //shift key depressed
556  controlModifier = true;
557  }
558 
559  if ( mIsDragging )
560  {
561  //currently dragging a selection
562  dragMouseMove( event->lastScenePos(), shiftModifier, controlModifier );
563  }
564  else if ( mIsResizing )
565  {
566  //currently resizing a selection
567  resizeMouseMove( event->lastScenePos(), shiftModifier, controlModifier );
568  }
569 
570  mLastMouseEventPos = event->lastScenePos();
571 }
572 
573 void QgsComposerMouseHandles::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
574 {
575  QPointF mouseMoveStopPoint = event->lastScenePos();
576  double diffX = mouseMoveStopPoint.x() - mMouseMoveStartPos.x();
577  double diffY = mouseMoveStopPoint.y() - mMouseMoveStartPos.y();
578 
579  //it was only a click
580  if ( qAbs( diffX ) < std::numeric_limits<double>::min() && qAbs( diffY ) < std::numeric_limits<double>::min() )
581  {
582  mIsDragging = false;
583  mIsResizing = false;
584  return;
585  }
586 
588  {
589  //move selected items
590  QUndoCommand* parentCommand = new QUndoCommand( tr( "Change item position" ) );
591 
592  QPointF mEndHandleMovePos = scenePos();
593 
594  //move all selected items
595  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
596  QList<QgsComposerItem*>::iterator itemIter = selectedItems.begin();
597  for ( ; itemIter != selectedItems.end(); ++itemIter )
598  {
599  if (( *itemIter )->positionLock() || (( *itemIter )->flags() & QGraphicsItem::ItemIsSelectable ) == 0 )
600  {
601  //don't move locked items
602  continue;
603  }
604  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *itemIter, "", parentCommand );
605  subcommand->savePreviousState();
606  ( *itemIter )->move( mEndHandleMovePos.x() - mBeginHandlePos.x(), mEndHandleMovePos.y() - mBeginHandlePos.y() );
607  subcommand->saveAfterState();
608  }
609  mComposition->undoStack()->push( parentCommand );
610 
611  }
613  {
614  //resize selected items
615  QUndoCommand* parentCommand = new QUndoCommand( tr( "Change item size" ) );
616 
617  //resize all selected items
618  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
619  QList<QgsComposerItem*>::iterator itemIter = selectedItems.begin();
620  for ( ; itemIter != selectedItems.end(); ++itemIter )
621  {
622  if (( *itemIter )->positionLock() || (( *itemIter )->flags() & QGraphicsItem::ItemIsSelectable ) == 0 )
623  {
624  //don't resize locked items or unselectable items (eg, items which make up an item group)
625  continue;
626  }
627  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *itemIter, "", parentCommand );
628  subcommand->savePreviousState();
629 
630  QRectF itemRect;
631  if ( selectedItems.size() == 1 )
632  {
633  //only a single item is selected, so set its size to the final resized mouse handle size
634  itemRect = mResizeRect;
635  }
636  else
637  {
638  //multiple items selected, so each needs to be scaled relatively to the final size of the mouse handles
639  itemRect = mapRectFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() );
641  }
642 
643  itemRect = itemRect.normalized();
644  QPointF newPos = mapToScene( itemRect.topLeft() );
645  ( *itemIter )->setItemPosition( newPos.x(), newPos.y(), itemRect.width(), itemRect.height(), QgsComposerItem::UpperLeft, true );
646 
647  subcommand->saveAfterState();
648  }
649  mComposition->undoStack()->push( parentCommand );
650  }
651 
653 
654  if ( mIsDragging )
655  {
656  mIsDragging = false;
657  }
658  if ( mIsResizing )
659  {
660  mIsResizing = false;
661  }
662 
663  //reset default action
665  setViewportCursor( Qt::ArrowCursor );
666  //redraw handles
667  resetTransform();
668  updateHandles();
669  //reset status bar message
670  resetStatusBar();
671 }
672 
674 {
675  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
676  int selectedCount = selectedItems.size();
677  if ( selectedCount > 1 )
678  {
679  //set status bar message to count of selected items
680  mComposition->setStatusMessage( QString( tr( "%1 items selected" ) ).arg( selectedCount ) );
681  }
682  else if ( selectedCount == 1 )
683  {
684  //set status bar message to count of selected items
685  mComposition->setStatusMessage( tr( "1 item selected" ) );
686  }
687  else
688  {
689  //clear status bar message
690  mComposition->setStatusMessage( QString( "" ) );
691  }
692 }
693 
694 void QgsComposerMouseHandles::mousePressEvent( QGraphicsSceneMouseEvent* event )
695 {
696  //save current cursor position
697  mMouseMoveStartPos = event->lastScenePos();
698  mLastMouseEventPos = event->lastScenePos();
699  //save current item geometry
700  mBeginMouseEventPos = event->lastScenePos();
701  mBeginHandlePos = scenePos();
702  mBeginHandleWidth = rect().width();
703  mBeginHandleHeight = rect().height();
704  //type of mouse move action
706 
708 
710  {
711  //moving items
712  mIsDragging = true;
713  }
716  {
717  //resizing items
718  mIsResizing = true;
720  mResizeMoveX = 0;
721  mResizeMoveY = 0;
723 
724  }
725 
726 }
727 
728 QSizeF QgsComposerMouseHandles::calcCursorEdgeOffset( const QPointF &cursorPos )
729 {
730  //find offset between cursor position and actual edge of item
731  QPointF sceneMousePos = mapFromScene( cursorPos );
732 
733  switch ( mCurrentMouseMoveAction )
734  {
735  //vertical resize
737  return QSizeF( 0, sceneMousePos.y() );
738 
740  return QSizeF( 0, sceneMousePos.y() - rect().height() );
741 
742  //horizontal resize
744  return QSizeF( sceneMousePos.x(), 0 );
745 
747  return QSizeF( sceneMousePos.x() - rect().width(), 0 );
748 
749  //diagonal resize
751  return QSizeF( sceneMousePos.x(), sceneMousePos.y() );
752 
754  return QSizeF( sceneMousePos.x() - rect().width(), sceneMousePos.y() - rect().height() );
755 
757  return QSizeF( sceneMousePos.x() - rect().width(), sceneMousePos.y() );
758 
760  return QSizeF( sceneMousePos.x(), sceneMousePos.y() - rect().height() );
761 
762  default:
763  return QSizeF( 0, 0 );
764  }
765 
766 }
767 
768 void QgsComposerMouseHandles::dragMouseMove( const QPointF& currentPosition, bool lockMovement, bool preventSnap )
769 {
770  if ( !mComposition )
771  {
772  return;
773  }
774 
775  //calculate total amount of mouse movement since drag began
776  double moveX = currentPosition.x() - mBeginMouseEventPos.x();
777  double moveY = currentPosition.y() - mBeginMouseEventPos.y();
778 
779  //find target position before snapping (in scene coordinates)
780  QPointF upperLeftPoint( mBeginHandlePos.x() + moveX, mBeginHandlePos.y() + moveY );
781 
782  QPointF snappedLeftPoint;
783  //no snapping for rotated items for now
784  if ( !preventSnap && rotation() == 0 )
785  {
786  //snap to grid and guides
787  snappedLeftPoint = snapPoint( upperLeftPoint, QgsComposerMouseHandles::Item );
788  }
789  else
790  {
791  //no snapping
792  snappedLeftPoint = upperLeftPoint;
794  }
795 
796  //calculate total shift for item from beginning of drag operation to current position
797  double moveRectX = snappedLeftPoint.x() - mBeginHandlePos.x();
798  double moveRectY = snappedLeftPoint.y() - mBeginHandlePos.y();
799 
800  if ( lockMovement )
801  {
802  //constrained (shift) moving should lock to horizontal/vertical movement
803  //reset the smaller of the x/y movements
804  if ( abs( moveRectX ) <= abs( moveRectY ) )
805  {
806  moveRectX = 0;
807  }
808  else
809  {
810  moveRectY = 0;
811  }
812  }
813 
814  //shift handle item to new position
815  QTransform moveTransform;
816  moveTransform.translate( moveRectX, moveRectY );
817  setTransform( moveTransform );
818  //show current displacement of selection in status bar
819  mComposition->setStatusMessage( QString( tr( "dx: %1 mm dy: %2 mm" ) ).arg( moveRectX ).arg( moveRectY ) );
820 }
821 
822 void QgsComposerMouseHandles::resizeMouseMove( const QPointF& currentPosition, bool lockRatio, bool fromCenter )
823 {
824 
825  if ( !mComposition )
826  {
827  return;
828  }
829 
830  double mx = 0.0, my = 0.0, rx = 0.0, ry = 0.0;
831 
832  QPointF beginMousePos;
833  QPointF finalPosition;
834  if ( rotation() == 0 )
835  {
836  //snapping only occurs if handles are not rotated for now
837 
838  //subtract cursor edge offset from begin mouse event and current cursor position, so that snapping occurs to edge of mouse handles
839  //rather then cursor position
840  beginMousePos = mapFromScene( QPointF( mBeginMouseEventPos.x() - mCursorOffset.width(), mBeginMouseEventPos.y() - mCursorOffset.height() ) );
841  QPointF snappedPosition = snapPoint( QPointF( currentPosition.x() - mCursorOffset.width(), currentPosition.y() - mCursorOffset.height() ), QgsComposerMouseHandles::Point );
842  finalPosition = mapFromScene( snappedPosition );
843  }
844  else
845  {
846  //no snapping for rotated items for now
847  beginMousePos = mapFromScene( mBeginMouseEventPos );
848  finalPosition = mapFromScene( currentPosition );
849  }
850 
851  double diffX = finalPosition.x() - beginMousePos.x();
852  double diffY = finalPosition.y() - beginMousePos.y();
853 
854  double ratio = 0;
855  if ( lockRatio && mBeginHandleHeight != 0 )
856  {
858  }
859 
860  switch ( mCurrentMouseMoveAction )
861  {
862  //vertical resize
864  {
865  if ( ratio )
866  {
867  diffX = (( mBeginHandleHeight - diffY ) * ratio ) - mBeginHandleWidth;
868  mx = -diffX / 2; my = diffY; rx = diffX; ry = -diffY;
869  }
870  else
871  {
872  mx = 0; my = diffY; rx = 0; ry = -diffY;
873  }
874  break;
875  }
876 
878  {
879  if ( ratio )
880  {
881  diffX = (( mBeginHandleHeight + diffY ) * ratio ) - mBeginHandleWidth;
882  mx = -diffX / 2; my = 0; rx = diffX; ry = diffY;
883  }
884  else
885  {
886  mx = 0; my = 0; rx = 0; ry = diffY;
887  }
888  break;
889  }
890 
891  //horizontal resize
893  {
894  if ( ratio )
895  {
896  diffY = (( mBeginHandleWidth - diffX ) / ratio ) - mBeginHandleHeight;
897  mx = diffX; my = -diffY / 2; rx = -diffX; ry = diffY;
898  }
899  else
900  {
901  mx = diffX, my = 0; rx = -diffX; ry = 0;
902  }
903  break;
904  }
905 
907  {
908  if ( ratio )
909  {
910  diffY = (( mBeginHandleWidth + diffX ) / ratio ) - mBeginHandleHeight;
911  mx = 0; my = -diffY / 2; rx = diffX; ry = diffY;
912  }
913  else
914  {
915  mx = 0; my = 0; rx = diffX, ry = 0;
916  }
917  break;
918  }
919 
920  //diagonal resize
922  {
923  if ( ratio )
924  {
925  //ratio locked resize
926  if (( mBeginHandleWidth - diffX ) / ( mBeginHandleHeight - diffY ) > ratio )
927  {
928  diffX = mBeginHandleWidth - (( mBeginHandleHeight - diffY ) * ratio );
929  }
930  else
931  {
932  diffY = mBeginHandleHeight - (( mBeginHandleWidth - diffX ) / ratio );
933  }
934  }
935  mx = diffX, my = diffY; rx = -diffX; ry = -diffY;
936  break;
937  }
938 
940  {
941  if ( ratio )
942  {
943  //ratio locked resize
944  if (( mBeginHandleWidth + diffX ) / ( mBeginHandleHeight + diffY ) > ratio )
945  {
946  diffX = (( mBeginHandleHeight + diffY ) * ratio ) - mBeginHandleWidth;
947  }
948  else
949  {
950  diffY = (( mBeginHandleWidth + diffX ) / ratio ) - mBeginHandleHeight;
951  }
952  }
953  mx = 0; my = 0; rx = diffX, ry = diffY;
954  break;
955  }
956 
958  {
959  if ( ratio )
960  {
961  //ratio locked resize
962  if (( mBeginHandleWidth + diffX ) / ( mBeginHandleHeight - diffY ) > ratio )
963  {
964  diffX = (( mBeginHandleHeight - diffY ) * ratio ) - mBeginHandleWidth;
965  }
966  else
967  {
968  diffY = mBeginHandleHeight - (( mBeginHandleWidth + diffX ) / ratio );
969  }
970  }
971  mx = 0; my = diffY, rx = diffX, ry = -diffY;
972  break;
973  }
974 
976  {
977  if ( ratio )
978  {
979  //ratio locked resize
980  if (( mBeginHandleWidth - diffX ) / ( mBeginHandleHeight + diffY ) > ratio )
981  {
982  diffX = mBeginHandleWidth - (( mBeginHandleHeight + diffY ) * ratio );
983  }
984  else
985  {
986  diffY = (( mBeginHandleWidth - diffX ) / ratio ) - mBeginHandleHeight;
987  }
988  }
989  mx = diffX, my = 0; rx = -diffX; ry = diffY;
990  break;
991  }
992 
996  break;
997  }
998 
999  //resizing from center of objects?
1000  if ( fromCenter )
1001  {
1002  my = -ry;
1003  mx = -rx;
1004  ry = 2 * ry;
1005  rx = 2 * rx;
1006  }
1007 
1008  //update selection handle rectangle
1009 
1010  //make sure selection handle size rectangle is normalized (ie, left coord < right coord)
1011  mResizeMoveX = mBeginHandleWidth + rx > 0 ? mx : mx + mBeginHandleWidth + rx;
1012  mResizeMoveY = mBeginHandleHeight + ry > 0 ? my : my + mBeginHandleHeight + ry;
1013 
1014  //calculate movement in scene coordinates
1015  QLineF translateLine = QLineF( 0, 0, mResizeMoveX, mResizeMoveY );
1016  translateLine.setAngle( translateLine.angle() - rotation() );
1017  QPointF sceneTranslate = translateLine.p2();
1018 
1019  //move selection handles
1020  QTransform itemTransform;
1021  itemTransform.translate( sceneTranslate.x(), sceneTranslate.y() );
1022  setTransform( itemTransform );
1023 
1024  //handle non-normalised resizes - eg, dragging the left handle so far to the right that it's past the right handle
1025  if ( mBeginHandleWidth + rx >= 0 && mBeginHandleHeight + ry >= 0 )
1026  {
1027  mResizeRect = QRectF( 0, 0, mBeginHandleWidth + rx, mBeginHandleHeight + ry );
1028  }
1029  else if ( mBeginHandleHeight + ry >= 0 )
1030  {
1031  mResizeRect = QRectF( QPointF( -( mBeginHandleWidth + rx ), 0 ), QPointF( 0, mBeginHandleHeight + ry ) );
1032  }
1033  else if ( mBeginHandleWidth + rx >= 0 )
1034  {
1035  mResizeRect = QRectF( QPointF( 0, -( mBeginHandleHeight + ry ) ), QPointF( mBeginHandleWidth + rx, 0 ) );
1036  }
1037  else
1038  {
1039  mResizeRect = QRectF( QPointF( -( mBeginHandleWidth + rx ), -( mBeginHandleHeight + ry ) ), QPointF( 0, 0 ) );
1040  }
1041 
1042  setRect( 0, 0, fabs( mBeginHandleWidth + rx ), fabs( mBeginHandleHeight + ry ) );
1043 
1044  //show current size of selection in status bar
1045  mComposition->setStatusMessage( QString( tr( "width: %1 mm height: %2 mm" ) ).arg( rect().width() ).arg( rect().height() ) );
1046 }
1047 
1049 {
1050  //snap to grid
1051  QPointF snappedPoint = mComposition->snapPointToGrid( point );
1052 
1053  if ( snappedPoint != point ) //don't do align snap if grid snap has been done
1054  {
1055  deleteAlignItems();
1056  return snappedPoint;
1057  }
1058 
1059  //align item
1061  {
1062  return point;
1063  }
1064 
1065  double alignX = 0;
1066  double alignY = 0;
1067 
1068  //depending on the mode, we either snap just the single point, or all the bounds of the selection
1069  switch ( mode )
1070  {
1072  snappedPoint = alignItem( alignX, alignY, point.x(), point.y() );
1073  break;
1075  snappedPoint = alignPos( point, alignX, alignY );
1076  break;
1077  }
1078 
1079  if ( alignX != -1 )
1080  {
1081  QGraphicsLineItem* item = hAlignSnapItem();
1082  int numPages = mComposition->numPages();
1083  double yLineCoord = 300; //default in case there is no single page
1084  if ( numPages > 0 )
1085  {
1086  yLineCoord = mComposition->paperHeight() * numPages + mComposition->spaceBetweenPages() * ( numPages - 1 );
1087  }
1088  item->setLine( QLineF( alignX, 0, alignX, yLineCoord ) );
1089  item->show();
1090  }
1091  else
1092  {
1094  }
1095  if ( alignY != -1 )
1096  {
1097  QGraphicsLineItem* item = vAlignSnapItem();
1098  item->setLine( QLineF( 0, alignY, mComposition->paperWidth(), alignY ) );
1099  item->show();
1100  }
1101  else
1102  {
1104  }
1105  return snappedPoint;
1106 }
1107 
1109 {
1110  if ( !mHAlignSnapItem )
1111  {
1112  mHAlignSnapItem = new QGraphicsLineItem( 0 );
1113  mHAlignSnapItem->setPen( QPen( QColor( Qt::red ) ) );
1114  scene()->addItem( mHAlignSnapItem );
1115  mHAlignSnapItem->setZValue( 90 );
1116  }
1117  return mHAlignSnapItem;
1118 }
1119 
1121 {
1122  if ( !mVAlignSnapItem )
1123  {
1124  mVAlignSnapItem = new QGraphicsLineItem( 0 );
1125  mVAlignSnapItem->setPen( QPen( QColor( Qt::red ) ) );
1126  scene()->addItem( mVAlignSnapItem );
1127  mVAlignSnapItem->setZValue( 90 );
1128  }
1129  return mVAlignSnapItem;
1130 }
1131 
1133 {
1134  if ( mHAlignSnapItem )
1135  {
1136  scene()->removeItem( mHAlignSnapItem );
1137  delete mHAlignSnapItem;
1138  mHAlignSnapItem = 0;
1139  }
1140 }
1141 
1143 {
1144  if ( mVAlignSnapItem )
1145  {
1146  scene()->removeItem( mVAlignSnapItem );
1147  delete mVAlignSnapItem;
1148  mVAlignSnapItem = 0;
1149  }
1150 }
1151 
1153 {
1156 }
1157 
1158 QPointF QgsComposerMouseHandles::alignItem( double& alignX, double& alignY, double unalignedX, double unalignedY )
1159 {
1160  double left = unalignedX;
1161  double right = left + rect().width();
1162  double midH = ( left + right ) / 2.0;
1163  double top = unalignedY;
1164  double bottom = top + rect().height();
1165  double midV = ( top + bottom ) / 2.0;
1166 
1167  QMap<double, const QgsComposerItem* > xAlignCoordinates;
1168  QMap<double, const QgsComposerItem* > yAlignCoordinates;
1169  collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates );
1170 
1171  //find nearest matches x
1172  double xItemLeft = left; //new left coordinate of the item
1173  double xAlignCoord = 0;
1174  double smallestDiffX = DBL_MAX;
1175 
1176  checkNearestItem( left, xAlignCoordinates, smallestDiffX, 0, xItemLeft, xAlignCoord );
1177  checkNearestItem( midH, xAlignCoordinates, smallestDiffX, ( left - right ) / 2.0, xItemLeft, xAlignCoord );
1178  checkNearestItem( right, xAlignCoordinates, smallestDiffX, left - right, xItemLeft, xAlignCoord );
1179 
1180  //find nearest matches y
1181  double yItemTop = top; //new top coordinate of the item
1182  double yAlignCoord = 0;
1183  double smallestDiffY = DBL_MAX;
1184 
1185  checkNearestItem( top, yAlignCoordinates, smallestDiffY, 0, yItemTop, yAlignCoord );
1186  checkNearestItem( midV, yAlignCoordinates, smallestDiffY, ( top - bottom ) / 2.0, yItemTop, yAlignCoord );
1187  checkNearestItem( bottom, yAlignCoordinates, smallestDiffY, top - bottom, yItemTop, yAlignCoord );
1188 
1189  double xCoord = ( smallestDiffX < 5 ) ? xItemLeft : unalignedX;
1190  alignX = ( smallestDiffX < 5 ) ? xAlignCoord : -1;
1191  double yCoord = ( smallestDiffY < 5 ) ? yItemTop : unalignedY;
1192  alignY = ( smallestDiffY < 5 ) ? yAlignCoord : -1;
1193  return QPointF( xCoord, yCoord );
1194 }
1195 
1196 QPointF QgsComposerMouseHandles::alignPos( const QPointF& pos, double& alignX, double& alignY )
1197 {
1198  QMap<double, const QgsComposerItem* > xAlignCoordinates;
1199  QMap<double, const QgsComposerItem* > yAlignCoordinates;
1200  collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates );
1201 
1202  double nearestX = pos.x();
1203  double nearestY = pos.y();
1204  if ( !nearestItem( xAlignCoordinates, pos.x(), nearestX )
1205  || !nearestItem( yAlignCoordinates, pos.y(), nearestY ) )
1206  {
1207  alignX = -1;
1208  alignY = -1;
1209  return pos;
1210  }
1211 
1212  QPointF result( pos.x(), pos.y() );
1213  if ( abs( nearestX - pos.x() ) < mComposition->alignmentSnapTolerance() )
1214  {
1215  result.setX( nearestX );
1216  alignX = nearestX;
1217  }
1218  else
1219  {
1220  alignX = -1;
1221  }
1222 
1223  if ( abs( nearestY - pos.y() ) < mComposition->alignmentSnapTolerance() )
1224  {
1225  result.setY( nearestY );
1226  alignY = nearestY;
1227  }
1228  else
1229  {
1230  alignY = -1;
1231  }
1232  return result;
1233 }
1234 
1235 void QgsComposerMouseHandles::collectAlignCoordinates( QMap< double, const QgsComposerItem* >& alignCoordsX, QMap< double, const QgsComposerItem* >& alignCoordsY )
1236 {
1237  alignCoordsX.clear();
1238  alignCoordsY.clear();
1239 
1241  {
1242  QList<QGraphicsItem *> itemList = mComposition->items();
1243  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1244  for ( ; itemIt != itemList.end(); ++itemIt )
1245  {
1246  const QgsComposerItem* currentItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
1247  //don't snap to selected items, since they're the ones that will be snapping to something else
1248  if ( !currentItem || currentItem->selected() )
1249  {
1250  continue;
1251  }
1252  QRectF itemRect;
1253  if ( dynamic_cast<const QgsPaperItem *>( *itemIt ) )
1254  {
1255  //if snapping to paper use the paper item's rect rather then the bounding rect,
1256  //since we want to snap to the page edge and not any outlines drawn around the page
1257  itemRect = currentItem->rect();
1258  }
1259  else
1260  {
1261  itemRect = currentItem->mapRectToScene( currentItem->rectWithFrame() );
1262  }
1263  alignCoordsX.insert( itemRect.left(), currentItem );
1264  alignCoordsX.insert( itemRect.right(), currentItem );
1265  alignCoordsX.insert( itemRect.center().x(), currentItem );
1266  alignCoordsY.insert( itemRect.top(), currentItem );
1267  alignCoordsY.insert( itemRect.center().y(), currentItem );
1268  alignCoordsY.insert( itemRect.bottom(), currentItem );
1269  }
1270  }
1271 
1272  //arbitrary snap lines
1273  if ( mComposition->alignmentSnap() )
1274  {
1275  QList< QGraphicsLineItem* >::const_iterator sIt = mComposition->snapLines()->constBegin();
1276  for ( ; sIt != mComposition->snapLines()->constEnd(); ++sIt )
1277  {
1278  double x = ( *sIt )->line().x1();
1279  double y = ( *sIt )->line().y1();
1280  if ( qgsDoubleNear( y, 0.0 ) )
1281  {
1282  alignCoordsX.insert( x, 0 );
1283  }
1284  else
1285  {
1286  alignCoordsY.insert( y, 0 );
1287  }
1288  }
1289  }
1290 }
1291 
1292 void QgsComposerMouseHandles::checkNearestItem( double checkCoord, const QMap< double, const QgsComposerItem* >& alignCoords, double& smallestDiff, double itemCoordOffset, double& itemCoord, double& alignCoord ) const
1293 {
1294  double currentCoord = 0;
1295  if ( !nearestItem( alignCoords, checkCoord, currentCoord ) )
1296  {
1297  return;
1298  }
1299 
1300  double currentDiff = abs( checkCoord - currentCoord );
1301  if ( currentDiff < mComposition->alignmentSnapTolerance() )
1302  {
1303  itemCoord = currentCoord + itemCoordOffset;
1304  alignCoord = currentCoord;
1305  smallestDiff = currentDiff;
1306  }
1307 }
1308 
1309 bool QgsComposerMouseHandles::nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value, double& nearestValue ) const
1310 {
1311  if ( coords.size() < 1 )
1312  {
1313  return false;
1314  }
1315 
1316  QMap< double, const QgsComposerItem* >::const_iterator it = coords.lowerBound( value );
1317  if ( it == coords.constBegin() ) //value smaller than first map value
1318  {
1319  nearestValue = it.key();
1320  return true;
1321  }
1322  else if ( it == coords.constEnd() ) //value larger than last map value
1323  {
1324  --it;
1325  nearestValue = it.key();
1326  return true;
1327  }
1328  else
1329  {
1330  //get smaller value and larger value and return the closer one
1331  double upperVal = it.key();
1332  --it;
1333  double lowerVal = it.key();
1334 
1335  double lowerDiff = value - lowerVal;
1336  double upperDiff = upperVal - value;
1337  if ( lowerDiff < upperDiff )
1338  {
1339  nearestValue = lowerVal;
1340  return true;
1341  }
1342  else
1343  {
1344  nearestValue = upperVal;
1345  return true;
1346  }
1347  }
1348 }
QGraphicsLineItem * hAlignSnapItem()
Return horizontal align snap item.
QUndoStack * undoStack()
Returns pointer to undo/redo command storage.
double alignmentSnapTolerance() const
double paperWidth() const
Returns width of paper item.
bool mIsDragging
True if user is currently dragging items.
void drawHandles(QPainter *painter, double rectHandlerSize)
Draws the handles.
QPointF mLastMouseEventPos
Position of the last mouse move event (in scene coordinates)
QPointF alignPos(const QPointF &pos, double &alignX, double &alignY)
Snaps a point to to the grid or align rulers.
void updateHandles()
Redraws or hides the handles based on the current selection.
Qt::CursorShape cursorForPosition(const QPointF &itemCoordPos)
Finds out the appropriate cursor for the current mouse position in the widget (e.g.
void selectedItemRotationChanged()
Redraws handles when selected item rotation changes.
virtual bool selected() const
Is selected.
bool smartGuidesEnabled() const
A item that forms part of a map composition.
bool preventCursorChange()
QGraphicsLineItem * mVAlignSnapItem
QPointF snapPointToGrid(const QPointF &scenePoint) const
Snaps a scene coordinate point to grid.
void savePreviousState()
Saves current item state as previous state.
MouseAction
Describes the action (move or resize in different directon) to be done during mouse move...
double mBeginHandleWidth
Width and height of composer handles at beginning of resize.
void selectedItemSizeChanged()
Redraws handles when selected item size changes.
double spaceBetweenPages() const
bool alignmentSnap() const
void setStatusMessage(const QString &message)
Sets the status bar message for the composer window.
int numPages() const
Note: added in version 1.9.
QPointF mMouseMoveStartPos
Start point of the last mouse move action (in scene coordinates)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:305
void setViewportCursor(Qt::CursorShape cursor)
double rectHandlerBorderTolerance()
Returns the current (zoom level dependent) tolerance to decide if mouse position is close enough to t...
void mousePressEvent(QGraphicsSceneMouseEvent *event)
QgsComposerMouseHandles::MouseAction mouseActionForPosition(const QPointF &itemCoordPos)
Finds out which mouse move action to choose depending on the cursor position inside the widget...
QRectF selectionBounds() const
Returns the mouse handle bounds of current selection.
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
void resizeMouseMove(const QPointF &currentPosition, bool lockAspect, bool fromCenter)
Handles resizing of items during mouse move.
bool nearestItem(const QMap< double, const QgsComposerItem * > &coords, double value, double &nearestValue) const
void drawSelectedItemBounds(QPainter *painter)
Draw outlines for selected items.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
void selectionChanged()
Sets up listeners to sizeChanged signal for all selected items.
Graphics scene for map printing.
void collectAlignCoordinates(QMap< double, const QgsComposerItem * > &alignCoordsX, QMap< double, const QgsComposerItem * > &alignCoordsY)
QGraphicsLineItem * vAlignSnapItem()
Return vertical align snap item.
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.
void hoverMoveEvent(QGraphicsSceneHoverEvent *event)
QGraphicsLineItem * mHAlignSnapItem
Align snap lines.
QPointF snapPoint(const QPointF &originalPoint, QgsComposerMouseHandles::SnapGuideMode mode)
Snaps an item or point (depending on mode) originating at originalPoint to the grid or align rulers...
Undo command to undo/redo all composer item related changes.
QPointF mBeginMouseEventPos
Position of the mouse at beginning of move/resize (in scene coordinates)
QgsComposerMouseHandles::MouseAction mCurrentMouseMoveAction
void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void dragMouseMove(const QPointF &currentPosition, bool lockMovement, bool preventSnap)
Handles dragging of items during mouse move.
QPointF mBeginHandlePos
Position of composer handles at beginning of move/resize (in scene coordinates)
double paperHeight() const
Returns height of paper item.
QSizeF calcCursorEdgeOffset(const QPointF &cursorPos)
Calculates the distance of the mouse cursor from thed edge of the mouse handles.
static void relativeResizeRect(QRectF &rectToResize, const QRectF &boundsBefore, const QRectF &boundsAfter)
Resizes a QRectF relative to the change from boundsBefore to boundsAfter.
double ANALYSIS_EXPORT min(double x, double y)
returns the minimum of two doubles or the first argument if both are equal
QgsComposerMouseHandles(QgsComposition *composition)
QgsComposition::PlotStyle plotStyle() const
QList< QgsComposerItem * > selectedComposerItems()
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
QgsComposerMouseHandles::MouseAction mouseActionForScenePos(const QPointF &sceneCoordPos)
Finds out which mouse move action to choose depending on the scene cursor position.
QPointF alignItem(double &alignX, double &alignY, double unalignedX, double unalignedY)
Snaps an item originating at unalignedX, unalignedY to the grid or align rulers.
bool selectionRotation(double &rotation) const
Returns true if all selected items have same rotation, and if so, updates passed rotation variable...
void checkNearestItem(double checkCoord, const QMap< double, const QgsComposerItem * > &alignCoords, double &smallestDiff, double itemCoordOffset, double &itemCoord, double &alignCoord) const
bool mIsResizing
True is user is currently resizing items.
#define tr(sourceText)
QList< QGraphicsLineItem * > * snapLines()
Returns pointer to snap lines collection.