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

source code of qtbase/src/widgets/widgets/qlcdnumber.cpp