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

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal