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 ( brush != d_data->symbolBrush[ direction ] )
00239 {
00240 d_data->symbolBrush[ direction ] = brush;
00241
00242 legendChanged();
00243 itemChanged();
00244 }
00245 }
00246
00254 QBrush QwtPlotTradingCurve::symbolBrush( Direction direction ) const
00255 {
00256 return d_data->symbolBrush[ direction ];
00257 }
00258
00272 void QwtPlotTradingCurve::setSymbolExtent( double extent )
00273 {
00274 extent = qMax( 0.0, extent );
00275 if ( extent != d_data->symbolExtent )
00276 {
00277 d_data->symbolExtent = extent;
00278
00279 legendChanged();
00280 itemChanged();
00281 }
00282 }
00283
00289 double QwtPlotTradingCurve::symbolExtent() const
00290 {
00291 return d_data->symbolExtent;
00292 }
00293
00300 void QwtPlotTradingCurve::setMinSymbolWidth( double width )
00301 {
00302 width = qMax( width, 0.0 );
00303 if ( width != d_data->minSymbolWidth )
00304 {
00305 d_data->minSymbolWidth = width;
00306
00307 legendChanged();
00308 itemChanged();
00309 }
00310 }
00311
00316 double QwtPlotTradingCurve::minSymbolWidth() const
00317 {
00318 return d_data->minSymbolWidth;
00319 }
00320
00329 void QwtPlotTradingCurve::setMaxSymbolWidth( double width )
00330 {
00331 if ( width != d_data->maxSymbolWidth )
00332 {
00333 d_data->maxSymbolWidth = width;
00334
00335 legendChanged();
00336 itemChanged();
00337 }
00338 }
00339
00344 double QwtPlotTradingCurve::maxSymbolWidth() const
00345 {
00346 return d_data->maxSymbolWidth;
00347 }
00348
00353 QRectF QwtPlotTradingCurve::boundingRect() const
00354 {
00355 QRectF rect = QwtPlotSeriesItem::boundingRect();
00356 if ( rect.isValid() && orientation() == Qt::Vertical )
00357 rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
00358
00359 return rect;
00360 }
00361
00375 void QwtPlotTradingCurve::drawSeries( QPainter *painter,
00376 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00377 const QRectF &canvasRect, int from, int to ) const
00378 {
00379 if ( to < 0 )
00380 to = dataSize() - 1;
00381
00382 if ( from < 0 )
00383 from = 0;
00384
00385 if ( from > to )
00386 return;
00387
00388 painter->save();
00389
00390 if ( d_data->symbolStyle != QwtPlotTradingCurve::NoSymbol )
00391 drawSymbols( painter, xMap, yMap, canvasRect, from, to );
00392
00393 painter->restore();
00394 }
00395
00408 void QwtPlotTradingCurve::drawSymbols( QPainter *painter,
00409 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00410 const QRectF &canvasRect, int from, int to ) const
00411 {
00412 const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
00413
00414 const QwtScaleMap *timeMap, *valueMap;
00415 double tMin, tMax, vMin, vMax;
00416
00417 const Qt::Orientation orient = orientation();
00418 if ( orient == Qt::Vertical )
00419 {
00420 timeMap = &xMap;
00421 valueMap = &yMap;
00422
00423 tMin = tr.left();
00424 tMax = tr.right();
00425 vMin = tr.top();
00426 vMax = tr.bottom();
00427 }
00428 else
00429 {
00430 timeMap = &yMap;
00431 valueMap = &xMap;
00432
00433 vMin = tr.left();
00434 vMax = tr.right();
00435 tMin = tr.top();
00436 tMax = tr.bottom();
00437 }
00438
00439 const bool inverted = timeMap->isInverting();
00440 const bool doClip = d_data->paintAttributes & ClipSymbols;
00441 const bool doAlign = QwtPainter::roundingAlignment( painter );
00442
00443 double symbolWidth = scaledSymbolWidth( xMap, yMap, canvasRect );
00444 if ( doAlign )
00445 symbolWidth = qFloor( 0.5 * symbolWidth ) * 2.0;
00446
00447 QPen pen = d_data->symbolPen;
00448 pen.setCapStyle( Qt::FlatCap );
00449
00450 painter->setPen( pen );
00451
00452 for ( int i = from; i <= to; i++ )
00453 {
00454 const QwtOHLCSample s = sample( i );
00455
00456 if ( !doClip || qwtIsSampleInside( s, tMin, tMax, vMin, vMax ) )
00457 {
00458 QwtOHLCSample translatedSample;
00459
00460 translatedSample.time = timeMap->transform( s.time );
00461 translatedSample.open = valueMap->transform( s.open );
00462 translatedSample.high = valueMap->transform( s.high );
00463 translatedSample.low = valueMap->transform( s.low );
00464 translatedSample.close = valueMap->transform( s.close );
00465
00466 const int brushIndex = ( s.open < s.close )
00467 ? QwtPlotTradingCurve::Increasing
00468 : QwtPlotTradingCurve::Decreasing;
00469
00470 if ( doAlign )
00471 {
00472 translatedSample.time = qRound( translatedSample.time );
00473 translatedSample.open = qRound( translatedSample.open );
00474 translatedSample.high = qRound( translatedSample.high );
00475 translatedSample.low = qRound( translatedSample.low );
00476 translatedSample.close = qRound( translatedSample.close );
00477 }
00478
00479 switch( d_data->symbolStyle )
00480 {
00481 case Bar:
00482 {
00483 drawBar( painter, translatedSample,
00484 orient, inverted, symbolWidth );
00485 break;
00486 }
00487 case CandleStick:
00488 {
00489 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
00490 drawCandleStick( painter, translatedSample,
00491 orient, symbolWidth );
00492 break;
00493 }
00494 default:
00495 {
00496 if ( d_data->symbolStyle >= UserSymbol )
00497 {
00498 painter->setBrush( d_data->symbolBrush[ brushIndex ] );
00499 drawUserSymbol( painter, d_data->symbolStyle,
00500 translatedSample, orient, inverted, symbolWidth );
00501 }
00502 }
00503 }
00504 }
00505 }
00506 }
00507
00522 void QwtPlotTradingCurve::drawUserSymbol( QPainter *painter,
00523 SymbolStyle symbolStyle, const QwtOHLCSample &sample,
00524 Qt::Orientation orientation, bool inverted, double symbolWidth ) const
00525 {
00526 Q_UNUSED( painter )
00527 Q_UNUSED( symbolStyle )
00528 Q_UNUSED( orientation )
00529 Q_UNUSED( inverted )
00530 Q_UNUSED( symbolWidth )
00531 Q_UNUSED( sample )
00532 }
00533
00550 void QwtPlotTradingCurve::drawBar( QPainter *painter,
00551 const QwtOHLCSample &sample, Qt::Orientation orientation,
00552 bool inverted, double width ) const
00553 {
00554 double w2 = 0.5 * width;
00555 if ( inverted )
00556 w2 *= -1;
00557
00558 if ( orientation == Qt::Vertical )
00559 {
00560 QwtPainter::drawLine( painter,
00561 sample.time, sample.low, sample.time, sample.high );
00562
00563 QwtPainter::drawLine( painter,
00564 sample.time - w2, sample.open, sample.time, sample.open );
00565 QwtPainter::drawLine( painter,
00566 sample.time + w2, sample.close, sample.time, sample.close );
00567 }
00568 else
00569 {
00570 QwtPainter::drawLine( painter, sample.low, sample.time,
00571 sample.high, sample.time );
00572 QwtPainter::drawLine( painter,
00573 sample.open, sample.time - w2, sample.open, sample.time );
00574 QwtPainter::drawLine( painter,
00575 sample.close, sample.time + w2, sample.close, sample.time );
00576 }
00577 }
00578
00589 void QwtPlotTradingCurve::drawCandleStick( QPainter *painter,
00590 const QwtOHLCSample &sample, Qt::Orientation orientation,
00591 double width ) const
00592 {
00593 const double t = sample.time;
00594 const double v1 = qMin( sample.low, sample.high );
00595 const double v2 = qMin( sample.open, sample.close );
00596 const double v3 = qMax( sample.low, sample.high );
00597 const double v4 = qMax( sample.open, sample.close );
00598
00599 if ( orientation == Qt::Vertical )
00600 {
00601 QwtPainter::drawLine( painter, t, v1, t, v2 );
00602 QwtPainter::drawLine( painter, t, v3, t, v4 );
00603
00604 QRectF rect( t - 0.5 * width, sample.open,
00605 width, sample.close - sample.open );
00606
00607 QwtPainter::drawRect( painter, rect );
00608 }
00609 else
00610 {
00611 QwtPainter::drawLine( painter, v1, t, v2, t );
00612 QwtPainter::drawLine( painter, v3, t, v4, t );
00613
00614 const QRectF rect( sample.open, t - 0.5 * width,
00615 sample.close - sample.open, width );
00616
00617 QwtPainter::drawRect( painter, rect );
00618 }
00619 }
00620
00630 QwtGraphic QwtPlotTradingCurve::legendIcon( int index,
00631 const QSizeF &size ) const
00632 {
00633 Q_UNUSED( index );
00634 return defaultIcon( d_data->symbolPen.color(), size );
00635 }
00636
00652 double QwtPlotTradingCurve::scaledSymbolWidth(
00653 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00654 const QRectF &canvasRect ) const
00655 {
00656 Q_UNUSED( canvasRect );
00657
00658 if ( d_data->maxSymbolWidth > 0.0 &&
00659 d_data->minSymbolWidth >= d_data->maxSymbolWidth )
00660 {
00661 return d_data->minSymbolWidth;
00662 }
00663
00664 const QwtScaleMap *map =
00665 ( orientation() == Qt::Vertical ) ? &xMap : &yMap;
00666
00667 const double pos = map->transform( map->s1() + d_data->symbolExtent );
00668
00669 double width = qAbs( pos - map->p1() );
00670
00671 width = qMax( width, d_data->minSymbolWidth );
00672 if ( d_data->maxSymbolWidth > 0.0 )
00673 width = qMin( width, d_data->maxSymbolWidth );
00674
00675 return width;
00676 }