• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

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

KDE's Doxygen guidelines are available online.

KDEUI

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

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal