--- a/src/hbinput/inputwidgets/hbinputbutton.cpp Mon Oct 04 17:49:30 2010 +0300
+++ b/src/hbinput/inputwidgets/hbinputbutton.cpp Mon Oct 18 18:23:13 2010 +0300
@@ -25,8 +25,34 @@
#include "hbinputbutton.h"
+#include <QTime>
+#include <hbdeviceprofile.h>
+
+/*!
+@stable
+@hbinput
+\class HbInputButton
+\brief Provides vkb button definitions used by HbInputButtonGroup
+
+\sa HbInputButtonGroup
+*/
+
/// @cond
+// Defines how much the button size should be increased from its original size.
+const qreal HbInputThresholdMultiplier = 0.25;
+
+// Threshold for touch point position comparison
+const qreal HbInputTouchThreshold = 5.0;
+
+// Timeout for increased touch down region
+const int HbInputInstantTouchTimeout = 500;
+
+// Threshold for increased touch down region in mm
+const qreal HbInputInstantTouchThreshold = 3.5;
+
+const QPoint HbInputInvalidPoint = QPoint(-1, -1);
+
class HbInputButtonPrivate
{
public:
@@ -40,6 +66,7 @@
HbInputButton::HbInputButtonType mType;
HbInputButton::HbInputButtonState mState;
+ HbInputButton::HbInputButtonState mPreviousState;
QPoint mPosition;
QSize mSize;
int mKeyCode;
@@ -48,11 +75,18 @@
QString mMappedCharacters;
QList<HbIcon> mIcons;
QRectF mBoundingRect;
+ QPointF mTouchPoint;
+ QPointF mLastInteractionPoint;
+ bool mTap;
+ QTime mTouchTime;
+ qreal mTouchThreshold;
};
HbInputButtonPrivate::HbInputButtonPrivate()
: mType(HbInputButton::ButtonTypeNormal), mState(HbInputButton::ButtonStateReleased),
- mPosition(0, 0), mSize(1, 1), mKeyCode(-1), mAutoRepeat(false)
+ mPreviousState(HbInputButton::ButtonStateReleased), mPosition(0, 0), mSize(1, 1),
+ mKeyCode(-1), mAutoRepeat(false), mTouchPoint(HbInputInvalidPoint),
+ mLastInteractionPoint(HbInputInvalidPoint), mTap(false)
{
for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) {
mTexts.append("");
@@ -61,11 +95,16 @@
for (int i = 0; i < HbInputButton::ButtonIconIndexCount; ++i) {
mIcons.append(HbIcon());
}
+
+ // Convert millimeters to pixels
+ mTouchThreshold = HbDeviceProfile::current().ppmValue() * HbInputInstantTouchThreshold;
}
HbInputButtonPrivate::HbInputButtonPrivate(int keyCode, const QPoint &position, const QSize &size)
: mType(HbInputButton::ButtonTypeNormal), mState(HbInputButton::ButtonStateReleased),
- mPosition(position), mSize(size), mKeyCode(keyCode), mAutoRepeat(false)
+ mPreviousState(HbInputButton::ButtonStateReleased), mPosition(position),
+ mSize(size), mKeyCode(keyCode), mAutoRepeat(false), mTouchPoint(HbInputInvalidPoint),
+ mLastInteractionPoint(HbInputInvalidPoint), mTap(false)
{
for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) {
mTexts.append("");
@@ -92,13 +131,17 @@
if (mKeyCode == HbInputButton::ButtonKeyCodeDelete || mKeyCode == HbInputButton::ButtonKeyCodeSpace) {
mAutoRepeat = true;
}
+
+ // Convert millimeters to pixels
+ mTouchThreshold = HbDeviceProfile::current().ppmValue() * HbInputInstantTouchThreshold;
}
HbInputButtonPrivate::HbInputButtonPrivate(HbInputButton::HbInputButtonType type, HbInputButton::HbInputButtonState state,
const QPoint &position, const QSize &size, int keyCode, bool autoRepeat,
const QList<QString> &texts, const QString &mappedCharacters, const QList<HbIcon> &icons)
- : mType(type), mState(state), mPosition(position), mSize(size), mKeyCode(keyCode), mAutoRepeat(autoRepeat),
- mMappedCharacters(mappedCharacters)
+ : mType(type), mState(state), mPreviousState(state), mPosition(position), mSize(size),
+ mKeyCode(keyCode), mAutoRepeat(autoRepeat), mMappedCharacters(mappedCharacters),
+ mTouchPoint(HbInputInvalidPoint), mLastInteractionPoint(HbInputInvalidPoint), mTap(false)
{
for (int i = 0; i < HbInputButton::ButtonTextIndexCount; ++i) {
if (i < texts.count()) {
@@ -122,40 +165,80 @@
if (mSize.height() < 1) {
mSize.setHeight(1);
}
+
+ // Convert millimeters to pixels
+ mTouchThreshold = HbDeviceProfile::current().ppmValue() * HbInputInstantTouchThreshold;
}
void HbInputButtonPrivate::setDefaultGraphics(int keyCode)
{
switch(keyCode) {
- case HbInputButton::ButtonKeyCodeDelete:
- mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconDelete));
- break;
- case HbInputButton::ButtonKeyCodeShift:
- mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconShift));
- break;
- case HbInputButton::ButtonKeyCodeSymbol:
- mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol));
- break;
- case HbInputButton::ButtonKeyCodeEnter:
- mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconEnter));
- break;
- case HbInputButton::ButtonKeyCodeSpace:
- mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSpace));
- break;
- case HbInputButton::ButtonKeyCodeAlphabet:
- mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol));
- break;
- case HbInputButton::ButtonKeyCodeSmiley:
- mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSmiley));
- break;
- default:
- break;
+ case HbInputButton::ButtonKeyCodeDelete:
+ mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconDelete));
+ break;
+ case HbInputButton::ButtonKeyCodeShift:
+ mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconShift));
+ break;
+ case HbInputButton::ButtonKeyCodeSymbol:
+ mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol));
+ break;
+ case HbInputButton::ButtonKeyCodeEnter:
+ mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconEnter));
+ break;
+ case HbInputButton::ButtonKeyCodeSpace:
+ mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSpace));
+ break;
+ case HbInputButton::ButtonKeyCodeAlphabet:
+ mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSymbol));
+ break;
+ case HbInputButton::ButtonKeyCodeSmiley:
+ mIcons.replace(HbInputButton::ButtonTextIndexPrimary, HbIcon(HbInputButtonIconSmiley));
+ break;
+ default:
+ break;
}
}
/// @endcond
/*!
+ \enum HbInputButton::HbInputButtonKeyCode
+
+ This enum defines a set of predefined key codes for input button. ButtonKeyCodeCustom should
+ always be the last item so that all values bigger than ButtonKeyCodeCustom can be interpreted
+ as custom key codes
+ */
+
+/*!
+ \enum HbInputButton::HbInputButtonType
+
+ This enum defines different button types. Button's graphics, text layout and functionality
+ depend of the this type. ButtonTypeCount should always be the last value.
+ */
+
+/*!
+ \enum HbInputButton::HbInputButtonState
+
+ This enum defines button states. State mostly affects the button's visual look in addition
+ to what can be done with the button (i.e. no interaction with disabled buttons, released and
+ latched buttons can be pressed). ButtonStateCount should always be the last value.
+ */
+
+/*!
+ \enum HbInputButton::HbInputButtonTextIndex
+
+ This enum defines set of text indices that can be used when setting texts to different parts of
+ a button using setText function. ButtonTextIndexCount should always be the last value.
+ */
+
+/*!
+ \enum HbInputButton::HbInputButtonIconIndex
+
+ This enum defines set of icon indices that can be used when setting icons to different parts of
+ a button using setIcon function. ButtonIconIndexCount should always be the last value.
+ */
+
+/*!
Constructor
*/
HbInputButton::HbInputButton()
@@ -210,6 +293,8 @@
/*!
Updates button's state.
+State change sequence latched, pressed, released will result
+in a latched state. Otherwise the new state will be the given state.
\sa state
*/
@@ -217,7 +302,19 @@
{
Q_D(HbInputButton);
- d->mState = state;
+ if (state == ButtonStateReleased) {
+ d->mTap = false;
+ clearLastTriggeredPosition();
+ }
+
+ if (d->mState == ButtonStatePressed &&
+ d->mPreviousState == ButtonStateLatched &&
+ state == ButtonStateReleased) {
+ d->mState = d->mPreviousState;
+ } else {
+ d->mPreviousState = d->mState;
+ d->mState = state;
+ }
}
/*!
@@ -517,4 +614,123 @@
return d->mBoundingRect;
}
+/*!
+\brief Returns an active touch area for current button.
+
+Button contains bounding rectangle for actual size of the item, while touch area
+can actually extend over buttons physical boundaries. This is to make interacting
+with button easier.
+
+\return Active touch area as a rectangle, centered to its button.
+\sa setBoundingRect
+*/
+QRectF HbInputButton::activeTouchArea() const
+{
+ Q_D(const HbInputButton);
+
+ QRectF threshold(d->mBoundingRect);
+
+ qreal mod_w = d->mBoundingRect.width() * HbInputThresholdMultiplier;
+ qreal mod_h = d->mBoundingRect.height() * HbInputThresholdMultiplier;
+ threshold.adjust(-mod_w, -mod_h, mod_w, mod_h);
+
+ return threshold;
+}
+
+/*!
+\brief Set position where last user interaction occurred.
+*/
+void HbInputButton::setLastTriggeredPosition(const QPointF &position)
+{
+ Q_D(HbInputButton);
+
+ d->mLastInteractionPoint = position;
+}
+
+/*!
+\brief Clear last user interaction data.
+*/
+void HbInputButton::clearLastTriggeredPosition()
+{
+ Q_D(HbInputButton);
+
+ d->mLastInteractionPoint = HbInputInvalidPoint;
+}
+
+/*!
+Checks whether the new touch point position is close enough to the previous
+one that hit this button so that the new touch point can
+be interpreted as the same as the old one.
+*/
+bool HbInputButton::wasTriggeredAt(const QPointF &position) const
+{
+ Q_D(const HbInputButton);
+
+ QRectF rect(d->mLastInteractionPoint.x() - HbInputTouchThreshold, d->mLastInteractionPoint.y() - HbInputTouchThreshold,
+ 2 * HbInputTouchThreshold, 2 * HbInputTouchThreshold);
+
+ return rect.contains(position);
+}
+
+/*!
+\brief Set position where the button was first touched.
+*/
+void HbInputButton::setTouchPointPosition(const QPointF &position)
+{
+ Q_D(HbInputButton);
+
+ d->mTouchPoint = position;
+ d->mTap = true;
+ d->mTouchTime.start();
+}
+
+/*!
+Returns the current touch position which in case of
+a short tap is the touch down position and otherwise the
+last triggered position.
+*/
+QPointF HbInputButton::currentTouchPointPosition() const
+{
+ Q_D(const HbInputButton);
+
+ if (d->mTap) {
+ return d->mTouchPoint;
+ }
+ return d->mLastInteractionPoint;
+}
+
+/*!
+\brief Checks whether move to given \a position should be ignored or processed normally
+
+True is returned if given position is close enough to touch down point during
+short timeout after the button has been pressed or after timeout if the
+position is inside button's active touch area. Otherwise false is returned and
+move event should be handled normally.
+*/
+bool HbInputButton::suppressMoveEvent(const QPointF &position)
+{
+ Q_D(HbInputButton);
+
+ // Check if the timeout from the touch down event has passed
+ if (d->mTap && d->mTouchTime.elapsed() < HbInputInstantTouchTimeout) {
+ // Create rectangle around touch down position
+ QRectF rect(d->mTouchPoint.x() - d->mTouchThreshold, d->mTouchPoint.y() - d->mTouchThreshold,
+ 2 * d->mTouchThreshold, 2 * d->mTouchThreshold);
+
+ // If inside created rectangle, update last position and ignore the event
+ if (rect.contains(position)) {
+ setLastTriggeredPosition(position);
+ return true;
+ }
+ // Check if new position is still inside active button
+ } else if (activeTouchArea().contains(position)) {
+ setLastTriggeredPosition(position);
+ d->mTap = false;
+ return true;
+ }
+
+ d->mTap = false;
+ return false;
+}
+
// End of file