summaryrefslogtreecommitdiffabout
path: root/microkde/kdeui/knuminput.cpp
Unidiff
Diffstat (limited to 'microkde/kdeui/knuminput.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--microkde/kdeui/knuminput.cpp1095
1 files changed, 1095 insertions, 0 deletions
diff --git a/microkde/kdeui/knuminput.cpp b/microkde/kdeui/knuminput.cpp
new file mode 100644
index 0000000..335d6f4
--- a/dev/null
+++ b/microkde/kdeui/knuminput.cpp
@@ -0,0 +1,1095 @@
1// -*- c-basic-offset: 4 -*-
2/*
3 * knuminput.cpp
4 *
5 * Initial implementation:
6 * Copyright (c) 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
7 * Rewritten and maintained by:
8 * Copyright (c) 2000 Dirk A. Mueller <mueller@kde.org>
9 * KDoubleSpinBox:
10 * Copyright (c) 2002 Marc Mutz <mutz@kde.org>
11 *
12 * Requires the Qt widget libraries, available at no cost at
13 * http://www.troll.no/
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Library General Public
17 * License as published by the Free Software Foundation; either
18 * version 2 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Library General Public License for more details.
24 *
25 * You should have received a copy of the GNU Library General Public License
26 * along with this library; see the file COPYING.LIB. If not, write to
27 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28 * Boston, MA 02111-1307, USA.
29 */
30
31//US #include <config.h>
32#ifdef HAVE_LIMITS_H
33#include <limits.h>
34#endif
35#include <assert.h>
36#include <math.h>
37#include <algorithm>
38
39#include <qlabel.h>
40#include <qlineedit.h>
41#include <qsize.h>
42#include <qslider.h>
43#include <qspinbox.h>
44#include <qstyle.h>
45
46#include <kglobal.h>
47#include <klocale.h>
48#include <kdebug.h>
49
50#include "knumvalidator.h"
51#include "knuminput.h"
52
53static inline int calcDiffByTen( int x, int y ) {
54 // calculate ( x - y ) / 10 without overflowing ints:
55 return ( x / 10 ) - ( y / 10 ) + ( x % 10 - y % 10 ) / 10;
56}
57
58// ----------------------------------------------------------------------------
59
60KNumInput::KNumInput(QWidget* parent, const char* name)
61 : QWidget(parent, name)
62{
63 init();
64}
65
66KNumInput::KNumInput(KNumInput* below, QWidget* parent, const char* name)
67 : QWidget(parent, name)
68{
69 init();
70
71 if(below) {
72 m_next = below->m_next;
73 m_prev = below;
74 below->m_next = this;
75 if(m_next)
76 m_next->m_prev = this;
77 }
78}
79
80void KNumInput::init()
81{
82 m_prev = m_next = 0;
83 m_colw1 = m_colw2 = 0;
84
85 m_label = 0;
86 m_slider = 0;
87 m_alignment = 0;
88}
89
90KNumInput::~KNumInput()
91{
92 if(m_prev)
93 m_prev->m_next = m_next;
94
95 if(m_next)
96 m_next->m_prev = m_prev;
97}
98
99void KNumInput::setLabel(const QString & label, int a)
100{
101 if(label.isEmpty()) {
102 delete m_label;
103 m_label = 0;
104 m_alignment = 0;
105 }
106 else {
107 if (m_label) m_label->setText(label);
108 else m_label = new QLabel(label, this, "KNumInput::QLabel");
109 m_label->setAlignment((a & (~(AlignTop|AlignBottom|AlignVCenter)))
110 | AlignVCenter);
111 // if no vertical alignment set, use Top alignment
112 if(!(a & (AlignTop|AlignBottom|AlignVCenter)))
113 a |= AlignTop;
114 m_alignment = a;
115 }
116
117 layout(true);
118}
119
120QString KNumInput::label() const
121{
122 if (m_label) return m_label->text();
123 return QString::null;
124}
125
126void KNumInput::layout(bool deep)
127{
128 int w1 = m_colw1;
129 int w2 = m_colw2;
130
131 // label sizeHint
132 m_sizeLabel = (m_label ? m_label->sizeHint() : QSize(0,0));
133
134 if(m_label && (m_alignment & AlignVCenter))
135 m_colw1 = m_sizeLabel.width() + 4;
136 else
137 m_colw1 = 0;
138
139 // slider sizeHint
140 m_sizeSlider = (m_slider ? m_slider->sizeHint() : QSize(0, 0));
141
142 doLayout();
143
144 if(!deep) {
145 m_colw1 = w1;
146 m_colw2 = w2;
147 return;
148 }
149
150 KNumInput* p = this;
151 while(p) {
152 p->doLayout();
153 w1 = QMAX(w1, p->m_colw1);
154 w2 = QMAX(w2, p->m_colw2);
155 p = p->m_prev;
156 }
157
158 p = m_next;
159 while(p) {
160 p->doLayout();
161 w1 = QMAX(w1, p->m_colw1);
162 w2 = QMAX(w2, p->m_colw2);
163 p = p->m_next;
164 }
165
166 p = this;
167 while(p) {
168 p->m_colw1 = w1;
169 p->m_colw2 = w2;
170 p = p->m_prev;
171 }
172
173 p = m_next;
174 while(p) {
175 p->m_colw1 = w1;
176 p->m_colw2 = w2;
177 p = p->m_next;
178 }
179
180// kdDebug() << "w1 " << w1 << " w2 " << w2 << endl;
181}
182
183QSizePolicy KNumInput::sizePolicy() const
184{
185 return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
186}
187
188QSize KNumInput::sizeHint() const
189{
190 return minimumSizeHint();
191}
192
193void KNumInput::setSteps(int minor, int major)
194{
195 if(m_slider)
196 m_slider->setSteps( minor, major );
197}
198
199
200// ----------------------------------------------------------------------------
201
202KIntSpinBox::KIntSpinBox(QWidget *parent, const char *name)
203 : QSpinBox(0, 99, 1, parent, name)
204{
205 editor()->setAlignment(AlignRight);
206 val_base = 10;
207 setValue(0);
208}
209
210KIntSpinBox::~KIntSpinBox()
211{
212}
213
214KIntSpinBox::KIntSpinBox(int lower, int upper, int step, int value, int base,
215 QWidget* parent, const char* name)
216 : QSpinBox(lower, upper, step, parent, name)
217{
218 editor()->setAlignment(AlignRight);
219 val_base = base;
220 setValue(value);
221}
222
223void KIntSpinBox::setBase(int base)
224{
225 val_base = base;
226}
227
228
229int KIntSpinBox::base() const
230{
231 return val_base;
232}
233
234QString KIntSpinBox::mapValueToText(int v)
235{
236 return QString::number(v, val_base);
237}
238
239int KIntSpinBox::mapTextToValue(bool* ok)
240{
241 return cleanText().toInt(ok, val_base);
242}
243
244void KIntSpinBox::setEditFocus(bool mark)
245{
246 editor()->setFocus();
247 if(mark)
248 editor()->selectAll();
249}
250
251
252// ----------------------------------------------------------------------------
253
254class KIntNumInput::KIntNumInputPrivate {
255public:
256 int referencePoint;
257 short blockRelative;
258 KIntNumInputPrivate( int r )
259 : referencePoint( r ),
260 blockRelative( 0 ) {}
261};
262
263
264KIntNumInput::KIntNumInput(KNumInput* below, int val, QWidget* parent,
265 int _base, const char* name)
266 : KNumInput(below, parent, name)
267{
268 init(val, _base);
269}
270
271KIntNumInput::KIntNumInput(QWidget *parent, const char *name)
272 : KNumInput(parent, name)
273{
274 init(0, 10);
275}
276
277KIntNumInput::KIntNumInput(int val, QWidget *parent, int _base, const char *name)
278 : KNumInput(parent, name)
279{
280 init(val, _base);
281
282}
283
284void KIntNumInput::init(int val, int _base)
285{
286 d = new KIntNumInputPrivate( val );
287 m_spin = new KIntSpinBox(INT_MIN, INT_MAX, 1, val, _base, this, "KIntNumInput::KIntSpinBox");
288 m_spin->setValidator(new KIntValidator(this, _base, "KNumInput::KIntValidtr"));
289 connect(m_spin, SIGNAL(valueChanged(int)), SLOT(spinValueChanged(int)));
290 connect(this, SIGNAL(valueChanged(int)),
291 SLOT(slotEmitRelativeValueChanged(int)));
292
293 setFocusProxy(m_spin);
294 layout(true);
295}
296
297void KIntNumInput::setReferencePoint( int ref ) {
298 // clip to valid range:
299 ref = kMin( maxValue(), kMax( minValue(), ref ) );
300 d->referencePoint = ref;
301}
302
303int KIntNumInput::referencePoint() const {
304 return d->referencePoint;
305}
306
307void KIntNumInput::spinValueChanged(int val)
308{
309 if(m_slider)
310 m_slider->setValue(val);
311
312 emit valueChanged(val);
313}
314
315void KIntNumInput::slotEmitRelativeValueChanged( int value ) {
316 if ( d->blockRelative || !d->referencePoint ) return;
317 emit relativeValueChanged( double( value ) / double( d->referencePoint ) );
318}
319
320void KIntNumInput::setRange(int lower, int upper, int step, bool slider)
321{
322 upper = kMax(upper, lower);
323 lower = kMin(upper, lower);
324 m_spin->setMinValue(lower);
325 m_spin->setMaxValue(upper);
326 m_spin->setLineStep(step);
327
328 step = m_spin->lineStep(); // maybe QRangeControl didn't like out lineStep?
329
330 if(slider) {
331 if (m_slider)
332 m_slider->setRange(lower, upper);
333 else {
334 m_slider = new QSlider(lower, upper, step, m_spin->value(),
335 QSlider::Horizontal, this);
336 m_slider->setTickmarks(QSlider::Below);
337 connect(m_slider, SIGNAL(valueChanged(int)),
338 m_spin, SLOT(setValue(int)));
339 }
340
341 // calculate (upper-lower)/10 without overflowing int's:
342 int major = calcDiffByTen( upper, lower );
343 if ( major==0 ) major = step; // #### workaround Qt bug in 2.1-beta4
344
345 m_slider->setSteps(step, major);
346 m_slider->setTickInterval(major);
347 }
348 else {
349 delete m_slider;
350 m_slider = 0;
351 }
352
353 // check that reference point is still inside valid range:
354 setReferencePoint( referencePoint() );
355
356 layout(true);
357}
358
359void KIntNumInput::setMinValue(int min)
360{
361 setRange(min, m_spin->maxValue(), m_spin->lineStep(), m_slider);
362}
363
364int KIntNumInput::minValue() const
365{
366 return m_spin->minValue();
367}
368
369void KIntNumInput::setMaxValue(int max)
370{
371 setRange(m_spin->minValue(), max, m_spin->lineStep(), m_slider);
372}
373
374int KIntNumInput::maxValue() const
375{
376 return m_spin->maxValue();
377}
378
379void KIntNumInput::setSuffix(const QString &suffix)
380{
381 m_spin->setSuffix(suffix);
382
383 layout(true);
384}
385
386QString KIntNumInput::suffix() const
387{
388 return m_spin->suffix();
389}
390
391void KIntNumInput::setPrefix(const QString &prefix)
392{
393 m_spin->setPrefix(prefix);
394
395 layout(true);
396}
397
398QString KIntNumInput::prefix() const
399{
400 return m_spin->prefix();
401}
402
403void KIntNumInput::setEditFocus(bool mark)
404{
405 m_spin->setEditFocus(mark);
406}
407
408QSize KIntNumInput::minimumSizeHint() const
409{
410 constPolish();
411
412 int w;
413 int h;
414
415 h = 2 + QMAX(m_sizeSpin.height(), m_sizeSlider.height());
416
417 // if in extra row, then count it here
418 if(m_label && (m_alignment & (AlignBottom|AlignTop)))
419 h += 4 + m_sizeLabel.height();
420 else
421 // label is in the same row as the other widgets
422 h = QMAX(h, m_sizeLabel.height() + 2);
423
424 w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
425 w += m_colw1 + m_colw2;
426
427 if(m_alignment & (AlignTop|AlignBottom))
428 w = QMAX(w, m_sizeLabel.width() + 4);
429
430 return QSize(w, h);
431}
432
433void KIntNumInput::doLayout()
434{
435 m_sizeSpin = m_spin->sizeHint();
436 m_colw2 = m_sizeSpin.width();
437
438 if (m_label)
439 m_label->setBuddy(m_spin);
440}
441
442void KIntNumInput::resizeEvent(QResizeEvent* e)
443{
444 int w = m_colw1;
445 int h = 0;
446
447 if(m_label && (m_alignment & AlignTop)) {
448 m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
449 h += m_sizeLabel.height() + 4;
450 }
451
452 if(m_label && (m_alignment & AlignVCenter))
453 m_label->setGeometry(0, 0, w, m_sizeSpin.height());
454
455 m_spin->setGeometry(w, h, m_slider ? m_colw2 : QMAX(m_colw2, e->size().width() - w), m_sizeSpin.height());
456 w += m_colw2 + 8;
457
458 if(m_slider)
459 m_slider->setGeometry(w, h, e->size().width() - w, m_sizeSpin.height());
460
461 h += m_sizeSpin.height() + 2;
462
463 if(m_label && (m_alignment & AlignBottom))
464 m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
465}
466
467KIntNumInput::~KIntNumInput()
468{
469 delete d;
470}
471
472void KIntNumInput::setValue(int val)
473{
474 m_spin->setValue(val);
475 // slider value is changed by spinValueChanged
476}
477
478void KIntNumInput::setRelativeValue( double r ) {
479 if ( !d->referencePoint ) return;
480 ++d->blockRelative;
481 setValue( int( d->referencePoint * r + 0.5 ) );
482 --d->blockRelative;
483}
484
485double KIntNumInput::relativeValue() const {
486 if ( !d->referencePoint ) return 0;
487 return double( value() ) / double ( d->referencePoint );
488}
489
490int KIntNumInput::value() const
491{
492 return m_spin->value();
493}
494
495void KIntNumInput::setSpecialValueText(const QString& text)
496{
497 m_spin->setSpecialValueText(text);
498 layout(true);
499}
500
501QString KIntNumInput::specialValueText() const
502{
503 return m_spin->specialValueText();
504}
505
506void KIntNumInput::setLabel(const QString & label, int a)
507{
508 KNumInput::setLabel(label, a);
509
510 if(m_label)
511 m_label->setBuddy(m_spin);
512}
513
514// ----------------------------------------------------------------------------
515
516class KDoubleNumInput::KDoubleNumInputPrivate {
517public:
518 KDoubleNumInputPrivate( double r )
519 : spin( 0 ),
520 referencePoint( r ),
521 blockRelative ( 0 ) {}
522 KDoubleSpinBox * spin;
523 double referencePoint;
524 short blockRelative;
525};
526
527KDoubleNumInput::KDoubleNumInput(QWidget *parent, const char *name)
528 : KNumInput(parent, name)
529{
530 init(0.0, 0.0, 9999.0, 0.01, 2);
531}
532
533KDoubleNumInput::KDoubleNumInput(double lower, double upper, double value,
534 double step, int precision, QWidget* parent,
535 const char *name)
536 : KNumInput(parent, name)
537{
538 init(value, lower, upper, step, precision);
539}
540
541KDoubleNumInput::KDoubleNumInput(KNumInput *below,
542 double lower, double upper, double value,
543 double step, int precision, QWidget* parent,
544 const char *name)
545 : KNumInput(below, parent, name)
546{
547 init(value, lower, upper, step, precision);
548}
549
550KDoubleNumInput::KDoubleNumInput(double value, QWidget *parent, const char *name)
551 : KNumInput(parent, name)
552{
553 init(value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
554}
555
556KDoubleNumInput::KDoubleNumInput(KNumInput* below, double value, QWidget* parent,
557 const char* name)
558 : KNumInput(below, parent, name)
559{
560 init( value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
561}
562
563KDoubleNumInput::~KDoubleNumInput()
564{
565 delete d;
566}
567
568// ### remove when BIC changes are allowed again:
569
570bool KDoubleNumInput::eventFilter( QObject * o, QEvent * e ) {
571 return KNumInput::eventFilter( o, e );
572}
573
574void KDoubleNumInput::resetEditBox() {
575
576}
577
578// ### end stuff to remove when BIC changes are allowed again
579
580
581
582void KDoubleNumInput::init(double value, double lower, double upper,
583 double step, int precision )
584{
585 // ### init no longer used members:
586 edit = 0;
587 m_range = true;
588 m_value = 0.0;
589 m_precision = 2;
590 // ### end
591
592 d = new KDoubleNumInputPrivate( value );
593
594 d->spin = new KDoubleSpinBox( lower, upper, step, value, precision,
595 this, "KDoubleNumInput::d->spin" );
596 setFocusProxy(d->spin);
597 connect( d->spin, SIGNAL(valueChanged(double)),
598 this, SIGNAL(valueChanged(double)) );
599 connect( this, SIGNAL(valueChanged(double)),
600 this, SLOT(slotEmitRelativeValueChanged(double)) );
601
602 updateLegacyMembers();
603
604 layout(true);
605}
606
607void KDoubleNumInput::updateLegacyMembers() {
608 // ### update legacy members that are either not private or for
609 // which an inlined getter exists:
610 m_lower = minValue();
611 m_upper = maxValue();
612 m_step = d->spin->lineStep();
613 m_specialvalue = specialValueText();
614}
615
616
617double KDoubleNumInput::mapSliderToSpin( int val ) const
618{
619 // map [slidemin,slidemax] to [spinmin,spinmax]
620 double spinmin = d->spin->minValue();
621 double spinmax = d->spin->maxValue();
622 double slidemin = m_slider->minValue(); // cast int to double to avoid
623 double slidemax = m_slider->maxValue(); // overflow in rel denominator
624 double rel = ( double(val) - slidemin ) / ( slidemax - slidemin );
625 return spinmin + rel * ( spinmax - spinmin );
626}
627
628void KDoubleNumInput::sliderMoved(int val)
629{
630 d->spin->setValue( mapSliderToSpin( val ) );
631}
632
633void KDoubleNumInput::slotEmitRelativeValueChanged( double value )
634{
635 if ( !d->referencePoint ) return;
636 emit relativeValueChanged( value / d->referencePoint );
637}
638
639QSize KDoubleNumInput::minimumSizeHint() const
640{
641 constPolish();
642
643 int w;
644 int h;
645
646 h = 2 + QMAX(m_sizeEdit.height(), m_sizeSlider.height());
647
648 // if in extra row, then count it here
649 if(m_label && (m_alignment & (AlignBottom|AlignTop)))
650 h += 4 + m_sizeLabel.height();
651 else
652 // label is in the same row as the other widgets
653 h = QMAX(h, m_sizeLabel.height() + 2);
654
655 w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
656 w += m_colw1 + m_colw2;
657
658 if(m_alignment & (AlignTop|AlignBottom))
659 w = QMAX(w, m_sizeLabel.width() + 4);
660
661 return QSize(w, h);
662}
663
664void KDoubleNumInput::resizeEvent(QResizeEvent* e)
665{
666 int w = m_colw1;
667 int h = 0;
668
669 if(m_label && (m_alignment & AlignTop)) {
670 m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
671 h += m_sizeLabel.height() + 4;
672 }
673
674 if(m_label && (m_alignment & AlignVCenter))
675 m_label->setGeometry(0, 0, w, m_sizeEdit.height());
676
677 d->spin->setGeometry(w, h, m_slider ? m_colw2
678 : e->size().width() - w, m_sizeEdit.height());
679 w += m_colw2 + 8;
680
681 if(m_slider)
682 m_slider->setGeometry(w, h, e->size().width() - w, m_sizeEdit.height());
683
684 h += m_sizeEdit.height() + 2;
685
686 if(m_label && (m_alignment & AlignBottom))
687 m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
688}
689
690void KDoubleNumInput::doLayout()
691{
692 m_sizeEdit = d->spin->sizeHint();
693 m_colw2 = m_sizeEdit.width();
694}
695
696void KDoubleNumInput::setValue(double val)
697{
698 d->spin->setValue( val );
699}
700
701void KDoubleNumInput::setRelativeValue( double r )
702{
703 if ( !d->referencePoint ) return;
704 ++d->blockRelative;
705 setValue( r * d->referencePoint );
706 --d->blockRelative;
707}
708
709void KDoubleNumInput::setReferencePoint( double ref )
710{
711 // clip to valid range:
712 ref = kMin( maxValue(), kMax( minValue(), ref ) );
713 d->referencePoint = ref;
714}
715
716void KDoubleNumInput::setRange(double lower, double upper, double step,
717 bool slider)
718{
719 if( m_slider ) {
720 // don't update the slider to avoid an endless recursion
721 QSpinBox * spin = d->spin;
722 disconnect(spin, SIGNAL(valueChanged(int)),
723 m_slider, SLOT(setValue(int)) );
724 }
725 d->spin->setRange( lower, upper, step, d->spin->precision() );
726
727 if(slider) {
728 // upcast to base type to get the min/maxValue in int form:
729 QSpinBox * spin = d->spin;
730 int slmax = spin->maxValue();
731 int slmin = spin->minValue();
732 int slvalue = spin->value();
733 int slstep = spin->lineStep();
734 if (m_slider) {
735 m_slider->setRange(slmin, slmax);
736 m_slider->setLineStep(slstep);
737 m_slider->setValue(slvalue);
738 } else {
739 m_slider = new QSlider(slmin, slmax, slstep, slvalue,
740 QSlider::Horizontal, this);
741 m_slider->setTickmarks(QSlider::Below);
742 // feedback line: when one moves, the other moves, too:
743 connect(m_slider, SIGNAL(valueChanged(int)),
744 SLOT(sliderMoved(int)) );
745 }
746 connect(spin, SIGNAL(valueChanged(int)),
747 m_slider, SLOT(setValue(int)) );
748 // calculate ( slmax - slmin ) / 10 without overflowing ints:
749 int major = calcDiffByTen( slmax, slmin );
750 if ( !major ) major = slstep; // ### needed?
751 m_slider->setTickInterval(major);
752 } else {
753 delete m_slider;
754 m_slider = 0;
755 }
756
757 setReferencePoint( referencePoint() );
758
759 layout(true);
760 updateLegacyMembers();
761}
762
763void KDoubleNumInput::setMinValue(double min)
764{
765 setRange(min, maxValue(), d->spin->lineStep(), m_slider);
766}
767
768double KDoubleNumInput::minValue() const
769{
770 return d->spin->minValue();
771}
772
773void KDoubleNumInput::setMaxValue(double max)
774{
775 setRange(minValue(), max, d->spin->lineStep(), m_slider);
776}
777
778double KDoubleNumInput::maxValue() const
779{
780 return d->spin->maxValue();
781}
782
783double KDoubleNumInput::value() const
784{
785 return d->spin->value();
786}
787
788double KDoubleNumInput::relativeValue() const
789{
790 if ( !d->referencePoint ) return 0;
791 return value() / d->referencePoint;
792}
793
794double KDoubleNumInput::referencePoint() const
795{
796 return d->referencePoint;
797}
798
799QString KDoubleNumInput::suffix() const
800{
801 return d->spin->suffix();
802}
803
804QString KDoubleNumInput::prefix() const
805{
806 return d->spin->prefix();
807}
808
809void KDoubleNumInput::setSuffix(const QString &suffix)
810{
811 d->spin->setSuffix( suffix );
812
813 layout(true);
814}
815
816void KDoubleNumInput::setPrefix(const QString &prefix)
817{
818 d->spin->setPrefix( prefix );
819
820 layout(true);
821}
822
823void KDoubleNumInput::setPrecision(int precision)
824{
825 d->spin->setPrecision( precision );
826
827 layout(true);
828}
829
830int KDoubleNumInput::precision() const
831{
832 return d->spin->precision();
833}
834
835void KDoubleNumInput::setSpecialValueText(const QString& text)
836{
837 d->spin->setSpecialValueText( text );
838
839 layout(true);
840 updateLegacyMembers();
841}
842
843void KDoubleNumInput::setLabel(const QString & label, int a)
844{
845 KNumInput::setLabel(label, a);
846
847 if(m_label)
848 m_label->setBuddy(d->spin);
849
850}
851
852// ----------------------------------------------------------------------------
853
854
855// We use a kind of fixed-point arithmetic to represent the range of
856// doubles [mLower,mUpper] in steps of 10^(-mPrecision). Thus, the
857// following relations hold:
858//
859// 1. factor = 10^mPrecision
860// 2. basicStep = 1/factor = 10^(-mPrecision);
861// 3. lowerInt = lower * factor;
862// 4. upperInt = upper * factor;
863// 5. lower = lowerInt * basicStep;
864// 6. upper = upperInt * basicStep;
865class KDoubleSpinBox::Private {
866public:
867 Private( int precision=1 )
868 : mPrecision( precision ),
869 mValidator( 0 )
870 {
871 }
872
873 int factor() const {
874 int f = 1;
875 for ( int i = 0 ; i < mPrecision ; ++i ) f *= 10;
876 return f;
877 }
878
879 double basicStep() const {
880 return 1.0/double(factor());
881 }
882
883 int mapToInt( double value, bool * ok ) const {
884 assert( ok );
885 const double f = factor();
886 if ( value > double(INT_MAX) / f ) {
887 kdWarning() << "KDoubleSpinBox: can't represent value " << value
888 << "in terms of fixed-point numbers with precision "
889 << mPrecision << endl;
890 *ok = false;
891 return INT_MAX;
892 } else if ( value < double(INT_MIN) / f ) {
893 kdWarning() << "KDoubleSpinBox: can't represent value " << value
894 << "in terms of fixed-point numbers with precision "
895 << mPrecision << endl;
896 *ok = false;
897 return INT_MIN;
898 } else {
899 *ok = true;
900 return int( value * f + ( value < 0 ? -0.5 : 0.5 ) );
901 }
902 }
903
904 double mapToDouble( int value ) const {
905 return double(value) * basicStep();
906 }
907
908 int mPrecision;
909 KDoubleValidator * mValidator;
910};
911
912KDoubleSpinBox::KDoubleSpinBox( QWidget * parent, const char * name )
913 : QSpinBox( parent, name )
914{
915 editor()->setAlignment( Qt::AlignRight );
916 d = new Private();
917 updateValidator();
918}
919
920KDoubleSpinBox::KDoubleSpinBox( double lower, double upper, double step,
921 double value, int precision,
922 QWidget * parent, const char * name )
923 : QSpinBox( parent, name )
924{
925 editor()->setAlignment( Qt::AlignRight );
926 d = new Private();
927 setRange( lower, upper, step, precision );
928 setValue( value );
929 connect( this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)) );
930}
931
932KDoubleSpinBox::~KDoubleSpinBox() {
933 delete d; d = 0;
934}
935
936bool KDoubleSpinBox::acceptLocalizedNumbers() const {
937 if ( !d->mValidator ) return true; // we'll set one that does;
938 // can't do it now, since we're const
939 return d->mValidator->acceptLocalizedNumbers();
940}
941
942void KDoubleSpinBox::setAcceptLocalizedNumbers( bool accept ) {
943 if ( !d->mValidator ) updateValidator();
944 d->mValidator->setAcceptLocalizedNumbers( accept );
945}
946
947void KDoubleSpinBox::setRange( double lower, double upper, double step,
948 int precision ) {
949 lower = kMin(upper, lower);
950 upper = kMax(upper, lower);
951 setPrecision( precision, true ); // disable bounds checking, since
952 setMinValue( lower ); // it's done in set{Min,Max}Value
953 setMaxValue( upper ); // anyway and we want lower, upper
954 setLineStep( step ); // and step to have the right precision
955}
956
957int KDoubleSpinBox::precision() const {
958 return d->mPrecision;
959}
960
961void KDoubleSpinBox::setPrecision( int precision ) {
962 setPrecision( precision, false );
963}
964
965void KDoubleSpinBox::setPrecision( int precision, bool force ) {
966 if ( precision < 1 ) return;
967 if ( !force ) {
968 int maxPrec = maxPrecision();
969 if ( precision > maxPrec )
970 precision = maxPrec;
971 }
972 d->mPrecision = precision;
973 updateValidator();
974}
975
976int KDoubleSpinBox::maxPrecision() const {
977 // INT_MAX must be > maxAbsValue * 10^precision
978 // ==> 10^precision < INT_MAX / maxAbsValue
979 // ==> precision < log10 ( INT_MAX / maxAbsValue )
980 // ==> maxPrecision = floor( log10 ( INT_MAX / maxAbsValue ) );
981 double maxAbsValue = kMax( fabs(minValue()), fabs(maxValue()) );
982 if ( maxAbsValue == 0 ) return 6; // return arbitrary value to avoid dbz...
983
984 return int( floor( log10( double(INT_MAX) / maxAbsValue ) ) );
985}
986
987double KDoubleSpinBox::value() const {
988 return d->mapToDouble( base::value() );
989}
990
991void KDoubleSpinBox::setValue( double value ) {
992 if ( value == this->value() ) return;
993 if ( value < minValue() )
994 base::setValue( base::minValue() );
995 else if ( value > maxValue() )
996 base::setValue( base::maxValue() );
997 else {
998 bool ok = false;
999 base::setValue( d->mapToInt( value, &ok ) );
1000 assert( ok );
1001 }
1002}
1003
1004double KDoubleSpinBox::minValue() const {
1005 return d->mapToDouble( base::minValue() );
1006}
1007
1008void KDoubleSpinBox::setMinValue( double value ) {
1009 bool ok = false;
1010 int min = d->mapToInt( value, &ok );
1011 if ( !ok ) return;
1012 base::setMinValue( min );
1013 updateValidator();
1014}
1015
1016
1017double KDoubleSpinBox::maxValue() const {
1018 return d->mapToDouble( base::maxValue() );
1019}
1020
1021void KDoubleSpinBox::setMaxValue( double value ) {
1022 bool ok = false;
1023 int max = d->mapToInt( value, &ok );
1024 if ( !ok ) return;
1025 base::setMaxValue( max );
1026 updateValidator();
1027}
1028
1029double KDoubleSpinBox::lineStep() const {
1030 return d->mapToDouble( base::lineStep() );
1031}
1032
1033void KDoubleSpinBox::setLineStep( double step ) {
1034 bool ok = false;
1035 if ( step > maxValue() - minValue() )
1036 base::setLineStep( 1 );
1037 else
1038 base::setLineStep( kMax( d->mapToInt( step, &ok ), 1 ) );
1039}
1040
1041QString KDoubleSpinBox::mapValueToText( int value ) {
1042 if ( acceptLocalizedNumbers() )
1043 return KGlobal::locale()
1044 ->formatNumber( d->mapToDouble( value ), d->mPrecision );
1045 else
1046 return QString().setNum( d->mapToDouble( value ), 'f', d->mPrecision );
1047}
1048
1049int KDoubleSpinBox::mapTextToValue( bool * ok ) {
1050 double value;
1051 if ( acceptLocalizedNumbers() )
1052 value = KGlobal::locale()->readNumber( cleanText(), ok );
1053 else
1054 value = cleanText().toDouble( ok );
1055 if ( !*ok ) return 0;
1056 if ( value > maxValue() )
1057 value = maxValue();
1058 else if ( value < minValue() )
1059 value = minValue();
1060 return d->mapToInt( value, ok );
1061}
1062
1063void KDoubleSpinBox::setValidator( const QValidator * ) {
1064 // silently discard the new validator. We don't want another one ;-)
1065}
1066
1067void KDoubleSpinBox::slotValueChanged( int value ) {
1068 emit valueChanged( d->mapToDouble( value ) );
1069}
1070
1071void KDoubleSpinBox::updateValidator() {
1072 if ( !d->mValidator ) {
1073 d->mValidator = new KDoubleValidator( minValue(), maxValue(), precision(),
1074 this, "d->mValidator" );
1075 base::setValidator( d->mValidator );
1076 } else
1077 d->mValidator->setRange( minValue(), maxValue(), precision() );
1078}
1079
1080void KNumInput::virtual_hook( int, void* )
1081{ /*BASE::virtual_hook( id, data );*/ }
1082
1083void KIntNumInput::virtual_hook( int id, void* data )
1084{ KNumInput::virtual_hook( id, data ); }
1085
1086void KDoubleNumInput::virtual_hook( int id, void* data )
1087{ KNumInput::virtual_hook( id, data ); }
1088
1089void KIntSpinBox::virtual_hook( int, void* )
1090{ /*BASE::virtual_hook( id, data );*/ }
1091
1092void KDoubleSpinBox::virtual_hook( int, void* )
1093{ /*BASE::virtual_hook( id, data );*/ }
1094
1095//US #include "knuminput.moc"