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