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"
KDE 4.6 API Reference