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

Last change on this file since 9573 was 9383, checked in by stoecker, 3 years ago

update to qwt verion 6.1.1 to fix build with newer Qt5

File size: 18.0 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 // silencing -Wtautological-constant-out-of-range-compare
239 const int index = static_cast< int >( direction );
240 if ( index < 0 || index >= 2 )
241 return;
242
243 if ( brush != d_data->symbolBrush[ index ] )
244 {
245 d_data->symbolBrush[ index ] = brush;
246
247 legendChanged();
248 itemChanged();
249 }
250}
251
252/*!
253 \param direction
254 \return Brush used to fill the body of all candlestick
255 symbols with the direction
256
257 \sa setSymbolPen(), symbolBrush()
258*/
259QBrush QwtPlotTradingCurve::symbolBrush( Direction direction ) const
260{
261 const int index = static_cast< int >( direction );
262 if ( index < 0 || index >= 2 )
263 return QBrush();
264
265 return d_data->symbolBrush[ index ];
266}
267
268/*!
269 \brief Set the extent of the symbol
270
271 The width of the symbol is given in scale coordinates. When painting
272 a symbol the width is scaled into paint device coordinates
273 by scaledSymbolWidth(). The scaled width is bounded by
274 minSymbolWidth(), maxSymbolWidth()
275
276 \param extent Symbol width in scale coordinates
277
278 \sa symbolExtent(), scaledSymbolWidth(),
279 setMinSymbolWidth(), setMaxSymbolWidth()
280*/
281void QwtPlotTradingCurve::setSymbolExtent( double extent )
282{
283 extent = qMax( 0.0, extent );
284 if ( extent != d_data->symbolExtent )
285 {
286 d_data->symbolExtent = extent;
287
288 legendChanged();
289 itemChanged();
290 }
291}
292
293/*!
294 \return Extent of a symbol in scale coordinates
295 \sa setSymbolExtent(), scaledSymbolWidth(),
296 minSymbolWidth(), maxSymbolWidth()
297*/
298double QwtPlotTradingCurve::symbolExtent() const
299{
300 return d_data->symbolExtent;
301}
302
303/*!
304 Set a minimum for the symbol width
305
306 \param width Width in paint device coordinates
307 \sa minSymbolWidth(), setMaxSymbolWidth(), setSymbolExtent()
308 */
309void QwtPlotTradingCurve::setMinSymbolWidth( double width )
310{
311 width = qMax( width, 0.0 );
312 if ( width != d_data->minSymbolWidth )
313 {
314 d_data->minSymbolWidth = width;
315
316 legendChanged();
317 itemChanged();
318 }
319}
320
321/*!
322 \return Minmum for the symbol width
323 \sa setMinSymbolWidth(), maxSymbolWidth(), symbolExtent()
324 */
325double QwtPlotTradingCurve::minSymbolWidth() const
326{
327 return d_data->minSymbolWidth;
328}
329
330/*!
331 Set a maximum for the symbol width
332
333 A value <= 0.0 means an unlimited width
334
335 \param width Width in paint device coordinates
336 \sa maxSymbolWidth(), setMinSymbolWidth(), setSymbolExtent()
337 */
338void QwtPlotTradingCurve::setMaxSymbolWidth( double width )
339{
340 if ( width != d_data->maxSymbolWidth )
341 {
342 d_data->maxSymbolWidth = width;
343
344 legendChanged();
345 itemChanged();
346 }
347}
348
349/*!
350 \return Maximum for the symbol width
351 \sa setMaxSymbolWidth(), minSymbolWidth(), symbolExtent()
352 */
353double QwtPlotTradingCurve::maxSymbolWidth() const
354{
355 return d_data->maxSymbolWidth;
356}
357
358/*!
359 \return Bounding rectangle of all samples.
360 For an empty series the rectangle is invalid.
361*/
362QRectF QwtPlotTradingCurve::boundingRect() const
363{
364 QRectF rect = QwtPlotSeriesItem::boundingRect();
365 if ( orientation() == Qt::Vertical )
366 rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
367
368 return rect;
369}
370
371/*!
372 Draw an interval of the curve
373
374 \param painter Painter
375 \param xMap Maps x-values into pixel coordinates.
376 \param yMap Maps y-values into pixel coordinates.
377 \param canvasRect Contents rectangle of the canvas
378 \param from Index of the first point to be painted
379 \param to Index of the last point to be painted. If to < 0 the
380 curve will be painted to its last point.
381
382 \sa drawSymbols()
383*/
384void QwtPlotTradingCurve::drawSeries( QPainter *painter,
385 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
386 const QRectF &canvasRect, int from, int to ) const
387{
388 if ( to < 0 )
389 to = dataSize() - 1;
390
391 if ( from < 0 )
392 from = 0;
393
394 if ( from > to )
395 return;
396
397 painter->save();
398
399 if ( d_data->symbolStyle != QwtPlotTradingCurve::NoSymbol )
400 drawSymbols( painter, xMap, yMap, canvasRect, from, to );
401
402 painter->restore();
403}
404
405/*!
406 Draw symbols
407
408 \param painter Painter
409 \param xMap x map
410 \param yMap y map
411 \param canvasRect Contents rectangle of the canvas
412 \param from Index of the first point to be painted
413 \param to Index of the last point to be painted
414
415 \sa drawSeries()
416*/
417void QwtPlotTradingCurve::drawSymbols( QPainter *painter,
418 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
419 const QRectF &canvasRect, int from, int to ) const
420{
421 const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
422
423 const QwtScaleMap *timeMap, *valueMap;
424 double tMin, tMax, vMin, vMax;
425
426 const Qt::Orientation orient = orientation();
427 if ( orient == Qt::Vertical )
428 {
429 timeMap = &xMap;
430 valueMap = &yMap;
431
432 tMin = tr.left();
433 tMax = tr.right();
434 vMin = tr.top();
435 vMax = tr.bottom();
436 }
437 else
438 {
439 timeMap = &yMap;
440 valueMap = &xMap;
441
442 vMin = tr.left();
443 vMax = tr.right();
444 tMin = tr.top();
445 tMax = tr.bottom();
446 }
447
448 const bool inverted = timeMap->isInverting();
449 const bool doClip = d_data->paintAttributes & ClipSymbols;
450 const bool doAlign = QwtPainter::roundingAlignment( painter );
451
452 double symbolWidth = scaledSymbolWidth( xMap, yMap, canvasRect );
453 if ( doAlign )
454 symbolWidth = qFloor( 0.5 * symbolWidth ) * 2.0;
455
456 QPen pen = d_data->symbolPen;
457 pen.setCapStyle( Qt::FlatCap );
458
459 painter->setPen( pen );
460
461 for ( int i = from; i <= to; i++ )
462 {
463 const QwtOHLCSample s = sample( i );
464
465 if ( !doClip || qwtIsSampleInside( s, tMin, tMax, vMin, vMax ) )
466 {
467 QwtOHLCSample translatedSample;
468
469 translatedSample.time = timeMap->transform( s.time );
470 translatedSample.open = valueMap->transform( s.open );
471 translatedSample.high = valueMap->transform( s.high );
472 translatedSample.low = valueMap->transform( s.low );
473 translatedSample.close = valueMap->transform( s.close );
474
475 const int brushIndex = ( s.open < s.close )
476 ? QwtPlotTradingCurve::Increasing
477 : QwtPlotTradingCurve::Decreasing;
478
479 if ( doAlign )
480 {
481 translatedSample.time = qRound( translatedSample.time );
482 translatedSample.open = qRound( translatedSample.open );
483 translatedSample.high = qRound( translatedSample.high );
484 translatedSample.low = qRound( translatedSample.low );
485 translatedSample.close = qRound( translatedSample.close );
486 }
487
488 switch( d_data->symbolStyle )
489 {
490 case Bar:
491 {
492 drawBar( painter, translatedSample,
493 orient, inverted, symbolWidth );
494 break;
495 }
496 case CandleStick:
497 {
498 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
499 drawCandleStick( painter, translatedSample,
500 orient, symbolWidth );
501 break;
502 }
503 default:
504 {
505 if ( d_data->symbolStyle >= UserSymbol )
506 {
507 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
508 drawUserSymbol( painter, d_data->symbolStyle,
509 translatedSample, orient, inverted, symbolWidth );
510 }
511 }
512 }
513 }
514 }
515}
516
517/*!
518 \brief Draw a symbol for a symbol style >= UserSymbol
519
520 The implementation does nothing and is intended to be overloaded
521
522 \param painter Qt painter, initialized with pen/brush
523 \param symbolStyle Symbol style
524 \param sample Samples already translated into paint device coordinates
525 \param orientation Vertical or horizontal
526 \param inverted True, when the opposite scale
527 ( Qt::Vertical: x, Qt::Horizontal: y ) is increasing
528 in the opposite direction as QPainter coordinates.
529 \param symbolWidth Width of the symbol in paint device coordinates
530*/
531void QwtPlotTradingCurve::drawUserSymbol( QPainter *painter,
532 SymbolStyle symbolStyle, const QwtOHLCSample &sample,
533 Qt::Orientation orientation, bool inverted, double symbolWidth ) const
534{
535 Q_UNUSED( painter )
536 Q_UNUSED( symbolStyle )
537 Q_UNUSED( orientation )
538 Q_UNUSED( inverted )
539 Q_UNUSED( symbolWidth )
540 Q_UNUSED( sample )
541}
542
543/*!
544 \brief Draw a bar
545
546 \param painter Qt painter, initialized with pen/brush
547 \param sample Sample, already translated into paint device coordinates
548 \param orientation Vertical or horizontal
549 \param inverted When inverted is false the open tick is painted
550 to the left/top, otherwise it is painted right/bottom.
551 The close tick is painted in the opposite direction
552 of the open tick.
553 painted in the opposite d
554 opposite direction.
555 \param width Width or height of the candle, depending on the orientation
556
557 \sa Bar
558*/
559void QwtPlotTradingCurve::drawBar( QPainter *painter,
560 const QwtOHLCSample &sample, Qt::Orientation orientation,
561 bool inverted, double width ) const
562{
563 double w2 = 0.5 * width;
564 if ( inverted )
565 w2 *= -1;
566
567 if ( orientation == Qt::Vertical )
568 {
569 QwtPainter::drawLine( painter,
570 sample.time, sample.low, sample.time, sample.high );
571
572 QwtPainter::drawLine( painter,
573 sample.time - w2, sample.open, sample.time, sample.open );
574 QwtPainter::drawLine( painter,
575 sample.time + w2, sample.close, sample.time, sample.close );
576 }
577 else
578 {
579 QwtPainter::drawLine( painter, sample.low, sample.time,
580 sample.high, sample.time );
581 QwtPainter::drawLine( painter,
582 sample.open, sample.time - w2, sample.open, sample.time );
583 QwtPainter::drawLine( painter,
584 sample.close, sample.time + w2, sample.close, sample.time );
585 }
586}
587
588/*!
589 \brief Draw a candle stick
590
591 \param painter Qt painter, initialized with pen/brush
592 \param sample Samples already translated into paint device coordinates
593 \param orientation Vertical or horizontal
594 \param width Width or height of the candle, depending on the orientation
595
596 \sa CandleStick
597*/
598void QwtPlotTradingCurve::drawCandleStick( QPainter *painter,
599 const QwtOHLCSample &sample, Qt::Orientation orientation,
600 double width ) const
601{
602 const double t = sample.time;
603 const double v1 = qMin( sample.low, sample.high );
604 const double v2 = qMin( sample.open, sample.close );
605 const double v3 = qMax( sample.low, sample.high );
606 const double v4 = qMax( sample.open, sample.close );
607
608 if ( orientation == Qt::Vertical )
609 {
610 QwtPainter::drawLine( painter, t, v1, t, v2 );
611 QwtPainter::drawLine( painter, t, v3, t, v4 );
612
613 QRectF rect( t - 0.5 * width, sample.open,
614 width, sample.close - sample.open );
615
616 QwtPainter::drawRect( painter, rect );
617 }
618 else
619 {
620 QwtPainter::drawLine( painter, v1, t, v2, t );
621 QwtPainter::drawLine( painter, v3, t, v4, t );
622
623 const QRectF rect( sample.open, t - 0.5 * width,
624 sample.close - sample.open, width );
625
626 QwtPainter::drawRect( painter, rect );
627 }
628}
629
630/*!
631 \return A rectangle filled with the color of the symbol pen
632
633 \param index Index of the legend entry
634 ( usually there is only one )
635 \param size Icon size
636
637 \sa setLegendIconSize(), legendData()
638*/
639QwtGraphic QwtPlotTradingCurve::legendIcon( int index,
640 const QSizeF &size ) const
641{
642 Q_UNUSED( index );
643 return defaultIcon( d_data->symbolPen.color(), size );
644}
645
646/*!
647 Calculate the symbol width in paint coordinates
648
649 The width is calculated by scaling the symbol extent into
650 paint device coordinates bounded by the minimum/maximum
651 symbol width.
652
653 \param xMap Maps x-values into pixel coordinates.
654 \param yMap Maps y-values into pixel coordinates.
655 \param canvasRect Contents rectangle of the canvas
656
657 \return Symbol width in paint coordinates
658
659 \sa symbolExtent(), minSymbolWidth(), maxSymbolWidth()
660*/
661double QwtPlotTradingCurve::scaledSymbolWidth(
662 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
663 const QRectF &canvasRect ) const
664{
665 Q_UNUSED( canvasRect );
666
667 if ( d_data->maxSymbolWidth > 0.0 &&
668 d_data->minSymbolWidth >= d_data->maxSymbolWidth )
669 {
670 return d_data->minSymbolWidth;
671 }
672
673 const QwtScaleMap *map =
674 ( orientation() == Qt::Vertical ) ? &xMap : &yMap;
675
676 const double pos = map->transform( map->s1() + d_data->symbolExtent );
677
678 double width = qAbs( pos - map->p1() );
679
680 width = qMax( width, d_data->minSymbolWidth );
681 if ( d_data->maxSymbolWidth > 0.0 )
682 width = qMin( width, d_data->maxSymbolWidth );
683
684 return width;
685}
Note: See TracBrowser for help on using the repository browser.