/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying
** this package.
**
** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwindowsvistastyle.h"
#include "qwindowsvistastyle_p.h"
#include <private/qstylehelper_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
static 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 QWindowsVistaAnimation::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 QWindowsVistaAnimation::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 QWindowsVistaTransition::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 QWindowsVistaPulse::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);
}
/*!
\internal
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 = oldState &&
((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);
QWindowsVistaAnimation *anim = d->widgetAnimation(widget);
QWindowsVistaTransition *t = new QWindowsVistaTransition;
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)
proxy()->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;
proxy()->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 int decoration_size = 0;
if (theme.isValid() && !decoration_size) {
SIZE size;
pGetThemePartSize(theme.handle(), 0, TVP_HOTGLYPH, GLPS_OPENED, 0, TS_TRUE, &size);
decoration_size = qMax(size.cx, size.cy);
}
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 (QWindowsVistaAnimation *a = d->widgetAnimation(widget)) {
a->paint(painter, option);
} else {
QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
}
}
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)
proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
return;
}
break;
case PE_FrameLineEdit:
if (QWindowsVistaAnimation *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_IndicatorToolBarHandle:
{
XPThemeData theme;
QRect rect;
if (option->state & State_Horizontal) {
theme = XPThemeData(widget, painter, QLatin1String("REBAR"), RP_GRIPPER, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
rect = option->rect.adjusted(0, 1, 0, -2);
rect.setWidth(4);
} else {
theme = XPThemeData(widget, painter, QLatin1String("REBAR"), RP_GRIPPERVERT, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
rect = option->rect.adjusted(1, 0, -1, 0);
rect.setHeight(4);
}
theme.rect = rect;
d->drawBackground(theme);
}
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 = true;
if (qobject_cast<const QTableView*>(widget))
newStyle = false;
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(QRect(pixmapRect.topLeft(),
QSize(frame, pixmapRect.height())), pixmap,
QRect(QPoint(0, 0), QSize(frame, pixmapRect.height())));
painter->drawPixmap(pixmapRect.adjusted(frame, 0, 0, 0),
pixmap, srcRect.adjusted(frame, 0, -frame, 0));
} else if (reverse ? leftSection : rightSection) {
painter->drawPixmap(QRect(pixmapRect.topRight() - QPoint(frame - 1, 0),
QSize(frame, pixmapRect.height())), pixmap,
QRect(QPoint(pixmapRect.width() - frame, 0),
QSize(frame, pixmapRect.height())));
painter->drawPixmap(pixmapRect.adjusted(0, 0, -frame, 0),
pixmap, srcRect.adjusted(frame, 0, -frame, 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;
}
}
/*!
\internal
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);
QWindowsVistaAnimation *anim = d->widgetAnimation(widget);
QStyleOptionButton opt = *button;
opt.state = (QStyle::State)oldState;
startImage.fill(0);
QWindowsVistaTransition *t = new QWindowsVistaTransition;
t->setWidget(w);
QPainter startPainter(&startImage);
if (!anim) {
proxy()->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);
proxy()->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 (QWindowsVistaAnimation *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))
{
QWindowsVistaAnimation *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);
QWindowsVistaPulse *pulse = new QWindowsVistaPulse;
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.top() + (option->rect.height()/2) - (mbih/2),
mbiw + 1, mbih + 1));
proxy()->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()) {
QWindowsVistaAnimation *a = new QWindowsVistaAnimation;
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 (QWindowsVistaAnimation *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 (QWindowsVistaAnimation *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(proxy()->pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
if (!proxy()->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, 0, 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 = 28;
{
SIZE size;
MARGINS margins;
XPThemeData theme(widget, 0, QLatin1String("MENU"), MENU_POPUPCHECKBACKGROUND, MBI_HOT);
pGetThemePartSize(theme.handle(), NULL, MENU_POPUPCHECK, 0, NULL,TS_TRUE, &size);
pGetThemeMargins(theme.handle(), NULL, MENU_POPUPCHECK, 0, TMT_CONTENTMARGINS, NULL, &margins);
checkcol = qMax(menuitem->maxIconWidth, int(6 + size.cx + margins.cxLeftWidth + margins.cxRightWidth));
}
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);
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) {
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);
SIZE size;
MARGINS margins;
pGetThemePartSize(theme.handle(), NULL, MENU_POPUPCHECK, 0, NULL,TS_TRUE, &size);
pGetThemeMargins(theme.handle(), NULL, MENU_POPUPCHECK, 0,
TMT_CONTENTMARGINS, NULL, &margins);
QRect checkRect(0, 0, size.cx + margins.cxLeftWidth + margins.cxRightWidth ,
size.cy + margins.cyBottomHeight + margins.cyTopHeight);
checkRect.moveCenter(vCheckRect.center());
theme.rect = checkRect;
d->drawBackground(theme);
if (menuitem->icon.isNull()) {
checkRect = QRect(0, 0, size.cx, size.cy);
checkRect.moveCenter(theme.rect.center());
theme.rect = checkRect;
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(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On);
else
pixmap = menuitem->icon.pixmap(proxy()->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 (!proxy()->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;
proxy()->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:
{
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 = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
int fw = proxy()->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() != QApplication::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 = true;
if (qobject_cast<const QTableView*>(widget))
newStyle = false;
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;
}
}
/*!
\internal
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 = proxy()->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);
QWindowsVistaAnimation *anim = d->widgetAnimation(widget);
QWindowsVistaTransition *t = new QWindowsVistaTransition;
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;
proxy()->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;
proxy()->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);
proxy()->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 (QWindowsVistaAnimation *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 = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
XPThemeData theme(widget, painter, QLatin1String("COMBOBOX"));
theme.rect = subRect;
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;
proxy()->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 = proxy()->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 = proxy()->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 = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
theme.rect = theme.rect.united(proxy()->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 = proxy()->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 = proxy()->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 = proxy()->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 = proxy()->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 = proxy()->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 = proxy()->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;
}
}
/*!
\internal
*/
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);
int minimumHeight;
{
SIZE size;
MARGINS margins;
XPThemeData theme(widget, 0, QLatin1String("MENU"), MENU_POPUPCHECKBACKGROUND, MBI_HOT);
pGetThemePartSize(theme.handle(), NULL, MENU_POPUPCHECK, 0, NULL,TS_TRUE, &size);
pGetThemeMargins(theme.handle(), NULL, MENU_POPUPCHECK, 0, TMT_CONTENTMARGINS, NULL, &margins);
minimumHeight = qMax<qint32>(size.cy + margins.cyBottomHeight+ margins.cyTopHeight, sz.height());
sz.rwidth() += size.cx + margins.cxLeftWidth + margins.cxRightWidth;
}
if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
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 = proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget);
sz -= QSize(2*border, 2*border);
}
return sz;
default:
break;
}
return newSize;
}
/*!
\internal
*/
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 = PBS_NORMAL;
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;
int border = proxy()->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 = proxy()->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 = proxy()->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 (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;
}
/*! \internal */
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;
}
/*!
\internal
*/
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;
int arrowButtonWidth = bmarg + 16;
xpos += wi - arrowButtonWidth;
switch (subControl) {
case SC_ComboBoxFrame:
rect = cb->rect;
break;
case SC_ComboBoxArrow:
rect.setRect(xpos, y , arrowButtonWidth, 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 = proxy()->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 = proxy()->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;
default:
break;
}
}
break;
default:
break;
}
return rect;
}
/*!
\internal
*/
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);
}
/*!
\internal
*/
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);
}
/*!
\internal
*/
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 int(QStyleHelper::dpiScaled(5.));
case PM_ScrollBarSliderMin:
return int(QStyleHelper::dpiScaled(18.));
case PM_MenuHMargin:
case PM_MenuVMargin:
return 0;
case PM_MenuPanelWidth:
return 3;
default:
break;
}
return QWindowsXPStyle::pixelMetric(metric, option, widget);
}
/*!
\internal
*/
QPalette QWindowsVistaStyle::standardPalette() const
{
return QWindowsXPStyle::standardPalette();
}
/*!
\internal
*/
void QWindowsVistaStyle::polish(QApplication *app)
{
QWindowsXPStyle::polish(app);
}
/*!
\internal
*/
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);
}
else if (QListView *list = qobject_cast<QListView *> (widget)) {
list->viewport()->setAttribute(Qt::WA_Hover);
}
}
/*!
\internal
*/
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 = QApplication::font("QCommandLinkButton");
QFont widgetFont = widget->font();
widgetFont.setFamily(font.family()); //Only family set by polish
widget->setFont(widgetFont);
}
}
/*!
\internal
*/
void QWindowsVistaStyle::unpolish(QApplication *app)
{
QWindowsXPStyle::unpolish(app);
}
/*!
\internal
*/
void QWindowsVistaStyle::polish(QPalette &pal)
{
QWindowsStyle::polish(pal);
pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(104));
}
/*!
\internal
*/
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())
{
QWindowsVistaAnimation *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) {
QWindowsVistaAnimation *a = animations.takeAt(i);
delete a;
break;
}
}
}
void QWindowsVistaStylePrivate::startAnimation(QWindowsVistaAnimation *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 (SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0))
{
if (animEnabled)
return true;
}
return false;
}
QWindowsVistaAnimation * QWindowsVistaStylePrivate::widgetAnimation(const QWidget *widget) const
{
if (!widget)
return 0;
foreach (QWindowsVistaAnimation *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