source: ntrip/trunk/BNC/qwt/qwt_graphic.cpp@ 8963

Last change on this file since 8963 was 8127, checked in by stoecker, 7 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 25.6 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_graphic.h"
11#include "qwt_painter_command.h"
12#include <qvector.h>
13#include <qpainter.h>
14#include <qpaintengine.h>
15#include <qimage.h>
16#include <qpixmap.h>
17#include <qpainterpath.h>
18#include <qmath.h>
19
20static bool qwtHasScalablePen( const QPainter *painter )
21{
22 const QPen pen = painter->pen();
23
24 bool scalablePen = false;
25
26 if ( pen.style() != Qt::NoPen && pen.brush().style() != Qt::NoBrush )
27 {
28 scalablePen = !pen.isCosmetic();
29 if ( !scalablePen && pen.widthF() == 0.0 )
30 {
31 const QPainter::RenderHints hints = painter->renderHints();
32 if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) )
33 scalablePen = true;
34 }
35 }
36
37 return scalablePen;
38}
39
40static QRectF qwtStrokedPathRect(
41 const QPainter *painter, const QPainterPath &path )
42{
43 QPainterPathStroker stroker;
44 stroker.setWidth( painter->pen().widthF() );
45 stroker.setCapStyle( painter->pen().capStyle() );
46 stroker.setJoinStyle( painter->pen().joinStyle() );
47 stroker.setMiterLimit( painter->pen().miterLimit() );
48
49 QRectF rect;
50 if ( qwtHasScalablePen( painter ) )
51 {
52 QPainterPath stroke = stroker.createStroke(path);
53 rect = painter->transform().map(stroke).boundingRect();
54 }
55 else
56 {
57 QPainterPath mappedPath = painter->transform().map(path);
58 mappedPath = stroker.createStroke( mappedPath );
59
60 rect = mappedPath.boundingRect();
61 }
62
63 return rect;
64}
65
66static inline void qwtExecCommand(
67 QPainter *painter, const QwtPainterCommand &cmd,
68 QwtGraphic::RenderHints renderHints,
69 const QTransform &transform,
70 const QTransform *initialTransform )
71{
72 switch( cmd.type() )
73 {
74 case QwtPainterCommand::Path:
75 {
76 bool doMap = false;
77
78 if ( renderHints.testFlag( QwtGraphic::RenderPensUnscaled )
79 && painter->transform().isScaling() )
80 {
81 bool isCosmetic = painter->pen().isCosmetic();
82 if ( isCosmetic && painter->pen().widthF() == 0.0 )
83 {
84 QPainter::RenderHints hints = painter->renderHints();
85 if ( hints.testFlag( QPainter::NonCosmeticDefaultPen ) )
86 isCosmetic = false;
87 }
88
89 doMap = !isCosmetic;
90 }
91
92 if ( doMap )
93 {
94 const QTransform tr = painter->transform();
95
96 painter->resetTransform();
97
98 QPainterPath path = tr.map( *cmd.path() );
99 if ( initialTransform )
100 {
101 painter->setTransform( *initialTransform );
102 path = initialTransform->inverted().map( path );
103 }
104
105 painter->drawPath( path );
106
107 painter->setTransform( tr );
108 }
109 else
110 {
111 painter->drawPath( *cmd.path() );
112 }
113 break;
114 }
115 case QwtPainterCommand::Pixmap:
116 {
117 const QwtPainterCommand::PixmapData *data = cmd.pixmapData();
118 painter->drawPixmap( data->rect, data->pixmap, data->subRect );
119 break;
120 }
121 case QwtPainterCommand::Image:
122 {
123 const QwtPainterCommand::ImageData *data = cmd.imageData();
124 painter->drawImage( data->rect, data->image,
125 data->subRect, data->flags );
126 break;
127 }
128 case QwtPainterCommand::State:
129 {
130 const QwtPainterCommand::StateData *data = cmd.stateData();
131
132 if ( data->flags & QPaintEngine::DirtyPen )
133 painter->setPen( data->pen );
134
135 if ( data->flags & QPaintEngine::DirtyBrush )
136 painter->setBrush( data->brush );
137
138 if ( data->flags & QPaintEngine::DirtyBrushOrigin )
139 painter->setBrushOrigin( data->brushOrigin );
140
141 if ( data->flags & QPaintEngine::DirtyFont )
142 painter->setFont( data->font );
143
144 if ( data->flags & QPaintEngine::DirtyBackground )
145 {
146 painter->setBackgroundMode( data->backgroundMode );
147 painter->setBackground( data->backgroundBrush );
148 }
149
150 if ( data->flags & QPaintEngine::DirtyTransform )
151 {
152 painter->setTransform( data->transform * transform );
153 }
154
155 if ( data->flags & QPaintEngine::DirtyClipEnabled )
156 painter->setClipping( data->isClipEnabled );
157
158 if ( data->flags & QPaintEngine::DirtyClipRegion)
159 {
160 painter->setClipRegion( data->clipRegion,
161 data->clipOperation );
162 }
163
164 if ( data->flags & QPaintEngine::DirtyClipPath )
165 {
166 painter->setClipPath( data->clipPath, data->clipOperation );
167 }
168
169 if ( data->flags & QPaintEngine::DirtyHints)
170 {
171 const QPainter::RenderHints hints = data->renderHints;
172
173 painter->setRenderHint( QPainter::Antialiasing,
174 hints.testFlag( QPainter::Antialiasing ) );
175
176 painter->setRenderHint( QPainter::TextAntialiasing,
177 hints.testFlag( QPainter::TextAntialiasing ) );
178
179 painter->setRenderHint( QPainter::SmoothPixmapTransform,
180 hints.testFlag( QPainter::SmoothPixmapTransform ) );
181
182 painter->setRenderHint( QPainter::HighQualityAntialiasing,
183 hints.testFlag( QPainter::HighQualityAntialiasing ) );
184
185 painter->setRenderHint( QPainter::NonCosmeticDefaultPen,
186 hints.testFlag( QPainter::NonCosmeticDefaultPen ) );
187 }
188
189 if ( data->flags & QPaintEngine::DirtyCompositionMode)
190 painter->setCompositionMode( data->compositionMode );
191
192 if ( data->flags & QPaintEngine::DirtyOpacity)
193 painter->setOpacity( data->opacity );
194
195 break;
196 }
197 default:
198 break;
199 }
200
201}
202
203class QwtGraphic::PathInfo
204{
205public:
206 PathInfo():
207 d_scalablePen( false )
208 {
209 // QVector needs a default constructor
210 }
211
212 PathInfo( const QRectF &pointRect,
213 const QRectF &boundingRect, bool scalablePen ):
214 d_pointRect( pointRect ),
215 d_boundingRect( boundingRect ),
216 d_scalablePen( scalablePen )
217 {
218 }
219
220 inline QRectF scaledBoundingRect( double sx, double sy,
221 bool scalePens ) const
222 {
223 if ( sx == 1.0 && sy == 1.0 )
224 return d_boundingRect;
225
226 QTransform transform;
227 transform.scale( sx, sy );
228
229 QRectF rect;
230 if ( scalePens && d_scalablePen )
231 {
232 rect = transform.mapRect( d_boundingRect );
233 }
234 else
235 {
236 rect = transform.mapRect( d_pointRect );
237
238 const double l = qAbs( d_pointRect.left() - d_boundingRect.left() );
239 const double r = qAbs( d_pointRect.right() - d_boundingRect.right() );
240 const double t = qAbs( d_pointRect.top() - d_boundingRect.top() );
241 const double b = qAbs( d_pointRect.bottom() - d_boundingRect.bottom() );
242
243 rect.adjust( -l, -t, r, b );
244 }
245
246 return rect;
247 }
248
249 inline double scaleFactorX( const QRectF& pathRect,
250 const QRectF &targetRect, bool scalePens ) const
251 {
252 if ( pathRect.width() <= 0.0 )
253 return 0.0;
254
255 const QPointF p0 = d_pointRect.center();
256
257 const double l = qAbs( pathRect.left() - p0.x() );
258 const double r = qAbs( pathRect.right() - p0.x() );
259
260 const double w = 2.0 * qMin( l, r )
261 * targetRect.width() / pathRect.width();
262
263 double sx;
264 if ( scalePens && d_scalablePen )
265 {
266 sx = w / d_boundingRect.width();
267 }
268 else
269 {
270 const double pw = qMax(
271 qAbs( d_boundingRect.left() - d_pointRect.left() ),
272 qAbs( d_boundingRect.right() - d_pointRect.right() ) );
273
274 sx = ( w - 2 * pw ) / d_pointRect.width();
275 }
276
277 return sx;
278 }
279
280 inline double scaleFactorY( const QRectF& pathRect,
281 const QRectF &targetRect, bool scalePens ) const
282 {
283 if ( pathRect.height() <= 0.0 )
284 return 0.0;
285
286 const QPointF p0 = d_pointRect.center();
287
288 const double t = qAbs( pathRect.top() - p0.y() );
289 const double b = qAbs( pathRect.bottom() - p0.y() );
290
291 const double h = 2.0 * qMin( t, b )
292 * targetRect.height() / pathRect.height();
293
294 double sy;
295 if ( scalePens && d_scalablePen )
296 {
297 sy = h / d_boundingRect.height();
298 }
299 else
300 {
301 const double pw =
302 qMax( qAbs( d_boundingRect.top() - d_pointRect.top() ),
303 qAbs( d_boundingRect.bottom() - d_pointRect.bottom() ) );
304
305 sy = ( h - 2 * pw ) / d_pointRect.height();
306 }
307
308 return sy;
309 }
310
311private:
312 QRectF d_pointRect;
313 QRectF d_boundingRect;
314 bool d_scalablePen;
315};
316
317class QwtGraphic::PrivateData
318{
319public:
320 PrivateData():
321 boundingRect( 0.0, 0.0, -1.0, -1.0 ),
322 pointRect( 0.0, 0.0, -1.0, -1.0 ),
323 initialTransform( NULL )
324 {
325 }
326
327 QSizeF defaultSize;
328 QVector<QwtPainterCommand> commands;
329 QVector<QwtGraphic::PathInfo> pathInfos;
330
331 QRectF boundingRect;
332 QRectF pointRect;
333
334 QwtGraphic::RenderHints renderHints;
335 QTransform *initialTransform;
336};
337
338/*!
339 \brief Constructor
340
341 Initializes a null graphic
342 \sa isNull()
343 */
344QwtGraphic::QwtGraphic():
345 QwtNullPaintDevice()
346{
347 setMode( QwtNullPaintDevice::PathMode );
348 d_data = new PrivateData;
349}
350
351/*!
352 \brief Copy constructor
353
354 \param other Source
355 \sa operator=()
356 */
357QwtGraphic::QwtGraphic( const QwtGraphic &other ):
358 QwtNullPaintDevice()
359{
360 setMode( other.mode() );
361 d_data = new PrivateData( *other.d_data );
362}
363
364//! Destructor
365QwtGraphic::~QwtGraphic()
366{
367 delete d_data;
368}
369
370/*!
371 \brief Assignment operator
372
373 \param other Source
374 \return A reference of this object
375 */
376QwtGraphic& QwtGraphic::operator=(const QwtGraphic &other)
377{
378 setMode( other.mode() );
379 *d_data = *other.d_data;
380
381 return *this;
382}
383
384/*!
385 \brief Clear all stored commands
386 \sa isNull()
387 */
388void QwtGraphic::reset()
389{
390 d_data->commands.clear();
391 d_data->pathInfos.clear();
392
393 d_data->boundingRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
394 d_data->pointRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
395 d_data->defaultSize = QSizeF();
396
397}
398
399/*!
400 \return True, when no painter commands have been stored
401 \sa isEmpty(), commands()
402*/
403bool QwtGraphic::isNull() const
404{
405 return d_data->commands.isEmpty();
406}
407
408/*!
409 \return True, when the bounding rectangle is empty
410 \sa boundingRect(), isNull()
411*/
412bool QwtGraphic::isEmpty() const
413{
414 return d_data->boundingRect.isEmpty();
415}
416
417/*!
418 Toggle an render hint
419
420 \param hint Render hint
421 \param on true/false
422
423 \sa testRenderHint(), RenderHint
424*/
425void QwtGraphic::setRenderHint( RenderHint hint, bool on )
426{
427 if ( on )
428 d_data->renderHints |= hint;
429 else
430 d_data->renderHints &= ~hint;
431}
432
433/*!
434 Test a render hint
435
436 \param hint Render hint
437 \return true/false
438 \sa setRenderHint(), RenderHint
439*/
440bool QwtGraphic::testRenderHint( RenderHint hint ) const
441{
442 return d_data->renderHints.testFlag( hint );
443}
444
445/*!
446 The bounding rectangle is the controlPointRect()
447 extended by the areas needed for rendering the outlines
448 with unscaled pens.
449
450 \return Bounding rectangle of the graphic
451 \sa controlPointRect(), scaledBoundingRect()
452 */
453QRectF QwtGraphic::boundingRect() const
454{
455 if ( d_data->boundingRect.width() < 0 )
456 return QRectF();
457
458 return d_data->boundingRect;
459}
460
461/*!
462 The control point rectangle is the bounding rectangle
463 of all control points of the paths and the target
464 rectangles of the images/pixmaps.
465
466 \return Control point rectangle
467 \sa boundingRect(), scaledBoundingRect()
468 */
469QRectF QwtGraphic::controlPointRect() const
470{
471 if ( d_data->pointRect.width() < 0 )
472 return QRectF();
473
474 return d_data->pointRect;
475}
476
477/*!
478 \brief Calculate the target rectangle for scaling the graphic
479
480 \param sx Horizontal scaling factor
481 \param sy Vertical scaling factor
482
483 \note In case of paths that are painted with a cosmetic pen
484 ( see QPen::isCosmetic() ) the target rectangle is different to
485 multiplying the bounding rectangle.
486
487 \return Scaled bounding rectangle
488 \sa boundingRect(), controlPointRect()
489 */
490QRectF QwtGraphic::scaledBoundingRect( double sx, double sy ) const
491{
492 if ( sx == 1.0 && sy == 1.0 )
493 return d_data->boundingRect;
494
495 QTransform transform;
496 transform.scale( sx, sy );
497
498 QRectF rect = transform.mapRect( d_data->pointRect );
499
500 for ( int i = 0; i < d_data->pathInfos.size(); i++ )
501 {
502 rect |= d_data->pathInfos[i].scaledBoundingRect( sx, sy,
503 !d_data->renderHints.testFlag( RenderPensUnscaled ) );
504 }
505
506 return rect;
507}
508
509//! \return Ceiled defaultSize()
510QSize QwtGraphic::sizeMetrics() const
511{
512 const QSizeF sz = defaultSize();
513 return QSize( qCeil( sz.width() ), qCeil( sz.height() ) );
514}
515
516/*!
517 \brief Set a default size
518
519 The default size is used in all methods rendering the graphic,
520 where no size is explicitly specified. Assigning an empty size
521 means, that the default size will be calculated from the bounding
522 rectangle.
523
524 The default setting is an empty size.
525
526 \param size Default size
527
528 \sa defaultSize(), boundingRect()
529 */
530void QwtGraphic::setDefaultSize( const QSizeF &size )
531{
532 const double w = qMax( qreal( 0.0 ), size.width() );
533 const double h = qMax( qreal( 0.0 ), size.height() );
534
535 d_data->defaultSize = QSizeF( w, h );
536}
537
538/*!
539 \brief Default size
540
541 When a non empty size has been assigned by setDefaultSize() this
542 size will be returned. Otherwise the default size is the size
543 of the bounding rectangle.
544
545 The default size is used in all methods rendering the graphic,
546 where no size is explicitly specified.
547
548 \return Default size
549 \sa setDefaultSize(), boundingRect()
550 */
551QSizeF QwtGraphic::defaultSize() const
552{
553 if ( !d_data->defaultSize.isEmpty() )
554 return d_data->defaultSize;
555
556 return boundingRect().size();
557}
558
559/*!
560 \brief Replay all recorded painter commands
561 \param painter Qt painter
562 */
563void QwtGraphic::render( QPainter *painter ) const
564{
565 if ( isNull() )
566 return;
567
568 const int numCommands = d_data->commands.size();
569 const QwtPainterCommand *commands = d_data->commands.constData();
570
571 const QTransform transform = painter->transform();
572
573 painter->save();
574
575 for ( int i = 0; i < numCommands; i++ )
576 {
577 qwtExecCommand( painter, commands[i],
578 d_data->renderHints, transform, d_data->initialTransform );
579 }
580
581 painter->restore();
582}
583
584/*!
585 \brief Replay all recorded painter commands
586
587 The graphic is scaled to fit into the rectangle
588 of the given size starting at ( 0, 0 ).
589
590 \param painter Qt painter
591 \param size Size for the scaled graphic
592 \param aspectRatioMode Mode how to scale - See Qt::AspectRatioMode
593 */
594void QwtGraphic::render( QPainter *painter, const QSizeF &size,
595 Qt::AspectRatioMode aspectRatioMode ) const
596{
597 const QRectF r( 0.0, 0.0, size.width(), size.height() );
598 render( painter, r, aspectRatioMode );
599}
600
601/*!
602 \brief Replay all recorded painter commands
603
604 The graphic is scaled to fit into the given rectangle
605
606 \param painter Qt painter
607 \param rect Rectangle for the scaled graphic
608 \param aspectRatioMode Mode how to scale - See Qt::AspectRatioMode
609 */
610void QwtGraphic::render( QPainter *painter, const QRectF &rect,
611 Qt::AspectRatioMode aspectRatioMode ) const
612{
613 if ( isEmpty() || rect.isEmpty() )
614 return;
615
616 double sx = 1.0;
617 double sy = 1.0;
618
619 if ( d_data->pointRect.width() > 0.0 )
620 sx = rect.width() / d_data->pointRect.width();
621
622 if ( d_data->pointRect.height() > 0.0 )
623 sy = rect.height() / d_data->pointRect.height();
624
625 const bool scalePens =
626 !d_data->renderHints.testFlag( RenderPensUnscaled );
627
628 for ( int i = 0; i < d_data->pathInfos.size(); i++ )
629 {
630 const PathInfo info = d_data->pathInfos[i];
631
632 const double ssx = info.scaleFactorX(
633 d_data->pointRect, rect, scalePens );
634
635 if ( ssx > 0.0 )
636 sx = qMin( sx, ssx );
637
638 const double ssy = info.scaleFactorY(
639 d_data->pointRect, rect, scalePens );
640
641 if ( ssy > 0.0 )
642 sy = qMin( sy, ssy );
643 }
644
645 if ( aspectRatioMode == Qt::KeepAspectRatio )
646 {
647 const double s = qMin( sx, sy );
648 sx = s;
649 sy = s;
650 }
651 else if ( aspectRatioMode == Qt::KeepAspectRatioByExpanding )
652 {
653 const double s = qMax( sx, sy );
654 sx = s;
655 sy = s;
656 }
657
658 QTransform tr;
659 tr.translate( rect.center().x() - 0.5 * sx * d_data->pointRect.width(),
660 rect.center().y() - 0.5 * sy * d_data->pointRect.height() );
661 tr.scale( sx, sy );
662 tr.translate( -d_data->pointRect.x(), -d_data->pointRect.y() );
663
664 const QTransform transform = painter->transform();
665 if ( !scalePens && transform.isScaling() )
666 {
667 // we don't want to scale pens according to sx/sy,
668 // but we want to apply the scaling from the
669 // painter transformation later
670
671 d_data->initialTransform = new QTransform();
672 d_data->initialTransform->scale( transform.m11(), transform.m22() );
673 }
674
675 painter->setTransform( tr, true );
676 render( painter );
677
678 painter->setTransform( transform );
679
680 delete d_data->initialTransform;
681 d_data->initialTransform = NULL;
682}
683
684/*!
685 \brief Replay all recorded painter commands
686
687 The graphic is scaled to the defaultSize() and aligned
688 to a position.
689
690 \param painter Qt painter
691 \param pos Reference point, where to render
692 \param alignment Flags how to align the target rectangle
693 to pos.
694 */
695void QwtGraphic::render( QPainter *painter,
696 const QPointF &pos, Qt::Alignment alignment ) const
697{
698 QRectF r( pos, defaultSize() );
699
700 if ( alignment & Qt::AlignLeft )
701 {
702 r.moveLeft( pos.x() );
703 }
704 else if ( alignment & Qt::AlignHCenter )
705 {
706 r.moveCenter( QPointF( pos.x(), r.center().y() ) );
707 }
708 else if ( alignment & Qt::AlignRight )
709 {
710 r.moveRight( pos.x() );
711 }
712
713 if ( alignment & Qt::AlignTop )
714 {
715 r.moveTop( pos.y() );
716 }
717 else if ( alignment & Qt::AlignVCenter )
718 {
719 r.moveCenter( QPointF( r.center().x(), pos.y() ) );
720 }
721 else if ( alignment & Qt::AlignBottom )
722 {
723 r.moveBottom( pos.y() );
724 }
725
726 render( painter, r );
727}
728
729/*!
730 \brief Convert the graphic to a QPixmap
731
732 All pixels of the pixmap get initialized by Qt::transparent
733 before the graphic is scaled and rendered on it.
734
735 The size of the pixmap is the default size ( ceiled to integers )
736 of the graphic.
737
738 \return The graphic as pixmap in default size
739 \sa defaultSize(), toImage(), render()
740 */
741QPixmap QwtGraphic::toPixmap() const
742{
743 if ( isNull() )
744 return QPixmap();
745
746 const QSizeF sz = defaultSize();
747
748 const int w = qCeil( sz.width() );
749 const int h = qCeil( sz.height() );
750
751 QPixmap pixmap( w, h );
752 pixmap.fill( Qt::transparent );
753
754 const QRectF r( 0.0, 0.0, sz.width(), sz.height() );
755
756 QPainter painter( &pixmap );
757 render( &painter, r, Qt::KeepAspectRatio );
758 painter.end();
759
760 return pixmap;
761}
762
763/*!
764 \brief Convert the graphic to a QPixmap
765
766 All pixels of the pixmap get initialized by Qt::transparent
767 before the graphic is scaled and rendered on it.
768
769 \param size Size of the image
770 \param aspectRatioMode Aspect ratio how to scale the graphic
771
772 \return The graphic as pixmap
773 \sa toImage(), render()
774 */
775QPixmap QwtGraphic::toPixmap( const QSize &size,
776 Qt::AspectRatioMode aspectRatioMode ) const
777{
778 QPixmap pixmap( size );
779 pixmap.fill( Qt::transparent );
780
781 const QRect r( 0, 0, size.width(), size.height() );
782
783 QPainter painter( &pixmap );
784 render( &painter, r, aspectRatioMode );
785 painter.end();
786
787 return pixmap;
788}
789
790/*!
791 \brief Convert the graphic to a QImage
792
793 All pixels of the image get initialized by 0 ( transparent )
794 before the graphic is scaled and rendered on it.
795
796 The format of the image is QImage::Format_ARGB32_Premultiplied.
797
798 \param size Size of the image
799 \param aspectRatioMode Aspect ratio how to scale the graphic
800
801 \return The graphic as image
802 \sa toPixmap(), render()
803 */
804QImage QwtGraphic::toImage( const QSize &size,
805 Qt::AspectRatioMode aspectRatioMode ) const
806{
807 QImage image( size, QImage::Format_ARGB32_Premultiplied );
808 image.fill( 0 );
809
810 const QRect r( 0, 0, size.width(), size.height() );
811
812 QPainter painter( &image );
813 render( &painter, r, aspectRatioMode );
814 painter.end();
815
816 return image;
817}
818
819/*!
820 \brief Convert the graphic to a QImage
821
822 All pixels of the image get initialized by 0 ( transparent )
823 before the graphic is scaled and rendered on it.
824
825 The format of the image is QImage::Format_ARGB32_Premultiplied.
826
827 The size of the image is the default size ( ceiled to integers )
828 of the graphic.
829
830 \return The graphic as image in default size
831 \sa defaultSize(), toPixmap(), render()
832 */
833QImage QwtGraphic::toImage() const
834{
835 if ( isNull() )
836 return QImage();
837
838 const QSizeF sz = defaultSize();
839
840 const int w = qCeil( sz.width() );
841 const int h = qCeil( sz.height() );
842
843 QImage image( w, h, QImage::Format_ARGB32 );
844 image.fill( 0 );
845
846 const QRect r( 0, 0, sz.width(), sz.height() );
847
848 QPainter painter( &image );
849 render( &painter, r, Qt::KeepAspectRatio );
850 painter.end();
851
852 return image;
853}
854
855/*!
856 Store a path command in the command list
857
858 \param path Painter path
859 \sa QPaintEngine::drawPath()
860*/
861void QwtGraphic::drawPath( const QPainterPath &path )
862{
863 const QPainter *painter = paintEngine()->painter();
864 if ( painter == NULL )
865 return;
866
867 d_data->commands += QwtPainterCommand( path );
868
869 if ( !path.isEmpty() )
870 {
871 const QPainterPath scaledPath = painter->transform().map( path );
872
873 QRectF pointRect = scaledPath.boundingRect();
874 QRectF boundingRect = pointRect;
875
876 if ( painter->pen().style() != Qt::NoPen
877 && painter->pen().brush().style() != Qt::NoBrush )
878 {
879 boundingRect = qwtStrokedPathRect( painter, path );
880 }
881
882 updateControlPointRect( pointRect );
883 updateBoundingRect( boundingRect );
884
885 d_data->pathInfos += PathInfo( pointRect,
886 boundingRect, qwtHasScalablePen( painter ) );
887 }
888}
889
890/*!
891 \brief Store a pixmap command in the command list
892
893 \param rect target rectangle
894 \param pixmap Pixmap to be painted
895 \param subRect Reactangle of the pixmap to be painted
896
897 \sa QPaintEngine::drawPixmap()
898*/
899void QwtGraphic::drawPixmap( const QRectF &rect,
900 const QPixmap &pixmap, const QRectF &subRect )
901{
902 const QPainter *painter = paintEngine()->painter();
903 if ( painter == NULL )
904 return;
905
906 d_data->commands += QwtPainterCommand( rect, pixmap, subRect );
907
908 const QRectF r = painter->transform().mapRect( rect );
909 updateControlPointRect( r );
910 updateBoundingRect( r );
911}
912
913/*!
914 \brief Store a image command in the command list
915
916 \param rect traget rectangle
917 \param image Image to be painted
918 \param subRect Reactangle of the pixmap to be painted
919 \param flags Image conversion flags
920
921 \sa QPaintEngine::drawImage()
922 */
923void QwtGraphic::drawImage( const QRectF &rect, const QImage &image,
924 const QRectF &subRect, Qt::ImageConversionFlags flags)
925{
926 const QPainter *painter = paintEngine()->painter();
927 if ( painter == NULL )
928 return;
929
930 d_data->commands += QwtPainterCommand( rect, image, subRect, flags );
931
932 const QRectF r = painter->transform().mapRect( rect );
933
934 updateControlPointRect( r );
935 updateBoundingRect( r );
936}
937
938/*!
939 \brief Store a state command in the command list
940
941 \param state State to be stored
942 \sa QPaintEngine::updateState()
943 */
944void QwtGraphic::updateState( const QPaintEngineState &state)
945{
946 d_data->commands += QwtPainterCommand( state );
947}
948
949void QwtGraphic::updateBoundingRect( const QRectF &rect )
950{
951 QRectF br = rect;
952
953 const QPainter *painter = paintEngine()->painter();
954 if ( painter && painter->hasClipping() )
955 {
956 QRectF cr = painter->clipRegion().boundingRect();
957 cr = painter->transform().mapRect( cr );
958
959 br &= cr;
960 }
961
962 if ( d_data->boundingRect.width() < 0 )
963 d_data->boundingRect = br;
964 else
965 d_data->boundingRect |= br;
966}
967
968void QwtGraphic::updateControlPointRect( const QRectF &rect )
969{
970 if ( d_data->pointRect.width() < 0.0 )
971 d_data->pointRect = rect;
972 else
973 d_data->pointRect |= rect;
974}
975
976/*!
977 \return List of recorded paint commands
978 \sa setCommands()
979 */
980const QVector< QwtPainterCommand > &QwtGraphic::commands() const
981{
982 return d_data->commands;
983}
984
985/*!
986 \brief Append paint commands
987
988 \param commands Paint commands
989 \sa commands()
990 */
991void QwtGraphic::setCommands( QVector< QwtPainterCommand > &commands )
992{
993 reset();
994
995 const int numCommands = commands.size();
996 if ( numCommands <= 0 )
997 return;
998
999 // to calculate a proper bounding rectangle we don't simply copy
1000 // the commands.
1001
1002 const QwtPainterCommand *cmds = commands.constData();
1003
1004 QPainter painter( this );
1005 for ( int i = 0; i < numCommands; i++ )
1006 qwtExecCommand( &painter, cmds[i], RenderHints(), QTransform(), NULL );
1007
1008 painter.end();
1009}
Note: See TracBrowser for help on using the repository browser.