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>
15
#include "qwt_text_label.h"
16
#include "qwt_plot_canvas.h"
17
#include "qwt_scale_widget.h"
18
#include "qwt_legend.h"
19
#include "qwt_plot_layout.h"
21
class QwtPlotLayout::LayoutData
24
void init(const QwtPlot *, const QRect &rect);
43
const QwtScaleWidget *scaleWidget;
50
} scale[QwtPlot::axisCnt];
59
Extract all layout relevant data from the plot components
62
void QwtPlotLayout::LayoutData::init(const QwtPlot *plot, const QRect &rect)
66
if ( plot->plotLayout()->legendPosition() != QwtPlot::ExternalLegend
69
legend.frameWidth = plot->legend()->frameWidth();
70
legend.vScrollBarWidth =
71
plot->legend()->verticalScrollBar()->sizeHint().width();
72
legend.hScrollBarHeight =
73
plot->legend()->horizontalScrollBar()->sizeHint().height();
75
const QSize hint = plot->legend()->sizeHint();
77
int w = qwtMin(hint.width(), rect.width());
78
int h = plot->legend()->heightForWidth(w);
82
if ( h > rect.height() )
83
w += legend.vScrollBarWidth;
85
legend.hint = QSize(w, h);
91
title.text = QwtText();
93
if (plot->titleLabel() )
95
const QwtTextLabel *label = plot->titleLabel();
96
title.text = label->text();
97
if ( !(title.text.testPaintAttribute(QwtText::PaintUsingTextFont)) )
98
title.text.setFont(label->font());
100
title.frameWidth = plot->titleLabel()->frameWidth();
105
for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
107
if ( plot->axisEnabled(axis) )
109
const QwtScaleWidget *scaleWidget = plot->axisWidget(axis);
111
scale[axis].isEnabled = true;
113
scale[axis].scaleWidget = scaleWidget;
115
scale[axis].scaleFont = scaleWidget->font();
117
scale[axis].start = scaleWidget->startBorderDist();
118
scale[axis].end = scaleWidget->endBorderDist();
120
scale[axis].baseLineOffset = scaleWidget->margin();
121
scale[axis].tickOffset = scaleWidget->margin();
122
if ( scaleWidget->scaleDraw()->hasComponent(
123
QwtAbstractScaleDraw::Ticks) )
125
scale[axis].tickOffset +=
126
(int)scaleWidget->scaleDraw()->majTickLength();
129
scale[axis].dimWithoutTitle = scaleWidget->dimForLength(
130
QWIDGETSIZE_MAX, scale[axis].scaleFont);
132
if ( !scaleWidget->title().isEmpty() )
134
scale[axis].dimWithoutTitle -=
135
scaleWidget->titleHeightForWidth(QWIDGETSIZE_MAX);
140
scale[axis].isEnabled = false;
141
scale[axis].start = 0;
143
scale[axis].baseLineOffset = 0;
144
scale[axis].tickOffset = 0;
145
scale[axis].dimWithoutTitle = 0;
151
canvas.frameWidth = plot->canvas()->frameWidth();
154
class QwtPlotLayout::PrivateData
160
alignCanvasToScales(false)
166
QRect scaleRect[QwtPlot::axisCnt];
169
QwtPlotLayout::LayoutData layoutData;
171
QwtPlot::LegendPosition legendPos;
174
unsigned int spacing;
175
unsigned int canvasMargin[QwtPlot::axisCnt];
176
bool alignCanvasToScales;
183
QwtPlotLayout::QwtPlotLayout()
185
d_data = new PrivateData;
187
setLegendPosition(QwtPlot::BottomLegend);
194
QwtPlotLayout::~QwtPlotLayout()
200
Change the margin of the plot. The margin is the space
201
around all components.
203
\param margin new margin
204
\sa margin(), setSpacing(),
207
void QwtPlotLayout::setMargin(int margin)
211
d_data->margin = margin;
216
\sa setMargin(), spacing(), QwtPlot::margin()
218
int QwtPlotLayout::margin() const
220
return d_data->margin;
224
Change a margin of the canvas. The margin is the space
225
above/below the scale ticks. A negative margin will
226
be set to -1, excluding the borders of the scales.
228
\param margin New margin
229
\param axis One of QwtPlot::Axis. Specifies where the position of the margin.
230
-1 means margin at all borders.
233
\warning The margin will have no effect when alignCanvasToScales is true
236
void QwtPlotLayout::setCanvasMargin(int margin, int axis)
243
for (axis = 0; axis < QwtPlot::axisCnt; axis++)
244
d_data->canvasMargin[axis] = margin;
246
else if ( axis >= 0 || axis < QwtPlot::axisCnt )
247
d_data->canvasMargin[axis] = margin;
251
\return Margin around the scale tick borders
252
\sa setCanvasMargin()
254
int QwtPlotLayout::canvasMargin(int axis) const
256
if ( axis < 0 || axis >= QwtPlot::axisCnt )
259
return d_data->canvasMargin[axis];
263
Change the align-canvas-to-axis-scales setting. The canvas may:
264
- extend beyond the axis scale ends to maximize its size,
265
- align with the axis scale ends to control its size.
267
\param alignCanvasToScales New align-canvas-to-axis-scales setting
269
\sa setCanvasMargin()
270
\note In this context the term 'scale' means the backbone of a scale.
271
\warning In case of alignCanvasToScales == true canvasMargin will have
274
void QwtPlotLayout::setAlignCanvasToScales(bool alignCanvasToScales)
276
d_data->alignCanvasToScales = alignCanvasToScales;
280
Return the align-canvas-to-axis-scales setting. The canvas may:
281
- extend beyond the axis scale ends to maximize its size
282
- align with the axis scale ends to control its size.
284
\return align-canvas-to-axis-scales setting
285
\sa setAlignCanvasToScales, setCanvasMargin()
286
\note In this context the term 'scale' means the backbone of a scale.
288
bool QwtPlotLayout::alignCanvasToScales() const
290
return d_data->alignCanvasToScales;
294
Change the spacing of the plot. The spacing is the distance
295
between the plot components.
297
\param spacing new spacing
298
\sa setMargin(), spacing()
300
void QwtPlotLayout::setSpacing(int spacing)
302
d_data->spacing = qwtMax(0, spacing);
307
\sa margin(), setSpacing()
309
int QwtPlotLayout::spacing() const
311
return d_data->spacing;
315
\brief Specify the position of the legend
316
\param pos The legend's position.
317
\param ratio Ratio between legend and the bounding rect
318
of title, canvas and axes. The legend will be shrinked
319
if it would need more space than the given ratio.
320
The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
321
it will be reset to the default ratio.
322
The default vertical/horizontal ratio is 0.33/0.5.
324
\sa QwtPlot::setLegendPosition()
327
void QwtPlotLayout::setLegendPosition(QwtPlot::LegendPosition pos, double ratio)
334
case QwtPlot::TopLegend:
335
case QwtPlot::BottomLegend:
338
d_data->legendRatio = ratio;
339
d_data->legendPos = pos;
341
case QwtPlot::LeftLegend:
342
case QwtPlot::RightLegend:
345
d_data->legendRatio = ratio;
346
d_data->legendPos = pos;
348
case QwtPlot::ExternalLegend:
349
d_data->legendRatio = ratio; // meaningless
350
d_data->legendPos = pos;
357
\brief Specify the position of the legend
358
\param pos The legend's position. Valid values are
359
\c QwtPlot::LeftLegend, \c QwtPlot::RightLegend,
360
\c QwtPlot::TopLegend, \c QwtPlot::BottomLegend.
362
\sa QwtPlot::setLegendPosition()
364
void QwtPlotLayout::setLegendPosition(QwtPlot::LegendPosition pos)
366
setLegendPosition(pos, 0.0);
370
\return Position of the legend
371
\sa setLegendPosition(), QwtPlot::setLegendPosition(),
372
QwtPlot::legendPosition()
374
QwtPlot::LegendPosition QwtPlotLayout::legendPosition() const
376
return d_data->legendPos;
380
Specify the relative size of the legend in the plot
381
\param ratio Ratio between legend and the bounding rect
382
of title, canvas and axes. The legend will be shrinked
383
if it would need more space than the given ratio.
384
The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
385
it will be reset to the default ratio.
386
The default vertical/horizontal ratio is 0.33/0.5.
388
void QwtPlotLayout::setLegendRatio(double ratio)
390
setLegendPosition(legendPosition(), ratio);
394
\return The relative size of the legend in the plot.
395
\sa setLegendPosition()
397
double QwtPlotLayout::legendRatio() const
399
return d_data->legendRatio;
403
\return Geometry for the title
404
\sa activate(), invalidate()
407
const QRect &QwtPlotLayout::titleRect() const
409
return d_data->titleRect;
413
\return Geometry for the legend
414
\sa activate(), invalidate()
417
const QRect &QwtPlotLayout::legendRect() const
419
return d_data->legendRect;
423
\param axis Axis index
424
\return Geometry for the scale
425
\sa activate(), invalidate()
428
const QRect &QwtPlotLayout::scaleRect(int axis) const
430
if ( axis < 0 || axis >= QwtPlot::axisCnt )
432
static QRect dummyRect;
435
return d_data->scaleRect[axis];
439
\return Geometry for the canvas
440
\sa activate(), invalidate()
443
const QRect &QwtPlotLayout::canvasRect() const
445
return d_data->canvasRect;
449
Invalidate the geometry of all components.
452
void QwtPlotLayout::invalidate()
454
d_data->titleRect = d_data->legendRect = d_data->canvasRect = QRect();
455
for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
456
d_data->scaleRect[axis] = QRect();
460
\brief Return a minimum size hint
461
\sa QwtPlot::minimumSizeHint()
464
QSize QwtPlotLayout::minimumSizeHint(const QwtPlot *plot) const
471
w = h = minLeft = minRight = tickOffset = 0;
479
} scaleData[QwtPlot::axisCnt];
481
int canvasBorder[QwtPlot::axisCnt];
484
for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
486
if ( plot->axisEnabled(axis) )
488
const QwtScaleWidget *scl = plot->axisWidget(axis);
489
ScaleData &sd = scaleData[axis];
491
const QSize hint = scl->minimumSizeHint();
493
sd.h = hint.height();
494
scl->getBorderDistHint(sd.minLeft, sd.minRight);
495
sd.tickOffset = scl->margin();
496
if ( scl->scaleDraw()->hasComponent(QwtAbstractScaleDraw::Ticks) )
497
sd.tickOffset += scl->scaleDraw()->majTickLength();
500
canvasBorder[axis] = plot->canvas()->frameWidth() +
501
d_data->canvasMargin[axis] + 1;
506
for ( axis = 0; axis < QwtPlot::axisCnt; axis++ )
508
ScaleData &sd = scaleData[axis];
509
if ( sd.w && (axis == QwtPlot::xBottom || axis == QwtPlot::xTop) )
511
if ( (sd.minLeft > canvasBorder[QwtPlot::yLeft])
512
&& scaleData[QwtPlot::yLeft].w )
514
int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft];
515
if ( shiftLeft > scaleData[QwtPlot::yLeft].w )
516
shiftLeft = scaleData[QwtPlot::yLeft].w;
520
if ( (sd.minRight > canvasBorder[QwtPlot::yRight])
521
&& scaleData[QwtPlot::yRight].w )
523
int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight];
524
if ( shiftRight > scaleData[QwtPlot::yRight].w )
525
shiftRight = scaleData[QwtPlot::yRight].w;
531
if ( sd.h && (axis == QwtPlot::yLeft || axis == QwtPlot::yRight) )
533
if ( (sd.minLeft > canvasBorder[QwtPlot::xBottom]) &&
534
scaleData[QwtPlot::xBottom].h )
536
int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom];
537
if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset )
538
shiftBottom = scaleData[QwtPlot::xBottom].tickOffset;
542
if ( (sd.minLeft > canvasBorder[QwtPlot::xTop]) &&
543
scaleData[QwtPlot::xTop].h )
545
int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop];
546
if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset )
547
shiftTop = scaleData[QwtPlot::xTop].tickOffset;
554
const QwtPlotCanvas *canvas = plot->canvas();
555
const QSize minCanvasSize = canvas->minimumSize();
557
int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w;
558
int cw = qwtMax(scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w)
559
+ 2 * (canvas->frameWidth() + 1);
560
w += qwtMax(cw, minCanvasSize.width());
562
int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h;
563
int ch = qwtMax(scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h)
564
+ 2 * (canvas->frameWidth() + 1);
565
h += qwtMax(ch, minCanvasSize.height());
567
const QwtTextLabel *title = plot->titleLabel();
568
if (title && !title->text().isEmpty())
570
// If only QwtPlot::yLeft or QwtPlot::yRight is showing,
571
// we center on the plot canvas.
572
const bool centerOnCanvas = !(plot->axisEnabled(QwtPlot::yLeft)
573
&& plot->axisEnabled(QwtPlot::yRight));
576
if ( centerOnCanvas )
578
titleW -= scaleData[QwtPlot::yLeft].w
579
+ scaleData[QwtPlot::yRight].w;
582
int titleH = title->heightForWidth(titleW);
583
if ( titleH > titleW ) // Compensate for a long title
586
if ( centerOnCanvas )
588
w += scaleData[QwtPlot::yLeft].w
589
+ scaleData[QwtPlot::yRight].w;
592
titleH = title->heightForWidth(titleW);
594
h += titleH + d_data->spacing;
597
// Compute the legend contribution
599
const QwtLegend *legend = plot->legend();
600
if ( d_data->legendPos != QwtPlot::ExternalLegend
601
&& legend && !legend->isEmpty() )
603
if ( d_data->legendPos == QwtPlot::LeftLegend
604
|| d_data->legendPos == QwtPlot::RightLegend )
606
int legendW = legend->sizeHint().width();
607
int legendH = legend->heightForWidth(legendW);
609
if ( legend->frameWidth() > 0 )
610
w += d_data->spacing;
613
legendW += legend->verticalScrollBar()->sizeHint().height();
615
if ( d_data->legendRatio < 1.0 )
616
legendW = qwtMin(legendW, int(w / (1.0 - d_data->legendRatio)));
620
else // QwtPlot::Top, QwtPlot::Bottom
622
int legendW = qwtMin(legend->sizeHint().width(), w);
623
int legendH = legend->heightForWidth(legendW);
625
if ( legend->frameWidth() > 0 )
626
h += d_data->spacing;
628
if ( d_data->legendRatio < 1.0 )
629
legendH = qwtMin(legendH, int(h / (1.0 - d_data->legendRatio)));
635
w += 2 * d_data->margin;
636
h += 2 * d_data->margin;
638
return QSize( w, h );
642
Find the geometry for the legend
643
\param options Options how to layout the legend
644
\param rect Rectangle where to place the legend
645
\return Geometry for the legend
648
QRect QwtPlotLayout::layoutLegend(int options,
649
const QRect &rect) const
651
const QSize hint(d_data->layoutData.legend.hint);
654
if ( d_data->legendPos == QwtPlot::LeftLegend
655
|| d_data->legendPos == QwtPlot::RightLegend )
657
// We don't allow vertical legends to take more than
658
// half of the available space.
660
dim = qwtMin(hint.width(), int(rect.width() * d_data->legendRatio));
662
if ( !(options & IgnoreScrollbars) )
664
if ( hint.height() > rect.height() )
666
// The legend will need additional
667
// space for the vertical scrollbar.
669
dim += d_data->layoutData.legend.vScrollBarWidth;
675
dim = qwtMin(hint.height(), int(rect.height() * d_data->legendRatio));
676
dim = qwtMax(dim, d_data->layoutData.legend.hScrollBarHeight);
679
QRect legendRect = rect;
680
switch(d_data->legendPos)
682
case QwtPlot::LeftLegend:
683
legendRect.setWidth(dim);
685
case QwtPlot::RightLegend:
686
legendRect.setX(rect.right() - dim + 1);
687
legendRect.setWidth(dim);
689
case QwtPlot::TopLegend:
690
legendRect.setHeight(dim);
692
case QwtPlot::BottomLegend:
693
legendRect.setY(rect.bottom() - dim + 1);
694
legendRect.setHeight(dim);
696
case QwtPlot::ExternalLegend:
704
Align the legend to the canvas
705
\param canvasRect Geometry of the canvas
706
\param legendRect Maximum geometry for the legend
707
\return Geometry for the aligned legend
709
QRect QwtPlotLayout::alignLegend(const QRect &canvasRect,
710
const QRect &legendRect) const
712
QRect alignedRect = legendRect;
714
if ( d_data->legendPos == QwtPlot::BottomLegend
715
|| d_data->legendPos == QwtPlot::TopLegend )
717
if ( d_data->layoutData.legend.hint.width() < canvasRect.width() )
719
alignedRect.setX(canvasRect.x());
720
alignedRect.setWidth(canvasRect.width());
725
if ( d_data->layoutData.legend.hint.height() < canvasRect.height() )
727
alignedRect.setY(canvasRect.y());
728
alignedRect.setHeight(canvasRect.height());
736
Expand all line breaks in text labels, and calculate the height
737
of their widgets in orientation of the text.
739
\param options Options how to layout the legend
740
\param rect Bounding rect for title, axes and canvas.
741
\param dimTitle Expanded height of the title widget
742
\param dimAxis Expanded heights of the axis in axis orientation.
744
void QwtPlotLayout::expandLineBreaks(int options, const QRect &rect,
745
int &dimTitle, int dimAxis[QwtPlot::axisCnt]) const
748
for ( int i = 0; i < QwtPlot::axisCnt; i++ )
756
// the size for the 4 axis depend on each other. Expanding
757
// the height of a horizontal axis will shrink the height
758
// for the vertical axis, shrinking the height of a vertical
759
// axis will result in a line break what will expand the
760
// width and results in shrinking the width of a horizontal
761
// axis what might result in a line break of a horizontal
762
// axis ... . So we loop as long until no size changes.
764
if ( !d_data->layoutData.title.text.isEmpty() )
766
int w = rect.width();
768
if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
769
!= d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
771
// center to the canvas
772
w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
775
int d = d_data->layoutData.title.text.heightForWidth(w);
776
if ( !(options & IgnoreFrames) )
777
d += 2 * d_data->layoutData.title.frameWidth;
786
for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
788
int backboneOffset = d_data->canvasMargin[axis];
789
if ( !(options & IgnoreFrames) )
790
backboneOffset += d_data->layoutData.canvas.frameWidth;
792
const struct LayoutData::t_scaleData &scaleData =
793
d_data->layoutData.scale[axis];
795
if (scaleData.isEnabled)
798
if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
800
length = rect.width() - dimAxis[QwtPlot::yLeft]
801
- dimAxis[QwtPlot::yRight];
802
length += qwtMin(dimAxis[QwtPlot::yLeft],
803
scaleData.start - backboneOffset);
804
length += qwtMin(dimAxis[QwtPlot::yRight],
805
scaleData.end - backboneOffset);
807
else // QwtPlot::yLeft, QwtPlot::yRight
809
length = rect.height() - dimAxis[QwtPlot::xTop]
810
- dimAxis[QwtPlot::xBottom];
812
if ( dimAxis[QwtPlot::xBottom] > 0 )
815
d_data->layoutData.scale[QwtPlot::xBottom].tickOffset,
816
scaleData.start - backboneOffset);
818
if ( dimAxis[QwtPlot::xTop] > 0 )
821
d_data->layoutData.scale[QwtPlot::xTop].tickOffset,
822
scaleData.end - backboneOffset);
826
length -= dimTitle + d_data->spacing;
829
int d = scaleData.dimWithoutTitle;
830
if ( !scaleData.scaleWidget->title().isEmpty() )
832
d += scaleData.scaleWidget->titleHeightForWidth(length);
835
if ( d > dimAxis[axis] )
846
Align the ticks of the axis to the canvas borders using
850
void QwtPlotLayout::alignScales(int options,
851
QRect &canvasRect, QRect scaleRect[QwtPlot::axisCnt]) const
855
int backboneOffset[QwtPlot::axisCnt];
856
for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
858
backboneOffset[axis] = 0;
859
if ( !d_data->alignCanvasToScales )
860
backboneOffset[axis] += d_data->canvasMargin[axis];
861
if ( !(options & IgnoreFrames) )
862
backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
865
for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
867
if ( !scaleRect[axis].isValid() )
870
const int startDist = d_data->layoutData.scale[axis].start;
871
const int endDist = d_data->layoutData.scale[axis].end;
873
QRect &axisRect = scaleRect[axis];
875
if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
877
const int leftOffset =
878
backboneOffset[QwtPlot::yLeft] - startDist;
880
if ( scaleRect[QwtPlot::yLeft].isValid() )
882
int minLeft = scaleRect[QwtPlot::yLeft].left();
883
int left = axisRect.left() + leftOffset;
884
axisRect.setLeft(qwtMax(left, minLeft));
888
if ( d_data->alignCanvasToScales && leftOffset < 0 )
890
canvasRect.setLeft(qwtMax(canvasRect.left(),
891
axisRect.left() - leftOffset));
895
if ( leftOffset > 0 )
896
axisRect.setLeft(axisRect.left() + leftOffset);
900
const int rightOffset =
901
backboneOffset[QwtPlot::yRight] - endDist + 1;
903
if ( scaleRect[QwtPlot::yRight].isValid() )
905
int maxRight = scaleRect[QwtPlot::yRight].right();
906
int right = axisRect.right() - rightOffset;
907
axisRect.setRight(qwtMin(right, maxRight));
911
if ( d_data->alignCanvasToScales && rightOffset < 0 )
913
canvasRect.setRight( qwtMin(canvasRect.right(),
914
axisRect.right() + rightOffset) );
918
if ( rightOffset > 0 )
919
axisRect.setRight(axisRect.right() - rightOffset);
923
else // QwtPlot::yLeft, QwtPlot::yRight
925
const int bottomOffset =
926
backboneOffset[QwtPlot::xBottom] - endDist + 1;
928
if ( scaleRect[QwtPlot::xBottom].isValid() )
930
int maxBottom = scaleRect[QwtPlot::xBottom].top() +
931
d_data->layoutData.scale[QwtPlot::xBottom].tickOffset;
933
int bottom = axisRect.bottom() - bottomOffset;
934
axisRect.setBottom(qwtMin(bottom, maxBottom));
938
if ( d_data->alignCanvasToScales && bottomOffset < 0 )
940
canvasRect.setBottom(qwtMin(canvasRect.bottom(),
941
axisRect.bottom() + bottomOffset));
945
if ( bottomOffset > 0 )
946
axisRect.setBottom(axisRect.bottom() - bottomOffset);
950
const int topOffset = backboneOffset[QwtPlot::xTop] - startDist;
952
if ( scaleRect[QwtPlot::xTop].isValid() )
954
int minTop = scaleRect[QwtPlot::xTop].bottom() -
955
d_data->layoutData.scale[QwtPlot::xTop].tickOffset;
957
int top = axisRect.top() + topOffset;
958
axisRect.setTop(qwtMax(top, minTop));
962
if ( d_data->alignCanvasToScales && topOffset < 0 )
964
canvasRect.setTop(qwtMax(canvasRect.top(),
965
axisRect.top() - topOffset));
970
axisRect.setTop(axisRect.top() + topOffset);
976
if ( d_data->alignCanvasToScales )
979
The canvas has been aligned to the scale with largest
980
border distances. Now we have to realign the other scale.
984
if ( !(options & IgnoreFrames) )
985
fw = d_data->layoutData.canvas.frameWidth;
987
if ( scaleRect[QwtPlot::xBottom].isValid() &&
988
scaleRect[QwtPlot::xTop].isValid() )
990
for ( int axis = QwtPlot::xBottom; axis <= QwtPlot::xTop; axis++ )
992
scaleRect[axis].setLeft(canvasRect.left() + fw
993
- d_data->layoutData.scale[axis].start);
994
scaleRect[axis].setRight(canvasRect.right() - fw - 1
995
+ d_data->layoutData.scale[axis].end);
999
if ( scaleRect[QwtPlot::yLeft].isValid() &&
1000
scaleRect[QwtPlot::yRight].isValid() )
1002
for ( int axis = QwtPlot::yLeft; axis <= QwtPlot::yRight; axis++ )
1004
scaleRect[axis].setTop(canvasRect.top() + fw
1005
- d_data->layoutData.scale[axis].start);
1006
scaleRect[axis].setBottom(canvasRect.bottom() - fw - 1
1007
+ d_data->layoutData.scale[axis].end);
1014
\brief Recalculate the geometry of all components.
1016
\param plot Plot to be layout
1017
\param plotRect Rect where to place the components
1018
\param options Options
1020
\sa invalidate(), titleRect(),
1021
legendRect(), scaleRect(), canvasRect()
1023
void QwtPlotLayout::activate(const QwtPlot *plot,
1024
const QRect &plotRect, int options)
1028
QRect rect(plotRect); // undistributed rest of the plot rect
1030
if ( !(options & IgnoreMargin) )
1032
// subtract the margin
1035
rect.x() + d_data->margin,
1036
rect.y() + d_data->margin,
1037
rect.width() - 2 * d_data->margin,
1038
rect.height() - 2 * d_data->margin
1042
// We extract all layout relevant data from the widgets,
1043
// filter them through pfilter and save them to d_data->layoutData.
1045
d_data->layoutData.init(plot, rect);
1047
if (!(options & IgnoreLegend)
1048
&& d_data->legendPos != QwtPlot::ExternalLegend
1049
&& plot->legend() && !plot->legend()->isEmpty() )
1051
d_data->legendRect = layoutLegend(options, rect);
1053
// subtract d_data->legendRect from rect
1055
const QRegion region(rect);
1056
rect = region.subtract(d_data->legendRect).boundingRect();
1058
if ( d_data->layoutData.legend.frameWidth &&
1059
!(options & IgnoreFrames ) )
1061
// In case of a frame we have to insert a spacing.
1062
// Otherwise the leading of the font separates
1063
// legend and scale/canvas
1065
switch(d_data->legendPos)
1067
case QwtPlot::LeftLegend:
1068
rect.setLeft(rect.left() + d_data->spacing);
1070
case QwtPlot::RightLegend:
1071
rect.setRight(rect.right() - d_data->spacing);
1073
case QwtPlot::TopLegend:
1074
rect.setTop(rect.top() + d_data->spacing);
1076
case QwtPlot::BottomLegend:
1077
rect.setBottom(rect.bottom() - d_data->spacing);
1079
case QwtPlot::ExternalLegend:
1080
break; // suppress compiler warning
1086
+---+-----------+---+
1088
+---+-----------+---+
1090
+---+-----------+---+
1095
+---+-----------+---+
1097
+---+-----------+---+
1101
// axes and title include text labels. The height of each
1102
// label depends on its line breaks, that depend on the width
1103
// for the label. A line break in a horizontal text will reduce
1104
// the available width for vertical texts and vice versa.
1105
// expandLineBreaks finds the height/width for title and axes
1106
// including all line breaks.
1108
int dimTitle, dimAxes[QwtPlot::axisCnt];
1109
expandLineBreaks(options, rect, dimTitle, dimAxes);
1113
d_data->titleRect = QRect(rect.x(), rect.y(),
1114
rect.width(), dimTitle);
1116
if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
1117
d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
1119
// if only one of the y axes is missing we align
1120
// the title centered to the canvas
1122
d_data->titleRect.setX(rect.x() + dimAxes[QwtPlot::yLeft]);
1123
d_data->titleRect.setWidth(rect.width()
1124
- dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight]);
1128
rect.setTop(rect.top() + dimTitle + d_data->spacing);
1131
d_data->canvasRect.setRect(
1132
rect.x() + dimAxes[QwtPlot::yLeft],
1133
rect.y() + dimAxes[QwtPlot::xTop],
1134
rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
1135
rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop]);
1137
for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
1139
// set the rects for the axes
1141
if ( dimAxes[axis] )
1143
int dim = dimAxes[axis];
1144
QRect &scaleRect = d_data->scaleRect[axis];
1146
scaleRect = d_data->canvasRect;
1149
case QwtPlot::yLeft:
1150
scaleRect.setX(d_data->canvasRect.left() - dim);
1151
scaleRect.setWidth(dim);
1153
case QwtPlot::yRight:
1154
scaleRect.setX(d_data->canvasRect.right() + 1);
1155
scaleRect.setWidth(dim);
1157
case QwtPlot::xBottom:
1158
scaleRect.setY(d_data->canvasRect.bottom() + 1);
1159
scaleRect.setHeight(dim);
1162
scaleRect.setY(d_data->canvasRect.top() - dim);
1163
scaleRect.setHeight(dim);
1166
#if QT_VERSION < 0x040000
1167
scaleRect = scaleRect.normalize();
1169
scaleRect = scaleRect.normalized();
1174
// +---+-----------+---+
1176
// +-^-+-----------+-^-+
1180
// | x | Canvas | x |
1185
// +-V-+-----------+-V-+
1187
// +---+-----------+---+
1189
// The ticks of the axes - not the labels above - should
1190
// be aligned to the canvas. So we try to use the empty
1191
// corners to extend the axes, so that the label texts
1192
// left/right of the min/max ticks are moved into them.
1194
alignScales(options, d_data->canvasRect, d_data->scaleRect);
1196
if (!d_data->legendRect.isEmpty() )
1198
// We prefer to align the legend to the canvas - not to
1199
// the complete plot - if possible.
1201
d_data->legendRect = alignLegend(d_data->canvasRect, d_data->legendRect);