QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposerruler.cpp
Go to the documentation of this file.
1 #include "qgscomposerruler.h"
2 #include "qgscomposition.h"
3 #include "qgis.h"
4 #include <QDragEnterEvent>
5 #include <QGraphicsLineItem>
6 #include <QPainter>
7 #include <cmath>
8 
9 const int RULER_MIN_SIZE = 20;
10 
11 QgsComposerRuler::QgsComposerRuler( QgsComposerRuler::Direction d ): QWidget( 0 ), mDirection( d ), mComposition( 0 ), mLineSnapItem( 0 )
12 {
13  setMouseTracking( true );
14 }
15 
17 {
18 }
19 
21 {
22  return QSize( RULER_MIN_SIZE, RULER_MIN_SIZE );
23 }
24 
25 void QgsComposerRuler::paintEvent( QPaintEvent* event )
26 {
27  Q_UNUSED( event );
28  if ( !mComposition )
29  {
30  return;
31  }
32 
33  QPainter p( this );
34 
35  QTransform t = mTransform.inverted();
36 
37  //find optimal ruler display scale (steps of 1, 10 or 50)
38  double pixelDiff1 = mTransform.map( QPointF( 1, 0 ) ).x() - mTransform.map( QPointF( 0, 0 ) ).x();
39  double pixelDiff10 = mTransform.map( QPointF( 10, 0 ) ).x() - mTransform.map( QPointF( 0, 0 ) ).x();
40  //double pixelDiff50 = mTransform.map( QPointF( 50, 0 ) ).x() - mTransform.map( QPointF( 5, 0 ) ).x();
41 
42  double mmDisplay = 50.0;
43  if ( pixelDiff1 > 25 )
44  {
45  mmDisplay = 1.0;
46  }
47  else if ( pixelDiff10 > 25 )
48  {
49  mmDisplay = 10.0;
50  }
51 
52  if ( mDirection == Horizontal )
53  {
54  if ( qgsDoubleNear( width(), 0 ) )
55  {
56  return;
57  }
58 
59  //start x-coordinate
60  double startX = t.map( QPointF( 0, 0 ) ).x();
61  double endX = t.map( QPointF( width(), 0 ) ).x();
62 
63  double markerPos = ( floor( startX / mmDisplay ) + 1 ) * mmDisplay; //marker position in mm
64  while ( markerPos <= endX )
65  {
66  if ( markerPos >= 0 && markerPos <= mComposition->paperWidth() ) //todo: need to know paper size
67  {
68  double pixelCoord = mTransform.map( QPointF( markerPos, 0 ) ).x();
69  p.drawLine( pixelCoord, 0, pixelCoord, RULER_MIN_SIZE );
70  p.drawText( QPointF( pixelCoord + 2, RULER_MIN_SIZE / 2.0 ), QString::number(( int )( markerPos ) ) );
71  }
72  markerPos += mmDisplay;
73  }
74 
75  p.setPen( QColor( Qt::red ) );
76  p.drawLine( mMarkerPos.x(), 0, mMarkerPos.x(), RULER_MIN_SIZE );
77  }
78  else //vertical
79  {
80  if ( qgsDoubleNear( height(), 0 ) )
81  {
82  return;
83  }
84 
85  double startY = t.map( QPointF( 0, 0 ) ).y(); //start position in mm (total including space between pages)
86  double endY = t.map( QPointF( 0, height() ) ).y(); //stop position in mm (total including space between pages)
87  int startPage = ( int )( startY / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() ) );
88  if ( startPage < 0 )
89  {
90  startPage = 0;
91  }
92  int endPage = ( int )( endY / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() ) );
93  if ( endPage > ( mComposition->numPages() - 1 ) )
94  {
95  endPage = mComposition->numPages() - 1;
96  }
97 
98  for ( int i = startPage; i <= endPage; ++i )
99  {
100  double pageCoord = 0; //page coordinate in mm
101  //total (composition) coordinate in mm, including space between pages
102  double totalCoord = i * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
103  while ( pageCoord < mComposition->paperHeight() )
104  {
105  if ( totalCoord > endY )
106  {
107  break;
108  }
109  double pixelCoord = mTransform.map( QPointF( 0, totalCoord ) ).y();
110  p.drawLine( 0, pixelCoord, RULER_MIN_SIZE, pixelCoord );
111  p.drawText( QPointF( 0, pixelCoord - 2.0 ), QString::number( pageCoord ) );
112  pageCoord += mmDisplay;
113  totalCoord += mmDisplay;
114  }
115  }
116 
117  p.setPen( QColor( Qt::red ) );
118  p.drawLine( 0, mMarkerPos.y(), RULER_MIN_SIZE, mMarkerPos.y() );
119  }
120 }
121 
122 void QgsComposerRuler::setSceneTransform( const QTransform& transform )
123 {
124  QString debug = QString::number( transform.dx() ) + "," + QString::number( transform.dy() ) + ","
125  + QString::number( transform.m11() ) + "," + QString::number( transform.m22() );
126  mTransform = transform;
127  update();
128 }
129 
130 void QgsComposerRuler::mouseMoveEvent( QMouseEvent* event )
131 {
132  //qWarning( "QgsComposerRuler::mouseMoveEvent" );
133  updateMarker( event->posF() );
134  setSnapLinePosition( event->posF() );
135 }
136 
137 void QgsComposerRuler::mouseReleaseEvent( QMouseEvent* event )
138 {
139  Q_UNUSED( event );
140 
141  //remove snap line if coordinate under 0
142  QPointF pos = mTransform.inverted().map( event->pos() );
143  bool removeItem = false;
144  if ( mDirection == Horizontal )
145  {
146  removeItem = pos.x() < 0 ? true : false;
147  }
148  else
149  {
150  removeItem = pos.y() < 0 ? true : false;
151  }
152 
153  if ( removeItem )
154  {
156  mSnappedItems.clear();
157  }
158  mLineSnapItem = 0;
159 }
160 
161 void QgsComposerRuler::mousePressEvent( QMouseEvent* event )
162 {
163  double x = 0;
164  double y = 0;
165  if ( mDirection == Horizontal )
166  {
167  x = mTransform.inverted().map( event->pos() ).x();
168  }
169  else //vertical
170  {
171  y = mTransform.inverted().map( event->pos() ).y();
172  }
173 
174  //horizontal ruler means vertical snap line
175  QGraphicsLineItem* line = mComposition->nearestSnapLine( mDirection != Horizontal, x, y, 10.0, mSnappedItems );
176  if ( !line )
177  {
178  //create new snap line
180  }
181  else
182  {
183  mLineSnapItem = line;
184  }
185 }
186 
187 void QgsComposerRuler::setSnapLinePosition( const QPointF& pos )
188 {
189  if ( !mLineSnapItem || !mComposition )
190  {
191  return;
192  }
193 
194  QPointF transformedPt = mTransform.inverted().map( pos );
195  if ( mDirection == Horizontal )
196  {
197  int numPages = mComposition->numPages();
198  double lineHeight = numPages * mComposition->paperHeight();
199  if ( numPages > 1 )
200  {
201  lineHeight += ( numPages - 1 ) * mComposition->spaceBetweenPages();
202  }
203  mLineSnapItem->setLine( QLineF( transformedPt.x(), 0, transformedPt.x(), lineHeight ) );
204  }
205  else //vertical
206  {
207  mLineSnapItem->setLine( QLineF( 0, transformedPt.y(), mComposition->paperWidth(), transformedPt.y() ) );
208  }
209 
210  //move snapped items together with the snap line
211  QList< QPair< QgsComposerItem*, QgsComposerItem::ItemPositionMode > >::iterator itemIt = mSnappedItems.begin();
212  for ( ; itemIt != mSnappedItems.end(); ++itemIt )
213  {
214  if ( mDirection == Horizontal )
215  {
216  if ( itemIt->second == QgsComposerItem::MiddleLeft )
217  {
218  itemIt->first->setItemPosition( transformedPt.x(), itemIt->first->transform().dy(), QgsComposerItem::UpperLeft );
219  }
220  else if ( itemIt->second == QgsComposerItem::Middle )
221  {
222  itemIt->first->setItemPosition( transformedPt.x(), itemIt->first->transform().dy(), QgsComposerItem::UpperMiddle );
223  }
224  else
225  {
226  itemIt->first->setItemPosition( transformedPt.x(), itemIt->first->transform().dy(), QgsComposerItem::UpperRight );
227  }
228  }
229  else
230  {
231  if ( itemIt->second == QgsComposerItem::UpperMiddle )
232  {
233  itemIt->first->setItemPosition( itemIt->first->transform().dx(), transformedPt.y(), QgsComposerItem::UpperLeft );
234  }
235  else if ( itemIt->second == QgsComposerItem::Middle )
236  {
237  itemIt->first->setItemPosition( itemIt->first->transform().dx(), transformedPt.y(), QgsComposerItem::MiddleLeft );
238  }
239  else
240  {
241  itemIt->first->setItemPosition( itemIt->first->transform().dx(), transformedPt.y(), QgsComposerItem::LowerLeft );
242  }
243  }
244  }
245 }