source: trunk/src/gui/widgets/qlcdnumber.cpp@ 500

Last change on this file since 500 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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