~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/widgets/qpushbutton.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the widgets module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qapplication.h"
 
30
#include "qbitmap.h"
 
31
#include "qdesktopwidget.h"
 
32
#include "qdialog.h"
 
33
#include <private/qdialog_p.h>
 
34
#include "qdrawutil.h"
 
35
#include "qevent.h"
 
36
#include "qfontmetrics.h"
 
37
#include "qmenu.h"
 
38
#include "qstylepainter.h"
 
39
#include "qpixmap.h"
 
40
#include "qpointer.h"
 
41
#include "qpushbutton.h"
 
42
#include "qstyle.h"
 
43
#include "qstyleoption.h"
 
44
#include "qtoolbar.h"
 
45
 
 
46
#ifndef QT_NO_ACCESSIBILITY
 
47
#include "qaccessible.h"
 
48
#endif
 
49
 
 
50
#include "private/qabstractbutton_p.h"
 
51
 
 
52
 
 
53
class QPushButtonPrivate : public QAbstractButtonPrivate
 
54
{
 
55
    Q_DECLARE_PUBLIC(QPushButton)
 
56
public:
 
57
    QPushButtonPrivate():autoDefault(true), defaultButton(false), flat(false){}
 
58
    void init();
 
59
    void popupPressed();
 
60
    QStyleOptionButton getStyleOption() const;
 
61
    QPointer<QMenu> menu;
 
62
    uint autoDefault : 1;
 
63
    uint defaultButton : 1;
 
64
    uint flat : 1;
 
65
};
 
66
 
 
67
/*!
 
68
    \class QPushButton qpushbutton.h
 
69
    \brief The QPushButton widget provides a command button.
 
70
 
 
71
    \ingroup basic
 
72
    \mainclass
 
73
 
 
74
    The push button, or command button, is perhaps the most commonly
 
75
    used widget in any graphical user interface. Push (click) a button
 
76
    to command the computer to perform some action, or to answer a
 
77
    question. Typical buttons are OK, Apply, Cancel, Close, Yes, No
 
78
    and Help.
 
79
 
 
80
    A command button is rectangular and typically displays a text
 
81
    label describing its action. An underlined character in the label
 
82
    (signified by preceding it with an ampersand in the text)
 
83
    indicates a shortcut key, e.g.
 
84
    \code
 
85
        QPushButton *pb = new QPushButton("&Download", this);
 
86
    \endcode
 
87
    In this example the shortcut is \e{Alt+D}, and the label text
 
88
    will be displayed as \bold{\underline{D}ownload}.
 
89
 
 
90
    Push buttons display a textual label, and optionally a small
 
91
    icon. These can be set using the constructors and changed later
 
92
    using setText() and setIcon().  If the button is disabled the
 
93
    appearance of the text and icon will be manipulated with respect
 
94
    to the GUI style to make the button look "disabled".
 
95
 
 
96
    A push button emits the signal clicked() when it is activated by
 
97
    the mouse, the Spacebar or by a keyboard shortcut. Connect to
 
98
    this signal to perform the button's action. Push buttons also
 
99
    provide less commonly used signals, for example, pressed() and
 
100
    released().
 
101
 
 
102
    Command buttons in dialogs are by default auto-default buttons,
 
103
    i.e. they become the default push button automatically when they
 
104
    receive the keyboard input focus. A default button is a push
 
105
    button that is activated when the user presses the Enter or Return
 
106
    key in a dialog. You can change this with setAutoDefault(). Note
 
107
    that auto-default buttons reserve a little extra space which is
 
108
    necessary to draw a default-button indicator. If you do not want
 
109
    this space around your buttons, call setAutoDefault(false).
 
110
 
 
111
    Being so central, the button widget has grown to accommodate a
 
112
    great many variations in the past decade. The Microsoft style
 
113
    guide now shows about ten different states of Windows push buttons
 
114
    and the text implies that there are dozens more when all the
 
115
    combinations of features are taken into consideration.
 
116
 
 
117
    The most important modes or states are:
 
118
    \list
 
119
    \i Available or not (grayed out, disabled).
 
120
    \i Standard push button, toggling push button or menu button.
 
121
    \i On or off (only for toggling push buttons).
 
122
    \i Default or normal. The default button in a dialog can generally
 
123
       be "clicked" using the Enter or Return key.
 
124
    \i Auto-repeat or not.
 
125
    \i Pressed down or not.
 
126
    \endlist
 
127
 
 
128
    As a general rule, use a push button when the application or
 
129
    dialog window performs an action when the user clicks on it (such
 
130
    as Apply, Cancel, Close and Help) \e and when the widget is
 
131
    supposed to have a wide, rectangular shape with a text label.
 
132
    Small, typically square buttons that change the state of the
 
133
    window rather than performing an action (such as the buttons in
 
134
    the top-right corner of the QFileDialog) are not command buttons,
 
135
    but tool buttons. Qt provides a special class (QToolButton) for
 
136
    these buttons.
 
137
 
 
138
    If you need toggle behavior (see setCheckable()) or a button
 
139
    that auto-repeats the activation signal when being pushed down
 
140
    like the arrows in a scroll bar (see setAutoRepeat()), a command
 
141
    button is probably not what you want. When in doubt, use a tool
 
142
    button.
 
143
 
 
144
    A variation of a command button is a menu button. These provide
 
145
    not just one command, but several, since when they are clicked
 
146
    they pop up a menu of options. Use the method setMenu() to
 
147
    associate a popup menu with a push button.
 
148
 
 
149
    Other classes of buttons are option buttons (see QRadioButton) and
 
150
    check boxes (see QCheckBox).
 
151
 
 
152
    \inlineimage macintosh-pushbutton.png Screenshot in Macintosh style
 
153
    \inlineimage windows-pushbutton.png Screenshot in Windows style
 
154
 
 
155
    In Qt, the QAbstractButton base class provides most of the modes
 
156
    and other API, and QPushButton provides GUI logic.
 
157
    See QAbstractButton for more information about the API.
 
158
 
 
159
    \sa QToolButton, QRadioButton, QCheckBox, {fowler}{GUI Design Handbook: Push Button}
 
160
*/
 
161
 
 
162
/*!
 
163
    \property QPushButton::autoDefault
 
164
    \brief whether the push button is the auto default button
 
165
 
 
166
    If this property is set to true then the push button is the auto
 
167
    default button in a dialog.
 
168
 
 
169
    In some GUI styles a default button is drawn with an extra frame
 
170
    around it, up to 3 pixels or more. Qt automatically keeps this
 
171
    space free around auto-default buttons, i.e. auto-default buttons
 
172
    may have a slightly larger size hint.
 
173
 
 
174
    This property's default is true for buttons that have a QDialog
 
175
    parent; otherwise it defaults to false.
 
176
 
 
177
    See the \l default property for details of how \l default and
 
178
    auto-default interact.
 
179
*/
 
180
 
 
181
/*!
 
182
    \property QPushButton::default
 
183
    \brief whether the push button is the default button
 
184
 
 
185
    If this property is set to true then the push button will be
 
186
    pressed if the user presses the Enter (or Return) key in a dialog.
 
187
 
 
188
    Regardless of focus, if the user presses Enter: If there is a
 
189
    default button the default button is pressed; otherwise, if
 
190
    there are one or more \l autoDefault buttons the first \l autoDefault
 
191
    button that is next in the tab order is pressed. If there are no
 
192
    default or \l autoDefault buttons only pressing Space on a button
 
193
    with focus, mouse clicking, or using a shortcut will press a
 
194
    button.
 
195
 
 
196
    In a dialog, only one push button at a time can be the default
 
197
    button. This button is then displayed with an additional frame
 
198
    (depending on the GUI style).
 
199
 
 
200
    The default button behavior is provided only in dialogs. Buttons
 
201
    can always be clicked from the keyboard by pressing Enter (or
 
202
    Return) or the Spacebar when the button has focus.
 
203
 
 
204
    This property's default is false.
 
205
*/
 
206
 
 
207
/*!
 
208
    \property QPushButton::flat
 
209
    \brief whether the border is disabled
 
210
 
 
211
    This property's default is false.
 
212
*/
 
213
 
 
214
 
 
215
 
 
216
/*!
 
217
    Constructs a push button with no text and a \a parent.
 
218
*/
 
219
 
 
220
QPushButton::QPushButton(QWidget *parent)
 
221
    : QAbstractButton(*new QPushButtonPrivate, parent)
 
222
{
 
223
    Q_D(QPushButton);
 
224
    d->init();
 
225
}
 
226
 
 
227
/*!
 
228
    Constructs a push button with the parent \a parent and the text \a
 
229
    text.
 
230
*/
 
231
 
 
232
QPushButton::QPushButton(const QString &text, QWidget *parent)
 
233
    : QAbstractButton(*new QPushButtonPrivate, parent)
 
234
{
 
235
    Q_D(QPushButton);
 
236
    d->init();
 
237
    setText(text);
 
238
}
 
239
 
 
240
 
 
241
/*!
 
242
    Constructs a push button with an \a icon and a \a text, and a \a parent.
 
243
 
 
244
    Note that you can also pass a QPixmap object as an icon (thanks to
 
245
    the implicit type conversion provided by C++).
 
246
 
 
247
*/
 
248
QPushButton::QPushButton(const QIcon& icon, const QString &text, QWidget *parent)
 
249
    : QAbstractButton(*new QPushButtonPrivate, parent)
 
250
{
 
251
    Q_D(QPushButton);
 
252
    d->init();
 
253
    setText(text);
 
254
    setIcon(icon);
 
255
}
 
256
 
 
257
 
 
258
/*!
 
259
    Destroys the push button.
 
260
*/
 
261
QPushButton::~QPushButton()
 
262
{
 
263
}
 
264
 
 
265
void QPushButtonPrivate::init()
 
266
{
 
267
    Q_Q(QPushButton);
 
268
#ifndef QT_NO_DIALOG
 
269
    autoDefault = (qobject_cast<QDialog*>(q->window()) != 0);
 
270
#endif
 
271
    q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
 
272
}
 
273
 
 
274
QStyleOptionButton QPushButtonPrivate::getStyleOption() const
 
275
{
 
276
    Q_Q(const QPushButton);
 
277
    QStyleOptionButton opt;
 
278
    opt.init(q);
 
279
    opt.features = QStyleOptionButton::None;
 
280
    if (flat)
 
281
        opt.features |= QStyleOptionButton::Flat;
 
282
    if (menu)
 
283
        opt.features |= QStyleOptionButton::HasMenu;
 
284
    if (autoDefault || defaultButton)
 
285
        opt.features |= QStyleOptionButton::AutoDefaultButton;
 
286
    if (defaultButton)
 
287
        opt.features |= QStyleOptionButton::DefaultButton;
 
288
    if (down)
 
289
        opt.state |= QStyle::State_Sunken;
 
290
    if (checked)
 
291
        opt.state |= QStyle::State_On;
 
292
    if (!flat && !down)
 
293
        opt.state |= QStyle::State_Raised;
 
294
    opt.text = text;
 
295
    opt.icon = icon;
 
296
    opt.iconSize = q->iconSize();
 
297
    return opt;
 
298
}
 
299
 
 
300
void QPushButton::setAutoDefault(bool enable)
 
301
{
 
302
    Q_D(QPushButton);
 
303
    if (d->autoDefault == enable)
 
304
        return;
 
305
    d->autoDefault = enable;
 
306
    update();
 
307
    updateGeometry();
 
308
}
 
309
 
 
310
bool QPushButton::autoDefault() const
 
311
{
 
312
    Q_D(const QPushButton);
 
313
    return d->autoDefault;
 
314
}
 
315
 
 
316
void QPushButton::setDefault(bool enable)
 
317
{
 
318
    Q_D(QPushButton);
 
319
    if (d->defaultButton == enable)
 
320
        return;
 
321
    d->defaultButton = enable;
 
322
#ifndef QT_NO_DIALOG
 
323
    if (d->defaultButton) {
 
324
        QDialog *dlg = qobject_cast<QDialog*>(window());
 
325
        if (dlg)
 
326
            dlg->d_func()->setMainDefault(this);
 
327
    }
 
328
#endif
 
329
    update();
 
330
#ifndef QT_NO_ACCESSIBILITY
 
331
    QAccessible::updateAccessibility(this, 0, QAccessible::StateChanged);
 
332
#endif
 
333
}
 
334
 
 
335
bool QPushButton::isDefault() const
 
336
{
 
337
    Q_D(const QPushButton);
 
338
    return d->defaultButton;
 
339
}
 
340
 
 
341
/*!
 
342
    \reimp
 
343
*/
 
344
QSize QPushButton::sizeHint() const
 
345
{
 
346
    Q_D(const QPushButton);
 
347
    ensurePolished();
 
348
 
 
349
    int w = 0, h = 0;
 
350
 
 
351
    QStyleOptionButton opt = d->getStyleOption();
 
352
 
 
353
    // calculate contents size...
 
354
#ifndef QT_NO_ICON
 
355
    if (!icon().isNull()) {
 
356
        int ih = opt.iconSize.height();
 
357
        int iw = opt.iconSize.width() + 4;
 
358
        w += iw;
 
359
        h = qMax(h, ih);
 
360
    }
 
361
#endif
 
362
    if (menu())
 
363
        w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
 
364
    QString s(text());
 
365
    bool empty = s.isEmpty();
 
366
    if (empty)
 
367
        s = QString::fromLatin1("XXXX");
 
368
    QFontMetrics fm = fontMetrics();
 
369
    QSize sz = fm.size(Qt::TextShowMnemonic, s);
 
370
    if(!empty || !w)
 
371
        w += sz.width();
 
372
    if(!empty || !h)
 
373
        h = qMax(h, sz.height());
 
374
    return (style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(w, h), this).
 
375
            expandedTo(QApplication::globalStrut()));
 
376
}
 
377
 
 
378
 
 
379
 
 
380
/*!\reimp
 
381
*/
 
382
void QPushButton::paintEvent(QPaintEvent *)
 
383
{
 
384
    Q_D(QPushButton);
 
385
    QStylePainter p(this);
 
386
    p.drawControl(QStyle::CE_PushButton, d->getStyleOption());
 
387
}
 
388
 
 
389
 
 
390
/*! \reimp */
 
391
void QPushButton::keyPressEvent(QKeyEvent *e)
 
392
{
 
393
    Q_D(QPushButton);
 
394
    switch (e->key()) {
 
395
    case Qt::Key_Enter:
 
396
    case Qt::Key_Return:
 
397
        if (d->autoDefault || d->defaultButton) {
 
398
            click();
 
399
            break;
 
400
        }
 
401
        // fall through
 
402
    default:
 
403
        QAbstractButton::keyPressEvent(e);
 
404
    }
 
405
}
 
406
 
 
407
/*!
 
408
    \reimp
 
409
*/
 
410
void QPushButton::focusInEvent(QFocusEvent *e)
 
411
{
 
412
    Q_D(QPushButton);
 
413
    if (e->reason() != Qt::PopupFocusReason && d->autoDefault && !d->defaultButton) {
 
414
        d->defaultButton = true;
 
415
#ifndef QT_NO_DIALOG
 
416
        QDialog *dlg = qobject_cast<QDialog*>(window());
 
417
        if (dlg)
 
418
            dlg->d_func()->setDefault(this);
 
419
#endif
 
420
    }
 
421
    QAbstractButton::focusInEvent(e);
 
422
}
 
423
 
 
424
/*!
 
425
    \reimp
 
426
*/
 
427
void QPushButton::focusOutEvent(QFocusEvent *e)
 
428
{
 
429
    Q_D(QPushButton);
 
430
    if (e->reason() != Qt::PopupFocusReason && d->autoDefault && d->defaultButton) {
 
431
#ifndef QT_NO_DIALOG
 
432
        QDialog *dlg = qobject_cast<QDialog*>(window());
 
433
        if (dlg)
 
434
            dlg->d_func()->setDefault(0);
 
435
        else
 
436
#endif
 
437
            d->defaultButton = false;
 
438
    }
 
439
 
 
440
    QAbstractButton::focusOutEvent(e);
 
441
    if (d->menu && d->menu->isVisible())        // restore pressed status
 
442
        setDown(true);
 
443
}
 
444
 
 
445
 
 
446
/*!
 
447
    Associates the popup menu \a menu with this push button. This
 
448
    turns the button into a menu button, which in some styles will
 
449
    produce a small triangle to the right of the button's text.
 
450
 
 
451
    Ownership of the menu is \e not transferred to the push button.
 
452
 
 
453
    \sa menu()
 
454
*/
 
455
void QPushButton::setMenu(QMenu* menu)
 
456
{
 
457
    Q_D(QPushButton);
 
458
    if (menu && !d->menu) {
 
459
        disconnect(this, SIGNAL(pressed()), this, SLOT(popupPressed()));
 
460
        connect(this, SIGNAL(pressed()), this, SLOT(popupPressed()));
 
461
    }
 
462
    d->menu = menu;
 
463
    update();
 
464
    updateGeometry();
 
465
}
 
466
 
 
467
/*!
 
468
    Returns the button's associated popup menu or 0 if no popup menu
 
469
    has been set.
 
470
 
 
471
    \sa setMenu()
 
472
*/
 
473
QMenu* QPushButton::menu() const
 
474
{
 
475
    Q_D(const QPushButton);
 
476
    return d->menu;
 
477
}
 
478
 
 
479
/*!
 
480
    Shows (pops up) the associated popup menu. If there is no such
 
481
    menu, this function does nothing. This function does not return
 
482
    until the popup menu has been closed by the user.
 
483
*/
 
484
void QPushButton::showMenu()
 
485
{
 
486
    Q_D(QPushButton);
 
487
    if (!d || !d->menu)
 
488
        return;
 
489
    setDown(true);
 
490
    d->popupPressed();
 
491
}
 
492
 
 
493
void QPushButtonPrivate::popupPressed()
 
494
{
 
495
    Q_Q(QPushButton);
 
496
    if (!down || !menu)
 
497
        return;
 
498
 
 
499
    menu->setNoReplayFor(q);
 
500
    bool horizontal = true;
 
501
#if !defined(QT_NO_TOOLBAR)
 
502
    QToolBar *tb = qobject_cast<QToolBar*>(q->parentWidget());
 
503
    if (tb && tb->orientation() == Qt::Vertical)
 
504
        horizontal = false;
 
505
#endif
 
506
    QRect rect = q->rect();
 
507
    QSize menuSize = menu->sizeHint();
 
508
    QPoint globalPos = q->mapToGlobal(rect.topLeft());
 
509
    int x = globalPos.x();
 
510
    int y = globalPos.y();
 
511
    if (horizontal) {
 
512
        if (globalPos.y() + rect.height() + menuSize.height() <= qApp->desktop()->height()) {
 
513
            y += rect.height();
 
514
        } else {
 
515
            y -= menuSize.height();
 
516
        }
 
517
        if (q->layoutDirection() == Qt::RightToLeft)
 
518
            x += rect.width() - menuSize.width();
 
519
    } else {
 
520
        if (globalPos.x() + rect.width() + menu->sizeHint().width() <= qApp->desktop()->width())
 
521
            x += rect.width();
 
522
        else
 
523
            x -= menuSize.width();
 
524
    }
 
525
    QObject *guard = q;
 
526
    QMetaObject::addGuard(&guard);
 
527
    menu->exec(QPoint(x, y));
 
528
    if (guard)
 
529
        q->setDown(false);
 
530
    QMetaObject::removeGuard(&guard);
 
531
 
 
532
}
 
533
 
 
534
void QPushButton::setFlat(bool flat)
 
535
{
 
536
    Q_D(QPushButton);
 
537
    if (d->flat == flat)
 
538
        return;
 
539
    d->flat = flat;
 
540
    update();
 
541
    updateGeometry();
 
542
}
 
543
 
 
544
bool QPushButton::isFlat() const
 
545
{
 
546
    Q_D(const QPushButton);
 
547
    return d->flat;
 
548
}
 
549
 
 
550
#ifdef QT3_SUPPORT
 
551
/*!
 
552
    Use one of the constructors that doesn't take the \a name
 
553
    argument and then use setObjectName() instead.
 
554
*/
 
555
QPushButton::QPushButton(QWidget *parent, const char *name)
 
556
    : QAbstractButton(*new QPushButtonPrivate, parent)
 
557
{
 
558
    Q_D(QPushButton);
 
559
    setObjectName(name);
 
560
    d->init();
 
561
}
 
562
 
 
563
/*!
 
564
    Use one of the constructors that doesn't take the \a name
 
565
    argument and then use setObjectName() instead.
 
566
*/
 
567
QPushButton::QPushButton(const QString &text, QWidget *parent, const char *name)
 
568
    : QAbstractButton(*new QPushButtonPrivate, parent)
 
569
{
 
570
    Q_D(QPushButton);
 
571
    setObjectName(name);
 
572
    d->init();
 
573
    setText(text);
 
574
}
 
575
 
 
576
/*!
 
577
    Use one of the constructors that doesn't take the \a name
 
578
    argument and then use setObjectName() instead.
 
579
*/
 
580
QPushButton::QPushButton(const QIcon& icon, const QString &text, QWidget *parent, const char *name)
 
581
    : QAbstractButton(*new QPushButtonPrivate, parent)
 
582
{
 
583
    Q_D(QPushButton);
 
584
    setObjectName(name);
 
585
    d->init();
 
586
    setText(text);
 
587
    setIcon(icon);
 
588
}
 
589
#endif
 
590
 
 
591
/*!
 
592
    \fn void QPushButton::openPopup()
 
593
 
 
594
    Use showMenu() instead.
 
595
*/
 
596
 
 
597
/*!
 
598
    \fn bool QPushButton::isMenuButton() const
 
599
 
 
600
    Use menu() != 0 instead.
 
601
*/
 
602
 
 
603
/*!
 
604
    \fn void QPushButton::setPopup(QMenu* popup)
 
605
 
 
606
    Use setMenu() instead.
 
607
*/
 
608
 
 
609
/*!
 
610
    \fn QMenu* QPushButton::popup() const
 
611
 
 
612
    Use menu() instead.
 
613
*/
 
614
 
 
615
 
 
616
#include "moc_qpushbutton.cpp"