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

Last change on this file since 8127 was 8127, checked in by stoecker, 2 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.