1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qwindowsvistastyle_p.h"
41 #include "qwindowsvistastyle_p_p.h"
42 #include <qoperatingsystemversion.h>
43 #include <qscreen.h>
44 #include <qwindow.h>
45 #include <private/qstyleanimation_p.h>
46 #include <private/qstylehelper_p.h>
47 #include <qpa/qplatformnativeinterface.h>
48 
49 QT_BEGIN_NAMESPACE
50 
51 static const int windowsItemFrame        =  2; // menu item frame width
52 static const int windowsItemHMargin      =  3; // menu item hor text margin
53 static const int windowsItemVMargin      =  4; // menu item ver text margin
54 static const int windowsArrowHMargin     =  6; // arrow horizontal margin
55 static const int windowsRightBorder      = 15; // right border on windows
56 
57 #ifndef TMT_CONTENTMARGINS
58 #  define TMT_CONTENTMARGINS 3602
59 #endif
60 #ifndef TMT_SIZINGMARGINS
61 #  define TMT_SIZINGMARGINS 3601
62 #endif
63 #ifndef LISS_NORMAL
64 #  define LISS_NORMAL 1
65 #  define LISS_HOT 2
66 #  define LISS_SELECTED 3
67 #  define LISS_DISABLED 4
68 #  define LISS_SELECTEDNOTFOCUS 5
69 #  define LISS_HOTSELECTED 6
70 #endif
71 #ifndef BP_COMMANDLINK
72 #  define BP_COMMANDLINK 6
73 #  define BP_COMMANDLINKGLYPH 7
74 #  define CMDLGS_NORMAL 1
75 #  define CMDLGS_HOT 2
76 #  define CMDLGS_PRESSED 3
77 #  define CMDLGS_DISABLED 4
78 #endif
79 
80 /* \internal
81     Checks if we should use Vista style , or if we should
82     fall back to Windows style.
83 */
useVista()84 bool QWindowsVistaStylePrivate::useVista()
85 {
86     return QWindowsVistaStylePrivate::useXP();
87 }
88 
89 /* \internal
90     Checks and returns the style object
91 */
styleObject(const QStyleOption * option)92 inline QObject *styleObject(const QStyleOption *option) {
93     return option ? option->styleObject : nullptr;
94 }
95 
96 /* \internal
97     Checks if we can animate on a style option
98 */
canAnimate(const QStyleOption * option)99 bool canAnimate(const QStyleOption *option) {
100     return option
101             && option->styleObject
102             && !option->styleObject->property("_q_no_animation").toBool();
103 }
104 
createAnimationBuffer(const QStyleOption * option,const QWidget * widget)105 static inline QImage createAnimationBuffer(const QStyleOption *option, const QWidget *widget)
106 {
107     const qreal devicePixelRatio = widget
108         ? widget->devicePixelRatioF() : qApp->devicePixelRatio();
109     QImage result(option->rect.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
110     result.setDevicePixelRatio(devicePixelRatio);
111     result.fill(0);
112     return result;
113 }
114 
115 /* \internal
116     Used by animations to clone a styleoption and shift its offset
117 */
clonedAnimationStyleOption(const QStyleOption * option)118 QStyleOption *clonedAnimationStyleOption(const QStyleOption*option) {
119     QStyleOption *styleOption = nullptr;
120     if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
121         styleOption = new QStyleOptionSlider(*slider);
122     else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
123         styleOption = new QStyleOptionSpinBox(*spinbox);
124     else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
125         styleOption = new QStyleOptionGroupBox(*groupBox);
126     else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
127         styleOption = new QStyleOptionComboBox(*combo);
128     else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
129         styleOption = new QStyleOptionButton(*button);
130     else
131         styleOption = new QStyleOption(*option);
132     styleOption->rect = QRect(QPoint(0,0), option->rect.size());
133     return styleOption;
134 }
135 
136 /* \internal
137     Used by animations to delete cloned styleoption
138 */
deleteClonedAnimationStyleOption(const QStyleOption * option)139 void deleteClonedAnimationStyleOption(const QStyleOption *option)
140 {
141     if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
142         delete slider;
143     else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
144         delete spinbox;
145     else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
146         delete groupBox;
147     else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
148         delete combo;
149     else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
150         delete button;
151     else
152         delete option;
153 }
154 
155 /*!
156   \class QWindowsVistaStyle
157   \brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista.
158   \since 4.3
159   \ingroup appearance
160   \inmodule QtWidgets
161   \internal
162 
163   \warning This style is only available on the Windows Vista platform
164   because it makes use of Windows Vista's style engine.
165 
166   \sa QMacStyle, QWindowsXPStyle, QFusionStyle
167 */
168 
169 /*!
170   Constructs a QWindowsVistaStyle object.
171 */
QWindowsVistaStyle()172 QWindowsVistaStyle::QWindowsVistaStyle()
173     : QWindowsXPStyle(*new QWindowsVistaStylePrivate)
174 {
175 }
176 
177 /*!
178   Destructor.
179 */
180 QWindowsVistaStyle::~QWindowsVistaStyle() = default;
181 
182 //convert Qt state flags to uxtheme button states
buttonStateId(int flags,int partId)183 static int buttonStateId(int flags, int partId)
184 {
185     int stateId = 0;
186     if (partId == BP_RADIOBUTTON || partId == BP_CHECKBOX) {
187         if (!(flags & QStyle::State_Enabled))
188             stateId = RBS_UNCHECKEDDISABLED;
189         else if (flags & QStyle::State_Sunken)
190             stateId = RBS_UNCHECKEDPRESSED;
191         else if (flags & QStyle::State_MouseOver)
192             stateId = RBS_UNCHECKEDHOT;
193         else
194             stateId = RBS_UNCHECKEDNORMAL;
195 
196         if (flags & QStyle::State_On)
197             stateId += RBS_CHECKEDNORMAL-1;
198 
199     } else if (partId == BP_PUSHBUTTON) {
200         if (!(flags & QStyle::State_Enabled))
201             stateId = PBS_DISABLED;
202         else if (flags & (QStyle::State_Sunken | QStyle::State_On))
203             stateId = PBS_PRESSED;
204         else if (flags & QStyle::State_MouseOver)
205             stateId = PBS_HOT;
206         else
207             stateId = PBS_NORMAL;
208     } else {
209         Q_ASSERT(1);
210     }
211     return stateId;
212 }
213 
isUpdateNeeded() const214 bool QWindowsVistaAnimation::isUpdateNeeded() const
215 {
216     return QWindowsVistaStylePrivate::useVista();
217 }
218 
paint(QPainter * painter,const QStyleOption * option)219 void QWindowsVistaAnimation::paint(QPainter *painter, const QStyleOption *option)
220 {
221     painter->drawImage(option->rect, currentImage());
222 }
223 
supportsStateTransition(QStyle::PrimitiveElement element,const QStyleOption * option,const QWidget * widget)224 static inline bool supportsStateTransition(QStyle::PrimitiveElement element,
225                                            const QStyleOption *option,
226                                            const QWidget *widget)
227 {
228     bool result = false;
229     switch (element) {
230     case QStyle::PE_IndicatorRadioButton:
231     case QStyle::PE_IndicatorCheckBox:
232         result = true;
233         break;
234     // QTBUG-40634, do not animate when color is set in palette for PE_PanelLineEdit.
235     case QStyle::PE_FrameLineEdit:
236         result = !QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget);
237         break;
238     default:
239         break;
240     }
241     return result;
242 }
243 
244 /*!
245  \internal
246 
247   Animations are used for some state transitions on specific widgets.
248 
249   Only one running animation can exist for a widget at any specific
250   time.  Animations can be added through
251   QWindowsVistaStylePrivate::startAnimation(Animation *) and any
252   existing animation on a widget can be retrieved with
253   QWindowsVistaStylePrivate::widgetAnimation(Widget *).
254 
255   Once an animation has been started,
256   QWindowsVistaStylePrivate::timerEvent(QTimerEvent *) will
257   continuously call update() on the widget until it is stopped,
258   meaning that drawPrimitive will be called many times until the
259   transition has completed. During this time, the result will be
260   retrieved by the Animation::paint(...) function and not by the style
261   itself.
262 
263   To determine if a transition should occur, the style needs to know
264   the previous state of the widget as well as the current one. This is
265   solved by updating dynamic properties on the widget every time the
266   function is called.
267 
268   Transitions interrupting existing transitions should always be
269   smooth, so whenever a hover-transition is started on a pulsating
270   button, it uses the current frame of the pulse-animation as the
271   starting image for the hover transition.
272 
273  */
274 
drawPrimitive(PrimitiveElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const275 void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
276                                        QPainter *painter, const QWidget *widget) const
277 {
278     QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
279 
280     int state = option->state;
281     if (!QWindowsVistaStylePrivate::useVista()) {
282         QWindowsStyle::drawPrimitive(element, option, painter, widget);
283         return;
284     }
285 
286     if ((option->state & State_Enabled) && d->transitionsEnabled() && canAnimate(option)) {
287         {
288             QRect oldRect;
289             QRect newRect;
290 
291             if (supportsStateTransition(element, option, widget)) {
292                 // Retrieve and update the dynamic properties tracking
293                 // the previous state of the widget:
294                 QObject *styleObject = option->styleObject;
295                 styleObject->setProperty("_q_no_animation", true);
296 
297                 int oldState = styleObject->property("_q_stylestate").toInt();
298                 oldRect = styleObject->property("_q_stylerect").toRect();
299                 newRect = option->rect;
300                 styleObject->setProperty("_q_stylestate", int(option->state));
301                 styleObject->setProperty("_q_stylerect", option->rect);
302 
303                 bool doTransition = oldState &&
304                         ((state & State_Sunken)    != (oldState & State_Sunken) ||
305                         (state & State_On)         != (oldState & State_On)     ||
306                         (state & State_MouseOver)  != (oldState & State_MouseOver));
307 
308                 if (oldRect != newRect ||
309                         (state & State_Enabled) != (oldState & State_Enabled) ||
310                         (state & State_Active)  != (oldState & State_Active))
311                     d->stopAnimation(styleObject);
312 
313                 if (option->state & State_ReadOnly && element == PE_FrameLineEdit) // Do not animate read only line edits
314                     doTransition = false;
315 
316                 if (doTransition) {
317                     QStyleOption *styleOption = clonedAnimationStyleOption(option);
318                     styleOption->state = QStyle::State(oldState);
319 
320                     QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
321                     QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
322 
323                     // We create separate images for the initial and final transition states and store them in the
324                     // Transition object.
325                     QImage startImage = createAnimationBuffer(option, widget);
326                     QPainter startPainter(&startImage);
327 
328                     QImage endImage = createAnimationBuffer(option, widget);
329                     QPainter endPainter(&endImage);
330 
331                     // If we have a running animation on the widget already, we will use that to paint the initial
332                     // state of the new transition, this ensures a smooth transition from a current animation such as a
333                     // pulsating default button into the intended target state.
334                     if (!anim)
335                         proxy()->drawPrimitive(element, styleOption, &startPainter, widget);
336                     else
337                         anim->paint(&startPainter, styleOption);
338 
339                     t->setStartImage(startImage);
340 
341                     // The end state of the transition is simply the result we would have painted
342                     // if the style was not animated.
343                     styleOption->styleObject = nullptr;
344                     styleOption->state = option->state;
345                     proxy()->drawPrimitive(element, styleOption, &endPainter, widget);
346 
347 
348                     t->setEndImage(endImage);
349 
350                     HTHEME theme;
351                     int partId;
352                     DWORD duration;
353                     int fromState = 0;
354                     int toState = 0;
355 
356                     //translate state flags to UXTHEME states :
357                     if (element == PE_FrameLineEdit) {
358                         theme = OpenThemeData(nullptr, L"Edit");
359                         partId = EP_EDITBORDER_NOSCROLL;
360 
361                         if (oldState & State_MouseOver)
362                             fromState = ETS_HOT;
363                         else if (oldState & State_HasFocus)
364                             fromState = ETS_FOCUSED;
365                         else
366                             fromState = ETS_NORMAL;
367 
368                         if (state & State_MouseOver)
369                             toState = ETS_HOT;
370                         else if (state & State_HasFocus)
371                             toState = ETS_FOCUSED;
372                         else
373                             toState = ETS_NORMAL;
374 
375                     } else {
376                         theme = OpenThemeData(nullptr, L"Button");
377                         if (element == PE_IndicatorRadioButton)
378                             partId = BP_RADIOBUTTON;
379                         else if (element == PE_IndicatorCheckBox)
380                             partId = BP_CHECKBOX;
381                         else
382                             partId = BP_PUSHBUTTON;
383 
384                         fromState = buttonStateId(oldState, partId);
385                         toState = buttonStateId(option->state, partId);
386                     }
387 
388                     // Retrieve the transition time between the states from the system.
389                     if (theme
390                         && SUCCEEDED(GetThemeTransitionDuration(theme, partId, fromState, toState,
391                                                                 TMT_TRANSITIONDURATIONS, &duration))) {
392                         t->setDuration(int(duration));
393                     }
394                     t->setStartTime(QTime::currentTime());
395 
396                     deleteClonedAnimationStyleOption(styleOption);
397                     d->startAnimation(t);
398                 }
399                 styleObject->setProperty("_q_no_animation", false);
400             }
401 
402         } // End of animation part
403     }
404 
405     QRect rect = option->rect;
406 
407     switch (element) {
408     case PE_IndicatorHeaderArrow:
409         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
410             int stateId = HSAS_SORTEDDOWN;
411             if (header->sortIndicator & QStyleOptionHeader::SortDown)
412                 stateId = HSAS_SORTEDUP; //note that the uxtheme sort down indicator is the inverse of ours
413             XPThemeData theme(widget, painter,
414                               QWindowsXPStylePrivate::HeaderTheme,
415                               HP_HEADERSORTARROW, stateId, option->rect);
416             d->drawBackground(theme);
417         }
418         break;
419 
420     case PE_IndicatorBranch:
421         {
422             XPThemeData theme(widget, painter, QWindowsXPStylePrivate::VistaTreeViewTheme);
423             static int decoration_size = 0;
424             if (!decoration_size && theme.isValid()) {
425                 XPThemeData themeSize = theme;
426                 themeSize.partId = TVP_HOTGLYPH;
427                 themeSize.stateId = GLPS_OPENED;
428                 const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
429                 decoration_size = qRound(qMax(size.width(), size.height()));
430             }
431             int mid_h = option->rect.x() + option->rect.width() / 2;
432             int mid_v = option->rect.y() + option->rect.height() / 2;
433             int bef_h = mid_h;
434             int bef_v = mid_v;
435             int aft_h = mid_h;
436             int aft_v = mid_v;
437             if (option->state & State_Children) {
438                 int delta = decoration_size / 2;
439                 theme.rect = QRect(bef_h - delta, bef_v - delta, decoration_size, decoration_size);
440                 theme.partId = option->state & State_MouseOver ? TVP_HOTGLYPH : TVP_GLYPH;
441                 theme.stateId = option->state & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
442                 if (option->direction == Qt::RightToLeft)
443                     theme.mirrorHorizontally = true;
444                 d->drawBackground(theme);
445                 bef_h -= delta + 2;
446                 bef_v -= delta + 2;
447                 aft_h += delta - 2;
448                 aft_v += delta - 2;
449             }
450 #if 0
451             QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern);
452             if (option->state & State_Item) {
453                 if (option->direction == Qt::RightToLeft)
454                     painter->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush);
455                 else
456                     painter->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush);
457             }
458             if (option->state & State_Sibling && option->rect.bottom() > aft_v)
459                 painter->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush);
460             if (option->state & (State_Open | State_Children | State_Item | State_Sibling) && (bef_v > option->rect.y()))
461                 painter->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush);
462 #endif
463         }
464         break;
465 
466     case PE_PanelButtonBevel:
467     case PE_IndicatorCheckBox:
468     case PE_IndicatorRadioButton:
469         {
470             if (QWindowsVistaAnimation *a =
471                     qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))){
472                 a->paint(painter, option);
473             } else {
474                 QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
475             }
476         }
477         break;
478 
479     case PE_FrameMenu:
480         {
481             int stateId = option->state & State_Active ? MB_ACTIVE : MB_INACTIVE;
482             XPThemeData theme(widget, painter,
483                               QWindowsXPStylePrivate::MenuTheme,
484                               MENU_POPUPBORDERS, stateId, option->rect);
485             d->drawBackground(theme);
486         }
487         break;
488     case PE_Frame: {
489 #ifndef QT_NO_ACCESSIBILITY
490         if (QStyleHelper::isInstanceOf(option->styleObject, QAccessible::EditableText)
491                 || QStyleHelper::isInstanceOf(option->styleObject, QAccessible::StaticText) ||
492 #else
493         if (
494 #endif
495             (widget && widget->inherits("QTextEdit"))) {
496             painter->save();
497             int stateId = ETS_NORMAL;
498             if (!(state & State_Enabled))
499                 stateId = ETS_DISABLED;
500             else if (state & State_ReadOnly)
501                 stateId = ETS_READONLY;
502             else if (state & State_HasFocus)
503                 stateId = ETS_SELECTED;
504             XPThemeData theme(widget, painter,
505                               QWindowsXPStylePrivate::EditTheme,
506                               EP_EDITBORDER_HVSCROLL, stateId, option->rect);
507             // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping
508             int borderSize = 1;
509             GetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize);
510             QRegion clipRegion = option->rect;
511             QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize);
512             clipRegion ^= content;
513             painter->setClipRegion(clipRegion);
514             d->drawBackground(theme);
515             painter->restore();
516         } else {
517             QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
518         }
519     }
520     break;
521 
522     case PE_PanelLineEdit:
523         if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
524             bool isEnabled = option->state & State_Enabled;
525             if (QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget)) {
526                 painter->fillRect(panel->rect, panel->palette.brush(QPalette::Base));
527             } else {
528                 int partId = EP_BACKGROUND;
529                 int stateId = EBS_NORMAL;
530                 if (!isEnabled)
531                     stateId = EBS_DISABLED;
532                 else if (state & State_ReadOnly)
533                     stateId = EBS_READONLY;
534                 else if (state & State_MouseOver)
535                     stateId = EBS_HOT;
536 
537                 XPThemeData theme(nullptr, painter, QWindowsXPStylePrivate::EditTheme,
538                                   partId, stateId, rect);
539                 if (!theme.isValid()) {
540                     QWindowsStyle::drawPrimitive(element, option, painter, widget);
541                     return;
542                 }
543                 int bgType;
544                 GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &bgType);
545                 if( bgType == BT_IMAGEFILE ) {
546                     d->drawBackground(theme);
547                 } else {
548                     QBrush fillColor = option->palette.brush(QPalette::Base);
549                     if (!isEnabled) {
550                         PROPERTYORIGIN origin = PO_NOTFOUND;
551                         GetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
552                         // Use only if the fill property comes from our part
553                         if ((origin == PO_PART || origin == PO_STATE)) {
554                             COLORREF bgRef;
555                             GetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
556                             fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
557                         }
558                     }
559                     painter->fillRect(option->rect, fillColor);
560                 }
561             }
562             if (panel->lineWidth > 0)
563                 proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
564             return;
565         }
566         break;
567 
568     case PE_FrameLineEdit:
569         if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
570             anim->paint(painter, option);
571         } else {
572             QPainter *p = painter;
573             if (QWindowsXPStylePrivate::isItemViewDelegateLineEdit(widget)) {
574                 // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
575                 QPen oldPen = p->pen();
576                 // Inner white border
577                 p->setPen(QPen(option->palette.base().color(), 1));
578                 p->drawRect(option->rect.adjusted(1, 1, -2, -2));
579                 // Outer dark border
580                 p->setPen(QPen(option->palette.shadow().color(), 1));
581                 p->drawRect(option->rect.adjusted(0, 0, -1, -1));
582                 p->setPen(oldPen);
583                 return;
584             }
585             int stateId = ETS_NORMAL;
586             if (!(state & State_Enabled))
587                 stateId = ETS_DISABLED;
588             else if (state & State_ReadOnly)
589                 stateId = ETS_READONLY;
590             else if (state & State_MouseOver)
591                 stateId = ETS_HOT;
592             else if (state & State_HasFocus)
593                 stateId = ETS_SELECTED;
594             XPThemeData theme(widget, painter,
595                               QWindowsXPStylePrivate::EditTheme,
596                               EP_EDITBORDER_NOSCROLL, stateId, option->rect);
597             theme.noContent = true;
598             painter->save();
599             QRegion clipRegion = option->rect;
600             clipRegion -= option->rect.adjusted(2, 2, -2, -2);
601             painter->setClipRegion(clipRegion);
602             d->drawBackground(theme);
603             painter->restore();
604         }
605         break;
606 
607     case PE_IndicatorToolBarHandle:
608         {
609             XPThemeData theme;
610             QRect rect;
611             if (option->state & State_Horizontal) {
612                 theme = XPThemeData(widget, painter,
613                                     QWindowsXPStylePrivate::RebarTheme,
614                                     RP_GRIPPER, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
615                 rect = option->rect.adjusted(0, 1, 0, -2);
616                 rect.setWidth(4);
617             } else {
618                 theme = XPThemeData(widget, painter, QWindowsXPStylePrivate::RebarTheme,
619                                     RP_GRIPPERVERT, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
620                 rect = option->rect.adjusted(1, 0, -1, 0);
621                 rect.setHeight(4);
622             }
623             theme.rect = rect;
624             d->drawBackground(theme);
625         }
626         break;
627 
628     case PE_IndicatorToolBarSeparator:
629         {
630             QPen pen = painter->pen();
631             int margin = 3;
632             painter->setPen(option->palette.window().color().darker(114));
633             if (option->state & State_Horizontal) {
634                 int x1 = option->rect.center().x();
635                 painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin));
636             } else {
637                 int y1 = option->rect.center().y();
638                 painter->drawLine(QPoint(option->rect.left() + margin, y1), QPoint(option->rect.right() - margin, y1));
639             }
640             painter->setPen(pen);
641         }
642         break;
643 
644     case PE_PanelTipLabel: {
645         XPThemeData theme(widget, painter,
646                           QWindowsXPStylePrivate::ToolTipTheme,
647                           TTP_STANDARD, TTSS_NORMAL, option->rect);
648         d->drawBackground(theme);
649         break;
650     }
651 
652     case PE_PanelItemViewItem:
653         {
654             const QStyleOptionViewItem *vopt;
655             bool newStyle = true;
656             QAbstractItemView::SelectionBehavior selectionBehavior = QAbstractItemView::SelectRows;
657             QAbstractItemView::SelectionMode selectionMode = QAbstractItemView::NoSelection;
658             if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
659                 newStyle = !qobject_cast<const QTableView*>(view);
660                 selectionBehavior = view->selectionBehavior();
661                 selectionMode = view->selectionMode();
662 #ifndef QT_NO_ACCESSIBILITY
663             } else if (!widget) {
664                 newStyle = !QStyleHelper::hasAncestor(option->styleObject, QAccessible::MenuItem) ;
665 #endif
666             }
667 
668             if (newStyle && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
669                 bool selected = vopt->state & QStyle::State_Selected;
670                 const bool hover = selectionMode != QAbstractItemView::NoSelection && (vopt->state & QStyle::State_MouseOver);
671                 bool active = vopt->state & QStyle::State_Active;
672 
673                 if (vopt->features & QStyleOptionViewItem::Alternate)
674                     painter->fillRect(vopt->rect, vopt->palette.alternateBase());
675 
676                 QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled
677                                           ? QPalette::Normal : QPalette::Disabled;
678                 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
679                     cg = QPalette::Inactive;
680 
681                 QRect itemRect = subElementRect(QStyle::SE_ItemViewItemFocusRect, option, widget).adjusted(-1, 0, 1, 0);
682                 itemRect.setTop(vopt->rect.top());
683                 itemRect.setBottom(vopt->rect.bottom());
684 
685                 QSize sectionSize = itemRect.size();
686                 if (vopt->showDecorationSelected)
687                     sectionSize = vopt->rect.size();
688 
689                 if (selectionBehavior == QAbstractItemView::SelectRows)
690                     sectionSize.setWidth(vopt->rect.width());
691                 QPixmap pixmap;
692 
693                 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
694                     const QPointF oldBrushOrigin = painter->brushOrigin();
695                     painter->setBrushOrigin(vopt->rect.topLeft());
696                     painter->fillRect(vopt->rect, vopt->backgroundBrush);
697                     painter->setBrushOrigin(oldBrushOrigin);
698                 }
699 
700                 if (hover || selected) {
701                     if (sectionSize.width() > 0 && sectionSize.height() > 0) {
702                         QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width())
703                                                             .arg(sectionSize.height()).arg(selected).arg(active).arg(hover);
704                         if (!QPixmapCache::find(key, &pixmap)) {
705                             pixmap = QPixmap(sectionSize);
706                             pixmap.fill(Qt::transparent);
707 
708                             int state;
709                             if (selected && hover)
710                                 state = LISS_HOTSELECTED;
711                             else if (selected && !active)
712                                 state = LISS_SELECTEDNOTFOCUS;
713                             else if (selected)
714                                 state = LISS_SELECTED;
715                             else
716                                 state = LISS_HOT;
717 
718                             QPainter pixmapPainter(&pixmap);
719                             XPThemeData theme(widget, &pixmapPainter,
720                                               QWindowsXPStylePrivate::VistaTreeViewTheme,
721                                 LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height()));
722                             if (theme.isValid()) {
723                                 d->drawBackground(theme);
724                             } else {
725                                 QWindowsXPStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
726                                 break;
727                             }
728                             QPixmapCache::insert(key, pixmap);
729                         }
730                     }
731 
732                     if (vopt->showDecorationSelected) {
733                         const int frame = 2; //Assumes a 2 pixel pixmap border
734                         QRect srcRect = QRect(0, 0, sectionSize.width(), sectionSize.height());
735                         QRect pixmapRect = vopt->rect;
736                         bool reverse = vopt->direction == Qt::RightToLeft;
737                         bool leftSection = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
738                         bool rightSection = vopt->viewItemPosition == QStyleOptionViewItem::End;
739                         if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne
740                             || vopt->viewItemPosition == QStyleOptionViewItem::Invalid)
741                             painter->drawPixmap(pixmapRect.topLeft(), pixmap);
742                         else if (reverse ? rightSection : leftSection){
743                             painter->drawPixmap(QRect(pixmapRect.topLeft(),
744                                                 QSize(frame, pixmapRect.height())), pixmap,
745                                                 QRect(QPoint(0, 0), QSize(frame, pixmapRect.height())));
746                             painter->drawPixmap(pixmapRect.adjusted(frame, 0, 0, 0),
747                                                 pixmap, srcRect.adjusted(frame, 0, -frame, 0));
748                         } else if (reverse ? leftSection : rightSection) {
749                             painter->drawPixmap(QRect(pixmapRect.topRight() - QPoint(frame - 1, 0),
750                                                 QSize(frame, pixmapRect.height())), pixmap,
751                                                 QRect(QPoint(pixmapRect.width() - frame, 0),
752                                                 QSize(frame, pixmapRect.height())));
753                             painter->drawPixmap(pixmapRect.adjusted(0, 0, -frame, 0),
754                                                 pixmap, srcRect.adjusted(frame, 0, -frame, 0));
755                         } else if (vopt->viewItemPosition == QStyleOptionViewItem::Middle)
756                             painter->drawPixmap(pixmapRect, pixmap,
757                                                 srcRect.adjusted(frame, 0, -frame, 0));
758                     } else {
759                         if (vopt->text.isEmpty() && vopt->icon.isNull())
760                             break;
761                         painter->drawPixmap(itemRect.topLeft(), pixmap);
762                     }
763                 }
764             } else {
765                 QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
766             }
767             break;
768         }
769     case PE_Widget:
770         {
771 #if QT_CONFIG(dialogbuttonbox)
772             const QDialogButtonBox *buttonBox = nullptr;
773 
774             if (qobject_cast<const QMessageBox *> (widget))
775                 buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
776 #if QT_CONFIG(inputdialog)
777             else if (qobject_cast<const QInputDialog *> (widget))
778                 buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
779 #endif // QT_CONFIG(inputdialog)
780 
781             if (buttonBox) {
782                 //draw white panel part
783                 XPThemeData theme(widget, painter,
784                                   QWindowsXPStylePrivate::TaskDialogTheme,
785                                   TDLG_PRIMARYPANEL, 0, option->rect);
786                 QRect toprect = option->rect;
787                 toprect.setBottom(buttonBox->geometry().top());
788                 theme.rect = toprect;
789                 d->drawBackground(theme);
790 
791                 //draw bottom panel part
792                 QRect buttonRect = option->rect;
793                 buttonRect.setTop(buttonBox->geometry().top());
794                 theme.rect = buttonRect;
795                 theme.partId = TDLG_SECONDARYPANEL;
796                 d->drawBackground(theme);
797             }
798 #endif
799         }
800         break;
801     default:
802         QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
803         break;
804     }
805 }
806 
807 
808 /*!
809  \internal
810 
811  see drawPrimitive for comments on the animation support
812  */
drawControl(ControlElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const813 void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption *option,
814                                   QPainter *painter, const QWidget *widget) const
815 {
816     QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
817 
818     if (!QWindowsVistaStylePrivate::useVista()) {
819         QWindowsStyle::drawControl(element, option, painter, widget);
820         return;
821     }
822 
823     bool selected = option->state & State_Selected;
824     bool pressed = option->state & State_Sunken;
825     bool disabled = !(option->state & State_Enabled);
826 
827     int state = option->state;
828     int themeNumber  = -1;
829 
830     QRect rect(option->rect);
831     State flags = option->state;
832     int partId = 0;
833     int stateId = 0;
834 
835     if (d->transitionsEnabled() && canAnimate(option))
836     {
837         if (element == CE_PushButtonBevel) {
838             QRect oldRect;
839             QRect newRect;
840 
841             QObject *styleObject = option->styleObject;
842 
843             int oldState = styleObject->property("_q_stylestate").toInt();
844             oldRect = styleObject->property("_q_stylerect").toRect();
845             newRect = option->rect;
846             styleObject->setProperty("_q_stylestate", int(option->state));
847             styleObject->setProperty("_q_stylerect", option->rect);
848 
849             bool wasDefault = false;
850             bool isDefault = false;
851             if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
852                 wasDefault = styleObject->property("_q_isdefault").toBool();
853                 isDefault = button->features & QStyleOptionButton::DefaultButton;
854                 styleObject->setProperty("_q_isdefault", isDefault);
855             }
856 
857             bool doTransition = ((state & State_Sunken)     != (oldState & State_Sunken) ||
858                     (state & State_On)         != (oldState & State_On)     ||
859                     (state & State_MouseOver)  != (oldState & State_MouseOver));
860 
861             if (oldRect != newRect || (wasDefault && !isDefault)) {
862                 doTransition = false;
863                 d->stopAnimation(styleObject);
864             }
865 
866             if (doTransition) {
867                 styleObject->setProperty("_q_no_animation", true);
868 
869                 QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
870                 QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
871                 QStyleOption *styleOption = clonedAnimationStyleOption(option);
872                 styleOption->state = QStyle::State(oldState);
873 
874                 QImage startImage = createAnimationBuffer(option, widget);
875                 QPainter startPainter(&startImage);
876 
877                 // Use current state of existing animation if already one is running
878                 if (!anim) {
879                     proxy()->drawControl(element, styleOption, &startPainter, widget);
880                 } else {
881                     anim->paint(&startPainter, styleOption);
882                     d->stopAnimation(styleObject);
883                 }
884 
885                 t->setStartImage(startImage);
886                 QImage endImage = createAnimationBuffer(option, widget);
887                 QPainter endPainter(&endImage);
888                 styleOption->state = option->state;
889                 proxy()->drawControl(element, styleOption, &endPainter, widget);
890                 t->setEndImage(endImage);
891 
892 
893                 DWORD duration = 0;
894                 const HTHEME theme = OpenThemeData(nullptr, L"Button");
895 
896                 int fromState = buttonStateId(oldState, BP_PUSHBUTTON);
897                 int toState = buttonStateId(option->state, BP_PUSHBUTTON);
898                 if (GetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK)
899                     t->setDuration(int(duration));
900                 else
901                     t->setDuration(0);
902                 t->setStartTime(QTime::currentTime());
903                 styleObject->setProperty("_q_no_animation", false);
904 
905                 deleteClonedAnimationStyleOption(styleOption);
906                 d->startAnimation(t);
907             }
908 
909             QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
910             if (anim) {
911                 anim->paint(painter, option);
912                 return;
913             }
914 
915         }
916     }
917     switch (element) {
918     case CE_PushButtonBevel:
919         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))
920         {
921             themeNumber = QWindowsXPStylePrivate::ButtonTheme;
922             partId = BP_PUSHBUTTON;
923             if (btn->features & QStyleOptionButton::CommandLinkButton)
924                 partId = BP_COMMANDLINK;
925             bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken));
926             if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
927                 stateId = PBS_DISABLED;
928             else if (justFlat)
929                 ;
930             else if (flags & (State_Sunken | State_On))
931                 stateId = PBS_PRESSED;
932             else if (flags & State_MouseOver)
933                 stateId = PBS_HOT;
934             else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active))
935                 stateId = PBS_DEFAULTED;
936             else
937                 stateId = PBS_NORMAL;
938 
939             if (!justFlat) {
940 
941                 if (d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) &&
942                         !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) &&
943                         (state & State_Enabled) && (state & State_Active))
944                 {
945                     QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)));
946 
947                     if (!anim) {
948                         QImage startImage = createAnimationBuffer(option, widget);
949                         QImage alternateImage = createAnimationBuffer(option, widget);
950 
951                         QWindowsVistaPulse *pulse = new QWindowsVistaPulse(styleObject(option));
952 
953                         QPainter startPainter(&startImage);
954                         stateId = PBS_DEFAULTED;
955                         XPThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect);
956                         d->drawBackground(theme);
957 
958                         QPainter alternatePainter(&alternateImage);
959                         theme.stateId = PBS_DEFAULTED_ANIMATING;
960                         theme.painter = &alternatePainter;
961                         d->drawBackground(theme);
962                         pulse->setStartImage(startImage);
963                         pulse->setEndImage(alternateImage);
964                         pulse->setStartTime(QTime::currentTime());
965                         pulse->setDuration(2000);
966                         d->startAnimation(pulse);
967                         anim = pulse;
968                     }
969 
970                     if (anim)
971                         anim->paint(painter, option);
972                     else {
973                         XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
974                         d->drawBackground(theme);
975                     }
976                 }
977                 else {
978                     XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
979                     d->drawBackground(theme);
980                 }
981             }
982 
983             if (btn->features & QStyleOptionButton::HasMenu) {
984                 int mbiw = 0, mbih = 0;
985                 XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::ToolBarTheme,
986                                   TP_DROPDOWNBUTTON);
987                 if (theme.isValid()) {
988                     const QSizeF size = theme.size() * QStyleHelper::dpiScaled(1, option);
989                     if (!size.isEmpty()) {
990                         mbiw = qRound(size.width());
991                         mbih = qRound(size.height());
992                     }
993                 }
994                 QRect ir = subElementRect(SE_PushButtonContents, option, nullptr);
995                 QStyleOptionButton newBtn = *btn;
996                 newBtn.rect = QStyle::visualRect(option->direction, option->rect,
997                                                 QRect(ir.right() - mbiw - 2,
998                                                       option->rect.top() + (option->rect.height()/2) - (mbih/2),
999                                                       mbiw + 1, mbih + 1));
1000                 proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
1001             }
1002             return;
1003         }
1004         break;
1005 
1006     case CE_ProgressBarContents:
1007         if (const QStyleOptionProgressBar *bar
1008                 = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
1009             bool isIndeterminate = (bar->minimum == 0 && bar->maximum == 0);
1010             const bool vertical = bar->orientation == Qt::Vertical;
1011             const bool inverted = bar->invertedAppearance;
1012 
1013             if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) {
1014                 if (!d->animation(styleObject(option)))
1015                     d->startAnimation(new QProgressStyleAnimation(d->animationFps, styleObject(option)));
1016             } else {
1017                 d->stopAnimation(styleObject(option));
1018             }
1019 
1020             XPThemeData theme(widget, painter,
1021                               QWindowsXPStylePrivate::ProgressTheme,
1022                               vertical ? PP_FILLVERT : PP_FILL);
1023             theme.rect = option->rect;
1024             bool reverse = (bar->direction == Qt::LeftToRight && inverted) || (bar->direction == Qt::RightToLeft && !inverted);
1025             QTime current = QTime::currentTime();
1026 
1027             if (isIndeterminate) {
1028                 if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
1029                     int glowSize = 120;
1030                     int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
1031                     int animOffset = a->startTime().msecsTo(current) / 4;
1032                     if (animOffset > animationWidth)
1033                         a->setStartTime(QTime::currentTime());
1034                     painter->save();
1035                     painter->setClipRect(theme.rect);
1036                     QRect animRect;
1037                     QSize pixmapSize(14, 14);
1038                     if (vertical) {
1039                         animRect = QRect(theme.rect.left(),
1040                                          inverted ? rect.top() - glowSize + animOffset :
1041                                                     rect.bottom() + glowSize - animOffset,
1042                                          rect.width(), glowSize);
1043                          pixmapSize.setHeight(animRect.height());
1044                     } else {
1045                         animRect = QRect(rect.left() - glowSize + animOffset,
1046                                          rect.top(), glowSize, rect.height());
1047                         animRect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
1048                                                                 option->rect, animRect);
1049                         pixmapSize.setWidth(animRect.width());
1050                     }
1051                     QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height());
1052                     QPixmap pixmap;
1053                     if (!QPixmapCache::find(name, &pixmap)) {
1054                         QImage image(pixmapSize, QImage::Format_ARGB32);
1055                         image.fill(Qt::transparent);
1056                         QPainter imagePainter(&image);
1057                         theme.painter = &imagePainter;
1058                         theme.partId = vertical ? PP_FILLVERT : PP_FILL;
1059                         theme.rect = QRect(QPoint(0,0), animRect.size());
1060                         QLinearGradient alphaGradient(0, 0, vertical ? 0 : image.width(),
1061                                                       vertical ? image.height() : 0);
1062                         alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
1063                         alphaGradient.setColorAt(0.5, QColor(0, 0, 0, 220));
1064                         alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
1065                         imagePainter.fillRect(image.rect(), alphaGradient);
1066                         imagePainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
1067                         d->drawBackground(theme);
1068                         imagePainter.end();
1069                         pixmap = QPixmap::fromImage(image);
1070                         QPixmapCache::insert(name, pixmap);
1071                     }
1072                     painter->drawPixmap(animRect, pixmap);
1073                     painter->restore();
1074                 }
1075             }
1076             else {
1077                 qint64 progress = qMax<qint64>(bar->progress, bar->minimum); // workaround for bug in QProgressBar
1078 
1079                 if (vertical) {
1080                     int maxHeight = option->rect.height();
1081                     int minHeight = 0;
1082                     double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxHeight);
1083                     int height = isIndeterminate ? maxHeight: qMax(int(vc6_workaround), minHeight);
1084                     theme.rect.setHeight(height);
1085                     if (!inverted)
1086                         theme.rect.moveTop(rect.height() - theme.rect.height());
1087                 } else {
1088                     int maxWidth = option->rect.width();
1089                     int minWidth = 0;
1090                     double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth);
1091                     int width = isIndeterminate ? maxWidth : qMax(int(vc6_workaround), minWidth);
1092                     theme.rect.setWidth(width);
1093                     theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
1094                                                               option->rect, theme.rect);
1095                 }
1096                 d->drawBackground(theme);
1097 
1098                 if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
1099                     int glowSize = 140;
1100                     int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
1101                     int animOffset = a->startTime().msecsTo(current) / 4;
1102                     theme.partId = vertical ? PP_MOVEOVERLAYVERT : PP_MOVEOVERLAY;
1103                     if (animOffset > animationWidth) {
1104                         if (bar->progress < bar->maximum)
1105                             a->setStartTime(QTime::currentTime());
1106                         else
1107                             d->stopAnimation(styleObject(option)); //we stop the glow motion only after it has
1108                                                                    //moved out of view
1109                     }
1110                     painter->save();
1111                     painter->setClipRect(theme.rect);
1112                     if (vertical) {
1113                         theme.rect = QRect(theme.rect.left(),
1114                                            inverted ? rect.top() - glowSize + animOffset :
1115                                                       rect.bottom() + glowSize - animOffset,
1116                                            rect.width(), glowSize);
1117                     } else {
1118                         theme.rect = QRect(rect.left() - glowSize + animOffset,rect.top(), glowSize, rect.height());
1119                         theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, option->rect, theme.rect);
1120                     }
1121                     d->drawBackground(theme);
1122                     painter->restore();
1123                 }
1124             }
1125         }
1126         break;
1127 
1128     case CE_MenuBarItem:
1129         {
1130 
1131         if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
1132         {
1133             if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
1134                 break;
1135 
1136             QPalette::ColorRole textRole = disabled ? QPalette::Text : QPalette::ButtonText;
1137             QPixmap pix = mbi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
1138 
1139             int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1140             if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
1141                 alignment |= Qt::TextHideMnemonic;
1142 
1143             if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls
1144                 //The rect adjustment is a workaround for the menu not really filling its background.
1145                 XPThemeData theme(widget, painter,
1146                                   QWindowsXPStylePrivate::MenuTheme,
1147                                   MENU_BARBACKGROUND, 0, option->rect.adjusted(-1, 0, 2, 1));
1148                 d->drawBackground(theme);
1149             }
1150 
1151             int stateId = MBI_NORMAL;
1152             if (disabled)
1153                 stateId = MBI_DISABLED;
1154             else if (pressed)
1155                 stateId = MBI_PUSHED;
1156             else if (selected)
1157                 stateId = MBI_HOT;
1158 
1159             XPThemeData theme2(widget, painter,
1160                                QWindowsXPStylePrivate::MenuTheme,
1161                                MENU_BARITEM, stateId, option->rect);
1162             d->drawBackground(theme2);
1163 
1164             if (!pix.isNull())
1165                 drawItemPixmap(painter, mbi->rect, alignment, pix);
1166             else
1167                 drawItemText(painter, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
1168         }
1169     }
1170     break;
1171 #if QT_CONFIG(menu)
1172     case CE_MenuItem:
1173         if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
1174             // windows always has a check column, regardless whether we have an icon or not
1175             const qreal factor = QWindowsXPStylePrivate::nativeMetricScaleFactor(widget);
1176             int checkcol = qRound(qreal(25) * factor);
1177             const int gutterWidth = qRound(qreal(3) * factor);
1178             {
1179                 XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::MenuTheme,
1180                                   MENU_POPUPCHECKBACKGROUND, MBI_HOT);
1181                 XPThemeData themeSize = theme;
1182                 themeSize.partId = MENU_POPUPCHECK;
1183                 themeSize.stateId = 0;
1184                 const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1185                 const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1186                 checkcol = qMax(menuitem->maxIconWidth, qRound(gutterWidth + size.width() + margins.left() + margins.right()));
1187             }
1188             QRect rect = option->rect;
1189 
1190             //draw vertical menu line
1191             if (option->direction == Qt::LeftToRight)
1192                 checkcol += rect.x();
1193             QPoint p1 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.top()));
1194             QPoint p2 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.bottom()));
1195             QRect gutterRect(p1.x(), p1.y(), gutterWidth, p2.y() - p1.y() + 1);
1196             XPThemeData theme2(widget, painter, QWindowsXPStylePrivate::MenuTheme,
1197                                MENU_POPUPGUTTER, stateId, gutterRect);
1198             d->drawBackground(theme2);
1199 
1200             int x, y, w, h;
1201             menuitem->rect.getRect(&x, &y, &w, &h);
1202             int tab = menuitem->tabWidth;
1203             bool dis = !(menuitem->state & State_Enabled);
1204             bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
1205                             ? menuitem->checked : false;
1206             bool act = menuitem->state & State_Selected;
1207 
1208             if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
1209                 int yoff = y-2 + h / 2;
1210                 const int separatorSize = qRound(qreal(6) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
1211                 QPoint p1 = QPoint(x + checkcol, yoff);
1212                 QPoint p2 = QPoint(x + w + separatorSize, yoff);
1213                 stateId = MBI_HOT;
1214                 QRect subRect(p1.x() + (gutterWidth - menuitem->rect.x()), p1.y(),
1215                               p2.x() - p1.x(), separatorSize);
1216                 subRect  = QStyle::visualRect(option->direction, option->rect, subRect );
1217                 XPThemeData theme2(widget, painter,
1218                                    QWindowsXPStylePrivate::MenuTheme,
1219                                    MENU_POPUPSEPARATOR, stateId, subRect);
1220                 d->drawBackground(theme2);
1221                 return;
1222             }
1223 
1224             QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(),
1225                                           menuitem->rect.y(), checkcol - (gutterWidth + menuitem->rect.x()), menuitem->rect.height()));
1226 
1227             if (act) {
1228                 stateId = dis ? MBI_DISABLED : MBI_HOT;
1229                 XPThemeData theme2(widget, painter,
1230                                    QWindowsXPStylePrivate::MenuTheme,
1231                                    MENU_POPUPITEM, stateId, option->rect);
1232                 d->drawBackground(theme2);
1233             }
1234 
1235             if (checked) {
1236                 XPThemeData theme(widget, painter,
1237                                   QWindowsXPStylePrivate::MenuTheme,
1238                                   MENU_POPUPCHECKBACKGROUND,
1239                                   menuitem->icon.isNull() ? MBI_HOT : MBI_PUSHED, vCheckRect);
1240                 XPThemeData themeSize = theme;
1241                 themeSize.partId = MENU_POPUPCHECK;
1242                 themeSize.stateId = 0;
1243                 const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1244                 const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1245                 QRect checkRect(0, 0, qRound(size.width() + margins.left() + margins.right()),
1246                                 qRound(size.height() + margins.bottom() + margins.top()));
1247                 checkRect.moveCenter(vCheckRect.center());
1248                 theme.rect = checkRect;
1249 
1250                 d->drawBackground(theme);
1251 
1252                 if (menuitem->icon.isNull()) {
1253                     checkRect = QRect(QPoint(0, 0), size.toSize());
1254                     checkRect.moveCenter(theme.rect.center());
1255                     theme.rect = checkRect;
1256 
1257                     theme.partId = MENU_POPUPCHECK;
1258                     bool bullet = menuitem->checkType & QStyleOptionMenuItem::Exclusive;
1259                     if (dis)
1260                         theme.stateId = bullet ? MC_BULLETDISABLED: MC_CHECKMARKDISABLED;
1261                     else
1262                         theme.stateId = bullet ? MC_BULLETNORMAL: MC_CHECKMARKNORMAL;
1263                     d->drawBackground(theme);
1264                 }
1265             }
1266 
1267             if (!menuitem->icon.isNull()) {
1268                 QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
1269                 if (act && !dis)
1270                     mode = QIcon::Active;
1271                 QPixmap pixmap;
1272                 if (checked)
1273                     pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On);
1274                 else
1275                     pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode);
1276                 const int pixw = pixmap.width() / pixmap.devicePixelRatio();
1277                 const int pixh = pixmap.height() / pixmap.devicePixelRatio();
1278                 QRect pmr(0, 0, pixw, pixh);
1279                 pmr.moveCenter(vCheckRect.center());
1280                 painter->setPen(menuitem->palette.text().color());
1281                 painter->drawPixmap(pmr.topLeft(), pixmap);
1282             }
1283 
1284             painter->setPen(menuitem->palette.buttonText().color());
1285 
1286             const QColor textColor = menuitem->palette.text().color();
1287             if (dis)
1288                 painter->setPen(textColor);
1289 
1290             int xm = windowsItemFrame + checkcol + windowsItemHMargin + (gutterWidth - menuitem->rect.x()) - 1;
1291             int xpos = menuitem->rect.x() + xm;
1292             QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
1293             QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
1294             QString s = menuitem->text;
1295             if (!s.isEmpty()) {    // draw text
1296                 painter->save();
1297                 int t = s.indexOf(QLatin1Char('\t'));
1298                 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1299                 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
1300                     text_flags |= Qt::TextHideMnemonic;
1301                 text_flags |= Qt::AlignLeft;
1302                 if (t >= 0) {
1303                     QRect vShortcutRect = visualRect(option->direction, menuitem->rect,
1304                     QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
1305                     painter->drawText(vShortcutRect, text_flags, s.mid(t + 1));
1306                     s = s.left(t);
1307                 }
1308                 QFont font = menuitem->font;
1309                 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1310                     font.setBold(true);
1311                 painter->setFont(font);
1312                 painter->setPen(textColor);
1313                 painter->drawText(vTextRect, text_flags, s.left(t));
1314                 painter->restore();
1315             }
1316             if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
1317                 int dim = (h - 2 * windowsItemFrame) / 2;
1318                 PrimitiveElement arrow;
1319                 arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
1320                 xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
1321                 QRect  vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
1322                 QStyleOptionMenuItem newMI = *menuitem;
1323                 newMI.rect = vSubMenuRect;
1324                 newMI.state = dis ? State_None : State_Enabled;
1325                 proxy()->drawPrimitive(arrow, &newMI, painter, widget);
1326             }
1327         }
1328         break;
1329 #endif // QT_CONFIG(menu)
1330     case CE_HeaderSection:
1331         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
1332             partId = HP_HEADERITEM;
1333             if (flags & State_Sunken)
1334                 stateId = HIS_PRESSED;
1335             else if (flags & State_MouseOver)
1336                 stateId = HIS_HOT;
1337             else
1338                 stateId = HIS_NORMAL;
1339 
1340             if (header->sortIndicator != QStyleOptionHeader::None)
1341                 stateId += 3;
1342 
1343             XPThemeData theme(widget, painter,
1344                               QWindowsXPStylePrivate::HeaderTheme,
1345                               partId, stateId, option->rect);
1346             d->drawBackground(theme);
1347         }
1348         break;
1349     case CE_MenuBarEmptyArea:
1350         {
1351             stateId = MBI_NORMAL;
1352             if (!(state & State_Enabled))
1353                 stateId = MBI_DISABLED;
1354             XPThemeData theme(widget, painter,
1355                               QWindowsXPStylePrivate::MenuTheme,
1356                               MENU_BARBACKGROUND, stateId, option->rect);
1357             d->drawBackground(theme);
1358         }
1359         break;
1360     case CE_ToolBar:
1361         if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) {
1362             QPalette pal = option->palette;
1363             pal.setColor(QPalette::Dark, option->palette.window().color().darker(130));
1364             QStyleOptionToolBar copyOpt = *toolbar;
1365             copyOpt.palette = pal;
1366             QWindowsStyle::drawControl(element, &copyOpt, painter, widget);
1367         }
1368         break;
1369 #if QT_CONFIG(dockwidget)
1370     case CE_DockWidgetTitle:
1371         if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
1372             const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(widget);
1373             QRect rect = option->rect;
1374             if (dockWidget && dockWidget->isFloating()) {
1375                 QWindowsXPStyle::drawControl(element, option, painter, widget);
1376                 break; //otherwise fall through
1377             }
1378 
1379             const bool verticalTitleBar = dwOpt->verticalTitleBar;
1380 
1381             if (verticalTitleBar) {
1382                 rect = rect.transposed();
1383 
1384                 painter->translate(rect.left() - 1, rect.top() + rect.width());
1385                 painter->rotate(-90);
1386                 painter->translate(-rect.left() + 1, -rect.top());
1387             }
1388 
1389             painter->setBrush(option->palette.window().color().darker(110));
1390             painter->setPen(option->palette.window().color().darker(130));
1391             painter->drawRect(rect.adjusted(0, 1, -1, -3));
1392 
1393             int buttonMargin = 4;
1394             int mw = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
1395             int fw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget);
1396             const QDockWidget *dw = qobject_cast<const QDockWidget *>(widget);
1397             bool isFloating = dw && dw->isFloating();
1398 
1399             QRect r = option->rect.adjusted(0, 2, -1, -3);
1400             QRect titleRect = r;
1401 
1402             if (dwOpt->closable) {
1403                 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10));
1404                 titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
1405             }
1406 
1407             if (dwOpt->floatable) {
1408                 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10));
1409                 titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
1410             }
1411 
1412             if (isFloating) {
1413                 titleRect.adjust(0, -fw, 0, 0);
1414                 if (widget && widget->windowIcon().cacheKey() != QApplication::windowIcon().cacheKey())
1415                     titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
1416             } else {
1417                 titleRect.adjust(mw, 0, 0, 0);
1418                 if (!dwOpt->floatable && !dwOpt->closable)
1419                     titleRect.adjust(0, 0, -mw, 0);
1420             }
1421             if (!verticalTitleBar)
1422                 titleRect = visualRect(dwOpt->direction, r, titleRect);
1423 
1424             if (!dwOpt->title.isEmpty()) {
1425                 QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
1426                                                                       verticalTitleBar ? titleRect.height() : titleRect.width());
1427                 const int indent = 4;
1428                 drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1),
1429                                 Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
1430                                 dwOpt->palette,
1431                                 dwOpt->state & State_Enabled, titleText,
1432                                 QPalette::WindowText);
1433                 }
1434             }
1435             break;
1436 #endif // QT_CONFIG(dockwidget)
1437 #if QT_CONFIG(itemviews)
1438     case CE_ItemViewItem:
1439         {
1440             const QStyleOptionViewItem *vopt;
1441 
1442             const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
1443             bool newStyle = true;
1444 
1445             if (qobject_cast<const QTableView*>(widget))
1446                 newStyle = false;
1447 
1448             if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
1449                 /*
1450                 // We cannot currently get the correct selection color for "explorer style" views
1451                 COLORREF cref = 0;
1452                 XPThemeData theme(d->treeViewHelper(), 0, QLatin1String("LISTVIEW"), 0, 0);
1453                 unsigned int res = GetThemeColor(theme.handle(), LVP_LISTITEM, LISS_SELECTED, TMT_TEXTCOLOR, &cref);
1454                 QColor textColor(GetRValue(cref), GetGValue(cref), GetBValue(cref));
1455                 */
1456                 QPalette palette = vopt->palette;
1457                 palette.setColor(QPalette::All, QPalette::HighlightedText, palette.color(QPalette::Active, QPalette::Text));
1458                 // Note that setting a saturated color here results in ugly XOR colors in the focus rect
1459                 palette.setColor(QPalette::All, QPalette::Highlight, palette.base().color().darker(108));
1460                 QStyleOptionViewItem adjustedOption = *vopt;
1461                 adjustedOption.palette = palette;
1462                 // We hide the  focusrect in singleselection as it is not required
1463                 if ((view->selectionMode() == QAbstractItemView::SingleSelection)
1464                     && !(vopt->state & State_KeyboardFocusChange))
1465                 adjustedOption.state &= ~State_HasFocus;
1466                 QWindowsXPStyle::drawControl(element, &adjustedOption, painter, widget);
1467             } else {
1468                 QWindowsXPStyle::drawControl(element, option, painter, widget);
1469             }
1470             break;
1471         }
1472 #endif // QT_CONFIG(itemviews)
1473 #if QT_CONFIG(combobox)
1474     case CE_ComboBoxLabel:
1475         QCommonStyle::drawControl(element, option, painter, widget);
1476         break;
1477 #endif // QT_CONFIG(combobox)
1478     default:
1479         QWindowsXPStyle::drawControl(element, option, painter, widget);
1480         break;
1481     }
1482 }
1483 
1484 /*!
1485   \internal
1486 
1487   see drawPrimitive for comments on the animation support
1488 
1489  */
drawComplexControl(ComplexControl control,const QStyleOptionComplex * option,QPainter * painter,const QWidget * widget) const1490 void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
1491                                          QPainter *painter, const QWidget *widget) const
1492 {
1493     QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
1494     if (!QWindowsVistaStylePrivate::useVista()) {
1495         QWindowsStyle::drawComplexControl(control, option, painter, widget);
1496         return;
1497     }
1498 
1499     State state = option->state;
1500     SubControls sub = option->subControls;
1501     QRect r = option->rect;
1502 
1503     int partId = 0;
1504     int stateId = 0;
1505 
1506     State flags = option->state;
1507     if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
1508         flags |= State_MouseOver;
1509 
1510     if (d->transitionsEnabled() && canAnimate(option))
1511     {
1512 
1513         if (control == CC_ScrollBar || control == CC_SpinBox || control == CC_ComboBox) {
1514 
1515             QObject *styleObject = option->styleObject; // Can be widget or qquickitem
1516 
1517             int oldState = styleObject->property("_q_stylestate").toInt();
1518             int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
1519 
1520             QRect oldRect = styleObject->property("_q_stylerect").toRect();
1521             styleObject->setProperty("_q_stylestate", int(option->state));
1522             styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
1523             styleObject->setProperty("_q_stylerect", option->rect);
1524 
1525             bool doTransition = ((state & State_Sunken)     != (oldState & State_Sunken)    ||
1526                                  (state & State_On)         != (oldState & State_On)        ||
1527                                  (state & State_MouseOver)  != (oldState & State_MouseOver) ||
1528                                   oldActiveControls         != int(option->activeSubControls));
1529 
1530             if (qstyleoption_cast<const QStyleOptionSlider *>(option)) {
1531                 QRect oldSliderPos = styleObject->property("_q_stylesliderpos").toRect();
1532                 QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
1533                 styleObject->setProperty("_q_stylesliderpos", currentPos);
1534                 if (oldSliderPos != currentPos) {
1535                     doTransition = false;
1536                     d->stopAnimation(styleObject);
1537                 }
1538             } else if (control == CC_SpinBox) {
1539                 //spinboxes have a transition when focus changes
1540                 if (!doTransition)
1541                     doTransition = (state & State_HasFocus) != (oldState & State_HasFocus);
1542             }
1543 
1544             if (oldRect != option->rect) {
1545                 doTransition = false;
1546                 d->stopAnimation(styleObject);
1547             }
1548 
1549             if (doTransition) {
1550                 QImage startImage = createAnimationBuffer(option, widget);
1551                 QPainter startPainter(&startImage);
1552 
1553                 QImage endImage = createAnimationBuffer(option, widget);
1554                 QPainter endPainter(&endImage);
1555 
1556                 QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
1557                 QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
1558 
1559                 // Draw the image that ends the animation by using the current styleoption
1560                 QStyleOptionComplex *styleOption = qstyleoption_cast<QStyleOptionComplex*>(clonedAnimationStyleOption(option));
1561 
1562                 styleObject->setProperty("_q_no_animation", true);
1563 
1564                 // Draw transition source
1565                 if (!anim) {
1566                     styleOption->state = QStyle::State(oldState);
1567                     styleOption->activeSubControls = QStyle::SubControl(oldActiveControls);
1568                     proxy()->drawComplexControl(control, styleOption, &startPainter, widget);
1569                 } else {
1570                     anim->paint(&startPainter, option);
1571                 }
1572                 t->setStartImage(startImage);
1573 
1574                 // Draw transition target
1575                 styleOption->state = option->state;
1576                 styleOption->activeSubControls = option->activeSubControls;
1577                 proxy()->drawComplexControl(control, styleOption, &endPainter, widget);
1578 
1579                 styleObject->setProperty("_q_no_animation", false);
1580 
1581                 t->setEndImage(endImage);
1582                 t->setStartTime(QTime::currentTime());
1583 
1584                 if (option->state & State_MouseOver || option->state & State_Sunken)
1585                     t->setDuration(150);
1586                 else
1587                     t->setDuration(500);
1588 
1589                 deleteClonedAnimationStyleOption(styleOption);
1590                 d->startAnimation(t);
1591             }
1592             if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject))) {
1593                 anim->paint(painter, option);
1594                 return;
1595             }
1596         }
1597     }
1598 
1599     switch (control) {
1600     case CC_ComboBox:
1601         if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option))
1602         {
1603             if (cmb->editable) {
1604                 if (sub & SC_ComboBoxEditField) {
1605                     partId = EP_EDITBORDER_NOSCROLL;
1606                     if (!(flags & State_Enabled))
1607                         stateId = ETS_DISABLED;
1608                     else if (flags & State_MouseOver)
1609                         stateId = ETS_HOT;
1610                     else if (flags & State_HasFocus)
1611                         stateId = ETS_FOCUSED;
1612                     else
1613                         stateId = ETS_NORMAL;
1614 
1615                     XPThemeData theme(widget, painter,
1616                                       QWindowsXPStylePrivate::EditTheme,
1617                                       partId, stateId, r);
1618 
1619                     d->drawBackground(theme);
1620                 }
1621                 if (sub & SC_ComboBoxArrow) {
1622                     QRect subRect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
1623                     XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
1624                     theme.rect = subRect;
1625                     partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
1626 
1627                     if (!(cmb->state & State_Enabled))
1628                         stateId = CBXS_DISABLED;
1629                     else if (cmb->state & State_Sunken || cmb->state & State_On)
1630                         stateId = CBXS_PRESSED;
1631                     else if (cmb->state & State_MouseOver && option->activeSubControls & SC_ComboBoxArrow)
1632                         stateId = CBXS_HOT;
1633                     else
1634                         stateId = CBXS_NORMAL;
1635 
1636                     theme.partId = partId;
1637                     theme.stateId = stateId;
1638                     d->drawBackground(theme);
1639                 }
1640 
1641             } else {
1642                 if (sub & SC_ComboBoxFrame) {
1643                     XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
1644                     theme.rect = option->rect;
1645                     theme.partId = CP_READONLY;
1646                     if (!(cmb->state & State_Enabled))
1647                         theme.stateId = CBXS_DISABLED;
1648                     else if (cmb->state & State_Sunken || cmb->state & State_On)
1649                         theme.stateId = CBXS_PRESSED;
1650                     else if (cmb->state & State_MouseOver)
1651                         theme.stateId = CBXS_HOT;
1652                     else
1653                         theme.stateId = CBXS_NORMAL;
1654                     d->drawBackground(theme);
1655                 }
1656                 if (sub & SC_ComboBoxArrow) {
1657                     XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
1658                     theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
1659                     theme.partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
1660                     if (!(cmb->state & State_Enabled))
1661                         theme.stateId = CBXS_DISABLED;
1662                     else
1663                         theme.stateId = CBXS_NORMAL;
1664                     d->drawBackground(theme);
1665                 }
1666                 if ((sub & SC_ComboBoxEditField) && (flags & State_HasFocus)) {
1667                     QStyleOptionFocusRect fropt;
1668                     fropt.QStyleOption::operator=(*cmb);
1669                     fropt.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget);
1670                     proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
1671                 }
1672             }
1673         }
1674         break;
1675     case CC_ScrollBar:
1676         if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option))
1677         {
1678             XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ScrollBarTheme);
1679             bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
1680             if (maxedOut)
1681                 flags &= ~State_Enabled;
1682 
1683             bool isHorz = flags & State_Horizontal;
1684             bool isRTL  = option->direction == Qt::RightToLeft;
1685             if (sub & SC_ScrollBarAddLine) {
1686                 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
1687                 partId = SBP_ARROWBTN;
1688                 if (!(flags & State_Enabled))
1689                     stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
1690                 else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
1691                     stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
1692                 else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
1693                     stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
1694                 else if (scrollbar->state & State_MouseOver)
1695                     stateId = (isHorz ? (isRTL ? ABS_LEFTHOVER : ABS_RIGHTHOVER) : ABS_DOWNHOVER);
1696                 else
1697                     stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
1698                 theme.partId = partId;
1699                 theme.stateId = stateId;
1700                 d->drawBackground(theme);
1701             }
1702             if (sub & SC_ScrollBarSubLine) {
1703                 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
1704                 partId = SBP_ARROWBTN;
1705                 if (!(flags & State_Enabled))
1706                     stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
1707                 else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
1708                     stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
1709                 else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
1710                     stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
1711                 else if (scrollbar->state & State_MouseOver)
1712                     stateId = (isHorz ? (isRTL ? ABS_RIGHTHOVER : ABS_LEFTHOVER) : ABS_UPHOVER);
1713                 else
1714                     stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
1715                 theme.partId = partId;
1716                 theme.stateId = stateId;
1717                 d->drawBackground(theme);
1718             }
1719             if (maxedOut) {
1720                 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
1721                 theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
1722                 theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget));
1723                 partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
1724                 stateId = SCRBS_DISABLED;
1725                 theme.partId = partId;
1726                 theme.stateId = stateId;
1727                 d->drawBackground(theme);
1728             } else {
1729                 if (sub & SC_ScrollBarSubPage) {
1730                     theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget);
1731                     partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
1732                     if (!(flags & State_Enabled))
1733                         stateId = SCRBS_DISABLED;
1734                     else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
1735                         stateId = SCRBS_PRESSED;
1736                     else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
1737                         stateId = SCRBS_HOT;
1738                     else
1739                         stateId = SCRBS_NORMAL;
1740                     theme.partId = partId;
1741                     theme.stateId = stateId;
1742                     d->drawBackground(theme);
1743                 }
1744                 if (sub & SC_ScrollBarAddPage) {
1745                     theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget);
1746                     partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
1747                     if (!(flags & State_Enabled))
1748                         stateId = SCRBS_DISABLED;
1749                     else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
1750                         stateId = SCRBS_PRESSED;
1751                     else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
1752                         stateId = SCRBS_HOT;
1753                     else
1754                         stateId = SCRBS_NORMAL;
1755                     theme.partId = partId;
1756                     theme.stateId = stateId;
1757                     d->drawBackground(theme);
1758                 }
1759                 if (sub & SC_ScrollBarSlider) {
1760                     theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
1761                     if (!(flags & State_Enabled))
1762                         stateId = SCRBS_DISABLED;
1763                     else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
1764                         stateId = SCRBS_PRESSED;
1765                     else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
1766                         stateId = SCRBS_HOT;
1767                     else if (option->state & State_MouseOver)
1768                         stateId = SCRBS_HOVER;
1769                     else
1770                         stateId = SCRBS_NORMAL;
1771 
1772                     // Draw handle
1773                     theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
1774                     theme.stateId = stateId;
1775                     d->drawBackground(theme);
1776 
1777                     if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) {
1778                         const QRect gripperBounds = QWindowsXPStylePrivate::scrollBarGripperBounds(flags, widget, &theme);
1779                         // Draw gripper if there is enough space
1780                         if (!gripperBounds.isEmpty() && flags & State_Enabled) {
1781                             painter->save();
1782                             XPThemeData grippBackground = theme;
1783                             grippBackground.partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
1784                             theme.rect = gripperBounds;
1785                             painter->setClipRegion(d->region(theme));// Only change inside the region of the gripper
1786                             d->drawBackground(grippBackground);// The gutter is the grippers background
1787                             d->drawBackground(theme);          // Transparent gripper ontop of background
1788                             painter->restore();
1789                         }
1790                     }
1791                 }
1792             }
1793         }
1794         break;
1795 #if QT_CONFIG(spinbox)
1796     case CC_SpinBox:
1797         if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option))
1798         {
1799             XPThemeData theme(widget, painter, QWindowsXPStylePrivate::SpinTheme);
1800             if (sb->frame && (sub & SC_SpinBoxFrame)) {
1801                 partId = EP_EDITBORDER_NOSCROLL;
1802                 if (!(flags & State_Enabled))
1803                     stateId = ETS_DISABLED;
1804                 else if (flags & State_MouseOver)
1805                     stateId = ETS_HOT;
1806                 else if (flags & State_HasFocus)
1807                     stateId = ETS_SELECTED;
1808                 else
1809                     stateId = ETS_NORMAL;
1810 
1811                 XPThemeData ftheme(widget, painter,
1812                                    QWindowsXPStylePrivate::EditTheme,
1813                                    partId, stateId, r);
1814                 // The spinbox in Windows QStyle is drawn with frameless QLineEdit inside it
1815                 // That however breaks with QtQuickControls where this results in transparent
1816                 // spinbox background, so if there's no "widget" passed (QtQuickControls case),
1817                 // let ftheme.noContent be false, which fixes the spinbox rendering in QQC
1818                 ftheme.noContent = (widget != nullptr);
1819                 d->drawBackground(ftheme);
1820             }
1821             if (sub & SC_SpinBoxUp) {
1822                 theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1);
1823                 partId = SPNP_UP;
1824                 if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled))
1825                     stateId = UPS_DISABLED;
1826                 else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
1827                     stateId = UPS_PRESSED;
1828                 else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
1829                     stateId = UPS_HOT;
1830                 else
1831                     stateId = UPS_NORMAL;
1832                 theme.partId = partId;
1833                 theme.stateId = stateId;
1834                 d->drawBackground(theme);
1835             }
1836             if (sub & SC_SpinBoxDown) {
1837                 theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
1838                 partId = SPNP_DOWN;
1839                 if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled))
1840                     stateId = DNS_DISABLED;
1841                 else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
1842                     stateId = DNS_PRESSED;
1843                 else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
1844                     stateId = DNS_HOT;
1845                 else
1846                     stateId = DNS_NORMAL;
1847                 theme.partId = partId;
1848                 theme.stateId = stateId;
1849                 d->drawBackground(theme);
1850             }
1851         }
1852         break;
1853 #endif // QT_CONFIG(spinbox)
1854     default:
1855         QWindowsXPStyle::drawComplexControl(control, option, painter, widget);
1856         break;
1857     }
1858 }
1859 
1860 /*!
1861  \internal
1862  */
sizeFromContents(ContentsType type,const QStyleOption * option,const QSize & size,const QWidget * widget) const1863 QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
1864                                         const QSize &size, const QWidget *widget) const
1865 {
1866     if (!QWindowsVistaStylePrivate::useVista())
1867         return QWindowsStyle::sizeFromContents(type, option, size, widget);
1868 
1869     QSize sz(size);
1870     switch (type) {
1871     case CT_MenuItem:
1872         sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
1873         int minimumHeight;
1874         {
1875             XPThemeData theme(widget, nullptr,
1876                               QWindowsXPStylePrivate::MenuTheme,
1877                               MENU_POPUPCHECKBACKGROUND, MBI_HOT);
1878             XPThemeData themeSize = theme;
1879             themeSize.partId = MENU_POPUPCHECK;
1880             themeSize.stateId = 0;
1881             const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1882             const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1883             minimumHeight = qMax(qRound(size.height() + margins.bottom() + margins.top()), sz.height());
1884             sz.rwidth() += qRound(size.width() + margins.left() + margins.right());
1885         }
1886 
1887         if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
1888             if (menuitem->menuItemType != QStyleOptionMenuItem::Separator)
1889                 sz.setHeight(minimumHeight);
1890         }
1891         return sz;
1892 #if QT_CONFIG(menubar)
1893     case CT_MenuBarItem:
1894         if (!sz.isEmpty())
1895             sz += QSize(windowsItemHMargin * 5 + 1, 5);
1896         return sz;
1897 #endif
1898     case CT_ItemViewItem:
1899         sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
1900         sz.rheight() += 2;
1901         return sz;
1902     case CT_SpinBox:
1903         {
1904             //Spinbox adds frame twice
1905             sz = QWindowsStyle::sizeFromContents(type, option, size, widget);
1906             int border = proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget);
1907             sz -= QSize(2*border, 2*border);
1908         }
1909         return sz;
1910     case CT_HeaderSection:
1911         {
1912             // When there is a sort indicator it adds to the width but it is shown
1913             // above the text natively and not on the side
1914             if (QStyleOptionHeader *hdr = qstyleoption_cast<QStyleOptionHeader *>(const_cast<QStyleOption *>(option))) {
1915                 QStyleOptionHeader::SortIndicator sortInd = hdr->sortIndicator;
1916                 hdr->sortIndicator = QStyleOptionHeader::None;
1917                 sz = QWindowsXPStyle::sizeFromContents(type, hdr, size, widget);
1918                 hdr->sortIndicator = sortInd;
1919                 return sz;
1920             }
1921             break;
1922         }
1923     default:
1924         break;
1925     }
1926     return QWindowsXPStyle::sizeFromContents(type, option, size, widget);
1927 }
1928 
1929 /*!
1930  \internal
1931  */
subElementRect(SubElement element,const QStyleOption * option,const QWidget * widget) const1932 QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
1933 {
1934    if (!QWindowsVistaStylePrivate::useVista())
1935         return QWindowsStyle::subElementRect(element, option, widget);
1936 
1937    QRect rect = QWindowsXPStyle::subElementRect(element, option, widget);
1938     switch (element) {
1939 
1940     case SE_PushButtonContents:
1941         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
1942             MARGINS borderSize;
1943             const HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"Button");
1944             if (theme) {
1945                 int stateId = PBS_NORMAL;
1946                 if (!(option->state & State_Enabled))
1947                     stateId = PBS_DISABLED;
1948                 else if (option->state & State_Sunken)
1949                     stateId = PBS_PRESSED;
1950                 else if (option->state & State_MouseOver)
1951                     stateId = PBS_HOT;
1952                 else if (btn->features & QStyleOptionButton::DefaultButton)
1953                     stateId = PBS_DEFAULTED;
1954 
1955                 int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn, widget);
1956                 rect = option->rect.adjusted(border, border, -border, -border);
1957 
1958                 if (SUCCEEDED(GetThemeMargins(theme, nullptr, BP_PUSHBUTTON, stateId, TMT_CONTENTMARGINS, nullptr, &borderSize))) {
1959                     rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
1960                                 -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
1961                     rect = visualRect(option->direction, option->rect, rect);
1962                 }
1963             }
1964         }
1965         break;
1966 
1967     case SE_HeaderArrow:
1968         {
1969             QRect r = rect;
1970             int h = option->rect.height();
1971             int w = option->rect.width();
1972             int x = option->rect.x();
1973             int y = option->rect.y();
1974             int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
1975 
1976             XPThemeData theme(widget, nullptr,
1977                               QWindowsXPStylePrivate::HeaderTheme,
1978                               HP_HEADERSORTARROW, HSAS_SORTEDDOWN, option->rect);
1979 
1980             int arrowWidth = 13;
1981             int arrowHeight = 5;
1982             if (theme.isValid()) {
1983                 const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1984                 if (!size.isEmpty()) {
1985                     arrowWidth = qRound(size.width());
1986                     arrowHeight = qRound(size.height());
1987                 }
1988             }
1989             if (option->state & State_Horizontal) {
1990                 r.setRect(x + w/2 - arrowWidth/2, y , arrowWidth, arrowHeight);
1991             } else {
1992                 int vert_size = w / 2;
1993                 r.setRect(x + 5, y + h - margin * 2 - vert_size,
1994                           w - margin * 2 - 5, vert_size);
1995             }
1996             rect = visualRect(option->direction, option->rect, r);
1997         }
1998         break;
1999 
2000     case SE_HeaderLabel:
2001         {
2002             int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
2003             QRect r = option->rect;
2004             r.setRect(option->rect.x() + margin, option->rect.y() + margin,
2005                       option->rect.width() - margin * 2, option->rect.height() - margin * 2);
2006             if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
2007                 // Subtract width needed for arrow, if there is one
2008                 if (header->sortIndicator != QStyleOptionHeader::None) {
2009                     if (!(option->state & State_Horizontal)) //horizontal arrows are positioned on top
2010                         r.setHeight(r.height() - (option->rect.width() / 2) - (margin * 2));
2011                 }
2012             }
2013             rect = visualRect(option->direction, option->rect, r);
2014         }
2015         break;
2016     case SE_ProgressBarContents:
2017         rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget);
2018         break;
2019     case SE_ItemViewItemDecoration:
2020         if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
2021             rect.adjust(-2, 0, 2, 0);
2022         break;
2023     case SE_ItemViewItemFocusRect:
2024         if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
2025             QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, option, widget);
2026             QRect displayRect = subElementRect(QStyle::SE_ItemViewItemDecoration, option, widget);
2027             if (!vopt->icon.isNull())
2028                 rect = textRect.united(displayRect);
2029             else
2030                 rect = textRect;
2031             rect = rect.adjusted(1, 0, -1, 0);
2032         }
2033         break;
2034     default:
2035         break;
2036     }
2037     return rect;
2038 }
2039 
2040 
2041 /*
2042   This function is used by subControlRect to check if a button
2043   should be drawn for the given subControl given a set of window flags.
2044 */
buttonVisible(const QStyle::SubControl sc,const QStyleOptionTitleBar * tb)2045 static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){
2046 
2047     bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
2048     bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
2049     const auto flags = tb->titleBarFlags;
2050     bool retVal = false;
2051     switch (sc) {
2052     case QStyle::SC_TitleBarContextHelpButton:
2053         if (flags & Qt::WindowContextHelpButtonHint)
2054             retVal = true;
2055         break;
2056     case QStyle::SC_TitleBarMinButton:
2057         if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
2058             retVal = true;
2059         break;
2060     case QStyle::SC_TitleBarNormalButton:
2061         if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
2062             retVal = true;
2063         else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
2064             retVal = true;
2065         break;
2066     case QStyle::SC_TitleBarMaxButton:
2067         if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
2068             retVal = true;
2069         break;
2070     case QStyle::SC_TitleBarShadeButton:
2071         if (!isMinimized &&  flags & Qt::WindowShadeButtonHint)
2072             retVal = true;
2073         break;
2074     case QStyle::SC_TitleBarUnshadeButton:
2075         if (isMinimized && flags & Qt::WindowShadeButtonHint)
2076             retVal = true;
2077         break;
2078     case QStyle::SC_TitleBarCloseButton:
2079         if (flags & Qt::WindowSystemMenuHint)
2080             retVal = true;
2081         break;
2082     case QStyle::SC_TitleBarSysMenu:
2083         if (flags & Qt::WindowSystemMenuHint)
2084             retVal = true;
2085         break;
2086     default :
2087         retVal = true;
2088     }
2089     return retVal;
2090 }
2091 
2092 
2093 /*! \internal */
styleHint(StyleHint hint,const QStyleOption * option,const QWidget * widget,QStyleHintReturn * returnData) const2094 int QWindowsVistaStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
2095                              QStyleHintReturn *returnData) const
2096 {
2097     QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
2098     int ret = 0;
2099     switch (hint) {
2100     case SH_MessageBox_CenterButtons:
2101         ret = false;
2102         break;
2103     case SH_ToolTip_Mask:
2104         if (option) {
2105             if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(returnData)) {
2106                 ret = true;
2107                 XPThemeData themeData(widget, nullptr,
2108                                       QWindowsXPStylePrivate::ToolTipTheme,
2109                                       TTP_STANDARD, TTSS_NORMAL, option->rect);
2110                 mask->region = d->region(themeData);
2111             }
2112         }
2113         break;
2114      case SH_Table_GridLineColor:
2115         if (option)
2116             ret = int(option->palette.color(QPalette::Base).darker(118).rgba());
2117         else
2118             ret = -1;
2119         break;
2120     case SH_Header_ArrowAlignment:
2121         ret = Qt::AlignTop | Qt::AlignHCenter;
2122         break;
2123     default:
2124         ret = QWindowsXPStyle::styleHint(hint, option, widget, returnData);
2125         break;
2126     }
2127     return ret;
2128 }
2129 
2130 
2131 /*!
2132  \internal
2133  */
subControlRect(ComplexControl control,const QStyleOptionComplex * option,SubControl subControl,const QWidget * widget) const2134 QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
2135                                   SubControl subControl, const QWidget *widget) const
2136 {
2137    if (!QWindowsVistaStylePrivate::useVista())
2138         return QWindowsStyle::subControlRect(control, option, subControl, widget);
2139 
2140     QRect rect = QWindowsXPStyle::subControlRect(control, option, subControl, widget);
2141     switch (control) {
2142 #if QT_CONFIG(combobox)
2143     case CC_ComboBox:
2144         if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
2145             const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height();
2146             const int margin = cb->frame ? 3 : 0;
2147             const int bmarg = cb->frame ? 2 : 0;
2148             const int arrowWidth = qRound(QStyleHelper::dpiScaled(16, option));
2149             const int arrowButtonWidth = bmarg + arrowWidth;
2150             const int xpos = x + wi - arrowButtonWidth;
2151 
2152             switch (subControl) {
2153             case SC_ComboBoxFrame:
2154                 rect = cb->rect;
2155                 break;
2156             case SC_ComboBoxArrow:
2157                 rect.setRect(xpos, y , arrowButtonWidth, he);
2158                 break;
2159             case SC_ComboBoxEditField:
2160                 rect.setRect(x + margin, y + margin, wi - 2 * margin - arrowWidth, he - 2 * margin);
2161                 break;
2162             case SC_ComboBoxListBoxPopup:
2163                 rect = cb->rect;
2164                 break;
2165             default:
2166                 break;
2167             }
2168             rect = visualRect(cb->direction, cb->rect, rect);
2169             return rect;
2170         }
2171         break;
2172 #endif // QT_CONFIG(combobox)
2173     case CC_TitleBar:
2174         if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
2175             if (!buttonVisible(subControl, tb))
2176                 return rect;
2177             const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
2178             const bool isToolTitle = false;
2179             const int height = tb->rect.height();
2180             const int width = tb->rect.width();
2181             const int buttonWidth =
2182                 qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor - QStyleHelper::dpiScaled(4, option));
2183 
2184             const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
2185             const bool sysmenuHint  = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
2186             const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
2187             const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
2188             const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
2189             const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
2190 
2191             switch (subControl) {
2192             case SC_TitleBarLabel:
2193                 rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
2194                 if (isToolTitle) {
2195                     if (sysmenuHint) {
2196                         rect.adjust(0, 0, int(-buttonWidth - 3 * factor), 0);
2197                     }
2198                     if (minimizeHint || maximizeHint)
2199                         rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
2200                 } else {
2201                     if (sysmenuHint) {
2202                         const int leftOffset = int(height - 8 * factor);
2203                         rect.adjust(leftOffset, 0, 0, int(4 * factor));
2204                     }
2205                     if (minimizeHint)
2206                         rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
2207                     if (maximizeHint)
2208                         rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
2209                     if (contextHint)
2210                         rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
2211                     if (shadeHint)
2212                         rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
2213                 }
2214                 rect.translate(0, int(2 * factor));
2215                 rect = visualRect(option->direction, option->rect, rect);
2216                 break;
2217             case SC_TitleBarSysMenu:
2218                 {
2219                     const int controlTop = int(6 * factor);
2220                     const int controlHeight = int(height - controlTop - 3 * factor);
2221                     int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option);
2222                     QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
2223                     if (tb->icon.isNull())
2224                         iconSize = QSize(controlHeight, controlHeight);
2225                     int hPad = (controlHeight - iconSize.height())/2;
2226                     int vPad = (controlHeight - iconSize.width())/2;
2227                     rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
2228                     rect.translate(0, int(3 * factor));
2229                     rect = visualRect(option->direction, option->rect, rect);
2230                 }
2231                 break;
2232             default:
2233                 break;
2234             }
2235         }
2236         break;
2237     default:
2238         break;
2239     }
2240     return rect;
2241 }
2242 
2243 /*!
2244  \internal
2245  */
hitTestComplexControl(ComplexControl control,const QStyleOptionComplex * option,const QPoint & pos,const QWidget * widget) const2246 QStyle::SubControl QWindowsVistaStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
2247                                                           const QPoint &pos, const QWidget *widget) const
2248 {
2249     if (!QWindowsVistaStylePrivate::useVista()) {
2250         return QWindowsStyle::hitTestComplexControl(control, option, pos, widget);
2251     }
2252     return QWindowsXPStyle::hitTestComplexControl(control, option, pos, widget);
2253 }
2254 
fixedPixelMetric(QStyle::PixelMetric pm)2255 int QWindowsVistaStylePrivate::fixedPixelMetric(QStyle::PixelMetric pm)
2256 {
2257     switch (pm) {
2258     case QStyle::PM_DockWidgetTitleBarButtonMargin:
2259         return 5;
2260     case QStyle::PM_ScrollBarSliderMin:
2261         return 18;
2262     case QStyle::PM_MenuHMargin:
2263     case QStyle::PM_MenuVMargin:
2264         return 0;
2265     case QStyle::PM_MenuPanelWidth:
2266         return 3;
2267     default:
2268         break;
2269     }
2270     return QWindowsVistaStylePrivate::InvalidMetric;
2271 }
2272 
2273 /*!
2274  \internal
2275  */
pixelMetric(PixelMetric metric,const QStyleOption * option,const QWidget * widget) const2276 int QWindowsVistaStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
2277 {
2278     if (!QWindowsVistaStylePrivate::useVista())
2279         return QWindowsStyle::pixelMetric(metric, option, widget);
2280 
2281     int ret = QWindowsVistaStylePrivate::fixedPixelMetric(metric);
2282     if (ret != QWindowsStylePrivate::InvalidMetric)
2283         return int(QStyleHelper::dpiScaled(ret, option));
2284 
2285     return QWindowsXPStyle::pixelMetric(metric, option, widget);
2286 }
2287 
2288 /*!
2289  \internal
2290  */
standardPalette() const2291 QPalette QWindowsVistaStyle::standardPalette() const
2292 {
2293     return QWindowsXPStyle::standardPalette();
2294 }
2295 
2296 /*!
2297  \internal
2298  */
polish(QApplication * app)2299 void QWindowsVistaStyle::polish(QApplication *app)
2300 {
2301     QWindowsXPStyle::polish(app);
2302 }
2303 
2304 /*!
2305  \internal
2306  */
polish(QWidget * widget)2307 void QWindowsVistaStyle::polish(QWidget *widget)
2308 {
2309     QWindowsXPStyle::polish(widget);
2310 #if QT_CONFIG(lineedit)
2311     if (qobject_cast<QLineEdit*>(widget))
2312         widget->setAttribute(Qt::WA_Hover);
2313     else
2314 #endif // QT_CONFIG(lineedit)
2315     if (qobject_cast<QGroupBox*>(widget))
2316         widget->setAttribute(Qt::WA_Hover);
2317 #if QT_CONFIG(commandlinkbutton)
2318     else if (qobject_cast<QCommandLinkButton*>(widget)) {
2319         QFont buttonFont = widget->font();
2320         buttonFont.setFamily(QLatin1String("Segoe UI"));
2321         widget->setFont(buttonFont);
2322     }
2323 #endif // QT_CONFIG(commandlinkbutton)
2324     else if (widget->inherits("QTipLabel")){
2325         //note that since tooltips are not reused
2326         //we do not have to care about unpolishing
2327         widget->setContentsMargins(3, 0, 4, 0);
2328         COLORREF bgRef;
2329         HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"TOOLTIP");
2330         if (theme && SUCCEEDED(GetThemeColor(theme, TTP_STANDARD, TTSS_NORMAL, TMT_TEXTCOLOR, &bgRef))) {
2331             QColor textColor = QColor::fromRgb(bgRef);
2332             QPalette pal;
2333             pal.setColor(QPalette::All, QPalette::ToolTipText, textColor);
2334             widget->setPalette(pal);
2335         }
2336     } else if (qobject_cast<QMessageBox *> (widget)) {
2337         widget->setAttribute(Qt::WA_StyledBackground);
2338 #if QT_CONFIG(dialogbuttonbox)
2339         QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
2340         if (buttonBox)
2341             buttonBox->setContentsMargins(0, 9, 0, 0);
2342 #endif
2343     }
2344 #if QT_CONFIG(inputdialog)
2345     else if (qobject_cast<QInputDialog *> (widget)) {
2346         widget->setAttribute(Qt::WA_StyledBackground);
2347 #if QT_CONFIG(dialogbuttonbox)
2348         QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
2349         if (buttonBox)
2350             buttonBox->setContentsMargins(0, 9, 0, 0);
2351 #endif
2352     }
2353 #endif // QT_CONFIG(inputdialog)
2354     else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
2355         tree->viewport()->setAttribute(Qt::WA_Hover);
2356     }
2357     else if (QListView *list = qobject_cast<QListView *> (widget)) {
2358         list->viewport()->setAttribute(Qt::WA_Hover);
2359     }
2360 }
2361 
2362 /*!
2363  \internal
2364  */
unpolish(QWidget * widget)2365 void QWindowsVistaStyle::unpolish(QWidget *widget)
2366 {
2367     QWindowsXPStyle::unpolish(widget);
2368 
2369     QWindowsVistaStylePrivate *d = d_func();
2370 
2371     d->stopAnimation(widget);
2372 
2373 #if QT_CONFIG(lineedit)
2374     if (qobject_cast<QLineEdit*>(widget))
2375         widget->setAttribute(Qt::WA_Hover, false);
2376     else
2377 #endif // QT_CONFIG(lineedit)
2378     if (qobject_cast<QGroupBox*>(widget))
2379         widget->setAttribute(Qt::WA_Hover, false);
2380     else if (qobject_cast<QMessageBox *> (widget)) {
2381         widget->setAttribute(Qt::WA_StyledBackground, false);
2382 #if QT_CONFIG(dialogbuttonbox)
2383         QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
2384         if (buttonBox)
2385             buttonBox->setContentsMargins(0, 0, 0, 0);
2386 #endif
2387     }
2388 #if QT_CONFIG(inputdialog)
2389     else if (qobject_cast<QInputDialog *> (widget)) {
2390         widget->setAttribute(Qt::WA_StyledBackground, false);
2391 #if QT_CONFIG(dialogbuttonbox)
2392         QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
2393         if (buttonBox)
2394             buttonBox->setContentsMargins(0, 0, 0, 0);
2395 #endif
2396     }
2397 #endif // QT_CONFIG(inputdialog)
2398     else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
2399         tree->viewport()->setAttribute(Qt::WA_Hover, false);
2400     }
2401 #if QT_CONFIG(commandlinkbutton)
2402     else if (qobject_cast<QCommandLinkButton*>(widget)) {
2403         QFont font = QApplication::font("QCommandLinkButton");
2404         QFont widgetFont = widget->font();
2405         widgetFont.setFamily(font.family()); //Only family set by polish
2406         widget->setFont(widgetFont);
2407     }
2408 #endif // QT_CONFIG(commandlinkbutton)
2409 }
2410 
2411 
2412 /*!
2413  \internal
2414  */
unpolish(QApplication * app)2415 void QWindowsVistaStyle::unpolish(QApplication *app)
2416 {
2417     QWindowsXPStyle::unpolish(app);
2418 }
2419 
2420 /*!
2421  \internal
2422  */
polish(QPalette & pal)2423 void QWindowsVistaStyle::polish(QPalette &pal)
2424 {
2425     QWindowsStyle::polish(pal);
2426     pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(104));
2427 }
2428 
2429 /*!
2430  \internal
2431  */
standardPixmap(StandardPixmap standardPixmap,const QStyleOption * option,const QWidget * widget) const2432 QPixmap QWindowsVistaStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option,
2433                                       const QWidget *widget) const
2434 {
2435     if (!QWindowsVistaStylePrivate::useVista()) {
2436         return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
2437     }
2438     return QWindowsXPStyle::standardPixmap(standardPixmap, option, widget);
2439 }
2440 
QWindowsVistaStylePrivate()2441 QWindowsVistaStylePrivate::QWindowsVistaStylePrivate() :
2442     QWindowsXPStylePrivate()
2443 {
2444 }
2445 
transitionsEnabled() const2446 bool QWindowsVistaStylePrivate::transitionsEnabled() const
2447 {
2448     BOOL animEnabled = false;
2449     if (SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0))
2450     {
2451         if (animEnabled)
2452             return true;
2453     }
2454     return false;
2455 }
2456 
2457 /*!
2458 \reimp
2459 */
standardIcon(StandardPixmap standardIcon,const QStyleOption * option,const QWidget * widget) const2460 QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon,
2461                                        const QStyleOption *option,
2462                                        const QWidget *widget) const
2463 {
2464     if (!QWindowsVistaStylePrivate::useVista()) {
2465         return QWindowsStyle::standardIcon(standardIcon, option, widget);
2466     }
2467 
2468     QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate *>(d_func());
2469     switch(standardIcon) {
2470     case SP_CommandLink:
2471         {
2472             XPThemeData theme(nullptr, nullptr,
2473                               QWindowsXPStylePrivate::ButtonTheme,
2474                               BP_COMMANDLINKGLYPH, CMDLGS_NORMAL);
2475             if (theme.isValid()) {
2476                 const QSize size = theme.size().toSize();
2477                 QIcon linkGlyph;
2478                 QPixmap pm(size);
2479                 pm.fill(Qt::transparent);
2480                 QPainter p(&pm);
2481                 theme.painter = &p;
2482                 theme.rect = QRect(QPoint(0, 0), size);
2483                 d->drawBackground(theme);
2484                 linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::Off);    // Normal
2485                 pm.fill(Qt::transparent);
2486 
2487                 theme.stateId = CMDLGS_PRESSED;
2488                 d->drawBackground(theme);
2489                 linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::On);     // Pressed
2490                 pm.fill(Qt::transparent);
2491 
2492                 theme.stateId = CMDLGS_HOT;
2493                 d->drawBackground(theme);
2494                 linkGlyph.addPixmap(pm, QIcon::Active, QIcon::Off);    // Hover
2495                 pm.fill(Qt::transparent);
2496 
2497                 theme.stateId = CMDLGS_DISABLED;
2498                 d->drawBackground(theme);
2499                 linkGlyph.addPixmap(pm, QIcon::Disabled, QIcon::Off);  // Disabled
2500                 return linkGlyph;
2501             }
2502         }
2503         break;
2504     default:
2505         break;
2506     }
2507     return QWindowsXPStyle::standardIcon(standardIcon, option, widget);
2508 }
2509 
2510 QT_END_NAMESPACE
2511