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_compass.h"
11 #include "qwt_compass_rose.h"
12 #include "qwt_math.h"
13 #include "qwt_scale_draw.h"
14 #include "qwt_painter.h"
15 #include "qwt_dial_needle.h"
16 #include <qpainter.h>
17 #include <qpixmap.h>
18 #include <qevent.h>
19 
20 /*!
21   \brief Constructor
22 
23   Initializes a label map for multiples of 45 degrees
24  */
QwtCompassScaleDraw()25 QwtCompassScaleDraw::QwtCompassScaleDraw()
26 {
27     enableComponent( QwtAbstractScaleDraw::Backbone, false );
28     enableComponent( QwtAbstractScaleDraw::Ticks, false );
29 
30     d_labelMap.insert( 0.0, QString::fromLatin1( "N" ) );
31     d_labelMap.insert( 45.0, QString::fromLatin1( "NE" ) );
32     d_labelMap.insert( 90.0, QString::fromLatin1( "E" ) );
33     d_labelMap.insert( 135.0, QString::fromLatin1( "SE" ) );
34     d_labelMap.insert( 180.0, QString::fromLatin1( "S" ) );
35     d_labelMap.insert( 225.0, QString::fromLatin1( "SW" ) );
36     d_labelMap.insert( 270.0, QString::fromLatin1( "W" ) );
37     d_labelMap.insert( 315.0, QString::fromLatin1( "NW" ) );
38 
39 #if 0
40     d_labelMap.insert( 22.5, QString::fromLatin1( "NNE" ) );
41     d_labelMap.insert( 67.5, QString::fromLatin1( "NEE" ) );
42     d_labelMap.insert( 112.5, QString::fromLatin1( "SEE" ) );
43     d_labelMap.insert( 157.5, QString::fromLatin1( "SSE" ) );
44     d_labelMap.insert( 202.5, QString::fromLatin1( "SSW" ) );
45     d_labelMap.insert( 247.5, QString::fromLatin1( "SWW" ) );
46     d_labelMap.insert( 292.5, QString::fromLatin1( "NWW" ) );
47     d_labelMap.insert( 337.5, QString::fromLatin1( "NNW" ) );
48 #endif
49 }
50 
51 /*!
52   \brief Constructor
53 
54   \param map Value to label map
55  */
QwtCompassScaleDraw(const QMap<double,QString> & map)56 QwtCompassScaleDraw::QwtCompassScaleDraw( const QMap<double, QString> &map ):
57     d_labelMap( map )
58 {
59     enableComponent( QwtAbstractScaleDraw::Backbone, false );
60     enableComponent( QwtAbstractScaleDraw::Ticks, false );
61 }
62 
63 /*!
64   \brief Set a map, mapping values to labels
65   \param map Value to label map
66 
67   The values of the major ticks are found by looking into this
68   map. The default map consists of the labels N, NE, E, SE, S, SW, W, NW.
69 
70   \warning The map will have no effect for values that are no major
71            tick values. Major ticks can be changed by QwtScaleDraw::setScale
72 
73   \sa labelMap(), scaleDraw(), setScale()
74 */
setLabelMap(const QMap<double,QString> & map)75 void QwtCompassScaleDraw::setLabelMap( const QMap<double, QString> &map )
76 {
77     d_labelMap = map;
78 }
79 
80 
81 /*!
82   \return map, mapping values to labels
83   \sa setLabelMap()
84 */
labelMap() const85 QMap<double, QString> QwtCompassScaleDraw::labelMap() const
86 {
87     return d_labelMap;
88 }
89 
90 /*!
91   Map a value to a corresponding label
92 
93   \param value Value that will be mapped
94 
95   label() looks in the labelMap() for a corresponding label for value
96   or returns an null text.
97 
98   \return Label
99   \sa labelMap(), setLabelMap()
100 */
101 
label(double value) const102 QwtText QwtCompassScaleDraw::label( double value ) const
103 {
104     if ( qFuzzyCompare( value + 1.0, 1.0 ) )
105         value = 0.0;
106 
107     if ( value < 0.0 )
108         value += 360.0;
109 
110     if ( d_labelMap.contains( value ) )
111         return d_labelMap[value];
112 
113     return QwtText();
114 }
115 
116 class QwtCompass::PrivateData
117 {
118 public:
PrivateData()119     PrivateData():
120         rose( NULL )
121     {
122     }
123 
~PrivateData()124     ~PrivateData()
125     {
126         delete rose;
127     }
128 
129     QwtCompassRose *rose;
130 };
131 
132 /*!
133   \brief Constructor
134   \param parent Parent widget
135 
136   Create a compass widget with a scale, no needle and no rose.
137   The default origin is 270.0 with no valid value. It accepts
138   mouse and keyboard inputs and has no step size. The default mode
139   is QwtDial::RotateNeedle.
140 */
QwtCompass(QWidget * parent)141 QwtCompass::QwtCompass( QWidget* parent ):
142     QwtDial( parent )
143 {
144     d_data = new PrivateData;
145 
146     setScaleDraw( new QwtCompassScaleDraw() );
147 
148     setOrigin( 270.0 );
149     setWrapping( true );
150 
151     setScaleMaxMajor( 36 );
152     setScaleMaxMinor( 10 );
153 
154     setScale( 0.0, 360.0 ); // degrees as default
155     setTotalSteps( 360 );
156 }
157 
158 //!  Destructor
~QwtCompass()159 QwtCompass::~QwtCompass()
160 {
161     delete d_data;
162 }
163 
164 
165 /*!
166    Draw the contents of the scale
167 
168    \param painter Painter
169    \param center Center of the content circle
170    \param radius Radius of the content circle
171 */
drawScaleContents(QPainter * painter,const QPointF & center,double radius) const172 void QwtCompass::drawScaleContents( QPainter *painter,
173     const QPointF &center, double radius ) const
174 {
175     QPalette::ColorGroup cg;
176     if ( isEnabled() )
177         cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
178     else
179         cg = QPalette::Disabled;
180 
181     double north = origin();
182     if ( isValid() )
183     {
184         if ( mode() == RotateScale )
185             north -= value();
186     }
187 
188     const int margin = 4;
189     drawRose( painter, center, radius - margin, 360.0 - north,  cg );
190 }
191 
192 /*!
193   Draw the compass rose
194 
195   \param painter Painter
196   \param center Center of the compass
197   \param radius of the circle, where to paint the rose
198   \param north Direction pointing north, in degrees counter clockwise
199   \param cg Color group
200 */
drawRose(QPainter * painter,const QPointF & center,double radius,double north,QPalette::ColorGroup cg) const201 void QwtCompass::drawRose( QPainter *painter, const QPointF &center,
202     double radius, double north, QPalette::ColorGroup cg ) const
203 {
204     if ( d_data->rose )
205         d_data->rose->draw( painter, center, radius, north,  cg );
206 }
207 
208 /*!
209   Set a rose for the compass
210   \param rose Compass rose
211   \warning The rose will be deleted, when a different rose is
212     set or in ~QwtCompass
213   \sa rose()
214 */
setRose(QwtCompassRose * rose)215 void QwtCompass::setRose( QwtCompassRose *rose )
216 {
217     if ( rose != d_data->rose )
218     {
219         if ( d_data->rose )
220             delete d_data->rose;
221 
222         d_data->rose = rose;
223         update();
224     }
225 }
226 
227 /*!
228   \return rose
229   \sa setRose()
230 */
rose() const231 const QwtCompassRose *QwtCompass::rose() const
232 {
233     return d_data->rose;
234 }
235 
236 /*!
237   \return rose
238   \sa setRose()
239 */
rose()240 QwtCompassRose *QwtCompass::rose()
241 {
242     return d_data->rose;
243 }
244 
245 /*!
246   Handles key events
247 
248   Beside the keys described in QwtDial::keyPressEvent numbers
249   from 1-9 (without 5) set the direction according to their
250   position on the num pad.
251 
252   \sa isReadOnly()
253 */
keyPressEvent(QKeyEvent * kev)254 void QwtCompass::keyPressEvent( QKeyEvent *kev )
255 {
256     if ( isReadOnly() )
257         return;
258 
259 #if 0
260     if ( kev->key() == Key_5 )
261     {
262         invalidate(); // signal ???
263         return;
264     }
265 #endif
266 
267     double newValue = value();
268 
269     if ( kev->key() >= Qt::Key_1 && kev->key() <= Qt::Key_9 )
270     {
271         if ( mode() != RotateNeedle || kev->key() == Qt::Key_5 )
272             return;
273 
274         switch ( kev->key() )
275         {
276             case Qt::Key_6:
277                 newValue = 180.0 * 0.0;
278                 break;
279             case Qt::Key_3:
280                 newValue = 180.0 * 0.25;
281                 break;
282             case Qt::Key_2:
283                 newValue = 180.0 * 0.5;
284                 break;
285             case Qt::Key_1:
286                 newValue = 180.0 * 0.75;
287                 break;
288             case Qt::Key_4:
289                 newValue = 180.0 * 1.0;
290                 break;
291             case Qt::Key_7:
292                 newValue = 180.0 * 1.25;
293                 break;
294             case Qt::Key_8:
295                 newValue = 180.0 * 1.5;
296                 break;
297             case Qt::Key_9:
298                 newValue = 180.0 * 1.75;
299                 break;
300         }
301         newValue -= origin();
302         setValue( newValue );
303     }
304     else
305     {
306         QwtDial::keyPressEvent( kev );
307     }
308 }
309