source: ntrip/trunk/BNC/qwt/qwt_painter.cpp@ 9184

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

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 35.5 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_painter.h"
11#include "qwt_math.h"
12#include "qwt_clipper.h"
13#include "qwt_color_map.h"
14#include "qwt_scale_map.h"
15#include <qwindowdefs.h>
16#include <qwidget.h>
17#include <qframe.h>
18#include <qrect.h>
19#include <qpainter.h>
20#include <qpalette.h>
21#include <qpaintdevice.h>
22#include <qpixmap.h>
23#include <qstyle.h>
24#include <qtextdocument.h>
25#include <qabstracttextdocumentlayout.h>
26#include <qstyleoption.h>
27#include <qpaintengine.h>
28#include <qapplication.h>
29#include <qdesktopwidget.h>
30
31#if QT_VERSION >= 0x050000
32#include <qwindow.h>
33#endif
34
35#if QT_VERSION < 0x050000
36
37#ifdef Q_WS_X11
38#include <qx11info_x11.h>
39#endif
40
41#endif
42
43bool QwtPainter::d_polylineSplitting = true;
44bool QwtPainter::d_roundingAlignment = true;
45
46static inline bool qwtIsClippingNeeded(
47 const QPainter *painter, QRectF &clipRect )
48{
49 bool doClipping = false;
50 const QPaintEngine *pe = painter->paintEngine();
51 if ( pe && pe->type() == QPaintEngine::SVG )
52 {
53 // The SVG paint engine ignores any clipping,
54
55 if ( painter->hasClipping() )
56 {
57 doClipping = true;
58 clipRect = painter->clipRegion().boundingRect();
59 }
60 }
61
62 return doClipping;
63}
64
65template <class T>
66static inline void qwtDrawPolyline( QPainter *painter,
67 const T *points, int pointCount, bool polylineSplitting )
68{
69 bool doSplit = false;
70 if ( polylineSplitting )
71 {
72 const QPaintEngine *pe = painter->paintEngine();
73 if ( pe && pe->type() == QPaintEngine::Raster )
74 {
75 /*
76 The raster paint engine seems to use some algo with O(n*n).
77 ( Qt 4.3 is better than Qt 4.2, but remains unacceptable)
78 To work around this problem, we have to split the polygon into
79 smaller pieces.
80 */
81 doSplit = true;
82 }
83 }
84
85 if ( doSplit )
86 {
87 const int splitSize = 6;
88
89 for ( int i = 0; i < pointCount; i += splitSize )
90 {
91 const int n = qMin( splitSize + 1, pointCount - i );
92 painter->drawPolyline( points + i, n );
93 }
94 }
95 else
96 {
97 painter->drawPolyline( points, pointCount );
98 }
99}
100
101static inline QSize qwtScreenResolution()
102{
103 static QSize screenResolution;
104 if ( !screenResolution.isValid() )
105 {
106 QDesktopWidget *desktop = QApplication::desktop();
107 if ( desktop )
108 {
109 screenResolution.setWidth( desktop->logicalDpiX() );
110 screenResolution.setHeight( desktop->logicalDpiY() );
111 }
112 }
113
114 return screenResolution;
115}
116
117static inline void qwtUnscaleFont( QPainter *painter )
118{
119 if ( painter->font().pixelSize() >= 0 )
120 return;
121
122 const QSize screenResolution = qwtScreenResolution();
123
124 const QPaintDevice *pd = painter->device();
125 if ( pd->logicalDpiX() != screenResolution.width() ||
126 pd->logicalDpiY() != screenResolution.height() )
127 {
128 QFont pixelFont( painter->font(), QApplication::desktop() );
129 pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() );
130
131 painter->setFont( pixelFont );
132 }
133}
134
135/*!
136 Check is the application is running with the X11 graphics system
137 that has some special capabilities that can be used for incremental
138 painting to a widget.
139
140 \return True, when the graphics system is X11
141*/
142bool QwtPainter::isX11GraphicsSystem()
143{
144 static int onX11 = -1;
145 if ( onX11 < 0 )
146 {
147 QPixmap pm( 1, 1 );
148 QPainter painter( &pm );
149
150 onX11 = ( painter.paintEngine()->type() == QPaintEngine::X11 ) ? 1 : 0;
151 }
152
153 return onX11 == 1;
154}
155
156/*!
157 Check if the painter is using a paint engine, that aligns
158 coordinates to integers. Today these are all paint engines
159 beside QPaintEngine::Pdf and QPaintEngine::SVG.
160
161 If we have an integer based paint engine it is also
162 checked if the painter has a transformation matrix,
163 that rotates or scales.
164
165 \param painter Painter
166 \return true, when the painter is aligning
167
168 \sa setRoundingAlignment()
169*/
170bool QwtPainter::isAligning( QPainter *painter )
171{
172 if ( painter && painter->isActive() )
173 {
174 switch ( painter->paintEngine()->type() )
175 {
176 case QPaintEngine::Pdf:
177 case QPaintEngine::SVG:
178 return false;
179
180 default:;
181 }
182
183 const QTransform tr = painter->transform();
184 if ( tr.isRotating() || tr.isScaling() )
185 {
186 // we might have to check translations too
187 return false;
188 }
189 }
190
191 return true;
192}
193
194/*!
195 Enable whether coordinates should be rounded, before they are painted
196 to a paint engine that floors to integer values. For other paint engines
197 ( PDF, SVG ) this flag has no effect.
198 QwtPainter stores this flag only, the rounding itself is done in
199 the painting code ( f.e the plot items ).
200
201 The default setting is true.
202
203 \sa roundingAlignment(), isAligning()
204*/
205void QwtPainter::setRoundingAlignment( bool enable )
206{
207 d_roundingAlignment = enable;
208}
209
210/*!
211 \brief En/Disable line splitting for the raster paint engine
212
213 In some Qt versions the raster paint engine paints polylines of many points
214 much faster when they are split in smaller chunks: f.e all supported Qt versions
215 >= Qt 5.0 when drawing an antialiased polyline with a pen width >=2.
216
217 The default setting is true.
218
219 \sa polylineSplitting()
220*/
221void QwtPainter::setPolylineSplitting( bool enable )
222{
223 d_polylineSplitting = enable;
224}
225
226//! Wrapper for QPainter::drawPath()
227void QwtPainter::drawPath( QPainter *painter, const QPainterPath &path )
228{
229 painter->drawPath( path );
230}
231
232//! Wrapper for QPainter::drawRect()
233void QwtPainter::drawRect( QPainter *painter, double x, double y, double w, double h )
234{
235 drawRect( painter, QRectF( x, y, w, h ) );
236}
237
238//! Wrapper for QPainter::drawRect()
239void QwtPainter::drawRect( QPainter *painter, const QRectF &rect )
240{
241 const QRectF r = rect;
242
243 QRectF clipRect;
244 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
245
246 if ( deviceClipping )
247 {
248 if ( !clipRect.intersects( r ) )
249 return;
250
251 if ( !clipRect.contains( r ) )
252 {
253 fillRect( painter, r & clipRect, painter->brush() );
254
255 painter->save();
256 painter->setBrush( Qt::NoBrush );
257 drawPolyline( painter, QPolygonF( r ) );
258 painter->restore();
259
260 return;
261 }
262 }
263
264 painter->drawRect( r );
265}
266
267//! Wrapper for QPainter::fillRect()
268void QwtPainter::fillRect( QPainter *painter,
269 const QRectF &rect, const QBrush &brush )
270{
271 if ( !rect.isValid() )
272 return;
273
274 QRectF clipRect;
275 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
276
277 /*
278 Performance of Qt4 is horrible for a non trivial brush. Without
279 clipping expect minutes or hours for repainting large rectangles
280 (might result from zooming)
281 */
282
283 if ( deviceClipping )
284 clipRect &= painter->window();
285 else
286 clipRect = painter->window();
287
288 if ( painter->hasClipping() )
289 clipRect &= painter->clipRegion().boundingRect();
290
291 QRectF r = rect;
292 if ( deviceClipping )
293 r = r.intersected( clipRect );
294
295 if ( r.isValid() )
296 painter->fillRect( r, brush );
297}
298
299//! Wrapper for QPainter::drawPie()
300void QwtPainter::drawPie( QPainter *painter, const QRectF &rect,
301 int a, int alen )
302{
303 QRectF clipRect;
304 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
305 if ( deviceClipping && !clipRect.contains( rect ) )
306 return;
307
308 painter->drawPie( rect, a, alen );
309}
310
311//! Wrapper for QPainter::drawEllipse()
312void QwtPainter::drawEllipse( QPainter *painter, const QRectF &rect )
313{
314 QRectF clipRect;
315 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
316
317 if ( deviceClipping && !clipRect.contains( rect ) )
318 return;
319
320 painter->drawEllipse( rect );
321}
322
323//! Wrapper for QPainter::drawText()
324void QwtPainter::drawText( QPainter *painter, double x, double y,
325 const QString &text )
326{
327 drawText( painter, QPointF( x, y ), text );
328}
329
330//! Wrapper for QPainter::drawText()
331void QwtPainter::drawText( QPainter *painter, const QPointF &pos,
332 const QString &text )
333{
334 QRectF clipRect;
335 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
336
337 if ( deviceClipping && !clipRect.contains( pos ) )
338 return;
339
340
341 painter->save();
342 qwtUnscaleFont( painter );
343 painter->drawText( pos, text );
344 painter->restore();
345}
346
347//! Wrapper for QPainter::drawText()
348void QwtPainter::drawText( QPainter *painter,
349 double x, double y, double w, double h,
350 int flags, const QString &text )
351{
352 drawText( painter, QRectF( x, y, w, h ), flags, text );
353}
354
355//! Wrapper for QPainter::drawText()
356void QwtPainter::drawText( QPainter *painter, const QRectF &rect,
357 int flags, const QString &text )
358{
359 painter->save();
360 qwtUnscaleFont( painter );
361 painter->drawText( rect, flags, text );
362 painter->restore();
363}
364
365#ifndef QT_NO_RICHTEXT
366
367/*!
368 Draw a text document into a rectangle
369
370 \param painter Painter
371 \param rect Traget rectangle
372 \param flags Alignments/Text flags, see QPainter::drawText()
373 \param text Text document
374*/
375void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect,
376 int flags, const QTextDocument &text )
377{
378 QTextDocument *txt = text.clone();
379
380 painter->save();
381
382 QRectF unscaledRect = rect;
383
384 if ( painter->font().pixelSize() < 0 )
385 {
386 const QSize res = qwtScreenResolution();
387
388 const QPaintDevice *pd = painter->device();
389 if ( pd->logicalDpiX() != res.width() ||
390 pd->logicalDpiY() != res.height() )
391 {
392 QTransform transform;
393 transform.scale( res.width() / double( pd->logicalDpiX() ),
394 res.height() / double( pd->logicalDpiY() ));
395
396 painter->setWorldTransform( transform, true );
397 unscaledRect = transform.inverted().mapRect(rect);
398 }
399 }
400
401 txt->setDefaultFont( painter->font() );
402 txt->setPageSize( QSizeF( unscaledRect.width(), QWIDGETSIZE_MAX ) );
403
404 QAbstractTextDocumentLayout* layout = txt->documentLayout();
405
406 const double height = layout->documentSize().height();
407 double y = unscaledRect.y();
408 if ( flags & Qt::AlignBottom )
409 y += ( unscaledRect.height() - height );
410 else if ( flags & Qt::AlignVCenter )
411 y += ( unscaledRect.height() - height ) / 2;
412
413 QAbstractTextDocumentLayout::PaintContext context;
414 context.palette.setColor( QPalette::Text, painter->pen().color() );
415
416 painter->translate( unscaledRect.x(), y );
417 layout->draw( painter, context );
418
419 painter->restore();
420 delete txt;
421}
422
423#endif // !QT_NO_RICHTEXT
424
425
426//! Wrapper for QPainter::drawLine()
427void QwtPainter::drawLine( QPainter *painter,
428 const QPointF &p1, const QPointF &p2 )
429{
430 QRectF clipRect;
431 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
432
433 if ( deviceClipping &&
434 !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) )
435 {
436 QPolygonF polygon;
437 polygon += p1;
438 polygon += p2;
439 drawPolyline( painter, polygon );
440 return;
441 }
442
443 painter->drawLine( p1, p2 );
444}
445
446//! Wrapper for QPainter::drawPolygon()
447void QwtPainter::drawPolygon( QPainter *painter, const QPolygonF &polygon )
448{
449 QRectF clipRect;
450 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
451
452 QPolygonF cpa = polygon;
453 if ( deviceClipping )
454 cpa = QwtClipper::clipPolygonF( clipRect, polygon );
455
456 painter->drawPolygon( cpa );
457}
458
459//! Wrapper for QPainter::drawPolyline()
460void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon )
461{
462 QRectF clipRect;
463 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
464
465 QPolygonF cpa = polygon;
466 if ( deviceClipping )
467 cpa = QwtClipper::clipPolygonF( clipRect, cpa );
468
469 qwtDrawPolyline<QPointF>( painter,
470 cpa.constData(), cpa.size(), d_polylineSplitting );
471}
472
473//! Wrapper for QPainter::drawPolyline()
474void QwtPainter::drawPolyline( QPainter *painter,
475 const QPointF *points, int pointCount )
476{
477 QRectF clipRect;
478 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
479
480 if ( deviceClipping )
481 {
482 QPolygonF polygon( pointCount );
483 ::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) );
484
485 polygon = QwtClipper::clipPolygonF( clipRect, polygon );
486 qwtDrawPolyline<QPointF>( painter,
487 polygon.constData(), polygon.size(), d_polylineSplitting );
488 }
489 else
490 {
491 qwtDrawPolyline<QPointF>( painter, points, pointCount, d_polylineSplitting );
492 }
493}
494
495//! Wrapper for QPainter::drawPolygon()
496void QwtPainter::drawPolygon( QPainter *painter, const QPolygon &polygon )
497{
498 QRectF clipRect;
499 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
500
501 QPolygon cpa = polygon;
502 if ( deviceClipping )
503 cpa = QwtClipper::clipPolygon( clipRect, polygon );
504
505 painter->drawPolygon( cpa );
506}
507
508//! Wrapper for QPainter::drawPolyline()
509void QwtPainter::drawPolyline( QPainter *painter, const QPolygon &polygon )
510{
511 QRectF clipRect;
512 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
513
514 QPolygon cpa = polygon;
515 if ( deviceClipping )
516 cpa = QwtClipper::clipPolygon( clipRect, cpa );
517
518 qwtDrawPolyline<QPoint>( painter,
519 cpa.constData(), cpa.size(), d_polylineSplitting );
520}
521
522//! Wrapper for QPainter::drawPolyline()
523void QwtPainter::drawPolyline( QPainter *painter,
524 const QPoint *points, int pointCount )
525{
526 QRectF clipRect;
527 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
528
529 if ( deviceClipping )
530 {
531 QPolygon polygon( pointCount );
532 ::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) );
533
534 polygon = QwtClipper::clipPolygon( clipRect, polygon );
535 qwtDrawPolyline<QPoint>( painter,
536 polygon.constData(), polygon.size(), d_polylineSplitting );
537 }
538 else
539 qwtDrawPolyline<QPoint>( painter, points, pointCount, d_polylineSplitting );
540}
541
542//! Wrapper for QPainter::drawPoint()
543void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos )
544{
545 QRectF clipRect;
546 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
547
548 if ( deviceClipping && !clipRect.contains( pos ) )
549 return;
550
551 painter->drawPoint( pos );
552}
553
554//! Wrapper for QPainter::drawPoint()
555void QwtPainter::drawPoint( QPainter *painter, const QPoint &pos )
556{
557 QRectF clipRect;
558 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
559
560 if ( deviceClipping )
561 {
562 const int minX = qCeil( clipRect.left() );
563 const int maxX = qFloor( clipRect.right() );
564 const int minY = qCeil( clipRect.top() );
565 const int maxY = qFloor( clipRect.bottom() );
566
567 if ( pos.x() < minX || pos.x() > maxX
568 || pos.y() < minY || pos.y() > maxY )
569 {
570 return;
571 }
572 }
573
574 painter->drawPoint( pos );
575}
576
577//! Wrapper for QPainter::drawPoints()
578void QwtPainter::drawPoints( QPainter *painter,
579 const QPoint *points, int pointCount )
580{
581 QRectF clipRect;
582 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
583
584 if ( deviceClipping )
585 {
586 const int minX = qCeil( clipRect.left() );
587 const int maxX = qFloor( clipRect.right() );
588 const int minY = qCeil( clipRect.top() );
589 const int maxY = qFloor( clipRect.bottom() );
590
591 const QRect r( minX, minY, maxX - minX, maxY - minY );
592
593 QPolygon clippedPolygon( pointCount );
594 QPoint *clippedData = clippedPolygon.data();
595
596 int numClippedPoints = 0;
597 for ( int i = 0; i < pointCount; i++ )
598 {
599 if ( r.contains( points[i] ) )
600 clippedData[ numClippedPoints++ ] = points[i];
601 }
602 painter->drawPoints( clippedData, numClippedPoints );
603 }
604 else
605 {
606 painter->drawPoints( points, pointCount );
607 }
608}
609
610//! Wrapper for QPainter::drawPoints()
611void QwtPainter::drawPoints( QPainter *painter,
612 const QPointF *points, int pointCount )
613{
614 QRectF clipRect;
615 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
616
617 if ( deviceClipping )
618 {
619 QPolygonF clippedPolygon( pointCount );
620 QPointF *clippedData = clippedPolygon.data();
621
622 int numClippedPoints = 0;
623 for ( int i = 0; i < pointCount; i++ )
624 {
625 if ( clipRect.contains( points[i] ) )
626 clippedData[ numClippedPoints++ ] = points[i];
627 }
628 painter->drawPoints( clippedData, numClippedPoints );
629 }
630 else
631 {
632 painter->drawPoints( points, pointCount );
633 }
634}
635
636//! Wrapper for QPainter::drawImage()
637void QwtPainter::drawImage( QPainter *painter,
638 const QRectF &rect, const QImage &image )
639{
640 const QRect alignedRect = rect.toAlignedRect();
641
642 if ( alignedRect != rect )
643 {
644 const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
645
646 painter->save();
647 painter->setClipRect( clipRect, Qt::IntersectClip );
648 painter->drawImage( alignedRect, image );
649 painter->restore();
650 }
651 else
652 {
653 painter->drawImage( alignedRect, image );
654 }
655}
656
657//! Wrapper for QPainter::drawPixmap()
658void QwtPainter::drawPixmap( QPainter *painter,
659 const QRectF &rect, const QPixmap &pixmap )
660{
661 const QRect alignedRect = rect.toAlignedRect();
662
663 if ( alignedRect != rect )
664 {
665 const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
666
667 painter->save();
668 painter->setClipRect( clipRect, Qt::IntersectClip );
669 painter->drawPixmap( alignedRect, pixmap );
670 painter->restore();
671 }
672 else
673 {
674 painter->drawPixmap( alignedRect, pixmap );
675 }
676}
677
678//! Draw a focus rectangle on a widget using its style.
679void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget )
680{
681 drawFocusRect( painter, widget, widget->rect() );
682}
683
684//! Draw a focus rectangle on a widget using its style.
685void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget,
686 const QRect &rect )
687{
688 QStyleOptionFocusRect opt;
689 opt.init( widget );
690 opt.rect = rect;
691 opt.state |= QStyle::State_HasFocus;
692 opt.backgroundColor = widget->palette().color( widget->backgroundRole() );
693
694 widget->style()->drawPrimitive(
695 QStyle::PE_FrameFocusRect, &opt, painter, widget );
696}
697
698/*!
699 Draw a round frame
700
701 \param painter Painter
702 \param rect Frame rectangle
703 \param palette QPalette::WindowText is used for plain borders
704 QPalette::Dark and QPalette::Light for raised
705 or sunken borders
706 \param lineWidth Line width
707 \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
708*/
709void QwtPainter::drawRoundFrame( QPainter *painter,
710 const QRectF &rect, const QPalette &palette,
711 int lineWidth, int frameStyle )
712{
713 enum Style
714 {
715 Plain,
716 Sunken,
717 Raised
718 };
719
720 Style style = Plain;
721 if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
722 style = Sunken;
723 else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
724 style = Raised;
725
726 const double lw2 = 0.5 * lineWidth;
727 QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
728
729 QBrush brush;
730
731 if ( style != Plain )
732 {
733 QColor c1 = palette.color( QPalette::Light );
734 QColor c2 = palette.color( QPalette::Dark );
735
736 if ( style == Sunken )
737 qSwap( c1, c2 );
738
739 QLinearGradient gradient( r.topLeft(), r.bottomRight() );
740 gradient.setColorAt( 0.0, c1 );
741#if 0
742 gradient.setColorAt( 0.3, c1 );
743 gradient.setColorAt( 0.7, c2 );
744#endif
745 gradient.setColorAt( 1.0, c2 );
746
747 brush = QBrush( gradient );
748 }
749 else // Plain
750 {
751 brush = palette.brush( QPalette::WindowText );
752 }
753
754 painter->save();
755
756 painter->setPen( QPen( brush, lineWidth ) );
757 painter->setBrush( Qt::NoBrush );
758
759 painter->drawEllipse( r );
760
761 painter->restore();
762}
763
764/*!
765 Draw a rectangular frame
766
767 \param painter Painter
768 \param rect Frame rectangle
769 \param palette Palette
770 \param foregroundRole Foreground role used for QFrame::Plain
771 \param frameWidth Frame width
772 \param midLineWidth Used for QFrame::Box
773 \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
774*/
775void QwtPainter::drawFrame( QPainter *painter, const QRectF &rect,
776 const QPalette &palette, QPalette::ColorRole foregroundRole,
777 int frameWidth, int midLineWidth, int frameStyle )
778{
779 if ( frameWidth <= 0 || rect.isEmpty() )
780 return;
781
782 const int shadow = frameStyle & QFrame::Shadow_Mask;
783
784 painter->save();
785
786 if ( shadow == QFrame::Plain )
787 {
788 const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
789 const QRectF innerRect = outerRect.adjusted(
790 frameWidth, frameWidth, -frameWidth, -frameWidth );
791
792 QPainterPath path;
793 path.addRect( outerRect );
794 path.addRect( innerRect );
795
796 painter->setPen( Qt::NoPen );
797 painter->setBrush( palette.color( foregroundRole ) );
798
799 painter->drawPath( path );
800 }
801 else
802 {
803 const int shape = frameStyle & QFrame::Shape_Mask;
804
805 if ( shape == QFrame::Box )
806 {
807 const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
808 const QRectF midRect1 = outerRect.adjusted(
809 frameWidth, frameWidth, -frameWidth, -frameWidth );
810 const QRectF midRect2 = midRect1.adjusted(
811 midLineWidth, midLineWidth, -midLineWidth, -midLineWidth );
812
813 const QRectF innerRect = midRect2.adjusted(
814 frameWidth, frameWidth, -frameWidth, -frameWidth );
815
816 QPainterPath path1;
817 path1.moveTo( outerRect.bottomLeft() );
818 path1.lineTo( outerRect.topLeft() );
819 path1.lineTo( outerRect.topRight() );
820 path1.lineTo( midRect1.topRight() );
821 path1.lineTo( midRect1.topLeft() );
822 path1.lineTo( midRect1.bottomLeft() );
823
824 QPainterPath path2;
825 path2.moveTo( outerRect.bottomLeft() );
826 path2.lineTo( outerRect.bottomRight() );
827 path2.lineTo( outerRect.topRight() );
828 path2.lineTo( midRect1.topRight() );
829 path2.lineTo( midRect1.bottomRight() );
830 path2.lineTo( midRect1.bottomLeft() );
831
832 QPainterPath path3;
833 path3.moveTo( midRect2.bottomLeft() );
834 path3.lineTo( midRect2.topLeft() );
835 path3.lineTo( midRect2.topRight() );
836 path3.lineTo( innerRect.topRight() );
837 path3.lineTo( innerRect.topLeft() );
838 path3.lineTo( innerRect.bottomLeft() );
839
840 QPainterPath path4;
841 path4.moveTo( midRect2.bottomLeft() );
842 path4.lineTo( midRect2.bottomRight() );
843 path4.lineTo( midRect2.topRight() );
844 path4.lineTo( innerRect.topRight() );
845 path4.lineTo( innerRect.bottomRight() );
846 path4.lineTo( innerRect.bottomLeft() );
847
848 QPainterPath path5;
849 path5.addRect( midRect1 );
850 path5.addRect( midRect2 );
851
852 painter->setPen( Qt::NoPen );
853
854 QBrush brush1 = palette.dark().color();
855 QBrush brush2 = palette.light().color();
856
857 if ( shadow == QFrame::Raised )
858 qSwap( brush1, brush2 );
859
860 painter->setBrush( brush1 );
861 painter->drawPath( path1 );
862 painter->drawPath( path4 );
863
864 painter->setBrush( brush2 );
865 painter->drawPath( path2 );
866 painter->drawPath( path3 );
867
868 painter->setBrush( palette.mid() );
869 painter->drawPath( path5 );
870 }
871#if 0
872 // qDrawWinPanel doesn't result in something nice
873 // on a scalable document like PDF. Better draw a
874 // Panel.
875
876 else if ( shape == QFrame::WinPanel )
877 {
878 painter->setRenderHint( QPainter::NonCosmeticDefaultPen, true );
879 qDrawWinPanel ( painter, rect.toRect(), palette,
880 frameStyle & QFrame::Sunken );
881 }
882 else if ( shape == QFrame::StyledPanel )
883 {
884 }
885#endif
886 else
887 {
888 const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
889 const QRectF innerRect = outerRect.adjusted(
890 frameWidth - 1.0, frameWidth - 1.0,
891 -( frameWidth - 1.0 ), -( frameWidth - 1.0 ) );
892
893 QPainterPath path1;
894 path1.moveTo( outerRect.bottomLeft() );
895 path1.lineTo( outerRect.topLeft() );
896 path1.lineTo( outerRect.topRight() );
897 path1.lineTo( innerRect.topRight() );
898 path1.lineTo( innerRect.topLeft() );
899 path1.lineTo( innerRect.bottomLeft() );
900
901
902 QPainterPath path2;
903 path2.moveTo( outerRect.bottomLeft() );
904 path2.lineTo( outerRect.bottomRight() );
905 path2.lineTo( outerRect.topRight() );
906 path2.lineTo( innerRect.topRight() );
907 path2.lineTo( innerRect.bottomRight() );
908 path2.lineTo( innerRect.bottomLeft() );
909
910 painter->setPen( Qt::NoPen );
911
912 QBrush brush1 = palette.dark().color();
913 QBrush brush2 = palette.light().color();
914
915 if ( shadow == QFrame::Raised )
916 qSwap( brush1, brush2 );
917
918 painter->setBrush( brush1 );
919 painter->drawPath( path1 );
920
921 painter->setBrush( brush2 );
922 painter->drawPath( path2 );
923 }
924
925 }
926
927 painter->restore();
928}
929
930/*!
931 Draw a rectangular frame with rounded borders
932
933 \param painter Painter
934 \param rect Frame rectangle
935 \param xRadius x-radius of the ellipses defining the corners
936 \param yRadius y-radius of the ellipses defining the corners
937 \param palette QPalette::WindowText is used for plain borders
938 QPalette::Dark and QPalette::Light for raised
939 or sunken borders
940 \param lineWidth Line width
941 \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
942*/
943
944void QwtPainter::drawRoundedFrame( QPainter *painter,
945 const QRectF &rect, double xRadius, double yRadius,
946 const QPalette &palette, int lineWidth, int frameStyle )
947{
948 painter->save();
949 painter->setRenderHint( QPainter::Antialiasing, true );
950 painter->setBrush( Qt::NoBrush );
951
952 double lw2 = lineWidth * 0.5;
953 QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
954
955 QPainterPath path;
956 path.addRoundedRect( r, xRadius, yRadius );
957
958 enum Style
959 {
960 Plain,
961 Sunken,
962 Raised
963 };
964
965 Style style = Plain;
966 if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
967 style = Sunken;
968 else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
969 style = Raised;
970
971 if ( style != Plain && path.elementCount() == 17 )
972 {
973 // move + 4 * ( cubicTo + lineTo )
974 QPainterPath pathList[8];
975
976 for ( int i = 0; i < 4; i++ )
977 {
978 const int j = i * 4 + 1;
979
980 pathList[ 2 * i ].moveTo(
981 path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
982 );
983
984 pathList[ 2 * i ].cubicTo(
985 path.elementAt(j + 0).x, path.elementAt(j + 0).y,
986 path.elementAt(j + 1).x, path.elementAt(j + 1).y,
987 path.elementAt(j + 2).x, path.elementAt(j + 2).y );
988
989 pathList[ 2 * i + 1 ].moveTo(
990 path.elementAt(j + 2).x, path.elementAt(j + 2).y
991 );
992 pathList[ 2 * i + 1 ].lineTo(
993 path.elementAt(j + 3).x, path.elementAt(j + 3).y
994 );
995 }
996
997 QColor c1( palette.color( QPalette::Dark ) );
998 QColor c2( palette.color( QPalette::Light ) );
999
1000 if ( style == Raised )
1001 qSwap( c1, c2 );
1002
1003 for ( int i = 0; i < 4; i++ )
1004 {
1005 QRectF r = pathList[2 * i].controlPointRect();
1006
1007 QPen arcPen;
1008 arcPen.setCapStyle( Qt::FlatCap );
1009 arcPen.setWidth( lineWidth );
1010
1011 QPen linePen;
1012 linePen.setCapStyle( Qt::FlatCap );
1013 linePen.setWidth( lineWidth );
1014
1015 switch( i )
1016 {
1017 case 0:
1018 {
1019 arcPen.setColor( c1 );
1020 linePen.setColor( c1 );
1021 break;
1022 }
1023 case 1:
1024 {
1025 QLinearGradient gradient;
1026 gradient.setStart( r.topLeft() );
1027 gradient.setFinalStop( r.bottomRight() );
1028 gradient.setColorAt( 0.0, c1 );
1029 gradient.setColorAt( 1.0, c2 );
1030
1031 arcPen.setBrush( gradient );
1032 linePen.setColor( c2 );
1033 break;
1034 }
1035 case 2:
1036 {
1037 arcPen.setColor( c2 );
1038 linePen.setColor( c2 );
1039 break;
1040 }
1041 case 3:
1042 {
1043 QLinearGradient gradient;
1044
1045 gradient.setStart( r.bottomRight() );
1046 gradient.setFinalStop( r.topLeft() );
1047 gradient.setColorAt( 0.0, c2 );
1048 gradient.setColorAt( 1.0, c1 );
1049
1050 arcPen.setBrush( gradient );
1051 linePen.setColor( c1 );
1052 break;
1053 }
1054 }
1055
1056
1057 painter->setPen( arcPen );
1058 painter->drawPath( pathList[ 2 * i] );
1059
1060 painter->setPen( linePen );
1061 painter->drawPath( pathList[ 2 * i + 1] );
1062 }
1063 }
1064 else
1065 {
1066 QPen pen( palette.color( QPalette::WindowText ), lineWidth );
1067 painter->setPen( pen );
1068 painter->drawPath( path );
1069 }
1070
1071 painter->restore();
1072}
1073
1074/*!
1075 Draw a color bar into a rectangle
1076
1077 \param painter Painter
1078 \param colorMap Color map
1079 \param interval Value range
1080 \param scaleMap Scale map
1081 \param orientation Orientation
1082 \param rect Traget rectangle
1083*/
1084void QwtPainter::drawColorBar( QPainter *painter,
1085 const QwtColorMap &colorMap, const QwtInterval &interval,
1086 const QwtScaleMap &scaleMap, Qt::Orientation orientation,
1087 const QRectF &rect )
1088{
1089 QVector<QRgb> colorTable;
1090 if ( colorMap.format() == QwtColorMap::Indexed )
1091 colorTable = colorMap.colorTable( interval );
1092
1093 QColor c;
1094
1095 const QRect devRect = rect.toAlignedRect();
1096
1097 /*
1098 We paint to a pixmap first to have something scalable for printing
1099 ( f.e. in a Pdf document )
1100 */
1101
1102 QPixmap pixmap( devRect.size() );
1103 pixmap.fill( Qt::transparent );
1104
1105 QPainter pmPainter( &pixmap );
1106 pmPainter.translate( -devRect.x(), -devRect.y() );
1107
1108 if ( orientation == Qt::Horizontal )
1109 {
1110 QwtScaleMap sMap = scaleMap;
1111 sMap.setPaintInterval( rect.left(), rect.right() );
1112
1113 for ( int x = devRect.left(); x <= devRect.right(); x++ )
1114 {
1115 const double value = sMap.invTransform( x );
1116
1117 if ( colorMap.format() == QwtColorMap::RGB )
1118 c.setRgba( colorMap.rgb( interval, value ) );
1119 else
1120 c = colorTable[colorMap.colorIndex( interval, value )];
1121
1122 pmPainter.setPen( c );
1123 pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() );
1124 }
1125 }
1126 else // Vertical
1127 {
1128 QwtScaleMap sMap = scaleMap;
1129 sMap.setPaintInterval( rect.bottom(), rect.top() );
1130
1131 for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
1132 {
1133 const double value = sMap.invTransform( y );
1134
1135 if ( colorMap.format() == QwtColorMap::RGB )
1136 c.setRgba( colorMap.rgb( interval, value ) );
1137 else
1138 c = colorTable[colorMap.colorIndex( interval, value )];
1139
1140 pmPainter.setPen( c );
1141 pmPainter.drawLine( devRect.left(), y, devRect.right(), y );
1142 }
1143 }
1144 pmPainter.end();
1145
1146 drawPixmap( painter, rect, pixmap );
1147}
1148
1149static inline void qwtFillRect( const QWidget *widget, QPainter *painter,
1150 const QRect &rect, const QBrush &brush)
1151{
1152 if ( brush.style() == Qt::TexturePattern )
1153 {
1154 painter->save();
1155
1156 painter->setClipRect( rect );
1157 painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
1158
1159 painter->restore();
1160 }
1161 else if ( brush.gradient() )
1162 {
1163 painter->save();
1164
1165 painter->setClipRect( rect );
1166 painter->fillRect(0, 0, widget->width(),
1167 widget->height(), brush);
1168
1169 painter->restore();
1170 }
1171 else
1172 {
1173 painter->fillRect(rect, brush);
1174 }
1175}
1176
1177/*!
1178 Fill a pixmap with the content of a widget
1179
1180 In Qt >= 5.0 QPixmap::fill() is a nop, in Qt 4.x it is buggy
1181 for backgrounds with gradients. Thus fillPixmap() offers
1182 an alternative implementation.
1183
1184 \param widget Widget
1185 \param pixmap Pixmap to be filled
1186 \param offset Offset
1187
1188 \sa QPixmap::fill()
1189 */
1190void QwtPainter::fillPixmap( const QWidget *widget,
1191 QPixmap &pixmap, const QPoint &offset )
1192{
1193 const QRect rect( offset, pixmap.size() );
1194
1195 QPainter painter( &pixmap );
1196 painter.translate( -offset );
1197
1198 const QBrush autoFillBrush =
1199 widget->palette().brush( widget->backgroundRole() );
1200
1201 if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) )
1202 {
1203 const QBrush bg = widget->palette().brush( QPalette::Window );
1204 qwtFillRect( widget, &painter, rect, bg);
1205 }
1206
1207 if ( widget->autoFillBackground() )
1208 qwtFillRect( widget, &painter, rect, autoFillBrush);
1209
1210 if ( widget->testAttribute(Qt::WA_StyledBackground) )
1211 {
1212 painter.setClipRegion( rect );
1213
1214 QStyleOption opt;
1215 opt.initFrom( widget );
1216 widget->style()->drawPrimitive( QStyle::PE_Widget,
1217 &opt, &painter, widget );
1218 }
1219}
1220
1221/*!
1222 Fill rect with the background of a widget
1223
1224 \param painter Painter
1225 \param rect Rectangle to be filled
1226 \param widget Widget
1227
1228 \sa QStyle::PE_Widget, QWidget::backgroundRole()
1229 */
1230void QwtPainter::drawBackgound( QPainter *painter,
1231 const QRectF &rect, const QWidget *widget )
1232{
1233 if ( widget->testAttribute( Qt::WA_StyledBackground ) )
1234 {
1235 QStyleOption opt;
1236 opt.initFrom( widget );
1237 opt.rect = rect.toAlignedRect();
1238
1239 widget->style()->drawPrimitive(
1240 QStyle::PE_Widget, &opt, painter, widget);
1241 }
1242 else
1243 {
1244 const QBrush brush =
1245 widget->palette().brush( widget->backgroundRole() );
1246
1247 painter->fillRect( rect, brush );
1248 }
1249}
1250
1251/*!
1252 \return A pixmap that can be used as backing store
1253
1254 \param widget Widget, for which the backingstore is intended
1255 \param size Size of the pixmap
1256 */
1257QPixmap QwtPainter::backingStore( QWidget *widget, const QSize &size )
1258{
1259 QPixmap pm;
1260
1261#define QWT_HIGH_DPI 1
1262
1263#if QT_VERSION >= 0x050000 && QWT_HIGH_DPI
1264 qreal pixelRatio = 1.0;
1265
1266 if ( widget && widget->windowHandle() )
1267 {
1268#if QT_VERSION < 0x050100
1269 pixelRatio = widget->windowHandle()->devicePixelRatio();
1270#else
1271 pixelRatio = widget->devicePixelRatio();
1272#endif
1273 }
1274 else
1275 {
1276 if ( qApp )
1277 pixelRatio = qApp->devicePixelRatio();
1278 }
1279
1280 pm = QPixmap( size * pixelRatio );
1281 pm.setDevicePixelRatio( pixelRatio );
1282#else
1283 Q_UNUSED( widget )
1284 pm = QPixmap( size );
1285#endif
1286
1287#if QT_VERSION < 0x050000
1288#ifdef Q_WS_X11
1289 if ( widget && isX11GraphicsSystem() )
1290 {
1291 if ( pm.x11Info().screen() != widget->x11Info().screen() )
1292 pm.x11SetScreen( widget->x11Info().screen() );
1293 }
1294#endif
1295#endif
1296
1297 return pm;
1298}
1299
Note: See TracBrowser for help on using the repository browser.