source: trunk/src/gui/styles/qwindowsvistastyle.cpp@ 100

Last change on this file since 100 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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