From cdda0b9492920424d8ffb1af1f3e9dfe0f031b44 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 31 Oct 2015 21:41:18 +0100 Subject: Add AbstractButton::autoRepeat Change-Id: Idbb94bac9ccdfae730f6e4da6d63c664971f41a3 Reviewed-by: Mitch Curtis --- src/templates/qquickabstractbutton.cpp | 109 +++++++++++++++++++++++++++++-- src/templates/qquickabstractbutton_p.h | 6 ++ src/templates/qquickabstractbutton_p_p.h | 9 +++ tests/auto/controls/data/tst_button.qml | 58 ++++++++++++++++ 4 files changed, 177 insertions(+), 5 deletions(-) diff --git a/src/templates/qquickabstractbutton.cpp b/src/templates/qquickabstractbutton.cpp index df5822fa..849d2340 100644 --- a/src/templates/qquickabstractbutton.cpp +++ b/src/templates/qquickabstractbutton.cpp @@ -37,10 +37,15 @@ #include "qquickabstractbutton_p.h" #include "qquickabstractbutton_p_p.h" +#include #include QT_BEGIN_NAMESPACE +// copied from qabstractbutton.cpp +static const int AUTO_REPEAT_DELAY = 300; +static const int AUTO_REPEAT_INTERVAL = 100; + /*! \qmltype AbstractButton \inherits Control @@ -95,9 +100,36 @@ QT_BEGIN_NAMESPACE */ QQuickAbstractButtonPrivate::QQuickAbstractButtonPrivate() : - pressed(false), checked(false), checkable(false), exclusive(false), - label(Q_NULLPTR), indicator(Q_NULLPTR) + pressed(false), checked(false), checkable(false), exclusive(false), autoRepeat(false), + delayTimer(0), repeatTimer(0), repeatButton(Qt::NoButton), label(Q_NULLPTR), indicator(Q_NULLPTR) +{ +} + +void QQuickAbstractButtonPrivate::startRepeatDelay() { + Q_Q(QQuickAbstractButton); + stopPressRepeat(); + delayTimer = q->startTimer(AUTO_REPEAT_DELAY); +} + +void QQuickAbstractButtonPrivate::startPressRepeat() +{ + Q_Q(QQuickAbstractButton); + stopPressRepeat(); + repeatTimer = q->startTimer(AUTO_REPEAT_INTERVAL); +} + +void QQuickAbstractButtonPrivate::stopPressRepeat() +{ + Q_Q(QQuickAbstractButton); + if (delayTimer > 0) { + q->killTimer(delayTimer); + delayTimer = 0; + } + if (repeatTimer > 0) { + q->killTimer(repeatTimer); + repeatTimer = 0; + } } QQuickAbstractButton::QQuickAbstractButton(QQuickItem *parent) : @@ -216,6 +248,30 @@ void QQuickAbstractButton::setExclusive(bool exclusive) d->exclusive = exclusive; } +/*! + \qmlproperty bool Qt.labs.controls::AbstractButton::autoRepeat + + This property holds whether the button repeats pressed(), released() + and clicked() signals while the button is pressed and held down. + + The default value is \c false. +*/ +bool QQuickAbstractButton::autoRepeat() const +{ + Q_D(const QQuickAbstractButton); + return d->autoRepeat; +} + +void QQuickAbstractButton::setAutoRepeat(bool repeat) +{ + Q_D(QQuickAbstractButton); + if (d->autoRepeat != repeat) { + d->stopPressRepeat(); + d->autoRepeat = repeat; + emit autoRepeatChanged(); + } +} + /*! \qmlproperty Item Qt.labs.controls::AbstractButton::indicator @@ -290,11 +346,18 @@ void QQuickAbstractButton::focusOutEvent(QFocusEvent *event) void QQuickAbstractButton::keyPressEvent(QKeyEvent *event) { + Q_D(QQuickAbstractButton); QQuickControl::keyPressEvent(event); if (event->key() == Qt::Key_Space) { setPressed(true); + d->pressPoint = QPoint(qRound(width() / 2), qRound(height() / 2)); + + if (d->autoRepeat) { + d->startRepeatDelay(); + d->repeatButton = Qt::NoButton; + } - QQuickMouseEvent me(width() / 2, height() / 2, Qt::NoButton, Qt::NoButton, event->modifiers()); + QQuickMouseEvent me(d->pressPoint.x(), d->pressPoint.y(), Qt::NoButton, QGuiApplication::mouseButtons(), event->modifiers()); emit pressed(&me); event->setAccepted(me.isAccepted()); } @@ -302,33 +365,48 @@ void QQuickAbstractButton::keyPressEvent(QKeyEvent *event) void QQuickAbstractButton::keyReleaseEvent(QKeyEvent *event) { + Q_D(QQuickAbstractButton); QQuickControl::keyReleaseEvent(event); if (event->key() == Qt::Key_Space) { setPressed(false); - QQuickMouseEvent mre(width() / 2, height() / 2, Qt::NoButton, Qt::NoButton, event->modifiers()); + QQuickMouseEvent mre(d->pressPoint.x(), d->pressPoint.y(), Qt::NoButton, QGuiApplication::mouseButtons(), event->modifiers()); emit released(&mre); - QQuickMouseEvent mce(width() / 2, height() / 2, Qt::NoButton, Qt::NoButton, event->modifiers(), true /* isClick */); + QQuickMouseEvent mce(d->pressPoint.x(), d->pressPoint.y(), Qt::NoButton, QGuiApplication::mouseButtons(), event->modifiers(), true /* isClick */); emit clicked(&mce); nextCheckState(); event->setAccepted(mre.isAccepted() || mce.isAccepted()); + + if (d->autoRepeat) + d->stopPressRepeat(); } } void QQuickAbstractButton::mousePressEvent(QMouseEvent *event) { + Q_D(QQuickAbstractButton); QQuickControl::mousePressEvent(event); setPressed(true); + d->pressPoint = event->pos(); QQuickMouseEvent me(event->x(), event->y(), event->button(), event->buttons(), event->modifiers()); emit pressed(&me); event->setAccepted(me.isAccepted()); + + if (d->autoRepeat) { + d->startRepeatDelay(); + d->repeatButton = event->button(); + } } void QQuickAbstractButton::mouseMoveEvent(QMouseEvent *event) { + Q_D(QQuickAbstractButton); QQuickControl::mouseMoveEvent(event); setPressed(contains(event->pos())); + + if (d->autoRepeat) + d->stopPressRepeat(); } void QQuickAbstractButton::mouseReleaseEvent(QMouseEvent *event) @@ -347,8 +425,12 @@ void QQuickAbstractButton::mouseReleaseEvent(QMouseEvent *event) } else { emit canceled(); } + if (contains(event->pos())) nextCheckState(); + + if (d->autoRepeat) + d->stopPressRepeat(); } void QQuickAbstractButton::mouseDoubleClickEvent(QMouseEvent *event) @@ -366,10 +448,27 @@ void QQuickAbstractButton::mouseUngrabEvent() QQuickControl::mouseUngrabEvent(); if (d->pressed) { setPressed(false); + d->stopPressRepeat(); emit canceled(); } } +void QQuickAbstractButton::timerEvent(QTimerEvent *event) +{ + Q_D(QQuickAbstractButton); + QQuickControl::timerEvent(event); + if (event->timerId() == d->delayTimer) { + d->startPressRepeat(); + } else if (event->timerId() == d->repeatTimer) { + QQuickMouseEvent mre(d->pressPoint.x(), d->pressPoint.y(), d->repeatButton, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + emit released(&mre); + QQuickMouseEvent mce(d->pressPoint.x(), d->pressPoint.y(), d->repeatButton, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers(), true /* isClick */); + emit clicked(&mce); + QQuickMouseEvent mpe(d->pressPoint.x(), d->pressPoint.y(), d->repeatButton, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + emit pressed(&mpe); + } +} + void QQuickAbstractButton::checkStateSet() { } diff --git a/src/templates/qquickabstractbutton_p.h b/src/templates/qquickabstractbutton_p.h index ea1eacc8..5ab24a23 100644 --- a/src/templates/qquickabstractbutton_p.h +++ b/src/templates/qquickabstractbutton_p.h @@ -62,6 +62,7 @@ class Q_LABSTEMPLATES_EXPORT QQuickAbstractButton : public QQuickControl Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged FINAL) Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL) Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL) Q_PROPERTY(QQuickItem *label READ label WRITE setLabel NOTIFY labelChanged FINAL) @@ -83,6 +84,9 @@ public: bool isExclusive() const; void setExclusive(bool exclusive); + bool autoRepeat() const; + void setAutoRepeat(bool repeat); + QQuickItem *indicator() const; void setIndicator(QQuickItem *indicator); @@ -102,6 +106,7 @@ Q_SIGNALS: void pressedChanged(); void checkedChanged(); void checkableChanged(); + void autoRepeatChanged(); void indicatorChanged(); void labelChanged(); @@ -116,6 +121,7 @@ protected: void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseUngrabEvent() Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; virtual void checkStateSet(); virtual void nextCheckState(); diff --git a/src/templates/qquickabstractbutton_p_p.h b/src/templates/qquickabstractbutton_p_p.h index e8def77d..bfdadb19 100644 --- a/src/templates/qquickabstractbutton_p_p.h +++ b/src/templates/qquickabstractbutton_p_p.h @@ -59,11 +59,20 @@ class QQuickAbstractButtonPrivate : public QQuickControlPrivate public: QQuickAbstractButtonPrivate(); + void startRepeatDelay(); + void startPressRepeat(); + void stopPressRepeat(); + QString text; bool pressed; bool checked; bool checkable; bool exclusive; + bool autoRepeat; + int delayTimer; + int repeatTimer; + QPointF pressPoint; + Qt::MouseButton repeatButton; QQuickItem *label; QQuickItem *indicator; }; diff --git a/tests/auto/controls/data/tst_button.qml b/tests/auto/controls/data/tst_button.qml index 638a773c..76d45e03 100644 --- a/tests/auto/controls/data/tst_button.qml +++ b/tests/auto/controls/data/tst_button.qml @@ -232,4 +232,62 @@ TestCase { control.destroy() } + + SignalSpy { id: clickSpy; signalName: "clicked" } + + function test_autoRepeat() { + var control = button.createObject(testCase) + verify(control) + + compare(control.autoRepeat, false) + control.autoRepeat = true + compare(control.autoRepeat, true) + + control.forceActiveFocus() + verify(control.activeFocus) + + clickSpy.target = control + verify(clickSpy.valid) + + var repeatCount = 2 + var repeatSequence = [["pressedChanged", { "pressed": true }], + "pressed", + "released", + "clicked", + "pressed", + "released", + "clicked", + "pressed"] + + // auto-repeat a couple of mouse clicks + control.spy.expectedSequence = repeatSequence + mousePress(control) + compare(control.pressed, true) + tryCompare(clickSpy, "count", repeatCount) + verify(control.spy.success) + + control.spy.expectedSequence = [["pressedChanged", { "pressed": false }], + "released", + "clicked"] + mouseRelease(control) + compare(control.pressed, false) + verify(control.spy.success) + + // auto-repeat a couple of key clicks + clickSpy.clear() + control.spy.expectedSequence = repeatSequence + keyPress(Qt.Key_Space) + compare(control.pressed, true) + tryCompare(clickSpy, "count", repeatCount) + verify(control.spy.success) + + control.spy.expectedSequence = [["pressedChanged", { "pressed": false }], + "released", + "clicked"] + keyRelease(Qt.Key_Space) + compare(control.pressed, false) + verify(control.spy.success) + + control.destroy() + } } -- cgit v1.2.3