source: ntrip/branches/BNC_2.13.beta/qwt/qwt_plot_canvas.cpp@ 10132

Last change on this file since 10132 was 9383, checked in by stoecker, 4 years ago

update to qwt verion 6.1.1 to fix build with newer Qt5

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