src/gui/widgets/qlcdnumber.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/widgets/qlcdnumber.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1286 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlcdnumber.h"
+#ifndef QT_NO_LCDNUMBER
+#include "qbitarray.h"
+#include "qpainter.h"
+#include "private/qframe_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLCDNumberPrivate : public QFramePrivate
+{
+    Q_DECLARE_PUBLIC(QLCDNumber)
+public:
+    void init();
+    void internalSetString(const QString& s);
+    void drawString(const QString& s, QPainter &, QBitArray * = 0, bool = true);
+    //void drawString(const QString &, QPainter &, QBitArray * = 0) const;
+    void drawDigit(const QPoint &, QPainter &, int, char, char = ' ');
+    void drawSegment(const QPoint &, char, QPainter &, int, bool = false);
+
+    int ndigits;
+    double val;
+    uint base : 2;
+    uint smallPoint : 1;
+    uint fill : 1;
+    uint shadow : 1;
+    QString digitStr;
+    QBitArray points;
+};
+
+/*!
+    \class QLCDNumber
+
+    \brief The QLCDNumber widget displays a number with LCD-like digits.
+
+    \ingroup basicwidgets
+
+
+    It can display a number in just about any size. It can display
+    decimal, hexadecimal, octal or binary numbers. It is easy to
+    connect to data sources using the display() slot, which is
+    overloaded to take any of five argument types.
+
+    There are also slots to change the base with setMode() and the
+    decimal point with setSmallDecimalPoint().
+
+    QLCDNumber emits the overflow() signal when it is asked to display
+    something beyond its range. The range is set by setNumDigits(),
+    but setSmallDecimalPoint() also influences it. If the display is
+    set to hexadecimal, octal or binary, the integer equivalent of the
+    value is displayed.
+
+    These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
+    6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
+    P, r, u, U, Y, colon, degree sign (which is specified as single
+    quote in the string) and space. QLCDNumber substitutes spaces for
+    illegal characters.
+
+    It is not possible to retrieve the contents of a QLCDNumber
+    object, although you can retrieve the numeric value with value().
+    If you really need the text, we recommend that you connect the
+    signals that feed the display() slot to another slot as well and
+    store the value there.
+
+    Incidentally, QLCDNumber is the very oldest part of Qt, tracing
+    its roots back to a BASIC program on the \link
+    http://www.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm
+    Sinclair Spectrum\endlink.
+
+    \table
+    \row \o \inlineimage motif-lcdnumber.png Screenshot of a Motif style LCD number widget
+    \inlineimage cde-lcdnumber.png Screenshot of a CDE style LCD number widget
+    \inlineimage windows-lcdnumber.png Screenshot of a Windows style LCD number widget
+    \inlineimage windowsxp-lcdnumber.png Screenshot of a Windows XP style LCD number widget
+    \inlineimage macintosh-lcdnumber.png Screenshot of a Macintosh style LCD number widget
+    \inlineimage plastique-lcdnumber.png Screenshot of a Plastique style LCD number widget
+    \row \o LCD number widgets shown in various widget styles (from left to right):
+    \l{Motif Style Widget Gallery}{Motif}, \l{CDE Style Widget Gallery}{CDE},
+    \l{Windows Style Widget Gallery}{Windows}, \l{Windows XP Style Widget Gallery}{Windows XP},
+    \l{Macintosh Style Widget Gallery}{Macintosh}, \l{Plastique Style Widget Gallery}{Plastique}.
+    \endtable
+
+    \sa QLabel, QFrame, {Digital Clock Example}, {Tetrix Example}
+*/
+
+/*!
+    \enum QLCDNumber::Mode
+
+    This type determines how numbers are shown.
+
+    \value Hex  Hexadecimal
+    \value Dec  Decimal
+    \value Oct  Octal
+    \value Bin  Binary
+    \omitvalue HEX
+    \omitvalue DEC
+    \omitvalue OCT
+    \omitvalue BIN
+
+    If the display is set to hexadecimal, octal or binary, the integer
+    equivalent of the value is displayed.
+*/
+
+/*!
+    \enum QLCDNumber::SegmentStyle
+
+    This type determines the visual appearance of the QLCDNumber
+    widget.
+
+    \value Outline gives raised segments filled with the background color.
+    \value Filled gives raised segments filled with the windowText color.
+    \value Flat gives flat segments filled with the windowText color.
+*/
+
+
+
+/*!
+    \fn void QLCDNumber::overflow()
+
+    This signal is emitted whenever the QLCDNumber is asked to display
+    a too-large number or a too-long string.
+
+    It is never emitted by setNumDigits().
+*/
+
+
+static QString int2string(int num, int base, int ndigits, bool *oflow)
+{
+    QString s;
+    bool negative;
+    if (num < 0) {
+        negative = true;
+        num      = -num;
+    } else {
+        negative = false;
+    }
+    switch(base) {
+        case QLCDNumber::Hex:
+            s.sprintf("%*x", ndigits, num);
+            break;
+        case QLCDNumber::Dec:
+            s.sprintf("%*i", ndigits, num);
+            break;
+        case QLCDNumber::Oct:
+            s.sprintf("%*o", ndigits, num);
+            break;
+        case QLCDNumber::Bin:
+            {
+                char buf[42];
+                char *p = &buf[41];
+                uint n = num;
+                int len = 0;
+                *p = '\0';
+                do {
+                    *--p = (char)((n&1)+'0');
+                    n >>= 1;
+                    len++;
+                } while (n != 0);
+                len = ndigits - len;
+                if (len > 0)
+                s.fill(QLatin1Char(' '), len);
+                s += QString::fromLatin1(p);
+            }
+            break;
+    }
+    if (negative) {
+        for (int i=0; i<(int)s.length(); i++) {
+            if (s[i] != QLatin1Char(' ')) {
+                if (i != 0) {
+                    s[i-1] = QLatin1Char('-');
+                } else {
+                    s.insert(0, QLatin1Char('-'));
+                }
+                break;
+            }
+        }
+    }
+    if (oflow)
+        *oflow = (int)s.length() > ndigits;
+    return s;
+}
+
+
+static QString double2string(double num, int base, int ndigits, bool *oflow)
+{
+    QString s;
+    if (base != QLCDNumber::Dec) {
+        bool of = num >= 2147483648.0 || num < -2147483648.0;
+        if (of) {                             // oops, integer overflow
+            if (oflow)
+                *oflow = true;
+            return s;
+        }
+        s = int2string((int)num, base, ndigits, 0);
+    } else {                                    // decimal base
+        int nd = ndigits;
+        do {
+            s.sprintf("%*.*g", ndigits, nd, num);
+            int i = s.indexOf(QLatin1Char('e'));
+            if (i > 0 && s[i+1]==QLatin1Char('+')) {
+                s[i] = QLatin1Char(' ');
+                s[i+1] = QLatin1Char('e');
+            }
+        } while (nd-- && (int)s.length() > ndigits);
+    }
+    if (oflow)
+        *oflow = (int)s.length() > ndigits;
+    return s;
+}
+
+
+static const char *getSegments(char ch)               // gets list of segments for ch
+{
+    static const char segments[30][8] =
+       { { 0, 1, 2, 4, 5, 6,99, 0},             // 0    0 / O
+         { 2, 5,99, 0, 0, 0, 0, 0},             // 1    1
+         { 0, 2, 3, 4, 6,99, 0, 0},             // 2    2
+         { 0, 2, 3, 5, 6,99, 0, 0},             // 3    3
+         { 1, 2, 3, 5,99, 0, 0, 0},             // 4    4
+         { 0, 1, 3, 5, 6,99, 0, 0},             // 5    5 / S
+         { 0, 1, 3, 4, 5, 6,99, 0},             // 6    6
+         { 0, 2, 5,99, 0, 0, 0, 0},             // 7    7
+         { 0, 1, 2, 3, 4, 5, 6,99},             // 8    8
+         { 0, 1, 2, 3, 5, 6,99, 0},             // 9    9 / g
+         { 3,99, 0, 0, 0, 0, 0, 0},             // 10   -
+         { 7,99, 0, 0, 0, 0, 0, 0},             // 11   .
+         { 0, 1, 2, 3, 4, 5,99, 0},             // 12   A
+         { 1, 3, 4, 5, 6,99, 0, 0},             // 13   B
+         { 0, 1, 4, 6,99, 0, 0, 0},             // 14   C
+         { 2, 3, 4, 5, 6,99, 0, 0},             // 15   D
+         { 0, 1, 3, 4, 6,99, 0, 0},             // 16   E
+         { 0, 1, 3, 4,99, 0, 0, 0},             // 17   F
+         { 1, 3, 4, 5,99, 0, 0, 0},             // 18   h
+         { 1, 2, 3, 4, 5,99, 0, 0},             // 19   H
+         { 1, 4, 6,99, 0, 0, 0, 0},             // 20   L
+         { 3, 4, 5, 6,99, 0, 0, 0},             // 21   o
+         { 0, 1, 2, 3, 4,99, 0, 0},             // 22   P
+         { 3, 4,99, 0, 0, 0, 0, 0},             // 23   r
+         { 4, 5, 6,99, 0, 0, 0, 0},             // 24   u
+         { 1, 2, 4, 5, 6,99, 0, 0},             // 25   U
+         { 1, 2, 3, 5, 6,99, 0, 0},             // 26   Y
+         { 8, 9,99, 0, 0, 0, 0, 0},             // 27   :
+         { 0, 1, 2, 3,99, 0, 0, 0},             // 28   '
+         {99, 0, 0, 0, 0, 0, 0, 0} };           // 29   empty
+
+    if (ch >= '0' && ch <= '9')
+        return segments[ch - '0'];
+    if (ch >= 'A' && ch <= 'F')
+        return segments[ch - 'A' + 12];
+    if (ch >= 'a' && ch <= 'f')
+        return segments[ch - 'a' + 12];
+
+    int n;
+    switch (ch) {
+        case '-':
+            n = 10;  break;
+        case 'O':
+            n = 0;   break;
+        case 'g':
+            n = 9;   break;
+        case '.':
+            n = 11;  break;
+        case 'h':
+            n = 18;  break;
+        case 'H':
+            n = 19;  break;
+        case 'l':
+        case 'L':
+            n = 20;  break;
+        case 'o':
+            n = 21;  break;
+        case 'p':
+        case 'P':
+            n = 22;  break;
+        case 'r':
+        case 'R':
+            n = 23;  break;
+        case 's':
+        case 'S':
+            n = 5;   break;
+        case 'u':
+            n = 24;  break;
+        case 'U':
+            n = 25;  break;
+        case 'y':
+        case 'Y':
+            n = 26;  break;
+        case ':':
+            n = 27;  break;
+        case '\'':
+            n = 28;  break;
+        default:
+            n = 29;  break;
+    }
+    return segments[n];
+}
+
+
+#ifdef QT3_SUPPORT
+/*! \obsolete
+    Constructs an LCD number, sets the number of digits to 5, the base
+    to decimal, the decimal point mode to 'small' and the frame style
+    to a raised box. The segmentStyle() is set to \c Outline.
+
+    The \a parent and \a name arguments are passed to the QFrame
+    constructor.
+
+    \sa setNumDigits(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(QWidget *parent, const char *name)
+        : QFrame(*new QLCDNumberPrivate, parent)
+{
+    setObjectName(QString::fromAscii(name));
+    Q_D(QLCDNumber);
+    d->ndigits = 5;
+    d->init();
+}
+
+
+/*! \obsolete
+    Constructs an LCD number, sets the number of digits to \a
+    numDigits, the base to decimal, the decimal point mode to 'small'
+    and the frame style to a raised box. The segmentStyle() is set to
+    \c Outline.
+
+    The \a parent and \a name arguments are passed to the QFrame
+    constructor.
+
+    \sa setNumDigits(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(uint numDigits, QWidget *parent, const char *name)
+        : QFrame(*new QLCDNumberPrivate, parent)
+{
+    setObjectName(QString::fromAscii(name));
+    Q_D(QLCDNumber);
+    d->ndigits = numDigits;
+    d->init();
+}
+#endif //QT3_SUPPORT
+
+/*!
+    Constructs an LCD number, sets the number of digits to 5, the base
+    to decimal, the decimal point mode to 'small' and the frame style
+    to a raised box. The segmentStyle() is set to \c Outline.
+
+    The \a parent argument is passed to the QFrame constructor.
+
+    \sa setNumDigits(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(QWidget *parent)
+        : QFrame(*new QLCDNumberPrivate, parent)
+{
+    Q_D(QLCDNumber);
+    d->ndigits = 5;
+    d->init();
+}
+
+
+/*!
+    Constructs an LCD number, sets the number of digits to \a
+    numDigits, the base to decimal, the decimal point mode to 'small'
+    and the frame style to a raised box. The segmentStyle() is set to
+    \c Filled.
+
+    The \a parent argument is passed to the QFrame constructor.
+
+    \sa setNumDigits(), setSmallDecimalPoint()
+*/
+
+QLCDNumber::QLCDNumber(uint numDigits, QWidget *parent)
+        : QFrame(*new QLCDNumberPrivate, parent)
+{
+    Q_D(QLCDNumber);
+    d->ndigits = numDigits;
+    d->init();
+}
+
+void QLCDNumberPrivate::init()
+{
+    Q_Q(QLCDNumber);
+
+    q->setFrameStyle(QFrame::Box | QFrame::Raised);
+    val        = 0;
+    base       = QLCDNumber::Dec;
+    smallPoint = false;
+    q->setNumDigits(ndigits);
+    q->setSegmentStyle(QLCDNumber::Filled);
+    q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
+}
+
+/*!
+    Destroys the LCD number.
+*/
+
+QLCDNumber::~QLCDNumber()
+{
+}
+
+
+/*!
+    \property QLCDNumber::numDigits
+    \brief the current number of digits displayed
+
+    Corresponds to the current number of digits. If \l
+    QLCDNumber::smallDecimalPoint is false, the decimal point occupies
+    one digit position.
+
+    By default, this property contains a value of 5.
+
+    \sa smallDecimalPoint
+*/
+
+void QLCDNumber::setNumDigits(int numDigits)
+{
+    Q_D(QLCDNumber);
+    if (numDigits > 99) {
+        qWarning("QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
+                 objectName().toLocal8Bit().constData());
+        numDigits = 99;
+    }
+    if (numDigits < 0) {
+        qWarning("QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
+                 objectName().toLocal8Bit().constData());
+        numDigits = 0;
+    }
+    if (d->digitStr.isNull()) {                  // from constructor
+        d->ndigits = numDigits;
+        d->digitStr.fill(QLatin1Char(' '), d->ndigits);
+        d->points.fill(0, d->ndigits);
+        d->digitStr[d->ndigits - 1] = QLatin1Char('0');            // "0" is the default number
+    } else {
+        bool doDisplay = d->ndigits == 0;
+        if (numDigits == d->ndigits)             // no change
+            return;
+        register int i;
+        int dif;
+        if (numDigits > d->ndigits) {            // expand
+            dif = numDigits - d->ndigits;
+            QString buf;
+            buf.fill(QLatin1Char(' '), dif);
+            d->digitStr.insert(0, buf);
+            d->points.resize(numDigits);
+            for (i=numDigits-1; i>=dif; i--)
+                d->points.setBit(i, d->points.testBit(i-dif));
+            for (i=0; i<dif; i++)
+                d->points.clearBit(i);
+        } else {                                        // shrink
+            dif = d->ndigits - numDigits;
+            d->digitStr = d->digitStr.right(numDigits);
+            QBitArray tmpPoints = d->points;
+            d->points.resize(numDigits);
+            for (i=0; i<(int)numDigits; i++)
+                d->points.setBit(i, tmpPoints.testBit(i+dif));
+        }
+        d->ndigits = numDigits;
+        if (doDisplay)
+            display(value());
+        update();
+    }
+}
+
+int QLCDNumber::numDigits() const
+{
+    Q_D(const QLCDNumber);
+    return d->ndigits;
+}
+
+/*!
+    \overload
+
+    Returns true if \a num is too big to be displayed in its entirety;
+    otherwise returns false.
+
+    \sa display(), numDigits(), smallDecimalPoint()
+*/
+
+bool QLCDNumber::checkOverflow(int num) const
+{
+    Q_D(const QLCDNumber);
+    bool of;
+    int2string(num, d->base, d->ndigits, &of);
+    return of;
+}
+
+
+/*!
+    Returns true if \a num is too big to be displayed in its entirety;
+    otherwise returns false.
+
+    \sa display(), numDigits(), smallDecimalPoint()
+*/
+
+bool QLCDNumber::checkOverflow(double num) const
+{
+    Q_D(const QLCDNumber);
+    bool of;
+    double2string(num, d->base, d->ndigits, &of);
+    return of;
+}
+
+
+/*!
+    \property QLCDNumber::mode
+    \brief the current display mode (number base)
+
+    Corresponds to the current display mode, which is one of \c Bin,
+    \c Oct, \c Dec (the default) and \c Hex. \c Dec mode can display
+    floating point values, the other modes display the integer
+    equivalent.
+
+    \sa smallDecimalPoint(), setHexMode(), setDecMode(), setOctMode(), setBinMode()
+*/
+
+QLCDNumber::Mode QLCDNumber::mode() const
+{
+    Q_D(const QLCDNumber);
+    return (QLCDNumber::Mode) d->base;
+}
+
+void QLCDNumber::setMode(Mode m)
+{
+    Q_D(QLCDNumber);
+    d->base = m;
+    display(d->val);
+}
+
+
+/*!
+    \property QLCDNumber::value
+    \brief the displayed value
+
+    This property corresponds to the current value displayed by the
+    LCDNumber.
+
+    If the displayed value is not a number, the property has a value
+    of 0.
+
+    By default, this property contains a value of 0.
+*/
+
+double QLCDNumber::value() const
+{
+    Q_D(const QLCDNumber);
+    return d->val;
+}
+
+/*!
+    \overload
+
+    Displays the number \a num.
+*/
+void QLCDNumber::display(double num)
+{
+    Q_D(QLCDNumber);
+    d->val = num;
+    bool of;
+    QString s = double2string(d->val, d->base, d->ndigits, &of);
+    if (of)
+        emit overflow();
+    else
+        d->internalSetString(s);
+}
+
+/*!
+    \property QLCDNumber::intValue
+    \brief the displayed value rounded to the nearest integer
+
+    This property corresponds to the nearest integer to the current
+    value displayed by the LCDNumber. This is the value used for
+    hexadecimal, octal and binary modes.
+
+    If the displayed value is not a number, the property has a value
+    of 0.
+
+    By default, this property contains a value of 0.
+*/
+int QLCDNumber::intValue() const
+{
+    Q_D(const QLCDNumber);
+    return qRound(d->val);
+}
+
+
+/*!
+    \overload
+
+    Displays the number \a num.
+*/
+void QLCDNumber::display(int num)
+{
+    Q_D(QLCDNumber);
+    d->val = (double)num;
+    bool of;
+    QString s = int2string(num, d->base, d->ndigits, &of);
+    if (of)
+        emit overflow();
+    else
+        d->internalSetString(s);
+}
+
+
+/*!
+    Displays the number represented by the string \a s.
+
+    This version of the function disregards mode() and
+    smallDecimalPoint().
+
+    These digits and other symbols can be shown: 0/O, 1, 2, 3, 4, 5/S,
+    6, 7, 8, 9/g, minus, decimal point, A, B, C, D, E, F, h, H, L, o,
+    P, r, u, U, Y, colon, degree sign (which is specified as single
+    quote in the string) and space. QLCDNumber substitutes spaces for
+    illegal characters.
+*/
+
+void QLCDNumber::display(const QString &s)
+{
+    Q_D(QLCDNumber);
+    d->val = 0;
+    bool ok = false;
+    double v = s.toDouble(&ok);
+    if (ok)
+        d->val = v;
+    d->internalSetString(s);
+}
+
+/*!
+    Calls setMode(Hex). Provided for convenience (e.g. for
+    connecting buttons to it).
+
+    \sa setMode(), setDecMode(), setOctMode(), setBinMode(), mode()
+*/
+
+void QLCDNumber::setHexMode()
+{
+    setMode(Hex);
+}
+
+
+/*!
+    Calls setMode(Dec). Provided for convenience (e.g. for
+    connecting buttons to it).
+
+    \sa setMode(), setHexMode(), setOctMode(), setBinMode(), mode()
+*/
+
+void QLCDNumber::setDecMode()
+{
+    setMode(Dec);
+}
+
+
+/*!
+    Calls setMode(Oct). Provided for convenience (e.g. for
+    connecting buttons to it).
+
+    \sa setMode(), setHexMode(), setDecMode(), setBinMode(), mode()
+*/
+
+void QLCDNumber::setOctMode()
+{
+    setMode(Oct);
+}
+
+
+/*!
+    Calls setMode(Bin). Provided for convenience (e.g. for
+    connecting buttons to it).
+
+    \sa setMode(), setHexMode(), setDecMode(), setOctMode(), mode()
+*/
+
+void QLCDNumber::setBinMode()
+{
+    setMode(Bin);
+}
+
+
+/*!
+    \property QLCDNumber::smallDecimalPoint
+    \brief the style of the decimal point
+
+    If true the decimal point is drawn between two digit positions.
+    Otherwise it occupies a digit position of its own, i.e. is drawn
+    in a digit position. The default is false.
+
+    The inter-digit space is made slightly wider when the decimal
+    point is drawn between the digits.
+
+    \sa mode
+*/
+
+void QLCDNumber::setSmallDecimalPoint(bool b)
+{
+    Q_D(QLCDNumber);
+    d->smallPoint = b;
+    update();
+}
+
+bool QLCDNumber::smallDecimalPoint() const
+{
+    Q_D(const QLCDNumber);
+    return d->smallPoint;
+}
+
+
+
+/*!\reimp
+*/
+
+
+void QLCDNumber::paintEvent(QPaintEvent *)
+{
+    Q_D(QLCDNumber);
+    QPainter p(this);
+    drawFrame(&p);
+    p.setRenderHint(QPainter::Antialiasing);
+    if (d->shadow)
+        p.translate(0.5, 0.5);
+
+    if (d->smallPoint)
+        d->drawString(d->digitStr, p, &d->points, false);
+    else
+        d->drawString(d->digitStr, p, 0, false);
+}
+
+
+void QLCDNumberPrivate::internalSetString(const QString& s)
+{
+    Q_Q(QLCDNumber);
+    QString buffer;
+    int i;
+    int len = s.length();
+    QBitArray newPoints(ndigits);
+
+    if (!smallPoint) {
+        if (len == ndigits)
+            buffer = s;
+        else
+            buffer = s.right(ndigits).rightJustified(ndigits, QLatin1Char(' '));
+    } else {
+        int  index = -1;
+        bool lastWasPoint = true;
+        newPoints.clearBit(0);
+        for (i=0; i<len; i++) {
+            if (s[i] == QLatin1Char('.')) {
+                if (lastWasPoint) {           // point already set for digit?
+                    if (index == ndigits - 1) // no more digits
+                        break;
+                    index++;
+                    buffer[index] = QLatin1Char(' ');        // 2 points in a row, add space
+                }
+                newPoints.setBit(index);        // set decimal point
+                lastWasPoint = true;
+            } else {
+                if (index == ndigits - 1)
+                    break;
+                index++;
+                buffer[index] = s[i];
+                newPoints.clearBit(index);      // decimal point default off
+                lastWasPoint = false;
+            }
+        }
+        if (index < ((int) ndigits) - 1) {
+            for(i=index; i>=0; i--) {
+                buffer[ndigits - 1 - index + i] = buffer[i];
+                newPoints.setBit(ndigits - 1 - index + i,
+                                   newPoints.testBit(i));
+            }
+            for(i=0; i<ndigits-index-1; i++) {
+                buffer[i] = QLatin1Char(' ');
+                newPoints.clearBit(i);
+            }
+        }
+    }
+
+    if (buffer == digitStr)
+        return;
+
+    digitStr = buffer;
+    if (smallPoint)
+        points = newPoints;
+    q->update();
+}
+
+/*!
+  \internal
+*/
+
+void QLCDNumberPrivate::drawString(const QString &s, QPainter &p,
+                                   QBitArray *newPoints, bool newString)
+{
+    Q_Q(QLCDNumber);
+    QPoint  pos;
+
+    int digitSpace = smallPoint ? 2 : 1;
+    int xSegLen    = q->width()*5/(ndigits*(5 + digitSpace) + digitSpace);
+    int ySegLen    = q->height()*5/12;
+    int segLen     = ySegLen > xSegLen ? xSegLen : ySegLen;
+    int xAdvance   = segLen*(5 + digitSpace)/5;
+    int xOffset    = (q->width() - ndigits*xAdvance + segLen/5)/2;
+    int yOffset    = (q->height() - segLen*2)/2;
+
+    for (int i=0;  i<ndigits; i++) {
+        pos = QPoint(xOffset + xAdvance*i, yOffset);
+        if (newString)
+            drawDigit(pos, p, segLen, s[i].toLatin1(), digitStr[i].toLatin1());
+        else
+            drawDigit(pos, p, segLen, s[i].toLatin1());
+        if (newPoints) {
+            char newPoint = newPoints->testBit(i) ? '.' : ' ';
+            if (newString) {
+                char oldPoint = points.testBit(i) ? '.' : ' ';
+                drawDigit(pos, p, segLen, newPoint, oldPoint);
+            } else {
+                drawDigit(pos, p, segLen, newPoint);
+            }
+        }
+    }
+    if (newString) {
+        digitStr = s;
+        digitStr.truncate(ndigits);
+        if (newPoints)
+            points = *newPoints;
+    }
+}
+
+
+/*!
+  \internal
+*/
+
+void QLCDNumberPrivate::drawDigit(const QPoint &pos, QPainter &p, int segLen,
+                                  char newCh, char oldCh)
+{
+// Draws and/or erases segments to change display of a single digit
+// from oldCh to newCh
+
+    char updates[18][2];        // can hold 2 times number of segments, only
+                                // first 9 used if segment table is correct
+    int  nErases;
+    int  nUpdates;
+    const char *segs;
+    int  i,j;
+
+    const char erase      = 0;
+    const char draw       = 1;
+    const char leaveAlone = 2;
+
+    segs = getSegments(oldCh);
+    for (nErases=0; segs[nErases] != 99; nErases++) {
+        updates[nErases][0] = erase;            // get segments to erase to
+        updates[nErases][1] = segs[nErases];    // remove old char
+    }
+    nUpdates = nErases;
+    segs = getSegments(newCh);
+    for(i = 0 ; segs[i] != 99 ; i++) {
+        for (j=0;  j<nErases; j++)
+            if (segs[i] == updates[j][1]) {   // same segment ?
+                updates[j][0] = leaveAlone;     // yes, already on screen
+                break;
+            }
+        if (j == nErases) {                   // if not already on screen
+            updates[nUpdates][0] = draw;
+            updates[nUpdates][1] = segs[i];
+            nUpdates++;
+        }
+    }
+    for (i=0; i<nUpdates; i++) {
+        if (updates[i][0] == draw)
+            drawSegment(pos, updates[i][1], p, segLen);
+        if (updates[i][0] == erase)
+            drawSegment(pos, updates[i][1], p, segLen, true);
+    }
+}
+
+
+static void addPoint(QPolygon &a, const QPoint &p)
+{
+    uint n = a.size();
+    a.resize(n + 1);
+    a.setPoint(n, p);
+}
+
+/*!
+  \internal
+*/
+
+void QLCDNumberPrivate::drawSegment(const QPoint &pos, char segmentNo, QPainter &p,
+                                    int segLen, bool erase)
+{
+    Q_Q(QLCDNumber);
+    QPoint ppt;
+    QPoint pt = pos;
+    int width = segLen/5;
+
+    const QPalette &pal = q->palette();
+    QColor lightColor,darkColor,fgColor;
+    if (erase){
+        lightColor = pal.color(q->backgroundRole());
+        darkColor  = lightColor;
+        fgColor    = lightColor;
+    } else {
+        lightColor = pal.light().color();
+        darkColor  = pal.dark().color();
+        fgColor    = pal.color(q->foregroundRole());
+    }
+
+
+#define LINETO(X,Y) addPoint(a, QPoint(pt.x() + (X),pt.y() + (Y)))
+#define LIGHT
+#define DARK
+
+    if (fill) {
+        QPolygon a(0);
+        //The following is an exact copy of the switch below.
+        //don't make any changes here
+        switch (segmentNo) {
+        case 0 :
+            ppt = pt;
+            LIGHT;
+            LINETO(segLen - 1,0);
+            DARK;
+            LINETO(segLen - width - 1,width);
+            LINETO(width,width);
+            LINETO(0,0);
+            break;
+        case 1 :
+            pt += QPoint(0 , 1);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,width);
+            DARK;
+            LINETO(width,segLen - width/2 - 2);
+            LINETO(0,segLen - 2);
+            LIGHT;
+            LINETO(0,0);
+            break;
+        case 2 :
+            pt += QPoint(segLen - 1 , 1);
+            ppt = pt;
+            DARK;
+            LINETO(0,segLen - 2);
+            LINETO(-width,segLen - width/2 - 2);
+            LIGHT;
+            LINETO(-width,width);
+            LINETO(0,0);
+            break;
+        case 3 :
+            pt += QPoint(0 , segLen);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,-width/2);
+            LINETO(segLen - width - 1,-width/2);
+            LINETO(segLen - 1,0);
+            DARK;
+            if (width & 1) {            // adjust for integer division error
+                LINETO(segLen - width - 3,width/2 + 1);
+                LINETO(width + 2,width/2 + 1);
+            } else {
+                LINETO(segLen - width - 1,width/2);
+                LINETO(width,width/2);
+            }
+            LINETO(0,0);
+            break;
+        case 4 :
+            pt += QPoint(0 , segLen + 1);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,width/2);
+            DARK;
+            LINETO(width,segLen - width - 2);
+            LINETO(0,segLen - 2);
+            LIGHT;
+            LINETO(0,0);
+            break;
+        case 5 :
+            pt += QPoint(segLen - 1 , segLen + 1);
+            ppt = pt;
+            DARK;
+            LINETO(0,segLen - 2);
+            LINETO(-width,segLen - width - 2);
+            LIGHT;
+            LINETO(-width,width/2);
+            LINETO(0,0);
+            break;
+        case 6 :
+            pt += QPoint(0 , segLen*2);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,-width);
+            LINETO(segLen - width - 1,-width);
+            LINETO(segLen - 1,0);
+            DARK;
+            LINETO(0,0);
+            break;
+        case 7 :
+            if (smallPoint)   // if smallpoint place'.' between other digits
+                pt += QPoint(segLen + width/2 , segLen*2);
+            else
+                pt += QPoint(segLen/2 , segLen*2);
+            ppt = pt;
+            DARK;
+            LINETO(width,0);
+            LINETO(width,-width);
+            LIGHT;
+            LINETO(0,-width);
+            LINETO(0,0);
+            break;
+        case 8 :
+            pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
+            ppt = pt;
+            DARK;
+            LINETO(width,0);
+            LINETO(width,-width);
+            LIGHT;
+            LINETO(0,-width);
+            LINETO(0,0);
+            break;
+        case 9 :
+            pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
+            ppt = pt;
+            DARK;
+            LINETO(width,0);
+            LINETO(width,-width);
+            LIGHT;
+            LINETO(0,-width);
+            LINETO(0,0);
+            break;
+        default :
+            qWarning("QLCDNumber::drawSegment: (%s) Illegal segment id: %d\n",
+                     q->objectName().toLocal8Bit().constData(), segmentNo);
+        }
+        // End exact copy
+        p.setPen(Qt::NoPen);
+        p.setBrush(fgColor);
+        p.drawPolygon(a);
+        p.setBrush(Qt::NoBrush);
+
+        pt = pos;
+    }
+#undef LINETO
+#undef LIGHT
+#undef DARK
+
+#define LINETO(X,Y) p.drawLine(ppt.x(), ppt.y(), pt.x()+(X), pt.y()+(Y)); \
+                    ppt = QPoint(pt.x()+(X), pt.y()+(Y))
+#define LIGHT p.setPen(lightColor)
+#define DARK  p.setPen(darkColor)
+    if (shadow)
+        switch (segmentNo) {
+        case 0 :
+            ppt = pt;
+            LIGHT;
+            LINETO(segLen - 1,0);
+            DARK;
+            LINETO(segLen - width - 1,width);
+            LINETO(width,width);
+            LINETO(0,0);
+            break;
+        case 1 :
+            pt += QPoint(0,1);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,width);
+            DARK;
+            LINETO(width,segLen - width/2 - 2);
+            LINETO(0,segLen - 2);
+            LIGHT;
+            LINETO(0,0);
+            break;
+        case 2 :
+            pt += QPoint(segLen - 1 , 1);
+            ppt = pt;
+            DARK;
+            LINETO(0,segLen - 2);
+            LINETO(-width,segLen - width/2 - 2);
+            LIGHT;
+            LINETO(-width,width);
+            LINETO(0,0);
+            break;
+        case 3 :
+            pt += QPoint(0 , segLen);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,-width/2);
+            LINETO(segLen - width - 1,-width/2);
+            LINETO(segLen - 1,0);
+            DARK;
+            if (width & 1) {            // adjust for integer division error
+                LINETO(segLen - width - 3,width/2 + 1);
+                LINETO(width + 2,width/2 + 1);
+            } else {
+                LINETO(segLen - width - 1,width/2);
+                LINETO(width,width/2);
+            }
+            LINETO(0,0);
+            break;
+        case 4 :
+            pt += QPoint(0 , segLen + 1);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,width/2);
+            DARK;
+            LINETO(width,segLen - width - 2);
+            LINETO(0,segLen - 2);
+            LIGHT;
+            LINETO(0,0);
+            break;
+        case 5 :
+            pt += QPoint(segLen - 1 , segLen + 1);
+            ppt = pt;
+            DARK;
+            LINETO(0,segLen - 2);
+            LINETO(-width,segLen - width - 2);
+            LIGHT;
+            LINETO(-width,width/2);
+            LINETO(0,0);
+            break;
+        case 6 :
+            pt += QPoint(0 , segLen*2);
+            ppt = pt;
+            LIGHT;
+            LINETO(width,-width);
+            LINETO(segLen - width - 1,-width);
+            LINETO(segLen - 1,0);
+            DARK;
+            LINETO(0,0);
+            break;
+        case 7 :
+            if (smallPoint)   // if smallpoint place'.' between other digits
+                pt += QPoint(segLen + width/2 , segLen*2);
+            else
+                pt += QPoint(segLen/2 , segLen*2);
+            ppt = pt;
+            DARK;
+            LINETO(width,0);
+            LINETO(width,-width);
+            LIGHT;
+            LINETO(0,-width);
+            LINETO(0,0);
+            break;
+        case 8 :
+            pt += QPoint(segLen/2 - width/2 + 1 , segLen/2 + width);
+            ppt = pt;
+            DARK;
+            LINETO(width,0);
+            LINETO(width,-width);
+            LIGHT;
+            LINETO(0,-width);
+            LINETO(0,0);
+            break;
+        case 9 :
+            pt += QPoint(segLen/2 - width/2 + 1 , 3*segLen/2 + width);
+            ppt = pt;
+            DARK;
+            LINETO(width,0);
+            LINETO(width,-width);
+            LIGHT;
+            LINETO(0,-width);
+            LINETO(0,0);
+            break;
+        default :
+            qWarning("QLCDNumber::drawSegment: (%s) Illegal segment id: %d\n",
+                     q->objectName().toLocal8Bit().constData(), segmentNo);
+        }
+
+#undef LINETO
+#undef LIGHT
+#undef DARK
+}
+
+
+
+/*!
+    \property QLCDNumber::segmentStyle
+    \brief the style of the LCDNumber
+
+    \table
+    \header \i Style \i Result
+    \row \i \c Outline
+         \i Produces raised segments filled with the background color
+    \row \i \c Filled
+            (this is the default).
+         \i Produces raised segments filled with the foreground color.
+    \row \i \c Flat
+         \i Produces flat segments filled with the foreground color.
+    \endtable
+
+    \c Outline and \c Filled will additionally use
+    QPalette::light() and QPalette::dark() for shadow effects.
+*/
+void QLCDNumber::setSegmentStyle(SegmentStyle s)
+{
+    Q_D(QLCDNumber);
+    d->fill = (s == Flat || s == Filled);
+    d->shadow = (s == Outline || s == Filled);
+    update();
+}
+
+QLCDNumber::SegmentStyle QLCDNumber::segmentStyle() const
+{
+    Q_D(const QLCDNumber);
+    Q_ASSERT(d->fill || d->shadow);
+    if (!d->fill && d->shadow)
+        return Outline;
+    if (d->fill && d->shadow)
+        return Filled;
+    return Flat;
+}
+
+
+/*!\reimp
+*/
+QSize QLCDNumber::sizeHint() const
+{
+    return QSize(10 + 9 * (numDigits() + (smallDecimalPoint() ? 0 : 1)), 23);
+}
+
+/*! \reimp */
+bool QLCDNumber::event(QEvent *e)
+{
+    return QFrame::event(e);
+}
+
+/*!
+    \fn void QLCDNumber::setMargin(int margin)
+    Sets the width of the margin around the contents of the widget to \a margin.
+    
+    Use QWidget::setContentsMargins() instead.
+    \sa margin(), QWidget::setContentsMargins()
+*/
+
+/*!
+    \fn int QLCDNumber::margin() const
+    Returns the width of the margin around the contents of the widget.
+    
+    Use QWidget::getContentsMargins() instead.
+    \sa setMargin(), QWidget::getContentsMargins()
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LCDNUMBER