• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kalarm/lib

  • sources
  • kde-4.12
  • kdepim
  • kalarm
  • lib
spinbox.cpp
Go to the documentation of this file.
1 /*
2  * spinbox.cpp - spin box with read-only option and shift-click step value
3  * Program: kalarm
4  * Copyright © 2002,2004-2008 by David Jarvie <djarvie@kde.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include <kdebug.h>
22 
23 #include "spinbox.moc"
24 
25 #include <QLineEdit>
26 #include <QObject>
27 #include <QApplication>
28 #include <QStyle>
29 #include <QStyleOptionSpinBox>
30 #include <QPainter>
31 #include <QMouseEvent>
32 #include <QKeyEvent>
33 #include <QEvent>
34 
35 
36 SpinBox::SpinBox(QWidget* parent)
37  : QSpinBox(parent),
38  mMinValue(QSpinBox::minimum()),
39  mMaxValue(QSpinBox::maximum())
40 {
41  setRange(0, 99999);
42  init();
43 }
44 
45 SpinBox::SpinBox(int minValue, int maxValue, QWidget* parent)
46  : QSpinBox(parent),
47  mMinValue(minValue),
48  mMaxValue(maxValue)
49 {
50  setRange(minValue, maxValue);
51  init();
52 }
53 
54 void SpinBox::init()
55 {
56  int step = QSpinBox::singleStep();
57  mLineStep = step;
58  mLineShiftStep = step;
59  mCurrentButton = NO_BUTTON;
60  mShiftMouse = false;
61  mShiftMinBound = false;
62  mShiftMaxBound = false;
63  mSelectOnStep = true;
64  mUpDownOnly = false;
65  mReadOnly = false;
66  mSuppressSignals = false;
67  mEdited = false;
68 
69  lineEdit()->installEventFilter(this); // handle shift-up/down arrow presses
70 
71  // Detect when the text field is edited
72  connect(lineEdit(), SIGNAL(textChanged(QString)), SLOT(textEdited()));
73  connect(this, SIGNAL(valueChanged(int)), SLOT(valueChange()));
74 }
75 
76 void SpinBox::setReadOnly(bool ro)
77 {
78  if ((int)ro != (int)mReadOnly)
79  {
80  mReadOnly = ro;
81  lineEdit()->setReadOnly(ro);
82  if (ro)
83  setShiftStepping(false, mCurrentButton);
84  }
85 }
86 
87 int SpinBox::bound(int val) const
88 {
89  return (val < mMinValue) ? mMinValue : (val > mMaxValue) ? mMaxValue : val;
90 }
91 
92 void SpinBox::setMinimum(int val)
93 {
94  mMinValue = val;
95  QSpinBox::setMinimum(val);
96  mShiftMinBound = false;
97 }
98 
99 void SpinBox::setMaximum(int val)
100 {
101  mMaxValue = val;
102  QSpinBox::setMaximum(val);
103  mShiftMaxBound = false;
104 }
105 
106 void SpinBox::setSingleStep(int step)
107 {
108  mLineStep = step;
109  if (!mShiftMouse)
110  QSpinBox::setSingleStep(step);
111 }
112 
113 void SpinBox::setSingleShiftStep(int step)
114 {
115  mLineShiftStep = step;
116  if (mShiftMouse)
117  QSpinBox::setSingleStep(step);
118 }
119 
120 void SpinBox::stepBy(int steps)
121 {
122  int increment = steps * QSpinBox::singleStep();
123  addValue(increment);
124  emit stepped(increment);
125 }
126 
127 /******************************************************************************
128 * Adds a positive or negative increment to the current value, wrapping as appropriate.
129 * If 'current' is true, any temporary 'shift' values for the range are used instead
130 * of the real maximum and minimum values.
131 */
132 void SpinBox::addValue(int change, bool current)
133 {
134  int newval = value() + change;
135  int maxval = current ? QSpinBox::maximum() : mMaxValue;
136  int minval = current ? QSpinBox::minimum() : mMinValue;
137  if (wrapping())
138  {
139  int range = maxval - minval + 1;
140  if (newval > maxval)
141  newval = minval + (newval - maxval - 1) % range;
142  else if (newval < minval)
143  newval = maxval - (minval - 1 - newval) % range;
144  }
145  else
146  {
147  if (newval > maxval)
148  newval = maxval;
149  else if (newval < minval)
150  newval = minval;
151  }
152  setValue(newval);
153 }
154 
155 void SpinBox::valueChange()
156 {
157  if (!mSuppressSignals)
158  {
159  int val = value();
160  if (mShiftMinBound && val >= mMinValue)
161  {
162  // Reinstate the minimum bound now that the value has returned to the normal range.
163  QSpinBox::setMinimum(mMinValue);
164  mShiftMinBound = false;
165  }
166  if (mShiftMaxBound && val <= mMaxValue)
167  {
168  // Reinstate the maximum bound now that the value has returned to the normal range.
169  QSpinBox::setMaximum(mMaxValue);
170  mShiftMaxBound = false;
171  }
172 
173  if (!mSelectOnStep && hasFocus())
174  lineEdit()->deselect(); // prevent selection of the spin box text
175  }
176 }
177 
178 /******************************************************************************
179 * Called whenever the line edit text is changed.
180 */
181 void SpinBox::textEdited()
182 {
183  mEdited = true;
184 }
185 
186 /******************************************************************************
187 * Receives events destined for the spin widget or for the edit field.
188 */
189 bool SpinBox::eventFilter(QObject* obj, QEvent* e)
190 {
191  if (obj == lineEdit())
192  {
193  int step = 0;
194  switch (e->type())
195  {
196  case QEvent::KeyPress:
197  {
198  // Up and down arrow keys step the value
199  QKeyEvent* ke = (QKeyEvent*)e;
200  int key = ke->key();
201  if (key == Qt::Key_Up)
202  step = 1;
203  else if (key == Qt::Key_Down)
204  step = -1;
205  break;
206  }
207  case QEvent::Wheel:
208  {
209  QWheelEvent* we = (QWheelEvent*)e;
210  step = (we->delta() > 0) ? 1 : -1;
211  break;
212  }
213  default:
214  break;
215  }
216  if (step)
217  {
218  if (mReadOnly)
219  return true; // discard up/down arrow keys
220  QInputEvent* ie = (QInputEvent*)e;
221  if ((ie->modifiers() & (Qt::ShiftModifier | Qt::AltModifier)) == Qt::ShiftModifier)
222  {
223  // Shift stepping
224  int val = value();
225  if (step > 0)
226  step = mLineShiftStep - val % mLineShiftStep;
227  else
228  step = - ((val + mLineShiftStep - 1) % mLineShiftStep + 1);
229  }
230  else
231  step = (step > 0) ? mLineStep : -mLineStep;
232  addValue(step, false);
233  return true;
234  }
235  }
236  return QSpinBox::eventFilter(obj, e);
237 }
238 
239 void SpinBox::focusOutEvent(QFocusEvent* e)
240 {
241  if (mEdited)
242  {
243  interpretText();
244  mEdited = false;
245  }
246  QSpinBox::focusOutEvent(e);
247 }
248 
249 void SpinBox::mousePressEvent(QMouseEvent* e)
250 {
251  if (!clickEvent(e))
252  QSpinBox::mousePressEvent(e);
253 }
254 
255 void SpinBox::mouseDoubleClickEvent(QMouseEvent* e)
256 {
257  if (!clickEvent(e))
258  QSpinBox::mouseDoubleClickEvent(e);
259 }
260 
261 bool SpinBox::clickEvent(QMouseEvent* e)
262 {
263  if (e->button() == Qt::LeftButton)
264  {
265  // It's a left button press. Set normal or shift stepping as appropriate.
266  if (mReadOnly)
267  return true; // discard the event
268  mCurrentButton = whichButton(e->pos());
269  if (mCurrentButton == NO_BUTTON)
270  {
271  e->accept();
272  return true;
273  }
274  bool shift = (e->modifiers() & (Qt::ShiftModifier | Qt::AltModifier)) == Qt::ShiftModifier;
275  if (setShiftStepping(shift, mCurrentButton))
276  {
277  e->accept();
278  return true; // hide the event from the spin widget
279  }
280  }
281  return false;
282 }
283 
284 void SpinBox::wheelEvent(QWheelEvent* e)
285 {
286  if (mReadOnly)
287  return; // discard the event
288  bool shift = (e->modifiers() & (Qt::ShiftModifier | Qt::AltModifier)) == Qt::ShiftModifier;
289  if (setShiftStepping(shift, (e->delta() > 0 ? UP : DOWN)))
290  {
291  e->accept();
292  return; // hide the event from the spin widget
293  }
294  QSpinBox::wheelEvent(e);
295 }
296 
297 void SpinBox::mouseReleaseEvent(QMouseEvent* e)
298 {
299  if (e->button() == Qt::LeftButton && mShiftMouse)
300  setShiftStepping(false, mCurrentButton); // cancel shift stepping
301  QSpinBox::mouseReleaseEvent(e);
302 }
303 
304 void SpinBox::mouseMoveEvent(QMouseEvent* e)
305 {
306  if (e->buttons() & Qt::LeftButton)
307  {
308  // The left button is down. Track which spin button it's in.
309  if (mReadOnly)
310  return; // discard the event
311  int newButton = whichButton(e->pos());
312  if (newButton != mCurrentButton)
313  {
314  // The mouse has moved to a new spin button.
315  // Set normal or shift stepping as appropriate.
316  mCurrentButton = newButton;
317  bool shift = (e->modifiers() & (Qt::ShiftModifier | Qt::AltModifier)) == Qt::ShiftModifier;
318  if (setShiftStepping(shift, mCurrentButton))
319  {
320  e->accept();
321  return; // hide the event from the spin widget
322  }
323  }
324  }
325  QSpinBox::mouseMoveEvent(e);
326 }
327 
328 void SpinBox::keyPressEvent(QKeyEvent* e)
329 {
330  if (!keyEvent(e))
331  QSpinBox::keyPressEvent(e);
332 }
333 
334 void SpinBox::keyReleaseEvent(QKeyEvent* e)
335 {
336  if (!keyEvent(e))
337  QSpinBox::keyReleaseEvent(e);
338 }
339 
340 bool SpinBox::keyEvent(QKeyEvent* e)
341 {
342  int key = e->key();
343  int state = e->modifiers();
344  if ((QApplication::mouseButtons() & Qt::LeftButton)
345  && (key == Qt::Key_Shift || key == Qt::Key_Alt))
346  {
347  // The left mouse button is down, and the Shift or Alt key has changed
348  if (mReadOnly)
349  return true; // discard the event
350  bool shift = (state & (Qt::ShiftModifier | Qt::AltModifier)) == Qt::ShiftModifier;
351  if ((!shift && mShiftMouse) || (shift && !mShiftMouse))
352  {
353  // The effective shift state has changed.
354  // Set normal or shift stepping as appropriate.
355  if (setShiftStepping(shift, mCurrentButton))
356  {
357  e->accept();
358  return true; // hide the event from the spin widget
359  }
360  }
361  }
362  return false;
363 }
364 
365 /******************************************************************************
366 * Set spin widget stepping to the normal or shift increment.
367 */
368 bool SpinBox::setShiftStepping(bool shift, int currentButton)
369 {
370  if (currentButton == NO_BUTTON)
371  shift = false;
372  if (shift && !mShiftMouse)
373  {
374  /* The value is to be stepped to a multiple of the shift increment.
375  * Adjust the value so that after the spin widget steps it, it will be correct.
376  * Then, if the mouse button is held down, the spin widget will continue to
377  * step by the shift amount.
378  */
379  int val = value();
380  int step = (currentButton == UP) ? mLineShiftStep : (currentButton == DOWN) ? -mLineShiftStep : 0;
381  int adjust = shiftStepAdjustment(val, step);
382  mShiftMouse = true;
383  if (adjust)
384  {
385  /* The value is to be stepped by other than the shift increment,
386  * presumably because it is being set to a multiple of the shift
387  * increment. Achieve this by making the adjustment here, and then
388  * allowing the normal step processing to complete the job by
389  * adding/subtracting the normal shift increment.
390  */
391  if (!wrapping())
392  {
393  // Prevent the step from going past the spinbox's range, or
394  // to the minimum value if that has a special text unless it is
395  // already at the minimum value + 1.
396  int newval = val + adjust + step;
397  int svt = specialValueText().isEmpty() ? 0 : 1;
398  int minval = mMinValue + svt;
399  if (newval <= minval || newval >= mMaxValue)
400  {
401  // Stepping to the minimum or maximum value
402  if (svt && newval <= mMinValue && val == mMinValue)
403  newval = mMinValue;
404  else
405  newval = (newval <= minval) ? minval : mMaxValue;
406  QSpinBox::setValue(newval);
407  emit stepped(step);
408  return true;
409  }
410 
411  // If the interim value will lie outside the spinbox's range,
412  // temporarily adjust the range to allow the value to be set.
413  int tempval = val + adjust;
414  if (tempval < mMinValue)
415  {
416  QSpinBox::setMinimum(tempval);
417  mShiftMinBound = true;
418  }
419  else if (tempval > mMaxValue)
420  {
421  QSpinBox::setMaximum(tempval);
422  mShiftMaxBound = true;
423  }
424  }
425 
426  // Don't process changes since this new value will be stepped immediately
427  mSuppressSignals = true;
428  bool blocked = signalsBlocked();
429  blockSignals(true);
430  addValue(adjust, true);
431  blockSignals(blocked);
432  mSuppressSignals = false;
433  }
434  QSpinBox::setSingleStep(mLineShiftStep);
435  }
436  else if (!shift && mShiftMouse)
437  {
438  // Reinstate to normal (non-shift) stepping
439  QSpinBox::setSingleStep(mLineStep);
440  QSpinBox::setMinimum(mMinValue);
441  QSpinBox::setMaximum(mMaxValue);
442  mShiftMinBound = mShiftMaxBound = false;
443  mShiftMouse = false;
444  }
445  return false;
446 }
447 
448 /******************************************************************************
449 * Return the initial adjustment to the value for a shift step up or down.
450 * The default is to step up or down to the nearest multiple of the shift
451 * increment, so the adjustment returned is for stepping up the decrement
452 * required to round down to a multiple of the shift increment <= current value,
453 * or for stepping down the increment required to round up to a multiple of the
454 * shift increment >= current value.
455 * This method's caller then adjusts the resultant value if necessary to cater
456 * for the widget's minimum/maximum value, and wrapping.
457 * This should really be a static method, but it needs to be virtual...
458 */
459 int SpinBox::shiftStepAdjustment(int oldValue, int shiftStep)
460 {
461  if (oldValue == 0 || shiftStep == 0)
462  return 0;
463  if (shiftStep > 0)
464  {
465  if (oldValue >= 0)
466  return -(oldValue % shiftStep);
467  else
468  return (-oldValue - 1) % shiftStep + 1 - shiftStep;
469  }
470  else
471  {
472  shiftStep = -shiftStep;
473  if (oldValue >= 0)
474  return shiftStep - ((oldValue - 1) % shiftStep + 1);
475  else
476  return (-oldValue) % shiftStep;
477  }
478 }
479 
480 /******************************************************************************
481 * Find which spin widget button a mouse event is in.
482 */
483 int SpinBox::whichButton(const QPoint& pos)
484 {
485  QStyleOptionSpinBox option;
486  initStyleOption(option);
487  if (style()->subControlRect(QStyle::CC_SpinBox, &option, QStyle::SC_SpinBoxUp).contains(pos))
488  return UP;
489  if (style()->subControlRect(QStyle::CC_SpinBox, &option, QStyle::SC_SpinBoxDown).contains(pos))
490  return DOWN;
491  return NO_BUTTON;
492 }
493 
494 QRect SpinBox::upRect() const
495 {
496  QStyleOptionSpinBox option;
497  initStyleOption(option);
498  return style()->subControlRect(QStyle::CC_SpinBox, &option, QStyle::SC_SpinBoxUp);
499 }
500 
501 QRect SpinBox::downRect() const
502 {
503  QStyleOptionSpinBox option;
504  initStyleOption(option);
505  return style()->subControlRect(QStyle::CC_SpinBox, &option, QStyle::SC_SpinBoxDown);
506 }
507 
508 QRect SpinBox::upDownRect() const
509 {
510  QStyleOptionSpinBox option;
511  initStyleOption(option);
512  return style()->subControlRect(QStyle::CC_SpinBox, &option, QStyle::SC_SpinBoxUp)
513  | style()->subControlRect(QStyle::CC_SpinBox, &option, QStyle::SC_SpinBoxDown);
514 }
515 
516 void SpinBox::paintEvent(QPaintEvent* pe)
517 {
518  if (mUpDownOnly)
519  {
520  QStyleOptionSpinBox option;
521  initStyleOption(option);
522  QPainter painter(this);
523  style()->drawComplexControl(QStyle::CC_SpinBox, &option, &painter, this);
524  }
525  else
526  QSpinBox::paintEvent(pe);
527 }
528 
529 void SpinBox::initStyleOption(QStyleOptionSpinBox& so) const
530 {
531  so.init(this);
532 // so.activeSubControls = ??;
533  so.subControls = mUpDownOnly ? (QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown | QStyle::SC_SpinBoxFrame)
534  : (QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown | QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField);
535  so.buttonSymbols = buttonSymbols();
536  so.frame = hasFrame();
537  so.stepEnabled = stepEnabled();
538 }
539 
540 // vim: et sw=4:
SpinBox::upRect
QRect upRect() const
Returns the rectangle containing the up arrow.
Definition: spinbox.cpp:494
SpinBox::downRect
QRect downRect() const
Returns the rectangle containing the down arrow.
Definition: spinbox.cpp:501
SpinBox::initStyleOption
void initStyleOption(QStyleOptionSpinBox &) const
Initialise a QStyleOptionSpinBox with this instance's details.
Definition: spinbox.cpp:529
SpinBox::setSingleStep
void setSingleStep(int step)
Sets the unshifted step increment, i.e.
Definition: spinbox.cpp:106
QWidget
SpinBox::upDownRect
QRect upDownRect() const
Returns the rectangle containing the up and down arrows.
Definition: spinbox.cpp:508
SpinBox::paintEvent
virtual void paintEvent(QPaintEvent *)
Definition: spinbox.cpp:516
SpinBox::focusOutEvent
virtual void focusOutEvent(QFocusEvent *)
Definition: spinbox.cpp:239
SpinBox::keyPressEvent
virtual void keyPressEvent(QKeyEvent *)
Definition: spinbox.cpp:328
QObject
SpinBox::setMinimum
void setMinimum(int val)
Sets the minimum value of the spin box.
Definition: spinbox.cpp:92
SpinBox::mousePressEvent
virtual void mousePressEvent(QMouseEvent *)
Definition: spinbox.cpp:249
SpinBox::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *)
Definition: spinbox.cpp:297
SpinBox::mouseDoubleClickEvent
virtual void mouseDoubleClickEvent(QMouseEvent *)
Definition: spinbox.cpp:255
SpinBox::eventFilter
virtual bool eventFilter(QObject *, QEvent *)
Receives events destined for the spin widget or for the edit field.
Definition: spinbox.cpp:189
SpinBox::setRange
void setRange(int minValue, int maxValue)
Sets the minimum and maximum values of the spin box.
Definition: spinbox.h:79
SpinBox::SpinBox
SpinBox(QWidget *parent=0)
Constructor.
Definition: spinbox.cpp:36
SpinBox::keyReleaseEvent
virtual void keyReleaseEvent(QKeyEvent *)
Definition: spinbox.cpp:334
SpinBox::stepped
void stepped(int step)
Signal emitted when the spin box's value is stepped (by the shifted or unshifted increment).
SpinBox::shiftStepAdjustment
virtual int shiftStepAdjustment(int oldValue, int shiftStep)
Returns the initial adjustment to the value for a shift step up or down.
Definition: spinbox.cpp:459
SpinBox::addValue
void addValue(int change)
Adds a value to the current value of the spin box.
Definition: spinbox.h:69
SpinBox::setMaximum
void setMaximum(int val)
Sets the maximum value of the spin box.
Definition: spinbox.cpp:99
SpinBox::stepBy
virtual void stepBy(int steps)
Called whenever the user triggers a step, to adjust the value of the spin box by the unshifted increm...
Definition: spinbox.cpp:120
SpinBox::wheelEvent
virtual void wheelEvent(QWheelEvent *)
Definition: spinbox.cpp:284
SpinBox::setSingleShiftStep
void setSingleShiftStep(int step)
Sets the shifted step increment, i.e.
Definition: spinbox.cpp:113
SpinBox::bound
int bound(int val) const
Returns the specified value clamped to the range of the spin box.
Definition: spinbox.cpp:87
SpinBox::mouseMoveEvent
virtual void mouseMoveEvent(QMouseEvent *)
Definition: spinbox.cpp:304
QSpinBox
SpinBox::setReadOnly
virtual void setReadOnly(bool readOnly)
Sets whether the spin box can be changed by the user.
Definition: spinbox.cpp:76
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:59:20 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kalarm/lib

Skip menu "kalarm/lib"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal