1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickdelaybutton_p.h"
5#include "qquickabstractbutton_p_p.h"
6
7#include <QtQuick/private/qquickanimation_p.h>
8#include <QtQuick/private/qquicktransition_p.h>
9#include <QtQuick/private/qquicktransitionmanager_p_p.h>
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \qmltype DelayButton
15 \inherits AbstractButton
16//! \instantiates QQuickDelayButton
17 \inqmlmodule QtQuick.Controls
18 \since 5.9
19 \ingroup qtquickcontrols-buttons
20 \brief Check button that triggers when held down long enough.
21
22 \image qtquickcontrols-delaybutton.gif
23
24 DelayButton is a checkable button that incorporates a delay before the
25 button becomes \l {AbstractButton::}{checked} and the \l activated()
26 signal is emitted. This delay prevents accidental presses.
27
28 The current progress is expressed as a decimal value between \c 0.0
29 and \c 1.0. The time it takes for \l activated() to be emitted is
30 measured in milliseconds, and can be set with the \l delay property.
31
32 The progress is indicated by a progress indicator on the button.
33
34 \sa {Customizing DelayButton}, {Button Controls}
35*/
36
37/*!
38 \qmlsignal QtQuick.Controls::DelayButton::activated()
39
40 This signal is emitted when \l progress reaches \c 1.0.
41*/
42
43class QQuickDelayTransitionManager;
44
45class QQuickDelayButtonPrivate : public QQuickAbstractButtonPrivate
46{
47 Q_DECLARE_PUBLIC(QQuickDelayButton)
48
49public:
50 void beginTransition(qreal to);
51 void finishTransition();
52 void cancelTransition();
53
54 QPalette defaultPalette() const override { return QQuickTheme::palette(scope: QQuickTheme::Button); }
55
56 int delay = 300;
57 qreal progress = 0.0;
58 QQuickTransition *transition = nullptr;
59 QScopedPointer<QQuickDelayTransitionManager> transitionManager;
60};
61
62class QQuickDelayTransitionManager : public QQuickTransitionManager
63{
64public:
65 QQuickDelayTransitionManager(QQuickDelayButton *button) : m_button(button) { }
66
67 void transition(QQuickTransition *transition, qreal progress);
68
69protected:
70 void finished() override;
71
72private:
73 QQuickDelayButton *m_button = nullptr;
74};
75
76void QQuickDelayTransitionManager::transition(QQuickTransition *transition, qreal progress)
77{
78 qmlExecuteDeferred(transition);
79
80 QQmlProperty defaultTarget(m_button, QLatin1String("progress"));
81 QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations();
82 const int count = animations.count(&animations);
83 for (int i = 0; i < count; ++i) {
84 QQuickAbstractAnimation *anim = animations.at(&animations, i);
85 anim->setDefaultTarget(defaultTarget);
86 }
87
88 QList<QQuickStateAction> actions;
89 actions << QQuickStateAction(m_button, QLatin1String("progress"), progress);
90 QQuickTransitionManager::transition(actions, transition, defaultTarget: m_button);
91}
92
93void QQuickDelayTransitionManager::finished()
94{
95 if (qFuzzyCompare(p1: m_button->progress(), p2: qreal(1.0)))
96 emit m_button->activated();
97}
98
99void QQuickDelayButtonPrivate::beginTransition(qreal to)
100{
101 Q_Q(QQuickDelayButton);
102 if (!transition) {
103 q->setProgress(to);
104 finishTransition();
105 return;
106 }
107
108 if (!transitionManager)
109 transitionManager.reset(other: new QQuickDelayTransitionManager(q));
110
111 transitionManager->transition(transition, progress: to);
112}
113
114void QQuickDelayButtonPrivate::finishTransition()
115{
116 Q_Q(QQuickDelayButton);
117 if (qFuzzyCompare(p1: progress, p2: qreal(1.0)))
118 emit q->activated();
119}
120
121void QQuickDelayButtonPrivate::cancelTransition()
122{
123 if (transitionManager)
124 transitionManager->cancel();
125}
126
127QQuickDelayButton::QQuickDelayButton(QQuickItem *parent)
128 : QQuickAbstractButton(*(new QQuickDelayButtonPrivate), parent)
129{
130 setCheckable(true);
131}
132
133/*!
134 \qmlproperty int QtQuick.Controls::DelayButton::delay
135
136 This property holds the time it takes (in milliseconds) for \l progress
137 to reach \c 1.0 and emit \l activated().
138
139 The default value is \c 3000 ms.
140*/
141int QQuickDelayButton::delay() const
142{
143 Q_D(const QQuickDelayButton);
144 return d->delay;
145}
146
147void QQuickDelayButton::setDelay(int delay)
148{
149 Q_D(QQuickDelayButton);
150 if (d->delay == delay)
151 return;
152
153 d->delay = delay;
154 emit delayChanged();
155}
156
157/*!
158 \qmlproperty real QtQuick.Controls::DelayButton::progress
159
160 This property holds the current progress as displayed by the progress
161 indicator, in the range \c 0.0 - \c 1.0.
162*/
163qreal QQuickDelayButton::progress() const
164{
165 Q_D(const QQuickDelayButton);
166 return d->progress;
167}
168
169void QQuickDelayButton::setProgress(qreal progress)
170{
171 Q_D(QQuickDelayButton);
172 if (qFuzzyCompare(p1: d->progress, p2: progress))
173 return;
174
175 d->progress = progress;
176 emit progressChanged();
177}
178
179/*!
180 \qmlproperty Transition QtQuick.Controls::DelayButton::transition
181
182 This property holds the transition that is applied on the \l progress
183 property when the button is pressed or released.
184*/
185QQuickTransition *QQuickDelayButton::transition() const
186{
187 Q_D(const QQuickDelayButton);
188 return d->transition;
189}
190
191void QQuickDelayButton::setTransition(QQuickTransition *transition)
192{
193 Q_D(QQuickDelayButton);
194 if (d->transition == transition)
195 return;
196
197 d->transition = transition;
198 emit transitionChanged();
199}
200
201void QQuickDelayButton::buttonChange(ButtonChange change)
202{
203 Q_D(QQuickDelayButton);
204 switch (change) {
205 case ButtonCheckedChange:
206 d->cancelTransition();
207 setProgress(d->checked ? 1.0 : 0.0);
208 break;
209 case ButtonPressedChanged:
210 if (!d->checked)
211 d->beginTransition(to: d->pressed ? 1.0 : 0.0);
212 break;
213 default:
214 QQuickAbstractButton::buttonChange(change);
215 break;
216 }
217}
218
219void QQuickDelayButton::nextCheckState()
220{
221 Q_D(QQuickDelayButton);
222 setChecked(!d->checked && qFuzzyCompare(p1: d->progress, p2: qreal(1.0)));
223}
224
225QFont QQuickDelayButton::defaultFont() const
226{
227 return QQuickTheme::font(scope: QQuickTheme::Button);
228}
229
230QT_END_NAMESPACE
231
232#include "moc_qquickdelaybutton_p.cpp"
233

source code of qtdeclarative/src/quicktemplates/qquickdelaybutton.cpp