summaryrefslogtreecommitdiffstats
path: root/src/widgets/styles/qpixmapstyle.cpp
diff options
context:
space:
mode:
authorRafael Roquetto <rafael.roquetto.qnx@kdab.com>2015-09-21 14:54:00 +0000
committerLouai Al-Khanji <louai.al-khanji@theqtcompany.com>2015-11-19 15:43:53 +0000
commit986a5262e3e753958a6ec9058eb7332d44a9065f (patch)
tree5c097e240cafb439ab10fd0127180ccaeaad9676 /src/widgets/styles/qpixmapstyle.cpp
parent3d93fb077109e2190ca5f2c7ad04a46768ccad50 (diff)
Add QPixmapStyle class
The QPixmapStyle class provides a mechanism for implementing pixmap based QStyles, using the same concept introduced by the BorderImage QML component. The bb10style plugin in qtstyleplugins uses this class and is currently the only user. Change-Id: Ibfa2104e95ba6a91e89a6277baa97a7fc9edaec2 Done-with: Louai Al-Khanji <louai.al-khanji@theqtcompany.com> Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Diffstat (limited to 'src/widgets/styles/qpixmapstyle.cpp')
-rw-r--r--src/widgets/styles/qpixmapstyle.cpp1157
1 files changed, 1157 insertions, 0 deletions
diff --git a/src/widgets/styles/qpixmapstyle.cpp b/src/widgets/styles/qpixmapstyle.cpp
new file mode 100644
index 0000000000..b2f2e91d5f
--- /dev/null
+++ b/src/widgets/styles/qpixmapstyle.cpp
@@ -0,0 +1,1157 @@
+/***************************************************************************
+**
+** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpixmapstyle_p.h"
+#include "qpixmapstyle_p_p.h"
+
+#include <QDebug>
+#include <QTextEdit>
+#include <QStringBuilder>
+#include <QPainter>
+#include <QPixmapCache>
+#include <QStyleOption>
+#include <QString>
+#include <QProgressBar>
+#include <QSlider>
+#include <QEvent>
+#include <QComboBox>
+#include <QAbstractItemView>
+#include <QListView>
+#include <QTreeView>
+#include <QStyledItemDelegate>
+#include <QAbstractScrollArea>
+#include <QScrollBar>
+
+#include <qscroller.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPixmapStyle
+ \brief The QPixmapStyle class provides mechanism for writing pixmap based styles.
+
+ \since 5.7
+ \ingroup appearance
+ \inmodule QtWidgets
+ \internal
+
+ This is a convenience class that enables the implementation of a widget style using
+ pixmaps, on the same fashion used by the \l{BorderImage} QML type.
+
+ In order to style a QWidget, one simply needs to call QPixmapStyle::addDescriptor()
+ or QPixmapStyle::addPixmap() with the id of the component to be styled, the path of
+ the image to be used, the margins and the tiling rules:
+
+ \snippet styles/qcustompixmapstyle.cpp 0
+
+ \sa QStyle, QCommonStyle
+*/
+
+/*!
+ \internal
+
+ Constructs a QPixmapStyle object.
+*/
+QPixmapStyle::QPixmapStyle()
+ : QCommonStyle(*new QPixmapStylePrivate)
+{
+}
+
+/*!
+ Destroys the QPixmapStyle object.
+*/
+QPixmapStyle::~QPixmapStyle()
+{
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::polish(QApplication *application)
+{
+ QCommonStyle::polish(application);
+#if defined(Q_DEAD_CODE_FROM_QT4_WIN)
+ QApplication::setEffectEnabled(Qt::UI_AnimateCombo, false);
+#endif
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::polish(QPalette &palette)
+{
+ palette = proxy()->standardPalette();
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::polish(QWidget *widget)
+{
+ Q_D(QPixmapStyle);
+
+ // Don't fill the interior of the QTextEdit
+ if (qobject_cast<QTextEdit*>(widget)) {
+ QPalette p = widget->palette();
+ p.setBrush(QPalette::Base, Qt::NoBrush);
+ widget->setPalette(p);
+ }
+
+ if (QProgressBar *pb = qobject_cast<QProgressBar*>(widget)) {
+ // Center the text in the progress bar
+ pb->setAlignment(Qt::AlignCenter);
+ // Change the font size if needed, as it's used to compute the minimum size
+ QFont font = pb->font();
+ font.setPixelSize(d->descriptors.value(PB_HBackground).size.height()/2);
+ pb->setFont(font);
+ }
+
+ if (qobject_cast<QSlider*>(widget))
+ widget->installEventFilter(this);
+
+ if (QComboBox *cb = qobject_cast<QComboBox*>(widget)) {
+ widget->installEventFilter(this);
+ // NOTE: This will break if the private API of QComboBox changes drastically
+ // Make sure the popup is created so we can change the frame style
+ QAbstractItemView *list = cb->view();
+ list->setProperty("_pixmap_combobox_list", true);
+ list->setItemDelegate(new QStyledItemDelegate(list));
+ QPalette p = list->palette();
+ p.setBrush(QPalette::Active, QPalette::Base, QBrush(Qt::transparent) );
+ p.setBrush(QPalette::Active, QPalette::AlternateBase, QBrush(Qt::transparent) );
+ p.setBrush(QPalette::Inactive, QPalette::Base, QBrush(Qt::transparent) );
+ p.setBrush(QPalette::Inactive, QPalette::AlternateBase, QBrush(Qt::transparent) );
+ p.setBrush(QPalette::Disabled, QPalette::Base, QBrush(Qt::transparent) );
+ p.setBrush(QPalette::Disabled, QPalette::AlternateBase, QBrush(Qt::transparent) );
+ list->setPalette(p);
+
+ QFrame *frame = qobject_cast<QFrame*>(list->parent());
+ if (frame) {
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(DD_PopupDown);
+ const QPixmapStylePixmap &pix = d->pixmaps.value(DD_ItemSeparator);
+ frame->setContentsMargins(pix.margins.left(), desc.margins.top(),
+ pix.margins.right(), desc.margins.bottom());
+ frame->setAttribute(Qt::WA_TranslucentBackground);
+#ifdef Q_DEAD_CODE_FROM_QT4_WIN
+ // FramelessWindowHint is needed on windows to make
+ // WA_TranslucentBackground work properly
+ frame->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint);
+#endif
+ }
+ }
+
+ if (qstrcmp(widget->metaObject()->className(),"QComboBoxPrivateContainer") == 0)
+ widget->installEventFilter(this);
+
+ if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget)) {
+ scrollArea->viewport()->setAutoFillBackground(false);
+ if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(scrollArea)) {
+ view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ }
+ QScroller::grabGesture(scrollArea->viewport(), QScroller::LeftMouseButtonGesture);
+ }
+
+ if (qobject_cast<QScrollBar*>(widget))
+ widget->setAttribute(Qt::WA_OpaquePaintEvent, false);
+
+ QCommonStyle::polish(widget);
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::unpolish(QApplication *application)
+{
+ QCommonStyle::unpolish(application);
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::unpolish(QWidget *widget)
+{
+ if (qobject_cast<QSlider*>(widget) ||
+ qobject_cast<QComboBox*>(widget)) {
+ widget->removeEventFilter(this);
+ }
+
+ if (qstrcmp(widget->metaObject()->className(),"QComboBoxPrivateContainer") == 0)
+ widget->removeEventFilter(this);
+
+ if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget))
+ QScroller::ungrabGesture(scrollArea->viewport());
+
+ QCommonStyle::unpolish(widget);
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ switch (element) {
+ case PE_FrameFocusRect: //disable focus rectangle
+ break;
+ case PE_PanelButtonBevel:
+ case PE_PanelButtonCommand:
+ drawPushButton(option, painter, widget);
+ break;
+ case PE_PanelLineEdit:
+ case PE_FrameLineEdit:
+ drawLineEdit(option, painter, widget);
+ break;
+ case PE_Frame:
+ case PE_FrameDefaultButton:
+ if (qobject_cast<const QTextEdit*>(widget))
+ drawTextEdit(option, painter, widget);
+ break;
+ case PE_IndicatorCheckBox:
+ drawCheckBox(option, painter, widget);
+ break;
+ case PE_IndicatorRadioButton:
+ drawRadioButton(option, painter, widget);
+ break;
+ case PE_PanelItemViewItem:
+ if (qobject_cast<const QListView*>(widget))
+ drawPanelItemViewItem(option, painter, widget);
+ else
+ QCommonStyle::drawPrimitive(element, option, painter, widget);
+ break;
+ default:
+ QCommonStyle::drawPrimitive(element, option, painter, widget);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ switch (element) {
+ case CE_ProgressBarGroove:
+ drawProgressBarBackground(option, painter, widget);
+ break;
+ case CE_ProgressBarLabel:
+ drawProgressBarLabel(option, painter, widget);
+ break;
+ case CE_ProgressBarContents:
+ drawProgressBarFill(option, painter, widget);
+ break;
+ case CE_ShapedFrame:
+ // NOTE: This will break if the private API of QComboBox changes drastically
+ if (qstrcmp(widget->metaObject()->className(),"QComboBoxPrivateContainer") == 0) {
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(DD_PopupDown);
+ const QPixmapStylePixmap &pix = d->pixmaps.value(DD_ItemSeparator);
+ QRect rect = option->rect;
+ rect.adjust(-pix.margins.left(), -desc.margins.top(),
+ pix.margins.right(), desc.margins.bottom());
+ bool up = widget->property("_pixmapstyle_combobox_up").toBool();
+ drawCachedPixmap(up ? DD_PopupUp : DD_PopupDown, rect, painter);
+ }
+ else {
+ QCommonStyle::drawControl(element, option, painter, widget);
+ }
+ break;
+ default:
+ QCommonStyle::drawControl(element, option, painter, widget);
+ }
+}
+
+/*!
+ \reimp
+*/
+void QPixmapStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ switch (cc) {
+ case CC_Slider:
+ drawSlider(option, painter, widget);
+ break;
+ case CC_ComboBox:
+ drawComboBox(option, painter, widget);
+ break;
+ case CC_ScrollBar:
+ drawScrollBar(option, painter, widget);
+ break;
+ default:
+ QCommonStyle::drawComplexControl(cc, option, painter, widget);
+ }
+}
+
+/*!
+ \reimp
+*/
+QSize QPixmapStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &contentsSize, const QWidget *widget) const
+{
+ switch (type) {
+ case CT_PushButton:
+ return pushButtonSizeFromContents(option, contentsSize, widget);
+ case CT_LineEdit:
+ return lineEditSizeFromContents(option, contentsSize, widget);
+ case CT_ProgressBar:
+ return progressBarSizeFromContents(option, contentsSize, widget);
+ case CT_Slider:
+ return sliderSizeFromContents(option, contentsSize, widget);
+ case CT_ComboBox:
+ return comboBoxSizeFromContents(option, contentsSize, widget);
+ case CT_ItemViewItem:
+ return itemViewSizeFromContents(option, contentsSize, widget);
+ default: ;
+ }
+
+ return QCommonStyle::sizeFromContents(type, option, contentsSize, widget);
+}
+
+/*!
+ \reimp
+*/
+QRect QPixmapStyle::subElementRect(SubElement element, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ switch (element) {
+ case SE_LineEditContents:
+ {
+ QRect rect = QCommonStyle::subElementRect(element, option, widget);
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(LE_Enabled);
+ rect.adjust(desc.margins.left(), desc.margins.top(),
+ -desc.margins.right(), -desc.margins.bottom());
+ rect = visualRect(option->direction, option->rect, rect);
+ return rect;
+ }
+ default: ;
+ }
+
+ return QCommonStyle::subElementRect(element, option, widget);
+}
+
+/*!
+ \reimp
+*/
+QRect QPixmapStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *option,
+ SubControl sc, const QWidget *widget) const
+{
+ switch (cc) {
+ case CC_ComboBox:
+ return comboBoxSubControlRect(option, sc, widget);
+ case CC_ScrollBar:
+ return scrollBarSubControlRect(option, sc, widget);
+ default: ;
+ }
+
+ return QCommonStyle::subControlRect(cc, option, sc, widget);
+}
+
+/*!
+ \reimp
+*/
+int QPixmapStyle::pixelMetric(PixelMetric metric, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ switch (metric) {
+ case PM_ButtonShiftHorizontal:
+ case PM_ButtonShiftVertical:
+ return 0;
+ case PM_DefaultFrameWidth:
+ if (qobject_cast<const QTextEdit*>(widget)) {
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(LE_Enabled);
+ return qMax(qMax(desc.margins.left(), desc.margins.right()),
+ qMax(desc.margins.top(), desc.margins.bottom()));
+ }
+ return 0;
+ case PM_IndicatorWidth:
+ return d->pixmaps.value(CB_Enabled).pixmap.width();
+ case PM_IndicatorHeight:
+ return d->pixmaps.value(CB_Enabled).pixmap.height();
+ case PM_CheckBoxLabelSpacing:
+ {
+ const QPixmapStylePixmap &pix = d->pixmaps.value(CB_Enabled);
+ return qMax(qMax(pix.margins.left(), pix.margins.right()),
+ qMax(pix.margins.top(), pix.margins.bottom()));
+ }
+ case PM_ExclusiveIndicatorWidth:
+ return d->pixmaps.value(RB_Enabled).pixmap.width();
+ case PM_ExclusiveIndicatorHeight:
+ return d->pixmaps.value(RB_Enabled).pixmap.height();
+ case PM_RadioButtonLabelSpacing:
+ {
+ const QPixmapStylePixmap &pix = d->pixmaps.value(RB_Enabled);
+ return qMax(qMax(pix.margins.left(), pix.margins.right()),
+ qMax(pix.margins.top(), pix.margins.bottom()));
+ }
+ case PM_SliderThickness:
+ if (const QStyleOptionSlider *slider =
+ qstyleoption_cast<const QStyleOptionSlider*>(option)) {
+ const QPixmapStyleDescriptor desc =
+ d->descriptors.value(slider->orientation == Qt::Horizontal
+ ? SG_HEnabled : SG_VEnabled);
+ return slider->orientation == Qt::Horizontal
+ ? desc.size.height() : desc.size.width();
+ }
+ break;
+ case PM_SliderControlThickness:
+ if (const QStyleOptionSlider *slider =
+ qstyleoption_cast<const QStyleOptionSlider*>(option)) {
+ const QPixmapStylePixmap pix =
+ d->pixmaps.value(slider->orientation == Qt::Horizontal
+ ? SH_HEnabled : SH_VEnabled);
+ return slider->orientation == Qt::Horizontal
+ ? pix.pixmap.height() : pix.pixmap.width();
+ }
+ break;
+ case PM_SliderLength:
+ if (const QStyleOptionSlider *slider =
+ qstyleoption_cast<const QStyleOptionSlider*>(option)) {
+ const QPixmapStylePixmap pix =
+ d->pixmaps.value(slider->orientation == Qt::Horizontal
+ ? SH_HEnabled : SH_VEnabled);
+ return slider->orientation == Qt::Horizontal
+ ? pix.pixmap.width() : pix.pixmap.height();
+ }
+ break;
+ case PM_ScrollBarExtent:
+ if (const QStyleOptionSlider *slider =
+ qstyleoption_cast<const QStyleOptionSlider*>(option)) {
+ const QPixmapStyleDescriptor desc =
+ d->descriptors.value(slider->orientation == Qt::Horizontal
+ ? SB_Horizontal : SB_Vertical);
+ return slider->orientation == Qt::Horizontal
+ ? desc.size.height() : desc.size.width();
+ }
+ break;
+ case PM_ScrollBarSliderMin:
+ return 0;
+ default: ;
+ }
+
+ return QCommonStyle::pixelMetric(metric, option, widget);
+}
+
+/*!
+ \reimp
+*/
+int QPixmapStyle::styleHint(StyleHint hint, const QStyleOption *option,
+ const QWidget *widget, QStyleHintReturn *returnData) const
+{
+ switch (hint) {
+ case SH_EtchDisabledText:
+ return false;
+ case SH_ComboBox_Popup:
+ return false;
+ default: ;
+ }
+
+ return QCommonStyle::styleHint(hint, option, widget, returnData);
+}
+
+/*!
+ \reimp
+*/
+QStyle::SubControl QPixmapStyle::hitTestComplexControl(QStyle::ComplexControl control,
+ const QStyleOptionComplex *option,
+ const QPoint &pos,
+ const QWidget *widget) const
+{
+ const SubControl sc = QCommonStyle::hitTestComplexControl(control, option, pos, widget);
+ if (control == CC_ScrollBar) {
+ if (sc == SC_ScrollBarAddLine)
+ return SC_ScrollBarAddPage;
+ else if (sc == SC_ScrollBarSubLine)
+ return SC_ScrollBarSubPage;
+ }
+
+ return sc;
+}
+
+/*!
+ \reimp
+*/
+bool QPixmapStyle::eventFilter(QObject *watched, QEvent *event)
+{
+ Q_D(QPixmapStyle);
+
+ if (QSlider *slider = qobject_cast<QSlider*>(watched)) {
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ slider->update();
+ break;
+ default: ;
+ }
+ }
+
+ if (QComboBox *comboBox = qobject_cast<QComboBox*>(watched)) {
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ event->ignore();
+ comboBox->setProperty("_pixmapstyle_combobox_pressed", true);
+ comboBox->repaint();
+ return true;
+ case QEvent::MouseButtonRelease:
+ comboBox->setProperty("_pixmapstyle_combobox_pressed", false);
+ comboBox->repaint();
+ if ( comboBox->view() ) {
+ if ( comboBox->view()->isVisible() || (!comboBox->isEnabled()))
+ comboBox->hidePopup();
+ else
+ comboBox->showPopup();
+ }
+ break;
+ default: ;
+ }
+ }
+
+ if (qstrcmp(watched->metaObject()->className(),"QComboBoxPrivateContainer") == 0) {
+ if (event->type() == QEvent::Show) {
+ QWidget *widget = qobject_cast<QWidget*>(watched);
+ int yPopup = widget->geometry().top();
+ int yCombo = widget->parentWidget()->mapToGlobal(QPoint(0, 0)).y();
+ QRect geom = widget->geometry();
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(DD_ButtonEnabled);
+ const bool up = yPopup < yCombo;
+ geom.moveTop(geom.top() + (up ? desc.margins.top() : -desc.margins.bottom()));
+ widget->setGeometry(geom);
+ widget->setProperty("_pixmapstyle_combobox_up", up);
+ widget->parentWidget()->setProperty("_pixmapstyle_combobox_up", up);
+ }
+ }
+
+ return QCommonStyle::eventFilter(watched, event);
+}
+
+/*!
+ \fn void QPixmapStyle::addDescriptor(QPixmapStyle::ControlDescriptor control, const QString &fileName, QMargins margins, QTileRules tileRules)
+
+ Associates the pixmap having the given \a fileName with the given \a control. The \a margins parameter describe the boundaries
+ of the pixmap's top-left, top-right, bottom-left and bottom-right corners, as well as the left, right, top and bottorm segments
+ and the middle. The \a tileRules parameter describes how QPixmapStyle is supposed to handle the scaling of the center of the pixmap.
+
+ Use QPixmapStyle::addPixmap() for controls that are not resizable.
+
+ \snippet styles/qcustompixmapstyle.cpp 1
+
+ \sa addPixmap, copyDescriptor
+
+*/
+void QPixmapStyle::addDescriptor(QPixmapStyle::ControlDescriptor control, const QString &fileName,
+ QMargins margins, QTileRules tileRules)
+{
+ Q_D(QPixmapStyle);
+
+ QPixmapStyleDescriptor desc;
+ QImage image(fileName);
+
+ if (image.isNull())
+ return;
+
+ desc.fileName = fileName;
+ desc.margins = margins;
+ desc.tileRules = tileRules;
+ desc.size = image.size();
+
+ d->descriptors[control] = desc;
+}
+
+/*!
+ \fn void QPixmapStyle::copyDescriptor(QPixmapStyle::ControlDescriptor source, QPixmapStyle::ControlDescriptor dest)
+
+ Copies the data associated with the \a source descriptor to the \a dest descriptor.
+
+ \snippet styles/qcustompixmapstyle.cpp 2
+*/
+
+void QPixmapStyle::copyDescriptor(QPixmapStyle::ControlDescriptor source,
+ QPixmapStyle::ControlDescriptor dest)
+{
+ Q_D(QPixmapStyle);
+ d->descriptors[dest] = d->descriptors.value(source);
+}
+
+/*!
+ \fn void QPixmapStyle::drawCachedPixmap(QPixmapStyle::ControlDescriptor control, const QRect &rect, QPainter *painter) const
+
+ Draws the image associated with the current \a control on the given \a rect using the given \a painter.
+*/
+void QPixmapStyle::drawCachedPixmap(QPixmapStyle::ControlDescriptor control, const QRect &rect,
+ QPainter *p) const
+{
+ Q_D(const QPixmapStyle);
+ if (!d->descriptors.contains(control))
+ return;
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(control);
+ const QPixmap pix = d->getCachedPixmap(control, desc, rect.size());
+ Q_ASSERT(!pix.isNull());
+ p->drawPixmap(rect, pix);
+}
+
+/*!
+ \fn void QPixmapStyle::addPixmap(ControlPixmap control, const QString &fileName, QMargins margins)
+
+ Use this function to style statically sized controls such as check boxes.
+
+ \sa addDescriptor, copyPixmap
+*/
+void QPixmapStyle::addPixmap(ControlPixmap control, const QString &fileName,
+ QMargins margins)
+{
+ Q_D(QPixmapStyle);
+
+ QPixmapStylePixmap pix;
+ QPixmap image(fileName);
+
+ if (image.isNull())
+ return;
+
+ pix.pixmap = image;
+ pix.margins = margins;
+
+ d->pixmaps[control] = pix;
+}
+
+/*
+ \fn void QPixmapStyle::copyPixmap(QPixmapStyle::ControlPixmap source, QPixmapStyle::ControlPixmap dest)
+
+ Copies the data associated with the \a source pixmap to the \a dest pixmap.
+
+ \sa addPixmap, addDescriptor, copyDescriptor
+*/
+void QPixmapStyle::copyPixmap(QPixmapStyle::ControlPixmap source, QPixmapStyle::ControlPixmap dest)
+{
+ Q_D(QPixmapStyle);
+ d->pixmaps[dest] = d->pixmaps.value(source);
+}
+
+/*!
+ \internal
+
+ Constructs a QPixmapStyle object.
+*/
+QPixmapStyle::QPixmapStyle(QPixmapStylePrivate &dd)
+ : QCommonStyle(dd)
+{}
+
+void QPixmapStyle::drawPushButton(const QStyleOption *option,
+ QPainter *painter, const QWidget *) const
+{
+ const bool checked = option->state & State_On;
+ const bool pressed = option->state & State_Sunken;
+ const bool enabled = option->state & State_Enabled;
+
+ ControlDescriptor control = PB_Enabled;
+ if (enabled)
+ control = pressed ? PB_Pressed : (checked ? PB_Checked : PB_Enabled);
+ else
+ control = checked ? PB_PressedDisabled : PB_Disabled;
+ drawCachedPixmap(control, option->rect, painter);
+}
+
+void QPixmapStyle::drawLineEdit(const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ // Don't draw for the line edit inside a combobox
+ if (widget && qobject_cast<const QComboBox*>(widget->parentWidget()))
+ return;
+
+ const bool enabled = option->state & State_Enabled;
+ const bool focused = option->state & State_HasFocus;
+ ControlDescriptor control = enabled ? (focused ? LE_Focused : LE_Enabled) : LE_Disabled;
+ drawCachedPixmap(control, option->rect, painter);
+}
+
+void QPixmapStyle::drawTextEdit(const QStyleOption *option,
+ QPainter *painter, const QWidget *) const
+{
+ const bool enabled = option->state & State_Enabled;
+ const bool focused = option->state & State_HasFocus;
+ ControlDescriptor control = enabled ? (focused ? TE_Focused : TE_Enabled) : TE_Disabled;
+ drawCachedPixmap(control, option->rect, painter);
+}
+
+void QPixmapStyle::drawCheckBox(const QStyleOption *option,
+ QPainter *painter, const QWidget *) const
+{
+ Q_D(const QPixmapStyle);
+
+ const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option);
+
+ const bool down = button->state & State_Sunken;
+ const bool enabled = button->state & State_Enabled;
+ const bool on = button->state & State_On;
+
+ ControlPixmap control;
+ if (enabled)
+ control = on ? (down ? CB_PressedChecked : CB_Checked) : (down ? CB_Pressed : CB_Enabled);
+ else
+ control = on ? CB_DisabledChecked : CB_Disabled;
+ painter->drawPixmap(button->rect, d->pixmaps.value(control).pixmap);
+}
+
+void QPixmapStyle::drawRadioButton(const QStyleOption *option,
+ QPainter *painter, const QWidget *) const
+{
+ Q_D(const QPixmapStyle);
+
+ const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option);
+
+ const bool down = button->state & State_Sunken;
+ const bool enabled = button->state & State_Enabled;
+ const bool on = button->state & State_On;
+
+ ControlPixmap control;
+ if (enabled)
+ control = on ? RB_Checked : (down ? RB_Pressed : RB_Enabled);
+ else
+ control = on ? RB_DisabledChecked : RB_Disabled;
+ painter->drawPixmap(button->rect, d->pixmaps.value(control).pixmap);
+}
+
+void QPixmapStyle::drawPanelItemViewItem(const QStyleOption *option, QPainter *painter,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ ControlPixmap cp = ID_Separator;
+ ControlDescriptor cd = ID_Selected;
+
+ if (widget && widget->property("_pixmap_combobox_list").toBool()) {
+ cp = DD_ItemSeparator;
+ cd = DD_ItemSelected;
+ }
+
+ QPixmap pix = d->pixmaps.value(cp).pixmap;
+ QRect rect = option->rect;
+ rect.setBottom(rect.top() + pix.height()-1);
+ painter->drawPixmap(rect, pix);
+ if (option->state & QStyle::State_Selected) {
+ rect = option->rect;
+ rect.setTop(rect.top() + pix.height());
+ drawCachedPixmap(cd, rect, painter);
+ }
+}
+
+void QPixmapStyle::drawProgressBarBackground(const QStyleOption *option,
+ QPainter *painter, const QWidget *) const
+{
+ bool vertical = false;
+ if (const QStyleOptionProgressBar *pb =
+ qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
+ vertical = pb->orientation == Qt::Vertical;
+ }
+ drawCachedPixmap(vertical ? PB_VBackground : PB_HBackground, option->rect, painter);
+}
+
+void QPixmapStyle::drawProgressBarLabel(const QStyleOption *option,
+ QPainter *painter, const QWidget *) const
+{
+ if (const QStyleOptionProgressBar *pb =
+ qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
+ const bool vertical = pb->orientation == Qt::Vertical;
+ if (!vertical) {
+ QPalette::ColorRole textRole = QPalette::ButtonText;
+ proxy()->drawItemText(painter, pb->rect,
+ Qt::AlignCenter | Qt::TextSingleLine, pb->palette,
+ pb->state & State_Enabled, pb->text, textRole);
+ }
+ }
+}
+
+void QPixmapStyle::drawProgressBarFill(const QStyleOption *option,
+ QPainter *painter, const QWidget *) const
+{
+ const QStyleOptionProgressBar *pbar =
+ qstyleoption_cast<const QStyleOptionProgressBar*>(option);
+ const bool vertical = pbar->orientation == Qt::Vertical;
+ const bool flip = (pbar->direction == Qt::RightToLeft) ^ pbar->invertedAppearance;
+
+ if (pbar->progress == pbar->maximum) {
+ drawCachedPixmap(vertical ? PB_VComplete : PB_HComplete, option->rect, painter);
+
+ } else {
+ if (pbar->progress == 0)
+ return;
+ const int maximum = pbar->maximum;
+ const qreal ratio = qreal(vertical?option->rect.height():option->rect.width())/maximum;
+ const int progress = pbar->progress*ratio;
+
+ QRect optRect = option->rect;
+ if (vertical) {
+ if (flip)
+ optRect.setBottom(optRect.top()+progress-1);
+ else
+ optRect.setTop(optRect.bottom()-progress+1);
+ } else {
+ if (flip)
+ optRect.setLeft(optRect.right()-progress+1);
+ else
+ optRect.setRight(optRect.left()+progress-1);
+ }
+
+ drawCachedPixmap(vertical ? PB_VContent : PB_HContent, optRect, painter);
+ }
+}
+
+void QPixmapStyle::drawSlider(const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option);
+ if (!slider)
+ return;
+
+ const bool enabled = option->state & State_Enabled;
+ const bool pressed = option->state & State_Sunken;
+ const Qt::Orientation orient = slider->orientation;
+
+ const QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ if (option->subControls & SC_SliderGroove) {
+ QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
+ if (groove.isValid()) {
+ // Draw the background
+ ControlDescriptor control;
+ if (orient == Qt::Horizontal)
+ control = enabled ? SG_HEnabled : SG_HDisabled;
+ else
+ control = enabled ? SG_VEnabled : SG_VDisabled;
+ drawCachedPixmap(control, groove, painter);
+
+ // Draw the active part
+ if (orient == Qt::Horizontal) {
+ control = enabled ? (pressed ? SG_HActivePressed : SG_HActiveEnabled )
+ : SG_HActiveDisabled;
+ } else {
+ control = enabled ? (pressed ? SG_VActivePressed : SG_VActiveEnabled )
+ : SG_VActiveDisabled;
+ }
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(control);
+ const QPixmap pix = d->getCachedPixmap(control, desc, groove.size());
+ if (!pix.isNull()) {
+ groove.setRight(orient == Qt::Horizontal
+ ? handle.center().x() : handle.center().y());
+ painter->drawPixmap(groove, pix, groove);
+ }
+ }
+ }
+ if (option->subControls & SC_SliderHandle) {
+ if (handle.isValid()) {
+ ControlPixmap pix;
+ if (orient == Qt::Horizontal)
+ pix = enabled ? (pressed ? SH_HPressed : SH_HEnabled) : SH_HDisabled;
+ else
+ pix = enabled ? (pressed ? SH_VPressed : SH_VEnabled) : SH_VDisabled;
+ painter->drawPixmap(handle, d->pixmaps.value(pix).pixmap);
+ }
+ }
+}
+
+void QPixmapStyle::drawComboBox(const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ const bool enabled = option->state & State_Enabled;
+ const bool pressed = widget->property("_pixmapstyle_combobox_pressed").toBool();
+ const bool opened = option->state & State_On;
+
+ ControlDescriptor control =
+ enabled ? (pressed ? DD_ButtonPressed : DD_ButtonEnabled) : DD_ButtonDisabled;
+ drawCachedPixmap(control, option->rect, painter);
+
+ ControlPixmap cp = enabled ? (opened ? DD_ArrowOpen
+ : (pressed ? DD_ArrowPressed : DD_ArrowEnabled))
+ : DD_ArrowDisabled;
+ QPixmapStylePixmap pix = d->pixmaps.value(cp);
+ QRect rect = comboBoxSubControlRect(option, SC_ComboBoxArrow, widget);
+ painter->drawPixmap(rect, pix.pixmap);
+}
+
+void QPixmapStyle::drawScrollBar(const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ if (const QStyleOptionSlider *slider =
+ qstyleoption_cast<const QStyleOptionSlider*>(option)) {
+ // Do not draw the scrollbar
+ if (slider->minimum == slider->maximum)
+ return;
+
+ QRect rect = scrollBarSubControlRect(option, SC_ScrollBarSlider, widget);
+ ControlDescriptor control = slider->orientation == Qt::Horizontal
+ ? SB_Horizontal : SB_Vertical;
+ drawCachedPixmap(control, rect, painter);
+ }
+}
+
+QSize QPixmapStyle::pushButtonSizeFromContents(const QStyleOption *option,
+ const QSize &contentsSize,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(PB_Enabled);
+ const int bm = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
+
+ int w = contentsSize.width();
+ int h = contentsSize.height();
+ w += desc.margins.left() + desc.margins.right() + bm;
+ h += desc.margins.top() + desc.margins.bottom() + bm;
+
+ return d->computeSize(desc, w, h);
+}
+
+QSize QPixmapStyle::lineEditSizeFromContents(const QStyleOption *,
+ const QSize &contentsSize, const QWidget *) const
+{
+ Q_D(const QPixmapStyle);
+
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(LE_Enabled);
+ const int border = 2 * proxy()->pixelMetric(PM_DefaultFrameWidth);
+
+ int w = contentsSize.width() + border + desc.margins.left() + desc.margins.right();
+ int h = contentsSize.height() + border + desc.margins.top() + desc.margins.bottom();
+
+ return d->computeSize(desc, w, h);
+}
+
+QSize QPixmapStyle::progressBarSizeFromContents(const QStyleOption *option,
+ const QSize &contentsSize,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ bool vertical = false;
+ if (const QStyleOptionProgressBar *pb =
+ qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
+ vertical = pb->orientation == Qt::Vertical;
+ }
+ QSize result = QCommonStyle::sizeFromContents(CT_Slider, option, contentsSize, widget);
+ if (vertical) {
+ const QPixmapStyleDescriptor desc = d->descriptors.value(PB_VBackground);
+ return QSize(desc.size.height(), result.height());
+ } else {
+ const QPixmapStyleDescriptor desc = d->descriptors.value(PB_HBackground);
+ return QSize(result.width(), desc.size.height());
+ }
+}
+
+QSize QPixmapStyle::sliderSizeFromContents(const QStyleOption *option,
+ const QSize &contentsSize,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option);
+ if (!slider)
+ return QSize();
+
+ QSize result = QCommonStyle::sizeFromContents(CT_Slider, option, contentsSize, widget);
+
+ const QPixmapStyleDescriptor desc = d->descriptors.value(slider->orientation == Qt::Horizontal
+ ? SG_HEnabled : SG_VEnabled);
+
+ if (slider->orientation == Qt::Horizontal)
+ return QSize(result.width(), desc.size.height());
+ else
+ return QSize(desc.size.width(), result.height());
+}
+
+QSize QPixmapStyle::comboBoxSizeFromContents(const QStyleOption *option,
+ const QSize &contentsSize,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(DD_ButtonEnabled);
+
+ QSize result = QCommonStyle::sizeFromContents(CT_ComboBox, option, contentsSize, widget);
+ return d->computeSize(desc, result.width(), result.height());
+}
+
+QSize QPixmapStyle::itemViewSizeFromContents(const QStyleOption *option,
+ const QSize &contentsSize,
+ const QWidget *widget) const
+{
+ Q_D(const QPixmapStyle);
+
+ QSize size = QCommonStyle::sizeFromContents(CT_ItemViewItem, option, contentsSize, widget);
+
+ ControlPixmap cp = ID_Separator;
+ ControlDescriptor cd = ID_Selected;
+ if (widget && widget->property("_pixmap_combobox_list").toBool()) {
+ cp = DD_ItemSeparator;
+ cd = DD_ItemSelected;
+ }
+
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(cd);
+ const QPixmapStylePixmap &pix = d->pixmaps.value(cp);
+ size.setHeight(qMax(size.height(),
+ desc.size.height() + pix.pixmap.height()));
+ return size;
+}
+
+QRect QPixmapStyle::comboBoxSubControlRect(const QStyleOptionComplex *option,
+ QStyle::SubControl sc, const QWidget *) const
+{
+ Q_D(const QPixmapStyle);
+
+ QRect r = option->rect; // Default size
+ const QPixmapStylePixmap &pix = d->pixmaps.value(DD_ArrowEnabled);
+ const QPixmapStyleDescriptor &desc = d->descriptors.value(DD_ButtonEnabled);
+
+ switch (sc) {
+ case SC_ComboBoxArrow:
+ r.setRect(r.right() - pix.margins.right() - pix.pixmap.width(),
+ r.top() + pix.margins.top(),
+ pix.pixmap.width(), pix.pixmap.height());
+ break;
+ case SC_ComboBoxEditField:
+ r.adjust(desc.margins.left(), desc.margins.right(),
+ -desc.margins.right(), -desc.margins.bottom());
+ r.setRight(r.right() - pix.margins.right() - pix.margins.left() - pix.pixmap.width());
+ break;
+ default:
+ break;
+ }
+
+ r = visualRect(option->direction, option->rect, r);
+ return r;
+}
+
+QRect QPixmapStyle::scrollBarSubControlRect(const QStyleOptionComplex *option,
+ QStyle::SubControl sc, const QWidget *) const
+{
+ if (const QStyleOptionSlider *slider =
+ qstyleoption_cast<const QStyleOptionSlider*>(option)) {
+ int length = (slider->orientation == Qt::Horizontal)
+ ? slider->rect.width() : slider->rect.height();
+ int page = length * slider->pageStep
+ / (slider->maximum - slider->minimum + slider->pageStep);
+ int pos = length * slider->sliderValue
+ / (slider->maximum - slider->minimum + slider->pageStep);
+ pos = qMin(pos+page, length) - page;
+
+ QRect rect = slider->rect;
+
+ if (slider->orientation == Qt::Horizontal) {
+ switch (sc) {
+ case SC_ScrollBarAddPage:
+ rect.setLeft(pos+page);
+ return rect;
+ case SC_ScrollBarSubPage:
+ rect.setRight(pos);
+ return rect;
+ case SC_ScrollBarGroove:
+ return rect;
+ case SC_ScrollBarSlider:
+ rect.setLeft(pos);
+ rect.setRight(pos+page);
+ return rect;
+ default: ;
+ }
+ } else {
+ switch (sc) {
+ case SC_ScrollBarAddPage:
+ rect.setTop(pos+page);
+ return rect;
+ case SC_ScrollBarSubPage:
+ rect.setBottom(pos);
+ return rect;
+ case SC_ScrollBarGroove:
+ return rect;
+ case SC_ScrollBarSlider:
+ rect.setTop(pos);
+ rect.setBottom(pos+page);
+ return rect;
+ default: ;
+ }
+ }
+ }
+ return QRect();
+}
+
+QPixmap QPixmapStylePrivate::scale(int w, int h, const QPixmap &pixmap, const QPixmapStyleDescriptor &desc)
+{
+ QPixmap result(w, h);
+ {
+ const QColor transparent(0, 0, 0, 0);
+ result.fill( transparent );
+ QPainter p( &result );
+ const QMargins margins = desc.margins;
+ qDrawBorderPixmap(&p, result.rect(), margins, pixmap,
+ pixmap.rect(), margins, desc.tileRules);
+ }
+ return result;
+}
+
+QPixmap QPixmapStylePrivate::getCachedPixmap(QPixmapStyle::ControlDescriptor control,
+ const QPixmapStyleDescriptor &desc,
+ const QSize &size) const
+{
+ Q_Q(const QPixmapStyle);
+
+ const QString sizeString = QString::number(size.width()) % QLatin1Char('*')
+ % QString::number(size.height());
+ const QString key = QLatin1String(q->metaObject()->className()) % QString::number(control)
+ % QLatin1Char('@') % sizeString;
+
+ QPixmap result;
+
+ if (!QPixmapCache::find( key, &result)) {
+ QPixmap source(desc.fileName);
+ result = scale(size.width(), size.height(), source, desc);
+ QPixmapCache::insert(key, result);
+ }
+ return result;
+}
+
+QSize QPixmapStylePrivate::computeSize(const QPixmapStyleDescriptor &desc, int width, int height) const
+{
+ if (desc.tileRules.horizontal != Qt::RepeatTile)
+ width = qMax(width, desc.size.width());
+ if (desc.tileRules.vertical != Qt::RepeatTile)
+ height = qMax(height, desc.size.height());
+ return QSize(width, height);
+}
+
+QT_END_NAMESPACE