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     QPolygonF cpa = polygon;
00551     if ( deviceClipping )
00552         cpa = QwtClipper::clipPolygonF( clipRect, polygon );
00553 
00554     painter->drawPolygon( cpa );
00555 }
00556 
00558 void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon )
00559 {
00560     QRectF clipRect;
00561     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00562 
00563     QPolygonF cpa = polygon;
00564     if ( deviceClipping )
00565         cpa = QwtClipper::clipPolygonF( clipRect, cpa );
00566 
00567     qwtDrawPolyline<QPointF>( painter,
00568         cpa.constData(), cpa.size(), d_polylineSplitting );
00569 }
00570 
00572 void QwtPainter::drawPolyline( QPainter *painter,
00573     const QPointF *points, int pointCount )
00574 {
00575     QRectF clipRect;
00576     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00577 
00578     if ( deviceClipping )
00579     {
00580         QPolygonF polygon( pointCount );
00581         ::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) );
00582 
00583         polygon = QwtClipper::clipPolygonF( clipRect, polygon );
00584         qwtDrawPolyline<QPointF>( painter,
00585             polygon.constData(), polygon.size(), d_polylineSplitting );
00586     }
00587     else
00588     {
00589         qwtDrawPolyline<QPointF>( painter, points, pointCount, d_polylineSplitting );
00590     }
00591 }
00592 
00594 void QwtPainter::drawPolygon( QPainter *painter, const QPolygon &polygon )
00595 {
00596     QRectF clipRect;
00597     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00598 
00599     QPolygon cpa = polygon;
00600     if ( deviceClipping )
00601         cpa = QwtClipper::clipPolygon( clipRect, polygon );
00602 
00603     painter->drawPolygon( cpa );
00604 }
00605 
00607 void QwtPainter::drawPolyline( QPainter *painter, const QPolygon &polygon )
00608 {
00609     QRectF clipRect;
00610     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00611 
00612     QPolygon cpa = polygon;
00613     if ( deviceClipping )
00614         cpa = QwtClipper::clipPolygon( clipRect, cpa );
00615 
00616     qwtDrawPolyline<QPoint>( painter,
00617         cpa.constData(), cpa.size(), d_polylineSplitting );
00618 }
00619 
00621 void QwtPainter::drawPolyline( QPainter *painter,
00622     const QPoint *points, int pointCount )
00623 {
00624     QRectF clipRect;
00625     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00626 
00627     if ( deviceClipping )
00628     {
00629         QPolygon polygon( pointCount );
00630         ::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) );
00631 
00632         polygon = QwtClipper::clipPolygon( clipRect, polygon );
00633         qwtDrawPolyline<QPoint>( painter,
00634             polygon.constData(), polygon.size(), d_polylineSplitting );
00635     }
00636     else
00637         qwtDrawPolyline<QPoint>( painter, points, pointCount, d_polylineSplitting );
00638 }
00639 
00641 void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos )
00642 {
00643     QRectF clipRect;
00644     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00645 
00646     if ( deviceClipping && !clipRect.contains( pos ) )
00647         return;
00648 
00649     painter->drawPoint( pos );
00650 }
00651 
00653 void QwtPainter::drawPoint( QPainter *painter, const QPoint &pos )
00654 {
00655     QRectF clipRect;
00656     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00657 
00658     if ( deviceClipping )
00659     {
00660         const int minX = qCeil( clipRect.left() );
00661         const int maxX = qFloor( clipRect.right() );
00662         const int minY = qCeil( clipRect.top() );
00663         const int maxY = qFloor( clipRect.bottom() );
00664 
00665         if ( pos.x() < minX || pos.x() > maxX 
00666             || pos.y() < minY || pos.y() > maxY )
00667         {
00668             return;
00669         }
00670     }
00671 
00672     painter->drawPoint( pos );
00673 }
00674 
00676 void QwtPainter::drawPoints( QPainter *painter, 
00677     const QPoint *points, int pointCount )
00678 {
00679     QRectF clipRect;
00680     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00681 
00682     if ( deviceClipping )
00683     {
00684         const int minX = qCeil( clipRect.left() );
00685         const int maxX = qFloor( clipRect.right() );
00686         const int minY = qCeil( clipRect.top() );
00687         const int maxY = qFloor( clipRect.bottom() );
00688 
00689         const QRect r( minX, minY, maxX - minX, maxY - minY );
00690 
00691         QPolygon clippedPolygon( pointCount );
00692         QPoint *clippedData = clippedPolygon.data();
00693 
00694         int numClippedPoints = 0;
00695         for ( int i = 0; i < pointCount; i++ )
00696         {
00697             if ( r.contains( points[i] ) )
00698                 clippedData[ numClippedPoints++ ] = points[i];
00699         }
00700         painter->drawPoints( clippedData, numClippedPoints );
00701     }
00702     else
00703     {
00704         painter->drawPoints( points, pointCount );
00705     }
00706 }
00707 
00709 void QwtPainter::drawPoints( QPainter *painter, 
00710     const QPointF *points, int pointCount )
00711 {
00712     QRectF clipRect;
00713     const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
00714 
00715     if ( deviceClipping )
00716     {
00717         QPolygonF clippedPolygon( pointCount );
00718         QPointF *clippedData = clippedPolygon.data();
00719 
00720         int numClippedPoints = 0;
00721         for ( int i = 0; i < pointCount; i++ )
00722         {
00723             if ( clipRect.contains( points[i] ) )
00724                 clippedData[ numClippedPoints++ ] = points[i];
00725         }
00726         painter->drawPoints( clippedData, numClippedPoints );
00727     }
00728     else
00729     {
00730         painter->drawPoints( points, pointCount );
00731     }
00732 }
00733 
00735 void QwtPainter::drawImage( QPainter *painter,
00736     const QRectF &rect, const QImage &image )
00737 {
00738     const QRect alignedRect = rect.toAlignedRect();
00739 
00740     if ( alignedRect != rect )
00741     {
00742         const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00743 
00744         painter->save();
00745         painter->setClipRect( clipRect, Qt::IntersectClip );
00746         painter->drawImage( alignedRect, image );
00747         painter->restore();
00748     }
00749     else
00750     {
00751         painter->drawImage( alignedRect, image );
00752     }
00753 }
00754 
00756 void QwtPainter::drawPixmap( QPainter *painter,
00757     const QRectF &rect, const QPixmap &pixmap )
00758 {
00759     const QRect alignedRect = rect.toAlignedRect();
00760 
00761     if ( alignedRect != rect )
00762     {
00763         const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00764 
00765         painter->save();
00766         painter->setClipRect( clipRect, Qt::IntersectClip );
00767         painter->drawPixmap( alignedRect, pixmap );
00768         painter->restore();
00769     }
00770     else
00771     {
00772         painter->drawPixmap( alignedRect, pixmap );
00773     }
00774 }
00775 
00777 void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget )
00778 {
00779     drawFocusRect( painter, widget, widget->rect() );
00780 }
00781 
00783 void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget,
00784     const QRect &rect )
00785 {
00786     QStyleOptionFocusRect opt;
00787     opt.init( widget );
00788     opt.rect = rect;
00789     opt.state |= QStyle::State_HasFocus;
00790     opt.backgroundColor = widget->palette().color( widget->backgroundRole() );
00791 
00792     widget->style()->drawPrimitive(
00793         QStyle::PE_FrameFocusRect, &opt, painter, widget );
00794 }
00795 
00807 void QwtPainter::drawRoundFrame( QPainter *painter,
00808     const QRectF &rect, const QPalette &palette, 
00809     int lineWidth, int frameStyle )
00810 {
00811     enum Style
00812     {
00813         Plain,
00814         Sunken,
00815         Raised
00816     };
00817 
00818     Style style = Plain;
00819     if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
00820         style = Sunken;
00821     else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
00822         style = Raised;
00823 
00824     const double lw2 = 0.5 * lineWidth;
00825     QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
00826 
00827     QBrush brush;
00828 
00829     if ( style != Plain )
00830     {
00831         QColor c1 = palette.color( QPalette::Light );
00832         QColor c2 = palette.color( QPalette::Dark );
00833 
00834         if ( style == Sunken )
00835             qSwap( c1, c2 );
00836 
00837         QLinearGradient gradient( r.topLeft(), r.bottomRight() );
00838         gradient.setColorAt( 0.0, c1 );
00839 #if 0
00840         gradient.setColorAt( 0.3, c1 );
00841         gradient.setColorAt( 0.7, c2 );
00842 #endif
00843         gradient.setColorAt( 1.0, c2 );
00844 
00845         brush = QBrush( gradient );
00846     }
00847     else // Plain
00848     {
00849         brush = palette.brush( QPalette::WindowText );
00850     }
00851 
00852     painter->save();
00853 
00854     painter->setPen( QPen( brush, lineWidth ) );
00855     painter->setBrush( Qt::NoBrush );
00856 
00857     painter->drawEllipse( r );
00858 
00859     painter->restore();
00860 }
00861 
00873 void QwtPainter::drawFrame( QPainter *painter, const QRectF &rect,
00874     const QPalette &palette, QPalette::ColorRole foregroundRole,
00875     int frameWidth, int midLineWidth, int frameStyle )
00876 {
00877     if ( frameWidth <= 0 || rect.isEmpty() )
00878         return;
00879 
00880     const int shadow = frameStyle & QFrame::Shadow_Mask;
00881 
00882     painter->save();
00883 
00884     if ( shadow == QFrame::Plain )
00885     {
00886         const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00887         const QRectF innerRect = outerRect.adjusted( 
00888             frameWidth, frameWidth, -frameWidth, -frameWidth );
00889 
00890         QPainterPath path;
00891         path.addRect( outerRect );
00892         path.addRect( innerRect );
00893 
00894         painter->setPen( Qt::NoPen );
00895         painter->setBrush( palette.color( foregroundRole ) );
00896 
00897         painter->drawPath( path );
00898     }
00899     else
00900     {
00901         const int shape = frameStyle & QFrame::Shape_Mask;
00902 
00903         if ( shape == QFrame::Box )
00904         {
00905             const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00906             const QRectF midRect1 = outerRect.adjusted( 
00907                 frameWidth, frameWidth, -frameWidth, -frameWidth );
00908             const QRectF midRect2 = midRect1.adjusted( 
00909                 midLineWidth, midLineWidth, -midLineWidth, -midLineWidth );
00910 
00911             const QRectF innerRect = midRect2.adjusted( 
00912                 frameWidth, frameWidth, -frameWidth, -frameWidth );
00913 
00914             QPainterPath path1;
00915             path1.moveTo( outerRect.bottomLeft() );
00916             path1.lineTo( outerRect.topLeft() );
00917             path1.lineTo( outerRect.topRight() );
00918             path1.lineTo( midRect1.topRight() );
00919             path1.lineTo( midRect1.topLeft() );
00920             path1.lineTo( midRect1.bottomLeft() );
00921 
00922             QPainterPath path2;
00923             path2.moveTo( outerRect.bottomLeft() );
00924             path2.lineTo( outerRect.bottomRight() );
00925             path2.lineTo( outerRect.topRight() );
00926             path2.lineTo( midRect1.topRight() );
00927             path2.lineTo( midRect1.bottomRight() );
00928             path2.lineTo( midRect1.bottomLeft() );
00929 
00930             QPainterPath path3;
00931             path3.moveTo( midRect2.bottomLeft() );
00932             path3.lineTo( midRect2.topLeft() );
00933             path3.lineTo( midRect2.topRight() );
00934             path3.lineTo( innerRect.topRight() );
00935             path3.lineTo( innerRect.topLeft() );
00936             path3.lineTo( innerRect.bottomLeft() );
00937 
00938             QPainterPath path4;
00939             path4.moveTo( midRect2.bottomLeft() );
00940             path4.lineTo( midRect2.bottomRight() );
00941             path4.lineTo( midRect2.topRight() );
00942             path4.lineTo( innerRect.topRight() );
00943             path4.lineTo( innerRect.bottomRight() );
00944             path4.lineTo( innerRect.bottomLeft() );
00945 
00946             QPainterPath path5;
00947             path5.addRect( midRect1 );
00948             path5.addRect( midRect2 );
00949 
00950             painter->setPen( Qt::NoPen );
00951 
00952             QBrush brush1 = palette.dark().color();
00953             QBrush brush2 = palette.light().color();
00954 
00955             if ( shadow == QFrame::Raised )
00956                 qSwap( brush1, brush2 );
00957 
00958             painter->setBrush( brush1 );
00959             painter->drawPath( path1 );
00960             painter->drawPath( path4 );
00961 
00962             painter->setBrush( brush2 );
00963             painter->drawPath( path2 );
00964             painter->drawPath( path3 );
00965 
00966             painter->setBrush( palette.mid() );
00967             painter->drawPath( path5 );
00968         }
00969 #if 0
00970         // qDrawWinPanel doesn't result in something nice
00971         // on a scalable document like PDF. Better draw a
00972         // Panel.
00973 
00974         else if ( shape == QFrame::WinPanel )
00975         {
00976             painter->setRenderHint( QPainter::NonCosmeticDefaultPen, true );
00977             qDrawWinPanel ( painter, rect.toRect(), palette,
00978                 frameStyle & QFrame::Sunken );
00979         }
00980         else if ( shape == QFrame::StyledPanel )
00981         {
00982         }
00983 #endif
00984         else
00985         {
00986             const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
00987             const QRectF innerRect = outerRect.adjusted( 
00988                 frameWidth - 1.0, frameWidth - 1.0, 
00989                 -( frameWidth - 1.0 ), -( frameWidth - 1.0 ) );
00990 
00991             QPainterPath path1;
00992             path1.moveTo( outerRect.bottomLeft() );
00993             path1.lineTo( outerRect.topLeft() );
00994             path1.lineTo( outerRect.topRight() );
00995             path1.lineTo( innerRect.topRight() );
00996             path1.lineTo( innerRect.topLeft() );
00997             path1.lineTo( innerRect.bottomLeft() );
00998 
00999 
01000             QPainterPath path2;
01001             path2.moveTo( outerRect.bottomLeft() );
01002             path2.lineTo( outerRect.bottomRight() );
01003             path2.lineTo( outerRect.topRight() );
01004             path2.lineTo( innerRect.topRight() );
01005             path2.lineTo( innerRect.bottomRight() );
01006             path2.lineTo( innerRect.bottomLeft() );
01007 
01008             painter->setPen( Qt::NoPen );
01009 
01010             QBrush brush1 = palette.dark().color();
01011             QBrush brush2 = palette.light().color();
01012 
01013             if ( shadow == QFrame::Raised )
01014                 qSwap( brush1, brush2 );
01015 
01016             painter->setBrush( brush1 );
01017             painter->drawPath( path1 );
01018 
01019             painter->setBrush( brush2 );
01020             painter->drawPath( path2 );
01021         }
01022 
01023     }
01024 
01025     painter->restore();
01026 }
01027 
01042 void QwtPainter::drawRoundedFrame( QPainter *painter, 
01043     const QRectF &rect, double xRadius, double yRadius, 
01044     const QPalette &palette, int lineWidth, int frameStyle )
01045 {
01046     painter->save();
01047     painter->setRenderHint( QPainter::Antialiasing, true );
01048     painter->setBrush( Qt::NoBrush );
01049 
01050     double lw2 = lineWidth * 0.5;
01051     QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
01052 
01053     QPainterPath path;
01054     path.addRoundedRect( r, xRadius, yRadius );
01055 
01056     enum Style
01057     {
01058         Plain,
01059         Sunken,
01060         Raised
01061     };
01062 
01063     Style style = Plain;
01064     if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
01065         style = Sunken;
01066     else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
01067         style = Raised;
01068 
01069     if ( style != Plain && path.elementCount() == 17 )
01070     {
01071         // move + 4 * ( cubicTo + lineTo )
01072         QPainterPath pathList[8];
01073         
01074         for ( int i = 0; i < 4; i++ )
01075         {
01076             const int j = i * 4 + 1;
01077             
01078             pathList[ 2 * i ].moveTo(
01079                 path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
01080             );  
01081             
01082             pathList[ 2 * i ].cubicTo(
01083                 path.elementAt(j + 0).x, path.elementAt(j + 0).y,
01084                 path.elementAt(j + 1).x, path.elementAt(j + 1).y,
01085                 path.elementAt(j + 2).x, path.elementAt(j + 2).y );
01086                 
01087             pathList[ 2 * i + 1 ].moveTo(
01088                 path.elementAt(j + 2).x, path.elementAt(j + 2).y
01089             );  
01090             pathList[ 2 * i + 1 ].lineTo(
01091                 path.elementAt(j + 3).x, path.elementAt(j + 3).y
01092             );  
01093         }   
01094 
01095         QColor c1( palette.color( QPalette::Dark ) );
01096         QColor c2( palette.color( QPalette::Light ) );
01097 
01098         if ( style == Raised )
01099             qSwap( c1, c2 );
01100 
01101         for ( int i = 0; i < 4; i++ )
01102         {
01103             QRectF r = pathList[2 * i].controlPointRect();
01104 
01105             QPen arcPen;
01106             arcPen.setCapStyle( Qt::FlatCap );
01107             arcPen.setWidth( lineWidth );
01108 
01109             QPen linePen;
01110             linePen.setCapStyle( Qt::FlatCap );
01111             linePen.setWidth( lineWidth );
01112 
01113             switch( i )
01114             {
01115                 case 0:
01116                 {
01117                     arcPen.setColor( c1 );
01118                     linePen.setColor( c1 );
01119                     break;
01120                 }
01121                 case 1:
01122                 {
01123                     QLinearGradient gradient;
01124                     gradient.setStart( r.topLeft() );
01125                     gradient.setFinalStop( r.bottomRight() );
01126                     gradient.setColorAt( 0.0, c1 );
01127                     gradient.setColorAt( 1.0, c2 );
01128 
01129                     arcPen.setBrush( gradient );
01130                     linePen.setColor( c2 );
01131                     break;
01132                 }
01133                 case 2:
01134                 {
01135                     arcPen.setColor( c2 );
01136                     linePen.setColor( c2 );
01137                     break;
01138                 }
01139                 case 3:
01140                 {
01141                     QLinearGradient gradient;
01142 
01143                     gradient.setStart( r.bottomRight() );
01144                     gradient.setFinalStop( r.topLeft() );
01145                     gradient.setColorAt( 0.0, c2 );
01146                     gradient.setColorAt( 1.0, c1 );
01147 
01148                     arcPen.setBrush( gradient );
01149                     linePen.setColor( c1 );
01150                     break;
01151                 }
01152             }
01153 
01154 
01155             painter->setPen( arcPen );
01156             painter->drawPath( pathList[ 2 * i] );
01157 
01158             painter->setPen( linePen );
01159             painter->drawPath( pathList[ 2 * i + 1] );
01160         }
01161     }
01162     else
01163     {
01164         QPen pen( palette.color( QPalette::WindowText ), lineWidth );
01165         painter->setPen( pen );
01166         painter->drawPath( path );
01167     }
01168 
01169     painter->restore();
01170 }
01171 
01182 void QwtPainter::drawColorBar( QPainter *painter,
01183         const QwtColorMap &colorMap, const QwtInterval &interval,
01184         const QwtScaleMap &scaleMap, Qt::Orientation orientation,
01185         const QRectF &rect )
01186 {
01187     QVector<QRgb> colorTable;
01188     if ( colorMap.format() == QwtColorMap::Indexed )
01189         colorTable = colorMap.colorTable256();
01190 
01191     QColor c;
01192 
01193     const QRect devRect = rect.toAlignedRect();
01194 
01195     /*
01196       We paint to a pixmap first to have something scalable for printing
01197       ( f.e. in a Pdf document )
01198      */
01199 
01200     QPixmap pixmap( devRect.size() );
01201     pixmap.fill( Qt::transparent );
01202 
01203     QPainter pmPainter( &pixmap );
01204     pmPainter.translate( -devRect.x(), -devRect.y() );
01205 
01206     if ( orientation == Qt::Horizontal )
01207     {
01208         QwtScaleMap sMap = scaleMap;
01209         sMap.setPaintInterval( rect.left(), rect.right() );
01210 
01211         for ( int x = devRect.left(); x <= devRect.right(); x++ )
01212         {
01213             const double value = sMap.invTransform( x );
01214 
01215             if ( colorMap.format() == QwtColorMap::RGB )
01216                 c.setRgba( colorMap.rgb( interval, value ) );
01217             else
01218                 c = colorTable[colorMap.colorIndex( 256, interval, value )];
01219 
01220             pmPainter.setPen( c );
01221             pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() );
01222         }
01223     }
01224     else // Vertical
01225     {
01226         QwtScaleMap sMap = scaleMap;
01227         sMap.setPaintInterval( rect.bottom(), rect.top() );
01228 
01229         for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
01230         {
01231             const double value = sMap.invTransform( y );
01232 
01233             if ( colorMap.format() == QwtColorMap::RGB )
01234                 c.setRgba( colorMap.rgb( interval, value ) );
01235             else
01236                 c = colorTable[colorMap.colorIndex( 256, interval, value )];
01237 
01238             pmPainter.setPen( c );
01239             pmPainter.drawLine( devRect.left(), y, devRect.right(), y );
01240         }
01241     }
01242     pmPainter.end();
01243 
01244     drawPixmap( painter, rect, pixmap );
01245 }
01246 
01247 static inline void qwtFillRect( const QWidget *widget, QPainter *painter, 
01248     const QRect &rect, const QBrush &brush)
01249 {
01250     if ( brush.style() == Qt::TexturePattern ) 
01251     {
01252         painter->save();
01253 
01254         painter->setClipRect( rect );
01255         painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
01256 
01257         painter->restore();
01258     } 
01259     else if ( brush.gradient() )
01260     {
01261         painter->save();
01262 
01263         painter->setClipRect( rect );
01264         painter->fillRect(0, 0, widget->width(), 
01265             widget->height(), brush);
01266 
01267         painter->restore();
01268     } 
01269     else 
01270     {
01271         painter->fillRect(rect, brush);
01272     }
01273 }
01274 
01288 void QwtPainter::fillPixmap( const QWidget *widget, 
01289     QPixmap &pixmap, const QPoint &offset )
01290 {
01291     const QRect rect( offset, pixmap.size() );
01292 
01293     QPainter painter( &pixmap );
01294     painter.translate( -offset );
01295 
01296     const QBrush autoFillBrush = 
01297         widget->palette().brush( widget->backgroundRole() );
01298 
01299     if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) ) 
01300     {
01301         const QBrush bg = widget->palette().brush( QPalette::Window );
01302         qwtFillRect( widget, &painter, rect, bg);
01303     }
01304 
01305     if ( widget->autoFillBackground() )
01306         qwtFillRect( widget, &painter, rect, autoFillBrush);
01307 
01308     if ( widget->testAttribute(Qt::WA_StyledBackground) ) 
01309     {
01310         painter.setClipRegion( rect );
01311 
01312         QStyleOption opt;
01313         opt.initFrom( widget );
01314         widget->style()->drawPrimitive( QStyle::PE_Widget, 
01315             &opt, &painter, widget );
01316     }
01317 }
01318 
01328 void QwtPainter::drawBackgound( QPainter *painter,
01329     const QRectF &rect, const QWidget *widget )
01330 {
01331     if ( widget->testAttribute( Qt::WA_StyledBackground ) )
01332     {
01333         QStyleOption opt;
01334         opt.initFrom( widget );
01335         opt.rect = rect.toAlignedRect();
01336 
01337         widget->style()->drawPrimitive(
01338             QStyle::PE_Widget, &opt, painter, widget);
01339     }
01340     else
01341     {
01342         const QBrush brush =
01343             widget->palette().brush( widget->backgroundRole() );
01344 
01345         painter->fillRect( rect, brush );
01346     }
01347 }
01348 
01353 qreal QwtPainter::devicePixelRatio( const QPaintDevice *paintDevice )
01354 {
01355     qreal pixelRatio = 0.0;
01356 
01357 #if QT_VERSION >= 0x050100
01358     if ( paintDevice )
01359     {
01360 #if QT_VERSION >= 0x050600
01361         pixelRatio = paintDevice->devicePixelRatioF();
01362 #else
01363         pixelRatio = paintDevice->devicePixelRatio();
01364 #endif
01365     }
01366 #else
01367     Q_UNUSED( paintDevice )
01368 #endif
01369 
01370 #if QT_VERSION >= 0x050000
01371     if ( pixelRatio == 0.0 && qApp )
01372         pixelRatio = qApp->devicePixelRatio();
01373 #endif
01374 
01375     if ( pixelRatio == 0.0 )
01376         pixelRatio = 1.0;
01377 
01378     return pixelRatio;
01379 }
01380 
01387 QPixmap QwtPainter::backingStore( QWidget *widget, const QSize &size )
01388 {
01389     QPixmap pm;
01390 
01391 #if QT_VERSION >= 0x050000 
01392     const qreal pixelRatio = QwtPainter::devicePixelRatio( widget );
01393 
01394     pm = QPixmap( size * pixelRatio );
01395     pm.setDevicePixelRatio( pixelRatio );
01396 #else
01397     pm = QPixmap( size );
01398 #endif
01399 
01400 #ifdef Q_WS_X11
01401     if ( widget && isX11GraphicsSystem() )
01402     {
01403         if ( pm.x11Info().screen() != widget->x11Info().screen() )
01404             pm.x11SetScreen( widget->x11Info().screen() );
01405     }
01406 #else
01407     Q_UNUSED( widget )
01408 #endif
01409 
01410     return pm;
01411 }
01412 


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56