You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/gui/doublespinbox.cpp

279 lines
5.8 KiB

/***************************************************************************
* 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 <tdeglobal.h>
#include <tdelocale.h>
#include <tqlineedit.h>
#include <tqregexp.h>
#include <tqtimer.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 TQString &unit, TQWidget * parent )
: TQSpinBox( parent )
{
m_lastEmittedValue = value;
m_unit = unit;
m_minValue = lower;
m_maxValue = upper;
m_minAbsValue = minAbs;
m_queuedSuffix = TQString();
editor()->setAlignment( TQt::AlignRight );
connect( this, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(checkIfChanged()) );
TQSpinBox::setMinValue( -(1<<30) );
TQSpinBox::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 );
TQSpinBox::setValue( roundDouble( (value / Item::getMultiplier( value )) * 100 ) );
}
void DoubleSpinBox::setUnit( const TQString & 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 = "";
TQTimer::singleShot( 0, this, TQ_SLOT(setQueuedSuffix()) );
}
void DoubleSpinBox::setQueuedSuffix()
{
bool changed = false;
if ( !m_queuedSuffix.isNull() && suffix() != m_queuedSuffix )
{
setSuffix( m_queuedSuffix );
changed = true;
}
m_queuedSuffix = TQString();
if ( changed )
emit valueChanged( value() );
}
double DoubleSpinBox::getMult()
{
TQString text = this->text().stripWhiteSpace();
if ( !m_queuedSuffix.isNull() )
{
TQString 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();
TQChar siExp = text[ text.length()-1 ];
if ( siExp.isLetter() || siExp.isSymbol() )
return CNItem::getMultiplier((TQString)siExp);
else
return 1;
}
double DoubleSpinBox::getDisplayedNumber( bool * ok )
{
TDELocale * locale = TDEGlobal::locale();
// Fetch the characters that we don't want to discard
const TQString exclude = locale->decimalSymbol()
+ locale->thousandsSeparator()
+ locale->positiveSign()
+ locale->negativeSign();
TQString number = cleanText().remove( TQRegExp("[^"+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 );
}
TQString 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;
TDELocale * locale = TDEGlobal::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"