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