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