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