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  bool shiftModifier = false;
562  bool controlModifier = false;
563  if ( event->modifiers() & Qt::ShiftModifier )
564  {
565  //shift key depressed
566  shiftModifier = true;
567  }
568  if ( event->modifiers() & Qt::ControlModifier )
569  {
570  //shift key depressed
571  controlModifier = true;
572  }
573 
574  if ( mIsDragging )
575  {
576  //currently dragging a selection
577  dragMouseMove( event->lastScenePos(), shiftModifier, controlModifier );
578  }
579  else if ( mIsResizing )
580  {
581  //currently resizing a selection
582  resizeMouseMove( event->lastScenePos(), shiftModifier, controlModifier );
583  }
584 
585  mLastMouseEventPos = event->lastScenePos();
586 }
587 
588 void QgsComposerMouseHandles::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
589 {
590  QPointF mouseMoveStopPoint = event->lastScenePos();
591  double diffX = mouseMoveStopPoint.x() - mMouseMoveStartPos.x();
592  double diffY = mouseMoveStopPoint.y() - mMouseMoveStartPos.y();
593 
594  //it was only a click
595  if ( qAbs( diffX ) < std::numeric_limits<double>::min() && qAbs( diffY ) < std::numeric_limits<double>::min() )
596  {
597  mIsDragging = false;
598  mIsResizing = false;
599  return;
600  }
601 
603  {
604  //move selected items
605  QUndoCommand* parentCommand = new QUndoCommand( tr( "Change item position" ) );
606 
607  QPointF mEndHandleMovePos = scenePos();
608 
609  //move all selected items
610  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
611  QList<QgsComposerItem*>::iterator itemIter = selectedItems.begin();
612  for ( ; itemIter != selectedItems.end(); ++itemIter )
613  {
614  if (( *itemIter )->positionLock() || (( *itemIter )->flags() & QGraphicsItem::ItemIsSelectable ) == 0 )
615  {
616  //don't move locked items
617  continue;
618  }
619  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *itemIter, "", parentCommand );
620  subcommand->savePreviousState();
621  ( *itemIter )->move( mEndHandleMovePos.x() - mBeginHandlePos.x(), mEndHandleMovePos.y() - mBeginHandlePos.y() );
622  subcommand->saveAfterState();
623  }
624  mComposition->undoStack()->push( parentCommand );
625  QgsProject::instance()->dirty( true );
626  }
628  {
629  //resize selected items
630  QUndoCommand* parentCommand = new QUndoCommand( tr( "Change item size" ) );
631 
632  //resize all selected items
633  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
634  QList<QgsComposerItem*>::iterator itemIter = selectedItems.begin();
635  for ( ; itemIter != selectedItems.end(); ++itemIter )
636  {
637  if (( *itemIter )->positionLock() || (( *itemIter )->flags() & QGraphicsItem::ItemIsSelectable ) == 0 )
638  {
639  //don't resize locked items or unselectable items (eg, items which make up an item group)
640  continue;
641  }
642  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *itemIter, "", parentCommand );
643  subcommand->savePreviousState();
644 
645  QRectF itemRect;
646  if ( selectedItems.size() == 1 )
647  {
648  //only a single item is selected, so set its size to the final resized mouse handle size
649  itemRect = mResizeRect;
650  }
651  else
652  {
653  //multiple items selected, so each needs to be scaled relatively to the final size of the mouse handles
654  itemRect = mapRectFromItem(( *itemIter ), ( *itemIter )->rectWithFrame() );
656  }
657 
658  itemRect = itemRect.normalized();
659  QPointF newPos = mapToScene( itemRect.topLeft() );
660  ( *itemIter )->setItemPosition( newPos.x(), newPos.y(), itemRect.width(), itemRect.height(), QgsComposerItem::UpperLeft, true );
661 
662  subcommand->saveAfterState();
663  }
664  mComposition->undoStack()->push( parentCommand );
665  QgsProject::instance()->dirty( true );
666  }
667 
669 
670  if ( mIsDragging )
671  {
672  mIsDragging = false;
673  }
674  if ( mIsResizing )
675  {
676  mIsResizing = false;
677  }
678 
679  //reset default action
681  setViewportCursor( Qt::ArrowCursor );
682  //redraw handles
683  resetTransform();
684  updateHandles();
685  //reset status bar message
686  resetStatusBar();
687 }
688 
690 {
691  QList<QgsComposerItem*> selectedItems = mComposition->selectedComposerItems();
692  int selectedCount = selectedItems.size();
693  if ( selectedCount > 1 )
694  {
695  //set status bar message to count of selected items
696  mComposition->setStatusMessage( QString( tr( "%1 items selected" ) ).arg( selectedCount ) );
697  }
698  else if ( selectedCount == 1 )
699  {
700  //set status bar message to count of selected items
701  mComposition->setStatusMessage( tr( "1 item selected" ) );
702  }
703  else
704  {
705  //clear status bar message
706  mComposition->setStatusMessage( QString( "" ) );
707  }
708 }
709 
710 void QgsComposerMouseHandles::mousePressEvent( QGraphicsSceneMouseEvent* event )
711 {
712  //save current cursor position
713  mMouseMoveStartPos = event->lastScenePos();
714  mLastMouseEventPos = event->lastScenePos();
715  //save current item geometry
716  mBeginMouseEventPos = event->lastScenePos();
717  mBeginHandlePos = scenePos();
718  mBeginHandleWidth = rect().width();
719  mBeginHandleHeight = rect().height();
720  //type of mouse move action
722 
724 
726  {
727  //moving items
728  mIsDragging = true;
729  }
732  {
733  //resizing items
734  mIsResizing = true;
736  mResizeMoveX = 0;
737  mResizeMoveY = 0;
739 
740  }
741 
742 }
743 
744 void QgsComposerMouseHandles::mouseDoubleClickEvent( QGraphicsSceneMouseEvent *event )
745 {
746  Q_UNUSED( event );
747 }
748 
749 QSizeF QgsComposerMouseHandles::calcCursorEdgeOffset( const QPointF &cursorPos )
750 {
751  //find offset between cursor position and actual edge of item
752  QPointF sceneMousePos = mapFromScene( cursorPos );
753 
754  switch ( mCurrentMouseMoveAction )
755  {
756  //vertical resize
758  return QSizeF( 0, sceneMousePos.y() );
759 
761  return QSizeF( 0, sceneMousePos.y() - rect().height() );
762 
763  //horizontal resize
765  return QSizeF( sceneMousePos.x(), 0 );
766 
768  return QSizeF( sceneMousePos.x() - rect().width(), 0 );
769 
770  //diagonal resize
772  return QSizeF( sceneMousePos.x(), sceneMousePos.y() );
773 
775  return QSizeF( sceneMousePos.x() - rect().width(), sceneMousePos.y() - rect().height() );
776 
778  return QSizeF( sceneMousePos.x() - rect().width(), sceneMousePos.y() );
779 
781  return QSizeF( sceneMousePos.x(), sceneMousePos.y() - rect().height() );
782 
783  default:
784  return QSizeF( 0, 0 );
785  }
786 
787 }
788 
789 void QgsComposerMouseHandles::dragMouseMove( const QPointF& currentPosition, bool lockMovement, bool preventSnap )
790 {
791  if ( !mComposition )
792  {
793  return;
794  }
795 
796  //calculate total amount of mouse movement since drag began
797  double moveX = currentPosition.x() - mBeginMouseEventPos.x();
798  double moveY = currentPosition.y() - mBeginMouseEventPos.y();
799 
800  //find target position before snapping (in scene coordinates)
801  QPointF upperLeftPoint( mBeginHandlePos.x() + moveX, mBeginHandlePos.y() + moveY );
802 
803  QPointF snappedLeftPoint;
804  //no snapping for rotated items for now
805  if ( !preventSnap && rotation() == 0 )
806  {
807  //snap to grid and guides
808  snappedLeftPoint = snapPoint( upperLeftPoint, QgsComposerMouseHandles::Item );
809  }
810  else
811  {
812  //no snapping
813  snappedLeftPoint = upperLeftPoint;
815  }
816 
817  //calculate total shift for item from beginning of drag operation to current position
818  double moveRectX = snappedLeftPoint.x() - mBeginHandlePos.x();
819  double moveRectY = snappedLeftPoint.y() - mBeginHandlePos.y();
820 
821  if ( lockMovement )
822  {
823  //constrained (shift) moving should lock to horizontal/vertical movement
824  //reset the smaller of the x/y movements
825  if ( abs( moveRectX ) <= abs( moveRectY ) )
826  {
827  moveRectX = 0;
828  }
829  else
830  {
831  moveRectY = 0;
832  }
833  }
834 
835  //shift handle item to new position
836  QTransform moveTransform;
837  moveTransform.translate( moveRectX, moveRectY );
838  setTransform( moveTransform );
839  //show current displacement of selection in status bar
840  mComposition->setStatusMessage( QString( tr( "dx: %1 mm dy: %2 mm" ) ).arg( moveRectX ).arg( moveRectY ) );
841 }
842 
843 void QgsComposerMouseHandles::resizeMouseMove( const QPointF& currentPosition, bool lockRatio, bool fromCenter )
844 {
845 
846  if ( !mComposition )
847  {
848  return;
849  }
850 
851  double mx = 0.0, my = 0.0, rx = 0.0, ry = 0.0;
852 
853  QPointF beginMousePos;
854  QPointF finalPosition;
855  if ( rotation() == 0 )
856  {
857  //snapping only occurs if handles are not rotated for now
858 
859  //subtract cursor edge offset from begin mouse event and current cursor position, so that snapping occurs to edge of mouse handles
860  //rather then cursor position
861  beginMousePos = mapFromScene( QPointF( mBeginMouseEventPos.x() - mCursorOffset.width(), mBeginMouseEventPos.y() - mCursorOffset.height() ) );
862  QPointF snappedPosition = snapPoint( QPointF( currentPosition.x() - mCursorOffset.width(), currentPosition.y() - mCursorOffset.height() ), QgsComposerMouseHandles::Point );
863  finalPosition = mapFromScene( snappedPosition );
864  }
865  else
866  {
867  //no snapping for rotated items for now
868  beginMousePos = mapFromScene( mBeginMouseEventPos );
869  finalPosition = mapFromScene( currentPosition );
870  }
871 
872  double diffX = finalPosition.x() - beginMousePos.x();
873  double diffY = finalPosition.y() - beginMousePos.y();
874 
875  double ratio = 0;
876  if ( lockRatio && mBeginHandleHeight != 0 )
877  {
879  }
880 
881  switch ( mCurrentMouseMoveAction )
882  {
883  //vertical resize
885  {
886  if ( ratio )
887  {
888  diffX = (( mBeginHandleHeight - diffY ) * ratio ) - mBeginHandleWidth;
889  mx = -diffX / 2; my = diffY; rx = diffX; ry = -diffY;
890  }
891  else
892  {
893  mx = 0; my = diffY; rx = 0; ry = -diffY;
894  }
895  break;
896  }
897 
899  {
900  if ( ratio )
901  {
902  diffX = (( mBeginHandleHeight + diffY ) * ratio ) - mBeginHandleWidth;
903  mx = -diffX / 2; my = 0; rx = diffX; ry = diffY;
904  }
905  else
906  {
907  mx = 0; my = 0; rx = 0; ry = diffY;
908  }
909  break;
910  }
911 
912  //horizontal resize
914  {
915  if ( ratio )
916  {
917  diffY = (( mBeginHandleWidth - diffX ) / ratio ) - mBeginHandleHeight;
918  mx = diffX; my = -diffY / 2; rx = -diffX; ry = diffY;
919  }
920  else
921  {
922  mx = diffX, my = 0; rx = -diffX; ry = 0;
923  }
924  break;
925  }
926 
928  {
929  if ( ratio )
930  {
931  diffY = (( mBeginHandleWidth + diffX ) / ratio ) - mBeginHandleHeight;
932  mx = 0; my = -diffY / 2; rx = diffX; ry = diffY;
933  }
934  else
935  {
936  mx = 0; my = 0; rx = diffX, ry = 0;
937  }
938  break;
939  }
940 
941  //diagonal resize
943  {
944  if ( ratio )
945  {
946  //ratio locked resize
947  if (( mBeginHandleWidth - diffX ) / ( mBeginHandleHeight - diffY ) > ratio )
948  {
949  diffX = mBeginHandleWidth - (( mBeginHandleHeight - diffY ) * ratio );
950  }
951  else
952  {
953  diffY = mBeginHandleHeight - (( mBeginHandleWidth - diffX ) / ratio );
954  }
955  }
956  mx = diffX, my = diffY; rx = -diffX; ry = -diffY;
957  break;
958  }
959 
961  {
962  if ( ratio )
963  {
964  //ratio locked resize
965  if (( mBeginHandleWidth + diffX ) / ( mBeginHandleHeight + diffY ) > ratio )
966  {
967  diffX = (( mBeginHandleHeight + diffY ) * ratio ) - mBeginHandleWidth;
968  }
969  else
970  {
971  diffY = (( mBeginHandleWidth + diffX ) / ratio ) - mBeginHandleHeight;
972  }
973  }
974  mx = 0; my = 0; rx = diffX, ry = diffY;
975  break;
976  }
977 
979  {
980  if ( ratio )
981  {
982  //ratio locked resize
983  if (( mBeginHandleWidth + diffX ) / ( mBeginHandleHeight - diffY ) > ratio )
984  {
985  diffX = (( mBeginHandleHeight - diffY ) * ratio ) - mBeginHandleWidth;
986  }
987  else
988  {
989  diffY = mBeginHandleHeight - (( mBeginHandleWidth + diffX ) / ratio );
990  }
991  }
992  mx = 0; my = diffY, rx = diffX, ry = -diffY;
993  break;
994  }
995 
997  {
998  if ( ratio )
999  {
1000  //ratio locked resize
1001  if (( mBeginHandleWidth - diffX ) / ( mBeginHandleHeight + diffY ) > ratio )
1002  {
1003  diffX = mBeginHandleWidth - (( mBeginHandleHeight + diffY ) * ratio );
1004  }
1005  else
1006  {
1007  diffY = (( mBeginHandleWidth - diffX ) / ratio ) - mBeginHandleHeight;
1008  }
1009  }
1010  mx = diffX, my = 0; rx = -diffX; ry = diffY;
1011  break;
1012  }
1013 
1017  break;
1018  }
1019 
1020  //resizing from center of objects?
1021  if ( fromCenter )
1022  {
1023  my = -ry;
1024  mx = -rx;
1025  ry = 2 * ry;
1026  rx = 2 * rx;
1027  }
1028 
1029  //update selection handle rectangle
1030 
1031  //make sure selection handle size rectangle is normalized (ie, left coord < right coord)
1032  mResizeMoveX = mBeginHandleWidth + rx > 0 ? mx : mx + mBeginHandleWidth + rx;
1033  mResizeMoveY = mBeginHandleHeight + ry > 0 ? my : my + mBeginHandleHeight + ry;
1034 
1035  //calculate movement in scene coordinates
1036  QLineF translateLine = QLineF( 0, 0, mResizeMoveX, mResizeMoveY );
1037  translateLine.setAngle( translateLine.angle() - rotation() );
1038  QPointF sceneTranslate = translateLine.p2();
1039 
1040  //move selection handles
1041  QTransform itemTransform;
1042  itemTransform.translate( sceneTranslate.x(), sceneTranslate.y() );
1043  setTransform( itemTransform );
1044 
1045  //handle non-normalised resizes - eg, dragging the left handle so far to the right that it's past the right handle
1046  if ( mBeginHandleWidth + rx >= 0 && mBeginHandleHeight + ry >= 0 )
1047  {
1048  mResizeRect = QRectF( 0, 0, mBeginHandleWidth + rx, mBeginHandleHeight + ry );
1049  }
1050  else if ( mBeginHandleHeight + ry >= 0 )
1051  {
1052  mResizeRect = QRectF( QPointF( -( mBeginHandleWidth + rx ), 0 ), QPointF( 0, mBeginHandleHeight + ry ) );
1053  }
1054  else if ( mBeginHandleWidth + rx >= 0 )
1055  {
1056  mResizeRect = QRectF( QPointF( 0, -( mBeginHandleHeight + ry ) ), QPointF( mBeginHandleWidth + rx, 0 ) );
1057  }
1058  else
1059  {
1060  mResizeRect = QRectF( QPointF( -( mBeginHandleWidth + rx ), -( mBeginHandleHeight + ry ) ), QPointF( 0, 0 ) );
1061  }
1062 
1063  setRect( 0, 0, fabs( mBeginHandleWidth + rx ), fabs( mBeginHandleHeight + ry ) );
1064 
1065  //show current size of selection in status bar
1066  mComposition->setStatusMessage( QString( tr( "width: %1 mm height: %2 mm" ) ).arg( rect().width() ).arg( rect().height() ) );
1067 }
1068 
1070 {
1071  //snap to grid
1072  QPointF snappedPoint = mComposition->snapPointToGrid( point );
1073 
1074  if ( snappedPoint != point ) //don't do align snap if grid snap has been done
1075  {
1076  deleteAlignItems();
1077  return snappedPoint;
1078  }
1079 
1080  //align item
1082  {
1083  return point;
1084  }
1085 
1086  double alignX = 0;
1087  double alignY = 0;
1088 
1089  //depending on the mode, we either snap just the single point, or all the bounds of the selection
1090  switch ( mode )
1091  {
1093  snappedPoint = alignItem( alignX, alignY, point.x(), point.y() );
1094  break;
1096  snappedPoint = alignPos( point, alignX, alignY );
1097  break;
1098  }
1099 
1100  if ( alignX != -1 )
1101  {
1102  QGraphicsLineItem* item = hAlignSnapItem();
1103  int numPages = mComposition->numPages();
1104  double yLineCoord = 300; //default in case there is no single page
1105  if ( numPages > 0 )
1106  {
1107  yLineCoord = mComposition->paperHeight() * numPages + mComposition->spaceBetweenPages() * ( numPages - 1 );
1108  }
1109  item->setLine( QLineF( alignX, 0, alignX, yLineCoord ) );
1110  item->show();
1111  }
1112  else
1113  {
1115  }
1116  if ( alignY != -1 )
1117  {
1118  QGraphicsLineItem* item = vAlignSnapItem();
1119  item->setLine( QLineF( 0, alignY, mComposition->paperWidth(), alignY ) );
1120  item->show();
1121  }
1122  else
1123  {
1125  }
1126  return snappedPoint;
1127 }
1128 
1130 {
1131  if ( !mHAlignSnapItem )
1132  {
1133  mHAlignSnapItem = new QGraphicsLineItem( 0 );
1134  mHAlignSnapItem->setPen( QPen( QColor( Qt::red ) ) );
1135  scene()->addItem( mHAlignSnapItem );
1136  mHAlignSnapItem->setZValue( 90 );
1137  }
1138  return mHAlignSnapItem;
1139 }
1140 
1142 {
1143  if ( !mVAlignSnapItem )
1144  {
1145  mVAlignSnapItem = new QGraphicsLineItem( 0 );
1146  mVAlignSnapItem->setPen( QPen( QColor( Qt::red ) ) );
1147  scene()->addItem( mVAlignSnapItem );
1148  mVAlignSnapItem->setZValue( 90 );
1149  }
1150  return mVAlignSnapItem;
1151 }
1152 
1154 {
1155  if ( mHAlignSnapItem )
1156  {
1157  scene()->removeItem( mHAlignSnapItem );
1158  delete mHAlignSnapItem;
1159  mHAlignSnapItem = 0;
1160  }
1161 }
1162 
1164 {
1165  if ( mVAlignSnapItem )
1166  {
1167  scene()->removeItem( mVAlignSnapItem );
1168  delete mVAlignSnapItem;
1169  mVAlignSnapItem = 0;
1170  }
1171 }
1172 
1174 {
1177 }
1178 
1179 QPointF QgsComposerMouseHandles::alignItem( double& alignX, double& alignY, double unalignedX, double unalignedY )
1180 {
1181  double left = unalignedX;
1182  double right = left + rect().width();
1183  double midH = ( left + right ) / 2.0;
1184  double top = unalignedY;
1185  double bottom = top + rect().height();
1186  double midV = ( top + bottom ) / 2.0;
1187 
1188  QMap<double, const QgsComposerItem* > xAlignCoordinates;
1189  QMap<double, const QgsComposerItem* > yAlignCoordinates;
1190  collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates );
1191 
1192  //find nearest matches x
1193  double xItemLeft = left; //new left coordinate of the item
1194  double xAlignCoord = 0;
1195  double smallestDiffX = DBL_MAX;
1196 
1197  checkNearestItem( left, xAlignCoordinates, smallestDiffX, 0, xItemLeft, xAlignCoord );
1198  checkNearestItem( midH, xAlignCoordinates, smallestDiffX, ( left - right ) / 2.0, xItemLeft, xAlignCoord );
1199  checkNearestItem( right, xAlignCoordinates, smallestDiffX, left - right, xItemLeft, xAlignCoord );
1200 
1201  //find nearest matches y
1202  double yItemTop = top; //new top coordinate of the item
1203  double yAlignCoord = 0;
1204  double smallestDiffY = DBL_MAX;
1205 
1206  checkNearestItem( top, yAlignCoordinates, smallestDiffY, 0, yItemTop, yAlignCoord );
1207  checkNearestItem( midV, yAlignCoordinates, smallestDiffY, ( top - bottom ) / 2.0, yItemTop, yAlignCoord );
1208  checkNearestItem( bottom, yAlignCoordinates, smallestDiffY, top - bottom, yItemTop, yAlignCoord );
1209 
1210  double xCoord = ( smallestDiffX < 5 ) ? xItemLeft : unalignedX;
1211  alignX = ( smallestDiffX < 5 ) ? xAlignCoord : -1;
1212  double yCoord = ( smallestDiffY < 5 ) ? yItemTop : unalignedY;
1213  alignY = ( smallestDiffY < 5 ) ? yAlignCoord : -1;
1214  return QPointF( xCoord, yCoord );
1215 }
1216 
1217 QPointF QgsComposerMouseHandles::alignPos( const QPointF& pos, double& alignX, double& alignY )
1218 {
1219  QMap<double, const QgsComposerItem* > xAlignCoordinates;
1220  QMap<double, const QgsComposerItem* > yAlignCoordinates;
1221  collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates );
1222 
1223  double nearestX = pos.x();
1224  double nearestY = pos.y();
1225  if ( !nearestItem( xAlignCoordinates, pos.x(), nearestX )
1226  || !nearestItem( yAlignCoordinates, pos.y(), nearestY ) )
1227  {
1228  alignX = -1;
1229  alignY = -1;
1230  return pos;
1231  }
1232 
1233  //convert snap tolerance from pixels to mm
1234  double viewScaleFactor = graphicsView()->transform().m11();
1235  double alignThreshold = mComposition->snapTolerance() / viewScaleFactor;
1236 
1237  QPointF result( pos.x(), pos.y() );
1238  if ( fabs( nearestX - pos.x() ) < alignThreshold )
1239  {
1240  result.setX( nearestX );
1241  alignX = nearestX;
1242  }
1243  else
1244  {
1245  alignX = -1;
1246  }
1247 
1248  if ( fabs( nearestY - pos.y() ) < alignThreshold )
1249  {
1250  result.setY( nearestY );
1251  alignY = nearestY;
1252  }
1253  else
1254  {
1255  alignY = -1;
1256  }
1257  return result;
1258 }
1259 
1260 void QgsComposerMouseHandles::collectAlignCoordinates( QMap< double, const QgsComposerItem* >& alignCoordsX, QMap< double, const QgsComposerItem* >& alignCoordsY )
1261 {
1262  alignCoordsX.clear();
1263  alignCoordsY.clear();
1264 
1266  {
1267  QList<QGraphicsItem *> itemList = mComposition->items();
1268  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1269  for ( ; itemIt != itemList.end(); ++itemIt )
1270  {
1271  const QgsComposerItem* currentItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
1272  //don't snap to selected items, since they're the ones that will be snapping to something else
1273  //also ignore group members - only snap to bounds of group itself
1274  if ( !currentItem || currentItem->selected() || currentItem->isGroupMember() )
1275  {
1276  continue;
1277  }
1278  QRectF itemRect;
1279  if ( dynamic_cast<const QgsPaperItem *>( *itemIt ) )
1280  {
1281  //if snapping to paper use the paper item's rect rather then the bounding rect,
1282  //since we want to snap to the page edge and not any outlines drawn around the page
1283  itemRect = currentItem->rect();
1284  }
1285  else
1286  {
1287  itemRect = currentItem->mapRectToScene( currentItem->rectWithFrame() );
1288  }
1289  alignCoordsX.insert( itemRect.left(), currentItem );
1290  alignCoordsX.insert( itemRect.right(), currentItem );
1291  alignCoordsX.insert( itemRect.center().x(), currentItem );
1292  alignCoordsY.insert( itemRect.top(), currentItem );
1293  alignCoordsY.insert( itemRect.center().y(), currentItem );
1294  alignCoordsY.insert( itemRect.bottom(), currentItem );
1295  }
1296  }
1297 
1298  //arbitrary snap lines
1299  if ( mComposition->alignmentSnap() )
1300  {
1301  QList< QGraphicsLineItem* >::const_iterator sIt = mComposition->snapLines()->constBegin();
1302  for ( ; sIt != mComposition->snapLines()->constEnd(); ++sIt )
1303  {
1304  double x = ( *sIt )->line().x1();
1305  double y = ( *sIt )->line().y1();
1306  if ( qgsDoubleNear( y, 0.0 ) )
1307  {
1308  alignCoordsX.insert( x, 0 );
1309  }
1310  else
1311  {
1312  alignCoordsY.insert( y, 0 );
1313  }
1314  }
1315  }
1316 }
1317 
1318 void QgsComposerMouseHandles::checkNearestItem( double checkCoord, const QMap< double, const QgsComposerItem* >& alignCoords, double& smallestDiff, double itemCoordOffset, double& itemCoord, double& alignCoord )
1319 {
1320  double currentCoord = 0;
1321  if ( !nearestItem( alignCoords, checkCoord, currentCoord ) )
1322  {
1323  return;
1324  }
1325 
1326  double currentDiff = fabs( checkCoord - currentCoord );
1327  //convert snap tolerance from pixels to mm
1328  double viewScaleFactor = graphicsView()->transform().m11();
1329  double alignThreshold = mComposition->snapTolerance() / viewScaleFactor;
1330 
1331  if ( currentDiff < alignThreshold && currentDiff < smallestDiff )
1332  {
1333  itemCoord = currentCoord + itemCoordOffset;
1334  alignCoord = currentCoord;
1335  smallestDiff = currentDiff;
1336  }
1337 }
1338 
1339 bool QgsComposerMouseHandles::nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value, double& nearestValue ) const
1340 {
1341  if ( coords.size() < 1 )
1342  {
1343  return false;
1344  }
1345 
1346  QMap< double, const QgsComposerItem* >::const_iterator it = coords.lowerBound( value );
1347  if ( it == coords.constBegin() ) //value smaller than first map value
1348  {
1349  nearestValue = it.key();
1350  return true;
1351  }
1352  else if ( it == coords.constEnd() ) //value larger than last map value
1353  {
1354  --it;
1355  nearestValue = it.key();
1356  return true;
1357  }
1358  else
1359  {
1360  //get smaller value and larger value and return the closer one
1361  double upperVal = it.key();
1362  --it;
1363  double lowerVal = it.key();
1364 
1365  double lowerDiff = value - lowerVal;
1366  double upperDiff = upperVal - value;
1367  if ( lowerDiff < upperDiff )
1368  {
1369  nearestValue = lowerVal;
1370  return true;
1371  }
1372  else
1373  {
1374  nearestValue = upperVal;
1375  return true;
1376  }
1377  }
1378 }
1379 
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.