~ubuntu-branches/ubuntu/saucy/goldencheetah/saucy

« back to all changes in this revision

Viewing changes to qwt/src/qwt_plot_canvas.cpp

  • Committer: Package Import Robot
  • Author(s): KURASHIKI Satoru
  • Date: 2013-08-18 07:02:45 UTC
  • mfrom: (4.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20130818070245-zgdvb47e1k3mtgil
Tags: 3.0-3
debian/control: remove needless dependency. (Closes: #719571)

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
 * modify it under the terms of the Qwt License, Version 1.0
8
8
 *****************************************************************************/
9
9
 
10
 
// vim: expandtab
11
 
 
 
10
#include "qwt_plot_canvas.h"
 
11
#include "qwt_painter.h"
 
12
#include "qwt_null_paintdevice.h"
 
13
#include "qwt_math.h"
 
14
#include "qwt_plot.h"
12
15
#include <qpainter.h>
13
16
#include <qstyle.h>
14
 
#if QT_VERSION >= 0x040000
15
17
#include <qstyleoption.h>
16
18
#include <qpaintengine.h>
 
19
#include <qevent.h>
 
20
#include <qbitmap.h>
17
21
#ifdef Q_WS_X11
18
22
#include <qx11info_x11.h>
19
23
#endif
20
 
#endif
21
 
#include <qevent.h>
22
 
#include "qwt_painter.h"
23
 
#include "qwt_math.h"
24
 
#include "qwt_plot.h"
25
 
#include "qwt_paint_buffer.h"
26
 
#include "qwt_plot_canvas.h"
 
24
 
 
25
class QwtStyleSheetRecorder: public QwtNullPaintDevice
 
26
{
 
27
public:
 
28
    QwtStyleSheetRecorder( const QSize &size ):
 
29
        QwtNullPaintDevice( QPaintEngine::AllFeatures )
 
30
    {
 
31
        setSize( size );
 
32
    }
 
33
 
 
34
    virtual void updateState( const QPaintEngineState &state )
 
35
    {
 
36
        if ( state.state() & QPaintEngine::DirtyPen )
 
37
        {
 
38
            d_pen = state.pen();
 
39
        }
 
40
        if ( state.state() & QPaintEngine::DirtyBrush )
 
41
        {
 
42
            d_brush = state.brush();
 
43
        }
 
44
        if ( state.state() & QPaintEngine::DirtyBrushOrigin )
 
45
        {
 
46
            d_origin = state.brushOrigin();
 
47
        }
 
48
    }
 
49
 
 
50
    virtual void drawRects(const QRectF *rects, int count )
 
51
    {
 
52
        for ( int i = 0; i < count; i++ )
 
53
            border.rectList += rects[i];
 
54
    }
 
55
 
 
56
    virtual void drawPath( const QPainterPath &path )
 
57
    {
 
58
        const QRectF rect( QPointF( 0.0, 0.0 ) , size() );
 
59
        if ( path.controlPointRect().contains( rect.center() ) )
 
60
        {
 
61
            setCornerRects( path );
 
62
            alignCornerRects( rect );
 
63
 
 
64
            background.path = path;
 
65
            background.brush = d_brush;
 
66
            background.origin = d_origin;
 
67
        }
 
68
        else
 
69
        {
 
70
            border.pathList += path;
 
71
        }
 
72
    }
 
73
 
 
74
    void setCornerRects( const QPainterPath &path )
 
75
    {
 
76
        QPointF pos( 0.0, 0.0 );
 
77
 
 
78
        for ( int i = 0; i < path.elementCount(); i++ )
 
79
        {
 
80
            QPainterPath::Element el = path.elementAt(i);
 
81
            switch( el.type )
 
82
            {
 
83
                case QPainterPath::MoveToElement:
 
84
                case QPainterPath::LineToElement:
 
85
                {
 
86
                    pos.setX( el.x );
 
87
                    pos.setY( el.y );
 
88
                    break;
 
89
                }
 
90
                case QPainterPath::CurveToElement:
 
91
                {
 
92
                    QRectF r( pos, QPointF( el.x, el.y ) );
 
93
                    clipRects += r.normalized();
 
94
 
 
95
                    pos.setX( el.x );
 
96
                    pos.setY( el.y );
 
97
 
 
98
                    break;
 
99
                }
 
100
                case QPainterPath::CurveToDataElement:
 
101
                {
 
102
                    if ( clipRects.size() > 0 )
 
103
                    {
 
104
                        QRectF r = clipRects.last();
 
105
                        r.setCoords(
 
106
                            qMin( r.left(), el.x ),
 
107
                            qMin( r.top(), el.y ),
 
108
                            qMax( r.right(), el.x ),
 
109
                            qMax( r.bottom(), el.y )
 
110
                        );
 
111
                        clipRects.last() = r.normalized();
 
112
                    }
 
113
                    break;
 
114
                }
 
115
            }
 
116
        }
 
117
    }
 
118
 
 
119
private:
 
120
    void alignCornerRects( const QRectF &rect )
 
121
    {
 
122
        for ( int i = 0; i < clipRects.size(); i++ )
 
123
        {
 
124
            QRectF &r = clipRects[i];
 
125
            if ( r.center().x() < rect.center().x() )
 
126
                r.setLeft( rect.left() );
 
127
            else
 
128
                r.setRight( rect.right() );
 
129
 
 
130
            if ( r.center().y() < rect.center().y() )
 
131
                r.setTop( rect.top() );
 
132
            else
 
133
                r.setBottom( rect.bottom() );
 
134
        }
 
135
    }
 
136
 
 
137
 
 
138
public:
 
139
    QVector<QRectF> clipRects;
 
140
 
 
141
    struct Border
 
142
    {
 
143
        QList<QPainterPath> pathList;
 
144
        QList<QRectF> rectList;
 
145
        QRegion clipRegion;
 
146
    } border;
 
147
 
 
148
    struct Background
 
149
    {
 
150
        QPainterPath path;
 
151
        QBrush brush;
 
152
        QPointF origin;
 
153
    } background;
 
154
 
 
155
private:
 
156
    QPen d_pen;
 
157
    QBrush d_brush;
 
158
    QPointF d_origin;
 
159
};
 
160
 
 
161
static void qwtDrawBackground( QPainter *painter, QWidget *widget )
 
162
{
 
163
    const QBrush &brush =
 
164
        widget->palette().brush( widget->backgroundRole() );
 
165
 
 
166
    if ( brush.style() == Qt::TexturePattern )
 
167
    {
 
168
        QPixmap pm( widget->size() );
 
169
        pm.fill( widget, 0, 0 );
 
170
        painter->drawPixmap( 0, 0, pm );
 
171
    }
 
172
    else if ( brush.gradient() )
 
173
    {
 
174
        QVector<QRect> rects;
 
175
 
 
176
        if ( brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode )
 
177
        {
 
178
            rects += widget->rect();
 
179
        }
 
180
        else
 
181
        {
 
182
            rects = painter->clipRegion().rects();
 
183
        }
 
184
 
 
185
#if 1
 
186
        bool useRaster = false;
 
187
 
 
188
        if ( painter->paintEngine()->type() == QPaintEngine::X11 )
 
189
        {
 
190
            // Qt 4.7.1: gradients on X11 are broken ( subrects +
 
191
            // QGradient::StretchToDeviceMode ) and horrible slow.
 
192
            // As workaround we have to use the raster paintengine.
 
193
            // Even if the QImage -> QPixmap translation is slow
 
194
            // it is three times faster, than using X11 directly
 
195
 
 
196
            useRaster = true;
 
197
        }
 
198
#endif
 
199
        if ( useRaster )
 
200
        {
 
201
            QImage::Format format = QImage::Format_RGB32;
 
202
 
 
203
            const QGradientStops stops = brush.gradient()->stops();
 
204
            for ( int i = 0; i < stops.size(); i++ )
 
205
            {
 
206
                if ( stops[i].second.alpha() != 255 )
 
207
                {
 
208
                    // don't use Format_ARGB32_Premultiplied. It's
 
209
                    // recommended by the Qt docs, but QPainter::drawImage()
 
210
                    // is horrible slow on X11.
 
211
 
 
212
                    format = QImage::Format_ARGB32;
 
213
                    break;
 
214
                }
 
215
            }
 
216
 
 
217
            QImage image( widget->size(), format );
 
218
 
 
219
            QPainter p( &image );
 
220
            p.setPen( Qt::NoPen );
 
221
            p.setBrush( brush );
 
222
 
 
223
            p.drawRects( rects );
 
224
 
 
225
            p.end();
 
226
 
 
227
            painter->drawImage( 0, 0, image );
 
228
        }
 
229
        else
 
230
        {
 
231
            painter->save();
 
232
 
 
233
            painter->setPen( Qt::NoPen );
 
234
            painter->setBrush( brush );
 
235
 
 
236
            painter->drawRects( rects );
 
237
 
 
238
            painter->restore();
 
239
        }
 
240
    }
 
241
    else
 
242
    {
 
243
        painter->save();
 
244
 
 
245
        painter->setPen( Qt::NoPen );
 
246
        painter->setBrush( brush );
 
247
 
 
248
        painter->drawRects( painter->clipRegion().rects() );
 
249
 
 
250
        painter->restore();
 
251
    }
 
252
}
 
253
 
 
254
static inline void qwtRevertPath( QPainterPath &path )
 
255
{
 
256
    if ( path.elementCount() == 4 )
 
257
    {
 
258
        QPainterPath::Element &el0 =
 
259
            const_cast<QPainterPath::Element &>( path.elementAt(0) );
 
260
        QPainterPath::Element &el2 =
 
261
            const_cast<QPainterPath::Element &>( path.elementAt(3) );
 
262
 
 
263
        qSwap( el0.x, el2.x );
 
264
        qSwap( el0.y, el2.y );
 
265
    }
 
266
}
 
267
 
 
268
static QPainterPath qwtCombinePathList( const QRectF &rect,
 
269
    const QList<QPainterPath> &pathList )
 
270
{
 
271
    if ( pathList.isEmpty() )
 
272
        return QPainterPath();
 
273
 
 
274
    QPainterPath ordered[8]; // starting top left
 
275
 
 
276
    for ( int i = 0; i < pathList.size(); i++ )
 
277
    {
 
278
        int index = -1;
 
279
        QPainterPath subPath = pathList[i];
 
280
 
 
281
        const QRectF br = pathList[i].controlPointRect();
 
282
        if ( br.center().x() < rect.center().x() )
 
283
        {
 
284
            if ( br.center().y() < rect.center().y() )
 
285
            {
 
286
                if ( qAbs( br.top() - rect.top() ) <
 
287
                    qAbs( br.left() - rect.left() ) )
 
288
                {
 
289
                    index = 1;
 
290
                }
 
291
                else
 
292
                {
 
293
                    index = 0;
 
294
                }
 
295
            }
 
296
            else
 
297
            {
 
298
                if ( qAbs( br.bottom() - rect.bottom() ) <
 
299
                    qAbs( br.left() - rect.left() ) )
 
300
                {
 
301
                    index = 6;
 
302
                }
 
303
                else
 
304
                {
 
305
                    index = 7;
 
306
                }
 
307
            }
 
308
 
 
309
            if ( subPath.currentPosition().y() > br.center().y() )
 
310
                qwtRevertPath( subPath );
 
311
        }
 
312
        else
 
313
        {
 
314
            if ( br.center().y() < rect.center().y() )
 
315
            {
 
316
                if ( qAbs( br.top() - rect.top() ) <
 
317
                    qAbs( br.right() - rect.right() ) )
 
318
                {
 
319
                    index = 2;
 
320
                }
 
321
                else
 
322
                {
 
323
                    index = 3;
 
324
                }
 
325
            }
 
326
            else
 
327
            {
 
328
                if ( qAbs( br.bottom() - rect.bottom() ) <
 
329
                    qAbs( br.right() - rect.right() ) )
 
330
                {
 
331
                    index = 5;
 
332
                }
 
333
                else
 
334
                {
 
335
                    index = 4;
 
336
                }
 
337
            }
 
338
            if ( subPath.currentPosition().y() < br.center().y() )
 
339
                qwtRevertPath( subPath );
 
340
        }
 
341
        ordered[index] = subPath;
 
342
    }
 
343
 
 
344
    for ( int i = 0; i < 4; i++ )
 
345
    {
 
346
        if ( ordered[ 2 * i].isEmpty() != ordered[2 * i + 1].isEmpty() )
 
347
        {
 
348
            // we don't accept incomplete rounded borders
 
349
            return QPainterPath();
 
350
        }
 
351
    }
 
352
 
 
353
 
 
354
    const QPolygonF corners( rect );
 
355
 
 
356
    QPainterPath path;
 
357
    //path.moveTo( rect.topLeft() );
 
358
 
 
359
    for ( int i = 0; i < 4; i++ )
 
360
    {
 
361
        if ( ordered[2 * i].isEmpty() )
 
362
        {
 
363
            path.lineTo( corners[i] );
 
364
        }
 
365
        else
 
366
        {
 
367
            path.connectPath( ordered[2 * i] );
 
368
            path.connectPath( ordered[2 * i + 1] );
 
369
        }
 
370
    }
 
371
 
 
372
    path.closeSubpath();
 
373
 
 
374
#if 0
 
375
    return path.simplified();
 
376
#else
 
377
    return path;
 
378
#endif
 
379
}
 
380
 
 
381
static inline void qwtDrawStyledBackground(
 
382
    QWidget *w, QPainter *painter )
 
383
{
 
384
    QStyleOption opt;
 
385
    opt.initFrom(w);
 
386
    w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w);
 
387
}
 
388
 
 
389
static QWidget *qwtBackgroundWidget( QWidget *w )
 
390
{
 
391
    if ( w->parentWidget() == NULL )
 
392
        return w;
 
393
 
 
394
    if ( w->autoFillBackground() )
 
395
    {
 
396
        const QBrush brush = w->palette().brush( w->backgroundRole() );
 
397
        if ( brush.color().alpha() > 0 )
 
398
            return w;
 
399
    }
 
400
 
 
401
    if ( w->testAttribute( Qt::WA_StyledBackground ) )
 
402
    {
 
403
        QImage image( 1, 1, QImage::Format_ARGB32 );
 
404
        image.fill( Qt::transparent );
 
405
 
 
406
        QPainter painter( &image );
 
407
        painter.translate( -w->rect().center() );
 
408
        qwtDrawStyledBackground( w, &painter );
 
409
        painter.end();
 
410
 
 
411
        if ( qAlpha( image.pixel( 0, 0 ) ) != 0 )
 
412
            return w;
 
413
    }
 
414
 
 
415
    return qwtBackgroundWidget( w->parentWidget() );
 
416
}
 
417
 
 
418
static void qwtFillBackground( QPainter *painter,
 
419
    QWidget *widget, const QVector<QRectF> &fillRects )
 
420
{
 
421
    if ( fillRects.isEmpty() )
 
422
        return;
 
423
 
 
424
    QRegion clipRegion;
 
425
    if ( painter->hasClipping() )
 
426
        clipRegion = painter->transform().map( painter->clipRegion() );
 
427
    else
 
428
        clipRegion = widget->contentsRect();
 
429
 
 
430
    // Try to find out which widget fills
 
431
    // the unfilled areas of the styled background
 
432
 
 
433
    QWidget *bgWidget = qwtBackgroundWidget( widget->parentWidget() );
 
434
 
 
435
    for ( int i = 0; i < fillRects.size(); i++ )
 
436
    {
 
437
        const QRect rect = fillRects[i].toAlignedRect();
 
438
        if ( clipRegion.intersects( rect ) )
 
439
        {
 
440
            QPixmap pm( rect.size() );
 
441
            pm.fill( bgWidget, widget->mapTo( bgWidget, rect.topLeft() ) );
 
442
            painter->drawPixmap( rect, pm );
 
443
        }
 
444
    }
 
445
}
 
446
 
 
447
static void qwtFillBackground( QPainter *painter, QwtPlotCanvas *canvas )
 
448
{
 
449
    QVector<QRectF> rects;
 
450
 
 
451
    if ( canvas->testAttribute( Qt::WA_StyledBackground ) )
 
452
    {
 
453
        QwtStyleSheetRecorder recorder( canvas->size() );
 
454
 
 
455
        QPainter p( &recorder );
 
456
        qwtDrawStyledBackground( canvas, &p );
 
457
        p.end();
 
458
 
 
459
        if ( recorder.background.brush.isOpaque() )
 
460
            rects = recorder.clipRects;
 
461
        else
 
462
            rects += canvas->rect();
 
463
    }
 
464
    else
 
465
    {
 
466
        const QRectF r = canvas->rect();
 
467
        const double radius = canvas->borderRadius();
 
468
        if ( radius > 0.0 )
 
469
        {
 
470
            QSize sz( radius, radius );
 
471
 
 
472
            rects += QRectF( r.topLeft(), sz );
 
473
            rects += QRectF( r.topRight() - QPointF( radius, 0 ), sz );
 
474
            rects += QRectF( r.bottomRight() - QPointF( radius, radius ), sz );
 
475
            rects += QRectF( r.bottomLeft() - QPointF( 0, radius ), sz );
 
476
        }
 
477
    }
 
478
 
 
479
    qwtFillBackground( painter, canvas, rects);
 
480
}
 
481
 
27
482
 
28
483
class QwtPlotCanvas::PrivateData
29
484
{
30
485
public:
31
486
    PrivateData():
32
 
        focusIndicator(NoFocusIndicator),
33
 
        paintAttributes(0),
34
 
        cache(NULL)
 
487
        focusIndicator( NoFocusIndicator ),
 
488
        borderRadius( 0 ),
 
489
        paintAttributes( 0 ),
 
490
        backingStore( NULL )
35
491
    {
 
492
        styleSheet.hasBorder = false;
36
493
    }
37
494
 
38
495
    ~PrivateData()
39
496
    {
40
 
        delete cache;
 
497
        delete backingStore;
41
498
    }
42
499
 
43
500
    FocusIndicator focusIndicator;
44
 
    int paintAttributes;
45
 
    QPixmap *cache;
 
501
    double borderRadius;
 
502
    QwtPlotCanvas::PaintAttributes paintAttributes;
 
503
    QPixmap *backingStore;
 
504
 
 
505
    struct StyleSheet
 
506
    {
 
507
        bool hasBorder;
 
508
        QPainterPath borderPath;
 
509
        QVector<QRectF> cornerRects;
 
510
 
 
511
        struct StyleSheetBackground
 
512
        {
 
513
            QBrush brush;
 
514
            QPointF origin;
 
515
        } background;
 
516
 
 
517
    } styleSheet;
 
518
 
46
519
};
47
520
 
48
 
//! Sets a cross cursor, enables QwtPlotCanvas::PaintCached
 
521
//! Sets a cross cursor, enables QwtPlotCanvas::BackingStore
49
522
 
50
 
QwtPlotCanvas::QwtPlotCanvas(QwtPlot *plot):
51
 
    QFrame(plot)
 
523
QwtPlotCanvas::QwtPlotCanvas( QwtPlot *plot ):
 
524
    QFrame( plot )
52
525
{
53
526
    d_data = new PrivateData;
54
527
 
55
 
#if QT_VERSION >= 0x040100
56
 
    setAutoFillBackground(true);
57
 
#endif
58
 
 
59
 
#if QT_VERSION < 0x040000
60
 
    setWFlags(Qt::WNoAutoErase);
61
 
#ifndef QT_NO_CURSOR
62
 
    setCursor(Qt::crossCursor);
63
 
#endif
64
 
#else
65
 
#ifndef QT_NO_CURSOR
66
 
    setCursor(Qt::CrossCursor);
67
 
#endif
68
 
#endif // >= 0x040000
69
 
 
70
 
    setPaintAttribute(PaintCached, true);
71
 
    setPaintAttribute(PaintPacked, true);
 
528
#ifndef QT_NO_CURSOR
 
529
    setCursor( Qt::CrossCursor );
 
530
#endif
 
531
 
 
532
    setAutoFillBackground( true );
 
533
    setPaintAttribute( QwtPlotCanvas::BackingStore, true );
 
534
    setPaintAttribute( QwtPlotCanvas::Opaque, true );
 
535
    setPaintAttribute( QwtPlotCanvas::HackStyledBackground, true );
72
536
}
73
537
 
74
538
//! Destructor
80
544
//! Return parent plot widget
81
545
QwtPlot *QwtPlotCanvas::plot()
82
546
{
83
 
    QWidget *w = parentWidget();
84
 
    if ( w && w->inherits("QwtPlot") )
85
 
        return (QwtPlot *)w;
86
 
 
87
 
    return NULL;
 
547
    return qobject_cast<QwtPlot *>( parentWidget() );
88
548
}
89
549
 
90
550
//! Return parent plot widget
91
551
const QwtPlot *QwtPlotCanvas::plot() const
92
552
{
93
 
    const QWidget *w = parentWidget();
94
 
    if ( w && w->inherits("QwtPlot") )
95
 
        return (QwtPlot *)w;
96
 
 
97
 
    return NULL;
 
553
    return qobject_cast<const QwtPlot *>( parentWidget() );
98
554
}
99
555
 
100
556
/*!
103
559
  \param attribute Paint attribute
104
560
  \param on On/Off
105
561
 
106
 
  The default setting enables PaintCached and PaintPacked
107
 
 
108
 
  \sa testPaintAttribute(), drawCanvas(), drawContents(), paintCache()
 
562
  \sa testPaintAttribute(), backingStore()
109
563
*/
110
 
void QwtPlotCanvas::setPaintAttribute(PaintAttribute attribute, bool on)
 
564
void QwtPlotCanvas::setPaintAttribute( PaintAttribute attribute, bool on )
111
565
{
112
 
    if ( bool(d_data->paintAttributes & attribute) == on )
 
566
    if ( bool( d_data->paintAttributes & attribute ) == on )
113
567
        return;
114
568
 
115
569
    if ( on )
117
571
    else
118
572
        d_data->paintAttributes &= ~attribute;
119
573
 
120
 
    switch(attribute)
 
574
    switch ( attribute )
121
575
    {
122
 
        case PaintCached:
 
576
        case BackingStore:
123
577
        {
124
578
            if ( on )
125
579
            {
126
 
                if ( d_data->cache == NULL )
127
 
                    d_data->cache = new QPixmap();
 
580
                if ( d_data->backingStore == NULL )
 
581
                    d_data->backingStore = new QPixmap();
128
582
 
129
583
                if ( isVisible() )
130
584
                {
131
 
                    const QRect cr = contentsRect();
132
 
                    *d_data->cache = QPixmap::grabWidget(this,
133
 
                        cr.x(), cr.y(), cr.width(), cr.height() );
 
585
                    *d_data->backingStore =
 
586
                        QPixmap::grabWidget( this, rect() );
134
587
                }
135
588
            }
136
589
            else
137
590
            {
138
 
                delete d_data->cache;
139
 
                d_data->cache = NULL;
 
591
                delete d_data->backingStore;
 
592
                d_data->backingStore = NULL;
140
593
            }
141
594
            break;
142
595
        }
143
 
        case PaintPacked:
144
 
        {
145
 
            /*
146
 
              If not visible, changing of the background mode
147
 
              is delayed until it becomes visible. This tries to avoid 
148
 
              looking through the canvas when the canvas is shown the first 
149
 
              time.
150
 
             */
151
 
 
152
 
            if ( on == false || isVisible() )
153
 
                QwtPlotCanvas::setSystemBackground(!on);
154
 
 
 
596
        case Opaque:
 
597
        {
 
598
            if ( on )
 
599
                setAttribute( Qt::WA_OpaquePaintEvent, true );
 
600
 
 
601
            break;
 
602
        }
 
603
        case HackStyledBackground:
 
604
        case ImmediatePaint:
 
605
        {
155
606
            break;
156
607
        }
157
608
    }
164
615
  \return true if the attribute is enabled
165
616
  \sa setPaintAttribute()
166
617
*/
167
 
bool QwtPlotCanvas::testPaintAttribute(PaintAttribute attribute) const
168
 
{
169
 
    return (d_data->paintAttributes & attribute) != 0;
170
 
}
171
 
 
172
 
//! Return the paint cache, might be null
173
 
QPixmap *QwtPlotCanvas::paintCache()
174
 
{
175
 
    return d_data->cache;
176
 
}
177
 
 
178
 
//! Return the paint cache, might be null
179
 
const QPixmap *QwtPlotCanvas::paintCache() const
180
 
{
181
 
    return d_data->cache;
182
 
}
183
 
 
184
 
//! Invalidate the internal paint cache
185
 
void QwtPlotCanvas::invalidatePaintCache()
186
 
{
187
 
    if ( d_data->cache )
188
 
        *d_data->cache = QPixmap();
 
618
bool QwtPlotCanvas::testPaintAttribute( PaintAttribute attribute ) const
 
619
{
 
620
    return d_data->paintAttributes & attribute;
 
621
}
 
622
 
 
623
//! \return Backing store, might be null
 
624
const QPixmap *QwtPlotCanvas::backingStore() const
 
625
{
 
626
    return d_data->backingStore;
 
627
}
 
628
 
 
629
//! Invalidate the internal backing store
 
630
void QwtPlotCanvas::invalidateBackingStore()
 
631
{
 
632
    if ( d_data->backingStore )
 
633
        *d_data->backingStore = QPixmap();
189
634
}
190
635
 
191
636
/*!
193
638
 
194
639
  \sa FocusIndicator, focusIndicator()
195
640
*/
196
 
void QwtPlotCanvas::setFocusIndicator(FocusIndicator focusIndicator)
 
641
void QwtPlotCanvas::setFocusIndicator( FocusIndicator focusIndicator )
197
642
{
198
643
    d_data->focusIndicator = focusIndicator;
199
644
}
200
645
 
201
646
/*!
202
647
  \return Focus indicator
203
 
  
 
648
 
204
649
  \sa FocusIndicator, setFocusIndicator()
205
650
*/
206
651
QwtPlotCanvas::FocusIndicator QwtPlotCanvas::focusIndicator() const
209
654
}
210
655
 
211
656
/*!
212
 
  Hide event
213
 
  \param event Hide event
214
 
*/
215
 
void QwtPlotCanvas::hideEvent(QHideEvent *event)
216
 
{
217
 
    QFrame::hideEvent(event);
218
 
 
219
 
    if ( d_data->paintAttributes & PaintPacked )
220
 
    {
221
 
        // enable system background to avoid the "looking through
222
 
        // the canvas" effect, for the next show
223
 
 
224
 
        setSystemBackground(true);
225
 
    }
 
657
  Set the radius for the corners of the border frame
 
658
 
 
659
  \param radius Radius of a rounded corner
 
660
  \sa borderRadius()
 
661
*/
 
662
void QwtPlotCanvas::setBorderRadius( double radius )
 
663
{
 
664
    d_data->borderRadius = qMax( 0.0, radius );
 
665
}
 
666
 
 
667
/*!
 
668
  \return Radius for the corners of the border frame
 
669
  \sa setBorderRadius()
 
670
*/
 
671
double QwtPlotCanvas::borderRadius() const
 
672
{
 
673
    return d_data->borderRadius;
 
674
}
 
675
 
 
676
/*!
 
677
  Qt event handler for QEvent::PolishRequest and QEvent::StyleChange
 
678
  \param event Qt Event
 
679
*/
 
680
bool QwtPlotCanvas::event( QEvent *event )
 
681
{
 
682
    if ( event->type() == QEvent::PolishRequest )
 
683
    {
 
684
        if ( testPaintAttribute( QwtPlotCanvas::Opaque ) )
 
685
        {
 
686
            // Setting a style sheet changes the
 
687
            // Qt::WA_OpaquePaintEvent attribute, but we insist
 
688
            // on painting the background.
 
689
 
 
690
            setAttribute( Qt::WA_OpaquePaintEvent, true );
 
691
        }
 
692
    }
 
693
 
 
694
    if ( event->type() == QEvent::PolishRequest ||
 
695
        event->type() == QEvent::StyleChange )
 
696
    {
 
697
        updateStyleSheetInfo();
 
698
    }
 
699
 
 
700
    return QFrame::event( event );
226
701
}
227
702
 
228
703
/*!
229
704
  Paint event
230
705
  \param event Paint event
231
706
*/
232
 
void QwtPlotCanvas::paintEvent(QPaintEvent *event)
 
707
void QwtPlotCanvas::paintEvent( QPaintEvent *event )
233
708
{
234
 
#if QT_VERSION >= 0x040000
235
 
    QPainter painter(this);
236
 
    
237
 
    if ( !contentsRect().contains( event->rect() ) ) 
 
709
    QPainter painter( this );
 
710
    painter.setClipRegion( event->region() );
 
711
 
 
712
    if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) &&
 
713
        d_data->backingStore != NULL )
238
714
    {
239
 
        painter.save();
240
 
        painter.setClipRegion( event->region() & frameRect() );
241
 
        drawFrame( &painter );
242
 
        painter.restore(); 
243
 
    }
244
 
 
245
 
    painter.setClipRegion(event->region() & contentsRect());
246
 
 
247
 
    drawContents( &painter );
248
 
#else // QT_VERSION < 0x040000
249
 
    QFrame::paintEvent(event);
 
715
        QPixmap &bs = *d_data->backingStore;
 
716
        if ( bs.size() != size() )
 
717
        {
 
718
            bs = QPixmap( size() );
 
719
 
 
720
#ifdef Q_WS_X11
 
721
            if ( bs.x11Info().screen() != x11Info().screen() )
 
722
                bs.x11SetScreen( x11Info().screen() );
250
723
#endif
251
724
 
252
 
    if ( d_data->paintAttributes & PaintPacked )
253
 
        setSystemBackground(false);
254
 
}
255
 
 
256
 
/*! 
257
 
  Redraw the canvas, and focus rect
258
 
  \param painter Painter
259
 
*/
260
 
void QwtPlotCanvas::drawContents(QPainter *painter)
261
 
{
262
 
    if ( d_data->paintAttributes & PaintCached && d_data->cache 
263
 
        && d_data->cache->size() == contentsRect().size() )
264
 
    {
265
 
        painter->drawPixmap(contentsRect().topLeft(), *d_data->cache);
 
725
            if ( testAttribute(Qt::WA_StyledBackground) )
 
726
            {
 
727
                QPainter p( &bs );
 
728
                qwtFillBackground( &p, this );
 
729
                drawCanvas( &p, true );
 
730
            }
 
731
            else
 
732
            {
 
733
                QPainter p;
 
734
                if ( d_data->borderRadius <= 0.0 )
 
735
                {
 
736
                    bs.fill( this, 0, 0 );
 
737
                    p.begin( &bs );
 
738
                    drawCanvas( &p, false );
 
739
                }
 
740
                else
 
741
                {
 
742
                    p.begin( &bs );
 
743
                    qwtFillBackground( &p, this );
 
744
                    drawCanvas( &p, true );
 
745
                }
 
746
 
 
747
                if ( frameWidth() > 0 )
 
748
                    drawBorder( &p );
 
749
            }
 
750
        }
 
751
 
 
752
        painter.drawPixmap( 0, 0, *d_data->backingStore );
266
753
    }
267
754
    else
268
755
    {
269
 
        QwtPlot *plot = ((QwtPlot *)parent());
270
 
        const bool doAutoReplot = plot->autoReplot();
271
 
        plot->setAutoReplot(false);
272
 
 
273
 
        drawCanvas(painter);
274
 
 
275
 
        plot->setAutoReplot(doAutoReplot);
 
756
        if ( testAttribute(Qt::WA_StyledBackground ) )
 
757
        {
 
758
            if ( testAttribute( Qt::WA_OpaquePaintEvent ) )
 
759
            {
 
760
                qwtFillBackground( &painter, this );
 
761
                drawCanvas( &painter, true );
 
762
            }
 
763
            else
 
764
            {
 
765
                drawCanvas( &painter, false );
 
766
            }
 
767
        }
 
768
        else
 
769
        {
 
770
            if ( testAttribute( Qt::WA_OpaquePaintEvent ) )
 
771
            {
 
772
                if ( autoFillBackground() )
 
773
                    qwtDrawBackground( &painter, this );
 
774
            }
 
775
 
 
776
            drawCanvas( &painter, false );
 
777
 
 
778
            if ( frameWidth() > 0 )
 
779
                drawBorder( &painter );
 
780
        }
276
781
    }
277
782
 
278
783
    if ( hasFocus() && focusIndicator() == CanvasFocusIndicator )
279
 
        drawFocusIndicator(painter);
 
784
        drawFocusIndicator( &painter );
 
785
}
 
786
 
 
787
void QwtPlotCanvas::drawCanvas( QPainter *painter, bool withBackground )
 
788
{
 
789
    bool hackStyledBackground = false;
 
790
 
 
791
    if ( withBackground && testAttribute( Qt::WA_StyledBackground )
 
792
        && testPaintAttribute( HackStyledBackground ) )
 
793
    {
 
794
        // Antialiasing rounded borders is done by
 
795
        // inserting pixels with colors between the
 
796
        // border color and the color on the canvas,
 
797
        // When the border is painted before the plot items
 
798
        // these colors are interpolated for the canvas
 
799
        // and the plot items need to be clipped excluding
 
800
        // the anialiased pixels. In situations, where
 
801
        // the plot items fill the area at the rounded
 
802
        // borders this is noticeable.
 
803
        // The only way to avoid these annoying "artefacts"
 
804
        // is to paint the border on top of the plot items.
 
805
 
 
806
        if ( d_data->styleSheet.hasBorder &&
 
807
            !d_data->styleSheet.borderPath.isEmpty() )
 
808
        {
 
809
            // We have a border with at least one rounded corner
 
810
            hackStyledBackground = true;
 
811
        }
 
812
    }
 
813
 
 
814
    if ( withBackground )
 
815
    {
 
816
        painter->save();
 
817
 
 
818
        if ( testAttribute( Qt::WA_StyledBackground ) )
 
819
        {
 
820
            if ( hackStyledBackground )
 
821
            {
 
822
                // paint background without border
 
823
 
 
824
                painter->setPen( Qt::NoPen );
 
825
                painter->setBrush( d_data->styleSheet.background.brush );
 
826
                painter->setBrushOrigin( d_data->styleSheet.background.origin );
 
827
                painter->setClipPath( d_data->styleSheet.borderPath );
 
828
                painter->drawRect( contentsRect() );
 
829
            }
 
830
            else
 
831
            {
 
832
                qwtDrawStyledBackground( this, painter );
 
833
            }
 
834
        }
 
835
        else if ( autoFillBackground() )
 
836
        {
 
837
            painter->setPen( Qt::NoPen );
 
838
            painter->setBrush( palette().brush( backgroundRole() ) );
 
839
 
 
840
            if ( d_data->borderRadius > 0.0 )
 
841
            {
 
842
                if ( frameWidth() > 0 )
 
843
                {
 
844
                    painter->setClipPath( borderPath( rect() ) );
 
845
                    painter->drawRect( rect() );
 
846
                }
 
847
                else
 
848
                {
 
849
                    painter->setRenderHint( QPainter::Antialiasing, true );
 
850
                    painter->drawPath( borderPath( rect() ) );
 
851
                }
 
852
            }
 
853
            else
 
854
            {
 
855
                painter->drawRect( contentsRect() );
 
856
            }
 
857
        }
 
858
 
 
859
        painter->restore();
 
860
    }
 
861
 
 
862
    painter->save();
 
863
 
 
864
    if ( !d_data->styleSheet.borderPath.isEmpty() )
 
865
    {
 
866
        painter->setClipPath(
 
867
            d_data->styleSheet.borderPath, Qt::IntersectClip );
 
868
    }
 
869
    else
 
870
    {
 
871
        if ( d_data->borderRadius > 0.0 )
 
872
            painter->setClipPath( borderPath( rect() ), Qt::IntersectClip );
 
873
        else
 
874
            painter->setClipRect( contentsRect(), Qt::IntersectClip );
 
875
    }
 
876
 
 
877
    plot()->drawCanvas( painter );
 
878
 
 
879
    painter->restore();
 
880
 
 
881
    if ( withBackground && hackStyledBackground )
 
882
    {
 
883
        // Now paint the border on top
 
884
        QStyleOptionFrame opt;
 
885
        opt.initFrom(this);
 
886
        style()->drawPrimitive( QStyle::PE_Frame, &opt, painter, this);
 
887
    }
280
888
}
281
889
 
282
890
/*!
283
 
  Draw the the canvas
284
 
 
285
 
  Paints all plot items to the contentsRect(), using QwtPlot::drawCanvas
286
 
  and updates the paint cache.
 
891
  Draw the border of the plot canvas
287
892
 
288
893
  \param painter Painter
289
 
 
290
 
  \sa QwtPlot::drawCanvas(), setPaintAttributes(), testPaintAttributes()
 
894
  \sa setBorderRadius(), QFrame::drawFrame()
291
895
*/
292
 
void QwtPlotCanvas::drawCanvas(QPainter *painter)
 
896
void QwtPlotCanvas::drawBorder( QPainter *painter )
293
897
{
294
 
    if ( !contentsRect().isValid() )
295
 
        return;
296
 
 
297
 
    QBrush bgBrush;
298
 
#if QT_VERSION >= 0x040000
299
 
        bgBrush = palette().brush(backgroundRole());
300
 
#else
301
 
    QColorGroup::ColorRole role = 
302
 
        QPalette::backgroundRoleFromMode( backgroundMode() );
303
 
    bgBrush = colorGroup().brush( role );
304
 
#endif
305
 
 
306
 
    if ( d_data->paintAttributes & PaintCached && d_data->cache )
 
898
    if ( d_data->borderRadius > 0 )
307
899
    {
308
 
        *d_data->cache = QPixmap(contentsRect().size());
309
 
 
310
 
#ifdef Q_WS_X11
311
 
#if QT_VERSION >= 0x040000
312
 
        if ( d_data->cache->x11Info().screen() != x11Info().screen() )
313
 
            d_data->cache->x11SetScreen(x11Info().screen());
314
 
#else
315
 
        if ( d_data->cache->x11Screen() != x11Screen() )
316
 
            d_data->cache->x11SetScreen(x11Screen());
317
 
#endif
318
 
#endif
319
 
 
320
 
        if ( d_data->paintAttributes & PaintPacked )
 
900
        if ( frameWidth() > 0 )
321
901
        {
322
 
            QPainter bgPainter(d_data->cache);
323
 
            bgPainter.setPen(Qt::NoPen);
324
 
 
325
 
            bgPainter.setBrush(bgBrush);
326
 
            bgPainter.drawRect(d_data->cache->rect());
 
902
            QwtPainter::drawRoundedFrame( painter, QRectF( rect() ),
 
903
                d_data->borderRadius, d_data->borderRadius,
 
904
                palette(), frameWidth(), frameStyle() );
327
905
        }
328
 
        else
329
 
            d_data->cache->fill(this, d_data->cache->rect().topLeft());
330
 
 
331
 
        QPainter cachePainter(d_data->cache);
332
 
        cachePainter.translate(-contentsRect().x(),
333
 
            -contentsRect().y());
334
 
 
335
 
        ((QwtPlot *)parent())->drawCanvas(&cachePainter);
336
 
 
337
 
        cachePainter.end();
338
 
 
339
 
        painter->drawPixmap(contentsRect(), *d_data->cache);
340
906
    }
341
907
    else
342
908
    {
343
 
#if QT_VERSION >= 0x040000
344
 
        if ( d_data->paintAttributes & PaintPacked )
345
 
#endif
346
 
        {
347
 
            painter->save();
348
 
 
349
 
            painter->setPen(Qt::NoPen);
350
 
            painter->setBrush(bgBrush);
351
 
            painter->drawRect(contentsRect());
352
 
 
353
 
            painter->restore();
354
 
        }
355
 
 
356
 
        ((QwtPlot *)parent())->drawCanvas(painter);
 
909
        drawFrame( painter );
357
910
    }
358
911
}
359
912
 
360
 
/*! 
 
913
/*!
 
914
  Resize event
 
915
  \param event Resize event
 
916
*/
 
917
void QwtPlotCanvas::resizeEvent( QResizeEvent *event )
 
918
{
 
919
    QFrame::resizeEvent( event );
 
920
    updateStyleSheetInfo();
 
921
}
 
922
 
 
923
/*!
361
924
  Draw the focus indication
362
925
  \param painter Painter
363
926
*/
364
 
void QwtPlotCanvas::drawFocusIndicator(QPainter *painter)
 
927
void QwtPlotCanvas::drawFocusIndicator( QPainter *painter )
365
928
{
366
929
    const int margin = 1;
367
930
 
368
931
    QRect focusRect = contentsRect();
369
 
    focusRect.setRect(focusRect.x() + margin, focusRect.y() + margin,
370
 
        focusRect.width() - 2 * margin, focusRect.height() - 2 * margin);
371
 
 
372
 
    QwtPainter::drawFocusRect(painter, this, focusRect);
373
 
}
374
 
 
375
 
void QwtPlotCanvas::setSystemBackground(bool on)
376
 
{
377
 
#if QT_VERSION < 0x040000
378
 
    if ( backgroundMode() == Qt::NoBackground )
379
 
    {
380
 
        if ( on )
381
 
            setBackgroundMode(Qt::PaletteBackground);
382
 
    }
383
 
    else
384
 
    {
385
 
        if ( !on )
386
 
            setBackgroundMode(Qt::NoBackground);
387
 
    }
388
 
#else
389
 
    if ( testAttribute(Qt::WA_NoSystemBackground) == on )
390
 
        setAttribute(Qt::WA_NoSystemBackground, !on);
391
 
#endif
 
932
    focusRect.setRect( focusRect.x() + margin, focusRect.y() + margin,
 
933
        focusRect.width() - 2 * margin, focusRect.height() - 2 * margin );
 
934
 
 
935
    QwtPainter::drawFocusRect( painter, this, focusRect );
392
936
}
393
937
 
394
938
/*!
397
941
*/
398
942
void QwtPlotCanvas::replot()
399
943
{
400
 
    invalidatePaintCache();
401
 
 
402
 
    /*
403
 
      In case of cached or packed painting the canvas
404
 
      is repainted completely and doesn't need to be erased.
405
 
     */
406
 
    const bool erase =
407
 
        !testPaintAttribute(QwtPlotCanvas::PaintPacked)
408
 
        && !testPaintAttribute(QwtPlotCanvas::PaintCached);
409
 
 
410
 
#if QT_VERSION >= 0x040000
411
 
    const bool noBackgroundMode = testAttribute(Qt::WA_NoBackground);
412
 
    if ( !erase && !noBackgroundMode )
413
 
        setAttribute(Qt::WA_NoBackground, true);
414
 
 
415
 
    repaint(contentsRect());
416
 
 
417
 
    if ( !erase && !noBackgroundMode )
418
 
        setAttribute(Qt::WA_NoBackground, false);
419
 
#else
420
 
    repaint(contentsRect(), erase);
421
 
#endif
 
944
    invalidateBackingStore();
 
945
 
 
946
    if ( testPaintAttribute( QwtPlotCanvas::ImmediatePaint ) )
 
947
        repaint( contentsRect() );
 
948
    else
 
949
        update( contentsRect() );
 
950
}
 
951
 
 
952
//! Update the cached informations about the current style sheet
 
953
void QwtPlotCanvas::updateStyleSheetInfo()
 
954
{
 
955
    if ( !testAttribute(Qt::WA_StyledBackground ) )
 
956
        return;
 
957
 
 
958
    QwtStyleSheetRecorder recorder( size() );
 
959
 
 
960
    QPainter painter( &recorder );
 
961
 
 
962
    QStyleOption opt;
 
963
    opt.initFrom(this);
 
964
    style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this);
 
965
 
 
966
    painter.end();
 
967
 
 
968
    d_data->styleSheet.hasBorder = !recorder.border.rectList.isEmpty();
 
969
    d_data->styleSheet.cornerRects = recorder.clipRects;
 
970
 
 
971
    if ( recorder.background.path.isEmpty() )
 
972
    {
 
973
        if ( !recorder.border.rectList.isEmpty() )
 
974
        {
 
975
            d_data->styleSheet.borderPath =
 
976
                qwtCombinePathList( rect(), recorder.border.pathList );
 
977
        }
 
978
    }
 
979
    else
 
980
    {
 
981
        d_data->styleSheet.borderPath = recorder.background.path;
 
982
        d_data->styleSheet.background.brush = recorder.background.brush;
 
983
        d_data->styleSheet.background.origin = recorder.background.origin;
 
984
    }
 
985
}
 
986
 
 
987
/*!
 
988
   Calculate the painter path for a styled or rounded border
 
989
 
 
990
   When the canvas has no styled background or rounded borders
 
991
   the painter path is empty.
 
992
 
 
993
   \param rect Bounding rectangle of the canvas
 
994
   \return Painter path, that can be used for clipping
 
995
*/
 
996
QPainterPath QwtPlotCanvas::borderPath( const QRect &rect ) const
 
997
{
 
998
    if ( testAttribute(Qt::WA_StyledBackground ) )
 
999
    {
 
1000
        QwtStyleSheetRecorder recorder( rect.size() );
 
1001
 
 
1002
        QPainter painter( &recorder );
 
1003
 
 
1004
        QStyleOption opt;
 
1005
        opt.initFrom(this);
 
1006
        opt.rect = rect;
 
1007
        style()->drawPrimitive( QStyle::PE_Widget, &opt, &painter, this);
 
1008
 
 
1009
        painter.end();
 
1010
 
 
1011
        if ( !recorder.background.path.isEmpty() )
 
1012
            return recorder.background.path;
 
1013
 
 
1014
        if ( !recorder.border.rectList.isEmpty() )
 
1015
            return qwtCombinePathList( rect, recorder.border.pathList );
 
1016
    }
 
1017
    else if ( d_data->borderRadius > 0.0 )
 
1018
    {
 
1019
        double fw2 = frameWidth() * 0.5;
 
1020
        QRectF r = QRectF(rect).adjusted( fw2, fw2, -fw2, -fw2 );
 
1021
 
 
1022
        QPainterPath path;
 
1023
        path.addRoundedRect( r, d_data->borderRadius, d_data->borderRadius );
 
1024
        return path;
 
1025
    }
 
1026
 
 
1027
    return QPainterPath();
 
1028
}
 
1029
 
 
1030
/*!
 
1031
   Calculate a mask, that can be used to clip away the border frame
 
1032
 
 
1033
   \param size Size including the frame
 
1034
*/
 
1035
QBitmap QwtPlotCanvas::borderMask( const QSize &size ) const
 
1036
{
 
1037
    const QRect r( 0, 0, size.width(), size.height() );
 
1038
 
 
1039
    const QPainterPath path = borderPath( r );
 
1040
    if ( path.isEmpty() )
 
1041
        return QBitmap();
 
1042
 
 
1043
    QImage image( size, QImage::Format_ARGB32_Premultiplied );
 
1044
    image.fill( Qt::color0 );
 
1045
 
 
1046
    QPainter painter( &image );
 
1047
    painter.setClipPath( path );
 
1048
    painter.fillRect( r, Qt::color1 );
 
1049
 
 
1050
    // now erase the frame
 
1051
 
 
1052
    painter.setCompositionMode( QPainter::CompositionMode_DestinationOut );
 
1053
 
 
1054
    if ( testAttribute(Qt::WA_StyledBackground ) )
 
1055
    {
 
1056
        QStyleOptionFrame opt;
 
1057
        opt.initFrom(this);
 
1058
        opt.rect = r;
 
1059
        style()->drawPrimitive( QStyle::PE_Frame, &opt, &painter, this );
 
1060
    }
 
1061
    else
 
1062
    {
 
1063
        if ( d_data->borderRadius > 0 && frameWidth() > 0 )
 
1064
        {
 
1065
            painter.setPen( QPen( Qt::color1, frameWidth() ) );
 
1066
            painter.setBrush( Qt::NoBrush );
 
1067
            painter.setRenderHint( QPainter::Antialiasing, true );
 
1068
 
 
1069
            painter.drawPath( path );
 
1070
        }
 
1071
    }
 
1072
 
 
1073
    painter.end();
 
1074
 
 
1075
    const QImage mask = image.createMaskFromColor(
 
1076
        QColor( Qt::color1 ).rgb(), Qt::MaskOutColor );
 
1077
 
 
1078
    return QBitmap::fromImage( mask );
422
1079
}