File indexing completed on 2024-06-02 05:19:16

0001 /*
0002  *  spinbox.h  -  spin box with shift-click step value and read-only option
0003  *  Program:  kalarm
0004  *  SPDX-FileCopyrightText: 2002-2023 David Jarvie <djarvie@kde.org>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #pragma once
0010 
0011 #include <QSpinBox>
0012 class QEvent;
0013 class QStyle;
0014 class QStyleOptionSpinBox;
0015 
0016 
0017 /**
0018  *  @short Spin box with accelerated shift or control key stepping, and read-only option.
0019  *
0020  *  The SpinBox class provides a QSpinBox with accelerated stepping using the shift or
0021  *  control key.
0022  *
0023  *  A separate step increment may optionally be specified for use when the shift or
0024  *  control key is held down. Typically this would be larger than the normal step. Then,
0025  *  when the user clicks the spin buttons, he/she can increment or decrement the value
0026  *  faster by holding the shift key down.
0027  *
0028  *  The widget may be set as read-only. This has the same effect as disabling it, except
0029  *  that its appearance is unchanged.
0030  *
0031  *  @author David Jarvie <djarvie@kde.org>
0032  */
0033 class SpinBox : public QSpinBox
0034 {
0035     Q_OBJECT
0036 public:
0037     /** Constructor.
0038      *  @param parent The parent object of this widget.
0039      */
0040     explicit SpinBox(QWidget* parent = nullptr);
0041 
0042     /** Constructor.
0043      *  @param minValue The minimum value which the spin box can have.
0044      *  @param maxValue The maximum value which the spin box can have.
0045      *  @param parent The parent object of this widget.
0046      */
0047     SpinBox(int minValue, int maxValue, QWidget* parent = nullptr);
0048 
0049     ~SpinBox() override;
0050 
0051     /** Returns true if the widget is read only. */
0052     bool         isReadOnly() const                    { return mReadOnly; }
0053 
0054     /** Sets whether the spin box can be changed by the user.
0055      *  @param readOnly True to set the widget read-only, false to set it read-write.
0056      */
0057     virtual void setReadOnly(bool readOnly);
0058 
0059     /** Returns whether the spin box value text is selected when its value is stepped. */
0060     bool         selectOnStep() const                  { return mSelectOnStep; }
0061 
0062     /** Sets whether the spin box value text should be selected when its value is stepped. */
0063     void         setSelectOnStep(bool sel)             { mSelectOnStep = sel; }
0064 
0065     /** Adds a value to the current value of the spin box. */
0066     void         addValue(int change)                  { addValue(change, false); }
0067 
0068     /** Returns the minimum value of the spin box. */
0069     int          minimum() const                       { return mMinValue; }
0070 
0071     /** Returns the maximum value of the spin box. */
0072     int          maximum() const                       { return mMaxValue; }
0073 
0074     /** Sets the minimum value of the spin box. */
0075     void         setMinimum(int val);
0076 
0077     /** Sets the maximum value of the spin box. */
0078     void         setMaximum(int val);
0079 
0080     /** Sets the minimum and maximum values of the spin box. */
0081     void         setRange(int minValue, int maxValue)  { setMinimum(minValue);  setMaximum(maxValue); }
0082 
0083     /** Returns the specified value clamped to the range of the spin box. */
0084     int          bound(int val) const;
0085 
0086     /** Called whenever the user triggers a step, to adjust the value of
0087      *  the spin box by the unshifted increment.
0088      */
0089     void         stepBy(int steps) override;
0090 
0091     /** Returns the unshifted step increment, i.e. the amount by which the spin box value
0092      *  changes when a spin button is clicked without the shift or control key being pressed.
0093      */
0094     int          singleStep() const                    { return mLineStep; }
0095 
0096     /** Sets the unshifted step increment, i.e. the amount by which the spin box value
0097      *  changes when a spin button is clicked without the shift or control key being pressed.
0098      */
0099     void         setSingleStep(int step);
0100 
0101     /** Returns the shifted step increment, i.e. the amount by which the spin box value
0102      *  changes when a spin button is clicked while the shift key is pressed.
0103      */
0104     int          singleShiftStep() const               { return mLineShiftStep; }
0105 
0106     /** Sets the shifted step increment, i.e. the amount by which the spin box value
0107      *  changes when a spin button is clicked while the shift key is pressed.
0108      */
0109     void         setSingleShiftStep(int step);
0110 
0111     /** Returns the control step increment, i.e. the amount by which the spin box value
0112      *  changes when a spin button is clicked while the control key is pressed.
0113      *  @return  control key step increment, or 0 if none has been set.
0114      */
0115     int          singleControlStep() const             { return mLineControlStep; }
0116 
0117     /** Returns whether control steps should always set the value to a multiple of
0118      *  the control step increment.
0119      */
0120     bool         modControlStep() const                { return mModControlStep; }
0121 
0122     /** Sets the control step increment, i.e. the amount by which the spin box value
0123      *  changes when a spin button is clicked while the control key is pressed.
0124      *  By default, Qt uses the single step increment multiplied by 10.
0125      *  @param step Increment when control key is pressed, or 0 to use default Qt
0126      *              handling which multiplies the default step by 10.
0127      *  @param mod  Control steps should always set value to multiple of @p step.
0128      */
0129     void         setSingleControlStep(int step, bool mod = true);
0130 
0131     /** Returns the rectangle containing the up arrow. */
0132     QRect        upRect() const;
0133 
0134     /** Returns the rectangle containing the down arrow. */
0135     QRect        downRect() const;
0136 
0137     /** Returns the rectangle containing the up and down arrows. */
0138     QRect        upDownRect() const;
0139 
0140     /** Sets whether the edit field is displayed. */
0141     void         setUpDownOnly(bool only)              { mUpDownOnly = only; }
0142 
0143     /** Initialise a QStyleOptionSpinBox with this instance's details. */
0144     void         initStyleOption(QStyleOptionSpinBox*) const override;
0145 
0146 Q_SIGNALS:
0147     /** Signal emitted when the spin box's value is stepped (by the shifted or unshifted increment).
0148      *  @param step The requested step in the spin box's value. Note that the actual change in value
0149      *              may have been less than this.
0150      *  @param modified Qt has automatically modified the step due to the control key.
0151      */
0152     void         stepped(int step, bool control);
0153 
0154 protected:
0155     /** Returns the initial adjustment to the value for a shift step up or down.
0156      * The default is to step up or down to the nearest multiple of the shift
0157      * increment, so the adjustment returned is for stepping up the decrement
0158      * required to round down to a multiple of the shift increment <= current value,
0159      * or for stepping down the increment required to round up to a multiple of the
0160      * shift increment >= current value.
0161      * This method's caller then adjusts the resultant value if necessary to cater
0162      * for the widget's minimum/maximum value, and wrapping.
0163      * This should really be a static method, but it needs to be virtual...
0164      */
0165     virtual int  shiftStepAdjustment(int oldValue, int shiftStep);
0166 
0167     /** Receives events destined for the spin widget or for the edit field. */
0168     bool         eventFilter(QObject*, QEvent*) override;
0169 
0170     void         paintEvent(QPaintEvent*) override;
0171     void         focusOutEvent(QFocusEvent*) override;
0172     void         mousePressEvent(QMouseEvent*) override;
0173     void         mouseDoubleClickEvent(QMouseEvent*) override;
0174     void         mouseReleaseEvent(QMouseEvent*) override;
0175     void         mouseMoveEvent(QMouseEvent*) override;
0176     void         keyPressEvent(QKeyEvent*) override;
0177     void         keyReleaseEvent(QKeyEvent*) override;
0178     void         wheelEvent(QWheelEvent*) override;
0179 
0180 private Q_SLOTS:
0181     void         textEdited();
0182     void         valueChange();
0183 private:
0184     enum class Modifier { None, Shift, Control };
0185 
0186     void         init();
0187     void         addValue(int change, bool current);
0188     int          whichButton(const QPoint&);
0189     bool         setShiftStepping(Modifier, int currentButton);
0190     bool         clickEvent(QMouseEvent*);
0191     bool         keyEvent(QKeyEvent*);
0192     static Modifier getModifier(Qt::KeyboardModifiers);
0193 
0194     enum { NO_BUTTON, UP, DOWN };
0195 
0196     int          mMinValue;
0197     int          mMaxValue;
0198     int          mLineStep;                  // step when spin arrows are pressed
0199     int          mLineShiftStep;             // step when spin arrows are pressed with shift key
0200     int          mLineControlStep {0};       // step when spin arrows are pressed with control key
0201     int          mCurrentButton {NO_BUTTON}; // current spin widget button
0202     Modifier     mMouseKey {Modifier::None}; // which modifier key applies while left button is being held down
0203     QStyle*      mControlStyle {nullptr};    // style to prevent Qt multiplying control step by 10
0204     bool         mShiftMinBound {false};     // true if a temporary minimum bound has been set during shift stepping
0205     bool         mShiftMaxBound {false};     // true if a temporary maximum bound has been set during shift stepping
0206     bool         mSelectOnStep {true};       // select the editor text whenever spin buttons are clicked (default)
0207     bool         mModControlStep {true};     // control steps set value to multiple of step
0208     bool         mUpDownOnly {false};        // true if edit field isn't displayed
0209     bool         mReadOnly {false};          // value cannot be changed
0210     bool         mSuppressSignals {false};
0211     bool         mEdited {false};            // text field has been edited
0212 };
0213 
0214 // vim: et sw=4: