From f15468cf9e5c440518a7af9a265234bff8e6c627 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 20 Dec 2016 21:52:25 +0100 Subject: Add DelayButton [ChangeLog][Controls][DelayButton] Added DelayButton. Change-Id: I94820dfb41ba9b90f0a29cda01ac476b54cf3de8 Reviewed-by: Mitch Curtis --- src/imports/controls/DelayButton.qml | 126 ++++++++++ src/imports/controls/controls.pri | 1 + .../images/qtquickcontrols2-delaybutton-custom.png | Bin 0 -> 7340 bytes .../doc/images/qtquickcontrols2-delaybutton.gif | Bin 0 -> 12595 bytes .../qtquickcontrols2-delaybutton-custom.qml | 82 +++++++ .../controls/doc/src/qtquickcontrols2-buttons.qdoc | 15 ++ .../doc/src/qtquickcontrols2-customize.qdoc | 10 + .../doc/src/qtquickcontrols2-differences.qdoc | 2 +- src/imports/controls/material/DelayButton.qml | 126 ++++++++++ src/imports/controls/material/material.pri | 1 + src/imports/controls/qtquickcontrols2plugin.cpp | 1 + src/imports/controls/universal/DelayButton.qml | 96 ++++++++ src/imports/controls/universal/universal.pri | 1 + src/imports/templates/qtquicktemplates2plugin.cpp | 2 + src/quicktemplates2/qquickabstractbutton.cpp | 1 + src/quicktemplates2/qquickabstractbutton_p.h | 1 + src/quicktemplates2/qquickdelaybutton.cpp | 271 +++++++++++++++++++++ src/quicktemplates2/qquickdelaybutton_p.h | 98 ++++++++ src/quicktemplates2/quicktemplates2.pri | 2 + 19 files changed, 835 insertions(+), 1 deletion(-) create mode 100644 src/imports/controls/DelayButton.qml create mode 100644 src/imports/controls/doc/images/qtquickcontrols2-delaybutton-custom.png create mode 100644 src/imports/controls/doc/images/qtquickcontrols2-delaybutton.gif create mode 100644 src/imports/controls/doc/snippets/screenshots/qtquickcontrols2-delaybutton-custom.qml create mode 100644 src/imports/controls/material/DelayButton.qml create mode 100644 src/imports/controls/universal/DelayButton.qml create mode 100644 src/quicktemplates2/qquickdelaybutton.cpp create mode 100644 src/quicktemplates2/qquickdelaybutton_p.h (limited to 'src') diff --git a/src/imports/controls/DelayButton.qml b/src/imports/controls/DelayButton.qml new file mode 100644 index 00000000..4a569fcf --- /dev/null +++ b/src/imports/controls/DelayButton.qml @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Controls.impl 2.2 +import QtQuick.Templates 2.2 as T + +T.DelayButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + padding: 6 + leftPadding: padding + 2 + rightPadding: padding + 2 + + transition: Transition { + NumberAnimation { + duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress) + } + } + + contentItem: Item { + implicitWidth: label.implicitWidth + implicitHeight: label.implicitHeight + + Item { + x: -control.leftPadding + (control.progress * control.width) + width: (1.0 - control.progress) * control.width + height: parent.height + + clip: control.progress > 0 + visible: control.progress < 1 + + Text { + id: label + x: -parent.x + width: control.availableWidth + height: parent.height + + text: control.text + font: control.font + opacity: enabled ? 1 : 0.3 + color: control.visualFocus ? Default.focusColor : (control.down ? Default.textDarkColor : Default.textColor) + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + } + + Item { + x: -control.leftPadding + width: control.progress * control.width + height: parent.height + + clip: control.progress > 0 + visible: control.progress > 0 + + Text { + x: control.leftPadding + width: control.availableWidth + height: parent.height + + text: control.text + font: control.font + opacity: enabled ? 1 : 0.3 + color: Default.textLightColor + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + } + } + + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + color: control.visualFocus ? (control.down ? Default.focusPressedColor : Default.focusLightColor) : (control.down ? Default.buttonPressedColor : Default.buttonColor) + border.color: Default.focusColor + border.width: control.visualFocus ? 2 : 0 + + Rectangle { + width: control.progress * parent.width + height: parent.height + color: control.visualFocus ? (control.down ? Default.buttonCheckedFocusColor : Default.focusColor) : (control.down ? Default.buttonCheckedPressedColor : Default.textColor) + } + } +} diff --git a/src/imports/controls/controls.pri b/src/imports/controls/controls.pri index 8a262694..04e31103 100644 --- a/src/imports/controls/controls.pri +++ b/src/imports/controls/controls.pri @@ -21,6 +21,7 @@ QML_CONTROLS = \ ComboBox.qml \ Container.qml \ Control.qml \ + DelayButton.qml \ Dial.qml \ Dialog.qml \ DialogButtonBox.qml \ diff --git a/src/imports/controls/doc/images/qtquickcontrols2-delaybutton-custom.png b/src/imports/controls/doc/images/qtquickcontrols2-delaybutton-custom.png new file mode 100644 index 00000000..be7f2586 Binary files /dev/null and b/src/imports/controls/doc/images/qtquickcontrols2-delaybutton-custom.png differ diff --git a/src/imports/controls/doc/images/qtquickcontrols2-delaybutton.gif b/src/imports/controls/doc/images/qtquickcontrols2-delaybutton.gif new file mode 100644 index 00000000..16a198f9 Binary files /dev/null and b/src/imports/controls/doc/images/qtquickcontrols2-delaybutton.gif differ diff --git a/src/imports/controls/doc/snippets/screenshots/qtquickcontrols2-delaybutton-custom.qml b/src/imports/controls/doc/snippets/screenshots/qtquickcontrols2-delaybutton-custom.qml new file mode 100644 index 00000000..2453e2d6 --- /dev/null +++ b/src/imports/controls/doc/snippets/screenshots/qtquickcontrols2-delaybutton-custom.qml @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [file] +import QtQuick 2.6 +import QtQuick.Controls 2.2 + +DelayButton { + id: control + checked: true + text: qsTr("Delay\nButton") + + contentItem: Text { + text: control.text + font: control.font + opacity: enabled ? 1.0 : 0.3 + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Rectangle { + implicitWidth: 100 + implicitHeight: 100 + opacity: enabled ? 1 : 0.3 + color: control.down ? "#17a81a" : "#21be2b" + radius: size / 2 + + readonly property real size: Math.min(control.width, control.height) + width: size + height: size + anchors.centerIn: parent + + Canvas { + id: canvas + anchors.fill: parent + + Connections { + target: control + onProgressChanged: canvas.requestPaint() + } + + onPaint: { + var ctx = getContext("2d") + ctx.clearRect(0, 0, width, height) + ctx.strokeStyle = "white" + ctx.lineWidth = parent.size / 20 + ctx.beginPath() + var startAngle = Math.PI / 5 * 3 + var endAngle = startAngle + control.progress * Math.PI / 5 * 9 + ctx.arc(width / 2, height / 2, width / 2 - ctx.lineWidth / 2 - 2, startAngle, endAngle) + ctx.stroke() + } + } + } +} +//! [file] diff --git a/src/imports/controls/doc/src/qtquickcontrols2-buttons.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-buttons.qdoc index 434cf839..6080d7b1 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-buttons.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-buttons.qdoc @@ -99,6 +99,21 @@ \b {See also} \l CheckBox + \section1 DelayButton Control + + \l DelayButton is a button that incorporates a delay before triggering an action. + This delay prevents accidental presses. + + \image qtquickcontrols2-delaybutton.gif + + Recommendations: + \list + \li Use in touch user interfaces. + \li Use for actions that must be triggered with care. + \endlist + + \b {See also} \l Button and \l AbstractButton + \section1 RadioButton Control \image qtquickcontrols2-radiobutton.gif diff --git a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc index 06201404..82914610 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc @@ -419,6 +419,16 @@ \snippet qtquickcontrols2-combobox-custom.qml file + \section2 Customizing DelayButton + + DelayButton consists of two visual items: \l {Control::background}{background} + and \l {Control::contentItem}{content item}. + + \image qtquickcontrols2-delaybutton-custom.png + + \snippet qtquickcontrols2-delaybutton-custom.qml file + + \section2 Customizing Dial Dial consists of two visual items: \l {Control::background}{background} diff --git a/src/imports/controls/doc/src/qtquickcontrols2-differences.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-differences.qdoc index 01429b94..4ea5e4e6 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-differences.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-differences.qdoc @@ -471,7 +471,7 @@ \li \row \li \l [QML QtQuickExtras] {DelayButton} - \li \mdash + \li \l [QML QtQuickControls2] {DelayButton} \li \li \row diff --git a/src/imports/controls/material/DelayButton.qml b/src/imports/controls/material/DelayButton.qml new file mode 100644 index 00000000..8bc48784 --- /dev/null +++ b/src/imports/controls/material/DelayButton.qml @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Templates 2.2 as T +import QtQuick.Controls.Material 2.2 +import QtQuick.Controls.Material.impl 2.2 + +T.DelayButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + // external vertical padding is 6 (to increase touch area) + padding: 12 + leftPadding: padding - 4 + rightPadding: padding - 4 + + Material.elevation: control.down ? 8 : 2 + + transition: Transition { + NumberAnimation { + duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress) + } + } + + contentItem: Text { + text: control.text + font: control.font + color: !control.enabled ? control.Material.hintTextColor : control.Material.foreground + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + // TODO: Add a proper ripple/ink effect for mouse/touch input and focus state + background: Rectangle { + implicitWidth: 64 + implicitHeight: 48 + + // external vertical padding is 6 (to increase touch area) + y: 6 + width: parent.width + height: parent.height - 12 + radius: 2 + color: !control.enabled ? control.Material.buttonDisabledColor : control.Material.buttonColor + + PaddedRectangle { + y: parent.height - 4 + width: parent.width + height: 4 + radius: 2 + topPadding: -2 + clip: true + color: control.checked && control.enabled ? control.Material.accentColor : control.Material.secondaryTextColor + + PaddedRectangle { + width: parent.width * control.progress + height: 4 + radius: 2 + topPadding: -2 + rightPadding: Math.max(-2, width - parent.width) + clip: true + color: control.Material.accentColor + } + } + + Behavior on color { + ColorAnimation { + duration: 400 + } + } + + layer.enabled: control.enabled && control.Material.buttonColor.a > 0 + layer.effect: ElevationEffect { + elevation: control.Material.elevation + } + + Ripple { + clipRadius: 2 + width: parent.width + height: parent.height + pressed: control.pressed + anchor: control + active: control.down || control.visualFocus || control.hovered + color: control.Material.rippleColor + } + } +} diff --git a/src/imports/controls/material/material.pri b/src/imports/controls/material/material.pri index 5f70ca32..64d91442 100644 --- a/src/imports/controls/material/material.pri +++ b/src/imports/controls/material/material.pri @@ -22,6 +22,7 @@ QML_FILES += \ $$PWD/CheckIndicator.qml \ $$PWD/ComboBox.qml \ $$PWD/CursorDelegate.qml \ + $$PWD/DelayButton.qml \ $$PWD/Dial.qml \ $$PWD/Dialog.qml \ $$PWD/DialogButtonBox.qml \ diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index 5af9b910..70f6879b 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -141,6 +141,7 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("ToolSeparator.qml")), uri, 2, 1, "ToolSeparator"); // QtQuick.Controls 2.2 (new types in Qt 5.9) + qmlRegisterType(selector.select(QStringLiteral("DelayButton.qml")), uri, 2, 2, "DelayButton"); } static QObject *styleSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) diff --git a/src/imports/controls/universal/DelayButton.qml b/src/imports/controls/universal/DelayButton.qml new file mode 100644 index 00000000..9d43be44 --- /dev/null +++ b/src/imports/controls/universal/DelayButton.qml @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Templates 2.2 as T +import QtQuick.Controls.Universal 2.2 + +T.DelayButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + padding: 8 + topPadding: padding - 4 + bottomPadding: padding - 4 + + property bool useSystemFocusVisuals: true + + transition: Transition { + NumberAnimation { + duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress) + } + } + + contentItem: Text { + text: control.text + font: control.font + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + opacity: enabled ? 1.0 : 0.2 + color: control.Universal.foreground + } + + background: Rectangle { + implicitWidth: 32 + implicitHeight: 32 + + color: control.down ? control.Universal.baseMediumLowColor : + control.enabled && control.checked ? control.Universal.accent : control.Universal.baseLowColor + + Rectangle { + visible: !control.checked + width: parent.width * control.progress + height: parent.height + color: control.Universal.accent + } + + Rectangle { + width: parent.width + height: parent.height + color: "transparent" + visible: control.hovered + border.width: 2 // ButtonBorderThemeThickness + border.color: control.Universal.baseMediumLowColor + } + } +} diff --git a/src/imports/controls/universal/universal.pri b/src/imports/controls/universal/universal.pri index 833bf2b6..c80a2dfc 100644 --- a/src/imports/controls/universal/universal.pri +++ b/src/imports/controls/universal/universal.pri @@ -6,6 +6,7 @@ QML_FILES += \ $$PWD/CheckDelegate.qml \ $$PWD/CheckIndicator.qml \ $$PWD/ComboBox.qml \ + $$PWD/DelayButton.qml \ $$PWD/Dial.qml \ $$PWD/Dialog.qml \ $$PWD/DialogButtonBox.qml \ diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index b78d3146..d7f6cf18 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -225,6 +226,7 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri) // QtQuick.Templates 2.2 (new types and revisions in Qt 5.9) qmlRegisterRevision(uri, 2, 2); qmlRegisterType(uri, 2, 2, "ComboBox"); + qmlRegisterType(uri, 2, 2, "DelayButton"); qmlRegisterType(uri, 2, 2, "Dial"); qmlRegisterType(uri, 2, 2, "Drawer"); qmlRegisterType(uri, 2, 2, "RangeSlider"); diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index c4fde34d..7ca776cd 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -400,6 +400,7 @@ void QQuickAbstractButton::setPressed(bool isPressed) d->pressed = isPressed; setAccessibleProperty("pressed", isPressed); emit pressedChanged(); + buttonChange(ButtonPressedChanged); if (!d->explicitDown) { setDown(d->pressed); diff --git a/src/quicktemplates2/qquickabstractbutton_p.h b/src/quicktemplates2/qquickabstractbutton_p.h index b8c9476f..8a1d960b 100644 --- a/src/quicktemplates2/qquickabstractbutton_p.h +++ b/src/quicktemplates2/qquickabstractbutton_p.h @@ -130,6 +130,7 @@ protected: ButtonAutoRepeatChange, ButtonCheckedChange, ButtonCheckableChange, + ButtonPressedChanged, ButtonTextChange }; virtual void buttonChange(ButtonChange change); diff --git a/src/quicktemplates2/qquickdelaybutton.cpp b/src/quicktemplates2/qquickdelaybutton.cpp new file mode 100644 index 00000000..3c8eaeb0 --- /dev/null +++ b/src/quicktemplates2/qquickdelaybutton.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdelaybutton_p.h" +#include "qquickabstractbutton_p_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype DelayButton + \inherits AbstractButton + \instantiates QQuickDelayButton + \inqmlmodule QtQuick.Controls + \since 5.9 + \ingroup qtquickcontrols2-buttons + \brief Check button that triggers when held down long enough. + + \image qtquickcontrols2-delaybutton.gif + + DelayButton is a checkable button that incorporates a delay before the + button becomes \l {AbstractButton::}{checked} and the \l activated() + signal is emitted. This delay prevents accidental presses. + + The current progress is expressed as a decimal value between \c 0.0 + and \c 1.0. The time it takes for \l activated() to be emitted is + measured in milliseconds, and can be set with the \l delay property. + + The progress is indicated by a progress indicator on the button. + + \sa {Customizing DelayButton}, {Button Controls} +*/ + +/*! + \qmlsignal QtQuick.Controls::DelayButton::activated() + + This signal is emitted when \l progress reaches \c 1.0. +*/ + +class QQuickDelayTransitionManager; + +class QQuickDelayButtonPrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickDelayButton) + +public: + QQuickDelayButtonPrivate(); + + void beginTransition(qreal to); + void finishTransition(); + void cancelTransition(); + + int delay; + qreal progress; + QQuickTransition *transition; + QScopedPointer transitionManager; +}; + +class QQuickDelayTransitionManager : public QQuickTransitionManager +{ +public: + QQuickDelayTransitionManager(QQuickDelayButton *button) : m_button(button) { } + + void transition(QQuickTransition *transition, qreal progress); + +protected: + void finished() override; + +private: + QQuickDelayButton *m_button; +}; + +void QQuickDelayTransitionManager::transition(QQuickTransition *transition, qreal progress) +{ + qmlExecuteDeferred(transition); + + QQmlProperty defaultTarget(m_button, QLatin1String("progress")); + QQmlListProperty animations = transition->animations(); + const int count = animations.count(&animations); + for (int i = 0; i < count; ++i) { + QQuickAbstractAnimation *anim = animations.at(&animations, i); + anim->setDefaultTarget(defaultTarget); + } + + QList actions; + actions << QQuickStateAction(m_button, QLatin1String("progress"), progress); + QQuickTransitionManager::transition(actions, transition, m_button); +} + +void QQuickDelayTransitionManager::finished() +{ + if (qFuzzyCompare(m_button->progress(), 1.0)) + emit m_button->activated(); +} + +QQuickDelayButtonPrivate::QQuickDelayButtonPrivate() + : delay(3000), + progress(0.0), + transition(nullptr) +{ +} + +void QQuickDelayButtonPrivate::beginTransition(qreal to) +{ + Q_Q(QQuickDelayButton); + if (!transition) { + q->setProgress(to); + finishTransition(); + return; + } + + if (!transitionManager) + transitionManager.reset(new QQuickDelayTransitionManager(q)); + + transitionManager->transition(transition, to); +} + +void QQuickDelayButtonPrivate::finishTransition() +{ + Q_Q(QQuickDelayButton); + if (qFuzzyCompare(progress, 1.0)) + emit q->activated(); +} + +void QQuickDelayButtonPrivate::cancelTransition() +{ + if (transitionManager) + transitionManager->cancel(); +} + +QQuickDelayButton::QQuickDelayButton(QQuickItem *parent) : + QQuickAbstractButton(*(new QQuickDelayButtonPrivate), parent) +{ + setCheckable(true); +} + +/*! + \qmlproperty int QtQuick.Controls::DelayButton::delay + + This property holds the time it takes (in milliseconds) for \l progress + to reach \c 1.0 and emit \l activated(). + + The default value is \c 3000 ms. +*/ +int QQuickDelayButton::delay() const +{ + Q_D(const QQuickDelayButton); + return d->delay; +} + +void QQuickDelayButton::setDelay(int delay) +{ + Q_D(QQuickDelayButton); + if (d->delay == delay) + return; + + d->delay = delay; + emit delayChanged(); +} + +/*! + \qmlproperty real QtQuick.Controls::DelayButton::progress + \readonly + + This property holds the current progress as displayed by the progress + indicator, in the range \c 0.0 - \c 1.0. +*/ +qreal QQuickDelayButton::progress() const +{ + Q_D(const QQuickDelayButton); + return d->progress; +} + +void QQuickDelayButton::setProgress(qreal progress) +{ + Q_D(QQuickDelayButton); + if (qFuzzyCompare(d->progress, progress)) + return; + + d->progress = progress; + emit progressChanged(); +} + +/*! + \qmlproperty Transition QtQuick.Controls::DelayButton::transition + + This property holds the transition that is applied on the \l progress + property when the button is pressed or released. +*/ +QQuickTransition *QQuickDelayButton::transition() const +{ + Q_D(const QQuickDelayButton); + return d->transition; +} + +void QQuickDelayButton::setTransition(QQuickTransition *transition) +{ + Q_D(QQuickDelayButton); + if (d->transition == transition) + return; + + d->transition = transition; + emit transitionChanged(); +} + +void QQuickDelayButton::buttonChange(ButtonChange change) +{ + Q_D(QQuickDelayButton); + switch (change) { + case ButtonCheckedChange: + d->cancelTransition(); + setProgress(d->checked ? 1.0 : 0.0); + break; + case ButtonPressedChanged: + if (!d->checked) + d->beginTransition(d->pressed ? 1.0 : 0.0); + break; + default: + QQuickAbstractButton::buttonChange(change); + break; + } +} + +void QQuickDelayButton::nextCheckState() +{ + Q_D(QQuickDelayButton); + setChecked(!d->checked && qFuzzyCompare(d->progress, 1.0)); +} + +QFont QQuickDelayButton::defaultFont() const +{ + return QQuickControlPrivate::themeFont(QPlatformTheme::PushButtonFont); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickdelaybutton_p.h b/src/quicktemplates2/qquickdelaybutton_p.h new file mode 100644 index 00000000..5ac0885d --- /dev/null +++ b/src/quicktemplates2/qquickdelaybutton_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKDELAYBUTTON_P_H +#define QQUICKDELAYBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickTransition; +class QQuickDelayButtonPrivate; + +class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDelayButton : public QQuickAbstractButton +{ + Q_OBJECT + Q_PROPERTY(int delay READ delay WRITE setDelay NOTIFY delayChanged FINAL) + Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged FINAL) + Q_PROPERTY(QQuickTransition *transition READ transition WRITE setTransition NOTIFY transitionChanged FINAL) + +public: + explicit QQuickDelayButton(QQuickItem *parent = nullptr); + + int delay() const; + void setDelay(int delay); + + qreal progress() const; + void setProgress(qreal progress); + + QQuickTransition *transition() const; + void setTransition(QQuickTransition *transition); + +Q_SIGNALS: + void activated(); + void delayChanged(); + void progressChanged(); + void transitionChanged(); + +protected: + void buttonChange(ButtonChange change) override; + void nextCheckState() override; + + QFont defaultFont() const override; + +private: + Q_DISABLE_COPY(QQuickDelayButton) + Q_DECLARE_PRIVATE(QQuickDelayButton) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickDelayButton) + +#endif // QQUICKDELAYBUTTON_P_H diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri index fd92e9d1..e8f02d62 100644 --- a/src/quicktemplates2/quicktemplates2.pri +++ b/src/quicktemplates2/quicktemplates2.pri @@ -15,6 +15,7 @@ HEADERS += \ $$PWD/qquickcontainer_p_p.h \ $$PWD/qquickcontrol_p.h \ $$PWD/qquickcontrol_p_p.h \ + $$PWD/qquickdelaybutton_p.h \ $$PWD/qquickdial_p.h \ $$PWD/qquickdialog_p.h \ $$PWD/qquickdialog_p_p.h \ @@ -90,6 +91,7 @@ SOURCES += \ $$PWD/qquickcombobox.cpp \ $$PWD/qquickcontainer.cpp \ $$PWD/qquickcontrol.cpp \ + $$PWD/qquickdelaybutton.cpp \ $$PWD/qquickdial.cpp \ $$PWD/qquickdialog.cpp \ $$PWD/qquickdialogbuttonbox.cpp \ -- cgit v1.2.3