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 <qpainter.h>
11 #include <qapplication.h>
12 #include "qwt_painter.h"
13 #include "qwt_polygon.h"
14 #include "qwt_symbol.h"
15 
16 /*!
17   Default Constructor
18 
19   The symbol is constructed with gray interior,
20   black outline with zero width, no size and style 'NoSymbol'.
21 */
QwtSymbol()22 QwtSymbol::QwtSymbol():
23     d_brush(Qt::gray),
24     d_pen(Qt::black),
25     d_size(0,0),
26     d_style(QwtSymbol::NoSymbol)
27 {
28 }
29 
30 /*!
31   \brief Constructor
32   \param style Symbol Style
33   \param brush brush to fill the interior
34   \param pen outline pen
35   \param size size
36 */
QwtSymbol(QwtSymbol::Style style,const QBrush & brush,const QPen & pen,const QSize & size)37 QwtSymbol::QwtSymbol(QwtSymbol::Style style, const QBrush &brush,
38         const QPen &pen, const QSize &size):
39     d_brush(brush),
40     d_pen(pen),
41     d_size(size),
42     d_style(style)
43 {
44 }
45 
46 //! Destructor
~QwtSymbol()47 QwtSymbol::~QwtSymbol()
48 {
49 }
50 
51 /*!
52   Allocate and return a symbol with the same attributes
53   \return Cloned symbol
54 */
clone() const55 QwtSymbol *QwtSymbol::clone() const
56 {
57     QwtSymbol *other = new QwtSymbol;
58     *other = *this;
59 
60     return other;
61 }
62 
63 /*!
64   \brief Specify the symbol's size
65 
66   If the 'h' parameter is left out or less than 0,
67   and the 'w' parameter is greater than or equal to 0,
68   the symbol size will be set to (w,w).
69   \param width Width
70   \param height Height (defaults to -1)
71 */
setSize(int width,int height)72 void QwtSymbol::setSize(int width, int height)
73 {
74     if ((width >= 0) && (height < 0))
75         height = width;
76     d_size = QSize(width, height);
77 }
78 
79 /*!
80    Set the symbol's size
81    \param size Size
82 */
setSize(const QSize & size)83 void QwtSymbol::setSize(const QSize &size)
84 {
85     if (size.isValid())
86         d_size = size;
87 }
88 
89 /*!
90   \brief Assign a brush
91 
92   The brush is used to draw the interior of the symbol.
93   \param brush Brush
94 */
setBrush(const QBrush & brush)95 void QwtSymbol::setBrush(const QBrush &brush)
96 {
97     d_brush = brush;
98 }
99 
100 /*!
101   Assign a pen
102 
103   The pen is used to draw the symbol's outline.
104 
105   The width of non cosmetic pens is scaled according to the resolution
106   of the paint device.
107 
108   \param pen Pen
109   \sa pen(), setBrush(), QwtPainter::scaledPen()
110 */
setPen(const QPen & pen)111 void QwtSymbol::setPen(const QPen &pen)
112 {
113     d_pen = pen;
114 }
115 
116 /*!
117   \brief Draw the symbol at a point (x,y).
118 */
draw(QPainter * painter,int x,int y) const119 void QwtSymbol::draw(QPainter *painter, int x, int y) const
120 {
121     draw(painter, QPoint(x, y));
122 }
123 
124 
125 /*!
126   \brief Draw the symbol into a bounding rectangle.
127 
128   This function assumes that the painter has been initialized with
129   brush and pen before. This allows a much more performant implementation
130   when painting many symbols with the same brush and pen like in curves.
131 
132   \param painter Painter
133   \param r Bounding rectangle
134 */
draw(QPainter * painter,const QRect & r) const135 void QwtSymbol::draw(QPainter *painter, const QRect& r) const
136 {
137     switch(d_style)
138     {
139         case QwtSymbol::Ellipse:
140             QwtPainter::drawEllipse(painter, r);
141             break;
142         case QwtSymbol::Rect:
143             QwtPainter::drawRect(painter, r);
144             break;
145         case QwtSymbol::Diamond:
146         {
147             const int w2 = r.width() / 2;
148             const int h2 = r.height() / 2;
149 
150             QwtPolygon pa(4);
151             pa.setPoint(0, r.x() + w2, r.y());
152             pa.setPoint(1, r.right(), r.y() + h2);
153             pa.setPoint(2, r.x() + w2, r.bottom());
154             pa.setPoint(3, r.x(), r.y() + h2);
155             QwtPainter::drawPolygon(painter, pa);
156             break;
157         }
158         case QwtSymbol::Cross:
159         {
160             const int w2 = r.width() / 2;
161             const int h2 = r.height() / 2;
162 
163             QwtPainter::drawLine(painter, r.x() + w2, r.y(),
164                 r.x() + w2, r.bottom());
165             QwtPainter::drawLine(painter, r.x(), r.y() + h2,
166                 r.right(), r.y() + h2);
167             break;
168         }
169         case QwtSymbol::XCross:
170         {
171             QwtPainter::drawLine(painter, r.left(), r.top(),
172                 r.right(), r.bottom());
173             QwtPainter::drawLine(painter, r.left(), r.bottom(),
174                 r.right(), r.top());
175             break;
176         }
177         case QwtSymbol::Triangle:
178         case QwtSymbol::UTriangle:
179         {
180             const int w2 = r.width() / 2;
181 
182             QwtPolygon pa(3);
183             pa.setPoint(0, r.x() + w2, r.y());
184             pa.setPoint(1, r.right(), r.bottom());
185             pa.setPoint(2, r.x(), r.bottom());
186             QwtPainter::drawPolygon(painter, pa);
187             break;
188         }
189         case QwtSymbol::DTriangle:
190         {
191             const int w2 = r.width() / 2;
192 
193             QwtPolygon pa(3);
194             pa.setPoint(0, r.x(), r.y());
195             pa.setPoint(1, r.right(), r.y());
196             pa.setPoint(2, r.x() + w2, r.bottom());
197             QwtPainter::drawPolygon(painter, pa);
198             break;
199         }
200         case QwtSymbol::RTriangle:
201         {
202             const int h2 = r.height() / 2;
203 
204             QwtPolygon pa(3);
205             pa.setPoint(0, r.x(), r.y());
206             pa.setPoint(1, r.right(), r.y() + h2);
207             pa.setPoint(2, r.x(), r.bottom());
208             QwtPainter::drawPolygon(painter, pa);
209             break;
210         }
211         case QwtSymbol::LTriangle:
212         {
213             const int h2 = r.height() / 2;
214 
215             QwtPolygon pa(3);
216             pa.setPoint(0, r.right(), r.y());
217             pa.setPoint(1, r.x(), r.y() + h2);
218             pa.setPoint(2, r.right(), r.bottom());
219             QwtPainter::drawPolygon(painter, pa);
220             break;
221         }
222         case QwtSymbol::HLine:
223         {
224             const int h2 = r.height() / 2;
225             QwtPainter::drawLine(painter, r.left(), r.top() + h2,
226                     r.right(), r.top() + h2);
227             break;
228         }
229         case QwtSymbol::VLine:
230         {
231             const int w2 = r.width() / 2;
232             QwtPainter::drawLine(painter, r.left() + w2, r.top(),
233                     r.left() + w2, r.bottom());
234             break;
235         }
236         case QwtSymbol::Star1:
237         {
238             const double sqrt1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
239 
240             const int w2 = r.width() / 2;
241             const int h2 = r.height() / 2;
242             const int d1  = (int)( (double)w2 * (1.0 - sqrt1_2) );
243 
244             QwtPainter::drawLine(painter, r.left() + d1, r.top() + d1,
245                     r.right() - d1, r.bottom() - d1);
246             QwtPainter::drawLine(painter, r.left() + d1, r.bottom() - d1,
247                     r.right() - d1, r.top() + d1);
248             QwtPainter::drawLine(painter, r.left() + w2, r.top(),
249                     r.left() + w2, r.bottom());
250             QwtPainter::drawLine(painter, r.left(), r.top() + h2,
251                     r.right(), r.top() + h2);
252             break;
253         }
254         case QwtSymbol::Star2:
255         {
256             const int w = r.width();
257             const int side = (int)(((double)r.width() * (1.0 - 0.866025)) /
258                 2.0);  // 0.866025 = cos(30°)
259             const int h4 = r.height() / 4;
260             const int h2 = r.height() / 2;
261             const int h34 = (r.height() * 3) / 4;
262 
263             QwtPolygon pa(12);
264             pa.setPoint(0, r.left() + (w / 2), r.top());
265             pa.setPoint(1, r.right() - (side + (w - 2 * side) / 3),
266                 r.top() + h4 );
267             pa.setPoint(2, r.right() - side, r.top() + h4);
268             pa.setPoint(3, r.right() - (side + (w / 2 - side) / 3),
269                 r.top() + h2 );
270             pa.setPoint(4, r.right() - side, r.top() + h34);
271             pa.setPoint(5, r.right() - (side + (w - 2 * side) / 3),
272                 r.top() + h34 );
273             pa.setPoint(6, r.left() + (w / 2), r.bottom());
274             pa.setPoint(7, r.left() + (side + (w - 2 * side) / 3),
275                 r.top() + h34 );
276             pa.setPoint(8, r.left() + side, r.top() + h34);
277             pa.setPoint(9, r.left() + (side + (w / 2 - side) / 3),
278                 r.top() + h2 );
279             pa.setPoint(10, r.left() + side, r.top() + h4);
280             pa.setPoint(11, r.left() + (side + (w - 2 * side) / 3),
281                 r.top() + h4 );
282             QwtPainter::drawPolygon(painter, pa);
283             break;
284         }
285         case QwtSymbol::Hexagon:
286         {
287             const int w2 = r.width() / 2;
288             const int side = (int)(((double)r.width() * (1.0 - 0.866025)) /
289                 2.0);  // 0.866025 = cos(30°)
290             const int h4 = r.height() / 4;
291             const int h34 = (r.height() * 3) / 4;
292 
293             QwtPolygon pa(6);
294             pa.setPoint(0, r.left() + w2, r.top());
295             pa.setPoint(1, r.right() - side, r.top() + h4);
296             pa.setPoint(2, r.right() - side, r.top() + h34);
297             pa.setPoint(3, r.left() + w2, r.bottom());
298             pa.setPoint(4, r.left() + side, r.top() + h34);
299             pa.setPoint(5, r.left() + side, r.top() + h4);
300             QwtPainter::drawPolygon(painter, pa);
301             break;
302         }
303         default:;
304     }
305 }
306 
307 /*!
308   \brief Draw the symbol at a specified point
309 
310   \param painter Painter
311   \param pos Center of the symbol
312 */
draw(QPainter * painter,const QPoint & pos) const313 void QwtSymbol::draw(QPainter *painter, const QPoint &pos) const
314 {
315     QRect rect;
316     rect.setSize(QwtPainter::metricsMap().screenToLayout(d_size));
317     rect.moveCenter(pos);
318 
319     painter->setBrush(d_brush);
320     painter->setPen(QwtPainter::scaledPen(d_pen));
321 
322     draw(painter, rect);
323 }
324 
325 /*!
326   \brief Specify the symbol style
327 
328   The following styles are defined:<dl>
329   <dt>NoSymbol<dd>No Style. The symbol cannot be drawn.
330   <dt>Ellipse<dd>Ellipse or circle
331   <dt>Rect<dd>Rectangle
332   <dt>Diamond<dd>Diamond
333   <dt>Triangle<dd>Triangle pointing upwards
334   <dt>DTriangle<dd>Triangle pointing downwards
335   <dt>UTriangle<dd>Triangle pointing upwards
336   <dt>LTriangle<dd>Triangle pointing left
337   <dt>RTriangle<dd>Triangle pointing right
338   <dt>Cross<dd>Cross (+)
339   <dt>XCross<dd>Diagonal cross (X)
340   <dt>HLine<dd>Horizontal line
341   <dt>VLine<dd>Vertical line
342   <dt>Star1<dd>X combined with +
343   <dt>Star2<dd>Six-pointed star
344   <dt>Hexagon<dd>Hexagon</dl>
345 
346   \param s style
347 */
setStyle(QwtSymbol::Style s)348 void QwtSymbol::setStyle(QwtSymbol::Style s)
349 {
350     d_style = s;
351 }
352 
353 //! == operator
operator ==(const QwtSymbol & other) const354 bool QwtSymbol::operator==(const QwtSymbol &other) const
355 {
356     return brush() == other.brush() && pen() == other.pen()
357             && style() == other.style() && size() == other.size();
358 }
359 
360 //! != operator
operator !=(const QwtSymbol & other) const361 bool QwtSymbol::operator!=(const QwtSymbol &other) const
362 {
363     return !(*this == other);
364 }
365