knuminput.cpp
// -*- c-basic-offset: 4 -*-
/*
* knuminput.cpp
*
* Initial implementation:
* Copyright (c) 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
* Rewritten and maintained by:
* Copyright (c) 2000 Dirk A. Mueller <mueller@kde.org>
* KDoubleSpinBox:
* Copyright (c) 2002 Marc Mutz <mutz@kde.org>
*
* Requires the Qt widget libraries, available at no cost at
* http://www.troll.no/
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <config.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <assert.h>
#include <math.h>
#include <algorithm>
#include <qapplication.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qsize.h>
#include <qslider.h>
#include <qspinbox.h>
#include <qstyle.h>
#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>
#include "kdialog.h"
#include "knumvalidator.h"
#include "knuminput.h"
static inline int calcDiffByTen( int x, int y ) {
// calculate ( x - y ) / 10 without overflowing ints:
return ( x / 10 ) - ( y / 10 ) + ( x % 10 - y % 10 ) / 10;
}
// ----------------------------------------------------------------------------
KNumInput::KNumInput(QWidget* parent, const char* name)
: QWidget(parent, name)
{
init();
}
KNumInput::KNumInput(KNumInput* below, QWidget* parent, const char* name)
: QWidget(parent, name)
{
init();
if(below) {
m_next = below->m_next;
m_prev = below;
below->m_next = this;
if(m_next)
m_next->m_prev = this;
}
}
void KNumInput::init()
{
m_prev = m_next = 0;
m_colw1 = m_colw2 = 0;
m_label = 0;
m_slider = 0;
m_alignment = 0;
}
KNumInput::~KNumInput()
{
if(m_prev)
m_prev->m_next = m_next;
if(m_next)
m_next->m_prev = m_prev;
}
void KNumInput::setLabel(const QString & label, int a)
{
if(label.isEmpty()) {
delete m_label;
m_label = 0;
m_alignment = 0;
}
else {
if (m_label) m_label->setText(label);
else m_label = new QLabel(label, this, "KNumInput::QLabel");
m_label->setAlignment((a & (~(AlignTop|AlignBottom|AlignVCenter)))
| AlignVCenter);
// if no vertical alignment set, use Top alignment
if(!(a & (AlignTop|AlignBottom|AlignVCenter)))
a |= AlignTop;
m_alignment = a;
}
layout(true);
}
QString KNumInput::label() const
{
if (m_label) return m_label->text();
return QString::null;
}
void KNumInput::layout(bool deep)
{
int w1 = m_colw1;
int w2 = m_colw2;
// label sizeHint
m_sizeLabel = (m_label ? m_label->sizeHint() : QSize(0,0));
if(m_label && (m_alignment & AlignVCenter))
m_colw1 = m_sizeLabel.width() + 4;
else
m_colw1 = 0;
// slider sizeHint
m_sizeSlider = (m_slider ? m_slider->sizeHint() : QSize(0, 0));
doLayout();
if(!deep) {
m_colw1 = w1;
m_colw2 = w2;
return;
}
KNumInput* p = this;
while(p) {
p->doLayout();
w1 = QMAX(w1, p->m_colw1);
w2 = QMAX(w2, p->m_colw2);
p = p->m_prev;
}
p = m_next;
while(p) {
p->doLayout();
w1 = QMAX(w1, p->m_colw1);
w2 = QMAX(w2, p->m_colw2);
p = p->m_next;
}
p = this;
while(p) {
p->m_colw1 = w1;
p->m_colw2 = w2;
p = p->m_prev;
}
p = m_next;
while(p) {
p->m_colw1 = w1;
p->m_colw2 = w2;
p = p->m_next;
}
// kdDebug() << "w1 " << w1 << " w2 " << w2 << endl;
}
QSizePolicy KNumInput::sizePolicy() const
{
return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
}
QSize KNumInput::sizeHint() const
{
return minimumSizeHint();
}
void KNumInput::setSteps(int minor, int major)
{
if(m_slider)
m_slider->setSteps( minor, major );
}
// ----------------------------------------------------------------------------
KIntSpinBox::KIntSpinBox(QWidget *parent, const char *name)
: QSpinBox(0, 99, 1, parent, name)
{
editor()->setAlignment(AlignRight);
val_base = 10;
setValue(0);
}
KIntSpinBox::~KIntSpinBox()
{
}
KIntSpinBox::KIntSpinBox(int lower, int upper, int step, int value, int base,
QWidget* parent, const char* name)
: QSpinBox(lower, upper, step, parent, name)
{
editor()->setAlignment(AlignRight);
val_base = base;
setValue(value);
}
void KIntSpinBox::setBase(int base)
{
val_base = base;
}
int KIntSpinBox::base() const
{
return val_base;
}
QString KIntSpinBox::mapValueToText(int v)
{
return QString::number(v, val_base);
}
int KIntSpinBox::mapTextToValue(bool* ok)
{
return cleanText().toInt(ok, val_base);
}
void KIntSpinBox::setEditFocus(bool mark)
{
editor()->setFocus();
if(mark)
editor()->selectAll();
}
// ----------------------------------------------------------------------------
class KIntNumInput::KIntNumInputPrivate {
public:
int referencePoint;
short blockRelative;
KIntNumInputPrivate( int r )
: referencePoint( r ),
blockRelative( 0 ) {}
};
KIntNumInput::KIntNumInput(KNumInput* below, int val, QWidget* parent,
int _base, const char* name)
: KNumInput(below, parent, name)
{
init(val, _base);
}
KIntNumInput::KIntNumInput(QWidget *parent, const char *name)
: KNumInput(parent, name)
{
init(0, 10);
}
KIntNumInput::KIntNumInput(int val, QWidget *parent, int _base, const char *name)
: KNumInput(parent, name)
{
init(val, _base);
}
void KIntNumInput::init(int val, int _base)
{
d = new KIntNumInputPrivate( val );
m_spin = new KIntSpinBox(INT_MIN, INT_MAX, 1, val, _base, this, "KIntNumInput::KIntSpinBox");
// the KIntValidator is broken beyond believe for
// spinboxes which have suffix or prefix texts, so
// better don't use it unless absolutely necessary
if (_base != 10)
m_spin->setValidator(new KIntValidator(this, _base, "KNumInput::KIntValidtr"));
connect(m_spin, SIGNAL(valueChanged(int)), SLOT(spinValueChanged(int)));
connect(this, SIGNAL(valueChanged(int)),
SLOT(slotEmitRelativeValueChanged(int)));
setFocusProxy(m_spin);
layout(true);
}
void KIntNumInput::setReferencePoint( int ref ) {
// clip to valid range:
ref = kMin( maxValue(), kMax( minValue(), ref ) );
d->referencePoint = ref;
}
int KIntNumInput::referencePoint() const {
return d->referencePoint;
}
void KIntNumInput::spinValueChanged(int val)
{
if(m_slider)
m_slider->setValue(val);
emit valueChanged(val);
}
void KIntNumInput::slotEmitRelativeValueChanged( int value ) {
if ( d->blockRelative || !d->referencePoint ) return;
emit relativeValueChanged( double( value ) / double( d->referencePoint ) );
}
void KIntNumInput::setRange(int lower, int upper, int step, bool slider)
{
upper = kMax(upper, lower);
lower = kMin(upper, lower);
m_spin->setMinValue(lower);
m_spin->setMaxValue(upper);
m_spin->setLineStep(step);
step = m_spin->lineStep(); // maybe QRangeControl didn't like out lineStep?
if(slider) {
if (m_slider)
m_slider->setRange(lower, upper);
else {
m_slider = new QSlider(lower, upper, step, m_spin->value(),
QSlider::Horizontal, this);
m_slider->setTickmarks(QSlider::Below);
connect(m_slider, SIGNAL(valueChanged(int)),
m_spin, SLOT(setValue(int)));
}
// calculate (upper-lower)/10 without overflowing int's:
int major = calcDiffByTen( upper, lower );
if ( major==0 ) major = step; // #### workaround Qt bug in 2.1-beta4
m_slider->setSteps(step, major);
m_slider->setTickInterval(major);
}
else {
delete m_slider;
m_slider = 0;
}
// check that reference point is still inside valid range:
setReferencePoint( referencePoint() );
layout(true);
}
void KIntNumInput::setMinValue(int min)
{
setRange(min, m_spin->maxValue(), m_spin->lineStep(), m_slider);
}
int KIntNumInput::minValue() const
{
return m_spin->minValue();
}
void KIntNumInput::setMaxValue(int max)
{
setRange(m_spin->minValue(), max, m_spin->lineStep(), m_slider);
}
int KIntNumInput::maxValue() const
{
return m_spin->maxValue();
}
void KIntNumInput::setSuffix(const QString &suffix)
{
m_spin->setSuffix(suffix);
layout(true);
}
QString KIntNumInput::suffix() const
{
return m_spin->suffix();
}
void KIntNumInput::setPrefix(const QString &prefix)
{
m_spin->setPrefix(prefix);
layout(true);
}
QString KIntNumInput::prefix() const
{
return m_spin->prefix();
}
void KIntNumInput::setEditFocus(bool mark)
{
m_spin->setEditFocus(mark);
}
QSize KIntNumInput::minimumSizeHint() const
{
constPolish();
int w;
int h;
h = 2 + QMAX(m_sizeSpin.height(), m_sizeSlider.height());
// if in extra row, then count it here
if(m_label && (m_alignment & (AlignBottom|AlignTop)))
h += 4 + m_sizeLabel.height();
else
// label is in the same row as the other widgets
h = QMAX(h, m_sizeLabel.height() + 2);
w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
w += m_colw1 + m_colw2;
if(m_alignment & (AlignTop|AlignBottom))
w = QMAX(w, m_sizeLabel.width() + 4);
return QSize(w, h);
}
void KIntNumInput::doLayout()
{
m_sizeSpin = m_spin->sizeHint();
m_colw2 = m_sizeSpin.width();
if (m_label)
m_label->setBuddy(m_spin);
}
void KIntNumInput::resizeEvent(QResizeEvent* e)
{
int w = m_colw1;
int h = 0;
if(m_label && (m_alignment & AlignTop)) {
m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
h += m_sizeLabel.height() + KDialog::spacingHint();
}
if(m_label && (m_alignment & AlignVCenter))
m_label->setGeometry(0, 0, w, m_sizeSpin.height());
if (qApp->reverseLayout())
{
m_spin->setGeometry(w, h, m_slider ? m_colw2 : QMAX(m_colw2, e->size().width() - w), m_sizeSpin.height());
w += m_colw2 + 8;
if(m_slider)
m_slider->setGeometry(w, h, e->size().width() - w, m_sizeSpin.height());
}
else if(m_slider) {
m_slider->setGeometry(w, h, e->size().width() - (w + m_colw2 + KDialog::spacingHint()), m_sizeSpin.height());
m_spin->setGeometry(w + m_slider->size().width() + KDialog::spacingHint(), h, m_colw2, m_sizeSpin.height());
}
else {
m_spin->setGeometry(w, h, QMAX(m_colw2, e->size().width() - w), m_sizeSpin.height());
}
h += m_sizeSpin.height() + 2;
if(m_label && (m_alignment & AlignBottom))
m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
}
KIntNumInput::~KIntNumInput()
{
delete d;
}
void KIntNumInput::setValue(int val)
{
m_spin->setValue(val);
// slider value is changed by spinValueChanged
}
void KIntNumInput::setRelativeValue( double r ) {
if ( !d->referencePoint ) return;
++d->blockRelative;
setValue( int( d->referencePoint * r + 0.5 ) );
--d->blockRelative;
}
double KIntNumInput::relativeValue() const {
if ( !d->referencePoint ) return 0;
return double( value() ) / double ( d->referencePoint );
}
int KIntNumInput::value() const
{
return m_spin->value();
}
void KIntNumInput::setSpecialValueText(const QString& text)
{
m_spin->setSpecialValueText(text);
layout(true);
}
QString KIntNumInput::specialValueText() const
{
return m_spin->specialValueText();
}
void KIntNumInput::setLabel(const QString & label, int a)
{
KNumInput::setLabel(label, a);
if(m_label)
m_label->setBuddy(m_spin);
}
// ----------------------------------------------------------------------------
class KDoubleNumInput::KDoubleNumInputPrivate {
public:
KDoubleNumInputPrivate( double r )
: spin( 0 ),
referencePoint( r ),
blockRelative ( 0 ) {}
KDoubleSpinBox * spin;
double referencePoint;
short blockRelative;
};
KDoubleNumInput::KDoubleNumInput(QWidget *parent, const char *name)
: KNumInput(parent, name)
{
init(0.0, 0.0, 9999.0, 0.01, 2);
}
KDoubleNumInput::KDoubleNumInput(double lower, double upper, double value,
double step, int precision, QWidget* parent,
const char *name)
: KNumInput(parent, name)
{
init(value, lower, upper, step, precision);
}
KDoubleNumInput::KDoubleNumInput(KNumInput *below,
double lower, double upper, double value,
double step, int precision, QWidget* parent,
const char *name)
: KNumInput(below, parent, name)
{
init(value, lower, upper, step, precision);
}
KDoubleNumInput::KDoubleNumInput(double value, QWidget *parent, const char *name)
: KNumInput(parent, name)
{
init(value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
}
KDoubleNumInput::KDoubleNumInput(KNumInput* below, double value, QWidget* parent,
const char* name)
: KNumInput(below, parent, name)
{
init( value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
}
KDoubleNumInput::~KDoubleNumInput()
{
delete d;
}
// ### remove when BIC changes are allowed again:
bool KDoubleNumInput::eventFilter( QObject * o, QEvent * e ) {
return KNumInput::eventFilter( o, e );
}
void KDoubleNumInput::resetEditBox() {
}
// ### end stuff to remove when BIC changes are allowed again
void KDoubleNumInput::init(double value, double lower, double upper,
double step, int precision )
{
// ### init no longer used members:
edit = 0;
m_range = true;
m_value = 0.0;
m_precision = 2;
// ### end
d = new KDoubleNumInputPrivate( value );
d->spin = new KDoubleSpinBox( lower, upper, step, value, precision,
this, "KDoubleNumInput::d->spin" );
setFocusProxy(d->spin);
connect( d->spin, SIGNAL(valueChanged(double)),
this, SIGNAL(valueChanged(double)) );
connect( this, SIGNAL(valueChanged(double)),
this, SLOT(slotEmitRelativeValueChanged(double)) );
updateLegacyMembers();
layout(true);
}
void KDoubleNumInput::updateLegacyMembers() {
// ### update legacy members that are either not private or for
// which an inlined getter exists:
m_lower = minValue();
m_upper = maxValue();
m_step = d->spin->lineStep();
m_specialvalue = specialValueText();
}
double KDoubleNumInput::mapSliderToSpin( int val ) const
{
// map [slidemin,slidemax] to [spinmin,spinmax]
double spinmin = d->spin->minValue();
double spinmax = d->spin->maxValue();
double slidemin = m_slider->minValue(); // cast int to double to avoid
double slidemax = m_slider->maxValue(); // overflow in rel denominator
double rel = ( double(val) - slidemin ) / ( slidemax - slidemin );
return spinmin + rel * ( spinmax - spinmin );
}
void KDoubleNumInput::sliderMoved(int val)
{
d->spin->setValue( mapSliderToSpin( val ) );
}
void KDoubleNumInput::slotEmitRelativeValueChanged( double value )
{
if ( !d->referencePoint ) return;
emit relativeValueChanged( value / d->referencePoint );
}
QSize KDoubleNumInput::minimumSizeHint() const
{
constPolish();
int w;
int h;
h = 2 + QMAX(m_sizeEdit.height(), m_sizeSlider.height());
// if in extra row, then count it here
if(m_label && (m_alignment & (AlignBottom|AlignTop)))
h += 4 + m_sizeLabel.height();
else
// label is in the same row as the other widgets
h = QMAX(h, m_sizeLabel.height() + 2);
w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
w += m_colw1 + m_colw2;
if(m_alignment & (AlignTop|AlignBottom))
w = QMAX(w, m_sizeLabel.width() + 4);
return QSize(w, h);
}
void KDoubleNumInput::resizeEvent(QResizeEvent* e)
{
int w = m_colw1;
int h = 0;
if(m_label && (m_alignment & AlignTop)) {
m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
h += m_sizeLabel.height() + 4;
}
if(m_label && (m_alignment & AlignVCenter))
m_label->setGeometry(0, 0, w, m_sizeEdit.height());
if (qApp->reverseLayout())
{
d->spin->setGeometry(w, h, m_slider ? m_colw2
: e->size().width() - w, m_sizeEdit.height());
w += m_colw2 + KDialog::spacingHint();
if(m_slider)
m_slider->setGeometry(w, h, e->size().width() - w, m_sizeEdit.height());
}
else if(m_slider) {
m_slider->setGeometry(w, h, e->size().width() -
(m_colw1 + m_colw2 + KDialog::spacingHint()),
m_sizeEdit.height());
d->spin->setGeometry(w + m_slider->width() + KDialog::spacingHint(), h,
m_colw2, m_sizeEdit.height());
}
else {
d->spin->setGeometry(w, h, e->size().width() - w, m_sizeEdit.height());
}
h += m_sizeEdit.height() + 2;
if(m_label && (m_alignment & AlignBottom))
m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
}
void KDoubleNumInput::doLayout()
{
m_sizeEdit = d->spin->sizeHint();
m_colw2 = m_sizeEdit.width();
}
void KDoubleNumInput::setValue(double val)
{
d->spin->setValue( val );
}
void KDoubleNumInput::setRelativeValue( double r )
{
if ( !d->referencePoint ) return;
++d->blockRelative;
setValue( r * d->referencePoint );
--d->blockRelative;
}
void KDoubleNumInput::setReferencePoint( double ref )
{
// clip to valid range:
ref = kMin( maxValue(), kMax( minValue(), ref ) );
d->referencePoint = ref;
}
void KDoubleNumInput::setRange(double lower, double upper, double step,
bool slider)
{
if( m_slider ) {
// don't update the slider to avoid an endless recursion
QSpinBox * spin = d->spin;
disconnect(spin, SIGNAL(valueChanged(int)),
m_slider, SLOT(setValue(int)) );
}
d->spin->setRange( lower, upper, step, d->spin->precision() );
if(slider) {
// upcast to base type to get the min/maxValue in int form:
QSpinBox * spin = d->spin;
int slmax = spin->maxValue();
int slmin = spin->minValue();
int slvalue = spin->value();
int slstep = spin->lineStep();
if (m_slider) {
m_slider->setRange(slmin, slmax);
m_slider->setLineStep(slstep);
m_slider->setValue(slvalue);
} else {
m_slider = new QSlider(slmin, slmax, slstep, slvalue,
QSlider::Horizontal, this);
m_slider->setTickmarks(QSlider::Below);
// feedback line: when one moves, the other moves, too:
connect(m_slider, SIGNAL(valueChanged(int)),
SLOT(sliderMoved(int)) );
}
connect(spin, SIGNAL(valueChanged(int)),
m_slider, SLOT(setValue(int)) );
// calculate ( slmax - slmin ) / 10 without overflowing ints:
int major = calcDiffByTen( slmax, slmin );
if ( !major ) major = slstep; // ### needed?
m_slider->setTickInterval(major);
} else {
delete m_slider;
m_slider = 0;
}
setReferencePoint( referencePoint() );
layout(true);
updateLegacyMembers();
}
void KDoubleNumInput::setMinValue(double min)
{
setRange(min, maxValue(), d->spin->lineStep(), m_slider);
}
double KDoubleNumInput::minValue() const
{
return d->spin->minValue();
}
void KDoubleNumInput::setMaxValue(double max)
{
setRange(minValue(), max, d->spin->lineStep(), m_slider);
}
double KDoubleNumInput::maxValue() const
{
return d->spin->maxValue();
}
double KDoubleNumInput::value() const
{
return d->spin->value();
}
double KDoubleNumInput::relativeValue() const
{
if ( !d->referencePoint ) return 0;
return value() / d->referencePoint;
}
double KDoubleNumInput::referencePoint() const
{
return d->referencePoint;
}
QString KDoubleNumInput::suffix() const
{
return d->spin->suffix();
}
QString KDoubleNumInput::prefix() const
{
return d->spin->prefix();
}
void KDoubleNumInput::setSuffix(const QString &suffix)
{
d->spin->setSuffix( suffix );
layout(true);
}
void KDoubleNumInput::setPrefix(const QString &prefix)
{
d->spin->setPrefix( prefix );
layout(true);
}
void KDoubleNumInput::setPrecision(int precision)
{
d->spin->setPrecision( precision );
layout(true);
}
int KDoubleNumInput::precision() const
{
return d->spin->precision();
}
void KDoubleNumInput::setSpecialValueText(const QString& text)
{
d->spin->setSpecialValueText( text );
layout(true);
updateLegacyMembers();
}
void KDoubleNumInput::setLabel(const QString & label, int a)
{
KNumInput::setLabel(label, a);
if(m_label)
m_label->setBuddy(d->spin);
}
// ----------------------------------------------------------------------------
class KDoubleSpinBoxValidator : public KDoubleValidator
{
public:
KDoubleSpinBoxValidator( double bottom, double top, int decimals, KDoubleSpinBox* sb, const char *name )
: KDoubleValidator( bottom, top, decimals, sb, name ), spinBox( sb ) { }
virtual State validate( QString& str, int& pos ) const;
private:
KDoubleSpinBox *spinBox;
};
QValidator::State KDoubleSpinBoxValidator::validate( QString& str, int& pos ) const
{
QString pref = spinBox->prefix();
QString suff = spinBox->suffix();
QString suffStriped = suff.stripWhiteSpace();
uint overhead = pref.length() + suff.length();
State state = Invalid;
if ( overhead == 0 ) {
state = KDoubleValidator::validate( str, pos );
} else {
bool stripedVersion = false;
if ( str.length() >= overhead && str.startsWith(pref)
&& (str.endsWith(suff)
|| (stripedVersion = str.endsWith(suffStriped))) ) {
if ( stripedVersion )
overhead = pref.length() + suffStriped.length();
QString core = str.mid( pref.length(), str.length() - overhead );
int corePos = pos - pref.length();
state = KDoubleValidator::validate( core, corePos );
pos = corePos + pref.length();
str.replace( pref.length(), str.length() - overhead, core );
} else {
state = KDoubleValidator::validate( str, pos );
if ( state == Invalid ) {
// stripWhiteSpace(), cf. QSpinBox::interpretText()
QString special = spinBox->specialValueText().stripWhiteSpace();
QString candidate = str.stripWhiteSpace();
if ( special.startsWith(candidate) ) {
if ( candidate.length() == special.length() ) {
state = Acceptable;
} else {
state = Intermediate;
}
}
}
}
}
return state;
}
// We use a kind of fixed-point arithmetic to represent the range of
// doubles [mLower,mUpper] in steps of 10^(-mPrecision). Thus, the
// following relations hold:
//
// 1. factor = 10^mPrecision
// 2. basicStep = 1/factor = 10^(-mPrecision);
// 3. lowerInt = lower * factor;
// 4. upperInt = upper * factor;
// 5. lower = lowerInt * basicStep;
// 6. upper = upperInt * basicStep;
class KDoubleSpinBox::Private {
public:
Private( int precision=1 )
: mPrecision( precision ),
mValidator( 0 )
{
}
int factor() const {
int f = 1;
for ( int i = 0 ; i < mPrecision ; ++i ) f *= 10;
return f;
}
double basicStep() const {
return 1.0/double(factor());
}
int mapToInt( double value, bool * ok ) const {
assert( ok );
const double f = factor();
if ( value > double(INT_MAX) / f ) {
kdWarning() << "KDoubleSpinBox: can't represent value " << value
<< "in terms of fixed-point numbers with precision "
<< mPrecision << endl;
*ok = false;
return INT_MAX;
} else if ( value < double(INT_MIN) / f ) {
kdWarning() << "KDoubleSpinBox: can't represent value " << value
<< "in terms of fixed-point numbers with precision "
<< mPrecision << endl;
*ok = false;
return INT_MIN;
} else {
*ok = true;
return int( value * f + ( value < 0 ? -0.5 : 0.5 ) );
}
}
double mapToDouble( int value ) const {
return double(value) * basicStep();
}
int mPrecision;
KDoubleSpinBoxValidator * mValidator;
};
KDoubleSpinBox::KDoubleSpinBox( QWidget * parent, const char * name )
: QSpinBox( parent, name )
{
editor()->setAlignment( Qt::AlignRight );
d = new Private();
updateValidator();
connect( this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)) );
}
KDoubleSpinBox::KDoubleSpinBox( double lower, double upper, double step,
double value, int precision,
QWidget * parent, const char * name )
: QSpinBox( parent, name )
{
editor()->setAlignment( Qt::AlignRight );
d = new Private();
setRange( lower, upper, step, precision );
setValue( value );
connect( this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)) );
}
KDoubleSpinBox::~KDoubleSpinBox() {
delete d; d = 0;
}
bool KDoubleSpinBox::acceptLocalizedNumbers() const {
if ( !d->mValidator ) return true; // we'll set one that does;
// can't do it now, since we're const
return d->mValidator->acceptLocalizedNumbers();
}
void KDoubleSpinBox::setAcceptLocalizedNumbers( bool accept ) {
if ( !d->mValidator ) updateValidator();
d->mValidator->setAcceptLocalizedNumbers( accept );
}
void KDoubleSpinBox::setRange( double lower, double upper, double step,
int precision ) {
lower = kMin(upper, lower);
upper = kMax(upper, lower);
setPrecision( precision, true ); // disable bounds checking, since
setMinValue( lower ); // it's done in set{Min,Max}Value
setMaxValue( upper ); // anyway and we want lower, upper
setLineStep( step ); // and step to have the right precision
}
int KDoubleSpinBox::precision() const {
return d->mPrecision;
}
void KDoubleSpinBox::setPrecision( int precision ) {
setPrecision( precision, false );
}
void KDoubleSpinBox::setPrecision( int precision, bool force ) {
if ( precision < 1 ) return;
if ( !force ) {
int maxPrec = maxPrecision();
if ( precision > maxPrec )
precision = maxPrec;
}
d->mPrecision = precision;
updateValidator();
}
int KDoubleSpinBox::maxPrecision() const {
// INT_MAX must be > maxAbsValue * 10^precision
// ==> 10^precision < INT_MAX / maxAbsValue
// ==> precision < log10 ( INT_MAX / maxAbsValue )
// ==> maxPrecision = floor( log10 ( INT_MAX / maxAbsValue ) );
double maxAbsValue = kMax( fabs(minValue()), fabs(maxValue()) );
if ( maxAbsValue == 0 ) return 6; // return arbitrary value to avoid dbz...
return int( floor( log10( double(INT_MAX) / maxAbsValue ) ) );
}
double KDoubleSpinBox::value() const {
return d->mapToDouble( base::value() );
}
void KDoubleSpinBox::setValue( double value ) {
if ( value == this->value() ) return;
if ( value < minValue() )
base::setValue( base::minValue() );
else if ( value > maxValue() )
base::setValue( base::maxValue() );
else {
bool ok = false;
base::setValue( d->mapToInt( value, &ok ) );
assert( ok );
}
}
double KDoubleSpinBox::minValue() const {
return d->mapToDouble( base::minValue() );
}
void KDoubleSpinBox::setMinValue( double value ) {
bool ok = false;
int min = d->mapToInt( value, &ok );
if ( !ok ) return;
base::setMinValue( min );
updateValidator();
}
double KDoubleSpinBox::maxValue() const {
return d->mapToDouble( base::maxValue() );
}
void KDoubleSpinBox::setMaxValue( double value ) {
bool ok = false;
int max = d->mapToInt( value, &ok );
if ( !ok ) return;
base::setMaxValue( max );
updateValidator();
}
double KDoubleSpinBox::lineStep() const {
return d->mapToDouble( base::lineStep() );
}
void KDoubleSpinBox::setLineStep( double step ) {
bool ok = false;
if ( step > maxValue() - minValue() )
base::setLineStep( 1 );
else
base::setLineStep( kMax( d->mapToInt( step, &ok ), 1 ) );
}
QString KDoubleSpinBox::mapValueToText( int value ) {
if ( acceptLocalizedNumbers() )
return KGlobal::locale()
->formatNumber( d->mapToDouble( value ), d->mPrecision );
else
return QString().setNum( d->mapToDouble( value ), 'f', d->mPrecision );
}
int KDoubleSpinBox::mapTextToValue( bool * ok ) {
double value;
if ( acceptLocalizedNumbers() )
value = KGlobal::locale()->readNumber( cleanText(), ok );
else
value = cleanText().toDouble( ok );
if ( !*ok ) return 0;
if ( value > maxValue() )
value = maxValue();
else if ( value < minValue() )
value = minValue();
return d->mapToInt( value, ok );
}
void KDoubleSpinBox::setValidator( const QValidator * ) {
// silently discard the new validator. We don't want another one ;-)
}
void KDoubleSpinBox::slotValueChanged( int value ) {
emit valueChanged( d->mapToDouble( value ) );
}
void KDoubleSpinBox::updateValidator() {
if ( !d->mValidator ) {
d->mValidator = new KDoubleSpinBoxValidator( minValue(), maxValue(), precision(),
this, "d->mValidator" );
base::setValidator( d->mValidator );
} else
d->mValidator->setRange( minValue(), maxValue(), precision() );
}
void KNumInput::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
void KIntNumInput::virtual_hook( int id, void* data )
{ KNumInput::virtual_hook( id, data ); }
void KDoubleNumInput::virtual_hook( int id, void* data )
{ KNumInput::virtual_hook( id, data ); }
void KIntSpinBox::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
void KDoubleSpinBox::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
#include "knuminput.moc"
KIntNumInput::relativeValue
double relativeValue() const
KDoubleNumInput::setPrefix
void setPrefix(const QString &prefix)
Sets the prefix to be displayed to prefix.
Definition: knuminput.cpp:846
KDoubleNumInput::setPrecision
void setPrecision(int precision)
Specifies the number of digits to use.
Definition: knuminput.cpp:853
KDoubleSpinBox::setPrecision
void setPrecision(int precision)
Equivalent to setPrecision( precision, false ); Needed since Qt's moc doesn't ignore trailing paramet...
Definition: knuminput.cpp:1046
KDoubleNumInput::specialValueText
QString specialValueText() const
Definition: knuminput.h:547
KIntSpinBox::~KIntSpinBox
virtual ~KIntSpinBox()
Destructor.
Definition: knuminput.cpp:212
KGlobal::locale
static KLocale * locale()
KDoubleSpinBox::setRange
void setRange(double lower, double upper, double step=0.01, int precision=2)
Sets a new range for the spin box values.
Definition: knuminput.cpp:1032
KIntNumInput::relativeValueChanged
void relativeValueChanged(double)
Emitted whenever valueChanged is.
KNumInput::layout
void layout(bool deep)
Call this function whenever you change something in the geometry of your KNumInput child...
Definition: knuminput.cpp:128
KDoubleSpinBox::acceptLocalizedNumbers
bool acceptLocalizedNumbers() const
KIntNumInput::setSpecialValueText
void setSpecialValueText(const QString &text)
Sets the special value text.
Definition: knuminput.cpp:512
KDoubleNumInput::setMinValue
void setMinValue(double min)
Sets the minimum value.
Definition: knuminput.cpp:793
KNumInput::sizeHint
virtual QSize sizeHint() const
Returns a size which fits the contents of the control.
Definition: knuminput.cpp:190
KIntNumInput::prefix
QString prefix() const
KDoubleNumInput::referencePoint
double referencePoint() const
KDoubleNumInput::setSpecialValueText
void setSpecialValueText(const QString &text)
Sets the special value text.
Definition: knuminput.cpp:865
KDoubleNumInput::precision
int precision() const
KDoubleSpinBox
A spin box for fractional numbers.
Definition: knuminput.h:834
KDoubleSpinBox::minValue
double minValue() const
Definition: knuminput.cpp:1089
KIntNumInput::setRelativeValue
void setRelativeValue(double)
Sets the value in units of the referencePoint.
Definition: knuminput.cpp:495
KNumInput::sizePolicy
QSizePolicy sizePolicy() const
Specifies that this widget may stretch horizontally, but is fixed vertically (like QSpinBox itself)...
Definition: knuminput.cpp:185
KDoubleNumInput::setLabel
virtual void setLabel(const QString &label, int a=AlignLeft|AlignTop)
Sets the text and alignment of the main description label.
Definition: knuminput.cpp:873
klocale.h
KDoubleNumInput::maxValue
double maxValue() const
KDoubleSpinBox::setMinValue
void setMinValue(double value)
Sets the lower bound of the range to value, subject to the contraints that value is first rounded to ...
Definition: knuminput.cpp:1093
KDoubleSpinBox::precision
int precision() const
KNumInput
You need to inherit from this class if you want to implement K*NumInput for a different variable type...
Definition: knuminput.h:49
KDoubleNumInput::valueChanged
void valueChanged(double)
Emitted every time the value changes (by calling setValue() or by user interaction).
KDoubleNumInput::doLayout
virtual void doLayout()
You need to overwrite this method and implement your layout calculations there.
Definition: knuminput.cpp:720
KIntNumInput::setMaxValue
void setMaxValue(int max)
Sets the maximum value.
Definition: knuminput.cpp:376
KIntNumInput::maxValue
int maxValue() const
KIntNumInput::suffix
QString suffix() const
KLocale::readNumber
double readNumber(const QString &numStr, bool *ok=0) const
KIntNumInput::value
int value() const
KIntSpinBox::base
int base() const
KDialog::spacingHint
static int spacingHint()
Return the number of pixels you shall use between widgets inside a dialog according to the KDE standa...
Definition: kdialog.cpp:103
KDoubleSpinBox::value
double value() const
Definition: knuminput.cpp:1072
KDoubleNumInput::setSuffix
void setSuffix(const QString &suffix)
Sets the suffix to be displayed to suffix.
Definition: knuminput.cpp:839
kdWarning
kdbgstream kdWarning(int area=0)
KIntSpinBox::KIntSpinBox
KIntSpinBox(QWidget *parent=0, const char *name=0)
Constructor.
Definition: knuminput.cpp:204
KDoubleSpinBox::setValue
virtual void setValue(double value)
Sets the current value to value, subject to the constraints that value is first rounded to the curren...
Definition: knuminput.cpp:1076
KIntNumInput::referencePoint
int referencePoint() const
KIntValidator
QValidator for integers.
Definition: knumvalidator.h:44
KIntNumInput::setLabel
virtual void setLabel(const QString &label, int a=AlignLeft|AlignTop)
Sets the text and alignment of the main description label.
Definition: knuminput.cpp:523
KDoubleNumInput::relativeValueChanged
void relativeValueChanged(double)
This is an overloaded member function, provided for convenience.
KDoubleValidator
A locale-aware QDoubleValidator.
Definition: knumvalidator.h:181
KDoubleSpinBox::setValidator
void setValidator(const QValidator *)
Overridden to ignore any setValidator() calls.
Definition: knuminput.cpp:1148
KDoubleNumInput::setRelativeValue
void setRelativeValue(double)
Sets the value in units of referencePoint.
Definition: knuminput.cpp:731
KIntNumInput::setRange
void setRange(int min, int max, int step=1, bool slider=true)
Definition: knuminput.cpp:327
KIntNumInput::setSuffix
void setSuffix(const QString &suffix)
Sets the suffix to suffix.
Definition: knuminput.cpp:386
KIntNumInput::specialValueText
QString specialValueText() const
KDoubleSpinBox::KDoubleSpinBox
KDoubleSpinBox(QWidget *parent=0, const char *name=0)
Constructs a KDoubleSpinBox with parent parent and default values for range and value (whatever QRang...
Definition: knuminput.cpp:996
KDoubleSpinBox::setAcceptLocalizedNumbers
virtual void setAcceptLocalizedNumbers(bool accept)
Sets whether to use and accept localized numbers as returned by KLocale::formatNumber() ...
Definition: knuminput.cpp:1027
KDoubleValidator::validate
virtual QValidator::State validate(QString &input, int &pos) const
Overloaded for internal reasons.
Definition: knumvalidator.cpp:326
KDoubleNumInput::prefix
QString prefix() const
KDoubleNumInput::setReferencePoint
void setReferencePoint(double ref)
Sets the reference Point to ref.
Definition: knuminput.cpp:739
KIntSpinBox
A QSpinBox with support for arbitrary base numbers.
Definition: knuminput.h:704
KIntSpinBox::mapTextToValue
virtual int mapTextToValue(bool *)
Overloaded the method in QSpinBox to make use of the base given in the constructor.
Definition: knuminput.cpp:241
KDoubleNumInput::~KDoubleNumInput
virtual ~KDoubleNumInput()
destructor
Definition: knuminput.cpp:580
KDoubleNumInput::setValue
void setValue(double)
Sets the value of the control.
Definition: knuminput.cpp:726
KIntNumInput::setMinValue
void setMinValue(int min)
Sets the minimum value.
Definition: knuminput.cpp:366
KIntSpinBox::setBase
void setBase(int base)
Sets the base in which the numbers in the spin box are represented.
Definition: knuminput.cpp:225
KDoubleNumInput::KDoubleNumInput
KDoubleNumInput(QWidget *parent=0, const char *name=0)
Constructs an input control for double values with initial value 0.00.
Definition: knuminput.cpp:544
KIntSpinBox::setEditFocus
void setEditFocus(bool mark)
sets focus and optionally marks all text
Definition: knuminput.cpp:246
KDoubleNumInput::setMaxValue
void setMaxValue(double max)
Sets the maximum value.
Definition: knuminput.cpp:803
KIntNumInput::minValue
int minValue() const
KIntNumInput::valueChanged
void valueChanged(int)
Emitted every time the value changes (by calling setValue() or by user interaction).
KDoubleSpinBox::maxValue
double maxValue() const
Definition: knuminput.cpp:1102
KIntNumInput::doLayout
virtual void doLayout()
You need to overwrite this method and implement your layout calculations there.
Definition: knuminput.cpp:440
KDoubleNumInput::relativeValue
double relativeValue() const
KDoubleNumInput::setRange
void setRange(double min, double max, double step=1, bool slider=true)
Definition: knuminput.cpp:746
KIntNumInput::setPrefix
void setPrefix(const QString &prefix)
Sets the prefix to prefix.
Definition: knuminput.cpp:398
endl
kndbgstream & endl(kndbgstream &s)
KDoubleNumInput::value
double value() const
KLocale::formatNumber
QString formatNumber(double num, int precision=-1) const
KNumInput::label
QString label() const
KIntNumInput::KIntNumInput
KIntNumInput(QWidget *parent=0, const char *name=0)
Constructs an input control for integer values with base 10 and initial value 0.
Definition: knuminput.cpp:273
KIntSpinBox::mapValueToText
virtual QString mapValueToText(int)
Overloaded the method in QSpinBox to make use of the base given in the constructor.
Definition: knuminput.cpp:236
KNumInput::doLayout
virtual void doLayout()=0
You need to overwrite this method and implement your layout calculations there.
KIntNumInput::~KIntNumInput
virtual ~KIntNumInput()
Destructor.
Definition: knuminput.cpp:484
KDoubleNumInput::suffix
QString suffix() const
KDoubleSpinBox::lineStep
double lineStep() const
Definition: knuminput.cpp:1114
KDoubleNumInput::minValue
double minValue() const
KIntNumInput::setEditFocus
void setEditFocus(bool mark=true)
sets focus to the edit widget and marks all text in if mark == true
Definition: knuminput.cpp:410
KNumInput::setSteps
void setSteps(int minor, int major)
Sets the spacing of tickmarks for the slider.
Definition: knuminput.cpp:195
KDoubleSpinBox::setLineStep
void setLineStep(double step)
Sets the step size for clicking the up/down buttons to step, subject to the constraints that step is ...
Definition: knuminput.cpp:1118
KIntNumInput::minimumSizeHint
virtual QSize minimumSizeHint() const
This method returns the minimum size necessary to display the control.
Definition: knuminput.cpp:415
KIntNumInput::setReferencePoint
void setReferencePoint(int)
Sets the reference point for relativeValue.
Definition: knuminput.cpp:304
KDoubleSpinBox::valueChanged
void valueChanged(double value)
Emitted whenever QSpinBox::valueChanged( int ) is emitted.
KIntNumInput::setValue
void setValue(int)
Sets the value of the control.
Definition: knuminput.cpp:489
KNumInput::setLabel
virtual void setLabel(const QString &label, int a=AlignLeft|AlignTop)
Sets the text and alignment of the main description label.
Definition: knuminput.cpp:101
KDoubleSpinBox::setMaxValue
void setMaxValue(double value)
Sets the upper bound of the range to value, subject to the contraints that value is first rounded to ...
Definition: knuminput.cpp:1106
KNumInput::KNumInput
KNumInput(QWidget *parent=0, const char *name=0)
Default constructor.
Definition: knuminput.cpp:62

KDE Home | KDE Accessibility Home | Description of Access Keys