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_clipper.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 return QwtClipper::clipPolygon(deviceClipRect(), pa);
00098 }
00099
00100 #if QT_VERSION < 0x040000
00101
00113 void QwtPainter::setSVGMode(bool on)
00114 {
00115 d_SVGMode = on;
00116 }
00117
00118 bool QwtPainter::isSVGMode()
00119 {
00120 return d_SVGMode;
00121 }
00122
00123 #endif // QT_VERSION < 0x040000
00124
00133 void QwtPainter::setMetricsMap(const QPaintDevice *layout,
00134 const QPaintDevice *device)
00135 {
00136 d_metricsMap.setMetrics(layout, device);
00137 }
00138
00143 void QwtPainter::setMetricsMap(const QwtMetricsMap &map)
00144 {
00145 d_metricsMap = map;
00146 }
00147
00152 void QwtPainter::resetMetricsMap()
00153 {
00154 d_metricsMap = QwtMetricsMap();
00155 }
00156
00160 const QwtMetricsMap &QwtPainter::metricsMap()
00161 {
00162 return d_metricsMap;
00163 }
00164
00168 void QwtPainter::setClipRect(QPainter *painter, const QRect &rect)
00169 {
00170 painter->setClipRect(d_metricsMap.layoutToDevice(rect, painter));
00171 }
00172
00176 void QwtPainter::drawRect(QPainter *painter, int x, int y, int w, int h)
00177 {
00178 drawRect(painter, QRect(x, y, w, h));
00179 }
00180
00184 void QwtPainter::drawRect(QPainter *painter, const QRect &rect)
00185 {
00186 const QRect r = d_metricsMap.layoutToDevice(rect, painter);
00187
00188 QRect clipRect;
00189
00190 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00191 if ( deviceClipping )
00192 clipRect = deviceClipRect();
00193
00194 if ( clipRect.isValid() )
00195 {
00196 if ( !clipRect.intersects(r) )
00197 return;
00198
00199 if ( !clipRect.contains(r) )
00200 {
00201 fillRect(painter, r & clipRect, painter->brush());
00202
00203 int pw = painter->pen().width();
00204 pw = pw % 2 + pw / 2;
00205
00206 QwtPolygon pa(5);
00207 pa.setPoint(0, r.left(), r.top());
00208 pa.setPoint(1, r.right() - pw, r.top());
00209 pa.setPoint(2, r.right() - pw, r.bottom() - pw);
00210 pa.setPoint(3, r.left(), r.bottom() - pw);
00211 pa.setPoint(4, r.left(), r.top());
00212
00213 painter->save();
00214 painter->setBrush(Qt::NoBrush);
00215 drawPolyline(painter, pa);
00216 painter->restore();
00217
00218 return;
00219 }
00220 }
00221
00222 painter->drawRect(r);
00223 }
00224
00228 void QwtPainter::fillRect(QPainter *painter,
00229 const QRect &rect, const QBrush &brush)
00230 {
00231 if ( !rect.isValid() )
00232 return;
00233
00234 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00235
00236 QRect clipRect;
00237 #if QT_VERSION >= 0x040000
00238
00239
00240
00241
00242
00243
00244
00245 clipRect = painter->window();
00246 if ( painter->hasClipping() )
00247 clipRect &= painter->clipRegion().boundingRect();
00248 if ( deviceClipping )
00249 clipRect &= deviceClipRect();
00250 #else
00251 if ( deviceClipping )
00252 clipRect = deviceClipRect();
00253 #endif
00254
00255 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00256 if ( clipRect.isValid() )
00257 r = r.intersect(clipRect);
00258
00259 if ( r.isValid() )
00260 painter->fillRect(r, brush);
00261 }
00262
00266 void QwtPainter::drawPie(QPainter *painter, const QRect &rect,
00267 int a, int alen)
00268 {
00269 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00270
00271 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00272 if ( deviceClipping && !deviceClipRect().contains(rect) )
00273 return;
00274
00275 painter->drawPie(r, a, alen);
00276 }
00277
00281 void QwtPainter::drawEllipse(QPainter *painter, const QRect &rect)
00282 {
00283 QRect r = d_metricsMap.layoutToDevice(rect, painter);
00284
00285 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00286
00287 if ( deviceClipping && !deviceClipRect().contains(rect) )
00288 return;
00289
00290 #if QT_VERSION >= 0x040000
00291 if ( painter->pen().style() != Qt::NoPen &&
00292 painter->pen().color().isValid() )
00293 {
00294
00295 int pw = painter->pen().width();
00296 if ( pw == 0 )
00297 pw = 1;
00298
00299 r.setWidth(r.width() - pw);
00300 r.setHeight(r.height() - pw);
00301 }
00302 #endif
00303
00304 painter->drawEllipse(r);
00305 }
00306
00310 void QwtPainter::drawText(QPainter *painter, int x, int y,
00311 const QString &text)
00312 {
00313 drawText(painter, QPoint(x, y), text);
00314 }
00315
00319 void QwtPainter::drawText(QPainter *painter, const QPoint &pos,
00320 const QString &text)
00321 {
00322 const QPoint p = d_metricsMap.layoutToDevice(pos, painter);
00323
00324 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00325
00326 if ( deviceClipping && !deviceClipRect().contains(p) )
00327 return;
00328
00329 painter->drawText(p, text);
00330 }
00331
00335 void QwtPainter::drawText(QPainter *painter, int x, int y, int w, int h,
00336 int flags, const QString &text)
00337 {
00338 drawText(painter, QRect(x, y, w, h), flags, text);
00339 }
00340
00344 void QwtPainter::drawText(QPainter *painter, const QRect &rect,
00345 int flags, const QString &text)
00346 {
00347 QRect textRect = d_metricsMap.layoutToDevice(rect, painter);
00348 #if QT_VERSION < 0x040000
00349 if ( d_SVGMode &&
00350 ( flags == 0 || flags & Qt::AlignVCenter )
00351 && painter->device()->devType() & QInternal::Picture )
00352 {
00353
00354
00355
00356
00357 textRect.setY(textRect.y() - painter->fontMetrics().height() / 4);
00358 }
00359 #endif
00360 painter->drawText(textRect, flags, text);
00361 }
00362
00363 #ifndef QT_NO_RICHTEXT
00364
00368 #if QT_VERSION < 0x040000
00369
00370 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00371 int flags, QSimpleRichText &text)
00372 {
00373 QColorGroup cg;
00374 cg.setColor(QColorGroup::Text, painter->pen().color());
00375
00376 const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00377
00378 text.setWidth(painter, scaledRect.width());
00379
00380
00381
00382 int y = scaledRect.y();
00383 if (flags & Qt::AlignBottom)
00384 y += (scaledRect.height() - text.height());
00385 else if (flags & Qt::AlignVCenter)
00386 y += (scaledRect.height() - text.height())/2;
00387
00388 text.draw(painter, scaledRect.x(), y, scaledRect, cg);
00389 }
00390 #else
00391 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00392 int flags, QTextDocument &text)
00393 {
00394 const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00395 text.setPageSize(QSize(scaledRect.width(), QWIDGETSIZE_MAX));
00396
00397 QAbstractTextDocumentLayout* layout = text.documentLayout();
00398
00399 const int height = qRound(layout->documentSize().height());
00400 int y = scaledRect.y();
00401 if (flags & Qt::AlignBottom)
00402 y += (scaledRect.height() - height);
00403 else if (flags & Qt::AlignVCenter)
00404 y += (scaledRect.height() - height)/2;
00405
00406 QAbstractTextDocumentLayout::PaintContext context;
00407 context.palette.setColor(QPalette::Text, painter->pen().color());
00408
00409 painter->save();
00410
00411 painter->translate(scaledRect.x(), y);
00412 layout->draw(painter, context);
00413
00414 painter->restore();
00415 }
00416 #endif
00417
00418 #endif // !QT_NO_RICHTEXT
00419
00420
00424 void QwtPainter::drawLine(QPainter *painter, int x1, int y1, int x2, int y2)
00425 {
00426 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00427
00428 if ( deviceClipping &&
00429 !(deviceClipRect().contains(x1, y1) && deviceClipRect().contains(x2, y2)) )
00430 {
00431 QwtPolygon pa(2);
00432 pa.setPoint(0, x1, y1);
00433 pa.setPoint(1, x2, y2);
00434 drawPolyline(painter, pa);
00435 return;
00436 }
00437
00438 if ( d_metricsMap.isIdentity() )
00439 {
00440 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00441 if ( !painter->device()->isExtDev() )
00442 #endif
00443 {
00444 painter->drawLine(x1, y1, x2, y2);
00445 return;
00446 }
00447 }
00448
00449 const QPoint p1 = d_metricsMap.layoutToDevice(QPoint(x1, y1));
00450 const QPoint p2 = d_metricsMap.layoutToDevice(QPoint(x2, y2));
00451
00452 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00453 if ( painter->device()->isExtDev() )
00454 {
00455
00456
00457
00458
00459 QwtPolygon pa(2);
00460 pa.setPoint(0, p1);
00461 pa.setPoint(1, p2);
00462 painter->drawLineSegments(pa);
00463 }
00464 else
00465 painter->drawLine(p1, p2);
00466 #else
00467 painter->drawLine(p1, p2);
00468 #endif
00469 }
00470
00474 void QwtPainter::drawPolygon(QPainter *painter, const QwtPolygon &pa)
00475 {
00476 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00477
00478 QwtPolygon cpa = d_metricsMap.layoutToDevice(pa);
00479 if ( deviceClipping )
00480 {
00481 #ifdef __GNUC__
00482 #endif
00483 cpa = clip(cpa);
00484 }
00485 painter->drawPolygon(cpa);
00486 }
00487
00491 void QwtPainter::drawPolyline(QPainter *painter, const QwtPolygon &pa)
00492 {
00493 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00494
00495 QwtPolygon cpa = d_metricsMap.layoutToDevice(pa);
00496 if ( deviceClipping )
00497 cpa = clip(cpa);
00498
00499 #if QT_VERSION >= 0x040000
00500 bool doSplit = false;
00501 if ( painter->paintEngine()->type() == QPaintEngine::Raster &&
00502 painter->pen().width() >= 2 )
00503 {
00504
00505
00506
00507
00508
00509
00510 doSplit = true;
00511 }
00512
00513 if ( doSplit )
00514 {
00515 const int numPoints = cpa.size();
00516 const QPoint *points = cpa.data();
00517
00518 const int splitSize = 20;
00519 for ( int i = 0; i < numPoints; i += splitSize )
00520 {
00521 const int n = qwtMin(splitSize + 1, cpa.size() - i);
00522 painter->drawPolyline(points + i, n);
00523 }
00524 }
00525 else
00526 #endif
00527 painter->drawPolyline(cpa);
00528 }
00529
00534 void QwtPainter::drawPoint(QPainter *painter, int x, int y)
00535 {
00536 const bool deviceClipping = needDeviceClipping(painter, d_deviceClipping);
00537
00538 const QPoint pos = d_metricsMap.layoutToDevice(QPoint(x, y));
00539
00540 if ( deviceClipping && !deviceClipRect().contains(pos) )
00541 return;
00542
00543 painter->drawPoint(pos);
00544 }
00545
00546 void QwtPainter::drawColoredArc(QPainter *painter, const QRect &rect,
00547 int peak, int arc, int interval, const QColor &c1, const QColor &c2)
00548 {
00549 int h1, s1, v1;
00550 int h2, s2, v2;
00551
00552 #if QT_VERSION < 0x040000
00553 c1.hsv(&h1, &s1, &v1);
00554 c2.hsv(&h2, &s2, &v2);
00555 #else
00556 c1.getHsv(&h1, &s1, &v1);
00557 c2.getHsv(&h2, &s2, &v2);
00558 #endif
00559
00560 arc /= 2;
00561 for ( int angle = -arc; angle < arc; angle += interval)
00562 {
00563 double ratio;
00564 if ( angle >= 0 )
00565 ratio = 1.0 - angle / double(arc);
00566 else
00567 ratio = 1.0 + angle / double(arc);
00568
00569
00570 QColor c;
00571 c.setHsv( h1 + qRound(ratio * (h2 - h1)),
00572 s1 + qRound(ratio * (s2 - s1)),
00573 v1 + qRound(ratio * (v2 - v1)) );
00574
00575 painter->setPen(QPen(c, painter->pen().width()));
00576 painter->drawArc(rect, (peak + angle) * 16, interval * 16);
00577 }
00578 }
00579
00580 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget)
00581 {
00582 drawFocusRect(painter, widget, widget->rect());
00583 }
00584
00585 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget,
00586 const QRect &rect)
00587 {
00588 #if QT_VERSION < 0x040000
00589 widget->style().drawPrimitive(QStyle::PE_FocusRect, painter,
00590 rect, widget->colorGroup());
00591 #else
00592 QStyleOptionFocusRect opt;
00593 opt.init(widget);
00594 opt.rect = rect;
00595 opt.state |= QStyle::State_HasFocus;
00596
00597 widget->style()->drawPrimitive(QStyle::PE_FrameFocusRect,
00598 &opt, painter, widget);
00599 #endif
00600
00601 }
00602
00604 #if QT_VERSION < 0x040000
00605 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00606 int width, const QColorGroup &cg, bool sunken)
00607 #else
00608 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00609 int width, const QPalette &palette, bool sunken)
00610 #endif
00611 {
00612
00613 #if QT_VERSION < 0x040000
00614 QColor c0 = cg.mid();
00615 QColor c1, c2;
00616 if ( sunken )
00617 {
00618 c1 = cg.dark();
00619 c2 = cg.light();
00620 }
00621 else
00622 {
00623 c1 = cg.light();
00624 c2 = cg.dark();
00625 }
00626 #else
00627 QColor c0 = palette.color(QPalette::Mid);
00628 QColor c1, c2;
00629 if ( sunken )
00630 {
00631 c1 = palette.color(QPalette::Dark);
00632 c2 = palette.color(QPalette::Light);
00633 }
00634 else
00635 {
00636 c1 = palette.color(QPalette::Light);
00637 c2 = palette.color(QPalette::Dark);
00638 }
00639 #endif
00640
00641 painter->setPen(QPen(c0, width));
00642 painter->drawArc(rect, 0, 360 * 16);
00643
00644 const int peak = 150;
00645 const int interval = 2;
00646
00647 if ( c0 != c1 )
00648 drawColoredArc(painter, rect, peak, 160, interval, c0, c1);
00649 if ( c0 != c2 )
00650 drawColoredArc(painter, rect, peak + 180, 120, interval, c0, c2);
00651 }
00652
00653 void QwtPainter::drawColorBar(QPainter *painter,
00654 const QwtColorMap &colorMap, const QwtDoubleInterval &interval,
00655 const QwtScaleMap &scaleMap, Qt::Orientation orientation,
00656 const QRect &rect)
00657 {
00658 #if QT_VERSION < 0x040000
00659 QValueVector<QRgb> colorTable;
00660 #else
00661 QVector<QRgb> colorTable;
00662 #endif
00663 if ( colorMap.format() == QwtColorMap::Indexed )
00664 colorTable = colorMap.colorTable(interval);
00665
00666 QColor c;
00667
00668 const QRect devRect = d_metricsMap.layoutToDevice(rect);
00669
00670
00671
00672
00673
00674
00675 QPixmap pixmap(devRect.size());
00676 QPainter pmPainter(&pixmap);
00677 pmPainter.translate(-devRect.x(), -devRect.y());
00678
00679 if ( orientation == Qt::Horizontal )
00680 {
00681 QwtScaleMap sMap = scaleMap;
00682 sMap.setPaintInterval(devRect.left(), devRect.right());
00683
00684 for ( int x = devRect.left(); x <= devRect.right(); x++ )
00685 {
00686 const double value = sMap.invTransform(x);
00687
00688 if ( colorMap.format() == QwtColorMap::RGB )
00689 c.setRgb(colorMap.rgb(interval, value));
00690 else
00691 c = colorTable[colorMap.colorIndex(interval, value)];
00692
00693 pmPainter.setPen(c);
00694 pmPainter.drawLine(x, devRect.top(), x, devRect.bottom());
00695 }
00696 }
00697 else
00698 {
00699 QwtScaleMap sMap = scaleMap;
00700 sMap.setPaintInterval(devRect.bottom(), devRect.top());
00701
00702 for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
00703 {
00704 const double value = sMap.invTransform(y);
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(devRect.left(), y, devRect.right(), y);
00713 }
00714 }
00715 pmPainter.end();
00716 painter->drawPixmap(devRect, pixmap);
00717 }