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