1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
3
* Copyright (C) 1997 Josef Wilgen
4
* Copyright (C) 2002 Uwe Rathmann
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
*****************************************************************************/
12
#include <qscrollbar.h>
14
#include "qwt_text_label.h"
15
#include "qwt_plot_canvas.h"
16
#include "qwt_scale_widget.h"
17
#include "qwt_legend.h"
18
#include "qwt_plot_layout.h"
20
class QwtPlotLayout::LayoutData
23
void init(const QwtPlot *, const QRect &rect);
42
const QwtScaleWidget *scaleWidget;
49
} scale[QwtPlot::axisCnt];
58
Extract all layout relevant data from the plot components
61
void QwtPlotLayout::LayoutData::init(const QwtPlot *plot, const QRect &rect)
65
if ( plot->plotLayout()->legendPosition() != QwtPlot::ExternalLegend
68
legend.frameWidth = plot->legend()->frameWidth();
69
legend.vScrollBarWidth =
70
plot->legend()->verticalScrollBar()->sizeHint().width();
71
legend.hScrollBarHeight =
72
plot->legend()->horizontalScrollBar()->sizeHint().height();
74
const QSize hint = plot->legend()->sizeHint();
76
int w = qwtMin(hint.width(), rect.width());
77
int h = plot->legend()->heightForWidth(w);
81
if ( h > rect.height() )
82
w += legend.vScrollBarWidth;
84
legend.hint = QSize(w, h);
90
title.text = QwtText();
92
if (plot->titleLabel() )
94
const QwtTextLabel *label = plot->titleLabel();
95
title.text = label->text();
96
if ( !(title.text.testPaintAttribute(QwtText::PaintUsingTextFont)) )
97
title.text.setFont(label->font());
99
title.frameWidth = plot->titleLabel()->frameWidth();
104
for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
106
if ( plot->axisEnabled(axis) )
108
const QwtScaleWidget *scaleWidget = plot->axisWidget(axis);
110
scale[axis].isEnabled = true;
112
scale[axis].scaleWidget = scaleWidget;
114
scale[axis].scaleFont = scaleWidget->font();
116
scale[axis].start = scaleWidget->startBorderDist();
117
scale[axis].end = scaleWidget->endBorderDist();
119
scale[axis].baseLineOffset = scaleWidget->margin();
120
scale[axis].tickOffset = scaleWidget->margin();
121
if ( scaleWidget->scaleDraw()->hasComponent(
122
QwtAbstractScaleDraw::Ticks) )
124
scale[axis].tickOffset +=
125
(int)scaleWidget->scaleDraw()->majTickLength();
128
scale[axis].dimWithoutTitle = scaleWidget->dimForLength(
129
QWIDGETSIZE_MAX, scale[axis].scaleFont);
131
if ( !scaleWidget->title().isEmpty() )
133
scale[axis].dimWithoutTitle -=
134
scaleWidget->titleHeightForWidth(QWIDGETSIZE_MAX);
139
scale[axis].isEnabled = false;
140
scale[axis].start = 0;
142
scale[axis].baseLineOffset = 0;
143
scale[axis].tickOffset = 0;
144
scale[axis].dimWithoutTitle = 0;
150
canvas.frameWidth = plot->canvas()->frameWidth();
153
class QwtPlotLayout::PrivateData
159
alignCanvasToScales(false)
165
QRect scaleRect[QwtPlot::axisCnt];
168
QwtPlotLayout::LayoutData layoutData;
170
QwtPlot::LegendPosition legendPos;
173
unsigned int spacing;
174
unsigned int canvasMargin[QwtPlot::axisCnt];
175
bool alignCanvasToScales;
182
QwtPlotLayout::QwtPlotLayout()
184
d_data = new PrivateData;
186
setLegendPosition(QwtPlot::BottomLegend);
193
QwtPlotLayout::~QwtPlotLayout()
199
Change the margin of the plot. The margin is the space
200
around all components.
202
\param margin new margin
203
\sa margin(), setSpacing(),
206
void QwtPlotLayout::setMargin(int margin)
210
d_data->margin = margin;
215
\sa setMargin(), spacing(), QwtPlot::margin()
217
int QwtPlotLayout::margin() const
219
return d_data->margin;
223
Change a margin of the canvas. The margin is the space
224
above/below the scale ticks. A negative margin will
225
be set to -1, excluding the borders of the scales.
227
\param margin New margin
228
\param axis One of QwtPlot::Axis. Specifies where the position of the margin.
229
-1 means margin at all borders.
232
\warning The margin will have no effect when alignCanvasToScales is true
235
void QwtPlotLayout::setCanvasMargin(int margin, int axis)
242
for (axis = 0; axis < QwtPlot::axisCnt; axis++)
243
d_data->canvasMargin[axis] = margin;
245
else if ( axis >= 0 || axis < QwtPlot::axisCnt )
246
d_data->canvasMargin[axis] = margin;
250
\return Margin around the scale tick borders
251
\sa setCanvasMargin()
253
int QwtPlotLayout::canvasMargin(int axis) const
255
if ( axis < 0 || axis >= QwtPlot::axisCnt )
258
return d_data->canvasMargin[axis];
262
Change the align-canvas-to-axis-scales setting. The canvas may:
263
- extend beyond the axis scale ends to maximize its size,
264
- align with the axis scale ends to control its size.
266
\param alignCanvasToScales New align-canvas-to-axis-scales setting
268
\sa setCanvasMargin()
269
\note In this context the term 'scale' means the backbone of a scale.
270
\warning In case of alignCanvasToScales == true canvasMargin will have
273
void QwtPlotLayout::setAlignCanvasToScales(bool alignCanvasToScales)
275
d_data->alignCanvasToScales = alignCanvasToScales;
279
Return the align-canvas-to-axis-scales setting. The canvas may:
280
- extend beyond the axis scale ends to maximize its size
281
- align with the axis scale ends to control its size.
283
\return align-canvas-to-axis-scales setting
284
\sa setAlignCanvasToScales, setCanvasMargin()
285
\note In this context the term 'scale' means the backbone of a scale.
287
bool QwtPlotLayout::alignCanvasToScales() const
289
return d_data->alignCanvasToScales;
293
Change the spacing of the plot. The spacing is the distance
294
between the plot components.
296
\param spacing new spacing
297
\sa setMargin(), spacing()
299
void QwtPlotLayout::setSpacing(int spacing)
301
d_data->spacing = qwtMax(0, spacing);
306
\sa margin(), setSpacing()
308
int QwtPlotLayout::spacing() const
310
return d_data->spacing;
314
\brief Specify the position of the legend
315
\param pos The legend's position.
316
\param ratio Ratio between legend and the bounding rect
317
of title, canvas and axes. The legend will be shrinked
318
if it would need more space than the given ratio.
319
The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
320
it will be reset to the default ratio.
321
The default vertical/horizontal ratio is 0.33/0.5.
323
\sa QwtPlot::setLegendPosition()
326
void QwtPlotLayout::setLegendPosition(QwtPlot::LegendPosition pos, double ratio)
333
case QwtPlot::TopLegend:
334
case QwtPlot::BottomLegend:
337
d_data->legendRatio = ratio;
338
d_data->legendPos = pos;
340
case QwtPlot::LeftLegend:
341
case QwtPlot::RightLegend:
344
d_data->legendRatio = ratio;
345
d_data->legendPos = pos;
347
case QwtPlot::ExternalLegend:
348
d_data->legendRatio = ratio; // meaningless
349
d_data->legendPos = pos;
356
\brief Specify the position of the legend
357
\param pos The legend's position. Valid values are
358
\c QwtPlot::LeftLegend, \c QwtPlot::RightLegend,
359
\c QwtPlot::TopLegend, \c QwtPlot::BottomLegend.
361
\sa QwtPlot::setLegendPosition()
363
void QwtPlotLayout::setLegendPosition(QwtPlot::LegendPosition pos)
365
setLegendPosition(pos, 0.0);
369
\return Position of the legend
370
\sa setLegendPosition(), QwtPlot::setLegendPosition(),
371
QwtPlot::legendPosition()
373
QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const
375
return d_data->legendPos;
379
Specify the relative size of the legend in the plot
380
\param ratio Ratio between legend and the bounding rect
381
of title, canvas and axes. The legend will be shrinked
382
if it would need more space than the given ratio.
383
The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
384
it will be reset to the default ratio.
385
The default vertical/horizontal ratio is 0.33/0.5.
387
void QwtPlotLayout::setLegendRatio(double ratio)
389
setLegendPosition(legendPosition(), ratio);
393
\return The relative size of the legend in the plot.
394
\sa setLegendPosition()
396
double QwtPlotLayout::legendRatio() const
398
return d_data->legendRatio;
402
\return Geometry for the title
403
\sa activate(), invalidate()
406
const QRect &QwtPlotLayout::titleRect() const
408
return d_data->titleRect;
412
\return Geometry for the legend
413
\sa activate(), invalidate()
416
const QRect &QwtPlotLayout::legendRect() const
418
return d_data->legendRect;
422
\param axis Axis index
423
\return Geometry for the scale
424
\sa activate(), invalidate()
427
const QRect &QwtPlotLayout::scaleRect(int axis) const
429
if ( axis < 0 || axis >= QwtPlot::axisCnt )
431
static QRect dummyRect;
434
return d_data->scaleRect[axis];
438
\return Geometry for the canvas
439
\sa activate(), invalidate()
442
const QRect &QwtPlotLayout::canvasRect() const
444
return d_data->canvasRect;
448
Invalidate the geometry of all components.
451
void QwtPlotLayout::invalidate()
453
d_data->titleRect = d_data->legendRect = d_data->canvasRect = QRect();
454
for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
455
d_data->scaleRect[axis] = QRect();
459
\brief Return a minimum size hint
460
\sa QwtPlot::minimumSizeHint()
463
QSize QwtPlotLayout::minimumSizeHint(const QwtPlot *plot) const
470
w = h = minLeft = minRight = tickOffset = 0;
478
} scaleData[QwtPlot::axisCnt];
480
int canvasBorder[QwtPlot::axisCnt];
483
for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
485
if ( plot->axisEnabled(axis) )
487
const QwtScaleWidget *scl = plot->axisWidget(axis);
488
ScaleData &sd = scaleData[axis];
490
const QSize hint = scl->minimumSizeHint();
492
sd.h = hint.height();
493
scl->getBorderDistHint(sd.minLeft, sd.minRight);
494
sd.tickOffset = scl->margin();
495
if ( scl->scaleDraw()->hasComponent(QwtAbstractScaleDraw::Ticks) )
496
sd.tickOffset += scl->scaleDraw()->majTickLength();
499
canvasBorder[axis] = plot->canvas()->frameWidth() +
500
d_data->canvasMargin[axis] + 1;
505
for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
507
ScaleData &sd = scaleData[axis];
508
if ( sd.w && (axis == QwtPlot::xBottom || axis == QwtPlot::xTop) )
510
if ( (sd.minLeft > canvasBorder[QwtPlot::yLeft])
511
&& scaleData[QwtPlot::yLeft].w )
513
int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
514
if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
515
shiftLeft = scaleData[QwtPlot::yLeft].w;
519
if ( (sd.minRight > canvasBorder[QwtPlot::yRight])
520
&& scaleData[QwtPlot::yRight].w )
522
int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
523
if ( shiftRight > scaleData[QwtPlot::yRight].w )
524
shiftRight = scaleData[QwtPlot::yRight].w;
530
if ( sd.h && (axis == QwtPlot::yLeft || axis == QwtPlot::yRight) )
532
if ( (sd.minLeft > canvasBorder[QwtPlot::xBottom]) &&
533
scaleData[QwtPlot::xBottom].h )
535
int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
536
if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
537
shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
541
if ( (sd.minLeft > canvasBorder[QwtPlot::xTop]) &&
542
scaleData[QwtPlot::xTop].h )
544
int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
545
if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
546
shiftTop = scaleData[QwtPlot::xTop].tickOffset;
553
const QwtPlotCanvas *canvas = plot->canvas();
554
const QSize minCanvasSize = canvas->minimumSize();
556
int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w;
557
int cw = qwtMax(scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w)
558
+ 2 * (canvas->frameWidth() + 1);
559
w += qwtMax(cw, minCanvasSize.width());
561
int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h;
562
int ch = qwtMax(scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h)
563
+ 2 * (canvas->frameWidth() + 1);
564
h += qwtMax(ch, minCanvasSize.height());
566
const QwtTextLabel *title = plot->titleLabel();
567
if (title && !title->text().isEmpty())
569
// If only QwtPlot::yLeft or QwtPlot::yRight is showing,
570
// we center on the plot canvas.
571
const bool centerOnCanvas = !(plot->axisEnabled(QwtPlot::yLeft)
572
&& plot->axisEnabled(QwtPlot::yRight));
575
if ( centerOnCanvas )
577
titleW -= scaleData[QwtPlot::yLeft].w
578
+ scaleData[QwtPlot::yRight].w;
581
int titleH = title->heightForWidth(titleW);
582
if ( titleH > titleW ) // Compensate for a long title
585
if ( centerOnCanvas )
587
w += scaleData[QwtPlot::yLeft].w
588
+ scaleData[QwtPlot::yRight].w;
591
titleH = title->heightForWidth(titleW);
593
h += titleH + d_data->spacing;
596
// Compute the legend contribution
598
const QwtLegend *legend = plot->legend();
599
if ( d_data->legendPos != QwtPlot::ExternalLegend
600
&& legend && !legend->isEmpty() )
602
if ( d_data->legendPos == QwtPlot::LeftLegend
603
|| d_data->legendPos == QwtPlot::RightLegend )
605
int legendW = legend->sizeHint().width();
606
int legendH = legend->heightForWidth(legendW);
608
if ( legend->frameWidth() > 0 )
609
w += d_data->spacing;
612
legendW += legend->verticalScrollBar()->sizeHint().height();
614
if ( d_data->legendRatio < 1.0 )
615
legendW = qwtMin(legendW, int(w / (1.0 - d_data->legendRatio)));
619
else // QwtPlot::Top, QwtPlot::Bottom
621
int legendW = qwtMin(legend->sizeHint().width(), w);
622
int legendH = legend->heightForWidth(legendW);
624
if ( legend->frameWidth() > 0 )
625
h += d_data->spacing;
627
if ( d_data->legendRatio < 1.0 )
628
legendH = qwtMin(legendH, int(h / (1.0 - d_data->legendRatio)));
634
w += 2 * d_data->margin;
635
h += 2 * d_data->margin;
637
return QSize( w, h );
641
Find the geometry for the legend
642
\param options Options how to layout the legend
643
\param rect Rectangle where to place the legend
644
\return Geometry for the legend
647
QRect QwtPlotLayout::layoutLegend(int options,
648
const QRect &rect) const
650
const QSize hint(d_data->layoutData.legend.hint);
653
if ( d_data->legendPos == QwtPlot::LeftLegend
654
|| d_data->legendPos == QwtPlot::RightLegend )
656
// We don't allow vertical legends to take more than
657
// half of the available space.
659
dim = qwtMin(hint.width(), int(rect.width() * d_data->legendRatio));
661
if ( !(options & IgnoreScrollbars) )
663
if ( hint.height() > rect.height() )
665
// The legend will need additional
666
// space for the vertical scrollbar.
668
dim += d_data->layoutData.legend.vScrollBarWidth;
674
dim = qwtMin(hint.height(), int(rect.height() * d_data->legendRatio));
675
dim = qwtMax(dim, d_data->layoutData.legend.hScrollBarHeight);
678
QRect legendRect = rect;
679
switch(d_data->legendPos)
681
case QwtPlot::LeftLegend:
682
legendRect.setWidth(dim);
684
case QwtPlot::RightLegend:
685
legendRect.setX(rect.right() - dim + 1);
686
legendRect.setWidth(dim);
688
case QwtPlot::TopLegend:
689
legendRect.setHeight(dim);
691
case QwtPlot::BottomLegend:
692
legendRect.setY(rect.bottom() - dim + 1);
693
legendRect.setHeight(dim);
695
case QwtPlot::ExternalLegend:
703
Align the legend to the canvas
704
\param canvasRect Geometry of the canvas
705
\param legendRect Maximum geometry for the legend
706
\return Geometry for the aligned legend
708
QRect QwtPlotLayout::alignLegend(const QRect &canvasRect,
709
const QRect &legendRect) const
711
QRect alignedRect = legendRect;
713
if ( d_data->legendPos == QwtPlot::BottomLegend
714
|| d_data->legendPos == QwtPlot::TopLegend )
716
if ( d_data->layoutData.legend.hint.width() < canvasRect.width() )
718
alignedRect.setX(canvasRect.x());
719
alignedRect.setWidth(canvasRect.width());
724
if ( d_data->layoutData.legend.hint.height() < canvasRect.height() )
726
alignedRect.setY(canvasRect.y());
727
alignedRect.setHeight(canvasRect.height());
735
Expand all line breaks in text labels, and calculate the height
736
of their widgets in orientation of the text.
738
\param options Options how to layout the legend
739
\param rect Bounding rect for title, axes and canvas.
740
\param dimTitle Expanded height of the title widget
741
\param dimAxis Expanded heights of the axis in axis orientation.
743
void QwtPlotLayout::expandLineBreaks(int options, const QRect &rect,
744
int &dimTitle, int dimAxis[QwtPlot::axisCnt]) const
747
for ( int i = 0; i < QwtPlot::axisCnt; i++ )
755
// the size for the 4 axis depend on each other. Expanding
756
// the height of a horizontal axis will shrink the height
757
// for the vertical axis, shrinking the height of a vertical
758
// axis will result in a line break what will expand the
759
// width and results in shrinking the width of a horizontal
760
// axis what might result in a line break of a horizontal
761
// axis ... . So we loop as long until no size changes.
763
if ( !d_data->layoutData.title.text.isEmpty() )
765
int w = rect.width();
767
if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
768
!= d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
770
// center to the canvas
771
w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
774
int d = d_data->layoutData.title.text.heightForWidth(w);
775
if ( !(options & IgnoreFrames) )
776
d += 2 * d_data->layoutData.title.frameWidth;
785
for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
787
int backboneOffset = d_data->canvasMargin[axis];
788
if ( !(options & IgnoreFrames) )
789
backboneOffset += d_data->layoutData.canvas.frameWidth;
791
const struct LayoutData::t_scaleData &scaleData =
792
d_data->layoutData.scale[axis];
794
if (scaleData.isEnabled)
797
if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
799
length = rect.width() - dimAxis[QwtPlot::yLeft]
800
- dimAxis[QwtPlot::yRight];
801
length += qwtMin(dimAxis[QwtPlot::yLeft],
802
scaleData.start - backboneOffset);
803
length += qwtMin(dimAxis[QwtPlot::yRight],
804
scaleData.end - backboneOffset);
806
else // QwtPlot::yLeft, QwtPlot::yRight
808
length = rect.height() - dimAxis[QwtPlot::xTop]
809
- dimAxis[QwtPlot::xBottom];
811
if ( dimAxis[QwtPlot::xBottom] > 0 )
814
d_data->layoutData.scale[QwtPlot::xBottom].tickOffset,
815
scaleData.start - backboneOffset);
817
if ( dimAxis[QwtPlot::xTop] > 0 )
820
d_data->layoutData.scale[QwtPlot::xTop].tickOffset,
821
scaleData.end - backboneOffset);
825
length -= dimTitle + d_data->spacing;
828
int d = scaleData.dimWithoutTitle;
829
if ( !scaleData.scaleWidget->title().isEmpty() )
831
d += scaleData.scaleWidget->titleHeightForWidth(length);
834
if ( d > dimAxis[axis] )
845
Align the ticks of the axis to the canvas borders using
849
void QwtPlotLayout::alignScales(int options,
850
QRect &canvasRect, QRect scaleRect[QwtPlot::axisCnt]) const
854
int backboneOffset[QwtPlot::axisCnt];
855
for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
857
backboneOffset[axis] = 0;
858
if ( !d_data->alignCanvasToScales )
859
backboneOffset[axis] += d_data->canvasMargin[axis];
860
if ( !(options & IgnoreFrames) )
861
backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
864
for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
866
if ( !scaleRect[axis].isValid() )
869
const int startDist = d_data->layoutData.scale[axis].start;
870
const int endDist = d_data->layoutData.scale[axis].end;
872
QRect &axisRect = scaleRect[axis];
874
if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
876
const int leftOffset =
877
backboneOffset[QwtPlot::yLeft] - startDist;
879
if ( scaleRect[QwtPlot::yLeft].isValid() )
881
int minLeft = scaleRect[QwtPlot::yLeft].left();
882
int left = axisRect.left() + leftOffset;
883
axisRect.setLeft(qwtMax(left, minLeft));
887
if ( d_data->alignCanvasToScales && leftOffset < 0 )
889
canvasRect.setLeft(qwtMax(canvasRect.left(),
890
axisRect.left() - leftOffset));
894
if ( leftOffset > 0 )
895
axisRect.setLeft(axisRect.left() + leftOffset);
899
const int rightOffset =
900
backboneOffset[QwtPlot::yRight] - endDist + 1;
902
if ( scaleRect[QwtPlot::yRight].isValid() )
904
int maxRight = scaleRect[QwtPlot::yRight].right();
905
int right = axisRect.right() - rightOffset;
906
axisRect.setRight(qwtMin(right, maxRight));
910
if ( d_data->alignCanvasToScales && rightOffset < 0 )
912
canvasRect.setRight( qwtMin(canvasRect.right(),
913
axisRect.right() + rightOffset) );
917
if ( rightOffset > 0 )
918
axisRect.setRight(axisRect.right() - rightOffset);
922
else // QwtPlot::yLeft, QwtPlot::yRight
924
const int bottomOffset =
925
backboneOffset[QwtPlot::xBottom] - endDist + 1;
927
if ( scaleRect[QwtPlot::xBottom].isValid() )
929
int maxBottom = scaleRect[QwtPlot::xBottom].top() +
930
d_data->layoutData.scale[QwtPlot::xBottom].tickOffset;
932
int bottom = axisRect.bottom() - bottomOffset;
933
axisRect.setBottom(qwtMin(bottom, maxBottom));
937
if ( d_data->alignCanvasToScales && bottomOffset < 0 )
939
canvasRect.setBottom(qwtMin(canvasRect.bottom(),
940
axisRect.bottom() + bottomOffset));
944
if ( bottomOffset > 0 )
945
axisRect.setBottom(axisRect.bottom() - bottomOffset);
949
const int topOffset = backboneOffset[QwtPlot::xTop] - startDist;
951
if ( scaleRect[QwtPlot::xTop].isValid() )
953
int minTop = scaleRect[QwtPlot::xTop].bottom() -
954
d_data->layoutData.scale[QwtPlot::xTop].tickOffset;
956
int top = axisRect.top() + topOffset;
957
axisRect.setTop(qwtMax(top, minTop));
961
if ( d_data->alignCanvasToScales && topOffset < 0 )
963
canvasRect.setTop(qwtMax(canvasRect.top(),
964
axisRect.top() - topOffset));
969
axisRect.setTop(axisRect.top() + topOffset);
975
if ( d_data->alignCanvasToScales )
978
The canvas has been aligned to the scale with largest
979
border distances. Now we have to realign the other scale.
983
if ( !(options & IgnoreFrames) )
984
fw = d_data->layoutData.canvas.frameWidth;
986
if ( scaleRect[QwtPlot::xBottom].isValid() &&
987
scaleRect[QwtPlot::xTop].isValid() )
989
for ( int axis = QwtPlot::xBottom; axis <= QwtPlot::xTop; axis++ )
991
scaleRect[axis].setLeft(canvasRect.left() + fw
992
- d_data->layoutData.scale[axis].start);
993
scaleRect[axis].setRight(canvasRect.right() - fw - 1
994
+ d_data->layoutData.scale[axis].end);
998
if ( scaleRect[QwtPlot::yLeft].isValid() &&
999
scaleRect[QwtPlot::yRight].isValid() )
1001
for ( int axis = QwtPlot::yLeft; axis <= QwtPlot::yRight; axis++ )
1003
scaleRect[axis].setTop(canvasRect.top() + fw
1004
- d_data->layoutData.scale[axis].start);
1005
scaleRect[axis].setBottom(canvasRect.bottom() - fw - 1
1006
+ d_data->layoutData.scale[axis].end);
1013
\brief Recalculate the geometry of all components.
1015
\param plot Plot to be layout
1016
\param plotRect Rect where to place the components
1017
\param options Options
1019
\sa invalidate(), titleRect(),
1020
legendRect(), scaleRect(), canvasRect()
1022
void QwtPlotLayout::activate(const QwtPlot *plot,
1023
const QRect &plotRect, int options)
1027
QRect rect(plotRect); // undistributed rest of the plot rect
1029
if ( !(options & IgnoreMargin) )
1031
// subtract the margin
1034
rect.x() + d_data->margin,
1035
rect.y() + d_data->margin,
1036
rect.width() - 2 * d_data->margin,
1037
rect.height() - 2 * d_data->margin
1041
// We extract all layout relevant data from the widgets,
1042
// filter them through pfilter and save them to d_data->layoutData.
1044
d_data->layoutData.init(plot, rect);
1046
if (!(options & IgnoreLegend)
1047
&& d_data->legendPos != QwtPlot::ExternalLegend
1048
&& plot->legend() && !plot->legend()->isEmpty() )
1050
d_data->legendRect = layoutLegend(options, rect);
1052
// subtract d_data->legendRect from rect
1054
const QRegion region(rect);
1055
rect = region.subtract(d_data->legendRect).boundingRect();
1057
if ( d_data->layoutData.legend.frameWidth &&
1058
!(options & IgnoreFrames ) )
1060
// In case of a frame we have to insert a spacing.
1061
// Otherwise the leading of the font separates
1062
// legend and scale/canvas
1064
switch(d_data->legendPos)
1066
case QwtPlot::LeftLegend:
1067
rect.setLeft(rect.left() + d_data->spacing);
1069
case QwtPlot::RightLegend:
1070
rect.setRight(rect.right() - d_data->spacing);
1072
case QwtPlot::TopLegend:
1073
rect.setTop(rect.top() + d_data->spacing);
1075
case QwtPlot::BottomLegend:
1076
rect.setBottom(rect.bottom() - d_data->spacing);
1078
case QwtPlot::ExternalLegend:
1079
break; // suppress compiler warning
1085
+---+-----------+---+
1087
+---+-----------+---+
1089
+---+-----------+---+
1094
+---+-----------+---+
1096
+---+-----------+---+
1100
// axes and title include text labels. The height of each
1101
// label depends on its line breaks, that depend on the width
1102
// for the label. A line break in a horizontal text will reduce
1103
// the available width for vertical texts and vice versa.
1104
// expandLineBreaks finds the height/width for title and axes
1105
// including all line breaks.
1107
int dimTitle, dimAxes[QwtPlot::axisCnt];
1108
expandLineBreaks(options, rect, dimTitle, dimAxes);
1112
d_data->titleRect = QRect(rect.x(), rect.y(),
1113
rect.width(), dimTitle);
1115
if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
1116
d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
1118
// if only one of the y axes is missing we align
1119
// the title centered to the canvas
1121
d_data->titleRect.setX(rect.x() + dimAxes[QwtPlot::yLeft]);
1122
d_data->titleRect.setWidth(rect.width()
1123
- dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight]);
1127
rect.setTop(rect.top() + dimTitle + d_data->spacing);
1130
d_data->canvasRect.setRect(
1131
rect.x() + dimAxes[QwtPlot::yLeft],
1132
rect.y() + dimAxes[QwtPlot::xTop],
1133
rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
1134
rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop]);
1136
for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
1138
// set the rects for the axes
1140
if ( dimAxes[axis] )
1142
int dim = dimAxes[axis];
1143
QRect &scaleRect = d_data->scaleRect[axis];
1145
scaleRect = d_data->canvasRect;
1148
case QwtPlot::yLeft:
1149
scaleRect.setX(d_data->canvasRect.left() - dim);
1150
scaleRect.setWidth(dim);
1152
case QwtPlot::yRight:
1153
scaleRect.setX(d_data->canvasRect.right() + 1);
1154
scaleRect.setWidth(dim);
1156
case QwtPlot::xBottom:
1157
scaleRect.setY(d_data->canvasRect.bottom() + 1);
1158
scaleRect.setHeight(dim);
1161
scaleRect.setY(d_data->canvasRect.top() - dim);
1162
scaleRect.setHeight(dim);
1165
#if QT_VERSION < 0x040000
1166
scaleRect = scaleRect.normalize();
1168
scaleRect = scaleRect.normalized();
1173
// +---+-----------+---+
1175
// +-^-+-----------+-^-+
1179
// | x | Canvas | x |
1184
// +-V-+-----------+-V-+
1186
// +---+-----------+---+
1188
// The ticks of the axes - not the labels above - should
1189
// be aligned to the canvas. So we try to use the empty
1190
// corners to extend the axes, so that the label texts
1191
// left/right of the min/max ticks are moved into them.
1193
alignScales(options, d_data->canvasRect, d_data->scaleRect);
1195
if (!d_data->legendRect.isEmpty() )
1197
// We prefer to align the legend to the canvas - not to
1198
// the complete plot - if possible.
1200
d_data->legendRect = alignLegend(d_data->canvasRect, d_data->legendRect);