source: trunk/src/gui/widgets/qabstractbutton.cpp@ 1166

Last change on this file since 1166 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 38.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qabstractbutton.h"
43#include "qabstractitemview.h"
44#include "qbuttongroup.h"
45#include "qabstractbutton_p.h"
46#include "qevent.h"
47#include "qpainter.h"
48#include "qapplication.h"
49#include "qstyle.h"
50#include "qaction.h"
51#ifndef QT_NO_ACCESSIBILITY
52#include "qaccessible.h"
53#endif
54
55QT_BEGIN_NAMESPACE
56
57#define AUTO_REPEAT_DELAY 300
58#define AUTO_REPEAT_INTERVAL 100
59
60Q_GUI_EXPORT extern bool qt_tab_all_widgets;
61
62/*!
63 \class QAbstractButton
64
65 \brief The QAbstractButton class is the abstract base class of
66 button widgets, providing functionality common to buttons.
67
68 \ingroup abstractwidgets
69
70 This class implements an \e abstract button.
71 Subclasses of this class handle user actions, and specify how the button
72 is drawn.
73
74 QAbstractButton provides support for both push buttons and checkable
75 (toggle) buttons. Checkable buttons are implemented in the QRadioButton
76 and QCheckBox classes. Push buttons are implemented in the
77 QPushButton and QToolButton classes; these also provide toggle
78 behavior if required.
79
80 Any button can display a label containing text and an icon. setText()
81 sets the text; setIcon() sets the icon. If a button is disabled, its label
82 is changed to give the button a "disabled" appearance.
83
84 If the button is a text button with a string containing an
85 ampersand ('&'), QAbstractButton automatically creates a shortcut
86 key. For example:
87
88 \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 0
89
90 The \key Alt+C shortcut is assigned to the button, i.e., when the
91 user presses \key Alt+C the button will call animateClick(). See
92 the \l {QShortcut#mnemonic}{QShortcut} documentation for details
93 (to display an actual ampersand, use '&&').
94
95 You can also set a custom shortcut key using the setShortcut()
96 function. This is useful mostly for buttons that do not have any
97 text, because they have no automatic shortcut.
98
99 \snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 1
100
101 All of the buttons provided by Qt (QPushButton, QToolButton,
102 QCheckBox, and QRadioButton) can display both \l text and \l{icon}{icons}.
103
104 A button can be made the default button in a dialog are provided by
105 QPushButton::setDefault() and QPushButton::setAutoDefault().
106
107 QAbstractButton provides most of the states used for buttons:
108
109 \list
110
111 \o isDown() indicates whether the button is \e pressed down.
112
113 \o isChecked() indicates whether the button is \e checked. Only
114 checkable buttons can be checked and unchecked (see below).
115
116 \o isEnabled() indicates whether the button can be pressed by the
117 user.
118
119 \o setAutoRepeat() sets whether the button will auto-repeat if the
120 user holds it down. \l autoRepeatDelay and \l autoRepeatInterval
121 define how auto-repetition is done.
122
123 \o setCheckable() sets whether the button is a toggle button or not.
124
125 \endlist
126
127 The difference between isDown() and isChecked() is as follows.
128 When the user clicks a toggle button to check it, the button is first
129 \e pressed then released into the \e checked state. When the user
130 clicks it again (to uncheck it), the button moves first to the
131 \e pressed state, then to the \e unchecked state (isChecked() and
132 isDown() are both false).
133
134 QAbstractButton provides four signals:
135
136 \list 1
137
138 \o pressed() is emitted when the left mouse button is pressed while
139 the mouse cursor is inside the button.
140
141 \o released() is emitted when the left mouse button is released.
142
143 \o clicked() is emitted when the button is first pressed and then
144 released, when the shortcut key is typed, or when click() or
145 animateClick() is called.
146
147 \o toggled() is emitted when the state of a toggle button changes.
148
149 \endlist
150
151 To subclass QAbstractButton, you must reimplement at least
152 paintEvent() to draw the button's outline and its text or pixmap. It
153 is generally advisable to reimplement sizeHint() as well, and
154 sometimes hitButton() (to determine whether a button press is within
155 the button). For buttons with more than two states (like tri-state
156 buttons), you will also have to reimplement checkStateSet() and
157 nextCheckState().
158
159 \sa QButtonGroup
160*/
161
162QAbstractButtonPrivate::QAbstractButtonPrivate(QSizePolicy::ControlType type)
163 :
164#ifndef QT_NO_SHORTCUT
165 shortcutId(0),
166#endif
167 checkable(false), checked(false), autoRepeat(false), autoExclusive(false),
168 down(false), blockRefresh(false), pressed(false),
169#ifndef QT_NO_BUTTONGROUP
170 group(0),
171#endif
172 autoRepeatDelay(AUTO_REPEAT_DELAY),
173 autoRepeatInterval(AUTO_REPEAT_INTERVAL),
174 controlType(type)
175{}
176
177#ifndef QT_NO_BUTTONGROUP
178
179class QButtonGroupPrivate: public QObjectPrivate
180{
181 Q_DECLARE_PUBLIC(QButtonGroup)
182
183public:
184 QButtonGroupPrivate():exclusive(true){}
185 QList<QAbstractButton *> buttonList;
186 QPointer<QAbstractButton> checkedButton;
187 void detectCheckedButton();
188 void notifyChecked(QAbstractButton *button);
189 bool exclusive;
190 QMap<QAbstractButton*, int> mapping;
191};
192
193QButtonGroup::QButtonGroup(QObject *parent)
194 : QObject(*new QButtonGroupPrivate, parent)
195{
196}
197
198QButtonGroup::~QButtonGroup()
199{
200 Q_D(QButtonGroup);
201 for (int i = 0; i < d->buttonList.count(); ++i)
202 d->buttonList.at(i)->d_func()->group = 0;
203}
204
205
206bool QButtonGroup::exclusive() const
207{
208 Q_D(const QButtonGroup);
209 return d->exclusive;
210}
211
212void QButtonGroup::setExclusive(bool exclusive)
213{
214 Q_D(QButtonGroup);
215 d->exclusive = exclusive;
216}
217
218
219// TODO: Qt 5: Merge with addButton(QAbstractButton *button, int id)
220void QButtonGroup::addButton(QAbstractButton *button)
221{
222 addButton(button, -1);
223}
224
225void QButtonGroup::addButton(QAbstractButton *button, int id)
226{
227 Q_D(QButtonGroup);
228 if (QButtonGroup *previous = button->d_func()->group)
229 previous->removeButton(button);
230 button->d_func()->group = this;
231 d->buttonList.append(button);
232 if (id == -1) {
233 QList<int> ids = d->mapping.values();
234 if (ids.isEmpty())
235 d->mapping[button] = -2;
236 else {
237 qSort(ids);
238 d->mapping[button] = ids.first()-1;
239 }
240 } else {
241 d->mapping[button] = id;
242 }
243
244 if (d->exclusive && button->isChecked())
245 button->d_func()->notifyChecked();
246}
247
248void QButtonGroup::removeButton(QAbstractButton *button)
249{
250 Q_D(QButtonGroup);
251 if (d->checkedButton == button) {
252 d->detectCheckedButton();
253 }
254 if (button->d_func()->group == this) {
255 button->d_func()->group = 0;
256 d->buttonList.removeAll(button);
257 d->mapping.remove(button);
258 }
259}
260
261QList<QAbstractButton*> QButtonGroup::buttons() const
262{
263 Q_D(const QButtonGroup);
264 return d->buttonList;
265}
266
267QAbstractButton *QButtonGroup::checkedButton() const
268{
269 Q_D(const QButtonGroup);
270 return d->checkedButton;
271}
272
273QAbstractButton *QButtonGroup::button(int id) const
274{
275 Q_D(const QButtonGroup);
276 return d->mapping.key(id);
277}
278
279void QButtonGroup::setId(QAbstractButton *button, int id)
280{
281 Q_D(QButtonGroup);
282 if (button && id != -1)
283 d->mapping[button] = id;
284}
285
286int QButtonGroup::id(QAbstractButton *button) const
287{
288 Q_D(const QButtonGroup);
289 return d->mapping.value(button, -1);
290}
291
292int QButtonGroup::checkedId() const
293{
294 Q_D(const QButtonGroup);
295 return d->mapping.value(d->checkedButton, -1);
296}
297
298// detect a checked button other than the current one
299void QButtonGroupPrivate::detectCheckedButton()
300{
301 QAbstractButton *previous = checkedButton;
302 checkedButton = 0;
303 if (exclusive)
304 return;
305 for (int i = 0; i < buttonList.count(); i++) {
306 if (buttonList.at(i) != previous && buttonList.at(i)->isChecked()) {
307 checkedButton = buttonList.at(i);
308 return;
309 }
310 }
311}
312
313#endif // QT_NO_BUTTONGROUP
314
315QList<QAbstractButton *>QAbstractButtonPrivate::queryButtonList() const
316{
317#ifndef QT_NO_BUTTONGROUP
318 if (group)
319 return group->d_func()->buttonList;
320#endif
321
322 QList<QAbstractButton*>candidates = qFindChildren<QAbstractButton *>(parent);
323 if (autoExclusive) {
324 for (int i = candidates.count() - 1; i >= 0; --i) {
325 QAbstractButton *candidate = candidates.at(i);
326 if (!candidate->autoExclusive()
327#ifndef QT_NO_BUTTONGROUP
328 || candidate->group()
329#endif
330 )
331 candidates.removeAt(i);
332 }
333 }
334 return candidates;
335}
336
337QAbstractButton *QAbstractButtonPrivate::queryCheckedButton() const
338{
339#ifndef QT_NO_BUTTONGROUP
340 if (group)
341 return group->d_func()->checkedButton;
342#endif
343
344 Q_Q(const QAbstractButton);
345 QList<QAbstractButton *> buttonList = queryButtonList();
346 if (!autoExclusive || buttonList.count() == 1) // no group
347 return 0;
348
349 for (int i = 0; i < buttonList.count(); ++i) {
350 QAbstractButton *b = buttonList.at(i);
351 if (b->d_func()->checked && b != q)
352 return b;
353 }
354 return checked ? const_cast<QAbstractButton *>(q) : 0;
355}
356
357void QAbstractButtonPrivate::notifyChecked()
358{
359#ifndef QT_NO_BUTTONGROUP
360 Q_Q(QAbstractButton);
361 if (group) {
362 QAbstractButton *previous = group->d_func()->checkedButton;
363 group->d_func()->checkedButton = q;
364 if (group->d_func()->exclusive && previous && previous != q)
365 previous->nextCheckState();
366 } else
367#endif
368 if (autoExclusive) {
369 if (QAbstractButton *b = queryCheckedButton())
370 b->setChecked(false);
371 }
372}
373
374void QAbstractButtonPrivate::moveFocus(int key)
375{
376 QList<QAbstractButton *> buttonList = queryButtonList();;
377#ifndef QT_NO_BUTTONGROUP
378 bool exclusive = group ? group->d_func()->exclusive : autoExclusive;
379#else
380 bool exclusive = autoExclusive;
381#endif
382 QWidget *f = QApplication::focusWidget();
383 QAbstractButton *fb = qobject_cast<QAbstractButton *>(f);
384 if (!fb || !buttonList.contains(fb))
385 return;
386
387 QAbstractButton *candidate = 0;
388 int bestScore = -1;
389 QRect target = f->rect().translated(f->mapToGlobal(QPoint(0,0)));
390 QPoint goal = target.center();
391 uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
392
393 for (int i = 0; i < buttonList.count(); ++i) {
394 QAbstractButton *button = buttonList.at(i);
395 if (button != f && button->window() == f->window() && button->isEnabled() && !button->isHidden() &&
396 (autoExclusive || (button->focusPolicy() & focus_flag) == focus_flag)) {
397 QRect buttonRect = button->rect().translated(button->mapToGlobal(QPoint(0,0)));
398 QPoint p = buttonRect.center();
399
400 //Priority to widgets that overlap on the same coordinate.
401 //In that case, the distance in the direction will be used as significant score,
402 //take also in account orthogonal distance in case two widget are in the same distance.
403 int score;
404 if ((buttonRect.x() < target.right() && target.x() < buttonRect.right())
405 && (key == Qt::Key_Up || key == Qt::Key_Down)) {
406 //one item's is at the vertical of the other
407 score = (qAbs(p.y() - goal.y()) << 16) + qAbs(p.x() - goal.x());
408 } else if ((buttonRect.y() < target.bottom() && target.y() < buttonRect.bottom())
409 && (key == Qt::Key_Left || key == Qt::Key_Right) ) {
410 //one item's is at the horizontal of the other
411 score = (qAbs(p.x() - goal.x()) << 16) + qAbs(p.y() - goal.y());
412 } else {
413 score = (1 << 30) + (p.y() - goal.y()) * (p.y() - goal.y()) + (p.x() - goal.x()) * (p.x() - goal.x());
414 }
415
416 if (score > bestScore && candidate)
417 continue;
418
419 switch(key) {
420 case Qt::Key_Up:
421 if (p.y() < goal.y()) {
422 candidate = button;
423 bestScore = score;
424 }
425 break;
426 case Qt::Key_Down:
427 if (p.y() > goal.y()) {
428 candidate = button;
429 bestScore = score;
430 }
431 break;
432 case Qt::Key_Left:
433 if (p.x() < goal.x()) {
434 candidate = button;
435 bestScore = score;
436 }
437 break;
438 case Qt::Key_Right:
439 if (p.x() > goal.x()) {
440 candidate = button;
441 bestScore = score;
442 }
443 break;
444 }
445 }
446 }
447
448 if (exclusive
449#ifdef QT_KEYPAD_NAVIGATION
450 && !QApplication::keypadNavigationEnabled()
451#endif
452 && candidate
453 && fb->d_func()->checked
454 && candidate->d_func()->checkable)
455 candidate->click();
456
457 if (candidate) {
458 if (key == Qt::Key_Up || key == Qt::Key_Left)
459 candidate->setFocus(Qt::BacktabFocusReason);
460 else
461 candidate->setFocus(Qt::TabFocusReason);
462 }
463}
464
465void QAbstractButtonPrivate::fixFocusPolicy()
466{
467 Q_Q(QAbstractButton);
468#ifndef QT_NO_BUTTONGROUP
469 if (!group && !autoExclusive)
470#else
471 if (!autoExclusive)
472#endif
473 return;
474
475 QList<QAbstractButton *> buttonList = queryButtonList();
476 for (int i = 0; i < buttonList.count(); ++i) {
477 QAbstractButton *b = buttonList.at(i);
478 if (!b->isCheckable())
479 continue;
480 b->setFocusPolicy((Qt::FocusPolicy) ((b == q || !q->isCheckable())
481 ? (b->focusPolicy() | Qt::TabFocus)
482 : (b->focusPolicy() & ~Qt::TabFocus)));
483 }
484}
485
486void QAbstractButtonPrivate::init()
487{
488 Q_Q(QAbstractButton);
489
490 q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy)));
491 q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, controlType));
492 q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
493 q->setForegroundRole(QPalette::ButtonText);
494 q->setBackgroundRole(QPalette::Button);
495}
496
497void QAbstractButtonPrivate::refresh()
498{
499 Q_Q(QAbstractButton);
500
501 if (blockRefresh)
502 return;
503 q->update();
504#ifndef QT_NO_ACCESSIBILITY
505 QAccessible::updateAccessibility(q, 0, QAccessible::StateChanged);
506#endif
507}
508
509void QAbstractButtonPrivate::click()
510{
511 Q_Q(QAbstractButton);
512
513 down = false;
514 blockRefresh = true;
515 bool changeState = true;
516 if (checked && queryCheckedButton() == q) {
517 // the checked button of an exclusive or autoexclusive group cannot be unchecked
518#ifndef QT_NO_BUTTONGROUP
519 if (group ? group->d_func()->exclusive : autoExclusive)
520#else
521 if (autoExclusive)
522#endif
523 changeState = false;
524 }
525
526 QPointer<QAbstractButton> guard(q);
527 if (changeState) {
528 q->nextCheckState();
529 if (!guard)
530 return;
531 }
532 blockRefresh = false;
533 refresh();
534 q->repaint(); //flush paint event before invoking potentially expensive operation
535 QApplication::flush();
536 if (guard)
537 emitReleased();
538 if (guard)
539 emitClicked();
540}
541
542void QAbstractButtonPrivate::emitClicked()
543{
544 Q_Q(QAbstractButton);
545 QPointer<QAbstractButton> guard(q);
546 emit q->clicked(checked);
547#ifndef QT_NO_BUTTONGROUP
548 if (guard && group) {
549 emit group->buttonClicked(group->id(q));
550 if (guard && group)
551 emit group->buttonClicked(q);
552 }
553#endif
554}
555
556void QAbstractButtonPrivate::emitPressed()
557{
558 Q_Q(QAbstractButton);
559 QPointer<QAbstractButton> guard(q);
560 emit q->pressed();
561#ifndef QT_NO_BUTTONGROUP
562 if (guard && group) {
563 emit group->buttonPressed(group->id(q));
564 if (guard && group)
565 emit group->buttonPressed(q);
566 }
567#endif
568}
569
570void QAbstractButtonPrivate::emitReleased()
571{
572 Q_Q(QAbstractButton);
573 QPointer<QAbstractButton> guard(q);
574 emit q->released();
575#ifndef QT_NO_BUTTONGROUP
576 if (guard && group) {
577 emit group->buttonReleased(group->id(q));
578 if (guard && group)
579 emit group->buttonReleased(q);
580 }
581#endif
582}
583
584/*!
585 Constructs an abstract button with a \a parent.
586*/
587QAbstractButton::QAbstractButton(QWidget *parent)
588 : QWidget(*new QAbstractButtonPrivate, parent, 0)
589{
590 Q_D(QAbstractButton);
591 d->init();
592}
593
594/*!
595 Destroys the button.
596 */
597 QAbstractButton::~QAbstractButton()
598{
599#ifndef QT_NO_BUTTONGROUP
600 Q_D(QAbstractButton);
601 if (d->group)
602 d->group->removeButton(this);
603#endif
604}
605
606
607/*! \internal
608 */
609QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent)
610 : QWidget(dd, parent, 0)
611{
612 Q_D(QAbstractButton);
613 d->init();
614}
615
616/*!
617\property QAbstractButton::text
618\brief the text shown on the button
619
620If the button has no text, the text() function will return a an empty
621string.
622
623If the text contains an ampersand character ('&'), a shortcut is
624automatically created for it. The character that follows the '&' will
625be used as the shortcut key. Any previous shortcut will be
626overwritten, or cleared if no shortcut is defined by the text. See the
627\l {QShortcut#mnemonic}{QShortcut} documentation for details (to
628display an actual ampersand, use '&&').
629
630There is no default text.
631*/
632
633void QAbstractButton::setText(const QString &text)
634{
635 Q_D(QAbstractButton);
636 if (d->text == text)
637 return;
638 d->text = text;
639#ifndef QT_NO_SHORTCUT
640 QKeySequence newMnemonic = QKeySequence::mnemonic(text);
641 setShortcut(newMnemonic);
642#endif
643 d->sizeHint = QSize();
644 update();
645 updateGeometry();
646#ifndef QT_NO_ACCESSIBILITY
647 QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged);
648#endif
649}
650
651QString QAbstractButton::text() const
652{
653 Q_D(const QAbstractButton);
654 return d->text;
655}
656
657
658/*!
659 \property QAbstractButton::icon
660 \brief the icon shown on the button
661
662 The icon's default size is defined by the GUI style, but can be
663 adjusted by setting the \l iconSize property.
664*/
665void QAbstractButton::setIcon(const QIcon &icon)
666{
667 Q_D(QAbstractButton);
668 d->icon = icon;
669 d->sizeHint = QSize();
670 update();
671 updateGeometry();
672}
673
674QIcon QAbstractButton::icon() const
675{
676 Q_D(const QAbstractButton);
677 return d->icon;
678}
679
680#ifndef QT_NO_SHORTCUT
681/*!
682\property QAbstractButton::shortcut
683\brief the mnemonic associated with the button
684*/
685
686void QAbstractButton::setShortcut(const QKeySequence &key)
687{
688 Q_D(QAbstractButton);
689 if (d->shortcutId != 0)
690 releaseShortcut(d->shortcutId);
691 d->shortcut = key;
692 d->shortcutId = grabShortcut(key);
693}
694
695QKeySequence QAbstractButton::shortcut() const
696{
697 Q_D(const QAbstractButton);
698 return d->shortcut;
699}
700#endif // QT_NO_SHORTCUT
701
702/*!
703\property QAbstractButton::checkable
704\brief whether the button is checkable
705
706By default, the button is not checkable.
707
708\sa checked
709*/
710void QAbstractButton::setCheckable(bool checkable)
711{
712 Q_D(QAbstractButton);
713 if (d->checkable == checkable)
714 return;
715
716 d->checkable = checkable;
717 d->checked = false;
718}
719
720bool QAbstractButton::isCheckable() const
721{
722 Q_D(const QAbstractButton);
723 return d->checkable;
724}
725
726/*!
727\property QAbstractButton::checked
728\brief whether the button is checked
729
730Only checkable buttons can be checked. By default, the button is unchecked.
731
732\sa checkable
733*/
734void QAbstractButton::setChecked(bool checked)
735{
736 Q_D(QAbstractButton);
737 if (!d->checkable || d->checked == checked) {
738 if (!d->blockRefresh)
739 checkStateSet();
740 return;
741 }
742
743 if (!checked && d->queryCheckedButton() == this) {
744 // the checked button of an exclusive or autoexclusive group cannot be unchecked
745#ifndef QT_NO_BUTTONGROUP
746 if (d->group ? d->group->d_func()->exclusive : d->autoExclusive)
747 return;
748 if (d->group)
749 d->group->d_func()->detectCheckedButton();
750#else
751 if (d->autoExclusive)
752 return;
753#endif
754 }
755
756 QPointer<QAbstractButton> guard(this);
757
758 d->checked = checked;
759 if (!d->blockRefresh)
760 checkStateSet();
761 d->refresh();
762
763 if (guard && checked)
764 d->notifyChecked();
765 if (guard)
766 emit toggled(checked);
767}
768
769bool QAbstractButton::isChecked() const
770{
771 Q_D(const QAbstractButton);
772 return d->checked;
773}
774
775/*!
776 \property QAbstractButton::down
777 \brief whether the button is pressed down
778
779 If this property is true, the button is pressed down. The signals
780 pressed() and clicked() are not emitted if you set this property
781 to true. The default is false.
782*/
783
784void QAbstractButton::setDown(bool down)
785{
786 Q_D(QAbstractButton);
787 if (d->down == down)
788 return;
789 d->down = down;
790 d->refresh();
791 if (d->autoRepeat && d->down)
792 d->repeatTimer.start(d->autoRepeatDelay, this);
793 else
794 d->repeatTimer.stop();
795}
796
797bool QAbstractButton::isDown() const
798{
799 Q_D(const QAbstractButton);
800 return d->down;
801}
802
803/*!
804\property QAbstractButton::autoRepeat
805\brief whether autoRepeat is enabled
806
807If autoRepeat is enabled, then the pressed(), released(), and clicked() signals are emitted at
808regular intervals when the button is down. autoRepeat is off by default.
809The initial delay and the repetition interval are defined in milliseconds by \l
810autoRepeatDelay and \l autoRepeatInterval.
811
812Note: If a button is pressed down by a shortcut key, then auto-repeat is enabled and timed by the
813system and not by this class. The pressed(), released(), and clicked() signals will be emitted
814like in the normal case.
815*/
816
817void QAbstractButton::setAutoRepeat(bool autoRepeat)
818{
819 Q_D(QAbstractButton);
820 if (d->autoRepeat == autoRepeat)
821 return;
822 d->autoRepeat = autoRepeat;
823 if (d->autoRepeat && d->down)
824 d->repeatTimer.start(d->autoRepeatDelay, this);
825 else
826 d->repeatTimer.stop();
827}
828
829bool QAbstractButton::autoRepeat() const
830{
831 Q_D(const QAbstractButton);
832 return d->autoRepeat;
833}
834
835/*!
836 \property QAbstractButton::autoRepeatDelay
837 \brief the initial delay of auto-repetition
838 \since 4.2
839
840 If \l autoRepeat is enabled, then autoRepeatDelay defines the initial
841 delay in milliseconds before auto-repetition kicks in.
842
843 \sa autoRepeat, autoRepeatInterval
844*/
845
846void QAbstractButton::setAutoRepeatDelay(int autoRepeatDelay)
847{
848 Q_D(QAbstractButton);
849 d->autoRepeatDelay = autoRepeatDelay;
850}
851
852int QAbstractButton::autoRepeatDelay() const
853{
854 Q_D(const QAbstractButton);
855 return d->autoRepeatDelay;
856}
857
858/*!
859 \property QAbstractButton::autoRepeatInterval
860 \brief the interval of auto-repetition
861 \since 4.2
862
863 If \l autoRepeat is enabled, then autoRepeatInterval defines the
864 length of the auto-repetition interval in millisecons.
865
866 \sa autoRepeat, autoRepeatDelay
867*/
868
869void QAbstractButton::setAutoRepeatInterval(int autoRepeatInterval)
870{
871 Q_D(QAbstractButton);
872 d->autoRepeatInterval = autoRepeatInterval;
873}
874
875int QAbstractButton::autoRepeatInterval() const
876{
877 Q_D(const QAbstractButton);
878 return d->autoRepeatInterval;
879}
880
881
882
883/*!
884\property QAbstractButton::autoExclusive
885\brief whether auto-exclusivity is enabled
886
887If auto-exclusivity is enabled, checkable buttons that belong to the
888same parent widget behave as if they were part of the same
889exclusive button group. In an exclusive button group, only one button
890can be checked at any time; checking another button automatically
891unchecks the previously checked one.
892
893The property has no effect on buttons that belong to a button
894group.
895
896autoExclusive is off by default, except for radio buttons.
897
898\sa QRadioButton
899*/
900void QAbstractButton::setAutoExclusive(bool autoExclusive)
901{
902 Q_D(QAbstractButton);
903 d->autoExclusive = autoExclusive;
904}
905
906bool QAbstractButton::autoExclusive() const
907{
908 Q_D(const QAbstractButton);
909 return d->autoExclusive;
910}
911
912#ifndef QT_NO_BUTTONGROUP
913/*!
914 Returns the group that this button belongs to.
915
916 If the button is not a member of any QButtonGroup, this function
917 returns 0.
918
919 \sa QButtonGroup
920*/
921QButtonGroup *QAbstractButton::group() const
922{
923 Q_D(const QAbstractButton);
924 return d->group;
925}
926#endif // QT_NO_BUTTONGROUP
927
928/*!
929Performs an animated click: the button is pressed immediately, and
930released \a msec milliseconds later (the default is 100 ms).
931
932Calling this function again before the button was released will reset
933the release timer.
934
935All signals associated with a click are emitted as appropriate.
936
937This function does nothing if the button is \link setEnabled()
938disabled. \endlink
939
940\sa click()
941*/
942void QAbstractButton::animateClick(int msec)
943{
944 if (!isEnabled())
945 return;
946 Q_D(QAbstractButton);
947 if (d->checkable && focusPolicy() & Qt::ClickFocus)
948 setFocus();
949 setDown(true);
950 repaint(); //flush paint event before invoking potentially expensive operation
951 QApplication::flush();
952 if (!d->animateTimer.isActive())
953 d->emitPressed();
954 d->animateTimer.start(msec, this);
955}
956
957/*!
958Performs a click.
959
960All the usual signals associated with a click are emitted as
961appropriate. If the button is checkable, the state of the button is
962toggled.
963
964This function does nothing if the button is \link setEnabled()
965disabled. \endlink
966
967\sa animateClick()
968 */
969void QAbstractButton::click()
970{
971 if (!isEnabled())
972 return;
973 Q_D(QAbstractButton);
974 QPointer<QAbstractButton> guard(this);
975 d->down = true;
976 d->emitPressed();
977 if (guard) {
978 d->down = false;
979 nextCheckState();
980 if (guard)
981 d->emitReleased();
982 if (guard)
983 d->emitClicked();
984 }
985}
986
987/*! \fn void QAbstractButton::toggle()
988
989 Toggles the state of a checkable button.
990
991 \sa checked
992*/
993void QAbstractButton::toggle()
994{
995 Q_D(QAbstractButton);
996 setChecked(!d->checked);
997}
998
999
1000/*! This virtual handler is called when setChecked() was called,
1001unless it was called from within nextCheckState(). It allows
1002subclasses to reset their intermediate button states.
1003
1004\sa nextCheckState()
1005 */
1006void QAbstractButton::checkStateSet()
1007{
1008}
1009
1010/*! This virtual handler is called when a button is clicked. The
1011default implementation calls setChecked(!isChecked()) if the button
1012isCheckable(). It allows subclasses to implement intermediate button
1013states.
1014
1015\sa checkStateSet()
1016*/
1017void QAbstractButton::nextCheckState()
1018{
1019 if (isCheckable())
1020 setChecked(!isChecked());
1021}
1022
1023/*!
1024Returns true if \a pos is inside the clickable button rectangle;
1025otherwise returns false.
1026
1027By default, the clickable area is the entire widget. Subclasses
1028may reimplement this function to provide support for clickable
1029areas of different shapes and sizes.
1030*/
1031bool QAbstractButton::hitButton(const QPoint &pos) const
1032{
1033 return rect().contains(pos);
1034}
1035
1036/*! \reimp */
1037bool QAbstractButton::event(QEvent *e)
1038{
1039 // as opposed to other widgets, disabled buttons accept mouse
1040 // events. This avoids surprising click-through scenarios
1041 if (!isEnabled()) {
1042 switch(e->type()) {
1043 case QEvent::TabletPress:
1044 case QEvent::TabletRelease:
1045 case QEvent::TabletMove:
1046 case QEvent::MouseButtonPress:
1047 case QEvent::MouseButtonRelease:
1048 case QEvent::MouseButtonDblClick:
1049 case QEvent::MouseMove:
1050 case QEvent::HoverMove:
1051 case QEvent::HoverEnter:
1052 case QEvent::HoverLeave:
1053 case QEvent::ContextMenu:
1054#ifndef QT_NO_WHEELEVENT
1055 case QEvent::Wheel:
1056#endif
1057 return true;
1058 default:
1059 break;
1060 }
1061 }
1062
1063#ifndef QT_NO_SHORTCUT
1064 if (e->type() == QEvent::Shortcut) {
1065 Q_D(QAbstractButton);
1066 QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1067 if (d->shortcutId != se->shortcutId())
1068 return false;
1069 if (!se->isAmbiguous()) {
1070 if (!d->animateTimer.isActive())
1071 animateClick();
1072 } else {
1073 if (focusPolicy() != Qt::NoFocus)
1074 setFocus(Qt::ShortcutFocusReason);
1075 window()->setAttribute(Qt::WA_KeyboardFocusChange);
1076 }
1077 return true;
1078 }
1079#endif
1080 return QWidget::event(e);
1081}
1082
1083/*! \reimp */
1084void QAbstractButton::mousePressEvent(QMouseEvent *e)
1085{
1086 Q_D(QAbstractButton);
1087 if (e->button() != Qt::LeftButton) {
1088 e->ignore();
1089 return;
1090 }
1091 if (hitButton(e->pos())) {
1092 setDown(true);
1093 d->pressed = true;
1094 repaint(); //flush paint event before invoking potentially expensive operation
1095 QApplication::flush();
1096 d->emitPressed();
1097 e->accept();
1098 } else {
1099 e->ignore();
1100 }
1101}
1102
1103/*! \reimp */
1104void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
1105{
1106 Q_D(QAbstractButton);
1107 d->pressed = false;
1108
1109 if (e->button() != Qt::LeftButton) {
1110 e->ignore();
1111 return;
1112 }
1113
1114 if (!d->down) {
1115 e->ignore();
1116 return;
1117 }
1118
1119 if (hitButton(e->pos())) {
1120 d->repeatTimer.stop();
1121 d->click();
1122 e->accept();
1123 } else {
1124 setDown(false);
1125 e->ignore();
1126 }
1127}
1128
1129/*! \reimp */
1130void QAbstractButton::mouseMoveEvent(QMouseEvent *e)
1131{
1132 Q_D(QAbstractButton);
1133 if (!(e->buttons() & Qt::LeftButton) || !d->pressed) {
1134 e->ignore();
1135 return;
1136 }
1137
1138 if (hitButton(e->pos()) != d->down) {
1139 setDown(!d->down);
1140 repaint(); //flush paint event before invoking potentially expensive operation
1141 QApplication::flush();
1142 if (d->down)
1143 d->emitPressed();
1144 else
1145 d->emitReleased();
1146 e->accept();
1147 } else if (!hitButton(e->pos())) {
1148 e->ignore();
1149 }
1150}
1151
1152/*! \reimp */
1153void QAbstractButton::keyPressEvent(QKeyEvent *e)
1154{
1155 Q_D(QAbstractButton);
1156 bool next = true;
1157 switch (e->key()) {
1158 case Qt::Key_Enter:
1159 case Qt::Key_Return:
1160 e->ignore();
1161 break;
1162 case Qt::Key_Select:
1163 case Qt::Key_Space:
1164 if (!e->isAutoRepeat()) {
1165 setDown(true);
1166 repaint(); //flush paint event before invoking potentially expensive operation
1167 QApplication::flush();
1168 d->emitPressed();
1169 }
1170 break;
1171 case Qt::Key_Up:
1172 case Qt::Key_Left:
1173 next = false;
1174 // fall through
1175 case Qt::Key_Right:
1176 case Qt::Key_Down:
1177#ifdef QT_KEYPAD_NAVIGATION
1178 if ((QApplication::keypadNavigationEnabled()
1179 && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right))
1180 || (!QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
1181 || (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down))) {
1182 e->ignore();
1183 return;
1184 }
1185#endif
1186 QWidget *pw;
1187 if (d->autoExclusive
1188#ifndef QT_NO_BUTTONGROUP
1189 || d->group
1190#endif
1191#ifndef QT_NO_ITEMVIEWS
1192 || ((pw = parentWidget()) && qobject_cast<QAbstractItemView *>(pw->parentWidget()))
1193#endif
1194 ) {
1195 // ### Using qobject_cast to check if the parent is a viewport of
1196 // QAbstractItemView is a crude hack, and should be revisited and
1197 // cleaned up when fixing task 194373. It's here to ensure that we
1198 // keep compatibility outside QAbstractItemView.
1199 d->moveFocus(e->key());
1200 if (hasFocus()) // nothing happend, propagate
1201 e->ignore();
1202 } else {
1203 focusNextPrevChild(next);
1204 }
1205 break;
1206 case Qt::Key_Escape:
1207 if (d->down) {
1208 setDown(false);
1209 repaint(); //flush paint event before invoking potentially expensive operation
1210 QApplication::flush();
1211 d->emitReleased();
1212 break;
1213 }
1214 // fall through
1215 default:
1216 e->ignore();
1217 }
1218}
1219
1220/*! \reimp */
1221void QAbstractButton::keyReleaseEvent(QKeyEvent *e)
1222{
1223 Q_D(QAbstractButton);
1224
1225 if (!e->isAutoRepeat())
1226 d->repeatTimer.stop();
1227
1228 switch (e->key()) {
1229 case Qt::Key_Select:
1230 case Qt::Key_Space:
1231 if (!e->isAutoRepeat() && d->down)
1232 d->click();
1233 break;
1234 default:
1235 e->ignore();
1236 }
1237}
1238
1239/*!\reimp
1240 */
1241void QAbstractButton::timerEvent(QTimerEvent *e)
1242{
1243 Q_D(QAbstractButton);
1244 if (e->timerId() == d->repeatTimer.timerId()) {
1245 d->repeatTimer.start(d->autoRepeatInterval, this);
1246 if (d->down) {
1247 QPointer<QAbstractButton> guard(this);
1248 nextCheckState();
1249 if (guard)
1250 d->emitReleased();
1251 if (guard)
1252 d->emitClicked();
1253 if (guard)
1254 d->emitPressed();
1255 }
1256 } else if (e->timerId() == d->animateTimer.timerId()) {
1257 d->animateTimer.stop();
1258 d->click();
1259 }
1260}
1261
1262/*! \reimp */
1263void QAbstractButton::focusInEvent(QFocusEvent *e)
1264{
1265 Q_D(QAbstractButton);
1266#ifdef QT_KEYPAD_NAVIGATION
1267 if (!QApplication::keypadNavigationEnabled())
1268#endif
1269 d->fixFocusPolicy();
1270 QWidget::focusInEvent(e);
1271}
1272
1273/*! \reimp */
1274void QAbstractButton::focusOutEvent(QFocusEvent *e)
1275{
1276 Q_D(QAbstractButton);
1277 if (e->reason() != Qt::PopupFocusReason)
1278 d->down = false;
1279 QWidget::focusOutEvent(e);
1280}
1281
1282/*! \reimp */
1283void QAbstractButton::changeEvent(QEvent *e)
1284{
1285 Q_D(QAbstractButton);
1286 switch (e->type()) {
1287 case QEvent::EnabledChange:
1288 if (!isEnabled())
1289 setDown(false);
1290 break;
1291 default:
1292 d->sizeHint = QSize();
1293 break;
1294 }
1295 QWidget::changeEvent(e);
1296}
1297
1298/*!
1299 \fn void QAbstractButton::paintEvent(QPaintEvent *e)
1300 \reimp
1301*/
1302
1303/*!
1304 \fn void QAbstractButton::pressed()
1305
1306 This signal is emitted when the button is pressed down.
1307
1308 \sa released(), clicked()
1309*/
1310
1311/*!
1312 \fn void QAbstractButton::released()
1313
1314 This signal is emitted when the button is released.
1315
1316 \sa pressed(), clicked(), toggled()
1317*/
1318
1319/*!
1320\fn void QAbstractButton::clicked(bool checked)
1321
1322This signal is emitted when the button is activated (i.e. pressed down
1323then released while the mouse cursor is inside the button), when the
1324shortcut key is typed, or when click() or animateClick() is called.
1325Notably, this signal is \e not emitted if you call setDown(),
1326setChecked() or toggle().
1327
1328If the button is checkable, \a checked is true if the button is
1329checked, or false if the button is unchecked.
1330
1331\sa pressed(), released(), toggled()
1332*/
1333
1334/*!
1335\fn void QAbstractButton::toggled(bool checked)
1336
1337This signal is emitted whenever a checkable button changes its state.
1338\a checked is true if the button is checked, or false if the button is
1339unchecked.
1340
1341This may be the result of a user action, click() slot activation,
1342or because setChecked() was called.
1343
1344The states of buttons in exclusive button groups are updated before this
1345signal is emitted. This means that slots can act on either the "off"
1346signal or the "on" signal emitted by the buttons in the group whose
1347states have changed.
1348
1349For example, a slot that reacts to signals emitted by newly checked
1350buttons but which ignores signals from buttons that have been unchecked
1351can be implemented using the following pattern:
1352
1353\snippet doc/src/snippets/code/src_gui_widgets_qabstractbutton.cpp 2
1354
1355Button groups can be created using the QButtonGroup class, and
1356updates to the button states monitored with the
1357\l{QButtonGroup::buttonClicked()} signal.
1358
1359\sa checked, clicked()
1360*/
1361
1362/*!
1363 \property QAbstractButton::iconSize
1364 \brief the icon size used for this button.
1365
1366 The default size is defined by the GUI style. This is a maximum
1367 size for the icons. Smaller icons will not be scaled up.
1368*/
1369
1370QSize QAbstractButton::iconSize() const
1371{
1372 Q_D(const QAbstractButton);
1373 if (d->iconSize.isValid())
1374 return d->iconSize;
1375 int e = style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, this);
1376 return QSize(e, e);
1377}
1378
1379void QAbstractButton::setIconSize(const QSize &size)
1380{
1381 Q_D(QAbstractButton);
1382 if (d->iconSize == size)
1383 return;
1384
1385 d->iconSize = size;
1386 d->sizeHint = QSize();
1387 updateGeometry();
1388 if (isVisible()) {
1389 update();
1390 }
1391}
1392
1393
1394#ifdef QT3_SUPPORT
1395/*!
1396 Use icon() instead.
1397*/
1398QIcon *QAbstractButton::iconSet() const
1399{
1400 Q_D(const QAbstractButton);
1401 if (!d->icon.isNull())
1402 return const_cast<QIcon *>(&d->icon);
1403 return 0;
1404}
1405
1406/*!
1407 Use QAbstractButton(QWidget *) instead.
1408
1409 Call setObjectName() if you want to specify an object name, and
1410 setParent() if you want to set the window flags.
1411*/
1412QAbstractButton::QAbstractButton(QWidget *parent, const char *name, Qt::WindowFlags f)
1413 : QWidget(*new QAbstractButtonPrivate, parent, f)
1414{
1415 Q_D(QAbstractButton);
1416 setObjectName(QString::fromAscii(name));
1417 d->init();
1418}
1419
1420/*! \fn bool QAbstractButton::isOn() const
1421
1422 Use isChecked() instead.
1423*/
1424
1425/*!
1426 \fn QPixmap *QAbstractButton::pixmap() const
1427
1428 This compatibility function always returns 0.
1429
1430 Use icon() instead.
1431*/
1432
1433/*! \fn void QAbstractButton::setPixmap(const QPixmap &p)
1434
1435 Use setIcon() instead.
1436*/
1437
1438/*! \fn void QAbstractButton::setIconSet(const QIcon &icon)
1439
1440 Use setIcon() instead.
1441*/
1442
1443/*! \fn void QAbstractButton::setOn(bool b)
1444
1445 Use setChecked() instead.
1446*/
1447
1448/*! \fn bool QAbstractButton::isToggleButton() const
1449
1450 Use isCheckable() instead.
1451*/
1452
1453/*!
1454 \fn void QAbstractButton::setToggleButton(bool b)
1455
1456 Use setCheckable() instead.
1457*/
1458
1459/*! \fn void QAbstractButton::setAccel(const QKeySequence &key)
1460
1461 Use setShortcut() instead.
1462*/
1463
1464/*! \fn QKeySequence QAbstractButton::accel() const
1465
1466 Use shortcut() instead.
1467*/
1468#endif
1469
1470QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.