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

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2008-05-26 10:26:31 UTC
  • mfrom: (1.1.3 upstream) (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526102631-bp95mfccnrb957nx
Tags: 5.1.1-1
New upstream release.

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 <qpen.h>
 
13
#include <qpainter.h>
 
14
#include "qwt_math.h"
 
15
#include "qwt_painter.h"
 
16
#include "qwt_polygon.h"
 
17
#include "qwt_scale_div.h"
 
18
#include "qwt_scale_map.h"
 
19
#include "qwt_scale_draw.h"
 
20
 
 
21
#if QT_VERSION < 0x040000
 
22
#include <qwmatrix.h>
 
23
#define QwtMatrix QWMatrix
 
24
#else
 
25
#include <qmatrix.h>
 
26
#define QwtMatrix QMatrix
 
27
#endif
 
28
 
 
29
class QwtScaleDraw::PrivateData
 
30
{
 
31
public:
 
32
    PrivateData():
 
33
        len(0),
 
34
        alignment(QwtScaleDraw::BottomScale),
 
35
        labelAlignment(0),
 
36
        labelRotation(0.0)
 
37
    {
 
38
    }
 
39
 
 
40
    QPoint pos;
 
41
    int len;
 
42
 
 
43
    Alignment alignment;
 
44
 
 
45
#if QT_VERSION < 0x040000
 
46
    int labelAlignment;
 
47
#else
 
48
    Qt::Alignment labelAlignment;
 
49
#endif
 
50
    double labelRotation;
 
51
};
 
52
 
 
53
/*!
 
54
  \brief Constructor
 
55
 
 
56
  The range of the scale is initialized to [0, 100],
 
57
  The position is at (0, 0) with a length of 100.
 
58
  The orientation is QwtAbstractScaleDraw::Bottom.
 
59
*/
 
60
QwtScaleDraw::QwtScaleDraw()
 
61
{
 
62
    d_data = new QwtScaleDraw::PrivateData;
 
63
    setLength(100);
 
64
}
 
65
 
 
66
//! Copy constructor
 
67
QwtScaleDraw::QwtScaleDraw(const QwtScaleDraw &other):
 
68
    QwtAbstractScaleDraw(other)
 
69
{
 
70
    d_data = new QwtScaleDraw::PrivateData(*other.d_data);
 
71
}
 
72
 
 
73
//! Destructor
 
74
QwtScaleDraw::~QwtScaleDraw()
 
75
{
 
76
    delete d_data;
 
77
}
 
78
 
 
79
//! Assignment operator
 
80
QwtScaleDraw &QwtScaleDraw::operator=(const QwtScaleDraw &other)
 
81
{
 
82
    *(QwtAbstractScaleDraw*)this = (const QwtAbstractScaleDraw &)other;
 
83
    *d_data = *other.d_data;
 
84
    return *this;
 
85
}
 
86
 
 
87
/*! 
 
88
   Return alignment of the scale
 
89
   \sa setAlignment()
 
90
*/
 
91
QwtScaleDraw::Alignment QwtScaleDraw::alignment() const 
 
92
{
 
93
    return d_data->alignment; 
 
94
}
 
95
 
 
96
/*!
 
97
   Set the alignment of the scale
 
98
 
 
99
   The default alignment is QwtScaleDraw::BottomScale
 
100
   \sa alignment()
 
101
*/
 
102
void QwtScaleDraw::setAlignment(Alignment align)
 
103
{
 
104
    d_data->alignment = align;
 
105
}
 
106
 
 
107
/*!
 
108
  Return the orientation
 
109
 
 
110
  TopScale, BottomScale are horizontal (Qt::Horizontal) scales,
 
111
  LeftScale, RightScale are vertical (Qt::Vertical) scales.
 
112
 
 
113
  \sa alignment()
 
114
*/
 
115
Qt::Orientation QwtScaleDraw::orientation() const
 
116
{
 
117
    switch(d_data->alignment)
 
118
    {
 
119
        case TopScale:
 
120
        case BottomScale:
 
121
            return Qt::Horizontal;
 
122
        case LeftScale:
 
123
        case RightScale:
 
124
        default:
 
125
            return Qt::Vertical;
 
126
    }
 
127
}
 
128
 
 
129
/*!
 
130
  \brief Determine the minimum border distance
 
131
 
 
132
  This member function returns the minimum space
 
133
  needed to draw the mark labels at the scale's endpoints.
 
134
 
 
135
  \param font Font
 
136
  \param start Start border distance
 
137
  \param end End border distance
 
138
*/
 
139
void QwtScaleDraw::getBorderDistHint(const QFont &font,
 
140
    int &start, int &end ) const
 
141
{
 
142
    start = 0;
 
143
    end = 0;
 
144
    
 
145
    if ( !hasComponent(QwtAbstractScaleDraw::Labels) )
 
146
        return;
 
147
 
 
148
    const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
 
149
    if ( ticks.count() == 0 ) 
 
150
        return;
 
151
 
 
152
    QRect lr = labelRect(font, ticks[0]);
 
153
 
 
154
    // find the distance between tick and border
 
155
    int off = qwtAbs(map().transform(ticks[0]) - qRound(map().p1()));
 
156
 
 
157
    if ( orientation() == Qt::Vertical )
 
158
        end = lr.bottom() + 1 - off;
 
159
    else
 
160
        start = -lr.left() - off;
 
161
 
 
162
    const int lastTick = ticks.count() - 1;
 
163
    lr = labelRect(font, ticks[lastTick]);
 
164
 
 
165
    // find the distance between tick and border
 
166
    off = qwtAbs(map().transform(ticks[lastTick]) - qRound(map().p2()));
 
167
 
 
168
    if ( orientation() == Qt::Vertical )
 
169
        start = -lr.top() - off;
 
170
    else
 
171
        end = lr.right() + 1 - off;
 
172
 
 
173
    // if the distance between tick and border is larger
 
174
    // than half of the label width/height, we set to 0
 
175
 
 
176
    if ( start < 0 )
 
177
        start = 0;
 
178
    if ( end < 0 )
 
179
        end = 0;
 
180
}
 
181
 
 
182
/*!
 
183
  Determine the minimum distance between two labels, that is necessary
 
184
  that the texts don't overlap.
 
185
 
 
186
  \param font Font
 
187
  \return The maximum width of a label
 
188
 
 
189
  \sa getBorderDistHint()
 
190
*/
 
191
 
 
192
int QwtScaleDraw::minLabelDist(const QFont &font) const
 
193
{
 
194
    if ( !hasComponent(QwtAbstractScaleDraw::Labels) )
 
195
        return 0;
 
196
 
 
197
    const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
 
198
    if (ticks.count() == 0)
 
199
        return 0;
 
200
 
 
201
    const QFontMetrics fm(font);
 
202
 
 
203
    const bool vertical = (orientation() == Qt::Vertical);
 
204
 
 
205
    QRect bRect1;
 
206
    QRect bRect2 = labelRect(font, ticks[0]);
 
207
    if ( vertical )
 
208
    {
 
209
        bRect2.setRect(-bRect2.bottom(), 0, bRect2.height(), bRect2.width());
 
210
    }
 
211
    int maxDist = 0;
 
212
 
 
213
    for (uint i = 1; i < (uint)ticks.count(); i++ )
 
214
    {
 
215
        bRect1 = bRect2;
 
216
        bRect2 = labelRect(font, ticks[i]);
 
217
        if ( vertical )
 
218
        {
 
219
            bRect2.setRect(-bRect2.bottom(), 0,
 
220
                bRect2.height(), bRect2.width());
 
221
        }
 
222
 
 
223
        int dist = fm.leading(); // space between the labels
 
224
        if ( bRect1.right() > 0 )
 
225
            dist += bRect1.right();
 
226
        if ( bRect2.left() < 0 )
 
227
            dist += -bRect2.left();
 
228
 
 
229
        if ( dist > maxDist )
 
230
            maxDist = dist;
 
231
    }
 
232
 
 
233
    double angle = labelRotation() / 180.0 * M_PI;
 
234
    if ( vertical )
 
235
        angle += M_PI / 2;
 
236
 
 
237
    if ( sin(angle) == 0.0 )
 
238
        return maxDist;
 
239
 
 
240
    const int fmHeight = fm.ascent() - 2; 
 
241
 
 
242
    // The distance we need until there is
 
243
    // the height of the label font. This height is needed
 
244
    // for the neighbour labal.
 
245
 
 
246
    int labelDist = (int)(fmHeight / sin(angle) * cos(angle));
 
247
    if ( labelDist < 0 )
 
248
        labelDist = -labelDist;
 
249
 
 
250
    // The cast above floored labelDist. We want to ceil.
 
251
    labelDist++; 
 
252
 
 
253
    // For text orientations close to the scale orientation 
 
254
 
 
255
    if ( labelDist > maxDist )
 
256
        labelDist = maxDist;
 
257
 
 
258
    // For text orientations close to the opposite of the 
 
259
    // scale orientation
 
260
 
 
261
    if ( labelDist < fmHeight )
 
262
        labelDist = fmHeight;
 
263
 
 
264
    return labelDist;
 
265
}
 
266
 
 
267
/*!
 
268
   Calculate the width/height that is needed for a
 
269
   vertical/horizontal scale.
 
270
 
 
271
   The extent is calculated from the pen width of the backbone,
 
272
   the major tick length, the spacing and the maximum width/height
 
273
   of the labels.
 
274
 
 
275
   \param pen Pen that is used for painting backbone and ticks
 
276
   \param font Font used for painting the labels
 
277
 
 
278
   \sa minLength()
 
279
*/
 
280
int QwtScaleDraw::extent(const QPen &pen, const QFont &font) const
 
281
{
 
282
    int d = 0;
 
283
 
 
284
    if ( hasComponent(QwtAbstractScaleDraw::Labels) )
 
285
    {
 
286
        if ( orientation() == Qt::Vertical )
 
287
            d = maxLabelWidth(font);
 
288
        else
 
289
            d = maxLabelHeight(font);
 
290
 
 
291
        if ( d > 0 )
 
292
            d += spacing();
 
293
    }
 
294
 
 
295
    if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
 
296
    {
 
297
        d += majTickLength();
 
298
    }
 
299
 
 
300
    if ( hasComponent(QwtAbstractScaleDraw::Backbone) )
 
301
    {
 
302
        const int pw = qwtMax( 1, pen.width() );  // penwidth can be zero
 
303
        d += pw;
 
304
    }
 
305
 
 
306
    d = qwtMax(d, minimumExtent());
 
307
    return d;
 
308
}
 
309
 
 
310
/*!
 
311
   Calculate the minimum length that is needed to draw the scale
 
312
 
 
313
   \param pen Pen that is used for painting backbone and ticks
 
314
   \param font Font used for painting the labels
 
315
 
 
316
   \sa extent()
 
317
*/
 
318
int QwtScaleDraw::minLength(const QPen &pen, const QFont &font) const
 
319
{
 
320
    int startDist, endDist;
 
321
    getBorderDistHint(font, startDist, endDist);
 
322
 
 
323
    const QwtScaleDiv &sd = scaleDiv();
 
324
 
 
325
    const uint minorCount =
 
326
        sd.ticks(QwtScaleDiv::MinorTick).count() +
 
327
        sd.ticks(QwtScaleDiv::MediumTick).count();
 
328
    const uint majorCount =
 
329
        sd.ticks(QwtScaleDiv::MajorTick).count();
 
330
 
 
331
    int lengthForLabels = 0;
 
332
    if ( hasComponent(QwtAbstractScaleDraw::Labels) )
 
333
    {
 
334
        if ( majorCount >= 2 )
 
335
            lengthForLabels = minLabelDist(font) * (majorCount - 1);
 
336
    }
 
337
 
 
338
    int lengthForTicks = 0;
 
339
    if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
 
340
    {
 
341
        const int pw = qwtMax( 1, pen.width() );  // penwidth can be zero
 
342
        lengthForTicks = 2 * (majorCount + minorCount) * pw;
 
343
    }
 
344
 
 
345
    return startDist + endDist + qwtMax(lengthForLabels, lengthForTicks);
 
346
}
 
347
 
 
348
/*!
 
349
   Find the position, where to paint a label
 
350
 
 
351
   The position has a distance of majTickLength() + spacing() + 1
 
352
   from the backbone. The direction depends on the alignment()
 
353
 
 
354
   \param value Value
 
355
*/
 
356
QPoint QwtScaleDraw::labelPosition( double value) const
 
357
{
 
358
    const int tval = map().transform(value);
 
359
    int dist = spacing() + 1;
 
360
    if ( hasComponent(QwtAbstractScaleDraw::Ticks) )
 
361
        dist += majTickLength();
 
362
 
 
363
    int px = 0;
 
364
    int py = 0;
 
365
 
 
366
    switch(alignment())
 
367
    {
 
368
        case RightScale:
 
369
        {
 
370
            px = d_data->pos.x() + dist;
 
371
            py = tval;
 
372
            break;
 
373
        }
 
374
        case LeftScale:
 
375
        {
 
376
            px = d_data->pos.x() - dist;
 
377
            py = tval;
 
378
            break;
 
379
        }
 
380
        case BottomScale:
 
381
        {
 
382
            px = tval;
 
383
            py = d_data->pos.y() + dist;
 
384
            break;
 
385
        }
 
386
        case TopScale:
 
387
        {
 
388
            px = tval;
 
389
            py = d_data->pos.y() - dist;
 
390
            break;
 
391
        }
 
392
    }
 
393
 
 
394
    return QPoint(px, py);
 
395
}
 
396
 
 
397
/*!
 
398
   Draw a tick
 
399
 
 
400
   \param painter Painter
 
401
   \param value Value of the tick
 
402
   \param len Lenght of the tick
 
403
 
 
404
   \sa drawBackbone(), drawLabel()
 
405
*/
 
406
void QwtScaleDraw::drawTick(QPainter *painter, double value, int len) const
 
407
{
 
408
    if ( len <= 0 )
 
409
        return;
 
410
 
 
411
    int pw2 = qwtMin((int)painter->pen().width(), len) / 2;
 
412
    
 
413
    QwtScaleMap scaleMap = map();
 
414
    const QwtMetricsMap metricsMap = QwtPainter::metricsMap();
 
415
    QPoint pos = d_data->pos;
 
416
 
 
417
    if ( !metricsMap.isIdentity() )
 
418
    {
 
419
        /*
 
420
           The perfect position of the ticks is important.
 
421
           To avoid rounding errors we have to use 
 
422
           device coordinates.
 
423
         */
 
424
        QwtPainter::resetMetricsMap();
 
425
 
 
426
        pos = metricsMap.layoutToDevice(pos);
 
427
    
 
428
        if ( orientation() == Qt::Vertical )
 
429
        {
 
430
            scaleMap.setPaintInterval(
 
431
                metricsMap.layoutToDeviceY((int)scaleMap.p1()),
 
432
                metricsMap.layoutToDeviceY((int)scaleMap.p2())
 
433
            );
 
434
            len = metricsMap.layoutToDeviceX(len);
 
435
        }
 
436
        else
 
437
        {
 
438
            scaleMap.setPaintInterval(
 
439
                metricsMap.layoutToDeviceX((int)scaleMap.p1()),
 
440
                metricsMap.layoutToDeviceX((int)scaleMap.p2())
 
441
            );
 
442
            len = metricsMap.layoutToDeviceY(len);
 
443
        }
 
444
    }
 
445
 
 
446
    const int tval = scaleMap.transform(value);
 
447
 
 
448
    switch(alignment())
 
449
    {
 
450
        case LeftScale:
 
451
        {
 
452
#if QT_VERSION < 0x040000
 
453
            QwtPainter::drawLine(painter, pos.x() + pw2, tval,
 
454
                pos.x() - len - 2 * pw2, tval);
 
455
#else
 
456
            QwtPainter::drawLine(painter, pos.x() - pw2, tval,
 
457
                pos.x() - len, tval);
 
458
#endif
 
459
            break;
 
460
        }
 
461
 
 
462
        case RightScale:
 
463
        {
 
464
#if QT_VERSION < 0x040000
 
465
            QwtPainter::drawLine(painter, pos.x(), tval,
 
466
                pos.x() + len + pw2, tval);
 
467
#else
 
468
            QwtPainter::drawLine(painter, pos.x() + pw2, tval,
 
469
                pos.x() + len, tval);
 
470
#endif
 
471
            break;
 
472
        }
 
473
    
 
474
        case BottomScale:
 
475
        {
 
476
#if QT_VERSION < 0x040000
 
477
            QwtPainter::drawLine(painter, tval, pos.y(),
 
478
                tval, pos.y() + len + 2 * pw2);
 
479
#else
 
480
            QwtPainter::drawLine(painter, tval, pos.y() + pw2,
 
481
                tval, pos.y() + len);
 
482
#endif
 
483
            break;
 
484
        }
 
485
 
 
486
        case TopScale:
 
487
        {
 
488
#if QT_VERSION < 0x040000
 
489
            QwtPainter::drawLine(painter, tval, pos.y() + pw2,
 
490
                tval, pos.y() - len - 2 * pw2);
 
491
#else
 
492
            QwtPainter::drawLine(painter, tval, pos.y() - pw2,
 
493
                tval, pos.y() - len);
 
494
#endif
 
495
            break;
 
496
        }
 
497
    }
 
498
    QwtPainter::setMetricsMap(metricsMap); // restore metrics map
 
499
}
 
500
 
 
501
/*! 
 
502
   Draws the baseline of the scale
 
503
   \param painter Painter
 
504
 
 
505
   \sa drawTick(), drawLabel()
 
506
*/
 
507
void QwtScaleDraw::drawBackbone(QPainter *painter) const
 
508
{
 
509
    const int bw2 = painter->pen().width() / 2;
 
510
 
 
511
    const QPoint &pos = d_data->pos;
 
512
    const int len = d_data->len - 1;
 
513
 
 
514
    switch(alignment())
 
515
    {
 
516
        case LeftScale:
 
517
            QwtPainter::drawLine(painter, pos.x() - bw2,
 
518
                pos.y(), pos.x() - bw2, pos.y() + len );
 
519
            break;
 
520
        case RightScale:
 
521
            QwtPainter::drawLine(painter, pos.x() + bw2,
 
522
                pos.y(), pos.x() + bw2, pos.y() + len);
 
523
            break;
 
524
        case TopScale:
 
525
            QwtPainter::drawLine(painter, pos.x(), pos.y() - bw2,
 
526
                pos.x() + len, pos.y() - bw2);
 
527
            break;
 
528
        case BottomScale:
 
529
            QwtPainter::drawLine(painter, pos.x(), pos.y() + bw2,
 
530
                pos.x() + len, pos.y() + bw2);
 
531
            break;
 
532
    }
 
533
}
 
534
 
 
535
/*!
 
536
  \brief Move the position of the scale
 
537
 
 
538
  The meaning of the parameter pos depends on the alignment:
 
539
  <dl>
 
540
  <dt>QwtScaleDraw::LeftScale
 
541
  <dd>The origin is the topmost point of the
 
542
      backbone. The backbone is a vertical line. 
 
543
      Scale marks and labels are drawn 
 
544
      at the left of the backbone.
 
545
  <dt>QwtScaleDraw::RightScale
 
546
  <dd>The origin is the topmost point of the
 
547
      backbone. The backbone is a vertical line. 
 
548
      Scale marks and labels are drawn
 
549
      at the right of the backbone.
 
550
  <dt>QwtScaleDraw::TopScale
 
551
  <dd>The origin is the leftmost point of the
 
552
      backbone. The backbone is a horizontal line. 
 
553
      Scale marks and labels are drawn
 
554
      above the backbone.
 
555
  <dt>QwtScaleDraw::BottomScale
 
556
  <dd>The origin is the leftmost point of the
 
557
      backbone. The backbone is a horizontal line 
 
558
      Scale marks and labels are drawn
 
559
      below the backbone.
 
560
  </dl>
 
561
 
 
562
  \param pos Origin of the scale
 
563
 
 
564
  \sa pos(), setLength()
 
565
*/
 
566
void QwtScaleDraw::move(const QPoint &pos)
 
567
{
 
568
    d_data->pos = pos;
 
569
    updateMap();
 
570
}
 
571
 
 
572
/*! 
 
573
   \return Origin of the scale
 
574
   \sa move(), length()
 
575
*/
 
576
QPoint QwtScaleDraw::pos() const
 
577
{
 
578
    return d_data->pos;
 
579
}
 
580
 
 
581
/*!
 
582
  Set the length of the backbone.
 
583
  
 
584
  The length doesn't include the space needed for
 
585
  overlapping labels.
 
586
 
 
587
  \sa move(), minLabelDist()
 
588
*/
 
589
void QwtScaleDraw::setLength(int length)
 
590
{
 
591
    if ( length >= 0 && length < 10 )
 
592
        length = 10;
 
593
    if ( length < 0 && length > -10 )
 
594
        length = -10;
 
595
    
 
596
    d_data->len = length;
 
597
    updateMap();
 
598
}
 
599
 
 
600
/*! 
 
601
   \return the length of the backbone
 
602
   \sa setLength(), pos()
 
603
*/
 
604
int QwtScaleDraw::length() const
 
605
{
 
606
    return d_data->len;
 
607
}
 
608
 
 
609
/*! 
 
610
   Draws the label for a major scale tick
 
611
 
 
612
   \param painter Painter
 
613
   \param value Value
 
614
 
 
615
   \sa drawTick(), drawBackbone(), boundingLabelRect()
 
616
*/
 
617
void QwtScaleDraw::drawLabel(QPainter *painter, double value) const
 
618
{
 
619
    QwtText lbl = tickLabel(painter->font(), value);
 
620
    if ( lbl.isEmpty() )
 
621
        return; 
 
622
 
 
623
    const QPoint pos = labelPosition(value);
 
624
 
 
625
    QSize labelSize = lbl.textSize(painter->font());
 
626
    if ( labelSize.height() % 2 )
 
627
        labelSize.setHeight(labelSize.height() + 1);
 
628
    
 
629
    const QwtMatrix m = labelMatrix( pos, labelSize);
 
630
 
 
631
    painter->save();
 
632
#if QT_VERSION < 0x040000
 
633
    painter->setWorldMatrix(m, true);
 
634
#else
 
635
    painter->setMatrix(m, true);
 
636
#endif
 
637
 
 
638
    lbl.draw (painter, QRect(QPoint(0, 0), labelSize) );
 
639
    painter->restore();
 
640
}
 
641
 
 
642
/*!
 
643
  Find the bounding rect for the label. The coordinates of
 
644
  the rect are absolute coordinates ( calculated from pos() ).
 
645
  in direction of the tick.
 
646
 
 
647
  \param font Font used for painting
 
648
  \param value Value
 
649
 
 
650
  \sa labelRect()
 
651
*/
 
652
QRect QwtScaleDraw::boundingLabelRect(const QFont &font, double value) const
 
653
{
 
654
    QwtText lbl = tickLabel(font, value);
 
655
    if ( lbl.isEmpty() )
 
656
        return QRect(); 
 
657
 
 
658
    const QPoint pos = labelPosition(value);
 
659
    QSize labelSize = lbl.textSize(font);
 
660
    if ( labelSize.height() % 2 )
 
661
        labelSize.setHeight(labelSize.height() + 1);
 
662
 
 
663
    const QwtMatrix m = labelMatrix( pos, labelSize);
 
664
    return m.mapRect(QRect(QPoint(0, 0), labelSize));
 
665
}
 
666
 
 
667
/*!
 
668
   Calculate the matrix that is needed to paint a label
 
669
   depending on its alignment and rotation.
 
670
 
 
671
   \param pos Position where to paint the label
 
672
   \param size Size of the label
 
673
 
 
674
   \sa setLabelAlignment(), setLabelRotation()
 
675
*/
 
676
QwtMatrix QwtScaleDraw::labelMatrix( 
 
677
    const QPoint &pos, const QSize &size) const
 
678
{   
 
679
    QwtMatrix m;
 
680
    m.translate(pos.x(), pos.y());
 
681
    m.rotate(labelRotation());
 
682
    
 
683
    int flags = labelAlignment();
 
684
    if ( flags == 0 )
 
685
    {
 
686
        switch(alignment())
 
687
        {
 
688
            case RightScale:
 
689
            {
 
690
                if ( flags == 0 )
 
691
                    flags = Qt::AlignRight | Qt::AlignVCenter;
 
692
                break;
 
693
            }
 
694
            case LeftScale:
 
695
            {
 
696
                if ( flags == 0 )
 
697
                    flags = Qt::AlignLeft | Qt::AlignVCenter;
 
698
                break;
 
699
            }
 
700
            case BottomScale:
 
701
            {
 
702
                if ( flags == 0 )
 
703
                    flags = Qt::AlignHCenter | Qt::AlignBottom;
 
704
                break;
 
705
            }
 
706
            case TopScale:
 
707
            {
 
708
                if ( flags == 0 )
 
709
                    flags = Qt::AlignHCenter | Qt::AlignTop;
 
710
                break;
 
711
            }
 
712
        }
 
713
    }
 
714
 
 
715
    const int w = size.width();
 
716
    const int h = size.height();
 
717
 
 
718
    int x, y;
 
719
    
 
720
    if ( flags & Qt::AlignLeft )
 
721
        x = -w;
 
722
    else if ( flags & Qt::AlignRight )
 
723
        x = -(w % 2); 
 
724
    else // Qt::AlignHCenter
 
725
        x = -(w / 2);
 
726
        
 
727
    if ( flags & Qt::AlignTop )
 
728
        y =  -h ;
 
729
    else if ( flags & Qt::AlignBottom )
 
730
        y = -(h % 2); 
 
731
    else // Qt::AlignVCenter
 
732
        y = -(h/2);
 
733
        
 
734
    m.translate(x, y);
 
735
    
 
736
    return m;
 
737
}   
 
738
 
 
739
/*!
 
740
  Find the bounding rect for the label. The coordinates of
 
741
  the rect are relative to spacing + ticklength from the backbone
 
742
  in direction of the tick.
 
743
 
 
744
  \param font Font used for painting
 
745
  \param value Value
 
746
*/
 
747
QRect QwtScaleDraw::labelRect(const QFont &font, double value) const
 
748
{   
 
749
    QwtText lbl = tickLabel(font, value);
 
750
    if ( lbl.isEmpty() )
 
751
        return QRect(0, 0, 0, 0);
 
752
 
 
753
    const QPoint pos = labelPosition(value);
 
754
 
 
755
    QSize labelSize = lbl.textSize(font);
 
756
    if ( labelSize.height() % 2 )
 
757
    {
 
758
        labelSize.setHeight(labelSize.height() + 1);
 
759
    }
 
760
 
 
761
    const QwtMatrix m = labelMatrix(pos, labelSize);
 
762
 
 
763
#if 0
 
764
    QRect br = QwtMetricsMap::translate(m, QRect(QPoint(0, 0), labelSize));
 
765
#else
 
766
    QwtPolygon pol(4);
 
767
    pol.setPoint(0, 0, 0); 
 
768
    pol.setPoint(1, 0, labelSize.height() - 1 );
 
769
    pol.setPoint(2, labelSize.width() - 1, 0);
 
770
    pol.setPoint(3, labelSize.width() - 1, labelSize.height() - 1 );
 
771
 
 
772
    pol = QwtMetricsMap::translate(m, pol);
 
773
    QRect br = pol.boundingRect();
 
774
#endif
 
775
 
 
776
#if QT_VERSION < 0x040000
 
777
    br.moveBy(-pos.x(), -pos.y());
 
778
#else
 
779
    br.translate(-pos.x(), -pos.y());
 
780
#endif
 
781
 
 
782
    return br;
 
783
}
 
784
 
 
785
/*!
 
786
   Calculate the size that is needed to draw a label
 
787
 
 
788
   \param font Label font
 
789
   \param value Value
 
790
*/
 
791
QSize QwtScaleDraw::labelSize(const QFont &font, double value) const
 
792
{
 
793
    return labelRect(font, value).size();
 
794
}
 
795
 
 
796
/*!
 
797
  Rotate all labels.
 
798
 
 
799
  When changing the rotation, it might be necessary to
 
800
  adjust the label flags too. Finding a useful combination is
 
801
  often the result of try and error.
 
802
 
 
803
  \param rotation Angle in degrees. When changing the label rotation,
 
804
                  the label flags often needs to be adjusted too.
 
805
 
 
806
  \sa setLabelAlignment(), labelRotation(), labelAlignment().
 
807
 
 
808
*/
 
809
void QwtScaleDraw::setLabelRotation(double rotation)
 
810
{
 
811
    d_data->labelRotation = rotation;
 
812
}
 
813
 
 
814
/*!
 
815
  \return the label rotation
 
816
  \sa setLabelRotation(), labelAlignment()
 
817
*/
 
818
double QwtScaleDraw::labelRotation() const
 
819
{
 
820
    return d_data->labelRotation;
 
821
}
 
822
 
 
823
/*!
 
824
  \brief Change the label flags
 
825
 
 
826
  Labels are aligned to the point ticklength + spacing away from the backbone.
 
827
 
 
828
  The alignment is relative to the orientation of the label text.
 
829
  In case of an flags of 0 the label will be aligned  
 
830
  depending on the orientation of the scale: 
 
831
  
 
832
      QwtScaleDraw::TopScale: Qt::AlignHCenter | Qt::AlignTop\n
 
833
      QwtScaleDraw::BottomScale: Qt::AlignHCenter | Qt::AlignBottom\n
 
834
      QwtScaleDraw::LeftScale: Qt::AlignLeft | Qt::AlignVCenter\n
 
835
      QwtScaleDraw::RightScale: Qt::AlignRight | Qt::AlignVCenter\n
 
836
  
 
837
  Changing the alignment is often necessary for rotated labels.
 
838
  
 
839
  \param alignment Or'd Qt::AlignmentFlags <see qnamespace.h>
 
840
 
 
841
  \sa setLabelRotation(), labelRotation(), labelAlignment()
 
842
  \warning The various alignments might be confusing. 
 
843
           The alignment of the label is not the alignment
 
844
           of the scale and is not the alignment of the flags
 
845
           (QwtText::flags()) returned from QwtAbstractScaleDraw::label().
 
846
*/    
 
847
      
 
848
#if QT_VERSION < 0x040000
 
849
void QwtScaleDraw::setLabelAlignment(int alignment)
 
850
#else
 
851
void QwtScaleDraw::setLabelAlignment(Qt::Alignment alignment)
 
852
#endif
 
853
{
 
854
    d_data->labelAlignment = alignment;
 
855
}   
 
856
 
 
857
/*!
 
858
  \return the label flags
 
859
  \sa setLabelAlignment(), labelRotation()
 
860
*/
 
861
#if QT_VERSION < 0x040000
 
862
int QwtScaleDraw::labelAlignment() const
 
863
#else
 
864
Qt::Alignment QwtScaleDraw::labelAlignment() const
 
865
#endif
 
866
{
 
867
    return d_data->labelAlignment;
 
868
}
 
869
 
 
870
/*!
 
871
  \param font Font
 
872
  \return the maximum width of a label
 
873
*/
 
874
int QwtScaleDraw::maxLabelWidth(const QFont &font) const
 
875
{
 
876
    int maxWidth = 0;
 
877
 
 
878
    const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
 
879
    for (uint i = 0; i < (uint)ticks.count(); i++)
 
880
    {
 
881
        const double v = ticks[i];
 
882
        if ( scaleDiv().contains(v) )
 
883
        {
 
884
            const int w = labelSize(font, ticks[i]).width();
 
885
            if ( w > maxWidth )
 
886
                maxWidth = w;
 
887
        }
 
888
    }
 
889
 
 
890
    return maxWidth;
 
891
}
 
892
 
 
893
/*!
 
894
  \param font Font
 
895
  \return the maximum height of a label
 
896
*/
 
897
int QwtScaleDraw::maxLabelHeight(const QFont &font) const
 
898
{
 
899
    int maxHeight = 0;
 
900
    
 
901
    const QwtValueList &ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
 
902
    for (uint i = 0; i < (uint)ticks.count(); i++)
 
903
    {
 
904
        const double v = ticks[i];
 
905
        if ( scaleDiv().contains(v) )
 
906
        {
 
907
            const int h = labelSize(font, ticks[i]).height();
 
908
            if ( h > maxHeight )
 
909
                maxHeight = h; 
 
910
        }       
 
911
    }   
 
912
    
 
913
    return maxHeight;
 
914
}   
 
915
 
 
916
void QwtScaleDraw::updateMap()
 
917
{
 
918
    QwtScaleMap &sm = scaleMap();
 
919
    if ( orientation() == Qt::Vertical )
 
920
        sm.setPaintInterval(d_data->pos.y() + d_data->len, d_data->pos.y());
 
921
    else
 
922
        sm.setPaintInterval(d_data->pos.x(), d_data->pos.x() + d_data->len);
 
923
}