source: ntrip/trunk/BNC/qwt/qwt_plot_canvas.cpp@ 9045

Last change on this file since 9045 was 8127, checked in by stoecker, 8 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

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