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

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