--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) Qxt Foundation. Some rights reserved.
+**
+** This file is part of the QxtGui module of the Qt eXTension library
+**
+** This library is free software; you can redistribute it and/or modify it
+** under the terms of th Common Public License, version 1.0, as published by
+** IBM.
+**
+** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
+** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
+** FITNESS FOR A PARTICULAR PURPOSE.
+**
+** You should have received a copy of the CPL along with this file.
+** See the LICENSE file and the cpl1.0.txt file included with the source
+** distribution for more information. If you did not receive a copy of the
+** license, contact the Qxt Foundation.
+**
+** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
+**
+****************************************************************************/
+#include "qxtpushbutton.h"
+#include <QAbstractTextDocumentLayout>
+#include <QStyleOptionButton>
+#include <QTextDocument>
+#include <QStylePainter>
+#include <QStyle>
+#include <QMenu>
+
+static const int Vertical_Mask = 0x02;
+
+class QxtPushButtonPrivate : public QxtPrivate<QxtPushButton>
+{
+public:
+ QXT_DECLARE_PUBLIC(QxtPushButton);
+ QxtPushButtonPrivate();
+
+ bool isRichText() const;
+ QStyleOptionButton getStyleOption() const;
+
+ QString text;
+ Qxt::Rotation rot;
+ Qt::TextFormat format;
+ mutable QTextDocument* doc;
+};
+
+QxtPushButtonPrivate::QxtPushButtonPrivate() :
+ rot(Qxt::NoRotation), format(Qt::PlainText), doc(0)
+{}
+
+bool QxtPushButtonPrivate::isRichText() const
+{
+#if QT_VERSION >= 0x040200
+ bool rich = (format == Qt::RichText) || (format == Qt::AutoText && Qt::mightBeRichText(qxt_p().text()));
+ if (rich && !doc)
+ {
+ doc = new QTextDocument(const_cast<QxtPushButton*>(&qxt_p()));
+ doc->setUndoRedoEnabled(false);
+ }
+#else // QT_VERSION < 0x040200
+ bool rich = false;
+#endif // QT_VERSION
+ return rich;
+}
+
+QStyleOptionButton QxtPushButtonPrivate::getStyleOption() const
+{
+ QStyleOptionButton option;
+ option.initFrom(&qxt_p());
+ if (rot & Vertical_Mask)
+ {
+ QSize size = option.rect.size();
+ size.transpose();
+ option.rect.setSize(size);
+ }
+ option.features = QStyleOptionButton::None;
+ if (qxt_p().isFlat())
+ option.features |= QStyleOptionButton::Flat;
+ if (qxt_p().menu())
+ option.features |= QStyleOptionButton::HasMenu;
+ if (qxt_p().autoDefault() || qxt_p().isDefault())
+ option.features |= QStyleOptionButton::AutoDefaultButton;
+ if (qxt_p().isDefault())
+ option.features |= QStyleOptionButton::DefaultButton;
+ if (qxt_p().isDown() || (qxt_p().menu() && qxt_p().menu()->isVisible()))
+ option.state |= QStyle::State_Sunken;
+ if (qxt_p().isChecked())
+ option.state |= QStyle::State_On;
+ if (!qxt_p().isFlat() && !qxt_p().isDown())
+ option.state |= QStyle::State_Raised;
+ if (!isRichText())
+ {
+ option.text = qxt_p().text();
+ option.icon = qxt_p().icon();
+ option.iconSize = qxt_p().iconSize();
+ }
+ return option;
+}
+
+/*!
+ \class QxtPushButton QxtPushButton
+ \ingroup QxtGui
+ \brief An extended QPushButton with rotation and rich text support.
+
+ QxtPushButton is a QPushButton which can be rotated. In addition, QxtPushButton
+ provides rich text support.
+
+ \image html qxtpushbutton.png "QxtPushButton in action."
+ */
+
+/*!
+ Constructs a new QxtPushButton with \a parent.
+ */
+QxtPushButton::QxtPushButton(QWidget* parent) : QPushButton(parent)
+{
+ QXT_INIT_PRIVATE(QxtPushButton);
+}
+
+/*!
+ Constructs a new QxtPushButton with \a text and \a parent.
+ */
+QxtPushButton::QxtPushButton(const QString& text, QWidget* parent) : QPushButton(text, parent)
+{
+ QXT_INIT_PRIVATE(QxtPushButton);
+}
+
+/*!
+ Constructs a new QxtPushButton with \a icon, \a text and \a parent.
+
+ \note An icon is not rendered when using rich text.
+ */
+QxtPushButton::QxtPushButton(const QIcon& icon, const QString& text, QWidget* parent) : QPushButton(icon, text, parent)
+{
+ QXT_INIT_PRIVATE(QxtPushButton);
+}
+
+/*!
+ Constructs a new QxtPushButton with \a rotation, \a text and \a parent.
+ */
+QxtPushButton::QxtPushButton(Qxt::Rotation rotation, const QString& text, QWidget* parent) : QPushButton(text, parent)
+{
+ QXT_INIT_PRIVATE(QxtPushButton);
+ setRotation(rotation);
+}
+
+/*!
+ Destructs the button.
+ */
+QxtPushButton::~QxtPushButton()
+{}
+
+/*!
+ \property QxtPushButton::rotation
+ \brief This property holds the rotation of the button
+
+ The button is rotated according to this property.
+ The default value is \b Qxt::NoRotation.
+
+ \sa Qxt::Rotation
+ */
+Qxt::Rotation QxtPushButton::rotation() const
+{
+ return qxt_d().rot;
+}
+
+void QxtPushButton::setRotation(Qxt::Rotation rotation)
+{
+ if (qxt_d().rot != rotation)
+ {
+ qxt_d().rot = rotation;
+ switch (rotation)
+ {
+ case Qxt::NoRotation:
+ case Qxt::UpsideDown:
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ break;
+
+ case Qxt::Clockwise:
+ case Qxt::CounterClockwise:
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
+ break;
+
+ default:
+ // nothing to do
+ break;
+ }
+ updateGeometry();
+ update();
+ }
+}
+
+/*!
+ \property QxtPushButton::textFormat
+ \brief This property holds the text format of the button
+
+ Supported formats are \b Qt::PlainText, \b Qt::RichText and \b Qt::AutoText.
+
+ The default format is \b Qt::PlainText.
+
+ \note Rich text requires Qt 4.2 or newer.
+
+ \sa Qt::TextFormat
+ */
+Qt::TextFormat QxtPushButton::textFormat() const
+{
+ return qxt_d().format;
+}
+
+void QxtPushButton::setTextFormat(Qt::TextFormat format)
+{
+ if (qxt_d().format != format)
+ {
+ qxt_d().format = format;
+ if (!qxt_d().isRichText())
+ {
+ delete qxt_d().doc;
+ qxt_d().doc = 0;
+ }
+ qxt_d().text.clear();
+ update();
+ updateGeometry();
+ }
+}
+
+QSize QxtPushButton::sizeHint() const
+{
+ QSize size;
+ if (qxt_d().isRichText())
+ size = qxt_d().doc->documentLayout()->documentSize().toSize();
+ else
+ size = QPushButton::sizeHint();
+
+ if (qxt_d().rot & Vertical_Mask)
+ size.transpose();
+ return size;
+}
+
+QSize QxtPushButton::minimumSizeHint() const
+{
+ QSize size;
+ if (qxt_d().isRichText())
+ size = qxt_d().doc->documentLayout()->documentSize().toSize();
+ else
+ size = QPushButton::minimumSizeHint();
+
+ if (qxt_d().rot & Vertical_Mask)
+ size.transpose();
+ return size;
+}
+
+void QxtPushButton::paintEvent(QPaintEvent* event)
+{
+ Q_UNUSED(event);
+
+ // the only reliable way to detect text changes
+ if (text() != qxt_d().text)
+ {
+ qxt_d().text = text();
+ if (qxt_d().isRichText())
+ qxt_d().doc->setHtml(qxt_d().text);
+ updateGeometry();
+ }
+
+ QStylePainter painter(this);
+ painter.rotate(qxt_d().rot);
+ switch (qxt_d().rot)
+ {
+ case Qxt::UpsideDown:
+ painter.translate(-width(), -height());
+ break;
+
+ case Qxt::Clockwise:
+ painter.translate(0, -width());
+ break;
+
+ case Qxt::CounterClockwise:
+ painter.translate(-height(), 0);
+ break;
+
+ default:
+ // nothing to do
+ break;
+ }
+
+ const QStyleOptionButton option = qxt_d().getStyleOption();
+ painter.drawControl(QStyle::CE_PushButton, option);
+
+#if QT_VERSION >= 0x040200
+ if (qxt_d().isRichText())
+ {
+ int dx = 0;
+ int dy = 0;
+ if (option.state & (QStyle::State_On | QStyle::State_Sunken))
+ {
+ dx += style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option, this);
+ dy += style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option, this);
+ }
+
+ QRect area = rect();
+ const QSizeF docSize = qxt_d().doc->documentLayout()->documentSize();
+ if (qxt_d().rot & Vertical_Mask)
+ {
+ dx += static_cast<int>((height() - docSize.width()) / 2);
+ dy += static_cast<int>((width() - docSize.height()) / 2);
+ painter.translate(dx, dy);
+
+ QSize size = area.size();
+ size.transpose();
+ area.setSize(size);
+ }
+ else
+ {
+ dx += static_cast<int>((width() - docSize.width()) / 2);
+ dy += static_cast<int>((height() - docSize.height()) / 2);
+ painter.translate(dx, dy);
+ }
+ qxt_d().doc->drawContents(&painter, area);
+ }
+#endif // QT_VERSION
+}