00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_plot_tradingcurve.h"
00011 #include "qwt_scale_map.h"
00012 #include "qwt_clipper.h"
00013 #include "qwt_painter.h"
00014 #include <qpainter.h>
00015
00016 static inline bool qwtIsSampleInside( const QwtOHLCSample &sample,
00017 double tMin, double tMax, double vMin, double vMax )
00018 {
00019 const double t = sample.time;
00020 const QwtInterval interval = sample.boundingInterval();
00021
00022 const bool isOffScreen = ( t < tMin ) || ( t > tMax )
00023 || ( interval.maxValue() < vMin ) || ( interval.minValue() > vMax );
00024
00025 return !isOffScreen;
00026 }
00027
00028 class QwtPlotTradingCurve::PrivateData
00029 {
00030 public:
00031 PrivateData():
00032 symbolStyle( QwtPlotTradingCurve::CandleStick ),
00033 symbolExtent( 0.6 ),
00034 minSymbolWidth( 2.0 ),
00035 maxSymbolWidth( -1.0 ),
00036 paintAttributes( QwtPlotTradingCurve::ClipSymbols )
00037 {
00038 symbolBrush[0] = QBrush( Qt::white );
00039 symbolBrush[1] = QBrush( Qt::black );
00040 }
00041
00042 QwtPlotTradingCurve::SymbolStyle symbolStyle;
00043 double symbolExtent;
00044 double minSymbolWidth;
00045 double maxSymbolWidth;
00046
00047 QPen symbolPen;
00048 QBrush symbolBrush[2];
00049
00050 QwtPlotTradingCurve::PaintAttributes paintAttributes;
00051 };
00052
00057 QwtPlotTradingCurve::QwtPlotTradingCurve( const QwtText &title ):
00058 QwtPlotSeriesItem( title )
00059 {
00060 init();
00061 }
00062
00067 QwtPlotTradingCurve::QwtPlotTradingCurve( const QString &title ):
00068 QwtPlotSeriesItem( QwtText( title ) )
00069 {
00070 init();
00071 }
00072
00074 QwtPlotTradingCurve::~QwtPlotTradingCurve()
00075 {
00076 delete d_data;
00077 }
00078
00080 void QwtPlotTradingCurve::init()
00081 {
00082 setItemAttribute( QwtPlotItem::Legend, true );
00083 setItemAttribute( QwtPlotItem::AutoScale, true );
00084
00085 d_data = new PrivateData;
00086 setData( new QwtTradingChartData() );
00087
00088 setZ( 19.0 );
00089 }
00090
00092 int QwtPlotTradingCurve::rtti() const
00093 {
00094 return QwtPlotTradingCurve::Rtti_PlotTradingCurve;
00095 }
00096
00104 void QwtPlotTradingCurve::setPaintAttribute(
00105 PaintAttribute attribute, bool on )
00106 {
00107 if ( on )
00108 d_data->paintAttributes |= attribute;
00109 else
00110 d_data->paintAttributes &= ~attribute;
00111 }
00112
00117 bool QwtPlotTradingCurve::testPaintAttribute(
00118 PaintAttribute attribute ) const
00119 {
00120 return ( d_data->paintAttributes & attribute );
00121 }
00122
00129 void QwtPlotTradingCurve::setSamples(
00130 const QVector<QwtOHLCSample> &samples )
00131 {
00132 setData( new QwtTradingChartData( samples ) );
00133 }
00134
00145 void QwtPlotTradingCurve::setSamples(
00146 QwtSeriesData<QwtOHLCSample> *data )
00147 {
00148 setData( data );
00149 }
00150
00159 void QwtPlotTradingCurve::setSymbolStyle( SymbolStyle style )
00160 {
00161 if ( style != d_data->symbolStyle )
00162 {
00163 d_data->symbolStyle = style;
00164
00165 legendChanged();
00166 itemChanged();
00167 }
00168 }
00169
00174 QwtPlotTradingCurve::SymbolStyle QwtPlotTradingCurve::symbolStyle() const
00175 {
00176 return d_data->symbolStyle;
00177 }
00178
00192 void QwtPlotTradingCurve::setSymbolPen(
00193 const QColor &color, qreal width, Qt::PenStyle style )
00194 {
00195 setSymbolPen( QPen( color, width, style ) );
00196 }
00197
00206 void QwtPlotTradingCurve::setSymbolPen( const QPen &pen )
00207 {
00208 if ( pen != d_data->symbolPen )
00209 {
00210 d_data->symbolPen = pen;
00211
00212 legendChanged();
00213 itemChanged();
00214 }
00215 }
00216
00221 QPen QwtPlotTradingCurve::symbolPen() const
00222 {
00223 return d_data->symbolPen;
00224 }
00225
00235 void QwtPlotTradingCurve::setSymbolBrush(
00236 Direction direction, const QBrush &brush )
00237 {
00238 if ( direction < 0 || direction >= 2 )
00239 return;
00240
00241 if ( brush != d_data->symbolBrush[ direction ] )
00242 {
00243 d_data->symbolBrush[ direction ] = brush;
00244
00245 legendChanged();
00246 itemChanged();
00247 }
00248 }
00249
00257 QBrush QwtPlotTradingCurve::symbolBrush( Direction direction ) const
00258 {
00259 if ( direction < 0 || direction >= 2 )
00260 return QBrush();
00261
00262 return d_data->symbolBrush[ direction ];
00263 }
00264
00278 void QwtPlotTradingCurve::setSymbolExtent( double extent )
00279 {
00280 extent = qMax( 0.0, extent );
00281 if ( extent != d_data->symbolExtent )
00282 {
00283 d_data->symbolExtent = extent;
00284
00285 legendChanged();
00286 itemChanged();
00287 }
00288 }
00289
00295 double QwtPlotTradingCurve::symbolExtent() const
00296 {
00297 return d_data->symbolExtent;
00298 }
00299
00306 void QwtPlotTradingCurve::setMinSymbolWidth( double width )
00307 {
00308 width = qMax( width, 0.0 );
00309 if ( width != d_data->minSymbolWidth )
00310 {
00311 d_data->minSymbolWidth = width;
00312
00313 legendChanged();
00314 itemChanged();
00315 }
00316 }
00317
00322 double QwtPlotTradingCurve::minSymbolWidth() const
00323 {
00324 return d_data->minSymbolWidth;
00325 }
00326
00335 void QwtPlotTradingCurve::setMaxSymbolWidth( double width )
00336 {
00337 if ( width != d_data->maxSymbolWidth )
00338 {
00339 d_data->maxSymbolWidth = width;
00340
00341 legendChanged();
00342 itemChanged();
00343 }
00344 }
00345
00350 double QwtPlotTradingCurve::maxSymbolWidth() const
00351 {
00352 return d_data->maxSymbolWidth;
00353 }
00354
00359 QRectF QwtPlotTradingCurve::boundingRect() const
00360 {
00361 QRectF rect = QwtPlotSeriesItem::boundingRect();
00362 if ( rect.isValid() && orientation() == Qt::Vertical )
00363 rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
00364
00365 return rect;
00366 }
00367
00381 void QwtPlotTradingCurve::drawSeries( QPainter *painter,
00382 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00383 const QRectF &canvasRect, int from, int to ) const
00384 {
00385 if ( to < 0 )
00386 to = dataSize() - 1;
00387
00388 if ( from < 0 )
00389 from = 0;
00390
00391 if ( from > to )
00392 return;
00393
00394 painter->save();
00395
00396 if ( d_data->symbolStyle != QwtPlotTradingCurve::NoSymbol )
00397 drawSymbols( painter, xMap, yMap, canvasRect, from, to );
00398
00399 painter->restore();
00400 }
00401
00414 void QwtPlotTradingCurve::drawSymbols( QPainter *painter,
00415 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00416 const QRectF &canvasRect, int from, int to ) const
00417 {
00418 const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
00419
00420 const QwtScaleMap *timeMap, *valueMap;
00421 double tMin, tMax, vMin, vMax;
00422
00423 const Qt::Orientation orient = orientation();
00424 if ( orient == Qt::Vertical )
00425 {
00426 timeMap = &xMap;
00427 valueMap = &yMap;
00428
00429 tMin = tr.left();
00430 tMax = tr.right();
00431 vMin = tr.top();
00432 vMax = tr.bottom();
00433 }
00434 else
00435 {
00436 timeMap = &yMap;
00437 valueMap = &xMap;
00438
00439 vMin = tr.left();
00440 vMax = tr.right();
00441 tMin = tr.top();
00442 tMax = tr.bottom();
00443 }
00444
00445 const bool inverted = timeMap->isInverting();
00446 const bool doClip = d_data->paintAttributes & ClipSymbols;
00447 const bool doAlign = QwtPainter::roundingAlignment( painter );
00448
00449 double symbolWidth = scaledSymbolWidth( xMap, yMap, canvasRect );
00450 if ( doAlign )
00451 symbolWidth = qFloor( 0.5 * symbolWidth ) * 2.0;
00452
00453 QPen pen = d_data->symbolPen;
00454 pen.setCapStyle( Qt::FlatCap );
00455
00456 painter->setPen( pen );
00457
00458 for ( int i = from; i <= to; i++ )
00459 {
00460 const QwtOHLCSample s = sample( i );
00461
00462 if ( !doClip || qwtIsSampleInside( s, tMin, tMax, vMin, vMax ) )
00463 {
00464 QwtOHLCSample translatedSample;
00465
00466 translatedSample.time = timeMap->transform( s.time );
00467 translatedSample.open = valueMap->transform( s.open );
00468 translatedSample.high = valueMap->transform( s.high );
00469 translatedSample.low = valueMap->transform( s.low );
00470 translatedSample.close = valueMap->transform( s.close );
00471
00472 const int brushIndex = ( s.open < s.close )
00473 ? QwtPlotTradingCurve::Increasing
00474 : QwtPlotTradingCurve::Decreasing;
00475
00476 if ( doAlign )
00477 {
00478 translatedSample.time = qRound( translatedSample.time );
00479 translatedSample.open = qRound( translatedSample.open );
00480 translatedSample.high = qRound( translatedSample.high );
00481 translatedSample.low = qRound( translatedSample.low );
00482 translatedSample.close = qRound( translatedSample.close );
00483 }
00484
00485 switch( d_data->symbolStyle )
00486 {
00487 case Bar:
00488 {
00489 drawBar( painter, translatedSample,
00490 orient, inverted, symbolWidth );
00491 break;
00492 }
00493 case CandleStick:
00494 {
00495 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
00496 drawCandleStick( painter, translatedSample,
00497 orient, symbolWidth );
00498 break;
00499 }
00500 default:
00501 {
00502 if ( d_data->symbolStyle >= UserSymbol )
00503 {
00504 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
00505 drawUserSymbol( painter, d_data->symbolStyle,
00506 translatedSample, orient, inverted, symbolWidth );
00507 }
00508 }
00509 }
00510 }
00511 }
00512 }
00513
00528 void QwtPlotTradingCurve::drawUserSymbol( QPainter *painter,
00529 SymbolStyle symbolStyle, const QwtOHLCSample &sample,
00530 Qt::Orientation orientation, bool inverted, double symbolWidth ) const
00531 {
00532 Q_UNUSED( painter )
00533 Q_UNUSED( symbolStyle )
00534 Q_UNUSED( orientation )
00535 Q_UNUSED( inverted )
00536 Q_UNUSED( symbolWidth )
00537 Q_UNUSED( sample )
00538 }
00539
00556 void QwtPlotTradingCurve::drawBar( QPainter *painter,
00557 const QwtOHLCSample &sample, Qt::Orientation orientation,
00558 bool inverted, double width ) const
00559 {
00560 double w2 = 0.5 * width;
00561 if ( inverted )
00562 w2 *= -1;
00563
00564 if ( orientation == Qt::Vertical )
00565 {
00566 QwtPainter::drawLine( painter,
00567 sample.time, sample.low, sample.time, sample.high );
00568
00569 QwtPainter::drawLine( painter,
00570 sample.time - w2, sample.open, sample.time, sample.open );
00571 QwtPainter::drawLine( painter,
00572 sample.time + w2, sample.close, sample.time, sample.close );
00573 }
00574 else
00575 {
00576 QwtPainter::drawLine( painter, sample.low, sample.time,
00577 sample.high, sample.time );
00578 QwtPainter::drawLine( painter,
00579 sample.open, sample.time - w2, sample.open, sample.time );
00580 QwtPainter::drawLine( painter,
00581 sample.close, sample.time + w2, sample.close, sample.time );
00582 }
00583 }
00584
00595 void QwtPlotTradingCurve::drawCandleStick( QPainter *painter,
00596 const QwtOHLCSample &sample, Qt::Orientation orientation,
00597 double width ) const
00598 {
00599 const double t = sample.time;
00600 const double v1 = qMin( sample.low, sample.high );
00601 const double v2 = qMin( sample.open, sample.close );
00602 const double v3 = qMax( sample.low, sample.high );
00603 const double v4 = qMax( sample.open, sample.close );
00604
00605 if ( orientation == Qt::Vertical )
00606 {
00607 QwtPainter::drawLine( painter, t, v1, t, v2 );
00608 QwtPainter::drawLine( painter, t, v3, t, v4 );
00609
00610 QRectF rect( t - 0.5 * width, sample.open,
00611 width, sample.close - sample.open );
00612
00613 QwtPainter::drawRect( painter, rect );
00614 }
00615 else
00616 {
00617 QwtPainter::drawLine( painter, v1, t, v2, t );
00618 QwtPainter::drawLine( painter, v3, t, v4, t );
00619
00620 const QRectF rect( sample.open, t - 0.5 * width,
00621 sample.close - sample.open, width );
00622
00623 QwtPainter::drawRect( painter, rect );
00624 }
00625 }
00626
00636 QwtGraphic QwtPlotTradingCurve::legendIcon( int index,
00637 const QSizeF &size ) const
00638 {
00639 Q_UNUSED( index );
00640 return defaultIcon( d_data->symbolPen.color(), size );
00641 }
00642
00658 double QwtPlotTradingCurve::scaledSymbolWidth(
00659 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00660 const QRectF &canvasRect ) const
00661 {
00662 Q_UNUSED( canvasRect );
00663
00664 if ( d_data->maxSymbolWidth > 0.0 &&
00665 d_data->minSymbolWidth >= d_data->maxSymbolWidth )
00666 {
00667 return d_data->minSymbolWidth;
00668 }
00669
00670 const QwtScaleMap *map =
00671 ( orientation() == Qt::Vertical ) ? &xMap : &yMap;
00672
00673 const double pos = map->transform( map->s1() + d_data->symbolExtent );
00674
00675 double width = qAbs( pos - map->p1() );
00676
00677 width = qMax( width, d_data->minSymbolWidth );
00678 if ( d_data->maxSymbolWidth > 0.0 )
00679 width = qMin( width, d_data->maxSymbolWidth );
00680
00681 return width;
00682 }