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_picker.h"
11 #include "qwt_plot.h"
12 #include "qwt_scale_div.h"
13 #include "qwt_painter.h"
14 #include "qwt_scale_map.h"
15 #include "qwt_picker_machine.h"
16 
17 /*!
18   \brief Create a plot picker
19 
20   The picker is set to those x- and y-axis of the plot
21   that are enabled. If both or no x-axis are enabled, the picker
22   is set to QwtPlot::xBottom. If both or no y-axis are
23   enabled, it is set to QwtPlot::yLeft.
24 
25   \param canvas Plot canvas to observe, also the parent object
26 
27   \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect()
28 */
29 
QwtPlotPicker(QWidget * canvas)30 QwtPlotPicker::QwtPlotPicker( QWidget *canvas ):
31     QwtPicker( canvas ),
32     d_xAxis( -1 ),
33     d_yAxis( -1 )
34 {
35     if ( !canvas )
36         return;
37 
38     // attach axes
39 
40     int xAxis = QwtPlot::xBottom;
41 
42     const QwtPlot *plot = QwtPlotPicker::plot();
43     if ( !plot->axisEnabled( QwtPlot::xBottom ) &&
44         plot->axisEnabled( QwtPlot::xTop ) )
45     {
46         xAxis = QwtPlot::xTop;
47     }
48 
49     int yAxis = QwtPlot::yLeft;
50     if ( !plot->axisEnabled( QwtPlot::yLeft ) &&
51         plot->axisEnabled( QwtPlot::yRight ) )
52     {
53         yAxis = QwtPlot::yRight;
54     }
55 
56     setAxis( xAxis, yAxis );
57 }
58 
59 /*!
60   Create a plot picker
61 
62   \param xAxis Set the x axis of the picker
63   \param yAxis Set the y axis of the picker
64   \param canvas Plot canvas to observe, also the parent object
65 
66   \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect()
67 */
QwtPlotPicker(int xAxis,int yAxis,QWidget * canvas)68 QwtPlotPicker::QwtPlotPicker( int xAxis, int yAxis, QWidget *canvas ):
69     QwtPicker( canvas ),
70     d_xAxis( xAxis ),
71     d_yAxis( yAxis )
72 {
73 }
74 
75 /*!
76   Create a plot picker
77 
78   \param xAxis X axis of the picker
79   \param yAxis Y axis of the picker
80   \param rubberBand Rubber band style
81   \param trackerMode Tracker mode
82   \param canvas Plot canvas to observe, also the parent object
83 
84   \sa QwtPicker, QwtPicker::setSelectionFlags(), QwtPicker::setRubberBand(),
85       QwtPicker::setTrackerMode
86 
87   \sa QwtPlot::autoReplot(), QwtPlot::replot(), scaleRect()
88 */
QwtPlotPicker(int xAxis,int yAxis,RubberBand rubberBand,DisplayMode trackerMode,QWidget * canvas)89 QwtPlotPicker::QwtPlotPicker( int xAxis, int yAxis,
90         RubberBand rubberBand, DisplayMode trackerMode,
91         QWidget *canvas ):
92     QwtPicker( rubberBand, trackerMode, canvas ),
93     d_xAxis( xAxis ),
94     d_yAxis( yAxis )
95 {
96 }
97 
98 //! Destructor
~QwtPlotPicker()99 QwtPlotPicker::~QwtPlotPicker()
100 {
101 }
102 
103 //! \return Observed plot canvas
canvas()104 QWidget *QwtPlotPicker::canvas()
105 {
106     return parentWidget();
107 }
108 
109 //! \return Observed plot canvas
canvas() const110 const QWidget *QwtPlotPicker::canvas() const
111 {
112     return parentWidget();
113 }
114 
115 //! \return Plot widget, containing the observed plot canvas
plot()116 QwtPlot *QwtPlotPicker::plot()
117 {
118     QWidget *w = canvas();
119     if ( w )
120         w = w->parentWidget();
121 
122     return qobject_cast<QwtPlot *>( w );
123 }
124 
125 //! \return Plot widget, containing the observed plot canvas
plot() const126 const QwtPlot *QwtPlotPicker::plot() const
127 {
128     const QWidget *w = canvas();
129     if ( w )
130         w = w->parentWidget();
131 
132     return qobject_cast<const QwtPlot *>( w );
133 }
134 
135 /*!
136   \return Normalized bounding rectangle of the axes
137   \sa QwtPlot::autoReplot(), QwtPlot::replot().
138 */
scaleRect() const139 QRectF QwtPlotPicker::scaleRect() const
140 {
141     QRectF rect;
142 
143     if ( plot() )
144     {
145         const QwtScaleDiv &xs = plot()->axisScaleDiv( xAxis() );
146         const QwtScaleDiv &ys = plot()->axisScaleDiv( yAxis() );
147 
148         rect = QRectF( xs.lowerBound(), ys.lowerBound(),
149             xs.range(), ys.range() );
150         rect = rect.normalized();
151     }
152 
153     return rect;
154 }
155 
156 /*!
157   Set the x and y axes of the picker
158 
159   \param xAxis X axis
160   \param yAxis Y axis
161 */
setAxis(int xAxis,int yAxis)162 void QwtPlotPicker::setAxis( int xAxis, int yAxis )
163 {
164     const QwtPlot *plt = plot();
165     if ( !plt )
166         return;
167 
168     if ( xAxis != d_xAxis || yAxis != d_yAxis )
169     {
170         d_xAxis = xAxis;
171         d_yAxis = yAxis;
172     }
173 }
174 
175 //! Return x axis
xAxis() const176 int QwtPlotPicker::xAxis() const
177 {
178     return d_xAxis;
179 }
180 
181 //! Return y axis
yAxis() const182 int QwtPlotPicker::yAxis() const
183 {
184     return d_yAxis;
185 }
186 
187 /*!
188   Translate a pixel position into a position string
189 
190   \param pos Position in pixel coordinates
191   \return Position string
192 */
trackerText(const QPoint & pos) const193 QwtText QwtPlotPicker::trackerText( const QPoint &pos ) const
194 {
195     if ( plot() == NULL )
196         return QwtText();
197 
198     return trackerTextF( invTransform( pos ) );
199 }
200 
201 /*!
202   \brief Translate a position into a position string
203 
204   In case of HLineRubberBand the label is the value of the
205   y position, in case of VLineRubberBand the value of the x position.
206   Otherwise the label contains x and y position separated by a ',' .
207 
208   The format for the double to string conversion is "%.4f".
209 
210   \param pos Position
211   \return Position string
212 */
trackerTextF(const QPointF & pos) const213 QwtText QwtPlotPicker::trackerTextF( const QPointF &pos ) const
214 {
215     QString text;
216 
217     switch ( rubberBand() )
218     {
219         case HLineRubberBand:
220             text.sprintf( "%.4f", pos.y() );
221             break;
222         case VLineRubberBand:
223             text.sprintf( "%.4f", pos.x() );
224             break;
225         default:
226             text.sprintf( "%.4f, %.4f", pos.x(), pos.y() );
227     }
228     return QwtText( text );
229 }
230 
231 /*!
232   Append a point to the selection and update rubber band and tracker.
233 
234   \param pos Additional point
235   \sa isActive, begin(), end(), move(), appended()
236 
237   \note The appended(const QPoint &), appended(const QDoublePoint &)
238         signals are emitted.
239 */
append(const QPoint & pos)240 void QwtPlotPicker::append( const QPoint &pos )
241 {
242     QwtPicker::append( pos );
243     Q_EMIT appended( invTransform( pos ) );
244 }
245 
246 /*!
247   Move the last point of the selection
248 
249   \param pos New position
250   \sa isActive, begin(), end(), append()
251 
252   \note The moved(const QPoint &), moved(const QDoublePoint &)
253         signals are emitted.
254 */
move(const QPoint & pos)255 void QwtPlotPicker::move( const QPoint &pos )
256 {
257     QwtPicker::move( pos );
258     Q_EMIT moved( invTransform( pos ) );
259 }
260 
261 /*!
262   Close a selection setting the state to inactive.
263 
264   \param ok If true, complete the selection and emit selected signals
265             otherwise discard the selection.
266   \return True if the selection has been accepted, false otherwise
267 */
268 
end(bool ok)269 bool QwtPlotPicker::end( bool ok )
270 {
271     ok = QwtPicker::end( ok );
272     if ( !ok )
273         return false;
274 
275     QwtPlot *plot = QwtPlotPicker::plot();
276     if ( !plot )
277         return false;
278 
279     const QPolygon points = selection();
280     if ( points.count() == 0 )
281         return false;
282 
283     QwtPickerMachine::SelectionType selectionType =
284         QwtPickerMachine::NoSelection;
285 
286     if ( stateMachine() )
287         selectionType = stateMachine()->selectionType();
288 
289     switch ( selectionType )
290     {
291         case QwtPickerMachine::PointSelection:
292         {
293             const QPointF pos = invTransform( points.first() );
294             Q_EMIT selected( pos );
295             break;
296         }
297         case QwtPickerMachine::RectSelection:
298         {
299             if ( points.count() >= 2 )
300             {
301                 const QPoint p1 = points.first();
302                 const QPoint p2 = points.last();
303 
304                 const QRect rect = QRect( p1, p2 ).normalized();
305                 Q_EMIT selected( invTransform( rect ) );
306             }
307             break;
308         }
309         case QwtPickerMachine::PolygonSelection:
310         {
311             QVector<QPointF> dpa( points.count() );
312             for ( int i = 0; i < points.count(); i++ )
313                 dpa[i] = invTransform( points[i] );
314 
315             Q_EMIT selected( dpa );
316         }
317         default:
318             break;
319     }
320 
321     return true;
322 }
323 
324 /*!
325     Translate a rectangle from pixel into plot coordinates
326 
327     \return Rectangle in plot coordinates
328     \sa transform()
329 */
invTransform(const QRect & rect) const330 QRectF QwtPlotPicker::invTransform( const QRect &rect ) const
331 {
332     const QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
333     const QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
334 
335     return QwtScaleMap::invTransform( xMap, yMap, rect );
336 }
337 
338 /*!
339     Translate a rectangle from plot into pixel coordinates
340     \return Rectangle in pixel coordinates
341     \sa invTransform()
342 */
transform(const QRectF & rect) const343 QRect QwtPlotPicker::transform( const QRectF &rect ) const
344 {
345     const QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
346     const QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
347 
348     return QwtScaleMap::transform( xMap, yMap, rect ).toRect();
349 }
350 
351 /*!
352     Translate a point from pixel into plot coordinates
353     \return Point in plot coordinates
354     \sa transform()
355 */
invTransform(const QPoint & pos) const356 QPointF QwtPlotPicker::invTransform( const QPoint &pos ) const
357 {
358     QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
359     QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
360 
361     return QPointF(
362         xMap.invTransform( pos.x() ),
363         yMap.invTransform( pos.y() )
364     );
365 }
366 
367 /*!
368     Translate a point from plot into pixel coordinates
369     \return Point in pixel coordinates
370     \sa invTransform()
371 */
transform(const QPointF & pos) const372 QPoint QwtPlotPicker::transform( const QPointF &pos ) const
373 {
374     QwtScaleMap xMap = plot()->canvasMap( d_xAxis );
375     QwtScaleMap yMap = plot()->canvasMap( d_yAxis );
376 
377     const QPointF p( xMap.transform( pos.x() ),
378         yMap.transform( pos.y() ) );
379 
380     return p.toPoint();
381 }
382