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_layout.h"
|
---|
11 | #include "qwt_text.h"
|
---|
12 | #include "qwt_text_label.h"
|
---|
13 | #include "qwt_plot_canvas.h"
|
---|
14 | #include "qwt_scale_widget.h"
|
---|
15 | #include "qwt_legend.h"
|
---|
16 | #include <qscrollbar.h>
|
---|
17 | #include <qmath.h>
|
---|
18 |
|
---|
19 | class QwtPlotLayout::LayoutData
|
---|
20 | {
|
---|
21 | public:
|
---|
22 | void init( const QwtPlot *, const QRectF &rect );
|
---|
23 |
|
---|
24 | struct t_legendData
|
---|
25 | {
|
---|
26 | int frameWidth;
|
---|
27 | int vScrollBarWidth;
|
---|
28 | int hScrollBarHeight;
|
---|
29 | QSize hint;
|
---|
30 | } legend;
|
---|
31 |
|
---|
32 | struct t_titleData
|
---|
33 | {
|
---|
34 | QwtText text;
|
---|
35 | int frameWidth;
|
---|
36 | } title;
|
---|
37 |
|
---|
38 | struct t_scaleData
|
---|
39 | {
|
---|
40 | bool isEnabled;
|
---|
41 | const QwtScaleWidget *scaleWidget;
|
---|
42 | QFont scaleFont;
|
---|
43 | int start;
|
---|
44 | int end;
|
---|
45 | int baseLineOffset;
|
---|
46 | int tickOffset;
|
---|
47 | int dimWithoutTitle;
|
---|
48 | } scale[QwtPlot::axisCnt];
|
---|
49 |
|
---|
50 | struct t_canvasData
|
---|
51 | {
|
---|
52 | int frameWidth;
|
---|
53 | } canvas;
|
---|
54 | };
|
---|
55 |
|
---|
56 | /*
|
---|
57 | Extract all layout relevant data from the plot components
|
---|
58 | */
|
---|
59 |
|
---|
60 | void QwtPlotLayout::LayoutData::init( const QwtPlot *plot, const QRectF &rect )
|
---|
61 | {
|
---|
62 | // legend
|
---|
63 |
|
---|
64 | if ( plot->plotLayout()->legendPosition() != QwtPlot::ExternalLegend
|
---|
65 | && plot->legend() )
|
---|
66 | {
|
---|
67 | legend.frameWidth = plot->legend()->frameWidth();
|
---|
68 | legend.vScrollBarWidth =
|
---|
69 | plot->legend()->verticalScrollBar()->sizeHint().width();
|
---|
70 | legend.hScrollBarHeight =
|
---|
71 | plot->legend()->horizontalScrollBar()->sizeHint().height();
|
---|
72 |
|
---|
73 | const QSize hint = plot->legend()->sizeHint();
|
---|
74 |
|
---|
75 | int w = qMin( hint.width(), qFloor( rect.width() ) );
|
---|
76 | int h = plot->legend()->heightForWidth( w );
|
---|
77 | if ( h == 0 )
|
---|
78 | h = hint.height();
|
---|
79 |
|
---|
80 | if ( h > rect.height() )
|
---|
81 | w += legend.vScrollBarWidth;
|
---|
82 |
|
---|
83 | legend.hint = QSize( w, h );
|
---|
84 | }
|
---|
85 |
|
---|
86 | // title
|
---|
87 |
|
---|
88 | title.frameWidth = 0;
|
---|
89 | title.text = QwtText();
|
---|
90 |
|
---|
91 | if ( plot->titleLabel() )
|
---|
92 | {
|
---|
93 | const QwtTextLabel *label = plot->titleLabel();
|
---|
94 | title.text = label->text();
|
---|
95 | if ( !( title.text.testPaintAttribute( QwtText::PaintUsingTextFont ) ) )
|
---|
96 | title.text.setFont( label->font() );
|
---|
97 |
|
---|
98 | title.frameWidth = plot->titleLabel()->frameWidth();
|
---|
99 | }
|
---|
100 |
|
---|
101 | // scales
|
---|
102 |
|
---|
103 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
104 | {
|
---|
105 | if ( plot->axisEnabled( axis ) )
|
---|
106 | {
|
---|
107 | const QwtScaleWidget *scaleWidget = plot->axisWidget( axis );
|
---|
108 |
|
---|
109 | scale[axis].isEnabled = true;
|
---|
110 |
|
---|
111 | scale[axis].scaleWidget = scaleWidget;
|
---|
112 |
|
---|
113 | scale[axis].scaleFont = scaleWidget->font();
|
---|
114 |
|
---|
115 | scale[axis].start = scaleWidget->startBorderDist();
|
---|
116 | scale[axis].end = scaleWidget->endBorderDist();
|
---|
117 |
|
---|
118 | scale[axis].baseLineOffset = scaleWidget->margin();
|
---|
119 | scale[axis].tickOffset = scaleWidget->margin();
|
---|
120 | if ( scaleWidget->scaleDraw()->hasComponent(
|
---|
121 | QwtAbstractScaleDraw::Ticks ) )
|
---|
122 | {
|
---|
123 | scale[axis].tickOffset +=
|
---|
124 | scaleWidget->scaleDraw()->maxTickLength();
|
---|
125 | }
|
---|
126 |
|
---|
127 | scale[axis].dimWithoutTitle = scaleWidget->dimForLength(
|
---|
128 | QWIDGETSIZE_MAX, scale[axis].scaleFont );
|
---|
129 |
|
---|
130 | if ( !scaleWidget->title().isEmpty() )
|
---|
131 | {
|
---|
132 | scale[axis].dimWithoutTitle -=
|
---|
133 | scaleWidget->titleHeightForWidth( QWIDGETSIZE_MAX );
|
---|
134 | }
|
---|
135 | }
|
---|
136 | else
|
---|
137 | {
|
---|
138 | scale[axis].isEnabled = false;
|
---|
139 | scale[axis].start = 0;
|
---|
140 | scale[axis].end = 0;
|
---|
141 | scale[axis].baseLineOffset = 0;
|
---|
142 | scale[axis].tickOffset = 0;
|
---|
143 | scale[axis].dimWithoutTitle = 0;
|
---|
144 | }
|
---|
145 | }
|
---|
146 |
|
---|
147 | // canvas
|
---|
148 |
|
---|
149 | canvas.frameWidth = plot->canvas()->frameWidth();
|
---|
150 | }
|
---|
151 |
|
---|
152 | class QwtPlotLayout::PrivateData
|
---|
153 | {
|
---|
154 | public:
|
---|
155 | PrivateData():
|
---|
156 | spacing( 5 ),
|
---|
157 | alignCanvasToScales( false )
|
---|
158 | {
|
---|
159 | }
|
---|
160 |
|
---|
161 | QRectF titleRect;
|
---|
162 | QRectF legendRect;
|
---|
163 | QRectF scaleRect[QwtPlot::axisCnt];
|
---|
164 | QRectF canvasRect;
|
---|
165 |
|
---|
166 | QwtPlotLayout::LayoutData layoutData;
|
---|
167 |
|
---|
168 | QwtPlot::LegendPosition legendPos;
|
---|
169 | double legendRatio;
|
---|
170 | unsigned int spacing;
|
---|
171 | unsigned int canvasMargin[QwtPlot::axisCnt];
|
---|
172 | bool alignCanvasToScales;
|
---|
173 | };
|
---|
174 |
|
---|
175 | /*!
|
---|
176 | \brief Constructor
|
---|
177 | */
|
---|
178 |
|
---|
179 | QwtPlotLayout::QwtPlotLayout()
|
---|
180 | {
|
---|
181 | d_data = new PrivateData;
|
---|
182 |
|
---|
183 | setLegendPosition( QwtPlot::BottomLegend );
|
---|
184 | setCanvasMargin( 4 );
|
---|
185 |
|
---|
186 | invalidate();
|
---|
187 | }
|
---|
188 |
|
---|
189 | //! Destructor
|
---|
190 | QwtPlotLayout::~QwtPlotLayout()
|
---|
191 | {
|
---|
192 | delete d_data;
|
---|
193 | }
|
---|
194 |
|
---|
195 | /*!
|
---|
196 | Change a margin of the canvas. The margin is the space
|
---|
197 | above/below the scale ticks. A negative margin will
|
---|
198 | be set to -1, excluding the borders of the scales.
|
---|
199 |
|
---|
200 | \param margin New margin
|
---|
201 | \param axis One of QwtPlot::Axis. Specifies where the position of the margin.
|
---|
202 | -1 means margin at all borders.
|
---|
203 | \sa canvasMargin()
|
---|
204 |
|
---|
205 | \warning The margin will have no effect when alignCanvasToScales is true
|
---|
206 | */
|
---|
207 |
|
---|
208 | void QwtPlotLayout::setCanvasMargin( int margin, int axis )
|
---|
209 | {
|
---|
210 | if ( margin < -1 )
|
---|
211 | margin = -1;
|
---|
212 |
|
---|
213 | if ( axis == -1 )
|
---|
214 | {
|
---|
215 | for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
216 | d_data->canvasMargin[axis] = margin;
|
---|
217 | }
|
---|
218 | else if ( axis >= 0 && axis < QwtPlot::axisCnt )
|
---|
219 | d_data->canvasMargin[axis] = margin;
|
---|
220 | }
|
---|
221 |
|
---|
222 | /*!
|
---|
223 | \return Margin around the scale tick borders
|
---|
224 | \sa setCanvasMargin()
|
---|
225 | */
|
---|
226 | int QwtPlotLayout::canvasMargin( int axis ) const
|
---|
227 | {
|
---|
228 | if ( axis < 0 || axis >= QwtPlot::axisCnt )
|
---|
229 | return 0;
|
---|
230 |
|
---|
231 | return d_data->canvasMargin[axis];
|
---|
232 | }
|
---|
233 |
|
---|
234 | /*!
|
---|
235 | Change the align-canvas-to-axis-scales setting. The canvas may:
|
---|
236 | - extend beyond the axis scale ends to maximize its size,
|
---|
237 | - align with the axis scale ends to control its size.
|
---|
238 |
|
---|
239 | \param alignCanvasToScales New align-canvas-to-axis-scales setting
|
---|
240 |
|
---|
241 | \sa setCanvasMargin()
|
---|
242 | \note In this context the term 'scale' means the backbone of a scale.
|
---|
243 | \warning In case of alignCanvasToScales == true canvasMargin will have
|
---|
244 | no effect
|
---|
245 | */
|
---|
246 | void QwtPlotLayout::setAlignCanvasToScales( bool alignCanvasToScales )
|
---|
247 | {
|
---|
248 | d_data->alignCanvasToScales = alignCanvasToScales;
|
---|
249 | }
|
---|
250 |
|
---|
251 | /*!
|
---|
252 | Return the align-canvas-to-axis-scales setting. The canvas may:
|
---|
253 | - extend beyond the axis scale ends to maximize its size
|
---|
254 | - align with the axis scale ends to control its size.
|
---|
255 |
|
---|
256 | \return align-canvas-to-axis-scales setting
|
---|
257 | \sa setAlignCanvasToScales, setCanvasMargin()
|
---|
258 | \note In this context the term 'scale' means the backbone of a scale.
|
---|
259 | */
|
---|
260 | bool QwtPlotLayout::alignCanvasToScales() const
|
---|
261 | {
|
---|
262 | return d_data->alignCanvasToScales;
|
---|
263 | }
|
---|
264 |
|
---|
265 | /*!
|
---|
266 | Change the spacing of the plot. The spacing is the distance
|
---|
267 | between the plot components.
|
---|
268 |
|
---|
269 | \param spacing new spacing
|
---|
270 | \sa setMargin(), spacing()
|
---|
271 | */
|
---|
272 | void QwtPlotLayout::setSpacing( int spacing )
|
---|
273 | {
|
---|
274 | d_data->spacing = qMax( 0, spacing );
|
---|
275 | }
|
---|
276 |
|
---|
277 | /*!
|
---|
278 | \return spacing
|
---|
279 | \sa margin(), setSpacing()
|
---|
280 | */
|
---|
281 | int QwtPlotLayout::spacing() const
|
---|
282 | {
|
---|
283 | return d_data->spacing;
|
---|
284 | }
|
---|
285 |
|
---|
286 | /*!
|
---|
287 | \brief Specify the position of the legend
|
---|
288 | \param pos The legend's position.
|
---|
289 | \param ratio Ratio between legend and the bounding rect
|
---|
290 | of title, canvas and axes. The legend will be shrinked
|
---|
291 | if it would need more space than the given ratio.
|
---|
292 | The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
|
---|
293 | it will be reset to the default ratio.
|
---|
294 | The default vertical/horizontal ratio is 0.33/0.5.
|
---|
295 |
|
---|
296 | \sa QwtPlot::setLegendPosition()
|
---|
297 | */
|
---|
298 |
|
---|
299 | void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos, double ratio )
|
---|
300 | {
|
---|
301 | if ( ratio > 1.0 )
|
---|
302 | ratio = 1.0;
|
---|
303 |
|
---|
304 | switch ( pos )
|
---|
305 | {
|
---|
306 | case QwtPlot::TopLegend:
|
---|
307 | case QwtPlot::BottomLegend:
|
---|
308 | if ( ratio <= 0.0 )
|
---|
309 | ratio = 0.33;
|
---|
310 | d_data->legendRatio = ratio;
|
---|
311 | d_data->legendPos = pos;
|
---|
312 | break;
|
---|
313 | case QwtPlot::LeftLegend:
|
---|
314 | case QwtPlot::RightLegend:
|
---|
315 | if ( ratio <= 0.0 )
|
---|
316 | ratio = 0.5;
|
---|
317 | d_data->legendRatio = ratio;
|
---|
318 | d_data->legendPos = pos;
|
---|
319 | break;
|
---|
320 | case QwtPlot::ExternalLegend:
|
---|
321 | d_data->legendRatio = ratio; // meaningless
|
---|
322 | d_data->legendPos = pos;
|
---|
323 | default:
|
---|
324 | break;
|
---|
325 | }
|
---|
326 | }
|
---|
327 |
|
---|
328 | /*!
|
---|
329 | \brief Specify the position of the legend
|
---|
330 | \param pos The legend's position. Valid values are
|
---|
331 | \c QwtPlot::LeftLegend, \c QwtPlot::RightLegend,
|
---|
332 | \c QwtPlot::TopLegend, \c QwtPlot::BottomLegend.
|
---|
333 |
|
---|
334 | \sa QwtPlot::setLegendPosition()
|
---|
335 | */
|
---|
336 | void QwtPlotLayout::setLegendPosition( QwtPlot::LegendPosition pos )
|
---|
337 | {
|
---|
338 | setLegendPosition( pos, 0.0 );
|
---|
339 | }
|
---|
340 |
|
---|
341 | /*!
|
---|
342 | \return Position of the legend
|
---|
343 | \sa setLegendPosition(), QwtPlot::setLegendPosition(),
|
---|
344 | QwtPlot::legendPosition()
|
---|
345 | */
|
---|
346 | QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const
|
---|
347 | {
|
---|
348 | return d_data->legendPos;
|
---|
349 | }
|
---|
350 |
|
---|
351 | /*!
|
---|
352 | Specify the relative size of the legend in the plot
|
---|
353 | \param ratio Ratio between legend and the bounding rect
|
---|
354 | of title, canvas and axes. The legend will be shrinked
|
---|
355 | if it would need more space than the given ratio.
|
---|
356 | The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
|
---|
357 | it will be reset to the default ratio.
|
---|
358 | The default vertical/horizontal ratio is 0.33/0.5.
|
---|
359 | */
|
---|
360 | void QwtPlotLayout::setLegendRatio( double ratio )
|
---|
361 | {
|
---|
362 | setLegendPosition( legendPosition(), ratio );
|
---|
363 | }
|
---|
364 |
|
---|
365 | /*!
|
---|
366 | \return The relative size of the legend in the plot.
|
---|
367 | \sa setLegendPosition()
|
---|
368 | */
|
---|
369 | double QwtPlotLayout::legendRatio() const
|
---|
370 | {
|
---|
371 | return d_data->legendRatio;
|
---|
372 | }
|
---|
373 |
|
---|
374 | /*!
|
---|
375 | \return Geometry for the title
|
---|
376 | \sa activate(), invalidate()
|
---|
377 | */
|
---|
378 |
|
---|
379 | const QRectF &QwtPlotLayout::titleRect() const
|
---|
380 | {
|
---|
381 | return d_data->titleRect;
|
---|
382 | }
|
---|
383 |
|
---|
384 | /*!
|
---|
385 | \return Geometry for the legend
|
---|
386 | \sa activate(), invalidate()
|
---|
387 | */
|
---|
388 |
|
---|
389 | const QRectF &QwtPlotLayout::legendRect() const
|
---|
390 | {
|
---|
391 | return d_data->legendRect;
|
---|
392 | }
|
---|
393 |
|
---|
394 | /*!
|
---|
395 | \param axis Axis index
|
---|
396 | \return Geometry for the scale
|
---|
397 | \sa activate(), invalidate()
|
---|
398 | */
|
---|
399 |
|
---|
400 | const QRectF &QwtPlotLayout::scaleRect( int axis ) const
|
---|
401 | {
|
---|
402 | if ( axis < 0 || axis >= QwtPlot::axisCnt )
|
---|
403 | {
|
---|
404 | static QRectF dummyRect;
|
---|
405 | return dummyRect;
|
---|
406 | }
|
---|
407 | return d_data->scaleRect[axis];
|
---|
408 | }
|
---|
409 |
|
---|
410 | /*!
|
---|
411 | \return Geometry for the canvas
|
---|
412 | \sa activate(), invalidate()
|
---|
413 | */
|
---|
414 |
|
---|
415 | const QRectF &QwtPlotLayout::canvasRect() const
|
---|
416 | {
|
---|
417 | return d_data->canvasRect;
|
---|
418 | }
|
---|
419 |
|
---|
420 | /*!
|
---|
421 | Invalidate the geometry of all components.
|
---|
422 | \sa activate()
|
---|
423 | */
|
---|
424 | void QwtPlotLayout::invalidate()
|
---|
425 | {
|
---|
426 | d_data->titleRect = d_data->legendRect = d_data->canvasRect = QRect();
|
---|
427 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
428 | d_data->scaleRect[axis] = QRect();
|
---|
429 | }
|
---|
430 |
|
---|
431 | /*!
|
---|
432 | \brief Return a minimum size hint
|
---|
433 | \sa QwtPlot::minimumSizeHint()
|
---|
434 | */
|
---|
435 |
|
---|
436 | QSize QwtPlotLayout::minimumSizeHint( const QwtPlot *plot ) const
|
---|
437 | {
|
---|
438 | class ScaleData
|
---|
439 | {
|
---|
440 | public:
|
---|
441 | ScaleData()
|
---|
442 | {
|
---|
443 | w = h = minLeft = minRight = tickOffset = 0;
|
---|
444 | }
|
---|
445 |
|
---|
446 | int w;
|
---|
447 | int h;
|
---|
448 | int minLeft;
|
---|
449 | int minRight;
|
---|
450 | int tickOffset;
|
---|
451 | } scaleData[QwtPlot::axisCnt];
|
---|
452 |
|
---|
453 | int canvasBorder[QwtPlot::axisCnt];
|
---|
454 |
|
---|
455 | int axis;
|
---|
456 | for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
457 | {
|
---|
458 | if ( plot->axisEnabled( axis ) )
|
---|
459 | {
|
---|
460 | const QwtScaleWidget *scl = plot->axisWidget( axis );
|
---|
461 | ScaleData &sd = scaleData[axis];
|
---|
462 |
|
---|
463 | const QSize hint = scl->minimumSizeHint();
|
---|
464 | sd.w = hint.width();
|
---|
465 | sd.h = hint.height();
|
---|
466 | scl->getBorderDistHint( sd.minLeft, sd.minRight );
|
---|
467 | sd.tickOffset = scl->margin();
|
---|
468 | if ( scl->scaleDraw()->hasComponent( QwtAbstractScaleDraw::Ticks ) )
|
---|
469 | sd.tickOffset += scl->scaleDraw()->maxTickLength();
|
---|
470 | }
|
---|
471 |
|
---|
472 | canvasBorder[axis] = plot->canvas()->frameWidth() +
|
---|
473 | d_data->canvasMargin[axis] + 1;
|
---|
474 |
|
---|
475 | }
|
---|
476 |
|
---|
477 |
|
---|
478 | for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
479 | {
|
---|
480 | ScaleData &sd = scaleData[axis];
|
---|
481 | if ( sd.w && ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop ) )
|
---|
482 | {
|
---|
483 | if ( ( sd.minLeft > canvasBorder[QwtPlot::yLeft] )
|
---|
484 | && scaleData[QwtPlot::yLeft].w )
|
---|
485 | {
|
---|
486 | int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
|
---|
487 | if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
|
---|
488 | shiftLeft = scaleData[QwtPlot::yLeft].w;
|
---|
489 |
|
---|
490 | sd.w -= shiftLeft;
|
---|
491 | }
|
---|
492 | if ( ( sd.minRight > canvasBorder[QwtPlot::yRight] )
|
---|
493 | && scaleData[QwtPlot::yRight].w )
|
---|
494 | {
|
---|
495 | int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
|
---|
496 | if ( shiftRight > scaleData[QwtPlot::yRight].w )
|
---|
497 | shiftRight = scaleData[QwtPlot::yRight].w;
|
---|
498 |
|
---|
499 | sd.w -= shiftRight;
|
---|
500 | }
|
---|
501 | }
|
---|
502 |
|
---|
503 | if ( sd.h && ( axis == QwtPlot::yLeft || axis == QwtPlot::yRight ) )
|
---|
504 | {
|
---|
505 | if ( ( sd.minLeft > canvasBorder[QwtPlot::xBottom] ) &&
|
---|
506 | scaleData[QwtPlot::xBottom].h )
|
---|
507 | {
|
---|
508 | int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
|
---|
509 | if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
|
---|
510 | shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
|
---|
511 |
|
---|
512 | sd.h -= shiftBottom;
|
---|
513 | }
|
---|
514 | if ( ( sd.minLeft > canvasBorder[QwtPlot::xTop] ) &&
|
---|
515 | scaleData[QwtPlot::xTop].h )
|
---|
516 | {
|
---|
517 | int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
|
---|
518 | if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
|
---|
519 | shiftTop = scaleData[QwtPlot::xTop].tickOffset;
|
---|
520 |
|
---|
521 | sd.h -= shiftTop;
|
---|
522 | }
|
---|
523 | }
|
---|
524 | }
|
---|
525 |
|
---|
526 | const QwtPlotCanvas *canvas = plot->canvas();
|
---|
527 | const QSize minCanvasSize = canvas->minimumSize();
|
---|
528 |
|
---|
529 | int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w;
|
---|
530 | int cw = qMax( scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w )
|
---|
531 | + 2 * ( canvas->frameWidth() + 1 );
|
---|
532 | w += qMax( cw, minCanvasSize.width() );
|
---|
533 |
|
---|
534 | int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h;
|
---|
535 | int ch = qMax( scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h )
|
---|
536 | + 2 * ( canvas->frameWidth() + 1 );
|
---|
537 | h += qMax( ch, minCanvasSize.height() );
|
---|
538 |
|
---|
539 | const QwtTextLabel *title = plot->titleLabel();
|
---|
540 | if ( title && !title->text().isEmpty() )
|
---|
541 | {
|
---|
542 | // If only QwtPlot::yLeft or QwtPlot::yRight is showing,
|
---|
543 | // we center on the plot canvas.
|
---|
544 | const bool centerOnCanvas = !( plot->axisEnabled( QwtPlot::yLeft )
|
---|
545 | && plot->axisEnabled( QwtPlot::yRight ) );
|
---|
546 |
|
---|
547 | int titleW = w;
|
---|
548 | if ( centerOnCanvas )
|
---|
549 | {
|
---|
550 | titleW -= scaleData[QwtPlot::yLeft].w
|
---|
551 | + scaleData[QwtPlot::yRight].w;
|
---|
552 | }
|
---|
553 |
|
---|
554 | int titleH = title->heightForWidth( titleW );
|
---|
555 | if ( titleH > titleW ) // Compensate for a long title
|
---|
556 | {
|
---|
557 | w = titleW = titleH;
|
---|
558 | if ( centerOnCanvas )
|
---|
559 | {
|
---|
560 | w += scaleData[QwtPlot::yLeft].w
|
---|
561 | + scaleData[QwtPlot::yRight].w;
|
---|
562 | }
|
---|
563 |
|
---|
564 | titleH = title->heightForWidth( titleW );
|
---|
565 | }
|
---|
566 | h += titleH + d_data->spacing;
|
---|
567 | }
|
---|
568 |
|
---|
569 | // Compute the legend contribution
|
---|
570 |
|
---|
571 | const QwtLegend *legend = plot->legend();
|
---|
572 | if ( d_data->legendPos != QwtPlot::ExternalLegend
|
---|
573 | && legend && !legend->isEmpty() )
|
---|
574 | {
|
---|
575 | if ( d_data->legendPos == QwtPlot::LeftLegend
|
---|
576 | || d_data->legendPos == QwtPlot::RightLegend )
|
---|
577 | {
|
---|
578 | int legendW = legend->sizeHint().width();
|
---|
579 | int legendH = legend->heightForWidth( legendW );
|
---|
580 |
|
---|
581 | if ( legend->frameWidth() > 0 )
|
---|
582 | w += d_data->spacing;
|
---|
583 |
|
---|
584 | if ( legendH > h )
|
---|
585 | legendW += legend->verticalScrollBar()->sizeHint().height();
|
---|
586 |
|
---|
587 | if ( d_data->legendRatio < 1.0 )
|
---|
588 | legendW = qMin( legendW, int( w / ( 1.0 - d_data->legendRatio ) ) );
|
---|
589 |
|
---|
590 | w += legendW + d_data->spacing;
|
---|
591 | }
|
---|
592 | else // QwtPlot::Top, QwtPlot::Bottom
|
---|
593 | {
|
---|
594 | int legendW = qMin( legend->sizeHint().width(), w );
|
---|
595 | int legendH = legend->heightForWidth( legendW );
|
---|
596 |
|
---|
597 | if ( legend->frameWidth() > 0 )
|
---|
598 | h += d_data->spacing;
|
---|
599 |
|
---|
600 | if ( d_data->legendRatio < 1.0 )
|
---|
601 | legendH = qMin( legendH, int( h / ( 1.0 - d_data->legendRatio ) ) );
|
---|
602 |
|
---|
603 | h += legendH + d_data->spacing;
|
---|
604 | }
|
---|
605 | }
|
---|
606 |
|
---|
607 | return QSize( w, h );
|
---|
608 | }
|
---|
609 |
|
---|
610 | /*!
|
---|
611 | Find the geometry for the legend
|
---|
612 | \param options Options how to layout the legend
|
---|
613 | \param rect Rectangle where to place the legend
|
---|
614 | \return Geometry for the legend
|
---|
615 | \sa Options
|
---|
616 | */
|
---|
617 |
|
---|
618 | QRectF QwtPlotLayout::layoutLegend( Options options,
|
---|
619 | const QRectF &rect ) const
|
---|
620 | {
|
---|
621 | const QSize hint( d_data->layoutData.legend.hint );
|
---|
622 |
|
---|
623 | int dim;
|
---|
624 | if ( d_data->legendPos == QwtPlot::LeftLegend
|
---|
625 | || d_data->legendPos == QwtPlot::RightLegend )
|
---|
626 | {
|
---|
627 | // We don't allow vertical legends to take more than
|
---|
628 | // half of the available space.
|
---|
629 |
|
---|
630 | dim = qMin( hint.width(), int( rect.width() * d_data->legendRatio ) );
|
---|
631 |
|
---|
632 | if ( !( options & IgnoreScrollbars ) )
|
---|
633 | {
|
---|
634 | if ( hint.height() > rect.height() )
|
---|
635 | {
|
---|
636 | // The legend will need additional
|
---|
637 | // space for the vertical scrollbar.
|
---|
638 |
|
---|
639 | dim += d_data->layoutData.legend.vScrollBarWidth;
|
---|
640 | }
|
---|
641 | }
|
---|
642 | }
|
---|
643 | else
|
---|
644 | {
|
---|
645 | dim = qMin( hint.height(), int( rect.height() * d_data->legendRatio ) );
|
---|
646 | dim = qMax( dim, d_data->layoutData.legend.hScrollBarHeight );
|
---|
647 | }
|
---|
648 |
|
---|
649 | QRectF legendRect = rect;
|
---|
650 | switch ( d_data->legendPos )
|
---|
651 | {
|
---|
652 | case QwtPlot::LeftLegend:
|
---|
653 | legendRect.setWidth( dim );
|
---|
654 | break;
|
---|
655 | case QwtPlot::RightLegend:
|
---|
656 | legendRect.setX( rect.right() - dim );
|
---|
657 | legendRect.setWidth( dim );
|
---|
658 | break;
|
---|
659 | case QwtPlot::TopLegend:
|
---|
660 | legendRect.setHeight( dim );
|
---|
661 | break;
|
---|
662 | case QwtPlot::BottomLegend:
|
---|
663 | legendRect.setY( rect.bottom() - dim );
|
---|
664 | legendRect.setHeight( dim );
|
---|
665 | break;
|
---|
666 | case QwtPlot::ExternalLegend:
|
---|
667 | break;
|
---|
668 | }
|
---|
669 |
|
---|
670 | return legendRect;
|
---|
671 | }
|
---|
672 |
|
---|
673 | /*!
|
---|
674 | Align the legend to the canvas
|
---|
675 | \param canvasRect Geometry of the canvas
|
---|
676 | \param legendRect Maximum geometry for the legend
|
---|
677 | \return Geometry for the aligned legend
|
---|
678 | */
|
---|
679 | QRectF QwtPlotLayout::alignLegend( const QRectF &canvasRect,
|
---|
680 | const QRectF &legendRect ) const
|
---|
681 | {
|
---|
682 | QRectF alignedRect = legendRect;
|
---|
683 |
|
---|
684 | if ( d_data->legendPos == QwtPlot::BottomLegend
|
---|
685 | || d_data->legendPos == QwtPlot::TopLegend )
|
---|
686 | {
|
---|
687 | if ( d_data->layoutData.legend.hint.width() < canvasRect.width() )
|
---|
688 | {
|
---|
689 | alignedRect.setX( canvasRect.x() );
|
---|
690 | alignedRect.setWidth( canvasRect.width() );
|
---|
691 | }
|
---|
692 | }
|
---|
693 | else
|
---|
694 | {
|
---|
695 | if ( d_data->layoutData.legend.hint.height() < canvasRect.height() )
|
---|
696 | {
|
---|
697 | alignedRect.setY( canvasRect.y() );
|
---|
698 | alignedRect.setHeight( canvasRect.height() );
|
---|
699 | }
|
---|
700 | }
|
---|
701 |
|
---|
702 | return alignedRect;
|
---|
703 | }
|
---|
704 |
|
---|
705 | /*!
|
---|
706 | Expand all line breaks in text labels, and calculate the height
|
---|
707 | of their widgets in orientation of the text.
|
---|
708 |
|
---|
709 | \param options Options how to layout the legend
|
---|
710 | \param rect Bounding rect for title, axes and canvas.
|
---|
711 | \param dimTitle Expanded height of the title widget
|
---|
712 | \param dimAxis Expanded heights of the axis in axis orientation.
|
---|
713 |
|
---|
714 | \sa Options
|
---|
715 | */
|
---|
716 | void QwtPlotLayout::expandLineBreaks( int options, const QRectF &rect,
|
---|
717 | int &dimTitle, int dimAxis[QwtPlot::axisCnt] ) const
|
---|
718 | {
|
---|
719 | dimTitle = 0;
|
---|
720 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
721 | dimAxis[axis] = 0;
|
---|
722 |
|
---|
723 | int backboneOffset[QwtPlot::axisCnt];
|
---|
724 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
725 | {
|
---|
726 | backboneOffset[axis] = 0;
|
---|
727 | if ( !d_data->alignCanvasToScales )
|
---|
728 | backboneOffset[axis] += d_data->canvasMargin[axis];
|
---|
729 | if ( !( options & IgnoreFrames ) )
|
---|
730 | backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
|
---|
731 | }
|
---|
732 |
|
---|
733 | bool done = false;
|
---|
734 | while ( !done )
|
---|
735 | {
|
---|
736 | done = true;
|
---|
737 |
|
---|
738 | // the size for the 4 axis depend on each other. Expanding
|
---|
739 | // the height of a horizontal axis will shrink the height
|
---|
740 | // for the vertical axis, shrinking the height of a vertical
|
---|
741 | // axis will result in a line break what will expand the
|
---|
742 | // width and results in shrinking the width of a horizontal
|
---|
743 | // axis what might result in a line break of a horizontal
|
---|
744 | // axis ... . So we loop as long until no size changes.
|
---|
745 |
|
---|
746 | if ( !d_data->layoutData.title.text.isEmpty() )
|
---|
747 | {
|
---|
748 | int w = rect.width();
|
---|
749 |
|
---|
750 | if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
|
---|
751 | != d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
|
---|
752 | {
|
---|
753 | // center to the canvas
|
---|
754 | w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
|
---|
755 | }
|
---|
756 |
|
---|
757 | int d = qCeil( d_data->layoutData.title.text.heightForWidth( w ) );
|
---|
758 | if ( !( options & IgnoreFrames ) )
|
---|
759 | d += 2 * d_data->layoutData.title.frameWidth;
|
---|
760 |
|
---|
761 | if ( d > dimTitle )
|
---|
762 | {
|
---|
763 | dimTitle = d;
|
---|
764 | done = false;
|
---|
765 | }
|
---|
766 | }
|
---|
767 |
|
---|
768 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
769 | {
|
---|
770 | const struct LayoutData::t_scaleData &scaleData =
|
---|
771 | d_data->layoutData.scale[axis];
|
---|
772 |
|
---|
773 | if ( scaleData.isEnabled )
|
---|
774 | {
|
---|
775 | int length;
|
---|
776 | if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
|
---|
777 | {
|
---|
778 | length = rect.width() - dimAxis[QwtPlot::yLeft]
|
---|
779 | - dimAxis[QwtPlot::yRight];
|
---|
780 | length -= scaleData.start + scaleData.end;
|
---|
781 |
|
---|
782 | if ( dimAxis[QwtPlot::yRight] > 0 )
|
---|
783 | length -= 1;
|
---|
784 |
|
---|
785 | length += qMin( dimAxis[QwtPlot::yLeft],
|
---|
786 | scaleData.start - backboneOffset[QwtPlot::yLeft] );
|
---|
787 | length += qMin( dimAxis[QwtPlot::yRight],
|
---|
788 | scaleData.end - backboneOffset[QwtPlot::yRight] );
|
---|
789 | }
|
---|
790 | else // QwtPlot::yLeft, QwtPlot::yRight
|
---|
791 | {
|
---|
792 | length = rect.height() - dimAxis[QwtPlot::xTop]
|
---|
793 | - dimAxis[QwtPlot::xBottom];
|
---|
794 | length -= scaleData.start + scaleData.end;
|
---|
795 | length -= 1;
|
---|
796 |
|
---|
797 | if ( dimAxis[QwtPlot::xBottom] <= 0 )
|
---|
798 | length -= 1;
|
---|
799 | if ( dimAxis[QwtPlot::xTop] <= 0 )
|
---|
800 | length -= 1;
|
---|
801 |
|
---|
802 | if ( dimAxis[QwtPlot::xBottom] > 0 )
|
---|
803 | {
|
---|
804 | length += qMin(
|
---|
805 | d_data->layoutData.scale[QwtPlot::xBottom].tickOffset,
|
---|
806 | scaleData.start - backboneOffset[QwtPlot::xBottom] );
|
---|
807 | }
|
---|
808 | if ( dimAxis[QwtPlot::xTop] > 0 )
|
---|
809 | {
|
---|
810 | length += qMin(
|
---|
811 | d_data->layoutData.scale[QwtPlot::xTop].tickOffset,
|
---|
812 | scaleData.end - backboneOffset[QwtPlot::xTop] );
|
---|
813 | }
|
---|
814 |
|
---|
815 | if ( dimTitle > 0 )
|
---|
816 | length -= dimTitle + d_data->spacing;
|
---|
817 | }
|
---|
818 |
|
---|
819 | int d = scaleData.dimWithoutTitle;
|
---|
820 | if ( !scaleData.scaleWidget->title().isEmpty() )
|
---|
821 | {
|
---|
822 | d += scaleData.scaleWidget->titleHeightForWidth( length );
|
---|
823 | }
|
---|
824 |
|
---|
825 |
|
---|
826 | if ( d > dimAxis[axis] )
|
---|
827 | {
|
---|
828 | dimAxis[axis] = d;
|
---|
829 | done = false;
|
---|
830 | }
|
---|
831 | }
|
---|
832 | }
|
---|
833 | }
|
---|
834 | }
|
---|
835 |
|
---|
836 | /*!
|
---|
837 | Align the ticks of the axis to the canvas borders using
|
---|
838 | the empty corners.
|
---|
839 |
|
---|
840 | \sa Options
|
---|
841 | */
|
---|
842 |
|
---|
843 | void QwtPlotLayout::alignScales( int options,
|
---|
844 | QRectF &canvasRect, QRectF scaleRect[QwtPlot::axisCnt] ) const
|
---|
845 | {
|
---|
846 | int backboneOffset[QwtPlot::axisCnt];
|
---|
847 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
848 | {
|
---|
849 | backboneOffset[axis] = 0;
|
---|
850 | if ( !d_data->alignCanvasToScales )
|
---|
851 | backboneOffset[axis] += d_data->canvasMargin[axis];
|
---|
852 | if ( !( options & IgnoreFrames ) )
|
---|
853 | backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
|
---|
854 | }
|
---|
855 |
|
---|
856 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
857 | {
|
---|
858 | if ( !scaleRect[axis].isValid() )
|
---|
859 | continue;
|
---|
860 |
|
---|
861 | const int startDist = d_data->layoutData.scale[axis].start;
|
---|
862 | const int endDist = d_data->layoutData.scale[axis].end;
|
---|
863 |
|
---|
864 | QRectF &axisRect = scaleRect[axis];
|
---|
865 |
|
---|
866 | if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
|
---|
867 | {
|
---|
868 | const QRectF &leftScaleRect = scaleRect[QwtPlot::yLeft];
|
---|
869 | const int leftOffset =
|
---|
870 | backboneOffset[QwtPlot::yLeft] - startDist;
|
---|
871 |
|
---|
872 | if ( leftScaleRect.isValid() )
|
---|
873 | {
|
---|
874 | const int dx = leftOffset + leftScaleRect.width();
|
---|
875 | if ( d_data->alignCanvasToScales && dx < 0 )
|
---|
876 | {
|
---|
877 | /*
|
---|
878 | The axis needs more space than the width
|
---|
879 | of the left scale.
|
---|
880 | */
|
---|
881 | canvasRect.setLeft( qMax( canvasRect.left(),
|
---|
882 | axisRect.left() - dx ) );
|
---|
883 | }
|
---|
884 | else
|
---|
885 | {
|
---|
886 | const double minLeft = leftScaleRect.left();
|
---|
887 | const double left = axisRect.left() + leftOffset;
|
---|
888 | axisRect.setLeft( qMax( left, minLeft ) );
|
---|
889 | }
|
---|
890 | }
|
---|
891 | else
|
---|
892 | {
|
---|
893 | if ( d_data->alignCanvasToScales && leftOffset < 0 )
|
---|
894 | {
|
---|
895 | canvasRect.setLeft( qMax( canvasRect.left(),
|
---|
896 | axisRect.left() - leftOffset ) );
|
---|
897 | }
|
---|
898 | else
|
---|
899 | {
|
---|
900 | if ( leftOffset > 0 )
|
---|
901 | axisRect.setLeft( axisRect.left() + leftOffset );
|
---|
902 | }
|
---|
903 | }
|
---|
904 |
|
---|
905 | const QRectF &rightScaleRect = scaleRect[QwtPlot::yRight];
|
---|
906 | const int rightOffset =
|
---|
907 | backboneOffset[QwtPlot::yRight] - endDist + 1;
|
---|
908 |
|
---|
909 | if ( rightScaleRect.isValid() )
|
---|
910 | {
|
---|
911 | const int dx = rightOffset + rightScaleRect.width();
|
---|
912 | if ( d_data->alignCanvasToScales && dx < 0 )
|
---|
913 | {
|
---|
914 | /*
|
---|
915 | The axis needs more space than the width
|
---|
916 | of the right scale.
|
---|
917 | */
|
---|
918 | canvasRect.setRight( qMin( canvasRect.right(),
|
---|
919 | axisRect.right() + dx ) );
|
---|
920 | }
|
---|
921 |
|
---|
922 | const double maxRight = rightScaleRect.right();
|
---|
923 | const double right = axisRect.right() - rightOffset;
|
---|
924 | axisRect.setRight( qMin( right, maxRight ) );
|
---|
925 | }
|
---|
926 | else
|
---|
927 | {
|
---|
928 | if ( d_data->alignCanvasToScales && rightOffset < 0 )
|
---|
929 | {
|
---|
930 | canvasRect.setRight( qMin( canvasRect.right(),
|
---|
931 | axisRect.right() + rightOffset ) );
|
---|
932 | }
|
---|
933 | else
|
---|
934 | {
|
---|
935 | if ( rightOffset > 0 )
|
---|
936 | axisRect.setRight( axisRect.right() - rightOffset );
|
---|
937 | }
|
---|
938 | }
|
---|
939 | }
|
---|
940 | else // QwtPlot::yLeft, QwtPlot::yRight
|
---|
941 | {
|
---|
942 | const QRectF &bottomScaleRect = scaleRect[QwtPlot::xBottom];
|
---|
943 | const int bottomOffset =
|
---|
944 | backboneOffset[QwtPlot::xBottom] - endDist + 1;
|
---|
945 |
|
---|
946 | if ( bottomScaleRect.isValid() )
|
---|
947 | {
|
---|
948 | const int dy = bottomOffset + bottomScaleRect.height();
|
---|
949 | if ( d_data->alignCanvasToScales && dy < 0 )
|
---|
950 | {
|
---|
951 | /*
|
---|
952 | The axis needs more space than the height
|
---|
953 | of the bottom scale.
|
---|
954 | */
|
---|
955 | canvasRect.setBottom( qMin( canvasRect.bottom(),
|
---|
956 | axisRect.bottom() + dy ) );
|
---|
957 | }
|
---|
958 | else
|
---|
959 | {
|
---|
960 | const double maxBottom = bottomScaleRect.top() +
|
---|
961 | d_data->layoutData.scale[QwtPlot::xBottom].tickOffset;
|
---|
962 | const double bottom = axisRect.bottom() - bottomOffset;
|
---|
963 | axisRect.setBottom( qMin( bottom, maxBottom ) );
|
---|
964 | }
|
---|
965 | }
|
---|
966 | else
|
---|
967 | {
|
---|
968 | if ( d_data->alignCanvasToScales && bottomOffset < 0 )
|
---|
969 | {
|
---|
970 | canvasRect.setBottom( qMin( canvasRect.bottom(),
|
---|
971 | axisRect.bottom() + bottomOffset ) );
|
---|
972 | }
|
---|
973 | else
|
---|
974 | {
|
---|
975 | if ( bottomOffset > 0 )
|
---|
976 | axisRect.setBottom( axisRect.bottom() - bottomOffset );
|
---|
977 | }
|
---|
978 | }
|
---|
979 |
|
---|
980 | const QRectF &topScaleRect = scaleRect[QwtPlot::xTop];
|
---|
981 | const int topOffset = backboneOffset[QwtPlot::xTop] - startDist;
|
---|
982 |
|
---|
983 | if ( topScaleRect.isValid() )
|
---|
984 | {
|
---|
985 | const int dy = topOffset + topScaleRect.height();
|
---|
986 | if ( d_data->alignCanvasToScales && dy < 0 )
|
---|
987 | {
|
---|
988 | /*
|
---|
989 | The axis needs more space than the height
|
---|
990 | of the top scale.
|
---|
991 | */
|
---|
992 | canvasRect.setTop( qMax( canvasRect.top(),
|
---|
993 | axisRect.top() - dy ) );
|
---|
994 | }
|
---|
995 | else
|
---|
996 | {
|
---|
997 | const double minTop = topScaleRect.bottom() -
|
---|
998 | d_data->layoutData.scale[QwtPlot::xTop].tickOffset;
|
---|
999 | const double top = axisRect.top() + topOffset;
|
---|
1000 | axisRect.setTop( qMax( top, minTop ) );
|
---|
1001 | }
|
---|
1002 | }
|
---|
1003 | else
|
---|
1004 | {
|
---|
1005 | if ( d_data->alignCanvasToScales && topOffset < 0 )
|
---|
1006 | {
|
---|
1007 | canvasRect.setTop( qMax( canvasRect.top(),
|
---|
1008 | axisRect.top() - topOffset ) );
|
---|
1009 | }
|
---|
1010 | else
|
---|
1011 | {
|
---|
1012 | if ( topOffset > 0 )
|
---|
1013 | axisRect.setTop( axisRect.top() + topOffset );
|
---|
1014 | }
|
---|
1015 | }
|
---|
1016 | }
|
---|
1017 | }
|
---|
1018 |
|
---|
1019 | if ( d_data->alignCanvasToScales )
|
---|
1020 | {
|
---|
1021 | /*
|
---|
1022 | The canvas has been aligned to the scale with largest
|
---|
1023 | border distances. Now we have to realign the other scale.
|
---|
1024 | */
|
---|
1025 |
|
---|
1026 | int fw = 0;
|
---|
1027 | if ( !( options & IgnoreFrames ) )
|
---|
1028 | fw = d_data->layoutData.canvas.frameWidth;
|
---|
1029 |
|
---|
1030 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
1031 | {
|
---|
1032 | if ( !scaleRect[axis].isValid() )
|
---|
1033 | continue;
|
---|
1034 |
|
---|
1035 | if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )
|
---|
1036 | {
|
---|
1037 | scaleRect[axis].setLeft( canvasRect.left() + fw
|
---|
1038 | - d_data->layoutData.scale[axis].start );
|
---|
1039 | scaleRect[axis].setRight( canvasRect.right() - fw - 1
|
---|
1040 | + d_data->layoutData.scale[axis].end );
|
---|
1041 | }
|
---|
1042 | else
|
---|
1043 | {
|
---|
1044 | scaleRect[axis].setTop( canvasRect.top() + fw
|
---|
1045 | - d_data->layoutData.scale[axis].start );
|
---|
1046 | scaleRect[axis].setBottom( canvasRect.bottom() - fw - 1
|
---|
1047 | + d_data->layoutData.scale[axis].end );
|
---|
1048 | }
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | if ( scaleRect[QwtPlot::xTop].isValid() )
|
---|
1052 | scaleRect[QwtPlot::xTop].setBottom( canvasRect.top() );
|
---|
1053 | if ( scaleRect[QwtPlot::xBottom].isValid() )
|
---|
1054 | scaleRect[QwtPlot::xBottom].setTop( canvasRect.bottom() );
|
---|
1055 | if ( scaleRect[QwtPlot::yLeft].isValid() )
|
---|
1056 | scaleRect[QwtPlot::yLeft].setRight( canvasRect.left() );
|
---|
1057 | if ( scaleRect[QwtPlot::yRight].isValid() )
|
---|
1058 | scaleRect[QwtPlot::yRight].setLeft( canvasRect.right() );
|
---|
1059 | }
|
---|
1060 | }
|
---|
1061 |
|
---|
1062 | /*!
|
---|
1063 | \brief Recalculate the geometry of all components.
|
---|
1064 |
|
---|
1065 | \param plot Plot to be layout
|
---|
1066 | \param plotRect Rect where to place the components
|
---|
1067 | \param options Layout options
|
---|
1068 |
|
---|
1069 | \sa invalidate(), titleRect(),
|
---|
1070 | legendRect(), scaleRect(), canvasRect()
|
---|
1071 | */
|
---|
1072 | void QwtPlotLayout::activate( const QwtPlot *plot,
|
---|
1073 | const QRectF &plotRect, Options options )
|
---|
1074 | {
|
---|
1075 | invalidate();
|
---|
1076 |
|
---|
1077 | QRectF rect( plotRect ); // undistributed rest of the plot rect
|
---|
1078 |
|
---|
1079 | // We extract all layout relevant data from the widgets,
|
---|
1080 | // filter them through pfilter and save them to d_data->layoutData.
|
---|
1081 |
|
---|
1082 | d_data->layoutData.init( plot, rect );
|
---|
1083 |
|
---|
1084 | if ( !( options & IgnoreLegend )
|
---|
1085 | && d_data->legendPos != QwtPlot::ExternalLegend
|
---|
1086 | && plot->legend() && !plot->legend()->isEmpty() )
|
---|
1087 | {
|
---|
1088 | d_data->legendRect = layoutLegend( options, rect );
|
---|
1089 |
|
---|
1090 | // subtract d_data->legendRect from rect
|
---|
1091 |
|
---|
1092 | const QRegion region( rect.toRect() );
|
---|
1093 | rect = region.subtract( d_data->legendRect.toRect() ).boundingRect();
|
---|
1094 |
|
---|
1095 | switch ( d_data->legendPos )
|
---|
1096 | {
|
---|
1097 | case QwtPlot::LeftLegend:
|
---|
1098 | rect.setLeft( rect.left() + d_data->spacing );
|
---|
1099 | break;
|
---|
1100 | case QwtPlot::RightLegend:
|
---|
1101 | rect.setRight( rect.right() - d_data->spacing );
|
---|
1102 | break;
|
---|
1103 | case QwtPlot::TopLegend:
|
---|
1104 | rect.setTop( rect.top() + d_data->spacing );
|
---|
1105 | break;
|
---|
1106 | case QwtPlot::BottomLegend:
|
---|
1107 | rect.setBottom( rect.bottom() - d_data->spacing );
|
---|
1108 | break;
|
---|
1109 | case QwtPlot::ExternalLegend:
|
---|
1110 | break; // suppress compiler warning
|
---|
1111 | }
|
---|
1112 | }
|
---|
1113 |
|
---|
1114 | /*
|
---|
1115 | +---+-----------+---+
|
---|
1116 | | Title |
|
---|
1117 | +---+-----------+---+
|
---|
1118 | | | Axis | |
|
---|
1119 | +---+-----------+---+
|
---|
1120 | | A | | A |
|
---|
1121 | | x | Canvas | x |
|
---|
1122 | | i | | i |
|
---|
1123 | | s | | s |
|
---|
1124 | +---+-----------+---+
|
---|
1125 | | | Axis | |
|
---|
1126 | +---+-----------+---+
|
---|
1127 | */
|
---|
1128 |
|
---|
1129 | // axes and title include text labels. The height of each
|
---|
1130 | // label depends on its line breaks, that depend on the width
|
---|
1131 | // for the label. A line break in a horizontal text will reduce
|
---|
1132 | // the available width for vertical texts and vice versa.
|
---|
1133 | // expandLineBreaks finds the height/width for title and axes
|
---|
1134 | // including all line breaks.
|
---|
1135 |
|
---|
1136 | int dimTitle, dimAxes[QwtPlot::axisCnt];
|
---|
1137 | expandLineBreaks( options, rect, dimTitle, dimAxes );
|
---|
1138 |
|
---|
1139 | if ( dimTitle > 0 )
|
---|
1140 | {
|
---|
1141 | d_data->titleRect = QRect( rect.x(), rect.y(),
|
---|
1142 | rect.width(), dimTitle );
|
---|
1143 |
|
---|
1144 | if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
|
---|
1145 | d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
|
---|
1146 | {
|
---|
1147 | // if only one of the y axes is missing we align
|
---|
1148 | // the title centered to the canvas
|
---|
1149 |
|
---|
1150 | d_data->titleRect.setX( rect.x() + dimAxes[QwtPlot::yLeft] );
|
---|
1151 | d_data->titleRect.setWidth( rect.width()
|
---|
1152 | - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight] );
|
---|
1153 | }
|
---|
1154 |
|
---|
1155 | // subtract title
|
---|
1156 | rect.setTop( rect.top() + dimTitle + d_data->spacing );
|
---|
1157 | }
|
---|
1158 |
|
---|
1159 | d_data->canvasRect.setRect(
|
---|
1160 | rect.x() + dimAxes[QwtPlot::yLeft],
|
---|
1161 | rect.y() + dimAxes[QwtPlot::xTop],
|
---|
1162 | rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
|
---|
1163 | rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop] );
|
---|
1164 |
|
---|
1165 | for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
|
---|
1166 | {
|
---|
1167 | // set the rects for the axes
|
---|
1168 |
|
---|
1169 | if ( dimAxes[axis] )
|
---|
1170 | {
|
---|
1171 | int dim = dimAxes[axis];
|
---|
1172 | QRectF &scaleRect = d_data->scaleRect[axis];
|
---|
1173 |
|
---|
1174 | scaleRect = d_data->canvasRect;
|
---|
1175 | switch ( axis )
|
---|
1176 | {
|
---|
1177 | case QwtPlot::yLeft:
|
---|
1178 | scaleRect.setX( d_data->canvasRect.left() - dim );
|
---|
1179 | scaleRect.setWidth( dim );
|
---|
1180 | break;
|
---|
1181 | case QwtPlot::yRight:
|
---|
1182 | scaleRect.setX( d_data->canvasRect.right() );
|
---|
1183 | scaleRect.setWidth( dim );
|
---|
1184 | break;
|
---|
1185 | case QwtPlot::xBottom:
|
---|
1186 | scaleRect.setY( d_data->canvasRect.bottom() );
|
---|
1187 | scaleRect.setHeight( dim );
|
---|
1188 | break;
|
---|
1189 | case QwtPlot::xTop:
|
---|
1190 | scaleRect.setY( d_data->canvasRect.top() - dim );
|
---|
1191 | scaleRect.setHeight( dim );
|
---|
1192 | break;
|
---|
1193 | }
|
---|
1194 | scaleRect = scaleRect.normalized();
|
---|
1195 | }
|
---|
1196 | }
|
---|
1197 |
|
---|
1198 | // +---+-----------+---+
|
---|
1199 | // | <- Axis -> |
|
---|
1200 | // +-^-+-----------+-^-+
|
---|
1201 | // | | | | | |
|
---|
1202 | // | | | |
|
---|
1203 | // | A | | A |
|
---|
1204 | // | x | Canvas | x |
|
---|
1205 | // | i | | i |
|
---|
1206 | // | s | | s |
|
---|
1207 | // | | | |
|
---|
1208 | // | | | | | |
|
---|
1209 | // +-V-+-----------+-V-+
|
---|
1210 | // | <- Axis -> |
|
---|
1211 | // +---+-----------+---+
|
---|
1212 |
|
---|
1213 | // The ticks of the axes - not the labels above - should
|
---|
1214 | // be aligned to the canvas. So we try to use the empty
|
---|
1215 | // corners to extend the axes, so that the label texts
|
---|
1216 | // left/right of the min/max ticks are moved into them.
|
---|
1217 |
|
---|
1218 | alignScales( options, d_data->canvasRect, d_data->scaleRect );
|
---|
1219 |
|
---|
1220 | if ( !d_data->legendRect.isEmpty() )
|
---|
1221 | {
|
---|
1222 | // We prefer to align the legend to the canvas - not to
|
---|
1223 | // the complete plot - if possible.
|
---|
1224 |
|
---|
1225 | d_data->legendRect = alignLegend( d_data->canvasRect, d_data->legendRect );
|
---|
1226 | }
|
---|
1227 | }
|
---|