Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
qwt_painter.cpp
1/******************************************************************************
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
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 <qpainterpath.h>
23#include <qpixmap.h>
24#include <qstyle.h>
25#include <qtextdocument.h>
26#include <qabstracttextdocumentlayout.h>
27#include <qstyleoption.h>
28#include <qpaintengine.h>
29#include <qapplication.h>
30
31#if QT_VERSION >= 0x060000
32#include <qscreen.h>
33#else
34#include <qdesktopwidget.h>
35#endif
36
37#if QT_VERSION < 0x050000
38
39#ifdef Q_WS_X11
40#include <qx11info_x11.h>
41#endif
42
43#endif
44
45#include <cstring>
46
47bool QwtPainter::m_polylineSplitting = true;
48bool QwtPainter::m_roundingAlignment = true;
49
50static inline bool qwtIsRasterPaintEngineBuggy()
51{
52#if 0
53 static int isBuggy = -1;
54 if ( isBuggy < 0 )
55 {
56 // auto detect bug of the raster paint engine,
57 // fixed with: https://codereview.qt-project.org/#/c/99456/
58
59 QImage image( 2, 3, QImage::Format_ARGB32 );
60 image.fill( 0u );
61
62 QPolygonF p;
63 p += QPointF(0, 1);
64 p += QPointF(0, 0);
65 p += QPointF(1, 0 );
66 p += QPointF(1, 2 );
67
68 QPainter painter( &image );
69 painter.drawPolyline( p );
70 painter.end();
71
72 isBuggy = ( image.pixel( 1, 1 ) == 0 ) ? 1 : 0;
73 }
74
75 return isBuggy == 1;
76#endif
77
78#if QT_VERSION < 0x050000
79 return true;
80#elif QT_VERSION < 0x050100
81 return false;
82#elif QT_VERSION < 0x050400
83 return true;
84#else
85 return false;
86#endif
87}
88
89static inline bool qwtIsClippingNeeded(
90 const QPainter* painter, QRectF& clipRect )
91{
92 bool doClipping = false;
93 const QPaintEngine* pe = painter->paintEngine();
94 if ( pe && pe->type() == QPaintEngine::SVG )
95 {
96 // The SVG paint engine ignores any clipping,
97
98 if ( painter->hasClipping() )
99 {
100 doClipping = true;
101 clipRect = painter->clipRegion().boundingRect();
102 }
103 }
104
105 return doClipping;
106}
107
108template< class T >
109static inline void qwtDrawPolyline( QPainter* painter,
110 const T* points, int pointCount, bool polylineSplitting )
111{
112 bool doSplit = false;
113 if ( polylineSplitting )
114 {
115 const QPaintEngine* pe = painter->paintEngine();
116 if ( pe && pe->type() == QPaintEngine::Raster )
117 {
118 /*
119 Raster paint engine is much faster when splitting
120 the polygon, but of course we might see some issues where
121 the pieces are joining
122 */
123 doSplit = true;
124 }
125 }
126
127 if ( doSplit )
128 {
129 QPen pen = painter->pen();
130
131 const int splitSize = 6;
132
133 if ( pen.width() <= 1 && pen.isSolid() && qwtIsRasterPaintEngineBuggy()
134 && !( painter->renderHints() & QPainter::Antialiasing ) )
135 {
136 int k = 0;
137
138 for ( int i = k + 1; i < pointCount; i++ )
139 {
140 const QPointF& p1 = points[i - 1];
141 const QPointF& p2 = points[i];
142
143 const bool isBad = ( qAbs( p2.y() - p1.y() ) <= 1 )
144 && qAbs( p2.x() - p1.x() ) <= 1;
145
146 if ( isBad || ( i - k >= splitSize ) )
147 {
148 painter->drawPolyline( points + k, i - k + 1 );
149 k = i;
150 }
151 }
152
153 painter->drawPolyline( points + k, pointCount - k );
154 }
155 else
156 {
157 for ( int i = 0; i < pointCount; i += splitSize )
158 {
159 const int n = qMin( splitSize + 1, pointCount - i );
160 painter->drawPolyline( points + i, n );
161 }
162 }
163 }
164 else
165 {
166 painter->drawPolyline( points, pointCount );
167 }
168}
169
170static inline QSize qwtScreenResolution()
171{
172 static QSize screenResolution;
173 if ( !screenResolution.isValid() )
174 {
175 /*
176 We might have screens with different resolutions. TODO ...
177 */
178#if QT_VERSION >= 0x060000
179 QScreen* screen = QGuiApplication::primaryScreen();
180 if ( screen )
181 {
182 screenResolution.setWidth( screen->logicalDotsPerInchX() );
183 screenResolution.setHeight( screen->logicalDotsPerInchY() );
184 }
185#else
186 QDesktopWidget* desktop = QApplication::desktop();
187 if ( desktop )
188 {
189 screenResolution.setWidth( desktop->logicalDpiX() );
190 screenResolution.setHeight( desktop->logicalDpiY() );
191 }
192#endif
193 }
194
195 return screenResolution;
196}
197
198static inline void qwtUnscaleFont( QPainter* painter )
199{
200 if ( painter->font().pixelSize() >= 0 )
201 return;
202
203 const QSize screenResolution = qwtScreenResolution();
204
205 const QPaintDevice* pd = painter->device();
206 if ( pd->logicalDpiX() != screenResolution.width() ||
207 pd->logicalDpiY() != screenResolution.height() )
208 {
209 QFont pixelFont = QwtPainter::scaledFont( painter->font() );
210 pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() );
211
212 painter->setFont( pixelFont );
213 }
214}
215
224{
225 /*
226 The X11 paint engine has been removed with Qt 5.0, but
227 reintroduced with Qt 5.10. It can be enabled with
228 "export QT_XCB_NATIVE_PAINTING=1".
229 */
230
231 static int onX11 = -1;
232 if ( onX11 < 0 )
233 {
234 QPixmap pm( 1, 1 );
235 QPainter painter( &pm );
236
237 onX11 = ( painter.paintEngine()->type() == QPaintEngine::X11 ) ? 1 : 0;
238 }
239
240 return onX11 == 1;
241}
242
257bool QwtPainter::isAligning( const QPainter* painter )
258{
259 if ( painter && painter->isActive() )
260 {
261 const QPaintEngine::Type type =
262 painter->paintEngine()->type();
263
264 if ( type >= QPaintEngine::User )
265 {
266 // we have no idea - better don't align
267 return false;
268 }
269
270 switch ( type )
271 {
272 case QPaintEngine::Pdf:
273 case QPaintEngine::SVG:
274#if 0
275 case QPaintEngine::MacPrinter:
276#endif
277 return false;
278
279 default:
280 break;
281 }
282
283 const QTransform& tr = painter->transform();
284 if ( tr.isRotating() || tr.isScaling() )
285 {
286 // we might have to check translations too
287 return false;
288 }
289 }
290
291 return true;
292}
293
306{
307 m_roundingAlignment = enable;
308}
309
326{
327 m_polylineSplitting = enable;
328}
329
331void QwtPainter::drawPath( QPainter* painter, const QPainterPath& path )
332{
333 painter->drawPath( path );
334}
335
337void QwtPainter::drawRect( QPainter* painter, qreal x, qreal y, qreal w, qreal h )
338{
339 drawRect( painter, QRectF( x, y, w, h ) );
340}
341
343void QwtPainter::drawRect( QPainter* painter, const QRectF& rect )
344{
345 const QRectF r = rect;
346
347 QRectF clipRect;
348 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
349
350 if ( deviceClipping )
351 {
352 if ( !clipRect.intersects( r ) )
353 return;
354
355 if ( !clipRect.contains( r ) )
356 {
357 fillRect( painter, r & clipRect, painter->brush() );
358
359 painter->save();
360 painter->setBrush( Qt::NoBrush );
361 drawPolyline( painter, QPolygonF( r ) );
362 painter->restore();
363
364 return;
365 }
366 }
367
368 painter->drawRect( r );
369}
370
372void QwtPainter::fillRect( QPainter* painter,
373 const QRectF& rect, const QBrush& brush )
374{
375 if ( !rect.isValid() )
376 return;
377
378 QRectF clipRect;
379 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
380
381 /*
382 Performance of Qt4 is horrible for a non trivial brush. Without
383 clipping expect minutes or hours for repainting large rectangles
384 (might result from zooming)
385 */
386
387 if ( deviceClipping )
388 clipRect &= painter->window();
389 else
390 clipRect = painter->window();
391
392 if ( painter->hasClipping() )
393 clipRect &= painter->clipRegion().boundingRect();
394
395 QRectF r = rect;
396 if ( deviceClipping )
397 r = r.intersected( clipRect );
398
399 if ( r.isValid() )
400 painter->fillRect( r, brush );
401}
402
404void QwtPainter::drawPie( QPainter* painter, const QRectF& rect,
405 int a, int alen )
406{
407 QRectF clipRect;
408 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
409 if ( deviceClipping && !clipRect.contains( rect ) )
410 return;
411
412 painter->drawPie( rect, a, alen );
413}
414
416void QwtPainter::drawEllipse( QPainter* painter, const QRectF& rect )
417{
418 QRectF clipRect;
419 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
420
421 if ( deviceClipping && !clipRect.contains( rect ) )
422 return;
423
424 painter->drawEllipse( rect );
425}
426
428void QwtPainter::drawText( QPainter* painter,
429 qreal x, qreal y, const QString& text )
430{
431 drawText( painter, QPointF( x, y ), text );
432}
433
435void QwtPainter::drawText( QPainter* painter, const QPointF& pos,
436 const QString& text )
437{
438 QRectF clipRect;
439 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
440
441 if ( deviceClipping && !clipRect.contains( pos ) )
442 return;
443
444
445 painter->save();
446 qwtUnscaleFont( painter );
447 painter->drawText( pos, text );
448 painter->restore();
449}
450
452void QwtPainter::drawText( QPainter* painter,
453 qreal x, qreal y, qreal w, qreal h,
454 int flags, const QString& text )
455{
456 drawText( painter, QRectF( x, y, w, h ), flags, text );
457}
458
460void QwtPainter::drawText( QPainter* painter, const QRectF& rect,
461 int flags, const QString& text )
462{
463 painter->save();
464 qwtUnscaleFont( painter );
465 painter->drawText( rect, flags, text );
466 painter->restore();
467}
468
469#ifndef QT_NO_RICHTEXT
470
479void QwtPainter::drawSimpleRichText( QPainter* painter, const QRectF& rect,
480 int flags, const QTextDocument& text )
481{
482 QTextDocument* txt = text.clone();
483
484 painter->save();
485
486 QRectF unscaledRect = rect;
487
488 if ( painter->font().pixelSize() < 0 )
489 {
490 const QSize res = qwtScreenResolution();
491
492 const QPaintDevice* pd = painter->device();
493 if ( pd->logicalDpiX() != res.width() ||
494 pd->logicalDpiY() != res.height() )
495 {
496 QTransform transform;
497 transform.scale( res.width() / qreal( pd->logicalDpiX() ),
498 res.height() / qreal( pd->logicalDpiY() ) );
499
500 painter->setWorldTransform( transform, true );
501 unscaledRect = transform.inverted().mapRect(rect);
502 }
503 }
504
505 txt->setDefaultFont( painter->font() );
506 txt->setPageSize( QSizeF( unscaledRect.width(), QWIDGETSIZE_MAX ) );
507
508 QAbstractTextDocumentLayout* layout = txt->documentLayout();
509
510 const qreal height = layout->documentSize().height();
511 qreal y = unscaledRect.y();
512 if ( flags & Qt::AlignBottom )
513 y += ( unscaledRect.height() - height );
514 else if ( flags & Qt::AlignVCenter )
515 y += ( unscaledRect.height() - height ) / 2;
516
517 QAbstractTextDocumentLayout::PaintContext context;
518 context.palette.setColor( QPalette::Text, painter->pen().color() );
519
520 painter->translate( unscaledRect.x(), y );
521 layout->draw( painter, context );
522
523 painter->restore();
524 delete txt;
525}
526
527#endif // !QT_NO_RICHTEXT
528
529
531void QwtPainter::drawLine( QPainter* painter,
532 const QPointF& p1, const QPointF& p2 )
533{
534 QRectF clipRect;
535 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
536
537 if ( deviceClipping &&
538 !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) )
539 {
540 QPolygonF polygon;
541 polygon += p1;
542 polygon += p2;
543 drawPolyline( painter, polygon );
544 return;
545 }
546
547 painter->drawLine( p1, p2 );
548}
549
551void QwtPainter::drawPolygon( QPainter* painter, const QPolygonF& polygon )
552{
553 QRectF clipRect;
554 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
555
556 if ( deviceClipping )
557 {
558 painter->drawPolygon(
559 QwtClipper::clippedPolygonF( clipRect, polygon, true ) );
560 }
561 else
562 {
563 painter->drawPolygon( polygon );
564 }
565}
566
568void QwtPainter::drawPolyline( QPainter* painter, const QPolygonF& polygon )
569{
570 QRectF clipRect;
571 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
572
573 if ( deviceClipping )
574 {
575 const QPolygonF cpa = QwtClipper::clippedPolygonF( clipRect, polygon );
576
577 qwtDrawPolyline< QPointF >( painter,
578 cpa.constData(), cpa.size(), m_polylineSplitting );
579 }
580 else
581 {
582 qwtDrawPolyline< QPointF >( painter,
583 polygon.constData(), polygon.size(), m_polylineSplitting );
584 }
585}
586
588void QwtPainter::drawPolyline( QPainter* painter,
589 const QPointF* points, int pointCount )
590{
591 QRectF clipRect;
592 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
593
594 if ( deviceClipping )
595 {
596 QPolygonF polygon( pointCount );
597 std::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) );
598
599 QwtClipper::clipPolygonF( clipRect, polygon );
600 qwtDrawPolyline< QPointF >( painter,
601 polygon.constData(), polygon.size(), m_polylineSplitting );
602 }
603 else
604 {
605 qwtDrawPolyline< QPointF >( painter, points, pointCount, m_polylineSplitting );
606 }
607}
608
610void QwtPainter::drawPolygon( QPainter* painter, const QPolygon& polygon )
611{
612 QRectF clipRect;
613 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
614
615 if ( deviceClipping )
616 {
617 painter->drawPolygon(
618 QwtClipper::clippedPolygon( clipRect, polygon, true ) );
619 }
620 else
621 {
622 painter->drawPolygon( polygon );
623 }
624}
625
627void QwtPainter::drawPolyline( QPainter* painter, const QPolygon& polygon )
628{
629 QRectF clipRect;
630 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
631
632 if ( deviceClipping )
633 {
634 const QPolygon cpa = QwtClipper::clippedPolygon( clipRect, polygon );
635
636 qwtDrawPolyline< QPoint >( painter,
637 cpa.constData(), cpa.size(), m_polylineSplitting );
638 }
639 else
640 {
641 qwtDrawPolyline< QPoint >( painter,
642 polygon.constData(), polygon.size(), m_polylineSplitting );
643 }
644}
645
647void QwtPainter::drawPolyline( QPainter* painter,
648 const QPoint* points, int pointCount )
649{
650 QRectF clipRect;
651 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
652
653 if ( deviceClipping )
654 {
655 QPolygon polygon( pointCount );
656 std::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) );
657
658 QwtClipper::clipPolygon( clipRect, polygon );
659 qwtDrawPolyline< QPoint >( painter,
660 polygon.constData(), polygon.size(), m_polylineSplitting );
661 }
662 else
663 {
664 qwtDrawPolyline< QPoint >( painter, points, pointCount, m_polylineSplitting );
665 }
666}
667
669void QwtPainter::drawPoint( QPainter* painter, const QPointF& pos )
670{
671 QRectF clipRect;
672 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
673
674 if ( deviceClipping && !clipRect.contains( pos ) )
675 return;
676
677 painter->drawPoint( pos );
678}
679
681void QwtPainter::drawPoint( QPainter* painter, const QPoint& pos )
682{
683 QRectF clipRect;
684 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
685
686 if ( deviceClipping )
687 {
688 const int minX = qwtCeil( clipRect.left() );
689 const int maxX = qwtFloor( clipRect.right() );
690 const int minY = qwtCeil( clipRect.top() );
691 const int maxY = qwtFloor( clipRect.bottom() );
692
693 if ( pos.x() < minX || pos.x() > maxX
694 || pos.y() < minY || pos.y() > maxY )
695 {
696 return;
697 }
698 }
699
700 painter->drawPoint( pos );
701}
702
704void QwtPainter::drawPoints( QPainter* painter,
705 const QPoint* points, int pointCount )
706{
707 QRectF clipRect;
708 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
709
710 if ( deviceClipping )
711 {
712 const int minX = qwtCeil( clipRect.left() );
713 const int maxX = qwtFloor( clipRect.right() );
714 const int minY = qwtCeil( clipRect.top() );
715 const int maxY = qwtFloor( clipRect.bottom() );
716
717 const QRect r( minX, minY, maxX - minX, maxY - minY );
718
719 QPolygon clippedPolygon( pointCount );
720 QPoint* clippedData = clippedPolygon.data();
721
722 int numClippedPoints = 0;
723 for ( int i = 0; i < pointCount; i++ )
724 {
725 if ( r.contains( points[i] ) )
726 clippedData[ numClippedPoints++ ] = points[i];
727 }
728 painter->drawPoints( clippedData, numClippedPoints );
729 }
730 else
731 {
732 painter->drawPoints( points, pointCount );
733 }
734}
735
737void QwtPainter::drawPoints( QPainter* painter,
738 const QPointF* points, int pointCount )
739{
740 QRectF clipRect;
741 const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
742
743 if ( deviceClipping )
744 {
745 QPolygonF clippedPolygon( pointCount );
746 QPointF* clippedData = clippedPolygon.data();
747
748 int numClippedPoints = 0;
749 for ( int i = 0; i < pointCount; i++ )
750 {
751 if ( clipRect.contains( points[i] ) )
752 clippedData[ numClippedPoints++ ] = points[i];
753 }
754 painter->drawPoints( clippedData, numClippedPoints );
755 }
756 else
757 {
758 painter->drawPoints( points, pointCount );
759 }
760}
761
763void QwtPainter::drawImage( QPainter* painter,
764 const QRectF& rect, const QImage& image )
765{
766 const QRect alignedRect = rect.toAlignedRect();
767
768 if ( alignedRect != rect )
769 {
770 const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
771
772 painter->save();
773 painter->setClipRect( clipRect, Qt::IntersectClip );
774 painter->drawImage( alignedRect, image );
775 painter->restore();
776 }
777 else
778 {
779 painter->drawImage( alignedRect, image );
780 }
781}
782
784void QwtPainter::drawPixmap( QPainter* painter,
785 const QRectF& rect, const QPixmap& pixmap )
786{
787 const QRect alignedRect = rect.toAlignedRect();
788
789 if ( alignedRect != rect )
790 {
791 const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
792
793 painter->save();
794 painter->setClipRect( clipRect, Qt::IntersectClip );
795 painter->drawPixmap( alignedRect, pixmap );
796 painter->restore();
797 }
798 else
799 {
800 painter->drawPixmap( alignedRect, pixmap );
801 }
802}
803
805void QwtPainter::drawFocusRect( QPainter* painter, const QWidget* widget )
806{
807 drawFocusRect( painter, widget, widget->rect() );
808}
809
811void QwtPainter::drawFocusRect( QPainter* painter, const QWidget* widget,
812 const QRect& rect )
813{
814 QStyleOptionFocusRect opt;
815 opt.initFrom( widget );
816 opt.rect = rect;
817 opt.state |= QStyle::State_HasFocus;
818 opt.backgroundColor = widget->palette().color( widget->backgroundRole() );
819
820 widget->style()->drawPrimitive(
821 QStyle::PE_FrameFocusRect, &opt, painter, widget );
822}
823
835void QwtPainter::drawRoundFrame( QPainter* painter,
836 const QRectF& rect, const QPalette& palette,
837 int lineWidth, int frameStyle )
838{
839 enum Style
840 {
841 Plain,
842 Sunken,
843 Raised
844 };
845
846 Style style = Plain;
847 if ( (frameStyle& QFrame::Sunken) == QFrame::Sunken )
848 style = Sunken;
849 else if ( (frameStyle& QFrame::Raised) == QFrame::Raised )
850 style = Raised;
851
852 const qreal lw2 = 0.5 * lineWidth;
853 QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
854
855 QBrush brush;
856
857 if ( style != Plain )
858 {
859 QColor c1 = palette.color( QPalette::Light );
860 QColor c2 = palette.color( QPalette::Dark );
861
862 if ( style == Sunken )
863 qSwap( c1, c2 );
864
865 QLinearGradient gradient( r.topLeft(), r.bottomRight() );
866 gradient.setColorAt( 0.0, c1 );
867#if 0
868 gradient.setColorAt( 0.3, c1 );
869 gradient.setColorAt( 0.7, c2 );
870#endif
871 gradient.setColorAt( 1.0, c2 );
872
873 brush = QBrush( gradient );
874 }
875 else // Plain
876 {
877 brush = palette.brush( QPalette::WindowText );
878 }
879
880 painter->save();
881
882 painter->setPen( QPen( brush, lineWidth ) );
883 painter->setBrush( Qt::NoBrush );
884
885 painter->drawEllipse( r );
886
887 painter->restore();
888}
889
901void QwtPainter::drawFrame( QPainter* painter, const QRectF& rect,
902 const QPalette& palette, QPalette::ColorRole foregroundRole,
903 int frameWidth, int midLineWidth, int frameStyle )
904{
905 if ( frameWidth <= 0 || rect.isEmpty() )
906 return;
907
908 const int shadow = frameStyle & QFrame::Shadow_Mask;
909
910 painter->save();
911
912 if ( shadow == QFrame::Plain )
913 {
914 const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
915 const QRectF innerRect = outerRect.adjusted(
916 frameWidth, frameWidth, -frameWidth, -frameWidth );
917
918 QPainterPath path;
919 path.addRect( outerRect );
920 path.addRect( innerRect );
921
922 painter->setPen( Qt::NoPen );
923 painter->setBrush( palette.color( foregroundRole ) );
924
925 painter->drawPath( path );
926 }
927 else
928 {
929 const int shape = frameStyle & QFrame::Shape_Mask;
930
931 if ( shape == QFrame::Box )
932 {
933 const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
934 const QRectF midRect1 = outerRect.adjusted(
935 frameWidth, frameWidth, -frameWidth, -frameWidth );
936 const QRectF midRect2 = midRect1.adjusted(
937 midLineWidth, midLineWidth, -midLineWidth, -midLineWidth );
938
939 const QRectF innerRect = midRect2.adjusted(
940 frameWidth, frameWidth, -frameWidth, -frameWidth );
941
942 QPainterPath path1;
943 path1.moveTo( outerRect.bottomLeft() );
944 path1.lineTo( outerRect.topLeft() );
945 path1.lineTo( outerRect.topRight() );
946 path1.lineTo( midRect1.topRight() );
947 path1.lineTo( midRect1.topLeft() );
948 path1.lineTo( midRect1.bottomLeft() );
949
950 QPainterPath path2;
951 path2.moveTo( outerRect.bottomLeft() );
952 path2.lineTo( outerRect.bottomRight() );
953 path2.lineTo( outerRect.topRight() );
954 path2.lineTo( midRect1.topRight() );
955 path2.lineTo( midRect1.bottomRight() );
956 path2.lineTo( midRect1.bottomLeft() );
957
958 QPainterPath path3;
959 path3.moveTo( midRect2.bottomLeft() );
960 path3.lineTo( midRect2.topLeft() );
961 path3.lineTo( midRect2.topRight() );
962 path3.lineTo( innerRect.topRight() );
963 path3.lineTo( innerRect.topLeft() );
964 path3.lineTo( innerRect.bottomLeft() );
965
966 QPainterPath path4;
967 path4.moveTo( midRect2.bottomLeft() );
968 path4.lineTo( midRect2.bottomRight() );
969 path4.lineTo( midRect2.topRight() );
970 path4.lineTo( innerRect.topRight() );
971 path4.lineTo( innerRect.bottomRight() );
972 path4.lineTo( innerRect.bottomLeft() );
973
974 QPainterPath path5;
975 path5.addRect( midRect1 );
976 path5.addRect( midRect2 );
977
978 painter->setPen( Qt::NoPen );
979
980 QBrush brush1 = palette.dark().color();
981 QBrush brush2 = palette.light().color();
982
983 if ( shadow == QFrame::Raised )
984 qSwap( brush1, brush2 );
985
986 painter->setBrush( brush1 );
987 painter->drawPath( path1 );
988 painter->drawPath( path4 );
989
990 painter->setBrush( brush2 );
991 painter->drawPath( path2 );
992 painter->drawPath( path3 );
993
994 painter->setBrush( palette.mid() );
995 painter->drawPath( path5 );
996 }
997 else
998 {
999 const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
1000 const QRectF innerRect = outerRect.adjusted(
1001 frameWidth - 1.0, frameWidth - 1.0,
1002 -( frameWidth - 1.0 ), -( frameWidth - 1.0 ) );
1003
1004 QPainterPath path1;
1005 path1.moveTo( outerRect.bottomLeft() );
1006 path1.lineTo( outerRect.topLeft() );
1007 path1.lineTo( outerRect.topRight() );
1008 path1.lineTo( innerRect.topRight() );
1009 path1.lineTo( innerRect.topLeft() );
1010 path1.lineTo( innerRect.bottomLeft() );
1011
1012
1013 QPainterPath path2;
1014 path2.moveTo( outerRect.bottomLeft() );
1015 path2.lineTo( outerRect.bottomRight() );
1016 path2.lineTo( outerRect.topRight() );
1017 path2.lineTo( innerRect.topRight() );
1018 path2.lineTo( innerRect.bottomRight() );
1019 path2.lineTo( innerRect.bottomLeft() );
1020
1021 painter->setPen( Qt::NoPen );
1022
1023 QBrush brush1 = palette.dark().color();
1024 QBrush brush2 = palette.light().color();
1025
1026 if ( shadow == QFrame::Raised )
1027 qSwap( brush1, brush2 );
1028
1029 painter->setBrush( brush1 );
1030 painter->drawPath( path1 );
1031
1032 painter->setBrush( brush2 );
1033 painter->drawPath( path2 );
1034 }
1035
1036 }
1037
1038 painter->restore();
1039}
1040
1055void QwtPainter::drawRoundedFrame( QPainter* painter,
1056 const QRectF& rect, qreal xRadius, qreal yRadius,
1057 const QPalette& palette, int lineWidth, int frameStyle )
1058{
1059 painter->save();
1060 painter->setRenderHint( QPainter::Antialiasing, true );
1061 painter->setBrush( Qt::NoBrush );
1062
1063 qreal lw2 = lineWidth * 0.5;
1064 QRectF innerRect = rect.adjusted( lw2, lw2, -lw2, -lw2 );
1065
1066 QPainterPath path;
1067 path.addRoundedRect( innerRect, xRadius, yRadius );
1068
1069 enum Style
1070 {
1071 Plain,
1072 Sunken,
1073 Raised
1074 };
1075
1076 Style style = Plain;
1077 if ( (frameStyle& QFrame::Sunken) == QFrame::Sunken )
1078 style = Sunken;
1079 else if ( (frameStyle& QFrame::Raised) == QFrame::Raised )
1080 style = Raised;
1081
1082 if ( style != Plain && path.elementCount() == 17 )
1083 {
1084 // move + 4 * ( cubicTo + lineTo )
1085 QPainterPath pathList[8];
1086
1087 for ( int i = 0; i < 4; i++ )
1088 {
1089 const int j = i * 4 + 1;
1090
1091 pathList[ 2 * i ].moveTo(
1092 path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
1093 );
1094
1095 pathList[ 2 * i ].cubicTo(
1096 path.elementAt(j + 0).x, path.elementAt(j + 0).y,
1097 path.elementAt(j + 1).x, path.elementAt(j + 1).y,
1098 path.elementAt(j + 2).x, path.elementAt(j + 2).y );
1099
1100 pathList[ 2 * i + 1 ].moveTo(
1101 path.elementAt(j + 2).x, path.elementAt(j + 2).y
1102 );
1103 pathList[ 2 * i + 1 ].lineTo(
1104 path.elementAt(j + 3).x, path.elementAt(j + 3).y
1105 );
1106 }
1107
1108 QColor c1( palette.color( QPalette::Dark ) );
1109 QColor c2( palette.color( QPalette::Light ) );
1110
1111 if ( style == Raised )
1112 qSwap( c1, c2 );
1113
1114 for ( int i = 0; i < 4; i++ )
1115 {
1116 const QRectF r = pathList[2 * i].controlPointRect();
1117
1118 QPen arcPen;
1119 arcPen.setCapStyle( Qt::FlatCap );
1120 arcPen.setWidth( lineWidth );
1121
1122 QPen linePen;
1123 linePen.setCapStyle( Qt::FlatCap );
1124 linePen.setWidth( lineWidth );
1125
1126 switch( i )
1127 {
1128 case 0:
1129 {
1130 arcPen.setColor( c1 );
1131 linePen.setColor( c1 );
1132 break;
1133 }
1134 case 1:
1135 {
1136 QLinearGradient gradient;
1137 gradient.setStart( r.topLeft() );
1138 gradient.setFinalStop( r.bottomRight() );
1139 gradient.setColorAt( 0.0, c1 );
1140 gradient.setColorAt( 1.0, c2 );
1141
1142 arcPen.setBrush( gradient );
1143 linePen.setColor( c2 );
1144 break;
1145 }
1146 case 2:
1147 {
1148 arcPen.setColor( c2 );
1149 linePen.setColor( c2 );
1150 break;
1151 }
1152 case 3:
1153 {
1154 QLinearGradient gradient;
1155
1156 gradient.setStart( r.bottomRight() );
1157 gradient.setFinalStop( r.topLeft() );
1158 gradient.setColorAt( 0.0, c2 );
1159 gradient.setColorAt( 1.0, c1 );
1160
1161 arcPen.setBrush( gradient );
1162 linePen.setColor( c1 );
1163 break;
1164 }
1165 }
1166
1167
1168 painter->setPen( arcPen );
1169 painter->drawPath( pathList[ 2 * i] );
1170
1171 painter->setPen( linePen );
1172 painter->drawPath( pathList[ 2 * i + 1] );
1173 }
1174 }
1175 else
1176 {
1177 QPen pen( palette.color( QPalette::WindowText ), lineWidth );
1178 painter->setPen( pen );
1179 painter->drawPath( path );
1180 }
1181
1182 painter->restore();
1183}
1184
1195void QwtPainter::drawColorBar( QPainter* painter,
1196 const QwtColorMap& colorMap, const QwtInterval& interval,
1197 const QwtScaleMap& scaleMap, Qt::Orientation orientation,
1198 const QRectF& rect )
1199{
1200 QVector< QRgb > colorTable;
1201 if ( colorMap.format() == QwtColorMap::Indexed )
1202 colorTable = colorMap.colorTable256();
1203
1204 QColor c;
1205
1206 const QRect devRect = rect.toAlignedRect();
1207
1208 /*
1209 We paint to a pixmap first to have something scalable for printing
1210 ( f.e. in a Pdf document )
1211 */
1212
1213 QPixmap pixmap( devRect.size() );
1214 pixmap.fill( Qt::transparent );
1215
1216 QPainter pmPainter( &pixmap );
1217 pmPainter.translate( -devRect.x(), -devRect.y() );
1218
1219 if ( orientation == Qt::Horizontal )
1220 {
1221 QwtScaleMap sMap = scaleMap;
1222 sMap.setPaintInterval( rect.left(), rect.right() );
1223
1224 for ( int x = devRect.left(); x <= devRect.right(); x++ )
1225 {
1226 const double value = sMap.invTransform( x );
1227
1228 if ( colorMap.format() == QwtColorMap::RGB )
1229 c.setRgba( colorMap.rgb( interval, value ) );
1230 else
1231 c = colorTable[colorMap.colorIndex( 256, interval, value )];
1232
1233 pmPainter.setPen( c );
1234 pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() );
1235 }
1236 }
1237 else // Vertical
1238 {
1239 QwtScaleMap sMap = scaleMap;
1240 sMap.setPaintInterval( rect.bottom(), rect.top() );
1241
1242 for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
1243 {
1244 const double value = sMap.invTransform( y );
1245
1246 if ( colorMap.format() == QwtColorMap::RGB )
1247 c.setRgba( colorMap.rgb( interval, value ) );
1248 else
1249 c = colorTable[colorMap.colorIndex( 256, interval, value )];
1250
1251 pmPainter.setPen( c );
1252 pmPainter.drawLine( devRect.left(), y, devRect.right(), y );
1253 }
1254 }
1255 pmPainter.end();
1256
1257 drawPixmap( painter, rect, pixmap );
1258}
1259
1260static inline void qwtFillRect( const QWidget* widget, QPainter* painter,
1261 const QRect& rect, const QBrush& brush)
1262{
1263 if ( brush.style() == Qt::TexturePattern )
1264 {
1265 painter->save();
1266
1267 painter->setClipRect( rect );
1268 painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft() );
1269
1270 painter->restore();
1271 }
1272 else if ( brush.gradient() )
1273 {
1274 painter->save();
1275
1276 painter->setClipRect( rect );
1277 painter->fillRect(0, 0, widget->width(),
1278 widget->height(), brush);
1279
1280 painter->restore();
1281 }
1282 else
1283 {
1284 painter->fillRect(rect, brush);
1285 }
1286}
1287
1301void QwtPainter::fillPixmap( const QWidget* widget,
1302 QPixmap& pixmap, const QPoint& offset )
1303{
1304 const QRect rect( offset, pixmap.size() );
1305
1306 QPainter painter( &pixmap );
1307 painter.translate( -offset );
1308
1309 const QBrush autoFillBrush =
1310 widget->palette().brush( widget->backgroundRole() );
1311
1312 if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) )
1313 {
1314 const QBrush bg = widget->palette().brush( QPalette::Window );
1315 qwtFillRect( widget, &painter, rect, bg);
1316 }
1317
1318 if ( widget->autoFillBackground() )
1319 qwtFillRect( widget, &painter, rect, autoFillBrush);
1320
1321 if ( widget->testAttribute(Qt::WA_StyledBackground) )
1322 {
1323 painter.setClipRegion( rect );
1324
1325 QStyleOption opt;
1326 opt.initFrom( widget );
1327 widget->style()->drawPrimitive( QStyle::PE_Widget,
1328 &opt, &painter, widget );
1329 }
1330}
1331
1341void QwtPainter::drawBackgound( QPainter* painter,
1342 const QRectF& rect, const QWidget* widget )
1343{
1344 if ( widget->testAttribute( Qt::WA_StyledBackground ) )
1345 {
1346 QStyleOption opt;
1347 opt.initFrom( widget );
1348 opt.rect = rect.toAlignedRect();
1349
1350 widget->style()->drawPrimitive(
1351 QStyle::PE_Widget, &opt, painter, widget);
1352 }
1353 else
1354 {
1355 const QBrush brush =
1356 widget->palette().brush( widget->backgroundRole() );
1357
1358 painter->fillRect( rect, brush );
1359 }
1360}
1361
1370 const QFontMetrics& fontMetrics, const QString& text )
1371{
1372#if QT_VERSION >= 0x050b00
1373 return fontMetrics.horizontalAdvance( text );
1374#else
1375 return fontMetrics.width( text );
1376#endif
1377
1378}
1379
1388 const QFontMetricsF& fontMetrics, const QString& text )
1389{
1390#if QT_VERSION >= 0x050b00
1391 return fontMetrics.horizontalAdvance( text );
1392#else
1393 return fontMetrics.width( text );
1394#endif
1395}
1396
1405 const QFontMetrics& fontMetrics, QChar ch )
1406{
1407#if QT_VERSION >= 0x050b00
1408 return fontMetrics.horizontalAdvance( ch );
1409#else
1410 return fontMetrics.width( ch );
1411#endif
1412}
1413
1422 const QFontMetricsF& fontMetrics, QChar ch )
1423{
1424#if QT_VERSION >= 0x050b00
1425 return fontMetrics.horizontalAdvance( ch );
1426#else
1427 return fontMetrics.width( ch );
1428#endif
1429}
1430
1440QFont QwtPainter::scaledFont( const QFont& font, const QPaintDevice* paintDevice )
1441{
1442 if ( paintDevice == NULL )
1443 {
1444#if QT_VERSION < 0x060000
1445 paintDevice = QApplication::desktop();
1446#else
1447 class PaintDevice : public QPaintDevice
1448 {
1449 virtual QPaintEngine* paintEngine() const QWT_OVERRIDE
1450 {
1451 return NULL;
1452 }
1453
1454 virtual int metric( PaintDeviceMetric metric ) const QWT_OVERRIDE
1455 {
1456 if ( metric == PdmDpiY )
1457 {
1458 QScreen* screen = QGuiApplication::primaryScreen();
1459 if ( screen )
1460 {
1461 return screen->logicalDotsPerInchY();
1462 }
1463 }
1464
1465 return QPaintDevice::metric( metric );
1466 }
1467 };
1468
1469 static PaintDevice dummyPaintDevice;
1470 paintDevice = &dummyPaintDevice;
1471#endif
1472 }
1473
1474 return QFont( font, const_cast< QPaintDevice* >( paintDevice ) );
1475}
1476
1481qreal QwtPainter::devicePixelRatio( const QPaintDevice* paintDevice )
1482{
1483 qreal pixelRatio = 0.0;
1484
1485#if QT_VERSION >= 0x050100
1486 if ( paintDevice )
1487 {
1488#if QT_VERSION >= 0x050600
1489 pixelRatio = paintDevice->devicePixelRatioF();
1490#else
1491 pixelRatio = paintDevice->devicePixelRatio();
1492#endif
1493 }
1494#else
1495 Q_UNUSED( paintDevice )
1496#endif
1497
1498#if QT_VERSION >= 0x050000
1499 if ( pixelRatio == 0.0 && qApp )
1500 pixelRatio = qApp->devicePixelRatio();
1501#endif
1502
1503 if ( pixelRatio == 0.0 )
1504 pixelRatio = 1.0;
1505
1506 return pixelRatio;
1507}
1508
1515QPixmap QwtPainter::backingStore( QWidget* widget, const QSize& size )
1516{
1517 QPixmap pm;
1518
1519#if QT_VERSION >= 0x050000
1520 const qreal pixelRatio = QwtPainter::devicePixelRatio( widget );
1521
1522 pm = QPixmap( size * pixelRatio );
1523 pm.setDevicePixelRatio( pixelRatio );
1524#else
1525 pm = QPixmap( size );
1526#endif
1527
1528#ifdef Q_WS_X11
1529 if ( widget && isX11GraphicsSystem() )
1530 {
1531 if ( pm.x11Info().screen() != widget->x11Info().screen() )
1532 pm.x11SetScreen( widget->x11Info().screen() );
1533 }
1534#else
1535 Q_UNUSED( widget )
1536#endif
1537
1538 return pm;
1539}
QwtColorMap is used to map values into colors.
virtual uint colorIndex(int numColors, const QwtInterval &interval, double value) const
Map a value of a given interval into a color index.
@ RGB
The map is intended to map into RGB values.
virtual QVector< QRgb > colorTable256() const
virtual QRgb rgb(const QwtInterval &interval, double value) const =0
A class representing an interval.
static void drawEllipse(QPainter *, const QRectF &)
Wrapper for QPainter::drawEllipse()
static void drawPoints(QPainter *, const QPolygon &)
Wrapper for QPainter::drawPoints()
static void setPolylineSplitting(bool)
En/Disable line splitting for the raster paint engine.
static void drawSimpleRichText(QPainter *, const QRectF &, int flags, const QTextDocument &)
static void drawPath(QPainter *, const QPainterPath &)
Wrapper for QPainter::drawPath()
static void drawImage(QPainter *, const QRectF &, const QImage &)
Wrapper for QPainter::drawImage()
static void drawPolygon(QPainter *, const QPolygonF &)
Wrapper for QPainter::drawPolygon()
static void drawRoundFrame(QPainter *, const QRectF &, const QPalette &, int lineWidth, int frameStyle)
static void setRoundingAlignment(bool)
static void drawPolyline(QPainter *, const QPolygonF &)
Wrapper for QPainter::drawPolyline()
static void drawText(QPainter *, qreal x, qreal y, const QString &)
Wrapper for QPainter::drawText()
static bool isAligning(const QPainter *)
static void fillRect(QPainter *, const QRectF &, const QBrush &)
Wrapper for QPainter::fillRect()
static void drawRoundedFrame(QPainter *, const QRectF &, qreal xRadius, qreal yRadius, const QPalette &, int lineWidth, int frameStyle)
static void drawBackgound(QPainter *, const QRectF &, const QWidget *)
static void drawFocusRect(QPainter *, const QWidget *)
Draw a focus rectangle on a widget using its style.
static void drawPoint(QPainter *, const QPoint &)
Wrapper for QPainter::drawPoint()
static void fillPixmap(const QWidget *, QPixmap &, const QPoint &offset=QPoint())
static void drawRect(QPainter *, qreal x, qreal y, qreal w, qreal h)
Wrapper for QPainter::drawRect()
static qreal devicePixelRatio(const QPaintDevice *)
static void drawFrame(QPainter *, const QRectF &rect, const QPalette &palette, QPalette::ColorRole foregroundRole, int lineWidth, int midLineWidth, int frameStyle)
static QPixmap backingStore(QWidget *, const QSize &)
static void drawColorBar(QPainter *, const QwtColorMap &, const QwtInterval &, const QwtScaleMap &, Qt::Orientation, const QRectF &)
static void drawPixmap(QPainter *, const QRectF &, const QPixmap &)
Wrapper for QPainter::drawPixmap()
static QFont scaledFont(const QFont &, const QPaintDevice *=NULL)
static bool isX11GraphicsSystem()
static void drawPie(QPainter *, const QRectF &r, int a, int alen)
Wrapper for QPainter::drawPie()
static int horizontalAdvance(const QFontMetrics &, const QString &)
static void drawLine(QPainter *, qreal x1, qreal y1, qreal x2, qreal y2)
Wrapper for QPainter::drawLine()
A scale map.
void setPaintInterval(double p1, double p2)
Specify the borders of the paint device interval.
double invTransform(double p) const
QWT_EXPORT void clipPolygon(const QRect &, QPolygon &, bool closePolygon=false)
QWT_EXPORT QPolygonF clippedPolygonF(const QRectF &, const QPolygonF &, bool closePolygon=false)
QWT_EXPORT void clipPolygonF(const QRectF &, QPolygonF &, bool closePolygon=false)
QWT_EXPORT QPolygon clippedPolygon(const QRect &, const QPolygon &, bool closePolygon=false)