32#include <QtGui/QApplication>
33#include <QtGui/QLabel>
34#include <QtGui/QLineEdit>
35#include <QtGui/QResizeEvent>
36#include <QtGui/QSlider>
45 return (x / 10) - (y / 10) + (x % 10 - y % 10) / 10;
64 nextNumInput = below->d->nextNumInput;
65 previousNumInput = below;
66 below->d->nextNumInput = q;
68 nextNumInput->d->previousNumInput = q;
73 static KNumInputPrivate *get(
const KNumInput *i) {
78 KNumInput* previousNumInput, *nextNumInput;
79 int column1Width, column2Width;
83 QSize sliderSize, labelSize;
85 Qt::Alignment labelAlignment;
89#define K_USING_KNUMINPUT_P(_d) KNumInputPrivate *_d = KNumInputPrivate::get(this)
92 :
QWidget(parent), d(new KNumInputPrivate(this))
94 setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
95 setFocusPolicy(Qt::StrongFocus);
98#ifndef KDE_NO_DEPRECATED
100 :
QWidget(parent), d(new KNumInputPrivate(this, below))
102 setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
103 setFocusPolicy(Qt::StrongFocus);
109 if (d->previousNumInput) {
110 d->previousNumInput->d->nextNumInput = d->nextNumInput;
113 if (d->nextNumInput) {
114 d->nextNumInput->d->previousNumInput = d->previousNumInput;
132 if (label.isEmpty()) {
135 d->labelAlignment = 0;
138 d->label =
new QLabel(
this);
140 d->label->setText(label);
141 d->label->setObjectName(
"KNumInput::QLabel");
142 d->label->setAlignment(a);
144 if (!(a & (Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter))) {
147 d->labelAlignment = a;
155 return d->label ? d->label->text() : QString();
160 int w1 = d->column1Width;
161 int w2 = d->column2Width;
164 d->labelSize = (d->label ? d->label->sizeHint() : QSize(0, 0));
166 if (d->label && (d->labelAlignment & Qt::AlignVCenter)) {
167 d->column1Width = d->labelSize.width() + 4;
173 d->sliderSize = (d->slider ? d->slider->sizeHint() : QSize(0, 0));
178 d->column1Width = w1;
179 d->column2Width = w2;
183 w2 = d->column2Width;
188 w1 = qMax(w1, p->d->column1Width);
189 w2 = qMax(w2, p->d->column2Width);
190 p = p->d->previousNumInput;
196 w1 = qMax(w1, p->d->column1Width);
197 w2 = qMax(w2, p->d->column2Width);
198 p = p->d->nextNumInput;
203 p->d->column1Width = w1;
204 p->d->column2Width = w2;
205 p = p->d->previousNumInput;
210 p->d->column1Width = w1;
211 p->d->column2Width = w2;
212 p = p->d->nextNumInput;
220 return minimumSizeHint();
226 d->slider->setSingleStep(minor);
227 d->slider->setPageStep(major);
234class KIntSpinBox::KIntSpinBoxPrivate
237 KIntSpinBoxPrivate(
KIntSpinBox *q,
int val_base = 10): q(q), val_base(val_base)
239 connect(q, SIGNAL(valueChanged(
int)), q, SLOT(updateSuffix(
int)));
242 void updateSuffix(
int value)
244 if (!pluralSuffix.isEmpty()) {
256 : QSpinBox(parent), d(new KIntSpinBoxPrivate(this))
267 : QSpinBox(parent), d(new KIntSpinBoxPrivate(this, base))
269 setRange(lower, upper);
270 setSingleStep(singleStep);
287 return QString::number(v, d->val_base);
293 QString theText = text;
294 if (theText.startsWith(
prefix())) {
295 theText.remove(0,
prefix().length());
297 if (theText.endsWith(suffix())) {
298 theText.chop(suffix().length());
300 return theText.trimmed().toInt(&ok, d->val_base);
305 lineEdit()->setFocus();
307 lineEdit()->selectAll();
313 d->pluralSuffix = suffix;
317 d->updateSuffix(value());
322class KIntNumInput::KIntNumInputPrivate
329 QSize intSpinBoxSize;
338#ifndef KDE_NO_DEPRECATED
341 , d(new KIntNumInputPrivate(this, val))
349 , d(new KIntNumInputPrivate(this, 0))
356 , d(new KIntNumInputPrivate(this, val))
363 return d->intSpinBox;
366void KIntNumInput::init(
int val,
int _base)
368 d->intSpinBox =
new KIntSpinBox(INT_MIN, INT_MAX, 1, val,
this, _base);
369 d->intSpinBox->setObjectName(
"KIntNumInput::KIntSpinBox");
375 kWarning() <<
"WARNING: Validation is broken in KIntNumInput! Needs to be fixed.";
379 connect(d->intSpinBox, SIGNAL(
valueChanged(
int)), SLOT(spinValueChanged(
int)));
381 SLOT(slotEmitRelativeValueChanged(
int)));
383 setFocusProxy(d->intSpinBox);
391 d->referencePoint =
ref;
396 return d->referencePoint;
399void KIntNumInput::spinValueChanged(
int val)
404 priv->slider->setValue(val);
410void KIntNumInput::slotEmitRelativeValueChanged(
int value)
412 if (d->blockRelative || !d->referencePoint) {
423 priv->slider =
new QSlider(Qt::Horizontal,
this);
425 d->intSpinBox, SLOT(
setValue(
int)));
426 priv->slider->setTickPosition(QSlider::TicksBelow);
430 const int value = d->intSpinBox->value();
431 priv->slider->setRange(d->intSpinBox->minimum(), d->intSpinBox->maximum());
432 priv->slider->setPageStep(d->intSpinBox->singleStep());
433 priv->slider->setValue(value);
436 const int major =
calcDiffByTen(d->intSpinBox->maximum(), d->intSpinBox->minimum());
438 priv->slider->setSingleStep(d->intSpinBox->singleStep());
439 priv->slider->setPageStep(qMax(1, major));
440 priv->slider->setTickInterval(major);
452 if (upper < lower || singleStep <= 0) {
453 kWarning() <<
"WARNING: KIntNumInput::setRange() called with bad arguments. Ignoring call...";
457 d->intSpinBox->setMinimum(lower);
458 d->intSpinBox->setMaximum(upper);
459 d->intSpinBox->setSingleStep(singleStep);
461 singleStep = d->intSpinBox->singleStep();
473#ifndef KDE_NO_DEPRECATED
483 setRange(min, d->intSpinBox->maximum(), d->intSpinBox->singleStep());
488 return d->intSpinBox->minimum();
493 setRange(d->intSpinBox->minimum(), max, d->intSpinBox->singleStep());
498 return d->intSpinBox->maximum();
503 return d->intSpinBox->singleStep();
508 d->intSpinBox->setSingleStep(singleStep);
513 d->intSpinBox->setSuffix(suffix);
520 d->intSpinBox->setSuffix(suffix);
526 return d->intSpinBox->suffix();
531 d->intSpinBox->setPrefix(
prefix);
538 return d->intSpinBox->prefix();
543 d->intSpinBox->setEditFocus(mark);
554 h = qMax(d->intSpinBoxSize.height(), priv->sliderSize.height());
557 if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) {
558 h += 4 + priv->labelSize.height();
561 h = qMax(h, priv->labelSize.height() + 2);
565 w += priv->column1Width + priv->column2Width;
567 if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) {
568 w = qMax(w, priv->labelSize.width() + 4);
578 d->intSpinBoxSize = d->intSpinBox->sizeHint();
579 priv->column2Width = d->intSpinBoxSize.width();
582 priv->label->setBuddy(d->intSpinBox);
590 int w = priv->column1Width;
593 if (priv->label && (priv->labelAlignment & Qt::AlignTop)) {
594 priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height());
598 if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) {
599 priv->label->setGeometry(0, 0, w, d->intSpinBoxSize.height());
602 if (qApp->layoutDirection() == Qt::RightToLeft) {
603 d->intSpinBox->setGeometry(w, h, priv->slider ? priv->column2Width : qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height());
607 priv->slider->setGeometry(w, h, e->size().width() - w, d->intSpinBoxSize.height() +
KDialog::spacingHint());
609 }
else if (priv->slider) {
611 d->intSpinBox->setGeometry(w + priv->slider->size().width() +
KDialog::spacingHint(), h, priv->column2Width, d->intSpinBoxSize.height());
613 d->intSpinBox->setGeometry(w, h, qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height());
616 h += d->intSpinBoxSize.height() + 2;
618 if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) {
619 priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height());
630 d->intSpinBox->setValue(val);
636 if (!d->referencePoint) {
640 setValue(qRound(d->referencePoint * r + 0.5));
646 if (!d->referencePoint) {
649 return double(value()) / double(d->referencePoint);
654 return d->intSpinBox->value();
659 d->intSpinBox->setSpecialValueText(text);
665 return d->intSpinBox->specialValueText();
675 priv->label->setBuddy(d->intSpinBox);
681class KDoubleNumInput::KDoubleNumInputPrivate
684 KDoubleNumInputPrivate(
double r)
688 exponentRatio(1.0) {}
689 QDoubleSpinBox * spin;
690 double referencePoint;
693 QString specialValue;
694 double exponentRatio;
699 , d(new KDoubleNumInputPrivate(0.0))
702 init(0.0, 0.0, 9999.0, 0.01, 2);
706 double singleStep,
int precision)
708 , d(new KDoubleNumInputPrivate(value))
710 init(value, lower, upper, singleStep, precision);
713#ifndef KDE_NO_DEPRECATED
715 double lower,
double upper,
double value,
QWidget *parent,
716 double singleStep,
int precision)
718 , d(new KDoubleNumInputPrivate(value))
720 init(value, lower, upper, singleStep, precision);
731 return d->specialValue;
735void KDoubleNumInput::init(
double value,
double lower,
double upper,
736 double singleStep,
int precision)
738 d->spin =
new QDoubleSpinBox(
this);
739 d->spin->setRange(lower, upper);
740 d->spin->setSingleStep(singleStep);
741 d->spin->setValue(value);
742 d->spin->setDecimals(precision);
744 d->spin->setObjectName(
"KDoubleNumInput::QDoubleSpinBox");
745 setFocusProxy(d->spin);
746 connect(d->spin, SIGNAL(valueChanged(
double)),
747 this, SIGNAL(valueChanged(
double)));
748 connect(
this, SIGNAL(valueChanged(
double)),
749 this, SLOT(slotEmitRelativeValueChanged(
double)));
751 updateLegacyMembers();
756void KDoubleNumInput::updateLegacyMembers()
761double KDoubleNumInput::mapSliderToSpin(
int val)
const
766 const double spinmin = d->spin->minimum();
767 const double spinmax = d->spin->maximum();
768 const double slidemin = priv->slider->minimum();
769 const double slidemax = priv->slider->maximum();
770 const double rel = (double(val) - slidemin) / (slidemax - slidemin);
771 Q_ASSERT(d->exponentRatio > 0.0);
772 return spinmin + pow(rel, d->exponentRatio ) * (spinmax - spinmin);
775void KDoubleNumInput::sliderMoved(
int val)
777 d->spin->setValue(mapSliderToSpin(val));
780void KDoubleNumInput::spinBoxChanged(
double val)
784 const double spinmin = d->spin->minimum();
785 const double spinmax = d->spin->maximum();
786 const double slidemin = priv->slider->minimum();
787 const double slidemax = priv->slider->maximum();
789 Q_ASSERT(d->exponentRatio > 0.0);
790 const double rel = pow((val - spinmin) / (spinmax - spinmin) , 1.0 / d->exponentRatio);
793 priv->slider->blockSignals(
true);
794 priv->slider->setValue(qRound(slidemin + rel * (slidemax - slidemin)));
795 priv->slider->blockSignals(
false);
799void KDoubleNumInput::slotEmitRelativeValueChanged(
double value)
801 if (!d->referencePoint) {
816 h = qMax(d->editSize.height(), priv->sliderSize.height());
819 if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) {
820 h += 4 + priv->labelSize.height();
823 h = qMax(h, priv->labelSize.height() + 2);
827 w += priv->column1Width + priv->column2Width;
829 if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) {
830 w = qMax(w, priv->labelSize.width() + 4);
840 int w = priv->column1Width;
843 if (priv->label && (priv->labelAlignment & Qt::AlignTop)) {
844 priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height());
845 h += priv->labelSize.height() + 4;
848 if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) {
849 priv->label->setGeometry(0, 0, w, d->editSize.height());
852 if (qApp->layoutDirection() == Qt::RightToLeft) {
853 d->spin->setGeometry(w, h, priv->slider ? priv->column2Width
854 : e->size().width() - w, d->editSize.height());
858 priv->slider->setGeometry(w, h, e->size().width() - w, d->editSize.height() +
KDialog::spacingHint());
859 }
else if (priv->slider) {
860 priv->slider->setGeometry(w, h, e->size().width() -
864 priv->column2Width, d->editSize.height());
866 d->spin->setGeometry(w, h, e->size().width() - w, d->editSize.height());
869 h += d->editSize.height() + 2;
871 if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) {
872 priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height());
880 d->editSize = d->spin->sizeHint();
881 priv->column2Width = d->editSize.width();
886 d->spin->setValue(val);
891 if (!d->referencePoint) {
903 d->referencePoint =
ref;
913 QDoubleSpinBox * spin = d->spin;
917 d->spin->setRange(lower, upper);
918 d->spin->setSingleStep(singleStep);
925 updateLegacyMembers();
932 QDoubleSpinBox * spin = d->spin;
933 const double range = spin->maximum() - spin->minimum();
934 const double steps = range * pow(10.0, spin->decimals());
936 priv->slider =
new QSlider(Qt::Horizontal,
this);
937 priv->slider->setTickPosition(QSlider::TicksBelow);
940 SLOT(sliderMoved(
int)));
943 if (steps > 1000 || d->exponentRatio != 1.0) {
944 priv->slider->setRange(0, 1000);
945 priv->slider->setSingleStep(1);
946 priv->slider->setPageStep(50);
948 const int singleSteps = qRound(steps);
949 priv->slider->setRange(0, singleSteps);
950 priv->slider->setSingleStep(1);
951 const int pageSteps = qBound(1, singleSteps / 20, 10);
952 priv->slider->setPageStep(pageSteps);
954 spinBoxChanged(spin->value());
955 connect(spin, SIGNAL(
valueChanged(
double)), SLOT(spinBoxChanged(
double)));
974 return d->spin->minimum();
985 return d->spin->maximum();
990 return d->spin->singleStep();
995 d->spin->setSingleStep(singleStep);
1000 return d->spin->value();
1005 if (!d->referencePoint) {
1008 return value() / d->referencePoint;
1013 return d->referencePoint;
1018 return d->spin->suffix();
1023 return d->spin->prefix();
1028 d->spin->setSuffix(suffix);
1035 d->spin->setPrefix(
prefix);
1042 d->spin->setDecimals(decimals);
1049 return d->spin->decimals();
1054 d->spin->setSpecialValueText(text);
1057 updateLegacyMembers();
1067 priv->label->setBuddy(d->spin);
1073 return d->exponentRatio;
1078 Q_ASSERT(dbl > 0.0);
1080 d->exponentRatio = dbl;
1081 spinBoxChanged( d->spin->value() );
1083 kError() <<
"ExponentRatio need to be strictly positive.";
1088#include "knuminput.moc"
static int spacingHint()
Returns the number of pixels that should be used between widgets inside a dialog according to the KDE...
A QSpinBox with support for arbitrary base numbers.
virtual ~KIntSpinBox()
Destructor.
void setBase(int base)
Sets the base in which the numbers in the spin box are represented.
virtual QString textFromValue(int) const
Overloaded the method in QSpinBox to make use of the base given in the constructor.
void setEditFocus(bool mark)
sets focus and optionally marks all text
KIntSpinBox(QWidget *parent=0)
Constructor.
void setSuffix(const KLocalizedString &suffix)
Sets the suffix to suffix.
virtual int valueFromText(const QString &text) const
Overloaded the method in QSpinBox to make use of the base given in the constructor.
KLocalizedString subs(const QString &a, int fieldWidth=0, const QChar &fillChar=QLatin1Char(' ')) const
QString label(StandardShortcut id)
Returns a localized label for user-visible display.