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
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.
746
void QwtPlotLayout::expandLineBreaks(int options, const QRect &rect,
747
int &dimTitle, int dimAxis[QwtPlot::axisCnt]) const
750
for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
753
int backboneOffset[QwtPlot::axisCnt];
754
for (int axis = 0; axis < QwtPlot::axisCnt; axis++ )
756
backboneOffset[axis] = 0;
757
if ( !d_data->alignCanvasToScales )
758
backboneOffset[axis] += d_data->canvasMargin[axis];
759
if ( !(options & IgnoreFrames) )
760
backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
768
// the size for the 4 axis depend on each other. Expanding
769
// the height of a horizontal axis will shrink the height
770
// for the vertical axis, shrinking the height of a vertical
771
// axis will result in a line break what will expand the
772
// width and results in shrinking the width of a horizontal
773
// axis what might result in a line break of a horizontal
774
// axis ... . So we loop as long until no size changes.
776
if ( !d_data->layoutData.title.text.isEmpty() )
778
int w = rect.width();
780
if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled
781
!= d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
783
// center to the canvas
784
w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight];
787
int d = d_data->layoutData.title.text.heightForWidth(w);
788
if ( !(options & IgnoreFrames) )
789
d += 2 * d_data->layoutData.title.frameWidth;
798
for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
800
const struct LayoutData::t_scaleData &scaleData =
801
d_data->layoutData.scale[axis];
803
if (scaleData.isEnabled)
806
if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
808
length = rect.width() - dimAxis[QwtPlot::yLeft]
809
- dimAxis[QwtPlot::yRight];
810
length -= scaleData.start + scaleData.end;
812
if ( dimAxis[QwtPlot::yRight] > 0 )
815
length += qwtMin(dimAxis[QwtPlot::yLeft],
816
scaleData.start - backboneOffset[QwtPlot::yLeft]);
817
length += qwtMin(dimAxis[QwtPlot::yRight],
818
scaleData.end - backboneOffset[QwtPlot::yRight]);
820
else // QwtPlot::yLeft, QwtPlot::yRight
822
length = rect.height() - dimAxis[QwtPlot::xTop]
823
- dimAxis[QwtPlot::xBottom];
824
length -= scaleData.start + scaleData.end;
827
if ( dimAxis[QwtPlot::xBottom] <= 0 )
829
if ( dimAxis[QwtPlot::xTop] <= 0 )
832
if ( dimAxis[QwtPlot::xBottom] > 0 )
835
d_data->layoutData.scale[QwtPlot::xBottom].tickOffset,
836
scaleData.start - backboneOffset[QwtPlot::xBottom]);
838
if ( dimAxis[QwtPlot::xTop] > 0 )
841
d_data->layoutData.scale[QwtPlot::xTop].tickOffset,
842
scaleData.end - backboneOffset[QwtPlot::xTop]);
846
length -= dimTitle + d_data->spacing;
849
int d = scaleData.dimWithoutTitle;
850
if ( !scaleData.scaleWidget->title().isEmpty() )
852
d += scaleData.scaleWidget->titleHeightForWidth(length);
856
if ( d > dimAxis[axis] )
867
Align the ticks of the axis to the canvas borders using
873
void QwtPlotLayout::alignScales(int options,
874
QRect &canvasRect, QRect scaleRect[QwtPlot::axisCnt]) const
878
int backboneOffset[QwtPlot::axisCnt];
879
for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
881
backboneOffset[axis] = 0;
882
if ( !d_data->alignCanvasToScales )
883
backboneOffset[axis] += d_data->canvasMargin[axis];
884
if ( !(options & IgnoreFrames) )
885
backboneOffset[axis] += d_data->layoutData.canvas.frameWidth;
888
for (axis = 0; axis < QwtPlot::axisCnt; axis++ )
890
if ( !scaleRect[axis].isValid() )
893
const int startDist = d_data->layoutData.scale[axis].start;
894
const int endDist = d_data->layoutData.scale[axis].end;
896
QRect &axisRect = scaleRect[axis];
898
if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom )
900
const int leftOffset =
901
backboneOffset[QwtPlot::yLeft] - startDist;
903
if ( scaleRect[QwtPlot::yLeft].isValid() )
905
int minLeft = scaleRect[QwtPlot::yLeft].left();
906
int left = axisRect.left() + leftOffset;
907
axisRect.setLeft(qwtMax(left, minLeft));
911
if ( d_data->alignCanvasToScales && leftOffset < 0 )
913
canvasRect.setLeft(qwtMax(canvasRect.left(),
914
axisRect.left() - leftOffset));
918
if ( leftOffset > 0 )
919
axisRect.setLeft(axisRect.left() + leftOffset);
923
const int rightOffset =
924
backboneOffset[QwtPlot::yRight] - endDist + 1;
926
if ( scaleRect[QwtPlot::yRight].isValid() )
928
int maxRight = scaleRect[QwtPlot::yRight].right();
929
int right = axisRect.right() - rightOffset;
930
axisRect.setRight(qwtMin(right, maxRight));
934
if ( d_data->alignCanvasToScales && rightOffset < 0 )
936
canvasRect.setRight( qwtMin(canvasRect.right(),
937
axisRect.right() + rightOffset) );
941
if ( rightOffset > 0 )
942
axisRect.setRight(axisRect.right() - rightOffset);
946
else // QwtPlot::yLeft, QwtPlot::yRight
948
const int bottomOffset =
949
backboneOffset[QwtPlot::xBottom] - endDist + 1;
951
if ( scaleRect[QwtPlot::xBottom].isValid() )
953
int maxBottom = scaleRect[QwtPlot::xBottom].top() +
954
d_data->layoutData.scale[QwtPlot::xBottom].tickOffset;
956
int bottom = axisRect.bottom() - bottomOffset;
957
axisRect.setBottom(qwtMin(bottom, maxBottom));
961
if ( d_data->alignCanvasToScales && bottomOffset < 0 )
963
canvasRect.setBottom(qwtMin(canvasRect.bottom(),
964
axisRect.bottom() + bottomOffset));
968
if ( bottomOffset > 0 )
969
axisRect.setBottom(axisRect.bottom() - bottomOffset);
973
const int topOffset = backboneOffset[QwtPlot::xTop] - startDist;
975
if ( scaleRect[QwtPlot::xTop].isValid() )
977
int minTop = scaleRect[QwtPlot::xTop].bottom() -
978
d_data->layoutData.scale[QwtPlot::xTop].tickOffset;
980
int top = axisRect.top() + topOffset;
981
axisRect.setTop(qwtMax(top, minTop));
985
if ( d_data->alignCanvasToScales && topOffset < 0 )
987
canvasRect.setTop(qwtMax(canvasRect.top(),
988
axisRect.top() - topOffset));
993
axisRect.setTop(axisRect.top() + topOffset);
999
if ( d_data->alignCanvasToScales )
1002
The canvas has been aligned to the scale with largest
1003
border distances. Now we have to realign the other scale.
1007
if ( !(options & IgnoreFrames) )
1008
fw = d_data->layoutData.canvas.frameWidth;
1010
if ( scaleRect[QwtPlot::xBottom].isValid() &&
1011
scaleRect[QwtPlot::xTop].isValid() )
1013
for ( int axis = QwtPlot::xBottom; axis <= QwtPlot::xTop; axis++ )
1015
scaleRect[axis].setLeft(canvasRect.left() + fw
1016
- d_data->layoutData.scale[axis].start);
1017
scaleRect[axis].setRight(canvasRect.right() - fw - 1
1018
+ d_data->layoutData.scale[axis].end);
1022
if ( scaleRect[QwtPlot::yLeft].isValid() &&
1023
scaleRect[QwtPlot::yRight].isValid() )
1025
for ( int axis = QwtPlot::yLeft; axis <= QwtPlot::yRight; axis++ )
1027
scaleRect[axis].setTop(canvasRect.top() + fw
1028
- d_data->layoutData.scale[axis].start);
1029
scaleRect[axis].setBottom(canvasRect.bottom() - fw - 1
1030
+ d_data->layoutData.scale[axis].end);
1037
\brief Recalculate the geometry of all components.
1039
\param plot Plot to be layout
1040
\param plotRect Rect where to place the components
1041
\param options Options
1043
\sa invalidate(), Options, titleRect(),
1044
legendRect(), scaleRect(), canvasRect()
1046
void QwtPlotLayout::activate(const QwtPlot *plot,
1047
const QRect &plotRect, int options)
1051
QRect rect(plotRect); // undistributed rest of the plot rect
1053
if ( !(options & IgnoreMargin) )
1055
// subtract the margin
1058
rect.x() + d_data->margin,
1059
rect.y() + d_data->margin,
1060
rect.width() - 2 * d_data->margin,
1061
rect.height() - 2 * d_data->margin
1065
// We extract all layout relevant data from the widgets,
1066
// filter them through pfilter and save them to d_data->layoutData.
1068
d_data->layoutData.init(plot, rect);
1070
if (!(options & IgnoreLegend)
1071
&& d_data->legendPos != QwtPlot::ExternalLegend
1072
&& plot->legend() && !plot->legend()->isEmpty() )
1074
d_data->legendRect = layoutLegend(options, rect);
1076
// subtract d_data->legendRect from rect
1078
const QRegion region(rect);
1079
rect = region.subtract(d_data->legendRect).boundingRect();
1081
if ( d_data->layoutData.legend.frameWidth &&
1082
!(options & IgnoreFrames ) )
1084
// In case of a frame we have to insert a spacing.
1085
// Otherwise the leading of the font separates
1086
// legend and scale/canvas
1088
switch(d_data->legendPos)
1090
case QwtPlot::LeftLegend:
1091
rect.setLeft(rect.left() + d_data->spacing);
1093
case QwtPlot::RightLegend:
1094
rect.setRight(rect.right() - d_data->spacing);
1096
case QwtPlot::TopLegend:
1097
rect.setTop(rect.top() + d_data->spacing);
1099
case QwtPlot::BottomLegend:
1100
rect.setBottom(rect.bottom() - d_data->spacing);
1102
case QwtPlot::ExternalLegend:
1103
break; // suppress compiler warning
1111
+---+-----------+---+
1113
+---+-----------+---+
1115
+---+-----------+---+
1120
+---+-----------+---+
1122
+---+-----------+---+
1125
// axes and title include text labels. The height of each
1126
// label depends on its line breaks, that depend on the width
1127
// for the label. A line break in a horizontal text will reduce
1128
// the available width for vertical texts and vice versa.
1129
// expandLineBreaks finds the height/width for title and axes
1130
// including all line breaks.
1132
int dimTitle, dimAxes[QwtPlot::axisCnt];
1133
expandLineBreaks(options, rect, dimTitle, dimAxes);
1137
d_data->titleRect = QRect(rect.x(), rect.y(),
1138
rect.width(), dimTitle);
1140
if ( d_data->layoutData.scale[QwtPlot::yLeft].isEnabled !=
1141
d_data->layoutData.scale[QwtPlot::yRight].isEnabled )
1143
// if only one of the y axes is missing we align
1144
// the title centered to the canvas
1146
d_data->titleRect.setX(rect.x() + dimAxes[QwtPlot::yLeft]);
1147
d_data->titleRect.setWidth(rect.width()
1148
- dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight]);
1152
rect.setTop(rect.top() + dimTitle + d_data->spacing);
1155
d_data->canvasRect.setRect(
1156
rect.x() + dimAxes[QwtPlot::yLeft],
1157
rect.y() + dimAxes[QwtPlot::xTop],
1158
rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft],
1159
rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop]);
1161
for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
1163
// set the rects for the axes
1165
if ( dimAxes[axis] )
1167
int dim = dimAxes[axis];
1168
QRect &scaleRect = d_data->scaleRect[axis];
1170
scaleRect = d_data->canvasRect;
1173
case QwtPlot::yLeft:
1174
scaleRect.setX(d_data->canvasRect.left() - dim);
1175
scaleRect.setWidth(dim);
1177
case QwtPlot::yRight:
1178
scaleRect.setX(d_data->canvasRect.right() + 1);
1179
scaleRect.setWidth(dim);
1181
case QwtPlot::xBottom:
1182
scaleRect.setY(d_data->canvasRect.bottom() + 1);
1183
scaleRect.setHeight(dim);
1186
scaleRect.setY(d_data->canvasRect.top() - dim);
1187
scaleRect.setHeight(dim);
1190
#if QT_VERSION < 0x040000
1191
scaleRect = scaleRect.normalize();
1193
scaleRect = scaleRect.normalized();
1198
// +---+-----------+---+
1200
// +-^-+-----------+-^-+
1204
// | x | Canvas | x |
1209
// +-V-+-----------+-V-+
1211
// +---+-----------+---+
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.
1218
alignScales(options, d_data->canvasRect, d_data->scaleRect);
1220
if (!d_data->legendRect.isEmpty() )
1222
// We prefer to align the legend to the canvas - not to
1223
// the complete plot - if possible.
1225
d_data->legendRect = alignLegend(d_data->canvasRect, d_data->legendRect);