~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/widgets/qlcdnumber.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the widgets module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qlcdnumber.h"
 
30
#ifndef QT_NO_LCDNUMBER
 
31
#include "qbitarray.h"
 
32
#include "qpainter.h"
 
33
#include "private/qframe_p.h"
 
34
 
 
35
class QLCDNumberPrivate : public QFramePrivate
 
36
{
 
37
    Q_DECLARE_PUBLIC(QLCDNumber)
 
38
public:
 
39
    void init();
 
40
    void internalSetString(const QString& s);
 
41
    void drawString(const QString& s, QPainter &, QBitArray * = 0, bool = true);
 
42
    //void drawString(const QString &, QPainter &, QBitArray * = 0) const;
 
43
    void drawDigit(const QPoint &, QPainter &, int, char, char = ' ');
 
44
    void drawSegment(const QPoint &, char, QPainter &, int, bool = false);
 
45
 
 
46
    int ndigits;
 
47
    double val;
 
48
    uint base : 2;
 
49
    uint smallPoint : 1;
 
50
    uint fill : 1;
 
51
    uint shadow : 1;
 
52
    QString digitStr;
 
53
    QBitArray points;
 
54
};
 
55
 
 
56
/*!
 
57
    \class QLCDNumber qlcdnumber.h
 
58
 
 
59
    \brief The QLCDNumber widget displays a number with LCD-like digits.
 
60
 
 
61
    \ingroup basic
 
62
    \mainclass
 
63
 
 
64
    It can display a number in just about any size. It can display
 
65
    decimal, hexadecimal, octal or binary numbers. It is easy to
 
66
    connect to data sources using the display() slot, which is
 
67
    overloaded to take any of five argument types.
 
68
 
 
69
    There are also slots to change the base with setMode() and the
 
70
    decimal point with setSmallDecimalPoint().
 
71
 
 
72
    QLCDNumber emits the overflow() signal when it is asked to display
 
73
    something beyond its range. The range is set by setNumDigits(),
 
74
    but setSmallDecimalPoint() also influences it. If the display is
 
75
    set to hexadecimal, octal or binary, the integer equivalent of the
 
76
    value is displayed.
 
77
 
 
78
    These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
 
79
    6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
 
80
    P, r, u, U, Y, colon, degree sign (which is specified as single
 
81
    quote in the string) and space. QLCDNumber substitutes spaces for
 
82
    illegal characters.
 
83
 
 
84
    It is not possible to retrieve the contents of a QLCDNumber
 
85
    object, although you can retrieve the numeric value with value().
 
86
    If you really need the text, we recommend that you connect the
 
87
    signals that feed the display() slot to another slot as well and
 
88
    store the value there.
 
89
 
 
90
    Incidentally, QLCDNumber is the very oldest part of Qt, tracing
 
91
    its roots back to a BASIC program on the \link
 
92
    http://www.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm
 
93
    Sinclair Spectrum\endlink.
 
94
 
 
95
    \inlineimage qlcdnum-m.png Screenshot in Motif style
 
96
    \inlineimage qlcdnum-w.png Screenshot in Windows style
 
97
 
 
98
    \sa QLabel, QFrame
 
99
*/
 
100
 
 
101
/*!
 
102
    \enum QLCDNumber::Mode
 
103
 
 
104
    This type determines how numbers are shown.
 
105
 
 
106
    \value Hex  Hexadecimal
 
107
    \value Dec  Decimal
 
108
    \value Oct  Octal
 
109
    \value Bin  Binary
 
110
    \omitvalue HEX
 
111
    \omitvalue DEC
 
112
    \omitvalue OCT
 
113
    \omitvalue BIN
 
114
 
 
115
    If the display is set to hexadecimal, octal or binary, the integer
 
116
    equivalent of the value is displayed.
 
117
*/
 
118
 
 
119
/*!
 
120
    \enum QLCDNumber::SegmentStyle
 
121
 
 
122
    This type determines the visual appearance of the QLCDNumber
 
123
    widget.
 
124
 
 
125
    \value Outline gives raised segments filled with the background brush.
 
126
    \value Filled gives raised segments filled with the foreground brush.
 
127
    \value Flat gives flat segments filled with the foreground brush.
 
128
*/
 
129
 
 
130
 
 
131
 
 
132
/*!
 
133
    \fn void QLCDNumber::overflow()
 
134
 
 
135
    This signal is emitted whenever the QLCDNumber is asked to display
 
136
    a too-large number or a too-long string.
 
137
 
 
138
    It is never emitted by setNumDigits().
 
139
*/
 
140
 
 
141
 
 
142
static QString int2string(int num, int base, int ndigits, bool *oflow)
 
143
{
 
144
    QString s;
 
145
    bool negative;
 
146
    if (num < 0) {
 
147
        negative = true;
 
148
        num      = -num;
 
149
    } else {
 
150
        negative = false;
 
151
    }
 
152
    switch(base) {
 
153
        case QLCDNumber::Hex:
 
154
            s.sprintf("%*x", ndigits, num);
 
155
            break;
 
156
        case QLCDNumber::Dec:
 
157
            s.sprintf("%*i", ndigits, num);
 
158
            break;
 
159
        case QLCDNumber::Oct:
 
160
            s.sprintf("%*o", ndigits, num);
 
161
            break;
 
162
        case QLCDNumber::Bin:
 
163
            {
 
164
                char buf[42];
 
165
                char *p = &buf[41];
 
166
                uint n = num;
 
167
                int len = 0;
 
168
                *p = '\0';
 
169
                do {
 
170
                    *--p = (char)((n&1)+'0');
 
171
                    n >>= 1;
 
172
                    len++;
 
173
                } while (n != 0);
 
174
                len = ndigits - len;
 
175
                if (len > 0)
 
176
                s.fill(' ', len);
 
177
                s += QString::fromLatin1(p);
 
178
            }
 
179
            break;
 
180
    }
 
181
    if (negative) {
 
182
        for (int i=0; i<(int)s.length(); i++) {
 
183
            if (s[i] != ' ') {
 
184
                if (i != 0) {
 
185
                    s[i-1] = '-';
 
186
                } else {
 
187
                    s.insert(0, '-');
 
188
                }
 
189
                break;
 
190
            }
 
191
        }
 
192
    }
 
193
    if (oflow)
 
194
        *oflow = (int)s.length() > ndigits;
 
195
    return s;
 
196
}
 
197
 
 
198
 
 
199
static QString double2string(double num, int base, int ndigits, bool *oflow)
 
200
{
 
201
    QString s;
 
202
    if (base != QLCDNumber::Dec) {
 
203
        bool of = num >= 2147483648.0 || num < -2147483648.0;
 
204
        if (of) {                             // oops, integer overflow
 
205
            if (oflow)
 
206
                *oflow = true;
 
207
            return s;
 
208
        }
 
209
        s = int2string((int)num, base, ndigits, 0);
 
210
    } else {                                    // decimal base
 
211
        int nd = ndigits;
 
212
        do {
 
213
            s.sprintf("%*.*g", ndigits, nd, num);
 
214
            int i = s.indexOf('e');
 
215
            if (i > 0 && s[i+1]=='+') {
 
216
                s[i] = ' ';
 
217
                s[i+1] = 'e';
 
218
            }
 
219
        } while (nd-- && (int)s.length() > ndigits);
 
220
    }
 
221
    if (oflow)
 
222
        *oflow = (int)s.length() > ndigits;
 
223
    return s;
 
224
}
 
225
 
 
226
 
 
227
static const char *getSegments(char ch)               // gets list of segments for ch
 
228
{
 
229
    static const char segments[30][8] =
 
230
       { { 0, 1, 2, 4, 5, 6,99, 0},             // 0    0 / O
 
231
         { 2, 5,99, 0, 0, 0, 0, 0},             // 1    1
 
232
         { 0, 2, 3, 4, 6,99, 0, 0},             // 2    2
 
233
         { 0, 2, 3, 5, 6,99, 0, 0},             // 3    3
 
234
         { 1, 2, 3, 5,99, 0, 0, 0},             // 4    4
 
235
         { 0, 1, 3, 5, 6,99, 0, 0},             // 5    5 / S
 
236
         { 0, 1, 3, 4, 5, 6,99, 0},             // 6    6
 
237
         { 0, 2, 5,99, 0, 0, 0, 0},             // 7    7
 
238
         { 0, 1, 2, 3, 4, 5, 6,99},             // 8    8
 
239
         { 0, 1, 2, 3, 5, 6,99, 0},             // 9    9 / g
 
240
         { 3,99, 0, 0, 0, 0, 0, 0},             // 10   -
 
241
         { 7,99, 0, 0, 0, 0, 0, 0},             // 11   .
 
242
         { 0, 1, 2, 3, 4, 5,99, 0},             // 12   A
 
243
         { 1, 3, 4, 5, 6,99, 0, 0},             // 13   B
 
244
         { 0, 1, 4, 6,99, 0, 0, 0},             // 14   C
 
245
         { 2, 3, 4, 5, 6,99, 0, 0},             // 15   D
 
246
         { 0, 1, 3, 4, 6,99, 0, 0},             // 16   E
 
247
         { 0, 1, 3, 4,99, 0, 0, 0},             // 17   F
 
248
         { 1, 3, 4, 5,99, 0, 0, 0},             // 18   h
 
249
         { 1, 2, 3, 4, 5,99, 0, 0},             // 19   H
 
250
         { 1, 4, 6,99, 0, 0, 0, 0},             // 20   L
 
251
         { 3, 4, 5, 6,99, 0, 0, 0},             // 21   o
 
252
         { 0, 1, 2, 3, 4,99, 0, 0},             // 22   P
 
253
         { 3, 4,99, 0, 0, 0, 0, 0},             // 23   r
 
254
         { 4, 5, 6,99, 0, 0, 0, 0},             // 24   u
 
255
         { 1, 2, 4, 5, 6,99, 0, 0},             // 25   U
 
256
         { 1, 2, 3, 5, 6,99, 0, 0},             // 26   Y
 
257
         { 8, 9,99, 0, 0, 0, 0, 0},             // 27   :
 
258
         { 0, 1, 2, 3,99, 0, 0, 0},             // 28   '
 
259
         {99, 0, 0, 0, 0, 0, 0, 0} };           // 29   empty
 
260
 
 
261
    if (ch >= '0' && ch <= '9')
 
262
        return segments[ch - '0'];
 
263
    if (ch >= 'A' && ch <= 'F')
 
264
        return segments[ch - 'A' + 12];
 
265
    if (ch >= 'a' && ch <= 'f')
 
266
        return segments[ch - 'a' + 12];
 
267
 
 
268
    int n;
 
269
    switch (ch) {
 
270
        case '-':
 
271
            n = 10;  break;
 
272
        case 'O':
 
273
            n = 0;   break;
 
274
        case 'g':
 
275
            n = 9;   break;
 
276
        case '.':
 
277
            n = 11;  break;
 
278
        case 'h':
 
279
            n = 18;  break;
 
280
        case 'H':
 
281
            n = 19;  break;
 
282
        case 'l':
 
283
        case 'L':
 
284
            n = 20;  break;
 
285
        case 'o':
 
286
            n = 21;  break;
 
287
        case 'p':
 
288
        case 'P':
 
289
            n = 22;  break;
 
290
        case 'r':
 
291
        case 'R':
 
292
            n = 23;  break;
 
293
        case 's':
 
294
        case 'S':
 
295
            n = 5;   break;
 
296
        case 'u':
 
297
            n = 24;  break;
 
298
        case 'U':
 
299
            n = 25;  break;
 
300
        case 'y':
 
301
        case 'Y':
 
302
            n = 26;  break;
 
303
        case ':':
 
304
            n = 27;  break;
 
305
        case '\'':
 
306
            n = 28;  break;
 
307
        default:
 
308
            n = 29;  break;
 
309
    }
 
310
    return segments[n];
 
311
}
 
312
 
 
313
 
 
314
#ifdef QT3_SUPPORT
 
315
/*! \obsolete
 
316
    Constructs an LCD number, sets the number of digits to 5, the base
 
317
    to decimal, the decimal point mode to 'small' and the frame style
 
318
    to a raised box. The segmentStyle() is set to \c Outline.
 
319
 
 
320
    The \a parent and \a name arguments are passed to the QFrame
 
321
    constructor.
 
322
 
 
323
    \sa setNumDigits(), setSmallDecimalPoint()
 
324
*/
 
325
 
 
326
QLCDNumber::QLCDNumber(QWidget *parent, const char *name)
 
327
        : QFrame(*new QLCDNumberPrivate, parent)
 
328
{
 
329
    setObjectName(name);
 
330
    Q_D(QLCDNumber);
 
331
    d->ndigits = 5;
 
332
    d->init();
 
333
}
 
334
 
 
335
 
 
336
/*! \obsolete
 
337
    Constructs an LCD number, sets the number of digits to \a
 
338
    numDigits, the base to decimal, the decimal point mode to 'small'
 
339
    and the frame style to a raised box. The segmentStyle() is set to
 
340
    \c Outline.
 
341
 
 
342
    The \a parent and \a name arguments are passed to the QFrame
 
343
    constructor.
 
344
 
 
345
    \sa setNumDigits(), setSmallDecimalPoint()
 
346
*/
 
347
 
 
348
QLCDNumber::QLCDNumber(uint numDigits, QWidget *parent, const char *name)
 
349
        : QFrame(*new QLCDNumberPrivate, parent)
 
350
{
 
351
    setObjectName(name);
 
352
    Q_D(QLCDNumber);
 
353
    d->ndigits = numDigits;
 
354
    d->init();
 
355
}
 
356
#endif //QT3_SUPPORT
 
357
 
 
358
/*!
 
359
    Constructs an LCD number, sets the number of digits to 5, the base
 
360
    to decimal, the decimal point mode to 'small' and the frame style
 
361
    to a raised box. The segmentStyle() is set to \c Outline.
 
362
 
 
363
    The \a parent argument is passed to the QFrame constructor.
 
364
 
 
365
    \sa setNumDigits(), setSmallDecimalPoint()
 
366
*/
 
367
 
 
368
QLCDNumber::QLCDNumber(QWidget *parent)
 
369
        : QFrame(*new QLCDNumberPrivate, parent)
 
370
{
 
371
    Q_D(QLCDNumber);
 
372
    d->ndigits = 5;
 
373
    d->init();
 
374
}
 
375
 
 
376
 
 
377
/*!
 
378
    Constructs an LCD number, sets the number of digits to \a
 
379
    numDigits, the base to decimal, the decimal point mode to 'small'
 
380
    and the frame style to a raised box. The segmentStyle() is set to
 
381
    \c Outline.
 
382
 
 
383
    The \a parent argument is passed to the QFrame constructor.
 
384
 
 
385
    \sa setNumDigits(), setSmallDecimalPoint()
 
386
*/
 
387
 
 
388
QLCDNumber::QLCDNumber(uint numDigits, QWidget *parent)
 
389
        : QFrame(*new QLCDNumberPrivate, parent)
 
390
{
 
391
    Q_D(QLCDNumber);
 
392
    d->ndigits = numDigits;
 
393
    d->init();
 
394
}
 
395
 
 
396
void QLCDNumberPrivate::init()
 
397
{
 
398
    Q_Q(QLCDNumber);
 
399
 
 
400
    q->setFrameStyle(QFrame::Box | QFrame::Raised);
 
401
    val        = 0;
 
402
    base       = QLCDNumber::Dec;
 
403
    smallPoint = false;
 
404
    q->setNumDigits(ndigits);
 
405
    q->setSegmentStyle(QLCDNumber::Outline);
 
406
    q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
 
407
}
 
408
 
 
409
/*!
 
410
    Destroys the LCD number.
 
411
*/
 
412
 
 
413
QLCDNumber::~QLCDNumber()
 
414
{
 
415
}
 
416
 
 
417
 
 
418
/*!
 
419
    \property QLCDNumber::numDigits
 
420
    \brief the current number of digits displayed
 
421
 
 
422
    Corresponds to the current number of digits. If \l
 
423
    QLCDNumber::smallDecimalPoint is false, the decimal point occupies
 
424
    one digit position.
 
425
 
 
426
    \sa smallDecimalPoint
 
427
*/
 
428
 
 
429
void QLCDNumber::setNumDigits(int numDigits)
 
430
{
 
431
    Q_D(QLCDNumber);
 
432
    if (numDigits > 99) {
 
433
        qWarning("QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
 
434
                 objectName().toLocal8Bit().constData());
 
435
        numDigits = 99;
 
436
    }
 
437
    if (numDigits < 0) {
 
438
        qWarning("QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
 
439
                 objectName().toLocal8Bit().constData());
 
440
        numDigits = 0;
 
441
    }
 
442
    if (d->digitStr.isNull()) {                  // from constructor
 
443
        d->ndigits = numDigits;
 
444
        d->digitStr.fill(' ', d->ndigits);
 
445
        d->points.fill(0, d->ndigits);
 
446
        d->digitStr[d->ndigits - 1] = '0';            // "0" is the default number
 
447
    } else {
 
448
        bool doDisplay = d->ndigits == 0;
 
449
        if (numDigits == d->ndigits)             // no change
 
450
            return;
 
451
        register int i;
 
452
        int dif;
 
453
        if (numDigits > d->ndigits) {            // expand
 
454
            dif = numDigits - d->ndigits;
 
455
            QString buf;
 
456
            buf.fill(' ', dif);
 
457
            d->digitStr.insert(0, buf);
 
458
            d->points.resize(numDigits);
 
459
            for (i=numDigits-1; i>=dif; i--)
 
460
                d->points.setBit(i, d->points.testBit(i-dif));
 
461
            for (i=0; i<dif; i++)
 
462
                d->points.clearBit(i);
 
463
        } else {                                        // shrink
 
464
            dif = d->ndigits - numDigits;
 
465
            d->digitStr = d->digitStr.right(numDigits);
 
466
            QBitArray tmpPoints = d->points;
 
467
            d->points.resize(numDigits);
 
468
            for (i=0; i<(int)numDigits; i++)
 
469
                d->points.setBit(i, tmpPoints.testBit(i+dif));
 
470
        }
 
471
        d->ndigits = numDigits;
 
472
        if (doDisplay)
 
473
            display(value());
 
474
        update();
 
475
    }
 
476
}
 
477
 
 
478
int QLCDNumber::numDigits() const
 
479
{
 
480
    Q_D(const QLCDNumber);
 
481
    return d->ndigits;
 
482
}
 
483
 
 
484
/*!
 
485
    \overload
 
486
 
 
487
    Returns true if \a num is too big to be displayed in its entirety;
 
488
    otherwise returns false.
 
489
 
 
490
    \sa display(), numDigits(), smallDecimalPoint()
 
491
*/
 
492
 
 
493
bool QLCDNumber::checkOverflow(int num) const
 
494
{
 
495
    Q_D(const QLCDNumber);
 
496
    bool of;
 
497
    int2string(num, d->base, d->ndigits, &of);
 
498
    return of;
 
499
}
 
500
 
 
501
 
 
502
/*!
 
503
    Returns true if \a num is too big to be displayed in its entirety;
 
504
    otherwise returns false.
 
505
 
 
506
    \sa display(), numDigits(), smallDecimalPoint()
 
507
*/
 
508
 
 
509
bool QLCDNumber::checkOverflow(double num) const
 
510
{
 
511
    Q_D(const QLCDNumber);
 
512
    bool of;
 
513
    double2string(num, d->base, d->ndigits, &of);
 
514
    return of;
 
515
}
 
516
 
 
517
 
 
518
/*!
 
519
    \property QLCDNumber::mode
 
520
    \brief the current display mode (number base)
 
521
 
 
522
    Corresponds to the current display mode, which is one of \c Bin,
 
523
    \c Oct, \c Dec (the default) and \c Hex. \c Dec mode can display
 
524
    floating point values, the other modes display the integer
 
525
    equivalent.
 
526
 
 
527
    \sa smallDecimalPoint(), setHexMode(), setDecMode(), setOctMode(), setBinMode()
 
528
*/
 
529
 
 
530
QLCDNumber::Mode QLCDNumber::mode() const
 
531
{
 
532
    Q_D(const QLCDNumber);
 
533
    return (QLCDNumber::Mode) d->base;
 
534
}
 
535
 
 
536
void QLCDNumber::setMode(Mode m)
 
537
{
 
538
    Q_D(QLCDNumber);
 
539
    d->base = m;
 
540
    display(d->val);
 
541
}
 
542
 
 
543
 
 
544
/*!
 
545
    \property QLCDNumber::value
 
546
    \brief the displayed value
 
547
 
 
548
    This property corresponds to the current value displayed by the
 
549
    LCDNumber.
 
550
 
 
551
    If the displayed value is not a number, the property has a value
 
552
    of 0.
 
553
*/
 
554
 
 
555
double QLCDNumber::value() const
 
556
{
 
557
    Q_D(const QLCDNumber);
 
558
    return d->val;
 
559
}
 
560
 
 
561
/*!
 
562
    \overload
 
563
 
 
564
    Displays the number \a num.
 
565
*/
 
566
void QLCDNumber::display(double num)
 
567
{
 
568
    Q_D(QLCDNumber);
 
569
    d->val = num;
 
570
    bool of;
 
571
    QString s = double2string(d->val, d->base, d->ndigits, &of);
 
572
    if (of)
 
573
        emit overflow();
 
574
    else
 
575
        d->internalSetString(s);
 
576
}
 
577
 
 
578
/*!
 
579
    \property QLCDNumber::intValue
 
580
    \brief the displayed value rounded to the nearest integer
 
581
 
 
582
    This property corresponds to the nearest integer to the current
 
583
    value displayed by the LCDNumber. This is the value used for
 
584
    hexadecimal, octal and binary modes.
 
585
 
 
586
    If the displayed value is not a number, the property has a value
 
587
    of 0.
 
588
*/
 
589
int QLCDNumber::intValue() const
 
590
{
 
591
    Q_D(const QLCDNumber);
 
592
    return qRound(d->val);
 
593
}
 
594
 
 
595
 
 
596
/*!
 
597
    \overload
 
598
 
 
599
    Displays the number \a num.
 
600
*/
 
601
void QLCDNumber::display(int num)
 
602
{
 
603
    Q_D(QLCDNumber);
 
604
    d->val = (double)num;
 
605
    bool of;
 
606
    QString s = int2string(num, d->base, d->ndigits, &of);
 
607
    if (of)
 
608
        emit overflow();
 
609
    else
 
610
        d->internalSetString(s);
 
611
}
 
612
 
 
613
 
 
614
/*!
 
615
    Displays the number represented by the string \a s.
 
616
 
 
617
    This version of the function disregards mode() and
 
618
    smallDecimalPoint().
 
619
 
 
620
    These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
 
621
    6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
 
622
    P, r, u, U, Y, colon, degree sign (which is specified as single
 
623
    quote in the string) and space. QLCDNumber substitutes spaces for
 
624
    illegal characters.
 
625
*/
 
626
 
 
627
void QLCDNumber::display(const QString &s)
 
628
{
 
629
    Q_D(QLCDNumber);
 
630
    d->val = 0;
 
631
    bool ok = false;
 
632
    double v = s.toDouble(&ok);
 
633
    if (ok)
 
634
        d->val = v;
 
635
    d->internalSetString(s);
 
636
}
 
637
 
 
638
/*!
 
639
    Calls setMode(Hex). Provided for convenience (e.g. for
 
640
    connecting buttons to it).
 
641
 
 
642
    \sa setMode(), setDecMode(), setOctMode(), setBinMode(), mode()
 
643
*/
 
644
 
 
645
void QLCDNumber::setHexMode()
 
646
{
 
647
    setMode(Hex);
 
648
}
 
649
 
 
650
 
 
651
/*!
 
652
    Calls setMode(Dec). Provided for convenience (e.g. for
 
653
    connecting buttons to it).
 
654
 
 
655
    \sa setMode(), setHexMode(), setOctMode(), setBinMode(), mode()
 
656
*/
 
657
 
 
658
void QLCDNumber::setDecMode()
 
659
{
 
660
    setMode(Dec);
 
661
}
 
662
 
 
663
 
 
664
/*!
 
665
    Calls setMode(Oct). Provided for convenience (e.g. for
 
666
    connecting buttons to it).
 
667
 
 
668
    \sa setMode(), setHexMode(), setDecMode(), setBinMode(), mode()
 
669
*/
 
670
 
 
671
void QLCDNumber::setOctMode()
 
672
{
 
673
    setMode(Oct);
 
674
}
 
675
 
 
676
 
 
677
/*!
 
678
    Calls setMode(Bin). Provided for convenience (e.g. for
 
679
    connecting buttons to it).
 
680
 
 
681
    \sa setMode(), setHexMode(), setDecMode(), setOctMode(), mode()
 
682
*/
 
683
 
 
684
void QLCDNumber::setBinMode()
 
685
{
 
686
    setMode(Bin);
 
687
}
 
688
 
 
689
 
 
690
/*!
 
691
    \property QLCDNumber::smallDecimalPoint
 
692
    \brief the style of the decimal point
 
693
 
 
694
    If true the decimal point is drawn between two digit positions.
 
695
    Otherwise it occupies a digit position of its own, i.e. is drawn
 
696
    in a digit position. The default is false.
 
697
 
 
698
    The inter-digit space is made slightly wider when the decimal
 
699
    point is drawn between the digits.
 
700
 
 
701
    \sa mode
 
702
*/
 
703
 
 
704
void QLCDNumber::setSmallDecimalPoint(bool b)
 
705
{
 
706
    Q_D(QLCDNumber);
 
707
    d->smallPoint = b;
 
708
    update();
 
709
}
 
710
 
 
711
bool QLCDNumber::smallDecimalPoint() const
 
712
{
 
713
    Q_D(const QLCDNumber);
 
714
    return d->smallPoint;
 
715
}
 
716
 
 
717
 
 
718
 
 
719
/*!\reimp
 
720
*/
 
721
 
 
722
 
 
723
void QLCDNumber::paintEvent(QPaintEvent *)
 
724
{
 
725
    Q_D(QLCDNumber);
 
726
    QPainter p(this);
 
727
    drawFrame(&p);
 
728
    if (d->smallPoint)
 
729
        d->drawString(d->digitStr, p, &d->points, false);
 
730
    else
 
731
        d->drawString(d->digitStr, p, 0, false);
 
732
}
 
733
 
 
734
 
 
735
void QLCDNumberPrivate::internalSetString(const QString& s)
 
736
{
 
737
    Q_Q(QLCDNumber);
 
738
    QString buffer;
 
739
    int i;
 
740
    int len = s.length();
 
741
    QBitArray newPoints(ndigits);
 
742
 
 
743
    if (!smallPoint) {
 
744
        if (len == ndigits)
 
745
            buffer = s;
 
746
        else
 
747
            buffer = s.right(ndigits).rightJustified(ndigits, ' ');
 
748
    } else {
 
749
        int  index = -1;
 
750
        bool lastWasPoint = true;
 
751
        newPoints.clearBit(0);
 
752
        for (i=0; i<len; i++) {
 
753
            if (s[i] == '.') {
 
754
                if (lastWasPoint) {           // point already set for digit?
 
755
                    if (index == ndigits - 1) // no more digits
 
756
                        break;
 
757
                    index++;
 
758
                    buffer[index] = ' ';        // 2 points in a row, add space
 
759
                }
 
760
                newPoints.setBit(index);        // set decimal point
 
761
                lastWasPoint = true;
 
762
            } else {
 
763
                if (index == ndigits - 1)
 
764
                    break;
 
765
                index++;
 
766
                buffer[index] = s[i];
 
767
                newPoints.clearBit(index);      // decimal point default off
 
768
                lastWasPoint = false;
 
769
            }
 
770
        }
 
771
        if (index < ((int) ndigits) - 1) {
 
772
            for(i=index; i>=0; i--) {
 
773
                buffer[ndigits - 1 - index + i] = buffer[i];
 
774
                newPoints.setBit(ndigits - 1 - index + i,
 
775
                                   newPoints.testBit(i));
 
776
            }
 
777
            for(i=0; i<ndigits-index-1; i++) {
 
778
                buffer[i] = ' ';
 
779
                newPoints.clearBit(i);
 
780
            }
 
781
        }
 
782
    }
 
783
 
 
784
    if (buffer == digitStr)
 
785
        return;
 
786
 
 
787
    digitStr = buffer;
 
788
    if (smallPoint)
 
789
        points = newPoints;
 
790
    q->update();
 
791
}
 
792
 
 
793
/*!
 
794
  \internal
 
795
*/
 
796
 
 
797
void QLCDNumberPrivate::drawString(const QString &s, QPainter &p,
 
798
                                   QBitArray *newPoints, bool newString)
 
799
{
 
800
    Q_Q(QLCDNumber);
 
801
    QPoint  pos;
 
802
 
 
803
    int digitSpace = smallPoint ? 2 : 1;
 
804
    int xSegLen    = q->width()*5/(ndigits*(5 + digitSpace) + digitSpace);
 
805
    int ySegLen    = q->height()*5/12;
 
806
    int segLen     = ySegLen > xSegLen ? xSegLen : ySegLen;
 
807
    int xAdvance   = segLen*(5 + digitSpace)/5;
 
808
    int xOffset    = (q->width() - ndigits*xAdvance + segLen/5)/2;
 
809
    int yOffset    = (q->height() - segLen*2)/2;
 
810
 
 
811
    for (int i=0;  i<ndigits; i++) {
 
812
        pos = QPoint(xOffset + xAdvance*i, yOffset);
 
813
        if (newString)
 
814
            drawDigit(pos, p, segLen, s[i].toLatin1(), digitStr[i].toLatin1());
 
815
        else
 
816
            drawDigit(pos, p, segLen, s[i].toLatin1());
 
817
        if (newPoints) {
 
818
            char newPoint = newPoints->testBit(i) ? '.' : ' ';
 
819
            if (newString) {
 
820
                char oldPoint = points.testBit(i) ? '.' : ' ';
 
821
                drawDigit(pos, p, segLen, newPoint, oldPoint);
 
822
            } else {
 
823
                drawDigit(pos, p, segLen, newPoint);
 
824
            }
 
825
        }
 
826
    }
 
827
    if (newString) {
 
828
        digitStr = s;
 
829
        digitStr.truncate(ndigits);
 
830
        if (newPoints)
 
831
            points = *newPoints;
 
832
    }
 
833
}
 
834
 
 
835
 
 
836
/*!
 
837
  \internal
 
838
*/
 
839
 
 
840
void QLCDNumberPrivate::drawDigit(const QPoint &pos, QPainter &p, int segLen,
 
841
                                  char newCh, char oldCh)
 
842
{
 
843
// Draws and/or erases segments to change display of a single digit
 
844
// from oldCh to newCh
 
845
 
 
846
    char updates[18][2];        // can hold 2 times number of segments, only
 
847
                                // first 9 used if segment table is correct
 
848
    int  nErases;
 
849
    int  nUpdates;
 
850
    const char *segs;
 
851
    int  i,j;
 
852
 
 
853
    const char erase      = 0;
 
854
    const char draw       = 1;
 
855
    const char leaveAlone = 2;
 
856
 
 
857
    segs = getSegments(oldCh);
 
858
    for (nErases=0; segs[nErases] != 99; nErases++) {
 
859
        updates[nErases][0] = erase;            // get segments to erase to
 
860
        updates[nErases][1] = segs[nErases];    // remove old char
 
861
    }
 
862
    nUpdates = nErases;
 
863
    segs = getSegments(newCh);
 
864
    for(i = 0 ; segs[i] != 99 ; i++) {
 
865
        for (j=0;  j<nErases; j++)
 
866
            if (segs[i] == updates[j][1]) {   // same segment ?
 
867
                updates[j][0] = leaveAlone;     // yes, already on screen
 
868
                break;
 
869
            }
 
870
        if (j == nErases) {                   // if not already on screen
 
871
            updates[nUpdates][0] = draw;
 
872
            updates[nUpdates][1] = segs[i];
 
873
            nUpdates++;
 
874
        }
 
875
    }
 
876
    for (i=0; i<nUpdates; i++) {
 
877
        if (updates[i][0] == draw)
 
878
            drawSegment(pos, updates[i][1], p, segLen);
 
879
        if (updates[i][0] == erase)
 
880
            drawSegment(pos, updates[i][1], p, segLen, true);
 
881
    }
 
882
}
 
883
 
 
884
 
 
885
static void addPoint(QPolygon &a, const QPoint &p)
 
886
{
 
887
    uint n = a.size();
 
888
    a.resize(n + 1);
 
889
    a.setPoint(n, p);
 
890
}
 
891
 
 
892
/*!
 
893
  \internal
 
894
*/
 
895
 
 
896
void QLCDNumberPrivate::drawSegment(const QPoint &pos, char segmentNo, QPainter &p,
 
897
                                    int segLen, bool erase)
 
898
{
 
899
    Q_Q(QLCDNumber);
 
900
    QPoint ppt;
 
901
    QPoint pt = pos;
 
902
    int width = segLen/5;
 
903
 
 
904
    const QPalette &pal = q->palette();
 
905
    QColor lightColor,darkColor,fgColor;
 
906
    if (erase){
 
907
        lightColor = pal.color(q->backgroundRole());
 
908
        darkColor  = lightColor;
 
909
        fgColor    = lightColor;
 
910
    } else {
 
911
        lightColor = pal.light().color();
 
912
        darkColor  = pal.dark().color();
 
913
        fgColor    = pal.color(q->foregroundRole());
 
914
    }
 
915
 
 
916
 
 
917
#define LINETO(X,Y) addPoint(a, QPoint(pt.x() + (X),pt.y() + (Y)))
 
918
#define LIGHT
 
919
#define DARK
 
920
 
 
921
    if (fill) {
 
922
        QPolygon a(0);
 
923
        //The following is an exact copy of the switch below.
 
924
        //don't make any changes here
 
925
        switch (segmentNo) {
 
926
        case 0 :
 
927
            ppt = pt;
 
928
            LIGHT;
 
929
            LINETO(segLen - 1,0);
 
930
            DARK;
 
931
            LINETO(segLen - width - 1,width);
 
932
            LINETO(width,width);
 
933
            LINETO(0,0);
 
934
            break;
 
935
        case 1 :
 
936
            pt += QPoint(0 , 1);
 
937
            ppt = pt;
 
938
            LIGHT;
 
939
            LINETO(width,width);
 
940
            DARK;
 
941
            LINETO(width,segLen - width/2 - 2);
 
942
            LINETO(0,segLen - 2);
 
943
            LIGHT;
 
944
            LINETO(0,0);
 
945
            break;
 
946
        case 2 :
 
947
            pt += QPoint(segLen - 1 , 1);
 
948
            ppt = pt;
 
949
            DARK;
 
950
            LINETO(0,segLen - 2);
 
951
            LINETO(-width,segLen - width/2 - 2);
 
952
            LIGHT;
 
953
            LINETO(-width,width);
 
954
            LINETO(0,0);
 
955
            break;
 
956
        case 3 :
 
957
            pt += QPoint(0 , segLen);
 
958
            ppt = pt;
 
959
            LIGHT;
 
960
            LINETO(width,-width/2);
 
961
            LINETO(segLen - width - 1,-width/2);
 
962
            LINETO(segLen - 1,0);
 
963
            DARK;
 
964
            if (width & 1) {            // adjust for integer division error
 
965
                LINETO(segLen - width - 3,width/2 + 1);
 
966
                LINETO(width + 2,width/2 + 1);
 
967
            } else {
 
968
                LINETO(segLen - width - 1,width/2);
 
969
                LINETO(width,width/2);
 
970
            }
 
971
            LINETO(0,0);
 
972
            break;
 
973
        case 4 :
 
974
            pt += QPoint(0 , segLen + 1);
 
975
            ppt = pt;
 
976
            LIGHT;
 
977
            LINETO(width,width/2);
 
978
            DARK;
 
979
            LINETO(width,segLen - width - 2);
 
980
            LINETO(0,segLen - 2);
 
981
            LIGHT;
 
982
            LINETO(0,0);
 
983
            break;
 
984
        case 5 :
 
985
            pt += QPoint(segLen - 1 , segLen + 1);
 
986
            ppt = pt;
 
987
            DARK;
 
988
            LINETO(0,segLen - 2);
 
989
            LINETO(-width,segLen - width - 2);
 
990
            LIGHT;
 
991
            LINETO(-width,width/2);
 
992
            LINETO(0,0);
 
993
            break;
 
994
        case 6 :
 
995
            pt += QPoint(0 , segLen*2);
 
996
            ppt = pt;
 
997
            LIGHT;
 
998
            LINETO(width,-width);
 
999
            LINETO(segLen - width - 1,-width);
 
1000
            LINETO(segLen - 1,0);
 
1001
            DARK;
 
1002
            LINETO(0,0);
 
1003
            break;
 
1004
        case 7 :
 
1005
            if (smallPoint)   // if smallpoint place'.' between other digits
 
1006
                pt += QPoint(segLen + width/2 , segLen*2);
 
1007
            else
 
1008
                pt += QPoint(segLen/2 , segLen*2);
 
1009
            ppt = pt;
 
1010
            DARK;
 
1011
            LINETO(width,0);
 
1012
            LINETO(width,-width);
 
1013
            LIGHT;
 
1014
            LINETO(0,-width);
 
1015
            LINETO(0,0);
 
1016
            break;
 
1017
        case 8 :
 
1018
            pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
 
1019
            ppt = pt;
 
1020
            DARK;
 
1021
            LINETO(width,0);
 
1022
            LINETO(width,-width);
 
1023
            LIGHT;
 
1024
            LINETO(0,-width);
 
1025
            LINETO(0,0);
 
1026
            break;
 
1027
        case 9 :
 
1028
            pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
 
1029
            ppt = pt;
 
1030
            DARK;
 
1031
            LINETO(width,0);
 
1032
            LINETO(width,-width);
 
1033
            LIGHT;
 
1034
            LINETO(0,-width);
 
1035
            LINETO(0,0);
 
1036
            break;
 
1037
        default :
 
1038
            qWarning("QLCDNumber::drawSegment: (%s) Internal error."
 
1039
                     "  Illegal segment id: %d\n",
 
1040
                     q->objectName().toLocal8Bit().constData(), segmentNo);
 
1041
        }
 
1042
        // End exact copy
 
1043
        p.setPen(fgColor);
 
1044
        p.setBrush(fgColor);
 
1045
        p.drawPolygon(a);
 
1046
        p.setBrush(Qt::NoBrush);
 
1047
 
 
1048
        pt = pos;
 
1049
    }
 
1050
#undef LINETO
 
1051
#undef LIGHT
 
1052
#undef DARK
 
1053
 
 
1054
#define LINETO(X,Y) p.drawLine(ppt.x(), ppt.y(), pt.x()+(X), pt.y()+(Y)); \
 
1055
                    ppt = QPoint(pt.x()+(X), pt.y()+(Y))
 
1056
#define LIGHT p.setPen(lightColor)
 
1057
#define DARK  p.setPen(darkColor)
 
1058
    if (shadow)
 
1059
        switch (segmentNo) {
 
1060
        case 0 :
 
1061
            ppt = pt;
 
1062
            LIGHT;
 
1063
            LINETO(segLen - 1,0);
 
1064
            DARK;
 
1065
            LINETO(segLen - width - 1,width);
 
1066
            LINETO(width,width);
 
1067
            LINETO(0,0);
 
1068
            break;
 
1069
        case 1 :
 
1070
            pt += QPoint(0,1);
 
1071
            ppt = pt;
 
1072
            LIGHT;
 
1073
            LINETO(width,width);
 
1074
            DARK;
 
1075
            LINETO(width,segLen - width/2 - 2);
 
1076
            LINETO(0,segLen - 2);
 
1077
            LIGHT;
 
1078
            LINETO(0,0);
 
1079
            break;
 
1080
        case 2 :
 
1081
            pt += QPoint(segLen - 1 , 1);
 
1082
            ppt = pt;
 
1083
            DARK;
 
1084
            LINETO(0,segLen - 2);
 
1085
            LINETO(-width,segLen - width/2 - 2);
 
1086
            LIGHT;
 
1087
            LINETO(-width,width);
 
1088
            LINETO(0,0);
 
1089
            break;
 
1090
        case 3 :
 
1091
            pt += QPoint(0 , segLen);
 
1092
            ppt = pt;
 
1093
            LIGHT;
 
1094
            LINETO(width,-width/2);
 
1095
            LINETO(segLen - width - 1,-width/2);
 
1096
            LINETO(segLen - 1,0);
 
1097
            DARK;
 
1098
            if (width & 1) {            // adjust for integer division error
 
1099
                LINETO(segLen - width - 3,width/2 + 1);
 
1100
                LINETO(width + 2,width/2 + 1);
 
1101
            } else {
 
1102
                LINETO(segLen - width - 1,width/2);
 
1103
                LINETO(width,width/2);
 
1104
            }
 
1105
            LINETO(0,0);
 
1106
            break;
 
1107
        case 4 :
 
1108
            pt += QPoint(0 , segLen + 1);
 
1109
            ppt = pt;
 
1110
            LIGHT;
 
1111
            LINETO(width,width/2);
 
1112
            DARK;
 
1113
            LINETO(width,segLen - width - 2);
 
1114
            LINETO(0,segLen - 2);
 
1115
            LIGHT;
 
1116
            LINETO(0,0);
 
1117
            break;
 
1118
        case 5 :
 
1119
            pt += QPoint(segLen - 1 , segLen + 1);
 
1120
            ppt = pt;
 
1121
            DARK;
 
1122
            LINETO(0,segLen - 2);
 
1123
            LINETO(-width,segLen - width - 2);
 
1124
            LIGHT;
 
1125
            LINETO(-width,width/2);
 
1126
            LINETO(0,0);
 
1127
            break;
 
1128
        case 6 :
 
1129
            pt += QPoint(0 , segLen*2);
 
1130
            ppt = pt;
 
1131
            LIGHT;
 
1132
            LINETO(width,-width);
 
1133
            LINETO(segLen - width - 1,-width);
 
1134
            LINETO(segLen - 1,0);
 
1135
            DARK;
 
1136
            LINETO(0,0);
 
1137
            break;
 
1138
        case 7 :
 
1139
            if (smallPoint)   // if smallpoint place'.' between other digits
 
1140
                pt += QPoint(segLen + width/2 , segLen*2);
 
1141
            else
 
1142
                pt += QPoint(segLen/2 , segLen*2);
 
1143
            ppt = pt;
 
1144
            DARK;
 
1145
            LINETO(width,0);
 
1146
            LINETO(width,-width);
 
1147
            LIGHT;
 
1148
            LINETO(0,-width);
 
1149
            LINETO(0,0);
 
1150
            break;
 
1151
        case 8 :
 
1152
            pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
 
1153
            ppt = pt;
 
1154
            DARK;
 
1155
            LINETO(width,0);
 
1156
            LINETO(width,-width);
 
1157
            LIGHT;
 
1158
            LINETO(0,-width);
 
1159
            LINETO(0,0);
 
1160
            break;
 
1161
        case 9 :
 
1162
            pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
 
1163
            ppt = pt;
 
1164
            DARK;
 
1165
            LINETO(width,0);
 
1166
            LINETO(width,-width);
 
1167
            LIGHT;
 
1168
            LINETO(0,-width);
 
1169
            LINETO(0,0);
 
1170
            break;
 
1171
        default :
 
1172
            qWarning("QLCDNumber::drawSegment: (%s) Internal error."
 
1173
                     "  Illegal segment id: %d\n",
 
1174
                     q->objectName().toLocal8Bit().constData(), segmentNo);
 
1175
        }
 
1176
 
 
1177
#undef LINETO
 
1178
#undef LIGHT
 
1179
#undef DARK
 
1180
}
 
1181
 
 
1182
 
 
1183
 
 
1184
/*!
 
1185
    \property QLCDNumber::segmentStyle
 
1186
    \brief the style of the LCDNumber
 
1187
 
 
1188
    \table
 
1189
    \header \i Style \i Result
 
1190
    \row \i \c Outline
 
1191
         \i Produces raised segments filled with the background color
 
1192
            (this is the default).
 
1193
    \row \i \c Filled
 
1194
         \i Produces raised segments filled with the foreground color.
 
1195
    \row \i \c Flat
 
1196
         \i Produces flat segments filled with the foreground color.
 
1197
    \endtable
 
1198
 
 
1199
    \c Outline and \c Filled will additionally use
 
1200
    QPalette::light() and QPalette::dark() for shadow effects.
 
1201
*/
 
1202
void QLCDNumber::setSegmentStyle(SegmentStyle s)
 
1203
{
 
1204
    Q_D(QLCDNumber);
 
1205
    d->fill = (s == Flat || s == Filled);
 
1206
    d->shadow = (s == Outline || s == Filled);
 
1207
    update();
 
1208
}
 
1209
 
 
1210
QLCDNumber::SegmentStyle QLCDNumber::segmentStyle() const
 
1211
{
 
1212
    Q_D(const QLCDNumber);
 
1213
    Q_ASSERT(d->fill || d->shadow);
 
1214
    if (!d->fill && d->shadow)
 
1215
        return Outline;
 
1216
    if (d->fill && d->shadow)
 
1217
        return Filled;
 
1218
    return Flat;
 
1219
}
 
1220
 
 
1221
 
 
1222
/*!\reimp
 
1223
*/
 
1224
QSize QLCDNumber::sizeHint() const
 
1225
{
 
1226
    return QSize(10 + 9 * (numDigits() + (smallDecimalPoint() ? 0 : 1)), 23);
 
1227
}
 
1228
 
 
1229
 
 
1230
#endif // QT_NO_LCDNUMBER