qwt_painter.cpp 34.6 KB
Newer Older
pixhawk's avatar
pixhawk committed
1
2
3
4
5
6
7
8
9
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

Bryant's avatar
Bryant committed
10
11
12
13
14
#include "qwt_painter.h"
#include "qwt_math.h"
#include "qwt_clipper.h"
#include "qwt_color_map.h"
#include "qwt_scale_map.h"
pixhawk's avatar
pixhawk committed
15
16
#include <qwindowdefs.h>
#include <qwidget.h>
Bryant's avatar
Bryant committed
17
#include <qframe.h>
pixhawk's avatar
pixhawk committed
18
19
20
21
22
23
24
25
26
27
#include <qrect.h>
#include <qpainter.h>
#include <qpalette.h>
#include <qpaintdevice.h>
#include <qpixmap.h>
#include <qstyle.h>
#include <qtextdocument.h>
#include <qabstracttextdocumentlayout.h>
#include <qstyleoption.h>
#include <qpaintengine.h>
Bryant's avatar
Bryant committed
28
29
#include <qapplication.h>
#include <qdesktopwidget.h>
pixhawk's avatar
pixhawk committed
30

Bryant's avatar
Bryant committed
31
32
33
#if QT_VERSION >= 0x050000
#include <qwindow.h>
#endif
pixhawk's avatar
pixhawk committed
34

Bryant's avatar
Bryant committed
35
#if QT_VERSION < 0x050000 
pixhawk's avatar
pixhawk committed
36

Bryant's avatar
Bryant committed
37
38
#ifdef Q_WS_X11
#include <qx11info_x11.h>
pixhawk's avatar
pixhawk committed
39
40
41
42
#endif

#endif

Bryant's avatar
Bryant committed
43
44
bool QwtPainter::d_polylineSplitting = true;
bool QwtPainter::d_roundingAlignment = true;
pixhawk's avatar
pixhawk committed
45

Bryant's avatar
Bryant committed
46
47
static inline bool qwtIsClippingNeeded( 
    const QPainter *painter, QRectF &clipRect )
pixhawk's avatar
pixhawk committed
48
{
Bryant's avatar
Bryant committed
49
50
51
52
53
    bool doClipping = false;
    const QPaintEngine *pe = painter->paintEngine();
    if ( pe && pe->type() == QPaintEngine::SVG )
    {
        // The SVG paint engine ignores any clipping,
pixhawk's avatar
pixhawk committed
54

Bryant's avatar
Bryant committed
55
56
57
58
59
60
        if ( painter->hasClipping() )
        {
            doClipping = true;
            clipRect = painter->clipRegion().boundingRect();
        }
    }
pixhawk's avatar
pixhawk committed
61

Bryant's avatar
Bryant committed
62
    return doClipping;
pixhawk's avatar
pixhawk committed
63
64
}

Bryant's avatar
Bryant committed
65
66
67
template <class T>
static inline void qwtDrawPolyline( QPainter *painter,
    const T *points, int pointCount, bool polylineSplitting )
pixhawk's avatar
pixhawk committed
68
{
Bryant's avatar
Bryant committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    bool doSplit = false;
    if ( polylineSplitting )
    {
        const QPaintEngine *pe = painter->paintEngine();
        if ( pe && pe->type() == QPaintEngine::Raster )
        {
            /*
                The raster paint engine seems to use some algo with O(n*n).
                ( Qt 4.3 is better than Qt 4.2, but remains unacceptable)
                To work around this problem, we have to split the polygon into
                smaller pieces.
             */
            doSplit = true;
        }
    }
pixhawk's avatar
pixhawk committed
84

Bryant's avatar
Bryant committed
85
86
87
88
89
90
91
92
    if ( doSplit )
    {
        const int splitSize = 20;
        for ( int i = 0; i < pointCount; i += splitSize )
        {
            const int n = qMin( splitSize + 1, pointCount - i );
            painter->drawPolyline( points + i, n );
        }
pixhawk's avatar
pixhawk committed
93
    }
Bryant's avatar
Bryant committed
94
95
    else
        painter->drawPolyline( points, pointCount );
pixhawk's avatar
pixhawk committed
96
97
}

Bryant's avatar
Bryant committed
98
static inline void qwtUnscaleFont( QPainter *painter )
pixhawk's avatar
pixhawk committed
99
{
Bryant's avatar
Bryant committed
100
101
    if ( painter->font().pixelSize() >= 0 )
        return;
pixhawk's avatar
pixhawk committed
102

Bryant's avatar
Bryant committed
103
104
105
106
107
108
109
110
111
112
    static QSize screenResolution;
    if ( !screenResolution.isValid() )
    {
        QDesktopWidget *desktop = QApplication::desktop();
        if ( desktop )
        {
            screenResolution.setWidth( desktop->logicalDpiX() );
            screenResolution.setHeight( desktop->logicalDpiY() );
        }
    }
pixhawk's avatar
pixhawk committed
113

Bryant's avatar
Bryant committed
114
115
116
117
118
119
    const QPaintDevice *pd = painter->device();
    if ( pd->logicalDpiX() != screenResolution.width() ||
        pd->logicalDpiY() != screenResolution.height() )
    {
        QFont pixelFont( painter->font(), QApplication::desktop() );
        pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() );
pixhawk's avatar
pixhawk committed
120

Bryant's avatar
Bryant committed
121
122
        painter->setFont( pixelFont );
    }
pixhawk's avatar
pixhawk committed
123
124
125
}

/*!
Bryant's avatar
Bryant committed
126
127
128
  Check is the application is running with the X11 graphics system
  that has some special capabilities that can be used for incremental
  painting to a widget.
pixhawk's avatar
pixhawk committed
129

Bryant's avatar
Bryant committed
130
  \return True, when the graphics system is X11
pixhawk's avatar
pixhawk committed
131
*/
Bryant's avatar
Bryant committed
132
bool QwtPainter::isX11GraphicsSystem()
pixhawk's avatar
pixhawk committed
133
{
Bryant's avatar
Bryant committed
134
135
136
137
138
139
140
141
142
143
    static int onX11 = -1;
    if ( onX11 < 0 )
    {
        QPixmap pm( 1, 1 );
        QPainter painter( &pm );

        onX11 = ( painter.paintEngine()->type() == QPaintEngine::X11 ) ? 1 : 0;
    }

    return onX11 == 1;
pixhawk's avatar
pixhawk committed
144
145
}

146
/*!
Bryant's avatar
Bryant committed
147
148
149
150
151
152
153
154
155
156
157
158
  Check if the painter is using a paint engine, that aligns
  coordinates to integers. Today these are all paint engines
  beside QPaintEngine::Pdf and QPaintEngine::SVG.

  If we have an integer based paint engine it is also
  checked if the painter has a transformation matrix,
  that rotates or scales.

  \param  painter Painter
  \return true, when the painter is aligning

  \sa setRoundingAlignment()
pixhawk's avatar
pixhawk committed
159
*/
Bryant's avatar
Bryant committed
160
bool QwtPainter::isAligning( QPainter *painter )
pixhawk's avatar
pixhawk committed
161
{
Bryant's avatar
Bryant committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
    if ( painter && painter->isActive() )
    {
        switch ( painter->paintEngine()->type() )
        {
            case QPaintEngine::Pdf:
            case QPaintEngine::SVG:
                return false;

            default:;
        }

        const QTransform tr = painter->transform();
        if ( tr.isRotating() || tr.isScaling() )
        {
            // we might have to check translations too
            return false;
        }
    }

    return true;
pixhawk's avatar
pixhawk committed
182
183
}

184
/*!
Bryant's avatar
Bryant committed
185
186
187
188
189
190
191
192
193
  Enable whether coordinates should be rounded, before they are painted
  to a paint engine that floors to integer values. For other paint engines
  this ( PDF, SVG ), this flag has no effect.
  QwtPainter stores this flag only, the rounding itself is done in 
  the painting code ( f.e the plot items ).

  The default setting is true. 

  \sa roundingAlignment(), isAligning()
pixhawk's avatar
pixhawk committed
194
*/
Bryant's avatar
Bryant committed
195
void QwtPainter::setRoundingAlignment( bool enable )
pixhawk's avatar
pixhawk committed
196
{
Bryant's avatar
Bryant committed
197
    d_roundingAlignment = enable;
pixhawk's avatar
pixhawk committed
198
199
200
}

/*!
Bryant's avatar
Bryant committed
201
202
203
204
205
206
207
208
209
  \brief En/Disable line splitting for the raster paint engine

  In some Qt versions the raster paint engine paints polylines of many points
  much faster when they are split in smaller chunks: f.e all supported Qt versions
  >= Qt 5.0 when drawing an antialiased polyline with a pen width >=2.

  The default setting is true.

  \sa polylineSplitting()
pixhawk's avatar
pixhawk committed
210
*/
Bryant's avatar
Bryant committed
211
void QwtPainter::setPolylineSplitting( bool enable )
pixhawk's avatar
pixhawk committed
212
{
Bryant's avatar
Bryant committed
213
    d_polylineSplitting = enable;
pixhawk's avatar
pixhawk committed
214
215
}

Bryant's avatar
Bryant committed
216
217
//! Wrapper for QPainter::drawPath()
void QwtPainter::drawPath( QPainter *painter, const QPainterPath &path )
pixhawk's avatar
pixhawk committed
218
{
Bryant's avatar
Bryant committed
219
    painter->drawPath( path );
pixhawk's avatar
pixhawk committed
220
221
}

Bryant's avatar
Bryant committed
222
223
//! Wrapper for QPainter::drawRect()
void QwtPainter::drawRect( QPainter *painter, double x, double y, double w, double h )
pixhawk's avatar
pixhawk committed
224
{
Bryant's avatar
Bryant committed
225
    drawRect( painter, QRectF( x, y, w, h ) );
pixhawk's avatar
pixhawk committed
226
227
}

Bryant's avatar
Bryant committed
228
229
//! Wrapper for QPainter::drawRect()
void QwtPainter::drawRect( QPainter *painter, const QRectF &rect )
pixhawk's avatar
pixhawk committed
230
{
Bryant's avatar
Bryant committed
231
    const QRectF r = rect;
pixhawk's avatar
pixhawk committed
232

Bryant's avatar
Bryant committed
233
234
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
235
236

    if ( deviceClipping )
Bryant's avatar
Bryant committed
237
238
    {
        if ( !clipRect.intersects( r ) )
pixhawk's avatar
pixhawk committed
239
240
            return;

Bryant's avatar
Bryant committed
241
242
243
        if ( !clipRect.contains( r ) )
        {
            fillRect( painter, r & clipRect, painter->brush() );
pixhawk's avatar
pixhawk committed
244
245

            painter->save();
Bryant's avatar
Bryant committed
246
247
            painter->setBrush( Qt::NoBrush );
            drawPolyline( painter, QPolygonF( r ) );
pixhawk's avatar
pixhawk committed
248
249
250
251
252
253
            painter->restore();

            return;
        }
    }

Bryant's avatar
Bryant committed
254
    painter->drawRect( r );
pixhawk's avatar
pixhawk committed
255
256
}

Bryant's avatar
Bryant committed
257
258
259
//! Wrapper for QPainter::fillRect()
void QwtPainter::fillRect( QPainter *painter,
    const QRectF &rect, const QBrush &brush )
pixhawk's avatar
pixhawk committed
260
261
262
263
{
    if ( !rect.isValid() )
        return;

Bryant's avatar
Bryant committed
264
265
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
266
267

    /*
Bryant's avatar
Bryant committed
268
269
      Performance of Qt4 is horrible for a non trivial brush. Without
      clipping expect minutes or hours for repainting large rectangles
pixhawk's avatar
pixhawk committed
270
271
272
      (might result from zooming)
    */

Bryant's avatar
Bryant committed
273
274
275
276
277
    if ( deviceClipping )
        clipRect &= painter->window();
    else
        clipRect = painter->window();

pixhawk's avatar
pixhawk committed
278
279
280
    if ( painter->hasClipping() )
        clipRect &= painter->clipRegion().boundingRect();

Bryant's avatar
Bryant committed
281
282
283
    QRectF r = rect;
    if ( deviceClipping )
        r = r.intersected( clipRect );
pixhawk's avatar
pixhawk committed
284
285

    if ( r.isValid() )
Bryant's avatar
Bryant committed
286
        painter->fillRect( r, brush );
pixhawk's avatar
pixhawk committed
287
288
}

Bryant's avatar
Bryant committed
289
290
291
//! Wrapper for QPainter::drawPie()
void QwtPainter::drawPie( QPainter *painter, const QRectF &rect,
    int a, int alen )
pixhawk's avatar
pixhawk committed
292
{
Bryant's avatar
Bryant committed
293
294
295
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    if ( deviceClipping && !clipRect.contains( rect ) )
pixhawk's avatar
pixhawk committed
296
297
        return;

Bryant's avatar
Bryant committed
298
    painter->drawPie( rect, a, alen );
pixhawk's avatar
pixhawk committed
299
300
}

Bryant's avatar
Bryant committed
301
302
//! Wrapper for QPainter::drawEllipse()
void QwtPainter::drawEllipse( QPainter *painter, const QRectF &rect )
pixhawk's avatar
pixhawk committed
303
{
Bryant's avatar
Bryant committed
304
305
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
306

Bryant's avatar
Bryant committed
307
    if ( deviceClipping && !clipRect.contains( rect ) )
pixhawk's avatar
pixhawk committed
308
309
        return;

Bryant's avatar
Bryant committed
310
    painter->drawEllipse( rect );
pixhawk's avatar
pixhawk committed
311
312
}

Bryant's avatar
Bryant committed
313
314
315
//! Wrapper for QPainter::drawText()
void QwtPainter::drawText( QPainter *painter, double x, double y,
        const QString &text )
pixhawk's avatar
pixhawk committed
316
{
Bryant's avatar
Bryant committed
317
    drawText( painter, QPointF( x, y ), text );
pixhawk's avatar
pixhawk committed
318
319
}

Bryant's avatar
Bryant committed
320
321
322
//! Wrapper for QPainter::drawText()
void QwtPainter::drawText( QPainter *painter, const QPointF &pos,
        const QString &text )
pixhawk's avatar
pixhawk committed
323
{
Bryant's avatar
Bryant committed
324
325
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
326

Bryant's avatar
Bryant committed
327
    if ( deviceClipping && !clipRect.contains( pos ) )
pixhawk's avatar
pixhawk committed
328
329
        return;

Bryant's avatar
Bryant committed
330
331
332
333
334

    painter->save();
    qwtUnscaleFont( painter );
    painter->drawText( pos, text );
    painter->restore();
pixhawk's avatar
pixhawk committed
335
336
}

Bryant's avatar
Bryant committed
337
338
339
340
//! Wrapper for QPainter::drawText()
void QwtPainter::drawText( QPainter *painter,
    double x, double y, double w, double h,
    int flags, const QString &text )
pixhawk's avatar
pixhawk committed
341
{
Bryant's avatar
Bryant committed
342
    drawText( painter, QRectF( x, y, w, h ), flags, text );
pixhawk's avatar
pixhawk committed
343
344
}

Bryant's avatar
Bryant committed
345
346
347
348
349
350
351
352
//! Wrapper for QPainter::drawText()
void QwtPainter::drawText( QPainter *painter, const QRectF &rect,
        int flags, const QString &text )
{
    painter->save();
    qwtUnscaleFont( painter );
    painter->drawText( rect, flags, text );
    painter->restore();
pixhawk's avatar
pixhawk committed
353
354
355
356
357
}

#ifndef QT_NO_RICHTEXT

/*!
Bryant's avatar
Bryant committed
358
  Draw a text document into a rectangle
pixhawk's avatar
pixhawk committed
359

Bryant's avatar
Bryant committed
360
361
362
363
364
365
366
  \param painter Painter
  \param rect Traget rectangle
  \param flags Alignments/Text flags, see QPainter::drawText()
  \param text Text document
*/
void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect,
    int flags, const QTextDocument &text )
pixhawk's avatar
pixhawk committed
367
{
Bryant's avatar
Bryant committed
368
    QTextDocument *txt = text.clone();
pixhawk's avatar
pixhawk committed
369

Bryant's avatar
Bryant committed
370
    painter->save();
pixhawk's avatar
pixhawk committed
371

Bryant's avatar
Bryant committed
372
373
    painter->setFont( txt->defaultFont() );
    qwtUnscaleFont( painter );
pixhawk's avatar
pixhawk committed
374

Bryant's avatar
Bryant committed
375
376
    txt->setDefaultFont( painter->font() );
    txt->setPageSize( QSizeF( rect.width(), QWIDGETSIZE_MAX ) );
pixhawk's avatar
pixhawk committed
377

Bryant's avatar
Bryant committed
378
    QAbstractTextDocumentLayout* layout = txt->documentLayout();
pixhawk's avatar
pixhawk committed
379

Bryant's avatar
Bryant committed
380
381
382
383
384
385
    const double height = layout->documentSize().height();
    double y = rect.y();
    if ( flags & Qt::AlignBottom )
        y += ( rect.height() - height );
    else if ( flags & Qt::AlignVCenter )
        y += ( rect.height() - height ) / 2;
pixhawk's avatar
pixhawk committed
386
387

    QAbstractTextDocumentLayout::PaintContext context;
Bryant's avatar
Bryant committed
388
    context.palette.setColor( QPalette::Text, painter->pen().color() );
pixhawk's avatar
pixhawk committed
389

Bryant's avatar
Bryant committed
390
391
    painter->translate( rect.x(), y );
    layout->draw( painter, context );
pixhawk's avatar
pixhawk committed
392
393

    painter->restore();
Bryant's avatar
Bryant committed
394
    delete txt;
pixhawk's avatar
pixhawk committed
395
396
397
398
399
}

#endif // !QT_NO_RICHTEXT


Bryant's avatar
Bryant committed
400
401
402
//! Wrapper for QPainter::drawLine()
void QwtPainter::drawLine( QPainter *painter,
    const QPointF &p1, const QPointF &p2 )
pixhawk's avatar
pixhawk committed
403
{
Bryant's avatar
Bryant committed
404
405
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
406

407
    if ( deviceClipping &&
Bryant's avatar
Bryant committed
408
409
410
411
412
413
        !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) )
    {
        QPolygonF polygon;
        polygon += p1;
        polygon += p2;
        drawPolyline( painter, polygon );
pixhawk's avatar
pixhawk committed
414
415
416
        return;
    }

Bryant's avatar
Bryant committed
417
418
    painter->drawLine( p1, p2 );
}
pixhawk's avatar
pixhawk committed
419

Bryant's avatar
Bryant committed
420
421
422
423
424
//! Wrapper for QPainter::drawPolygon()
void QwtPainter::drawPolygon( QPainter *painter, const QPolygonF &polygon )
{
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
425

Bryant's avatar
Bryant committed
426
427
428
    QPolygonF cpa = polygon;
    if ( deviceClipping )
        cpa = QwtClipper::clipPolygonF( clipRect, polygon );
pixhawk's avatar
pixhawk committed
429

Bryant's avatar
Bryant committed
430
    painter->drawPolygon( cpa );
pixhawk's avatar
pixhawk committed
431
432
}

Bryant's avatar
Bryant committed
433
434
//! Wrapper for QPainter::drawPolyline()
void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon )
pixhawk's avatar
pixhawk committed
435
{
Bryant's avatar
Bryant committed
436
437
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
438

Bryant's avatar
Bryant committed
439
440
441
442
443
444
    QPolygonF cpa = polygon;
    if ( deviceClipping )
        cpa = QwtClipper::clipPolygonF( clipRect, cpa );

    qwtDrawPolyline<QPointF>( painter,
        cpa.constData(), cpa.size(), d_polylineSplitting );
pixhawk's avatar
pixhawk committed
445
446
}

Bryant's avatar
Bryant committed
447
448
449
//! Wrapper for QPainter::drawPolyline()
void QwtPainter::drawPolyline( QPainter *painter,
    const QPointF *points, int pointCount )
pixhawk's avatar
pixhawk committed
450
{
Bryant's avatar
Bryant committed
451
452
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
453
454

    if ( deviceClipping )
Bryant's avatar
Bryant committed
455
456
457
    {
        QPolygonF polygon( pointCount );
        ::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) );
pixhawk's avatar
pixhawk committed
458

Bryant's avatar
Bryant committed
459
460
461
        polygon = QwtClipper::clipPolygonF( clipRect, polygon );
        qwtDrawPolyline<QPointF>( painter,
            polygon.constData(), polygon.size(), d_polylineSplitting );
pixhawk's avatar
pixhawk committed
462
    }
Bryant's avatar
Bryant committed
463
464
465
466
467
    else
    {
        qwtDrawPolyline<QPointF>( painter, points, pointCount, d_polylineSplitting );
    }
}
pixhawk's avatar
pixhawk committed
468

Bryant's avatar
Bryant committed
469
470
471
472
473
//! Wrapper for QPainter::drawPolygon()
void QwtPainter::drawPolygon( QPainter *painter, const QPolygon &polygon )
{
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
474

Bryant's avatar
Bryant committed
475
476
477
478
479
    QPolygon cpa = polygon;
    if ( deviceClipping )
        cpa = QwtClipper::clipPolygon( clipRect, polygon );

    painter->drawPolygon( cpa );
pixhawk's avatar
pixhawk committed
480
481
}

Bryant's avatar
Bryant committed
482
483
484
485
486
487
488
489
490
491
492
493
494
//! Wrapper for QPainter::drawPolyline()
void QwtPainter::drawPolyline( QPainter *painter, const QPolygon &polygon )
{
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );

    QPolygon cpa = polygon;
    if ( deviceClipping )
        cpa = QwtClipper::clipPolygon( clipRect, cpa );

    qwtDrawPolyline<QPoint>( painter,
        cpa.constData(), cpa.size(), d_polylineSplitting );
}
pixhawk's avatar
pixhawk committed
495

Bryant's avatar
Bryant committed
496
497
498
//! Wrapper for QPainter::drawPolyline()
void QwtPainter::drawPolyline( QPainter *painter,
    const QPoint *points, int pointCount )
pixhawk's avatar
pixhawk committed
499
{
Bryant's avatar
Bryant committed
500
501
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
502

Bryant's avatar
Bryant committed
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
    if ( deviceClipping )
    {
        QPolygon polygon( pointCount );
        ::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) );

        polygon = QwtClipper::clipPolygon( clipRect, polygon );
        qwtDrawPolyline<QPoint>( painter,
            polygon.constData(), polygon.size(), d_polylineSplitting );
    }
    else
        qwtDrawPolyline<QPoint>( painter, points, pointCount, d_polylineSplitting );
}

//! Wrapper for QPainter::drawPoint()
void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos )
{
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
521

Bryant's avatar
Bryant committed
522
    if ( deviceClipping && !clipRect.contains( pos ) )
pixhawk's avatar
pixhawk committed
523
524
        return;

Bryant's avatar
Bryant committed
525
    painter->drawPoint( pos );
pixhawk's avatar
pixhawk committed
526
527
}

Bryant's avatar
Bryant committed
528
529
//! Wrapper for QPainter::drawPoint()
void QwtPainter::drawPoint( QPainter *painter, const QPoint &pos )
pixhawk's avatar
pixhawk committed
530
{
Bryant's avatar
Bryant committed
531
532
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
pixhawk's avatar
pixhawk committed
533

Bryant's avatar
Bryant committed
534
535
536
537
538
539
540
541
542
543
544
545
546
    if ( deviceClipping )
    {
        const int minX = qCeil( clipRect.left() );
        const int maxX = qFloor( clipRect.right() );
        const int minY = qCeil( clipRect.top() );
        const int maxY = qFloor( clipRect.bottom() );

        if ( pos.x() < minX || pos.x() > maxX 
            || pos.y() < minY || pos.y() > maxY )
        {
            return;
        }
    }
547

Bryant's avatar
Bryant committed
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
    painter->drawPoint( pos );
}

//! Wrapper for QPainter::drawPoints()
void QwtPainter::drawPoints( QPainter *painter, 
    const QPoint *points, int pointCount )
{
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );

    if ( deviceClipping )
    {
        const int minX = qCeil( clipRect.left() );
        const int maxX = qFloor( clipRect.right() );
        const int minY = qCeil( clipRect.top() );
        const int maxY = qFloor( clipRect.bottom() );
564

Bryant's avatar
Bryant committed
565
        const QRect r( minX, minY, maxX - minX, maxY - minY );
pixhawk's avatar
pixhawk committed
566

Bryant's avatar
Bryant committed
567
568
        QPolygon clippedPolygon( pointCount );
        QPoint *clippedData = clippedPolygon.data();
pixhawk's avatar
pixhawk committed
569

Bryant's avatar
Bryant committed
570
571
572
573
574
575
576
577
578
579
580
        int numClippedPoints = 0;
        for ( int i = 0; i < pointCount; i++ )
        {
            if ( r.contains( points[i] ) )
                clippedData[ numClippedPoints++ ] = points[i];
        }
        painter->drawPoints( clippedData, numClippedPoints );
    }
    else
    {
        painter->drawPoints( points, pointCount );
pixhawk's avatar
pixhawk committed
581
582
583
    }
}

Bryant's avatar
Bryant committed
584
585
586
//! Wrapper for QPainter::drawPoints()
void QwtPainter::drawPoints( QPainter *painter, 
    const QPointF *points, int pointCount )
pixhawk's avatar
pixhawk committed
587
{
Bryant's avatar
Bryant committed
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
    QRectF clipRect;
    const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );

    if ( deviceClipping )
    {
        QPolygonF clippedPolygon( pointCount );
        QPointF *clippedData = clippedPolygon.data();

        int numClippedPoints = 0;
        for ( int i = 0; i < pointCount; i++ )
        {
            if ( clipRect.contains( points[i] ) )
                clippedData[ numClippedPoints++ ] = points[i];
        }
        painter->drawPoints( clippedData, numClippedPoints );
    }
    else
    {
        painter->drawPoints( points, pointCount );
    }
pixhawk's avatar
pixhawk committed
608
609
}

Bryant's avatar
Bryant committed
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
//! Wrapper for QPainter::drawImage()
void QwtPainter::drawImage( QPainter *painter,
    const QRectF &rect, const QImage &image )
{
    const QRect alignedRect = rect.toAlignedRect();

    if ( alignedRect != rect )
    {
        const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );

        painter->save();
        painter->setClipRect( clipRect, Qt::IntersectClip );
        painter->drawImage( alignedRect, image );
        painter->restore();
    }
    else
    {
        painter->drawImage( alignedRect, image );
    }
}

//! Wrapper for QPainter::drawPixmap()
void QwtPainter::drawPixmap( QPainter *painter,
    const QRectF &rect, const QPixmap &pixmap )
{
    const QRect alignedRect = rect.toAlignedRect();

    if ( alignedRect != rect )
    {
        const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );

        painter->save();
        painter->setClipRect( clipRect, Qt::IntersectClip );
        painter->drawPixmap( alignedRect, pixmap );
        painter->restore();
    }
    else
    {
        painter->drawPixmap( alignedRect, pixmap );
    }
}

//! Draw a focus rectangle on a widget using its style.
void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget )
{
    drawFocusRect( painter, widget, widget->rect() );
}

//! Draw a focus rectangle on a widget using its style.
void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget,
    const QRect &rect )
pixhawk's avatar
pixhawk committed
661
{
662
    QStyleOptionFocusRect opt;
Bryant's avatar
Bryant committed
663
    opt.init( widget );
664
665
    opt.rect = rect;
    opt.state |= QStyle::State_HasFocus;
pixhawk's avatar
pixhawk committed
666

Bryant's avatar
Bryant committed
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
    widget->style()->drawPrimitive( QStyle::PE_FrameFocusRect,
        &opt, painter, widget );
}

/*!
  Draw a round frame 

  \param painter Painter
  \param rect Frame rectangle
  \param palette QPalette::WindowText is used for plain borders
                 QPalette::Dark and QPalette::Light for raised
                 or sunken borders
  \param lineWidth Line width
  \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
*/
void QwtPainter::drawRoundFrame( QPainter *painter,
    const QRectF &rect, const QPalette &palette, 
    int lineWidth, int frameStyle )
{
    enum Style
    {
        Plain,
        Sunken,
        Raised
    };

    Style style = Plain;
    if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
        style = Sunken;
    else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
        style = Raised;

    const double lw2 = 0.5 * lineWidth;
    QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );

    QBrush brush;

    if ( style != Plain )
    {
        QColor c1 = palette.color( QPalette::Light );
        QColor c2 = palette.color( QPalette::Dark );

        if ( style == Sunken )
            qSwap( c1, c2 );

        QLinearGradient gradient( r.topLeft(), r.bottomRight() );
        gradient.setColorAt( 0.0, c1 );
#if 0
        gradient.setColorAt( 0.3, c1 );
        gradient.setColorAt( 0.7, c2 );
pixhawk's avatar
pixhawk committed
717
#endif
Bryant's avatar
Bryant committed
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
        gradient.setColorAt( 1.0, c2 );

        brush = QBrush( gradient );
    }
    else // Plain
    {
        brush = palette.brush( QPalette::WindowText );
    }

    painter->save();

    painter->setPen( QPen( brush, lineWidth ) );
    painter->setBrush( Qt::NoBrush );

    painter->drawEllipse( r );
pixhawk's avatar
pixhawk committed
733

Bryant's avatar
Bryant committed
734
    painter->restore();
pixhawk's avatar
pixhawk committed
735
736
}

Bryant's avatar
Bryant committed
737
738
739
740
741
742
743
744
745
746
747
748
749
750
/*!
  Draw a rectangular frame

  \param painter Painter
  \param rect Frame rectangle
  \param palette Palette
  \param foregroundRole Foreground role used for QFrame::Plain
  \param frameWidth Frame width
  \param midLineWidth Used for QFrame::Box
  \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
*/
void QwtPainter::drawFrame( QPainter *painter, const QRectF &rect,
    const QPalette &palette, QPalette::ColorRole foregroundRole,
    int frameWidth, int midLineWidth, int frameStyle )
pixhawk's avatar
pixhawk committed
751
{
Bryant's avatar
Bryant committed
752
753
    if ( frameWidth <= 0 || rect.isEmpty() )
        return;
pixhawk's avatar
pixhawk committed
754

Bryant's avatar
Bryant committed
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
    const int shadow = frameStyle & QFrame::Shadow_Mask;

    painter->save();

    if ( shadow == QFrame::Plain )
    {
        const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
        const QRectF innerRect = outerRect.adjusted( 
            frameWidth, frameWidth, -frameWidth, -frameWidth );

        QPainterPath path;
        path.addRect( outerRect );
        path.addRect( innerRect );

        painter->setPen( Qt::NoPen );
        painter->setBrush( palette.color( foregroundRole ) );

        painter->drawPath( path );
pixhawk's avatar
pixhawk committed
773
    }
Bryant's avatar
Bryant committed
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
    else
    {
        const int shape = frameStyle & QFrame::Shape_Mask;

        if ( shape == QFrame::Box )
        {
            const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
            const QRectF midRect1 = outerRect.adjusted( 
                frameWidth, frameWidth, -frameWidth, -frameWidth );
            const QRectF midRect2 = midRect1.adjusted( 
                midLineWidth, midLineWidth, -midLineWidth, -midLineWidth );

            const QRectF innerRect = midRect2.adjusted( 
                frameWidth, frameWidth, -frameWidth, -frameWidth );

            QPainterPath path1;
            path1.moveTo( outerRect.bottomLeft() );
            path1.lineTo( outerRect.topLeft() );
            path1.lineTo( outerRect.topRight() );
            path1.lineTo( midRect1.topRight() );
            path1.lineTo( midRect1.topLeft() );
            path1.lineTo( midRect1.bottomLeft() );

            QPainterPath path2;
            path2.moveTo( outerRect.bottomLeft() );
            path2.lineTo( outerRect.bottomRight() );
            path2.lineTo( outerRect.topRight() );
            path2.lineTo( midRect1.topRight() );
            path2.lineTo( midRect1.bottomRight() );
            path2.lineTo( midRect1.bottomLeft() );

            QPainterPath path3;
            path3.moveTo( midRect2.bottomLeft() );
            path3.lineTo( midRect2.topLeft() );
            path3.lineTo( midRect2.topRight() );
            path3.lineTo( innerRect.topRight() );
            path3.lineTo( innerRect.topLeft() );
            path3.lineTo( innerRect.bottomLeft() );

            QPainterPath path4;
            path4.moveTo( midRect2.bottomLeft() );
            path4.lineTo( midRect2.bottomRight() );
            path4.lineTo( midRect2.topRight() );
            path4.lineTo( innerRect.topRight() );
            path4.lineTo( innerRect.bottomRight() );
            path4.lineTo( innerRect.bottomLeft() );

            QPainterPath path5;
            path5.addRect( midRect1 );
            path5.addRect( midRect2 );

            painter->setPen( Qt::NoPen );

            QBrush brush1 = palette.dark().color();
            QBrush brush2 = palette.light().color();

            if ( shadow == QFrame::Raised )
                qSwap( brush1, brush2 );

            painter->setBrush( brush1 );
            painter->drawPath( path1 );
            painter->drawPath( path4 );

            painter->setBrush( brush2 );
            painter->drawPath( path2 );
            painter->drawPath( path3 );

            painter->setBrush( palette.mid() );
            painter->drawPath( path5 );
        }
#if 0
        // qDrawWinPanel doesn't result in something nice
        // on a scalable document like PDF. Better draw a
        // Panel.

        else if ( shape == QFrame::WinPanel )
        {
            painter->setRenderHint( QPainter::NonCosmeticDefaultPen, true );
            qDrawWinPanel ( painter, rect.toRect(), palette,
                frameStyle & QFrame::Sunken );
        }
        else if ( shape == QFrame::StyledPanel )
        {
        }
pixhawk's avatar
pixhawk committed
858
#endif
Bryant's avatar
Bryant committed
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
        else
        {
            const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
            const QRectF innerRect = outerRect.adjusted( 
                frameWidth - 1.0, frameWidth - 1.0, 
                -( frameWidth - 1.0 ), -( frameWidth - 1.0 ) );

            QPainterPath path1;
            path1.moveTo( outerRect.bottomLeft() );
            path1.lineTo( outerRect.topLeft() );
            path1.lineTo( outerRect.topRight() );
            path1.lineTo( innerRect.topRight() );
            path1.lineTo( innerRect.topLeft() );
            path1.lineTo( innerRect.bottomLeft() );


            QPainterPath path2;
            path2.moveTo( outerRect.bottomLeft() );
            path2.lineTo( outerRect.bottomRight() );
            path2.lineTo( outerRect.topRight() );
            path2.lineTo( innerRect.topRight() );
            path2.lineTo( innerRect.bottomRight() );
            path2.lineTo( innerRect.bottomLeft() );

            painter->setPen( Qt::NoPen );
pixhawk's avatar
pixhawk committed
884

Bryant's avatar
Bryant committed
885
886
            QBrush brush1 = palette.dark().color();
            QBrush brush2 = palette.light().color();
pixhawk's avatar
pixhawk committed
887

Bryant's avatar
Bryant committed
888
889
890
891
892
893
894
895
896
897
898
            if ( shadow == QFrame::Raised )
                qSwap( brush1, brush2 );

            painter->setBrush( brush1 );
            painter->drawPath( path1 );

            painter->setBrush( brush2 );
            painter->drawPath( path2 );
        }

    }
pixhawk's avatar
pixhawk committed
899

Bryant's avatar
Bryant committed
900
    painter->restore();
pixhawk's avatar
pixhawk committed
901
902
}

Bryant's avatar
Bryant committed
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
/*!
  Draw a rectangular frame with rounded borders

  \param painter Painter
  \param rect Frame rectangle
  \param xRadius x-radius of the ellipses defining the corners
  \param yRadius y-radius of the ellipses defining the corners
  \param palette QPalette::WindowText is used for plain borders
                 QPalette::Dark and QPalette::Light for raised
                 or sunken borders
  \param lineWidth Line width
  \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
*/

void QwtPainter::drawRoundedFrame( QPainter *painter, 
    const QRectF &rect, double xRadius, double yRadius, 
    const QPalette &palette, int lineWidth, int frameStyle )
{
    painter->save();
    painter->setRenderHint( QPainter::Antialiasing, true );
    painter->setBrush( Qt::NoBrush );

    double lw2 = lineWidth * 0.5;
    QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );

    QPainterPath path;
    path.addRoundedRect( r, xRadius, yRadius );

    enum Style
    {
        Plain,
        Sunken,
        Raised
    };

    Style style = Plain;
    if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
        style = Sunken;
    else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
        style = Raised;

    if ( style != Plain && path.elementCount() == 17 )
    {
        // move + 4 * ( cubicTo + lineTo )
        QPainterPath pathList[8];
        
        for ( int i = 0; i < 4; i++ )
        {
            const int j = i * 4 + 1;
            
            pathList[ 2 * i ].moveTo(
                path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
            );  
            
            pathList[ 2 * i ].cubicTo(
                path.elementAt(j + 0).x, path.elementAt(j + 0).y,
                path.elementAt(j + 1).x, path.elementAt(j + 1).y,
                path.elementAt(j + 2).x, path.elementAt(j + 2).y );
                
            pathList[ 2 * i + 1 ].moveTo(
                path.elementAt(j + 2).x, path.elementAt(j + 2).y
            );  
            pathList[ 2 * i + 1 ].lineTo(
                path.elementAt(j + 3).x, path.elementAt(j + 3).y
            );  
        }   

        QColor c1( palette.color( QPalette::Dark ) );
        QColor c2( palette.color( QPalette::Light ) );

        if ( style == Raised )
            qSwap( c1, c2 );

        for ( int i = 0; i < 4; i++ )
        {
            QRectF r = pathList[2 * i].controlPointRect();

            QPen arcPen;
            arcPen.setCapStyle( Qt::FlatCap );
            arcPen.setWidth( lineWidth );

            QPen linePen;
            linePen.setCapStyle( Qt::FlatCap );
            linePen.setWidth( lineWidth );

            switch( i )
            {
                case 0:
                {
                    arcPen.setColor( c1 );
                    linePen.setColor( c1 );
                    break;
                }
                case 1:
                {
                    QLinearGradient gradient;
                    gradient.setStart( r.topLeft() );
                    gradient.setFinalStop( r.bottomRight() );
                    gradient.setColorAt( 0.0, c1 );
                    gradient.setColorAt( 1.0, c2 );

                    arcPen.setBrush( gradient );
                    linePen.setColor( c2 );
                    break;
                }
                case 2:
                {
                    arcPen.setColor( c2 );
                    linePen.setColor( c2 );
                    break;
                }
                case 3:
                {
                    QLinearGradient gradient;

                    gradient.setStart( r.bottomRight() );
                    gradient.setFinalStop( r.topLeft() );
                    gradient.setColorAt( 0.0, c2 );
                    gradient.setColorAt( 1.0, c1 );

                    arcPen.setBrush( gradient );
                    linePen.setColor( c1 );
                    break;
                }
            }


            painter->setPen( arcPen );
            painter->drawPath( pathList[ 2 * i] );

            painter->setPen( linePen );
            painter->drawPath( pathList[ 2 * i + 1] );
        }
    }
    else
    {
        QPen pen( palette.color( QPalette::WindowText ), lineWidth );
        painter->setPen( pen );
        painter->drawPath( path );
    }

    painter->restore();
}

/*!
  Draw a color bar into a rectangle

  \param painter Painter
  \param colorMap Color map
  \param interval Value range
  \param scaleMap Scale map
  \param orientation Orientation
  \param rect Traget rectangle
*/
void QwtPainter::drawColorBar( QPainter *painter,
        const QwtColorMap &colorMap, const QwtInterval &interval,
        const QwtScaleMap &scaleMap, Qt::Orientation orientation,
        const QRectF &rect )
pixhawk's avatar
pixhawk committed
1061
1062
1063
{
    QVector<QRgb> colorTable;
    if ( colorMap.format() == QwtColorMap::Indexed )
Bryant's avatar
Bryant committed
1064
        colorTable = colorMap.colorTable( interval );
pixhawk's avatar
pixhawk committed
1065
1066
1067

    QColor c;

Bryant's avatar
Bryant committed
1068
    const QRect devRect = rect.toAlignedRect();
pixhawk's avatar
pixhawk committed
1069
1070
1071
1072
1073

    /*
      We paint to a pixmap first to have something scalable for printing
      ( f.e. in a Pdf document )
     */
1074

Bryant's avatar
Bryant committed
1075
1076
1077
    QPixmap pixmap( devRect.size() );
    QPainter pmPainter( &pixmap );
    pmPainter.translate( -devRect.x(), -devRect.y() );
pixhawk's avatar
pixhawk committed
1078

Bryant's avatar
Bryant committed
1079
1080
    if ( orientation == Qt::Horizontal )
    {
pixhawk's avatar
pixhawk committed
1081
        QwtScaleMap sMap = scaleMap;
Bryant's avatar
Bryant committed
1082
        sMap.setPaintInterval( rect.left(), rect.right() );
pixhawk's avatar
pixhawk committed
1083

Bryant's avatar
Bryant committed
1084
1085
1086
        for ( int x = devRect.left(); x <= devRect.right(); x++ )
        {
            const double value = sMap.invTransform( x );
pixhawk's avatar
pixhawk committed
1087
1088

            if ( colorMap.format() == QwtColorMap::RGB )
Bryant's avatar
Bryant committed
1089
                c.setRgba( colorMap.rgb( interval, value ) );
pixhawk's avatar
pixhawk committed
1090
            else
Bryant's avatar
Bryant committed
1091
                c = colorTable[colorMap.colorIndex( interval, value )];
pixhawk's avatar
pixhawk committed
1092

Bryant's avatar
Bryant committed
1093
1094
            pmPainter.setPen( c );
            pmPainter.drawLine( x, devRect.top(), x, devRect.bottom() );
pixhawk's avatar
pixhawk committed
1095
        }
Bryant's avatar
Bryant committed
1096
1097
1098
    }
    else // Vertical
    {
pixhawk's avatar
pixhawk committed
1099
        QwtScaleMap sMap = scaleMap;
Bryant's avatar
Bryant committed
1100
        sMap.setPaintInterval( rect.bottom(), rect.top() );
pixhawk's avatar
pixhawk committed
1101

Bryant's avatar
Bryant committed
1102
1103
1104
        for ( int y = devRect.top(); y <= devRect.bottom(); y++ )
        {
            const double value = sMap.invTransform( y );
pixhawk's avatar
pixhawk committed
1105
1106

            if ( colorMap.format() == QwtColorMap::RGB )
Bryant's avatar
Bryant committed
1107
                c.setRgb( colorMap.rgb( interval, value ) );
pixhawk's avatar
pixhawk committed
1108
            else
Bryant's avatar
Bryant committed
1109
                c = colorTable[colorMap.colorIndex( interval, value )];
pixhawk's avatar
pixhawk committed
1110

Bryant's avatar
Bryant committed
1111
1112
            pmPainter.setPen( c );
            pmPainter.drawLine( devRect.left(), y, devRect.right(), y );
pixhawk's avatar
pixhawk committed
1113
1114
1115
        }
    }
    pmPainter.end();
Bryant's avatar
Bryant committed
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145

    drawPixmap( painter, rect, pixmap );
}

static inline void qwtFillRect( const QWidget *widget, QPainter *painter, 
    const QRect &rect, const QBrush &brush)
{
    if ( brush.style() == Qt::TexturePattern ) 
    {
        painter->save();

        painter->setClipRect( rect );
        painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());

        painter->restore();
    } 
    else if ( brush.gradient() )
    {
        painter->save();

        painter->setClipRect( rect );
        painter->fillRect(0, 0, widget->width(), 
            widget->height(), brush);

        painter->restore();
    } 
    else 
    {
        painter->fillRect(rect, brush);
    }
pixhawk's avatar
pixhawk committed
1146
}
Bryant's avatar
Bryant committed
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266

/*!
  Fill a pixmap with the content of a widget

  In Qt >= 5.0 QPixmap::fill() is a nop, in Qt 4.x it is buggy
  for backgrounds with gradients. Thus fillPixmap() offers 
  an alternative implementation.

  \param widget Widget
  \param pixmap Pixmap to be filled
  \param offset Offset 

  \sa QPixmap::fill()
 */
void QwtPainter::fillPixmap( const QWidget *widget, 
    QPixmap &pixmap, const QPoint &offset )
{
    const QRect rect( offset, pixmap.size() );

    QPainter painter( &pixmap );
    painter.translate( -offset );

    const QBrush autoFillBrush = 
        widget->palette().brush( widget->backgroundRole() );

    if ( !( widget->autoFillBackground() && autoFillBrush.isOpaque() ) ) 
    {
        const QBrush bg = widget->palette().brush( QPalette::Window );
        qwtFillRect( widget, &painter, rect, bg);
    }

    if ( widget->autoFillBackground() )
        qwtFillRect( widget, &painter, rect, autoFillBrush);

    if ( widget->testAttribute(Qt::WA_StyledBackground) ) 
    {
        painter.setClipRegion( rect );

        QStyleOption opt;
        opt.initFrom( widget );
        widget->style()->drawPrimitive( QStyle::PE_Widget, 
            &opt, &painter, widget );
    }
}

/*!
  Fill rect with the background of a widget

  \param painter Painter
  \param rect Rectangle to be filled
  \param widget Widget

  \sa QStyle::PE_Widget, QWidget::backgroundRole()
 */
void QwtPainter::drawBackgound( QPainter *painter,
    const QRectF &rect, const QWidget *widget )
{
    if ( widget->testAttribute( Qt::WA_StyledBackground ) )
    {
        QStyleOption opt;
        opt.initFrom( widget );
        opt.rect = rect.toAlignedRect();

        widget->style()->drawPrimitive(
            QStyle::PE_Widget, &opt, painter, widget);
    }
    else
    {
        const QBrush brush =
            widget->palette().brush( widget->backgroundRole() );

        painter->fillRect( rect, brush );
    }
}

/*!
  \return A pixmap that can be used as backing store

  \param widget Widget, for which the backinstore is intended
  \param size Size of the pixmap
 */
QPixmap QwtPainter::backingStore( QWidget *widget, const QSize &size )
{
    QPixmap pm;

#define QWT_HIGH_DPI 1

#if QT_VERSION >= 0x050000 && QWT_HIGH_DPI
    qreal pixelRatio = 1.0;

    if ( widget && widget->windowHandle() )
    {
        pixelRatio = widget->windowHandle()->devicePixelRatio();
    }
    else
    {
        if ( qApp )
            pixelRatio = qApp->devicePixelRatio();
    }

    pm = QPixmap( size * pixelRatio );
    pm.setDevicePixelRatio( pixelRatio );
#else
    Q_UNUSED( widget )
    pm = QPixmap( size );
#endif

#if QT_VERSION < 0x050000 
#ifdef Q_WS_X11
    if ( widget && isX11GraphicsSystem() )
    {
        if ( pm.x11Info().screen() != widget->x11Info().screen() )
            pm.x11SetScreen( widget->x11Info().screen() );
    }
#endif
#endif

    return pm;
}