23 ** |
23 ** |
24 ****************************************************************************/ |
24 ****************************************************************************/ |
25 |
25 |
26 #include "hbinputbutton.h" |
26 #include "hbinputbutton.h" |
27 |
27 |
|
28 #include <QTime> |
|
29 #include <hbdeviceprofile.h> |
|
30 |
|
31 /*! |
|
32 @stable |
|
33 @hbinput |
|
34 \class HbInputButton |
|
35 \brief Provides vkb button definitions used by HbInputButtonGroup |
|
36 |
|
37 \sa HbInputButtonGroup |
|
38 */ |
|
39 |
28 /// @cond |
40 /// @cond |
|
41 |
|
42 // Defines how much the button size should be increased from its original size. |
|
43 const qreal HbInputThresholdMultiplier = 0.25; |
|
44 |
|
45 // Threshold for touch point position comparison |
|
46 const qreal HbInputTouchThreshold = 5.0; |
|
47 |
|
48 // Timeout for increased touch down region |
|
49 const int HbInputInstantTouchTimeout = 500; |
|
50 |
|
51 // Threshold for increased touch down region in mm |
|
52 const qreal HbInputInstantTouchThreshold = 3.5; |
|
53 |
|
54 const QPoint HbInputInvalidPoint = QPoint(-1, -1); |
29 |
55 |
30 class HbInputButtonPrivate |
56 class HbInputButtonPrivate |
31 { |
57 { |
32 public: |
58 public: |
33 HbInputButtonPrivate(); |
59 HbInputButtonPrivate(); |
38 |
64 |
39 void setDefaultGraphics(int keyCode); |
65 void setDefaultGraphics(int keyCode); |
40 |
66 |
41 HbInputButton::HbInputButtonType mType; |
67 HbInputButton::HbInputButtonType mType; |
42 HbInputButton::HbInputButtonState mState; |
68 HbInputButton::HbInputButtonState mState; |
|
69 HbInputButton::HbInputButtonState mPreviousState; |
43 QPoint mPosition; |
70 QPoint mPosition; |
44 QSize mSize; |
71 QSize mSize; |
45 int mKeyCode; |
72 int mKeyCode; |
46 bool mAutoRepeat; |
73 bool mAutoRepeat; |
47 QList<QString> mTexts; |
74 QList<QString> mTexts; |
48 QString mMappedCharacters; |
75 QString mMappedCharacters; |
49 QList<HbIcon> mIcons; |
76 QList<HbIcon> mIcons; |
50 QRectF mBoundingRect; |
77 QRectF mBoundingRect; |
|
78 QPointF mTouchPoint; |
|
79 QPointF mLastInteractionPoint; |
|
80 bool mTap; |
|
81 QTime mTouchTime; |
|
82 qreal mTouchThreshold; |
51 }; |
83 }; |
52 |
84 |
53 HbInputButtonPrivate::HbInputButtonPrivate() |
85 HbInputButtonPrivate::HbInputButtonPrivate() |
54 : mType(HbInputButton::ButtonTypeNormal), mState(HbInputButton::ButtonStateReleased), |
86 : mType(HbInputButton::ButtonTypeNormal), mState(HbInputButton::ButtonStateReleased), |
55 mPosition(0, 0), mSize(1, 1), mKeyCode(-1), mAutoRepeat(false) |
87 mPreviousState(HbInputButton::ButtonStateReleased), mPosition(0, 0), mSize(1, 1), |
|
88 mKeyCode(-1), mAutoRepeat(false), mTouchPoint(HbInputInvalidPoint), |
|
89 mLastInteractionPoint(HbInputInvalidPoint), mTap(false) |
56 { |
90 { |
57 for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) { |
91 for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) { |
58 mTexts.append(""); |
92 mTexts.append(""); |
59 } |
93 } |
60 |
94 |
61 for (int i = 0; i < HbInputButton::ButtonIconIndexCount; ++i) { |
95 for (int i = 0; i < HbInputButton::ButtonIconIndexCount; ++i) { |
62 mIcons.append(HbIcon()); |
96 mIcons.append(HbIcon()); |
63 } |
97 } |
|
98 |
|
99 // Convert millimeters to pixels |
|
100 mTouchThreshold = HbDeviceProfile::current().ppmValue() * HbInputInstantTouchThreshold; |
64 } |
101 } |
65 |
102 |
66 HbInputButtonPrivate::HbInputButtonPrivate(int keyCode, const QPoint &position, const QSize &size) |
103 HbInputButtonPrivate::HbInputButtonPrivate(int keyCode, const QPoint &position, const QSize &size) |
67 : mType(HbInputButton::ButtonTypeNormal), mState(HbInputButton::ButtonStateReleased), |
104 : mType(HbInputButton::ButtonTypeNormal), mState(HbInputButton::ButtonStateReleased), |
68 mPosition(position), mSize(size), mKeyCode(keyCode), mAutoRepeat(false) |
105 mPreviousState(HbInputButton::ButtonStateReleased), mPosition(position), |
|
106 mSize(size), mKeyCode(keyCode), mAutoRepeat(false), mTouchPoint(HbInputInvalidPoint), |
|
107 mLastInteractionPoint(HbInputInvalidPoint), mTap(false) |
69 { |
108 { |
70 for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) { |
109 for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) { |
71 mTexts.append(""); |
110 mTexts.append(""); |
72 } |
111 } |
73 |
112 |
90 } |
129 } |
91 |
130 |
92 if (mKeyCode == HbInputButton::ButtonKeyCodeDelete || mKeyCode == HbInputButton::ButtonKeyCodeSpace) { |
131 if (mKeyCode == HbInputButton::ButtonKeyCodeDelete || mKeyCode == HbInputButton::ButtonKeyCodeSpace) { |
93 mAutoRepeat = true; |
132 mAutoRepeat = true; |
94 } |
133 } |
|
134 |
|
135 // Convert millimeters to pixels |
|
136 mTouchThreshold = HbDeviceProfile::current().ppmValue() * HbInputInstantTouchThreshold; |
95 } |
137 } |
96 |
138 |
97 HbInputButtonPrivate::HbInputButtonPrivate(HbInputButton::HbInputButtonType type, HbInputButton::HbInputButtonState state, |
139 HbInputButtonPrivate::HbInputButtonPrivate(HbInputButton::HbInputButtonType type, HbInputButton::HbInputButtonState state, |
98 const QPoint &position, const QSize &size, int keyCode, bool autoRepeat, |
140 const QPoint &position, const QSize &size, int keyCode, bool autoRepeat, |
99 const QList<QString> &texts, const QString &mappedCharacters, const QList<HbIcon> &icons) |
141 const QList<QString> &texts, const QString &mappedCharacters, const QList<HbIcon> &icons) |
100 : mType(type), mState(state), mPosition(position), mSize(size), mKeyCode(keyCode), mAutoRepeat(autoRepeat), |
142 : mType(type), mState(state), mPreviousState(state), mPosition(position), mSize(size), |
101 mMappedCharacters(mappedCharacters) |
143 mKeyCode(keyCode), mAutoRepeat(autoRepeat), mMappedCharacters(mappedCharacters), |
|
144 mTouchPoint(HbInputInvalidPoint), mLastInteractionPoint(HbInputInvalidPoint), mTap(false) |
102 { |
145 { |
103 for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) { |
146 for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) { |
104 if (i < texts.count()) { |
147 if (i < texts.count()) { |
105 mTexts.append(texts.at(i)); |
148 mTexts.append(texts.at(i)); |
106 } else { |
149 } else { |
120 mSize.setWidth(1); |
163 mSize.setWidth(1); |
121 } |
164 } |
122 if (mSize.height() < 1) { |
165 if (mSize.height() < 1) { |
123 mSize.setHeight(1); |
166 mSize.setHeight(1); |
124 } |
167 } |
|
168 |
|
169 // Convert millimeters to pixels |
|
170 mTouchThreshold = HbDeviceProfile::current().ppmValue() * HbInputInstantTouchThreshold; |
125 } |
171 } |
126 |
172 |
127 void HbInputButtonPrivate::setDefaultGraphics(int keyCode) |
173 void HbInputButtonPrivate::setDefaultGraphics(int keyCode) |
128 { |
174 { |
129 switch(keyCode) { |
175 switch(keyCode) { |
130 case HbInputButton::ButtonKeyCodeDelete: |
176 case HbInputButton::ButtonKeyCodeDelete: |
131 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconDelete)); |
177 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconDelete)); |
132 break; |
178 break; |
133 case HbInputButton::ButtonKeyCodeShift: |
179 case HbInputButton::ButtonKeyCodeShift: |
134 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconShift)); |
180 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconShift)); |
135 break; |
181 break; |
136 case HbInputButton::ButtonKeyCodeSymbol: |
182 case HbInputButton::ButtonKeyCodeSymbol: |
137 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol)); |
183 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol)); |
138 break; |
184 break; |
139 case HbInputButton::ButtonKeyCodeEnter: |
185 case HbInputButton::ButtonKeyCodeEnter: |
140 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconEnter)); |
186 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconEnter)); |
141 break; |
187 break; |
142 case HbInputButton::ButtonKeyCodeSpace: |
188 case HbInputButton::ButtonKeyCodeSpace: |
143 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSpace)); |
189 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSpace)); |
144 break; |
190 break; |
145 case HbInputButton::ButtonKeyCodeAlphabet: |
191 case HbInputButton::ButtonKeyCodeAlphabet: |
146 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol)); |
192 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol)); |
147 break; |
193 break; |
148 case HbInputButton::ButtonKeyCodeSmiley: |
194 case HbInputButton::ButtonKeyCodeSmiley: |
149 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSmiley)); |
195 mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSmiley)); |
150 break; |
196 break; |
151 default: |
197 default: |
152 break; |
198 break; |
153 } |
199 } |
154 } |
200 } |
155 |
201 |
156 /// @endcond |
202 /// @endcond |
|
203 |
|
204 /*! |
|
205 \enum HbInputButton::HbInputButtonKeyCode |
|
206 |
|
207 This enum defines a set of predefined key codes for input button. ButtonKeyCodeCustom should |
|
208 always be the last item so that all values bigger than ButtonKeyCodeCustom can be interpreted |
|
209 as custom key codes |
|
210 */ |
|
211 |
|
212 /*! |
|
213 \enum HbInputButton::HbInputButtonType |
|
214 |
|
215 This enum defines different button types. Button's graphics, text layout and functionality |
|
216 depend of the this type. ButtonTypeCount should always be the last value. |
|
217 */ |
|
218 |
|
219 /*! |
|
220 \enum HbInputButton::HbInputButtonState |
|
221 |
|
222 This enum defines button states. State mostly affects the button's visual look in addition |
|
223 to what can be done with the button (i.e. no interaction with disabled buttons, released and |
|
224 latched buttons can be pressed). ButtonStateCount should always be the last value. |
|
225 */ |
|
226 |
|
227 /*! |
|
228 \enum HbInputButton::HbInputButtonTextIndex |
|
229 |
|
230 This enum defines set of text indices that can be used when setting texts to different parts of |
|
231 a button using setText function. ButtonTextIndexCount should always be the last value. |
|
232 */ |
|
233 |
|
234 /*! |
|
235 \enum HbInputButton::HbInputButtonIconIndex |
|
236 |
|
237 This enum defines set of icon indices that can be used when setting icons to different parts of |
|
238 a button using setIcon function. ButtonIconIndexCount should always be the last value. |
|
239 */ |
157 |
240 |
158 /*! |
241 /*! |
159 Constructor |
242 Constructor |
160 */ |
243 */ |
161 HbInputButton::HbInputButton() |
244 HbInputButton::HbInputButton() |
208 return d->mType; |
291 return d->mType; |
209 } |
292 } |
210 |
293 |
211 /*! |
294 /*! |
212 Updates button's state. |
295 Updates button's state. |
|
296 State change sequence latched, pressed, released will result |
|
297 in a latched state. Otherwise the new state will be the given state. |
213 |
298 |
214 \sa state |
299 \sa state |
215 */ |
300 */ |
216 void HbInputButton::setState(HbInputButtonState state) |
301 void HbInputButton::setState(HbInputButtonState state) |
217 { |
302 { |
218 Q_D(HbInputButton); |
303 Q_D(HbInputButton); |
219 |
304 |
220 d->mState = state; |
305 if (state == ButtonStateReleased) { |
|
306 d->mTap = false; |
|
307 clearLastTriggeredPosition(); |
|
308 } |
|
309 |
|
310 if (d->mState == ButtonStatePressed && |
|
311 d->mPreviousState == ButtonStateLatched && |
|
312 state == ButtonStateReleased) { |
|
313 d->mState = d->mPreviousState; |
|
314 } else { |
|
315 d->mPreviousState = d->mState; |
|
316 d->mState = state; |
|
317 } |
221 } |
318 } |
222 |
319 |
223 /*! |
320 /*! |
224 Returns button's state. |
321 Returns button's state. |
225 |
322 |
515 Q_D(const HbInputButton); |
612 Q_D(const HbInputButton); |
516 |
613 |
517 return d->mBoundingRect; |
614 return d->mBoundingRect; |
518 } |
615 } |
519 |
616 |
|
617 /*! |
|
618 \brief Returns an active touch area for current button. |
|
619 |
|
620 Button contains bounding rectangle for actual size of the item, while touch area |
|
621 can actually extend over buttons physical boundaries. This is to make interacting |
|
622 with button easier. |
|
623 |
|
624 \return Active touch area as a rectangle, centered to its button. |
|
625 \sa setBoundingRect |
|
626 */ |
|
627 QRectF HbInputButton::activeTouchArea() const |
|
628 { |
|
629 Q_D(const HbInputButton); |
|
630 |
|
631 QRectF threshold(d->mBoundingRect); |
|
632 |
|
633 qreal mod_w = d->mBoundingRect.width() * HbInputThresholdMultiplier; |
|
634 qreal mod_h = d->mBoundingRect.height() * HbInputThresholdMultiplier; |
|
635 threshold.adjust(-mod_w, -mod_h, mod_w, mod_h); |
|
636 |
|
637 return threshold; |
|
638 } |
|
639 |
|
640 /*! |
|
641 \brief Set position where last user interaction occurred. |
|
642 */ |
|
643 void HbInputButton::setLastTriggeredPosition(const QPointF &position) |
|
644 { |
|
645 Q_D(HbInputButton); |
|
646 |
|
647 d->mLastInteractionPoint = position; |
|
648 } |
|
649 |
|
650 /*! |
|
651 \brief Clear last user interaction data. |
|
652 */ |
|
653 void HbInputButton::clearLastTriggeredPosition() |
|
654 { |
|
655 Q_D(HbInputButton); |
|
656 |
|
657 d->mLastInteractionPoint = HbInputInvalidPoint; |
|
658 } |
|
659 |
|
660 /*! |
|
661 Checks whether the new touch point position is close enough to the previous |
|
662 one that hit this button so that the new touch point can |
|
663 be interpreted as the same as the old one. |
|
664 */ |
|
665 bool HbInputButton::wasTriggeredAt(const QPointF &position) const |
|
666 { |
|
667 Q_D(const HbInputButton); |
|
668 |
|
669 QRectF rect(d->mLastInteractionPoint.x() - HbInputTouchThreshold, d->mLastInteractionPoint.y() - HbInputTouchThreshold, |
|
670 2 * HbInputTouchThreshold, 2 * HbInputTouchThreshold); |
|
671 |
|
672 return rect.contains(position); |
|
673 } |
|
674 |
|
675 /*! |
|
676 \brief Set position where the button was first touched. |
|
677 */ |
|
678 void HbInputButton::setTouchPointPosition(const QPointF &position) |
|
679 { |
|
680 Q_D(HbInputButton); |
|
681 |
|
682 d->mTouchPoint = position; |
|
683 d->mTap = true; |
|
684 d->mTouchTime.start(); |
|
685 } |
|
686 |
|
687 /*! |
|
688 Returns the current touch position which in case of |
|
689 a short tap is the touch down position and otherwise the |
|
690 last triggered position. |
|
691 */ |
|
692 QPointF HbInputButton::currentTouchPointPosition() const |
|
693 { |
|
694 Q_D(const HbInputButton); |
|
695 |
|
696 if (d->mTap) { |
|
697 return d->mTouchPoint; |
|
698 } |
|
699 return d->mLastInteractionPoint; |
|
700 } |
|
701 |
|
702 /*! |
|
703 \brief Checks whether move to given \a position should be ignored or processed normally |
|
704 |
|
705 True is returned if given position is close enough to touch down point during |
|
706 short timeout after the button has been pressed or after timeout if the |
|
707 position is inside button's active touch area. Otherwise false is returned and |
|
708 move event should be handled normally. |
|
709 */ |
|
710 bool HbInputButton::suppressMoveEvent(const QPointF &position) |
|
711 { |
|
712 Q_D(HbInputButton); |
|
713 |
|
714 // Check if the timeout from the touch down event has passed |
|
715 if (d->mTap && d->mTouchTime.elapsed() < HbInputInstantTouchTimeout) { |
|
716 // Create rectangle around touch down position |
|
717 QRectF rect(d->mTouchPoint.x() - d->mTouchThreshold, d->mTouchPoint.y() - d->mTouchThreshold, |
|
718 2 * d->mTouchThreshold, 2 * d->mTouchThreshold); |
|
719 |
|
720 // If inside created rectangle, update last position and ignore the event |
|
721 if (rect.contains(position)) { |
|
722 setLastTriggeredPosition(position); |
|
723 return true; |
|
724 } |
|
725 // Check if new position is still inside active button |
|
726 } else if (activeTouchArea().contains(position)) { |
|
727 setLastTriggeredPosition(position); |
|
728 d->mTap = false; |
|
729 return true; |
|
730 } |
|
731 |
|
732 d->mTap = false; |
|
733 return false; |
|
734 } |
|
735 |
520 // End of file |
736 // End of file |