We now have a current svn snapshot of libqxt in our contrib dir, and
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / gui / qxtpushbutton.cpp
diff --git a/src/contrib/libqxt-2007-10-24/src/gui/qxtpushbutton.cpp b/src/contrib/libqxt-2007-10-24/src/gui/qxtpushbutton.cpp
new file mode 100644 (file)
index 0000000..9b3cf8a
--- /dev/null
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** 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
+}