diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/styles/qwindowsvistastyle.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/styles/qwindowsvistastyle.cpp')
-rw-r--r-- | src/gui/styles/qwindowsvistastyle.cpp | 2650 |
1 files changed, 2650 insertions, 0 deletions
diff --git a/src/gui/styles/qwindowsvistastyle.cpp b/src/gui/styles/qwindowsvistastyle.cpp new file mode 100644 index 0000000..4c3060d --- /dev/null +++ b/src/gui/styles/qwindowsvistastyle.cpp @@ -0,0 +1,2650 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsvistastyle.h" +#include "qwindowsvistastyle_p.h" + +#if !defined(QT_NO_STYLE_WINDOWSVISTA) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +static const int windowsItemFrame = 2; // menu item frame width +static const int windowsItemHMargin = 3; // menu item hor text margin +static const int windowsItemVMargin = 4; // menu item ver text margin +static const int windowsArrowHMargin = 6; // arrow horizontal margin +static const int windowsRightBorder = 15; // right border on windows + +#ifndef TMT_CONTENTMARGINS +# define TMT_CONTENTMARGINS 3602 +#endif +#ifndef TMT_SIZINGMARGINS +# define TMT_SIZINGMARGINS 3601 +#endif +#ifndef LISS_NORMAL +# define LISS_NORMAL 1 +# define LISS_HOT 2 +# define LISS_SELECTED 3 +# define LISS_DISABLED 4 +# define LISS_SELECTEDNOTFOCUS 5 +# define LISS_HOTSELECTED 6 +#endif +#ifndef BP_COMMANDLINK +# define BP_COMMANDLINK 6 +# define BP_COMMANDLINKGLYPH 7 +# define CMDLGS_NORMAL 1 +# define CMDLGS_HOT 2 +# define CMDLGS_PRESSED 3 +# define CMDLGS_DISABLED 4 +#endif + +// Runtime resolved theme engine function calls + + +typedef HRESULT (WINAPI *PtrGetThemePartSize)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, OPTIONAL RECT *prc, enum THEMESIZE eSize, OUT SIZE *psz); +typedef HTHEME (WINAPI *PtrOpenThemeData)(HWND hwnd, LPCWSTR pszClassList); +typedef HTHEME (WINAPI *PtrOpenThemeData)(HWND hwnd, LPCWSTR pszClassList); +typedef HRESULT (WINAPI *PtrCloseThemeData)(HTHEME hTheme); +typedef HRESULT (WINAPI *PtrDrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect); +typedef HRESULT (WINAPI *PtrDrawThemeBackgroundEx)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const DTBGOPTS *pOptions); +typedef HRESULT (WINAPI *PtrGetCurrentThemeName)(OUT LPWSTR pszThemeFileName, int cchMaxNameChars, OUT OPTIONAL LPWSTR pszColorBuff, int cchMaxColorChars, OUT OPTIONAL LPWSTR pszSizeBuff, int cchMaxSizeChars); +typedef HRESULT (WINAPI *PtrGetThemeBool)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT BOOL *pfVal); +typedef HRESULT (WINAPI *PtrGetThemeColor)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT COLORREF *pColor); +typedef HRESULT (WINAPI *PtrGetThemeEnumValue)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT int *piVal); +typedef HRESULT (WINAPI *PtrGetThemeFilename)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT LPWSTR pszThemeFileName, int cchMaxBuffChars); +typedef HRESULT (WINAPI *PtrGetThemeFont)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, OUT LOGFONT *pFont); +typedef HRESULT (WINAPI *PtrGetThemeInt)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT int *piVal); +typedef HRESULT (WINAPI *PtrGetThemeIntList)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT INTLIST *pIntList); +typedef HRESULT (WINAPI *PtrGetThemeMargins)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, OPTIONAL RECT *prc, OUT MARGINS *pMargins); +typedef HRESULT (WINAPI *PtrGetThemeMetric)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, OUT int *piVal); +typedef HRESULT (WINAPI *PtrGetThemePartSize)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, OPTIONAL RECT *prc, enum THEMESIZE eSize, OUT SIZE *psz); +typedef HRESULT (WINAPI *PtrGetThemePosition)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT POINT *pPoint); +typedef HRESULT (WINAPI *PtrGetThemeRect)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT RECT *pRect); +typedef HRESULT (WINAPI *PtrGetThemeString)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT LPWSTR pszBuff, int cchMaxBuffChars); +typedef HRESULT (WINAPI *PtrGetThemeTransitionDuration)(HTHEME hTheme, int iPartId, int iStateFromId, int iStateToId, int iPropId, int *pDuration); +typedef HRESULT (WINAPI *PtrIsThemePartDefined)(HTHEME hTheme, int iPartId, int iStateId); +typedef HRESULT (WINAPI *PtrSetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); +typedef HRESULT (WINAPI *PtrGetThemePropertyOrigin)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT enum PROPERTYORIGIN *pOrigin); + +static PtrIsThemePartDefined pIsThemePartDefined = 0; +static PtrOpenThemeData pOpenThemeData = 0; +static PtrCloseThemeData pCloseThemeData = 0; +static PtrDrawThemeBackground pDrawThemeBackground = 0; +static PtrDrawThemeBackgroundEx pDrawThemeBackgroundEx = 0; +static PtrGetCurrentThemeName pGetCurrentThemeName = 0; +static PtrGetThemeBool pGetThemeBool = 0; +static PtrGetThemeColor pGetThemeColor = 0; +static PtrGetThemeEnumValue pGetThemeEnumValue = 0; +static PtrGetThemeFilename pGetThemeFilename = 0; +static PtrGetThemeFont pGetThemeFont = 0; +static PtrGetThemeInt pGetThemeInt = 0; +static PtrGetThemeIntList pGetThemeIntList = 0; +static PtrGetThemeMargins pGetThemeMargins = 0; +static PtrGetThemeMetric pGetThemeMetric = 0; +static PtrGetThemePartSize pGetThemePartSize = 0; +static PtrGetThemePosition pGetThemePosition = 0; +static PtrGetThemeRect pGetThemeRect = 0; +static PtrGetThemeString pGetThemeString = 0; +static PtrGetThemeTransitionDuration pGetThemeTransitionDuration= 0; +static PtrSetWindowTheme pSetWindowTheme = 0; +static PtrGetThemePropertyOrigin pGetThemePropertyOrigin = 0; + +/* \internal + Checks if we should use Vista style , or if we should + fall back to Windows style. +*/ +bool QWindowsVistaStylePrivate::useVista() +{ + return (QWindowsVistaStylePrivate::useXP() && + (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && + QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)); +} + +/*! + \class QWindowsVistaStyle + \brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista. + \since 4.3 + \ingroup appearance + + \warning This style is only available on the Windows Vista platform + because it makes use of Windows Vista's style engine. + + \sa QMacStyle, QWindowsXPStyle, QPlastiqueStyle, QCleanlooksStyle, QMotifStyle +*/ + +/*! + Constructs a QWindowsVistaStyle object. +*/ +QWindowsVistaStyle::QWindowsVistaStyle() + : QWindowsXPStyle(*new QWindowsVistaStylePrivate) +{ +} + +//convert Qt state flags to uxtheme button states +int buttonStateId(int flags, int partId) +{ + int stateId = 0; + if (partId == BP_RADIOBUTTON || partId == BP_CHECKBOX) { + if (!(flags & QStyle::State_Enabled)) + stateId = RBS_UNCHECKEDDISABLED; + else if (flags & QStyle::State_Sunken) + stateId = RBS_UNCHECKEDPRESSED; + else if (flags & QStyle::State_MouseOver) + stateId = RBS_UNCHECKEDHOT; + else + stateId = RBS_UNCHECKEDNORMAL; + + if (flags & QStyle::State_On) + stateId += RBS_CHECKEDNORMAL-1; + + } else if (partId == BP_PUSHBUTTON) { + if (!(flags & QStyle::State_Enabled)) + stateId = PBS_DISABLED; + else if (flags & (QStyle::State_Sunken | QStyle::State_On)) + stateId = PBS_PRESSED; + else if (flags & QStyle::State_MouseOver) + stateId = PBS_HOT; + else + stateId = PBS_NORMAL; + } else { + Q_ASSERT(1); + } + return stateId; +} + +void Animation::paint(QPainter *painter, const QStyleOption *option) +{ + Q_UNUSED(option); + Q_UNUSED(painter); +} + +/* +* ! \internal +* +* Helperfunction to paint the current transition state +* between two animation frames. +* +* The result is a blended image consisting of +* ((alpha)*_primaryImage) + ((1-alpha)*_secondaryImage) +* +*/ + +void Animation::drawBlendedImage(QPainter *painter, QRect rect, float alpha) { + if (_secondaryImage.isNull() || _primaryImage.isNull()) + return; + + if (_tempImage.isNull()) + _tempImage = _secondaryImage; + + const int a = qRound(alpha*256); + const int ia = 256 - a; + const int sw = _primaryImage.width(); + const int sh = _primaryImage.height(); + const int bpl = _primaryImage.bytesPerLine(); + switch(_primaryImage.depth()) { + case 32: + { + uchar *mixed_data = _tempImage.bits(); + const uchar *back_data = _primaryImage.bits(); + const uchar *front_data = _secondaryImage.bits(); + for (int sy = 0; sy < sh; sy++) { + quint32* mixed = (quint32*)mixed_data; + const quint32* back = (const quint32*)back_data; + const quint32* front = (const quint32*)front_data; + for (int sx = 0; sx < sw; sx++) { + quint32 bp = back[sx]; + quint32 fp = front[sx]; + mixed[sx] = qRgba ((qRed(bp)*ia + qRed(fp)*a)>>8, + (qGreen(bp)*ia + qGreen(fp)*a)>>8, + (qBlue(bp)*ia + qBlue(fp)*a)>>8, + (qAlpha(bp)*ia + qAlpha(fp)*a)>>8); + } + mixed_data += bpl; + back_data += bpl; + front_data += bpl; + } + } + default: + break; + } + painter->drawImage(rect, _tempImage); +} + +/* +* ! \internal +* +* Paints a transition state. The result will be a mix between the +* initial and final state of the transition, depending on the +* time difference between _startTime and current time. +*/ + +void Transition::paint(QPainter *painter, const QStyleOption *option) +{ + float alpha = 1.0; + if (_duration > 0) { + QTime current = QTime::currentTime(); + + if (_startTime > current) + _startTime = current; + + int timeDiff = _startTime.msecsTo(current); + alpha = timeDiff/(float)_duration; + if (timeDiff > _duration) { + _running = false; + alpha = 1.0; + } + } + else { + _running = false; + } + drawBlendedImage(painter, option->rect, alpha); +} + +/* +* ! \internal +* +* Paints a pulse. The result will be a mix between the +* primary and secondary pulse images depending on the +* time difference between _startTime and current time. +*/ + + +void Pulse::paint(QPainter *painter, const QStyleOption *option) +{ + float alpha = 1.0; + if (_duration > 0) { + QTime current = QTime::currentTime(); + + if (_startTime > current) + _startTime = current; + + int timeDiff = _startTime.msecsTo(current) % _duration*2; + if (timeDiff > _duration) + timeDiff = _duration*2 - timeDiff; + alpha = timeDiff/(float)_duration; + } else { + _running = false; + } + drawBlendedImage(painter, option->rect, alpha); +} + + +/*! + \reimp + * + * Animations are used for some state transitions on specific widgets. + * + * Only one running animation can exist for a widget at any specific time. + * Animations can be added through QWindowsVistaStylePrivate::startAnimation(Animation *) + * and any existing animation on a widget can be retrieved with + * QWindowsVistaStylePrivate::widgetAnimation(Widget *). + * + * Once an animation has been started, QWindowsVistaStylePrivate::timerEvent(QTimerEvent *) + * will continuously call update() on the widget until it is stopped, meaning that drawPrimitive + * will be called many times until the transition has completed. During this time, the result + * will be retrieved by the Animation::paint(...) function and not by the style itself. + * + * To determine if a transition should occur, the style needs to know the previous state of the + * widget as well as the current one. This is solved by updating dynamic properties on the widget + * every time the function is called. + * + * Transitions interrupting existing transitions should always be smooth, so whenever a hover-transition + * is started on a pulsating button, it uses the current frame of the pulse-animation as the + * starting image for the hover transition. + * + */ +void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func()); + + int state = option->state; + if (!QWindowsVistaStylePrivate::useVista()) { + QWindowsStyle::drawPrimitive(element, option, painter, widget); + return; + } + + QRect oldRect; + QRect newRect; + + if (widget && d->transitionsEnabled()) + { + /* all widgets that supports state transitions : */ + if ( +#ifndef QT_NO_LINEEDIT + (qobject_cast<const QLineEdit*>(widget) && element == PE_FrameLineEdit) || +#endif // QT_NO_LINEEDIT + (qobject_cast<const QRadioButton*>(widget)&& element == PE_IndicatorRadioButton) || + (qobject_cast<const QCheckBox*>(widget) && element == PE_IndicatorCheckBox) || + (qobject_cast<const QGroupBox *>(widget)&& element == PE_IndicatorCheckBox) || + (qobject_cast<const QToolButton*>(widget) && element == PE_PanelButtonBevel) + ) + { + // Retrieve and update the dynamic properties tracking + // the previous state of the widget: + QWidget *w = const_cast<QWidget *> (widget); + int oldState = w->property("_q_stylestate").toInt(); + oldRect = w->property("_q_stylerect").toRect(); + newRect = w->rect(); + w->setProperty("_q_stylestate", (int)option->state); + w->setProperty("_q_stylerect", w->rect()); + + bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || + (state & State_On) != (oldState & State_On) || + (state & State_MouseOver) != (oldState & State_MouseOver)); + + if (oldRect != newRect || + (state & State_Enabled) != (oldState & State_Enabled) || + (state & State_Active) != (oldState & State_Active)) + d->stopAnimation(widget); + +#ifndef QT_NO_LINEEDIT + if (const QLineEdit *edit = qobject_cast<const QLineEdit *>(widget)) + if (edit->isReadOnly() && element == PE_FrameLineEdit) // Do not animate read only line edits + doTransition = false; +#endif // QT_NO_LINEEDIT + + if (doTransition) { + + // We create separate images for the initial and final transition states and store them in the + // Transition object. + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + QStyleOption opt = *option; + + opt.rect.setRect(0, 0, option->rect.width(), option->rect.height()); + opt.state = (QStyle::State)oldState; + startImage.fill(0); + QPainter startPainter(&startImage); + + Animation *anim = d->widgetAnimation(widget); + Transition *t = new Transition; + t->setWidget(w); + + // If we have a running animation on the widget already, we will use that to paint the initial + // state of the new transition, this ensures a smooth transition from a current animation such as a + // pulsating default button into the intended target state. + + if (!anim) + drawPrimitive(element, &opt, &startPainter, 0); // Note that the widget pointer is intentionally 0 + else // this ensures that we do not recurse in the animation logic above + anim->paint(&startPainter, &opt); + + d->startAnimation(t); + t->setStartImage(startImage); + + // The end state of the transition is simply the result we would have painted + // if the style was not animated. + + QPainter endPainter(&endImage); + endImage.fill(0); + QStyleOption opt2 = opt; + opt2.state = option->state; + drawPrimitive(element, &opt2, &endPainter, 0); // Note that the widget pointer is intentionally 0 + // this ensures that we do not recurse in the animation logic above + t->setEndImage(endImage); + + HTHEME theme; + int partId; + int duration; + int fromState = 0; + int toState = 0; + + //translate state flags to UXTHEME states : + if (element == PE_FrameLineEdit) { + theme = pOpenThemeData(0, L"Edit"); + partId = EP_EDITBORDER_NOSCROLL; + + if (oldState & State_MouseOver) + fromState = ETS_HOT; + else if (oldState & State_HasFocus) + fromState = ETS_FOCUSED; + else + fromState = ETS_NORMAL; + + if (state & State_MouseOver) + toState = ETS_HOT; + else if (state & State_HasFocus) + toState = ETS_FOCUSED; + else + toState = ETS_NORMAL; + + } else { + theme = pOpenThemeData(0, L"Button"); + if (element == PE_IndicatorRadioButton) + partId = BP_RADIOBUTTON; + else if (element == PE_IndicatorCheckBox) + partId = BP_CHECKBOX; + else + partId = BP_PUSHBUTTON; + + fromState = buttonStateId(oldState, partId); + toState = buttonStateId(option->state, partId); + } + + // Retrieve the transition time between the states from the system. + if (theme && pGetThemeTransitionDuration(theme, partId, fromState, toState, + TMT_TRANSITIONDURATIONS, &duration) == S_OK) + { + t->setDuration(duration); + } + t->setStartTime(QTime::currentTime()); + } + } + } // End of animation part + + + QRect rect = option->rect; + + switch (element) { + case PE_IndicatorHeaderArrow: + if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + int stateId = HSAS_SORTEDDOWN; + if (header->sortIndicator & QStyleOptionHeader::SortDown) + stateId = HSAS_SORTEDUP; //note that the uxtheme sort down indicator is the inverse of ours + XPThemeData theme(widget, painter, QLatin1String("HEADER"), HP_HEADERSORTARROW, stateId, option->rect); + d->drawBackground(theme); + } + break; + + case PE_IndicatorBranch: + { + XPThemeData theme(d->treeViewHelper(), painter, QLatin1String("TREEVIEW")); + static const int decoration_size = 16; + int mid_h = option->rect.x() + option->rect.width() / 2; + int mid_v = option->rect.y() + option->rect.height() / 2; + int bef_h = mid_h; + int bef_v = mid_v; + int aft_h = mid_h; + int aft_v = mid_v; + if (option->state & State_Children) { + int delta = decoration_size / 2; + theme.rect = QRect(bef_h - delta, bef_v - delta, decoration_size, decoration_size); + theme.partId = option->state & State_MouseOver ? TVP_HOTGLYPH : TVP_GLYPH; + theme.stateId = option->state & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED; + if (option->direction == Qt::RightToLeft) + theme.mirrorHorizontally = true; + d->drawBackground(theme); + bef_h -= delta + 2; + bef_v -= delta + 2; + aft_h += delta - 2; + aft_v += delta - 2; + } +#if 0 + QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern); + if (option->state & State_Item) { + if (option->direction == Qt::RightToLeft) + painter->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush); + else + painter->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush); + } + if (option->state & State_Sibling && option->rect.bottom() > aft_v) + painter->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush); + if (option->state & (State_Open | State_Children | State_Item | State_Sibling) && (bef_v > option->rect.y())) + painter->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush); +#endif + } + break; + + case PE_PanelButtonBevel: + case PE_IndicatorCheckBox: + case PE_IndicatorRadioButton: + { + if (Animation *a = d->widgetAnimation(widget)) { + a->paint(painter, option); + } else { + QWindowsXPStyle::drawPrimitive(element, option, painter, widget); + } + } + break; + + case PE_IndicatorToolBarHandle: + { + XPThemeData theme; + if (option->state & State_Horizontal) + theme = XPThemeData(widget, painter, QLatin1String("REBAR"), RP_GRIPPER, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2)); + else + theme = XPThemeData(widget, painter, QLatin1String("REBAR"), RP_GRIPPERVERT, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2)); + d->drawBackground(theme); + } + break; + + case PE_FrameMenu: + { + int stateId = option->state & State_Active ? MB_ACTIVE : MB_INACTIVE; + XPThemeData theme(widget, painter, QLatin1String("MENU"), MENU_POPUPBORDERS, stateId, option->rect); + d->drawBackground(theme); + } + break; + case PE_Frame: +#ifndef QT_NO_TEXTEDIT + if (const QTextEdit *edit = qobject_cast<const QTextEdit*>(widget)) { + painter->save(); + int stateId = ETS_NORMAL; + if (!(state & State_Enabled)) + stateId = ETS_DISABLED; + else if (edit->isReadOnly()) + stateId = ETS_READONLY; + else if (state & State_HasFocus) + stateId = ETS_SELECTED; + XPThemeData theme(widget, painter, QLatin1String("EDIT"), EP_EDITBORDER_HVSCROLL, stateId, option->rect); + uint resolve_mask = option->palette.resolve(); + if (resolve_mask & (1 << QPalette::Base)) { + // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping + int borderSize = 1; + pGetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize); + QRegion clipRegion = option->rect; + QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize); + clipRegion ^= content; + painter->setClipRegion(clipRegion); + } + d->drawBackground(theme); + painter->restore(); + } else +#endif // QT_NO_TEXTEDIT + QWindowsXPStyle::drawPrimitive(element, option, painter, widget); + break; + + case PE_PanelLineEdit: + if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) { + QBrush bg; + bool usePalette = false; + bool isEnabled = option->state & State_Enabled; + uint resolve_mask = panel->palette.resolve(); + if (widget) { + //Since spin box and combo box includes a line edit we need to resolve the palette on the parent instead +#ifndef QT_NO_SPINBOX + if (QAbstractSpinBox *spinbox = qobject_cast<QAbstractSpinBox*>(widget->parentWidget())) + resolve_mask = spinbox->palette().resolve(); +#endif // QT_NO_SPINBOX +#ifndef QT_NO_COMBOBOX + if (QComboBox *combobox = qobject_cast<QComboBox*>(widget->parentWidget())) + resolve_mask = combobox->palette().resolve(); +#endif // QT_NO_COMBOBOX + } + if (resolve_mask & (1 << QPalette::Base)) { + // Base color is set for this widget, so use it + bg = panel->palette.brush(QPalette::Base); + usePalette = true; + } + if (usePalette) { + painter->fillRect(panel->rect, bg); + } else { + int partId = EP_BACKGROUND; + int stateId = EBS_NORMAL; + if (!isEnabled) + stateId = EBS_DISABLED; + else if (state & State_ReadOnly) + stateId = EBS_READONLY; + else if (state & State_MouseOver) + stateId = EBS_HOT; + + XPThemeData theme(0, painter, QLatin1String("EDIT"), partId, stateId, rect); + if (!theme.isValid()) { + QWindowsStyle::drawPrimitive(element, option, painter, widget); + return; + } + int bgType; + pGetThemeEnumValue( theme.handle(), + partId, + stateId, + TMT_BGTYPE, + &bgType); + if( bgType == BT_IMAGEFILE ) { + d->drawBackground(theme); + } else { + QBrush fillColor = option->palette.brush(QPalette::Base); + if (!isEnabled) { + PROPERTYORIGIN origin = PO_NOTFOUND; + pGetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin); + // Use only if the fill property comes from our part + if ((origin == PO_PART || origin == PO_STATE)) { + COLORREF bgRef; + pGetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef); + fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef))); + } + } + painter->fillRect(option->rect, fillColor); + } + } + if (panel->lineWidth > 0) + drawPrimitive(PE_FrameLineEdit, panel, painter, widget); + return; + } + break; + + case PE_FrameLineEdit: + if (Animation *anim = d->widgetAnimation(widget)) { + anim->paint(painter, option); + } else { + QPainter *p = painter; + QWidget *parentWidget = 0; + if (widget) { + parentWidget = widget->parentWidget(); + if (parentWidget) + parentWidget = parentWidget->parentWidget(); + } + if (widget && widget->inherits("QLineEdit") + && parentWidget && parentWidget->inherits("QAbstractItemView")) { + // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class. + QPen oldPen = p->pen(); + // Inner white border + p->setPen(QPen(option->palette.base().color(), 1)); + p->drawRect(option->rect.adjusted(1, 1, -2, -2)); + // Outer dark border + p->setPen(QPen(option->palette.shadow().color(), 1)); + p->drawRect(option->rect.adjusted(0, 0, -1, -1)); + p->setPen(oldPen); + return; + } else { + int stateId = ETS_NORMAL; + if (!(state & State_Enabled)) + stateId = ETS_DISABLED; + else if (state & State_ReadOnly) + stateId = ETS_READONLY; + else if (state & State_MouseOver) + stateId = ETS_HOT; + else if (state & State_HasFocus) + stateId = ETS_SELECTED; + XPThemeData theme(widget, painter, QLatin1String("EDIT"), EP_EDITBORDER_NOSCROLL, stateId, option->rect); + painter->save(); + QRegion clipRegion = option->rect; + clipRegion -= option->rect.adjusted(2, 2, -2, -2); + painter->setClipRegion(clipRegion); + d->drawBackground(theme); + painter->restore(); + } + } + break; + + case PE_IndicatorToolBarSeparator: + { + QPen pen = painter->pen(); + int margin = 3; + painter->setPen(option->palette.background().color().darker(114)); + if (option->state & State_Horizontal) { + int x1 = option->rect.center().x(); + painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin)); + } else { + int y1 = option->rect.center().y(); + painter->drawLine(QPoint(option->rect.left() + margin, y1), QPoint(option->rect.right() - margin, y1)); + } + painter->setPen(pen); + } + break; + + case PE_PanelTipLabel: { + XPThemeData theme(widget, painter, QLatin1String("TOOLTIP"), TTP_STANDARD, TTSS_NORMAL, option->rect); + d->drawBackground(theme); + break; + } + + case PE_PanelItemViewItem: + { + const QStyleOptionViewItemV4 *vopt; + const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget); + bool newStyle = false; + + if (const QListView *listview = qobject_cast<const QListView *>(widget)) { + if (listview->viewMode() == QListView::IconMode) + newStyle = true; + } else if (const QTreeView* treeview = qobject_cast<const QTreeView *>(widget)) { + newStyle = true; + } + if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option))) { + bool selected = vopt->state & QStyle::State_Selected; + bool hover = vopt->state & QStyle::State_MouseOver; + bool active = vopt->state & QStyle::State_Active; + + if (vopt->features & QStyleOptionViewItemV2::Alternate) + painter->fillRect(vopt->rect, vopt->palette.alternateBase()); + + QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled + ? QPalette::Normal : QPalette::Disabled; + if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active)) + cg = QPalette::Inactive; + + QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, option, widget); + QRect itemRect = subElementRect(QStyle::SE_ItemViewItemFocusRect, option, widget).adjusted(-1, 0, 1, 0); + itemRect.setTop(vopt->rect.top()); + itemRect.setBottom(vopt->rect.bottom()); + + QSize sectionSize = itemRect.size(); + if (vopt->showDecorationSelected) + sectionSize = vopt->rect.size(); + + if (view->selectionBehavior() == QAbstractItemView::SelectRows) + sectionSize.setWidth(vopt->rect.width()); + if (view->selectionMode() == QAbstractItemView::NoSelection) + hover = false; + QPixmap pixmap; + + if (vopt->backgroundBrush.style() != Qt::NoBrush) { + QPointF oldBO = painter->brushOrigin(); + painter->setBrushOrigin(vopt->rect.topLeft()); + painter->fillRect(vopt->rect, vopt->backgroundBrush); + } + + if (hover || selected) { + QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width()) + .arg(sectionSize.height()).arg(selected).arg(active).arg(hover); + if (!QPixmapCache::find(key, pixmap)) { + pixmap = QPixmap(sectionSize); + pixmap.fill(Qt::transparent); + + int state; + if (selected && hover) + state = LISS_HOTSELECTED; + else if (selected && !active) + state = LISS_SELECTEDNOTFOCUS; + else if (selected) + state = LISS_SELECTED; + else + state = LISS_HOT; + + QPainter pixmapPainter(&pixmap); + XPThemeData theme(d->treeViewHelper(), &pixmapPainter, QLatin1String("TREEVIEW"), + LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height())); + if (theme.isValid()) { + d->drawBackground(theme); + } else { + QWindowsXPStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget); + break;; + } + QPixmapCache::insert(key, pixmap); + } + + if (vopt->showDecorationSelected) { + const int frame = 2; //Assumes a 2 pixel pixmap border + QRect srcRect = QRect(0, 0, sectionSize.width(), sectionSize.height()); + QRect pixmapRect = vopt->rect; + bool reverse = vopt->direction == Qt::RightToLeft; + bool leftSection = vopt->viewItemPosition == QStyleOptionViewItemV4::Beginning; + bool rightSection = vopt->viewItemPosition == QStyleOptionViewItemV4::End; + if (vopt->viewItemPosition == QStyleOptionViewItemV4::OnlyOne + || vopt->viewItemPosition == QStyleOptionViewItemV4::Invalid) + painter->drawPixmap(pixmapRect.topLeft(), pixmap); + else if (reverse ? rightSection : leftSection) + painter->drawPixmap(pixmapRect, pixmap, srcRect.adjusted(0, 0, -frame, 0)); + else if (reverse ? leftSection : rightSection) + painter->drawPixmap(pixmapRect, pixmap, + srcRect.adjusted(frame, 0, 0, 0)); + else if (vopt->viewItemPosition == QStyleOptionViewItemV4::Middle) + painter->drawPixmap(pixmapRect, pixmap, + srcRect.adjusted(frame, 0, -frame, 0)); + } else { + if (vopt->text.isEmpty() && vopt->icon.isNull()) + break; + painter->drawPixmap(itemRect.topLeft(), pixmap); + } + } + } else { + QWindowsXPStyle::drawPrimitive(element, option, painter, widget); + } + break; + } + case PE_Widget: + { + const QDialogButtonBox *buttonBox = 0; + + if (qobject_cast<const QMessageBox *> (widget)) + buttonBox = qFindChild<const QDialogButtonBox *>(widget,QLatin1String("qt_msgbox_buttonbox")); +#ifndef QT_NO_INPUTDIALOG + else if (qobject_cast<const QInputDialog *> (widget)) + buttonBox = qFindChild<const QDialogButtonBox *>(widget,QLatin1String("qt_inputdlg_buttonbox")); +#endif // QT_NO_INPUTDIALOG + + if (buttonBox) { + //draw white panel part + XPThemeData theme(widget, painter, QLatin1String("TASKDIALOG"), TDLG_PRIMARYPANEL, 0, option->rect); + QRect toprect = option->rect; + toprect.setBottom(buttonBox->geometry().top()); + theme.rect = toprect; + d->drawBackground(theme); + + //draw bottom panel part + QRect buttonRect = option->rect; + buttonRect.setTop(buttonBox->geometry().top()); + theme.rect = buttonRect; + theme.partId = TDLG_SECONDARYPANEL; + d->drawBackground(theme); + } + } + break; + default: + QWindowsXPStyle::drawPrimitive(element, option, painter, widget); + break; + } +} + + +/*! + + \reimp + + see drawPrimitive for comments on the animation support + + */ +void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func()); + + if (!QWindowsVistaStylePrivate::useVista()) { + QWindowsStyle::drawControl(element, option, painter, widget); + return; + } + + bool selected = option->state & State_Selected; + bool pressed = option->state & State_Sunken; + bool disabled = !(option->state & State_Enabled); + + int state = option->state; + QString name; + + QRect rect(option->rect); + State flags = option->state; + int partId = 0; + int stateId = 0; + + QRect oldRect; + QRect newRect; + + if (d->transitionsEnabled() && widget) { + if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) { + if ((qobject_cast<const QPushButton*>(widget) && element == CE_PushButtonBevel)) + { + QWidget *w = const_cast<QWidget *> (widget); + int oldState = w->property("_q_stylestate").toInt(); + oldRect = w->property("_q_stylerect").toRect(); + newRect = w->rect(); + w->setProperty("_q_stylestate", (int)option->state); + w->setProperty("_q_stylerect", w->rect()); + + bool wasDefault = w->property("_q_isdefault").toBool(); + bool isDefault = button->features & QStyleOptionButton::DefaultButton; + w->setProperty("_q_isdefault", isDefault); + + bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || + (state & State_On) != (oldState & State_On) || + (state & State_MouseOver) != (oldState & State_MouseOver)); + + if (oldRect != newRect || (wasDefault && !isDefault)) + { + doTransition = false; + d->stopAnimation(widget); + } + + if (doTransition) { + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + Animation *anim = d->widgetAnimation(widget); + + QStyleOptionButton opt = *button; + opt.state = (QStyle::State)oldState; + + startImage.fill(0); + Transition *t = new Transition; + t->setWidget(w); + QPainter startPainter(&startImage); + + if (!anim) { + drawControl(element, &opt, &startPainter, 0 /* Intentional */); + } else { + anim->paint(&startPainter, &opt); + d->stopAnimation(widget); + } + + t->setStartImage(startImage); + d->startAnimation(t); + + endImage.fill(0); + QPainter endPainter(&endImage); + drawControl(element, option, &endPainter, 0 /* Intentional */); + t->setEndImage(endImage); + int duration = 0; + HTHEME theme = pOpenThemeData(0, L"Button"); + + int fromState = buttonStateId(oldState, BP_PUSHBUTTON); + int toState = buttonStateId(option->state, BP_PUSHBUTTON); + if (pGetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK) + t->setDuration(duration); + else + t->setDuration(0); + t->setStartTime(QTime::currentTime()); + } + } + } + } + switch (element) { + case CE_PushButtonBevel: + if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) + { + + if (Animation *anim = d->widgetAnimation(widget)) { + anim->paint(painter, option); + } else { + name = QLatin1String("BUTTON"); + partId = BP_PUSHBUTTON; + if (btn->features & QStyleOptionButton::CommandLinkButton) + partId = BP_COMMANDLINK; + bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken)); + if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat)) + stateId = PBS_DISABLED; + else if (justFlat) + ; + else if (flags & (State_Sunken | State_On)) + stateId = PBS_PRESSED; + else if (flags & State_MouseOver) + stateId = PBS_HOT; + else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active)) + stateId = PBS_DEFAULTED; + else + stateId = PBS_NORMAL; + + if (!justFlat) { + + if (widget && d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) && + !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) && + (state & State_Enabled) && (state & State_Active)) + { + Animation *anim = d->widgetAnimation(widget); + if (!anim && widget) { + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + startImage.fill(0); + QImage alternateImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + alternateImage.fill(0); + + Pulse *pulse = new Pulse; + pulse->setWidget(const_cast<QWidget*>(widget)); + + QPainter startPainter(&startImage); + stateId = PBS_DEFAULTED; + XPThemeData theme(widget, &startPainter, name, partId, stateId, rect); + d->drawBackground(theme); + + QPainter alternatePainter(&alternateImage); + theme.stateId = PBS_DEFAULTED_ANIMATING; + theme.painter = &alternatePainter; + d->drawBackground(theme); + pulse->setPrimaryImage(startImage); + pulse->setAlternateImage(alternateImage); + pulse->setStartTime(QTime::currentTime()); + pulse->setDuration(2000); + d->startAnimation(pulse); + anim = pulse; + } + + if (anim) + anim->paint(painter, option); + else { + XPThemeData theme(widget, painter, name, partId, stateId, rect); + d->drawBackground(theme); + } + } + else { + d->stopAnimation(widget); + XPThemeData theme(widget, painter, name, partId, stateId, rect); + d->drawBackground(theme); + } + } + } + if (btn->features & QStyleOptionButton::HasMenu) { + int mbiw = 0, mbih = 0; + XPThemeData theme(widget, 0, QLatin1String("TOOLBAR"), TP_DROPDOWNBUTTON); + if (theme.isValid()) { + SIZE size; + if (pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size) == S_OK) { + mbiw = size.cx; + mbih = size.cy; + } + } + QRect ir = subElementRect(SE_PushButtonContents, option, 0); + QStyleOptionButton newBtn = *btn; + newBtn.rect = QStyle::visualRect(option->direction, option->rect, + QRect(ir.right() - mbiw - 2, (option->rect.height()/2) - (mbih/2), + mbiw + 1, mbih + 1)); + drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget); + } + return; + } + break; +#ifndef QT_NO_PROGRESSBAR + case CE_ProgressBarContents: + if (const QStyleOptionProgressBar *bar + = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) { + int stateId = MBI_NORMAL; + if (disabled) + stateId = MBI_DISABLED; + bool isIndeterminate = (bar->minimum == 0 && bar->maximum == 0); + bool vertical = false; + bool inverted = false; + if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { + vertical = (pb2->orientation == Qt::Vertical); + inverted = pb2->invertedAppearance; + } + + if (const QProgressBar *progressbar = qobject_cast<const QProgressBar *>(widget)) { + if (((progressbar->value() > 0 && d->transitionsEnabled()) || isIndeterminate)) { + if (!d->widgetAnimation(progressbar) && progressbar->value() < progressbar->maximum()) { + Animation *a = new Animation; + a->setWidget(const_cast<QWidget*>(widget)); + a->setStartTime(QTime::currentTime()); + d->startAnimation(a); + } + } else { + d->stopAnimation(progressbar); + } + } + + XPThemeData theme(widget, painter, QLatin1String("PROGRESS"), vertical ? PP_FILLVERT : PP_FILL); + theme.rect = option->rect; + bool reverse = bar->direction == Qt::LeftToRight && inverted || bar->direction == Qt::RightToLeft && !inverted; + QTime current = QTime::currentTime(); + + if (isIndeterminate) { + if (Animation *a = d->widgetAnimation(widget)) { + int glowSize = 120; + int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width()); + int animOffset = a->startTime().msecsTo(current) / 4; + if (animOffset > animationWidth) + a->setStartTime(QTime::currentTime()); + painter->save(); + painter->setClipRect(theme.rect); + QRect animRect; + QSize pixmapSize(14, 14); + if (vertical) { + animRect = QRect(theme.rect.left(), + inverted ? rect.top() - glowSize + animOffset : + rect.bottom() + glowSize - animOffset, + rect.width(), glowSize); + pixmapSize.setHeight(animRect.height()); + } else { + animRect = QRect(rect.left() - glowSize + animOffset, + rect.top(), glowSize, rect.height()); + animRect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, + option->rect, animRect); + pixmapSize.setWidth(animRect.width()); + } + QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height()); + QPixmap pixmap; + if (!QPixmapCache::find(name, pixmap)) { + QImage image(pixmapSize, QImage::Format_ARGB32); + image.fill(Qt::transparent); + QPainter imagePainter(&image); + theme.painter = &imagePainter; + theme.partId = vertical ? PP_FILLVERT : PP_FILL; + theme.rect = QRect(QPoint(0,0), theme.rect.size()); + QLinearGradient alphaGradient(0, 0, vertical ? 0 : image.width(), + vertical ? image.height() : 0); + alphaGradient.setColorAt(0, QColor(0, 0, 0, 0)); + alphaGradient.setColorAt(0.5, QColor(0, 0, 0, 220)); + alphaGradient.setColorAt(1, QColor(0, 0, 0, 0)); + imagePainter.fillRect(image.rect(), alphaGradient); + imagePainter.setCompositionMode(QPainter::CompositionMode_SourceIn); + d->drawBackground(theme); + imagePainter.end(); + pixmap = QPixmap::fromImage(image); + QPixmapCache::insert(name, pixmap); + } + painter->drawPixmap(animRect, pixmap); + painter->restore(); + } + } + else { + qint64 progress = qMax<qint64>(bar->progress, bar->minimum); // workaround for bug in QProgressBar + + if (vertical) { + int maxHeight = option->rect.height(); + int minHeight = 0; + double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxHeight); + int height = isIndeterminate ? maxHeight: qMax(int(vc6_workaround), minHeight); + theme.rect.setHeight(height); + if (!inverted) + theme.rect.moveTop(rect.height() - theme.rect.height()); + } else { + int maxWidth = option->rect.width(); + int minWidth = 0; + double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth); + int width = isIndeterminate ? maxWidth : qMax(int(vc6_workaround), minWidth); + theme.rect.setWidth(width); + theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, + option->rect, theme.rect); + } + d->drawBackground(theme); + + if (Animation *a = d->widgetAnimation(widget)) { + int glowSize = 140; + int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width()); + int animOffset = a->startTime().msecsTo(current) / 4; + theme.partId = vertical ? PP_MOVEOVERLAYVERT : PP_MOVEOVERLAY; + if (animOffset > animationWidth) { + if (bar->progress < bar->maximum) + a->setStartTime(QTime::currentTime()); + else + d->stopAnimation(widget); //we stop the glow motion only after it has + //moved out of view + } + painter->save(); + painter->setClipRect(theme.rect); + if (vertical) { + theme.rect = QRect(theme.rect.left(), + inverted ? rect.top() - glowSize + animOffset : + rect.bottom() + glowSize - animOffset, + rect.width(), glowSize); + } else { + theme.rect = QRect(rect.left() - glowSize + animOffset,rect.top(), glowSize, rect.height()); + theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, option->rect, theme.rect); + } + d->drawBackground(theme); + painter->restore(); + } + } + } + break; +#endif // QT_NO_PROGRESSBAR + case CE_MenuBarItem: + { + + if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) + { + if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem) + break; + + QPalette::ColorRole textRole = disabled ? QPalette::Text : QPalette::ButtonText; + QPixmap pix = mbi->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal); + + uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; + if (!styleHint(SH_UnderlineShortcut, mbi, widget)) + alignment |= Qt::TextHideMnemonic; + + //The rect adjustment is a workaround for the menu not really filling its background. + XPThemeData theme(widget, painter, QLatin1String("MENU"), MENU_BARBACKGROUND, 0, option->rect.adjusted(-1, 1 , 2, 1)); + d->drawBackground(theme); + + int stateId = MBI_NORMAL; + if (disabled) + stateId = MBI_DISABLED; + else if (pressed) + stateId = MBI_PUSHED; + else if (selected) + stateId = MBI_HOT; + + XPThemeData theme2(widget, painter, QLatin1String("MENU"), MENU_BARITEM, stateId, option->rect); + d->drawBackground(theme2); + + if (!pix.isNull()) + drawItemPixmap(painter, mbi->rect, alignment, pix); + else + drawItemText(painter, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole); + } + } + break; +#ifndef QT_NO_MENU + case CE_MenuItem: + if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { + // windows always has a check column, regardless whether we have an icon or not + int checkcol = qMax(menuitem->maxIconWidth, 28); + QColor darkLine = option->palette.background().color().darker(108); + QColor lightLine = option->palette.background().color().lighter(107); + QRect rect = option->rect; + QStyleOptionMenuItem mbiCopy = *menuitem; + + //draw vertical menu line + QPoint p1 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.top())); + QPoint p2 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.bottom())); + QRect gutterRect(p1.x(), p1.y(), 3, p2.y() - p1.y() + 1); + XPThemeData theme2(widget, painter, QLatin1String("MENU"), MENU_POPUPGUTTER, stateId, gutterRect); + d->drawBackground(theme2); + + int x, y, w, h; + menuitem->rect.getRect(&x, &y, &w, &h); + int tab = menuitem->tabWidth; + bool dis = !(menuitem->state & State_Enabled); + bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable + ? menuitem->checked : false; + bool act = menuitem->state & State_Selected; + + if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) { + int yoff = y-2 + h / 2; + QPoint p1 = QPoint(x + checkcol, yoff); + QPoint p2 = QPoint(x + w + 6 , yoff); + int stateId = stateId = MBI_HOT; + QRect subRect(p1.x(), p1.y(), p2.x() - p1.x(), 6); + subRect = QStyle::visualRect(option->direction, option->rect, subRect ); + XPThemeData theme2(widget, painter, QLatin1String("MENU"), MENU_POPUPSEPARATOR, stateId, subRect); + d->drawBackground(theme2); + return; + } + + QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(), + menuitem->rect.y(), checkcol - 6, menuitem->rect.height())); + + if (act) { + int stateId = stateId = MBI_HOT; + XPThemeData theme2(widget, painter, QLatin1String("MENU"), MENU_POPUPITEM, stateId, option->rect); + d->drawBackground(theme2); + } + + if (checked) { + XPThemeData theme(widget, painter, QLatin1String("MENU"), MENU_POPUPCHECKBACKGROUND, + menuitem->icon.isNull() ? MBI_HOT : MBI_PUSHED, vCheckRect); + d->drawBackground(theme); + if (menuitem->icon.isNull()) { + theme.partId = MENU_POPUPCHECK; + bool bullet = menuitem->checkType & QStyleOptionMenuItem::Exclusive; + if (dis) + theme.stateId = bullet ? MC_BULLETDISABLED: MC_CHECKMARKDISABLED; + else + theme.stateId = bullet ? MC_BULLETNORMAL: MC_CHECKMARKNORMAL; + d->drawBackground(theme); + } + } + + if (!menuitem->icon.isNull()) { + QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; + if (act && !dis) + mode = QIcon::Active; + QPixmap pixmap; + if (checked) + pixmap = menuitem->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On); + else + pixmap = menuitem->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), mode); + int pixw = pixmap.width(); + int pixh = pixmap.height(); + QRect pmr(0, 0, pixw, pixh); + pmr.moveCenter(vCheckRect.center()); + painter->setPen(menuitem->palette.text().color()); + painter->drawPixmap(pmr.topLeft(), pixmap); + } + + painter->setPen(menuitem->palette.buttonText().color()); + + QColor discol; + if (dis) { + discol = menuitem->palette.text().color(); + painter->setPen(discol); + } + + int xm = windowsItemFrame + checkcol + windowsItemHMargin; + int xpos = menuitem->rect.x() + xm; + QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin); + QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect); + QString s = menuitem->text; + if (!s.isEmpty()) { // draw text + painter->save(); + int t = s.indexOf(QLatin1Char('\t')); + int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; + if (!styleHint(SH_UnderlineShortcut, menuitem, widget)) + text_flags |= Qt::TextHideMnemonic; + text_flags |= Qt::AlignLeft; + if (t >= 0) { + QRect vShortcutRect = visualRect(option->direction, menuitem->rect, + QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom()))); + painter->drawText(vShortcutRect, text_flags, s.mid(t + 1)); + s = s.left(t); + } + QFont font = menuitem->font; + if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem) + font.setBold(true); + painter->setFont(font); + painter->setPen(discol); + painter->drawText(vTextRect, text_flags, s.left(t)); + painter->restore(); + } + if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow + int dim = (h - 2 * windowsItemFrame) / 2; + PrimitiveElement arrow; + arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight; + xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim; + QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim)); + QStyleOptionMenuItem newMI = *menuitem; + newMI.rect = vSubMenuRect; + newMI.state = dis ? State_None : State_Enabled; + drawPrimitive(arrow, &newMI, painter, widget); + } + } + break; +#endif // QT_NO_MENU + case CE_HeaderSection: + if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + name = QLatin1String("HEADER"); + partId = HP_HEADERITEM; + if (flags & State_Sunken) + stateId = HIS_PRESSED; + else if (flags & State_MouseOver) + stateId = HIS_HOT; + else + stateId = HIS_NORMAL; + + if (header->sortIndicator != QStyleOptionHeader::None) + stateId += 3; + + XPThemeData theme(widget, painter, name, partId, stateId, option->rect); + d->drawBackground(theme); + } + break; + case CE_MenuBarEmptyArea: + { + int stateId = MBI_NORMAL; + if (!(state & State_Enabled)) + stateId = MBI_DISABLED; + XPThemeData theme(widget, painter, QLatin1String("MENU"), MENU_BARBACKGROUND, stateId, option->rect); + d->drawBackground(theme); + } + break; + case CE_ToolBar: + if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) { + QPalette pal = option->palette; + pal.setColor(QPalette::Dark, option->palette.background().color().darker(130)); + QStyleOptionToolBar copyOpt = *toolbar; + copyOpt.palette = pal; + QWindowsStyle::drawControl(element, ©Opt, painter, widget); + } + break; + case CE_DockWidgetTitle: + if (const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(widget)) { + QRect rect = option->rect; + if (dockWidget->isFloating()) { + QWindowsXPStyle::drawControl(element, option, painter, widget); + break; //otherwise fall through + } + + if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option)) { + + const QStyleOptionDockWidgetV2 *v2 + = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(dwOpt); + bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar; + + if (verticalTitleBar) { + QSize s = rect.size(); + s.transpose(); + rect.setSize(s); + + painter->translate(rect.left() - 1, rect.top() + rect.width()); + painter->rotate(-90); + painter->translate(-rect.left() + 1, -rect.top()); + } + + painter->setBrush(option->palette.background().color().darker(110)); + painter->setPen(option->palette.background().color().darker(130)); + painter->drawRect(rect.adjusted(0, 1, -1, -3)); + + int buttonMargin = 4; + int mw = pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget); + int fw = pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget); + const QDockWidget *dw = qobject_cast<const QDockWidget *>(widget); + bool isFloating = dw != 0 && dw->isFloating(); + + QRect r = option->rect.adjusted(0, 2, -1, -3); + QRect titleRect = r; + + if (dwOpt->closable) { + QSize sz = standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10)); + titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0); + } + + if (dwOpt->floatable) { + QSize sz = standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10)); + titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0); + } + + if (isFloating) { + titleRect.adjust(0, -fw, 0, 0); + if (widget != 0 && widget->windowIcon().cacheKey() != qApp->windowIcon().cacheKey()) + titleRect.adjust(titleRect.height() + mw, 0, 0, 0); + } else { + titleRect.adjust(mw, 0, 0, 0); + if (!dwOpt->floatable && !dwOpt->closable) + titleRect.adjust(0, 0, -mw, 0); + } + if (!verticalTitleBar) + titleRect = visualRect(dwOpt->direction, r, titleRect); + + if (!dwOpt->title.isEmpty()) { + QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, + verticalTitleBar ? titleRect.height() : titleRect.width()); + const int indent = painter->fontMetrics().descent(); + drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1), + Qt::AlignLeft | Qt::AlignVCenter, dwOpt->palette, + dwOpt->state & State_Enabled, titleText, + QPalette::WindowText); + } + } + break; + } +#ifndef QT_NO_ITEMVIEWS + case CE_ItemViewItem: + { + const QStyleOptionViewItemV4 *vopt; + const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget); + bool newStyle = false; + + if (const QListView *listview = qobject_cast<const QListView *>(widget)) { + if (listview->viewMode() == QListView::IconMode) + newStyle = true; + } else if (const QTreeView* treeview = qobject_cast<const QTreeView *>(widget)) { + newStyle = true; + } + if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option))) { + /* + // We cannot currently get the correct selection color for "explorer style" views + COLORREF cref = 0; + XPThemeData theme(d->treeViewHelper(), 0, QLatin1String("LISTVIEW"), 0, 0); + unsigned int res = pGetThemeColor(theme.handle(), LVP_LISTITEM, LISS_SELECTED, TMT_TEXTCOLOR, &cref); + QColor textColor(GetRValue(cref), GetGValue(cref), GetBValue(cref)); + */ + QPalette palette = vopt->palette; + palette.setColor(QPalette::All, QPalette::HighlightedText, palette.color(QPalette::Active, QPalette::Text)); + // Note that setting a saturated color here results in ugly XOR colors in the focus rect + palette.setColor(QPalette::All, QPalette::Highlight, palette.base().color().darker(108)); + QStyleOptionViewItemV4 adjustedOption = *vopt; + adjustedOption.palette = palette; + // We hide the focusrect in singleselection as it is not required + if ((view->selectionMode() == QAbstractItemView::SingleSelection) + && !(vopt->state & State_KeyboardFocusChange)) + adjustedOption.state &= ~State_HasFocus; + QWindowsXPStyle::drawControl(element, &adjustedOption, painter, widget); + } else { + QWindowsXPStyle::drawControl(element, option, painter, widget); + } + break; + } +#endif // QT_NO_ITEMVIEWS + + default: + QWindowsXPStyle::drawControl(element, option, painter, widget); + break; + } +} + +/*! + \reimp + + see drawPrimitive for comments on the animation support + + */ +void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, + QPainter *painter, const QWidget *widget) const +{ + QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func()); + if (!QWindowsVistaStylePrivate::useVista()) { + QWindowsStyle::drawComplexControl(control, option, painter, widget); + return; + } + + State state = option->state; + SubControls sub = option->subControls; + QRect r = option->rect; + + int partId = 0; + int stateId = 0; + + State flags = option->state; + if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow()) + flags |= State_MouseOver; + + if (d->transitionsEnabled() && widget) { + if ((qobject_cast<const QScrollBar *>(widget) && control == CC_ScrollBar) +#ifndef QT_NO_SPINBOX + || (qobject_cast<const QAbstractSpinBox*>(widget) && control == CC_SpinBox) +#endif // QT_NO_SPINBOX +#ifndef QT_NO_COMBOBOX + || (qobject_cast<const QComboBox*>(widget) && control == CC_ComboBox) +#endif // QT_NO_COMBOBOX + ) + { + QWidget *w = const_cast<QWidget *> (widget); + + int oldState = w->property("_q_stylestate").toInt(); + int oldActiveControls = w->property("_q_stylecontrols").toInt(); + QRect oldRect = w->property("_q_stylerect").toRect(); + w->setProperty("_q_stylestate", (int)option->state); + w->setProperty("_q_stylecontrols", (int)option->activeSubControls); + w->setProperty("_q_stylerect", w->rect()); + + bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || + (state & State_On) != (oldState & State_On) || + (state & State_MouseOver) != (oldState & State_MouseOver) || + oldActiveControls != option->activeSubControls); + + + if (qstyleoption_cast<const QStyleOptionSlider *>(option)) { + QRect oldSliderPos = w->property("_q_stylesliderpos").toRect(); + QRect currentPos = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget); + w->setProperty("_q_stylesliderpos", currentPos); + if (oldSliderPos != currentPos) { + doTransition = false; + d->stopAnimation(widget); + } + } else if (control == CC_SpinBox) { + //spinboxes have a transition when focus changes + if (!doTransition) + doTransition = (state & State_HasFocus) != (oldState & State_HasFocus); + } + + if (oldRect != option->rect) { + doTransition = false; + d->stopAnimation(widget); + } + + if (doTransition) { + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + Animation *anim = d->widgetAnimation(widget); + Transition *t = new Transition; + t->setWidget(w); + if (!anim) { + if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option)) { + //Combo boxes are special cased to avoid cleartype issues + startImage.fill(0); + QPainter startPainter(&startImage); + QStyleOptionComboBox startCombo = *combo; + startCombo.state = (QStyle::State)oldState; + startCombo.activeSubControls = (QStyle::SubControl)oldActiveControls; + drawComplexControl(control, &startCombo, &startPainter, 0 /* Intentional */); + t->setStartImage(startImage); + } else if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option)) { + //This is a workaround for the direct3d engine as it currently has some issues with grabWindow + startImage.fill(0); + QPainter startPainter(&startImage); + QStyleOptionSlider startSlider = *slider; + startSlider.state = (QStyle::State)oldState; + startSlider.activeSubControls = (QStyle::SubControl)oldActiveControls; + drawComplexControl(control, &startSlider, &startPainter, 0 /* Intentional */); + t->setStartImage(startImage); + } else { + QPoint offset(0, 0); + if (!widget->internalWinId()) + offset = widget->mapTo(widget->nativeParentWidget(), offset); + t->setStartImage(QPixmap::grabWindow(widget->effectiveWinId(), offset.x(), offset.y(), + option->rect.width(), option->rect.height()).toImage()); + } + } else { + startImage.fill(0); + QPainter startPainter(&startImage); + anim->paint(&startPainter, option); + t->setStartImage(startImage); + } + d->startAnimation(t); + endImage.fill(0); + QPainter endPainter(&endImage); + drawComplexControl(control, option, &endPainter, 0 /* Intentional */); + t->setEndImage(endImage); + t->setStartTime(QTime::currentTime()); + + if (option->state & State_MouseOver || option->state & State_Sunken) + t->setDuration(150); + else + t->setDuration(500); + } + + if (Animation *anim = d->widgetAnimation(widget)) { + anim->paint(painter, option); + return; + } + + } + } + + switch (control) { + case CC_ComboBox: + if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) + { + if (cmb->editable) { + if (sub & SC_ComboBoxEditField) { + partId = EP_EDITBORDER_NOSCROLL; + if (!(flags & State_Enabled)) + stateId = ETS_DISABLED; + else if (flags & State_MouseOver) + stateId = ETS_HOT; + else if (flags & State_HasFocus) + stateId = ETS_FOCUSED; + else + stateId = ETS_NORMAL; + + XPThemeData theme(widget, painter, QLatin1String("EDIT"), partId, stateId, r); + + d->drawBackground(theme); + } + if (sub & SC_ComboBoxArrow) { + QRect subRect = subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget); + XPThemeData theme(widget, painter, QLatin1String("COMBOBOX")); + theme.rect = subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget); + partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT; + + if (!(cmb->state & State_Enabled)) + stateId = CBXS_DISABLED; + else if (cmb->state & State_Sunken || cmb->state & State_On) + stateId = CBXS_PRESSED; + else if (cmb->state & State_MouseOver && option->activeSubControls & SC_ComboBoxArrow) + stateId = CBXS_HOT; + else + stateId = CBXS_NORMAL; + + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } + + } else { + if (sub & SC_ComboBoxFrame) { + QStyleOptionButton btn; + btn.QStyleOption::operator=(*option); + btn.rect = option->rect.adjusted(-1, -1, 1, 1); + if (sub & SC_ComboBoxArrow) + btn.features = QStyleOptionButton::HasMenu; + drawControl(QStyle::CE_PushButton, &btn, painter, widget); + } + } + } + break; + case CC_ScrollBar: + if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) + { + XPThemeData theme(widget, painter, QLatin1String("SCROLLBAR")); + + bool maxedOut = (scrollbar->maximum == scrollbar->minimum); + if (maxedOut) + flags &= ~State_Enabled; + + bool isHorz = flags & State_Horizontal; + bool isRTL = option->direction == Qt::RightToLeft; + if (sub & SC_ScrollBarAddLine) { + theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget); + partId = SBP_ARROWBTN; + if (!(flags & State_Enabled)) + stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED); + else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken)) + stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED); + else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver)) + stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT); + else if (scrollbar->state & State_MouseOver) + stateId = (isHorz ? (isRTL ? ABS_LEFTHOVER : ABS_RIGHTHOVER) : ABS_DOWNHOVER); + else + stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL); + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } + if (sub & SC_ScrollBarSubLine) { + theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget); + partId = SBP_ARROWBTN; + if (!(flags & State_Enabled)) + stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED); + else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken)) + stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED); + else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver)) + stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT); + else if (scrollbar->state & State_MouseOver) + stateId = (isHorz ? (isRTL ? ABS_RIGHTHOVER : ABS_LEFTHOVER) : ABS_UPHOVER); + else + stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL); + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } + if (maxedOut) { + theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget); + theme.rect = theme.rect.united(subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget)); + theme.rect = theme.rect.united(subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget)); + partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT; + stateId = SCRBS_DISABLED; + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } else { + if (sub & SC_ScrollBarSubPage) { + theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget); + partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT; + if (!(flags & State_Enabled)) + stateId = SCRBS_DISABLED; + else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken)) + stateId = SCRBS_PRESSED; + else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver)) + stateId = SCRBS_HOT; + else + stateId = SCRBS_NORMAL; + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } + if (sub & SC_ScrollBarAddPage) { + theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget); + partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT; + if (!(flags & State_Enabled)) + stateId = SCRBS_DISABLED; + else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken)) + stateId = SCRBS_PRESSED; + else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver)) + stateId = SCRBS_HOT; + else + stateId = SCRBS_NORMAL; + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } + if (sub & SC_ScrollBarSlider) { + theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget); + if (!(flags & State_Enabled)) + stateId = SCRBS_DISABLED; + else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken)) + stateId = SCRBS_PRESSED; + else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver)) + stateId = SCRBS_HOT; + else if (option->state & State_MouseOver) + stateId = SCRBS_HOVER; + else + stateId = SCRBS_NORMAL; + + // Draw handle + theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget); + theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT; + theme.stateId = stateId; + d->drawBackground(theme); + + // Calculate rect of gripper + const int swidth = theme.rect.width(); + const int sheight = theme.rect.height(); + + MARGINS contentsMargin; + RECT rect = theme.toRECT(theme.rect); + pGetThemeMargins(theme.handle(), 0, theme.partId, theme.stateId, TMT_SIZINGMARGINS, &rect, &contentsMargin); + + SIZE size; + theme.partId = flags & State_Horizontal ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT; + pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size); + int gw = size.cx, gh = size.cy; + + + QRect gripperBounds; + if (flags & State_Horizontal && ((swidth - contentsMargin.cxLeftWidth - contentsMargin.cxRightWidth) > gw)) { + gripperBounds.setLeft(theme.rect.left() + swidth/2 - gw/2); + gripperBounds.setTop(theme.rect.top() + sheight/2 - gh/2); + gripperBounds.setWidth(gw); + gripperBounds.setHeight(gh); + } else if ((sheight - contentsMargin.cyTopHeight - contentsMargin.cyBottomHeight) > gh) { + gripperBounds.setLeft(theme.rect.left() + swidth/2 - gw/2); + gripperBounds.setTop(theme.rect.top() + sheight/2 - gh/2); + gripperBounds.setWidth(gw); + gripperBounds.setHeight(gh); + } + + // Draw gripper if there is enough space + if (!gripperBounds.isEmpty() && flags & State_Enabled) { + painter->save(); + XPThemeData grippBackground = theme; + grippBackground.partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT; + theme.rect = gripperBounds; + painter->setClipRegion(d->region(theme));// Only change inside the region of the gripper + d->drawBackground(grippBackground);// The gutter is the grippers background + d->drawBackground(theme); // Transparent gripper ontop of background + painter->restore(); + } + } + } + } + break; +#ifndef QT_NO_SPINBOX + case CC_SpinBox: + if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) + { + XPThemeData theme(widget, painter, QLatin1String("SPIN")); + if (sb->frame && (sub & SC_SpinBoxFrame)) { + partId = EP_EDITBORDER_NOSCROLL; + if (!(flags & State_Enabled)) + stateId = ETS_DISABLED; + else if (flags & State_MouseOver) + stateId = ETS_HOT; + else if (flags & State_HasFocus) + stateId = ETS_SELECTED; + else + stateId = ETS_NORMAL; + + XPThemeData ftheme(widget, painter, QLatin1String("EDIT"), partId, stateId, r); + ftheme.noContent = true; + d->drawBackground(ftheme); + } + if (sub & SC_SpinBoxUp) { + theme.rect = subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1); + partId = SPNP_UP; + if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled)) + stateId = UPS_DISABLED; + else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken)) + stateId = UPS_PRESSED; + else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver)) + stateId = UPS_HOT; + else + stateId = UPS_NORMAL; + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } + if (sub & SC_SpinBoxDown) { + theme.rect = subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget); + partId = SPNP_DOWN; + if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled)) + stateId = DNS_DISABLED; + else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken)) + stateId = DNS_PRESSED; + else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver)) + stateId = DNS_HOT; + else + stateId = DNS_NORMAL; + theme.partId = partId; + theme.stateId = stateId; + d->drawBackground(theme); + } + } + break; +#endif // QT_NO_SPINBOX + default: + QWindowsXPStyle::drawComplexControl(control, option, painter, widget); + break; + } +} + +/*! + \reimp + */ +QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption *option, + const QSize &size, const QWidget *widget) const +{ + if (!QWindowsVistaStylePrivate::useVista()) + return QWindowsStyle::sizeFromContents(type, option, size, widget); + + QSize sz(size); + + QSize newSize = QWindowsXPStyle::sizeFromContents(type, option, size, widget); + switch (type) { + case CT_LineEdit: + case CT_ComboBox: + { + HTHEME theme = pOpenThemeData(0, L"Button"); + MARGINS borderSize; + if (theme) { + int result = pGetThemeMargins(theme, + NULL, + BP_PUSHBUTTON, + PBS_NORMAL, + TMT_CONTENTMARGINS, + NULL, + &borderSize); + if (result == S_OK) { + sz += QSize(borderSize.cxLeftWidth + borderSize.cxRightWidth - 2, + borderSize.cyBottomHeight + borderSize.cyTopHeight - 2); + } + sz += QSize(23, 0); //arrow button + } + } + return sz; + case CT_MenuItem: + sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget); + sz.rwidth() += 28; + if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { + int minimumHeight = qMax<qint32>(22, sz.height()); + if (menuitem->menuItemType != QStyleOptionMenuItem::Separator) + sz.setHeight(minimumHeight); + } + return sz; +#ifndef QT_NO_MENUBAR + case CT_MenuBarItem: + if (!sz.isEmpty()) + sz += QSize(windowsItemHMargin * 5 + 1, 5); + return sz; + break; +#endif + case CT_ItemViewItem: + sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget); + sz.rheight() += 2; + return sz; + case CT_SpinBox: + { + //Spinbox adds frame twice + sz = QWindowsStyle::sizeFromContents(type, option, size, widget); + int border = pixelMetric(PM_SpinBoxFrameWidth, option, widget); + sz -= QSize(2*border, 2*border); + } + return sz; + default: + break; + } + return newSize; +} + +/*! + \reimp + */ +QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + if (!QWindowsVistaStylePrivate::useVista()) + return QWindowsStyle::subElementRect(element, option, widget); + + QRect rect = QWindowsXPStyle::subElementRect(element, option, widget); + switch (element) { + + case SE_PushButtonContents: + if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) { + MARGINS borderSize; + HTHEME theme = pOpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : 0, L"Button"); + if (theme) { + int stateId; + if (!(option->state & State_Enabled)) + stateId = PBS_DISABLED; + else if (option->state & State_Sunken) + stateId = PBS_PRESSED; + else if (option->state & State_MouseOver) + stateId = PBS_HOT; + else if (btn->features & QStyleOptionButton::DefaultButton) + stateId = PBS_DEFAULTED; + else + stateId = PBS_NORMAL; + + int border = pixelMetric(PM_DefaultFrameWidth, btn, widget); + rect = option->rect.adjusted(border, border, -border, -border); + + int result = pGetThemeMargins(theme, + NULL, + BP_PUSHBUTTON, + stateId, + TMT_CONTENTMARGINS, + NULL, + &borderSize); + + if (result == S_OK) { + rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight, + -borderSize.cxRightWidth, -borderSize.cyBottomHeight); + rect = visualRect(option->direction, option->rect, rect); + } + } + } + break; + + case SE_HeaderArrow: + { + QRect r = rect; + int h = option->rect.height(); + int w = option->rect.width(); + int x = option->rect.x(); + int y = option->rect.y(); + int margin = pixelMetric(QStyle::PM_HeaderMargin, option, widget); + + XPThemeData theme(widget, 0, QLatin1String("HEADER"), HP_HEADERSORTARROW, HSAS_SORTEDDOWN, option->rect); + + int arrowWidth = 13; + int arrowHeight = 5; + if (theme.isValid()) { + SIZE size; + if (pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size) == S_OK) { + arrowWidth = size.cx; + arrowHeight = size.cy; + } + } + if (option->state & State_Horizontal) { + r.setRect(x + w/2 - arrowWidth/2, y , arrowWidth, arrowHeight); + } else { + int vert_size = w / 2; + r.setRect(x + 5, y + h - margin * 2 - vert_size, + w - margin * 2 - 5, vert_size); + } + rect = visualRect(option->direction, option->rect, r); + } + break; + + case SE_HeaderLabel: + { + int margin = pixelMetric(QStyle::PM_HeaderMargin, option, widget); + QRect r = option->rect; + r.setRect(option->rect.x() + margin, option->rect.y() + margin, + option->rect.width() - margin * 2, option->rect.height() - margin * 2); + if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + // Subtract width needed for arrow, if there is one + if (header->sortIndicator != QStyleOptionHeader::None) { + if (!(option->state & State_Horizontal)) //horizontal arrows are positioned on top + r.setHeight(r.height() - (option->rect.width() / 2) - (margin * 2)); + } + } + rect = visualRect(option->direction, option->rect, r); + } + break; + case SE_ProgressBarContents: + rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget); + break; + case SE_ItemViewItemDecoration: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) + rect.adjust(-2, 0, 2, 0); + break; + case SE_ItemViewItemFocusRect: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) { + QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, option, widget); + QRect displayRect = subElementRect(QStyle::SE_ItemViewItemDecoration, option, widget); + if (!vopt->icon.isNull()) + rect = textRect.united(displayRect); + else + rect = textRect; + rect = rect.adjusted(1, 0, -1, 0); + } + break; + default: + break; + } + return rect; +} + + +/* + This function is used by subControlRect to check if a button + should be drawn for the given subControl given a set of window flags. +*/ +static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){ + + bool isMinimized = tb->titleBarState & Qt::WindowMinimized; + bool isMaximized = tb->titleBarState & Qt::WindowMaximized; + const uint flags = tb->titleBarFlags; + bool retVal = false; + switch (sc) { + case QStyle::SC_TitleBarContextHelpButton: + if (flags & Qt::WindowContextHelpButtonHint) + retVal = true; + break; + case QStyle::SC_TitleBarMinButton: + if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint)) + retVal = true; + break; + case QStyle::SC_TitleBarNormalButton: + if (isMinimized && (flags & Qt::WindowMinimizeButtonHint)) + retVal = true; + else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint)) + retVal = true; + break; + case QStyle::SC_TitleBarMaxButton: + if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint)) + retVal = true; + break; + case QStyle::SC_TitleBarShadeButton: + if (!isMinimized && flags & Qt::WindowShadeButtonHint) + retVal = true; + break; + case QStyle::SC_TitleBarUnshadeButton: + if (isMinimized && flags & Qt::WindowShadeButtonHint) + retVal = true; + break; + case QStyle::SC_TitleBarCloseButton: + if (flags & Qt::WindowSystemMenuHint) + retVal = true; + break; + case QStyle::SC_TitleBarSysMenu: + if (flags & Qt::WindowSystemMenuHint) + retVal = true; + break; + default : + retVal = true; + } + return retVal; +} + + +/*! \reimp */ +int QWindowsVistaStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, + QStyleHintReturn *returnData) const +{ + QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func()); + int ret = 0; + switch (hint) { + case SH_MessageBox_CenterButtons: + ret = false; + break; + case SH_ToolTip_Mask: + if (option) { + if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(returnData)) { + ret = true; + XPThemeData themeData(widget, 0, QLatin1String("TOOLTIP"), TTP_STANDARD, TTSS_NORMAL, option->rect); + mask->region = d->region(themeData); + } + } + break; + case SH_Table_GridLineColor: + if (option) + ret = option->palette.color(QPalette::Base).darker(118).rgb(); + else + ret = -1; + break; + default: + ret = QWindowsXPStyle::styleHint(hint, option, widget, returnData); + break; + } + return ret; +} + + +/*! + \reimp + */ +QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, + SubControl subControl, const QWidget *widget) const +{ + if (!QWindowsVistaStylePrivate::useVista()) + return QWindowsStyle::subControlRect(control, option, subControl, widget); + + QRect rect = QWindowsXPStyle::subControlRect(control, option, subControl, widget); + switch (control) { +#ifndef QT_NO_COMBOBOX + case CC_ComboBox: + if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + int x = cb->rect.x(), + y = cb->rect.y(), + wi = cb->rect.width(), + he = cb->rect.height(); + int xpos = x; + int margin = cb->frame ? 3 : 0; + int bmarg = cb->frame ? 2 : 0; + xpos += wi - bmarg - 16; + + switch (subControl) { + case SC_ComboBoxFrame: + rect = cb->rect; + break; + case SC_ComboBoxArrow: + rect.setRect(cb->editable ? xpos : 0, y , wi - xpos, he); + break; + case SC_ComboBoxEditField: + rect.setRect(x + margin, y + margin, wi - 2 * margin - 16, he - 2 * margin); + break; + case SC_ComboBoxListBoxPopup: + rect = cb->rect; + break; + default: + break; + } + rect = visualRect(cb->direction, cb->rect, rect); + return rect; + } +#endif // QT_NO_COMBOBOX + case CC_TitleBar: + if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) { + if (!buttonVisible(subControl, tb)) + return rect; + const bool isToolTitle = false; + const int height = tb->rect.height(); + const int width = tb->rect.width(); + int buttonWidth = GetSystemMetrics(SM_CXSIZE) - 4; + + const int frameWidth = pixelMetric(PM_MdiSubWindowFrameWidth, option, widget); + const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0; + const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0; + const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0; + const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0; + const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0; + + switch (subControl) { + case SC_TitleBarLabel: + rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height); + if (isToolTitle) { + if (sysmenuHint) { + rect.adjust(0, 0, -buttonWidth - 3, 0); + } + if (minimizeHint || maximizeHint) + rect.adjust(0, 0, -buttonWidth - 2, 0); + } else { + if (sysmenuHint) { + const int leftOffset = height - 8; + rect.adjust(leftOffset, 0, 0, 4); + } + if (minimizeHint) + rect.adjust(0, 0, -buttonWidth - 2, 0); + if (maximizeHint) + rect.adjust(0, 0, -buttonWidth - 2, 0); + if (contextHint) + rect.adjust(0, 0, -buttonWidth - 2, 0); + if (shadeHint) + rect.adjust(0, 0, -buttonWidth - 2, 0); + } + rect.translate(0, 2); + rect = visualRect(option->direction, option->rect, rect); + break; + case SC_TitleBarSysMenu: + { + const int controlTop = 6; + const int controlHeight = height - controlTop - 3; + int iconExtent = pixelMetric(PM_SmallIconSize); + QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent)); + if (tb->icon.isNull()) + iconSize = QSize(controlHeight, controlHeight); + int hPad = (controlHeight - iconSize.height())/2; + int vPad = (controlHeight - iconSize.width())/2; + rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height()); + rect.translate(0, 3); + rect = visualRect(option->direction, option->rect, rect); + } + break; + } + } + break; + default: + break; + } + return rect; +} + +/*! + \reimp + */ +bool QWindowsVistaStyle::event(QEvent *e) +{ + Q_D(QWindowsVistaStyle); + switch (e->type()) { + case QEvent::Timer: + { + QTimerEvent *timerEvent = (QTimerEvent *)e; + if (d->animationTimer.timerId() == timerEvent->timerId()) { + d->timerEvent(); + e->accept(); + return true; + } + } + break; + default: + break; + } + return QWindowsXPStyle::event(e); +} + +/*! + \reimp + */ +QStyle::SubControl QWindowsVistaStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, + const QPoint &pos, const QWidget *widget) const +{ + if (!QWindowsVistaStylePrivate::useVista()) { + return QWindowsStyle::hitTestComplexControl(control, option, pos, widget); + } + return QWindowsXPStyle::hitTestComplexControl(control, option, pos, widget); +} + +/*! + \reimp + */ +int QWindowsVistaStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + if (!QWindowsVistaStylePrivate::useVista()) { + return QWindowsStyle::pixelMetric(metric, option, widget); + } + switch (metric) { + + case PM_DockWidgetTitleBarButtonMargin: + return 5; + case PM_ScrollBarSliderMin: + return 18; + case PM_MenuHMargin: + case PM_MenuVMargin: + return 0; + case PM_MenuPanelWidth: + return 3; + default: + break; + } + return QWindowsXPStyle::pixelMetric(metric, option, widget); +} + +/*! + \reimp + */ +QPalette QWindowsVistaStyle::standardPalette() const +{ + return QWindowsXPStyle::standardPalette(); +} + +/*! + \reimp + */ +void QWindowsVistaStyle::polish(QApplication *app) +{ + QWindowsXPStyle::polish(app); +} + +/*! + \reimp + */ +void QWindowsVistaStyle::polish(QWidget *widget) +{ + QWindowsXPStyle::polish(widget); +#ifndef QT_NO_LINEEDIT + if (qobject_cast<QLineEdit*>(widget)) + widget->setAttribute(Qt::WA_Hover); + else +#endif // QT_NO_LINEEDIT + if (qobject_cast<QGroupBox*>(widget)) + widget->setAttribute(Qt::WA_Hover); + else if (qobject_cast<QCommandLinkButton*>(widget)) { + QFont buttonFont = widget->font(); + buttonFont.setFamily(QLatin1String("Segoe UI")); + widget->setFont(buttonFont); + } + else if (widget->inherits("QTipLabel")){ + //note that since tooltips are not reused + //we do not have to care about unpolishing + widget->setContentsMargins(3, 0, 4, 0); + COLORREF bgRef; + HTHEME theme = pOpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : 0, L"TOOLTIP"); + if (theme) { + if (pGetThemeColor(theme, TTP_STANDARD, TTSS_NORMAL, TMT_TEXTCOLOR, &bgRef) == S_OK) { + QColor textColor = QColor::fromRgb(bgRef); + QPalette pal; + pal.setColor(QPalette::All, QPalette::ToolTipText, textColor); + widget->setPalette(pal); + } + } + } else if (qobject_cast<QMessageBox *> (widget)) { + widget->setAttribute(Qt::WA_StyledBackground); + QDialogButtonBox *buttonBox = qFindChild<QDialogButtonBox *>(widget,QLatin1String("qt_msgbox_buttonbox")); + if (buttonBox) + buttonBox->setContentsMargins(0, 9, 0, 0); + } +#ifndef QT_NO_INPUTDIALOG + else if (qobject_cast<QInputDialog *> (widget)) { + widget->setAttribute(Qt::WA_StyledBackground); + QDialogButtonBox *buttonBox = qFindChild<QDialogButtonBox *>(widget,QLatin1String("qt_inputdlg_buttonbox")); + if (buttonBox) + buttonBox->setContentsMargins(0, 9, 0, 0); + } +#endif // QT_NO_INPUTDIALOG + else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) { + tree->viewport()->setAttribute(Qt::WA_Hover); + } +} + +/*! + \reimp + */ +void QWindowsVistaStyle::unpolish(QWidget *widget) +{ + QWindowsXPStyle::unpolish(widget); + + QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func()); + d->stopAnimation(widget); + +#ifndef QT_NO_LINEEDIT + if (qobject_cast<QLineEdit*>(widget)) + widget->setAttribute(Qt::WA_Hover, false); + else +#endif // QT_NO_LINEEDIT + if (qobject_cast<QGroupBox*>(widget)) + widget->setAttribute(Qt::WA_Hover, false); + else if (qobject_cast<QMessageBox *> (widget)) { + widget->setAttribute(Qt::WA_StyledBackground, false); + QDialogButtonBox *buttonBox = qFindChild<QDialogButtonBox *>(widget,QLatin1String("qt_msgbox_buttonbox")); + if (buttonBox) + buttonBox->setContentsMargins(0, 0, 0, 0); + } +#ifndef QT_NO_INPUTDIALOG + else if (qobject_cast<QInputDialog *> (widget)) { + widget->setAttribute(Qt::WA_StyledBackground, false); + QDialogButtonBox *buttonBox = qFindChild<QDialogButtonBox *>(widget,QLatin1String("qt_inputdlg_buttonbox")); + if (buttonBox) + buttonBox->setContentsMargins(0, 0, 0, 0); + } +#endif // QT_NO_INPUTDIALOG + else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) { + tree->viewport()->setAttribute(Qt::WA_Hover, false); + } else if (qobject_cast<QCommandLinkButton*>(widget)) { + QFont font = qApp->font("QCommandLinkButton"); + QFont widgetFont = widget->font(); + widgetFont.setFamily(font.family()); //Only family set by polish + widget->setFont(widgetFont); + } +} + + +/*! + \reimp + */ +void QWindowsVistaStyle::unpolish(QApplication *app) +{ + QWindowsXPStyle::unpolish(app); +} + +/*! + \reimp + */ +void QWindowsVistaStyle::polish(QPalette &pal) +{ + QWindowsStyle::polish(pal); + pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(104)); +} + +/*! + \reimp + */ +QPixmap QWindowsVistaStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option, + const QWidget *widget) const +{ + if (!QWindowsVistaStylePrivate::useVista()) { + return QWindowsStyle::standardPixmap(standardPixmap, option, widget); + } + return QWindowsXPStyle::standardPixmap(standardPixmap, option, widget); +} + +QWindowsVistaStylePrivate::QWindowsVistaStylePrivate() : + QWindowsXPStylePrivate(), m_treeViewHelper(0) +{ + resolveSymbols(); +} + +QWindowsVistaStylePrivate::~QWindowsVistaStylePrivate() +{ + delete m_treeViewHelper; +} + +void QWindowsVistaStylePrivate::timerEvent() +{ + for (int i = animations.size() - 1 ; i >= 0 ; --i) { + + if (animations[i]->widget()) + animations[i]->widget()->update(); + + if (!animations[i]->widget() || + !animations[i]->widget()->isEnabled() || + !animations[i]->widget()->isVisible() || + animations[i]->widget()->window()->isMinimized() || + !animations[i]->running() || + !QWindowsVistaStylePrivate::useVista()) + { + Animation *a = animations.takeAt(i); + delete a; + } + } + if (animations.size() == 0 && animationTimer.isActive()) { + animationTimer.stop(); + } +} + +void QWindowsVistaStylePrivate::stopAnimation(const QWidget *w) +{ + for (int i = animations.size() - 1 ; i >= 0 ; --i) { + if (animations[i]->widget() == w) { + Animation *a = animations.takeAt(i); + delete a; + break; + } + } +} + +void QWindowsVistaStylePrivate::startAnimation(Animation *t) +{ + Q_Q(QWindowsVistaStyle); + stopAnimation(t->widget()); + animations.append(t); + if (animations.size() > 0 && !animationTimer.isActive()) { + animationTimer.start(45, q); + } +} + +bool QWindowsVistaStylePrivate::transitionsEnabled() const +{ + BOOL animEnabled = false; + if (QT_WA_INLINE(SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0), + SystemParametersInfoA(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0) + )) + { + if (animEnabled) + return true; + } + return false; +} + + +Animation * QWindowsVistaStylePrivate::widgetAnimation(const QWidget *widget) const +{ + if (!widget) + return 0; + foreach (Animation *a, animations) { + if (a->widget() == widget) + return a; + } + return 0; +} + + +/*! \internal + Returns true if all the necessary theme engine symbols were + resolved. +*/ +bool QWindowsVistaStylePrivate::resolveSymbols() +{ + static bool tried = false; + if (!tried) { + tried = true; + QLibrary themeLib(QLatin1String("uxtheme")); + pSetWindowTheme = (PtrSetWindowTheme )themeLib.resolve("SetWindowTheme"); + pIsThemePartDefined = (PtrIsThemePartDefined )themeLib.resolve("IsThemePartDefined"); + pGetThemePartSize = (PtrGetThemePartSize )themeLib.resolve("GetThemePartSize"); + pOpenThemeData = (PtrOpenThemeData )themeLib.resolve("OpenThemeData"); + pCloseThemeData = (PtrCloseThemeData )themeLib.resolve("CloseThemeData"); + pDrawThemeBackground = (PtrDrawThemeBackground )themeLib.resolve("DrawThemeBackground"); + pDrawThemeBackgroundEx = (PtrDrawThemeBackgroundEx )themeLib.resolve("DrawThemeBackgroundEx"); + pGetCurrentThemeName = (PtrGetCurrentThemeName )themeLib.resolve("GetCurrentThemeName"); + pGetThemeBool = (PtrGetThemeBool )themeLib.resolve("GetThemeBool"); + pGetThemeColor = (PtrGetThemeColor )themeLib.resolve("GetThemeColor"); + pGetThemeEnumValue = (PtrGetThemeEnumValue )themeLib.resolve("GetThemeEnumValue"); + pGetThemeFilename = (PtrGetThemeFilename )themeLib.resolve("GetThemeFilename"); + pGetThemeFont = (PtrGetThemeFont )themeLib.resolve("GetThemeFont"); + pGetThemeInt = (PtrGetThemeInt )themeLib.resolve("GetThemeInt"); + pGetThemeIntList = (PtrGetThemeIntList )themeLib.resolve("GetThemeIntList"); + pGetThemeMargins = (PtrGetThemeMargins )themeLib.resolve("GetThemeMargins"); + pGetThemeMetric = (PtrGetThemeMetric )themeLib.resolve("GetThemeMetric"); + pGetThemePartSize = (PtrGetThemePartSize )themeLib.resolve("GetThemePartSize"); + pGetThemePosition = (PtrGetThemePosition )themeLib.resolve("GetThemePosition"); + pGetThemeRect = (PtrGetThemeRect )themeLib.resolve("GetThemeRect"); + pGetThemeString = (PtrGetThemeString )themeLib.resolve("GetThemeString"); + pGetThemeTransitionDuration = (PtrGetThemeTransitionDuration)themeLib.resolve("GetThemeTransitionDuration"); + pGetThemePropertyOrigin = (PtrGetThemePropertyOrigin)themeLib.resolve("GetThemePropertyOrigin"); + } + return pGetThemeTransitionDuration != 0; +} + +/* + * We need to set the windows explorer theme explicitly on a native widget + * in order to get Vista-style item view themes + */ +QWidget *QWindowsVistaStylePrivate::treeViewHelper() +{ + if (!m_treeViewHelper) { + m_treeViewHelper = new QWidget(0); + pSetWindowTheme(m_treeViewHelper->winId(), L"explorer", NULL); + } + return m_treeViewHelper; +} + + +/*! +\internal +*/ +QIcon QWindowsVistaStyle::standardIconImplementation(StandardPixmap standardIcon, + const QStyleOption *option, + const QWidget *widget) const +{ + if (!QWindowsVistaStylePrivate::useVista()) { + return QWindowsStyle::standardIconImplementation(standardIcon, option, widget); + } + + QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate *>(d_func()); + switch(standardIcon) { + case SP_CommandLink: + { + XPThemeData theme(0, 0, QLatin1String("BUTTON"), BP_COMMANDLINKGLYPH, CMDLGS_NORMAL); + if (theme.isValid()) { + SIZE size; + pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size); + QIcon linkGlyph; + QPixmap pm = QPixmap(size.cx, size.cy); + pm.fill(Qt::transparent); + QPainter p(&pm); + theme.painter = &p; + theme.rect = QRect(0, 0, size.cx, size.cy); + d->drawBackground(theme); + linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal + pm.fill(Qt::transparent); + + theme.stateId = CMDLGS_PRESSED; + d->drawBackground(theme); + linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed + pm.fill(Qt::transparent); + + theme.stateId = CMDLGS_HOT; + d->drawBackground(theme); + linkGlyph.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover + pm.fill(Qt::transparent); + + theme.stateId = CMDLGS_DISABLED; + d->drawBackground(theme); + linkGlyph.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled + return linkGlyph; + } + } + break; + default: + break; + } + return QWindowsXPStyle::standardIconImplementation(standardIcon, option, widget); +} + +QT_END_NAMESPACE + +#endif //QT_NO_WINDOWSVISTA |