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 #warning clipping ignores painter transformations
00497 #endif
00498 cpa = clip(cpa);
00499 }
00500 painter->drawPolygon(cpa);
00501 }
00502
00506 void QwtPainter::drawPolyline(QPainter *painter, const QwtPolygon &pa)
00507 {
00508 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00509
00510 QwtPolygon cpa = d_metricsMap.layoutToDevice(pa);
00511 if ( deviceClipping )
00512 cpa = clip(cpa);
00513
00514 #if QT_VERSION >= 0x040000
00515 bool doSplit = false;
00516 if ( painter->paintEngine()->type() == QPaintEngine::Raster &&
00517 painter->pen().width() >= 2 )
00518 {
00519
00520
00521
00522
00523
00524
00525 doSplit = true;
00526 }
00527
00528 if ( doSplit )
00529 {
00530 const int numPoints = cpa.size();
00531 const QPoint *points = cpa.data();
00532
00533 const int splitSize = 20;
00534 for ( int i = 0; i < numPoints; i += splitSize )
00535 {
00536 const int n = qwtMin(splitSize + 1, cpa.size() - i);
00537 painter->drawPolyline(points + i, n);
00538 }
00539 }
00540 else
00541 #endif
00542 painter->drawPolyline(cpa);
00543 }
00544
00549 void QwtPainter::drawPoint(QPainter *painter, int x, int y)
00550 {
00551 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00552
00553 const QPoint pos = d_metricsMap.layoutToDevice(QPoint(x, y));
00554
00555 if ( deviceClipping && !deviceClipRect().contains(pos) )
00556 return;
00557
00558 painter->drawPoint(pos);
00559 }
00560
00561 void QwtPainter::drawColoredArc(QPainter *painter, const QRect &rect,
00562 int peak, int arc, int interval, const QColor &c1, const QColor &c2)
00563 {
00564 int h1, s1, v1;
00565 int h2, s2, v2;
00566
00567 #if QT_VERSION < 0x040000
00568 c1.hsv(&h1, &s1, &v1);
00569 c2.hsv(&h2, &s2, &v2);
00570 #else
00571 c1.getHsv(&h1, &s1, &v1);
00572 c2.getHsv(&h2, &s2, &v2);
00573 #endif
00574
00575 arc /= 2;
00576 for ( int angle = -arc; angle < arc; angle += interval)
00577 {
00578 double ratio;
00579 if ( angle >= 0 )
00580 ratio = 1.0 - angle / double(arc);
00581 else
00582 ratio = 1.0 + angle / double(arc);
00583
00584
00585 QColor c;
00586 c.setHsv( h1 + qRound(ratio * (h2 - h1)),
00587 s1 + qRound(ratio * (s2 - s1)),
00588 v1 + qRound(ratio * (v2 - v1)) );
00589
00590 painter->setPen(QPen(c, painter->pen().width()));
00591 painter->drawArc(rect, (peak + angle) * 16, interval * 16);
00592 }
00593 }
00594
00595 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget)
00596 {
00597 drawFocusRect(painter, widget, widget->rect());
00598 }
00599
00600 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget,
00601 const QRect &rect)
00602 {
00603 #if QT_VERSION < 0x040000
00604 widget->style().drawPrimitive(QStyle::PE_FocusRect, painter,
00605 rect, widget->colorGroup());
00606 #else
00607 QStyleOptionFocusRect opt;
00608 opt.init(widget);
00609 opt.rect = rect;
00610 opt.state |= QStyle::State_HasFocus;
00611
00612 widget->style()->drawPrimitive(QStyle::PE_FrameFocusRect,
00613 &opt, painter, widget);
00614 #endif
00615
00616 }
00617
00619 #if QT_VERSION < 0x040000
00620 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00621 int width, const QColorGroup &cg, bool sunken)
00622 #else
00623 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00624 int width, const QPalette &palette, bool sunken)
00625 #endif
00626 {
00627
00628 #if QT_VERSION < 0x040000
00629 QColor c0 = cg.mid();
00630 QColor c1, c2;
00631 if ( sunken )
00632 {
00633 c1 = cg.dark();
00634 c2 = cg.light();
00635 }
00636 else
00637 {
00638 c1 = cg.light();
00639 c2 = cg.dark();
00640 }
00641 #else
00642 QColor c0 = palette.color(QPalette::Mid);
00643 QColor c1, c2;
00644 if ( sunken )
00645 {
00646 c1 = palette.color(QPalette::Dark);
00647 c2 = palette.color(QPalette::Light);
00648 }
00649 else
00650 {
00651 c1 = palette.color(QPalette::Light);
00652 c2 = palette.color(QPalette::Dark);
00653 }
00654 #endif
00655
00656 painter->setPen(QPen(c0, width));
00657 painter->drawArc(rect, 0, 360 * 16);
00658
00659 const int peak = 150;
00660 const int interval = 2;
00661
00662 if ( c0 != c1 )
00663 drawColoredArc(painter, rect, peak, 160, interval, c0, c1);
00664 if ( c0 != c2 )
00665 drawColoredArc(painter, rect, peak + 180, 120, interval, c0, c2);
00666 }
00667
00668 void QwtPainter::drawColorBar(QPainter *painter,
00669 const QwtColorMap &colorMap, const QwtDoubleInterval &interval,
00670 const QwtScaleMap &scaleMap, Qt::Orientation orientation,
00671 const QRect &rect)
00672 {
00673 painter->save();
00674
00675 QwtPainter::setClipRect(painter, rect);
00676
00677 #if QT_VERSION < 0x040000
00678 QValueVector<QRgb> colorTable;
00679 #else
00680 QVector<QRgb> colorTable;
00681 #endif
00682 if ( colorMap.format() == QwtColorMap::Indexed )
00683 colorTable = colorMap.colorTable(interval);
00684
00685 QColor c;
00686
00687 const QRect devRect = d_metricsMap.layoutToDevice(rect);
00688
00689 if ( orientation == Qt::Horizontal )
00690 {
00691 QwtScaleMap sMap = scaleMap;
00692 sMap.setPaintInterval(devRect.left(), devRect.right());
00693
00694 for ( int x = devRect.left(); x <= devRect.right(); x++ )
00695 {
00696 const double value = sMap.invTransform(x);
00697
00698 if ( colorMap.format() == QwtColorMap::RGB )
00699 c.setRgb(colorMap.rgb(interval, value));
00700 else
00701 c = colorTable[colorMap.colorIndex(interval, value)];
00702
00703 painter->setBrush(QBrush(c));
00704
00705 const QRect r(x, devRect.top(), 1, devRect.height());
00706 QwtPainter::drawRect(painter, r);
00707 painter->setPen(c);
00708 painter->drawLine(x, devRect.top(), x, devRect.bottom() - 1);
00709 }
00710 }
00711 else
00712 {
00713 QwtScaleMap sMap = scaleMap;
00714 sMap.setPaintInterval(devRect.bottom(), devRect.top());
00715
00716 for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
00717 {
00718 const double value = sMap.invTransform(y);
00719
00720 if ( colorMap.format() == QwtColorMap::RGB )
00721 c.setRgb(colorMap.rgb(interval, value));
00722 else
00723 c = colorTable[colorMap.colorIndex(interval, value)];
00724
00725 painter->setPen(c);
00726 painter->drawLine(devRect.left(), y, devRect.right() - 1, y);
00727 }
00728 }
00729 painter->restore();
00730 }