diff options
Diffstat (limited to 'src/gui/doublespinbox.cpp')
-rw-r--r-- | src/gui/doublespinbox.cpp | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/src/gui/doublespinbox.cpp b/src/gui/doublespinbox.cpp new file mode 100644 index 0000000..b8672b5 --- /dev/null +++ b/src/gui/doublespinbox.cpp @@ -0,0 +1,278 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 by David Saxton * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "cnitem.h" +#include "doublespinbox.h" + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> + +#include <qlineedit.h> +#include <qregexp.h> +#include <qtimer.h> + +#include <algorithm> +#include <cmath> +using namespace std; + + +inline int roundDouble( double val ) +{ + return (val > 0) ? int(val+0.5) : int(val-0.5); +} + + +DoubleSpinBox::DoubleSpinBox( double lower, double upper, double minAbs, double value, const QString &unit, QWidget * parent ) + : QSpinBox( parent ) +{ + m_lastEmittedValue = value; + m_unit = unit; + m_minValue = lower; + m_maxValue = upper; + m_minAbsValue = minAbs; + m_queuedSuffix = QString::null; + + editor()->setAlignment( Qt::AlignRight ); + + connect( this, SIGNAL(valueChanged(int)), this, SLOT(checkIfChanged()) ); + QSpinBox::setMinValue( -(1<<30) ); + QSpinBox::setMaxValue( +(1<<30) ); + setValue( value ); + + setValidator( 0 ); +} + + +DoubleSpinBox::~DoubleSpinBox() +{ +} + + +double DoubleSpinBox::value() +{ + return getDisplayedNumber( 0 ) * getMult(); +} + + +void DoubleSpinBox::setValue( double value ) +{ + if ( value > maxValue() ) + value = maxValue(); + + else if ( value < minValue() ) + value = minValue(); + + if ( std::abs(value) < m_minAbsValue*0.9999 ) + value = 0.0; + + updateSuffix( value ); + + QSpinBox::setValue( roundDouble( (value / Item::getMultiplier( value )) * 100 ) ); +} + + +void DoubleSpinBox::setUnit( const QString & unit ) +{ + updateSuffix( value() ); + m_unit = unit; +} + + +void DoubleSpinBox::updateSuffix( double value ) +{ + m_queuedSuffix = " " + CNItem::getNumberMag( value ) + m_unit; + + // Set suffix to be empty if it is nothing but white space + if ( m_queuedSuffix.stripWhiteSpace().isEmpty() ) + m_queuedSuffix = ""; + + QTimer::singleShot( 0, this, SLOT(setQueuedSuffix()) ); +} + + +void DoubleSpinBox::setQueuedSuffix() +{ + bool changed = false; + if ( !m_queuedSuffix.isNull() && suffix() != m_queuedSuffix ) + { + setSuffix( m_queuedSuffix ); + changed = true; + } + m_queuedSuffix = QString::null; + + if ( changed ) + emit valueChanged( value() ); +} + + +double DoubleSpinBox::getMult() +{ + QString text = this->text().stripWhiteSpace(); + if ( !m_queuedSuffix.isNull() ) + { + QString nsSuffix = suffix().stripWhiteSpace(); + + if ( nsSuffix.isEmpty() ) + text.append( m_queuedSuffix ); + else + text.replace( nsSuffix, m_queuedSuffix ); + } + + if ( text.length() == 0 ) + return 1.0; + + if ( text.endsWith( m_unit, false ) ) + text = text.remove( text.length() - m_unit.length(), m_unit.length() ); + + text.stripWhiteSpace(); + + QChar siExp = text[ text.length()-1 ]; + + if ( siExp.isLetter() || siExp.isSymbol() ) + return CNItem::getMultiplier((QString)siExp); + + else + return 1; +} + + +double DoubleSpinBox::getDisplayedNumber( bool * ok ) +{ + KLocale * locale = KGlobal::locale(); + + // Fetch the characters that we don't want to discard + const QString exclude = locale->decimalSymbol() + + locale->thousandsSeparator() + + locale->positiveSign() + + locale->negativeSign(); + + QString number = cleanText().remove( QRegExp("[^"+exclude+"\\d]") ); + + return locale->readNumber( number, ok ); +} + + +int DoubleSpinBox::mapTextToValue( bool * ok ) +{ + (void)ok; + + double value = this->value(); + + if ( value > maxValue() ) + value = maxValue(); + + else if ( value < minValue() ) + value = minValue(); + + if ( std::abs(value) < m_minAbsValue*0.9999 ) + value = 0.0; + + updateSuffix( value ); + + value /= Item::getMultiplier( value ); + + // Precision of 2 extra digits + return int( value * 100 ); +} + + +QString DoubleSpinBox::mapValueToText( int v ) +{ + double val = double(v)/100.0; + + int leftDigits = (int)floor( log10( abs(val) ) ) + 1; + if ( leftDigits < 0 ) + leftDigits = 0; + else if ( leftDigits > 3 ) + leftDigits = 3; + + KLocale * locale = KGlobal::locale(); + return locale->formatNumber( val, 3-leftDigits ); +} + + +void DoubleSpinBox::checkIfChanged() +{ + double newValue = value(); + + if ( m_lastEmittedValue == newValue ) + return; + + m_lastEmittedValue = newValue; + emit valueChanged( m_lastEmittedValue ); +} + + +double DoubleSpinBox::roundToOneSF( double value ) +{ + if ( value == 0.0 ) + return 0.0; + + value *= 1.000001; + double tens = pow( 10.0, floor(log10( abs(value) )) ); + + return int ( value / tens ) * tens; +} + + +void DoubleSpinBox::stepUp() +{ + double value = roundToOneSF( this->value() ); + + if ( value == 0 ) + value = m_minAbsValue; + + else if ( value > 0 ) + value += std::pow( 10., std::floor( std::log10(value) ) ); + + else + { + double sub = std::pow(10., std::floor( std::log10(std::abs(value))-1) ); + value += std::pow( 10., std::floor( std::log10(std::abs(value)-sub) ) ); + } + + value *= 1.00001; + + if ( std::abs(value) < m_minAbsValue ) + value = 0.; + + setValue( value ); +} + + +void DoubleSpinBox::stepDown() +{ + double value = roundToOneSF( this->value() ); + + if ( value == 0 ) + value = -m_minAbsValue; + + else if ( value > 0 ) + { + double sub = std::pow(10., std::floor( std::log10(value)-1) ); + value -= std::pow( 10., std::floor( std::log10(value-sub) ) ); + } + else + { + double add = std::pow(10., std::floor( std::log10(std::abs(value))-1) ); + value -= std::pow( 10., std::floor( std::log10(std::abs(value)+add) ) ); + } + + value *= 1.00001; + + if ( std::abs(value) < m_minAbsValue ) + value = 0.; + + setValue( value ); +} + +#include "doublespinbox.moc" + |