1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997   Josef Wilgen
4  * Copyright (C) 2002   Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_plot_grid.h"
11 #include "qwt_painter.h"
12 #include "qwt_text.h"
13 #include "qwt_scale_map.h"
14 #include "qwt_scale_div.h"
15 #include "qwt_math.h"
16 #include <qpainter.h>
17 #include <qpen.h>
18 
19 class QwtPlotGrid::PrivateData
20 {
21 public:
PrivateData()22     PrivateData():
23         xEnabled( true ),
24         yEnabled( true ),
25         xMinEnabled( false ),
26         yMinEnabled( false )
27     {
28     }
29 
30     bool xEnabled;
31     bool yEnabled;
32     bool xMinEnabled;
33     bool yMinEnabled;
34 
35     QwtScaleDiv xScaleDiv;
36     QwtScaleDiv yScaleDiv;
37 
38     QPen majorPen;
39     QPen minorPen;
40 };
41 
42 //! Enables major grid, disables minor grid
QwtPlotGrid()43 QwtPlotGrid::QwtPlotGrid():
44     QwtPlotItem( QwtText( "Grid" ) )
45 {
46     d_data = new PrivateData;
47 
48     setItemInterest( QwtPlotItem::ScaleInterest, true );
49     setZ( 10.0 );
50 }
51 
52 //! Destructor
~QwtPlotGrid()53 QwtPlotGrid::~QwtPlotGrid()
54 {
55     delete d_data;
56 }
57 
58 //! \return QwtPlotItem::Rtti_PlotGrid
rtti() const59 int QwtPlotGrid::rtti() const
60 {
61     return QwtPlotItem::Rtti_PlotGrid;
62 }
63 
64 /*!
65   \brief Enable or disable vertical grid lines
66   \param on Enable (true) or disable
67 
68   \sa Minor grid lines can be enabled or disabled with
69       enableXMin()
70 */
enableX(bool on)71 void QwtPlotGrid::enableX( bool on )
72 {
73     if ( d_data->xEnabled != on )
74     {
75         d_data->xEnabled = on;
76 
77         legendChanged();
78         itemChanged();
79     }
80 }
81 
82 /*!
83   \brief Enable or disable horizontal grid lines
84   \param on Enable (true) or disable
85   \sa Minor grid lines can be enabled or disabled with enableYMin()
86 */
enableY(bool on)87 void QwtPlotGrid::enableY( bool on )
88 {
89     if ( d_data->yEnabled != on )
90     {
91         d_data->yEnabled = on;
92 
93         legendChanged();
94         itemChanged();
95     }
96 }
97 
98 /*!
99   \brief Enable or disable  minor vertical grid lines.
100   \param on Enable (true) or disable
101   \sa enableX()
102 */
enableXMin(bool on)103 void QwtPlotGrid::enableXMin( bool on )
104 {
105     if ( d_data->xMinEnabled != on )
106     {
107         d_data->xMinEnabled = on;
108 
109         legendChanged();
110         itemChanged();
111     }
112 }
113 
114 /*!
115   \brief Enable or disable minor horizontal grid lines
116   \param on Enable (true) or disable
117   \sa enableY()
118 */
enableYMin(bool on)119 void QwtPlotGrid::enableYMin( bool on )
120 {
121     if ( d_data->yMinEnabled != on )
122     {
123         d_data->yMinEnabled = on;
124 
125         legendChanged();
126         itemChanged();
127     }
128 }
129 
130 /*!
131   Assign an x axis scale division
132 
133   \param scaleDiv Scale division
134 */
setXDiv(const QwtScaleDiv & scaleDiv)135 void QwtPlotGrid::setXDiv( const QwtScaleDiv &scaleDiv )
136 {
137     if ( d_data->xScaleDiv != scaleDiv )
138     {
139         d_data->xScaleDiv = scaleDiv;
140         itemChanged();
141     }
142 }
143 
144 /*!
145   Assign a y axis division
146 
147   \param scaleDiv Scale division
148 */
setYDiv(const QwtScaleDiv & scaleDiv)149 void QwtPlotGrid::setYDiv( const QwtScaleDiv &scaleDiv )
150 {
151     if ( d_data->yScaleDiv != scaleDiv )
152     {
153         d_data->yScaleDiv = scaleDiv;
154         itemChanged();
155     }
156 }
157 
158 /*!
159   Build and assign a pen for both major and minor grid lines
160 
161   In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
162   non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
163   to hide this incompatibility.
164 
165   \param color Pen color
166   \param width Pen width
167   \param style Pen style
168 
169   \sa pen(), brush()
170  */
setPen(const QColor & color,qreal width,Qt::PenStyle style)171 void QwtPlotGrid::setPen( const QColor &color, qreal width, Qt::PenStyle style )
172 {
173     setPen( QPen( color, width, style ) );
174 }
175 
176 /*!
177   Assign a pen for both major and minor grid lines
178 
179   \param pen Pen
180   \sa setMajorPen(), setMinorPen()
181 */
setPen(const QPen & pen)182 void QwtPlotGrid::setPen( const QPen &pen )
183 {
184     if ( d_data->majorPen != pen || d_data->minorPen != pen )
185     {
186         d_data->majorPen = pen;
187         d_data->minorPen = pen;
188 
189         legendChanged();
190         itemChanged();
191     }
192 }
193 
194 /*!
195   Build and assign a pen for both major grid lines
196 
197   In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
198   non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
199   to hide this incompatibility.
200 
201   \param color Pen color
202   \param width Pen width
203   \param style Pen style
204 
205   \sa pen(), brush()
206  */
setMajorPen(const QColor & color,qreal width,Qt::PenStyle style)207 void QwtPlotGrid::setMajorPen( const QColor &color, qreal width, Qt::PenStyle style )
208 {
209     setMajorPen( QPen( color, width, style ) );
210 }
211 
212 /*!
213   Assign a pen for the major grid lines
214 
215   \param pen Pen
216   \sa majorPen(), setMinorPen(), setPen()
217 */
setMajorPen(const QPen & pen)218 void QwtPlotGrid::setMajorPen( const QPen &pen )
219 {
220     if ( d_data->majorPen != pen )
221     {
222         d_data->majorPen = pen;
223 
224         legendChanged();
225         itemChanged();
226     }
227 }
228 
229 /*!
230   Build and assign a pen for the minor grid lines
231 
232   In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
233   non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
234   to hide this incompatibility.
235 
236   \param color Pen color
237   \param width Pen width
238   \param style Pen style
239 
240   \sa pen(), brush()
241  */
setMinorPen(const QColor & color,qreal width,Qt::PenStyle style)242 void QwtPlotGrid::setMinorPen( const QColor &color, qreal width, Qt::PenStyle style )
243 {
244     setMinorPen( QPen( color, width, style ) );
245 }
246 
247 /*!
248   Assign a pen for the minor grid lines
249 
250   \param pen Pen
251   \sa minorPen(), setMajorPen(), setPen()
252 */
setMinorPen(const QPen & pen)253 void QwtPlotGrid::setMinorPen( const QPen &pen )
254 {
255     if ( d_data->minorPen != pen )
256     {
257         d_data->minorPen = pen;
258 
259         legendChanged();
260         itemChanged();
261     }
262 }
263 
264 /*!
265   \brief Draw the grid
266 
267   The grid is drawn into the bounding rectangle such that
268   grid lines begin and end at the rectangle's borders. The X and Y
269   maps are used to map the scale divisions into the drawing region
270   screen.
271 
272   \param painter  Painter
273   \param xMap X axis map
274   \param yMap Y axis
275   \param canvasRect Contents rectangle of the plot canvas
276 */
draw(QPainter * painter,const QwtScaleMap & xMap,const QwtScaleMap & yMap,const QRectF & canvasRect) const277 void QwtPlotGrid::draw( QPainter *painter,
278     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
279     const QRectF &canvasRect ) const
280 {
281     //  draw minor grid lines
282     QPen minorPen = d_data->minorPen;
283     minorPen.setCapStyle( Qt::FlatCap );
284 
285     painter->setPen( minorPen );
286 
287     if ( d_data->xEnabled && d_data->xMinEnabled )
288     {
289         drawLines( painter, canvasRect, Qt::Vertical, xMap,
290             d_data->xScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
291         drawLines( painter, canvasRect, Qt::Vertical, xMap,
292             d_data->xScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
293     }
294 
295     if ( d_data->yEnabled && d_data->yMinEnabled )
296     {
297         drawLines( painter, canvasRect, Qt::Horizontal, yMap,
298             d_data->yScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
299         drawLines( painter, canvasRect, Qt::Horizontal, yMap,
300             d_data->yScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
301     }
302 
303     //  draw major grid lines
304     QPen majorPen = d_data->majorPen;
305     majorPen.setCapStyle( Qt::FlatCap );
306 
307     painter->setPen( majorPen );
308 
309     if ( d_data->xEnabled )
310     {
311         drawLines( painter, canvasRect, Qt::Vertical, xMap,
312             d_data->xScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
313     }
314 
315     if ( d_data->yEnabled )
316     {
317         drawLines( painter, canvasRect, Qt::Horizontal, yMap,
318             d_data->yScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
319     }
320 }
321 
drawLines(QPainter * painter,const QRectF & canvasRect,Qt::Orientation orientation,const QwtScaleMap & scaleMap,const QList<double> & values) const322 void QwtPlotGrid::drawLines( QPainter *painter, const QRectF &canvasRect,
323     Qt::Orientation orientation, const QwtScaleMap &scaleMap,
324     const QList<double> &values ) const
325 {
326     const double x1 = canvasRect.left();
327     const double x2 = canvasRect.right() - 1.0;
328     const double y1 = canvasRect.top();
329     const double y2 = canvasRect.bottom() - 1.0;
330 
331     const bool doAlign = QwtPainter::roundingAlignment( painter );
332 
333     for ( int i = 0; i < values.count(); i++ )
334     {
335         double value = scaleMap.transform( values[i] );
336         if ( doAlign )
337             value = qRound( value );
338 
339         if ( orientation == Qt::Horizontal )
340         {
341             if ( qwtFuzzyGreaterOrEqual( value, y1 ) &&
342                 qwtFuzzyLessOrEqual( value, y2 ) )
343             {
344                 QwtPainter::drawLine( painter, x1, value, x2, value );
345             }
346         }
347         else
348         {
349             if ( qwtFuzzyGreaterOrEqual( value, x1 ) &&
350                 qwtFuzzyLessOrEqual( value, x2 ) )
351             {
352                 QwtPainter::drawLine( painter, value, y1, value, y2 );
353             }
354         }
355     }
356 }
357 
358 /*!
359   \return the pen for the major grid lines
360   \sa setMajorPen(), setMinorPen(), setPen()
361 */
majorPen() const362 const QPen &QwtPlotGrid::majorPen() const
363 {
364     return d_data->majorPen;
365 }
366 
367 /*!
368   \return the pen for the minor grid lines
369   \sa setMinorPen(), setMajorPen(), setPen()
370 */
minorPen() const371 const QPen &QwtPlotGrid::minorPen() const
372 {
373     return d_data->minorPen;
374 }
375 
376 /*!
377   \return true if vertical grid lines are enabled
378   \sa enableX()
379 */
xEnabled() const380 bool QwtPlotGrid::xEnabled() const
381 {
382     return d_data->xEnabled;
383 }
384 
385 /*!
386   \return true if minor vertical grid lines are enabled
387   \sa enableXMin()
388 */
xMinEnabled() const389 bool QwtPlotGrid::xMinEnabled() const
390 {
391     return d_data->xMinEnabled;
392 }
393 
394 /*!
395   \return true if horizontal grid lines are enabled
396   \sa enableY()
397 */
yEnabled() const398 bool QwtPlotGrid::yEnabled() const
399 {
400     return d_data->yEnabled;
401 }
402 
403 /*!
404   \return true if minor horizontal grid lines are enabled
405   \sa enableYMin()
406 */
yMinEnabled() const407 bool QwtPlotGrid::yMinEnabled() const
408 {
409     return d_data->yMinEnabled;
410 }
411 
412 
413 /*! \return the scale division of the x axis */
xScaleDiv() const414 const QwtScaleDiv &QwtPlotGrid::xScaleDiv() const
415 {
416     return d_data->xScaleDiv;
417 }
418 
419 /*! \return the scale division of the y axis */
yScaleDiv() const420 const QwtScaleDiv &QwtPlotGrid::yScaleDiv() const
421 {
422     return d_data->yScaleDiv;
423 }
424 
425 /*!
426    Update the grid to changes of the axes scale division
427 
428    \param xScaleDiv Scale division of the x-axis
429    \param yScaleDiv Scale division of the y-axis
430 
431    \sa QwtPlot::updateAxes()
432 */
updateScaleDiv(const QwtScaleDiv & xScaleDiv,const QwtScaleDiv & yScaleDiv)433 void QwtPlotGrid::updateScaleDiv( const QwtScaleDiv& xScaleDiv,
434     const QwtScaleDiv& yScaleDiv )
435 {
436     setXDiv( xScaleDiv );
437     setYDiv( yScaleDiv );
438 }
439