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