Remove widget dependencies on Vista style animations

This patch will make it possible to get animations on
desktop components without using the widget pointer.

Change-Id: I2d2eca111dab0d96f276ff3627505c0652c4b4e5
Reviewed-by: J-P Nurmi <jpnurmi@digia.com>
This commit is contained in:
Jens Bache-Wiig 2012-10-23 18:34:25 +02:00 committed by The Qt Project
parent 38630bc35a
commit 79a389c346

View File

@ -144,6 +144,20 @@ bool QWindowsVistaStylePrivate::useVista()
(QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))); (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)));
} }
/* \internal
Checks and returns the style object
*/
inline QObject *styleObject(const QStyleOption *option) {
return option ? option->styleObject : 0;
}
bool canAnimate(const QStyleOption *option) {
return option
&& option->styleObject
&& !option->styleObject->property("_q_no_animation").toBool();
}
/*! /*!
\class QWindowsVistaStyle \class QWindowsVistaStyle
\brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista. \brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista.
@ -328,17 +342,17 @@ void QWindowsVistaPulse::paint(QPainter *painter, const QStyleOption *option)
transition has completed. During this time, the result will be transition has completed. During this time, the result will be
retrieved by the Animation::paint(...) function and not by the style retrieved by the Animation::paint(...) function and not by the style
itself. itself.
To determine if a transition should occur, the style needs to know 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 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 solved by updating dynamic properties on the widget every time the
function is called. function is called.
Transitions interrupting existing transitions should always be Transitions interrupting existing transitions should always be
smooth, so whenever a hover-transition is started on a pulsating smooth, so whenever a hover-transition is started on a pulsating
button, it uses the current frame of the pulse-animation as the button, it uses the current frame of the pulse-animation as the
starting image for the hover transition. starting image for the hover transition.
*/ */
void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const QPainter *painter, const QWidget *widget) const
@ -353,135 +367,135 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
return; return;
} }
QRect oldRect; if (d->transitionsEnabled() && canAnimate(option)) {
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 QRect oldRect;
// the previous state of the widget: QRect newRect;
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 && /* widgets that support state transitions : */
((state & State_Sunken) != (oldState & State_Sunken) || if ( element == PE_FrameLineEdit
(state & State_On) != (oldState & State_On) || || element == PE_IndicatorRadioButton
(state & State_MouseOver) != (oldState & State_MouseOver)); || element == PE_IndicatorCheckBox)
{
// Retrieve and update the dynamic properties tracking
// the previous state of the widget:
QObject *styleObject = option->styleObject;
styleObject->setProperty("_q_no_animation", true);
if (oldRect != newRect || int oldState = styleObject->property("_q_stylestate").toInt();
(state & State_Enabled) != (oldState & State_Enabled) || oldRect = styleObject->property("_q_stylerect").toRect();
(state & State_Active) != (oldState & State_Active)) newRect = option->rect;
d->stopAnimation(widget); styleObject->setProperty("_q_stylestate", (int)option->state);
styleObject->setProperty("_q_stylerect", option->rect);
#ifndef QT_NO_LINEEDIT bool doTransition = oldState &&
if (const QLineEdit *edit = qobject_cast<const QLineEdit *>(widget)) ((state & State_Sunken) != (oldState & State_Sunken) ||
if (edit->isReadOnly() && element == PE_FrameLineEdit) // Do not animate read only line edits (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(styleObject);
if (option->state & State_ReadOnly && element == PE_FrameLineEdit) // Do not animate read only line edits
doTransition = false; doTransition = false;
#endif // QT_NO_LINEEDIT
if (doTransition) { if (doTransition) {
QStyleOption *styleOption = 0;
// We create separate images for the initial and final transition states and store them in the if (const QStyleOptionGroupBox *combo = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
// Transition object. styleOption = new QStyleOptionGroupBox(*combo);
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 = qobject_cast<QWindowsVistaAnimation *>(d->animation(widget));
QWindowsVistaTransition *t = new QWindowsVistaTransition(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 else
fromState = ETS_NORMAL; styleOption = new QStyleOption(*option);
if (state & State_MouseOver) styleOption->state = (QStyle::State)oldState;
toState = ETS_HOT; styleOption->rect = QRect(QPoint(0,0), newRect.size());
else if (state & State_HasFocus)
toState = ETS_FOCUSED; QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
// 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);
startImage.fill(0);
QPainter startPainter(&startImage);
QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
endImage.fill(0);
QPainter endPainter(&endImage);
// 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, styleOption, &startPainter, widget);
else else
toState = ETS_NORMAL; anim->paint(&startPainter, styleOption);
} else { t->setStartImage(startImage);
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); // The end state of the transition is simply the result we would have painted
toState = buttonStateId(option->state, partId); // if the style was not animated.
styleOption->state = option->state;
drawPrimitive(element, styleOption, &endPainter, widget);
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());
delete styleOption;
d->startAnimation(t);
} }
styleObject->setProperty("_q_no_animation", false);
// 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
} // End of animation part
}
QRect rect = option->rect; QRect rect = option->rect;
@ -546,7 +560,8 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
case PE_IndicatorCheckBox: case PE_IndicatorCheckBox:
case PE_IndicatorRadioButton: case PE_IndicatorRadioButton:
{ {
if (QWindowsVistaAnimation *a = qobject_cast<QWindowsVistaAnimation *>(d->animation(widget)) ){ if (QWindowsVistaAnimation *a =
qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))){
a->paint(painter, option); a->paint(painter, option);
} else { } else {
QWindowsXPStyle::drawPrimitive(element, option, painter, widget); QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
@ -563,36 +578,32 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
d->drawBackground(theme); d->drawBackground(theme);
} }
break; break;
case PE_Frame: case PE_Frame: {
#ifndef QT_NO_TEXTEDIT painter->save();
if (const QTextEdit *edit = qobject_cast<const QTextEdit*>(widget)) { int stateId = ETS_NORMAL;
painter->save(); if (!(state & State_Enabled))
int stateId = ETS_NORMAL; stateId = ETS_DISABLED;
if (!(state & State_Enabled)) else if (state & State_ReadOnly)
stateId = ETS_DISABLED; stateId = ETS_READONLY;
else if (edit->isReadOnly()) else if (state & State_HasFocus)
stateId = ETS_READONLY; stateId = ETS_SELECTED;
else if (state & State_HasFocus) XPThemeData theme(widget, painter,
stateId = ETS_SELECTED; QWindowsXPStylePrivate::EditTheme,
XPThemeData theme(widget, painter, EP_EDITBORDER_HVSCROLL, stateId, option->rect);
QWindowsXPStylePrivate::EditTheme, uint resolve_mask = option->palette.resolve();
EP_EDITBORDER_HVSCROLL, stateId, option->rect); if (resolve_mask & (1 << QPalette::Base)) {
uint resolve_mask = option->palette.resolve(); // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping
if (resolve_mask & (1 << QPalette::Base)) { int borderSize = 1;
// Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping pGetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize);
int borderSize = 1; QRegion clipRegion = option->rect;
pGetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize); QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize);
QRegion clipRegion = option->rect; clipRegion ^= content;
QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize); painter->setClipRegion(clipRegion);
clipRegion ^= content; }
painter->setClipRegion(clipRegion); d->drawBackground(theme);
} painter->restore();
d->drawBackground(theme); }
painter->restore(); break;
} else
#endif // QT_NO_TEXTEDIT
QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
break;
case PE_PanelLineEdit: case PE_PanelLineEdit:
if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) { if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
@ -662,7 +673,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
break; break;
case PE_FrameLineEdit: case PE_FrameLineEdit:
if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(widget))) { if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
anim->paint(painter, option); anim->paint(painter, option);
} else { } else {
QPainter *p = painter; QPainter *p = painter;
@ -928,145 +939,166 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
int partId = 0; int partId = 0;
int stateId = 0; int stateId = 0;
QRect oldRect; if (d->transitionsEnabled() && canAnimate(option))
QRect newRect; {
if (element == CE_PushButtonBevel) {
QRect oldRect;
QRect newRect;
if (d->transitionsEnabled() && widget) { QObject *styleObject = option->styleObject;
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(); int oldState = styleObject->property("_q_stylestate").toInt();
bool isDefault = button->features & QStyleOptionButton::DefaultButton; oldRect = styleObject->property("_q_stylerect").toRect();
w->setProperty("_q_isdefault", isDefault); newRect = option->rect;
styleObject->setProperty("_q_stylestate", (int)option->state);
styleObject->setProperty("_q_stylerect", option->rect);
bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || bool wasDefault = false;
(state & State_On) != (oldState & State_On) || bool isDefault = false;
(state & State_MouseOver) != (oldState & State_MouseOver)); if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
wasDefault = styleObject->property("_q_isdefault").toBool();
if (oldRect != newRect || (wasDefault && !isDefault)) isDefault = button->features & QStyleOptionButton::DefaultButton;
{ styleObject->setProperty("_q_isdefault", 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 = qobject_cast<QWindowsVistaAnimation *>(d->animation(widget));
QStyleOptionButton opt = *button;
opt.state = (QStyle::State)oldState;
startImage.fill(0);
QWindowsVistaTransition *t = new QWindowsVistaTransition(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());
}
} }
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(styleObject);
}
if (doTransition) {
styleObject->setProperty("_q_no_animation", true);
QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
QStyleOption *styleOption = 0;
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
styleOption = new QStyleOptionComboBox(*combo);
else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
styleOption = new QStyleOptionButton(*button);
else
styleOption = new QStyleOption(*option);
styleOption->state = (QStyle::State)oldState;
styleOption->rect = QRect(QPoint(0,0), newRect.size());
QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
startImage.fill(0);
QPainter startPainter(&startImage);
// Use current state of existing animation if already one is running
if (!anim) {
proxy()->drawControl(element, styleOption, &startPainter, widget);
} else {
anim->paint(&startPainter, styleOption);
d->stopAnimation(styleObject);
}
t->setStartImage(startImage);
QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
endImage.fill(0);
QPainter endPainter(&endImage);
styleOption->state = option->state;
proxy()->drawControl(element, styleOption, &endPainter, widget);
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());
styleObject->setProperty("_q_no_animation", false);
delete styleOption;
d->startAnimation(t);
}
QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
if (anim) {
anim->paint(painter, option);
return;
}
} }
} }
switch (element) { switch (element) {
case CE_PushButtonBevel: case CE_PushButtonBevel:
if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))
{ {
QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(widget)); themeNumber = QWindowsXPStylePrivate::ButtonTheme;
if (anim && (btn->state & State_Enabled)) { partId = BP_PUSHBUTTON;
anim->paint(painter, option); if (btn->features & QStyleOptionButton::CommandLinkButton)
} else { partId = BP_COMMANDLINK;
themeNumber = QWindowsXPStylePrivate::ButtonTheme; bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken));
partId = BP_PUSHBUTTON; if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
if (btn->features & QStyleOptionButton::CommandLinkButton) stateId = PBS_DISABLED;
partId = BP_COMMANDLINK; else if (justFlat)
bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken)); ;
if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat)) else if (flags & (State_Sunken | State_On))
stateId = PBS_DISABLED; stateId = PBS_PRESSED;
else if (justFlat) else if (flags & State_MouseOver)
; stateId = PBS_HOT;
else if (flags & (State_Sunken | State_On)) else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active))
stateId = PBS_PRESSED; stateId = PBS_DEFAULTED;
else if (flags & State_MouseOver) else
stateId = PBS_HOT; stateId = PBS_NORMAL;
else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active))
stateId = PBS_DEFAULTED;
else
stateId = PBS_NORMAL;
if (!justFlat) { if (!justFlat) {
if (widget && d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) && if (d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) &&
!(state & (State_Sunken | State_On)) && !(state & State_MouseOver) && !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) &&
(state & State_Enabled) && (state & State_Active)) (state & State_Enabled) && (state & State_Active))
{ {
if (!anim && widget) { QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)));
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(const_cast<QWidget*>(widget)); if (!anim) {
QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
startImage.fill(0);
QImage alternateImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
alternateImage.fill(0);
QPainter startPainter(&startImage); QWindowsVistaPulse *pulse = new QWindowsVistaPulse(styleObject(option));
stateId = PBS_DEFAULTED;
XPThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect);
d->drawBackground(theme);
QPainter alternatePainter(&alternateImage); QPainter startPainter(&startImage);
theme.stateId = PBS_DEFAULTED_ANIMATING; stateId = PBS_DEFAULTED;
theme.painter = &alternatePainter; XPThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect);
d->drawBackground(theme); d->drawBackground(theme);
pulse->setPrimaryImage(startImage);
pulse->setAlternateImage(alternateImage);
pulse->setStartTime(QTime::currentTime());
pulse->setDuration(2000);
d->startAnimation(pulse);
anim = pulse;
}
if (anim) QPainter alternatePainter(&alternateImage);
anim->paint(painter, option); theme.stateId = PBS_DEFAULTED_ANIMATING;
else { theme.painter = &alternatePainter;
XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect); d->drawBackground(theme);
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 { else {
d->stopAnimation(widget);
XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect); XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
d->drawBackground(theme); d->drawBackground(theme);
} }
} }
else {
XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
d->drawBackground(theme);
}
} }
if (btn->features & QStyleOptionButton::HasMenu) { if (btn->features & QStyleOptionButton::HasMenu) {
int mbiw = 0, mbih = 0; int mbiw = 0, mbih = 0;
XPThemeData theme(widget, 0, QWindowsXPStylePrivate::ToolBarTheme, XPThemeData theme(widget, 0, QWindowsXPStylePrivate::ToolBarTheme,
@ -1102,10 +1134,10 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
} }
if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) { if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) {
if (!d->animation(option->styleObject)) if (!d->animation(styleObject(option)))
d->startAnimation(new QProgressStyleAnimation(d->animationFps, option->styleObject)); d->startAnimation(new QProgressStyleAnimation(d->animationFps, styleObject(option)));
} else { } else {
d->stopAnimation(option->styleObject); d->stopAnimation(styleObject(option));
} }
XPThemeData theme(widget, painter, XPThemeData theme(widget, painter,
@ -1116,7 +1148,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
QTime current = QTime::currentTime(); QTime current = QTime::currentTime();
if (isIndeterminate) { if (isIndeterminate) {
if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(option->styleObject))) { if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
int glowSize = 120; int glowSize = 120;
int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width()); int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
int animOffset = a->startTime().msecsTo(current) / 4; int animOffset = a->startTime().msecsTo(current) / 4;
@ -1186,7 +1218,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
} }
d->drawBackground(theme); d->drawBackground(theme);
if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(option->styleObject))) { if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
int glowSize = 140; int glowSize = 140;
int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width()); int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
int animOffset = a->startTime().msecsTo(current) / 4; int animOffset = a->startTime().msecsTo(current) / 4;
@ -1195,7 +1227,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
if (bar->progress < bar->maximum) if (bar->progress < bar->maximum)
a->setStartTime(QTime::currentTime()); a->setStartTime(QTime::currentTime());
else else
d->stopAnimation(option->styleObject); //we stop the glow motion only after it has d->stopAnimation(styleObject(option)); //we stop the glow motion only after it has
//moved out of view //moved out of view
} }
painter->save(); painter->save();
@ -1592,38 +1624,33 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle
if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow()) if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
flags |= State_MouseOver; flags |= State_MouseOver;
if (d->transitionsEnabled() && widget) { if (d->transitionsEnabled() && canAnimate(option))
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(); if (control == CC_ScrollBar || control == CC_SpinBox ) {
int oldActiveControls = w->property("_q_stylecontrols").toInt();
QRect oldRect = w->property("_q_stylerect").toRect(); QObject *styleObject = option->styleObject; // Can be widget or qquickitem
w->setProperty("_q_stylestate", (int)option->state);
w->setProperty("_q_stylecontrols", (int)option->activeSubControls); int oldState = styleObject->property("_q_stylestate").toInt();
w->setProperty("_q_stylerect", w->rect()); int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
QRect oldRect = styleObject->property("_q_stylerect").toRect();
styleObject->setProperty("_q_stylestate", (int)option->state);
styleObject->setProperty("_q_stylecontrols", (int)option->activeSubControls);
styleObject->setProperty("_q_stylerect", option->rect);
bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) ||
(state & State_On) != (oldState & State_On) || (state & State_On) != (oldState & State_On) ||
(state & State_MouseOver) != (oldState & State_MouseOver) || (state & State_MouseOver) != (oldState & State_MouseOver) ||
oldActiveControls != option->activeSubControls); oldActiveControls != option->activeSubControls);
if (qstyleoption_cast<const QStyleOptionSlider *>(option)) { if (qstyleoption_cast<const QStyleOptionSlider *>(option)) {
QRect oldSliderPos = w->property("_q_stylesliderpos").toRect(); QRect oldSliderPos = styleObject->property("_q_stylesliderpos").toRect();
QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget); QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
w->setProperty("_q_stylesliderpos", currentPos); styleObject->setProperty("_q_stylesliderpos", currentPos);
if (oldSliderPos != currentPos) { if (oldSliderPos != currentPos) {
doTransition = false; doTransition = false;
d->stopAnimation(widget); d->stopAnimation(styleObject);
} }
} else if (control == CC_SpinBox) { } else if (control == CC_SpinBox) {
//spinboxes have a transition when focus changes //spinboxes have a transition when focus changes
@ -1633,58 +1660,51 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle
if (oldRect != option->rect) { if (oldRect != option->rect) {
doTransition = false; doTransition = false;
d->stopAnimation(widget); d->stopAnimation(styleObject);
} }
if (doTransition) { if (doTransition) {
QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
startImage.fill(0);
QPainter startPainter(&startImage);
QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(widget));
QWindowsVistaTransition *t = new QWindowsVistaTransition(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);
QWindow *window = widget->windowHandle();
if (!window) {
if (const QWidget *nativeParent = widget->nativeParentWidget()) {
offset = widget->mapTo(nativeParent, offset);
window = nativeParent->windowHandle();
}
}
if (window && window->handle()) {
const QPixmap pixmap = window->screen()->grabWindow(window->winId(),
offset.x(), offset.y(), option->rect.width(), option->rect.height());
t->setStartImage(pixmap.toImage());
}
}
} else {
startImage.fill(0);
QPainter startPainter(&startImage);
anim->paint(&startPainter, option);
t->setStartImage(startImage);
}
d->startAnimation(t);
endImage.fill(0); endImage.fill(0);
QPainter endPainter(&endImage); QPainter endPainter(&endImage);
proxy()->drawComplexControl(control, option, &endPainter, 0 /* Intentional */);
QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
// Draw the image that ends the animation by using the current styleoption
QStyleOptionComplex *styleOption = 0;
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
styleOption = new QStyleOptionSlider(*slider);
else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
styleOption = new QStyleOptionSpinBox(*spinbox);
else
styleOption = new QStyleOptionComplex(*option);
styleOption->rect = QRect(QPoint(0,0), option->rect.size());
styleObject->setProperty("_q_no_animation", true);
// Draw transition source
if (!anim) {
styleOption->state = (QStyle::State)oldState;
styleOption->activeSubControls = (QStyle::SubControl)oldActiveControls;
proxy()->drawComplexControl(control, styleOption, &startPainter, widget);
} else {
anim->paint(&startPainter, option);
}
t->setStartImage(startImage);
// Draw transition target
styleOption->state = option->state;
styleOption->activeSubControls = option->activeSubControls;
proxy()->drawComplexControl(control, styleOption, &endPainter, widget);
styleObject->setProperty("_q_no_animation", false);
t->setEndImage(endImage); t->setEndImage(endImage);
t->setStartTime(QTime::currentTime()); t->setStartTime(QTime::currentTime());
@ -1692,13 +1712,14 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle
t->setDuration(150); t->setDuration(150);
else else
t->setDuration(500); t->setDuration(500);
}
if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(widget))) { delete styleOption;
d->startAnimation(t);
}
if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject))) {
anim->paint(painter, option); anim->paint(painter, option);
return; return;
} }
} }
} }