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, ©Opt, 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