10#include "qwt_graphic.h"
11#include "qwt_painter_command.h"
16#include <qpaintengine.h>
19#include <qpainterpath.h>
21#if QT_VERSION >= 0x050000
23#include <qguiapplication.h>
25static inline qreal qwtDevicePixelRatio()
27 return qGuiApp ? qGuiApp->devicePixelRatio() : 1.0;
32static bool qwtHasScalablePen(
const QPainter* painter )
34 const QPen pen = painter->pen();
36 bool scalablePen =
false;
38 if ( pen.style() != Qt::NoPen && pen.brush().style() != Qt::NoBrush )
40 scalablePen = !pen.isCosmetic();
41#if QT_VERSION < 0x050000
42 if ( !scalablePen && pen.widthF() == 0.0 )
44 const QPainter::RenderHints hints = painter->renderHints();
45 if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) )
54static QRectF qwtStrokedPathRect(
55 const QPainter* painter,
const QPainterPath& path )
57 QPainterPathStroker stroker;
58 stroker.setWidth( painter->pen().widthF() );
59 stroker.setCapStyle( painter->pen().capStyle() );
60 stroker.setJoinStyle( painter->pen().joinStyle() );
61 stroker.setMiterLimit( painter->pen().miterLimit() );
64 if ( qwtHasScalablePen( painter ) )
66 QPainterPath stroke = stroker.createStroke( path );
67 rect = painter->transform().map( stroke ).boundingRect();
71 QPainterPath mappedPath = painter->transform().map( path );
72 mappedPath = stroker.createStroke( mappedPath );
74 rect = mappedPath.boundingRect();
80static inline void qwtExecCommand(
83 const QTransform& transform,
84 const QTransform* initialTransform )
92 if ( painter->transform().isScaling() )
94 bool isCosmetic = painter->pen().isCosmetic();
95#if QT_VERSION < 0x050000
96 if ( isCosmetic && painter->pen().widthF() == 0.0 )
98 QPainter::RenderHints hints = painter->renderHints();
99 if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) )
109 doMap = painter->paintEngine()->type() == QPaintEngine::OpenGL2;
119 const QTransform tr = painter->transform();
121 painter->resetTransform();
123 QPainterPath path = tr.map( *cmd.
path() );
124 if ( initialTransform )
126 painter->setTransform( *initialTransform );
127 path = initialTransform->inverted().map( path );
130 painter->drawPath( path );
132 painter->setTransform( tr );
136 painter->drawPath( *cmd.
path() );
142 const QwtPainterCommand::PixmapData* data = cmd.
pixmapData();
143 painter->drawPixmap( data->rect, data->pixmap, data->subRect );
148 const QwtPainterCommand::ImageData* data = cmd.
imageData();
149 painter->drawImage( data->rect, data->image,
150 data->subRect, data->flags );
155 const QwtPainterCommand::StateData* data = cmd.
stateData();
157 if ( data->flags & QPaintEngine::DirtyPen )
158 painter->setPen( data->pen );
160 if ( data->flags & QPaintEngine::DirtyBrush )
161 painter->setBrush( data->brush );
163 if ( data->flags & QPaintEngine::DirtyBrushOrigin )
164 painter->setBrushOrigin( data->brushOrigin );
166 if ( data->flags & QPaintEngine::DirtyFont )
167 painter->setFont( data->font );
169 if ( data->flags & QPaintEngine::DirtyBackground )
171 painter->setBackgroundMode( data->backgroundMode );
172 painter->setBackground( data->backgroundBrush );
175 if ( data->flags & QPaintEngine::DirtyTransform )
177 painter->setTransform( data->transform * transform );
180 if ( data->flags & QPaintEngine::DirtyClipEnabled )
181 painter->setClipping( data->isClipEnabled );
183 if ( data->flags & QPaintEngine::DirtyClipRegion )
185 painter->setClipRegion( data->clipRegion,
186 data->clipOperation );
189 if ( data->flags & QPaintEngine::DirtyClipPath )
191 painter->setClipPath( data->clipPath, data->clipOperation );
194 if ( data->flags & QPaintEngine::DirtyHints )
196 for (
int i = 0; i < 8; i++ )
198 const QPainter::RenderHint hint =
static_cast< QPainter::RenderHint
>( 1 << i );
199 painter->setRenderHint( hint, data->renderHints.testFlag( hint ) );
203 if ( data->flags & QPaintEngine::DirtyCompositionMode )
204 painter->setCompositionMode( data->compositionMode );
206 if ( data->flags & QPaintEngine::DirtyOpacity )
207 painter->setOpacity( data->opacity );
216class QwtGraphic::PathInfo
220 : m_scalablePen( false )
225 PathInfo(
const QRectF& pointRect,
227 : m_pointRect( pointRect )
229 , m_scalablePen( scalablePen )
233 inline QRectF scaledBoundingRect( qreal sx, qreal sy,
bool scalePens )
const
235 if ( sx == 1.0 && sy == 1.0 )
236 return m_boundingRect;
238 QTransform transform;
239 transform.scale( sx, sy );
242 if ( scalePens && m_scalablePen )
244 rect = transform.mapRect( m_boundingRect );
248 rect = transform.mapRect( m_pointRect );
250 const qreal l = qAbs( m_pointRect.left() - m_boundingRect.left() );
251 const qreal r = qAbs( m_pointRect.right() - m_boundingRect.right() );
252 const qreal t = qAbs( m_pointRect.top() - m_boundingRect.top() );
253 const qreal b = qAbs( m_pointRect.bottom() - m_boundingRect.bottom() );
255 rect.adjust( -l, -t, r, b );
261 inline double scaleFactorX(
const QRectF& pathRect,
262 const QRectF& targetRect,
bool scalePens )
const
264 if ( pathRect.width() <= 0.0 )
267 const QPointF p0 = m_pointRect.center();
269 const qreal l = qAbs( pathRect.left() - p0.x() );
270 const qreal r = qAbs( pathRect.right() - p0.x() );
272 const double w = 2.0 * qwtMinF( l, r )
273 * targetRect.width() / pathRect.width();
276 if ( scalePens && m_scalablePen )
278 sx = w / m_boundingRect.width();
282 const qreal pw = qwtMaxF(
283 qAbs( m_boundingRect.left() - m_pointRect.left() ),
284 qAbs( m_boundingRect.right() - m_pointRect.right() ) );
286 sx = ( w - 2 * pw ) / m_pointRect.width();
292 inline double scaleFactorY(
const QRectF& pathRect,
293 const QRectF& targetRect,
bool scalePens )
const
295 if ( pathRect.height() <= 0.0 )
298 const QPointF p0 = m_pointRect.center();
300 const qreal t = qAbs( pathRect.top() - p0.y() );
301 const qreal b = qAbs( pathRect.bottom() - p0.y() );
303 const qreal h = 2.0 * qwtMinF( t, b )
304 * targetRect.height() / pathRect.height();
307 if ( scalePens && m_scalablePen )
309 sy = h / m_boundingRect.height();
313 const qreal pw = qwtMaxF(
314 qAbs( m_boundingRect.top() - m_pointRect.top() ),
315 qAbs( m_boundingRect.bottom() - m_pointRect.bottom() ) );
317 sy = ( h - 2 * pw ) / m_pointRect.height();
325 QRectF m_boundingRect;
329class QwtGraphic::PrivateData
333 : boundingRect( 0.0, 0.0, -1.0, -1.0 )
334 , pointRect( 0.0, 0.0, -1.0, -1.0 )
358 m_data =
new PrivateData;
370 m_data =
new PrivateData( *other.m_data );
388 *m_data = *other.m_data;
399 m_data->commands.clear();
400 m_data->pathInfos.clear();
404 m_data->boundingRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
405 m_data->pointRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
406 m_data->defaultSize = QSizeF();
415 return m_data->commands.isEmpty();
424 return m_data->boundingRect.isEmpty();
432 return m_data->commandTypes;
446 m_data->renderHints |= hint;
448 m_data->renderHints &= ~hint;
460 return m_data->renderHints.testFlag( hint );
466 return m_data->renderHints;
479 if ( m_data->boundingRect.width() < 0 )
482 return m_data->boundingRect;
495 if ( m_data->pointRect.width() < 0 )
498 return m_data->pointRect;
516 if ( sx == 1.0 && sy == 1.0 )
517 return m_data->boundingRect;
521 QTransform transform;
522 transform.scale( sx, sy );
524 QRectF rect = transform.mapRect( m_data->pointRect );
526 for (
int i = 0; i < m_data->pathInfos.size(); i++ )
527 rect |= m_data->pathInfos[i].scaledBoundingRect( sx, sy, scalePens );
536 return QSize( qwtCeil( sz.width() ), qwtCeil( sz.height() ) );
555 const double w = qwtMaxF( 0.0, size.width() );
556 const double h = qwtMaxF( 0.0, size.height() );
558 m_data->defaultSize = QSizeF( w, h );
576 if ( !m_data->defaultSize.isEmpty() )
577 return m_data->defaultSize;
598 return sz.height() * width / sz.width();
617 return sz.width() * height / sz.height();
626 renderGraphic( painter, NULL );
629void QwtGraphic::renderGraphic( QPainter* painter, QTransform* initialTransform )
const
634 const int numCommands = m_data->commands.size();
637 const QTransform transform = painter->transform();
641 for (
int i = 0; i < numCommands; i++ )
643 qwtExecCommand( painter,
commands[i],
644 m_data->renderHints, transform, initialTransform );
661 Qt::AspectRatioMode aspectRatioMode )
const
663 const QRectF r( 0.0, 0.0, size.width(), size.height() );
664 render( painter, r, aspectRatioMode );
677 Qt::AspectRatioMode aspectRatioMode )
const
679 if (
isEmpty() || rect.isEmpty() )
685 if ( m_data->pointRect.width() > 0.0 )
686 sx = rect.width() / m_data->pointRect.width();
688 if ( m_data->pointRect.height() > 0.0 )
689 sy = rect.height() / m_data->pointRect.height();
693 for (
int i = 0; i < m_data->pathInfos.size(); i++ )
695 const PathInfo& info = m_data->pathInfos[i];
697 const double ssx = info.scaleFactorX(
698 m_data->pointRect, rect, scalePens );
701 sx = qwtMinF( sx, ssx );
703 const double ssy = info.scaleFactorY(
704 m_data->pointRect, rect, scalePens );
707 sy = qwtMinF( sy, ssy );
710 if ( aspectRatioMode == Qt::KeepAspectRatio )
712 const qreal s = qwtMinF( sx, sy );
716 else if ( aspectRatioMode == Qt::KeepAspectRatioByExpanding )
718 const qreal s = qwtMaxF( sx, sy );
724 tr.translate( rect.center().x() - 0.5 * sx * m_data->pointRect.width(),
725 rect.center().y() - 0.5 * sy * m_data->pointRect.height() );
727 tr.translate( -m_data->pointRect.x(), -m_data->pointRect.y() );
729 const QTransform transform = painter->transform();
731 painter->setTransform( tr,
true );
733 if ( !scalePens && transform.isScaling() )
739 QTransform initialTransform;
740 initialTransform.scale( transform.m11(), transform.m22() );
742 renderGraphic( painter, &initialTransform );
746 renderGraphic( painter, NULL );
749 painter->setTransform( transform );
763 const QPointF& pos, Qt::Alignment alignment )
const
767 if ( alignment & Qt::AlignLeft )
769 r.moveLeft( pos.x() );
771 else if ( alignment & Qt::AlignHCenter )
773 r.moveCenter( QPointF( pos.x(), r.center().y() ) );
775 else if ( alignment & Qt::AlignRight )
777 r.moveRight( pos.x() );
780 if ( alignment & Qt::AlignTop )
782 r.moveTop( pos.y() );
784 else if ( alignment & Qt::AlignVCenter )
786 r.moveCenter( QPointF( r.center().x(), pos.y() ) );
788 else if ( alignment & Qt::AlignBottom )
790 r.moveBottom( pos.y() );
819#if QT_VERSION >= 0x050000
820 if ( devicePixelRatio <= 0.0 )
821 devicePixelRatio = qwtDevicePixelRatio();
823 const int w = qwtCeil( sz.width() * devicePixelRatio );
824 const int h = qwtCeil( sz.height() * devicePixelRatio );
826 QPixmap pixmap( w, h );
827 pixmap.setDevicePixelRatio( devicePixelRatio );
829 Q_UNUSED( devicePixelRatio )
831 const int w = qwtCeil( sz.width() );
832 const int h = qwtCeil( sz.height() );
834 QPixmap pixmap( w, h );
837 pixmap.fill( Qt::transparent );
839 const QRectF r( 0.0, 0.0, sz.width(), sz.height() );
841 QPainter painter( &pixmap );
842 render( &painter, r, Qt::KeepAspectRatio );
864 Qt::AspectRatioMode aspectRatioMode, qreal devicePixelRatio )
const
866#if QT_VERSION >= 0x050000
867 if ( devicePixelRatio <= 0.0 )
868 devicePixelRatio = qwtDevicePixelRatio();
870 const int w = qwtCeil( size.width() * devicePixelRatio );
871 const int h = qwtCeil( size.height() * devicePixelRatio );
873 QPixmap pixmap( w, h );
874 pixmap.setDevicePixelRatio( devicePixelRatio );
876 Q_UNUSED( devicePixelRatio )
877 QPixmap pixmap( size );
879 pixmap.fill( Qt::transparent );
881 const QRect r( 0, 0, size.width(), size.height() );
883 QPainter painter( &pixmap );
884 render( &painter, r, aspectRatioMode );
908 Qt::AspectRatioMode aspectRatioMode, qreal devicePixelRatio )
const
910#if QT_VERSION >= 0x050000
911 if ( devicePixelRatio <= 0.0 )
912 devicePixelRatio = qwtDevicePixelRatio();
914 const int w = qwtCeil( size.width() * devicePixelRatio );
915 const int h = qwtCeil( size.height() * devicePixelRatio );
917 QImage image( w, h, QImage::Format_ARGB32_Premultiplied );
918 image.setDevicePixelRatio( devicePixelRatio );
920 Q_UNUSED( devicePixelRatio )
921 QImage image( size, QImage::Format_ARGB32_Premultiplied );
926 const QRect r( 0, 0, size.width(), size.height() );
928 QPainter painter( &image );
929 render( &painter, r, aspectRatioMode );
960#if QT_VERSION >= 0x050000
961 if ( devicePixelRatio <= 0.0 )
962 devicePixelRatio = qwtDevicePixelRatio();
964 const int w = qwtCeil( sz.width() * devicePixelRatio );
965 const int h = qwtCeil( sz.height() * devicePixelRatio );
967 QImage image( w, h, QImage::Format_ARGB32 );
968 image.setDevicePixelRatio( devicePixelRatio );
970 Q_UNUSED( devicePixelRatio )
972 const int w = qwtCeil( sz.width() );
973 const int h = qwtCeil( sz.height() );
975 QImage image( w, h, QImage::Format_ARGB32 );
980 const QRect r( 0, 0, sz.width(), sz.height() );
982 QPainter painter( &image );
983 render( &painter, r, Qt::KeepAspectRatio );
997 const QPainter* painter =
paintEngine()->painter();
998 if ( painter == NULL )
1004 if ( !path.isEmpty() )
1006 const QPainterPath scaledPath = painter->transform().map( path );
1008 QRectF pointRect = scaledPath.boundingRect();
1011 if ( painter->pen().style() != Qt::NoPen
1012 && painter->pen().brush().style() != Qt::NoBrush )
1017 updateControlPointRect( pointRect );
1020 m_data->pathInfos += PathInfo( pointRect,
1035 const QPixmap& pixmap,
const QRectF& subRect )
1037 const QPainter* painter =
paintEngine()->painter();
1038 if ( painter == NULL )
1044 const QRectF r = painter->transform().mapRect( rect );
1045 updateControlPointRect( r );
1046 updateBoundingRect( r );
1060 const QRectF& subRect, Qt::ImageConversionFlags flags )
1062 const QPainter* painter =
paintEngine()->painter();
1063 if ( painter == NULL )
1069 const QRectF r = painter->transform().mapRect( rect );
1071 updateControlPointRect( r );
1072 updateBoundingRect( r );
1085 if ( state.state() & QPaintEngine::DirtyTransform )
1094 if ( state.transform().isScaling() )
1100void QwtGraphic::updateBoundingRect(
const QRectF& rect )
1104 const QPainter* painter =
paintEngine()->painter();
1105 if ( painter && painter->hasClipping() )
1107 QRectF cr = painter->clipRegion().boundingRect();
1108 cr = painter->transform().mapRect( cr );
1113 if ( m_data->boundingRect.width() < 0 )
1114 m_data->boundingRect = br;
1116 m_data->boundingRect |= br;
1119void QwtGraphic::updateControlPointRect(
const QRectF& rect )
1121 if ( m_data->pointRect.width() < 0.0 )
1122 m_data->pointRect = rect;
1124 m_data->pointRect |= rect;
1133 return m_data->commands;
1146 const int numCommands =
commands.size();
1147 if ( numCommands <= 0 )
1155 const QTransform noTransform;
1158 QPainter painter(
this );
1159 for (
int i = 0; i < numCommands; i++ )
1160 qwtExecCommand( &painter, cmds[i], noRenderHints, noTransform, NULL );
A paint device for scalable graphics.
qreal heightForWidth(qreal width) const
virtual ~QwtGraphic()
Destructor.
virtual void updateState(const QPaintEngineState &) override
Store a state command in the command list.
bool testRenderHint(RenderHint) const
void reset()
Clear all stored commands.
void setRenderHint(RenderHint, bool on=true)
QwtGraphic & operator=(const QwtGraphic &)
Assignment operator.
QImage toImage(qreal devicePixelRatio=0.0) const
Convert the graphic to a QImage.
QPixmap toPixmap(qreal devicePixelRatio=0.0) const
Convert the graphic to a QPixmap.
qreal widthForHeight(qreal height) const
QFlags< RenderHint > RenderHints
QFlags< CommandType > CommandTypes
QRectF controlPointRect() const
virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) override
Store a pixmap command in the command list.
CommandTypes commandTypes() const
@ VectorData
The graphic contains scalable vector data.
@ Transformation
The graphic contains transformations beyond simple translations.
@ RasterData
The graphic contains raster data ( QPixmap or QImage )
QSizeF defaultSize() const
Default size.
virtual QSize sizeMetrics() const override
void setDefaultSize(const QSizeF &)
Set a default size.
void setCommands(const QVector< QwtPainterCommand > &)
Append paint commands.
const QVector< QwtPainterCommand > & commands() const
virtual void drawPath(const QPainterPath &) override
QRectF scaledBoundingRect(qreal sx, qreal sy) const
Calculate the target rectangle for scaling the graphic.
RenderHints renderHints() const
QRectF boundingRect() const
void render(QPainter *) const
Replay all recorded painter commands.
virtual void drawImage(const QRectF &, const QImage &, const QRectF &, Qt::ImageConversionFlags) override
Store a image command in the command list.
virtual QPaintEngine * paintEngine() const override
See QPaintDevice::paintEngine()
@ Path
Draw a QPainterPath.
@ State
QPainter state change.
PixmapData * pixmapData()