summaryrefslogtreecommitdiffstats
path: root/src/gui/doublespinbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/doublespinbox.cpp')
-rw-r--r--src/gui/doublespinbox.cpp278
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 *
+ * david@bluehaze.org *
+ * *
+ * 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"
+