qwt_painter.cpp
Go to the documentation of this file.
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 #include "qwt_painter.h"
00011 #include "qwt_math.h"
00012 #include "qwt_clipper.h"
00013 #include "qwt_color_map.h"
00014 #include "qwt_scale_map.h"
00015 #include <qwindowdefs.h>
00016 #include <qwidget.h>
00017 #include <qframe.h>
00018 #include <qrect.h>
00019 #include <qpainter.h>
00020 #include <qpalette.h>
00021 #include <qpaintdevice.h>
00022 #include <qpixmap.h>
00023 #include <qstyle.h>
00024 #include <qtextdocument.h>
00025 #include <qabstracttextdocumentlayout.h>
00026 #include <qstyleoption.h>
00027 #include <qpaintengine.h>
00028 #include <qapplication.h>
00029 #include <qdesktopwidget.h>
00030 
00031 #if QT_VERSION >= 0x050000
00032 #include <qwindow.h>
00033 #endif
00034 
00035 #if QT_VERSION < 0x050000 
00036 
00037 #ifdef Q_WS_X11
00038 #include <qx11info_x11.h>
00039 #endif
00040 
00041 #endif
00042 
00043 bool QwtPainter::d_polylineSplitting = true;
00044 bool QwtPainter::d_roundingAlignment = true;
00045 
00046 static inline bool qwtIsRasterPaintEngineBuggy()
00047 {
00048 #if 0
00049     static int isBuggy = -1; 
00050     if ( isBuggy < 0 )
00051     {
00052         // auto detect bug of the raster paint engine,
00053         // fixed with: https://codereview.qt-project.org/#/c/99456/
00054 
00055         QImage image( 2, 3, QImage::Format_ARGB32 );
00056         image.fill( 0u );
00057 
00058         QPolygonF p;
00059         p += QPointF(0, 1);
00060         p += QPointF(0, 0);
00061         p += QPointF(1, 0 );
00062         p += QPointF(1, 2 );
00063 
00064         QPainter painter( &image );
00065         painter.drawPolyline( p );
00066         painter.end();
00067 
00068         isBuggy = ( image.pixel( 1, 1 ) == 0 ) ? 1 : 0;
00069     }
00070 
00071     return isBuggy == 1;
00072 #endif
00073 
00074 #if QT_VERSION < 0x040800
00075     return false;
00076 #elif QT_VERSION < 0x050000
00077     return true;
00078 #elif QT_VERSION < 0x050100
00079     return false;
00080 #elif QT_VERSION < 0x050400
00081     return true;
00082 #else
00083     return false;
00084 #endif
00085 }
00086 
00087 static inline bool qwtIsClippingNeeded( 
00088     const QPainter *painter, QRectF &clipRect )
00089 {
00090     bool doClipping = false;
00091     const QPaintEngine *pe = painter->paintEngine();
00092     if ( pe && pe->type() == QPaintEngine::SVG )
00093     {
00094         // The SVG paint engine ignores any clipping,
00095 
00096         if ( painter->hasClipping() )
00097         {
00098             doClipping = true;
00099             clipRect = painter->clipRegion().boundingRect();
00100         }
00101     }
00102 
00103     return doClipping;
00104 }
00105 
00106 template <class T>
00107 static inline void qwtDrawPolyline( QPainter *painter,
00108     const T *points, int pointCount, bool polylineSplitting )
00109 {
00110     bool doSplit = false;
00111     if ( polylineSplitting && pointCount > 3 )
00112     {
00113         const QPaintEngine *pe = painter->paintEngine();
00114         if ( pe && pe->type() == QPaintEngine::Raster )
00115         {
00116             if ( painter->pen().width() <= 1 )
00117             {
00118 #if QT_VERSION < 0x040800
00119                 if ( painter->renderHints() & QPainter::Antialiasing )
00120                 {
00121                     /*
00122                         all versions <= 4.7 have issues with 
00123                         antialiased lines
00124                      */
00125 
00126                     doSplit = true;
00127                 }
00128 #endif
00129                 // work around a bug with short lines below 2 pixels difference
00130                 // in height and width
00131 
00132                 doSplit = qwtIsRasterPaintEngineBuggy();
00133             }
00134             else
00135             {
00136                 /*
00137                    Raster paint engine is much faster when splitting
00138                    the polygon, but of course we might see some issues where
00139                    the pieces are joining
00140                  */
00141                 doSplit = true;
00142             }
00143         }
00144     }
00145 
00146     if ( doSplit )
00147     {
00148         QPen pen = painter->pen();
00149 
00150         const int splitSize = 6;
00151 
00152         if ( pen.width() <= 1 && pen.isSolid() && qwtIsRasterPaintEngineBuggy()
00153             && !( painter->renderHints() & QPainter::Antialiasing ) )
00154         {
00155             int k = 0;
00156 
00157             for ( int i = k + 1; i < pointCount; i++ )
00158             {
00159                 const QPointF &p1 = points[i-1];
00160                 const QPointF &p2 = points[i];
00161 
00162                 const bool isBad = ( qAbs( p2.y() - p1.y() ) <= 1 )
00163                     &&  qAbs( p2.x() - p1.x() ) <= 1;
00164 
00165                 if ( isBad || ( i - k >= splitSize ) )
00166                 {
00167                     painter->drawPolyline( points + k, i - k + 1 );
00168                     k = i;
00169                 }
00170             }
00171 
00172             painter->drawPolyline( points + k, pointCount - k );
00173         }
00174         else
00175         {
00176             for ( int i = 0; i < pointCount; i += splitSize )
00177             {
00178                 const int n = qMin( splitSize + 1, pointCount - i );
00179                 painter->drawPolyline( points + i, n );
00180             }
00181         }
00182     }
00183     else
00184     {
00185         painter->drawPolyline( points, pointCount );
00186     }
00187 }
00188 
00189 static inline QSize qwtScreenResolution()
00190 {
00191     static QSize screenResolution;
00192     if ( !screenResolution.isValid() )
00193     {
00194         QDesktopWidget *desktop = QApplication::desktop();
00195         if ( desktop )
00196         {
00197             screenResolution.setWidth( desktop->logicalDpiX() );
00198             screenResolution.setHeight( desktop->logicalDpiY() );
00199         }
00200     }
00201 
00202     return screenResolution;
00203 }
00204 
00205 static inline void qwtUnscaleFont( QPainter *painter )
00206 {
00207     if ( painter->font().pixelSize() >= 0 )
00208         return;
00209 
00210     const QSize screenResolution = qwtScreenResolution();
00211 
00212     const QPaintDevice *pd = painter->device();
00213     if ( pd->logicalDpiX() != screenResolution.width() ||
00214         pd->logicalDpiY() != screenResolution.height() )
00215     {
00216         QFont pixelFont( painter->font(), QApplication::desktop() );
00217         pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() );
00218 
00219         painter->setFont( pixelFont );
00220     }
00221 }
00222 
00230 bool QwtPainter::isX11GraphicsSystem()
00231 {
00232 #if QT_VERSION < 0x050000
00233     static int onX11 = -1;
00234     if ( onX11 < 0 )
00235     {
00236         QPixmap pm( 1, 1 );
00237         QPainter painter( &pm );
00238 
00239         onX11 = ( painter.paintEngine()->type() == QPaintEngine::X11 ) ? 1 : 0;
00240     }
00241 
00242     return onX11 == 1;
00243 #else
00244     // the X11 paint engine has been removed with Qt5 - so sad, as it was
00245     // the best available graphic system around: no bugs + hardware accelerated.
00246     return false;
00247 #endif
00248 }
00249 
00264 bool QwtPainter::isAligning( QPainter *painter )
00265 {
00266     if ( painter && painter->isActive() )
00267     {
00268         switch ( painter->paintEngine()->type() )
00269         {
00270             case QPaintEngine::Pdf:
00271             case QPaintEngine::SVG:
00272                 return false;
00273 
00274             default:;
00275         }
00276 
00277         const QTransform tr = painter->transform();
00278         if ( tr.isRotating() || tr.isScaling() )
00279         {
00280             // we might have to check translations too
00281             return false;
00282         }
00283     }
00284 
00285     return true;
00286 }
00287 
00299 void QwtPainter::setRoundingAlignment( bool enable )
00300 {
00301     d_roundingAlignment = enable;
00302 }
00303 
00319 void QwtPainter::setPolylineSplitting( bool enable )
00320 {
00321     d_polylineSplitting = enable;
00322 }
00323 
00325 void QwtPainter::drawPath( QPainter *painter, const QPainterPath &path )
00326 {
00327     painter->drawPath( path );
00328 }
00329 
00331 void QwtPainter::drawRect( QPainter *painter, double x, double y, double w, double h )
00332 {
00333     drawRect( painter, QRectF( x, y, w, h ) );
00334 }
00335 
00337 void QwtPainter::drawRect( QPainter *painter, const QRectF &rect )
00338 {
00339     const QRectF r = rect;
00340 
00341     QRectF clipRect;
00342     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00343 
00344     if ( deviceClipping )
00345     {
00346         if ( !clipRect.intersects( r ) )
00347             return;
00348 
00349         if ( !clipRect.contains( r ) )
00350         {
00351             fillRect( painter, r & clipRect, painter->brush() );
00352 
00353             painter->save();
00354             painter->setBrush( Qt::NoBrush );
00355             drawPolyline( painter, QPolygonF( r ) );
00356             painter->restore();
00357 
00358             return;
00359         }
00360     }
00361 
00362     painter->drawRect( r );
00363 }
00364 
00366 void QwtPainter::fillRect( QPainter *painter,
00367     const QRectF &rect, const QBrush &brush )
00368 {
00369     if ( !rect.isValid() )
00370         return;
00371 
00372     QRectF clipRect;
00373     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00374 
00375     /*
00376       Performance of Qt4 is horrible for a non trivial brush. Without
00377       clipping expect minutes or hours for repainting large rectangles
00378       (might result from zooming)
00379     */
00380 
00381     if ( deviceClipping )
00382         clipRect &= painter->window();
00383     else
00384         clipRect = painter->window();
00385 
00386     if ( painter->hasClipping() )
00387         clipRect &= painter->clipRegion().boundingRect();
00388 
00389     QRectF r = rect;
00390     if ( deviceClipping )
00391         r = r.intersected( clipRect );
00392 
00393     if ( r.isValid() )
00394         painter->fillRect( r, brush );
00395 }
00396 
00398 void QwtPainter::drawPie( QPainter *painter, const QRectF &rect,
00399     int a, int alen )
00400 {
00401     QRectF clipRect;
00402     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00403     if ( deviceClipping && !clipRect.contains( rect ) )
00404         return;
00405 
00406     painter->drawPie( rect, a, alen );
00407 }
00408 
00410 void QwtPainter::drawEllipse( QPainter *painter, const QRectF &rect )
00411 {
00412     QRectF clipRect;
00413     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00414 
00415     if ( deviceClipping && !clipRect.contains( rect ) )
00416         return;
00417 
00418     painter->drawEllipse( rect );
00419 }
00420 
00422 void QwtPainter::drawText( QPainter *painter, double x, double y,
00423         const QString &text )
00424 {
00425     drawText( painter, QPointF( x, y ), text );
00426 }
00427 
00429 void QwtPainter::drawText( QPainter *painter, const QPointF &pos,
00430         const QString &text )
00431 {
00432     QRectF clipRect;
00433     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00434 
00435     if ( deviceClipping && !clipRect.contains( pos ) )
00436         return;
00437 
00438 
00439     painter->save();
00440     qwtUnscaleFont( painter );
00441     painter->drawText( pos, text );
00442     painter->restore();
00443 }
00444 
00446 void QwtPainter::drawText( QPainter *painter,
00447     double x, double y, double w, double h,
00448     int flags, const QString &text )
00449 {
00450     drawText( painter, QRectF( x, y, w, h ), flags, text );
00451 }
00452 
00454 void QwtPainter::drawText( QPainter *painter, const QRectF &rect,
00455         int flags, const QString &text )
00456 {
00457     painter->save();
00458     qwtUnscaleFont( painter );
00459     painter->drawText( rect, flags, text );
00460     painter->restore();
00461 }
00462 
00463 #ifndef QT_NO_RICHTEXT
00464 
00473 void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect,
00474     int flags, const QTextDocument &text )
00475 {
00476     QTextDocument *txt = text.clone();
00477 
00478     painter->save();
00479 
00480     QRectF unscaledRect = rect;
00481 
00482     if ( painter->font().pixelSize() < 0 )
00483     {
00484         const QSize res = qwtScreenResolution();
00485 
00486         const QPaintDevice *pd = painter->device();
00487         if ( pd->logicalDpiX() != res.width() ||
00488             pd->logicalDpiY() != res.height() )
00489         {
00490             QTransform transform;
00491             transform.scale( res.width() / double( pd->logicalDpiX() ),
00492                 res.height() / double( pd->logicalDpiY() ));
00493 
00494             painter->setWorldTransform( transform, true );
00495             unscaledRect = transform.inverted().mapRect(rect);
00496         }
00497     }  
00498 
00499     txt->setDefaultFont( painter->font() );
00500     txt->setPageSize( QSizeF( unscaledRect.width(), QWIDGETSIZE_MAX ) );
00501 
00502     QAbstractTextDocumentLayout* layout = txt->documentLayout();
00503 
00504     const double height = layout->documentSize().height();
00505     double y = unscaledRect.y();
00506     if ( flags & Qt::AlignBottom )
00507         y += ( unscaledRect.height() - height );
00508     else if ( flags & Qt::AlignVCenter )
00509         y += ( unscaledRect.height() - height ) / 2;
00510 
00511     QAbstractTextDocumentLayout::PaintContext context;
00512     context.palette.setColor( QPalette::Text, painter->pen().color() );
00513 
00514     painter->translate( unscaledRect.x(), y );
00515     layout->draw( painter, context );
00516 
00517     painter->restore();
00518     delete txt;
00519 }
00520 
00521 #endif // !QT_NO_RICHTEXT
00522 
00523 
00525 void QwtPainter::drawLine( QPainter *painter,
00526     const QPointF &p1, const QPointF &p2 )
00527 {
00528     QRectF clipRect;
00529     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00530 
00531     if ( deviceClipping &&
00532         !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) )
00533     {
00534         QPolygonF polygon;
00535         polygon += p1;
00536         polygon += p2;
00537         drawPolyline( painter, polygon );
00538         return;
00539     }
00540 
00541     painter->drawLine( p1, p2 );
00542 }
00543 
00545 void QwtPainter::drawPolygon( QPainter *painter, const QPolygonF &polygon )
00546 {
00547     QRectF clipRect;
00548     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00549 
00550     if ( deviceClipping )
00551     {
00552         painter->drawPolygon(
00553             QwtClipper::clippedPolygonF( clipRect, polygon, true ) );
00554     }
00555     else
00556     {
00557         painter->drawPolygon( polygon );
00558     }
00559 }
00560 
00562 void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon )
00563 {
00564     QRectF clipRect;
00565     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00566 
00567     if ( deviceClipping )
00568     {
00569         const QPolygonF cpa = QwtClipper::clippedPolygonF( clipRect, polygon );
00570 
00571         qwtDrawPolyline<QPointF>( painter,
00572             cpa.constData(), cpa.size(), d_polylineSplitting );
00573     }
00574     else
00575     {
00576         qwtDrawPolyline<QPointF>( painter,
00577             polygon.constData(), polygon.size(), d_polylineSplitting );
00578     }
00579 }
00580 
00582 void QwtPainter::drawPolyline( QPainter *painter,
00583     const QPointF *points, int pointCount )
00584 {
00585     QRectF clipRect;
00586     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00587 
00588     if ( deviceClipping )
00589     {
00590         QPolygonF polygon( pointCount );
00591         ::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) );
00592 
00593         QwtClipper::clipPolygonF( clipRect, polygon );
00594         qwtDrawPolyline<QPointF>( painter,
00595             polygon.constData(), polygon.size(), d_polylineSplitting );
00596     }
00597     else
00598     {
00599         qwtDrawPolyline<QPointF>( painter, points, pointCount, d_polylineSplitting );
00600     }
00601 }
00602 
00604 void QwtPainter::drawPolygon( QPainter *painter, const QPolygon &polygon )
00605 {
00606     QRectF clipRect;
00607     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00608 
00609     if ( deviceClipping )
00610     {
00611         painter->drawPolygon(
00612             QwtClipper::clippedPolygon( clipRect, polygon, true ) );
00613     }
00614     else
00615     {
00616         painter->drawPolygon( polygon );
00617     }
00618 }
00619 
00621 void QwtPainter::drawPolyline( QPainter *painter, const QPolygon &polygon )
00622 {
00623     QRectF clipRect;
00624     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00625 
00626     if ( deviceClipping )
00627     {
00628         const QPolygon cpa = QwtClipper::clippedPolygon( clipRect, polygon );
00629 
00630         qwtDrawPolyline<QPoint>( painter,
00631             cpa.constData(), cpa.size(), d_polylineSplitting );
00632     }
00633     else
00634     {
00635         qwtDrawPolyline<QPoint>( painter,
00636             polygon.constData(), polygon.size(), d_polylineSplitting );
00637     }
00638 }
00639 
00641 void QwtPainter::drawPolyline( QPainter *painter,
00642     const QPoint *points, int pointCount )
00643 {
00644     QRectF clipRect;
00645     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00646 
00647     if ( deviceClipping )
00648     {
00649         QPolygon polygon( pointCount );
00650         ::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) );
00651 
00652         QwtClipper::clipPolygon( clipRect, polygon );
00653         qwtDrawPolyline<QPoint>( painter,
00654             polygon.constData(), polygon.size(), d_polylineSplitting );
00655     }
00656     else
00657     {
00658         qwtDrawPolyline<QPoint>( painter, points, pointCount, d_polylineSplitting );
00659     }
00660 }
00661 
00663 void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos )
00664 {
00665     QRectF clipRect;
00666     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00667 
00668     if ( deviceClipping && !clipRect.contains( pos ) )
00669         return;
00670 
00671     painter->drawPoint( pos );
00672 }
00673 
00675 void QwtPainter::drawPoint( QPainter *painter, const QPoint &pos )
00676 {
00677     QRectF clipRect;
00678     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00679 
00680     if ( deviceClipping )
00681     {
00682         const int minX = qCeil( clipRect.left() );
00683         const int maxX = qFloor( clipRect.right() );
00684         const int minY = qCeil( clipRect.top() );
00685         const int maxY = qFloor( clipRect.bottom() );
00686 
00687         if ( pos.x() < minX || pos.x() > maxX 
00688             || pos.y() < minY || pos.y() > maxY )
00689         {
00690             return;
00691         }
00692     }
00693 
00694     painter->drawPoint( pos );
00695 }
00696 
00698 void QwtPainter::drawPoints( QPainter *painter, 
00699     const QPoint *points, int pointCount )
00700 {
00701     QRectF clipRect;
00702     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00703 
00704     if ( deviceClipping )
00705     {
00706         const int minX = qCeil( clipRect.left() );
00707         const int maxX = qFloor( clipRect.right() );
00708         const int minY = qCeil( clipRect.top() );
00709         const int maxY = qFloor( clipRect.bottom() );
00710 
00711         const QRect r( minX, minY, maxX - minX, maxY - minY );
00712 
00713         QPolygon clippedPolygon( pointCount );
00714         QPoint *clippedData = clippedPolygon.data();
00715 
00716         int numClippedPoints = 0;
00717         for ( int i = 0; i < pointCount; i++ )
00718         {
00719             if ( r.contains( points[i] ) )
00720                 clippedData[ numClippedPoints++ ] = points[i];
00721         }
00722         painter->drawPoints( clippedData, numClippedPoints );
00723     }
00724     else
00725     {
00726         painter->drawPoints( points, pointCount );
00727     }
00728 }
00729 
00731 void QwtPainter::drawPoints( QPainter *painter, 
00732     const QPointF *points, int pointCount )
00733 {
00734     QRectF clipRect;
00735     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00736 
00737     if ( deviceClipping )
00738     {
00739         QPolygonF clippedPolygon( pointCount );
00740         QPointF *clippedData = clippedPolygon.data();
00741 
00742         int numClippedPoints = 0;
00743         for ( int i = 0; i < pointCount; i++ )
00744         {
00745             if ( clipRect.contains( points[i] ) )
00746                 clippedData[ numClippedPoints++ ] = points[i];
00747         }
00748         painter->drawPoints( clippedData, numClippedPoints );
00749     }
00750     else
00751     {
00752         painter->drawPoints( points, pointCount );
00753     }
00754 }
00755 
00757 void QwtPainter::drawImage( QPainter *painter,
00758     const QRectF &rect, const QImage &image )
00759 {
00760     const QRect alignedRect = rect.toAlignedRect();
00761 
00762     if ( alignedRect != rect )
00763     {
00764         const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00765 
00766         painter->save();
00767         painter->setClipRect( clipRect, Qt::IntersectClip );
00768         painter->drawImage( alignedRect, image );
00769         painter->restore();
00770     }
00771     else
00772     {
00773         painter->drawImage( alignedRect, image );
00774     }
00775 }
00776 
00778 void QwtPainter::drawPixmap( QPainter *painter,
00779     const QRectF &rect, const QPixmap &pixmap )
00780 {
00781     const QRect alignedRect = rect.toAlignedRect();
00782 
00783     if ( alignedRect != rect )
00784     {
00785         const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00786 
00787         painter->save();
00788         painter->setClipRect( clipRect, Qt::IntersectClip );
00789         painter->drawPixmap( alignedRect, pixmap );
00790         painter->restore();
00791     }
00792     else
00793     {
00794         painter->drawPixmap( alignedRect, pixmap );
00795     }
00796 }
00797 
00799 void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget )
00800 {
00801     drawFocusRect( painter, widget, widget->rect() );
00802 }
00803 
00805 void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget,
00806     const QRect &rect )
00807 {
00808     QStyleOptionFocusRect opt;
00809     opt.init( widget );
00810     opt.rect = rect;
00811     opt.state |= QStyle::State_HasFocus;
00812     opt.backgroundColor = widget->palette().color( widget->backgroundRole() );
00813 
00814     widget->style()->drawPrimitive(
00815         QStyle::PE_FrameFocusRect, &opt, painter, widget );
00816 }
00817 
00829 void QwtPainter::drawRoundFrame( QPainter *painter,
00830     const QRectF &rect, const QPalette &palette, 
00831     int lineWidth, int frameStyle )
00832 {
00833     enum Style
00834     {
00835         Plain,
00836         Sunken,
00837         Raised
00838     };
00839 
00840     Style style = Plain;
00841     if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
00842         style = Sunken;
00843     else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
00844         style = Raised;
00845 
00846     const double lw2 = 0.5 * lineWidth;
00847     QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
00848 
00849     QBrush brush;
00850 
00851     if ( style != Plain )
00852     {
00853         QColor c1 = palette.color( QPalette::Light );
00854         QColor c2 = palette.color( QPalette::Dark );
00855 
00856         if ( style == Sunken )
00857             qSwap( c1, c2 );
00858 
00859         QLinearGradient gradient( r.topLeft(), r.bottomRight() );
00860         gradient.setColorAt( 0.0, c1 );
00861 #if 0
00862         gradient.setColorAt( 0.3, c1 );
00863         gradient.setColorAt( 0.7, c2 );
00864 #endif
00865         gradient.setColorAt( 1.0, c2 );
00866 
00867         brush = QBrush( gradient );
00868     }
00869     else // Plain
00870     {
00871         brush = palette.brush( QPalette::WindowText );
00872     }
00873 
00874     painter->save();
00875 
00876     painter->setPen( QPen( brush, lineWidth ) );
00877     painter->setBrush( Qt::NoBrush );
00878 
00879     painter->drawEllipse( r );
00880 
00881     painter->restore();
00882 }
00883 
00895 void QwtPainter::drawFrame( QPainter *painter, const QRectF &rect,
00896     const QPalette &palette, QPalette::ColorRole foregroundRole,
00897     int frameWidth, int midLineWidth, int frameStyle )
00898 {
00899     if ( frameWidth <= 0 || rect.isEmpty() )
00900         return;
00901 
00902     const int shadow = frameStyle & QFrame::Shadow_Mask;
00903 
00904     painter->save();
00905 
00906     if ( shadow == QFrame::Plain )
00907     {
00908         const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00909         const QRectF innerRect = outerRect.adjusted( 
00910             frameWidth, frameWidth, -frameWidth, -frameWidth );
00911 
00912         QPainterPath path;
00913         path.addRect( outerRect );
00914         path.addRect( innerRect );
00915 
00916         painter->setPen( Qt::NoPen );
00917         painter->setBrush( palette.color( foregroundRole ) );
00918 
00919         painter->drawPath( path );
00920     }
00921     else
00922     {
00923         const int shape = frameStyle & QFrame::Shape_Mask;
00924 
00925         if ( shape == QFrame::Box )
00926         {
00927             const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00928             const QRectF midRect1 = outerRect.adjusted( 
00929                 frameWidth, frameWidth, -frameWidth, -frameWidth );
00930             const QRectF midRect2 = midRect1.adjusted( 
00931                 midLineWidth, midLineWidth, -midLineWidth, -midLineWidth );
00932 
00933             const QRectF innerRect = midRect2.adjusted( 
00934                 frameWidth, frameWidth, -frameWidth, -frameWidth );
00935 
00936             QPainterPath path1;
00937             path1.moveTo( outerRect.bottomLeft() );
00938             path1.lineTo( outerRect.topLeft() );
00939             path1.lineTo( outerRect.topRight() );
00940             path1.lineTo( midRect1.topRight() );
00941             path1.lineTo( midRect1.topLeft() );
00942             path1.lineTo( midRect1.bottomLeft() );
00943 
00944             QPainterPath path2;
00945             path2.moveTo( outerRect.bottomLeft() );
00946             path2.lineTo( outerRect.bottomRight() );
00947             path2.lineTo( outerRect.topRight() );
00948             path2.lineTo( midRect1.topRight() );
00949             path2.lineTo( midRect1.bottomRight() );
00950             path2.lineTo( midRect1.bottomLeft() );
00951 
00952             QPainterPath path3;
00953             path3.moveTo( midRect2.bottomLeft() );
00954             path3.lineTo( midRect2.topLeft() );
00955             path3.lineTo( midRect2.topRight() );
00956             path3.lineTo( innerRect.topRight() );
00957             path3.lineTo( innerRect.topLeft() );
00958             path3.lineTo( innerRect.bottomLeft() );
00959 
00960             QPainterPath path4;
00961             path4.moveTo( midRect2.bottomLeft() );
00962             path4.lineTo( midRect2.bottomRight() );
00963             path4.lineTo( midRect2.topRight() );
00964             path4.lineTo( innerRect.topRight() );
00965             path4.lineTo( innerRect.bottomRight() );
00966             path4.lineTo( innerRect.bottomLeft() );
00967 
00968             QPainterPath path5;
00969             path5.addRect( midRect1 );
00970             path5.addRect( midRect2 );
00971 
00972             painter->setPen( Qt::NoPen );
00973 
00974             QBrush brush1 = palette.dark().color();
00975             QBrush brush2 = palette.light().color();
00976 
00977             if ( shadow == QFrame::Raised )
00978                 qSwap( brush1, brush2 );
00979 
00980             painter->setBrush( brush1 );
00981             painter->drawPath( path1 );
00982             painter->drawPath( path4 );
00983 
00984             painter->setBrush( brush2 );
00985             painter->drawPath( path2 );
00986             painter->drawPath( path3 );
00987 
00988             painter->setBrush( palette.mid() );
00989             painter->drawPath( path5 );
00990         }
00991 #if 0
00992         // qDrawWinPanel doesn't result in something nice
00993         // on a scalable document like PDF. Better draw a
00994         // Panel.
00995 
00996         else if ( shape == QFrame::WinPanel )
00997         {
00998             painter->setRenderHint( QPainter::NonCosmeticDefaultPen, true );
00999             qDrawWinPanel ( painter, rect.toRect(), palette,
01000                 frameStyle & QFrame::Sunken );
01001         }
01002         else if ( shape == QFrame::StyledPanel )
01003         {
01004         }
01005 #endif
01006         else
01007         {
01008             const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
01009             const QRectF innerRect = outerRect.adjusted( 
01010                 frameWidth - 1.0, frameWidth - 1.0, 
01011                 -( frameWidth - 1.0 ), -( frameWidth - 1.0 ) );
01012 
01013             QPainterPath path1;
01014             path1.moveTo( outerRect.bottomLeft() );
01015             path1.lineTo( outerRect.topLeft() );
01016             path1.lineTo( outerRect.topRight() );
01017             path1.lineTo( innerRect.topRight() );
01018             path1.lineTo( innerRect.topLeft() );
01019             path1.lineTo( innerRect.bottomLeft() );
01020 
01021 
01022             QPainterPath path2;
01023             path2.moveTo( outerRect.bottomLeft() );
01024             path2.lineTo( outerRect.bottomRight() );
01025             path2.lineTo( outerRect.topRight() );
01026             path2.lineTo( innerRect.topRight() );
01027             path2.lineTo( innerRect.bottomRight() );
01028             path2.lineTo( innerRect.bottomLeft() );
01029 
01030             painter->setPen( Qt::NoPen );
01031 
01032             QBrush brush1 = palette.dark().color();
01033             QBrush brush2 = palette.light().color();
01034 
01035             if ( shadow == QFrame::Raised )
01036                 qSwap( brush1, brush2 );
01037 
01038             painter->setBrush( brush1 );
01039             painter->drawPath( path1 );
01040 
01041             painter->setBrush( brush2 );
01042             painter->drawPath( path2 );
01043         }
01044 
01045     }
01046 
01047     painter->restore();
01048 }
01049 
01064 void QwtPainter::drawRoundedFrame( QPainter *painter, 
01065     const QRectF &rect, double xRadius, double yRadius, 
01066     const QPalette &palette, int lineWidth, int frameStyle )
01067 {
01068     painter->save();
01069     painter->setRenderHint( QPainter::Antialiasing, true );
01070     painter->setBrush( Qt::NoBrush );
01071 
01072     double lw2 = lineWidth * 0.5;
01073     QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
01074 
01075     QPainterPath path;
01076     path.addRoundedRect( r, xRadius, yRadius );
01077 
01078     enum Style
01079     {
01080         Plain,
01081         Sunken,
01082         Raised
01083     };
01084 
01085     Style style = Plain;
01086     if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
01087         style = Sunken;
01088     else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
01089         style = Raised;
01090 
01091     if ( style != Plain && path.elementCount() == 17 )
01092     {
01093         // move + 4 * ( cubicTo + lineTo )
01094         QPainterPath pathList[8];
01095         
01096         for ( int i = 0; i < 4; i++ )
01097         {
01098             const int j = i * 4 + 1;
01099             
01100             pathList[ 2 * i ].moveTo(
01101                 path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
01102             );  
01103             
01104             pathList[ 2 * i ].cubicTo(
01105                 path.elementAt(j + 0).x, path.elementAt(j + 0).y,
01106                 path.elementAt(j + 1).x, path.elementAt(j + 1).y,
01107                 path.elementAt(j + 2).x, path.elementAt(j + 2).y );
01108                 
01109             pathList[ 2 * i + 1 ].moveTo(
01110                 path.elementAt(j + 2).x, path.elementAt(j + 2).y
01111             );  
01112             pathList[ 2 * i + 1 ].lineTo(
01113                 path.elementAt(j + 3).x, path.elementAt(j + 3).y
01114             );  
01115         }   
01116 
01117         QColor c1( palette.color( QPalette::Dark ) );
01118         QColor c2( palette.color( QPalette::Light ) );
01119 
01120         if ( style == Raised )
01121             qSwap( c1, c2 );
01122 
01123         for ( int i = 0; i < 4; i++ )
01124         {
01125             QRectF r = pathList[2 * i].controlPointRect();
01126 
01127             QPen arcPen;
01128             arcPen.setCapStyle( Qt::FlatCap );
01129             arcPen.setWidth( lineWidth );
01130 
01131             QPen linePen;
01132             linePen.setCapStyle( Qt::FlatCap );
01133             linePen.setWidth( lineWidth );
01134 
01135             switch( i )
01136             {
01137                 case 0:
01138                 {
01139                     arcPen.setColor( c1 );
01140                     linePen.setColor( c1 );
01141                     break;
01142                 }
01143                 case 1:
01144                 {
01145                     QLinearGradient gradient;
01146                     gradient.setStart( r.topLeft() );
01147                     gradient.setFinalStop( r.bottomRight() );
01148                     gradient.setColorAt( 0.0, c1 );
01149                     gradient.setColorAt( 1.0, c2 );
01150 
01151                     arcPen.setBrush( gradient );
01152                     linePen.setColor( c2 );
01153                     break;
01154                 }
01155                 case 2:
01156                 {
01157                     arcPen.setColor( c2 );
01158                     linePen.setColor( c2 );
01159                     break;
01160                 }
01161                 case 3:
01162                 {
01163                     QLinearGradient gradient;
01164 
01165                     gradient.setStart( r.bottomRight() );
01166                     gradient.setFinalStop( r.topLeft() );
01167                     gradient.setColorAt( 0.0, c2 );
01168                     gradient.setColorAt( 1.0, c1 );
01169 
01170                     arcPen.setBrush( gradient );
01171                     linePen.setColor( c1 );
01172                     break;
01173                 }
01174             }
01175 
01176 
01177             painter->setPen( arcPen );
01178             painter->drawPath( pathList[ 2 * i] );
01179 
01180             painter->setPen( linePen );
01181             painter->drawPath( pathList[ 2 * i + 1] );
01182         }
01183     }
01184     else
01185     {
01186         QPen pen( palette.color( QPalette::WindowText ), lineWidth );
01187         painter->setPen( pen );
01188         painter->drawPath( path );
01189     }
01190 
01191     painter->restore();
01192 }
01193 
01204 void QwtPainter::drawColorBar( QPainter *painter,
01205         const QwtColorMap &colorMap, const QwtInterval &interval,
01206         const QwtScaleMap &scaleMap, Qt::Orientation orientation,
01207         const QRectF &rect )
01208 {
01209     QVector<QRgb> colorTable;
01210     if ( colorMap.format() == QwtColorMap::Indexed )
01211         colorTable = colorMap.colorTable256();
01212 
01213     QColor c;
01214 
01215     const QRect devRect = rect.toAlignedRect();
01216 
01217     /*
01218       We paint to a pixmap first to have something scalable for printing
01219       ( f.e. in a Pdf document )
01220      */
01221 
01222     QPixmap pixmap( devRect.size() );
01223     pixmap.fill( Qt::transparent );
01224 
01225     QPainter pmPainter( &pixmap );
01226     pmPainter.translate( -devRect.x(), -devRect.y() );
01227 
01228     if ( orientation == Qt::Horizontal )
01229     {
01230         QwtScaleMap sMap = scaleMap;
01231         sMap.setPaintInterval( rect.left(), rect.right() );
01232 
01233         for ( int x = devRect.left(); x <= devRect.right(); x++ )
01234         {
01235             const double value = sMap.invTransform( x );
01236 
01237             if ( colorMap.format() == QwtColorMap::RGB )
01238                 c.setRgba( colorMap.rgb( interval, value ) );
01239             else
01240                 c = colorTable[colorMap.colorIndex( 256, interval, value )];
01241 
01242             pmPainter.setPen( c );
01243             pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() );
01244         }
01245     }
01246     else // Vertical
01247     {
01248         QwtScaleMap sMap = scaleMap;
01249         sMap.setPaintInterval( rect.bottom(), rect.top() );
01250 
01251         for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
01252         {
01253             const double value = sMap.invTransform( y );
01254 
01255             if ( colorMap.format() == QwtColorMap::RGB )
01256                 c.setRgba( colorMap.rgb( interval, value ) );
01257             else
01258                 c = colorTable[colorMap.colorIndex( 256, interval, value )];
01259 
01260             pmPainter.setPen( c );
01261             pmPainter.drawLine( devRect.left(), y, devRect.right(), y );
01262         }
01263     }
01264     pmPainter.end();
01265 
01266     drawPixmap( painter, rect, pixmap );
01267 }
01268 
01269 static inline void qwtFillRect( const QWidget *widget, QPainter *painter, 
01270     const QRect &rect, const QBrush &brush)
01271 {
01272     if ( brush.style() == Qt::TexturePattern ) 
01273     {
01274         painter->save();
01275 
01276         painter->setClipRect( rect );
01277         painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
01278 
01279         painter->restore();
01280     } 
01281     else if ( brush.gradient() )
01282     {
01283         painter->save();
01284 
01285         painter->setClipRect( rect );
01286         painter->fillRect(0, 0, widget->width(), 
01287             widget->height(), brush);
01288 
01289         painter->restore();
01290     } 
01291     else 
01292     {
01293         painter->fillRect(rect, brush);
01294     }
01295 }
01296 
01310 void QwtPainter::fillPixmap( const QWidget *widget, 
01311     QPixmap &pixmap, const QPoint &offset )
01312 {
01313     const QRect rect( offset, pixmap.size() );
01314 
01315     QPainter painter( &pixmap );
01316     painter.translate( -offset );
01317 
01318     const QBrush autoFillBrush = 
01319         widget->palette().brush( widget->backgroundRole() );
01320 
01321     if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) ) 
01322     {
01323         const QBrush bg = widget->palette().brush( QPalette::Window );
01324         qwtFillRect( widget, &painter, rect, bg);
01325     }
01326 
01327     if ( widget->autoFillBackground() )
01328         qwtFillRect( widget, &painter, rect, autoFillBrush);
01329 
01330     if ( widget->testAttribute(Qt::WA_StyledBackground) ) 
01331     {
01332         painter.setClipRegion( rect );
01333 
01334         QStyleOption opt;
01335         opt.initFrom( widget );
01336         widget->style()->drawPrimitive( QStyle::PE_Widget, 
01337             &opt, &painter, widget );
01338     }
01339 }
01340 
01350 void QwtPainter::drawBackgound( QPainter *painter,
01351     const QRectF &rect, const QWidget *widget )
01352 {
01353     if ( widget->testAttribute( Qt::WA_StyledBackground ) )
01354     {
01355         QStyleOption opt;
01356         opt.initFrom( widget );
01357         opt.rect = rect.toAlignedRect();
01358 
01359         widget->style()->drawPrimitive(
01360             QStyle::PE_Widget, &opt, painter, widget);
01361     }
01362     else
01363     {
01364         const QBrush brush =
01365             widget->palette().brush( widget->backgroundRole() );
01366 
01367         painter->fillRect( rect, brush );
01368     }
01369 }
01370 
01375 qreal QwtPainter::devicePixelRatio( const QPaintDevice *paintDevice )
01376 {
01377     qreal pixelRatio = 0.0;
01378 
01379 #if QT_VERSION >= 0x050100
01380     if ( paintDevice )
01381     {
01382 #if QT_VERSION >= 0x050600
01383         pixelRatio = paintDevice->devicePixelRatioF();
01384 #else
01385         pixelRatio = paintDevice->devicePixelRatio();
01386 #endif
01387     }
01388 #else
01389     Q_UNUSED( paintDevice )
01390 #endif
01391 
01392 #if QT_VERSION >= 0x050000
01393     if ( pixelRatio == 0.0 && qApp )
01394         pixelRatio = qApp->devicePixelRatio();
01395 #endif
01396 
01397     if ( pixelRatio == 0.0 )
01398         pixelRatio = 1.0;
01399 
01400     return pixelRatio;
01401 }
01402 
01409 QPixmap QwtPainter::backingStore( QWidget *widget, const QSize &size )
01410 {
01411     QPixmap pm;
01412 
01413 #if QT_VERSION >= 0x050000 
01414     const qreal pixelRatio = QwtPainter::devicePixelRatio( widget );
01415 
01416     pm = QPixmap( size * pixelRatio );
01417     pm.setDevicePixelRatio( pixelRatio );
01418 #else
01419     pm = QPixmap( size );
01420 #endif
01421 
01422 #ifdef Q_WS_X11
01423     if ( widget && isX11GraphicsSystem() )
01424     {
01425         if ( pm.x11Info().screen() != widget->x11Info().screen() )
01426             pm.x11SetScreen( widget->x11Info().screen() );
01427     }
01428 #else
01429     Q_UNUSED( widget )
01430 #endif
01431 
01432     return pm;
01433 }
01434 


plotjuggler
Author(s): Davide Faconti
autogenerated on Wed Jul 3 2019 19:28:04