00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qwindowdefs.h>
00013 #include <qwidget.h>
00014 #include <qrect.h>
00015 #include <qpainter.h>
00016 #include <qpalette.h>
00017 #include <qpaintdevice.h>
00018 #include <qpixmap.h>
00019 #include <qstyle.h>
00020 #if QT_VERSION < 0x040000
00021 #include <qsimplerichtext.h>
00022 #else
00023 #include <qtextdocument.h>
00024 #include <qabstracttextdocumentlayout.h>
00025 #include <qstyleoption.h>
00026 #include <qpaintengine.h>
00027 #endif
00028
00029 #include "qwt_rect.h"
00030 #include "qwt_math.h"
00031 #include "qwt_color_map.h"
00032 #include "qwt_scale_map.h"
00033 #include "qwt_painter.h"
00034
00035 QwtMetricsMap QwtPainter::d_metricsMap;
00036
00037 #if defined(Q_WS_X11)
00038 bool QwtPainter::d_deviceClipping = true;
00039 #else
00040 bool QwtPainter::d_deviceClipping = false;
00041 #endif
00042
00043 #if QT_VERSION < 0x040000
00044 bool QwtPainter::d_SVGMode = false;
00045 #endif
00046
00047 static inline bool needDeviceClipping(
00048 const QPainter *painter, bool deviceClipping)
00049 {
00050 return deviceClipping &&
00051 (painter->device()->devType() == QInternal::Widget ||
00052 painter->device()->devType() == QInternal::Pixmap );
00053 }
00054
00062 void QwtPainter::setDeviceClipping(bool enable)
00063 {
00064 d_deviceClipping = enable;
00065 }
00066
00073 bool QwtPainter::deviceClipping()
00074 {
00075 return d_deviceClipping;
00076 }
00077
00082 const QRect &QwtPainter::deviceClipRect()
00083 {
00084 static QRect clip;
00085
00086 if ( !clip.isValid() )
00087 {
00088 clip.setCoords(QWT_COORD_MIN, QWT_COORD_MIN,
00089 QWT_COORD_MAX, QWT_COORD_MAX);
00090 }
00091 return clip;
00092 }
00093
00095 QwtPolygon QwtPainter::clip(const QwtPolygon &pa)
00096 {
00097 const QwtRect rect(deviceClipRect());
00098 return rect.clip(pa);
00099 }
00100
00101 #if QT_VERSION < 0x040000
00102
00114 void QwtPainter::setSVGMode(bool on)
00115 {
00116 d_SVGMode = on;
00117 }
00118
00119 bool QwtPainter::isSVGMode()
00120 {
00121 return d_SVGMode;
00122 }
00123
00124 #endif // QT_VERSION < 0x040000
00125
00134 void QwtPainter::setMetricsMap(const QPaintDevice *layout,
00135 const QPaintDevice *device)
00136 {
00137 d_metricsMap.setMetrics(layout, device);
00138 }
00139
00144 void QwtPainter::setMetricsMap(const QwtMetricsMap &map)
00145 {
00146 d_metricsMap = map;
00147 }
00148
00153 void QwtPainter::resetMetricsMap()
00154 {
00155 d_metricsMap = QwtMetricsMap();
00156 }
00157
00161 const QwtMetricsMap &QwtPainter::metricsMap()
00162 {
00163 return d_metricsMap;
00164 }
00165
00169 void QwtPainter::setClipRect(QPainter *painter, const QRect &rect)
00170 {
00171 painter->setClipRect(d_metricsMap.layoutToDevice(rect, painter));
00172 }
00173
00177 void QwtPainter::drawRect(QPainter *painter, int x, int y, int w, int h)
00178 {
00179 drawRect(painter, QRect(x, y, w, h));
00180 }
00181
00185 void QwtPainter::drawRect(QPainter *painter, const QRect &rect)
00186 {
00187 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00188
00189 QRect clipRect;
00190
00191 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00192 if ( deviceClipping )
00193 clipRect = deviceClipRect();
00194
00195 if ( clipRect.isValid() )
00196 {
00197 if ( !clipRect.intersects(r) )
00198 return;
00199
00200 if ( !clipRect.contains(r) )
00201 {
00202 fillRect(painter, r & clipRect, painter->brush());
00203
00204 int pw = painter->pen().width();
00205 pw = pw % 2 + pw / 2;
00206
00207 QwtPolygon pa(5);
00208 pa.setPoint(0, r.left(), r.top());
00209 pa.setPoint(1, r.right() - pw, r.top());
00210 pa.setPoint(2, r.right() - pw, r.bottom() - pw);
00211 pa.setPoint(3, r.left(), r.bottom() - pw);
00212 pa.setPoint(4, r.left(), r.top());
00213
00214 painter->save();
00215 painter->setBrush(Qt::NoBrush);
00216 drawPolyline(painter, pa);
00217 painter->restore();
00218
00219 return;
00220 }
00221 }
00222
00223 #if QT_VERSION >= 0x040000
00224 if ( painter->pen().style() != Qt::NoPen &&
00225 painter->pen().color().isValid() )
00226 {
00227
00228 int pw = painter->pen().width();
00229 if ( pw == 0 )
00230 pw = 1;
00231
00232 r.setWidth(r.width() - pw);
00233 r.setHeight(r.height() - pw);
00234 }
00235 #endif
00236 painter->drawRect(r);
00237 }
00238
00242 void QwtPainter::fillRect(QPainter *painter,
00243 const QRect &rect, const QBrush &brush)
00244 {
00245 if ( !rect.isValid() )
00246 return;
00247
00248 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00249
00250 QRect clipRect;
00251 #if QT_VERSION >= 0x040000
00252
00253
00254
00255
00256
00257
00258
00259 clipRect = painter->window();
00260 if ( painter->hasClipping() )
00261 clipRect &= painter->clipRegion().boundingRect();
00262 if ( deviceClipping )
00263 clipRect &= deviceClipRect();
00264 #else
00265 if ( deviceClipping )
00266 clipRect = deviceClipRect();
00267 #endif
00268
00269 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00270 if ( clipRect.isValid() )
00271 r = r.intersect(clipRect);
00272
00273 if ( r.isValid() )
00274 painter->fillRect(r, brush);
00275 }
00276
00280 void QwtPainter::drawPie(QPainter *painter, const QRect &rect,
00281 int a, int alen)
00282 {
00283 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00284
00285 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00286 if ( deviceClipping && !deviceClipRect().contains(rect) )
00287 return;
00288
00289 painter->drawPie(r, a, alen);
00290 }
00291
00295 void QwtPainter::drawEllipse(QPainter *painter, const QRect &rect)
00296 {
00297 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00298
00299 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00300
00301 if ( deviceClipping && !deviceClipRect().contains(rect) )
00302 return;
00303
00304 #if QT_VERSION >= 0x040000
00305 if ( painter->pen().style() != Qt::NoPen &&
00306 painter->pen().color().isValid() )
00307 {
00308
00309 int pw = painter->pen().width();
00310 if ( pw == 0 )
00311 pw = 1;
00312
00313 r.setWidth(r.width() - pw);
00314 r.setHeight(r.height() - pw);
00315 }
00316 #endif
00317
00318 painter->drawEllipse(r);
00319 }
00320
00324 void QwtPainter::drawText(QPainter *painter, int x, int y,
00325 const QString &text)
00326 {
00327 drawText(painter, QPoint(x, y), text);
00328 }
00329
00333 void QwtPainter::drawText(QPainter *painter, const QPoint &pos,
00334 const QString &text)
00335 {
00336 const QPoint p = d_metricsMap.layoutToDevice(pos, painter);
00337
00338 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00339
00340 if ( deviceClipping && !deviceClipRect().contains(p) )
00341 return;
00342
00343 painter->drawText(p, text);
00344 }
00345
00349 void QwtPainter::drawText(QPainter *painter, int x, int y, int w, int h,
00350 int flags, const QString &text)
00351 {
00352 drawText(painter, QRect(x, y, w, h), flags, text);
00353 }
00354
00358 void QwtPainter::drawText(QPainter *painter, const QRect &rect,
00359 int flags, const QString &text)
00360 {
00361 QRect textRect = d_metricsMap.layoutToDevice(rect, painter);
00362 #if QT_VERSION < 0x040000
00363 if ( d_SVGMode &&
00364 ( flags == 0 || flags & Qt::AlignVCenter )
00365 && painter->device()->devType() & QInternal::Picture )
00366 {
00367
00368
00369
00370
00371 textRect.setY(textRect.y() - painter->fontMetrics().height() / 4);
00372 }
00373 #endif
00374 painter->drawText(textRect, flags, text);
00375 }
00376
00377 #ifndef QT_NO_RICHTEXT
00378
00382 #if QT_VERSION < 0x040000
00383
00384 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00385 int flags, QSimpleRichText &text)
00386 {
00387 QColorGroup cg;
00388 cg.setColor(QColorGroup::Text, painter->pen().color());
00389
00390 const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00391
00392 text.setWidth(painter, scaledRect.width());
00393
00394
00395
00396 int y = scaledRect.y();
00397 if (flags & Qt::AlignBottom)
00398 y += (scaledRect.height() - text.height());
00399 else if (flags & Qt::AlignVCenter)
00400 y += (scaledRect.height() - text.height())/2;
00401
00402 text.draw(painter, scaledRect.x(), y, scaledRect, cg);
00403 }
00404 #else
00405 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00406 int flags, QTextDocument &text)
00407 {
00408 const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00409 text.setPageSize(QSize(scaledRect.width(), QWIDGETSIZE_MAX));
00410
00411 QAbstractTextDocumentLayout* layout = text.documentLayout();
00412
00413 const int height = qRound(layout->documentSize().height());
00414 int y = scaledRect.y();
00415 if (flags & Qt::AlignBottom)
00416 y += (scaledRect.height() - height);
00417 else if (flags & Qt::AlignVCenter)
00418 y += (scaledRect.height() - height)/2;
00419
00420 QAbstractTextDocumentLayout::PaintContext context;
00421 context.palette.setColor(QPalette::Text, painter->pen().color());
00422
00423 painter->save();
00424
00425 painter->translate(scaledRect.x(), y);
00426 layout->draw(painter, context);
00427
00428 painter->restore();
00429 }
00430 #endif
00431
00432 #endif // !QT_NO_RICHTEXT
00433
00434
00438 void QwtPainter::drawLine(QPainter *painter, int x1, int y1, int x2, int y2)
00439 {
00440 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00441
00442 if ( deviceClipping &&
00443 !(deviceClipRect().contains(x1, y1) && deviceClipRect().contains(x2, y2)) )
00444 {
00445 QwtPolygon pa(2);
00446 pa.setPoint(0, x1, y1);
00447 pa.setPoint(1, x2, y2);
00448 drawPolyline(painter, pa);
00449 return;
00450 }
00451
00452 if ( d_metricsMap.isIdentity() )
00453 {
00454 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00455 if ( !painter->device()->isExtDev() )
00456 #endif
00457 {
00458 painter->drawLine(x1, y1, x2, y2);
00459 return;
00460 }
00461 }
00462
00463 const QPoint p1 = d_metricsMap.layoutToDevice(QPoint(x1, y1));
00464 const QPoint p2 = d_metricsMap.layoutToDevice(QPoint(x2, y2));
00465
00466 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00467 if ( painter->device()->isExtDev() )
00468 {
00469
00470
00471
00472
00473 QwtPolygon pa(2);
00474 pa.setPoint(0, p1);
00475 pa.setPoint(1, p2);
00476 painter->drawLineSegments(pa);
00477 }
00478 else
00479 painter->drawLine(p1, p2);
00480 #else
00481 painter->drawLine(p1, p2);
00482 #endif
00483 }
00484
00488 void QwtPainter::drawPolygon(QPainter *painter, const QwtPolygon &pa)
00489 {
00490 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00491
00492 QwtPolygon cpa = d_metricsMap.layoutToDevice(pa);
00493 if ( deviceClipping )
00494 {
00495 #ifdef __GNUC__
00496 #endif
00497 cpa = clip(cpa);
00498 }
00499 painter->drawPolygon(cpa);
00500 }
00501
00505 void QwtPainter::drawPolyline(QPainter *painter, const QwtPolygon &pa)
00506 {
00507 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00508
00509 QwtPolygon cpa = d_metricsMap.layoutToDevice(pa);
00510 if ( deviceClipping )
00511 cpa = clip(cpa);
00512
00513 #if QT_VERSION >= 0x040000
00514 bool doSplit = false;
00515 if ( painter->paintEngine()->type() == QPaintEngine::Raster &&
00516 painter->pen().width() >= 2 )
00517 {
00518
00519
00520
00521
00522
00523
00524 doSplit = true;
00525 }
00526
00527 if ( doSplit )
00528 {
00529 const int numPoints = cpa.size();
00530 const QPoint *points = cpa.data();
00531
00532 const int splitSize = 20;
00533 for ( int i = 0; i < numPoints; i += splitSize )
00534 {
00535 const int n = qwtMin(splitSize + 1, cpa.size() - i);
00536 painter->drawPolyline(points + i, n);
00537 }
00538 }
00539 else
00540 #endif
00541 painter->drawPolyline(cpa);
00542 }
00543
00548 void QwtPainter::drawPoint(QPainter *painter, int x, int y)
00549 {
00550 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00551
00552 const QPoint pos = d_metricsMap.layoutToDevice(QPoint(x, y));
00553
00554 if ( deviceClipping && !deviceClipRect().contains(pos) )
00555 return;
00556
00557 painter->drawPoint(pos);
00558 }
00559
00560 void QwtPainter::drawColoredArc(QPainter *painter, const QRect &rect,
00561 int peak, int arc, int interval, const QColor &c1, const QColor &c2)
00562 {
00563 int h1, s1, v1;
00564 int h2, s2, v2;
00565
00566 #if QT_VERSION < 0x040000
00567 c1.hsv(&h1, &s1, &v1);
00568 c2.hsv(&h2, &s2, &v2);
00569 #else
00570 c1.getHsv(&h1, &s1, &v1);
00571 c2.getHsv(&h2, &s2, &v2);
00572 #endif
00573
00574 arc /= 2;
00575 for ( int angle = -arc; angle < arc; angle += interval)
00576 {
00577 double ratio;
00578 if ( angle >= 0 )
00579 ratio = 1.0 - angle / double(arc);
00580 else
00581 ratio = 1.0 + angle / double(arc);
00582
00583
00584 QColor c;
00585 c.setHsv( h1 + qRound(ratio * (h2 - h1)),
00586 s1 + qRound(ratio * (s2 - s1)),
00587 v1 + qRound(ratio * (v2 - v1)) );
00588
00589 painter->setPen(QPen(c, painter->pen().width()));
00590 painter->drawArc(rect, (peak + angle) * 16, interval * 16);
00591 }
00592 }
00593
00594 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget)
00595 {
00596 drawFocusRect(painter, widget, widget->rect());
00597 }
00598
00599 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget,
00600 const QRect &rect)
00601 {
00602 #if QT_VERSION < 0x040000
00603 widget->style().drawPrimitive(QStyle::PE_FocusRect, painter,
00604 rect, widget->colorGroup());
00605 #else
00606 QStyleOptionFocusRect opt;
00607 opt.init(widget);
00608 opt.rect = rect;
00609 opt.state |= QStyle::State_HasFocus;
00610
00611 widget->style()->drawPrimitive(QStyle::PE_FrameFocusRect,
00612 &opt, painter, widget);
00613 #endif
00614
00615 }
00616
00618 #if QT_VERSION < 0x040000
00619 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00620 int width, const QColorGroup &cg, bool sunken)
00621 #else
00622 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00623 int width, const QPalette &palette, bool sunken)
00624 #endif
00625 {
00626
00627 #if QT_VERSION < 0x040000
00628 QColor c0 = cg.mid();
00629 QColor c1, c2;
00630 if ( sunken )
00631 {
00632 c1 = cg.dark();
00633 c2 = cg.light();
00634 }
00635 else
00636 {
00637 c1 = cg.light();
00638 c2 = cg.dark();
00639 }
00640 #else
00641 QColor c0 = palette.color(QPalette::Mid);
00642 QColor c1, c2;
00643 if ( sunken )
00644 {
00645 c1 = palette.color(QPalette::Dark);
00646 c2 = palette.color(QPalette::Light);
00647 }
00648 else
00649 {
00650 c1 = palette.color(QPalette::Light);
00651 c2 = palette.color(QPalette::Dark);
00652 }
00653 #endif
00654
00655 painter->setPen(QPen(c0, width));
00656 painter->drawArc(rect, 0, 360 * 16);
00657
00658 const int peak = 150;
00659 const int interval = 2;
00660
00661 if ( c0 != c1 )
00662 drawColoredArc(painter, rect, peak, 160, interval, c0, c1);
00663 if ( c0 != c2 )
00664 drawColoredArc(painter, rect, peak + 180, 120, interval, c0, c2);
00665 }
00666
00667 void QwtPainter::drawColorBar(QPainter *painter,
00668 const QwtColorMap &colorMap, const QwtDoubleInterval &interval,
00669 const QwtScaleMap &scaleMap, Qt::Orientation orientation,
00670 const QRect &rect)
00671 {
00672 painter->save();
00673
00674 QwtPainter::setClipRect(painter, rect);
00675
00676 #if QT_VERSION < 0x040000
00677 QValueVector<QRgb> colorTable;
00678 #else
00679 QVector<QRgb> colorTable;
00680 #endif
00681 if ( colorMap.format() == QwtColorMap::Indexed )
00682 colorTable = colorMap.colorTable(interval);
00683
00684 QColor c;
00685
00686 const QRect devRect = d_metricsMap.layoutToDevice(rect);
00687
00688 if ( orientation == Qt::Horizontal )
00689 {
00690 QwtScaleMap sMap = scaleMap;
00691 sMap.setPaintInterval(devRect.left(), devRect.right());
00692
00693 for ( int x = devRect.left(); x <= devRect.right(); x++ )
00694 {
00695 const double value = sMap.invTransform(x);
00696
00697 if ( colorMap.format() == QwtColorMap::RGB )
00698 c.setRgb(colorMap.rgb(interval, value));
00699 else
00700 c = colorTable[colorMap.colorIndex(interval, value)];
00701
00702 painter->setBrush(QBrush(c));
00703
00704 const QRect r(x, devRect.top(), 1, devRect.height());
00705 QwtPainter::drawRect(painter, r);
00706 painter->setPen(c);
00707 painter->drawLine(x, devRect.top(), x, devRect.bottom() - 1);
00708 }
00709 }
00710 else
00711 {
00712 QwtScaleMap sMap = scaleMap;
00713 sMap.setPaintInterval(devRect.bottom(), devRect.top());
00714
00715 for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
00716 {
00717 const double value = sMap.invTransform(y);
00718
00719 if ( colorMap.format() == QwtColorMap::RGB )
00720 c.setRgb(colorMap.rgb(interval, value));
00721 else
00722 c = colorTable[colorMap.colorIndex(interval, value)];
00723
00724 painter->setPen(c);
00725 painter->drawLine(devRect.left(), y, devRect.right() - 1, y);
00726 }
00727 }
00728 painter->restore();
00729 }