• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kdeui
 

kdeui

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

kdeui

Skip menu "kdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdeui

Skip menu "kdeui"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdeui by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |