source: ntrip/branches/BNC_2.12/qwt/qwt_plot_canvas.cpp@ 9402

Last change on this file since 9402 was 4271, checked in by mervart, 12 years ago
File size: 27.2 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#include <qbitmap.h>
21#ifdef Q_WS_X11
22#include <qx11info_x11.h>
23#endif
24
25class QwtStyleSheetRecorder: public QwtNullPaintDevice
26{
27public:
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
119private:
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
138public:
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
155private:
156 QPen d_pen;
157 QBrush d_brush;
158 QPointF d_origin;
159};
160
161static 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
254static 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
268static 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
381static 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
389static 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
418static 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
447static 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
482
483class QwtPlotCanvas::PrivateData
484{
485public:
486 PrivateData():
487 focusIndicator( NoFocusIndicator ),
488 borderRadius( 0 ),
489 paintAttributes( 0 ),
490 backingStore( NULL )
491 {
492 styleSheet.hasBorder = false;
493 }
494
495 ~PrivateData()
496 {
497 delete backingStore;
498 }
499
500 FocusIndicator focusIndicator;
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
519};
520
521//! Sets a cross cursor, enables QwtPlotCanvas::BackingStore
522
523QwtPlotCanvas::QwtPlotCanvas( QwtPlot *plot ):
524 QFrame( plot )
525{
526 d_data = new PrivateData;
527
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 );
536}
537
538//! Destructor
539QwtPlotCanvas::~QwtPlotCanvas()
540{
541 delete d_data;
542}
543
544//! Return parent plot widget
545QwtPlot *QwtPlotCanvas::plot()
546{
547 return qobject_cast<QwtPlot *>( parentWidget() );
548}
549
550//! Return parent plot widget
551const QwtPlot *QwtPlotCanvas::plot() const
552{
553 return qobject_cast<const QwtPlot *>( parentWidget() );
554}
555
556/*!
557 \brief Changing the paint attributes
558
559 \param attribute Paint attribute
560 \param on On/Off
561
562 \sa testPaintAttribute(), backingStore()
563*/
564void QwtPlotCanvas::setPaintAttribute( PaintAttribute attribute, bool on )
565{
566 if ( bool( d_data->paintAttributes & attribute ) == on )
567 return;
568
569 if ( on )
570 d_data->paintAttributes |= attribute;
571 else
572 d_data->paintAttributes &= ~attribute;
573
574 switch ( attribute )
575 {
576 case BackingStore:
577 {
578 if ( on )
579 {
580 if ( d_data->backingStore == NULL )
581 d_data->backingStore = new QPixmap();
582
583 if ( isVisible() )
584 {
585 *d_data->backingStore =
586 QPixmap::grabWidget( this, rect() );
587 }
588 }
589 else
590 {
591 delete d_data->backingStore;
592 d_data->backingStore = NULL;
593 }
594 break;
595 }
596 case Opaque:
597 {
598 if ( on )
599 setAttribute( Qt::WA_OpaquePaintEvent, true );
600
601 break;
602 }
603 case HackStyledBackground:
604 case ImmediatePaint:
605 {
606 break;
607 }
608 }
609}
610
611/*!
612 Test wether a paint attribute is enabled
613
614 \param attribute Paint attribute
615 \return true if the attribute is enabled
616 \sa setPaintAttribute()
617*/
618bool QwtPlotCanvas::testPaintAttribute( PaintAttribute attribute ) const
619{
620 return d_data->paintAttributes & attribute;
621}
622
623//! \return Backing store, might be null
624const QPixmap *QwtPlotCanvas::backingStore() const
625{
626 return d_data->backingStore;
627}
628
629//! Invalidate the internal backing store
630void QwtPlotCanvas::invalidateBackingStore()
631{
632 if ( d_data->backingStore )
633 *d_data->backingStore = QPixmap();
634}
635
636/*!
637 Set the focus indicator
638
639 \sa FocusIndicator, focusIndicator()
640*/
641void QwtPlotCanvas::setFocusIndicator( FocusIndicator focusIndicator )
642{
643 d_data->focusIndicator = focusIndicator;
644}
645
646/*!
647 \return Focus indicator
648
649 \sa FocusIndicator, setFocusIndicator()
650*/
651QwtPlotCanvas::FocusIndicator QwtPlotCanvas::focusIndicator() const
652{
653 return d_data->focusIndicator;
654}
655
656/*!
657 Set the radius for the corners of the border frame
658
659 \param radius Radius of a rounded corner
660 \sa borderRadius()
661*/
662void 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*/
671double 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*/
680bool 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 );
701}
702
703/*!
704 Paint event
705 \param event Paint event
706*/
707void QwtPlotCanvas::paintEvent( QPaintEvent *event )
708{
709 QPainter painter( this );
710 painter.setClipRegion( event->region() );
711
712 if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) &&
713 d_data->backingStore != NULL )
714 {
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() );
723#endif
724
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 );
753 }
754 else
755 {
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 }
781 }
782
783 if ( hasFocus() && focusIndicator() == CanvasFocusIndicator )
784 drawFocusIndicator( &painter );
785}
786
787void 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 }
888}
889
890/*!
891 Draw the border of the plot canvas
892
893 \param painter Painter
894 \sa setBorderRadius(), QFrame::drawFrame()
895*/
896void QwtPlotCanvas::drawBorder( QPainter *painter )
897{
898 if ( d_data->borderRadius > 0 )
899 {
900 if ( frameWidth() > 0 )
901 {
902 QwtPainter::drawRoundedFrame( painter, QRectF( rect() ),
903 d_data->borderRadius, d_data->borderRadius,
904 palette(), frameWidth(), frameStyle() );
905 }
906 }
907 else
908 {
909 drawFrame( painter );
910 }
911}
912
913/*!
914 Resize event
915 \param event Resize event
916*/
917void QwtPlotCanvas::resizeEvent( QResizeEvent *event )
918{
919 QFrame::resizeEvent( event );
920 updateStyleSheetInfo();
921}
922
923/*!
924 Draw the focus indication
925 \param painter Painter
926*/
927void QwtPlotCanvas::drawFocusIndicator( QPainter *painter )
928{
929 const int margin = 1;
930
931 QRect focusRect = contentsRect();
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 );
936}
937
938/*!
939 Invalidate the paint cache and repaint the canvas
940 \sa invalidatePaintCache()
941*/
942void QwtPlotCanvas::replot()
943{
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
953void 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*/
996QPainterPath 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*/
1035QBitmap 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 );
1079}
Note: See TracBrowser for help on using the repository browser.