source: ntrip/trunk/BNC/qwtpolar/qwt_polar_layout.cpp@ 4544

Last change on this file since 4544 was 4272, checked in by mervart, 13 years ago
File size: 11.7 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * QwtPolar Widget Library
3 * Copyright (C) 2008 Uwe Rathmann
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the Qwt License, Version 1.0
7 *****************************************************************************/
8
9#include "qwt_polar_layout.h"
10#include "qwt_polar_plot.h"
11#include "qwt_polar_canvas.h"
12#include <qwt_text.h>
13#include <qwt_text_label.h>
14#include <qwt_legend.h>
15#include <qscrollbar.h>
16
17class QwtPolarLayout::LayoutData
18{
19public:
20 void init( const QwtPolarPlot *, const QRectF &rect );
21
22 struct t_legendData
23 {
24 int frameWidth;
25 int vScrollBarWidth;
26 int hScrollBarHeight;
27 QSizeF hint;
28 } legend;
29
30 struct t_titleData
31 {
32 QwtText text;
33 int frameWidth;
34 } title;
35
36 struct t_canvasData
37 {
38 int frameWidth;
39 } canvas;
40};
41
42void QwtPolarLayout::LayoutData::init(
43 const QwtPolarPlot *plot, const QRectF &rect )
44{
45 // legend
46
47 if ( plot->plotLayout()->legendPosition() != QwtPolarPlot::ExternalLegend
48 && plot->legend() )
49 {
50 legend.frameWidth = plot->legend()->frameWidth();
51 legend.vScrollBarWidth =
52 plot->legend()->verticalScrollBar()->sizeHint().width();
53 legend.hScrollBarHeight =
54 plot->legend()->horizontalScrollBar()->sizeHint().height();
55
56 const QSizeF hint = plot->legend()->sizeHint();
57
58 double w = qMin( hint.width(), rect.width() );
59 double h = plot->legend()->heightForWidth( w );
60 if ( h == 0.0 )
61 h = hint.height();
62
63 if ( h > rect.height() )
64 w += legend.vScrollBarWidth;
65
66 legend.hint = QSizeF( w, h );
67 }
68
69 // title
70
71 title.frameWidth = 0;
72 title.text = QwtText();
73
74 if ( plot->titleLabel() )
75 {
76 const QwtTextLabel *label = plot->titleLabel();
77 title.text = label->text();
78 if ( !( title.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) )
79 title.text.setFont( label->font() );
80
81 title.frameWidth = plot->titleLabel()->frameWidth();
82 }
83
84 // canvas
85
86 canvas.frameWidth = plot->canvas()->frameWidth();
87}
88
89class QwtPolarLayout::PrivateData
90{
91public:
92 PrivateData():
93 margin( 0 ),
94 spacing( 0 )
95 {
96 }
97
98 QRectF titleRect;
99 QRectF legendRect;
100 QRectF canvasRect;
101
102 QwtPolarLayout::LayoutData layoutData;
103
104 QwtPolarPlot::LegendPosition legendPos;
105 double legendRatio;
106
107 unsigned int margin;
108 unsigned int spacing;
109};
110
111/*!
112 \brief Constructor
113 */
114
115QwtPolarLayout::QwtPolarLayout()
116{
117 d_data = new PrivateData;
118
119 setLegendPosition( QwtPolarPlot::BottomLegend );
120 invalidate();
121}
122
123//! Destructor
124QwtPolarLayout::~QwtPolarLayout()
125{
126 delete d_data;
127}
128
129/*!
130 \brief Specify the position of the legend
131 \param pos The legend's position.
132 \param ratio Ratio between legend and the bounding rect
133 of title, canvas and axes. The legend will be shrinked
134 if it would need more space than the given ratio.
135 The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
136 it will be reset to the default ratio.
137 The default vertical/horizontal ratio is 0.33/0.5.
138
139 \sa QwtPolarPlot::setLegendPosition()
140*/
141
142void QwtPolarLayout::setLegendPosition(
143 QwtPolarPlot::LegendPosition pos, double ratio )
144{
145 if ( ratio > 1.0 )
146 ratio = 1.0;
147
148 switch( pos )
149 {
150 case QwtPolarPlot::TopLegend:
151 case QwtPolarPlot::BottomLegend:
152 {
153 if ( ratio <= 0.0 )
154 ratio = 0.33;
155 d_data->legendRatio = ratio;
156 d_data->legendPos = pos;
157 break;
158 }
159 case QwtPolarPlot::LeftLegend:
160 case QwtPolarPlot::RightLegend:
161 {
162 if ( ratio <= 0.0 )
163 ratio = 0.5;
164 d_data->legendRatio = ratio;
165 d_data->legendPos = pos;
166 break;
167 }
168 case QwtPolarPlot::ExternalLegend:
169 {
170 d_data->legendRatio = ratio; // meaningless
171 d_data->legendPos = pos;
172 break;
173 }
174 default:
175 break;
176 }
177}
178
179/*!
180 \brief Specify the position of the legend
181 \param pos The legend's position. Valid values are
182 \c QwtPolarPlot::LeftLegend, \c QwtPolarPlot::RightLegend,
183 \c QwtPolarPlot::TopLegend, \c QwtPolarPlot::BottomLegend.
184
185 \sa QwtPolarPlot::setLegendPosition()
186*/
187void QwtPolarLayout::setLegendPosition( QwtPolarPlot::LegendPosition pos )
188{
189 setLegendPosition( pos, 0.0 );
190}
191
192/*!
193 \return Position of the legend
194 \sa setLegendPosition(), QwtPolarPlot::setLegendPosition(),
195 QwtPolarPlot::legendPosition()
196*/
197QwtPolarPlot::LegendPosition QwtPolarLayout::legendPosition() const
198{
199 return d_data->legendPos;
200}
201
202/*!
203 Specify the relative size of the legend in the plot
204 \param ratio Ratio between legend and the bounding rect
205 of title, canvas and axes. The legend will be shrinked
206 if it would need more space than the given ratio.
207 The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
208 it will be reset to the default ratio.
209 The default vertical/horizontal ratio is 0.33/0.5.
210*/
211void QwtPolarLayout::setLegendRatio( double ratio )
212{
213 setLegendPosition( legendPosition(), ratio );
214}
215
216/*!
217 \return The relative size of the legend in the plot.
218 \sa setLegendPosition()
219*/
220double QwtPolarLayout::legendRatio() const
221{
222 return d_data->legendRatio;
223}
224
225/*!
226 \return Geometry for the title
227 \sa activate(), invalidate()
228*/
229
230const QRectF &QwtPolarLayout::titleRect() const
231{
232 return d_data->titleRect;
233}
234
235/*!
236 \return Geometry for the legend
237 \sa activate(), invalidate()
238*/
239
240const QRectF &QwtPolarLayout::legendRect() const
241{
242 return d_data->legendRect;
243}
244
245/*!
246 \return Geometry for the canvas
247 \sa activate(), invalidate()
248*/
249const QRectF &QwtPolarLayout::canvasRect() const
250{
251 return d_data->canvasRect;
252}
253
254/*!
255 Invalidate the geometry of all components.
256 \sa activate()
257*/
258void QwtPolarLayout::invalidate()
259{
260 d_data->titleRect = d_data->legendRect = d_data->canvasRect = QRect();
261}
262
263/*!
264 Find the geometry for the legend
265 \param options Options how to layout the legend
266 \param rect Rectangle where to place the legend
267 \return Geometry for the legend
268*/
269
270QRectF QwtPolarLayout::layoutLegend( Options options, QRectF &rect ) const
271{
272 const QSizeF hint( d_data->layoutData.legend.hint );
273
274 int dim;
275 if ( d_data->legendPos == QwtPolarPlot::LeftLegend
276 || d_data->legendPos == QwtPolarPlot::RightLegend )
277 {
278 // We don't allow vertical legends to take more than
279 // half of the available space.
280
281 dim = qMin( hint.width(), rect.width() * d_data->legendRatio );
282
283 if ( !( options & IgnoreScrollbars ) )
284 {
285 if ( hint.height() > rect.height() )
286 {
287 // The legend will need additional
288 // space for the vertical scrollbar.
289
290 dim += d_data->layoutData.legend.vScrollBarWidth;
291 }
292 }
293 }
294 else
295 {
296 dim = qMin( hint.height(), rect.height() * d_data->legendRatio );
297 dim = qMax( dim, d_data->layoutData.legend.hScrollBarHeight );
298 }
299
300 QRectF legendRect = rect;
301 switch( d_data->legendPos )
302 {
303 case QwtPolarPlot::LeftLegend:
304 {
305 legendRect.setWidth( dim );
306 rect.setLeft( legendRect.right() );
307 break;
308 }
309 case QwtPolarPlot::RightLegend:
310 {
311 legendRect.setX( rect.right() - dim + 1 );
312 legendRect.setWidth( dim );
313 rect.setRight( legendRect.left() );
314 break;
315 }
316 case QwtPolarPlot::TopLegend:
317 {
318 legendRect.setHeight( dim );
319 rect.setTop( legendRect.bottom() );
320 break;
321 }
322 case QwtPolarPlot::BottomLegend:
323 {
324 legendRect.setY( rect.bottom() - dim + 1 );
325 legendRect.setHeight( dim );
326 rect.setBottom( legendRect.top() );
327 break;
328 }
329 case QwtPolarPlot::ExternalLegend:
330 break;
331 }
332
333 return legendRect;
334}
335
336/*!
337 \brief Recalculate the geometry of all components.
338
339 \param plot Plot to be layout
340 \param boundingRect Rect where to place the components
341 \param options Options
342
343 \sa invalidate(), titleRect(), legendRect(), canvasRect()
344*/
345void QwtPolarLayout::activate( const QwtPolarPlot *plot,
346 const QRectF &boundingRect, Options options )
347{
348 invalidate();
349
350 QRectF rect( boundingRect ); // undistributed rest of the plot rect
351 rect.adjust( d_data->margin, d_data->margin,
352 -d_data->margin, -d_data->margin );
353
354 // We extract all layout relevant data from the widgets
355 // and save them to d_data->layoutData.
356
357 d_data->layoutData.init( plot, rect );
358 if ( !( options & IgnoreLegend )
359 && d_data->legendPos != QwtPolarPlot::ExternalLegend
360 && plot->legend() && !plot->legend()->isEmpty() )
361 {
362 d_data->legendRect = layoutLegend( options, rect );
363 if ( d_data->layoutData.legend.frameWidth &&
364 !( options & IgnoreFrames ) )
365 {
366 // In case of a frame we have to insert a spacing.
367 // Otherwise the leading of the font separates
368 // legend and scale/canvas
369
370 switch( d_data->legendPos )
371 {
372 case QwtPolarPlot::LeftLegend:
373 rect.setLeft( rect.left() + d_data->spacing );
374 break;
375
376 case QwtPolarPlot::RightLegend:
377 rect.setRight( rect.right() - d_data->spacing );
378 break;
379
380 case QwtPolarPlot::TopLegend:
381 rect.setTop( rect.top() + d_data->spacing );
382 break;
383
384 case QwtPolarPlot::BottomLegend:
385 rect.setBottom( rect.bottom() - d_data->spacing );
386 break;
387
388 case QwtPolarPlot::ExternalLegend:
389 break; // suppress compiler warning
390 }
391 }
392 }
393
394 if ( !( options & IgnoreTitle ) &&
395 !d_data->layoutData.title.text.isEmpty() )
396 {
397 int h = d_data->layoutData.title.text.heightForWidth( rect.width() );
398 if ( !( options & IgnoreFrames ) )
399 h += 2 * d_data->layoutData.title.frameWidth;
400
401 d_data->titleRect = QRectF( rect.x(), rect.y(), rect.width(), h );
402
403 // subtract title
404 rect.setTop( rect.top() + h + d_data->spacing );
405 }
406
407 if ( plot->zoomPos().radius() > 0.0 || plot->zoomFactor() < 1.0 )
408 {
409 // In zoomed state we have no idea about the geometry that
410 // is best for the plot. So we use the complete rectangle
411 // accepting, that there might a lot of space wasted
412 // around the plot.
413
414 d_data->canvasRect = rect;
415 }
416 else
417 {
418 // In full state we know, that we want
419 // to display something circular.
420
421 const int dim = qMin( rect.width(), rect.height() );
422
423 d_data->canvasRect.setX( rect.center().x() - dim / 2 );
424 d_data->canvasRect.setY( rect.y() );
425 d_data->canvasRect.setSize( QSize( dim, dim ) );
426 }
427
428 if ( !d_data->legendRect.isEmpty() )
429 {
430 if ( d_data->legendPos == QwtPolarPlot::LeftLegend
431 || d_data->legendPos == QwtPolarPlot::RightLegend )
432 {
433 // We prefer to align the legend to the canvas - not to
434 // the complete plot - if possible.
435
436 if ( d_data->layoutData.legend.hint.height()
437 < d_data->canvasRect.height() )
438 {
439 d_data->legendRect.setY( d_data->canvasRect.y() );
440 d_data->legendRect.setHeight( d_data->canvasRect.height() );
441 }
442 }
443 }
444}
Note: See TracBrowser for help on using the repository browser.