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 "qquickabstractbutton_p.h" |
5 | #include "qquickabstractbutton_p_p.h" |
6 | #include "qquickactiongroup_p.h" |
7 | #include "qquickbuttongroup_p.h" |
8 | #include "qquickaction_p.h" |
9 | #include "qquickaction_p_p.h" |
10 | #include "qquickshortcutcontext_p_p.h" |
11 | #include "qquickdeferredexecute_p_p.h" |
12 | |
13 | #include <QtGui/qstylehints.h> |
14 | #include <QtGui/qguiapplication.h> |
15 | #if QT_CONFIG(shortcut) |
16 | # include <QtGui/private/qshortcutmap_p.h> |
17 | #endif |
18 | #include <QtGui/private/qguiapplication_p.h> |
19 | #include <QtGui/qpa/qplatformtheme.h> |
20 | #include <QtQuick/private/qquickevents_p_p.h> |
21 | #include <QtQml/qqmllist.h> |
22 | |
23 | QT_BEGIN_NAMESPACE |
24 | |
25 | /*! |
26 | \qmltype AbstractButton |
27 | \inherits Control |
28 | //! \instantiates QQuickAbstractButton |
29 | \inqmlmodule QtQuick.Controls |
30 | \since 5.7 |
31 | \ingroup qtquickcontrols-buttons |
32 | \brief Abstract base type providing functionality common to buttons. |
33 | |
34 | AbstractButton provides the interface for controls with button-like |
35 | behavior; for example, push buttons and checkable controls like |
36 | radio buttons and check boxes. As an abstract control, it has no delegate |
37 | implementations, leaving them to the types that derive from it. |
38 | |
39 | \sa ButtonGroup, {Button Controls} |
40 | */ |
41 | |
42 | /*! |
43 | \qmlsignal QtQuick.Controls::AbstractButton::pressed() |
44 | |
45 | This signal is emitted when the button is interactively pressed by the user via touch, mouse, or keyboard. |
46 | */ |
47 | |
48 | /*! |
49 | \qmlsignal QtQuick.Controls::AbstractButton::released() |
50 | |
51 | This signal is emitted when the button is interactively released by the user via touch, mouse, or keyboard. |
52 | */ |
53 | |
54 | /*! |
55 | \qmlsignal QtQuick.Controls::AbstractButton::canceled() |
56 | |
57 | This signal is emitted when the button loses mouse grab |
58 | while being pressed, or when it would emit the \l released |
59 | signal but the mouse cursor is not inside the button. |
60 | */ |
61 | |
62 | /*! |
63 | \qmlsignal QtQuick.Controls::AbstractButton::clicked() |
64 | |
65 | This signal is emitted when the button is interactively clicked by the user via touch, mouse, or keyboard. |
66 | |
67 | \sa {Call a C++ function from QML when a Button is clicked} |
68 | */ |
69 | |
70 | /*! |
71 | \since QtQuick.Controls 2.2 (Qt 5.9) |
72 | \qmlsignal QtQuick.Controls::AbstractButton::toggled() |
73 | |
74 | This signal is emitted when a checkable button is interactively toggled by the user via touch, mouse, or keyboard. |
75 | */ |
76 | |
77 | /*! |
78 | \qmlsignal QtQuick.Controls::AbstractButton::pressAndHold() |
79 | |
80 | This signal is emitted when the button is interactively pressed and held down by the user via touch or mouse. |
81 | It is not emitted when \l autoRepeat is enabled. |
82 | */ |
83 | |
84 | /*! |
85 | \qmlsignal QtQuick.Controls::AbstractButton::doubleClicked() |
86 | |
87 | This signal is emitted when the button is interactively double clicked by the user via touch or mouse. |
88 | */ |
89 | |
90 | QPointF QQuickAbstractButtonPrivate::centerPressPoint() const |
91 | { |
92 | return QPointF(qRound(d: width / 2), qRound(d: height / 2)); |
93 | } |
94 | |
95 | void QQuickAbstractButtonPrivate::setPressPoint(const QPointF &point) |
96 | { |
97 | pressPoint = point; |
98 | setMovePoint(point); |
99 | } |
100 | |
101 | void QQuickAbstractButtonPrivate::setMovePoint(const QPointF &point) |
102 | { |
103 | Q_Q(QQuickAbstractButton); |
104 | bool xChange = !qFuzzyCompare(p1: point.x(), p2: movePoint.x()); |
105 | bool yChange = !qFuzzyCompare(p1: point.y(), p2: movePoint.y()); |
106 | movePoint = point; |
107 | if (xChange) |
108 | emit q->pressXChanged(); |
109 | if (yChange) |
110 | emit q->pressYChanged(); |
111 | } |
112 | |
113 | bool QQuickAbstractButtonPrivate::handlePress(const QPointF &point, ulong timestamp) |
114 | { |
115 | Q_Q(QQuickAbstractButton); |
116 | QQuickControlPrivate::handlePress(point, timestamp); |
117 | setPressPoint(point); |
118 | q->setPressed(true); |
119 | |
120 | emit q->pressed(); |
121 | |
122 | if (autoRepeat) |
123 | startRepeatDelay(); |
124 | else if (touchId != -1 || Qt::LeftButton == (pressButtons & Qt::LeftButton)) |
125 | startPressAndHold(); |
126 | else |
127 | stopPressAndHold(); |
128 | return true; |
129 | } |
130 | |
131 | bool QQuickAbstractButtonPrivate::handleMove(const QPointF &point, ulong timestamp) |
132 | { |
133 | Q_Q(QQuickAbstractButton); |
134 | QQuickControlPrivate::handleMove(point, timestamp); |
135 | setMovePoint(point); |
136 | q->setPressed(keepPressed || q->contains(point)); |
137 | |
138 | if (!pressed && autoRepeat) |
139 | stopPressRepeat(); |
140 | else if (holdTimer > 0 && (!pressed || QLineF(pressPoint, point).length() > QGuiApplication::styleHints()->startDragDistance())) |
141 | stopPressAndHold(); |
142 | return true; |
143 | } |
144 | |
145 | bool QQuickAbstractButtonPrivate::handleRelease(const QPointF &point, ulong timestamp) |
146 | { |
147 | Q_Q(QQuickAbstractButton); |
148 | // Store this here since the base class' handleRelease clears it. |
149 | const int pressTouchId = touchId; |
150 | |
151 | QQuickControlPrivate::handleRelease(point, timestamp); |
152 | bool wasPressed = pressed; |
153 | setPressPoint(point); |
154 | q->setPressed(false); |
155 | pressButtons = Qt::NoButton; |
156 | |
157 | const bool touchDoubleClick = pressTouchId != -1 && lastTouchReleaseTimestamp != 0 |
158 | && timestamp - lastTouchReleaseTimestamp < qApp->styleHints()->mouseDoubleClickInterval() |
159 | && isDoubleClickConnected(); |
160 | |
161 | if (!wasHeld && (keepPressed || q->contains(point))) |
162 | q->nextCheckState(); |
163 | |
164 | if (wasPressed) { |
165 | emit q->released(); |
166 | if (!wasHeld && !wasDoubleClick) |
167 | trigger(doubleClick: touchDoubleClick); |
168 | } else { |
169 | emit q->canceled(); |
170 | } |
171 | |
172 | if (autoRepeat) |
173 | stopPressRepeat(); |
174 | else |
175 | stopPressAndHold(); |
176 | |
177 | if (!touchDoubleClick) { |
178 | // This is not a double click yet, but it is potentially the |
179 | // first release before a double click. |
180 | if (pressTouchId != -1) { |
181 | // The corresponding press for this release was a touch press. |
182 | // Keep track of the timestamp of the release so that we can |
183 | // emit doubleClicked() if another one comes afterwards. |
184 | lastTouchReleaseTimestamp = timestamp; |
185 | } |
186 | } else { |
187 | // We just did a double click, so clear the release timestamp |
188 | // to prepare for any possible future double clicks. |
189 | lastTouchReleaseTimestamp = 0; |
190 | } |
191 | |
192 | wasDoubleClick = false; |
193 | return true; |
194 | } |
195 | |
196 | void QQuickAbstractButtonPrivate::handleUngrab() |
197 | { |
198 | Q_Q(QQuickAbstractButton); |
199 | QQuickControlPrivate::handleUngrab(); |
200 | pressButtons = Qt::NoButton; |
201 | if (!pressed) |
202 | return; |
203 | |
204 | q->setPressed(false); |
205 | stopPressRepeat(); |
206 | stopPressAndHold(); |
207 | wasDoubleClick = false; |
208 | lastTouchReleaseTimestamp = 0; |
209 | emit q->canceled(); |
210 | } |
211 | |
212 | bool QQuickAbstractButtonPrivate::acceptKeyClick(Qt::Key key) const |
213 | { |
214 | const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()->themeHint(hint: QPlatformTheme::ButtonPressKeys).value<QList<Qt::Key>>(); |
215 | return buttonPressKeys.contains(t: key); |
216 | } |
217 | |
218 | bool QQuickAbstractButtonPrivate::isPressAndHoldConnected() |
219 | { |
220 | Q_Q(QQuickAbstractButton); |
221 | static const QMetaMethod method = [&]() { |
222 | const auto signal = &QQuickAbstractButton::pressAndHold; |
223 | return QMetaMethod::fromSignal(signal); |
224 | }(); |
225 | return q->isSignalConnected(signal: method); |
226 | } |
227 | |
228 | bool QQuickAbstractButtonPrivate::isDoubleClickConnected() |
229 | { |
230 | Q_Q(QQuickAbstractButton); |
231 | static const QMetaMethod method = [&]() { |
232 | const auto signal = &QQuickAbstractButton::doubleClicked; |
233 | return QMetaMethod::fromSignal(signal); |
234 | }(); |
235 | return q->isSignalConnected(signal: method); |
236 | } |
237 | |
238 | void QQuickAbstractButtonPrivate::startPressAndHold() |
239 | { |
240 | Q_Q(QQuickAbstractButton); |
241 | wasHeld = false; |
242 | stopPressAndHold(); |
243 | if (isPressAndHoldConnected()) |
244 | holdTimer = q->startTimer(interval: QGuiApplication::styleHints()->mousePressAndHoldInterval()); |
245 | } |
246 | |
247 | void QQuickAbstractButtonPrivate::stopPressAndHold() |
248 | { |
249 | Q_Q(QQuickAbstractButton); |
250 | if (holdTimer > 0) { |
251 | q->killTimer(id: holdTimer); |
252 | holdTimer = 0; |
253 | } |
254 | } |
255 | |
256 | void QQuickAbstractButtonPrivate::startRepeatDelay() |
257 | { |
258 | Q_Q(QQuickAbstractButton); |
259 | stopPressRepeat(); |
260 | delayTimer = q->startTimer(interval: repeatDelay); |
261 | } |
262 | |
263 | void QQuickAbstractButtonPrivate::startPressRepeat() |
264 | { |
265 | Q_Q(QQuickAbstractButton); |
266 | stopPressRepeat(); |
267 | repeatTimer = q->startTimer(interval: repeatInterval); |
268 | } |
269 | |
270 | void QQuickAbstractButtonPrivate::stopPressRepeat() |
271 | { |
272 | Q_Q(QQuickAbstractButton); |
273 | if (delayTimer > 0) { |
274 | q->killTimer(id: delayTimer); |
275 | delayTimer = 0; |
276 | } |
277 | if (repeatTimer > 0) { |
278 | q->killTimer(id: repeatTimer); |
279 | repeatTimer = 0; |
280 | } |
281 | } |
282 | |
283 | #if QT_CONFIG(shortcut) |
284 | void QQuickAbstractButtonPrivate::grabShortcut() |
285 | { |
286 | Q_Q(QQuickAbstractButton); |
287 | if (shortcut.isEmpty()) |
288 | return; |
289 | |
290 | shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(owner: q, key: shortcut, context: Qt::WindowShortcut, matcher: QQuickShortcutContext::matcher); |
291 | |
292 | if (!q->isEnabled()) |
293 | QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable: false, id: shortcutId, owner: q); |
294 | } |
295 | |
296 | void QQuickAbstractButtonPrivate::ungrabShortcut() |
297 | { |
298 | Q_Q(QQuickAbstractButton); |
299 | if (!shortcutId) |
300 | return; |
301 | |
302 | QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(id: shortcutId, owner: q); |
303 | shortcutId = 0; |
304 | } |
305 | #endif |
306 | |
307 | void QQuickAbstractButtonPrivate::actionTextChange() |
308 | { |
309 | Q_Q(QQuickAbstractButton); |
310 | if (explicitText) |
311 | return; |
312 | |
313 | q->buttonChange(change: QQuickAbstractButton::ButtonTextChange); |
314 | } |
315 | |
316 | void QQuickAbstractButtonPrivate::setText(const QString &newText, bool isExplicit) |
317 | { |
318 | Q_Q(QQuickAbstractButton); |
319 | const QString oldText = q->text(); |
320 | explicitText = isExplicit; |
321 | text = newText; |
322 | if (oldText == q->text()) |
323 | return; |
324 | |
325 | q->buttonChange(change: QQuickAbstractButton::ButtonTextChange); |
326 | } |
327 | |
328 | void QQuickAbstractButtonPrivate::updateEffectiveIcon() |
329 | { |
330 | Q_Q(QQuickAbstractButton); |
331 | // We store effectiveIcon because we need to be able to tell if the icon has actually changed. |
332 | // If we only stored our icon and the action's icon, and resolved in the getter, we'd have |
333 | // no way of knowing what the old value was here. As an added benefit, we only resolve when |
334 | // something has changed, as opposed to doing it unconditionally in the icon() getter. |
335 | const QQuickIcon newEffectiveIcon = action ? icon.resolve(other: action->icon()) : icon; |
336 | if (newEffectiveIcon == effectiveIcon) |
337 | return; |
338 | |
339 | effectiveIcon = newEffectiveIcon; |
340 | emit q->iconChanged(); |
341 | } |
342 | |
343 | void QQuickAbstractButtonPrivate::click() |
344 | { |
345 | Q_Q(QQuickAbstractButton); |
346 | if (effectiveEnable) |
347 | emit q->clicked(); |
348 | } |
349 | |
350 | void QQuickAbstractButtonPrivate::trigger(bool doubleClick) |
351 | { |
352 | Q_Q(QQuickAbstractButton); |
353 | const bool wasEnabled = effectiveEnable; |
354 | if (action && action->isEnabled()) |
355 | QQuickActionPrivate::get(action)->trigger(q, doToggle: false); |
356 | if (wasEnabled && (!action || !action->isEnabled())) { |
357 | if (!doubleClick) |
358 | emit q->clicked(); |
359 | else |
360 | emit q->doubleClicked(); |
361 | } |
362 | } |
363 | |
364 | void QQuickAbstractButtonPrivate::toggle(bool value) |
365 | { |
366 | Q_Q(QQuickAbstractButton); |
367 | const bool wasChecked = checked; |
368 | q->setChecked(value); |
369 | if (wasChecked != checked) |
370 | emit q->toggled(); |
371 | } |
372 | |
373 | void QQuickAbstractButtonPrivate::cancelIndicator() |
374 | { |
375 | Q_Q(QQuickAbstractButton); |
376 | quickCancelDeferred(object: q, property: indicatorName()); |
377 | } |
378 | |
379 | void QQuickAbstractButtonPrivate::executeIndicator(bool complete) |
380 | { |
381 | Q_Q(QQuickAbstractButton); |
382 | if (indicator.wasExecuted()) |
383 | return; |
384 | |
385 | if (!indicator || complete) |
386 | quickBeginDeferred(object: q, property: indicatorName(), delegate&: indicator); |
387 | if (complete) |
388 | quickCompleteDeferred(object: q, property: indicatorName(), delegate&: indicator); |
389 | } |
390 | |
391 | void QQuickAbstractButtonPrivate::itemImplicitWidthChanged(QQuickItem *item) |
392 | { |
393 | Q_Q(QQuickAbstractButton); |
394 | QQuickControlPrivate::itemImplicitWidthChanged(item); |
395 | if (item == indicator) |
396 | emit q->implicitIndicatorWidthChanged(); |
397 | } |
398 | |
399 | void QQuickAbstractButtonPrivate::itemImplicitHeightChanged(QQuickItem *item) |
400 | { |
401 | Q_Q(QQuickAbstractButton); |
402 | QQuickControlPrivate::itemImplicitHeightChanged(item); |
403 | if (item == indicator) |
404 | emit q->implicitIndicatorHeightChanged(); |
405 | } |
406 | |
407 | void QQuickAbstractButtonPrivate::itemDestroyed(QQuickItem *item) |
408 | { |
409 | Q_Q(QQuickAbstractButton); |
410 | QQuickControlPrivate::itemDestroyed(item); |
411 | if (item == indicator) { |
412 | indicator = nullptr; |
413 | emit q->implicitIndicatorWidthChanged(); |
414 | emit q->implicitIndicatorHeightChanged(); |
415 | } |
416 | } |
417 | |
418 | QQuickAbstractButton *QQuickAbstractButtonPrivate::findCheckedButton() const |
419 | { |
420 | Q_Q(const QQuickAbstractButton); |
421 | if (group) |
422 | return qobject_cast<QQuickAbstractButton *>(object: group->checkedButton()); |
423 | |
424 | const QList<QQuickAbstractButton *> buttons = findExclusiveButtons(); |
425 | // TODO: A singular QRadioButton can be unchecked, which seems logical, |
426 | // because there's nothing to be exclusive with. However, a RadioButton |
427 | // from QtQuick.Controls 1.x can never be unchecked, which is the behavior |
428 | // that QQuickRadioButton adopted. Uncommenting the following count check |
429 | // gives the QRadioButton behavior. Notice that tst_radiobutton.qml needs |
430 | // to be updated. |
431 | if (!autoExclusive /*|| buttons.count() == 1*/) |
432 | return nullptr; |
433 | |
434 | for (QQuickAbstractButton *button : buttons) { |
435 | if (button->isChecked() && button != q) |
436 | return button; |
437 | } |
438 | return checked ? const_cast<QQuickAbstractButton *>(q) : nullptr; |
439 | } |
440 | |
441 | QList<QQuickAbstractButton *> QQuickAbstractButtonPrivate::findExclusiveButtons() const |
442 | { |
443 | QList<QQuickAbstractButton *> buttons; |
444 | if (group) { |
445 | QQmlListProperty<QQuickAbstractButton> groupButtons = group->buttons(); |
446 | int count = groupButtons.count(&groupButtons); |
447 | for (int i = 0; i < count; ++i) { |
448 | QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(object: groupButtons.at(&groupButtons, i)); |
449 | if (button) |
450 | buttons += button; |
451 | } |
452 | } else if (parentItem) { |
453 | const auto childItems = parentItem->childItems(); |
454 | for (QQuickItem *child : childItems) { |
455 | QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(object: child); |
456 | if (button && button->autoExclusive() && !QQuickAbstractButtonPrivate::get(button)->group) |
457 | buttons += button; |
458 | } |
459 | } |
460 | return buttons; |
461 | } |
462 | |
463 | QQuickAbstractButton::QQuickAbstractButton(QQuickItem *parent) |
464 | : QQuickControl(*(new QQuickAbstractButtonPrivate), parent) |
465 | { |
466 | setActiveFocusOnTab(true); |
467 | #ifdef Q_OS_MACOS |
468 | setFocusPolicy(Qt::TabFocus); |
469 | #else |
470 | setFocusPolicy(Qt::StrongFocus); |
471 | #endif |
472 | setAcceptedMouseButtons(Qt::LeftButton); |
473 | #if QT_CONFIG(quicktemplates2_multitouch) |
474 | setAcceptTouchEvents(true); |
475 | #endif |
476 | #if QT_CONFIG(cursor) |
477 | setCursor(Qt::ArrowCursor); |
478 | #endif |
479 | } |
480 | |
481 | QQuickAbstractButton::QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQuickItem *parent) |
482 | : QQuickControl(dd, parent) |
483 | { |
484 | setActiveFocusOnTab(true); |
485 | #ifdef Q_OS_MACOS |
486 | setFocusPolicy(Qt::TabFocus); |
487 | #else |
488 | setFocusPolicy(Qt::StrongFocus); |
489 | #endif |
490 | setAcceptedMouseButtons(Qt::LeftButton); |
491 | #if QT_CONFIG(quicktemplates2_multitouch) |
492 | setAcceptTouchEvents(true); |
493 | #endif |
494 | #if QT_CONFIG(cursor) |
495 | setCursor(Qt::ArrowCursor); |
496 | #endif |
497 | } |
498 | |
499 | QQuickAbstractButton::~QQuickAbstractButton() |
500 | { |
501 | Q_D(QQuickAbstractButton); |
502 | d->removeImplicitSizeListener(item: d->indicator); |
503 | if (d->group) { |
504 | auto *attached = qobject_cast<QQuickButtonGroupAttached *>( |
505 | object: qmlAttachedPropertiesObject<QQuickButtonGroup>(obj: this, create: false)); |
506 | if (attached) |
507 | attached->setGroup(nullptr); |
508 | else |
509 | d->group->removeButton(button: this); |
510 | } |
511 | #if QT_CONFIG(shortcut) |
512 | d->ungrabShortcut(); |
513 | #endif |
514 | } |
515 | |
516 | /*! |
517 | \qmlproperty string QtQuick.Controls::AbstractButton::text |
518 | |
519 | This property holds a textual description of the button. |
520 | |
521 | \note The text is used for accessibility purposes, so it makes sense to |
522 | set a textual description even if the content item is an image. |
523 | |
524 | \sa icon, display, {Control::contentItem}{contentItem} |
525 | */ |
526 | QString QQuickAbstractButton::text() const |
527 | { |
528 | Q_D(const QQuickAbstractButton); |
529 | return d->explicitText || !d->action ? d->text : d->action->text(); |
530 | } |
531 | |
532 | void QQuickAbstractButton::setText(const QString &text) |
533 | { |
534 | Q_D(QQuickAbstractButton); |
535 | d->setText(newText: text, isExplicit: true); |
536 | } |
537 | |
538 | void QQuickAbstractButton::resetText() |
539 | { |
540 | Q_D(QQuickAbstractButton); |
541 | d->setText(newText: QString(), isExplicit: false); |
542 | } |
543 | |
544 | /*! |
545 | \qmlproperty bool QtQuick.Controls::AbstractButton::down |
546 | |
547 | This property holds whether the button is visually down. |
548 | |
549 | Unless explicitly set, this property follows the value of \l pressed. To |
550 | return to the default value, set this property to \c undefined. |
551 | |
552 | \sa pressed |
553 | */ |
554 | bool QQuickAbstractButton::isDown() const |
555 | { |
556 | Q_D(const QQuickAbstractButton); |
557 | return d->down; |
558 | } |
559 | |
560 | void QQuickAbstractButton::setDown(bool down) |
561 | { |
562 | Q_D(QQuickAbstractButton); |
563 | d->explicitDown = true; |
564 | |
565 | if (d->down == down) |
566 | return; |
567 | |
568 | d->down = down; |
569 | emit downChanged(); |
570 | } |
571 | |
572 | void QQuickAbstractButton::resetDown() |
573 | { |
574 | Q_D(QQuickAbstractButton); |
575 | if (!d->explicitDown) |
576 | return; |
577 | |
578 | setDown(d->pressed); |
579 | d->explicitDown = false; |
580 | } |
581 | |
582 | /*! |
583 | \qmlproperty bool QtQuick.Controls::AbstractButton::pressed |
584 | \readonly |
585 | |
586 | This property holds whether the button is physically pressed. A button can |
587 | be pressed by either touch or key events. |
588 | |
589 | \sa down |
590 | */ |
591 | bool QQuickAbstractButton::isPressed() const |
592 | { |
593 | Q_D(const QQuickAbstractButton); |
594 | return d->pressed; |
595 | } |
596 | |
597 | void QQuickAbstractButton::setPressed(bool isPressed) |
598 | { |
599 | Q_D(QQuickAbstractButton); |
600 | if (d->pressed == isPressed) |
601 | return; |
602 | |
603 | d->pressed = isPressed; |
604 | setAccessibleProperty(propertyName: "pressed" , value: isPressed); |
605 | emit pressedChanged(); |
606 | buttonChange(change: ButtonPressedChanged); |
607 | |
608 | if (!d->explicitDown) { |
609 | setDown(d->pressed); |
610 | d->explicitDown = false; |
611 | } |
612 | } |
613 | |
614 | /*! |
615 | \qmlproperty bool QtQuick.Controls::AbstractButton::checked |
616 | |
617 | This property holds whether the button is checked. |
618 | |
619 | Since Qt 6.2, setting this property no longer affects the |
620 | \l {AbstractButton::}{checkable} property. Explicitly set the |
621 | \c checkable property if needed. |
622 | |
623 | \sa checkable |
624 | */ |
625 | bool QQuickAbstractButton::isChecked() const |
626 | { |
627 | Q_D(const QQuickAbstractButton); |
628 | return d->checked; |
629 | } |
630 | |
631 | void QQuickAbstractButton::setChecked(bool checked) |
632 | { |
633 | Q_D(QQuickAbstractButton); |
634 | if (d->checked == checked) |
635 | return; |
636 | |
637 | d->checked = checked; |
638 | if (d->action) |
639 | d->action->setChecked(checked); |
640 | setAccessibleProperty(propertyName: "checked" , value: checked); |
641 | buttonChange(change: ButtonCheckedChange); |
642 | emit checkedChanged(); |
643 | } |
644 | |
645 | /*! |
646 | \qmlproperty bool QtQuick.Controls::AbstractButton::checkable |
647 | |
648 | This property holds whether the button is checkable. |
649 | |
650 | A checkable button toggles between checked (on) and unchecked (off) when |
651 | the user clicks on it or presses the space bar while the button has active |
652 | focus. |
653 | |
654 | The default value is \c false. |
655 | |
656 | \sa checked |
657 | */ |
658 | bool QQuickAbstractButton::isCheckable() const |
659 | { |
660 | Q_D(const QQuickAbstractButton); |
661 | return d->checkable; |
662 | } |
663 | |
664 | void QQuickAbstractButton::setCheckable(bool checkable) |
665 | { |
666 | Q_D(QQuickAbstractButton); |
667 | if (d->checkable == checkable) |
668 | return; |
669 | |
670 | d->checkable = checkable; |
671 | if (d->action) |
672 | d->action->setCheckable(checkable); |
673 | setAccessibleProperty(propertyName: "checkable" , value: checkable); |
674 | buttonChange(change: ButtonCheckableChange); |
675 | emit checkableChanged(); |
676 | } |
677 | |
678 | /*! |
679 | \qmlproperty bool QtQuick.Controls::AbstractButton::autoExclusive |
680 | |
681 | This property holds whether auto-exclusivity is enabled. |
682 | |
683 | If auto-exclusivity is enabled, checkable buttons that belong to the same |
684 | parent item behave as if they were part of the same ButtonGroup. Only |
685 | one button can be checked at any time; checking another button automatically |
686 | unchecks the previously checked one. |
687 | |
688 | \note The property has no effect on buttons that belong to a ButtonGroup. |
689 | |
690 | RadioButton and TabButton are auto-exclusive by default. |
691 | */ |
692 | bool QQuickAbstractButton::autoExclusive() const |
693 | { |
694 | Q_D(const QQuickAbstractButton); |
695 | return d->autoExclusive; |
696 | } |
697 | |
698 | void QQuickAbstractButton::setAutoExclusive(bool exclusive) |
699 | { |
700 | Q_D(QQuickAbstractButton); |
701 | if (d->autoExclusive == exclusive) |
702 | return; |
703 | |
704 | d->autoExclusive = exclusive; |
705 | emit autoExclusiveChanged(); |
706 | } |
707 | |
708 | /*! |
709 | \qmlproperty bool QtQuick.Controls::AbstractButton::autoRepeat |
710 | |
711 | This property holds whether the button repeats \l pressed(), \l released() |
712 | and \l clicked() signals while the button is pressed and held down. |
713 | |
714 | If this property is set to \c true, the \l pressAndHold() signal will not |
715 | be emitted. |
716 | |
717 | The default value is \c false. |
718 | |
719 | The initial delay and the repetition interval are defined in milliseconds |
720 | by \l autoRepeatDelay and \l autoRepeatInterval. |
721 | */ |
722 | bool QQuickAbstractButton::autoRepeat() const |
723 | { |
724 | Q_D(const QQuickAbstractButton); |
725 | return d->autoRepeat; |
726 | } |
727 | |
728 | void QQuickAbstractButton::setAutoRepeat(bool repeat) |
729 | { |
730 | Q_D(QQuickAbstractButton); |
731 | if (d->autoRepeat == repeat) |
732 | return; |
733 | |
734 | d->stopPressRepeat(); |
735 | d->autoRepeat = repeat; |
736 | emit autoRepeatChanged(); |
737 | } |
738 | |
739 | /*! |
740 | \qmlproperty Item QtQuick.Controls::AbstractButton::indicator |
741 | |
742 | This property holds the indicator item. |
743 | */ |
744 | QQuickItem *QQuickAbstractButton::indicator() const |
745 | { |
746 | QQuickAbstractButtonPrivate *d = const_cast<QQuickAbstractButtonPrivate *>(d_func()); |
747 | if (!d->indicator) |
748 | d->executeIndicator(); |
749 | return d->indicator; |
750 | } |
751 | |
752 | void QQuickAbstractButton::setIndicator(QQuickItem *indicator) |
753 | { |
754 | Q_D(QQuickAbstractButton); |
755 | if (d->indicator == indicator) |
756 | return; |
757 | |
758 | QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item: indicator, QStringLiteral("indicator" )); |
759 | |
760 | if (!d->indicator.isExecuting()) |
761 | d->cancelIndicator(); |
762 | |
763 | const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth(); |
764 | const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight(); |
765 | |
766 | d->removeImplicitSizeListener(item: d->indicator); |
767 | QQuickControlPrivate::hideOldItem(item: d->indicator); |
768 | d->indicator = indicator; |
769 | |
770 | if (indicator) { |
771 | if (!indicator->parentItem()) |
772 | indicator->setParentItem(this); |
773 | indicator->setAcceptedMouseButtons(Qt::LeftButton); |
774 | d->addImplicitSizeListener(item: indicator); |
775 | } |
776 | |
777 | if (!qFuzzyCompare(p1: oldImplicitIndicatorWidth, p2: implicitIndicatorWidth())) |
778 | emit implicitIndicatorWidthChanged(); |
779 | if (!qFuzzyCompare(p1: oldImplicitIndicatorHeight, p2: implicitIndicatorHeight())) |
780 | emit implicitIndicatorHeightChanged(); |
781 | if (!d->indicator.isExecuting()) |
782 | emit indicatorChanged(); |
783 | } |
784 | |
785 | /*! |
786 | \qmlproperty string QtQuick.Controls::AbstractButton::icon.name |
787 | \qmlproperty url QtQuick.Controls::AbstractButton::icon.source |
788 | \qmlproperty int QtQuick.Controls::AbstractButton::icon.width |
789 | \qmlproperty int QtQuick.Controls::AbstractButton::icon.height |
790 | \qmlproperty color QtQuick.Controls::AbstractButton::icon.color |
791 | \qmlproperty bool QtQuick.Controls::AbstractButton::icon.cache |
792 | |
793 | This property group was added in QtQuick.Controls 2.3. |
794 | |
795 | \include qquickicon.qdocinc grouped-properties |
796 | |
797 | \sa text, display, {Icons in Qt Quick Controls} |
798 | */ |
799 | |
800 | QQuickIcon QQuickAbstractButton::icon() const |
801 | { |
802 | Q_D(const QQuickAbstractButton); |
803 | return d->effectiveIcon; |
804 | } |
805 | |
806 | void QQuickAbstractButton::setIcon(const QQuickIcon &icon) |
807 | { |
808 | Q_D(QQuickAbstractButton); |
809 | d->icon = icon; |
810 | d->icon.ensureRelativeSourceResolved(owner: this); |
811 | d->updateEffectiveIcon(); |
812 | } |
813 | |
814 | /*! |
815 | \since QtQuick.Controls 2.3 (Qt 5.10) |
816 | \qmlproperty enumeration QtQuick.Controls::AbstractButton::display |
817 | |
818 | This property determines how the \l icon and \l text are displayed within |
819 | the button. |
820 | |
821 | \table |
822 | \header \li Display \li Result |
823 | \row \li \c AbstractButton.IconOnly \li \image qtquickcontrols-button-icononly.png |
824 | \row \li \c AbstractButton.TextOnly \li \image qtquickcontrols-button-textonly.png |
825 | \row \li \c AbstractButton.TextBesideIcon \li \image qtquickcontrols-button-textbesideicon.png |
826 | \row \li \c AbstractButton.TextUnderIcon \li \image qtquickcontrols-button-textundericon.png |
827 | \endtable |
828 | |
829 | \sa {Control::}{spacing}, {Control::}{padding} |
830 | */ |
831 | QQuickAbstractButton::Display QQuickAbstractButton::display() const |
832 | { |
833 | Q_D(const QQuickAbstractButton); |
834 | return d->display; |
835 | } |
836 | |
837 | void QQuickAbstractButton::setDisplay(Display display) |
838 | { |
839 | Q_D(QQuickAbstractButton); |
840 | if (display == d->display) |
841 | return; |
842 | |
843 | d->display = display; |
844 | emit displayChanged(); |
845 | } |
846 | |
847 | /*! |
848 | \since QtQuick.Controls 2.3 (Qt 5.10) |
849 | \qmlproperty Action QtQuick.Controls::AbstractButton::action |
850 | |
851 | This property holds the button action. |
852 | |
853 | \sa Action |
854 | */ |
855 | QQuickAction *QQuickAbstractButton::action() const |
856 | { |
857 | Q_D(const QQuickAbstractButton); |
858 | return d->action; |
859 | } |
860 | |
861 | void QQuickAbstractButton::setAction(QQuickAction *action) |
862 | { |
863 | Q_D(QQuickAbstractButton); |
864 | if (d->action == action) |
865 | return; |
866 | |
867 | const QString oldText = text(); |
868 | |
869 | if (QQuickAction *oldAction = d->action.data()) { |
870 | QQuickActionPrivate::get(action: oldAction)->unregisterItem(item: this); |
871 | QObjectPrivate::disconnect(sender: oldAction, signal: &QQuickAction::triggered, receiverPrivate: d, slot: &QQuickAbstractButtonPrivate::click); |
872 | QObjectPrivate::disconnect(sender: oldAction, signal: &QQuickAction::textChanged, receiverPrivate: d, slot: &QQuickAbstractButtonPrivate::actionTextChange); |
873 | |
874 | QObjectPrivate::disconnect(sender: oldAction, signal: &QQuickAction::iconChanged, receiverPrivate: d, slot: &QQuickAbstractButtonPrivate::updateEffectiveIcon); |
875 | disconnect(sender: oldAction, signal: &QQuickAction::checkedChanged, receiver: this, slot: &QQuickAbstractButton::setChecked); |
876 | disconnect(sender: oldAction, signal: &QQuickAction::checkableChanged, receiver: this, slot: &QQuickAbstractButton::setCheckable); |
877 | disconnect(sender: oldAction, signal: &QQuickAction::enabledChanged, receiver: this, slot: &QQuickItem::setEnabled); |
878 | } |
879 | |
880 | if (action) { |
881 | QQuickActionPrivate::get(action)->registerItem(item: this); |
882 | QObjectPrivate::connect(sender: action, signal: &QQuickAction::triggered, receiverPrivate: d, slot: &QQuickAbstractButtonPrivate::click); |
883 | QObjectPrivate::connect(sender: action, signal: &QQuickAction::textChanged, receiverPrivate: d, slot: &QQuickAbstractButtonPrivate::actionTextChange); |
884 | |
885 | QObjectPrivate::connect(sender: action, signal: &QQuickAction::iconChanged, receiverPrivate: d, slot: &QQuickAbstractButtonPrivate::updateEffectiveIcon); |
886 | connect(sender: action, signal: &QQuickAction::checkedChanged, context: this, slot: &QQuickAbstractButton::setChecked); |
887 | connect(sender: action, signal: &QQuickAction::checkableChanged, context: this, slot: &QQuickAbstractButton::setCheckable); |
888 | connect(sender: action, signal: &QQuickAction::enabledChanged, context: this, slot: &QQuickItem::setEnabled); |
889 | |
890 | setChecked(action->isChecked()); |
891 | setCheckable(action->isCheckable()); |
892 | setEnabled(action->isEnabled()); |
893 | } |
894 | |
895 | d->action = action; |
896 | |
897 | if (oldText != text()) |
898 | buttonChange(change: ButtonTextChange); |
899 | |
900 | d->updateEffectiveIcon(); |
901 | |
902 | emit actionChanged(); |
903 | } |
904 | |
905 | /*! |
906 | \since QtQuick.Controls 2.4 (Qt 5.11) |
907 | \qmlproperty int QtQuick.Controls::AbstractButton::autoRepeatDelay |
908 | |
909 | This property holds the initial delay of auto-repetition in milliseconds. |
910 | The default value is \c 300 ms. |
911 | |
912 | \sa autoRepeat, autoRepeatInterval |
913 | */ |
914 | int QQuickAbstractButton::autoRepeatDelay() const |
915 | { |
916 | Q_D(const QQuickAbstractButton); |
917 | return d->repeatDelay; |
918 | } |
919 | |
920 | void QQuickAbstractButton::setAutoRepeatDelay(int delay) |
921 | { |
922 | Q_D(QQuickAbstractButton); |
923 | if (d->repeatDelay == delay) |
924 | return; |
925 | |
926 | d->repeatDelay = delay; |
927 | emit autoRepeatDelayChanged(); |
928 | } |
929 | |
930 | /*! |
931 | \since QtQuick.Controls 2.4 (Qt 5.11) |
932 | \qmlproperty int QtQuick.Controls::AbstractButton::autoRepeatInterval |
933 | |
934 | This property holds the interval of auto-repetition in milliseconds. |
935 | The default value is \c 100 ms. |
936 | |
937 | \sa autoRepeat, autoRepeatDelay |
938 | */ |
939 | int QQuickAbstractButton::autoRepeatInterval() const |
940 | { |
941 | Q_D(const QQuickAbstractButton); |
942 | return d->repeatInterval; |
943 | } |
944 | |
945 | void QQuickAbstractButton::setAutoRepeatInterval(int interval) |
946 | { |
947 | Q_D(QQuickAbstractButton); |
948 | if (d->repeatInterval == interval) |
949 | return; |
950 | |
951 | d->repeatInterval = interval; |
952 | emit autoRepeatIntervalChanged(); |
953 | } |
954 | |
955 | #if QT_CONFIG(shortcut) |
956 | QKeySequence QQuickAbstractButton::shortcut() const |
957 | { |
958 | Q_D(const QQuickAbstractButton); |
959 | return d->shortcut; |
960 | } |
961 | |
962 | void QQuickAbstractButton::setShortcut(const QKeySequence &shortcut) |
963 | { |
964 | Q_D(QQuickAbstractButton); |
965 | if (d->shortcut == shortcut) |
966 | return; |
967 | |
968 | d->ungrabShortcut(); |
969 | d->shortcut = shortcut; |
970 | if (isVisible()) |
971 | d->grabShortcut(); |
972 | } |
973 | #endif |
974 | |
975 | /*! |
976 | \readonly |
977 | \since QtQuick.Controls 2.4 (Qt 5.11) |
978 | \qmlproperty real QtQuick.Controls::AbstractButton::pressX |
979 | |
980 | This property holds the x-coordinate of the last press. |
981 | |
982 | \note The value is updated on touch moves, but left intact after touch release. |
983 | |
984 | \sa pressY |
985 | */ |
986 | qreal QQuickAbstractButton::pressX() const |
987 | { |
988 | Q_D(const QQuickAbstractButton); |
989 | return d->movePoint.x(); |
990 | } |
991 | |
992 | /*! |
993 | \readonly |
994 | \since QtQuick.Controls 2.4 (Qt 5.11) |
995 | \qmlproperty real QtQuick.Controls::AbstractButton::pressY |
996 | |
997 | This property holds the y-coordinate of the last press. |
998 | |
999 | \note The value is updated on touch moves, but left intact after touch release. |
1000 | |
1001 | \sa pressX |
1002 | */ |
1003 | qreal QQuickAbstractButton::pressY() const |
1004 | { |
1005 | Q_D(const QQuickAbstractButton); |
1006 | return d->movePoint.y(); |
1007 | } |
1008 | |
1009 | /*! |
1010 | \since QtQuick.Controls 2.5 (Qt 5.12) |
1011 | \qmlproperty real QtQuick.Controls::AbstractButton::implicitIndicatorWidth |
1012 | \readonly |
1013 | |
1014 | This property holds the implicit indicator width. |
1015 | |
1016 | The value is equal to \c {indicator ? indicator.implicitWidth : 0}. |
1017 | |
1018 | This is typically used, together with \l {Control::}{implicitContentWidth} and |
1019 | \l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}. |
1020 | |
1021 | \sa implicitIndicatorHeight |
1022 | */ |
1023 | qreal QQuickAbstractButton::implicitIndicatorWidth() const |
1024 | { |
1025 | Q_D(const QQuickAbstractButton); |
1026 | if (!d->indicator) |
1027 | return 0; |
1028 | return d->indicator->implicitWidth(); |
1029 | } |
1030 | |
1031 | /*! |
1032 | \since QtQuick.Controls 2.5 (Qt 5.12) |
1033 | \qmlproperty real QtQuick.Controls::AbstractButton::implicitIndicatorHeight |
1034 | \readonly |
1035 | |
1036 | This property holds the implicit indicator height. |
1037 | |
1038 | The value is equal to \c {indicator ? indicator.implicitHeight : 0}. |
1039 | |
1040 | This is typically used, together with \l {Control::}{implicitContentHeight} and |
1041 | \l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}. |
1042 | |
1043 | \sa implicitIndicatorWidth |
1044 | */ |
1045 | qreal QQuickAbstractButton::implicitIndicatorHeight() const |
1046 | { |
1047 | Q_D(const QQuickAbstractButton); |
1048 | if (!d->indicator) |
1049 | return 0; |
1050 | return d->indicator->implicitHeight(); |
1051 | } |
1052 | |
1053 | /*! |
1054 | \qmlmethod void QtQuick.Controls::AbstractButton::toggle() |
1055 | |
1056 | Toggles the checked state of the button. |
1057 | */ |
1058 | void QQuickAbstractButton::toggle() |
1059 | { |
1060 | Q_D(QQuickAbstractButton); |
1061 | setChecked(!d->checked); |
1062 | } |
1063 | |
1064 | void QQuickAbstractButton::componentComplete() |
1065 | { |
1066 | Q_D(QQuickAbstractButton); |
1067 | d->executeIndicator(complete: true); |
1068 | QQuickControl::componentComplete(); |
1069 | } |
1070 | |
1071 | bool QQuickAbstractButton::event(QEvent *event) |
1072 | { |
1073 | #if QT_CONFIG(shortcut) |
1074 | Q_D(QQuickAbstractButton); |
1075 | if (event->type() == QEvent::Shortcut) { |
1076 | QShortcutEvent *se = static_cast<QShortcutEvent *>(event); |
1077 | if (se->shortcutId() == d->shortcutId) { |
1078 | d->trigger(); |
1079 | return true; |
1080 | } |
1081 | } |
1082 | #endif |
1083 | return QQuickControl::event(event); |
1084 | } |
1085 | |
1086 | void QQuickAbstractButton::focusOutEvent(QFocusEvent *event) |
1087 | { |
1088 | Q_D(QQuickAbstractButton); |
1089 | QQuickControl::focusOutEvent(event); |
1090 | if (d->touchId == -1) // don't ungrab on multi-touch if another control gets focused |
1091 | d->handleUngrab(); |
1092 | } |
1093 | |
1094 | void QQuickAbstractButton::keyPressEvent(QKeyEvent *event) |
1095 | { |
1096 | Q_D(QQuickAbstractButton); |
1097 | QQuickControl::keyPressEvent(event); |
1098 | if (d->acceptKeyClick(key: static_cast<Qt::Key>(event->key()))) { |
1099 | d->setPressPoint(d->centerPressPoint()); |
1100 | setPressed(true); |
1101 | |
1102 | if (d->autoRepeat) |
1103 | d->startRepeatDelay(); |
1104 | |
1105 | emit pressed(); |
1106 | event->accept(); |
1107 | } |
1108 | } |
1109 | |
1110 | void QQuickAbstractButton::keyReleaseEvent(QKeyEvent *event) |
1111 | { |
1112 | Q_D(QQuickAbstractButton); |
1113 | QQuickControl::keyReleaseEvent(event); |
1114 | if (d->pressed && d->acceptKeyClick(key: static_cast<Qt::Key>(event->key()))) { |
1115 | setPressed(false); |
1116 | |
1117 | nextCheckState(); |
1118 | emit released(); |
1119 | d->trigger(); |
1120 | |
1121 | if (d->autoRepeat) |
1122 | d->stopPressRepeat(); |
1123 | event->accept(); |
1124 | } |
1125 | } |
1126 | |
1127 | void QQuickAbstractButton::mousePressEvent(QMouseEvent *event) |
1128 | { |
1129 | Q_D(QQuickAbstractButton); |
1130 | d->pressButtons = event->buttons(); |
1131 | QQuickControl::mousePressEvent(event); |
1132 | } |
1133 | |
1134 | void QQuickAbstractButton::mouseDoubleClickEvent(QMouseEvent *event) |
1135 | { |
1136 | Q_UNUSED(event); |
1137 | Q_D(QQuickAbstractButton); |
1138 | if (d->isDoubleClickConnected()) { |
1139 | // don't call QQuickItem::mouseDoubleClickEvent(): it would ignore() |
1140 | emit doubleClicked(); |
1141 | d->wasDoubleClick = true; |
1142 | } |
1143 | } |
1144 | |
1145 | void QQuickAbstractButton::timerEvent(QTimerEvent *event) |
1146 | { |
1147 | Q_D(QQuickAbstractButton); |
1148 | QQuickControl::timerEvent(event); |
1149 | if (event->timerId() == d->holdTimer) { |
1150 | d->stopPressAndHold(); |
1151 | d->wasHeld = true; |
1152 | emit pressAndHold(); |
1153 | } else if (event->timerId() == d->delayTimer) { |
1154 | d->startPressRepeat(); |
1155 | } else if (event->timerId() == d->repeatTimer) { |
1156 | emit released(); |
1157 | d->trigger(); |
1158 | emit pressed(); |
1159 | } |
1160 | } |
1161 | |
1162 | void QQuickAbstractButton::itemChange(ItemChange change, const ItemChangeData &value) |
1163 | { |
1164 | QQuickControl::itemChange(change, value); |
1165 | #if QT_CONFIG(shortcut) |
1166 | Q_D(QQuickAbstractButton); |
1167 | if (change == ItemVisibleHasChanged) { |
1168 | if (value.boolValue) |
1169 | d->grabShortcut(); |
1170 | else |
1171 | d->ungrabShortcut(); |
1172 | } |
1173 | #endif |
1174 | } |
1175 | |
1176 | void QQuickAbstractButton::buttonChange(ButtonChange change) |
1177 | { |
1178 | Q_D(QQuickAbstractButton); |
1179 | switch (change) { |
1180 | case ButtonCheckedChange: |
1181 | if (d->checked) { |
1182 | QQuickAbstractButton *button = d->findCheckedButton(); |
1183 | if (button && button != this) |
1184 | button->setChecked(false); |
1185 | } |
1186 | break; |
1187 | case ButtonTextChange: { |
1188 | const QString txt = text(); |
1189 | maybeSetAccessibleName(name: txt); |
1190 | #if QT_CONFIG(shortcut) |
1191 | setShortcut(QKeySequence::mnemonic(text: txt)); |
1192 | #endif |
1193 | emit textChanged(); |
1194 | break; |
1195 | } |
1196 | default: |
1197 | break; |
1198 | } |
1199 | } |
1200 | |
1201 | void QQuickAbstractButton::nextCheckState() |
1202 | { |
1203 | Q_D(QQuickAbstractButton); |
1204 | if (!d->checkable) |
1205 | return; |
1206 | |
1207 | if (d->checked) { |
1208 | if (d->findCheckedButton() == this) |
1209 | return; |
1210 | if (d->action) { |
1211 | // For non-exclusive groups checkedAction is null |
1212 | if (const auto group = QQuickActionPrivate::get(action: d->action)->group) |
1213 | if (group->checkedAction() == d->action) |
1214 | return; |
1215 | } |
1216 | } |
1217 | |
1218 | d->toggle(value: !d->checked); |
1219 | } |
1220 | |
1221 | #if QT_CONFIG(accessibility) |
1222 | void QQuickAbstractButton::accessibilityActiveChanged(bool active) |
1223 | { |
1224 | QQuickControl::accessibilityActiveChanged(active); |
1225 | |
1226 | Q_D(QQuickAbstractButton); |
1227 | if (active) { |
1228 | maybeSetAccessibleName(name: text()); |
1229 | setAccessibleProperty(propertyName: "pressed" , value: d->pressed); |
1230 | setAccessibleProperty(propertyName: "checked" , value: d->checked); |
1231 | setAccessibleProperty(propertyName: "checkable" , value: d->checkable); |
1232 | } |
1233 | } |
1234 | |
1235 | QAccessible::Role QQuickAbstractButton::accessibleRole() const |
1236 | { |
1237 | Q_D(const QQuickAbstractButton); |
1238 | if (d->checkable) { |
1239 | return QAccessible::CheckBox; |
1240 | } |
1241 | return QAccessible::Button; |
1242 | } |
1243 | |
1244 | void QQuickAbstractButton::accessiblePressAction() |
1245 | { |
1246 | Q_D(QQuickAbstractButton); |
1247 | d->trigger(); |
1248 | } |
1249 | #endif |
1250 | |
1251 | QT_END_NAMESPACE |
1252 | |
1253 | #include "moc_qquickabstractbutton_p.cpp" |
1254 | |