source: ntrip/trunk/BNC/qwt/qwt_plot_tradingcurve.cpp@ 9184

Last change on this file since 9184 was 8127, checked in by stoecker, 7 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 17.9 KB
Line 
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_tradingcurve.h"
11#include "qwt_scale_map.h"
12#include "qwt_clipper.h"
13#include "qwt_painter.h"
14#include <qpainter.h>
15
16static inline bool qwtIsSampleInside( const QwtOHLCSample &sample,
17 double tMin, double tMax, double vMin, double vMax )
18{
19 const double t = sample.time;
20 const QwtInterval interval = sample.boundingInterval();
21
22 const bool isOffScreen = ( t < tMin ) || ( t > tMax )
23 || ( interval.maxValue() < vMin ) || ( interval.minValue() > vMax );
24
25 return !isOffScreen;
26}
27
28class QwtPlotTradingCurve::PrivateData
29{
30public:
31 PrivateData():
32 symbolStyle( QwtPlotTradingCurve::CandleStick ),
33 symbolExtent( 0.6 ),
34 minSymbolWidth( 2.0 ),
35 maxSymbolWidth( -1.0 ),
36 paintAttributes( QwtPlotTradingCurve::ClipSymbols )
37 {
38 symbolBrush[0] = QBrush( Qt::white );
39 symbolBrush[1] = QBrush( Qt::black );
40 }
41
42 QwtPlotTradingCurve::SymbolStyle symbolStyle;
43 double symbolExtent;
44 double minSymbolWidth;
45 double maxSymbolWidth;
46
47 QPen symbolPen;
48 QBrush symbolBrush[2]; // Increasing/Decreasing
49
50 QwtPlotTradingCurve::PaintAttributes paintAttributes;
51};
52
53/*!
54 Constructor
55 \param title Title of the curve
56*/
57QwtPlotTradingCurve::QwtPlotTradingCurve( const QwtText &title ):
58 QwtPlotSeriesItem( title )
59{
60 init();
61}
62
63/*!
64 Constructor
65 \param title Title of the curve
66*/
67QwtPlotTradingCurve::QwtPlotTradingCurve( const QString &title ):
68 QwtPlotSeriesItem( QwtText( title ) )
69{
70 init();
71}
72
73//! Destructor
74QwtPlotTradingCurve::~QwtPlotTradingCurve()
75{
76 delete d_data;
77}
78
79//! Initialize internal members
80void QwtPlotTradingCurve::init()
81{
82 setItemAttribute( QwtPlotItem::Legend, true );
83 setItemAttribute( QwtPlotItem::AutoScale, true );
84
85 d_data = new PrivateData;
86 setData( new QwtTradingChartData() );
87
88 setZ( 19.0 );
89}
90
91//! \return QwtPlotItem::Rtti_PlotTradingCurve
92int QwtPlotTradingCurve::rtti() const
93{
94 return QwtPlotTradingCurve::Rtti_PlotTradingCurve;
95}
96
97/*!
98 Specify an attribute how to draw the curve
99
100 \param attribute Paint attribute
101 \param on On/Off
102 \sa testPaintAttribute()
103*/
104void QwtPlotTradingCurve::setPaintAttribute(
105 PaintAttribute attribute, bool on )
106{
107 if ( on )
108 d_data->paintAttributes |= attribute;
109 else
110 d_data->paintAttributes &= ~attribute;
111}
112
113/*!
114 \return True, when attribute is enabled
115 \sa PaintAttribute, setPaintAttribute()
116*/
117bool QwtPlotTradingCurve::testPaintAttribute(
118 PaintAttribute attribute ) const
119{
120 return ( d_data->paintAttributes & attribute );
121}
122
123/*!
124 Initialize data with an array of samples.
125 \param samples Vector of samples
126
127 \sa QwtPlotSeriesItem::setData()
128*/
129void QwtPlotTradingCurve::setSamples(
130 const QVector<QwtOHLCSample> &samples )
131{
132 setData( new QwtTradingChartData( samples ) );
133}
134
135/*!
136 Assign a series of samples
137
138 setSamples() is just a wrapper for setData() without any additional
139 value - beside that it is easier to find for the developer.
140
141 \param data Data
142 \warning The item takes ownership of the data object, deleting
143 it when its not used anymore.
144*/
145void QwtPlotTradingCurve::setSamples(
146 QwtSeriesData<QwtOHLCSample> *data )
147{
148 setData( data );
149}
150
151/*!
152 Set the symbol style
153
154 \param style Symbol style
155
156 \sa symbolStyle(), setSymbolExtent(),
157 setSymbolPen(), setSymbolBrush()
158*/
159void QwtPlotTradingCurve::setSymbolStyle( SymbolStyle style )
160{
161 if ( style != d_data->symbolStyle )
162 {
163 d_data->symbolStyle = style;
164
165 legendChanged();
166 itemChanged();
167 }
168}
169
170/*!
171 \return Symbol style
172 \sa setSymbolStyle(), symbolExtent(), symbolPen(), symbolBrush()
173*/
174QwtPlotTradingCurve::SymbolStyle QwtPlotTradingCurve::symbolStyle() const
175{
176 return d_data->symbolStyle;
177}
178
179/*!
180 Build and assign the symbol pen
181
182 In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
183 non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
184 to hide this incompatibility.
185
186 \param color Pen color
187 \param width Pen width
188 \param style Pen style
189
190 \sa pen(), brush()
191 */
192void QwtPlotTradingCurve::setSymbolPen(
193 const QColor &color, qreal width, Qt::PenStyle style )
194{
195 setSymbolPen( QPen( color, width, style ) );
196}
197
198/*!
199 \brief Set the symbol pen
200
201 The symbol pen is used for rendering the lines of the
202 bar or candlestick symbols
203
204 \sa symbolPen(), setSymbolBrush()
205*/
206void QwtPlotTradingCurve::setSymbolPen( const QPen &pen )
207{
208 if ( pen != d_data->symbolPen )
209 {
210 d_data->symbolPen = pen;
211
212 legendChanged();
213 itemChanged();
214 }
215}
216
217/*!
218 \return Symbol pen
219 \sa setSymbolPen(), symbolBrush()
220*/
221QPen QwtPlotTradingCurve::symbolPen() const
222{
223 return d_data->symbolPen;
224}
225
226/*!
227 Set the symbol brush
228
229 \param direction Direction type
230 \param brush Brush used to fill the body of all candlestick
231 symbols with the direction
232
233 \sa symbolBrush(), setSymbolPen()
234*/
235void QwtPlotTradingCurve::setSymbolBrush(
236 Direction direction, const QBrush &brush )
237{
238 if ( direction < 0 || direction >= 2 )
239 return;
240
241 if ( brush != d_data->symbolBrush[ direction ] )
242 {
243 d_data->symbolBrush[ direction ] = brush;
244
245 legendChanged();
246 itemChanged();
247 }
248}
249
250/*!
251 \param direction
252 \return Brush used to fill the body of all candlestick
253 symbols with the direction
254
255 \sa setSymbolPen(), symbolBrush()
256*/
257QBrush QwtPlotTradingCurve::symbolBrush( Direction direction ) const
258{
259 if ( direction < 0 || direction >= 2 )
260 return QBrush();
261
262 return d_data->symbolBrush[ direction ];
263}
264
265/*!
266 \brief Set the extent of the symbol
267
268 The width of the symbol is given in scale coordinates. When painting
269 a symbol the width is scaled into paint device coordinates
270 by scaledSymbolWidth(). The scaled width is bounded by
271 minSymbolWidth(), maxSymbolWidth()
272
273 \param extent Symbol width in scale coordinates
274
275 \sa symbolExtent(), scaledSymbolWidth(),
276 setMinSymbolWidth(), setMaxSymbolWidth()
277*/
278void QwtPlotTradingCurve::setSymbolExtent( double extent )
279{
280 extent = qMax( 0.0, extent );
281 if ( extent != d_data->symbolExtent )
282 {
283 d_data->symbolExtent = extent;
284
285 legendChanged();
286 itemChanged();
287 }
288}
289
290/*!
291 \return Extent of a symbol in scale coordinates
292 \sa setSymbolExtent(), scaledSymbolWidth(),
293 minSymbolWidth(), maxSymbolWidth()
294*/
295double QwtPlotTradingCurve::symbolExtent() const
296{
297 return d_data->symbolExtent;
298}
299
300/*!
301 Set a minimum for the symbol width
302
303 \param width Width in paint device coordinates
304 \sa minSymbolWidth(), setMaxSymbolWidth(), setSymbolExtent()
305 */
306void QwtPlotTradingCurve::setMinSymbolWidth( double width )
307{
308 width = qMax( width, 0.0 );
309 if ( width != d_data->minSymbolWidth )
310 {
311 d_data->minSymbolWidth = width;
312
313 legendChanged();
314 itemChanged();
315 }
316}
317
318/*!
319 \return Minmum for the symbol width
320 \sa setMinSymbolWidth(), maxSymbolWidth(), symbolExtent()
321 */
322double QwtPlotTradingCurve::minSymbolWidth() const
323{
324 return d_data->minSymbolWidth;
325}
326
327/*!
328 Set a maximum for the symbol width
329
330 A value <= 0.0 means an unlimited width
331
332 \param width Width in paint device coordinates
333 \sa maxSymbolWidth(), setMinSymbolWidth(), setSymbolExtent()
334 */
335void QwtPlotTradingCurve::setMaxSymbolWidth( double width )
336{
337 if ( width != d_data->maxSymbolWidth )
338 {
339 d_data->maxSymbolWidth = width;
340
341 legendChanged();
342 itemChanged();
343 }
344}
345
346/*!
347 \return Maximum for the symbol width
348 \sa setMaxSymbolWidth(), minSymbolWidth(), symbolExtent()
349 */
350double QwtPlotTradingCurve::maxSymbolWidth() const
351{
352 return d_data->maxSymbolWidth;
353}
354
355/*!
356 \return Bounding rectangle of all samples.
357 For an empty series the rectangle is invalid.
358*/
359QRectF QwtPlotTradingCurve::boundingRect() const
360{
361 QRectF rect = QwtPlotSeriesItem::boundingRect();
362 if ( rect.isValid() && orientation() == Qt::Vertical )
363 rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
364
365 return rect;
366}
367
368/*!
369 Draw an interval of the curve
370
371 \param painter Painter
372 \param xMap Maps x-values into pixel coordinates.
373 \param yMap Maps y-values into pixel coordinates.
374 \param canvasRect Contents rectangle of the canvas
375 \param from Index of the first point to be painted
376 \param to Index of the last point to be painted. If to < 0 the
377 curve will be painted to its last point.
378
379 \sa drawSymbols()
380*/
381void QwtPlotTradingCurve::drawSeries( QPainter *painter,
382 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
383 const QRectF &canvasRect, int from, int to ) const
384{
385 if ( to < 0 )
386 to = dataSize() - 1;
387
388 if ( from < 0 )
389 from = 0;
390
391 if ( from > to )
392 return;
393
394 painter->save();
395
396 if ( d_data->symbolStyle != QwtPlotTradingCurve::NoSymbol )
397 drawSymbols( painter, xMap, yMap, canvasRect, from, to );
398
399 painter->restore();
400}
401
402/*!
403 Draw symbols
404
405 \param painter Painter
406 \param xMap x map
407 \param yMap y map
408 \param canvasRect Contents rectangle of the canvas
409 \param from Index of the first point to be painted
410 \param to Index of the last point to be painted
411
412 \sa drawSeries()
413*/
414void QwtPlotTradingCurve::drawSymbols( QPainter *painter,
415 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
416 const QRectF &canvasRect, int from, int to ) const
417{
418 const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
419
420 const QwtScaleMap *timeMap, *valueMap;
421 double tMin, tMax, vMin, vMax;
422
423 const Qt::Orientation orient = orientation();
424 if ( orient == Qt::Vertical )
425 {
426 timeMap = &xMap;
427 valueMap = &yMap;
428
429 tMin = tr.left();
430 tMax = tr.right();
431 vMin = tr.top();
432 vMax = tr.bottom();
433 }
434 else
435 {
436 timeMap = &yMap;
437 valueMap = &xMap;
438
439 vMin = tr.left();
440 vMax = tr.right();
441 tMin = tr.top();
442 tMax = tr.bottom();
443 }
444
445 const bool inverted = timeMap->isInverting();
446 const bool doClip = d_data->paintAttributes & ClipSymbols;
447 const bool doAlign = QwtPainter::roundingAlignment( painter );
448
449 double symbolWidth = scaledSymbolWidth( xMap, yMap, canvasRect );
450 if ( doAlign )
451 symbolWidth = qFloor( 0.5 * symbolWidth ) * 2.0;
452
453 QPen pen = d_data->symbolPen;
454 pen.setCapStyle( Qt::FlatCap );
455
456 painter->setPen( pen );
457
458 for ( int i = from; i <= to; i++ )
459 {
460 const QwtOHLCSample s = sample( i );
461
462 if ( !doClip || qwtIsSampleInside( s, tMin, tMax, vMin, vMax ) )
463 {
464 QwtOHLCSample translatedSample;
465
466 translatedSample.time = timeMap->transform( s.time );
467 translatedSample.open = valueMap->transform( s.open );
468 translatedSample.high = valueMap->transform( s.high );
469 translatedSample.low = valueMap->transform( s.low );
470 translatedSample.close = valueMap->transform( s.close );
471
472 const int brushIndex = ( s.open < s.close )
473 ? QwtPlotTradingCurve::Increasing
474 : QwtPlotTradingCurve::Decreasing;
475
476 if ( doAlign )
477 {
478 translatedSample.time = qRound( translatedSample.time );
479 translatedSample.open = qRound( translatedSample.open );
480 translatedSample.high = qRound( translatedSample.high );
481 translatedSample.low = qRound( translatedSample.low );
482 translatedSample.close = qRound( translatedSample.close );
483 }
484
485 switch( d_data->symbolStyle )
486 {
487 case Bar:
488 {
489 drawBar( painter, translatedSample,
490 orient, inverted, symbolWidth );
491 break;
492 }
493 case CandleStick:
494 {
495 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
496 drawCandleStick( painter, translatedSample,
497 orient, symbolWidth );
498 break;
499 }
500 default:
501 {
502 if ( d_data->symbolStyle >= UserSymbol )
503 {
504 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
505 drawUserSymbol( painter, d_data->symbolStyle,
506 translatedSample, orient, inverted, symbolWidth );
507 }
508 }
509 }
510 }
511 }
512}
513
514/*!
515 \brief Draw a symbol for a symbol style >= UserSymbol
516
517 The implementation does nothing and is intended to be overloaded
518
519 \param painter Qt painter, initialized with pen/brush
520 \param symbolStyle Symbol style
521 \param sample Samples already translated into paint device coordinates
522 \param orientation Vertical or horizontal
523 \param inverted True, when the opposite scale
524 ( Qt::Vertical: x, Qt::Horizontal: y ) is increasing
525 in the opposite direction as QPainter coordinates.
526 \param symbolWidth Width of the symbol in paint device coordinates
527*/
528void QwtPlotTradingCurve::drawUserSymbol( QPainter *painter,
529 SymbolStyle symbolStyle, const QwtOHLCSample &sample,
530 Qt::Orientation orientation, bool inverted, double symbolWidth ) const
531{
532 Q_UNUSED( painter )
533 Q_UNUSED( symbolStyle )
534 Q_UNUSED( orientation )
535 Q_UNUSED( inverted )
536 Q_UNUSED( symbolWidth )
537 Q_UNUSED( sample )
538}
539
540/*!
541 \brief Draw a bar
542
543 \param painter Qt painter, initialized with pen/brush
544 \param sample Sample, already translated into paint device coordinates
545 \param orientation Vertical or horizontal
546 \param inverted When inverted is false the open tick is painted
547 to the left/top, otherwise it is painted right/bottom.
548 The close tick is painted in the opposite direction
549 of the open tick.
550 painted in the opposite d
551 opposite direction.
552 \param width Width or height of the candle, depending on the orientation
553
554 \sa Bar
555*/
556void QwtPlotTradingCurve::drawBar( QPainter *painter,
557 const QwtOHLCSample &sample, Qt::Orientation orientation,
558 bool inverted, double width ) const
559{
560 double w2 = 0.5 * width;
561 if ( inverted )
562 w2 *= -1;
563
564 if ( orientation == Qt::Vertical )
565 {
566 QwtPainter::drawLine( painter,
567 sample.time, sample.low, sample.time, sample.high );
568
569 QwtPainter::drawLine( painter,
570 sample.time - w2, sample.open, sample.time, sample.open );
571 QwtPainter::drawLine( painter,
572 sample.time + w2, sample.close, sample.time, sample.close );
573 }
574 else
575 {
576 QwtPainter::drawLine( painter, sample.low, sample.time,
577 sample.high, sample.time );
578 QwtPainter::drawLine( painter,
579 sample.open, sample.time - w2, sample.open, sample.time );
580 QwtPainter::drawLine( painter,
581 sample.close, sample.time + w2, sample.close, sample.time );
582 }
583}
584
585/*!
586 \brief Draw a candle stick
587
588 \param painter Qt painter, initialized with pen/brush
589 \param sample Samples already translated into paint device coordinates
590 \param orientation Vertical or horizontal
591 \param width Width or height of the candle, depending on the orientation
592
593 \sa CandleStick
594*/
595void QwtPlotTradingCurve::drawCandleStick( QPainter *painter,
596 const QwtOHLCSample &sample, Qt::Orientation orientation,
597 double width ) const
598{
599 const double t = sample.time;
600 const double v1 = qMin( sample.low, sample.high );
601 const double v2 = qMin( sample.open, sample.close );
602 const double v3 = qMax( sample.low, sample.high );
603 const double v4 = qMax( sample.open, sample.close );
604
605 if ( orientation == Qt::Vertical )
606 {
607 QwtPainter::drawLine( painter, t, v1, t, v2 );
608 QwtPainter::drawLine( painter, t, v3, t, v4 );
609
610 QRectF rect( t - 0.5 * width, sample.open,
611 width, sample.close - sample.open );
612
613 QwtPainter::drawRect( painter, rect );
614 }
615 else
616 {
617 QwtPainter::drawLine( painter, v1, t, v2, t );
618 QwtPainter::drawLine( painter, v3, t, v4, t );
619
620 const QRectF rect( sample.open, t - 0.5 * width,
621 sample.close - sample.open, width );
622
623 QwtPainter::drawRect( painter, rect );
624 }
625}
626
627/*!
628 \return A rectangle filled with the color of the symbol pen
629
630 \param index Index of the legend entry
631 ( usually there is only one )
632 \param size Icon size
633
634 \sa setLegendIconSize(), legendData()
635*/
636QwtGraphic QwtPlotTradingCurve::legendIcon( int index,
637 const QSizeF &size ) const
638{
639 Q_UNUSED( index );
640 return defaultIcon( d_data->symbolPen.color(), size );
641}
642
643/*!
644 Calculate the symbol width in paint coordinates
645
646 The width is calculated by scaling the symbol extent into
647 paint device coordinates bounded by the minimum/maximum
648 symbol width.
649
650 \param xMap Maps x-values into pixel coordinates.
651 \param yMap Maps y-values into pixel coordinates.
652 \param canvasRect Contents rectangle of the canvas
653
654 \return Symbol width in paint coordinates
655
656 \sa symbolExtent(), minSymbolWidth(), maxSymbolWidth()
657*/
658double QwtPlotTradingCurve::scaledSymbolWidth(
659 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
660 const QRectF &canvasRect ) const
661{
662 Q_UNUSED( canvasRect );
663
664 if ( d_data->maxSymbolWidth > 0.0 &&
665 d_data->minSymbolWidth >= d_data->maxSymbolWidth )
666 {
667 return d_data->minSymbolWidth;
668 }
669
670 const QwtScaleMap *map =
671 ( orientation() == Qt::Vertical ) ? &xMap : &yMap;
672
673 const double pos = map->transform( map->s1() + d_data->symbolExtent );
674
675 double width = qAbs( pos - map->p1() );
676
677 width = qMax( width, d_data->minSymbolWidth );
678 if ( d_data->maxSymbolWidth > 0.0 )
679 width = qMin( width, d_data->maxSymbolWidth );
680
681 return width;
682}
Note: See TracBrowser for help on using the repository browser.