~showard314/ubuntu/natty/qtiplot/Python2.7_fix

« back to all changes in this revision

Viewing changes to 3rdparty/qwt/src/qwt_plot_layout.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2008-04-04 15:11:55 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20080404151155-rjp12ziov4tryj0o
Tags: 0.9.4-1
* New upstream release.
* Refresh patches.
* Remove 04_homepage_url patch. Merged upstream.

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