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