Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickabstractbutton.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
13#include "qquickicon_p_p.h"
16
17#include <QtCore/qloggingcategory.h>
18#include <QtGui/qstylehints.h>
19#include <QtGui/qguiapplication.h>
20#if QT_CONFIG(shortcut)
21# include <QtGui/private/qshortcutmap_p.h>
22#endif
23#if QT_CONFIG(accessibility)
24#include <QtGui/private/qaccessiblehelper_p.h>
25#endif
26#include <QtGui/private/qguiapplication_p.h>
27#include <QtGui/qpa/qplatformtheme.h>
28#include <QtQuick/private/qquickevents_p_p.h>
29#include <QtQuick/private/qquickevents_p_p.h>
30#include <QtQuick/private/qquickaccessibleattached_p.h>
31#include <QtQml/qqmllist.h>
32
34
35Q_STATIC_LOGGING_CATEGORY(lcButtonAction, "qt.quick.controls.abstractbutton.action")
36#if !QT_CONFIG(shortcut)
37Q_STATIC_LOGGING_CATEGORY(lcButtonMnemonics, "qt.quick.controls.abstractbutton.mnemonics")
38#endif
39
40/*!
41 \qmltype AbstractButton
42 \inherits Control
43//! \nativetype QQuickAbstractButton
44 \inqmlmodule QtQuick.Controls
45 \since 5.7
46 \ingroup qtquickcontrols-buttons
47 \brief Abstract base type providing functionality common to buttons.
48
49 AbstractButton provides the interface for controls with button-like
50 behavior; for example, push buttons and checkable controls like
51 radio buttons and check boxes. As an abstract control, it has no delegate
52 implementations, leaving them to the types that derive from it.
53
54 \sa ButtonGroup, {Button Controls}
55*/
56
57/*!
58 \qmlsignal QtQuick.Controls::AbstractButton::pressed()
59
60 This signal is emitted when the button is interactively pressed by the user via touch, mouse, or keyboard.
61*/
62
63/*!
64 \qmlsignal QtQuick.Controls::AbstractButton::released()
65
66 This signal is emitted when the button is interactively released by the user via touch, mouse, or keyboard.
67*/
68
69/*!
70 \qmlsignal QtQuick.Controls::AbstractButton::canceled()
71
72 This signal is emitted when the button loses mouse grab
73 while being pressed, or when it would emit the \l released
74 signal but the mouse cursor is not inside the button.
75*/
76
77/*!
78 \qmlsignal QtQuick.Controls::AbstractButton::clicked()
79
80 This signal is emitted when the button is interactively clicked by the user via touch, mouse, or keyboard.
81
82 \sa click(), animateClick(), {Call a C++ function from QML when a Button is clicked}
83*/
84
85/*!
86 \since QtQuick.Controls 2.2 (Qt 5.9)
87 \qmlsignal QtQuick.Controls::AbstractButton::toggled()
88
89 This signal is emitted when a checkable button is interactively toggled by the user via touch, mouse, or keyboard.
90*/
91
92/*!
93 \qmlsignal QtQuick.Controls::AbstractButton::pressAndHold()
94
95 This signal is emitted when the button is interactively pressed and held down by the user via touch or mouse.
96 It is not emitted when \l autoRepeat is enabled.
97*/
98
99/*!
100 \qmlsignal QtQuick.Controls::AbstractButton::doubleClicked()
101
102 This signal is emitted when the button is interactively double clicked by the user via touch or mouse.
103*/
104
105void QQuickAbstractButtonPrivate::init()
106{
107 Q_Q(QQuickAbstractButton);
108 q->setActiveFocusOnTab(true);
109#ifdef Q_OS_MACOS
110 q->setFocusPolicy(Qt::TabFocus);
111#else
112 q->setFocusPolicy(Qt::StrongFocus);
113#endif
114 q->setAcceptedMouseButtons(Qt::LeftButton);
115#if QT_CONFIG(quicktemplates2_multitouch)
116 q->setAcceptTouchEvents(true);
117#endif
118#if QT_CONFIG(cursor)
119 q->setCursor(Qt::ArrowCursor);
120#endif
121 setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Fixed);
122 mnemonicEnabled = QGuiApplicationPrivate::platformTheme()->themeHint(
123 QPlatformTheme::MnemonicsEnabled).toBool();
124}
125
126QPointF QQuickAbstractButtonPrivate::centerPressPoint() const
127{
128 return QPointF(qRound(width / 2), qRound(height / 2));
129}
130
131void QQuickAbstractButtonPrivate::setPressPoint(const QPointF &point)
132{
133 pressPoint = point;
134 setMovePoint(point);
135}
136
137void QQuickAbstractButtonPrivate::setMovePoint(const QPointF &point)
138{
139 Q_Q(QQuickAbstractButton);
140 bool xChange = !qFuzzyCompare(point.x(), movePoint.x());
141 bool yChange = !qFuzzyCompare(point.y(), movePoint.y());
142 movePoint = point;
143 if (xChange)
144 emit q->pressXChanged();
145 if (yChange)
146 emit q->pressYChanged();
147}
148
149bool QQuickAbstractButtonPrivate::handlePress(const QPointF &point, ulong timestamp)
150{
151 Q_Q(QQuickAbstractButton);
152 if (pressed)
153 return true;
154 QQuickControlPrivate::handlePress(point, timestamp);
155 setPressPoint(point);
156 q->setPressed(true);
157
158 emit q->pressed();
159
160 if (autoRepeat)
161 startRepeatDelay();
162 else if (touchId != -1 || Qt::LeftButton == (pressButtons & Qt::LeftButton))
163 startPressAndHold();
164 else
165 stopPressAndHold();
166
167 // Tool tips on desktop should hide when their parent item is pressed.
168 if (touchId == -1)
169 QQuickToolTipAttachedPrivate::maybeSetVisibleImplicitly(q, false);
170
171 return true;
172}
173
174bool QQuickAbstractButtonPrivate::handleMove(const QPointF &point, ulong timestamp)
175{
176 Q_Q(QQuickAbstractButton);
177 QQuickControlPrivate::handleMove(point, timestamp);
178 setMovePoint(point);
179 q->setPressed(keepPressed || q->contains(point));
180
181 if (!pressed && autoRepeat)
182 stopPressRepeat();
183 else if (holdTimer > 0 && (!pressed || QLineF(pressPoint, point).length() > QGuiApplication::styleHints()->startDragDistance()))
184 stopPressAndHold();
185 return true;
186}
187
188bool QQuickAbstractButtonPrivate::handleRelease(const QPointF &point, ulong timestamp)
189{
190 Q_Q(QQuickAbstractButton);
191 // Store this here since the base class' handleRelease clears it.
192 const int pressTouchId = touchId;
193
194 QQuickControlPrivate::handleRelease(point, timestamp);
195 bool wasPressed = pressed;
196 setPressPoint(point);
197 q->setPressed(false);
198 pressButtons = Qt::NoButton;
199
200 const bool touchDoubleClick = pressTouchId != -1 && lastTouchReleaseTimestamp != 0
201 && QQuickDeliveryAgentPrivate::isWithinDoubleClickInterval(timestamp - lastTouchReleaseTimestamp)
202 && isDoubleClickConnected();
203
204 if (!wasHeld && wasPressed && (keepPressed || q->contains(point)))
205 q->nextCheckState();
206
207 if (wasPressed) {
208 if (wasHeld && pressTouchId != -1) {
209 // We were potentially showing a tool tip on long press; if we were, hide it now that
210 // we're no longer pressed.
211 QQuickToolTipAttachedPrivate::maybeSetVisibleImplicitly(q, false);
212 }
213
214 emit q->released();
215 if (!wasHeld && !wasDoubleClick)
216 trigger(touchDoubleClick);
217 } else {
218 emit q->canceled();
219 }
220
221 if (autoRepeat)
222 stopPressRepeat();
223 else
224 stopPressAndHold();
225
226 if (!touchDoubleClick) {
227 // This is not a double click yet, but it is potentially the
228 // first release before a double click.
229 if (pressTouchId != -1) {
230 // The corresponding press for this release was a touch press.
231 // Keep track of the timestamp of the release so that we can
232 // emit doubleClicked() if another one comes afterwards.
233 lastTouchReleaseTimestamp = timestamp;
234 }
235 } else {
236 // We just did a double click, so clear the release timestamp
237 // to prepare for any possible future double clicks.
238 lastTouchReleaseTimestamp = 0;
239 }
240
241 wasDoubleClick = false;
242 return true;
243}
244
245void QQuickAbstractButtonPrivate::handleUngrab()
246{
247 Q_Q(QQuickAbstractButton);
248 QQuickControlPrivate::handleUngrab();
249 pressButtons = Qt::NoButton;
250 if (!pressed)
251 return;
252
253 q->setPressed(false);
254 stopPressRepeat();
255 stopPressAndHold();
256 wasDoubleClick = false;
257 lastTouchReleaseTimestamp = 0;
258 emit q->canceled();
259}
260
261bool QQuickAbstractButtonPrivate::acceptKeyClick(Qt::Key key) const
262{
263 const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ButtonPressKeys).value<QList<Qt::Key>>();
264 return buttonPressKeys.contains(key);
265}
266
267bool QQuickAbstractButtonPrivate::isPressAndHoldConnected()
268{
269 Q_Q(QQuickAbstractButton);
270 static const QMetaMethod method = [&]() {
271 const auto signal = &QQuickAbstractButton::pressAndHold;
272 return QMetaMethod::fromSignal(signal);
273 }();
274 return q->isSignalConnected(method);
275}
276
277bool QQuickAbstractButtonPrivate::isDoubleClickConnected()
278{
279 Q_Q(QQuickAbstractButton);
280 static const QMetaMethod method = [&]() {
281 const auto signal = &QQuickAbstractButton::doubleClicked;
282 return QMetaMethod::fromSignal(signal);
283 }();
284 return q->isSignalConnected(method);
285}
286
287void QQuickAbstractButtonPrivate::startPressAndHold()
288{
289 Q_Q(QQuickAbstractButton);
290 wasHeld = false;
291 stopPressAndHold();
292 if (isPressAndHoldConnected())
293 holdTimer = q->startTimer(QGuiApplication::styleHints()->mousePressAndHoldInterval());
294}
295
296void QQuickAbstractButtonPrivate::stopPressAndHold()
297{
298 Q_Q(QQuickAbstractButton);
299 if (holdTimer > 0) {
300 q->killTimer(holdTimer);
301 holdTimer = 0;
302 }
303}
304
305void QQuickAbstractButtonPrivate::startRepeatDelay()
306{
307 Q_Q(QQuickAbstractButton);
308 stopPressRepeat();
309 delayTimer = q->startTimer(repeatDelay);
310}
311
312void QQuickAbstractButtonPrivate::startPressRepeat()
313{
314 Q_Q(QQuickAbstractButton);
315 stopPressRepeat();
316 repeatTimer = q->startTimer(repeatInterval);
317}
318
319void QQuickAbstractButtonPrivate::stopPressRepeat()
320{
321 Q_Q(QQuickAbstractButton);
322 if (delayTimer > 0) {
323 q->killTimer(delayTimer);
324 delayTimer = 0;
325 }
326 if (repeatTimer > 0) {
327 q->killTimer(repeatTimer);
328 repeatTimer = 0;
329 }
330}
331
332#if QT_CONFIG(shortcut)
333void QQuickAbstractButtonPrivate::grabShortcut()
334{
335 Q_Q(QQuickAbstractButton);
336 if (shortcut.isEmpty())
337 return;
338
339 shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(q, shortcut, Qt::WindowShortcut, QQuickShortcutContext::matcher);
340
341 if (!q->isEnabled())
342 QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(false, shortcutId, q);
343}
344
345void QQuickAbstractButtonPrivate::ungrabShortcut()
346{
347 Q_Q(QQuickAbstractButton);
348 if (!shortcutId)
349 return;
350
351 QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(shortcutId, q);
352 shortcutId = 0;
353}
354#endif
355
356void QQuickAbstractButtonPrivate::actionTextChange()
357{
358 Q_Q(QQuickAbstractButton);
359 if (explicitText)
360 return;
361
362 q->buttonChange(QQuickAbstractButton::ButtonTextChange);
363}
364
365void QQuickAbstractButtonPrivate::setText(const QString &newText, QQml::PropertyUtils::State propertyState)
366{
367 Q_Q(QQuickAbstractButton);
368 const QString oldText = q->text();
369 explicitText = isExplicitlySet(propertyState);
370 text = newText;
371 if (oldText == q->text())
372 return;
373
374 q->buttonChange(QQuickAbstractButton::ButtonTextChange);
375}
376
377/*!
378 \internal
379
380 Whether the \l text supports \l {QShortcut#mnemonic}{mnemonics} keys. An
381 example of a mnemonic is "E&xit": a button with this text can be clicked
382 by the keyboard shortcut \c Alt+X, and the \c x will be underlined.
383
384 If \c true, the mnemonic indicator (\c &) is always removed from the
385 displayed text. Depending on the current platform's conventions, this may
386 also enable the corresponding keyboard shortcut and underline the mnemonic.
387
388 If \c false, the mnemonic indicator (\c &) will not be removed from
389 the text and the shortcut will be disabled. This allows \c & to
390 be used literally, as in \c {"Cats & Dogs"}.
391
392 This isn't exposed to QML: whether mnemonics are supported is determined
393 by the platform (QPlatformTheme::MnemonicsEnabled) by default, and forced
394 to \c false by certain derived types (such as \l ItemDelegate and
395 \l DelayButton) for which mnemonics don't make sense. It isn't something
396 app code should be able to toggle per-instance.
397
398 When Qt is \l {Qt Configure Options}{configured} with
399 \c -no-feature-shortcut, shortcuts are disabled, and this has no effect.
400*/
401void QQuickAbstractButtonPrivate::setMnemonicEnabled(bool enabled)
402{
403 if (mnemonicEnabled == enabled)
404 return;
405
406 mnemonicEnabled = enabled;
407#if QT_CONFIG(shortcut)
408 Q_Q(QQuickAbstractButton);
409 q->setShortcut(mnemonicEnabled ? QKeySequence::mnemonic(text) : QKeySequence());
410#else
411 qCDebug(lcButtonMnemonics) << "The mnemonicEnabled property has no effect when Qt is configured"
412 << "with -no-feature-shortcut";
413#endif
414}
415
416void QQuickAbstractButtonPrivate::updateEffectiveIcon()
417{
418 Q_Q(QQuickAbstractButton);
419 // We store effectiveIcon because we need to be able to tell if the icon has actually changed.
420 // If we only stored our icon and the action's icon, and resolved in the getter, we'd have
421 // no way of knowing what the old value was here. As an added benefit, we only resolve when
422 // something has changed, as opposed to doing it unconditionally in the icon() getter.
423 QQuickIcon newEffectiveIcon = action ? icon.resolve(action->icon()) : icon;
424
425 bool unchanged = newEffectiveIcon == effectiveIcon;
426 if (action) {
427 // We can't rely purely on QQuickIcon::operator== for our unchanged check, because it
428 // doesn't account for the color being resolved. QQuickIconLabelPrivate::syncImage and
429 // createImage rely on the color's resolve mask to determine if a color was set on it
430 // that should override the style default (see QQuickIconLabel::defaultIconColor for
431 // more info). If we didn't check the resolve mask
432 // and the user set the color to transparent (the default), the resolveMask of d->icon
433 // wouldn't indicate that the color was resolved and iconChanged wouldn't be emitted,
434 // leading to the user's request being ignored.
435 const bool actionIconColorResolved = QQuickIconPrivate::isResolved(action->icon(),
436 QQuickIconPrivate::ColorResolved);
437 const bool iconColorResolved = QQuickIconPrivate::isResolved(icon,
438 QQuickIconPrivate::ColorResolved);
439
440 unchanged = newEffectiveIcon == effectiveIcon;
441
442 // Only set it to false if there was a change in icon color that would otherwise
443 // be undetectable.
444 if (unchanged && !iconColorResolved && actionIconColorResolved)
445 unchanged = false;
446
447 // We need to mark the effective icon's color as resolved, too.
448 if (actionIconColorResolved)
449 newEffectiveIcon.resolveColor();
450 }
451
452 // Always update effectiveIcon because the color may have been resolved in icon,
453 // which isn't accounted for QQuickIcon::operator==.
454 effectiveIcon = newEffectiveIcon;
455
456 if (unchanged)
457 return;
458
459 if (action && !QQuickIconPrivate::isResolved(effectiveIcon, QQuickIconPrivate::ColorResolved)) {
460 // A color wasn't set on the button's icon (which should always win over an Action's).
461 if (QQuickIconPrivate::isResolved(action->icon(), QQuickIconPrivate::ColorResolved)) {
462 // A color was set on the action's icon; mark the effective icon's color as being
463 // explicitly set so that QQuickIconLabel can detect that it's set and respect it.
464 effectiveIcon.resolveColor();
465 }
466 }
467
468 emit q->iconChanged();
469}
470
471void QQuickAbstractButtonPrivate::click()
472{
473 Q_Q(QQuickAbstractButton);
474 // If our Action's trigger signal handler disables us (or the action, which causes us to be
475 // disabled), we still want clicked to be emitted so that e.g. menus close when a menu item is
476 // clicked. That's why we check wasEnabledBeforeTrigger here.
477 if (effectiveEnable || wasEnabledBeforeTrigger)
478 emit q->clicked();
479}
480
481void QQuickAbstractButtonPrivate::accessiblePressAction()
482{
483 Q_Q(QQuickAbstractButton);
484 q->click();
485}
486
487void QQuickAbstractButtonPrivate::accessibleToggleAction()
488{
489 accessiblePressAction();
490}
491
492void QQuickAbstractButtonPrivate::trigger(bool doubleClick)
493{
494 Q_Q(QQuickAbstractButton);
495 const QScopedValueRollback<bool> rollback(wasEnabledBeforeTrigger, effectiveEnable);
496
497 bool actionTriggered = false;
498 if (action && action->isEnabled())
499 actionTriggered = QQuickActionPrivate::get(action)->trigger(q, false);
500
501 // Don't emit the signals below if we were disabled or if our action already emitted its
502 // triggered signal (which we connect to click, which emits clicked, so would emit twice).
503 if (!wasEnabledBeforeTrigger || actionTriggered)
504 return;
505
506 if (!doubleClick)
507 emit q->clicked();
508 else
509 emit q->doubleClicked();
510}
511
512void QQuickAbstractButtonPrivate::toggle(bool value)
513{
514 Q_Q(QQuickAbstractButton);
515 const bool wasChecked = checked;
516 q->setChecked(value);
517 if (wasChecked != checked)
518 emit q->toggled();
519}
520
521void QQuickAbstractButtonPrivate::cancelIndicator()
522{
523 Q_Q(QQuickAbstractButton);
524 quickCancelDeferred(q, indicatorName());
525}
526
527void QQuickAbstractButtonPrivate::executeIndicator(bool complete)
528{
529 Q_Q(QQuickAbstractButton);
530 if (indicator.wasExecuted())
531 return;
532
533 if (!indicator || complete)
534 quickBeginDeferred(q, indicatorName(), indicator);
535 if (complete)
536 quickCompleteDeferred(q, indicatorName(), indicator);
537}
538
539void QQuickAbstractButtonPrivate::itemImplicitWidthChanged(QQuickItem *item)
540{
541 Q_Q(QQuickAbstractButton);
542 QQuickControlPrivate::itemImplicitWidthChanged(item);
543 if (item == indicator)
544 emit q->implicitIndicatorWidthChanged();
545}
546
547void QQuickAbstractButtonPrivate::itemImplicitHeightChanged(QQuickItem *item)
548{
549 Q_Q(QQuickAbstractButton);
550 QQuickControlPrivate::itemImplicitHeightChanged(item);
551 if (item == indicator)
552 emit q->implicitIndicatorHeightChanged();
553}
554
555void QQuickAbstractButtonPrivate::itemDestroyed(QQuickItem *item)
556{
557 Q_Q(QQuickAbstractButton);
558 QQuickControlPrivate::itemDestroyed(item);
559 if (item == indicator) {
560 indicator = nullptr;
561 emit q->implicitIndicatorWidthChanged();
562 emit q->implicitIndicatorHeightChanged();
563 }
564}
565
566QQuickAbstractButton *QQuickAbstractButtonPrivate::findCheckedButton() const
567{
568 Q_Q(const QQuickAbstractButton);
569 if (group)
570 return group->checkedButton();
571
572 const QList<QQuickAbstractButton *> buttons = findExclusiveButtons();
573 // TODO: A singular QRadioButton can be unchecked, which seems logical,
574 // because there's nothing to be exclusive with. However, a RadioButton
575 // from QtQuick.Controls 1.x can never be unchecked, which is the behavior
576 // that QQuickRadioButton adopted. Uncommenting the following count check
577 // gives the QRadioButton behavior. Notice that tst_radiobutton.qml needs
578 // to be updated.
579 if (!autoExclusive /*|| buttons.count() == 1*/)
580 return nullptr;
581
582 for (QQuickAbstractButton *button : buttons) {
583 if (button->isChecked() && button != q)
584 return button;
585 }
586 return checked ? const_cast<QQuickAbstractButton *>(q) : nullptr;
587}
588
589QList<QQuickAbstractButton *> QQuickAbstractButtonPrivate::findExclusiveButtons() const
590{
591 QList<QQuickAbstractButton *> buttons;
592 if (group) {
593 QQmlListProperty<QQuickAbstractButton> groupButtons = group->buttons();
594 int count = groupButtons.count(&groupButtons);
595 for (int i = 0; i < count; ++i) {
596 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(groupButtons.at(&groupButtons, i));
597 if (button)
598 buttons += button;
599 }
600 } else if (parentItem) {
601 const auto childItems = parentItem->childItems();
602 for (QQuickItem *child : childItems) {
603 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(child);
604 if (button && button->autoExclusive() && !QQuickAbstractButtonPrivate::get(button)->group)
605 buttons += button;
606 }
607 }
608 return buttons;
609}
610
611QQuickAbstractButton::QQuickAbstractButton(QQuickItem *parent)
612 : QQuickControl(*(new QQuickAbstractButtonPrivate), parent)
613{
614 Q_D(QQuickAbstractButton);
615 d->init();
616}
617
618QQuickAbstractButton::QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQuickItem *parent)
619 : QQuickControl(dd, parent)
620{
621 Q_D(QQuickAbstractButton);
622 d->init();
623}
624
625QQuickAbstractButton::~QQuickAbstractButton()
626{
627 Q_D(QQuickAbstractButton);
628 d->removeImplicitSizeListener(d->indicator);
629 if (d->group) {
630 auto *attached = qobject_cast<QQuickButtonGroupAttached *>(
631 qmlAttachedPropertiesObject<QQuickButtonGroup>(this, false));
632 if (attached)
633 attached->setGroup(nullptr);
634 else
635 d->group->removeButton(this);
636 }
637#if QT_CONFIG(shortcut)
638 d->ungrabShortcut();
639#endif
640}
641
642/*!
643 \qmlproperty string QtQuick.Controls::AbstractButton::text
644
645 This property holds a textual description of the button.
646
647 \note The text is used for accessibility purposes, so it makes sense to
648 set a textual description even if the content item is an image.
649
650 \sa icon, display, {Control::contentItem}{contentItem}
651*/
652QString QQuickAbstractButton::text() const
653{
654 Q_D(const QQuickAbstractButton);
655 return d->explicitText || !d->action ? d->text : d->action->text();
656}
657
658void QQuickAbstractButton::setText(const QString &text)
659{
660 Q_D(QQuickAbstractButton);
661 d->setText(text, QQml::PropertyUtils::State::ExplicitlySet);
662}
663
664void QQuickAbstractButton::resetText()
665{
666 Q_D(QQuickAbstractButton);
667 d->setText(QString(), QQml::PropertyUtils::State::ImplicitlySet);
668}
669
670/*!
671 \qmlproperty bool QtQuick.Controls::AbstractButton::down
672
673 This property holds whether the button is visually down.
674
675 Unless explicitly set, this property follows the value of \l pressed. To
676 return to the default value, set this property to \c undefined.
677
678 \sa pressed
679*/
680bool QQuickAbstractButton::isDown() const
681{
682 Q_D(const QQuickAbstractButton);
683 return d->down;
684}
685
686void QQuickAbstractButton::setDown(bool down)
687{
688 Q_D(QQuickAbstractButton);
689 d->explicitDown = true;
690
691 if (d->down == down)
692 return;
693
694 d->down = down;
695 emit downChanged();
696}
697
698void QQuickAbstractButton::resetDown()
699{
700 Q_D(QQuickAbstractButton);
701 if (!d->explicitDown)
702 return;
703
704 setDown(d->pressed);
705 d->explicitDown = false;
706}
707
708/*!
709 \qmlproperty bool QtQuick.Controls::AbstractButton::pressed
710 \readonly
711
712 This property holds whether the button is physically pressed. A button can
713 be pressed by either touch or key events.
714
715 \sa down
716*/
717bool QQuickAbstractButton::isPressed() const
718{
719 Q_D(const QQuickAbstractButton);
720 return d->pressed;
721}
722
723void QQuickAbstractButton::setPressed(bool isPressed)
724{
725 Q_D(QQuickAbstractButton);
726 if (d->pressed == isPressed)
727 return;
728
729 d->pressed = isPressed;
730 setAccessibleProperty("pressed", isPressed);
731 emit pressedChanged();
732 buttonChange(ButtonPressedChanged);
733
734 if (!d->explicitDown) {
735 setDown(d->pressed);
736 d->explicitDown = false;
737 }
738}
739
740/*!
741 \qmlproperty bool QtQuick.Controls::AbstractButton::checked
742
743 This property holds whether the button is checked.
744
745 Since Qt 6.2, setting this property no longer affects the
746 \l {AbstractButton::}{checkable} property. Explicitly set the
747 \c checkable property if needed.
748
749 \sa checkable
750*/
751bool QQuickAbstractButton::isChecked() const
752{
753 Q_D(const QQuickAbstractButton);
754 return d->checked;
755}
756
757void QQuickAbstractButton::setChecked(bool checked)
758{
759 Q_D(QQuickAbstractButton);
760 if (d->checked == checked)
761 return;
762
763 d->checked = checked;
764 if (d->action)
765 d->action->setChecked(checked);
766 setAccessibleProperty("checked", checked);
767 buttonChange(ButtonCheckedChange);
768 emit checkedChanged();
769}
770
771/*!
772 \qmlproperty bool QtQuick.Controls::AbstractButton::checkable
773
774 This property holds whether the button is checkable.
775
776 A checkable button toggles between checked (on) and unchecked (off) when
777 the user clicks on it or presses the space bar while the button has active
778 focus.
779
780 The default value is \c false.
781
782 \sa checked
783*/
784bool QQuickAbstractButton::isCheckable() const
785{
786 Q_D(const QQuickAbstractButton);
787 return d->checkable;
788}
789
790void QQuickAbstractButton::setCheckable(bool checkable)
791{
792 Q_D(QQuickAbstractButton);
793 if (d->checkable == checkable)
794 return;
795
796 d->checkable = checkable;
797 if (d->action)
798 d->action->setCheckable(checkable);
799 setAccessibleProperty("checkable", checkable);
800 buttonChange(ButtonCheckableChange);
801 emit checkableChanged();
802}
803
804/*!
805 \qmlproperty bool QtQuick.Controls::AbstractButton::autoExclusive
806
807 This property holds whether auto-exclusivity is enabled.
808
809 If auto-exclusivity is enabled, checkable buttons that belong to the same
810 parent item behave as if they were part of the same ButtonGroup. Only
811 one button can be checked at any time; checking another button automatically
812 unchecks the previously checked one.
813
814 \note The property has no effect on buttons that belong to a ButtonGroup.
815
816 RadioButton and TabButton are auto-exclusive by default.
817*/
818bool QQuickAbstractButton::autoExclusive() const
819{
820 Q_D(const QQuickAbstractButton);
821 return d->autoExclusive;
822}
823
824void QQuickAbstractButton::setAutoExclusive(bool exclusive)
825{
826 Q_D(QQuickAbstractButton);
827 if (d->autoExclusive == exclusive)
828 return;
829
830 d->autoExclusive = exclusive;
831 emit autoExclusiveChanged();
832}
833
834/*!
835 \qmlproperty bool QtQuick.Controls::AbstractButton::autoRepeat
836
837 This property holds whether the button repeats \l pressed(), \l released()
838 and \l clicked() signals while the button is pressed and held down.
839
840 If this property is set to \c true, the \l pressAndHold() signal will not
841 be emitted.
842
843 The default value is \c false.
844
845 The initial delay and the repetition interval are defined in milliseconds
846 by \l autoRepeatDelay and \l autoRepeatInterval.
847*/
848bool QQuickAbstractButton::autoRepeat() const
849{
850 Q_D(const QQuickAbstractButton);
851 return d->autoRepeat;
852}
853
854void QQuickAbstractButton::setAutoRepeat(bool repeat)
855{
856 Q_D(QQuickAbstractButton);
857 if (d->autoRepeat == repeat)
858 return;
859
860 d->stopPressRepeat();
861 d->autoRepeat = repeat;
862 emit autoRepeatChanged();
863}
864
865/*!
866 \qmlproperty Item QtQuick.Controls::AbstractButton::indicator
867
868 This property holds the indicator item.
869*/
870QQuickItem *QQuickAbstractButton::indicator() const
871{
872 QQuickAbstractButtonPrivate *d = const_cast<QQuickAbstractButtonPrivate *>(d_func());
873 if (!d->indicator)
874 d->executeIndicator();
875 return d->indicator;
876}
877
878void QQuickAbstractButton::setIndicator(QQuickItem *indicator)
879{
880 Q_D(QQuickAbstractButton);
881 if (d->indicator == indicator)
882 return;
883
884 QQuickControlPrivate::warnIfCustomizationNotSupported(this, indicator, QStringLiteral("indicator"));
885
886 if (!d->indicator.isExecuting())
887 d->cancelIndicator();
888
889 const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth();
890 const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight();
891
892 d->removeImplicitSizeListener(d->indicator);
893 QQuickControlPrivate::hideOldItem(d->indicator);
894 d->indicator = indicator;
895
896 if (indicator) {
897 if (!indicator->parentItem())
898 indicator->setParentItem(this);
899 indicator->setAcceptedMouseButtons(Qt::LeftButton);
900 d->addImplicitSizeListener(indicator);
901 }
902
903 if (!qFuzzyCompare(oldImplicitIndicatorWidth, implicitIndicatorWidth()))
904 emit implicitIndicatorWidthChanged();
905 if (!qFuzzyCompare(oldImplicitIndicatorHeight, implicitIndicatorHeight()))
906 emit implicitIndicatorHeightChanged();
907 if (!d->indicator.isExecuting())
908 emit indicatorChanged();
909}
910
911/*!
912 \qmlproperty string QtQuick.Controls::AbstractButton::icon.name
913 \qmlproperty url QtQuick.Controls::AbstractButton::icon.source
914 \qmlproperty int QtQuick.Controls::AbstractButton::icon.width
915 \qmlproperty int QtQuick.Controls::AbstractButton::icon.height
916 \qmlproperty color QtQuick.Controls::AbstractButton::icon.color
917 \qmlproperty bool QtQuick.Controls::AbstractButton::icon.cache
918
919 \since QtQuick.Controls 2.3
920
921 \include qquickicon.qdocinc grouped-properties
922
923 \sa text, display, {Icons in Qt Quick Controls}
924*/
925
926QQuickIcon QQuickAbstractButton::icon() const
927{
928 Q_D(const QQuickAbstractButton);
929 return d->effectiveIcon;
930}
931
932void QQuickAbstractButton::setIcon(const QQuickIcon &icon)
933{
934 Q_D(QQuickAbstractButton);
935 d->icon = icon;
936 d->icon.ensureRelativeSourceResolved(this);
937 d->updateEffectiveIcon();
938}
939
940/*!
941 \since QtQuick.Controls 2.3 (Qt 5.10)
942 \qmlproperty enumeration QtQuick.Controls::AbstractButton::display
943
944 This property determines how the \l icon and \l text are displayed within
945 the button.
946
947 \table
948 \header \li Display \li Result
949 \row \li \c AbstractButton.IconOnly
950 \li \image qtquickcontrols-button-icononly.png
951 {Button displaying only icon}
952 \row \li \c AbstractButton.TextOnly
953 \li \image qtquickcontrols-button-textonly.png
954 {Button displaying only text}
955 \row \li \c AbstractButton.TextBesideIcon (default)
956 \li \image qtquickcontrols-button-textbesideicon.png
957 {Button with text beside icon}
958 \row \li \c AbstractButton.TextUnderIcon
959 \li \image qtquickcontrols-button-textundericon.png
960 {Button with text under icon}
961 \endtable
962
963 \sa {Control::}{spacing}, {Control::}{padding}
964*/
965QQuickAbstractButton::Display QQuickAbstractButton::display() const
966{
967 Q_D(const QQuickAbstractButton);
968 return d->display;
969}
970
971void QQuickAbstractButton::setDisplay(Display display)
972{
973 Q_D(QQuickAbstractButton);
974 if (display == d->display)
975 return;
976
977 d->display = display;
978 emit displayChanged();
979}
980
981/*!
982 \since QtQuick.Controls 2.3 (Qt 5.10)
983 \qmlproperty Action QtQuick.Controls::AbstractButton::action
984
985 This property holds the button action.
986
987 \sa Action
988*/
989QQuickAction *QQuickAbstractButton::action() const
990{
991 Q_D(const QQuickAbstractButton);
992 return d->action;
993}
994
995void QQuickAbstractButton::setAction(QQuickAction *action)
996{
997 Q_D(QQuickAbstractButton);
998 qCDebug(lcButtonAction) << this << "setAction called with" << action;
999 if (d->action == action)
1000 return;
1001
1002 const QString oldText = text();
1003
1004 if (QQuickAction *oldAction = d->action.data()) {
1005 QQuickActionPrivate::get(oldAction)->unregisterItem(this);
1006 QObjectPrivate::disconnect(oldAction, &QQuickAction::triggered, d, &QQuickAbstractButtonPrivate::click);
1007 QObjectPrivate::disconnect(oldAction, &QQuickAction::textChanged, d, &QQuickAbstractButtonPrivate::actionTextChange);
1008
1009 QObjectPrivate::disconnect(oldAction, &QQuickAction::iconChanged, d, &QQuickAbstractButtonPrivate::updateEffectiveIcon);
1010 disconnect(oldAction, &QQuickAction::checkedChanged, this, &QQuickAbstractButton::setChecked);
1011 disconnect(oldAction, &QQuickAction::checkableChanged, this, &QQuickAbstractButton::setCheckable);
1012 disconnect(oldAction, &QQuickAction::enabledChanged, this, &QQuickItem::setEnabled);
1013 }
1014
1015 if (action) {
1016 QQuickActionPrivate::get(action)->registerItem(this);
1017 QObjectPrivate::connect(action, &QQuickAction::triggered, d, &QQuickAbstractButtonPrivate::click);
1018 QObjectPrivate::connect(action, &QQuickAction::textChanged, d, &QQuickAbstractButtonPrivate::actionTextChange);
1019
1020 QObjectPrivate::connect(action, &QQuickAction::iconChanged, d, &QQuickAbstractButtonPrivate::updateEffectiveIcon);
1021 connect(action, &QQuickAction::checkedChanged, this, &QQuickAbstractButton::setChecked);
1022 connect(action, &QQuickAction::checkableChanged, this, &QQuickAbstractButton::setCheckable);
1023 connect(action, &QQuickAction::enabledChanged, this, &QQuickItem::setEnabled);
1024
1025 setChecked(action->isChecked());
1026 setCheckable(action->isCheckable());
1027 setEnabled(action->isEnabled());
1028 }
1029
1030#if QT_CONFIG(accessibility)
1031 auto attached = qobject_cast<QQuickAccessibleAttached*>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, true));
1032 Q_ASSERT(attached);
1033 attached->setProxying(qobject_cast<QQuickAccessibleAttached*>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(action, true)));
1034#endif
1035
1036 d->action = action;
1037
1038 if (oldText != text())
1039 buttonChange(ButtonTextChange);
1040
1041 d->updateEffectiveIcon();
1042
1043 emit actionChanged();
1044}
1045
1046/*!
1047 \since QtQuick.Controls 2.4 (Qt 5.11)
1048 \qmlproperty int QtQuick.Controls::AbstractButton::autoRepeatDelay
1049
1050 This property holds the initial delay of auto-repetition in milliseconds.
1051 The default value is \c 300 ms.
1052
1053 \sa autoRepeat, autoRepeatInterval
1054*/
1055int QQuickAbstractButton::autoRepeatDelay() const
1056{
1057 Q_D(const QQuickAbstractButton);
1058 return d->repeatDelay;
1059}
1060
1061void QQuickAbstractButton::setAutoRepeatDelay(int delay)
1062{
1063 Q_D(QQuickAbstractButton);
1064 if (d->repeatDelay == delay)
1065 return;
1066
1067 d->repeatDelay = delay;
1068 emit autoRepeatDelayChanged();
1069}
1070
1071/*!
1072 \since QtQuick.Controls 2.4 (Qt 5.11)
1073 \qmlproperty int QtQuick.Controls::AbstractButton::autoRepeatInterval
1074
1075 This property holds the interval of auto-repetition in milliseconds.
1076 The default value is \c 100 ms.
1077
1078 \sa autoRepeat, autoRepeatDelay
1079*/
1080int QQuickAbstractButton::autoRepeatInterval() const
1081{
1082 Q_D(const QQuickAbstractButton);
1083 return d->repeatInterval;
1084}
1085
1086void QQuickAbstractButton::setAutoRepeatInterval(int interval)
1087{
1088 Q_D(QQuickAbstractButton);
1089 if (d->repeatInterval == interval)
1090 return;
1091
1092 d->repeatInterval = interval;
1093 emit autoRepeatIntervalChanged();
1094}
1095
1096#if QT_CONFIG(shortcut)
1097/*!
1098 \internal
1099
1100 This is the mnemonic shortcut that is derived from the text;
1101 see \c QQuickAbstractButton::buttonChange().
1102*/
1103QKeySequence QQuickAbstractButton::shortcut() const
1104{
1105 Q_D(const QQuickAbstractButton);
1106 return d->shortcut;
1107}
1108
1109void QQuickAbstractButton::setShortcut(const QKeySequence &shortcut)
1110{
1111 Q_D(QQuickAbstractButton);
1112 if (d->shortcut == shortcut)
1113 return;
1114
1115 d->ungrabShortcut();
1116 d->shortcut = shortcut;
1117 if (isVisible() && d->mnemonicEnabled)
1118 d->grabShortcut();
1119}
1120#endif
1121
1122/*!
1123 \readonly
1124 \since QtQuick.Controls 2.4 (Qt 5.11)
1125 \qmlproperty real QtQuick.Controls::AbstractButton::pressX
1126
1127 This property holds the x-coordinate of the last press.
1128
1129 \note The value is updated on touch moves, but left intact after touch release.
1130
1131 \sa pressY
1132*/
1133qreal QQuickAbstractButton::pressX() const
1134{
1135 Q_D(const QQuickAbstractButton);
1136 return d->movePoint.x();
1137}
1138
1139/*!
1140 \readonly
1141 \since QtQuick.Controls 2.4 (Qt 5.11)
1142 \qmlproperty real QtQuick.Controls::AbstractButton::pressY
1143
1144 This property holds the y-coordinate of the last press.
1145
1146 \note The value is updated on touch moves, but left intact after touch release.
1147
1148 \sa pressX
1149*/
1150qreal QQuickAbstractButton::pressY() const
1151{
1152 Q_D(const QQuickAbstractButton);
1153 return d->movePoint.y();
1154}
1155
1156/*!
1157 \since QtQuick.Controls 2.5 (Qt 5.12)
1158 \qmlproperty real QtQuick.Controls::AbstractButton::implicitIndicatorWidth
1159 \readonly
1160
1161 This property holds the implicit indicator width.
1162
1163 The value is equal to \c {indicator ? indicator.implicitWidth : 0}.
1164
1165 This is typically used, together with \l {Control::}{implicitContentWidth} and
1166 \l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}.
1167
1168 \sa implicitIndicatorHeight
1169*/
1170qreal QQuickAbstractButton::implicitIndicatorWidth() const
1171{
1172 Q_D(const QQuickAbstractButton);
1173 if (!d->indicator)
1174 return 0;
1175 return d->indicator->implicitWidth();
1176}
1177
1178/*!
1179 \since QtQuick.Controls 2.5 (Qt 5.12)
1180 \qmlproperty real QtQuick.Controls::AbstractButton::implicitIndicatorHeight
1181 \readonly
1182
1183 This property holds the implicit indicator height.
1184
1185 The value is equal to \c {indicator ? indicator.implicitHeight : 0}.
1186
1187 This is typically used, together with \l {Control::}{implicitContentHeight} and
1188 \l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}.
1189
1190 \sa implicitIndicatorWidth
1191*/
1192qreal QQuickAbstractButton::implicitIndicatorHeight() const
1193{
1194 Q_D(const QQuickAbstractButton);
1195 if (!d->indicator)
1196 return 0;
1197 return d->indicator->implicitHeight();
1198}
1199
1200/*!
1201 \qmlmethod void QtQuick.Controls::AbstractButton::toggle()
1202
1203 Toggles the checked state of the button.
1204
1205 \sa click(), animateClick()
1206*/
1207void QQuickAbstractButton::toggle()
1208{
1209 Q_D(QQuickAbstractButton);
1210 setChecked(!d->checked);
1211}
1212
1213/*!
1214 \since Qt 6.8
1215 \qmlmethod void QtQuick.Controls::AbstractButton::click()
1216
1217 Simulates the button being clicked with no delay between press and release.
1218
1219 All signals associated with a click are emitted as appropriate.
1220
1221 If the \l [QML] {Item::} {focusPolicy} includes \c Qt.ClickFocus,
1222 \l [QML] {Item::} {activeFocus} will become \c true.
1223
1224 This function does nothing if the button is
1225 \l [QML] {Item::enabled} {disabled}.
1226
1227 Calling this function again before the button is released resets
1228 the release timer.
1229
1230 \sa animateClick(), pressed(), released(), clicked()
1231*/
1232void QQuickAbstractButton::click()
1233{
1234 Q_D(QQuickAbstractButton);
1235 if (!isEnabled())
1236 return;
1237
1238 // QQuickItemPrivate::deliverPointerEvent calls setFocusIfNeeded on real clicks,
1239 // so we need to do it ourselves.
1240 const bool setFocusOnPress = !QGuiApplication::styleHints()->setFocusOnTouchRelease();
1241 if (setFocusOnPress && focusPolicy() & Qt::ClickFocus)
1242 forceActiveFocus(Qt::MouseFocusReason);
1243
1244 const QPointF eventPos(d->width / 2, d->height / 2);
1245 d->handlePress(eventPos, 0);
1246 d->handleRelease(eventPos, 0);
1247}
1248
1249/*!
1250 \since Qt 6.8
1251 \qmlmethod void QtQuick.Controls::AbstractButton::animateClick()
1252
1253 Simulates the button being clicked, with a 100 millisecond delay
1254 between press and release, animating its visual state in the
1255 process.
1256
1257 All signals associated with a click are emitted as appropriate.
1258
1259 If the \l [QML] {Item::} {focusPolicy} includes \c Qt.ClickFocus,
1260 \l [QML] {Item::}{activeFocus} will become \c true.
1261
1262 This function does nothing if the button is
1263 \l [QML] {Item::enabled} {disabled}.
1264
1265 Calling this function again before the button is released resets
1266 the release timer.
1267
1268 \sa click(), pressed(), released(), clicked()
1269*/
1270void QQuickAbstractButton::animateClick()
1271{
1272 Q_D(QQuickAbstractButton);
1273 if (!isEnabled())
1274 return;
1275
1276 // See comment in click() for why we do this.
1277 const bool setFocusOnPress = !QGuiApplication::styleHints()->setFocusOnTouchRelease();
1278 if (setFocusOnPress && focusPolicy() & Qt::ClickFocus)
1279 forceActiveFocus(Qt::MouseFocusReason);
1280
1281 // If the timer was already running, kill it so we can restart it.
1282 if (d->animateTimer != 0) {
1283 killTimer(d->animateTimer);
1284 d->animateTimer = 0;
1285 } else {
1286 d->handlePress(QPointF(d->width / 2, d->height / 2), 0);
1287 }
1288
1289 d->animateTimer = startTimer(100);
1290}
1291
1292void QQuickAbstractButton::componentComplete()
1293{
1294 Q_D(QQuickAbstractButton);
1295 d->executeIndicator(true);
1296 QQuickControl::componentComplete();
1297}
1298
1299bool QQuickAbstractButton::event(QEvent *event)
1300{
1301#if QT_CONFIG(shortcut)
1302 Q_D(QQuickAbstractButton);
1303 if (event->type() == QEvent::Shortcut) {
1304 QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
1305 if (se->shortcutId() == d->shortcutId) {
1306 d->trigger();
1307 return true;
1308 }
1309 }
1310#endif
1311 return QQuickControl::event(event);
1312}
1313
1314void QQuickAbstractButton::focusOutEvent(QFocusEvent *event)
1315{
1316 Q_D(QQuickAbstractButton);
1317 QQuickControl::focusOutEvent(event);
1318 if (d->touchId == -1) // don't ungrab on multi-touch if another control gets focused
1319 d->handleUngrab();
1320}
1321
1322void QQuickAbstractButton::keyPressEvent(QKeyEvent *event)
1323{
1324 Q_D(QQuickAbstractButton);
1325 QQuickControl::keyPressEvent(event);
1326 if (d->acceptKeyClick(static_cast<Qt::Key>(event->key()))) {
1327 d->setPressPoint(d->centerPressPoint());
1328 setPressed(true);
1329
1330 if (d->autoRepeat)
1331 d->startRepeatDelay();
1332
1333 emit pressed();
1334 event->accept();
1335 }
1336}
1337
1338void QQuickAbstractButton::keyReleaseEvent(QKeyEvent *event)
1339{
1340 Q_D(QQuickAbstractButton);
1341 QQuickControl::keyReleaseEvent(event);
1342 if (d->pressed && d->acceptKeyClick(static_cast<Qt::Key>(event->key()))) {
1343 setPressed(false);
1344
1345 nextCheckState();
1346 emit released();
1347 d->trigger();
1348
1349 if (d->autoRepeat)
1350 d->stopPressRepeat();
1351 event->accept();
1352 }
1353}
1354
1355void QQuickAbstractButton::mousePressEvent(QMouseEvent *event)
1356{
1357 if (!(event->buttons() & Qt::LeftButton)) {
1358 event->ignore();
1359 return;
1360 }
1361
1362 Q_D(QQuickAbstractButton);
1363 d->pressButtons = event->buttons();
1364 QQuickControl::mousePressEvent(event);
1365}
1366
1367void QQuickAbstractButton::mouseDoubleClickEvent(QMouseEvent *event)
1368{
1369 Q_UNUSED(event);
1370 Q_D(QQuickAbstractButton);
1371 if (d->isDoubleClickConnected()) {
1372 // don't call QQuickItem::mouseDoubleClickEvent(): it would ignore()
1373 emit doubleClicked();
1374 d->wasDoubleClick = true;
1375 }
1376}
1377
1378void QQuickAbstractButton::timerEvent(QTimerEvent *event)
1379{
1380 Q_D(QQuickAbstractButton);
1381 QQuickControl::timerEvent(event);
1382 if (event->timerId() == d->holdTimer) {
1383 d->stopPressAndHold();
1384 d->wasHeld = true;
1385 emit pressAndHold();
1386 QQuickToolTipAttachedPrivate::maybeSetVisibleImplicitly(this, true);
1387 } else if (event->timerId() == d->delayTimer) {
1388 d->startPressRepeat();
1389 } else if (event->timerId() == d->repeatTimer) {
1390 emit released();
1391 d->trigger();
1392 emit pressed();
1393 } else if (event->timerId() == d->animateTimer) {
1394 const bool setFocusOnRelease = QGuiApplication::styleHints()->setFocusOnTouchRelease();
1395 if (setFocusOnRelease && focusPolicy() & Qt::ClickFocus)
1396 forceActiveFocus(Qt::MouseFocusReason);
1397 d->handleRelease(QPointF(d->width / 2, d->height / 2), 0);
1398 killTimer(d->animateTimer);
1399 d->animateTimer = 0;
1400 }
1401}
1402
1403void QQuickAbstractButton::itemChange(ItemChange change, const ItemChangeData &value)
1404{
1405 QQuickControl::itemChange(change, value);
1406#if QT_CONFIG(shortcut)
1407 Q_D(QQuickAbstractButton);
1408 if (change == ItemVisibleHasChanged && d->mnemonicEnabled) {
1409 if (value.boolValue)
1410 d->grabShortcut();
1411 else
1412 d->ungrabShortcut();
1413 }
1414#endif
1415}
1416
1417void QQuickAbstractButton::buttonChange(ButtonChange change)
1418{
1419 Q_D(QQuickAbstractButton);
1420 switch (change) {
1421 case ButtonCheckedChange:
1422 if (d->checked) {
1423 QQuickAbstractButton *button = d->findCheckedButton();
1424 if (button && button != this)
1425 button->setChecked(false);
1426 }
1427 break;
1428 case ButtonTextChange: {
1429 const QString txt = text();
1430#if QT_CONFIG(accessibility)
1431 maybeSetAccessibleName(qt_accStripAmp(txt));
1432#endif
1433#if QT_CONFIG(shortcut)
1434 if (d->mnemonicEnabled)
1435 setShortcut(QKeySequence::mnemonic(txt));
1436#endif
1437 emit textChanged();
1438 break;
1439 }
1440 default:
1441 break;
1442 }
1443}
1444
1445void QQuickAbstractButton::nextCheckState()
1446{
1447 Q_D(QQuickAbstractButton);
1448 if (!d->checkable)
1449 return;
1450
1451 if (d->checked) {
1452 if (d->findCheckedButton() == this)
1453 return;
1454 if (d->action) {
1455 // For non-exclusive groups checkedAction is null
1456 if (const auto group = QQuickActionPrivate::get(d->action)->group)
1457 if (group->checkedAction() == d->action)
1458 return;
1459 }
1460 }
1461
1462 d->toggle(!d->checked);
1463}
1464
1465#if QT_CONFIG(accessibility)
1466void QQuickAbstractButton::accessibilityActiveChanged(bool active)
1467{
1468 QQuickControl::accessibilityActiveChanged(active);
1469
1470 Q_D(QQuickAbstractButton);
1471 if (active) {
1472 maybeSetAccessibleName(qt_accStripAmp(text()));
1473 setAccessibleProperty("pressed", d->pressed);
1474 setAccessibleProperty("checked", d->checked);
1475 setAccessibleProperty("checkable", d->checkable);
1476 }
1477}
1478
1479QAccessible::Role QQuickAbstractButton::accessibleRole() const
1480{
1481 Q_D(const QQuickAbstractButton);
1482 if (d->checkable) {
1483 return QAccessible::CheckBox;
1484 }
1485 return QAccessible::Button;
1486}
1487
1488void QQuickAbstractButton::accessiblePressAction()
1489{
1490 Q_D(QQuickAbstractButton);
1491 d->accessiblePressAction();
1492}
1493
1494void QQuickAbstractButton::accessibleToggleAction()
1495{
1496 Q_D(QQuickAbstractButton);
1497 d->accessibleToggleAction();
1498}
1499#endif
1500
1501QT_END_NAMESPACE
1502
1503#include "moc_qquickabstractbutton_p.cpp"
Combined button and popup list for selecting options.