Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

qwt_painter.cpp

00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 // vim: expandtab
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 #include <qpointarray.h>
00023 #define QwtPointArray QPointArray
00024 #else
00025 #include <qtextdocument.h>
00026 #include <qabstracttextdocumentlayout.h>
00027 #include <qstyleoption.h>
00028 #include <qpolygon.h>
00029 #define QwtPointArray QPolygon
00030 #endif
00031 
00032 #include "qwt_painter.h"
00033 #include "qwt_rect.h"
00034 #include "qwt_math.h"
00035 
00036 QwtMetricsMap QwtPainter::d_metricsMap;
00037 
00038 #if defined(Q_WS_X11)
00039 bool QwtPainter::d_deviceClipping = true;
00040 #else
00041 bool QwtPainter::d_deviceClipping = false;
00042 #endif
00043 
00049 void QwtPainter::setDeviceClipping(bool enable)
00050 {
00051     d_deviceClipping = enable;
00052 }
00053 
00060 bool QwtPainter::deviceClipping()
00061 {
00062     return d_deviceClipping;
00063 }
00064 
00069 const QRect &QwtPainter::deviceClipRect()
00070 {
00071     static QRect clip;
00072 
00073     if ( !clip.isValid() )
00074     {
00075         clip.setCoords(QWT_COORD_MIN, QWT_COORD_MIN,
00076             QWT_COORD_MAX, QWT_COORD_MAX);
00077     }
00078     return clip;
00079 }
00080 
00082 QwtPointArray QwtPainter::clip(const QwtPointArray &pa)
00083 {
00084     const QwtRect rect(deviceClipRect());
00085     return rect.clip(pa);
00086 }
00087 
00096 void QwtPainter::setMetricsMap(const QPaintDevice *layout,
00097     const QPaintDevice *device)
00098 {
00099     d_metricsMap.setMetrics(layout, device);
00100 }
00101 
00106 void QwtPainter::setMetricsMap(const QwtMetricsMap &map)
00107 {
00108     d_metricsMap = map;
00109 }
00110 
00115 void QwtPainter::resetMetricsMap()
00116 {
00117     d_metricsMap = QwtMetricsMap();
00118 }
00119 
00123 const QwtMetricsMap &QwtPainter::metricsMap()
00124 {
00125     return d_metricsMap;
00126 }
00127 
00131 void QwtPainter::setClipRect(QPainter *painter, const QRect &rect)
00132 {
00133     painter->setClipRect(d_metricsMap.layoutToDevice(rect, painter));
00134 }
00135 
00139 void QwtPainter::drawRect(QPainter *painter, int x, int y, int w, int h) 
00140 {
00141     drawRect(painter, QRect(x, y, w, h));
00142 }
00143 
00147 void QwtPainter::drawRect(QPainter *painter, const QRect &rect) 
00148 {
00149     const QRect r = d_metricsMap.layoutToDevice(rect, painter);
00150 
00151     QRect clipRect;
00152 
00153 #if QT_VERSION == 0x040000 
00154     /*
00155       Performance of Qt4.0.0 is horrible for non trivial brushs. Without
00156       clipping expect minutes or hours for repainting large rects
00157       (might result from zooming). Announced to be fixed in 4.0.1.
00158      */
00159     clipRect = painter->window();
00160     if ( painter->hasClipping() )
00161         clipRect &= painter->clipRegion().boundingRect();
00162     if ( d_deviceClipping )
00163         clipRect &= deviceClipRect();
00164 #else
00165     if ( d_deviceClipping )
00166         clipRect = deviceClipRect();
00167 #endif
00168     if ( clipRect.isValid() )
00169     {
00170         if ( !clipRect.intersects(r) )
00171             return;
00172 
00173         if ( !clipRect.contains(r) )
00174         {
00175             fillRect(painter, r & clipRect, painter->brush());
00176 
00177 #ifdef __GNUC__
00178 #warning alignment of rects needs to be checked
00179 #endif
00180             int pw = painter->pen().width();
00181             pw = pw % 2 + pw / 2;
00182 
00183             QwtPointArray pa(5);
00184             pa.setPoint(0, r.left(), r.top());
00185             pa.setPoint(1, r.right() - pw, r.top());
00186             pa.setPoint(2, r.right() - pw, r.bottom() - pw);
00187             pa.setPoint(3, r.left(), r.bottom() - pw);
00188             pa.setPoint(4, r.left(), r.top());
00189 
00190             painter->save();
00191             painter->setBrush(Qt::NoBrush);
00192             drawPolyline(painter, pa);
00193             painter->restore();
00194 
00195             return;
00196         }
00197     }
00198 
00199     painter->drawRect(r);
00200 }
00201 
00205 void QwtPainter::fillRect(QPainter *painter, 
00206     const QRect &rect, const QBrush &brush)
00207 {
00208     if ( !rect.isValid() )
00209         return;
00210 
00211     QRect clipRect;
00212 #if QT_VERSION >= 0x040000
00213 
00214     /*
00215       Performance of Qt4 is horrible for non trivial brushs. Without
00216       clipping expect minutes or hours for repainting large rects
00217       (might result from zooming)
00218     */
00219 
00220     clipRect = painter->window();
00221     if ( painter->hasClipping() )
00222         clipRect &= painter->clipRegion().boundingRect();
00223     if ( d_deviceClipping )
00224         clipRect &= deviceClipRect();
00225 #else
00226     if ( d_deviceClipping )
00227         clipRect = deviceClipRect();
00228 #endif
00229 
00230     QRect r = d_metricsMap.layoutToDevice(rect, painter);
00231     if ( clipRect.isValid() )
00232         r = r.intersect(clipRect);
00233 
00234     if ( r.isValid() )
00235         painter->fillRect(r, brush);
00236 }
00237 
00241 void QwtPainter::drawEllipse(QPainter *painter, const QRect &rect)
00242 {
00243     const QRect r = d_metricsMap.layoutToDevice(rect, painter);
00244 
00245     if ( d_deviceClipping && !deviceClipRect().contains(rect) )
00246         return;
00247 
00248     painter->drawEllipse(r);
00249 }
00250 
00254 void QwtPainter::drawText(QPainter *painter, int x, int y, 
00255         const QString &text)
00256 {
00257     drawText(painter, QPoint(x, y), text);
00258 }
00259 
00263 void QwtPainter::drawText(QPainter *painter, const QPoint &pos, 
00264         const QString &text)
00265 {
00266     const QPoint p = d_metricsMap.layoutToDevice(pos, painter);
00267 
00268     if ( d_deviceClipping && !deviceClipRect().contains(p) )
00269         return;
00270 
00271     painter->drawText(p, text);
00272 }
00273 
00277 void QwtPainter::drawText(QPainter *painter, int x, int y, int w, int h, 
00278         int flags, const QString &text)
00279 {
00280     drawText(painter, QRect(x, y, w, h), flags, text);
00281 }
00282 
00286 void QwtPainter::drawText(QPainter *painter, const QRect &rect, 
00287         int flags, const QString &text)
00288 {
00289     painter->drawText(
00290         d_metricsMap.layoutToDevice(rect, painter), flags, text);
00291 }
00292 
00293 #ifndef QT_NO_RICHTEXT
00294 
00298 #if QT_VERSION < 0x040000
00299 
00300 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00301     int flags, QSimpleRichText &text)
00302 {
00303     QColorGroup cg;
00304     cg.setColor(QColorGroup::Text, painter->pen().color());
00305 
00306     const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00307 
00308     text.setWidth(painter, scaledRect.width());
00309 
00310     // QSimpleRichText is Qt::AlignTop by default
00311 
00312     int y = scaledRect.y();
00313     if (flags & Qt::AlignBottom)
00314         y += (scaledRect.height() - text.height());
00315     else if (flags & Qt::AlignVCenter)
00316         y += (scaledRect.height() - text.height())/2;
00317 
00318     text.draw(painter, scaledRect.x(), y, scaledRect, cg);
00319 }
00320 #else
00321 void QwtPainter::drawSimpleRichText(QPainter *painter, const QRect &rect,
00322     int flags, QTextDocument &text)
00323 {
00324     const QRect scaledRect = d_metricsMap.layoutToDevice(rect, painter);
00325     text.setPageSize(QSize(scaledRect.width(), QWIDGETSIZE_MAX));
00326 
00327     QAbstractTextDocumentLayout* layout = text.documentLayout();
00328 
00329     const int height = qRound(layout->documentSize().height());
00330     int y = scaledRect.y();
00331     if (flags & Qt::AlignBottom)
00332         y += (scaledRect.height() - height);
00333     else if (flags & Qt::AlignVCenter)
00334         y += (scaledRect.height() - height)/2;
00335 
00336     QAbstractTextDocumentLayout::PaintContext context;
00337     context.palette.setColor(QPalette::Text, painter->pen().color());
00338 
00339     painter->save();
00340 
00341     painter->translate(scaledRect.x(), scaledRect.y());
00342     layout->draw(painter, context);
00343 
00344     painter->restore();
00345 }
00346 #endif
00347 
00348 #endif // !QT_NO_RICHTEXT
00349 
00350 
00354 void QwtPainter::drawLine(QPainter *painter, int x1, int y1, int x2, int y2)
00355 {
00356     if ( d_deviceClipping && 
00357         !(deviceClipRect().contains(x1, y1) && deviceClipRect().contains(x2, y2)) )
00358     {
00359         QwtPointArray pa(2);
00360         pa.setPoint(0, x1, y1);
00361         pa.setPoint(1, x2, y2);
00362         drawPolyline(painter, pa);
00363         return;
00364     }
00365 
00366     if ( d_metricsMap.isIdentity() )
00367     {
00368 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00369         if ( !painter->device()->isExtDev() )
00370 #endif
00371         {
00372             painter->drawLine(x1, y1, x2, y2);
00373             return;
00374         }
00375     }
00376 
00377     const QPoint p1 = d_metricsMap.layoutToDevice(QPoint(x1, y1));
00378     const QPoint p2 = d_metricsMap.layoutToDevice(QPoint(x2, y2));
00379 
00380 #if QT_VERSION >= 0x030200 && QT_VERSION < 0x040000
00381     if ( painter->device()->isExtDev() )
00382     {
00383         // Strange: the postscript driver of QPrinter adds an offset 
00384         // of 0.5 to the start/endpoint when using drawLine, but not
00385         // for lines painted with drawLineSegments.
00386 
00387         QwtPointArray pa(2);
00388         pa.setPoint(0, p1);
00389         pa.setPoint(1, p2);
00390         painter->drawLineSegments(pa);
00391     }
00392     else
00393         painter->drawLine(p1, p2);
00394 #else
00395     painter->drawLine(p1, p2);
00396 #endif
00397 }
00398 
00402 void QwtPainter::drawPolygon(QPainter *painter, const QwtPointArray &pa)
00403 {
00404     QwtPointArray cpa = d_metricsMap.layoutToDevice(pa);
00405     if ( d_deviceClipping )
00406     {
00407 #ifdef __GNUC__
00408 #warning clipping ignores painter transformations
00409 #endif
00410         cpa = clip(cpa);
00411     }
00412     painter->drawPolygon(cpa);
00413 }
00414 
00418 void QwtPainter::drawPolyline(QPainter *painter, const QwtPointArray &pa)
00419 {
00420     QwtPointArray cpa = d_metricsMap.layoutToDevice(pa);
00421     if ( d_deviceClipping )
00422         cpa = clip(cpa);
00423     painter->drawPolyline(cpa);
00424 }
00425 
00430 void QwtPainter::drawPoint(QPainter *painter, int x, int y)
00431 {
00432     const QPoint pos = d_metricsMap.layoutToDevice(QPoint(x, y));
00433 
00434     if ( d_deviceClipping && !deviceClipRect().contains(pos) )
00435         return;
00436 
00437     painter->drawPoint(pos);
00438 }
00439 
00440 void QwtPainter::drawColoredArc(QPainter *painter, const QRect &rect, 
00441     int peak, int arc, int interval, const QColor &c1, const QColor &c2)
00442 {
00443     int h1, s1, v1;
00444     int h2, s2, v2;
00445 
00446 #if QT_VERSION < 0x040000
00447     c1.hsv(&h1, &s1, &v1);
00448     c2.hsv(&h2, &s2, &v2);
00449 #else
00450     c1.getHsv(&h1, &s1, &v1);
00451     c2.getHsv(&h2, &s2, &v2);
00452 #endif
00453     
00454     arc /= 2;
00455     for ( int angle = -arc; angle < arc; angle += interval)
00456     {
00457         double ratio;
00458         if ( angle >= 0 )
00459             ratio = 1.0 - angle / double(arc);
00460         else
00461             ratio = 1.0 + angle / double(arc);
00462             
00463 
00464         QColor c;
00465         c.setHsv( h1 + qRound(ratio * (h2 - h1)),
00466             s1 + qRound(ratio * (s2 - s1)),
00467             v1 + qRound(ratio * (v2 - v1)) );
00468 
00469         painter->setPen(QPen(c, painter->pen().width()));
00470         painter->drawArc(rect, (peak + angle) * 16, interval * 16);
00471     }
00472 }
00473 
00474 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget)
00475 {
00476     drawFocusRect(painter, widget, widget->rect());
00477 }
00478 
00479 void QwtPainter::drawFocusRect(QPainter *painter, QWidget *widget,
00480     const QRect &rect)
00481 {
00482 #if QT_VERSION < 0x040000
00483         widget->style().drawPrimitive(QStyle::PE_FocusRect, painter,
00484             rect, widget->colorGroup());
00485 #else
00486         QStyleOptionFocusRect opt;
00487         opt.init(widget);
00488         opt.rect = rect;
00489         opt.state |= QStyle::State_HasFocus;
00490 
00491         widget->style()->drawPrimitive(QStyle::PE_FrameFocusRect, 
00492             &opt, painter, widget);
00493 #endif
00494 
00495 }
00496 
00498 #if QT_VERSION < 0x040000
00499 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00500     int width, const QColorGroup &cg, bool sunken)
00501 #else
00502 void QwtPainter::drawRoundFrame(QPainter *painter, const QRect &rect,
00503     int width, const QPalette &palette, bool sunken)
00504 #endif
00505 {
00506 
00507 #if QT_VERSION < 0x040000
00508     QColor c0 = cg.mid();
00509     QColor c1, c2;
00510     if ( sunken )
00511     {
00512         c1 = cg.dark();
00513         c2 = cg.light();
00514     }
00515     else
00516     {
00517         c1 = cg.light();
00518         c2 = cg.dark();
00519     }
00520 #else
00521     QColor c0 = palette.color(QPalette::Mid);
00522     QColor c1, c2;
00523     if ( sunken )
00524     {
00525         c1 = palette.color(QPalette::Dark);
00526         c2 = palette.color(QPalette::Light);
00527     }
00528     else
00529     {
00530         c1 = palette.color(QPalette::Light);
00531         c2 = palette.color(QPalette::Dark);
00532     }
00533 #endif
00534 
00535     painter->setPen(QPen(c0, width));
00536     painter->drawArc(rect, 0, 360 * 16); // full
00537 
00538     const int peak = 150;
00539     const int interval = 2;
00540 
00541     if ( c0 != c1 )
00542         drawColoredArc(painter, rect, peak, 160, interval, c0, c1);
00543     if ( c0 != c2 )
00544         drawColoredArc(painter, rect, peak + 180, 120, interval, c0, c2);
00545 }

Generated on Mon Jan 30 22:16:25 2006 for Qwt User's Guide by  doxygen 1.4.4