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_math.h"
00030 #include "qwt_clipper.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 isClippingNeeded(const QPainter *painter, QRect &clipRect)
00048 {
00049 bool doClipping = false;
00050 #if QT_VERSION >= 0x040000
00051 const QPaintEngine *pe = painter->paintEngine();
00052 if ( pe && pe->type() == QPaintEngine::SVG )
00053 #else
00054 if ( painter->device()->devType() == QInternal::Picture )
00055 #endif
00056 {
00057
00058
00059 if ( painter->hasClipping() )
00060 {
00061 doClipping = true;
00062 clipRect = painter->clipRegion().boundingRect();
00063 }
00064 }
00065
00066 if ( QwtPainter::deviceClipping() )
00067 {
00068 if (painter->device()->devType() == QInternal::Widget ||
00069 painter->device()->devType() == QInternal::Pixmap )
00070 {
00071 if ( doClipping )
00072 {
00073 clipRect &= QwtPainter::deviceClipRect();
00074 }
00075 else
00076 {
00077 doClipping = true;
00078 clipRect = QwtPainter::deviceClipRect();
00079 }
00080 }
00081 }
00082
00083 return doClipping;
00084 }
00085
00093 void QwtPainter::setDeviceClipping(bool enable)
00094 {
00095 d_deviceClipping = enable;
00096 }
00097
00102 const QRect &QwtPainter::deviceClipRect()
00103 {
00104 static QRect clip;
00105
00106 if ( !clip.isValid() )
00107 {
00108 clip.setCoords(QWT_COORD_MIN, QWT_COORD_MIN,
00109 QWT_COORD_MAX, QWT_COORD_MAX);
00110 }
00111 return clip;
00112 }
00113
00114 #if QT_VERSION < 0x040000
00115
00127 void QwtPainter::setSVGMode(bool on)
00128 {
00129 d_SVGMode = on;
00130 }
00131
00132 bool QwtPainter::isSVGMode()
00133 {
00134 return d_SVGMode;
00135 }
00136
00137 #endif // QT_VERSION < 0x040000
00138
00147 void QwtPainter::setMetricsMap(const QPaintDevice *layout,
00148 const QPaintDevice *device)
00149 {
00150 d_metricsMap.setMetrics(layout, device);
00151 }
00152
00157 void QwtPainter::setMetricsMap(const QwtMetricsMap &map)
00158 {
00159 d_metricsMap = map;
00160 }
00161
00166 void QwtPainter::resetMetricsMap()
00167 {
00168 d_metricsMap = QwtMetricsMap();
00169 }
00170
00174 const QwtMetricsMap &QwtPainter::metricsMap()
00175 {
00176 return d_metricsMap;
00177 }
00178
00182 void QwtPainter::setClipRect(QPainter *painter, const QRect &rect)
00183 {
00184 painter->setClipRect(d_metricsMap.layoutToDevice(rect, painter));
00185 }
00186
00190 void QwtPainter::drawRect(QPainter *painter, int x, int y, int w, int h)
00191 {
00192 drawRect(painter, QRect(x, y, w, h));
00193 }
00194
00198 void QwtPainter::drawRect(QPainter *painter, const QRect &rect)
00199 {
00200 const QRect r = d_metricsMap.layoutToDevice(rect, painter);
00201
00202 QRect clipRect;
00203 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00204
00205 if ( deviceClipping )
00206 {
00207 if ( !clipRect.intersects(r) )
00208 return;
00209
00210 if ( !clipRect.contains(r) )
00211 {
00212 fillRect(painter, r & clipRect, painter->brush());
00213
00214 int pw = painter->pen().width();
00215 pw = pw % 2 + pw / 2;
00216
00217 QwtPolygon pa(5);
00218 pa.setPoint(0, r.left(), r.top());
00219 pa.setPoint(1, r.right() - pw, r.top());
00220 pa.setPoint(2, r.right() - pw, r.bottom() - pw);
00221 pa.setPoint(3, r.left(), r.bottom() - pw);
00222 pa.setPoint(4, r.left(), r.top());
00223
00224 painter->save();
00225 painter->setBrush(Qt::NoBrush);
00226 drawPolyline(painter, pa);
00227 painter->restore();
00228
00229 return;
00230 }
00231 }
00232
00233 painter->drawRect(r);
00234 }
00235
00239 void QwtPainter::fillRect(QPainter *painter,
00240 const QRect &rect, const QBrush &brush)
00241 {
00242 if ( !rect.isValid() )
00243 return;
00244
00245 QRect clipRect;
00246 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00247
00248 #if QT_VERSION >= 0x040000
00249
00250
00251
00252
00253
00254
00255 if ( deviceClipping )
00256 clipRect &= painter->window();
00257 else
00258 clipRect = painter->window();
00259
00260 if ( painter->hasClipping() )
00261 clipRect &= painter->clipRegion().boundingRect();
00262 #endif
00263
00264 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00265 if ( deviceClipping )
00266 r = r.intersect(clipRect);
00267
00268 if ( r.isValid() )
00269 painter->fillRect(r, brush);
00270 }
00271
00275 void QwtPainter::drawPie(QPainter *painter, const QRect &rect,
00276 int a, int alen)
00277 {
00278 const QRect r = d_metricsMap.layoutToDevice(rect, painter);
00279
00280 QRect clipRect;
00281 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00282 if ( deviceClipping && !clipRect.contains(r) )
00283 return;
00284
00285 painter->drawPie(r, a, alen);
00286 }
00287
00291 void QwtPainter::drawEllipse(QPainter *painter, const QRect &rect)
00292 {
00293 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00294
00295 QRect clipRect;
00296 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00297
00298 if ( deviceClipping && !clipRect.contains(r) )
00299 return;
00300
00301 #if QT_VERSION >= 0x040000
00302 if ( painter->pen().style() != Qt::NoPen &&
00303 painter->pen().color().isValid() )
00304 {
00305
00306 int pw = painter->pen().width();
00307 if ( pw == 0 )
00308 pw = 1;
00309
00310 r.setWidth(r.width() - pw);
00311 r.setHeight(r.height() - pw);
00312 }
00313 #endif
00314
00315 painter->drawEllipse(r);
00316 }
00317
00321 void QwtPainter::drawText(QPainter *painter, int x, int y,
00322 const QString &text)
00323 {
00324 drawText(painter, QPoint(x, y), text);
00325 }
00326
00330 void QwtPainter::drawText(QPainter *painter, const QPoint &pos,
00331 const QString &text)
00332 {
00333 const QPoint p = d_metricsMap.layoutToDevice(pos, painter);
00334
00335 QRect clipRect;
00336 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00337
00338 if ( deviceClipping && !clipRect.contains(p) )
00339 return;
00340
00341 painter->drawText(p, text);
00342 }
00343
00347 void QwtPainter::drawText(QPainter *painter, int x, int y, int w, int h,
00348 int flags, const QString &text)
00349 {
00350 drawText(painter, QRect(x, y, w, h), flags, text);
00351 }
00352
00356 void QwtPainter::drawText(QPainter *painter, const QRect &rect,
00357 int flags, const QString &text)
00358 {
00359 QRect textRect = d_metricsMap.layoutToDevice(rect, painter);
00360 #if QT_VERSION < 0x040000
00361 if ( d_SVGMode &&
00362 ( flags == 0 || flags & Qt::AlignVCenter )
00363 && painter->device()->devType() == QInternal::Picture )
00364 {
00365
00366
00367
00368
00369 textRect.setY(textRect.y() - painter->fontMetrics().height() / 4);
00370 }
00371 #endif
00372 painter->drawText(textRect, flags, text);
00373 }
00374
00375 #ifndef QT_NO_RICHTEXT
00376
00380 #if QT_VERSION < 0x040000
00381
00382 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00383 int flags, QSimpleRichText &text)
00384 {
00385 QColorGroup cg;
00386 cg.setColor(QColorGroup::Text, painter->pen().color());
00387
00388 const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00389
00390 text.setWidth(painter, scaledRect.width());
00391
00392
00393
00394 int y = scaledRect.y();
00395 if (flags & Qt::AlignBottom)
00396 y += (scaledRect.height() - text.height());
00397 else if (flags & Qt::AlignVCenter)
00398 y += (scaledRect.height() - text.height())/2;
00399
00400 text.draw(painter, scaledRect.x(), y, scaledRect, cg);
00401 }
00402 #else
00403 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00404 int flags, QTextDocument &text)
00405 {
00406 const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00407 text.setPageSize(QSize(scaledRect.width(), QWIDGETSIZE_MAX));
00408
00409 QAbstractTextDocumentLayout* layout = text.documentLayout();
00410
00411 const int height = qRound(layout->documentSize().height());
00412 int y = scaledRect.y();
00413 if (flags & Qt::AlignBottom)
00414 y += (scaledRect.height() - height);
00415 else if (flags & Qt::AlignVCenter)
00416 y += (scaledRect.height() - height)/2;
00417
00418 QAbstractTextDocumentLayout::PaintContext context;
00419 context.palette.setColor(QPalette::Text, painter->pen().color());
00420
00421 painter->save();
00422
00423 painter->translate(scaledRect.x(), y);
00424 layout->draw(painter, context);
00425
00426 painter->restore();
00427 }
00428 #endif
00429
00430 #endif // !QT_NO_RICHTEXT
00431
00432
00436 void QwtPainter::drawLine(QPainter *painter, int x1, int y1, int x2, int y2)
00437 {
00438 QRect clipRect;
00439 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00440
00441 if ( deviceClipping &&
00442 !(clipRect.contains(x1, y1) && clipRect.contains(x2, y2)) )
00443 {
00444 QwtPolygon pa(2);
00445 pa.setPoint(0, x1, y1);
00446 pa.setPoint(1, x2, y2);
00447 drawPolyline(painter, pa);
00448 return;
00449 }
00450
00451 if ( d_metricsMap.isIdentity() )
00452 {
00453 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00454 if ( !painter->device()->isExtDev() )
00455 #endif
00456 {
00457 painter->drawLine(x1, y1, x2, y2);
00458 return;
00459 }
00460 }
00461
00462 const QPoint p1 = d_metricsMap.layoutToDevice(QPoint(x1, y1));
00463 const QPoint p2 = d_metricsMap.layoutToDevice(QPoint(x2, y2));
00464
00465 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00466 if ( painter->device()->isExtDev() )
00467 {
00468
00469
00470
00471
00472 QwtPolygon pa(2);
00473 pa.setPoint(0, p1);
00474 pa.setPoint(1, p2);
00475 painter->drawLineSegments(pa);
00476 }
00477 else
00478 painter->drawLine(p1, p2);
00479 #else
00480 painter->drawLine(p1, p2);
00481 #endif
00482 }
00483
00487 void QwtPainter::drawPolygon(QPainter *painter, const QwtPolygon &pa)
00488 {
00489 QRect clipRect;
00490 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00491
00492 QwtPolygon cpa = d_metricsMap.layoutToDevice(pa);
00493 if ( deviceClipping )
00494 {
00495 #ifdef __GNUC__
00496 #endif
00497 cpa = QwtClipper::clipPolygon(clipRect, cpa);
00498 }
00499 painter->drawPolygon(cpa);
00500 }
00501
00505 void QwtPainter::drawPolyline(QPainter *painter, const QwtPolygon &pa)
00506 {
00507 QRect clipRect;
00508 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00509
00510 QwtPolygon cpa = d_metricsMap.layoutToDevice(pa);
00511 if ( deviceClipping )
00512 cpa = QwtClipper::clipPolygon(clipRect, cpa);
00513
00514 #if QT_VERSION >= 0x040000 && QT_VERSION < 0x040400
00515 bool doSplit = false;
00516
00517 const QPaintEngine *pe = painter->paintEngine();
00518 if ( pe && pe->type() == QPaintEngine::Raster &&
00519 painter->pen().width() >= 2 )
00520 {
00521
00522
00523
00524
00525
00526
00527 doSplit = true;
00528 }
00529
00530 if ( doSplit )
00531 {
00532 const int numPoints = cpa.size();
00533 const QPoint *points = cpa.data();
00534
00535 const int splitSize = 20;
00536 for ( int i = 0; i < numPoints; i += splitSize )
00537 {
00538 const int n = qwtMin(splitSize + 1, cpa.size() - i);
00539 painter->drawPolyline(points + i, n);
00540 }
00541 }
00542 else
00543 #endif
00544 painter->drawPolyline(cpa);
00545 }
00546
00551 void QwtPainter::drawPoint(QPainter *painter, int x, int y)
00552 {
00553 QRect clipRect;
00554 const bool deviceClipping = isClippingNeeded(painter, clipRect);
00555
00556 const QPoint pos = d_metricsMap.layoutToDevice(QPoint(x, y));
00557
00558 if ( deviceClipping && !clipRect.contains(pos) )
00559 return;
00560
00561 painter->drawPoint(pos);
00562 }
00563
00564 void QwtPainter::drawColoredArc(QPainter *painter, const QRect &rect,
00565 int peak, int arc, int interval, const QColor &c1, const QColor &c2)
00566 {
00567 int h1, s1, v1;
00568 int h2, s2, v2;
00569
00570 #if QT_VERSION < 0x040000
00571 c1.hsv(&h1, &s1, &v1);
00572 c2.hsv(&h2, &s2, &v2);
00573 #else
00574 c1.getHsv(&h1, &s1, &v1);
00575 c2.getHsv(&h2, &s2, &v2);
00576 #endif
00577
00578 arc /= 2;
00579 for ( int angle = -arc; angle < arc; angle += interval)
00580 {
00581 double ratio;
00582 if ( angle >= 0 )
00583 ratio = 1.0 - angle / double(arc);
00584 else
00585 ratio = 1.0 + angle / double(arc);
00586
00587
00588 QColor c;
00589 c.setHsv( h1 + qRound(ratio * (h2 - h1)),
00590 s1 + qRound(ratio * (s2 - s1)),
00591 v1 + qRound(ratio * (v2 - v1)) );
00592
00593 painter->setPen(QPen(c, painter->pen().width()));
00594 painter->drawArc(rect, (peak + angle) * 16, interval * 16);
00595 }
00596 }
00597
00598 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget)
00599 {
00600 drawFocusRect(painter, widget, widget->rect());
00601 }
00602
00603 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget,
00604 const QRect &rect)
00605 {
00606 #if QT_VERSION < 0x040000
00607 widget->style().drawPrimitive(QStyle::PE_FocusRect, painter,
00608 rect, widget->colorGroup());
00609 #else
00610 QStyleOptionFocusRect opt;
00611 opt.init(widget);
00612 opt.rect = rect;
00613 opt.state |= QStyle::State_HasFocus;
00614
00615 widget->style()->drawPrimitive(QStyle::PE_FrameFocusRect,
00616 &opt, painter, widget);
00617 #endif
00618
00619 }
00620
00622 #if QT_VERSION < 0x040000
00623 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00624 int width, const QColorGroup &cg, bool sunken)
00625 #else
00626 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00627 int width, const QPalette &palette, bool sunken)
00628 #endif
00629 {
00630
00631 #if QT_VERSION < 0x040000
00632 QColor c0 = cg.mid();
00633 QColor c1, c2;
00634 if ( sunken )
00635 {
00636 c1 = cg.dark();
00637 c2 = cg.light();
00638 }
00639 else
00640 {
00641 c1 = cg.light();
00642 c2 = cg.dark();
00643 }
00644 #else
00645 QColor c0 = palette.color(QPalette::Mid);
00646 QColor c1, c2;
00647 if ( sunken )
00648 {
00649 c1 = palette.color(QPalette::Dark);
00650 c2 = palette.color(QPalette::Light);
00651 }
00652 else
00653 {
00654 c1 = palette.color(QPalette::Light);
00655 c2 = palette.color(QPalette::Dark);
00656 }
00657 #endif
00658
00659 painter->setPen(QPen(c0, width));
00660 painter->drawArc(rect, 0, 360 * 16);
00661
00662 const int peak = 150;
00663 const int interval = 2;
00664
00665 if ( c0 != c1 )
00666 drawColoredArc(painter, rect, peak, 160, interval, c0, c1);
00667 if ( c0 != c2 )
00668 drawColoredArc(painter, rect, peak + 180, 120, interval, c0, c2);
00669 }
00670
00671 void QwtPainter::drawColorBar(QPainter *painter,
00672 const QwtColorMap &colorMap, const QwtDoubleInterval &interval,
00673 const QwtScaleMap &scaleMap, Qt::Orientation orientation,
00674 const QRect &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
00689
00690
00691
00692
00693 QPixmap pixmap(devRect.size());
00694 QPainter pmPainter(&pixmap);
00695 pmPainter.translate(-devRect.x(), -devRect.y());
00696
00697 if ( orientation == Qt::Horizontal )
00698 {
00699 QwtScaleMap sMap = scaleMap;
00700 sMap.setPaintInterval(devRect.left(), devRect.right());
00701
00702 for ( int x = devRect.left(); x <= devRect.right(); x++ )
00703 {
00704 const double value = sMap.invTransform(x);
00705
00706 if ( colorMap.format() == QwtColorMap::RGB )
00707 c.setRgb(colorMap.rgb(interval, value));
00708 else
00709 c = colorTable[colorMap.colorIndex(interval, value)];
00710
00711 pmPainter.setPen(c);
00712 pmPainter.drawLine(x, devRect.top(), x, devRect.bottom());
00713 }
00714 }
00715 else
00716 {
00717 QwtScaleMap sMap = scaleMap;
00718 sMap.setPaintInterval(devRect.bottom(), devRect.top());
00719
00720 for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
00721 {
00722 const double value = sMap.invTransform(y);
00723
00724 if ( colorMap.format() == QwtColorMap::RGB )
00725 c.setRgb(colorMap.rgb(interval, value));
00726 else
00727 c = colorTable[colorMap.colorIndex(interval, value)];
00728
00729 pmPainter.setPen(c);
00730 pmPainter.drawLine(devRect.left(), y, devRect.right(), y);
00731 }
00732 }
00733 pmPainter.end();
00734 painter->drawPixmap(devRect, pixmap);
00735 }
00736
00747 QPen QwtPainter::scaledPen(const QPen &pen)
00748 {
00749 #if QT_VERSION < 0x040000
00750 return pen;
00751 #else
00752 QPen sPen = pen;
00753
00754 if ( !pen.isCosmetic() )
00755 {
00756 int pw = pen.width();
00757 if ( pw == 0 )
00758 pw = 1;
00759
00760 sPen.setWidth(QwtPainter::metricsMap().screenToLayoutX(pw));
00761 sPen.setCosmetic(true);
00762 }
00763
00764 return sPen;
00765 #endif
00766 }
00767