/*************************************************************************** ** ** Copyright (C) 2014 BlackBerry Limited. All rights reserved. ** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWidgets module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qpixmapstyle_p.h" #include "qpixmapstyle_p_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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(widget)) { QPalette p = widget->palette(); p.setBrush(QPalette::Base, Qt::NoBrush); widget->setPalette(p); } if (QProgressBar *pb = qobject_cast(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(widget)) widget->installEventFilter(this); if (QComboBox *cb = qobject_cast(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(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(widget)) { scrollArea->viewport()->setAutoFillBackground(false); if (QAbstractItemView *view = qobject_cast(scrollArea)) { view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); } QScroller::grabGesture(scrollArea->viewport(), QScroller::LeftMouseButtonGesture); } if (qobject_cast(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(widget) || qobject_cast(widget)) { widget->removeEventFilter(this); } if (qstrcmp(widget->metaObject()->className(),"QComboBoxPrivateContainer") == 0) widget->removeEventFilter(this); if (QAbstractScrollArea *scrollArea = qobject_cast(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(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(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(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(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(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(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(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(watched)) { switch (event->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: slider->update(); break; default: ; } } if (QComboBox *comboBox = qobject_cast(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(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(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(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(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(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(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(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(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(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(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(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(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