18 #include <QDragEnterEvent> 19 #include <QGraphicsLineItem> 26 const int QgsComposerRuler::validScaleMultiples[] = {1, 2, 5};
27 const int QgsComposerRuler::validScaleMagnitudes[] = {1, 10, 100, 1000, 10000};
32 , mComposition( nullptr )
33 , mLineSnapItem( nullptr )
34 , mScaleMinPixelsWidth( 0 )
39 mRulerFont =
new QFont();
46 mScaleMinPixelsWidth = mRulerFontMetrics->
width(
"000" ) * 2.5;
48 mRulerMinSize = mRulerFontMetrics->
height() * 1.5;
50 mMinPixelsPerDivision = mRulerMinSize / 4;
52 if ( mMinPixelsPerDivision < 2 )
53 mMinPixelsPerDivision = 2;
55 mPixelsBetweenLineAndText = mRulerMinSize / 10;
56 mTextBaseline = mRulerMinSize / 1.667;
57 mMinSpacingVerticalLabels = mRulerMinSize / 5;
62 delete mRulerFontMetrics;
68 return QSize( mRulerMinSize, mRulerMinSize );
89 mmDisplay = optimumScale( mScaleMinPixelsWidth, magnitude, multiple );
92 int numSmallDivisions = optimumNumberDivisions( mmDisplay, multiple );
106 double markerPos = ( floor( startX / mmDisplay ) + 1 ) * mmDisplay;
109 drawSmallDivisions( &p, markerPos, numSmallDivisions, -mmDisplay );
111 while ( markerPos <= endX )
113 double pixelCoord = mTransform.
map(
QPointF( markerPos, 0 ) ).
x();
116 p.
drawLine( pixelCoord, 0, pixelCoord, mRulerMinSize );
120 drawSmallDivisions( &p, markerPos, numSmallDivisions, mmDisplay, endX );
122 markerPos += mmDisplay;
142 double beforePageCoord = -mmDisplay;
143 double firstPageY = mTransform.
map(
QPointF( 0, 0 ) ).
y();
146 while ( beforePageCoord > startY )
148 double pixelCoord = mTransform.
map(
QPointF( 0, beforePageCoord ) ).
y();
149 p.
drawLine( 0, pixelCoord, mRulerMinSize, pixelCoord );
152 int labelSize = mRulerFontMetrics->
width( label );
155 if ( pixelCoord + labelSize + 8 < firstPageY )
157 drawRotatedText( &p,
QPointF( mTextBaseline, pixelCoord + mMinSpacingVerticalLabels + labelSize ), label );
161 drawSmallDivisions( &p, beforePageCoord, numSmallDivisions, mmDisplay );
163 beforePageCoord -= mmDisplay;
167 drawSmallDivisions( &p, beforePageCoord + mmDisplay, numSmallDivisions, -mmDisplay, startY );
171 if ( endPage > ( mComposition->
numPages() - 1 ) )
173 endPage = mComposition->
numPages() - 1;
176 double nextPageStartPos = 0;
177 int nextPageStartPixel = 0;
179 for (
int i = startPage; i <= endPage; ++i )
181 double pageCoord = 0;
190 nextPageStartPixel = mTransform.
map(
QPointF( 0, nextPageStartPos ) ).
y();
195 nextPageStartPos = 0;
196 nextPageStartPixel = 0;
199 while (( totalCoord < nextPageStartPos ) || (( nextPageStartPos == 0 ) && ( totalCoord <= endY ) ) )
201 double pixelCoord = mTransform.
map(
QPointF( 0, totalCoord ) ).
y();
202 p.
drawLine( 0, pixelCoord, mRulerMinSize, pixelCoord );
205 int labelSize = mRulerFontMetrics->
width( label );
208 if (( pixelCoord + labelSize + 8 < nextPageStartPixel )
209 || ( nextPageStartPixel == 0 ) )
211 drawRotatedText( &p,
QPointF( mTextBaseline, pixelCoord + mMinSpacingVerticalLabels + labelSize ), label );
215 drawSmallDivisions( &p, totalCoord, numSmallDivisions, mmDisplay, nextPageStartPos );
217 pageCoord += mmDisplay;
218 totalCoord += mmDisplay;
227 void QgsComposerRuler::drawMarkerPos(
QPainter *painter )
233 painter->
drawLine( mMarkerPos.
x(), 0, mMarkerPos.
x(), mRulerMinSize );
237 painter->
drawLine( 0, mMarkerPos.
y(), mRulerMinSize, mMarkerPos.
y() );
250 void QgsComposerRuler::drawSmallDivisions(
QPainter *painter,
double startPos,
int numDivisions,
double rulerScale,
double maxPos )
252 if ( numDivisions == 0 )
256 double smallMarkerPos = startPos;
257 double smallDivisionSpacing = rulerScale / numDivisions;
262 for (
int i = 0; i < numDivisions; ++i )
264 smallMarkerPos += smallDivisionSpacing;
266 if ( maxPos > 0 && smallMarkerPos > maxPos )
275 pixelCoord = mTransform.
map(
QPointF( smallMarkerPos, 0 ) ).
x();
279 pixelCoord = mTransform.
map(
QPointF( 0, smallMarkerPos ) ).
y();
284 if (( numDivisions == 10 && i == 4 ) || ( numDivisions == 4 && i == 1 ) )
287 lineSize = mRulerMinSize / 1.5;
291 lineSize = mRulerMinSize / 1.25;
297 painter->
drawLine( pixelCoord, lineSize, pixelCoord, mRulerMinSize );
301 painter->
drawLine( lineSize, pixelCoord, mRulerMinSize, pixelCoord );
306 int QgsComposerRuler::optimumScale(
double minPixelDiff,
int &magnitude,
int &multiple )
311 for (
unsigned int magnitudeCandidate = 0; magnitudeCandidate <
COUNT_VALID_MAGNITUDES; ++magnitudeCandidate )
313 for (
unsigned int multipleCandidate = 0; multipleCandidate <
COUNT_VALID_MULTIPLES; ++multipleCandidate )
315 int candidateScale = validScaleMultiples[multipleCandidate] * validScaleMagnitudes[magnitudeCandidate];
317 double pixelDiff = mTransform.
map(
QPointF( candidateScale, 0 ) ).
x() - mTransform.
map(
QPointF( 0, 0 ) ).
x();
318 if ( pixelDiff > minPixelDiff )
321 magnitude = validScaleMagnitudes[magnitudeCandidate];
322 multiple = validScaleMultiples[multipleCandidate];
323 return candidateScale;
331 int QgsComposerRuler::optimumNumberDivisions(
double rulerScale,
int scaleMultiple )
334 double largeDivisionSize = mTransform.
map(
QPointF( rulerScale, 0 ) ).
x() - mTransform.
map(
QPointF( 0, 0 ) ).
x();
338 switch ( scaleMultiple )
343 validSmallDivisions << 10 << 5 << 2;
348 validSmallDivisions << 10 << 4 << 2;
353 validSmallDivisions << 10 << 5;
359 for ( divisions_it = validSmallDivisions.
begin(); divisions_it != validSmallDivisions.
end(); ++divisions_it )
362 double candidateSize = largeDivisionSize / ( *divisions_it );
364 if ( candidateSize >= mMinPixelsPerDivision )
367 return ( *divisions_it );
382 mTransform = transform;
390 setSnapLinePosition( event->
posF() );
397 displayPos.
setY( 0 );
402 displayPos.setX( 0 );
413 bool removeItem =
false;
416 removeItem = pos.
x() < 0 ? true :
false;
420 removeItem = pos.
y() < 0 ? true :
false;
426 mSnappedItems.
clear();
428 mLineSnapItem =
nullptr;
453 mLineSnapItem = line;
457 void QgsComposerRuler::setSnapLinePosition(
QPointF pos )
459 if ( !mLineSnapItem || !mComposition )
467 int numPages = mComposition->
numPages();
468 double lineHeight = numPages * mComposition->
paperHeight();
473 mLineSnapItem->
setLine(
QLineF( transformedPt.
x(), 0, transformedPt.
x(), lineHeight ) );
482 for ( ; itemIt != mSnappedItems.
constEnd(); ++itemIt )
void mousePressEvent(QMouseEvent *event) override
void setPointSize(int pointSize)
const unsigned int COUNT_VALID_MULTIPLES
const unsigned int COUNT_VALID_MAGNITUDES
int numPages() const
Returns the number of pages in the composition.
void drawLine(const QLineF &line)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
QGraphicsLineItem * nearestSnapLine(const bool horizontal, const double x, const double y, const double tolerance, QList< QPair< QgsComposerItem *, QgsComposerItem::ItemPositionMode > > &snappedItems) const
Get nearest snap line.
void paintEvent(QPaintEvent *event) override
void setFont(const QFont &font)
QString number(int n, int base)
QSize minimumSizeHint() const override
void mouseMoveEvent(QMouseEvent *event) override
void setPen(const QColor &color)
void removeSnapLine(QGraphicsLineItem *line)
Remove custom snap line (and delete the object)
void setLine(const QLineF &line)
void setSceneTransform(const QTransform &transform)
void mouseReleaseEvent(QMouseEvent *event) override
void drawText(const QPointF &position, const QString &text)
QgsComposerRuler(QgsComposerRuler::Direction d)
int width(const QString &text, int len) const
void cursorPosChanged(QPointF)
Is emitted when mouse cursor coordinates change.
void translate(const QPointF &offset)
double paperHeight() const
Height of paper item.
double paperWidth() const
Width of paper item.
void updateMarker(QPointF pos)
const QPoint & pos() const
const_iterator constEnd() const
QGraphicsLineItem * addSnapLine()
Add a custom snap line (can be horizontal or vertical)
const_iterator constBegin() const
const int RULER_FONT_SIZE
double spaceBetweenPages() const
Returns the vertical space between pages in a composer view.