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

Last change on this file since 603 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 36.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia 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
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 setDigitCount(),
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 setDigitCount().
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 setDigitCount(), 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 setDigitCount(), 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 setDigitCount(), 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 Filled.
407
408 The \a parent argument is passed to the QFrame constructor.
409
410 \sa setDigitCount(), 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->setDigitCount(ndigits);
430 q->setSegmentStyle(QLCDNumber::Filled);
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 \deprecated
445 \property QLCDNumber::numDigits
446 \brief the current number of digits displayed
447 \sa digitCount
448*/
449
450void QLCDNumber::setNumDigits(int numDigits)
451{
452 setDigitCount(numDigits);
453}
454
455/*!
456 \since 4.6
457 \property QLCDNumber::digitCount
458 \brief the current number of digits displayed
459
460 Corresponds to the current number of digits. If \l
461 QLCDNumber::smallDecimalPoint is false, the decimal point occupies
462 one digit position.
463
464 By default, this property contains a value of 5.
465
466 \sa smallDecimalPoint
467*/
468
469/*!
470 Sets the current number of digits to \a numDigits. Must
471 be in the range 0..99.
472 */
473void QLCDNumber::setDigitCount(int numDigits)
474{
475 Q_D(QLCDNumber);
476 if (numDigits > 99) {
477 qWarning("QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
478 objectName().toLocal8Bit().constData());
479 numDigits = 99;
480 }
481 if (numDigits < 0) {
482 qWarning("QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
483 objectName().toLocal8Bit().constData());
484 numDigits = 0;
485 }
486 if (d->digitStr.isNull()) { // from constructor
487 d->ndigits = numDigits;
488 d->digitStr.fill(QLatin1Char(' '), d->ndigits);
489 d->points.fill(0, d->ndigits);
490 d->digitStr[d->ndigits - 1] = QLatin1Char('0'); // "0" is the default number
491 } else {
492 bool doDisplay = d->ndigits == 0;
493 if (numDigits == d->ndigits) // no change
494 return;
495 register int i;
496 int dif;
497 if (numDigits > d->ndigits) { // expand
498 dif = numDigits - d->ndigits;
499 QString buf;
500 buf.fill(QLatin1Char(' '), dif);
501 d->digitStr.insert(0, buf);
502 d->points.resize(numDigits);
503 for (i=numDigits-1; i>=dif; i--)
504 d->points.setBit(i, d->points.testBit(i-dif));
505 for (i=0; i<dif; i++)
506 d->points.clearBit(i);
507 } else { // shrink
508 dif = d->ndigits - numDigits;
509 d->digitStr = d->digitStr.right(numDigits);
510 QBitArray tmpPoints = d->points;
511 d->points.resize(numDigits);
512 for (i=0; i<(int)numDigits; i++)
513 d->points.setBit(i, tmpPoints.testBit(i+dif));
514 }
515 d->ndigits = numDigits;
516 if (doDisplay)
517 display(value());
518 update();
519 }
520}
521
522int QLCDNumber::numDigits() const
523{
524 Q_D(const QLCDNumber);
525 return d->ndigits;
526}
527
528/*!
529 Returns the current number of digits.
530 */
531int QLCDNumber::digitCount() const
532{
533 Q_D(const QLCDNumber);
534 return d->ndigits;
535}
536
537/*!
538 \overload
539
540 Returns true if \a num is too big to be displayed in its entirety;
541 otherwise returns false.
542
543 \sa display(), digitCount(), smallDecimalPoint()
544*/
545
546bool QLCDNumber::checkOverflow(int num) const
547{
548 Q_D(const QLCDNumber);
549 bool of;
550 int2string(num, d->base, d->ndigits, &of);
551 return of;
552}
553
554
555/*!
556 Returns true if \a num is too big to be displayed in its entirety;
557 otherwise returns false.
558
559 \sa display(), digitCount(), smallDecimalPoint()
560*/
561
562bool QLCDNumber::checkOverflow(double num) const
563{
564 Q_D(const QLCDNumber);
565 bool of;
566 double2string(num, d->base, d->ndigits, &of);
567 return of;
568}
569
570
571/*!
572 \property QLCDNumber::mode
573 \brief the current display mode (number base)
574
575 Corresponds to the current display mode, which is one of \c Bin,
576 \c Oct, \c Dec (the default) and \c Hex. \c Dec mode can display
577 floating point values, the other modes display the integer
578 equivalent.
579
580 \sa smallDecimalPoint(), setHexMode(), setDecMode(), setOctMode(), setBinMode()
581*/
582
583QLCDNumber::Mode QLCDNumber::mode() const
584{
585 Q_D(const QLCDNumber);
586 return (QLCDNumber::Mode) d->base;
587}
588
589void QLCDNumber::setMode(Mode m)
590{
591 Q_D(QLCDNumber);
592 d->base = m;
593 display(d->val);
594}
595
596
597/*!
598 \property QLCDNumber::value
599 \brief the displayed value
600
601 This property corresponds to the current value displayed by the
602 LCDNumber.
603
604 If the displayed value is not a number, the property has a value
605 of 0.
606
607 By default, this property contains a value of 0.
608*/
609
610double QLCDNumber::value() const
611{
612 Q_D(const QLCDNumber);
613 return d->val;
614}
615
616/*!
617 \overload
618
619 Displays the number \a num.
620*/
621void QLCDNumber::display(double num)
622{
623 Q_D(QLCDNumber);
624 d->val = num;
625 bool of;
626 QString s = double2string(d->val, d->base, d->ndigits, &of);
627 if (of)
628 emit overflow();
629 else
630 d->internalSetString(s);
631}
632
633/*!
634 \property QLCDNumber::intValue
635 \brief the displayed value rounded to the nearest integer
636
637 This property corresponds to the nearest integer to the current
638 value displayed by the LCDNumber. This is the value used for
639 hexadecimal, octal and binary modes.
640
641 If the displayed value is not a number, the property has a value
642 of 0.
643
644 By default, this property contains a value of 0.
645*/
646int QLCDNumber::intValue() const
647{
648 Q_D(const QLCDNumber);
649 return qRound(d->val);
650}
651
652
653/*!
654 \overload
655
656 Displays the number \a num.
657*/
658void QLCDNumber::display(int num)
659{
660 Q_D(QLCDNumber);
661 d->val = (double)num;
662 bool of;
663 QString s = int2string(num, d->base, d->ndigits, &of);
664 if (of)
665 emit overflow();
666 else
667 d->internalSetString(s);
668}
669
670
671/*!
672 Displays the number represented by the string \a s.
673
674 This version of the function disregards mode() and
675 smallDecimalPoint().
676
677 These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
678 6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
679 P, r, u, U, Y, colon, degree sign (which is specified as single
680 quote in the string) and space. QLCDNumber substitutes spaces for
681 illegal characters.
682*/
683
684void QLCDNumber::display(const QString &s)
685{
686 Q_D(QLCDNumber);
687 d->val = 0;
688 bool ok = false;
689 double v = s.toDouble(&ok);
690 if (ok)
691 d->val = v;
692 d->internalSetString(s);
693}
694
695/*!
696 Calls setMode(Hex). Provided for convenience (e.g. for
697 connecting buttons to it).
698
699 \sa setMode(), setDecMode(), setOctMode(), setBinMode(), mode()
700*/
701
702void QLCDNumber::setHexMode()
703{
704 setMode(Hex);
705}
706
707
708/*!
709 Calls setMode(Dec). Provided for convenience (e.g. for
710 connecting buttons to it).
711
712 \sa setMode(), setHexMode(), setOctMode(), setBinMode(), mode()
713*/
714
715void QLCDNumber::setDecMode()
716{
717 setMode(Dec);
718}
719
720
721/*!
722 Calls setMode(Oct). Provided for convenience (e.g. for
723 connecting buttons to it).
724
725 \sa setMode(), setHexMode(), setDecMode(), setBinMode(), mode()
726*/
727
728void QLCDNumber::setOctMode()
729{
730 setMode(Oct);
731}
732
733
734/*!
735 Calls setMode(Bin). Provided for convenience (e.g. for
736 connecting buttons to it).
737
738 \sa setMode(), setHexMode(), setDecMode(), setOctMode(), mode()
739*/
740
741void QLCDNumber::setBinMode()
742{
743 setMode(Bin);
744}
745
746
747/*!
748 \property QLCDNumber::smallDecimalPoint
749 \brief the style of the decimal point
750
751 If true the decimal point is drawn between two digit positions.
752 Otherwise it occupies a digit position of its own, i.e. is drawn
753 in a digit position. The default is false.
754
755 The inter-digit space is made slightly wider when the decimal
756 point is drawn between the digits.
757
758 \sa mode
759*/
760
761void QLCDNumber::setSmallDecimalPoint(bool b)
762{
763 Q_D(QLCDNumber);
764 d->smallPoint = b;
765 update();
766}
767
768bool QLCDNumber::smallDecimalPoint() const
769{
770 Q_D(const QLCDNumber);
771 return d->smallPoint;
772}
773
774
775
776/*!\reimp
777*/
778
779
780void QLCDNumber::paintEvent(QPaintEvent *)
781{
782 Q_D(QLCDNumber);
783 QPainter p(this);
784 drawFrame(&p);
785 p.setRenderHint(QPainter::Antialiasing);
786 if (d->shadow)
787 p.translate(0.5, 0.5);
788
789 if (d->smallPoint)
790 d->drawString(d->digitStr, p, &d->points, false);
791 else
792 d->drawString(d->digitStr, p, 0, false);
793}
794
795
796void QLCDNumberPrivate::internalSetString(const QString& s)
797{
798 Q_Q(QLCDNumber);
799 QString buffer;
800 int i;
801 int len = s.length();
802 QBitArray newPoints(ndigits);
803
804 if (!smallPoint) {
805 if (len == ndigits)
806 buffer = s;
807 else
808 buffer = s.right(ndigits).rightJustified(ndigits, QLatin1Char(' '));
809 } else {
810 int index = -1;
811 bool lastWasPoint = true;
812 newPoints.clearBit(0);
813 for (i=0; i<len; i++) {
814 if (s[i] == QLatin1Char('.')) {
815 if (lastWasPoint) { // point already set for digit?
816 if (index == ndigits - 1) // no more digits
817 break;
818 index++;
819 buffer[index] = QLatin1Char(' '); // 2 points in a row, add space
820 }
821 newPoints.setBit(index); // set decimal point
822 lastWasPoint = true;
823 } else {
824 if (index == ndigits - 1)
825 break;
826 index++;
827 buffer[index] = s[i];
828 newPoints.clearBit(index); // decimal point default off
829 lastWasPoint = false;
830 }
831 }
832 if (index < ((int) ndigits) - 1) {
833 for(i=index; i>=0; i--) {
834 buffer[ndigits - 1 - index + i] = buffer[i];
835 newPoints.setBit(ndigits - 1 - index + i,
836 newPoints.testBit(i));
837 }
838 for(i=0; i<ndigits-index-1; i++) {
839 buffer[i] = QLatin1Char(' ');
840 newPoints.clearBit(i);
841 }
842 }
843 }
844
845 if (buffer == digitStr)
846 return;
847
848 digitStr = buffer;
849 if (smallPoint)
850 points = newPoints;
851 q->update();
852}
853
854/*!
855 \internal
856*/
857
858void QLCDNumberPrivate::drawString(const QString &s, QPainter &p,
859 QBitArray *newPoints, bool newString)
860{
861 Q_Q(QLCDNumber);
862 QPoint pos;
863
864 int digitSpace = smallPoint ? 2 : 1;
865 int xSegLen = q->width()*5/(ndigits*(5 + digitSpace) + digitSpace);
866 int ySegLen = q->height()*5/12;
867 int segLen = ySegLen > xSegLen ? xSegLen : ySegLen;
868 int xAdvance = segLen*(5 + digitSpace)/5;
869 int xOffset = (q->width() - ndigits*xAdvance + segLen/5)/2;
870 int yOffset = (q->height() - segLen*2)/2;
871
872 for (int i=0; i<ndigits; i++) {
873 pos = QPoint(xOffset + xAdvance*i, yOffset);
874 if (newString)
875 drawDigit(pos, p, segLen, s[i].toLatin1(), digitStr[i].toLatin1());
876 else
877 drawDigit(pos, p, segLen, s[i].toLatin1());
878 if (newPoints) {
879 char newPoint = newPoints->testBit(i) ? '.' : ' ';
880 if (newString) {
881 char oldPoint = points.testBit(i) ? '.' : ' ';
882 drawDigit(pos, p, segLen, newPoint, oldPoint);
883 } else {
884 drawDigit(pos, p, segLen, newPoint);
885 }
886 }
887 }
888 if (newString) {
889 digitStr = s;
890 digitStr.truncate(ndigits);
891 if (newPoints)
892 points = *newPoints;
893 }
894}
895
896
897/*!
898 \internal
899*/
900
901void QLCDNumberPrivate::drawDigit(const QPoint &pos, QPainter &p, int segLen,
902 char newCh, char oldCh)
903{
904// Draws and/or erases segments to change display of a single digit
905// from oldCh to newCh
906
907 char updates[18][2]; // can hold 2 times number of segments, only
908 // first 9 used if segment table is correct
909 int nErases;
910 int nUpdates;
911 const char *segs;
912 int i,j;
913
914 const char erase = 0;
915 const char draw = 1;
916 const char leaveAlone = 2;
917
918 segs = getSegments(oldCh);
919 for (nErases=0; segs[nErases] != 99; nErases++) {
920 updates[nErases][0] = erase; // get segments to erase to
921 updates[nErases][1] = segs[nErases]; // remove old char
922 }
923 nUpdates = nErases;
924 segs = getSegments(newCh);
925 for(i = 0 ; segs[i] != 99 ; i++) {
926 for (j=0; j<nErases; j++)
927 if (segs[i] == updates[j][1]) { // same segment ?
928 updates[j][0] = leaveAlone; // yes, already on screen
929 break;
930 }
931 if (j == nErases) { // if not already on screen
932 updates[nUpdates][0] = draw;
933 updates[nUpdates][1] = segs[i];
934 nUpdates++;
935 }
936 }
937 for (i=0; i<nUpdates; i++) {
938 if (updates[i][0] == draw)
939 drawSegment(pos, updates[i][1], p, segLen);
940 if (updates[i][0] == erase)
941 drawSegment(pos, updates[i][1], p, segLen, true);
942 }
943}
944
945
946static void addPoint(QPolygon &a, const QPoint &p)
947{
948 uint n = a.size();
949 a.resize(n + 1);
950 a.setPoint(n, p);
951}
952
953/*!
954 \internal
955*/
956
957void QLCDNumberPrivate::drawSegment(const QPoint &pos, char segmentNo, QPainter &p,
958 int segLen, bool erase)
959{
960 Q_Q(QLCDNumber);
961 QPoint ppt;
962 QPoint pt = pos;
963 int width = segLen/5;
964
965 const QPalette &pal = q->palette();
966 QColor lightColor,darkColor,fgColor;
967 if (erase){
968 lightColor = pal.color(q->backgroundRole());
969 darkColor = lightColor;
970 fgColor = lightColor;
971 } else {
972 lightColor = pal.light().color();
973 darkColor = pal.dark().color();
974 fgColor = pal.color(q->foregroundRole());
975 }
976
977
978#define LINETO(X,Y) addPoint(a, QPoint(pt.x() + (X),pt.y() + (Y)))
979#define LIGHT
980#define DARK
981
982 if (fill) {
983 QPolygon a(0);
984 //The following is an exact copy of the switch below.
985 //don't make any changes here
986 switch (segmentNo) {
987 case 0 :
988 ppt = pt;
989 LIGHT;
990 LINETO(segLen - 1,0);
991 DARK;
992 LINETO(segLen - width - 1,width);
993 LINETO(width,width);
994 LINETO(0,0);
995 break;
996 case 1 :
997 pt += QPoint(0 , 1);
998 ppt = pt;
999 LIGHT;
1000 LINETO(width,width);
1001 DARK;
1002 LINETO(width,segLen - width/2 - 2);
1003 LINETO(0,segLen - 2);
1004 LIGHT;
1005 LINETO(0,0);
1006 break;
1007 case 2 :
1008 pt += QPoint(segLen - 1 , 1);
1009 ppt = pt;
1010 DARK;
1011 LINETO(0,segLen - 2);
1012 LINETO(-width,segLen - width/2 - 2);
1013 LIGHT;
1014 LINETO(-width,width);
1015 LINETO(0,0);
1016 break;
1017 case 3 :
1018 pt += QPoint(0 , segLen);
1019 ppt = pt;
1020 LIGHT;
1021 LINETO(width,-width/2);
1022 LINETO(segLen - width - 1,-width/2);
1023 LINETO(segLen - 1,0);
1024 DARK;
1025 if (width & 1) { // adjust for integer division error
1026 LINETO(segLen - width - 3,width/2 + 1);
1027 LINETO(width + 2,width/2 + 1);
1028 } else {
1029 LINETO(segLen - width - 1,width/2);
1030 LINETO(width,width/2);
1031 }
1032 LINETO(0,0);
1033 break;
1034 case 4 :
1035 pt += QPoint(0 , segLen + 1);
1036 ppt = pt;
1037 LIGHT;
1038 LINETO(width,width/2);
1039 DARK;
1040 LINETO(width,segLen - width - 2);
1041 LINETO(0,segLen - 2);
1042 LIGHT;
1043 LINETO(0,0);
1044 break;
1045 case 5 :
1046 pt += QPoint(segLen - 1 , segLen + 1);
1047 ppt = pt;
1048 DARK;
1049 LINETO(0,segLen - 2);
1050 LINETO(-width,segLen - width - 2);
1051 LIGHT;
1052 LINETO(-width,width/2);
1053 LINETO(0,0);
1054 break;
1055 case 6 :
1056 pt += QPoint(0 , segLen*2);
1057 ppt = pt;
1058 LIGHT;
1059 LINETO(width,-width);
1060 LINETO(segLen - width - 1,-width);
1061 LINETO(segLen - 1,0);
1062 DARK;
1063 LINETO(0,0);
1064 break;
1065 case 7 :
1066 if (smallPoint) // if smallpoint place'.' between other digits
1067 pt += QPoint(segLen + width/2 , segLen*2);
1068 else
1069 pt += QPoint(segLen/2 , segLen*2);
1070 ppt = pt;
1071 DARK;
1072 LINETO(width,0);
1073 LINETO(width,-width);
1074 LIGHT;
1075 LINETO(0,-width);
1076 LINETO(0,0);
1077 break;
1078 case 8 :
1079 pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
1080 ppt = pt;
1081 DARK;
1082 LINETO(width,0);
1083 LINETO(width,-width);
1084 LIGHT;
1085 LINETO(0,-width);
1086 LINETO(0,0);
1087 break;
1088 case 9 :
1089 pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
1090 ppt = pt;
1091 DARK;
1092 LINETO(width,0);
1093 LINETO(width,-width);
1094 LIGHT;
1095 LINETO(0,-width);
1096 LINETO(0,0);
1097 break;
1098 default :
1099 qWarning("QLCDNumber::drawSegment: (%s) Illegal segment id: %d\n",
1100 q->objectName().toLocal8Bit().constData(), segmentNo);
1101 }
1102 // End exact copy
1103 p.setPen(Qt::NoPen);
1104 p.setBrush(fgColor);
1105 p.drawPolygon(a);
1106 p.setBrush(Qt::NoBrush);
1107
1108 pt = pos;
1109 }
1110#undef LINETO
1111#undef LIGHT
1112#undef DARK
1113
1114#define LINETO(X,Y) p.drawLine(ppt.x(), ppt.y(), pt.x()+(X), pt.y()+(Y)); \
1115 ppt = QPoint(pt.x()+(X), pt.y()+(Y))
1116#define LIGHT p.setPen(lightColor)
1117#define DARK p.setPen(darkColor)
1118 if (shadow)
1119 switch (segmentNo) {
1120 case 0 :
1121 ppt = pt;
1122 LIGHT;
1123 LINETO(segLen - 1,0);
1124 DARK;
1125 LINETO(segLen - width - 1,width);
1126 LINETO(width,width);
1127 LINETO(0,0);
1128 break;
1129 case 1 :
1130 pt += QPoint(0,1);
1131 ppt = pt;
1132 LIGHT;
1133 LINETO(width,width);
1134 DARK;
1135 LINETO(width,segLen - width/2 - 2);
1136 LINETO(0,segLen - 2);
1137 LIGHT;
1138 LINETO(0,0);
1139 break;
1140 case 2 :
1141 pt += QPoint(segLen - 1 , 1);
1142 ppt = pt;
1143 DARK;
1144 LINETO(0,segLen - 2);
1145 LINETO(-width,segLen - width/2 - 2);
1146 LIGHT;
1147 LINETO(-width,width);
1148 LINETO(0,0);
1149 break;
1150 case 3 :
1151 pt += QPoint(0 , segLen);
1152 ppt = pt;
1153 LIGHT;
1154 LINETO(width,-width/2);
1155 LINETO(segLen - width - 1,-width/2);
1156 LINETO(segLen - 1,0);
1157 DARK;
1158 if (width & 1) { // adjust for integer division error
1159 LINETO(segLen - width - 3,width/2 + 1);
1160 LINETO(width + 2,width/2 + 1);
1161 } else {
1162 LINETO(segLen - width - 1,width/2);
1163 LINETO(width,width/2);
1164 }
1165 LINETO(0,0);
1166 break;
1167 case 4 :
1168 pt += QPoint(0 , segLen + 1);
1169 ppt = pt;
1170 LIGHT;
1171 LINETO(width,width/2);
1172 DARK;
1173 LINETO(width,segLen - width - 2);
1174 LINETO(0,segLen - 2);
1175 LIGHT;
1176 LINETO(0,0);
1177 break;
1178 case 5 :
1179 pt += QPoint(segLen - 1 , segLen + 1);
1180 ppt = pt;
1181 DARK;
1182 LINETO(0,segLen - 2);
1183 LINETO(-width,segLen - width - 2);
1184 LIGHT;
1185 LINETO(-width,width/2);
1186 LINETO(0,0);
1187 break;
1188 case 6 :
1189 pt += QPoint(0 , segLen*2);
1190 ppt = pt;
1191 LIGHT;
1192 LINETO(width,-width);
1193 LINETO(segLen - width - 1,-width);
1194 LINETO(segLen - 1,0);
1195 DARK;
1196 LINETO(0,0);
1197 break;
1198 case 7 :
1199 if (smallPoint) // if smallpoint place'.' between other digits
1200 pt += QPoint(segLen + width/2 , segLen*2);
1201 else
1202 pt += QPoint(segLen/2 , segLen*2);
1203 ppt = pt;
1204 DARK;
1205 LINETO(width,0);
1206 LINETO(width,-width);
1207 LIGHT;
1208 LINETO(0,-width);
1209 LINETO(0,0);
1210 break;
1211 case 8 :
1212 pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
1213 ppt = pt;
1214 DARK;
1215 LINETO(width,0);
1216 LINETO(width,-width);
1217 LIGHT;
1218 LINETO(0,-width);
1219 LINETO(0,0);
1220 break;
1221 case 9 :
1222 pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
1223 ppt = pt;
1224 DARK;
1225 LINETO(width,0);
1226 LINETO(width,-width);
1227 LIGHT;
1228 LINETO(0,-width);
1229 LINETO(0,0);
1230 break;
1231 default :
1232 qWarning("QLCDNumber::drawSegment: (%s) Illegal segment id: %d\n",
1233 q->objectName().toLocal8Bit().constData(), segmentNo);
1234 }
1235
1236#undef LINETO
1237#undef LIGHT
1238#undef DARK
1239}
1240
1241
1242
1243/*!
1244 \property QLCDNumber::segmentStyle
1245 \brief the style of the LCDNumber
1246
1247 \table
1248 \header \i Style \i Result
1249 \row \i \c Outline
1250 \i Produces raised segments filled with the background color
1251 \row \i \c Filled
1252 (this is the default).
1253 \i Produces raised segments filled with the foreground color.
1254 \row \i \c Flat
1255 \i Produces flat segments filled with the foreground color.
1256 \endtable
1257
1258 \c Outline and \c Filled will additionally use
1259 QPalette::light() and QPalette::dark() for shadow effects.
1260*/
1261void QLCDNumber::setSegmentStyle(SegmentStyle s)
1262{
1263 Q_D(QLCDNumber);
1264 d->fill = (s == Flat || s == Filled);
1265 d->shadow = (s == Outline || s == Filled);
1266 update();
1267}
1268
1269QLCDNumber::SegmentStyle QLCDNumber::segmentStyle() const
1270{
1271 Q_D(const QLCDNumber);
1272 Q_ASSERT(d->fill || d->shadow);
1273 if (!d->fill && d->shadow)
1274 return Outline;
1275 if (d->fill && d->shadow)
1276 return Filled;
1277 return Flat;
1278}
1279
1280
1281/*!\reimp
1282*/
1283QSize QLCDNumber::sizeHint() const
1284{
1285 return QSize(10 + 9 * (digitCount() + (smallDecimalPoint() ? 0 : 1)), 23);
1286}
1287
1288/*! \reimp */
1289bool QLCDNumber::event(QEvent *e)
1290{
1291 return QFrame::event(e);
1292}
1293
1294/*!
1295 \fn void QLCDNumber::setMargin(int margin)
1296 Sets the width of the margin around the contents of the widget to \a margin.
1297
1298 Use QWidget::setContentsMargins() instead.
1299 \sa margin(), QWidget::setContentsMargins()
1300*/
1301
1302/*!
1303 \fn int QLCDNumber::margin() const
1304 Returns the width of the margin around the contents of the widget.
1305
1306 Use QWidget::getContentsMargins() instead.
1307 \sa setMargin(), QWidget::getContentsMargins()
1308*/
1309
1310QT_END_NAMESPACE
1311
1312#endif // QT_NO_LCDNUMBER
Note: See TracBrowser for help on using the repository browser.