• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • 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.endsWith(suffix())) {
00295         theText.chop(suffix().length());
00296     }
00297     return theText.toInt(&ok, d->val_base);
00298 }
00299 
00300 void KIntSpinBox::setEditFocus(bool mark)
00301 {
00302     lineEdit()->setFocus();
00303     if (mark) {
00304         lineEdit()->selectAll();
00305     }
00306 }
00307 
00308 void KIntSpinBox::setSuffix(const KLocalizedString& suffix)
00309 {
00310     d->pluralSuffix = suffix;
00311     if (suffix.isEmpty())
00312         setSuffix(QString());
00313     else
00314         d->updateSuffix(value());
00315 }
00316 
00317 // ----------------------------------------------------------------------------
00318 
00319 class KIntNumInput::KIntNumInputPrivate
00320 {
00321 public:
00322     KIntNumInput *q;
00323     int referencePoint;
00324     short blockRelative;
00325     KIntSpinBox* intSpinBox;
00326     QSize        intSpinBoxSize;
00327 
00328     KIntNumInputPrivate(KIntNumInput *q, int r)
00329             : q(q),
00330             referencePoint(r),
00331             blockRelative(0) {}
00332 };
00333 
00334 
00335 #ifndef KDE_NO_DEPRECATED
00336 KIntNumInput::KIntNumInput(KNumInput* below, int val, QWidget *parent, int _base)
00337     : KNumInput(parent, below)
00338     , d(new KIntNumInputPrivate(this, val))
00339 {
00340     init(val, _base);
00341 }
00342 #endif
00343 
00344 KIntNumInput::KIntNumInput(QWidget *parent)
00345     : KNumInput(parent)
00346     , d(new KIntNumInputPrivate(this, 0))
00347 {
00348     init(0, 10);
00349 }
00350 
00351 KIntNumInput::KIntNumInput(int val, QWidget *parent, int _base)
00352     : KNumInput(parent)
00353     , d(new KIntNumInputPrivate(this, val))
00354 {
00355     init(val, _base);
00356 }
00357 
00358 QSpinBox *KIntNumInput::spinBox() const
00359 {
00360     return d->intSpinBox;
00361 }
00362 
00363 void KIntNumInput::init(int val, int _base)
00364 {
00365     d->intSpinBox = new KIntSpinBox(INT_MIN, INT_MAX, 1, val, this, _base);
00366     d->intSpinBox->setObjectName("KIntNumInput::KIntSpinBox");
00367     // the KIntValidator is broken beyond believe for
00368     // spinboxes which have suffix or prefix texts, so
00369     // better don't use it unless absolutely necessary
00370 
00371     if (_base != 10) {
00372         kWarning() << "WARNING: Validation is broken in KIntNumInput! Needs to be fixed.";
00373 //         d->intSpinBox->setValidator(new KIntValidator(this, _base, "KNumInput::KIntValidator"));
00374     }
00375 
00376     connect(d->intSpinBox, SIGNAL(valueChanged(int)), SLOT(spinValueChanged(int)));
00377     connect(this, SIGNAL(valueChanged(int)),
00378             SLOT(slotEmitRelativeValueChanged(int)));
00379 
00380     setFocusProxy(d->intSpinBox);
00381     layout(true);
00382 }
00383 
00384 void KIntNumInput::setReferencePoint(int ref)
00385 {
00386     // clip to valid range:
00387     ref = qMin(maximum(), qMax(minimum(),  ref));
00388     d->referencePoint = ref;
00389 }
00390 
00391 int KIntNumInput::referencePoint() const
00392 {
00393     return d->referencePoint;
00394 }
00395 
00396 void KIntNumInput::spinValueChanged(int val)
00397 {
00398     K_USING_KNUMINPUT_P(priv);
00399 
00400     if (priv->slider) {
00401         priv->slider->setValue(val);
00402     }
00403 
00404     emit valueChanged(val);
00405 }
00406 
00407 void KIntNumInput::slotEmitRelativeValueChanged(int value)
00408 {
00409     if (d->blockRelative || !d->referencePoint) {
00410         return;
00411     }
00412     emit relativeValueChanged(double(value) / double(d->referencePoint));
00413 }
00414 
00415 void KIntNumInput::setSliderEnabled(bool slider)
00416 {
00417     K_USING_KNUMINPUT_P(priv);
00418     if (slider) {
00419         if (!priv->slider) {
00420             priv->slider = new QSlider(Qt::Horizontal, this);
00421             connect(priv->slider, SIGNAL(valueChanged(int)),
00422                     d->intSpinBox, SLOT(setValue(int)));
00423             priv->slider->setTickPosition(QSlider::TicksBelow);
00424             layout(true);
00425         }
00426 
00427         const int value = d->intSpinBox->value();
00428         priv->slider->setRange(d->intSpinBox->minimum(), d->intSpinBox->maximum());
00429         priv->slider->setPageStep(d->intSpinBox->singleStep());
00430         priv->slider->setValue(value);
00431 
00432         // calculate (upper-lower)/10 without overflowing int's:
00433         const int major = calcDiffByTen(d->intSpinBox->maximum(), d->intSpinBox->minimum());
00434 
00435         priv->slider->setSingleStep(d->intSpinBox->singleStep());
00436         priv->slider->setPageStep(qMax(1, major));
00437         priv->slider->setTickInterval(major);
00438     } else {
00439         if (priv->slider) {
00440             layout(true);
00441         }
00442         delete priv->slider;
00443         priv->slider = 0;
00444     }
00445 }
00446 
00447 void KIntNumInput::setRange(int lower, int upper, int singleStep)
00448 {
00449     if (upper < lower || singleStep <= 0) {
00450         kWarning() << "WARNING: KIntNumInput::setRange() called with bad arguments. Ignoring call...";
00451         return;
00452     }
00453 
00454     d->intSpinBox->setMinimum(lower);
00455     d->intSpinBox->setMaximum(upper);
00456     d->intSpinBox->setSingleStep(singleStep);
00457 
00458     singleStep = d->intSpinBox->singleStep(); // maybe QRangeControl didn't like our lineStep?
00459 
00460     // check that reference point is still inside valid range:
00461     setReferencePoint(referencePoint());
00462 
00463     layout(true);
00464 
00465     // update slider information if it's shown
00466     K_USING_KNUMINPUT_P(priv);
00467     setSliderEnabled(priv->slider);
00468 }
00469 
00470 #ifndef KDE_NO_DEPRECATED
00471 void KIntNumInput::setRange(int lower, int upper, int singleStep, bool slider)
00472 {
00473     setRange(lower, upper, singleStep);
00474     setSliderEnabled(slider);
00475 }
00476 #endif
00477 
00478 void KIntNumInput::setMinimum(int min)
00479 {
00480     setRange(min, d->intSpinBox->maximum(), d->intSpinBox->singleStep());
00481 }
00482 
00483 int KIntNumInput::minimum() const
00484 {
00485     return d->intSpinBox->minimum();
00486 }
00487 
00488 void KIntNumInput::setMaximum(int max)
00489 {
00490     setRange(d->intSpinBox->minimum(), max, d->intSpinBox->singleStep());
00491 }
00492 
00493 int KIntNumInput::maximum() const
00494 {
00495     return d->intSpinBox->maximum();
00496 }
00497 
00498 int KIntNumInput::singleStep() const
00499 {
00500     return d->intSpinBox->singleStep();
00501 }
00502 
00503 void KIntNumInput::setSingleStep(int singleStep)
00504 {
00505     d->intSpinBox->setSingleStep(singleStep);
00506 }
00507 
00508 void KIntNumInput::setSuffix(const QString &suffix)
00509 {
00510     d->intSpinBox->setSuffix(suffix);
00511 
00512     layout(true);
00513 }
00514 
00515 void KIntNumInput::setSuffix(const KLocalizedString& suffix)
00516 {
00517     d->intSpinBox->setSuffix(suffix);
00518     layout(true);
00519 }
00520 
00521 QString KIntNumInput::suffix() const
00522 {
00523     return d->intSpinBox->suffix();
00524 }
00525 
00526 void KIntNumInput::setPrefix(const QString &prefix)
00527 {
00528     d->intSpinBox->setPrefix(prefix);
00529 
00530     layout(true);
00531 }
00532 
00533 QString KIntNumInput::prefix() const
00534 {
00535     return d->intSpinBox->prefix();
00536 }
00537 
00538 void KIntNumInput::setEditFocus(bool mark)
00539 {
00540     d->intSpinBox->setEditFocus(mark);
00541 }
00542 
00543 QSize KIntNumInput::minimumSizeHint() const
00544 {
00545     K_USING_KNUMINPUT_P(priv);
00546     ensurePolished();
00547 
00548     int w;
00549     int h;
00550 
00551     h = qMax(d->intSpinBoxSize.height(), priv->sliderSize.height());
00552 
00553     // if in extra row, then count it here
00554     if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) {
00555         h += 4 + priv->labelSize.height();
00556     } else {
00557         // label is in the same row as the other widgets
00558         h = qMax(h, priv->labelSize.height() + 2);
00559     }
00560 
00561     w = priv->slider ? priv->slider->sizeHint().width() + KDialog::spacingHint() : 0;
00562     w += priv->column1Width + priv->column2Width;
00563 
00564     if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) {
00565         w = qMax(w, priv->labelSize.width() + 4);
00566     }
00567 
00568     return QSize(w, h);
00569 }
00570 
00571 void KIntNumInput::doLayout()
00572 {
00573     K_USING_KNUMINPUT_P(priv);
00574 
00575     d->intSpinBoxSize = d->intSpinBox->sizeHint();
00576     priv->column2Width = d->intSpinBoxSize.width();
00577 
00578     if (priv->label) {
00579         priv->label->setBuddy(d->intSpinBox);
00580     }
00581 }
00582 
00583 void KIntNumInput::resizeEvent(QResizeEvent* e)
00584 {
00585     K_USING_KNUMINPUT_P(priv);
00586 
00587     int w = priv->column1Width;
00588     int h = 0;
00589 
00590     if (priv->label && (priv->labelAlignment & Qt::AlignTop)) {
00591         priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height());
00592         h += priv->labelSize.height() + KDialog::spacingHint();
00593     }
00594 
00595     if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) {
00596         priv->label->setGeometry(0, 0, w, d->intSpinBoxSize.height());
00597     }
00598 
00599     if (qApp->layoutDirection() == Qt::RightToLeft) {
00600         d->intSpinBox->setGeometry(w, h, priv->slider ? priv->column2Width : qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height());
00601         w += priv->column2Width + KDialog::spacingHint();
00602 
00603         if (priv->slider) {
00604             priv->slider->setGeometry(w, h, e->size().width() - w, d->intSpinBoxSize.height() + KDialog::spacingHint());
00605         }
00606     } else if (priv->slider) {
00607         priv->slider->setGeometry(w, h, e->size().width() - (w + priv->column2Width + KDialog::spacingHint()), d->intSpinBoxSize.height() + KDialog::spacingHint());
00608         d->intSpinBox->setGeometry(w + priv->slider->size().width() + KDialog::spacingHint(), h, priv->column2Width, d->intSpinBoxSize.height());
00609     } else {
00610         d->intSpinBox->setGeometry(w, h, qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height());
00611     }
00612 
00613     h += d->intSpinBoxSize.height() + 2;
00614 
00615     if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) {
00616         priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height());
00617     }
00618 }
00619 
00620 KIntNumInput::~KIntNumInput()
00621 {
00622     delete d;
00623 }
00624 
00625 void KIntNumInput::setValue(int val)
00626 {
00627     d->intSpinBox->setValue(val);
00628     // slider value is changed by spinValueChanged
00629 }
00630 
00631 void KIntNumInput::setRelativeValue(double r)
00632 {
00633     if (!d->referencePoint) {
00634         return;
00635     }
00636     ++d->blockRelative;
00637     setValue(qRound(d->referencePoint * r + 0.5));
00638     --d->blockRelative;
00639 }
00640 
00641 double KIntNumInput::relativeValue() const
00642 {
00643     if (!d->referencePoint) {
00644         return 0;
00645     }
00646     return double(value()) / double(d->referencePoint);
00647 }
00648 
00649 int KIntNumInput::value() const
00650 {
00651     return d->intSpinBox->value();
00652 }
00653 
00654 void KIntNumInput::setSpecialValueText(const QString& text)
00655 {
00656     d->intSpinBox->setSpecialValueText(text);
00657     layout(true);
00658 }
00659 
00660 QString KIntNumInput::specialValueText() const
00661 {
00662     return d->intSpinBox->specialValueText();
00663 }
00664 
00665 void KIntNumInput::setLabel(const QString & label, Qt::Alignment a)
00666 {
00667     K_USING_KNUMINPUT_P(priv);
00668 
00669     KNumInput::setLabel(label, a);
00670 
00671     if (priv->label) {
00672         priv->label->setBuddy(d->intSpinBox);
00673     }
00674 }
00675 
00676 // ----------------------------------------------------------------------------
00677 
00678 class KDoubleNumInput::KDoubleNumInputPrivate
00679 {
00680 public:
00681     KDoubleNumInputPrivate(double r)
00682             : spin(0),
00683             referencePoint(r),
00684             blockRelative(0),
00685             exponentRatio(1.0) {}
00686     QDoubleSpinBox * spin;
00687     double referencePoint;
00688     short blockRelative;
00689     QSize editSize;
00690     QString specialValue;
00691     double exponentRatio;
00692 };
00693 
00694 KDoubleNumInput::KDoubleNumInput(QWidget *parent)
00695     : KNumInput(parent)
00696     , d(new KDoubleNumInputPrivate(0.0))
00697 
00698 {
00699     init(0.0, 0.0, 9999.0, 0.01, 2);
00700 }
00701 
00702 KDoubleNumInput::KDoubleNumInput(double lower, double upper, double value, QWidget *parent,
00703                                  double singleStep, int precision)
00704     : KNumInput(parent)
00705     , d(new KDoubleNumInputPrivate(value))
00706 {
00707     init(value, lower, upper, singleStep, precision);
00708 }
00709 
00710 #ifndef KDE_NO_DEPRECATED
00711 KDoubleNumInput::KDoubleNumInput(KNumInput *below,
00712                                  double lower, double upper, double value, QWidget *parent,
00713                                  double singleStep, int precision)
00714     : KNumInput(parent, below)
00715     , d(new KDoubleNumInputPrivate(value))
00716 {
00717     init(value, lower, upper, singleStep, precision);
00718 }
00719 #endif
00720 
00721 KDoubleNumInput::~KDoubleNumInput()
00722 {
00723     delete d;
00724 }
00725 
00726 QString KDoubleNumInput::specialValueText() const
00727 {
00728     return d->specialValue;
00729 }
00730 
00731 
00732 void KDoubleNumInput::init(double value, double lower, double upper,
00733                            double singleStep, int precision)
00734 {
00735     d->spin = new QDoubleSpinBox(this);
00736     d->spin->setRange(lower, upper);
00737     d->spin->setSingleStep(singleStep);
00738     d->spin->setValue(value);
00739     d->spin->setDecimals(precision);
00740 
00741     d->spin->setObjectName("KDoubleNumInput::QDoubleSpinBox");
00742     setFocusProxy(d->spin);
00743     connect(d->spin, SIGNAL(valueChanged(double)),
00744             this, SIGNAL(valueChanged(double)));
00745     connect(this, SIGNAL(valueChanged(double)),
00746             this, SLOT(slotEmitRelativeValueChanged(double)));
00747 
00748     updateLegacyMembers();
00749 
00750     layout(true);
00751 }
00752 
00753 void KDoubleNumInput::updateLegacyMembers()
00754 {
00755     d->specialValue = specialValueText();
00756 }
00757 
00758 double KDoubleNumInput::mapSliderToSpin(int val) const
00759 {
00760     K_USING_KNUMINPUT_P(priv);
00761 
00762     // map [slidemin,slidemax] to [spinmin,spinmax]
00763     const double spinmin = d->spin->minimum();
00764     const double spinmax = d->spin->maximum();
00765     const double slidemin = priv->slider->minimum(); // cast int to double to avoid
00766     const double slidemax = priv->slider->maximum(); // overflow in rel denominator
00767     const double rel = (double(val) - slidemin) / (slidemax - slidemin);
00768     Q_ASSERT(d->exponentRatio > 0.0);
00769     return spinmin + pow(rel, d->exponentRatio ) * (spinmax - spinmin);
00770 }
00771 
00772 void KDoubleNumInput::sliderMoved(int val)
00773 {
00774     d->spin->setValue(mapSliderToSpin(val));
00775 }
00776 
00777 void KDoubleNumInput::spinBoxChanged(double val)
00778 {
00779     K_USING_KNUMINPUT_P(priv);
00780 
00781     const double spinmin = d->spin->minimum();
00782     const double spinmax = d->spin->maximum();
00783     const double slidemin = priv->slider->minimum(); // cast int to double to avoid
00784     const double slidemax = priv->slider->maximum(); // overflow in rel denominator
00785 
00786     Q_ASSERT(d->exponentRatio > 0.0);
00787     const double rel = pow((val - spinmin) / (spinmax - spinmin) , 1.0 / d->exponentRatio);
00788 
00789     if (priv->slider) {
00790         priv->slider->blockSignals(true);
00791         priv->slider->setValue(qRound(slidemin + rel * (slidemax - slidemin)));
00792         priv->slider->blockSignals(false);
00793     }
00794 }
00795 
00796 void KDoubleNumInput::slotEmitRelativeValueChanged(double value)
00797 {
00798     if (!d->referencePoint) {
00799         return;
00800     }
00801     emit relativeValueChanged(value / d->referencePoint);
00802 }
00803 
00804 QSize KDoubleNumInput::minimumSizeHint() const
00805 {
00806     K_USING_KNUMINPUT_P(priv);
00807 
00808     ensurePolished();
00809 
00810     int w;
00811     int h;
00812 
00813     h = qMax(d->editSize.height(), priv->sliderSize.height());
00814 
00815     // if in extra row, then count it here
00816     if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) {
00817         h += 4 + priv->labelSize.height();
00818     } else {
00819         // label is in the same row as the other widgets
00820         h = qMax(h, priv->labelSize.height() + 2);
00821     }
00822 
00823     w = priv->slider ? priv->slider->sizeHint().width() + KDialog::spacingHint() : 0;
00824     w += priv->column1Width + priv->column2Width;
00825 
00826     if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) {
00827         w = qMax(w, priv->labelSize.width() + 4);
00828     }
00829 
00830     return QSize(w, h);
00831 }
00832 
00833 void KDoubleNumInput::resizeEvent(QResizeEvent* e)
00834 {
00835     K_USING_KNUMINPUT_P(priv);
00836 
00837     int w = priv->column1Width;
00838     int h = 0;
00839 
00840     if (priv->label && (priv->labelAlignment & Qt::AlignTop)) {
00841         priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height());
00842         h += priv->labelSize.height() + 4;
00843     }
00844 
00845     if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) {
00846         priv->label->setGeometry(0, 0, w, d->editSize.height());
00847     }
00848 
00849     if (qApp->layoutDirection() == Qt::RightToLeft) {
00850         d->spin->setGeometry(w, h, priv->slider ? priv->column2Width
00851                              : e->size().width() - w, d->editSize.height());
00852         w += priv->column2Width + KDialog::spacingHint();
00853 
00854         if (priv->slider)
00855             priv->slider->setGeometry(w, h, e->size().width() - w, d->editSize.height() + KDialog::spacingHint());
00856     } else if (priv->slider) {
00857         priv->slider->setGeometry(w, h, e->size().width() -
00858                                     (priv->column1Width + priv->column2Width + KDialog::spacingHint()),
00859                                     d->editSize.height() + KDialog::spacingHint());
00860         d->spin->setGeometry(w + priv->slider->width() + KDialog::spacingHint(), h,
00861                              priv->column2Width, d->editSize.height());
00862     } else {
00863         d->spin->setGeometry(w, h, e->size().width() - w, d->editSize.height());
00864     }
00865 
00866     h += d->editSize.height() + 2;
00867 
00868     if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) {
00869         priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height());
00870     }
00871 }
00872 
00873 void KDoubleNumInput::doLayout()
00874 {
00875     K_USING_KNUMINPUT_P(priv);
00876 
00877     d->editSize = d->spin->sizeHint();
00878     priv->column2Width = d->editSize.width();
00879 }
00880 
00881 void KDoubleNumInput::setValue(double val)
00882 {
00883     d->spin->setValue(val);
00884 }
00885 
00886 void KDoubleNumInput::setRelativeValue(double r)
00887 {
00888     if (!d->referencePoint) {
00889         return;
00890     }
00891     ++d->blockRelative;
00892     setValue(r * d->referencePoint);
00893     --d->blockRelative;
00894 }
00895 
00896 void KDoubleNumInput::setReferencePoint(double ref)
00897 {
00898     // clip to valid range:
00899     ref = qMin(maximum(), qMax(minimum(), ref));
00900     d->referencePoint = ref;
00901 }
00902 
00903 void KDoubleNumInput::setRange(double lower, double upper, double singleStep,
00904                                bool slider)
00905 {
00906     K_USING_KNUMINPUT_P(priv);
00907 
00908     if (priv->slider) {
00909         // don't update the slider to avoid an endless recursion
00910         QDoubleSpinBox * spin = d->spin;
00911         disconnect(spin, SIGNAL(valueChanged(double)),
00912                    priv->slider, SLOT(setValue(int)));
00913     }
00914     d->spin->setRange(lower, upper);
00915     d->spin->setSingleStep(singleStep);
00916 
00917     setSliderEnabled(slider);
00918 
00919     setReferencePoint(referencePoint());
00920 
00921     layout(true);
00922     updateLegacyMembers();
00923 }
00924 
00925 void KDoubleNumInput::setSliderEnabled(bool enabled)
00926 {
00927     K_USING_KNUMINPUT_P(priv);
00928     if (enabled) {
00929         QDoubleSpinBox * spin = d->spin;
00930         const double range = spin->maximum() - spin->minimum();
00931         const double steps = range * pow(10.0, spin->decimals());
00932         if (!priv->slider) {
00933             priv->slider = new QSlider(Qt::Horizontal, this);
00934             priv->slider->setTickPosition(QSlider::TicksBelow);
00935             // feedback line: when one moves, the other moves, too:
00936             connect(priv->slider, SIGNAL(valueChanged(int)),
00937                     SLOT(sliderMoved(int)));
00938             layout(true);
00939         }
00940         if (steps > 1000 || d->exponentRatio != 1.0) {
00941             priv->slider->setRange(0, 1000);
00942             priv->slider->setSingleStep(1);
00943             priv->slider->setPageStep(50);
00944         } else {
00945             const int singleSteps = qRound(steps);
00946             priv->slider->setRange(0, singleSteps);
00947             priv->slider->setSingleStep(1);
00948             const int pageSteps = qBound(1, singleSteps / 20, 10);
00949             priv->slider->setPageStep(pageSteps);
00950         }
00951         spinBoxChanged(spin->value());
00952         connect(spin, SIGNAL(valueChanged(double)), SLOT(spinBoxChanged(double)));
00953     } else {
00954         if (priv->slider) {
00955             layout(true);
00956         }
00957         delete priv->slider;
00958         priv->slider = 0;
00959     }
00960 }
00961 
00962 
00963 void KDoubleNumInput::setMinimum(double min)
00964 {
00965     K_USING_KNUMINPUT_P(priv);
00966     setRange(min, maximum(), d->spin->singleStep(), priv->slider);
00967 }
00968 
00969 double KDoubleNumInput::minimum() const
00970 {
00971     return d->spin->minimum();
00972 }
00973 
00974 void KDoubleNumInput::setMaximum(double max)
00975 {
00976     K_USING_KNUMINPUT_P(priv);
00977     setRange(minimum(), max, d->spin->singleStep(), priv->slider);
00978 }
00979 
00980 double KDoubleNumInput::maximum() const
00981 {
00982     return d->spin->maximum();
00983 }
00984 
00985 double KDoubleNumInput::singleStep() const
00986 {
00987   return d->spin->singleStep();
00988 }
00989 
00990 void KDoubleNumInput::setSingleStep(double singleStep)
00991 {
00992   d->spin->setSingleStep(singleStep);
00993 }
00994 
00995 double KDoubleNumInput::value() const
00996 {
00997     return d->spin->value();
00998 }
00999 
01000 double KDoubleNumInput::relativeValue() const
01001 {
01002     if (!d->referencePoint) {
01003         return 0;
01004     }
01005     return value() / d->referencePoint;
01006 }
01007 
01008 double KDoubleNumInput::referencePoint() const
01009 {
01010     return d->referencePoint;
01011 }
01012 
01013 QString KDoubleNumInput::suffix() const
01014 {
01015     return d->spin->suffix();
01016 }
01017 
01018 QString KDoubleNumInput::prefix() const
01019 {
01020     return d->spin->prefix();
01021 }
01022 
01023 void KDoubleNumInput::setSuffix(const QString &suffix)
01024 {
01025     d->spin->setSuffix(suffix);
01026 
01027     layout(true);
01028 }
01029 
01030 void KDoubleNumInput::setPrefix(const QString &prefix)
01031 {
01032     d->spin->setPrefix(prefix);
01033 
01034     layout(true);
01035 }
01036 
01037 void KDoubleNumInput::setDecimals(int decimals)
01038 {
01039     d->spin->setDecimals(decimals);
01040 
01041     layout(true);
01042 }
01043 
01044 int KDoubleNumInput::decimals() const
01045 {
01046     return d->spin->decimals();
01047 }
01048 
01049 void KDoubleNumInput::setSpecialValueText(const QString& text)
01050 {
01051     d->spin->setSpecialValueText(text);
01052 
01053     layout(true);
01054     updateLegacyMembers();
01055 }
01056 
01057 void KDoubleNumInput::setLabel(const QString & label, Qt::Alignment a)
01058 {
01059     K_USING_KNUMINPUT_P(priv);
01060 
01061     KNumInput::setLabel(label, a);
01062 
01063     if (priv->label) {
01064         priv->label->setBuddy(d->spin);
01065     }
01066 }
01067 
01068 double KDoubleNumInput::exponentRatio() const
01069 {
01070     return d->exponentRatio;
01071 }
01072 
01073 void KDoubleNumInput::setExponentRatio(double dbl)
01074 {
01075     Q_ASSERT(dbl > 0.0);
01076     if(dbl > 0.0) {
01077         d->exponentRatio = dbl;
01078         spinBoxChanged( d->spin->value() ); // used to reset the value of the slider
01079     } else {
01080         kError() << "ExponentRatio need to be strictly positive.";
01081     }
01082 }
01083 
01084 
01085 #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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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