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_glcanvas.h"
11 #include "qwt_plot.h"
12 #include "qwt_painter.h"
13 #include <qevent.h>
14 #include <qpainter.h>
15 #include <qdrawutil.h>
16 #include <qstyle.h>
17 #include <qstyleoption.h>
18 
19 #define FIX_GL_TRANSLATION 0
20 
qwtBGWidget(QWidget * widget)21 static QWidget *qwtBGWidget( QWidget *widget )
22 {
23     QWidget *w = widget;
24 
25     for ( ; w->parentWidget() != NULL; w = w->parentWidget() )
26     {
27         if ( w->autoFillBackground() ||
28             w->testAttribute( Qt::WA_StyledBackground ) )
29         {
30             return w;
31         }
32     }
33 
34     return w;
35 }
36 
qwtUpdateContentsRect(QwtPlotGLCanvas * canvas)37 static void qwtUpdateContentsRect( QwtPlotGLCanvas *canvas )
38 {
39     const int fw = canvas->frameWidth();
40     canvas->setContentsMargins( fw, fw, fw, fw );
41 }
42 
43 class QwtPlotGLCanvas::PrivateData
44 {
45 public:
PrivateData()46     PrivateData():
47         frameStyle( QFrame::Panel | QFrame::Sunken),
48         lineWidth( 2 ),
49         midLineWidth( 0 )
50     {
51     }
52 
53     int frameStyle;
54     int lineWidth;
55     int midLineWidth;
56 };
57 
58 class QwtPlotGLCanvasFormat: public QGLFormat
59 {
60 public:
QwtPlotGLCanvasFormat()61     QwtPlotGLCanvasFormat():
62         QGLFormat( QGLFormat::defaultFormat() )
63     {
64         setSampleBuffers( true );
65     }
66 };
67 
68 /*!
69   \brief Constructor
70 
71   \param plot Parent plot widget
72   \sa QwtPlot::setCanvas()
73 */
QwtPlotGLCanvas(QwtPlot * plot)74 QwtPlotGLCanvas::QwtPlotGLCanvas( QwtPlot *plot ):
75     QGLWidget( QwtPlotGLCanvasFormat(), plot )
76 {
77     d_data = new PrivateData;
78 
79 #ifndef QT_NO_CURSOR
80     setCursor( Qt::CrossCursor );
81 #endif
82 
83     setAutoFillBackground( true );
84     qwtUpdateContentsRect( this );
85 }
86 
87 //! Destructor
~QwtPlotGLCanvas()88 QwtPlotGLCanvas::~QwtPlotGLCanvas()
89 {
90     delete d_data;
91 }
92 
93 /*!
94   Set the frame style
95 
96   \param style The bitwise OR between a shape and a shadow.
97 
98   \sa frameStyle(), QFrame::setFrameStyle(),
99       setFrameShadow(), setFrameShape()
100  */
setFrameStyle(int style)101 void QwtPlotGLCanvas::setFrameStyle( int style )
102 {
103     if ( style != d_data->frameStyle )
104     {
105         d_data->frameStyle = style;
106         qwtUpdateContentsRect( this );
107 
108         update();
109     }
110 }
111 
112 /*!
113   \return The bitwise OR between a frameShape() and a frameShadow()
114   \sa setFrameStyle(), QFrame::frameStyle()
115  */
frameStyle() const116 int QwtPlotGLCanvas::frameStyle() const
117 {
118     return d_data->frameStyle;
119 }
120 
121 /*!
122   Set the frame shadow
123 
124   \param shadow Frame shadow
125   \sa frameShadow(), setFrameShape(), QFrame::setFrameShadow()
126  */
setFrameShadow(Shadow shadow)127 void QwtPlotGLCanvas::setFrameShadow( Shadow shadow )
128 {
129     setFrameStyle(( d_data->frameStyle & QFrame::Shape_Mask ) | shadow );
130 }
131 
132 /*!
133   \return Frame shadow
134   \sa setFrameShadow(), QFrame::setFrameShadow()
135  */
frameShadow() const136 QwtPlotGLCanvas::Shadow QwtPlotGLCanvas::frameShadow() const
137 {
138     return (Shadow) ( d_data->frameStyle & QFrame::Shadow_Mask );
139 }
140 
141 /*!
142   Set the frame shape
143 
144   \param shape Frame shape
145   \sa frameShape(), setFrameShadow(), QFrame::frameShape()
146  */
setFrameShape(Shape shape)147 void QwtPlotGLCanvas::setFrameShape( Shape shape )
148 {
149     setFrameStyle( ( d_data->frameStyle & QFrame::Shadow_Mask ) | shape );
150 }
151 
152 /*!
153   \return Frame shape
154   \sa setFrameShape(), QFrame::frameShape()
155  */
frameShape() const156 QwtPlotGLCanvas::Shape QwtPlotGLCanvas::frameShape() const
157 {
158     return (Shape) ( d_data->frameStyle & QFrame::Shape_Mask );
159 }
160 
161 /*!
162    Set the frame line width
163 
164    The default line width is 2 pixels.
165 
166    \param width Line width of the frame
167    \sa lineWidth(), setMidLineWidth()
168 */
setLineWidth(int width)169 void QwtPlotGLCanvas::setLineWidth( int width )
170 {
171     width = qMax( width, 0 );
172     if ( width != d_data->lineWidth )
173     {
174         d_data->lineWidth = qMax( width, 0 );
175         qwtUpdateContentsRect( this );
176         update();
177     }
178 }
179 
180 /*!
181   \return Line width of the frame
182   \sa setLineWidth(), midLineWidth()
183  */
lineWidth() const184 int QwtPlotGLCanvas::lineWidth() const
185 {
186     return d_data->lineWidth;
187 }
188 
189 /*!
190    Set the frame mid line width
191 
192    The default midline width is 0 pixels.
193 
194    \param width Midline width of the frame
195    \sa midLineWidth(), setLineWidth()
196 */
setMidLineWidth(int width)197 void QwtPlotGLCanvas::setMidLineWidth( int width )
198 {
199     width = qMax( width, 0 );
200     if ( width != d_data->midLineWidth )
201     {
202         d_data->midLineWidth = width;
203         qwtUpdateContentsRect( this );
204         update();
205     }
206 }
207 
208 /*!
209   \return Midline width of the frame
210   \sa setMidLineWidth(), lineWidth()
211  */
midLineWidth() const212 int QwtPlotGLCanvas::midLineWidth() const
213 {
214     return d_data->midLineWidth;
215 }
216 
217 /*!
218   \return Frame width depending on the style, line width and midline width.
219  */
frameWidth() const220 int QwtPlotGLCanvas::frameWidth() const
221 {
222     return ( frameStyle() != NoFrame ) ? d_data->lineWidth : 0;
223 }
224 
225 /*!
226   Paint event
227 
228   \param event Paint event
229   \sa QwtPlot::drawCanvas()
230 */
paintEvent(QPaintEvent * event)231 void QwtPlotGLCanvas::paintEvent( QPaintEvent *event )
232 {
233     Q_UNUSED( event );
234 
235     QPainter painter( this );
236 
237 #if FIX_GL_TRANSLATION
238     if ( painter.paintEngine()->type() == QPaintEngine::OpenGL2 )
239     {
240         // work around a translation bug of QPaintEngine::OpenGL2
241         painter.translate( 1, 1 );
242     }
243 #endif
244 
245     drawBackground( &painter );
246     drawItems( &painter );
247 
248     if ( !testAttribute( Qt::WA_StyledBackground ) )
249     {
250         if ( frameWidth() > 0 )
251             drawBorder( &painter );
252     }
253 }
254 /*!
255   Qt event handler for QEvent::PolishRequest and QEvent::StyleChange
256   \param event Qt Event
257   \return See QGLWidget::event()
258 */
event(QEvent * event)259 bool QwtPlotGLCanvas::event( QEvent *event )
260 {
261     const bool ok = QGLWidget::event( event );
262 
263     if ( event->type() == QEvent::PolishRequest ||
264         event->type() == QEvent::StyleChange )
265     {
266         // assuming, that we always have a styled background
267         // when we have a style sheet
268 
269         setAttribute( Qt::WA_StyledBackground,
270             testAttribute( Qt::WA_StyleSheet ) );
271     }
272 
273     return ok;
274 }
275 
276 /*!
277   Draw the plot items
278   \param painter Painter
279 
280   \sa QwtPlot::drawCanvas()
281 */
drawItems(QPainter * painter)282 void QwtPlotGLCanvas::drawItems( QPainter *painter )
283 {
284     painter->save();
285 
286     painter->setClipRect( contentsRect(), Qt::IntersectClip );
287 
288     QwtPlot *plot = qobject_cast< QwtPlot *>( parent() );
289     if ( plot )
290         plot->drawCanvas( painter );
291 
292     painter->restore();
293 }
294 
295 /*!
296   Draw the background of the canvas
297   \param painter Painter
298 */
drawBackground(QPainter * painter)299 void QwtPlotGLCanvas::drawBackground( QPainter *painter )
300 {
301     painter->save();
302 
303     QWidget *w = qwtBGWidget( this );
304 
305     const QPoint off = mapTo( w, QPoint() );
306     painter->translate( -off );
307 
308     const QRect fillRect = rect().translated( off );
309 
310     if ( w->testAttribute( Qt::WA_StyledBackground ) )
311     {
312         painter->setClipRect( fillRect );
313 
314         QStyleOption opt;
315         opt.initFrom( w );
316         w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w);
317     }
318     else
319     {
320         painter->fillRect( fillRect,
321             w->palette().brush( w->backgroundRole() ) );
322     }
323 
324     painter->restore();
325 }
326 
327 /*!
328   Draw the border of the canvas
329   \param painter Painter
330 */
drawBorder(QPainter * painter)331 void QwtPlotGLCanvas::drawBorder( QPainter *painter )
332 {
333     const int fw = frameWidth();
334     if ( fw <= 0 )
335         return;
336 
337     if ( frameShadow() == QwtPlotGLCanvas::Plain )
338     {
339         qDrawPlainRect( painter, frameRect(),
340             palette().shadow().color(), lineWidth() );
341     }
342     else
343     {
344         if ( frameShape() == QwtPlotGLCanvas::Box )
345         {
346             qDrawShadeRect( painter, frameRect(), palette(),
347                 frameShadow() == Sunken, lineWidth(), midLineWidth() );
348         }
349         else
350         {
351             qDrawShadePanel( painter, frameRect(), palette(),
352                 frameShadow() == Sunken, lineWidth() );
353         }
354     }
355 }
356 
357 //! Calls repaint()
replot()358 void QwtPlotGLCanvas::replot()
359 {
360     repaint();
361 }
362 
363 /*!
364    \return Empty path
365 */
borderPath(const QRect & rect) const366 QPainterPath QwtPlotGLCanvas::borderPath( const QRect &rect ) const
367 {
368     Q_UNUSED( rect );
369     return QPainterPath();
370 }
371 
372 //! \return The rectangle where the frame is drawn in.
frameRect() const373 QRect QwtPlotGLCanvas::frameRect() const
374 {
375     const int fw = frameWidth();
376     return contentsRect().adjusted( -fw, -fw, fw, fw );
377 }
378