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