# kdeui Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# knuminput.cpp

    00001 // -*- c-basic-offset: 4 -*-
    00002 /*
    00003  * knuminput.cpp
    00004  *
    00005  * Initial implementation:
    00006  *     Copyright (c) 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
    00007  * Rewritten and maintained by:
    00008  *     Copyright (c) 2000 Dirk A. Mueller <mueller@kde.org>
    00009  * KDoubleSpinBox:
    00010  *     Copyright (c) 2002 Marc Mutz <mutz@kde.org>
    00011  *
    00012  *  Requires the Qt widget libraries, available at no cost at
    00013  *  http://www.troll.no/
    00014  *
    00015  *  This library is free software; you can redistribute it and/or
    00016  *  modify it under the terms of the GNU Library General Public
    00017  *  License as published by the Free Software Foundation; either
    00018  *  version 2 of the License, or (at your option) any later version.
    00019  *
    00020  *  This library is distributed in the hope that it will be useful,
    00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00023  *  Library General Public License for more details.
    00024  *
    00025  *  You should have received a copy of the GNU Library General Public License
    00026  *  along with this library; see the file COPYING.LIB.  If not, write to
    00027  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00028  *  Boston, MA 02111-1307, USA.
    00029  */
    00030
    00031 #include <config.h>
    00032 #ifdef HAVE_LIMITS_H
    00033 #include <limits.h>
    00034 #endif
    00035 #include <assert.h>
    00036 #include <math.h>
    00037 #include <algorithm>
    00038
    00039 #include <qlabel.h>
    00040 #include <qlineedit.h>
    00041 #include <qsize.h>
    00042 #include <qslider.h>
    00043 #include <qspinbox.h>
    00044 #include <qstyle.h>
    00045
    00046 #include <kglobal.h>
    00047 #include <klocale.h>
    00048 #include <kdebug.h>
    00049
    00050 #include "knumvalidator.h"
    00051 #include "knuminput.h"
    00052
    00053 static inline int calcDiffByTen( int x, int y ) {
    00054     // calculate ( x - y ) / 10 without overflowing ints:
    00055     return ( x / 10 ) - ( y / 10 )  +  ( x % 10 - y % 10 ) / 10;
    00056 }
    00057
    00058 // ----------------------------------------------------------------------------
    00059
    00060 KNumInput::KNumInput(QWidget* parent, const char* name)
    00061     : QWidget(parent, name)
    00062 {
    00063     init();
    00064 }
    00065
    00066 KNumInput::KNumInput(KNumInput* below, QWidget* parent, const char* name)
    00067     : QWidget(parent, name)
    00068 {
    00069     init();
    00070
    00071     if(below) {
    00072         m_next = below->m_next;
    00073         m_prev = below;
    00074         below->m_next = this;
    00075         if(m_next)
    00076             m_next->m_prev = this;
    00077     }
    00078 }
    00079
    00080 void KNumInput::init()
    00081 {
    00082     m_prev = m_next = 0;
    00083     m_colw1 = m_colw2 = 0;
    00084
    00085     m_label = 0;
    00086     m_slider = 0;
    00087     m_alignment = 0;
    00088 }
    00089
    00090 KNumInput::~KNumInput()
    00091 {
    00092     if(m_prev)
    00093         m_prev->m_next = m_next;
    00094
    00095     if(m_next)
    00096         m_next->m_prev = m_prev;
    00097 }
    00098
    00099 void KNumInput::setLabel(const QString & label, int a)
    00100 {
    00101     if(label.isEmpty()) {
    00102         delete m_label;
    00103         m_label = 0;
    00104         m_alignment = 0;
    00105     }
    00106     else {
    00107         if (m_label) m_label->setText(label);
    00108         else m_label = new QLabel(label, this, "KNumInput::QLabel");
    00109         m_label->setAlignment((a & (~(AlignTop|AlignBottom|AlignVCenter)))
    00110                               | AlignVCenter);
    00111         // if no vertical alignment set, use Top alignment
    00112         if(!(a & (AlignTop|AlignBottom|AlignVCenter)))
    00113            a |= AlignTop;
    00114         m_alignment = a;
    00115     }
    00116
    00117     layout(true);
    00118 }
    00119
    00120 QString KNumInput::label() const
    00121 {
    00122     if (m_label) return m_label->text();
    00123     return QString::null;
    00124 }
    00125
    00126 void KNumInput::layout(bool deep)
    00127 {
    00128     int w1 = m_colw1;
    00129     int w2 = m_colw2;
    00130
    00131     // label sizeHint
    00132     m_sizeLabel = (m_label ? m_label->sizeHint() : QSize(0,0));
    00133
    00134     if(m_label && (m_alignment & AlignVCenter))
    00135         m_colw1 = m_sizeLabel.width() + 4;
    00136     else
    00137         m_colw1 = 0;
    00138
    00139     // slider sizeHint
    00140     m_sizeSlider = (m_slider ? m_slider->sizeHint() : QSize(0, 0));
    00141
    00142     doLayout();
    00143
    00144     if(!deep) {
    00145         m_colw1 = w1;
    00146         m_colw2 = w2;
    00147         return;
    00148     }
    00149
    00150     KNumInput* p = this;
    00151     while(p) {
    00152         p->doLayout();
    00153         w1 = QMAX(w1, p->m_colw1);
    00154         w2 = QMAX(w2, p->m_colw2);
    00155         p = p->m_prev;
    00156     }
    00157
    00158     p = m_next;
    00159     while(p) {
    00160         p->doLayout();
    00161         w1 = QMAX(w1, p->m_colw1);
    00162         w2 = QMAX(w2, p->m_colw2);
    00163         p = p->m_next;
    00164     }
    00165
    00166     p = this;
    00167     while(p) {
    00168         p->m_colw1 = w1;
    00169         p->m_colw2 = w2;
    00170         p = p->m_prev;
    00171     }
    00172
    00173     p = m_next;
    00174     while(p) {
    00175         p->m_colw1 = w1;
    00176         p->m_colw2 = w2;
    00177         p = p->m_next;
    00178     }
    00179
    00180 //    kdDebug() << "w1 " << w1 << " w2 " << w2 << endl;
    00181 }
    00182
    00183 QSizePolicy KNumInput::sizePolicy() const
    00184 {
    00185     return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
    00186 }
    00187
    00188 QSize KNumInput::sizeHint() const
    00189 {
    00190     return minimumSizeHint();
    00191 }
    00192
    00193 void KNumInput::setSteps(int minor, int major)
    00194 {
    00195     if(m_slider)
    00196         m_slider->setSteps( minor, major );
    00197 }
    00198
    00199
    00200 // ----------------------------------------------------------------------------
    00201
    00202 KIntSpinBox::KIntSpinBox(QWidget *parent, const char *name)
    00203     : QSpinBox(0, 99, 1, parent, name)
    00204 {
    00205     editor()->setAlignment(AlignRight);
    00206     val_base = 10;
    00207     setValue(0);
    00208 }
    00209
    00210 KIntSpinBox::~KIntSpinBox()
    00211 {
    00212 }
    00213
    00214 KIntSpinBox::KIntSpinBox(int lower, int upper, int step, int value, int base,
    00215                          QWidget* parent, const char* name)
    00216     : QSpinBox(lower, upper, step, parent, name)
    00217 {
    00218     editor()->setAlignment(AlignRight);
    00219     val_base = base;
    00220     setValue(value);
    00221 }
    00222
    00223 void KIntSpinBox::setBase(int base)
    00224 {
    00225     val_base = base;
    00226 }
    00227
    00228
    00229 int KIntSpinBox::base() const
    00230 {
    00231     return val_base;
    00232 }
    00233
    00234 QString KIntSpinBox::mapValueToText(int v)
    00235 {
    00236     return QString::number(v, val_base);
    00237 }
    00238
    00239 int KIntSpinBox::mapTextToValue(bool* ok)
    00240 {
    00241     return cleanText().toInt(ok, val_base);
    00242 }
    00243
    00244 void KIntSpinBox::setEditFocus(bool mark)
    00245 {
    00246     editor()->setFocus();
    00247     if(mark)
    00248         editor()->selectAll();
    00249 }
    00250
    00251
    00252 // ----------------------------------------------------------------------------
    00253
    00254 class KIntNumInput::KIntNumInputPrivate {
    00255 public:
    00256     int referencePoint;
    00257     short blockRelative;
    00258     KIntNumInputPrivate( int r )
    00259         : referencePoint( r ),
    00260           blockRelative( 0 ) {}
    00261 };
    00262
    00263
    00264 KIntNumInput::KIntNumInput(KNumInput* below, int val, QWidget* parent,
    00265                            int _base, const char* name)
    00266     : KNumInput(below, parent, name)
    00267 {
    00268     init(val, _base);
    00269 }
    00270
    00271 KIntNumInput::KIntNumInput(QWidget *parent, const char *name)
    00272     : KNumInput(parent, name)
    00273 {
    00274     init(0, 10);
    00275 }
    00276
    00277 KIntNumInput::KIntNumInput(int val, QWidget *parent, int _base, const char *name)
    00278     : KNumInput(parent, name)
    00279 {
    00280     init(val, _base);
    00281
    00282 }
    00283
    00284 void KIntNumInput::init(int val, int _base)
    00285 {
    00286     d = new KIntNumInputPrivate( val );
    00287     m_spin = new KIntSpinBox(INT_MIN, INT_MAX, 1, val, _base, this, "KIntNumInput::KIntSpinBox");
    00288     m_spin->setValidator(new KIntValidator(this, _base, "KNumInput::KIntValidtr"));
    00289     connect(m_spin, SIGNAL(valueChanged(int)), SLOT(spinValueChanged(int)));
    00290     connect(this, SIGNAL(valueChanged(int)),
    00291             SLOT(slotEmitRelativeValueChanged(int)));
    00292
    00293     setFocusProxy(m_spin);
    00294     layout(true);
    00295 }
    00296
    00297 void KIntNumInput::setReferencePoint( int ref ) {
    00298     // clip to valid range:
    00299     ref = kMin( maxValue(), kMax( minValue(),  ref ) );
    00300     d->referencePoint = ref;
    00301 }
    00302
    00303 int KIntNumInput::referencePoint() const {
    00304     return d->referencePoint;
    00305 }
    00306
    00307 void KIntNumInput::spinValueChanged(int val)
    00308 {
    00309     if(m_slider)
    00310         m_slider->setValue(val);
    00311
    00312     emit valueChanged(val);
    00313 }
    00314
    00315 void KIntNumInput::slotEmitRelativeValueChanged( int value ) {
    00316     if ( d->blockRelative || !d->referencePoint ) return;
    00317     emit relativeValueChanged( double( value ) / double( d->referencePoint ) );
    00318 }
    00319
    00320 void KIntNumInput::setRange(int lower, int upper, int step, bool slider)
    00321 {
    00322     upper = kMax(upper, lower);
    00323     lower = kMin(upper, lower);
    00324     m_spin->setMinValue(lower);
    00325     m_spin->setMaxValue(upper);
    00326     m_spin->setLineStep(step);
    00327
    00328     step = m_spin->lineStep(); // maybe QRangeControl didn't like out lineStep?
    00329
    00330     if(slider) {
    00331         if (m_slider)
    00332             m_slider->setRange(lower, upper);
    00333         else {
    00334             m_slider = new QSlider(lower, upper, step, m_spin->value(),
    00335                                    QSlider::Horizontal, this);
    00336             m_slider->setTickmarks(QSlider::Below);
    00337             connect(m_slider, SIGNAL(valueChanged(int)),
    00338                     m_spin, SLOT(setValue(int)));
    00339         }
    00340
    00341         // calculate (upper-lower)/10 without overflowing int's:
    00342         int major = calcDiffByTen( upper, lower );
    00343         if ( major==0 ) major = step; // #### workaround Qt bug in 2.1-beta4
    00344
    00345         m_slider->setSteps(step, major);
    00346         m_slider->setTickInterval(major);
    00347     }
    00348     else {
    00349         delete m_slider;
    00350         m_slider = 0;
    00351     }
    00352
    00353     // check that reference point is still inside valid range:
    00354     setReferencePoint( referencePoint() );
    00355
    00356     layout(true);
    00357 }
    00358
    00359 void KIntNumInput::setMinValue(int min)
    00360 {
    00361     setRange(min, m_spin->maxValue(), m_spin->lineStep(), m_slider);
    00362 }
    00363
    00364 int KIntNumInput::minValue() const
    00365 {
    00366     return m_spin->minValue();
    00367 }
    00368
    00369 void KIntNumInput::setMaxValue(int max)
    00370 {
    00371     setRange(m_spin->minValue(), max, m_spin->lineStep(), m_slider);
    00372 }
    00373
    00374 int KIntNumInput::maxValue() const
    00375 {
    00376     return m_spin->maxValue();
    00377 }
    00378
    00379 void KIntNumInput::setSuffix(const QString &suffix)
    00380 {
    00381     m_spin->setSuffix(suffix);
    00382
    00383     layout(true);
    00384 }
    00385
    00386 QString KIntNumInput::suffix() const
    00387 {
    00388     return m_spin->suffix();
    00389 }
    00390
    00391 void KIntNumInput::setPrefix(const QString &prefix)
    00392 {
    00393     m_spin->setPrefix(prefix);
    00394
    00395     layout(true);
    00396 }
    00397
    00398 QString KIntNumInput::prefix() const
    00399 {
    00400     return m_spin->prefix();
    00401 }
    00402
    00403 void KIntNumInput::setEditFocus(bool mark)
    00404 {
    00405     m_spin->setEditFocus(mark);
    00406 }
    00407
    00408 QSize KIntNumInput::minimumSizeHint() const
    00409 {
    00410     constPolish();
    00411
    00412     int w;
    00413     int h;
    00414
    00415     h = 2 + QMAX(m_sizeSpin.height(), m_sizeSlider.height());
    00416
    00417     // if in extra row, then count it here
    00418     if(m_label && (m_alignment & (AlignBottom|AlignTop)))
    00419         h += 4 + m_sizeLabel.height();
    00420     else
    00421         // label is in the same row as the other widgets
    00422         h = QMAX(h, m_sizeLabel.height() + 2);
    00423
    00424     w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
    00425     w += m_colw1 + m_colw2;
    00426
    00427     if(m_alignment & (AlignTop|AlignBottom))
    00428         w = QMAX(w, m_sizeLabel.width() + 4);
    00429
    00430     return QSize(w, h);
    00431 }
    00432
    00433 void KIntNumInput::doLayout()
    00434 {
    00435     m_sizeSpin = m_spin->sizeHint();
    00436     m_colw2 = m_sizeSpin.width();
    00437
    00438     if (m_label)
    00439         m_label->setBuddy(m_spin);
    00440 }
    00441
    00442 void KIntNumInput::resizeEvent(QResizeEvent* e)
    00443 {
    00444     int w = m_colw1;
    00445     int h = 0;
    00446
    00447     if(m_label && (m_alignment & AlignTop)) {
    00448         m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
    00449         h += m_sizeLabel.height() + 4;
    00450     }
    00451
    00452     if(m_label && (m_alignment & AlignVCenter))
    00453         m_label->setGeometry(0, 0, w, m_sizeSpin.height());
    00454
    00455     m_spin->setGeometry(w, h, m_slider ? m_colw2 : QMAX(m_colw2, e->size().width() - w), m_sizeSpin.height());
    00456     w += m_colw2 + 8;
    00457
    00458     if(m_slider)
    00459         m_slider->setGeometry(w, h, e->size().width() - w, m_sizeSpin.height());
    00460
    00461     h += m_sizeSpin.height() + 2;
    00462
    00463     if(m_label && (m_alignment & AlignBottom))
    00464         m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
    00465 }
    00466
    00467 KIntNumInput::~KIntNumInput()
    00468 {
    00469         delete d;
    00470 }
    00471
    00472 void KIntNumInput::setValue(int val)
    00473 {
    00474     m_spin->setValue(val);
    00475     // slider value is changed by spinValueChanged
    00476 }
    00477
    00478 void KIntNumInput::setRelativeValue( double r ) {
    00479     if ( !d->referencePoint ) return;
    00480     ++d->blockRelative;
    00481     setValue( int( d->referencePoint * r + 0.5 ) );
    00482     --d->blockRelative;
    00483 }
    00484
    00485 double KIntNumInput::relativeValue() const {
    00486     if ( !d->referencePoint ) return 0;
    00487     return double( value() ) / double ( d->referencePoint );
    00488 }
    00489
    00490 int  KIntNumInput::value() const
    00491 {
    00492     return m_spin->value();
    00493 }
    00494
    00495 void KIntNumInput::setSpecialValueText(const QString& text)
    00496 {
    00497     m_spin->setSpecialValueText(text);
    00498     layout(true);
    00499 }
    00500
    00501 QString KIntNumInput::specialValueText() const
    00502 {
    00503     return m_spin->specialValueText();
    00504 }
    00505
    00506 void KIntNumInput::setLabel(const QString & label, int a)
    00507 {
    00508     KNumInput::setLabel(label, a);
    00509
    00510     if(m_label)
    00511         m_label->setBuddy(m_spin);
    00512 }
    00513
    00514 // ----------------------------------------------------------------------------
    00515
    00516 class KDoubleNumInput::KDoubleNumInputPrivate {
    00517 public:
    00518     KDoubleNumInputPrivate( double r )
    00519         : spin( 0 ),
    00520           referencePoint( r ),
    00521           blockRelative ( 0 ) {}
    00522     KDoubleSpinBox * spin;
    00523     double referencePoint;
    00524     short blockRelative;
    00525 };
    00526
    00527 KDoubleNumInput::KDoubleNumInput(QWidget *parent, const char *name)
    00528     : KNumInput(parent, name)
    00529 {
    00530     init(0.0, 0.0, 9999.0, 0.01, 2);
    00531 }
    00532
    00533 KDoubleNumInput::KDoubleNumInput(double lower, double upper, double value,
    00534                                  double step, int precision, QWidget* parent,
    00535                                  const char *name)
    00536     : KNumInput(parent, name)
    00537 {
    00538     init(value, lower, upper, step, precision);
    00539 }
    00540
    00541 KDoubleNumInput::KDoubleNumInput(KNumInput *below,
    00542                                  double lower, double upper, double value,
    00543                                  double step, int precision, QWidget* parent,
    00544                                  const char *name)
    00545     : KNumInput(below, parent, name)
    00546 {
    00547     init(value, lower, upper, step, precision);
    00548 }
    00549
    00550 KDoubleNumInput::KDoubleNumInput(double value, QWidget *parent, const char *name)
    00551     : KNumInput(parent, name)
    00552 {
    00553     init(value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
    00554 }
    00555
    00556 KDoubleNumInput::KDoubleNumInput(KNumInput* below, double value, QWidget* parent,
    00557                                  const char* name)
    00558     : KNumInput(below, parent, name)
    00559 {
    00560     init( value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
    00561 }
    00562
    00563 KDoubleNumInput::~KDoubleNumInput()
    00564 {
    00565         delete d;
    00566 }
    00567
    00568 // ### remove when BIC changes are allowed again:
    00569
    00570 bool KDoubleNumInput::eventFilter( QObject * o, QEvent * e ) {
    00571     return KNumInput::eventFilter( o, e );
    00572 }
    00573
    00574 void KDoubleNumInput::resetEditBox() {
    00575
    00576 }
    00577
    00578 // ### end stuff to remove when BIC changes are allowed again
    00579
    00580
    00581
    00582 void KDoubleNumInput::init(double value, double lower, double upper,
    00583                            double step, int precision )
    00584 {
    00585     // ### init no longer used members:
    00586     edit = 0;
    00587     m_range = true;
    00588     m_value = 0.0;
    00589     m_precision = 2;
    00590     // ### end
    00591
    00592     d = new KDoubleNumInputPrivate( value );
    00593
    00594     d->spin = new KDoubleSpinBox( lower, upper, step, value, precision,
    00595                                   this, "KDoubleNumInput::d->spin" );
    00596     setFocusProxy(d->spin);
    00597     connect( d->spin, SIGNAL(valueChanged(double)),
    00598              this, SIGNAL(valueChanged(double)) );
    00599     connect( this, SIGNAL(valueChanged(double)),
    00600              this, SLOT(slotEmitRelativeValueChanged(double)) );
    00601
    00602     updateLegacyMembers();
    00603
    00604     layout(true);
    00605 }
    00606
    00607 void KDoubleNumInput::updateLegacyMembers() {
    00608     // ### update legacy members that are either not private or for
    00609     // which an inlined getter exists:
    00610     m_lower = minValue();
    00611     m_upper = maxValue();
    00612     m_step = d->spin->lineStep();
    00613     m_specialvalue = specialValueText();
    00614 }
    00615
    00616
    00617 double KDoubleNumInput::mapSliderToSpin( int val ) const
    00618 {
    00619     // map [slidemin,slidemax] to [spinmin,spinmax]
    00620     double spinmin = d->spin->minValue();
    00621     double spinmax = d->spin->maxValue();
    00622     double slidemin = m_slider->minValue(); // cast int to double to avoid
    00623     double slidemax = m_slider->maxValue(); // overflow in rel denominator
    00624     double rel = ( double(val) - slidemin ) / ( slidemax - slidemin );
    00625     return spinmin + rel * ( spinmax - spinmin );
    00626 }
    00627
    00628 void KDoubleNumInput::sliderMoved(int val)
    00629 {
    00630     d->spin->setValue( mapSliderToSpin( val ) );
    00631 }
    00632
    00633 void KDoubleNumInput::slotEmitRelativeValueChanged( double value )
    00634 {
    00635     if ( !d->referencePoint ) return;
    00636     emit relativeValueChanged( value / d->referencePoint );
    00637 }
    00638
    00639 QSize KDoubleNumInput::minimumSizeHint() const
    00640 {
    00641     constPolish();
    00642
    00643     int w;
    00644     int h;
    00645
    00646     h = 2 + QMAX(m_sizeEdit.height(), m_sizeSlider.height());
    00647
    00648     // if in extra row, then count it here
    00649     if(m_label && (m_alignment & (AlignBottom|AlignTop)))
    00650         h += 4 + m_sizeLabel.height();
    00651     else
    00652         // label is in the same row as the other widgets
    00653         h = QMAX(h, m_sizeLabel.height() + 2);
    00654
    00655     w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
    00656     w += m_colw1 + m_colw2;
    00657
    00658     if(m_alignment & (AlignTop|AlignBottom))
    00659         w = QMAX(w, m_sizeLabel.width() + 4);
    00660
    00661     return QSize(w, h);
    00662 }
    00663
    00664 void KDoubleNumInput::resizeEvent(QResizeEvent* e)
    00665 {
    00666     int w = m_colw1;
    00667     int h = 0;
    00668
    00669     if(m_label && (m_alignment & AlignTop)) {
    00670         m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
    00671         h += m_sizeLabel.height() + 4;
    00672     }
    00673
    00674     if(m_label && (m_alignment & AlignVCenter))
    00675         m_label->setGeometry(0, 0, w, m_sizeEdit.height());
    00676
    00677     d->spin->setGeometry(w, h, m_slider ? m_colw2
    00678                                           : e->size().width() - w, m_sizeEdit.height());
    00679     w += m_colw2 + 8;
    00680
    00681     if(m_slider)
    00682         m_slider->setGeometry(w, h, e->size().width() - w, m_sizeEdit.height());
    00683
    00684     h += m_sizeEdit.height() + 2;
    00685
    00686     if(m_label && (m_alignment & AlignBottom))
    00687         m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
    00688 }
    00689
    00690 void KDoubleNumInput::doLayout()
    00691 {
    00692     m_sizeEdit = d->spin->sizeHint();
    00693     m_colw2 = m_sizeEdit.width();
    00694 }
    00695
    00696 void KDoubleNumInput::setValue(double val)
    00697 {
    00698     d->spin->setValue( val );
    00699 }
    00700
    00701 void KDoubleNumInput::setRelativeValue( double r )
    00702 {
    00703     if ( !d->referencePoint ) return;
    00704     ++d->blockRelative;
    00705     setValue( r * d->referencePoint );
    00706     --d->blockRelative;
    00707 }
    00708
    00709 void KDoubleNumInput::setReferencePoint( double ref )
    00710 {
    00711     // clip to valid range:
    00712     ref = kMin( maxValue(), kMax( minValue(), ref ) );
    00713     d->referencePoint = ref;
    00714 }
    00715
    00716 void KDoubleNumInput::setRange(double lower, double upper, double step,
    00717                                                            bool slider)
    00718 {
    00719     if( m_slider ) {
    00720         // don't update the slider to avoid an endless recursion
    00721         QSpinBox * spin = d->spin;
    00722         disconnect(spin, SIGNAL(valueChanged(int)),
    00723                 m_slider, SLOT(setValue(int)) );
    00724     }
    00725     d->spin->setRange( lower, upper, step, d->spin->precision() );
    00726
    00727     if(slider) {
    00728         // upcast to base type to get the min/maxValue in int form:
    00729         QSpinBox * spin = d->spin;
    00730         int slmax = spin->maxValue();
    00731         int slmin = spin->minValue();
    00732         int slvalue = spin->value();
    00733         int slstep = spin->lineStep();
    00734         if (m_slider) {
    00735             m_slider->setRange(slmin, slmax);
    00736             m_slider->setLineStep(slstep);
    00737             m_slider->setValue(slvalue);
    00738         } else {
    00739             m_slider = new QSlider(slmin, slmax, slstep, slvalue,
    00740                                    QSlider::Horizontal, this);
    00741             m_slider->setTickmarks(QSlider::Below);
    00742             // feedback line: when one moves, the other moves, too:
    00743             connect(m_slider, SIGNAL(valueChanged(int)),
    00744                     SLOT(sliderMoved(int)) );
    00745         }
    00746         connect(spin, SIGNAL(valueChanged(int)),
    00747                         m_slider, SLOT(setValue(int)) );
    00748         // calculate ( slmax - slmin ) / 10 without overflowing ints:
    00749         int major = calcDiffByTen( slmax, slmin );
    00750         if ( !major ) major = slstep; // ### needed?
    00751         m_slider->setTickInterval(major);
    00752     } else {
    00753         delete m_slider;
    00754         m_slider = 0;
    00755     }
    00756
    00757     setReferencePoint( referencePoint() );
    00758
    00759     layout(true);
    00760     updateLegacyMembers();
    00761 }
    00762
    00763 void KDoubleNumInput::setMinValue(double min)
    00764 {
    00765     setRange(min, maxValue(), d->spin->lineStep(), m_slider);
    00766 }
    00767
    00768 double KDoubleNumInput::minValue() const
    00769 {
    00770     return d->spin->minValue();
    00771 }
    00772
    00773 void KDoubleNumInput::setMaxValue(double max)
    00774 {
    00775     setRange(minValue(), max, d->spin->lineStep(), m_slider);
    00776 }
    00777
    00778 double KDoubleNumInput::maxValue() const
    00779 {
    00780     return d->spin->maxValue();
    00781 }
    00782
    00783 double  KDoubleNumInput::value() const
    00784 {
    00785     return d->spin->value();
    00786 }
    00787
    00788 double KDoubleNumInput::relativeValue() const
    00789 {
    00790     if ( !d->referencePoint ) return 0;
    00791     return value() / d->referencePoint;
    00792 }
    00793
    00794 double KDoubleNumInput::referencePoint() const
    00795 {
    00796     return d->referencePoint;
    00797 }
    00798
    00799 QString KDoubleNumInput::suffix() const
    00800 {
    00801     return d->spin->suffix();
    00802 }
    00803
    00804 QString KDoubleNumInput::prefix() const
    00805 {
    00806     return d->spin->prefix();
    00807 }
    00808
    00809 void KDoubleNumInput::setSuffix(const QString &suffix)
    00810 {
    00811     d->spin->setSuffix( suffix );
    00812
    00813     layout(true);
    00814 }
    00815
    00816 void KDoubleNumInput::setPrefix(const QString &prefix)
    00817 {
    00818     d->spin->setPrefix( prefix );
    00819
    00820     layout(true);
    00821 }
    00822
    00823 void KDoubleNumInput::setPrecision(int precision)
    00824 {
    00825     d->spin->setPrecision( precision );
    00826
    00827     layout(true);
    00828 }
    00829
    00830 int KDoubleNumInput::precision() const
    00831 {
    00832     return d->spin->precision();
    00833 }
    00834
    00835 void KDoubleNumInput::setSpecialValueText(const QString& text)
    00836 {
    00837     d->spin->setSpecialValueText( text );
    00838
    00839     layout(true);
    00840     updateLegacyMembers();
    00841 }
    00842
    00843 void KDoubleNumInput::setLabel(const QString & label, int a)
    00844 {
    00845     KNumInput::setLabel(label, a);
    00846
    00847     if(m_label)
    00848         m_label->setBuddy(d->spin);
    00849
    00850 }
    00851
    00852 // ----------------------------------------------------------------------------
    00853
    00854
    00855 // We use a kind of fixed-point arithmetic to represent the range of
    00856 // doubles [mLower,mUpper] in steps of 10^(-mPrecision). Thus, the
    00857 // following relations hold:
    00858 //
    00859 // 1. factor = 10^mPrecision
    00860 // 2. basicStep = 1/factor = 10^(-mPrecision);
    00861 // 3. lowerInt = lower * factor;
    00862 // 4. upperInt = upper * factor;
    00863 // 5. lower = lowerInt * basicStep;
    00864 // 6. upper = upperInt * basicStep;
    00865 class KDoubleSpinBox::Private {
    00866 public:
    00867   Private( int precision=1 )
    00868     : mPrecision( precision ),
    00869       mValidator( 0 )
    00870   {
    00871   }
    00872
    00873   int factor() const {
    00874     int f = 1;
    00875     for ( int i = 0 ; i < mPrecision ; ++i ) f *= 10;
    00876     return f;
    00877   }
    00878
    00879   double basicStep() const {
    00880     return 1.0/double(factor());
    00881   }
    00882
    00883   int mapToInt( double value, bool * ok ) const {
    00884     assert( ok );
    00885     const double f = factor();
    00886     if ( value > double(INT_MAX) / f ) {
    00887       kdWarning() << "KDoubleSpinBox: can't represent value " << value
    00888                   << "in terms of fixed-point numbers with precision "
    00889                   << mPrecision << endl;
    00890       *ok = false;
    00891       return INT_MAX;
    00892     } else if ( value < double(INT_MIN) / f ) {
    00893       kdWarning() << "KDoubleSpinBox: can't represent value " << value
    00894                   << "in terms of fixed-point numbers with precision "
    00895                   << mPrecision << endl;
    00896       *ok = false;
    00897       return INT_MIN;
    00898     } else {
    00899       *ok = true;
    00900       return int( value * f + ( value < 0 ? -0.5 : 0.5 ) );
    00901     }
    00902   }
    00903
    00904   double mapToDouble( int value ) const {
    00905     return double(value) * basicStep();
    00906   }
    00907
    00908   int mPrecision;
    00909   KDoubleValidator * mValidator;
    00910 };
    00911
    00912 KDoubleSpinBox::KDoubleSpinBox( QWidget * parent, const char * name )
    00913   : QSpinBox( parent, name )
    00914 {
    00915   editor()->setAlignment( Qt::AlignRight );
    00916   d = new Private();
    00917   updateValidator();
    00918 }
    00919
    00920 KDoubleSpinBox::KDoubleSpinBox( double lower, double upper, double step,
    00921                                 double value, int precision,
    00922                                 QWidget * parent, const char * name )
    00923   : QSpinBox( parent, name )
    00924 {
    00925   editor()->setAlignment( Qt::AlignRight );
    00926   d = new Private();
    00927   setRange( lower, upper, step, precision );
    00928   setValue( value );
    00929   connect( this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)) );
    00930 }
    00931
    00932 KDoubleSpinBox::~KDoubleSpinBox() {
    00933   delete d; d = 0;
    00934 }
    00935
    00936 bool KDoubleSpinBox::acceptLocalizedNumbers() const {
    00937   if ( !d->mValidator ) return true; // we'll set one that does;
    00938                                      // can't do it now, since we're const
    00939   return d->mValidator->acceptLocalizedNumbers();
    00940 }
    00941
    00942 void KDoubleSpinBox::setAcceptLocalizedNumbers( bool accept ) {
    00943   if ( !d->mValidator ) updateValidator();
    00944   d->mValidator->setAcceptLocalizedNumbers( accept );
    00945 }
    00946
    00947 void KDoubleSpinBox::setRange( double lower, double upper, double step,
    00948                                int precision ) {
    00949   lower = kMin(upper, lower);
    00950   upper = kMax(upper, lower);
    00951   setPrecision( precision, true ); // disable bounds checking, since
    00952   setMinValue( lower );            // it's done in set{Min,Max}Value
    00953   setMaxValue( upper );            // anyway and we want lower, upper
    00954   setLineStep( step );             // and step to have the right precision
    00955 }
    00956
    00957 int KDoubleSpinBox::precision() const {
    00958   return d->mPrecision;
    00959 }
    00960
    00961 void KDoubleSpinBox::setPrecision( int precision ) {
    00962     setPrecision( precision, false );
    00963 }
    00964
    00965 void KDoubleSpinBox::setPrecision( int precision, bool force ) {
    00966   if ( precision < 1 ) return;
    00967   if ( !force ) {
    00968     int maxPrec = maxPrecision();
    00969     if ( precision > maxPrec )
    00970       precision = maxPrec;
    00971   }
    00972   d->mPrecision = precision;
    00973   updateValidator();
    00974 }
    00975
    00976 int KDoubleSpinBox::maxPrecision() const {
    00977     // INT_MAX must be > maxAbsValue * 10^precision
    00978     // ==> 10^precision < INT_MAX / maxAbsValue
    00979     // ==> precision < log10 ( INT_MAX / maxAbsValue )
    00980     // ==> maxPrecision = floor( log10 ( INT_MAX / maxAbsValue ) );
    00981     double maxAbsValue = kMax( fabs(minValue()), fabs(maxValue()) );
    00982     if ( maxAbsValue == 0 ) return 6; // return arbitrary value to avoid dbz...
    00983
    00984     return int( floor( log10( double(INT_MAX) / maxAbsValue ) ) );
    00985 }
    00986
    00987 double KDoubleSpinBox::value() const {
    00988   return d->mapToDouble( base::value() );
    00989 }
    00990
    00991 void KDoubleSpinBox::setValue( double value ) {
    00992     if ( value == this->value() ) return;
    00993     if ( value < minValue() )
    00994         base::setValue( base::minValue() );
    00995     else if ( value > maxValue() )
    00996         base::setValue( base::maxValue() );
    00997     else {
    00998         bool ok = false;
    00999         base::setValue( d->mapToInt( value, &ok ) );
    01000         assert( ok );
    01001     }
    01002 }
    01003
    01004 double KDoubleSpinBox::minValue() const {
    01005   return d->mapToDouble( base::minValue() );
    01006 }
    01007
    01008 void KDoubleSpinBox::setMinValue( double value ) {
    01009   bool ok = false;
    01010   int min = d->mapToInt( value, &ok );
    01011   if ( !ok ) return;
    01012   base::setMinValue( min );
    01013   updateValidator();
    01014 }
    01015
    01016
    01017 double KDoubleSpinBox::maxValue() const {
    01018   return d->mapToDouble( base::maxValue() );
    01019 }
    01020
    01021 void KDoubleSpinBox::setMaxValue( double value ) {
    01022   bool ok = false;
    01023   int max = d->mapToInt( value, &ok );
    01024   if ( !ok ) return;
    01025   base::setMaxValue( max );
    01026   updateValidator();
    01027 }
    01028
    01029 double KDoubleSpinBox::lineStep() const {
    01030   return d->mapToDouble( base::lineStep() );
    01031 }
    01032
    01033 void KDoubleSpinBox::setLineStep( double step ) {
    01034   bool ok = false;
    01035   if ( step > maxValue() - minValue() )
    01036     base::setLineStep( 1 );
    01037   else
    01038     base::setLineStep( kMax( d->mapToInt( step, &ok ), 1 ) );
    01039 }
    01040
    01041 QString KDoubleSpinBox::mapValueToText( int value ) {
    01042   if ( acceptLocalizedNumbers() )
    01043     return KGlobal::locale()
    01044       ->formatNumber( d->mapToDouble( value ), d->mPrecision );
    01045   else
    01046     return QString().setNum( d->mapToDouble( value ), 'f', d->mPrecision );
    01047 }
    01048
    01049 int KDoubleSpinBox::mapTextToValue( bool * ok ) {
    01050   double value;
    01051   if ( acceptLocalizedNumbers() )
    01052     value = KGlobal::locale()->readNumber( cleanText(), ok );
    01053   else
    01054     value = cleanText().toDouble( ok );
    01055   if ( !*ok ) return 0;
    01056   if ( value > maxValue() )
    01057     value = maxValue();
    01058   else if ( value < minValue() )
    01059     value = minValue();
    01060   return d->mapToInt( value, ok );
    01061 }
    01062
    01063 void KDoubleSpinBox::setValidator( const QValidator * ) {
    01064   // silently discard the new validator. We don't want another one ;-)
    01065 }
    01066
    01067 void KDoubleSpinBox::slotValueChanged( int value ) {
    01068   emit valueChanged( d->mapToDouble( value ) );
    01069 }
    01070
    01071 void KDoubleSpinBox::updateValidator() {
    01072   if ( !d->mValidator ) {
    01073     d->mValidator =  new KDoubleValidator( minValue(), maxValue(), precision(),
    01074                                            this, "d->mValidator" );
    01075     base::setValidator( d->mValidator );
    01076   } else
    01077     d->mValidator->setRange( minValue(), maxValue(), precision() );
    01078 }
    01079
    01080 void KNumInput::virtual_hook( int, void* )
    01081 { /*BASE::virtual_hook( id, data );*/ }
    01082
    01083 void KIntNumInput::virtual_hook( int id, void* data )
    01084 { KNumInput::virtual_hook( id, data ); }
    01085
    01086 void KDoubleNumInput::virtual_hook( int id, void* data )
    01087 { KNumInput::virtual_hook( id, data ); }
    01088
    01089 void KIntSpinBox::virtual_hook( int, void* )
    01090 { /*BASE::virtual_hook( id, data );*/ }
    01091
    01092 void KDoubleSpinBox::virtual_hook( int, void* )
    01093 { /*BASE::virtual_hook( id, data );*/ }
    01094
    01095 #include "knuminput.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:57:25 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001