Ok, the long awaited config wizard is here (at least in a very basic state). There...
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / gui / qxtpushbutton.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
4 **
5 ** This file is part of the QxtGui module of the Qt eXTension library
6 **
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
9 ** IBM.
10 **
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
15 **
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
20 **
21 ** <http://libqxt.sourceforge.net>  <foundation@libqxt.org>
22 **
23 ****************************************************************************/
24 #include "qxtpushbutton.h"
25 #include <QAbstractTextDocumentLayout>
26 #include <QStyleOptionButton>
27 #include <QTextDocument>
28 #include <QStylePainter>
29 #include <QStyle>
30 #include <QMenu>
31
32 static const int Vertical_Mask = 0x02;
33
34 class QxtPushButtonPrivate : public QxtPrivate<QxtPushButton>
35 {
36 public:
37     QXT_DECLARE_PUBLIC(QxtPushButton);
38     QxtPushButtonPrivate();
39
40     bool isRichText() const;
41     QStyleOptionButton getStyleOption() const;
42
43     QString text;
44     Qxt::Rotation rot;
45     Qt::TextFormat format;
46     mutable QTextDocument* doc;
47 };
48
49 QxtPushButtonPrivate::QxtPushButtonPrivate() :
50         rot(Qxt::NoRotation), format(Qt::PlainText), doc(0)
51 {}
52
53 bool QxtPushButtonPrivate::isRichText() const
54 {
55 #if QT_VERSION >= 0x040200
56     bool rich = (format == Qt::RichText) || (format == Qt::AutoText && Qt::mightBeRichText(qxt_p().text()));
57     if (rich && !doc)
58     {
59         doc = new QTextDocument(const_cast<QxtPushButton*>(&qxt_p()));
60         doc->setUndoRedoEnabled(false);
61     }
62 #else // QT_VERSION < 0x040200
63     bool rich = false;
64 #endif // QT_VERSION
65     return rich;
66 }
67
68 QStyleOptionButton QxtPushButtonPrivate::getStyleOption() const
69 {
70     QStyleOptionButton option;
71     option.initFrom(&qxt_p());
72     if (rot & Vertical_Mask)
73     {
74         QSize size = option.rect.size();
75         size.transpose();
76         option.rect.setSize(size);
77     }
78     option.features = QStyleOptionButton::None;
79     if (qxt_p().isFlat())
80         option.features |= QStyleOptionButton::Flat;
81     if (qxt_p().menu())
82         option.features |= QStyleOptionButton::HasMenu;
83     if (qxt_p().autoDefault() || qxt_p().isDefault())
84         option.features |= QStyleOptionButton::AutoDefaultButton;
85     if (qxt_p().isDefault())
86         option.features |= QStyleOptionButton::DefaultButton;
87     if (qxt_p().isDown() || (qxt_p().menu() && qxt_p().menu()->isVisible()))
88         option.state |= QStyle::State_Sunken;
89     if (qxt_p().isChecked())
90         option.state |= QStyle::State_On;
91     if (!qxt_p().isFlat() && !qxt_p().isDown())
92         option.state |= QStyle::State_Raised;
93     if (!isRichText())
94     {
95         option.text = qxt_p().text();
96         option.icon = qxt_p().icon();
97         option.iconSize = qxt_p().iconSize();
98     }
99     return option;
100 }
101
102 /*!
103     \class QxtPushButton QxtPushButton
104     \ingroup QxtGui
105     \brief An extended QPushButton with rotation and rich text support.
106
107     QxtPushButton is a QPushButton which can be rotated. In addition, QxtPushButton
108     provides rich text support.
109
110     \image html qxtpushbutton.png "QxtPushButton in action."
111  */
112
113 /*!
114     Constructs a new QxtPushButton with \a parent.
115  */
116 QxtPushButton::QxtPushButton(QWidget* parent) : QPushButton(parent)
117 {
118     QXT_INIT_PRIVATE(QxtPushButton);
119 }
120
121 /*!
122     Constructs a new QxtPushButton with \a text and \a parent.
123  */
124 QxtPushButton::QxtPushButton(const QString& text, QWidget* parent) : QPushButton(text, parent)
125 {
126     QXT_INIT_PRIVATE(QxtPushButton);
127 }
128
129 /*!
130     Constructs a new QxtPushButton with \a icon, \a text and \a parent.
131
132     \note An icon is not rendered when using rich text.
133  */
134 QxtPushButton::QxtPushButton(const QIcon& icon, const QString& text, QWidget* parent) : QPushButton(icon, text, parent)
135 {
136     QXT_INIT_PRIVATE(QxtPushButton);
137 }
138
139 /*!
140     Constructs a new QxtPushButton with \a rotation, \a text and \a parent.
141  */
142 QxtPushButton::QxtPushButton(Qxt::Rotation rotation, const QString& text, QWidget* parent) : QPushButton(text, parent)
143 {
144     QXT_INIT_PRIVATE(QxtPushButton);
145     setRotation(rotation);
146 }
147
148 /*!
149     Destructs the button.
150  */
151 QxtPushButton::~QxtPushButton()
152 {}
153
154 /*!
155     \property QxtPushButton::rotation
156     \brief This property holds the rotation of the button
157
158     The button is rotated according to this property.
159     The default value is \b Qxt::NoRotation.
160
161     \sa Qxt::Rotation
162  */
163 Qxt::Rotation QxtPushButton::rotation() const
164 {
165     return qxt_d().rot;
166 }
167
168 void QxtPushButton::setRotation(Qxt::Rotation rotation)
169 {
170     if (qxt_d().rot != rotation)
171     {
172         qxt_d().rot = rotation;
173         switch (rotation)
174         {
175         case Qxt::NoRotation:
176         case Qxt::UpsideDown:
177             setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
178             break;
179
180         case Qxt::Clockwise:
181         case Qxt::CounterClockwise:
182             setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
183             break;
184
185         default:
186             // nothing to do
187             break;
188         }
189         updateGeometry();
190         update();
191     }
192 }
193
194 /*!
195     \property QxtPushButton::textFormat
196     \brief This property holds the text format of the button
197
198     Supported formats are \b Qt::PlainText, \b Qt::RichText and \b Qt::AutoText.
199
200     The default format is \b Qt::PlainText.
201
202     \note Rich text requires Qt 4.2 or newer.
203
204     \sa Qt::TextFormat
205  */
206 Qt::TextFormat QxtPushButton::textFormat() const
207 {
208     return qxt_d().format;
209 }
210
211 void QxtPushButton::setTextFormat(Qt::TextFormat format)
212 {
213     if (qxt_d().format != format)
214     {
215         qxt_d().format = format;
216         if (!qxt_d().isRichText())
217         {
218             delete qxt_d().doc;
219             qxt_d().doc = 0;
220         }
221         qxt_d().text.clear();
222         update();
223         updateGeometry();
224     }
225 }
226
227 QSize QxtPushButton::sizeHint() const
228 {
229     QSize size;
230     if (qxt_d().isRichText())
231         size = qxt_d().doc->documentLayout()->documentSize().toSize();
232     else
233         size = QPushButton::sizeHint();
234
235     if (qxt_d().rot & Vertical_Mask)
236         size.transpose();
237     return size;
238 }
239
240 QSize QxtPushButton::minimumSizeHint() const
241 {
242     QSize size;
243     if (qxt_d().isRichText())
244         size = qxt_d().doc->documentLayout()->documentSize().toSize();
245     else
246         size = QPushButton::minimumSizeHint();
247
248     if (qxt_d().rot & Vertical_Mask)
249         size.transpose();
250     return size;
251 }
252
253 void QxtPushButton::paintEvent(QPaintEvent* event)
254 {
255     Q_UNUSED(event);
256
257     // the only reliable way to detect text changes
258     if (text() != qxt_d().text)
259     {
260         qxt_d().text = text();
261         if (qxt_d().isRichText())
262             qxt_d().doc->setHtml(qxt_d().text);
263         updateGeometry();
264     }
265
266     QStylePainter painter(this);
267     painter.rotate(qxt_d().rot);
268     switch (qxt_d().rot)
269     {
270     case Qxt::UpsideDown:
271         painter.translate(-width(), -height());
272         break;
273
274     case Qxt::Clockwise:
275         painter.translate(0, -width());
276         break;
277
278     case Qxt::CounterClockwise:
279         painter.translate(-height(), 0);
280         break;
281
282     default:
283         // nothing to do
284         break;
285     }
286
287     const QStyleOptionButton option = qxt_d().getStyleOption();
288     painter.drawControl(QStyle::CE_PushButton, option);
289
290 #if QT_VERSION >= 0x040200
291     if (qxt_d().isRichText())
292     {
293         int dx = 0;
294         int dy = 0;
295         if (option.state & (QStyle::State_On | QStyle::State_Sunken))
296         {
297             dx += style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option, this);
298             dy += style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option, this);
299         }
300
301         QRect area = rect();
302         const QSizeF docSize = qxt_d().doc->documentLayout()->documentSize();
303         if (qxt_d().rot & Vertical_Mask)
304         {
305             dx += static_cast<int>((height() - docSize.width())  / 2);
306             dy += static_cast<int>((width()  - docSize.height()) / 2);
307             painter.translate(dx, dy);
308
309             QSize size = area.size();
310             size.transpose();
311             area.setSize(size);
312         }
313         else
314         {
315             dx += static_cast<int>((width()  - docSize.width())  / 2);
316             dy += static_cast<int>((height() - docSize.height()) / 2);
317             painter.translate(dx, dy);
318         }
319         qxt_d().doc->drawContents(&painter, area);
320     }
321 #endif // QT_VERSION
322 }