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

This file is part of the documentation for kdeui Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:20:19 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003