KDELibs4Support

knuminput.cpp
1 /* This file is part of the KDE libraries
2  * Initial implementation:
3  * Copyright (c) 1997 Patrick Dowler <[email protected]>
4  * Rewritten and maintained by:
5  * Copyright (c) 2000 Dirk Mueller <[email protected]>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include "knuminput.h"
24 
25 #include <config-kdelibs4support.h>
26 #if HAVE_LIMITS_H
27 #include <limits.h>
28 #endif
29 
30 #include <cmath>
31 
32 #include <QApplication>
33 #include <QLabel>
34 #include <QLineEdit>
35 #include <QResizeEvent>
36 #include <QSlider>
37 #include <QStyle>
38 
39 #include <kconfigdialogmanager.h>
40 #include <kdebug.h>
41 #include <klocalizedstring.h>
42 
43 static inline int calcDiffByTen(int x, int y)
44 {
45  // calculate ( x - y ) / 10 without overflowing ints:
46  return (x / 10) - (y / 10) + (x % 10 - y % 10) / 10;
47 }
48 
49 // ----------------------------------------------------------------------------
50 
51 class KNumInputPrivate
52 {
53 public:
54  KNumInputPrivate(KNumInput *q, KNumInput *below = nullptr) :
55  q(q),
56  previousNumInput(nullptr),
57  nextNumInput(nullptr),
58  column1Width(0),
59  column2Width(0),
60  label(nullptr),
61  slider(nullptr),
62  labelAlignment(nullptr)
63  {
64  if (below) {
65  nextNumInput = below->d->nextNumInput;
66  previousNumInput = below;
67  below->d->nextNumInput = q;
68  if (nextNumInput) {
69  nextNumInput->d->previousNumInput = q;
70  }
71  }
72  }
73 
74  static KNumInputPrivate *get(const KNumInput *i)
75  {
76  return i->d;
77  }
78 
79  KNumInput *q;
80  KNumInput *previousNumInput, *nextNumInput;
81  int column1Width, column2Width;
82 
83  QLabel *label;
84  QSlider *slider;
85  QSize sliderSize, labelSize;
86 
87  Qt::Alignment labelAlignment;
88 };
89 
90 #define K_USING_KNUMINPUT_P(_d) KNumInputPrivate *_d = KNumInputPrivate::get(this)
91 
93  : QWidget(parent), d(new KNumInputPrivate(this))
94 {
95  setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
96  setFocusPolicy(Qt::StrongFocus);
97  KConfigDialogManager::changedMap()->insert("KIntNumInput", SIGNAL(valueChanged(int)));
98  KConfigDialogManager::changedMap()->insert("KIntSpinBox", SIGNAL(valueChanged(int)));
99  KConfigDialogManager::changedMap()->insert("KDoubleSpinBox", SIGNAL(valueChanged(double)));
100 }
101 
102 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
104  : QWidget(parent), d(new KNumInputPrivate(this, below))
105 {
106  setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
107  setFocusPolicy(Qt::StrongFocus);
108 }
109 #endif
110 
112 {
113  if (d->previousNumInput) {
114  d->previousNumInput->d->nextNumInput = d->nextNumInput;
115  }
116 
117  if (d->nextNumInput) {
118  d->nextNumInput->d->previousNumInput = d->previousNumInput;
119  }
120 
121  delete d;
122 }
123 
125 {
126  return d->slider;
127 }
128 
130 {
131  return d->slider;
132 }
133 
135 {
136  if (label.isEmpty()) {
137  delete d->label;
138  d->label = nullptr;
139  d->labelAlignment = nullptr;
140  } else {
141  if (!d->label) {
142  d->label = new QLabel(this);
143  }
144  d->label->setText(label);
145  d->label->setObjectName("KNumInput::QLabel");
146  d->label->setAlignment(a);
147  // if no vertical alignment set, use Top alignment
148  if (!(a & (Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter))) {
149  a |= Qt::AlignTop;
150  }
151  d->labelAlignment = a;
152  }
153 
154  layout(true);
155 }
156 
158 {
159  return d->label ? d->label->text() : QString();
160 }
161 
162 void KNumInput::layout(bool deep)
163 {
164  int w1 = d->column1Width;
165  int w2 = d->column2Width;
166 
167  // label sizeHint
168  d->labelSize = (d->label ? d->label->sizeHint() : QSize(0, 0));
169 
170  if (d->label && (d->labelAlignment & Qt::AlignVCenter)) {
171  d->column1Width = d->labelSize.width() + 4;
172  } else {
173  d->column1Width = 0;
174  }
175 
176  // slider sizeHint
177  d->sliderSize = (d->slider ? d->slider->sizeHint() : QSize(0, 0));
178 
179  doLayout();
180 
181  if (!deep) {
182  d->column1Width = w1;
183  d->column2Width = w2;
184  return;
185  }
186 
187  w2 = d->column2Width;
188 
189  KNumInput *p = d->previousNumInput;
190  while (p) {
191  p->doLayout();
192  w1 = qMax(w1, p->d->column1Width);
193  w2 = qMax(w2, p->d->column2Width);
194  p = p->d->previousNumInput;
195  }
196 
197  p = d->nextNumInput;
198  while (p) {
199  p->doLayout();
200  w1 = qMax(w1, p->d->column1Width);
201  w2 = qMax(w2, p->d->column2Width);
202  p = p->d->nextNumInput;
203  }
204 
205  p = this;
206  while (p) {
207  p->d->column1Width = w1;
208  p->d->column2Width = w2;
209  p = p->d->previousNumInput;
210  }
211 
212  p = d->nextNumInput;
213  while (p) {
214  p->d->column1Width = w1;
215  p->d->column2Width = w2;
216  p = p->d->nextNumInput;
217  }
218 
219 // kDebug() << "w1 " << w1 << " w2 " << w2;
220 }
221 
223 {
224  return minimumSizeHint();
225 }
226 
227 void KNumInput::setSteps(int minor, int major)
228 {
229  if (d->slider) {
230  d->slider->setSingleStep(minor);
231  d->slider->setPageStep(major);
232  }
233 }
234 
235 // ----------------------------------------------------------------------------
236 
237 class Q_DECL_HIDDEN KIntSpinBox::KIntSpinBoxPrivate
238 {
239 public:
240  KIntSpinBoxPrivate(KIntSpinBox *q, int val_base = 10): q(q), val_base(val_base)
241  {
242  connect(q, SIGNAL(valueChanged(int)), q, SLOT(updateSuffix(int)));
243  }
244 
245  void updateSuffix(int value)
246  {
247  if (!pluralSuffix.isEmpty()) {
248  KLocalizedString s = pluralSuffix;
249  q->setSuffix(s.subs(value).toString());
250  }
251  }
252 
253  KIntSpinBox *q;
254  int val_base;
255  KLocalizedString pluralSuffix;
256 };
257 
259  : QSpinBox(parent), d(new KIntSpinBoxPrivate(this))
260 {
261  setValue(0);
262 }
263 
265 {
266  delete d;
267 }
268 
270  : QSpinBox(parent), d(new KIntSpinBoxPrivate(this, base))
271 {
272  setRange(lower, upper);
273  setSingleStep(singleStep);
274  setValue(value);
275 }
276 
278 {
279  d->val_base = base;
280 }
281 
282 int KIntSpinBox::base() const
283 {
284  return d->val_base;
285 }
286 
288 {
289  return QString::number(v, d->val_base);
290 }
291 
293 {
294  bool ok;
295  QString theText = text;
296  if (theText.startsWith(prefix())) {
297  theText.remove(0, prefix().length());
298  }
299  if (theText.endsWith(suffix())) {
300  theText.chop(suffix().length());
301  }
302  return theText.trimmed().toInt(&ok, d->val_base);
303 }
304 
306 {
307  lineEdit()->setFocus();
308  if (mark) {
309  lineEdit()->selectAll();
310  }
311 }
312 
314 {
315  d->pluralSuffix = suffix;
316  if (suffix.isEmpty()) {
317  setSuffix(QString());
318  } else {
319  d->updateSuffix(value());
320  }
321 }
322 
323 // ----------------------------------------------------------------------------
324 
325 class Q_DECL_HIDDEN KIntNumInput::KIntNumInputPrivate
326 {
327 public:
328  KIntNumInput *q;
329  int referencePoint;
330  short blockRelative;
331  KIntSpinBox *intSpinBox;
332  QSize intSpinBoxSize;
333 
334  KIntNumInputPrivate(KIntNumInput *q, int r)
335  : q(q),
336  referencePoint(r),
337  blockRelative(0) {}
338 };
339 
340 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
341 KIntNumInput::KIntNumInput(KNumInput *below, int val, QWidget *parent, int _base)
342  : KNumInput(parent, below)
343  , d(new KIntNumInputPrivate(this, val))
344 {
345  initWidget(val, _base);
346 }
347 #endif
348 
350  : KNumInput(parent)
351  , d(new KIntNumInputPrivate(this, 0))
352 {
353  initWidget(0, 10);
354 }
355 
357  : KNumInput(parent)
358  , d(new KIntNumInputPrivate(this, val))
359 {
360  initWidget(val, _base);
361 }
362 
364 {
365  return d->intSpinBox;
366 }
367 
368 void KIntNumInput::initWidget(int val, int _base)
369 {
370  d->intSpinBox = new KIntSpinBox(INT_MIN, INT_MAX, 1, val, this, _base);
371  d->intSpinBox->setObjectName("KIntNumInput::KIntSpinBox");
372  // the KIntValidator is broken beyond believe for
373  // spinboxes which have suffix or prefix texts, so
374  // better don't use it unless absolutely necessary
375 
376  if (_base != 10) {
377  kWarning() << "WARNING: Validation is broken in KIntNumInput! Needs to be fixed.";
378 // d->intSpinBox->setValidator(new KIntValidator(this, _base, "KNumInput::KIntValidator"));
379  }
380 
381  connect(d->intSpinBox, SIGNAL(valueChanged(int)), SLOT(spinValueChanged(int)));
382  connect(this, SIGNAL(valueChanged(int)),
383  SLOT(slotEmitRelativeValueChanged(int)));
384 
385  setFocusProxy(d->intSpinBox);
386  layout(true);
387 }
388 
390 {
391  // clip to valid range:
392  ref = qMin(maximum(), qMax(minimum(), ref));
393  d->referencePoint = ref;
394 }
395 
397 {
398  return d->referencePoint;
399 }
400 
401 void KIntNumInput::spinValueChanged(int val)
402 {
403  K_USING_KNUMINPUT_P(priv);
404 
405  if (priv->slider) {
406  priv->slider->setValue(val);
407  }
408 
409  emit valueChanged(val);
410 }
411 
412 void KIntNumInput::slotEmitRelativeValueChanged(int value)
413 {
414  if (d->blockRelative || !d->referencePoint) {
415  return;
416  }
417  emit relativeValueChanged(double(value) / double(d->referencePoint));
418 }
419 
421 {
422  K_USING_KNUMINPUT_P(priv);
423  if (slider) {
424  if (!priv->slider) {
425  priv->slider = new QSlider(Qt::Horizontal, this);
426  connect(priv->slider, SIGNAL(valueChanged(int)),
427  d->intSpinBox, SLOT(setValue(int)));
428  priv->slider->setTickPosition(QSlider::TicksBelow);
429  layout(true);
430  }
431 
432  const int value = d->intSpinBox->value();
433  priv->slider->setRange(d->intSpinBox->minimum(), d->intSpinBox->maximum());
434  priv->slider->setPageStep(d->intSpinBox->singleStep());
435  priv->slider->setValue(value);
436 
437  // calculate (upper-lower)/10 without overflowing int's:
438  const int major = calcDiffByTen(d->intSpinBox->maximum(), d->intSpinBox->minimum());
439 
440  priv->slider->setSingleStep(d->intSpinBox->singleStep());
441  priv->slider->setPageStep(qMax(1, major));
442  priv->slider->setTickInterval(major);
443  } else {
444  if (priv->slider) {
445  layout(true);
446  }
447  delete priv->slider;
448  priv->slider = nullptr;
449  }
450 }
451 
452 void KIntNumInput::setRange(int lower, int upper, int singleStep)
453 {
454  if (upper < lower || singleStep <= 0) {
455  kWarning() << "WARNING: KIntNumInput::setRange() called with bad arguments. Ignoring call...";
456  return;
457  }
458 
459  d->intSpinBox->setMinimum(lower);
460  d->intSpinBox->setMaximum(upper);
461  d->intSpinBox->setSingleStep(singleStep);
462 
463  singleStep = d->intSpinBox->singleStep(); // maybe QRangeControl didn't like our lineStep?
464 
465  // check that reference point is still inside valid range:
467 
468  layout(true);
469 
470  // update slider information if it's shown
471  K_USING_KNUMINPUT_P(priv);
472  setSliderEnabled(priv->slider);
473 }
474 
475 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
476 void KIntNumInput::setRange(int lower, int upper, int singleStep, bool slider)
477 {
478  setRange(lower, upper, singleStep);
479  setSliderEnabled(slider);
480 }
481 #endif
482 
484 {
485  setRange(min, d->intSpinBox->maximum(), d->intSpinBox->singleStep());
486 }
487 
488 int KIntNumInput::minimum() const
489 {
490  return d->intSpinBox->minimum();
491 }
492 
494 {
495  setRange(d->intSpinBox->minimum(), max, d->intSpinBox->singleStep());
496 }
497 
498 int KIntNumInput::maximum() const
499 {
500  return d->intSpinBox->maximum();
501 }
502 
503 int KIntNumInput::singleStep() const
504 {
505  return d->intSpinBox->singleStep();
506 }
507 
509 {
510  d->intSpinBox->setSingleStep(singleStep);
511 }
512 
514 {
515  d->intSpinBox->setSuffix(suffix);
516 
517  layout(true);
518 }
519 
521 {
522  d->intSpinBox->setSuffix(suffix);
523  layout(true);
524 }
525 
527 {
528  return d->intSpinBox->suffix();
529 }
530 
532 {
533  d->intSpinBox->setPrefix(prefix);
534 
535  layout(true);
536 }
537 
539 {
540  return d->intSpinBox->prefix();
541 }
542 
544 {
545  d->intSpinBox->setEditFocus(mark);
546 }
547 
549 {
550  K_USING_KNUMINPUT_P(priv);
551  ensurePolished();
552 
553  int w;
554  int h;
555 
556  h = qMax(d->intSpinBoxSize.height(), priv->sliderSize.height());
557 
558  // if in extra row, then count it here
559  if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) {
560  h += 4 + priv->labelSize.height();
561  } else {
562  // label is in the same row as the other widgets
563  h = qMax(h, priv->labelSize.height() + 2);
564  }
565 
566  const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
567  w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0;
568  w += priv->column1Width + priv->column2Width;
569 
570  if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) {
571  w = qMax(w, priv->labelSize.width() + 4);
572  }
573 
574  return QSize(w, h);
575 }
576 
578 {
579  K_USING_KNUMINPUT_P(priv);
580 
581  d->intSpinBoxSize = d->intSpinBox->sizeHint();
582  priv->column2Width = d->intSpinBoxSize.width();
583 
584  if (priv->label) {
585  priv->label->setBuddy(d->intSpinBox);
586  }
587 }
588 
589 void KIntNumInput::resizeEvent(QResizeEvent *e)
590 {
591  K_USING_KNUMINPUT_P(priv);
592 
593  int w = priv->column1Width;
594  int h = 0;
595  const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
596 
597  if (priv->label && (priv->labelAlignment & Qt::AlignTop)) {
598  priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height());
599  h += priv->labelSize.height() + spacingHint;
600  }
601 
602  if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) {
603  priv->label->setGeometry(0, 0, w, d->intSpinBoxSize.height());
604  }
605 
606  if (qApp->layoutDirection() == Qt::RightToLeft) {
607  d->intSpinBox->setGeometry(w, h, priv->slider ? priv->column2Width : qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height());
608  w += priv->column2Width + spacingHint;
609 
610  if (priv->slider) {
611  priv->slider->setGeometry(w, h, e->size().width() - w, d->intSpinBoxSize.height() + spacingHint);
612  }
613  } else if (priv->slider) {
614  priv->slider->setGeometry(w, h, e->size().width() - (w + priv->column2Width + spacingHint), d->intSpinBoxSize.height() + spacingHint);
615  d->intSpinBox->setGeometry(w + priv->slider->size().width() + spacingHint, h, priv->column2Width, d->intSpinBoxSize.height());
616  } else {
617  d->intSpinBox->setGeometry(w, h, qMax(priv->column2Width, e->size().width() - w), d->intSpinBoxSize.height());
618  }
619 
620  h += d->intSpinBoxSize.height() + 2;
621 
622  if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) {
623  priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height());
624  }
625 }
626 
628 {
629  delete d;
630 }
631 
633 {
634  d->intSpinBox->setValue(val);
635  // slider value is changed by spinValueChanged
636 }
637 
639 {
640  if (!d->referencePoint) {
641  return;
642  }
643  ++d->blockRelative;
644  setValue(qRound(d->referencePoint * r + 0.5));
645  --d->blockRelative;
646 }
647 
648 double KIntNumInput::relativeValue() const
649 {
650  if (!d->referencePoint) {
651  return 0;
652  }
653  return double(value()) / double(d->referencePoint);
654 }
655 
656 int KIntNumInput::value() const
657 {
658  return d->intSpinBox->value();
659 }
660 
662 {
663  d->intSpinBox->setSpecialValueText(text);
664  layout(true);
665 }
666 
668 {
669  return d->intSpinBox->specialValueText();
670 }
671 
673 {
674  K_USING_KNUMINPUT_P(priv);
675 
676  KNumInput::setLabel(label, a);
677 
678  if (priv->label) {
679  priv->label->setBuddy(d->intSpinBox);
680  }
681 }
682 
683 // ----------------------------------------------------------------------------
684 
685 class Q_DECL_HIDDEN KDoubleNumInput::KDoubleNumInputPrivate
686 {
687 public:
688  KDoubleNumInputPrivate(double r)
689  : spin(nullptr),
690  referencePoint(r),
691  blockRelative(0),
692  exponentRatio(1.0) {}
693  QDoubleSpinBox *spin;
694  double referencePoint;
695  short blockRelative;
696  QSize editSize;
697  QString specialValue;
698  double exponentRatio;
699 };
700 
702  : KNumInput(parent)
703  , d(new KDoubleNumInputPrivate(0.0))
704 
705 {
706  initWidget(0.0, 0.0, 9999.0, 0.01, 2);
707 }
708 
709 KDoubleNumInput::KDoubleNumInput(double lower, double upper, double value, QWidget *parent,
710  double singleStep, int precision)
711  : KNumInput(parent)
712  , d(new KDoubleNumInputPrivate(value))
713 {
714  initWidget(value, lower, upper, singleStep, precision);
715 }
716 
717 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
719  double lower, double upper, double value, QWidget *parent,
720  double singleStep, int precision)
721  : KNumInput(parent, below)
722  , d(new KDoubleNumInputPrivate(value))
723 {
724  initWidget(value, lower, upper, singleStep, precision);
725 }
726 #endif
727 
729 {
730  delete d;
731 }
732 
734 {
735  return d->specialValue;
736 }
737 
738 void KDoubleNumInput::initWidget(double value, double lower, double upper,
739  double singleStep, int precision)
740 {
741  d->spin = new QDoubleSpinBox(this);
742  d->spin->setRange(lower, upper);
743  d->spin->setSingleStep(singleStep);
744  d->spin->setValue(value);
745  d->spin->setDecimals(precision);
746 
747  d->spin->setObjectName("KDoubleNumInput::QDoubleSpinBox");
748  setFocusProxy(d->spin);
749  connect(d->spin, SIGNAL(valueChanged(double)),
750  this, SIGNAL(valueChanged(double)));
751  connect(this, SIGNAL(valueChanged(double)),
752  this, SLOT(slotEmitRelativeValueChanged(double)));
753 
754  updateLegacyMembers();
755 
756  layout(true);
757 }
758 
759 void KDoubleNumInput::updateLegacyMembers()
760 {
761  d->specialValue = specialValueText();
762 }
763 
764 double KDoubleNumInput::mapSliderToSpin(int val) const
765 {
766  K_USING_KNUMINPUT_P(priv);
767 
768  // map [slidemin,slidemax] to [spinmin,spinmax]
769  const double spinmin = d->spin->minimum();
770  const double spinmax = d->spin->maximum();
771  const double slidemin = priv->slider->minimum(); // cast int to double to avoid
772  const double slidemax = priv->slider->maximum(); // overflow in rel denominator
773  const double rel = (double(val) - slidemin) / (slidemax - slidemin);
774  Q_ASSERT(d->exponentRatio > 0.0);
775  return spinmin + pow(rel, d->exponentRatio) * (spinmax - spinmin);
776 }
777 
778 void KDoubleNumInput::sliderMoved(int val)
779 {
780  d->spin->setValue(mapSliderToSpin(val));
781 }
782 
783 void KDoubleNumInput::spinBoxChanged(double val)
784 {
785  K_USING_KNUMINPUT_P(priv);
786 
787  const double spinmin = d->spin->minimum();
788  const double spinmax = d->spin->maximum();
789  const double slidemin = priv->slider->minimum(); // cast int to double to avoid
790  const double slidemax = priv->slider->maximum(); // overflow in rel denominator
791 
792  Q_ASSERT(d->exponentRatio > 0.0);
793  const double rel = pow((val - spinmin) / (spinmax - spinmin), 1.0 / d->exponentRatio);
794 
795  if (priv->slider) {
796  priv->slider->blockSignals(true);
797  priv->slider->setValue(qRound(slidemin + rel * (slidemax - slidemin)));
798  priv->slider->blockSignals(false);
799  }
800 }
801 
802 void KDoubleNumInput::slotEmitRelativeValueChanged(double value)
803 {
804  if (!d->referencePoint) {
805  return;
806  }
807  emit relativeValueChanged(value / d->referencePoint);
808 }
809 
810 QSize KDoubleNumInput::minimumSizeHint() const
811 {
812  K_USING_KNUMINPUT_P(priv);
813 
814  ensurePolished();
815 
816  int w;
817  int h;
818 
819  h = qMax(d->editSize.height(), priv->sliderSize.height());
820 
821  // if in extra row, then count it here
822  if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) {
823  h += 4 + priv->labelSize.height();
824  } else {
825  // label is in the same row as the other widgets
826  h = qMax(h, priv->labelSize.height() + 2);
827  }
828 
829  const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
830  w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0;
831  w += priv->column1Width + priv->column2Width;
832 
833  if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) {
834  w = qMax(w, priv->labelSize.width() + 4);
835  }
836 
837  return QSize(w, h);
838 }
839 
840 void KDoubleNumInput::resizeEvent(QResizeEvent *e)
841 {
842  K_USING_KNUMINPUT_P(priv);
843 
844  int w = priv->column1Width;
845  int h = 0;
846  const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
847 
848  if (priv->label && (priv->labelAlignment & Qt::AlignTop)) {
849  priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height());
850  h += priv->labelSize.height() + 4;
851  }
852 
853  if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) {
854  priv->label->setGeometry(0, 0, w, d->editSize.height());
855  }
856 
857  if (qApp->layoutDirection() == Qt::RightToLeft) {
858  d->spin->setGeometry(w, h, priv->slider ? priv->column2Width
859  : e->size().width() - w, d->editSize.height());
860  w += priv->column2Width + spacingHint;
861 
862  if (priv->slider) {
863  priv->slider->setGeometry(w, h, e->size().width() - w, d->editSize.height() + spacingHint);
864  }
865  } else if (priv->slider) {
866  priv->slider->setGeometry(w, h, e->size().width() -
867  (priv->column1Width + priv->column2Width + spacingHint),
868  d->editSize.height() + spacingHint);
869  d->spin->setGeometry(w + priv->slider->width() + spacingHint, h,
870  priv->column2Width, d->editSize.height());
871  } else {
872  d->spin->setGeometry(w, h, e->size().width() - w, d->editSize.height());
873  }
874 
875  h += d->editSize.height() + 2;
876 
877  if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) {
878  priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height());
879  }
880 }
881 
883 {
884  K_USING_KNUMINPUT_P(priv);
885 
886  d->editSize = d->spin->sizeHint();
887  priv->column2Width = d->editSize.width();
888 }
889 
891 {
892  d->spin->setValue(val);
893 }
894 
896 {
897  if (!d->referencePoint) {
898  return;
899  }
900  ++d->blockRelative;
901  setValue(r * d->referencePoint);
902  --d->blockRelative;
903 }
904 
906 {
907  // clip to valid range:
908  ref = qMin(maximum(), qMax(minimum(), ref));
909  d->referencePoint = ref;
910 }
911 
912 void KDoubleNumInput::setRange(double lower, double upper, double singleStep,
913  bool slider)
914 {
915  K_USING_KNUMINPUT_P(priv);
916 
917  if (priv->slider) {
918  // don't update the slider to avoid an endless recursion
919  QDoubleSpinBox *spin = d->spin;
920  disconnect(spin, SIGNAL(valueChanged(double)),
921  priv->slider, SLOT(setValue(int)));
922  }
923  d->spin->setRange(lower, upper);
924  d->spin->setSingleStep(singleStep);
925 
926  setSliderEnabled(slider);
927 
929 
930  layout(true);
931  updateLegacyMembers();
932 }
933 
935 {
936  K_USING_KNUMINPUT_P(priv);
937  if (enabled) {
938  QDoubleSpinBox *spin = d->spin;
939  const double range = spin->maximum() - spin->minimum();
940  const double steps = range * pow(10.0, spin->decimals());
941  if (!priv->slider) {
942  priv->slider = new QSlider(Qt::Horizontal, this);
943  priv->slider->setTickPosition(QSlider::TicksBelow);
944  // feedback line: when one moves, the other moves, too:
945  connect(priv->slider, SIGNAL(valueChanged(int)),
946  SLOT(sliderMoved(int)));
947  layout(true);
948  }
949  if (steps > 1000 || d->exponentRatio != 1.0) {
950  priv->slider->setRange(0, 1000);
951  priv->slider->setSingleStep(1);
952  priv->slider->setPageStep(50);
953  } else {
954  const int singleSteps = qRound(steps);
955  priv->slider->setRange(0, singleSteps);
956  priv->slider->setSingleStep(1);
957  const int pageSteps = qBound(1, singleSteps / 20, 10);
958  priv->slider->setPageStep(pageSteps);
959  }
960  spinBoxChanged(spin->value());
961  connect(spin, SIGNAL(valueChanged(double)), SLOT(spinBoxChanged(double)));
962  } else {
963  if (priv->slider) {
964  layout(true);
965  }
966  delete priv->slider;
967  priv->slider = nullptr;
968  }
969 }
970 
972 {
973  K_USING_KNUMINPUT_P(priv);
974  setRange(min, maximum(), d->spin->singleStep(), priv->slider);
975 }
976 
977 double KDoubleNumInput::minimum() const
978 {
979  return d->spin->minimum();
980 }
981 
983 {
984  K_USING_KNUMINPUT_P(priv);
985  setRange(minimum(), max, d->spin->singleStep(), priv->slider);
986 }
987 
988 double KDoubleNumInput::maximum() const
989 {
990  return d->spin->maximum();
991 }
992 
993 double KDoubleNumInput::singleStep() const
994 {
995  return d->spin->singleStep();
996 }
997 
998 void KDoubleNumInput::setSingleStep(double singleStep)
999 {
1000  d->spin->setSingleStep(singleStep);
1001 }
1002 
1003 double KDoubleNumInput::value() const
1004 {
1005  return d->spin->value();
1006 }
1007 
1008 double KDoubleNumInput::relativeValue() const
1009 {
1010  if (!d->referencePoint) {
1011  return 0;
1012  }
1013  return value() / d->referencePoint;
1014 }
1015 
1016 double KDoubleNumInput::referencePoint() const
1017 {
1018  return d->referencePoint;
1019 }
1020 
1022 {
1023  return d->spin->suffix();
1024 }
1025 
1027 {
1028  return d->spin->prefix();
1029 }
1030 
1032 {
1033  d->spin->setSuffix(suffix);
1034 
1035  layout(true);
1036 }
1037 
1039 {
1040  d->spin->setPrefix(prefix);
1041 
1042  layout(true);
1043 }
1044 
1046 {
1047  d->spin->setDecimals(decimals);
1048 
1049  layout(true);
1050 }
1051 
1052 int KDoubleNumInput::decimals() const
1053 {
1054  return d->spin->decimals();
1055 }
1056 
1058 {
1059  d->spin->setSpecialValueText(text);
1060 
1061  layout(true);
1062  updateLegacyMembers();
1063 }
1064 
1066 {
1067  K_USING_KNUMINPUT_P(priv);
1068 
1069  KNumInput::setLabel(label, a);
1070 
1071  if (priv->label) {
1072  priv->label->setBuddy(d->spin);
1073  }
1074 }
1075 
1076 double KDoubleNumInput::exponentRatio() const
1077 {
1078  return d->exponentRatio;
1079 }
1080 
1082 {
1083  Q_ASSERT(dbl > 0.0);
1084  if (dbl > 0.0) {
1085  d->exponentRatio = dbl;
1086  spinBoxChanged(d->spin->value()); // used to reset the value of the slider
1087  } else {
1088  kError() << "ExponentRatio need to be strictly positive.";
1089  }
1090 }
1091 
1092 #include "moc_knuminput.cpp"
QLayout * layout() const const
void setMinimum(int min)
Sets the minimum value.
Definition: knuminput.cpp:483
double relativeValue() const
virtual void setLabel(const QString &label, Qt::Alignment a=Qt::AlignLeft|Qt::AlignTop)
Sets the text and alignment of the main description label.
Definition: knuminput.cpp:134
int minimum() const
void setPrefix(const QString &prefix)
Sets the prefix to be displayed to prefix.
Definition: knuminput.cpp:1038
double minimum() const
QString specialValueText() const
virtual ~KIntSpinBox()
Destructor.
Definition: knuminput.cpp:264
int width() const const
QString toString() const
bool showSlider() const
Definition: knuminput.cpp:129
void relativeValueChanged(double)
Emitted whenever valueChanged is.
void lower()
QString suffix() const const
void setSingleStep(double singleStep)
Definition: knuminput.cpp:998
void setSpecialValueText(const QString &text)
Sets the special value text.
Definition: knuminput.cpp:661
void setFocusPolicy(Qt::FocusPolicy policy)
void setMaximum(int max)
Sets the maximum value.
Definition: knuminput.cpp:493
QStyle * style() const const
virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const =0
QString prefix() const
QString prefix() const const
void setLabel(const QString &label, Qt::Alignment a=Qt::AlignLeft|Qt::AlignTop) override
Sets the text and alignment of the main description label.
Definition: knuminput.cpp:672
double referencePoint() const
void setSpecialValueText(const QString &text)
Sets the special value text.
Definition: knuminput.cpp:1057
void setMaximum(double max)
Sets the maximum value.
Definition: knuminput.cpp:982
void ensurePolished() const const
virtual QSize minimumSizeHint() const const
void setRelativeValue(double)
Sets the value in units of the referencePoint.
Definition: knuminput.cpp:638
QString & remove(int position, int n)
KNumInput(QWidget *parent=nullptr)
Default constructor.
Definition: knuminput.cpp:92
void doLayout() override
You need to overwrite this method and implement your layout calculations there.
Definition: knuminput.cpp:882
void chop(int n)
double exponentRatio() const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString text() const const
typedef Alignment
void setRange(int minimum, int maximum)
~KNumInput()
Destructor.
Definition: knuminput.cpp:111
void valueChanged(double)
Emitted every time the value changes (by calling setValue() or by user interaction).
void setRange(int min, int max, int singleStep=1)
Sets the allowed input range and the step size for the slider and the spin box.
Definition: knuminput.cpp:452
QSize sizeHint() const override
Returns a size which fits the contents of the control.
Definition: knuminput.cpp:222
KLocalizedString subs(int a, int fieldWidth=0, int base=10, QChar fillChar=QLatin1Char(' ')) const
bool isEmpty() const
double singleStep() const
QSlider * slider() const
Definition: knuminput.cpp:124
QString number(int n, int base)
QString suffix() const
void setRange(double min, double max, double singleStep=1, bool slider=true)
Definition: knuminput.cpp:912
double maximum() const
int value() const
int base() const
void setFocus()
QString label(StandardShortcut id)
QSize minimumSizeHint() const override
This method returns the minimum size necessary to display the control.
Definition: knuminput.cpp:548
void setSuffix(const QString &suffix)
Sets the suffix to be displayed to suffix.
Definition: knuminput.cpp:1031
int toInt(bool *ok, int base) const const
QLineEdit * lineEdit() const const
void setFocusProxy(QWidget *w)
bool isEmpty() const const
QString trimmed() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
void doLayout() override
You need to overwrite this method and implement your layout calculations there.
Definition: knuminput.cpp:577
int valueFromText(const QString &text) const override
Overloaded the method in QSpinBox to make use of the base given in the constructor.
Definition: knuminput.cpp:292
int referencePoint() const
void setLabel(const QString &label, Qt::Alignment a=Qt::AlignLeft|Qt::AlignTop) override
Sets the text and alignment of the main description label.
Definition: knuminput.cpp:1065
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
int maximum() const
void selectAll()
void setSizePolicy(QSizePolicy)
void relativeValueChanged(double)
This is an overloaded member function, provided for convenience.
KIntSpinBox(QWidget *parent=nullptr)
Constructor.
Definition: knuminput.cpp:258
void setSingleStep(int step)
Definition: knuminput.cpp:508
int singleStep() const const
void setSliderEnabled(bool enabled=true)
Definition: knuminput.cpp:420
void setRelativeValue(double)
Sets the value in units of referencePoint.
Definition: knuminput.cpp:895
const QSize & size() const const
void setSuffix(const QString &suffix)
Sets the suffix to suffix.
Definition: knuminput.cpp:513
KIntNumInput(QWidget *parent=nullptr)
Constructs an input control for integer values with base 10 and initial value 0.
Definition: knuminput.cpp:349
QString specialValueText() const
QString prefix() const
void setReferencePoint(double ref)
Sets the reference Point to ref.
Definition: knuminput.cpp:905
KDoubleNumInput(QWidget *parent=nullptr)
Constructs an input control for double values with initial value 0.00.
Definition: knuminput.cpp:701
virtual ~KDoubleNumInput()
destructor
Definition: knuminput.cpp:728
void setValue(int val)
void setValue(double)
Sets the value of the control.
Definition: knuminput.cpp:890
void setBase(int base)
Sets the base in which the numbers in the spin box are represented.
Definition: knuminput.cpp:277
void setEditFocus(bool mark)
sets focus and optionally marks all text
Definition: knuminput.cpp:305
void valueChanged(int)
Emitted every time the value changes (by calling setValue() or by user interaction).
int decimals() const
void setDecimals(int decimals)
Specifies the number of digits to use.
Definition: knuminput.cpp:1045
double relativeValue() const
QSpinBox * spinBox() const
Definition: knuminput.cpp:363
int singleStep() const
void setExponentRatio(double dbl)
Definition: knuminput.cpp:1081
QString textFromValue(int) const override
Overloaded the method in QSpinBox to make use of the base given in the constructor.
Definition: knuminput.cpp:287
void setPrefix(const QString &prefix)
Sets the prefix to prefix.
Definition: knuminput.cpp:531
double value() const
QString label() const
void setMinimum(double min)
Sets the minimum value.
Definition: knuminput.cpp:971
virtual void doLayout()=0
You need to overwrite this method and implement your layout calculations there.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual ~KIntNumInput()
Destructor.
Definition: knuminput.cpp:627
QObject * parent() const const
QString suffix() const
void setSuffix(const KLocalizedString &suffix)
Sets the suffix to suffix.
Definition: knuminput.cpp:313
void setEditFocus(bool mark=true)
sets focus to the edit widget and marks all text in if mark == true
Definition: knuminput.cpp:543
void setSteps(int minor, int major)
Sets the spacing of tickmarks for the slider.
Definition: knuminput.cpp:227
void setReferencePoint(int)
Sets the reference point for relativeValue.
Definition: knuminput.cpp:389
void setValue(int)
Sets the value of the control.
Definition: knuminput.cpp:632
void setSliderEnabled(bool enabled)
Definition: knuminput.cpp:934
static QHash< QString, QByteArray > * changedMap()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Jun 6 2020 22:41:40 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.