1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997   Josef Wilgen
4  * Copyright (C) 2002   Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 // vim: expandtab
11 
12 #include <qlayout.h>
13 #include <qlineedit.h>
14 #include <qvalidator.h>
15 #include <qevent.h>
16 #include <qstyle.h>
17 #include "qwt_math.h"
18 #include "qwt_counter.h"
19 #include "qwt_arrow_button.h"
20 
21 class QwtCounter::PrivateData
22 {
23 public:
PrivateData()24     PrivateData():
25         editable(true)
26     {
27         increment[Button1] = 1;
28         increment[Button2] = 10;
29         increment[Button3] = 100;
30     }
31 
32     QwtArrowButton *buttonDown[ButtonCnt];
33     QwtArrowButton *buttonUp[ButtonCnt];
34     QLineEdit *valueEdit;
35 
36     int increment[ButtonCnt];
37     int nButtons;
38 
39     bool editable;
40 };
41 
42 /*!
43   The default number of buttons is set to 2. The default increments are:
44   \li Button 1: 1 step
45   \li Button 2: 10 steps
46   \li Button 3: 100 steps
47 
48   \param parent
49  */
QwtCounter(QWidget * parent)50 QwtCounter::QwtCounter(QWidget *parent):
51     QWidget(parent)
52 {
53     initCounter();
54 }
55 
56 #if QT_VERSION < 0x040000
57 /*!
58   The default number of buttons is set to 2. The default increments are:
59   \li Button 1: 1 step
60   \li Button 2: 10 steps
61   \li Button 3: 100 steps
62 
63   \param parent
64  */
QwtCounter(QWidget * parent,const char * name)65 QwtCounter::QwtCounter(QWidget *parent, const char *name):
66     QWidget(parent, name)
67 {
68     initCounter();
69 }
70 #endif
71 
initCounter()72 void QwtCounter::initCounter()
73 {
74     d_data = new PrivateData;
75 
76 #if QT_VERSION >= 0x040000
77     using namespace Qt;
78 #endif
79 
80     QHBoxLayout *layout = new QHBoxLayout(this);
81     layout->setSpacing(0);
82     layout->setMargin(0);
83 
84     int i;
85     for(i = ButtonCnt - 1; i >= 0; i--)
86     {
87         QwtArrowButton *btn =
88             new QwtArrowButton(i+1, Qt::DownArrow,this);
89         btn->setFocusPolicy(NoFocus);
90         btn->installEventFilter(this);
91         layout->addWidget(btn);
92 
93         connect(btn, SIGNAL(released()), SLOT(btnReleased()));
94         connect(btn, SIGNAL(clicked()), SLOT(btnClicked()));
95 
96         d_data->buttonDown[i] = btn;
97     }
98 
99     d_data->valueEdit = new QLineEdit(this);
100     d_data->valueEdit->setReadOnly(false);
101     d_data->valueEdit->setValidator(new QDoubleValidator(d_data->valueEdit));
102     layout->addWidget(d_data->valueEdit);
103 
104 #if QT_VERSION >= 0x040000
105     connect( d_data->valueEdit, SIGNAL(editingFinished()),
106         SLOT(textChanged()) );
107 #else
108     connect( d_data->valueEdit, SIGNAL(returnPressed()), SLOT(textChanged()) );
109     connect( d_data->valueEdit, SIGNAL(lostFocus()), SLOT(textChanged()) );
110 #endif
111 
112     layout->setStretchFactor(d_data->valueEdit, 10);
113 
114     for(i = 0; i < ButtonCnt; i++)
115     {
116 #if QT_VERSION >= 0x040000
117         using namespace Qt;
118 #endif
119         QwtArrowButton *btn =
120             new QwtArrowButton(i+1, Qt::UpArrow, this);
121         btn->setFocusPolicy(NoFocus);
122         btn->installEventFilter(this);
123         layout->addWidget(btn);
124 
125         connect(btn, SIGNAL(released()), SLOT(btnReleased()));
126         connect(btn, SIGNAL(clicked()), SLOT(btnClicked()));
127 
128         d_data->buttonUp[i] = btn;
129     }
130 
131     setNumButtons(2);
132     setRange(0.0,1.0,0.001);
133     setValue(0.0);
134 
135     setSizePolicy(
136         QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
137 
138     setFocusProxy(d_data->valueEdit);
139     setFocusPolicy(StrongFocus);
140 }
141 
142 //! Destructor
~QwtCounter()143 QwtCounter::~QwtCounter()
144 {
145     delete d_data;
146 }
147 
148 /*!
149   Sets the minimum width for the buttons
150 */
polish()151 void QwtCounter::polish()
152 {
153     const int w = d_data->valueEdit->fontMetrics().width("W") + 8;
154 
155     for ( int i = 0; i < ButtonCnt; i++ )
156     {
157         d_data->buttonDown[i]->setMinimumWidth(w);
158         d_data->buttonUp[i]->setMinimumWidth(w);
159     }
160 
161 #if QT_VERSION < 0x040000
162     QWidget::polish();
163 #endif
164 }
165 
166 //! Set from lineedit
textChanged()167 void QwtCounter::textChanged()
168 {
169     if ( !d_data->editable )
170         return;
171 
172     bool converted = false;
173 
174     const double value = d_data->valueEdit->text().toDouble(&converted);
175     if ( converted )
176        setValue( value );
177 }
178 
179 /**
180   \brief Allow/disallow the user to manually edit the value
181 
182   \param editable true enables editing
183   \sa editable()
184 */
setEditable(bool editable)185 void QwtCounter::setEditable(bool editable)
186 {
187 #if QT_VERSION >= 0x040000
188     using namespace Qt;
189 #endif
190     if ( editable == d_data->editable )
191         return;
192 
193     d_data->editable = editable;
194     d_data->valueEdit->setReadOnly(!editable);
195 }
196 
197 //! returns whether the line edit is edatble. (default is yes)
editable() const198 bool QwtCounter::editable() const
199 {
200     return d_data->editable;
201 }
202 
203 /*!
204    Handle PolishRequest events
205 */
event(QEvent * e)206 bool QwtCounter::event ( QEvent * e )
207 {
208 #if QT_VERSION >= 0x040000
209     if ( e->type() == QEvent::PolishRequest )
210         polish();
211 #endif
212     return QWidget::event(e);
213 }
214 
215 /*!
216   Handle key events
217 
218   - Ctrl + Qt::Key_Home
219     Step to minValue()
220   - Ctrl + Qt::Key_End
221     Step to maxValue()
222   - Qt::Key_Up
223     Increment by incSteps(QwtCounter::Button1)
224   - Qt::Key_Down
225     Decrement by incSteps(QwtCounter::Button1)
226   - Qt::Key_PageUp
227     Increment by incSteps(QwtCounter::Button2)
228   - Qt::Key_PageDown
229     Decrement by incSteps(QwtCounter::Button2)
230   - Shift + Qt::Key_PageUp
231     Increment by incSteps(QwtCounter::Button3)
232   - Shift + Qt::Key_PageDown
233     Decrement by incSteps(QwtCounter::Button3)
234 */
keyPressEvent(QKeyEvent * e)235 void QwtCounter::keyPressEvent (QKeyEvent *e)
236 {
237     bool accepted = true;
238 
239     switch ( e->key() )
240     {
241         case Qt::Key_Home:
242 #if QT_VERSION >= 0x040000
243             if ( e->modifiers() & Qt::ControlModifier )
244 #else
245             if ( e->state() & Qt::ControlButton )
246 #endif
247                 setValue(minValue());
248             else
249                 accepted = false;
250             break;
251         case Qt::Key_End:
252 #if QT_VERSION >= 0x040000
253             if ( e->modifiers() & Qt::ControlModifier )
254 #else
255             if ( e->state() & Qt::ControlButton )
256 #endif
257                 setValue(maxValue());
258             else
259                 accepted = false;
260             break;
261         case Qt::Key_Up:
262             incValue(d_data->increment[0]);
263             break;
264         case Qt::Key_Down:
265             incValue(-d_data->increment[0]);
266             break;
267         case Qt::Key_PageUp:
268         case Qt::Key_PageDown:
269         {
270             int increment = d_data->increment[0];
271             if ( d_data->nButtons >= 2 )
272                 increment = d_data->increment[1];
273             if ( d_data->nButtons >= 3 )
274             {
275 #if QT_VERSION >= 0x040000
276                 if ( e->modifiers() & Qt::ShiftModifier )
277 #else
278                 if ( e->state() & Qt::ShiftButton )
279 #endif
280                     increment = d_data->increment[2];
281             }
282             if ( e->key() == Qt::Key_PageDown )
283                 increment = -increment;
284             incValue(increment);
285             break;
286         }
287         default:
288             accepted = false;
289     }
290 
291     if ( accepted )
292     {
293         e->accept();
294         return;
295     }
296 
297     QWidget::keyPressEvent (e);
298 }
299 
300 /*!
301   Handle wheel events
302   \param e Wheel event
303 */
wheelEvent(QWheelEvent * e)304 void QwtCounter::wheelEvent(QWheelEvent *e)
305 {
306     e->accept();
307 
308     if ( d_data->nButtons <= 0 )
309         return;
310 
311     int increment = d_data->increment[0];
312     if ( d_data->nButtons >= 2 )
313     {
314 #if QT_VERSION >= 0x040000
315         if ( e->modifiers() & Qt::ControlModifier )
316 #else
317         if ( e->state() & Qt::ControlButton )
318 #endif
319             increment = d_data->increment[1];
320     }
321     if ( d_data->nButtons >= 3 )
322     {
323 #if QT_VERSION >= 0x040000
324         if ( e->modifiers() & Qt::ShiftModifier )
325 #else
326         if ( e->state() & Qt::ShiftButton )
327 #endif
328             increment = d_data->increment[2];
329     }
330 
331     for ( int i = 0; i < d_data->nButtons; i++ )
332     {
333         if ( d_data->buttonDown[i]->geometry().contains(e->pos()) ||
334             d_data->buttonUp[i]->geometry().contains(e->pos()) )
335         {
336             increment = d_data->increment[i];
337         }
338     }
339 
340     const int wheel_delta = 120;
341 
342     int delta = e->delta();
343     if ( delta >= 2 * wheel_delta )
344         delta /= 2; // Never saw an abs(delta) < 240
345 
346     incValue(delta / wheel_delta * increment);
347 }
348 
349 /*!
350   Specify the number of steps by which the value
351   is incremented or decremented when a specified button
352   is pushed.
353 
354   \param btn One of \c QwtCounter::Button1, \c QwtCounter::Button2,
355              \c QwtCounter::Button3
356   \param nSteps Number of steps
357 */
setIncSteps(QwtCounter::Button btn,int nSteps)358 void QwtCounter::setIncSteps(QwtCounter::Button btn, int nSteps)
359 {
360     if (( btn >= 0) && (btn < ButtonCnt))
361        d_data->increment[btn] = nSteps;
362 }
363 
364 /*!
365   \return the number of steps by which a specified button increments the value
366   or 0 if the button is invalid.
367   \param btn One of \c QwtCounter::Button1, \c QwtCounter::Button2,
368   \c QwtCounter::Button3
369 */
incSteps(QwtCounter::Button btn) const370 int QwtCounter::incSteps(QwtCounter::Button btn) const
371 {
372     if (( btn >= 0) && (btn < ButtonCnt))
373        return d_data->increment[btn];
374 
375     return 0;
376 }
377 
378 /*!
379   \brief Set a new value
380   \param v new value
381   Calls QwtDoubleRange::setValue and does all visual updates.
382   \sa QwtDoubleRange::setValue()
383 */
384 
setValue(double v)385 void QwtCounter::setValue(double v)
386 {
387     QwtDoubleRange::setValue(v);
388 
389     showNum(value());
390     updateButtons();
391 }
392 
393 /*!
394   \brief Notify a change of value
395 */
valueChange()396 void QwtCounter::valueChange()
397 {
398     if ( isValid() )
399         showNum(value());
400     else
401         d_data->valueEdit->setText(QString::null);
402 
403     updateButtons();
404 
405     if ( isValid() )
406         emit valueChanged(value());
407 }
408 
409 /*!
410   \brief Update buttons according to the current value
411 
412   When the QwtCounter under- or over-flows, the focus is set to the smallest
413   up- or down-button and counting is disabled.
414 
415   Counting is re-enabled on a button release event (mouse or space bar).
416 */
updateButtons()417 void QwtCounter::updateButtons()
418 {
419     if ( isValid() )
420     {
421         // 1. save enabled state of the smallest down- and up-button
422         // 2. change enabled state on under- or over-flow
423 
424         for ( int i = 0; i < ButtonCnt; i++ )
425         {
426             d_data->buttonDown[i]->setEnabled(value() > minValue());
427             d_data->buttonUp[i]->setEnabled(value() < maxValue());
428         }
429     }
430     else
431     {
432         for ( int i = 0; i < ButtonCnt; i++ )
433         {
434             d_data->buttonDown[i]->setEnabled(false);
435             d_data->buttonUp[i]->setEnabled(false);
436         }
437     }
438 }
439 
440 /*!
441   \brief Specify the number of buttons on each side of the label
442   \param n Number of buttons
443 */
setNumButtons(int n)444 void QwtCounter::setNumButtons(int n)
445 {
446     if ( n<0 || n>ButtonCnt )
447         return;
448 
449     for ( int i = 0; i < ButtonCnt; i++ )
450     {
451         if ( i < n )
452         {
453             d_data->buttonDown[i]->show();
454             d_data->buttonUp[i]->show();
455         }
456         else
457         {
458             d_data->buttonDown[i]->hide();
459             d_data->buttonUp[i]->hide();
460         }
461     }
462 
463     d_data->nButtons = n;
464 }
465 
466 /*!
467     \return The number of buttons on each side of the widget.
468 */
numButtons() const469 int QwtCounter::numButtons() const
470 {
471     return d_data->nButtons;
472 }
473 
474 /*!
475   Display number string
476 
477   \param number Number
478 */
showNum(double number)479 void QwtCounter::showNum(double number)
480 {
481     QString v;
482     v.setNum(number);
483 
484     const int cursorPos = d_data->valueEdit->cursorPosition();
485     d_data->valueEdit->setText(v);
486     d_data->valueEdit->setCursorPosition(cursorPos);
487 }
488 
489 //!  Button clicked
btnClicked()490 void QwtCounter::btnClicked()
491 {
492     for ( int i = 0; i < ButtonCnt; i++ )
493     {
494         if ( d_data->buttonUp[i] == sender() )
495             incValue(d_data->increment[i]);
496 
497         if ( d_data->buttonDown[i] == sender() )
498             incValue(-d_data->increment[i]);
499     }
500 }
501 
502 //!  Button released
btnReleased()503 void QwtCounter::btnReleased()
504 {
505     emit buttonReleased(value());
506 }
507 
508 /*!
509   \brief Notify change of range
510 
511   This function updates the enabled property of
512   all buttons contained in QwtCounter.
513 */
rangeChange()514 void QwtCounter::rangeChange()
515 {
516     updateButtons();
517 }
518 
519 //! A size hint
sizeHint() const520 QSize QwtCounter::sizeHint() const
521 {
522     QString tmp;
523 
524     int w = tmp.setNum(minValue()).length();
525     int w1 = tmp.setNum(maxValue()).length();
526     if ( w1 > w )
527         w = w1;
528     w1 = tmp.setNum(minValue() + step()).length();
529     if ( w1 > w )
530         w = w1;
531     w1 = tmp.setNum(maxValue() - step()).length();
532     if ( w1 > w )
533         w = w1;
534 
535     tmp.fill('9', w);
536 
537     QFontMetrics fm(d_data->valueEdit->font());
538     w = fm.width(tmp) + 2;
539 #if QT_VERSION >= 0x040000
540     if ( d_data->valueEdit->hasFrame() )
541         w += 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
542 #else
543     w += 2 * d_data->valueEdit->frameWidth();
544 #endif
545 
546     // Now we replace default sizeHint contribution of d_data->valueEdit by
547     // what we really need.
548 
549     w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();
550 
551     const int h = qwtMin(QWidget::sizeHint().height(),
552         d_data->valueEdit->minimumSizeHint().height());
553     return QSize(w, h);
554 }
555 
556 //! returns the step size
step() const557 double QwtCounter::step() const
558 {
559     return QwtDoubleRange::step();
560 }
561 
562 /*!
563    Set the step size
564    \param stepSize Step size
565    \sa QwtDoubleRange::setStep()
566 */
setStep(double stepSize)567 void QwtCounter::setStep(double stepSize)
568 {
569     QwtDoubleRange::setStep(stepSize);
570 }
571 
572 //! returns the minimum value of the range
minVal() const573 double QwtCounter::minVal() const
574 {
575     return minValue();
576 }
577 
578 /*!
579   Set the minimum value of the range
580 
581   \param value Minimum value
582   \sa setMaxValue(), minVal()
583 */
setMinValue(double value)584 void QwtCounter::setMinValue(double value)
585 {
586     setRange(value, maxValue(), step());
587 }
588 
589 //! returns the maximum value of the range
maxVal() const590 double QwtCounter::maxVal() const
591 {
592     return QwtDoubleRange::maxValue();
593 }
594 
595 /*!
596   Set the maximum value of the range
597 
598   \param value Maximum value
599   \sa setMinValue(), maxVal()
600 */
setMaxValue(double value)601 void QwtCounter::setMaxValue(double value)
602 {
603     setRange(minValue(), value, step());
604 }
605 
606 /*!
607   Set the number of increment steps for button 1
608   \param nSteps Number of steps
609 */
setStepButton1(int nSteps)610 void QwtCounter::setStepButton1(int nSteps)
611 {
612     setIncSteps(Button1, nSteps);
613 }
614 
615 //! returns the number of increment steps for button 1
stepButton1() const616 int QwtCounter::stepButton1() const
617 {
618     return incSteps(Button1);
619 }
620 
621 /*!
622   Set the number of increment steps for button 2
623   \param nSteps Number of steps
624 */
setStepButton2(int nSteps)625 void QwtCounter::setStepButton2(int nSteps)
626 {
627     setIncSteps(Button2, nSteps);
628 }
629 
630 //! returns the number of increment steps for button 2
stepButton2() const631 int QwtCounter::stepButton2() const
632 {
633     return incSteps(Button2);
634 }
635 
636 /*!
637   Set the number of increment steps for button 3
638   \param nSteps Number of steps
639 */
setStepButton3(int nSteps)640 void QwtCounter::setStepButton3(int nSteps)
641 {
642     setIncSteps(Button3, nSteps);
643 }
644 
645 //! returns the number of increment steps for button 3
stepButton3() const646 int QwtCounter::stepButton3() const
647 {
648     return incSteps(Button3);
649 }
650 
651 //! \return Current value
value() const652 double QwtCounter::value() const
653 {
654     return QwtDoubleRange::value();
655 }
656 
657