source: trunk/src/gui/widgets/qcommandlinkbutton.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 12.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 "qcommandlinkbutton.h"
43#include "qstylepainter.h"
44#include "qstyleoption.h"
45#include "qtextdocument.h"
46#include "qtextlayout.h"
47#include "qcolor.h"
48#include "qfont.h"
49
50#include "private/qpushbutton_p.h"
51
52QT_BEGIN_NAMESPACE
53
54/*!
55 \class QCommandLinkButton
56 \since 4.4
57 \brief The QCommandLinkButton widget provides a Vista style command link button.
58
59 \ingroup basicwidgets
60
61
62 The command link is a new control that was introduced by Windows Vista. It's
63 intended use is similar to that of a radio button in that it is used to choose
64 between a set of mutually exclusive options. Command link buttons should not
65 be used by themselves but rather as an alternative to radio buttons in
66 Wizards and dialogs and makes pressing the "next" button redundant.
67 The appearance is generally similar to that of a flat pushbutton, but
68 it allows for a descriptive text in addition to the normal button text.
69 By default it will also carry an arrow icon, indicating that pressing the
70 control will open another window or page.
71
72 \sa QPushButton QRadioButton
73*/
74
75/*!
76 \property QCommandLinkButton::description
77 \brief A descriptive label to complement the button text
78
79 Setting this property will set a descriptive text on the
80 button, complementing the text label. This will usually
81 be displayed in a smaller font than the primary text.
82*/
83
84/*!
85 \property QCommandLinkButton::flat
86 \brief This property determines whether the button is displayed as a flat
87 panel or with a border.
88
89 By default, this property is set to false.
90
91 \sa QPushButton::flat
92*/
93
94class QCommandLinkButtonPrivate : public QPushButtonPrivate
95{
96 Q_DECLARE_PUBLIC(QCommandLinkButton)
97
98public:
99 QCommandLinkButtonPrivate()
100 : QPushButtonPrivate(){}
101
102 void init();
103 qreal titleSize() const;
104 bool usingVistaStyle() const;
105
106 QFont titleFont() const;
107 QFont descriptionFont() const;
108
109 QRect titleRect() const;
110 QRect descriptionRect() const;
111
112 int textOffset() const;
113 int descriptionOffset() const;
114 int descriptionHeight(int width) const;
115 QColor mergedColors(const QColor &a, const QColor &b, int value) const;
116
117 int topMargin() const { return 10; }
118 int leftMargin() const { return 7; }
119 int rightMargin() const { return 4; }
120 int bottomMargin() const { return 4; }
121
122 QString description;
123 QColor currentColor;
124};
125
126// Mix colors a and b with a ratio in the range [0-255]
127QColor QCommandLinkButtonPrivate::mergedColors(const QColor &a, const QColor &b, int value = 50) const
128{
129 Q_ASSERT(value >= 0);
130 Q_ASSERT(value <= 255);
131 QColor tmp = a;
132 tmp.setRed((tmp.red() * value) / 255 + (b.red() * (255 - value)) / 255);
133 tmp.setGreen((tmp.green() * value) / 255 + (b.green() * (255 - value)) / 255);
134 tmp.setBlue((tmp.blue() * value) / 255 + (b.blue() * (255 - value)) / 255);
135 return tmp;
136}
137
138QFont QCommandLinkButtonPrivate::titleFont() const
139{
140 Q_Q(const QCommandLinkButton);
141 QFont font = q->font();
142 if (usingVistaStyle()) {
143 font.setPointSizeF(12.0);
144 } else {
145 font.setBold(true);
146 font.setPointSizeF(9.0);
147 }
148
149 // Note the font will be resolved against
150 // QPainters font, so we need to restore the mask
151 int resolve_mask = font.resolve_mask;
152 QFont modifiedFont = q->font().resolve(font);
153 modifiedFont.detach();
154 modifiedFont.resolve_mask = resolve_mask;
155 return modifiedFont;
156}
157
158QFont QCommandLinkButtonPrivate::descriptionFont() const
159{
160 Q_Q(const QCommandLinkButton);
161 QFont font = q->font();
162 font.setPointSizeF(9.0);
163
164 // Note the font will be resolved against
165 // QPainters font, so we need to restore the mask
166 int resolve_mask = font.resolve_mask;
167 QFont modifiedFont = q->font().resolve(font);
168 modifiedFont.detach();
169 modifiedFont.resolve_mask = resolve_mask;
170 return modifiedFont;
171}
172
173QRect QCommandLinkButtonPrivate::titleRect() const
174{
175 Q_Q(const QCommandLinkButton);
176 return q->rect().adjusted(textOffset(), topMargin(),
177 -rightMargin(), 0);
178}
179
180QRect QCommandLinkButtonPrivate::descriptionRect() const
181{
182 Q_Q(const QCommandLinkButton);
183 return q->rect().adjusted(textOffset(), descriptionOffset(),
184 -rightMargin(), -bottomMargin());
185}
186
187int QCommandLinkButtonPrivate::textOffset() const
188{
189 Q_Q(const QCommandLinkButton);
190 return q->icon().actualSize(q->iconSize()).width() + leftMargin() + 6;
191}
192
193int QCommandLinkButtonPrivate::descriptionOffset() const
194{
195 QFontMetrics fm(titleFont());
196 return topMargin() + fm.height();
197}
198
199bool QCommandLinkButtonPrivate::usingVistaStyle() const
200{
201 Q_Q(const QCommandLinkButton);
202 //### This is a hack to detect if we are indeed running Vista style themed and not in classic
203 // When we add api to query for this, we should change this implementation to use it.
204 return q->style()->inherits("QWindowsVistaStyle")
205 && !q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal);
206}
207
208void QCommandLinkButtonPrivate::init()
209{
210 Q_Q(QCommandLinkButton);
211 QPushButtonPrivate::init();
212 q->setAttribute(Qt::WA_Hover);
213
214 QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::PushButton);
215 policy.setHeightForWidth(true);
216 q->setSizePolicy(policy);
217
218 q->setIconSize(QSize(20, 20));
219 QStyleOptionButton opt;
220 q->initStyleOption(&opt);
221 q->setIcon(q->style()->standardIcon(QStyle::SP_CommandLink, &opt));
222}
223
224// Calculates the height of the description text based on widget width
225int QCommandLinkButtonPrivate::descriptionHeight(int widgetWidth) const
226{
227 // Calc width of actual paragraph
228 int lineWidth = widgetWidth - textOffset() - rightMargin();
229
230 qreal descriptionheight = 0;
231 if (!description.isEmpty()) {
232 QTextLayout layout(description);
233 layout.setFont(descriptionFont());
234 layout.beginLayout();
235 while (true) {
236 QTextLine line = layout.createLine();
237 if (!line.isValid())
238 break;
239 line.setLineWidth(lineWidth);
240 line.setPosition(QPointF(0, descriptionheight));
241 descriptionheight += line.height();
242 }
243 layout.endLayout();
244 }
245 return qRound(descriptionheight);
246}
247
248/*!
249 \reimp
250 */
251QSize QCommandLinkButton::minimumSizeHint() const
252{
253 Q_D(const QCommandLinkButton);
254 QSize size = sizeHint();
255 int minimumHeight = qMax(d->descriptionOffset() + d->bottomMargin(),
256 iconSize().height() + d->topMargin());
257 size.setHeight(minimumHeight);
258 return size;
259}
260
261/*!
262 Constructs a command link with no text and a \a parent.
263*/
264
265QCommandLinkButton::QCommandLinkButton(QWidget *parent)
266: QPushButton(*new QCommandLinkButtonPrivate, parent)
267{
268 Q_D(QCommandLinkButton);
269 d->init();
270}
271
272/*!
273 Constructs a command link with the parent \a parent and the text \a
274 text.
275*/
276
277QCommandLinkButton::QCommandLinkButton(const QString &text, QWidget *parent)
278 : QPushButton(*new QCommandLinkButtonPrivate, parent)
279{
280 Q_D(QCommandLinkButton);
281 setText(text);
282 d->init();
283}
284
285/*!
286 Constructs a command link with a \a text, a \a description, and a \a parent.
287*/
288QCommandLinkButton::QCommandLinkButton(const QString &text, const QString &description, QWidget *parent)
289 : QPushButton(*new QCommandLinkButtonPrivate, parent)
290{
291 Q_D(QCommandLinkButton);
292 setText(text);
293 setDescription(description);
294 d->init();
295}
296
297/*! \reimp */
298bool QCommandLinkButton::event(QEvent *e)
299{
300 return QPushButton::event(e);
301}
302
303/*! \reimp */
304QSize QCommandLinkButton::sizeHint() const
305{
306// Standard size hints from UI specs
307// Without note: 135, 41
308// With note: 135, 60
309 Q_D(const QCommandLinkButton);
310
311 QSize size = QPushButton::sizeHint();
312 QFontMetrics fm(d->titleFont());
313 int textWidth = qMax(fm.width(text()), 135);
314 int buttonWidth = textWidth + d->textOffset() + d->rightMargin();
315 int heightWithoutDescription = d->descriptionOffset() + d->bottomMargin();
316
317 size.setWidth(qMax(size.width(), buttonWidth));
318 size.setHeight(qMax(d->description.isEmpty() ? 41 : 60,
319 heightWithoutDescription + d->descriptionHeight(buttonWidth)));
320 return size;
321}
322
323/*! \reimp */
324int QCommandLinkButton::heightForWidth(int width) const
325{
326 Q_D(const QCommandLinkButton);
327 int heightWithoutDescription = d->descriptionOffset() + d->bottomMargin();
328 // find the width available for the description area
329 return qMax(heightWithoutDescription + d->descriptionHeight(width),
330 iconSize().height() + d->topMargin() + d->bottomMargin());
331}
332
333/*! \reimp */
334void QCommandLinkButton::paintEvent(QPaintEvent *)
335{
336 Q_D(QCommandLinkButton);
337 QStylePainter p(this);
338 p.save();
339
340 QStyleOptionButton option;
341 initStyleOption(&option);
342
343 //Enable command link appearence on Vista
344 option.features |= QStyleOptionButton::CommandLinkButton;
345 option.text = QString();
346 option.icon = QIcon(); //we draw this ourselves
347 QSize pixmapSize = icon().actualSize(iconSize());
348
349 int vOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical) : 0;
350 int hOffset = isDown() ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal) : 0;
351
352 //Draw icon
353 p.drawControl(QStyle::CE_PushButton, option);
354 if (!icon().isNull())
355 p.drawPixmap(d->leftMargin() + hOffset, d->topMargin() + vOffset,
356 icon().pixmap(pixmapSize, isEnabled() ? QIcon::Normal : QIcon::Disabled,
357 isChecked() ? QIcon::On : QIcon::Off));
358
359 //Draw title
360 QColor textColor = palette().buttonText().color();
361 if (isEnabled() && d->usingVistaStyle()) {
362 textColor = QColor(21, 28, 85);
363 if (underMouse() && !isDown())
364 textColor = QColor(7, 64, 229);
365 //A simple text color transition
366 d->currentColor = d->mergedColors(textColor, d->currentColor, 60);
367 option.palette.setColor(QPalette::ButtonText, d->currentColor);
368 }
369
370 int textflags = Qt::TextShowMnemonic;
371 if (!style()->styleHint(QStyle::SH_UnderlineShortcut, &option, this))
372 textflags |= Qt::TextHideMnemonic;
373
374 p.setFont(d->titleFont());
375 p.drawItemText(d->titleRect().translated(hOffset, vOffset),
376 textflags, option.palette, isEnabled(), text(), QPalette::ButtonText);
377
378 //Draw description
379 textflags |= Qt::TextWordWrap | Qt::ElideRight;
380 p.setFont(d->descriptionFont());
381 p.drawItemText(d->descriptionRect().translated(hOffset, vOffset), textflags,
382 option.palette, isEnabled(), description(), QPalette::ButtonText);
383 p.restore();
384}
385
386void QCommandLinkButton::setDescription(const QString &description)
387{
388 Q_D(QCommandLinkButton);
389 d->description = description;
390 updateGeometry();
391 update();
392}
393
394QString QCommandLinkButton::description() const
395{
396 Q_D(const QCommandLinkButton);
397 return d->description;
398}
399
400QT_END_NAMESPACE
401
Note: See TracBrowser for help on using the repository browser.