~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.1.1/src/qwt_plot_layout.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2009-04-12 23:25:58 UTC
  • mfrom: (1.1.4 upstream) (2.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090412232558-3bl06x785yr8xm8u
Tags: 5.1.2-1
* New upstream release.
* Bump compat/debhelper to 7.
* Bump Standards-Version to 3.8.1. No changes needed.
* Invert Maintainers and Uploaders field.
* Fix lintian warnings:
  - dh_clean _k deprecated.
  - missing dependency on libc.

Show diffs side-by-side

added added

removed removed

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