Loading...
Searching...
No Matches
qwt_painter.cpp
/******************************************************************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
#include "qwt_painter.h"
#include "qwt_math.h"
#include "qwt_clipper.h"
#include "qwt_color_map.h"
#include "qwt_scale_map.h"
#include <qwidget.h>
#include <qframe.h>
#include <qrect.h>
#include <qpainter.h>
#include <qpalette.h>
#include <qpaintdevice.h>
#include <qpainterpath.h>
#include <qpixmap.h>
#include <qstyle.h>
#include <qtextdocument.h>
#include <qabstracttextdocumentlayout.h>
#include <qstyleoption.h>
#include <qpaintengine.h>
#include <qapplication.h>
#if QT_VERSION >= 0x060000
#include <qscreen.h>
#else
#include <qdesktopwidget.h>
#endif
#if QT_VERSION < 0x050000
#ifdef Q_WS_X11
#include <qx11info_x11.h>
#endif
#endif
#include <cstring>
bool QwtPainter::m_polylineSplitting = true;
bool QwtPainter::m_roundingAlignment = true;
static inline bool qwtIsRasterPaintEngineBuggy()
{
#if 0
static int isBuggy = -1;
if ( isBuggy < 0 )
{
// auto detect bug of the raster paint engine,
// fixed with: https://codereview.qt-project.org/#/c/99456/
QImage image( 2, 3, QImage::Format_ARGB32 );
image.fill( 0u );
QPolygonF p;
p += QPointF(0, 1);
p += QPointF(0, 0);
p += QPointF(1, 0 );
p += QPointF(1, 2 );
QPainter painter( &image );
painter.drawPolyline( p );
painter.end();
isBuggy = ( image.pixel( 1, 1 ) == 0 ) ? 1 : 0;
}
return isBuggy == 1;
#endif
#if QT_VERSION < 0x050000
return true;
#elif QT_VERSION < 0x050100
return false;
#elif QT_VERSION < 0x050400
return true;
#else
return false;
#endif
}
static inline bool qwtIsClippingNeeded(
const QPainter* painter, QRectF& clipRect )
{
bool doClipping = false;
const QPaintEngine* pe = painter->paintEngine();
if ( pe && pe->type() == QPaintEngine::SVG )
{
// The SVG paint engine ignores any clipping,
if ( painter->hasClipping() )
{
doClipping = true;
clipRect = painter->clipRegion().boundingRect();
}
}
return doClipping;
}
template< class T >
static inline void qwtDrawPolyline( QPainter* painter,
const T* points, int pointCount, bool polylineSplitting )
{
bool doSplit = false;
if ( polylineSplitting )
{
const QPaintEngine* pe = painter->paintEngine();
if ( pe && pe->type() == QPaintEngine::Raster )
{
/*
Raster paint engine is much faster when splitting
the polygon, but of course we might see some issues where
the pieces are joining
*/
doSplit = true;
}
}
if ( doSplit )
{
QPen pen = painter->pen();
const int splitSize = 6;
if ( pen.width() <= 1 && pen.isSolid() && qwtIsRasterPaintEngineBuggy()
&& !( painter->renderHints() & QPainter::Antialiasing ) )
{
int k = 0;
for ( int i = k + 1; i < pointCount; i++ )
{
const QPointF& p1 = points[i - 1];
const QPointF& p2 = points[i];
const bool isBad = ( qAbs( p2.y() - p1.y() ) <= 1 )
&& qAbs( p2.x() - p1.x() ) <= 1;
if ( isBad || ( i - k >= splitSize ) )
{
painter->drawPolyline( points + k, i - k + 1 );
k = i;
}
}
painter->drawPolyline( points + k, pointCount - k );
}
else
{
for ( int i = 0; i < pointCount; i += splitSize )
{
const int n = qMin( splitSize + 1, pointCount - i );
painter->drawPolyline( points + i, n );
}
}
}
else
{
painter->drawPolyline( points, pointCount );
}
}
static inline QSize qwtScreenResolution()
{
static QSize screenResolution;
if ( !screenResolution.isValid() )
{
/*
We might have screens with different resolutions. TODO ...
*/
#if QT_VERSION >= 0x060000
QScreen* screen = QGuiApplication::primaryScreen();
if ( screen )
{
screenResolution.setWidth( screen->logicalDotsPerInchX() );
screenResolution.setHeight( screen->logicalDotsPerInchY() );
}
#else
QDesktopWidget* desktop = QApplication::desktop();
if ( desktop )
{
screenResolution.setWidth( desktop->logicalDpiX() );
screenResolution.setHeight( desktop->logicalDpiY() );
}
#endif
}
return screenResolution;
}
static inline void qwtUnscaleFont( QPainter* painter )
{
if ( painter->font().pixelSize() >= 0 )
return;
const QSize screenResolution = qwtScreenResolution();
const QPaintDevice* pd = painter->device();
if ( pd->logicalDpiX() != screenResolution.width() ||
pd->logicalDpiY() != screenResolution.height() )
{
QFont pixelFont = QwtPainter::scaledFont( painter->font() );
pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() );
painter->setFont( pixelFont );
}
}
bool QwtPainter::isX11GraphicsSystem()
{
/*
The X11 paint engine has been removed with Qt 5.0, but
reintroduced with Qt 5.10. It can be enabled with
"export QT_XCB_NATIVE_PAINTING=1".
*/
static int onX11 = -1;
if ( onX11 < 0 )
{
QPixmap pm( 1, 1 );
QPainter painter( &pm );
onX11 = ( painter.paintEngine()->type() == QPaintEngine::X11 ) ? 1 : 0;
}
return onX11 == 1;
}
bool QwtPainter::isAligning( const QPainter* painter )
{
if ( painter && painter->isActive() )
{
const QPaintEngine::Type type =
painter->paintEngine()->type();
if ( type >= QPaintEngine::User )
{
// we have no idea - better don't align
return false;
}
switch ( type )
{
case QPaintEngine::Pdf:
case QPaintEngine::SVG:
#if 0
case QPaintEngine::MacPrinter:
#endif
return false;
default:
break;
}
const QTransform& tr = painter->transform();
if ( tr.isRotating() || tr.isScaling() )
{
// we might have to check translations too
return false;
}
}
return true;
}
void QwtPainter::setRoundingAlignment( bool enable )
{
m_roundingAlignment = enable;
}
void QwtPainter::setPolylineSplitting( bool enable )
{
m_polylineSplitting = enable;
}
void QwtPainter::drawPath( QPainter* painter, const QPainterPath& path )
{
painter->drawPath( path );
}
void QwtPainter::drawRect( QPainter* painter, qreal x, qreal y, qreal w, qreal h )
{
drawRect( painter, QRectF( x, y, w, h ) );
}
void QwtPainter::drawRect( QPainter* painter, const QRectF& rect )
{
const QRectF r = rect;
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
if ( !clipRect.intersects( r ) )
return;
if ( !clipRect.contains( r ) )
{
fillRect( painter, r & clipRect, painter->brush() );
painter->save();
painter->setBrush( Qt::NoBrush );
drawPolyline( painter, QPolygonF( r ) );
painter->restore();
return;
}
}
painter->drawRect( r );
}
void QwtPainter::fillRect( QPainter* painter,
const QRectF& rect, const QBrush& brush )
{
if ( !rect.isValid() )
return;
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
/*
Performance of Qt4 is horrible for a non trivial brush. Without
clipping expect minutes or hours for repainting large rectangles
(might result from zooming)
*/
if ( deviceClipping )
clipRect &= painter->window();
else
clipRect = painter->window();
if ( painter->hasClipping() )
clipRect &= painter->clipRegion().boundingRect();
QRectF r = rect;
if ( deviceClipping )
r = r.intersected( clipRect );
if ( r.isValid() )
painter->fillRect( r, brush );
}
void QwtPainter::drawPie( QPainter* painter, const QRectF& rect,
int a, int alen )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping && !clipRect.contains( rect ) )
return;
painter->drawPie( rect, a, alen );
}
void QwtPainter::drawEllipse( QPainter* painter, const QRectF& rect )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping && !clipRect.contains( rect ) )
return;
painter->drawEllipse( rect );
}
void QwtPainter::drawText( QPainter* painter,
qreal x, qreal y, const QString& text )
{
drawText( painter, QPointF( x, y ), text );
}
void QwtPainter::drawText( QPainter* painter, const QPointF& pos,
const QString& text )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping && !clipRect.contains( pos ) )
return;
painter->save();
qwtUnscaleFont( painter );
painter->drawText( pos, text );
painter->restore();
}
void QwtPainter::drawText( QPainter* painter,
qreal x, qreal y, qreal w, qreal h,
int flags, const QString& text )
{
drawText( painter, QRectF( x, y, w, h ), flags, text );
}
void QwtPainter::drawText( QPainter* painter, const QRectF& rect,
int flags, const QString& text )
{
painter->save();
qwtUnscaleFont( painter );
painter->drawText( rect, flags, text );
painter->restore();
}
#ifndef QT_NO_RICHTEXT
void QwtPainter::drawSimpleRichText( QPainter* painter, const QRectF& rect,
int flags, const QTextDocument& text )
{
QTextDocument* txt = text.clone();
painter->save();
QRectF unscaledRect = rect;
if ( painter->font().pixelSize() < 0 )
{
const QSize res = qwtScreenResolution();
const QPaintDevice* pd = painter->device();
if ( pd->logicalDpiX() != res.width() ||
pd->logicalDpiY() != res.height() )
{
QTransform transform;
transform.scale( res.width() / qreal( pd->logicalDpiX() ),
res.height() / qreal( pd->logicalDpiY() ) );
painter->setWorldTransform( transform, true );
unscaledRect = transform.inverted().mapRect(rect);
}
}
txt->setDefaultFont( painter->font() );
txt->setPageSize( QSizeF( unscaledRect.width(), QWIDGETSIZE_MAX ) );
QAbstractTextDocumentLayout* layout = txt->documentLayout();
const qreal height = layout->documentSize().height();
qreal y = unscaledRect.y();
if ( flags & Qt::AlignBottom )
y += ( unscaledRect.height() - height );
else if ( flags & Qt::AlignVCenter )
y += ( unscaledRect.height() - height ) / 2;
QAbstractTextDocumentLayout::PaintContext context;
context.palette.setColor( QPalette::Text, painter->pen().color() );
painter->translate( unscaledRect.x(), y );
layout->draw( painter, context );
painter->restore();
delete txt;
}
#endif // !QT_NO_RICHTEXT
void QwtPainter::drawLine( QPainter* painter,
const QPointF& p1, const QPointF& p2 )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping &&
!( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) )
{
QPolygonF polygon;
polygon += p1;
polygon += p2;
drawPolyline( painter, polygon );
return;
}
painter->drawLine( p1, p2 );
}
void QwtPainter::drawPolygon( QPainter* painter, const QPolygonF& polygon )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
painter->drawPolygon(
QwtClipper::clippedPolygonF( clipRect, polygon, true ) );
}
else
{
painter->drawPolygon( polygon );
}
}
void QwtPainter::drawPolyline( QPainter* painter, const QPolygonF& polygon )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
const QPolygonF cpa = QwtClipper::clippedPolygonF( clipRect, polygon );
qwtDrawPolyline< QPointF >( painter,
cpa.constData(), cpa.size(), m_polylineSplitting );
}
else
{
qwtDrawPolyline< QPointF >( painter,
polygon.constData(), polygon.size(), m_polylineSplitting );
}
}
void QwtPainter::drawPolyline( QPainter* painter,
const QPointF* points, int pointCount )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
QPolygonF polygon( pointCount );
std::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) );
QwtClipper::clipPolygonF( clipRect, polygon );
qwtDrawPolyline< QPointF >( painter,
polygon.constData(), polygon.size(), m_polylineSplitting );
}
else
{
qwtDrawPolyline< QPointF >( painter, points, pointCount, m_polylineSplitting );
}
}
void QwtPainter::drawPolygon( QPainter* painter, const QPolygon& polygon )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
painter->drawPolygon(
QwtClipper::clippedPolygon( clipRect, polygon, true ) );
}
else
{
painter->drawPolygon( polygon );
}
}
void QwtPainter::drawPolyline( QPainter* painter, const QPolygon& polygon )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
const QPolygon cpa = QwtClipper::clippedPolygon( clipRect, polygon );
qwtDrawPolyline< QPoint >( painter,
cpa.constData(), cpa.size(), m_polylineSplitting );
}
else
{
qwtDrawPolyline< QPoint >( painter,
polygon.constData(), polygon.size(), m_polylineSplitting );
}
}
void QwtPainter::drawPolyline( QPainter* painter,
const QPoint* points, int pointCount )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
QPolygon polygon( pointCount );
std::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) );
QwtClipper::clipPolygon( clipRect, polygon );
qwtDrawPolyline< QPoint >( painter,
polygon.constData(), polygon.size(), m_polylineSplitting );
}
else
{
qwtDrawPolyline< QPoint >( painter, points, pointCount, m_polylineSplitting );
}
}
void QwtPainter::drawPoint( QPainter* painter, const QPointF& pos )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping && !clipRect.contains( pos ) )
return;
painter->drawPoint( pos );
}
void QwtPainter::drawPoint( QPainter* painter, const QPoint& pos )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
const int minX = qwtCeil( clipRect.left() );
const int maxX = qwtFloor( clipRect.right() );
const int minY = qwtCeil( clipRect.top() );
const int maxY = qwtFloor( clipRect.bottom() );
if ( pos.x() < minX || pos.x() > maxX
|| pos.y() < minY || pos.y() > maxY )
{
return;
}
}
painter->drawPoint( pos );
}
void QwtPainter::drawPoints( QPainter* painter,
const QPoint* points, int pointCount )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
const int minX = qwtCeil( clipRect.left() );
const int maxX = qwtFloor( clipRect.right() );
const int minY = qwtCeil( clipRect.top() );
const int maxY = qwtFloor( clipRect.bottom() );
const QRect r( minX, minY, maxX - minX, maxY - minY );
QPolygon clippedPolygon( pointCount );
QPoint* clippedData = clippedPolygon.data();
int numClippedPoints = 0;
for ( int i = 0; i < pointCount; i++ )
{
if ( r.contains( points[i] ) )
clippedData[ numClippedPoints++ ] = points[i];
}
painter->drawPoints( clippedData, numClippedPoints );
}
else
{
painter->drawPoints( points, pointCount );
}
}
void QwtPainter::drawPoints( QPainter* painter,
const QPointF* points, int pointCount )
{
QRectF clipRect;
const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
if ( deviceClipping )
{
QPolygonF clippedPolygon( pointCount );
QPointF* clippedData = clippedPolygon.data();
int numClippedPoints = 0;
for ( int i = 0; i < pointCount; i++ )
{
if ( clipRect.contains( points[i] ) )
clippedData[ numClippedPoints++ ] = points[i];
}
painter->drawPoints( clippedData, numClippedPoints );
}
else
{
painter->drawPoints( points, pointCount );
}
}
void QwtPainter::drawImage( QPainter* painter,
const QRectF& rect, const QImage& image )
{
const QRect alignedRect = rect.toAlignedRect();
if ( alignedRect != rect )
{
const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
painter->save();
painter->setClipRect( clipRect, Qt::IntersectClip );
painter->drawImage( alignedRect, image );
painter->restore();
}
else
{
painter->drawImage( alignedRect, image );
}
}
void QwtPainter::drawPixmap( QPainter* painter,
const QRectF& rect, const QPixmap& pixmap )
{
const QRect alignedRect = rect.toAlignedRect();
if ( alignedRect != rect )
{
const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
painter->save();
painter->setClipRect( clipRect, Qt::IntersectClip );
painter->drawPixmap( alignedRect, pixmap );
painter->restore();
}
else
{
painter->drawPixmap( alignedRect, pixmap );
}
}
void QwtPainter::drawFocusRect( QPainter* painter, const QWidget* widget )
{
drawFocusRect( painter, widget, widget->rect() );
}
void QwtPainter::drawFocusRect( QPainter* painter, const QWidget* widget,
const QRect& rect )
{
QStyleOptionFocusRect opt;
opt.initFrom( widget );
opt.rect = rect;
opt.state |= QStyle::State_HasFocus;
opt.backgroundColor = widget->palette().color( widget->backgroundRole() );
widget->style()->drawPrimitive(
QStyle::PE_FrameFocusRect, &opt, painter, widget );
}
void QwtPainter::drawRoundFrame( QPainter* painter,
const QRectF& rect, const QPalette& palette,
int lineWidth, int frameStyle )
{
enum Style
{
Plain,
Sunken,
Raised
};
Style style = Plain;
if ( (frameStyle& QFrame::Sunken) == QFrame::Sunken )
style = Sunken;
else if ( (frameStyle& QFrame::Raised) == QFrame::Raised )
style = Raised;
const qreal lw2 = 0.5 * lineWidth;
QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
QBrush brush;
if ( style != Plain )
{
QColor c1 = palette.color( QPalette::Light );
QColor c2 = palette.color( QPalette::Dark );
if ( style == Sunken )
qSwap( c1, c2 );
QLinearGradient gradient( r.topLeft(), r.bottomRight() );
gradient.setColorAt( 0.0, c1 );
#if 0
gradient.setColorAt( 0.3, c1 );
gradient.setColorAt( 0.7, c2 );
#endif
gradient.setColorAt( 1.0, c2 );
brush = QBrush( gradient );
}
else // Plain
{
brush = palette.brush( QPalette::WindowText );
}
painter->save();
painter->setPen( QPen( brush, lineWidth ) );
painter->setBrush( Qt::NoBrush );
painter->drawEllipse( r );
painter->restore();
}
void QwtPainter::drawFrame( QPainter* painter, const QRectF& rect,
const QPalette& palette, QPalette::ColorRole foregroundRole,
int frameWidth, int midLineWidth, int frameStyle )
{
if ( frameWidth <= 0 || rect.isEmpty() )
return;
const int shadow = frameStyle & QFrame::Shadow_Mask;
painter->save();
if ( shadow == QFrame::Plain )
{
const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
const QRectF innerRect = outerRect.adjusted(
frameWidth, frameWidth, -frameWidth, -frameWidth );
QPainterPath path;
path.addRect( outerRect );
path.addRect( innerRect );
painter->setPen( Qt::NoPen );
painter->setBrush( palette.color( foregroundRole ) );
painter->drawPath( path );
}
else
{
const int shape = frameStyle & QFrame::Shape_Mask;
if ( shape == QFrame::Box )
{
const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
const QRectF midRect1 = outerRect.adjusted(
frameWidth, frameWidth, -frameWidth, -frameWidth );
const QRectF midRect2 = midRect1.adjusted(
midLineWidth, midLineWidth, -midLineWidth, -midLineWidth );
const QRectF innerRect = midRect2.adjusted(
frameWidth, frameWidth, -frameWidth, -frameWidth );
QPainterPath path1;
path1.moveTo( outerRect.bottomLeft() );
path1.lineTo( outerRect.topLeft() );
path1.lineTo( outerRect.topRight() );
path1.lineTo( midRect1.topRight() );
path1.lineTo( midRect1.topLeft() );
path1.lineTo( midRect1.bottomLeft() );
QPainterPath path2;
path2.moveTo( outerRect.bottomLeft() );
path2.lineTo( outerRect.bottomRight() );
path2.lineTo( outerRect.topRight() );
path2.lineTo( midRect1.topRight() );
path2.lineTo( midRect1.bottomRight() );
path2.lineTo( midRect1.bottomLeft() );
QPainterPath path3;
path3.moveTo( midRect2.bottomLeft() );
path3.lineTo( midRect2.topLeft() );
path3.lineTo( midRect2.topRight() );
path3.lineTo( innerRect.topRight() );
path3.lineTo( innerRect.topLeft() );
path3.lineTo( innerRect.bottomLeft() );
QPainterPath path4;
path4.moveTo( midRect2.bottomLeft() );
path4.lineTo( midRect2.bottomRight() );
path4.lineTo( midRect2.topRight() );
path4.lineTo( innerRect.topRight() );
path4.lineTo( innerRect.bottomRight() );
path4.lineTo( innerRect.bottomLeft() );
QPainterPath path5;
path5.addRect( midRect1 );
path5.addRect( midRect2 );
painter->setPen( Qt::NoPen );
QBrush brush1 = palette.dark().color();
QBrush brush2 = palette.light().color();
if ( shadow == QFrame::Raised )
qSwap( brush1, brush2 );
painter->setBrush( brush1 );
painter->drawPath( path1 );
painter->drawPath( path4 );
painter->setBrush( brush2 );
painter->drawPath( path2 );
painter->drawPath( path3 );
painter->setBrush( palette.mid() );
painter->drawPath( path5 );
}
else
{
const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
const QRectF innerRect = outerRect.adjusted(
frameWidth - 1.0, frameWidth - 1.0,
-( frameWidth - 1.0 ), -( frameWidth - 1.0 ) );
QPainterPath path1;
path1.moveTo( outerRect.bottomLeft() );
path1.lineTo( outerRect.topLeft() );
path1.lineTo( outerRect.topRight() );
path1.lineTo( innerRect.topRight() );
path1.lineTo( innerRect.topLeft() );
path1.lineTo( innerRect.bottomLeft() );
QPainterPath path2;
path2.moveTo( outerRect.bottomLeft() );
path2.lineTo( outerRect.bottomRight() );
path2.lineTo( outerRect.topRight() );
path2.lineTo( innerRect.topRight() );
path2.lineTo( innerRect.bottomRight() );
path2.lineTo( innerRect.bottomLeft() );
painter->setPen( Qt::NoPen );
QBrush brush1 = palette.dark().color();
QBrush brush2 = palette.light().color();
if ( shadow == QFrame::Raised )
qSwap( brush1, brush2 );
painter->setBrush( brush1 );
painter->drawPath( path1 );
painter->setBrush( brush2 );
painter->drawPath( path2 );
}
}
painter->restore();
}
void QwtPainter::drawRoundedFrame( QPainter* painter,
const QRectF& rect, qreal xRadius, qreal yRadius,
const QPalette& palette, int lineWidth, int frameStyle )
{
painter->save();
painter->setRenderHint( QPainter::Antialiasing, true );
painter->setBrush( Qt::NoBrush );
qreal lw2 = lineWidth * 0.5;
QRectF innerRect = rect.adjusted( lw2, lw2, -lw2, -lw2 );
QPainterPath path;
path.addRoundedRect( innerRect, xRadius, yRadius );
enum Style
{
Plain,
Sunken,
Raised
};
Style style = Plain;
if ( (frameStyle& QFrame::Sunken) == QFrame::Sunken )
style = Sunken;
else if ( (frameStyle& QFrame::Raised) == QFrame::Raised )
style = Raised;
if ( style != Plain && path.elementCount() == 17 )
{
// move + 4 * ( cubicTo + lineTo )
QPainterPath pathList[8];
for ( int i = 0; i < 4; i++ )
{
const int j = i * 4 + 1;
pathList[ 2 * i ].moveTo(
path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
);
pathList[ 2 * i ].cubicTo(
path.elementAt(j + 0).x, path.elementAt(j + 0).y,
path.elementAt(j + 1).x, path.elementAt(j + 1).y,
path.elementAt(j + 2).x, path.elementAt(j + 2).y );
pathList[ 2 * i + 1 ].moveTo(
path.elementAt(j + 2).x, path.elementAt(j + 2).y
);
pathList[ 2 * i + 1 ].lineTo(
path.elementAt(j + 3).x, path.elementAt(j + 3).y
);
}
QColor c1( palette.color( QPalette::Dark ) );
QColor c2( palette.color( QPalette::Light ) );
if ( style == Raised )
qSwap( c1, c2 );
for ( int i = 0; i < 4; i++ )
{
const QRectF r = pathList[2 * i].controlPointRect();
QPen arcPen;
arcPen.setCapStyle( Qt::FlatCap );
arcPen.setWidth( lineWidth );
QPen linePen;
linePen.setCapStyle( Qt::FlatCap );
linePen.setWidth( lineWidth );
switch( i )
{
case 0:
{
arcPen.setColor( c1 );
linePen.setColor( c1 );
break;
}
case 1:
{
QLinearGradient gradient;
gradient.setStart( r.topLeft() );
gradient.setFinalStop( r.bottomRight() );
gradient.setColorAt( 0.0, c1 );
gradient.setColorAt( 1.0, c2 );
arcPen.setBrush( gradient );
linePen.setColor( c2 );
break;
}
case 2:
{
arcPen.setColor( c2 );
linePen.setColor( c2 );
break;
}
case 3:
{
QLinearGradient gradient;
gradient.setStart( r.bottomRight() );
gradient.setFinalStop( r.topLeft() );
gradient.setColorAt( 0.0, c2 );
gradient.setColorAt( 1.0, c1 );
arcPen.setBrush( gradient );
linePen.setColor( c1 );
break;
}
}
painter->setPen( arcPen );
painter->drawPath( pathList[ 2 * i] );
painter->setPen( linePen );
painter->drawPath( pathList[ 2 * i + 1] );
}
}
else
{
QPen pen( palette.color( QPalette::WindowText ), lineWidth );
painter->setPen( pen );
painter->drawPath( path );
}
painter->restore();
}
void QwtPainter::drawColorBar( QPainter* painter,
const QwtColorMap& colorMap, const QwtInterval& interval,
const QwtScaleMap& scaleMap, Qt::Orientation orientation,
const QRectF& rect )
{
QVector< QRgb > colorTable;
if ( colorMap.format() == QwtColorMap::Indexed )
colorTable = colorMap.colorTable256();
QColor c;
const QRect devRect = rect.toAlignedRect();
/*
We paint to a pixmap first to have something scalable for printing
( f.e. in a Pdf document )
*/
QPixmap pixmap( devRect.size() );
pixmap.fill( Qt::transparent );
QPainter pmPainter( &pixmap );
pmPainter.translate( -devRect.x(), -devRect.y() );
if ( orientation == Qt::Horizontal )
{
QwtScaleMap sMap = scaleMap;
sMap.setPaintInterval( rect.left(), rect.right() );
for ( int x = devRect.left(); x <= devRect.right(); x++ )
{
const double value = sMap.invTransform( x );
if ( colorMap.format() == QwtColorMap::RGB )
c.setRgba( colorMap.rgb( interval, value ) );
else
c = colorTable[colorMap.colorIndex( 256, interval, value )];
pmPainter.setPen( c );
pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() );
}
}
else // Vertical
{
QwtScaleMap sMap = scaleMap;
sMap.setPaintInterval( rect.bottom(), rect.top() );
for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
{
const double value = sMap.invTransform( y );
if ( colorMap.format() == QwtColorMap::RGB )
c.setRgba( colorMap.rgb( interval, value ) );
else
c = colorTable[colorMap.colorIndex( 256, interval, value )];
pmPainter.setPen( c );
pmPainter.drawLine( devRect.left(), y, devRect.right(), y );
}
}
pmPainter.end();
drawPixmap( painter, rect, pixmap );
}
static inline void qwtFillRect( const QWidget* widget, QPainter* painter,
const QRect& rect, const QBrush& brush)
{
if ( brush.style() == Qt::TexturePattern )
{
painter->save();
painter->setClipRect( rect );
painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft() );
painter->restore();
}
else if ( brush.gradient() )
{
painter->save();
painter->setClipRect( rect );
painter->fillRect(0, 0, widget->width(),
widget->height(), brush);
painter->restore();
}
else
{
painter->fillRect(rect, brush);
}
}
void QwtPainter::fillPixmap( const QWidget* widget,
QPixmap& pixmap, const QPoint& offset )
{
const QRect rect( offset, pixmap.size() );
QPainter painter( &pixmap );
painter.translate( -offset );
const QBrush autoFillBrush =
widget->palette().brush( widget->backgroundRole() );
if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) )
{
const QBrush bg = widget->palette().brush( QPalette::Window );
qwtFillRect( widget, &painter, rect, bg);
}
if ( widget->autoFillBackground() )
qwtFillRect( widget, &painter, rect, autoFillBrush);
if ( widget->testAttribute(Qt::WA_StyledBackground) )
{
painter.setClipRegion( rect );
QStyleOption opt;
opt.initFrom( widget );
widget->style()->drawPrimitive( QStyle::PE_Widget,
&opt, &painter, widget );
}
}
void QwtPainter::drawBackgound( QPainter* painter,
const QRectF& rect, const QWidget* widget )
{
if ( widget->testAttribute( Qt::WA_StyledBackground ) )
{
QStyleOption opt;
opt.initFrom( widget );
opt.rect = rect.toAlignedRect();
widget->style()->drawPrimitive(
QStyle::PE_Widget, &opt, painter, widget);
}
else
{
const QBrush brush =
widget->palette().brush( widget->backgroundRole() );
painter->fillRect( rect, brush );
}
}
int QwtPainter::horizontalAdvance(
const QFontMetrics& fontMetrics, const QString& text )
{
#if QT_VERSION >= 0x050b00
return fontMetrics.horizontalAdvance( text );
#else
return fontMetrics.width( text );
#endif
}
qreal QwtPainter::horizontalAdvance(
const QFontMetricsF& fontMetrics, const QString& text )
{
#if QT_VERSION >= 0x050b00
return fontMetrics.horizontalAdvance( text );
#else
return fontMetrics.width( text );
#endif
}
int QwtPainter::horizontalAdvance(
const QFontMetrics& fontMetrics, QChar ch )
{
#if QT_VERSION >= 0x050b00
return fontMetrics.horizontalAdvance( ch );
#else
return fontMetrics.width( ch );
#endif
}
qreal QwtPainter::horizontalAdvance(
const QFontMetricsF& fontMetrics, QChar ch )
{
#if QT_VERSION >= 0x050b00
return fontMetrics.horizontalAdvance( ch );
#else
return fontMetrics.width( ch );
#endif
}
QFont QwtPainter::scaledFont( const QFont& font, const QPaintDevice* paintDevice )
{
if ( paintDevice == NULL )
{
#if QT_VERSION < 0x060000
paintDevice = QApplication::desktop();
#else
class PaintDevice : public QPaintDevice
{
virtual QPaintEngine* paintEngine() const QWT_OVERRIDE
{
return NULL;
}
virtual int metric( PaintDeviceMetric metric ) const QWT_OVERRIDE
{
if ( metric == PdmDpiY )
{
QScreen* screen = QGuiApplication::primaryScreen();
if ( screen )
{
return screen->logicalDotsPerInchY();
}
}
return QPaintDevice::metric( metric );
}
};
static PaintDevice dummyPaintDevice;
paintDevice = &dummyPaintDevice;
#endif
}
return QFont( font, const_cast< QPaintDevice* >( paintDevice ) );
}
qreal QwtPainter::devicePixelRatio( const QPaintDevice* paintDevice )
{
qreal pixelRatio = 0.0;
#if QT_VERSION >= 0x050100
if ( paintDevice )
{
#if QT_VERSION >= 0x050600
pixelRatio = paintDevice->devicePixelRatioF();
#else
pixelRatio = paintDevice->devicePixelRatio();
#endif
}
#else
Q_UNUSED( paintDevice )
#endif
#if QT_VERSION >= 0x050000
if ( pixelRatio == 0.0 && qApp )
pixelRatio = qApp->devicePixelRatio();
#endif
if ( pixelRatio == 0.0 )
pixelRatio = 1.0;
return pixelRatio;
}
QPixmap QwtPainter::backingStore( QWidget* widget, const QSize& size )
{
QPixmap pm;
#if QT_VERSION >= 0x050000
const qreal pixelRatio = QwtPainter::devicePixelRatio( widget );
pm = QPixmap( size * pixelRatio );
pm.setDevicePixelRatio( pixelRatio );
#else
pm = QPixmap( size );
#endif
#ifdef Q_WS_X11
if ( widget && isX11GraphicsSystem() )
{
if ( pm.x11Info().screen() != widget->x11Info().screen() )
pm.x11SetScreen( widget->x11Info().screen() );
}
#else
Q_UNUSED( widget )
#endif
return pm;
}
QVector< QRgb >
QwtColorMap
QwtColorMap is used to map values into colors.
Definition qwt_color_map.h:38
QwtColorMap::colorIndex
virtual uint colorIndex(int numColors, const QwtInterval &interval, double value) const
Map a value of a given interval into a color index.
Definition qwt_color_map.cpp:278
QwtColorMap::Indexed
@ Indexed
Definition qwt_color_map.h:60
QwtColorMap::RGB
@ RGB
The map is intended to map into RGB values.
Definition qwt_color_map.h:48
QwtColorMap::colorTable256
virtual QVector< QRgb > colorTable256() const
Definition qwt_color_map.cpp:304
QwtColorMap::rgb
virtual QRgb rgb(const QwtInterval &interval, double value) const =0
QwtInterval
A class representing an interval.
Definition qwt_interval.h:23
QwtPainter::drawEllipse
static void drawEllipse(QPainter *, const QRectF &)
Wrapper for QPainter::drawEllipse()
Definition qwt_painter.cpp:416
QwtPainter::drawPoints
static void drawPoints(QPainter *, const QPolygon &)
Wrapper for QPainter::drawPoints()
Definition qwt_painter.h:142
QwtPainter::setPolylineSplitting
static void setPolylineSplitting(bool)
En/Disable line splitting for the raster paint engine.
Definition qwt_painter.cpp:325
QwtPainter::drawSimpleRichText
static void drawSimpleRichText(QPainter *, const QRectF &, int flags, const QTextDocument &)
Definition qwt_painter.cpp:479
QwtPainter::drawPath
static void drawPath(QPainter *, const QPainterPath &)
Wrapper for QPainter::drawPath()
Definition qwt_painter.cpp:331
QwtPainter::drawImage
static void drawImage(QPainter *, const QRectF &, const QImage &)
Wrapper for QPainter::drawImage()
Definition qwt_painter.cpp:763
QwtPainter::drawPolygon
static void drawPolygon(QPainter *, const QPolygonF &)
Wrapper for QPainter::drawPolygon()
Definition qwt_painter.cpp:551
QwtPainter::drawRoundFrame
static void drawRoundFrame(QPainter *, const QRectF &, const QPalette &, int lineWidth, int frameStyle)
Definition qwt_painter.cpp:835
QwtPainter::setRoundingAlignment
static void setRoundingAlignment(bool)
Definition qwt_painter.cpp:305
QwtPainter::drawPolyline
static void drawPolyline(QPainter *, const QPolygonF &)
Wrapper for QPainter::drawPolyline()
Definition qwt_painter.cpp:568
QwtPainter::drawText
static void drawText(QPainter *, qreal x, qreal y, const QString &)
Wrapper for QPainter::drawText()
Definition qwt_painter.cpp:428
QwtPainter::isAligning
static bool isAligning(const QPainter *)
Definition qwt_painter.cpp:257
QwtPainter::fillRect
static void fillRect(QPainter *, const QRectF &, const QBrush &)
Wrapper for QPainter::fillRect()
Definition qwt_painter.cpp:372
QwtPainter::drawRoundedFrame
static void drawRoundedFrame(QPainter *, const QRectF &, qreal xRadius, qreal yRadius, const QPalette &, int lineWidth, int frameStyle)
Definition qwt_painter.cpp:1055
QwtPainter::drawBackgound
static void drawBackgound(QPainter *, const QRectF &, const QWidget *)
Definition qwt_painter.cpp:1341
QwtPainter::drawFocusRect
static void drawFocusRect(QPainter *, const QWidget *)
Draw a focus rectangle on a widget using its style.
Definition qwt_painter.cpp:805
QwtPainter::drawPoint
static void drawPoint(QPainter *, const QPoint &)
Wrapper for QPainter::drawPoint()
Definition qwt_painter.cpp:681
QwtPainter::fillPixmap
static void fillPixmap(const QWidget *, QPixmap &, const QPoint &offset=QPoint())
Definition qwt_painter.cpp:1301
QwtPainter::drawRect
static void drawRect(QPainter *, qreal x, qreal y, qreal w, qreal h)
Wrapper for QPainter::drawRect()
Definition qwt_painter.cpp:337
QwtPainter::devicePixelRatio
static qreal devicePixelRatio(const QPaintDevice *)
Definition qwt_painter.cpp:1481
QwtPainter::drawFrame
static void drawFrame(QPainter *, const QRectF &rect, const QPalette &palette, QPalette::ColorRole foregroundRole, int lineWidth, int midLineWidth, int frameStyle)
Definition qwt_painter.cpp:901
QwtPainter::backingStore
static QPixmap backingStore(QWidget *, const QSize &)
Definition qwt_painter.cpp:1515
QwtPainter::drawColorBar
static void drawColorBar(QPainter *, const QwtColorMap &, const QwtInterval &, const QwtScaleMap &, Qt::Orientation, const QRectF &)
Definition qwt_painter.cpp:1195
QwtPainter::drawPixmap
static void drawPixmap(QPainter *, const QRectF &, const QPixmap &)
Wrapper for QPainter::drawPixmap()
Definition qwt_painter.cpp:784
QwtPainter::scaledFont
static QFont scaledFont(const QFont &, const QPaintDevice *=NULL)
Definition qwt_painter.cpp:1440
QwtPainter::isX11GraphicsSystem
static bool isX11GraphicsSystem()
Definition qwt_painter.cpp:223
QwtPainter::drawPie
static void drawPie(QPainter *, const QRectF &r, int a, int alen)
Wrapper for QPainter::drawPie()
Definition qwt_painter.cpp:404
QwtPainter::horizontalAdvance
static int horizontalAdvance(const QFontMetrics &, const QString &)
Definition qwt_painter.cpp:1369
QwtPainter::drawLine
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
Definition qwt_painter.h:154
QwtScaleMap
A scale map.
Definition qwt_scale_map.h:27
QwtScaleMap::setPaintInterval
void setPaintInterval(double p1, double p2)
Specify the borders of the paint device interval.
Definition qwt_scale_map.cpp:119
QwtScaleMap::invTransform
double invTransform(double p) const
Definition qwt_scale_map.h:154
QwtClipper::clipPolygon
QWT_EXPORT void clipPolygon(const QRect &, QPolygon &, bool closePolygon=false)
Definition qwt_clipper.cpp:390
QwtClipper::clippedPolygonF
QWT_EXPORT QPolygonF clippedPolygonF(const QRectF &, const QPolygonF &, bool closePolygon=false)
Definition qwt_clipper.cpp:455
QwtClipper::clipPolygonF
QWT_EXPORT void clipPolygonF(const QRectF &, QPolygonF &, bool closePolygon=false)
Definition qwt_clipper.cpp:404
QwtClipper::clippedPolygon
QWT_EXPORT QPolygon clippedPolygon(const QRect &, const QPolygon &, bool closePolygon=false)
Definition qwt_clipper.cpp:437