source: vendor/trolltech/current/src/widgets/qlcdnumber.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 32.5 KB
Line 
1/****************************************************************************
2** $Id: qlcdnumber.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QLCDNumber class
5**
6** Created : 940518
7**
8** Copyright (C) 1992-2004 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qlcdnumber.h"
39#ifndef QT_NO_LCDNUMBER
40#include "qbitarray.h"
41#include "qpainter.h"
42
43
44/*!
45 \class QLCDNumber qlcdnumber.h
46
47 \brief The QLCDNumber widget displays a number with LCD-like digits.
48
49 \ingroup basic
50 \mainclass
51
52 It can display a number in just about any size. It can display
53 decimal, hexadecimal, octal or binary numbers. It is easy to
54 connect to data sources using the display() slot, which is
55 overloaded to take any of five argument types.
56
57 There are also slots to change the base with setMode() and the
58 decimal point with setSmallDecimalPoint().
59
60 QLCDNumber emits the overflow() signal when it is asked to display
61 something beyond its range. The range is set by setNumDigits(),
62 but setSmallDecimalPoint() also influences it. If the display is
63 set to hexadecimal, octal or binary, the integer equivalent of the
64 value is displayed.
65
66 These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
67 6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
68 P, r, u, U, Y, colon, degree sign (which is specified as single
69 quote in the string) and space. QLCDNumber substitutes spaces for
70 illegal characters.
71
72 It is not possible to retrieve the contents of a QLCDNumber
73 object, although you can retrieve the numeric value with value().
74 If you really need the text, we recommend that you connect the
75 signals that feed the display() slot to another slot as well and
76 store the value there.
77
78 Incidentally, QLCDNumber is the very oldest part of Qt, tracing
79 back to a BASIC program on the \link
80 http://www.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm
81 Sinclair Spectrum\endlink.
82
83 <img src=qlcdnum-m.png> <img src=qlcdnum-w.png>
84
85 \sa QLabel, QFrame
86*/
87
88/*!
89 \enum QLCDNumber::Mode
90
91 This type determines how numbers are shown.
92
93 \value Hex Hexadecimal
94 \value Dec Decimal
95 \value Oct Octal
96 \value Bin Binary
97
98 If the display is set to hexadecimal, octal or binary, the integer
99 equivalent of the value is displayed.
100*/
101
102/*!
103 \enum QLCDNumber::SegmentStyle
104
105 This type determines the visual appearance of the QLCDNumber
106 widget.
107
108 \value Outline gives raised segments filled with the background brush.
109 \value Filled gives raised segments filled with the foreground brush.
110 \value Flat gives flat segments filled with the foreground brush.
111*/
112
113
114
115/*!
116 \fn void QLCDNumber::overflow()
117
118 This signal is emitted whenever the QLCDNumber is asked to display
119 a too-large number or a too-long string.
120
121 It is never emitted by setNumDigits().
122*/
123
124
125static QString int2string( int num, int base, int ndigits, bool *oflow )
126{
127 QString s;
128 bool negative;
129 if ( num < 0 ) {
130 negative = TRUE;
131 num = -num;
132 } else {
133 negative = FALSE;
134 }
135 switch( base ) {
136 case QLCDNumber::HEX:
137 s.sprintf( "%*x", ndigits, num );
138 break;
139 case QLCDNumber::DEC:
140 s.sprintf( "%*i", ndigits, num );
141 break;
142 case QLCDNumber::OCT:
143 s.sprintf( "%*o", ndigits, num );
144 break;
145 case QLCDNumber::BIN:
146 {
147 char buf[42];
148 char *p = &buf[41];
149 uint n = num;
150 int len = 0;
151 *p = '\0';
152 do {
153 *--p = (char)((n&1)+'0');
154 n >>= 1;
155 len++;
156 } while ( n != 0 );
157 len = ndigits - len;
158 if ( len > 0 )
159 s.fill( ' ', len );
160 s += QString::fromLatin1(p);
161 }
162 break;
163 }
164 if ( negative ) {
165 for ( int i=0; i<(int)s.length(); i++ ) {
166 if ( s[i] != ' ' ) {
167 if ( i != 0 ) {
168 s[i-1] = '-';
169 } else {
170 s.insert( 0, '-' );
171 }
172 break;
173 }
174 }
175 }
176 if ( oflow )
177 *oflow = (int)s.length() > ndigits;
178 return s;
179}
180
181
182static QString double2string( double num, int base, int ndigits, bool *oflow )
183{
184 QString s;
185 if ( base != QLCDNumber::DEC ) {
186 bool of = num >= 2147483648.0 || num < -2147483648.0;
187 if ( of ) { // oops, integer overflow
188 if ( oflow )
189 *oflow = TRUE;
190 return s;
191 }
192 s = int2string( (int)num, base, ndigits, 0 );
193 } else { // decimal base
194 int nd = ndigits;
195 do {
196 s.sprintf( "%*.*g", ndigits, nd, num );
197 int i = s.find('e');
198 if ( i > 0 && s[i+1]=='+' ) {
199 s[i] = ' ';
200 s[i+1] = 'e';
201 }
202 } while (nd-- && (int)s.length() > ndigits);
203 }
204 if ( oflow )
205 *oflow = (int)s.length() > ndigits;
206 return s;
207}
208
209
210static const char *getSegments( char ch ) // gets list of segments for ch
211{
212 static const char segments[30][8] =
213 { { 0, 1, 2, 4, 5, 6,99, 0}, // 0 0 / O
214 { 2, 5,99, 0, 0, 0, 0, 0}, // 1 1
215 { 0, 2, 3, 4, 6,99, 0, 0}, // 2 2
216 { 0, 2, 3, 5, 6,99, 0, 0}, // 3 3
217 { 1, 2, 3, 5,99, 0, 0, 0}, // 4 4
218 { 0, 1, 3, 5, 6,99, 0, 0}, // 5 5 / S
219 { 0, 1, 3, 4, 5, 6,99, 0}, // 6 6
220 { 0, 2, 5,99, 0, 0, 0, 0}, // 7 7
221 { 0, 1, 2, 3, 4, 5, 6,99}, // 8 8
222 { 0, 1, 2, 3, 5, 6,99, 0}, // 9 9 / g
223 { 3,99, 0, 0, 0, 0, 0, 0}, // 10 -
224 { 7,99, 0, 0, 0, 0, 0, 0}, // 11 .
225 { 0, 1, 2, 3, 4, 5,99, 0}, // 12 A
226 { 1, 3, 4, 5, 6,99, 0, 0}, // 13 B
227 { 0, 1, 4, 6,99, 0, 0, 0}, // 14 C
228 { 2, 3, 4, 5, 6,99, 0, 0}, // 15 D
229 { 0, 1, 3, 4, 6,99, 0, 0}, // 16 E
230 { 0, 1, 3, 4,99, 0, 0, 0}, // 17 F
231 { 1, 3, 4, 5,99, 0, 0, 0}, // 18 h
232 { 1, 2, 3, 4, 5,99, 0, 0}, // 19 H
233 { 1, 4, 6,99, 0, 0, 0, 0}, // 20 L
234 { 3, 4, 5, 6,99, 0, 0, 0}, // 21 o
235 { 0, 1, 2, 3, 4,99, 0, 0}, // 22 P
236 { 3, 4,99, 0, 0, 0, 0, 0}, // 23 r
237 { 4, 5, 6,99, 0, 0, 0, 0}, // 24 u
238 { 1, 2, 4, 5, 6,99, 0, 0}, // 25 U
239 { 1, 2, 3, 5, 6,99, 0, 0}, // 26 Y
240 { 8, 9,99, 0, 0, 0, 0, 0}, // 27 :
241 { 0, 1, 2, 3,99, 0, 0, 0}, // 28 '
242 {99, 0, 0, 0, 0, 0, 0, 0} }; // 29 empty
243
244 if (ch >= '0' && ch <= '9')
245 return segments[ch - '0'];
246 if (ch >= 'A' && ch <= 'F')
247 return segments[ch - 'A' + 12];
248 if (ch >= 'a' && ch <= 'f')
249 return segments[ch - 'a' + 12];
250
251 int n;
252 switch ( ch ) {
253 case '-':
254 n = 10; break;
255 case 'O':
256 n = 0; break;
257 case 'g':
258 n = 9; break;
259 case '.':
260 n = 11; break;
261 case 'h':
262 n = 18; break;
263 case 'H':
264 n = 19; break;
265 case 'l':
266 case 'L':
267 n = 20; break;
268 case 'o':
269 n = 21; break;
270 case 'p':
271 case 'P':
272 n = 22; break;
273 case 'r':
274 case 'R':
275 n = 23; break;
276 case 's':
277 case 'S':
278 n = 5; break;
279 case 'u':
280 n = 24; break;
281 case 'U':
282 n = 25; break;
283 case 'y':
284 case 'Y':
285 n = 26; break;
286 case ':':
287 n = 27; break;
288 case '\'':
289 n = 28; break;
290 default:
291 n = 29; break;
292 }
293 return segments[n];
294}
295
296
297/*!
298 Constructs an LCD number, sets the number of digits to 5, the base
299 to decimal, the decimal point mode to 'small' and the frame style
300 to a raised box. The segmentStyle() is set to \c Outline.
301
302 The \a parent and \a name arguments are passed to the QFrame
303 constructor.
304
305 \sa setNumDigits(), setSmallDecimalPoint()
306*/
307
308QLCDNumber::QLCDNumber( QWidget *parent, const char *name )
309 : QFrame( parent, name )
310{
311 ndigits = 5;
312 init();
313}
314
315
316/*!
317 Constructs an LCD number, sets the number of digits to \a
318 numDigits, the base to decimal, the decimal point mode to 'small'
319 and the frame style to a raised box. The segmentStyle() is set to
320 \c Outline.
321
322 The \a parent and \a name arguments are passed to the QFrame
323 constructor.
324
325 \sa setNumDigits(), setSmallDecimalPoint()
326*/
327
328QLCDNumber::QLCDNumber( uint numDigits, QWidget *parent, const char *name )
329 : QFrame( parent, name )
330{
331 ndigits = numDigits;
332 init();
333}
334
335/*!
336 \internal
337*/
338
339void QLCDNumber::init()
340{
341 setFrameStyle( QFrame::Box | QFrame::Raised );
342 val = 0;
343 base = DEC;
344 smallPoint = FALSE;
345 setNumDigits( ndigits );
346 setSegmentStyle( Outline );
347 d = 0;
348 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
349}
350
351/*!
352 Destroys the LCD number.
353*/
354
355QLCDNumber::~QLCDNumber()
356{
357}
358
359
360/*!
361 \property QLCDNumber::numDigits
362 \brief the current number of digits displayed
363
364 Corresponds to the current number of digits. If \l
365 QLCDNumber::smallDecimalPoint is FALSE, the decimal point occupies
366 one digit position.
367
368 \sa numDigits, smallDecimalPoint
369*/
370
371void QLCDNumber::setNumDigits( int numDigits )
372{
373 if ( numDigits > 99 ) {
374#if defined(QT_CHECK_RANGE)
375 qWarning( "QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
376 name( "unnamed" ) );
377#endif
378 numDigits = 99;
379 }
380 if (numDigits < 0 ) {
381#if defined(QT_CHECK_RANGE)
382 qWarning( "QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
383 name( "unnamed" ) );
384#endif
385 numDigits = 0;
386 }
387 if ( digitStr.isNull() ) { // from constructor
388 ndigits = numDigits;
389 digitStr.fill( ' ', ndigits );
390 points.fill( 0, ndigits );
391 digitStr[ndigits - 1] = '0'; // "0" is the default number
392 } else {
393 bool doDisplay = ndigits == 0;
394 if ( numDigits == ndigits ) // no change
395 return;
396 register int i;
397 int dif;
398 if ( numDigits > ndigits ) { // expand
399 dif = numDigits - ndigits;
400 QString buf;
401 buf.fill( ' ', dif );
402 digitStr.insert( 0, buf );
403 points.resize( numDigits );
404 for ( i=numDigits-1; i>=dif; i-- )
405 points.setBit( i, points.testBit(i-dif) );
406 for ( i=0; i<dif; i++ )
407 points.clearBit( i );
408 } else { // shrink
409 dif = ndigits - numDigits;
410 digitStr = digitStr.right( numDigits );
411 QBitArray tmpPoints = points.copy();
412 points.resize( numDigits );
413 for ( i=0; i<(int)numDigits; i++ )
414 points.setBit( i, tmpPoints.testBit(i+dif) );
415 }
416 ndigits = numDigits;
417 if ( doDisplay )
418 display( value() );
419 update();
420 }
421}
422
423
424/*!
425 \overload
426
427 Returns TRUE if \a num is too big to be displayed in its entirety;
428 otherwise returns FALSE.
429
430 \sa display(), numDigits(), smallDecimalPoint()
431*/
432
433bool QLCDNumber::checkOverflow( int num ) const
434{
435 bool of;
436 int2string( num, base, ndigits, &of );
437 return of;
438}
439
440
441/*!
442 Returns TRUE if \a num is too big to be displayed in its entirety;
443 otherwise returns FALSE.
444
445 \sa display(), numDigits(), smallDecimalPoint()
446*/
447
448bool QLCDNumber::checkOverflow( double num ) const
449{
450 bool of;
451 double2string( num, base, ndigits, &of );
452 return of;
453}
454
455
456/*!
457 \property QLCDNumber::mode
458 \brief the current display mode (number base)
459
460 Corresponds to the current display mode, which is one of \c BIN,
461 \c OCT, \c DEC (the default) and \c HEX. \c DEC mode can display
462 floating point values, the other modes display the integer
463 equivalent.
464
465 \sa smallDecimalPoint(), setHexMode(), setDecMode(), setOctMode(), setBinMode()
466*/
467
468QLCDNumber::Mode QLCDNumber::mode() const
469{
470 return (QLCDNumber::Mode) base;
471}
472
473void QLCDNumber::setMode( Mode m )
474{
475 base = m;
476
477 display( val );
478}
479
480
481/*!
482 \property QLCDNumber::value
483 \brief the displayed value
484
485 This property corresponds to the current value displayed by the
486 LCDNumber.
487
488 If the displayed value is not a number, the property has a value
489 of 0.
490*/
491
492double QLCDNumber::value() const
493{
494 return val;
495}
496
497/*!
498 \overload
499
500 Displays the number \a num.
501*/
502void QLCDNumber::display( double num )
503{
504 val = num;
505 bool of;
506 QString s = double2string( num, base, ndigits, &of );
507 if ( of )
508 emit overflow();
509 else
510 internalSetString( s );
511}
512
513/*!
514 \property QLCDNumber::intValue
515 \brief the displayed value rounded to the nearest integer
516
517 This property corresponds to the nearest integer to the current
518 value displayed by the LCDNumber. This is the value used for
519 hexadecimal, octal and binary modes.
520
521 If the displayed value is not a number, the property has a value
522 of 0.
523*/
524int QLCDNumber::intValue() const
525{
526 return (int)(val < 0 ? val - 0.5 : val + 0.5);
527}
528
529
530/*!
531 \overload
532
533 Displays the number \a num.
534*/
535void QLCDNumber::display( int num )
536{
537 val = (double)num;
538 bool of;
539 QString s = int2string( num, base, ndigits, &of );
540 if ( of )
541 emit overflow();
542 else
543 internalSetString( s );
544}
545
546
547/*!
548 Displays the number represented by the string \a s.
549
550 This version of the function disregards mode() and
551 smallDecimalPoint().
552
553 These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
554 6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
555 P, r, u, U, Y, colon, degree sign (which is specified as single
556 quote in the string) and space. QLCDNumber substitutes spaces for
557 illegal characters.
558*/
559
560void QLCDNumber::display( const QString &s )
561{
562 val = 0;
563 bool ok = FALSE;
564 double v = s.toDouble( &ok );
565 if ( ok )
566 val = v;
567 internalSetString( s );
568}
569
570/*!
571 Calls setMode( HEX ). Provided for convenience (e.g. for
572 connecting buttons to it).
573
574 \sa setMode(), setDecMode(), setOctMode(), setBinMode(), mode()
575*/
576
577void QLCDNumber::setHexMode()
578{
579 setMode( HEX );
580}
581
582
583/*!
584 Calls setMode( DEC ). Provided for convenience (e.g. for
585 connecting buttons to it).
586
587 \sa setMode(), setHexMode(), setOctMode(), setBinMode(), mode()
588*/
589
590void QLCDNumber::setDecMode()
591{
592 setMode( DEC );
593}
594
595
596/*!
597 Calls setMode( OCT ). Provided for convenience (e.g. for
598 connecting buttons to it).
599
600 \sa setMode(), setHexMode(), setDecMode(), setBinMode(), mode()
601*/
602
603void QLCDNumber::setOctMode()
604{
605 setMode( OCT );
606}
607
608
609/*!
610 Calls setMode( BIN ). Provided for convenience (e.g. for
611 connecting buttons to it).
612
613 \sa setMode(), setHexMode(), setDecMode(), setOctMode(), mode()
614*/
615
616void QLCDNumber::setBinMode()
617{
618 setMode( BIN );
619}
620
621
622/*!
623 \property QLCDNumber::smallDecimalPoint
624 \brief the style of the decimal point
625
626 If TRUE the decimal point is drawn between two digit positions.
627 Otherwise it occupies a digit position of its own, i.e. is drawn
628 in a digit position. The default is FALSE.
629
630 The inter-digit space is made slightly wider when the decimal
631 point is drawn between the digits.
632
633 \sa mode
634*/
635
636void QLCDNumber::setSmallDecimalPoint( bool b )
637{
638 smallPoint = b;
639}
640
641
642/*!
643 Draws the LCD number using painter \a p. This function is called
644 from QFrame::paintEvent().
645*/
646
647
648void QLCDNumber::drawContents( QPainter *p )
649{
650 if ( smallPoint )
651 drawString( digitStr, *p, &points, FALSE );
652 else
653 drawString( digitStr, *p, 0, FALSE );
654}
655
656
657/*!
658 \internal
659*/
660
661void QLCDNumber::internalDisplay( const QString & )
662{
663 // Not used anymore
664}
665
666void QLCDNumber::internalSetString( const QString& s )
667{
668 QString buffer;
669 int i;
670 int len = s.length();
671 QBitArray newPoints(ndigits);
672
673 if ( !smallPoint ) {
674 if ( len == ndigits )
675 buffer = s;
676 else
677 buffer = s.right( ndigits ).rightJustify( ndigits, ' ' );
678 } else {
679 int index = -1;
680 bool lastWasPoint = TRUE;
681 newPoints.clearBit(0);
682 for ( i=0; i<len; i++ ) {
683 if ( s[i] == '.' ) {
684 if ( lastWasPoint ) { // point already set for digit?
685 if ( index == ndigits - 1 ) // no more digits
686 break;
687 index++;
688 buffer[index] = ' '; // 2 points in a row, add space
689 }
690 newPoints.setBit(index); // set decimal point
691 lastWasPoint = TRUE;
692 } else {
693 if ( index == ndigits - 1 )
694 break;
695 index++;
696 buffer[index] = s[i];
697 newPoints.clearBit(index); // decimal point default off
698 lastWasPoint = FALSE;
699 }
700 }
701 if ( index < ((int) ndigits) - 1 ) {
702 for( i=index; i>=0; i-- ) {
703 buffer[ndigits - 1 - index + i] = buffer[i];
704 newPoints.setBit( ndigits - 1 - index + i,
705 newPoints.testBit(i) );
706 }
707 for( i=0; i<ndigits-index-1; i++ ) {
708 buffer[i] = ' ';
709 newPoints.clearBit(i);
710 }
711 }
712 }
713
714 if ( buffer == digitStr )
715 return;
716
717 if ( backgroundMode() == FixedPixmap
718 || colorGroup().brush( QColorGroup::Background ).pixmap() ) {
719 digitStr = buffer;
720 if ( smallPoint )
721 points = newPoints;
722 repaint( contentsRect() );
723 } else {
724 QPainter p( this );
725 if ( !smallPoint )
726 drawString( buffer, p );
727 else
728 drawString( buffer, p, &newPoints );
729 }
730}
731
732/*!
733 \internal
734*/
735
736void QLCDNumber::drawString( const QString &s, QPainter &p,
737 QBitArray *newPoints, bool newString )
738{
739 QPoint pos;
740
741 int digitSpace = smallPoint ? 2 : 1;
742 int xSegLen = width()*5/(ndigits*(5 + digitSpace) + digitSpace);
743 int ySegLen = height()*5/12;
744 int segLen = ySegLen > xSegLen ? xSegLen : ySegLen;
745 int xAdvance = segLen*( 5 + digitSpace )/5;
746 int xOffset = ( width() - ndigits*xAdvance + segLen/5 )/2;
747 int yOffset = ( height() - segLen*2 )/2;
748
749 for ( int i=0; i<ndigits; i++ ) {
750 pos = QPoint( xOffset + xAdvance*i, yOffset );
751 if ( newString )
752 drawDigit( pos, p, segLen, s[i], digitStr[i].latin1() );
753 else
754 drawDigit( pos, p, segLen, s[i]);
755 if ( newPoints ) {
756 char newPoint = newPoints->testBit(i) ? '.' : ' ';
757 if ( newString ) {
758 char oldPoint = points.testBit(i) ? '.' : ' ';
759 drawDigit( pos, p, segLen, newPoint, oldPoint );
760 } else {
761 drawDigit( pos, p, segLen, newPoint );
762 }
763 }
764 }
765 if ( newString ) {
766 digitStr = s;
767 if ( (int)digitStr.length() > ndigits )
768 digitStr.truncate( ndigits );
769 if ( newPoints )
770 points = *newPoints;
771 }
772}
773
774
775/*!
776 \internal
777*/
778
779void QLCDNumber::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( QPointArray &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 QLCDNumber::drawSegment( const QPoint &pos, char segmentNo, QPainter &p,
836 int segLen, bool erase )
837{
838 QPoint pt = pos;
839 int width = segLen/5;
840
841 const QColorGroup & g = colorGroup();
842 QColor lightColor,darkColor,fgColor;
843 if ( erase ){
844 lightColor = backgroundColor();
845 darkColor = lightColor;
846 fgColor = lightColor;
847 } else {
848 lightColor = g.light();
849 darkColor = g.dark();
850 fgColor = g.foreground();
851 }
852
853#define LINETO(X,Y) addPoint( a, QPoint(pt.x() + (X),pt.y() + (Y)))
854#define LIGHT
855#define DARK
856
857 if ( fill ) {
858 QPointArray a(0);
859
860 //The following is an exact copy of the switch below.
861 //don't make any changes here
862 switch ( segmentNo ) {
863 case 0 :
864 p.moveTo(pt);
865 LIGHT;
866 LINETO(segLen - 1,0);
867 DARK;
868 LINETO(segLen - width - 1,width);
869 LINETO(width,width);
870 LINETO(0,0);
871 break;
872 case 1 :
873 pt += QPoint(0 , 1);
874 p.moveTo(pt);
875 LIGHT;
876 LINETO(width,width);
877 DARK;
878 LINETO(width,segLen - width/2 - 2);
879 LINETO(0,segLen - 2);
880 LIGHT;
881 LINETO(0,0);
882 break;
883 case 2 :
884 pt += QPoint(segLen - 1 , 1);
885 p.moveTo(pt);
886 DARK;
887 LINETO(0,segLen - 2);
888 LINETO(-width,segLen - width/2 - 2);
889 LIGHT;
890 LINETO(-width,width);
891 LINETO(0,0);
892 break;
893 case 3 :
894 pt += QPoint(0 , segLen);
895 p.moveTo(pt);
896 LIGHT;
897 LINETO(width,-width/2);
898 LINETO(segLen - width - 1,-width/2);
899 LINETO(segLen - 1,0);
900 DARK;
901 if (width & 1) { // adjust for integer division error
902 LINETO(segLen - width - 3,width/2 + 1);
903 LINETO(width + 2,width/2 + 1);
904 } else {
905 LINETO(segLen - width - 1,width/2);
906 LINETO(width,width/2);
907 }
908 LINETO(0,0);
909 break;
910 case 4 :
911 pt += QPoint(0 , segLen + 1);
912 p.moveTo(pt);
913 LIGHT;
914 LINETO(width,width/2);
915 DARK;
916 LINETO(width,segLen - width - 2);
917 LINETO(0,segLen - 2);
918 LIGHT;
919 LINETO(0,0);
920 break;
921 case 5 :
922 pt += QPoint(segLen - 1 , segLen + 1);
923 p.moveTo(pt);
924 DARK;
925 LINETO(0,segLen - 2);
926 LINETO(-width,segLen - width - 2);
927 LIGHT;
928 LINETO(-width,width/2);
929 LINETO(0,0);
930 break;
931 case 6 :
932 pt += QPoint(0 , segLen*2);
933 p.moveTo(pt);
934 LIGHT;
935 LINETO(width,-width);
936 LINETO(segLen - width - 1,-width);
937 LINETO(segLen - 1,0);
938 DARK;
939 LINETO(0,0);
940 break;
941 case 7 :
942 if ( smallPoint ) // if smallpoint place'.' between other digits
943 pt += QPoint(segLen + width/2 , segLen*2);
944 else
945 pt += QPoint(segLen/2 , segLen*2);
946 p.moveTo(pt);
947 DARK;
948 LINETO(width,0);
949 LINETO(width,-width);
950 LIGHT;
951 LINETO(0,-width);
952 LINETO(0,0);
953 break;
954 case 8 :
955 pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
956 p.moveTo(pt);
957 DARK;
958 LINETO(width,0);
959 LINETO(width,-width);
960 LIGHT;
961 LINETO(0,-width);
962 LINETO(0,0);
963 break;
964 case 9 :
965 pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
966 p.moveTo(pt);
967 DARK;
968 LINETO(width,0);
969 LINETO(width,-width);
970 LIGHT;
971 LINETO(0,-width);
972 LINETO(0,0);
973 break;
974#if defined(QT_CHECK_RANGE)
975 default :
976 qWarning( "QLCDNumber::drawSegment: (%s) Internal error."
977 " Illegal segment id: %d\n",
978 name( "unnamed" ), segmentNo );
979#endif
980 }
981 // End exact copy
982 p.setPen( fgColor );
983 p.setBrush( fgColor );
984 p.drawPolygon( a );
985 p.setBrush( NoBrush );
986
987 pt = pos;
988 }
989#undef LINETO
990#undef LIGHT
991#undef DARK
992
993#define LINETO(X,Y) p.lineTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(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 p.moveTo(pt);
1102 DARK;
1103 LINETO(width,0);
1104 LINETO(width,-width);
1105 LIGHT;
1106 LINETO(0,-width);
1107 LINETO(0,0);
1108 break;
1109#if defined(QT_CHECK_RANGE)
1110 default :
1111 qWarning( "QLCDNumber::drawSegment: (%s) Internal error."
1112 " Illegal segment id: %d\n",
1113 name( "unnamed" ), segmentNo );
1114#endif
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 \i Style \i Result
1130 \row \i \c Outline
1131 \i Produces raised segments filled with the background color
1132 (this is the default).
1133 \row \i \c Filled
1134 \i Produces raised segments filled with the foreground color.
1135 \row \i \c Flat
1136 \i Produces flat segments filled with the foreground color.
1137 \endtable
1138
1139 \c Outline and \c Filled will additionally use
1140 QColorGroup::light() and QColorGroup::dark() for shadow effects.
1141*/
1142void QLCDNumber::setSegmentStyle( SegmentStyle s )
1143{
1144 fill = ( s == Flat || s == Filled );
1145 shadow = ( s == Outline || s == Filled );
1146 update();
1147}
1148
1149QLCDNumber::SegmentStyle QLCDNumber::segmentStyle() const
1150{
1151 Q_ASSERT( fill || shadow );
1152 if ( !fill && shadow )
1153 return Outline;
1154 if ( fill && shadow )
1155 return Filled;
1156 return Flat;
1157}
1158
1159
1160/*!\reimp
1161*/
1162QSize QLCDNumber::sizeHint() const
1163{
1164 return QSize( 10 + 9 * (numDigits() + (smallDecimalPoint() ? 0 : 1)), 23 );
1165}
1166
1167#endif // QT_NO_LCDNUMBER
Note: See TracBrowser for help on using the repository browser.