source: trunk/src/gui/styles/qwindowsxpstyle.cpp@ 371

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

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

File size: 171.4 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#include "qwindowsxpstyle.h"
42#include "qwindowsxpstyle_p.h"
43
44#if !defined(QT_NO_STYLE_WINDOWSXP) || defined(QT_PLUGIN)
45
46#include <private/qobject_p.h>
47#include <private/qpaintengine_raster_p.h>
48#include <private/qapplication_p.h>
49#include <qlibrary.h>
50#include <qpainter.h>
51#include <qpaintengine.h>
52#include <qwidget.h>
53#include <qapplication.h>
54#include <qpixmapcache.h>
55
56#include <qdesktopwidget.h>
57#include <qtoolbutton.h>
58#include <qtabbar.h>
59#include <qcombobox.h>
60#include <qscrollbar.h>
61#include <qheaderview.h>
62#include <qspinbox.h>
63#include <qlistview.h>
64#include <qstackedwidget.h>
65#include <qpushbutton.h>
66#include <qtoolbar.h>
67#include <qlabel.h>
68#include <qvarlengtharray.h>
69#include <qdebug.h>
70
71QT_BEGIN_NAMESPACE
72
73// Runtime resolved theme engine function calls
74typedef bool (WINAPI *PtrIsAppThemed)();
75typedef bool (WINAPI *PtrIsThemeActive)();
76typedef HRESULT (WINAPI *PtrGetThemePartSize)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, OPTIONAL RECT *prc, enum THEMESIZE eSize, OUT SIZE *psz);
77typedef HTHEME (WINAPI *PtrOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
78typedef HRESULT (WINAPI *PtrCloseThemeData)(HTHEME hTheme);
79typedef HRESULT (WINAPI *PtrDrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
80typedef HRESULT (WINAPI *PtrDrawThemeBackgroundEx)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const DTBGOPTS *pOptions);
81typedef HRESULT (WINAPI *PtrGetCurrentThemeName)(OUT LPWSTR pszThemeFileName, int cchMaxNameChars, OUT OPTIONAL LPWSTR pszColorBuff, int cchMaxColorChars, OUT OPTIONAL LPWSTR pszSizeBuff, int cchMaxSizeChars);
82typedef HRESULT (WINAPI *PtrGetThemeDocumentationProperty)(LPCWSTR pszThemeName, LPCWSTR pszPropertyName, OUT LPWSTR pszValueBuff, int cchMaxValChars);
83typedef HRESULT (WINAPI *PtrGetThemeBool)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT BOOL *pfVal);
84typedef HRESULT (WINAPI *PtrGetThemeColor)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT COLORREF *pColor);
85typedef HRESULT (WINAPI *PtrGetThemeEnumValue)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT int *piVal);
86typedef HRESULT (WINAPI *PtrGetThemeFilename)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT LPWSTR pszThemeFileName, int cchMaxBuffChars);
87typedef HRESULT (WINAPI *PtrGetThemeFont)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, OUT LOGFONT *pFont);
88typedef HRESULT (WINAPI *PtrGetThemeInt)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT int *piVal);
89typedef HRESULT (WINAPI *PtrGetThemeIntList)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT INTLIST *pIntList);
90typedef HRESULT (WINAPI *PtrGetThemeMargins)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, OPTIONAL RECT *prc, OUT MARGINS *pMargins);
91typedef HRESULT (WINAPI *PtrGetThemeMetric)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, OUT int *piVal);
92typedef HRESULT (WINAPI *PtrGetThemePartSize)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, OPTIONAL RECT *prc, enum THEMESIZE eSize, OUT SIZE *psz);
93typedef HRESULT (WINAPI *PtrGetThemePosition)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT POINT *pPoint);
94typedef HRESULT (WINAPI *PtrGetThemePropertyOrigin)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT enum PROPERTYORIGIN *pOrigin);
95typedef HRESULT (WINAPI *PtrGetThemeRect)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT RECT *pRect);
96typedef HRESULT (WINAPI *PtrGetThemeString)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, OUT LPWSTR pszBuff, int cchMaxBuffChars);
97typedef HRESULT (WINAPI *PtrGetThemeBackgroundRegion)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pRect, OUT HRGN *pRegion);
98typedef BOOL (WINAPI *PtrIsThemeBackgroundPartiallyTransparent)(HTHEME hTheme, int iPartId, int iStateId);
99
100static PtrIsAppThemed pIsAppThemed = 0;
101static PtrIsThemeActive pIsThemeActive = 0;
102static PtrOpenThemeData pOpenThemeData = 0;
103static PtrCloseThemeData pCloseThemeData = 0;
104static PtrDrawThemeBackground pDrawThemeBackground = 0;
105static PtrDrawThemeBackgroundEx pDrawThemeBackgroundEx = 0;
106static PtrGetCurrentThemeName pGetCurrentThemeName = 0;
107static PtrGetThemeBool pGetThemeBool = 0;
108static PtrGetThemeColor pGetThemeColor = 0;
109static PtrGetThemeEnumValue pGetThemeEnumValue = 0;
110static PtrGetThemeFilename pGetThemeFilename = 0;
111static PtrGetThemeFont pGetThemeFont = 0;
112static PtrGetThemeInt pGetThemeInt = 0;
113static PtrGetThemeIntList pGetThemeIntList = 0;
114static PtrGetThemeMargins pGetThemeMargins = 0;
115static PtrGetThemeMetric pGetThemeMetric = 0;
116static PtrGetThemePartSize pGetThemePartSize = 0;
117static PtrGetThemePosition pGetThemePosition = 0;
118static PtrGetThemePropertyOrigin pGetThemePropertyOrigin = 0;
119static PtrGetThemeRect pGetThemeRect = 0;
120static PtrGetThemeString pGetThemeString = 0;
121static PtrGetThemeBackgroundRegion pGetThemeBackgroundRegion = 0;
122static PtrGetThemeDocumentationProperty pGetThemeDocumentationProperty = 0;
123static PtrIsThemeBackgroundPartiallyTransparent pIsThemeBackgroundPartiallyTransparent = 0;
124
125// General const values
126static const int windowsItemFrame = 2; // menu item frame width
127static const int windowsSepHeight = 9; // separator item height
128static const int windowsItemHMargin = 3; // menu item hor text margin
129static const int windowsItemVMargin = 0; // menu item ver text margin
130static const int windowsArrowHMargin = 6; // arrow horizontal margin
131static const int windowsCheckMarkHMargin = 0; // horiz. margins of check mark
132static const int windowsRightBorder = 12; // right border on windows
133
134// External function calls
135extern Q_GUI_EXPORT HDC qt_win_display_dc();
136
137
138
139// Theme data helper ------------------------------------------------------------------------------
140/* \internal
141 Returns true if the themedata is valid for use.
142*/
143bool XPThemeData::isValid()
144{
145 return QWindowsXPStylePrivate::useXP() && name.size() && handle();
146}
147
148
149/* \internal
150 Returns the theme engine handle to the specific class.
151 If the handle hasn't been opened before, it opens the data, and
152 adds it to a static map, for caching.
153*/
154HTHEME XPThemeData::handle()
155{
156 if (!QWindowsXPStylePrivate::useXP())
157 return 0;
158
159 if (!htheme && QWindowsXPStylePrivate::handleMap)
160 htheme = QWindowsXPStylePrivate::handleMap->operator[](name);
161
162 if (!htheme) {
163 htheme = pOpenThemeData(QWindowsXPStylePrivate::winId(widget),
164 (TCHAR*)name.utf16());
165 if (htheme) {
166 if (!QWindowsXPStylePrivate::handleMap)
167 QWindowsXPStylePrivate::handleMap = new QMap<QString, HTHEME>;
168 QWindowsXPStylePrivate::handleMap->operator[](name) = htheme;
169 }
170 }
171
172 return htheme;
173}
174
175/* \internal
176 Converts a QRect to the native RECT structure.
177*/
178RECT XPThemeData::toRECT(const QRect &qr)
179{
180 RECT r;
181 r.left = qr.x();
182 r.right = qr.x() + qr.width();
183 r.top = qr.y();
184 r.bottom = qr.y() + qr.height();
185 return r;
186}
187
188/* \internal
189 Returns the native region of a part, if the part is considered
190 transparent. The region is scaled to the parts size (rect).
191*/
192HRGN XPThemeData::mask()
193{
194 if (!pIsThemeBackgroundPartiallyTransparent(handle(), partId, stateId))
195 return 0;
196
197 HRGN hrgn;
198 HDC dc = painter == 0 ? 0 : painter->paintEngine()->getDC();
199 RECT nativeRect = toRECT(rect);
200 pGetThemeBackgroundRegion(handle(), dc, partId, stateId, &nativeRect, &hrgn);
201 if (dc)
202 painter->paintEngine()->releaseDC(dc);
203 return hrgn;
204}
205
206// QWindowsXPStylePrivate -------------------------------------------------------------------------
207// Static initializations
208QWidget *QWindowsXPStylePrivate::limboWidget = 0;
209QPixmap *QWindowsXPStylePrivate::tabbody = 0;
210QMap<QString,HTHEME> *QWindowsXPStylePrivate::handleMap = 0;
211bool QWindowsXPStylePrivate::use_xp = false;
212QBasicAtomicInt QWindowsXPStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting
213
214/* \internal
215 Checks if the theme engine can/should be used, or if we should
216 fall back to Windows style.
217*/
218bool QWindowsXPStylePrivate::useXP(bool update)
219{
220 if (!update)
221 return use_xp;
222 return (use_xp = resolveSymbols() && pIsThemeActive()
223 && (pIsAppThemed() || !QApplication::instance()));
224}
225
226/* \internal
227 Handles refcounting, and queries the theme engine for usage.
228*/
229void QWindowsXPStylePrivate::init(bool force)
230{
231 if (ref.ref() && !force)
232 return;
233 if (!force) // -1 based atomic refcounting
234 ref.ref();
235
236 useXP(true);
237}
238
239/* \internal
240 Cleans up all static data.
241*/
242void QWindowsXPStylePrivate::cleanup(bool force)
243{
244 if(bufferBitmap) {
245 if (bufferDC && nullBitmap)
246 SelectObject(bufferDC, nullBitmap);
247 DeleteObject(bufferBitmap);
248 bufferBitmap = 0;
249 }
250
251 if(bufferDC)
252 DeleteDC(bufferDC);
253 bufferDC = 0;
254
255 if (ref.deref() && !force)
256 return;
257 if (!force) // -1 based atomic refcounting
258 ref.deref();
259
260 use_xp = false;
261 cleanupHandleMap();
262 if (limboWidget) {
263 if (qApp->closingDown())
264 delete limboWidget;
265 else
266 limboWidget->deleteLater();
267 }
268 delete tabbody;
269 limboWidget = 0;
270 tabbody = 0;
271}
272
273/* \internal
274 Closes all open theme data handles to ensure that we don't leak
275 resources, and that we don't refere to old handles when for
276 example the user changes the theme style.
277*/
278void QWindowsXPStylePrivate::cleanupHandleMap()
279{
280 if (!handleMap)
281 return;
282
283 QMap<QString, HTHEME>::Iterator it;
284 for (it = handleMap->begin(); it != handleMap->end(); ++it)
285 pCloseThemeData(it.value());
286 delete handleMap;
287 handleMap = 0;
288}
289
290/*! \internal
291 This function will always return a valid window handle, and might
292 create a limbo widget to do so.
293 We often need a window handle to for example open theme data, so
294 this function ensures that we get one.
295*/
296HWND QWindowsXPStylePrivate::winId(const QWidget *widget)
297{
298 if (widget && widget->internalWinId())
299 return widget->internalWinId();
300
301 if (!limboWidget) {
302 limboWidget = new QWidget(0);
303 limboWidget->setObjectName(QLatin1String("xp_limbo_widget"));
304 }
305
306 return limboWidget->winId();
307}
308
309/*! \internal
310 Returns the pointer to a tab widgets body pixmap, scaled to the
311 height of the screen. This way the theme engine doesn't need to
312 scale the body for every time we ask for it. (Speed optimization)
313*/
314const QPixmap *QWindowsXPStylePrivate::tabBody(QWidget *)
315{
316 if (!tabbody) {
317 SIZE sz;
318 XPThemeData theme(0, 0, QLatin1String("TAB"), TABP_BODY);
319 pGetThemePartSize(theme.handle(), qt_win_display_dc(), TABP_BODY, 0, 0, TS_TRUE, &sz);
320
321 tabbody = new QPixmap(sz.cx, QApplication::desktop()->screenGeometry().height());
322 QPainter painter(tabbody);
323 theme.rect = QRect(0, 0, sz.cx, sz.cy);
324 drawBackground(theme);
325 // We fill with the last line of the themedata, that
326 // way we don't get a tiled pixmap inside big tabs
327 QPixmap temp(sz.cx, 1);
328 painter.drawPixmap(0, 0, temp, 0, sz.cy-1, -1, -1);
329 painter.drawTiledPixmap(0, sz.cy, sz.cx, tabbody->height()-sz.cy, temp);
330 }
331 return tabbody;
332}
333
334/*! \internal
335 Returns true if all the necessary theme engine symbols were
336 resolved.
337*/
338bool QWindowsXPStylePrivate::resolveSymbols()
339{
340 static bool tried = false;
341 if (!tried) {
342 tried = true;
343 QLibrary themeLib(QLatin1String("uxtheme"));
344 pIsAppThemed = (PtrIsAppThemed)themeLib.resolve("IsAppThemed");
345 if (pIsAppThemed) {
346 pIsThemeActive = (PtrIsThemeActive )themeLib.resolve("IsThemeActive");
347 pGetThemePartSize = (PtrGetThemePartSize )themeLib.resolve("GetThemePartSize");
348 pOpenThemeData = (PtrOpenThemeData )themeLib.resolve("OpenThemeData");
349 pCloseThemeData = (PtrCloseThemeData )themeLib.resolve("CloseThemeData");
350 pDrawThemeBackground = (PtrDrawThemeBackground )themeLib.resolve("DrawThemeBackground");
351 pDrawThemeBackgroundEx = (PtrDrawThemeBackgroundEx )themeLib.resolve("DrawThemeBackgroundEx");
352 pGetCurrentThemeName = (PtrGetCurrentThemeName )themeLib.resolve("GetCurrentThemeName");
353 pGetThemeBool = (PtrGetThemeBool )themeLib.resolve("GetThemeBool");
354 pGetThemeColor = (PtrGetThemeColor )themeLib.resolve("GetThemeColor");
355 pGetThemeEnumValue = (PtrGetThemeEnumValue )themeLib.resolve("GetThemeEnumValue");
356 pGetThemeFilename = (PtrGetThemeFilename )themeLib.resolve("GetThemeFilename");
357 pGetThemeFont = (PtrGetThemeFont )themeLib.resolve("GetThemeFont");
358 pGetThemeInt = (PtrGetThemeInt )themeLib.resolve("GetThemeInt");
359 pGetThemeIntList = (PtrGetThemeIntList )themeLib.resolve("GetThemeIntList");
360 pGetThemeMargins = (PtrGetThemeMargins )themeLib.resolve("GetThemeMargins");
361 pGetThemeMetric = (PtrGetThemeMetric )themeLib.resolve("GetThemeMetric");
362 pGetThemePartSize = (PtrGetThemePartSize )themeLib.resolve("GetThemePartSize");
363 pGetThemePosition = (PtrGetThemePosition )themeLib.resolve("GetThemePosition");
364 pGetThemePropertyOrigin = (PtrGetThemePropertyOrigin)themeLib.resolve("GetThemePropertyOrigin");
365 pGetThemeRect = (PtrGetThemeRect )themeLib.resolve("GetThemeRect");
366 pGetThemeString = (PtrGetThemeString )themeLib.resolve("GetThemeString");
367 pGetThemeBackgroundRegion = (PtrGetThemeBackgroundRegion )themeLib.resolve("GetThemeBackgroundRegion");
368 pGetThemeDocumentationProperty = (PtrGetThemeDocumentationProperty )themeLib.resolve("GetThemeDocumentationProperty");
369 pIsThemeBackgroundPartiallyTransparent = (PtrIsThemeBackgroundPartiallyTransparent)themeLib.resolve("IsThemeBackgroundPartiallyTransparent");
370 }
371 }
372
373 return pIsAppThemed != 0;
374}
375
376/*! \internal
377 Returns a native buffer (DIB section) of at least the size of
378 ( \a x , \a y ). The buffer has a 32 bit depth, to not lose
379 the alpha values on proper alpha-pixmaps.
380*/
381HBITMAP QWindowsXPStylePrivate::buffer(int w, int h)
382{
383 // If we already have a HBITMAP which is of adequate size, just return that
384 if (bufferBitmap) {
385 if (bufferW >= w && bufferH >= h)
386 return bufferBitmap;
387 // Not big enough, discard the old one
388 if (bufferDC && nullBitmap)
389 SelectObject(bufferDC, nullBitmap);
390 DeleteObject(bufferBitmap);
391 bufferBitmap = 0;
392 }
393
394 w = qMax(bufferW, w);
395 h = qMax(bufferH, h);
396
397 if (!bufferDC)
398 bufferDC = CreateCompatibleDC(qt_win_display_dc());
399
400 // Define the header
401 BITMAPINFO bmi;
402 memset(&bmi, 0, sizeof(bmi));
403 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
404 bmi.bmiHeader.biWidth = w;
405 bmi.bmiHeader.biHeight = -h;
406 bmi.bmiHeader.biPlanes = 1;
407 bmi.bmiHeader.biBitCount = 32;
408 bmi.bmiHeader.biCompression = BI_RGB;
409
410 // Create the pixmap
411 bufferPixels = 0;
412 bufferBitmap = CreateDIBSection(bufferDC, &bmi, DIB_RGB_COLORS, (void **) &bufferPixels, 0, 0);
413 GdiFlush();
414 nullBitmap = (HBITMAP)SelectObject(bufferDC, bufferBitmap);
415
416 if (!bufferBitmap) {
417 qErrnoWarning("QWindowsXPStylePrivate::buffer(w,h), failed to create dibsection");
418 bufferW = 0;
419 bufferH = 0;
420 return 0;
421 }
422 if (!bufferPixels) {
423 qErrnoWarning("QWindowsXPStylePrivate::buffer(w,h), did not allocate pixel data");
424 bufferW = 0;
425 bufferH = 0;
426 return 0;
427 }
428 bufferW = w;
429 bufferH = h;
430#ifdef DEBUG_XP_STYLE
431 qDebug("Creating new dib section (%d, %d)", w, h);
432#endif
433 return bufferBitmap;
434}
435
436/*! \internal
437 Returns true if the part contains any transparency at all. This does
438 not indicate what kind of transparency we're dealing with. It can be
439 - Alpha transparency
440 - Masked transparency
441*/
442bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData)
443{
444 return pIsThemeBackgroundPartiallyTransparent(themeData.handle(), themeData.partId,
445 themeData.stateId);
446}
447
448/*! \internal
449 Returns a QRegion of the region of the part
450*/
451QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
452{
453 HRGN hRgn = 0;
454 RECT rect = themeData.toRECT(themeData.rect);
455 if (!SUCCEEDED(pGetThemeBackgroundRegion(themeData.handle(), bufferHDC(), themeData.partId,
456 themeData.stateId, &rect, &hRgn)))
457 return QRegion();
458
459 QRegion rgn = QRegion(0,0,1,1);
460 const bool success = CombineRgn(rgn.handle(), hRgn, 0, RGN_COPY) != ERROR;
461 DeleteObject(hRgn);
462 if (success)
463 return rgn;
464 return QRegion();
465}
466
467/*! \internal
468 Sets the parts region on a window.
469*/
470void QWindowsXPStylePrivate::setTransparency(QWidget *widget, XPThemeData &themeData)
471{
472 HRGN hrgn = themeData.mask();
473 if (hrgn && widget)
474 SetWindowRgn(winId(widget), hrgn, true);
475}
476
477/*! \internal
478 Returns true if the native doublebuffer contains a pixel which
479 has a non-0xFF alpha value. Should only be use when its
480 guaranteed that data painted into the buffer wasn't a proper
481 alpha pixmap.
482*/
483bool QWindowsXPStylePrivate::hasAnyData(const QRect &rect)
484{
485 const int startX = rect.left();
486 const int startY = rect.top();
487 const int w = rect.width();
488 const int h = rect.height();
489
490 for (int y = startY; y < h; ++y) {
491 register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW);
492 for (int x = startX; x < w; ++x, ++buffer) {
493 int alpha = (*buffer) >> 24;
494 if (alpha != 0xFF) // buffer has been touched
495 return true;
496 }
497 }
498 return false;
499}
500
501/*! \internal
502 Returns true if the native doublebuffer contains pixels with
503 varying alpha value.
504*/
505bool QWindowsXPStylePrivate::hasAlphaChannel(const QRect &rect)
506{
507 const int startX = rect.left();
508 const int startY = rect.top();
509 const int w = rect.width();
510 const int h = rect.height();
511
512 int firstAlpha = -1;
513 for (int y = startY; y < h/2; ++y) {
514 register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW);
515 for (int x = startX; x < w; ++x, ++buffer) {
516 int alpha = (*buffer) >> 24;
517 if (firstAlpha == -1)
518 firstAlpha = alpha;
519 else if (alpha != firstAlpha)
520 return true;
521 }
522 }
523 return false;
524}
525
526/*! \internal
527 When the theme engine paints both a true alpha pixmap and a glyph
528 into our buffer, the glyph might not contain a proper alpha value.
529 The rule of thumb for premultiplied pixmaps is that the color
530 values of a pixel can never be higher than the alpha values, so
531 we use this to our advantage here, and fix all instances where
532 this occures.
533*/
534bool QWindowsXPStylePrivate::fixAlphaChannel(const QRect &rect)
535{
536 const int startX = rect.left();
537 const int startY = rect.top();
538 const int w = rect.width();
539 const int h = rect.height();
540 bool hasFixedAlphaValue = false;
541
542 for (int y = startY; y < h; ++y) {
543 register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW);
544 for (register int x = startX; x < w; ++x, ++buffer) {
545 uint pixel = *buffer;
546 int alpha = qAlpha(pixel);
547 if (qRed(pixel) > alpha || qGreen(pixel) > alpha || qBlue(pixel) > alpha) {
548 *buffer |= 0xff000000;
549 hasFixedAlphaValue = true;
550 }
551 }
552 }
553 return hasFixedAlphaValue;
554}
555
556/*! \internal
557 Swaps the alpha values on certain pixels:
558 0xFF?????? -> 0x00??????
559 0x00?????? -> 0xFF??????
560 Used to determin the mask of a non-alpha transparent pixmap in
561 the native doublebuffer, and swap the alphas so we may paint
562 the image as a Premultiplied QImage with drawImage(), and obtain
563 the mask transparency.
564*/
565bool QWindowsXPStylePrivate::swapAlphaChannel(const QRect &rect, bool allPixels)
566{
567 const int startX = rect.left();
568 const int startY = rect.top();
569 const int w = rect.width();
570 const int h = rect.height();
571 bool valueChange = false;
572
573 // Flip the alphas, so that 255-alpha pixels are 0, and 0-alpha are 255.
574 for (int y = startY; y < h; ++y) {
575 register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW);
576 for (register int x = startX; x < w; ++x, ++buffer) {
577 if (allPixels) {
578 *buffer |= 0xFF000000;
579 continue;
580 }
581 register unsigned int alphaValue = (*buffer) & 0xFF000000;
582 if (alphaValue == 0xFF000000) {
583 *buffer &= 0x00FFFFFF;
584 valueChange = true;
585 } else if (alphaValue == 0) {
586 *buffer |= 0xFF000000;
587 valueChange = true;
588 }
589 }
590 }
591 return valueChange;
592}
593
594/*! \internal
595 Main theme drawing function.
596 Determines the correct lowlevel drawing method depending on several
597 factors.
598 Use drawBackgroundThruNativeBuffer() if:
599 - Painter does not have an HDC
600 - Theme part is flipped (mirrored horizontally)
601 else use drawBackgroundDirectly().
602*/
603void QWindowsXPStylePrivate::drawBackground(XPThemeData &themeData)
604{
605 if (themeData.rect.isEmpty())
606 return;
607
608 QPainter *painter = themeData.painter;
609 Q_ASSERT_X(painter != 0, "QWindowsXPStylePrivate::drawBackground()", "Trying to draw a theme part without a painter");
610 if (!painter)
611 return;
612
613 painter->save();
614
615 QMatrix m = painter->matrix();
616 bool complexXForm = m.m11() != 1.0 || m.m22() != 1.0 || m.m12() != 0.0 || m.m21() != 0.0;
617
618 bool useFallback = painter->paintEngine()->getDC() == 0
619 || painter->opacity() != 1.0
620 || themeData.rotate
621 || complexXForm
622 || themeData.mirrorVertically
623 || (themeData.mirrorHorizontally && pDrawThemeBackgroundEx == 0);
624 if (!useFallback)
625 drawBackgroundDirectly(themeData);
626 else
627 drawBackgroundThruNativeBuffer(themeData);
628
629 painter->restore();
630}
631
632/*! \internal
633 This function draws the theme parts directly to the paintengines HDC.
634 Do not use this if you need to perform other transformations on the
635 resulting data.
636*/
637void QWindowsXPStylePrivate::drawBackgroundDirectly(XPThemeData &themeData)
638{
639 QPainter *painter = themeData.painter;
640 HDC dc = painter->paintEngine()->getDC();
641
642 QPoint redirectionDelta(int(painter->deviceMatrix().dx()),
643 int(painter->deviceMatrix().dy()));
644 QRect area = themeData.rect.translated(redirectionDelta);
645
646 QRegion sysRgn = painter->paintEngine()->systemClip();
647 if (sysRgn.isEmpty())
648 sysRgn = area;
649 else
650 sysRgn &= area;
651 if (painter->hasClipping())
652 sysRgn &= painter->clipRegion().translated(redirectionDelta);
653 SelectClipRgn(dc, sysRgn.handle());
654
655#ifdef DEBUG_XP_STYLE
656 printf("---[ DIRECT PAINTING ]------------------> Name(%-10s) Part(%d) State(%d)\n",
657 qPrintable(themeData.name), themeData.partId, themeData.stateId);
658 showProperties(themeData);
659#endif
660
661 RECT drawRECT = themeData.toRECT(area);
662 DTBGOPTS drawOptions;
663 drawOptions.dwSize = sizeof(drawOptions);
664 drawOptions.rcClip = themeData.toRECT(sysRgn.boundingRect());
665 drawOptions.dwFlags = DTBG_CLIPRECT
666 | (themeData.noBorder ? DTBG_OMITBORDER : 0)
667 | (themeData.noContent ? DTBG_OMITCONTENT : 0)
668 | (themeData.mirrorHorizontally ? DTBG_MIRRORDC : 0);
669
670 if (pDrawThemeBackgroundEx != 0) {
671 pDrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &drawOptions);
672 } else {
673 // We are running on a system where the uxtheme.dll does not have
674 // the DrawThemeBackgroundEx function, so we need to clip away
675 // borders or contents manually. All flips and mirrors uses the
676 // fallback implementation
677
678 int borderSize = 0;
679 PROPERTYORIGIN origin = PO_NOTFOUND;
680 pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin);
681 pGetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize);
682
683 // Clip away border region
684 QRegion extraClip = sysRgn;
685 if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) {
686 if (themeData.noBorder) {
687 // extraClip &= area is already done
688 drawRECT = themeData.toRECT(area.adjusted(-borderSize, -borderSize, borderSize, borderSize));
689 }
690
691 // Clip away content region
692 if (themeData.noContent) {
693 QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize);
694 extraClip ^= content;
695 }
696
697 // Set the clip region, if used..
698 if (themeData.noBorder || themeData.noContent)
699 SelectClipRgn(dc, extraClip.handle());
700 }
701
702 pDrawThemeBackground(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &(drawOptions.rcClip));
703 }
704 SelectClipRgn(dc, 0);
705}
706
707/*! \internal
708 This function uses a secondary Native doublebuffer for painting parts.
709 It should only be used when the painteengine doesn't provide a proper
710 HDC for direct painting (e.g. when doing a grabWidget(), painting to
711 other pixmaps etc), or when special transformations are needed (e.g.
712 flips (horizonal mirroring only, vertical are handled by the theme
713 engine).
714*/
715void QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeData)
716{
717 QPainter *painter = themeData.painter;
718 QRect rect = themeData.rect;
719
720 if ((themeData.rotate + 90) % 180 == 0) { // Catch 90,270,etc.. degree flips.
721 rect = QRect(0, 0, rect.height(), rect.width());
722 }
723 rect.moveTo(0,0);
724 int partId = themeData.partId;
725 int stateId = themeData.stateId;
726 int w = rect.width();
727 int h = rect.height();
728
729 // Values initialized later, either from cached values, or from function calls
730 AlphaChannelType alphaType = UnknownAlpha;
731 bool stateHasData = true; // We assume so;
732 bool hasAlpha = false;
733 bool partIsTransparent;
734 bool inspectData;
735 bool potentialInvalidAlpha;
736
737 QString pixmapCacheKey = QString::fromLatin1("$qt_xp_%1p%2s%3s%4b%5c%6w%7h").arg(themeData.name)
738 .arg(partId).arg(stateId).arg(!themeData.noBorder).arg(!themeData.noContent)
739 .arg(w).arg(h);
740 QPixmap cachedPixmap;
741 ThemeMapKey key(themeData);
742 ThemeMapData data = alphaCache.value(key);
743
744 bool haveCachedPixmap = false;
745 bool isCached = data.dataValid;
746 if (isCached) {
747 if (!(stateHasData = data.hasAnyData))
748 return; // Cached NOOP
749 inspectData = data.wasAlphaSwapped;
750 partIsTransparent = data.partIsTransparent;
751 hasAlpha = data.hasAlphaChannel;
752 alphaType = data.alphaType;
753 potentialInvalidAlpha = data.hadInvalidAlpha;
754
755 haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, cachedPixmap);
756
757#ifdef DEBUG_XP_STYLE
758 char buf[25];
759 ::sprintf(buf, "+ Pixmap(%3d, %3d) ]", w, h);
760 printf("---[ CACHED %s--------> Name(%-10s) Part(%d) State(%d)\n",
761 haveCachedPixmap ? buf : "]-------------------",
762 qPrintable(themeData.name), themeData.partId, themeData.stateId);
763#endif
764 } else {
765 // Not cached, so get values from Theme Engine
766 BOOL tmt_borderonly = false;
767 COLORREF tmt_transparentcolor = 0x0;
768 PROPERTYORIGIN proporigin = PO_NOTFOUND;
769 pGetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERONLY, &tmt_borderonly);
770 pGetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, TMT_TRANSPARENTCOLOR, &tmt_transparentcolor);
771 pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_CAPTIONMARGINS, &proporigin);
772 inspectData = (tmt_transparentcolor != 0 || tmt_borderonly || proporigin == PO_PART || proporigin == PO_STATE);
773
774 // ### This is a vista-specific workaround for broken alpha in titlebar pixmaps
775 if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) {
776 if (themeData.partId == WP_CAPTION || themeData.partId == WP_SMALLCAPTION)
777 inspectData = false;
778 }
779
780 partIsTransparent = isTransparent(themeData);
781
782 potentialInvalidAlpha = false;
783 pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &proporigin);
784 if (proporigin == PO_PART || proporigin == PO_STATE) {
785 int tmt_glyphtype = GT_NONE;
786 pGetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &tmt_glyphtype);
787 potentialInvalidAlpha = partIsTransparent && !inspectData && tmt_glyphtype == GT_IMAGEGLYPH;
788 }
789
790#ifdef DEBUG_XP_STYLE
791 printf("---[ NOT CACHED ]-----------------------> Name(%-10s) Part(%d) State(%d)\n",
792 qPrintable(themeData.name), themeData.partId, themeData.stateId);
793 printf("-->partIsTransparen = %d\n", partIsTransparent);
794 printf("-->inspectData = %d\n", inspectData);
795 printf("-->potentialInvalidAlpha = %d\n", potentialInvalidAlpha);
796 showProperties(themeData);
797#endif
798 }
799 bool wasAlphaSwapped = false;
800 bool wasAlphaFixed = false;
801
802 // OLD PSDK Workaround ------------------------------------------------------------------------
803 // See if we need extra clipping for the older PSDK, which does
804 // not have a DrawThemeBackgroundEx function for DTGB_OMITBORDER
805 // and DTGB_OMITCONTENT
806 bool addBorderContentClipping = false;
807 QRegion extraClip;
808 QRect area = rect;
809 if (themeData.noBorder || themeData.noContent) {
810 extraClip = area;
811 // We are running on a system where the uxtheme.dll does not have
812 // the DrawThemeBackgroundEx function, so we need to clip away
813 // borders or contents manually.
814
815 int borderSize = 0;
816 PROPERTYORIGIN origin = PO_NOTFOUND;
817 pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin);
818 pGetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize);
819
820 // Clip away border region
821 if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) {
822 if (themeData.noBorder) {
823 extraClip &= area;
824 area = area.adjusted(-borderSize, -borderSize, borderSize, borderSize);
825 }
826
827 // Clip away content region
828 if (themeData.noContent) {
829 QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize);
830 extraClip ^= content;
831 }
832 }
833 addBorderContentClipping = (themeData.noBorder | themeData.noContent);
834 }
835
836 QImage img;
837 if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! -------------------------
838 buffer(w, h); // Ensure a buffer of at least (w, h) in size
839 HDC dc = bufferHDC();
840
841 // Clear the buffer
842 if (alphaType != NoAlpha) {
843 // Consider have separate "memset" function for small chunks for more speedup
844 memset(bufferPixels, inspectData ? 0xFF : 0x00, bufferW * h * 4);
845 }
846
847 // Difference between area and rect
848 int dx = area.x() - rect.x();
849 int dy = area.y() - rect.y();
850 int dr = area.right() - rect.right();
851 int db = area.bottom() - rect.bottom();
852
853 // Adjust so painting rect starts from Origo
854 rect.moveTo(0,0);
855 area.moveTo(dx,dy);
856 DTBGOPTS drawOptions;
857 drawOptions.dwSize = sizeof(drawOptions);
858 drawOptions.rcClip = themeData.toRECT(rect);
859 drawOptions.dwFlags = DTBG_CLIPRECT
860 | (themeData.noBorder ? DTBG_OMITBORDER : 0)
861 | (themeData.noContent ? DTBG_OMITCONTENT : 0);
862
863 // Drawing the part into the backing store
864 if (pDrawThemeBackgroundEx != 0) {
865 RECT rect(themeData.toRECT(area));
866 pDrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &rect, &drawOptions);
867 } else {
868 // Set the clip region, if used..
869 if (addBorderContentClipping) {
870 SelectClipRgn(dc, extraClip.handle());
871 // Compensate for the noBorder area difference (noContent has the same area)
872 drawOptions.rcClip = themeData.toRECT(rect.adjusted(dx, dy, dr, db));
873 }
874
875 pDrawThemeBackground(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawOptions.rcClip), 0);
876
877 if (addBorderContentClipping)
878 SelectClipRgn(dc, 0);
879 }
880
881 // If not cached, analyze the buffer data to figure
882 // out alpha type, and if it contains data
883 if (!isCached) {
884 if (inspectData)
885 stateHasData = hasAnyData(rect);
886 // SHORTCUT: If the part's state has no data, cache it for NOOP later
887 if (!stateHasData) {
888 memset(&data, 0, sizeof(data));
889 data.dataValid = true;
890 alphaCache.insert(key, data);
891 return;
892 }
893 hasAlpha = hasAlphaChannel(rect);
894 if (!hasAlpha && partIsTransparent)
895 potentialInvalidAlpha = true;
896#if defined(DEBUG_XP_STYLE) && 1
897 dumpNativeDIB(w, h);
898#endif
899 }
900
901 // Swap alpha values, if needed
902 if (inspectData)
903 wasAlphaSwapped = swapAlphaChannel(rect);
904
905 // Fix alpha values, if needed
906 if (potentialInvalidAlpha)
907 wasAlphaFixed = fixAlphaChannel(rect);
908
909 QImage::Format format;
910 if ((partIsTransparent && !wasAlphaSwapped) || (!partIsTransparent && hasAlpha)) {
911 format = QImage::Format_ARGB32_Premultiplied;
912 alphaType = RealAlpha;
913 } else if (wasAlphaSwapped) {
914 format = QImage::Format_ARGB32_Premultiplied;
915 alphaType = MaskAlpha;
916 } else {
917 format = QImage::Format_RGB32;
918 // The image data we got from the theme engine does not have any transparency,
919 // thus the alpha channel is set to 0.
920 // However, Format_RGB32 requires the alpha part to be set to 0xff, thus
921 // we must flip it from 0x00 to 0xff
922 swapAlphaChannel(rect, true);
923 alphaType = NoAlpha;
924 }
925#if defined(DEBUG_XP_STYLE) && 1
926 printf("Image format is: %s\n", alphaType == RealAlpha ? "Real Alpha" : alphaType == MaskAlpha ? "Masked Alpha" : "No Alpha");
927#endif
928 img = QImage(bufferPixels, bufferW, bufferH, format);
929 }
930
931 // Blitting backing store
932 bool useRegion = partIsTransparent && !hasAlpha && !wasAlphaSwapped;
933
934 QRegion newRegion;
935 QRegion oldRegion;
936 if (useRegion) {
937 newRegion = region(themeData);
938 oldRegion = painter->clipRegion();
939 painter->setClipRegion(newRegion);
940#if defined(DEBUG_XP_STYLE) && 0
941 printf("Using region:\n");
942 QVector<QRect> rects = newRegion.rects();
943 for (int i = 0; i < rects.count(); ++i) {
944 const QRect &r = rects.at(i);
945 printf(" (%d, %d, %d, %d)\n", r.x(), r.y(), r.right(), r.bottom());
946 }
947#endif
948 }
949
950 if (addBorderContentClipping)
951 painter->setClipRegion(extraClip, Qt::IntersectClip);
952
953 if (!themeData.mirrorHorizontally && !themeData.mirrorVertically && !themeData.rotate) {
954 if (!haveCachedPixmap)
955 painter->drawImage(themeData.rect, img, rect);
956 else
957 painter->drawPixmap(themeData.rect, cachedPixmap);
958 } else {
959 // This is _slow_!
960 // Make a copy containing only the necessary data, and mirror
961 // on all wanted axes. Then draw the copy.
962 // If cached, the normal pixmap is cached, instead of caching
963 // all possible orientations for each part and state.
964 QImage imgCopy;
965 if (!haveCachedPixmap)
966 imgCopy = img.copy(rect);
967 else
968 imgCopy = cachedPixmap.toImage();
969
970 if (themeData.rotate) {
971 QMatrix rotMatrix;
972 rotMatrix.rotate(themeData.rotate);
973 imgCopy = imgCopy.transformed(rotMatrix);
974 }
975 if (themeData.mirrorHorizontally || themeData.mirrorVertically) {
976 imgCopy = imgCopy.mirrored(themeData.mirrorHorizontally, themeData.mirrorVertically);
977 }
978 painter->drawImage(themeData.rect,
979 imgCopy);
980 }
981
982 if (useRegion || addBorderContentClipping) {
983 if (oldRegion.isEmpty())
984 painter->setClipping(false);
985 else
986 painter->setClipRegion(oldRegion);
987 }
988
989 // Cache the pixmap to avoid expensive swapAlphaChannel() calls
990 if (!haveCachedPixmap && w && h) {
991 QPixmap pix = QPixmap::fromImage(img).copy(rect);
992 QPixmapCache::insert(pixmapCacheKey, pix);
993#ifdef DEBUG_XP_STYLE
994 printf("+++Adding pixmap to cache, size(%d, %d), wasAlphaSwapped(%d), wasAlphaFixed(%d), name(%s)\n",
995 w, h, wasAlphaSwapped, wasAlphaFixed, qPrintable(pixmapCacheKey));
996#endif
997 }
998
999 // Add to theme part cache
1000 if (!isCached) {
1001 memset(&data, 0, sizeof(data));
1002 data.dataValid = true;
1003 data.partIsTransparent = partIsTransparent;
1004 data.alphaType = alphaType;
1005 data.hasAlphaChannel = hasAlpha;
1006 data.hasAnyData = stateHasData;
1007 data.wasAlphaSwapped = wasAlphaSwapped;
1008 data.hadInvalidAlpha = wasAlphaFixed;
1009 alphaCache.insert(key, data);
1010 }
1011}
1012
1013
1014// ------------------------------------------------------------------------------------------------
1015
1016/*!
1017 \class QWindowsXPStyle
1018 \brief The QWindowsXPStyle class provides a Microsoft Windows XP-like look and feel.
1019
1020 \ingroup appearance
1021
1022 \warning This style is only available on the Windows XP platform
1023 because it makes use of Windows XP's style engine.
1024
1025 Most of the functions are documented in the base classes
1026 QWindowsStyle, QCommonStyle, and QStyle, but the
1027 QWindowsXPStyle overloads of drawComplexControl(), drawControl(),
1028 drawControlMask(), drawPrimitive(), subControlRect(), and
1029 sizeFromContents(), are documented here.
1030
1031 \img qwindowsxpstyle.png
1032 \sa QMacStyle, QWindowsStyle, QPlastiqueStyle, QCDEStyle, QMotifStyle
1033*/
1034
1035/*!
1036 Constructs a QWindowsStyle
1037*/
1038QWindowsXPStyle::QWindowsXPStyle()
1039 : QWindowsStyle(*new QWindowsXPStylePrivate)
1040{
1041}
1042
1043/*!
1044 Destroys the style.
1045*/
1046QWindowsXPStyle::~QWindowsXPStyle()
1047{
1048}
1049
1050/*! \reimp */
1051void QWindowsXPStyle::unpolish(QApplication *app)
1052{
1053 QWindowsStyle::unpolish(app);
1054}
1055
1056/*! \reimp */
1057void QWindowsXPStyle::polish(QApplication *app)
1058{
1059 QWindowsStyle::polish(app);
1060 if (!QWindowsXPStylePrivate::useXP())
1061 return;
1062}
1063
1064/*! \reimp */
1065void QWindowsXPStyle::polish(QWidget *widget)
1066{
1067 QWindowsStyle::polish(widget);
1068 if (!QWindowsXPStylePrivate::useXP())
1069 return;
1070
1071 if (qobject_cast<QAbstractButton*>(widget)
1072 || qobject_cast<QToolButton*>(widget)
1073 || qobject_cast<QTabBar*>(widget)
1074#ifndef QT_NO_COMBOBOX
1075 || qobject_cast<QComboBox*>(widget)
1076#endif // QT_NO_COMBOBOX
1077 || qobject_cast<QScrollBar*>(widget)
1078 || qobject_cast<QSlider*>(widget)
1079 || qobject_cast<QHeaderView*>(widget)
1080#ifndef QT_NO_SPINBOX
1081 || qobject_cast<QAbstractSpinBox*>(widget)
1082 || qobject_cast<QSpinBox*>(widget)
1083#endif // QT_NO_SPINBOX
1084 || widget->inherits("QWorkspaceChild")
1085 || widget->inherits("Q3TitleBar"))
1086 widget->setAttribute(Qt::WA_Hover);
1087
1088#ifndef QT_NO_RUBBERBAND
1089 if (qobject_cast<QRubberBand*>(widget)) {
1090 widget->setWindowOpacity(0.6);
1091 }
1092#endif
1093 if (qobject_cast<QStackedWidget*>(widget) &&
1094 qobject_cast<QTabWidget*>(widget->parent()))
1095 widget->parentWidget()->setAttribute(Qt::WA_ContentsPropagated);
1096
1097 Q_D(QWindowsXPStyle);
1098 if (!d->hasInitColors) {
1099 // Get text color for group box labels
1100 COLORREF cref;
1101 XPThemeData theme(0, 0, QLatin1String("BUTTON"), 0, 0);
1102 pGetThemeColor(theme.handle(), BP_GROUPBOX, GBS_NORMAL, TMT_TEXTCOLOR, &cref);
1103 d->groupBoxTextColor = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
1104 pGetThemeColor(theme.handle(), BP_GROUPBOX, GBS_DISABLED, TMT_TEXTCOLOR, &cref);
1105 d->groupBoxTextColorDisabled = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
1106 // Where does this color come from?
1107 //pGetThemeColor(theme.handle(), TKP_TICS, TSS_NORMAL, TMT_COLOR, &cref);
1108 d->sliderTickColor = qRgb(165, 162, 148);
1109 d->hasInitColors = true;
1110 }
1111}
1112
1113/*! \reimp */
1114void QWindowsXPStyle::polish(QPalette &pal)
1115{
1116 QWindowsStyle::polish(pal);
1117 pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(110));
1118}
1119
1120/*! \reimp */
1121void QWindowsXPStyle::unpolish(QWidget *widget)
1122{
1123#ifndef QT_NO_RUBBERBAND
1124 if (qobject_cast<QRubberBand*>(widget)) {
1125 widget->setWindowOpacity(1.0);
1126 }
1127#endif
1128 Q_D(QWindowsXPStyle);
1129 // Unpolish of widgets is the first thing that
1130 // happens when a theme changes, or the theme
1131 // engine is turned off. So we detect it here.
1132 bool oldState = QWindowsXPStylePrivate::useXP();
1133 bool newState = QWindowsXPStylePrivate::useXP(true);
1134 if ((oldState != newState) && newState) {
1135 d->cleanup(true);
1136 d->init(true);
1137 } else {
1138 // Cleanup handle map, if just changing style,
1139 // or turning it on. In both cases the values
1140 // already in the map might be old (other style).
1141 d->cleanupHandleMap();
1142 }
1143 if (qobject_cast<QAbstractButton*>(widget)
1144 || qobject_cast<QToolButton*>(widget)
1145 || qobject_cast<QTabBar*>(widget)
1146#ifndef QT_NO_COMBOBOX
1147 || qobject_cast<QComboBox*>(widget)
1148#endif // QT_NO_COMBOBOX
1149 || qobject_cast<QScrollBar*>(widget)
1150 || qobject_cast<QSlider*>(widget)
1151 || qobject_cast<QHeaderView*>(widget)
1152#ifndef QT_NO_SPINBOX
1153 || qobject_cast<QAbstractSpinBox*>(widget)
1154 || qobject_cast<QSpinBox*>(widget)
1155#endif // QT_NO_SPINBOX
1156 || widget->inherits("QWorkspaceChild")
1157 || widget->inherits("Q3TitleBar"))
1158 widget->setAttribute(Qt::WA_Hover, false);
1159 QWindowsStyle::unpolish(widget);
1160}
1161
1162/*! \reimp */
1163QRect QWindowsXPStyle::subElementRect(SubElement sr, const QStyleOption *option, const QWidget *widget) const
1164{
1165 if (!QWindowsXPStylePrivate::useXP()) {
1166 return QWindowsStyle::subElementRect(sr, option, widget);
1167 }
1168
1169 QRect rect(option->rect);
1170 switch(sr) {
1171 case SE_DockWidgetCloseButton:
1172 case SE_DockWidgetFloatButton:
1173 rect = QWindowsStyle::subElementRect(sr, option, widget);
1174 return rect.translated(0, 1);
1175 break;
1176 case SE_TabWidgetTabContents:
1177 if (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option))
1178 {
1179 rect = QWindowsStyle::subElementRect(sr, option, widget);
1180 if (sr == SE_TabWidgetTabContents)
1181 rect.adjust(0, 0, -2, -2);
1182 }
1183 break;
1184 case SE_TabWidgetTabBar: {
1185 rect = QWindowsStyle::subElementRect(sr, option, widget);
1186 const QStyleOptionTabWidgetFrame *twfOption =
1187 qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option);
1188 if (twfOption && twfOption->direction == Qt::RightToLeft
1189 && (twfOption->shape == QTabBar::RoundedNorth
1190 || twfOption->shape == QTabBar::RoundedSouth))
1191 {
1192 QStyleOptionTab otherOption;
1193 otherOption.shape = (twfOption->shape == QTabBar::RoundedNorth
1194 ? QTabBar::RoundedEast : QTabBar::RoundedSouth);
1195 int overlap = pixelMetric(PM_TabBarBaseOverlap, &otherOption, widget);
1196 int borderThickness = pixelMetric(PM_DefaultFrameWidth, option, widget);
1197 rect.adjust(-overlap + borderThickness, 0, -overlap + borderThickness, 0);
1198 }
1199 break;}
1200
1201 case SE_PushButtonContents:
1202 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
1203 MARGINS borderSize;
1204 if (widget) {
1205 HTHEME theme = pOpenThemeData(QWindowsXPStylePrivate::winId(widget), L"Button");
1206 if (theme) {
1207 int stateId;
1208 if (!(option->state & State_Enabled))
1209 stateId = PBS_DISABLED;
1210 else if (option->state & State_Sunken)
1211 stateId = PBS_PRESSED;
1212 else if (option->state & State_MouseOver)
1213 stateId = PBS_HOT;
1214 else if (btn->features & QStyleOptionButton::DefaultButton)
1215 stateId = PBS_DEFAULTED;
1216 else
1217 stateId = PBS_NORMAL;
1218
1219 int border = pixelMetric(PM_DefaultFrameWidth, btn, widget);
1220 rect = option->rect.adjusted(border, border, -border, -border);
1221
1222 int result = pGetThemeMargins(theme,
1223 NULL,
1224 BP_PUSHBUTTON,
1225 stateId,
1226 TMT_CONTENTMARGINS,
1227 NULL,
1228 &borderSize);
1229
1230 if (result == S_OK) {
1231 rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
1232 -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
1233 rect = visualRect(option->direction, option->rect, rect);
1234 }
1235 }
1236 }
1237 }
1238 break;
1239 case SE_ProgressBarContents:
1240 rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget);
1241 if (option->state & QStyle::State_Horizontal)
1242 rect.adjust(4, 3, -4, -3);
1243 else
1244 rect.adjust(3, 2, -3, -2);
1245 break;
1246 default:
1247 rect = QWindowsStyle::subElementRect(sr, option, widget);
1248 }
1249 return rect;
1250}
1251
1252/*!
1253 \reimp
1254*/
1255void QWindowsXPStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *option, QPainter *p,
1256 const QWidget *widget) const
1257{
1258 QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
1259
1260 if (!QWindowsXPStylePrivate::useXP()) {
1261 QWindowsStyle::drawPrimitive(pe, option, p, widget);
1262 return;
1263 }
1264
1265 QString name;
1266 int partId = 0;
1267 int stateId = 0;
1268 QRect rect = option->rect;
1269 State flags = option->state;
1270 bool hMirrored = false;
1271 bool vMirrored = false;
1272 bool noBorder = false;
1273 bool noContent = false;
1274 int rotate = 0;
1275
1276 switch (pe) {
1277 case PE_FrameTabBarBase:
1278 if (const QStyleOptionTabBarBase *tbb
1279 = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
1280 p->save();
1281 switch (tbb->shape) {
1282 case QTabBar::RoundedNorth:
1283 p->setPen(QPen(tbb->palette.dark(), 0));
1284 p->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
1285 break;
1286 case QTabBar::RoundedWest:
1287 p->setPen(QPen(tbb->palette.dark(), 0));
1288 p->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom());
1289 break;
1290 case QTabBar::RoundedSouth:
1291 p->setPen(QPen(tbb->palette.dark(), 0));
1292 p->drawLine(tbb->rect.left(), tbb->rect.top(),
1293 tbb->rect.right(), tbb->rect.top());
1294 break;
1295 case QTabBar::RoundedEast:
1296 p->setPen(QPen(tbb->palette.dark(), 0));
1297 p->drawLine(tbb->rect.topLeft(), tbb->rect.bottomLeft());
1298 break;
1299 case QTabBar::TriangularNorth:
1300 case QTabBar::TriangularEast:
1301 case QTabBar::TriangularWest:
1302 case QTabBar::TriangularSouth:
1303 p->restore();
1304 QWindowsStyle::drawPrimitive(pe, option, p, widget);
1305 return;
1306 }
1307 p->restore();
1308 }
1309 return;
1310 case PE_PanelButtonBevel:
1311 name = QLatin1String("BUTTON");
1312 partId = BP_PUSHBUTTON;
1313 if (!(flags & State_Enabled))
1314 stateId = PBS_DISABLED;
1315 else if ((flags & State_Sunken) || (flags & State_On))
1316 stateId = PBS_PRESSED;
1317 else if (flags & State_MouseOver)
1318 stateId = PBS_HOT;
1319 //else if (flags & State_ButtonDefault)
1320 // stateId = PBS_DEFAULTED;
1321 else
1322 stateId = PBS_NORMAL;
1323 break;
1324
1325 case PE_PanelButtonTool:
1326 if (widget && widget->inherits("QDockWidgetTitleButton")) {
1327 if (const QWidget *dw = widget->parentWidget())
1328 if (dw->isWindow())
1329 return;
1330 }
1331 name = QLatin1String("TOOLBAR");
1332 partId = TP_BUTTON;
1333 if (!(flags & State_Enabled))
1334 stateId = TS_DISABLED;
1335 else if (flags & State_Sunken)
1336 stateId = TS_PRESSED;
1337 else if (flags & State_MouseOver)
1338 stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
1339 else if (flags & State_On)
1340 stateId = TS_CHECKED;
1341 else if (!(flags & State_AutoRaise))
1342 stateId = TS_HOT;
1343 else
1344 stateId = TS_NORMAL;
1345 break;
1346
1347 case PE_IndicatorButtonDropDown:
1348 name = QLatin1String("TOOLBAR");
1349 partId = TP_SPLITBUTTONDROPDOWN;
1350 if (!(flags & State_Enabled))
1351 stateId = TS_DISABLED;
1352 else if (flags & State_Sunken)
1353 stateId = TS_PRESSED;
1354 else if (flags & State_MouseOver)
1355 stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
1356 else if (flags & State_On)
1357 stateId = TS_CHECKED;
1358 else if (!(flags & State_AutoRaise))
1359 stateId = TS_HOT;
1360 else
1361 stateId = TS_NORMAL;
1362 if (option->direction == Qt::RightToLeft)
1363 hMirrored = true;
1364 break;
1365
1366 case PE_IndicatorCheckBox:
1367 name = QLatin1String("BUTTON");
1368 partId = BP_CHECKBOX;
1369 if (!(flags & State_Enabled))
1370 stateId = CBS_UNCHECKEDDISABLED;
1371 else if (flags & State_Sunken)
1372 stateId = CBS_UNCHECKEDPRESSED;
1373 else if (flags & State_MouseOver)
1374 stateId = CBS_UNCHECKEDHOT;
1375 else
1376 stateId = CBS_UNCHECKEDNORMAL;
1377
1378 if (flags & State_On)
1379 stateId += CBS_CHECKEDNORMAL-1;
1380 else if (flags & State_NoChange)
1381 stateId += CBS_MIXEDNORMAL-1;
1382
1383 break;
1384
1385 case PE_IndicatorRadioButton:
1386 name = QLatin1String("BUTTON");
1387 partId = BP_RADIOBUTTON;
1388 if (!(flags & State_Enabled))
1389 stateId = RBS_UNCHECKEDDISABLED;
1390 else if (flags & State_Sunken)
1391 stateId = RBS_UNCHECKEDPRESSED;
1392 else if (flags & State_MouseOver)
1393 stateId = RBS_UNCHECKEDHOT;
1394 else
1395 stateId = RBS_UNCHECKEDNORMAL;
1396
1397 if (flags & State_On)
1398 stateId += RBS_CHECKEDNORMAL-1;
1399 break;
1400
1401 case PE_IndicatorDockWidgetResizeHandle:
1402 return;
1403
1404case PE_Frame:
1405 {
1406 if (flags & State_Raised)
1407 return;
1408 name = QLatin1String("LISTVIEW");
1409 partId = LVP_LISTGROUP;
1410 XPThemeData theme(0, 0, name, partId, 0);
1411
1412 if (!(flags & State_Enabled))
1413 stateId = ETS_DISABLED;
1414 else
1415 stateId = ETS_NORMAL;
1416 int fillType;
1417 if (pGetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &fillType) == S_OK) {
1418 if (fillType == BT_BORDERFILL) {
1419 COLORREF bcRef;
1420 pGetThemeColor(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &bcRef);
1421 QColor bordercolor(qRgb(GetRValue(bcRef), GetGValue(bcRef), GetBValue(bcRef)));
1422 QPen oldPen = p->pen();
1423 // int borderSize = 1;
1424 // pGetThemeInt(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &borderSize);
1425
1426 // Inner white border
1427 p->setPen(QPen(option->palette.base().color(), 1));
1428 p->drawRect(option->rect.adjusted(1, 1, -2, -2));
1429 // Outer dark border
1430 p->setPen(QPen(bordercolor, 1));
1431 p->drawRect(option->rect.adjusted(0, 0, -1, -1));
1432 p->setPen(oldPen);
1433 return;
1434 } else if (fillType == BT_NONE) {
1435 return;
1436 } else {
1437 break;
1438 }
1439 }
1440 }
1441 case PE_FrameLineEdit: {
1442 // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
1443 QWidget *parentWidget = 0;
1444 if (widget)
1445 parentWidget = widget->parentWidget();
1446 if (parentWidget)
1447 parentWidget = parentWidget->parentWidget();
1448 if (widget && widget->inherits("QLineEdit")
1449 && parentWidget && parentWidget->inherits("QAbstractItemView")) {
1450 QPen oldPen = p->pen();
1451 // Inner white border
1452 p->setPen(QPen(option->palette.base().color(), 1));
1453 p->drawRect(option->rect.adjusted(1, 1, -2, -2));
1454 // Outer dark border
1455 p->setPen(QPen(option->palette.shadow().color(), 1));
1456 p->drawRect(option->rect.adjusted(0, 0, -1, -1));
1457 p->setPen(oldPen);
1458 return;
1459 } else if (qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1460 name = QLatin1String("EDIT");
1461 partId = EP_EDITTEXT;
1462 noContent = true;
1463 if (!(flags & State_Enabled))
1464 stateId = ETS_DISABLED;
1465 else
1466 stateId = ETS_NORMAL;
1467 }
1468 break;
1469 }
1470
1471 case PE_PanelLineEdit:
1472 if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1473 name = QLatin1String("EDIT");
1474 partId = EP_EDITTEXT;
1475 noBorder = true;
1476 QBrush bg;
1477 bool usePalette = false;
1478 bool isEnabled = flags & State_Enabled;
1479 uint resolve_mask = panel->palette.resolve();
1480
1481#ifndef QT_NO_SPINBOX
1482 //Since spin box includes a line edit we need to resolve the palette on the spin box instead
1483 if (widget) {
1484 if (QAbstractSpinBox *spinbox = qobject_cast<QAbstractSpinBox*>(widget->parentWidget()))
1485 resolve_mask = spinbox->palette().resolve();
1486 }
1487#endif // QT_NO_SPINBOX
1488 if (resolve_mask & (1 << QPalette::Base)) {
1489 // Base color is set for this widget, so use it
1490 bg = panel->palette.brush(QPalette::Base);
1491 usePalette = true;
1492 }
1493
1494 stateId = isEnabled ? ETS_NORMAL : ETS_DISABLED;
1495
1496 if (usePalette) {
1497 p->fillRect(panel->rect, bg);
1498 } else {
1499 XPThemeData theme(0, p, name, partId, stateId, rect);
1500 if (!theme.isValid()) {
1501 QWindowsStyle::drawPrimitive(pe, option, p, widget);
1502 return;
1503 }
1504 int bgType;
1505 pGetThemeEnumValue( theme.handle(),
1506 partId,
1507 stateId,
1508 TMT_BGTYPE,
1509 &bgType);
1510 if( bgType == BT_IMAGEFILE ) {
1511 theme.mirrorHorizontally = hMirrored;
1512 theme.mirrorVertically = vMirrored;
1513 theme.noBorder = noBorder;
1514 theme.noContent = noContent;
1515 theme.rotate = rotate;
1516 d->drawBackground(theme);
1517 } else {
1518 QBrush fillColor = option->palette.brush(QPalette::Base);
1519
1520 if (!isEnabled) {
1521 PROPERTYORIGIN origin = PO_NOTFOUND;
1522 pGetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
1523 // Use only if the fill property comes from our part
1524 if ((origin == PO_PART || origin == PO_STATE)) {
1525 COLORREF bgRef;
1526 pGetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
1527 fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
1528 }
1529 }
1530 p->fillRect(option->rect, fillColor);
1531 }
1532 }
1533
1534 if (panel->lineWidth > 0)
1535 drawPrimitive(PE_FrameLineEdit, panel, p, widget);
1536 return;
1537 }
1538 break;
1539
1540 case PE_FrameTabWidget:
1541 if (const QStyleOptionTabWidgetFrame *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option))
1542 {
1543 name = QLatin1String("TAB");
1544 partId = TABP_PANE;
1545
1546 if (widget) {
1547 bool useGradient = true;
1548 const int maxlength = 256;
1549 WCHAR themeFileName[maxlength];
1550 WCHAR themeColor[maxlength];
1551 // Due to a a scaling issue with the XP Silver theme, tab gradients are not used with it
1552 if (pGetCurrentThemeName(themeFileName, maxlength, themeColor, maxlength, NULL, 0) == S_OK) {
1553 WCHAR* offset;
1554 if ((offset = wcsrchr(themeFileName, QChar(QLatin1Char('\\')).unicode())) != NULL) {
1555 offset++;
1556 if (!lstrcmp(offset, L"Luna.msstyles") && !lstrcmp(offset, L"Metallic")) {
1557 useGradient = false;
1558 }
1559 }
1560 }
1561 // This should work, but currently there's an error in the ::drawBackgroundDirectly()
1562 // code, when using the HDC directly..
1563 if (useGradient) {
1564 QStyleOptionTabWidgetFrame frameOpt = *tab;
1565 frameOpt.rect = widget->rect();
1566 QRect contentsRect = subElementRect(SE_TabWidgetTabContents, &frameOpt, widget);
1567 QRegion reg = option->rect;
1568 reg -= contentsRect;
1569 p->setClipRegion(reg);
1570 XPThemeData theme(widget, p, name, partId, stateId, rect);
1571 theme.mirrorHorizontally = hMirrored;
1572 theme.mirrorVertically = vMirrored;
1573 d->drawBackground(theme);
1574 p->setClipRect(contentsRect);
1575 partId = TABP_BODY;
1576 }
1577 }
1578 switch (tab->shape) {
1579 case QTabBar::RoundedNorth:
1580 case QTabBar::TriangularNorth:
1581 break;
1582 case QTabBar::RoundedSouth:
1583 case QTabBar::TriangularSouth:
1584 vMirrored = true;
1585 break;
1586 case QTabBar::RoundedEast:
1587 case QTabBar::TriangularEast:
1588 rotate = 90;
1589 break;
1590 case QTabBar::RoundedWest:
1591 case QTabBar::TriangularWest:
1592 rotate = 90;
1593 hMirrored = true;
1594 break;
1595 default:
1596 break;
1597 }
1598 }
1599 break;
1600
1601 case PE_FrameMenu:
1602 p->save();
1603 p->setPen(option->palette.dark().color());
1604 p->drawRect(rect.adjusted(0, 0, -1, -1));
1605 p->restore();
1606 return;
1607
1608 case PE_PanelMenuBar:
1609 break;
1610
1611 case PE_FrameDockWidget:
1612 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(option))
1613 {
1614 name = QLatin1String("WINDOW");
1615 if (flags & State_Active)
1616 stateId = FS_ACTIVE;
1617 else
1618 stateId = FS_INACTIVE;
1619
1620 int fwidth = pixelMetric(PM_DockWidgetFrameWidth, frm, widget);
1621
1622 XPThemeData theme(widget, p, name, 0, stateId);
1623 if (!theme.isValid())
1624 break;
1625 theme.rect = QRect(frm->rect.x(), frm->rect.y(), frm->rect.x()+fwidth, frm->rect.height()-fwidth); theme.partId = WP_SMALLFRAMELEFT;
1626 d->drawBackground(theme);
1627 theme.rect = QRect(frm->rect.width()-fwidth, frm->rect.y(), fwidth, frm->rect.height()-fwidth);
1628 theme.partId = WP_SMALLFRAMERIGHT;
1629 d->drawBackground(theme);
1630 theme.rect = QRect(frm->rect.x(), frm->rect.bottom()-fwidth+1, frm->rect.width(), fwidth);
1631 theme.partId = WP_SMALLFRAMEBOTTOM;
1632 d->drawBackground(theme);
1633 return;
1634 }
1635 break;
1636
1637 case PE_IndicatorHeaderArrow:
1638 {
1639#if 0 // XP theme engine doesn't know about this :(
1640 name = QLatin1String("HEADER");
1641 partId = HP_HEADERSORTARROW;
1642 if (flags & State_Down)
1643 stateId = HSAS_SORTEDDOWN;
1644 else
1645 stateId = HSAS_SORTEDUP;
1646#else
1647 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
1648 p->save();
1649 p->setPen(option->palette.dark().color());
1650 p->translate(0, option->rect.height()/2 - 4);
1651 if (header->sortIndicator & QStyleOptionHeader::SortUp) { // invert logic to follow Windows style guide
1652 p->drawLine(option->rect.x(), option->rect.y(), option->rect.x()+8, option->rect.y());
1653 p->drawLine(option->rect.x()+1, option->rect.y()+1, option->rect.x()+7, option->rect.y()+1);
1654 p->drawLine(option->rect.x()+2, option->rect.y()+2, option->rect.x()+6, option->rect.y()+2);
1655 p->drawLine(option->rect.x()+3, option->rect.y()+3, option->rect.x()+5, option->rect.y()+3);
1656 p->drawPoint(option->rect.x()+4, option->rect.y()+4);
1657 } else if(header->sortIndicator & QStyleOptionHeader::SortDown) {
1658 p->drawLine(option->rect.x(), option->rect.y()+4, option->rect.x()+8, option->rect.y()+4);
1659 p->drawLine(option->rect.x()+1, option->rect.y()+3, option->rect.x()+7, option->rect.y()+3);
1660 p->drawLine(option->rect.x()+2, option->rect.y()+2, option->rect.x()+6, option->rect.y()+2);
1661 p->drawLine(option->rect.x()+3, option->rect.y()+1, option->rect.x()+5, option->rect.y()+1);
1662 p->drawPoint(option->rect.x()+4, option->rect.y());
1663 }
1664 p->restore();
1665 return;
1666 }
1667#endif
1668 }
1669 break;
1670
1671 case PE_FrameStatusBarItem:
1672 name = QLatin1String("STATUS");
1673 partId = SP_PANE;
1674 break;
1675
1676 case PE_FrameGroupBox:
1677 name = QLatin1String("BUTTON");
1678 partId = BP_GROUPBOX;
1679 if (!(flags & State_Enabled))
1680 stateId = GBS_DISABLED;
1681 else
1682 stateId = GBS_NORMAL;
1683 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1684 const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(option);
1685 if (frame2->features & QStyleOptionFrameV2::Flat) {
1686 // Windows XP does not have a theme part for a flat GroupBox, paint it with the windows style
1687 QRect fr = frame->rect;
1688 QPoint p1(fr.x(), fr.y() + 1);
1689 QPoint p2(fr.x() + fr.width(), p1.y() + 1);
1690 rect = QRect(p1, p2);
1691 name = QLatin1String("");
1692 }
1693 }
1694 break;
1695
1696 case PE_IndicatorProgressChunk:
1697 {
1698 Qt::Orientation orient = Qt::Horizontal;
1699 bool inverted = false;
1700 if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) {
1701 orient = pb2->orientation;
1702 if (pb2->invertedAppearance)
1703 inverted = true;
1704 }
1705 if (orient == Qt::Horizontal) {
1706 partId = PP_CHUNK;
1707 rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height() );
1708 if (inverted && option->direction == Qt::LeftToRight)
1709 hMirrored = true;
1710 } else {
1711 partId = PP_CHUNKVERT;
1712 rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height());
1713 }
1714 name = QLatin1String("PROGRESS");
1715 stateId = 1;
1716 }
1717 break;
1718
1719 case PE_Q3DockWindowSeparator:
1720 name = QLatin1String("TOOLBAR");
1721 if (flags & State_Horizontal)
1722 partId = TP_SEPARATOR;
1723 else
1724 partId = TP_SEPARATORVERT;
1725 break;
1726
1727 case PE_FrameWindow:
1728 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(option))
1729 {
1730 name = QLatin1String("WINDOW");
1731 if (flags & State_Active)
1732 stateId = FS_ACTIVE;
1733 else
1734 stateId = FS_INACTIVE;
1735
1736 int fwidth = frm->lineWidth + frm->midLineWidth;
1737
1738 XPThemeData theme(0, p, name, 0, stateId);
1739 if (!theme.isValid())
1740 break;
1741
1742 theme.rect = QRect(option->rect.x(), option->rect.y()+fwidth, option->rect.x()+fwidth, option->rect.height()-fwidth);
1743 theme.partId = WP_FRAMELEFT;
1744 d->drawBackground(theme);
1745 theme.rect = QRect(option->rect.width()-fwidth, option->rect.y()+fwidth, fwidth, option->rect.height()-fwidth);
1746 theme.partId = WP_FRAMERIGHT;
1747 d->drawBackground(theme);
1748 theme.rect = QRect(option->rect.x(), option->rect.height()-fwidth, option->rect.width(), fwidth);
1749 theme.partId = WP_FRAMEBOTTOM;
1750 d->drawBackground(theme);
1751 theme.rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.y()+fwidth);
1752 theme.partId = WP_CAPTION;
1753 d->drawBackground(theme);
1754 return;
1755 }
1756 break;
1757
1758 case PE_IndicatorBranch:
1759 {
1760 static const int decoration_size = 9;
1761 int mid_h = option->rect.x() + option->rect.width() / 2;
1762 int mid_v = option->rect.y() + option->rect.height() / 2;
1763 int bef_h = mid_h;
1764 int bef_v = mid_v;
1765 int aft_h = mid_h;
1766 int aft_v = mid_v;
1767 QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern);
1768 if (option->state & State_Item) {
1769 if (option->direction == Qt::RightToLeft)
1770 p->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush);
1771 else
1772 p->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush);
1773 }
1774 if (option->state & State_Sibling)
1775 p->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush);
1776 if (option->state & (State_Open | State_Children | State_Item | State_Sibling))
1777 p->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush);
1778 if (option->state & State_Children) {
1779 int delta = decoration_size / 2;
1780 bef_h -= delta;
1781 bef_v -= delta;
1782 aft_h += delta;
1783 aft_v += delta;
1784 XPThemeData theme(0, p, QLatin1String("TREEVIEW"));
1785 theme.rect = QRect(bef_h, bef_v, decoration_size, decoration_size);
1786 theme.partId = TVP_GLYPH;
1787 theme.stateId = flags & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
1788 d->drawBackground(theme);
1789 }
1790 }
1791 return;
1792
1793 case PE_IndicatorToolBarSeparator:
1794
1795 name = QLatin1String("TOOLBAR");
1796 partId = TP_SEPARATOR;
1797
1798 if (option->state & State_Horizontal)
1799 partId = TP_SEPARATOR;
1800 else
1801 partId = TP_SEPARATORVERT;
1802
1803 break;
1804
1805 case PE_IndicatorToolBarHandle:
1806
1807 name = QLatin1String("REBAR");
1808 partId = RP_GRIPPER;
1809 if (option->state & State_Horizontal) {
1810 partId = RP_GRIPPER;
1811 rect.adjust(0, 0, -2, 0);
1812 }
1813 else {
1814 partId = RP_GRIPPERVERT;
1815 rect.adjust(0, 0, 0, -2);
1816 }
1817 break;
1818
1819 case PE_IndicatorItemViewItemCheck: {
1820 QStyleOptionButton button;
1821 button.QStyleOption::operator=(*option);
1822 button.state &= ~State_MouseOver;
1823 drawPrimitive(PE_IndicatorCheckBox, &button, p, widget);
1824 return;
1825 }
1826
1827 default:
1828 break;
1829 }
1830
1831 XPThemeData theme(0, p, name, partId, stateId, rect);
1832 if (!theme.isValid()) {
1833 QWindowsStyle::drawPrimitive(pe, option, p, widget);
1834 return;
1835 }
1836 theme.mirrorHorizontally = hMirrored;
1837 theme.mirrorVertically = vMirrored;
1838 theme.noBorder = noBorder;
1839 theme.noContent = noContent;
1840 theme.rotate = rotate;
1841 d->drawBackground(theme);
1842}
1843
1844/*!
1845 \reimp
1846*/
1847void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *p,
1848 const QWidget *widget) const
1849{
1850 QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
1851 if (!QWindowsXPStylePrivate::useXP()) {
1852 QWindowsStyle::drawControl(element, option, p, widget);
1853 return;
1854 }
1855
1856 QRect rect(option->rect);
1857 State flags = option->state;
1858
1859 int rotate = 0;
1860 bool hMirrored = false;
1861 bool vMirrored = false;
1862
1863 QString name;
1864 int partId = 0;
1865 int stateId = 0;
1866 switch (element) {
1867 case CE_SizeGrip:
1868 {
1869 name = QLatin1String("STATUS");
1870 partId = SP_GRIPPER;
1871 SIZE sz;
1872 XPThemeData theme(0, p, name, partId, 0);
1873 pGetThemePartSize(theme.handle(), 0, partId, 0, 0, TS_TRUE, &sz);
1874 --sz.cy;
1875 if (const QStyleOptionSizeGrip *sg = qstyleoption_cast<const QStyleOptionSizeGrip *>(option)) {
1876 switch (sg->corner) {
1877 case Qt::BottomRightCorner:
1878 rect = QRect(rect.right() - sz.cx, rect.bottom() - sz.cy, sz.cx, sz.cy);
1879 break;
1880 case Qt::BottomLeftCorner:
1881 rect = QRect(rect.left() + 1, rect.bottom() - sz.cy, sz.cx, sz.cy);
1882 hMirrored = true;
1883 break;
1884 case Qt::TopRightCorner:
1885 rect = QRect(rect.right() - sz.cx, rect.top() + 1, sz.cx, sz.cy);
1886 vMirrored = true;
1887 break;
1888 case Qt::TopLeftCorner:
1889 rect = QRect(rect.left() + 1, rect.top() + 1, sz.cx, sz.cy);
1890 hMirrored = vMirrored = true;
1891 }
1892 }
1893 }
1894 break;
1895
1896 case CE_HeaderSection:
1897 name = QLatin1String("HEADER");
1898 partId = HP_HEADERITEM;
1899 if (flags & State_Sunken)
1900 stateId = HIS_PRESSED;
1901 else if (flags & State_MouseOver)
1902 stateId = HIS_HOT;
1903 else
1904 stateId = HIS_NORMAL;
1905 break;
1906
1907 case CE_Splitter:
1908 p->eraseRect(option->rect);
1909 return;
1910
1911 case CE_PushButtonBevel:
1912 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))
1913 {
1914 name = QLatin1String("BUTTON");
1915 partId = BP_PUSHBUTTON;
1916 bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken))
1917 || (btn->features & QStyleOptionButton::CommandLinkButton
1918 && !(flags & State_MouseOver)
1919 && !(btn->features & QStyleOptionButton::DefaultButton));
1920 if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
1921 stateId = PBS_DISABLED;
1922 else if (justFlat)
1923 ;
1924 else if (flags & (State_Sunken | State_On))
1925 stateId = PBS_PRESSED;
1926 else if (flags & State_MouseOver)
1927 stateId = PBS_HOT;
1928 else if (btn->features & QStyleOptionButton::DefaultButton)
1929 stateId = PBS_DEFAULTED;
1930 else
1931 stateId = PBS_NORMAL;
1932
1933 if (!justFlat) {
1934 XPThemeData theme(widget, p, name, partId, stateId, rect);
1935 d->drawBackground(theme);
1936 }
1937
1938 if (btn->features & QStyleOptionButton::HasMenu) {
1939 int mbiw = 0, mbih = 0;
1940 XPThemeData theme(widget, 0, QLatin1String("TOOLBAR"), TP_SPLITBUTTONDROPDOWN);
1941 if (theme.isValid()) {
1942 SIZE size;
1943 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
1944 mbiw = size.cx;
1945 mbih = size.cy;
1946 }
1947
1948 QRect ir = btn->rect;
1949 QStyleOptionButton newBtn = *btn;
1950 newBtn.rect = QRect(ir.right() - mbiw - 1, 1 + (ir.height()/2) - (mbih/2), mbiw, mbih);
1951 drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget);
1952 }
1953 return;
1954 }
1955 break;
1956 case CE_TabBarTab:
1957 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
1958 {
1959 stateId = tab->state & State_Enabled ? TIS_NORMAL : TIS_DISABLED;
1960 }
1961 break;
1962
1963 case CE_TabBarTabShape:
1964 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
1965 {
1966 name = QLatin1String("TAB");
1967 bool isDisabled = !(tab->state & State_Enabled);
1968 bool hasFocus = tab->state & State_HasFocus;
1969 bool isHot = tab->state & State_MouseOver;
1970 bool selected = tab->state & State_Selected;
1971 bool lastTab = tab->position == QStyleOptionTab::End;
1972 bool firstTab = tab->position == QStyleOptionTab::Beginning;
1973 bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
1974 bool leftAligned = styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignLeft;
1975 bool centerAligned = styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignCenter;
1976 int borderThickness = pixelMetric(PM_DefaultFrameWidth, option, widget);
1977 int tabOverlap = pixelMetric(PM_TabBarTabOverlap, option, widget);
1978
1979 if (isDisabled)
1980 stateId = TIS_DISABLED;
1981 else if (selected)
1982 stateId = TIS_SELECTED;
1983 else if (hasFocus)
1984 stateId = TIS_FOCUSED;
1985 else if (isHot)
1986 stateId = TIS_HOT;
1987 else
1988 stateId = TIS_NORMAL;
1989
1990 // Selecting proper part depending on position
1991 if (firstTab || onlyOne) {
1992 if (leftAligned) {
1993 partId = TABP_TABITEMLEFTEDGE;
1994 } else if (centerAligned) {
1995 partId = TABP_TABITEM;
1996 } else { // rightAligned
1997 partId = TABP_TABITEMRIGHTEDGE;
1998 }
1999 } else {
2000 partId = TABP_TABITEM;
2001 }
2002
2003 if (tab->direction == Qt::RightToLeft
2004 && (tab->shape == QTabBar::RoundedNorth
2005 || tab->shape == QTabBar::RoundedSouth)) {
2006 bool temp = firstTab;
2007 firstTab = lastTab;
2008 lastTab = temp;
2009 }
2010 bool begin = firstTab || onlyOne;
2011 bool end = lastTab || onlyOne;
2012 switch (tab->shape) {
2013 case QTabBar::RoundedNorth:
2014 if (selected)
2015 rect.adjust(begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap, borderThickness);
2016 else
2017 rect.adjust(begin? tabOverlap : 0, tabOverlap, end ? -tabOverlap : 0, 0);
2018 break;
2019 case QTabBar::RoundedSouth:
2020 //vMirrored = true;
2021 rotate = 180; // Not 100% correct, but works
2022 if (selected)
2023 rect.adjust(begin ? 0 : -tabOverlap , -borderThickness, end ? 0 : tabOverlap, 0);
2024 else
2025 rect.adjust(begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0 , -tabOverlap);
2026 break;
2027 case QTabBar::RoundedEast:
2028 rotate = 90;
2029 if (selected) {
2030 rect.adjust(-borderThickness, begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap);
2031 }else{
2032 rect.adjust(0, begin ? tabOverlap : 0, -tabOverlap, end ? -tabOverlap : 0);
2033 }
2034 break;
2035 case QTabBar::RoundedWest:
2036 hMirrored = true;
2037 rotate = 90;
2038 if (selected) {
2039 rect.adjust(0, begin ? 0 : -tabOverlap, borderThickness, end ? 0 : tabOverlap);
2040 }else{
2041 rect.adjust(tabOverlap, begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0);
2042 }
2043 break;
2044 default:
2045 name = QLatin1String(""); // Do our own painting for triangular
2046 break;
2047 }
2048
2049 if (!selected) {
2050 switch (tab->shape) {
2051 case QTabBar::RoundedNorth:
2052 rect.adjust(0,0, 0,-1);
2053 break;
2054 case QTabBar::RoundedSouth:
2055 rect.adjust(0,1, 0,0);
2056 break;
2057 case QTabBar::RoundedEast:
2058 rect.adjust( 1,0, 0,0);
2059 break;
2060 case QTabBar::RoundedWest:
2061 rect.adjust(0,0, -1,0);
2062 break;
2063 default:
2064 break;
2065 }
2066 }
2067 }
2068 break;
2069
2070 case CE_ProgressBarGroove:
2071 {
2072 Qt::Orientation orient = Qt::Horizontal;
2073 if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option))
2074 orient = pb2->orientation;
2075 partId = (orient == Qt::Horizontal) ? PP_BAR : PP_BARVERT;
2076 name = QLatin1String("PROGRESS");
2077 stateId = 1;
2078 }
2079 break;
2080
2081 case CE_MenuEmptyArea:
2082 case CE_MenuItem:
2083 if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
2084 {
2085 int tab = menuitem->tabWidth;
2086 bool dis = !(menuitem->state & State_Enabled);
2087 bool act = menuitem->state & State_Selected;
2088 bool checkable = menuitem->menuHasCheckableItems;
2089 bool checked = checkable ? menuitem->checked : false;
2090
2091 // windows always has a check column, regardless whether we have an icon or not
2092 int checkcol = qMax(menuitem->maxIconWidth, 12);
2093
2094 int x, y, w, h;
2095 rect.getRect(&x, &y, &w, &h);
2096
2097 QBrush fill = menuitem->palette.brush(act ? QPalette::Highlight : QPalette::Button);
2098 p->fillRect(rect, fill);
2099
2100 if (element == CE_MenuEmptyArea)
2101 break;
2102
2103 // draw separator -------------------------------------------------
2104 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
2105 int yoff = y-1 + h / 2;
2106 p->setPen(menuitem->palette.dark().color());
2107 p->drawLine(x, yoff, x+w, yoff);
2108 ++yoff;
2109 p->setPen(menuitem->palette.light().color());
2110 p->drawLine(x, yoff, x+w, yoff);
2111 return;
2112 }
2113
2114 int xpos = x;
2115
2116 // draw icon ------------------------------------------------------
2117 if (!menuitem->icon.isNull()) {
2118 QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
2119 if (act && !dis)
2120 mode = QIcon::Active;
2121 QPixmap pixmap = checked ?
2122 menuitem->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On) :
2123 menuitem->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), mode);
2124 int pixw = pixmap.width();
2125 int pixh = pixmap.height();
2126 QRect iconRect(0, 0, pixw, pixh);
2127 iconRect.moveCenter(QRect(xpos, y, checkcol, h).center());
2128 QRect vIconRect = visualRect(option->direction, option->rect, iconRect);
2129 p->setPen(menuitem->palette.text().color());
2130 p->setBrush(Qt::NoBrush);
2131 if (checked)
2132 p->drawRect(vIconRect.adjusted(-1, -2, 1, 1));
2133 p->drawPixmap(vIconRect.topLeft(), pixmap);
2134
2135 // draw checkmark -------------------------------------------------
2136 } else if (checked) {
2137 QStyleOptionMenuItem newMi = *menuitem;
2138 newMi.state = State_None;
2139 if (!dis)
2140 newMi.state |= State_Enabled;
2141 if (act)
2142 newMi.state |= State_On;
2143
2144 QRect checkMarkRect = QRect(menuitem->rect.x() + windowsItemFrame,
2145 menuitem->rect.y() + windowsItemFrame,
2146 checkcol - 2 * windowsItemFrame,
2147 menuitem->rect.height() - 2*windowsItemFrame);
2148 newMi.rect = visualRect(option->direction, option->rect, checkMarkRect);
2149 drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, widget);
2150 }
2151
2152 QColor textColor = dis ? menuitem->palette.text().color() :
2153 act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color();
2154 p->setPen(textColor);
2155
2156 // draw text ------------------------------------------------------
2157 int xm = windowsItemFrame + checkcol + windowsItemHMargin;
2158 xpos = menuitem->rect.x() + xm;
2159 QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
2160 QRect vTextRect = visualRect(option->direction, option->rect, textRect);
2161 QString s = menuitem->text;
2162 if (!s.isEmpty()) {
2163 p->save();
2164 int t = s.indexOf(QLatin1Char('\t'));
2165 int text_flags = Qt::AlignVCenter|Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignLeft;
2166 if (!styleHint(SH_UnderlineShortcut, menuitem, widget))
2167 text_flags |= Qt::TextHideMnemonic;
2168 // draw tab text ----------------
2169 if (t >= 0) {
2170 QRect vShortcutRect = visualRect(option->direction, option->rect, QRect(textRect.topRight(), menuitem->rect.bottomRight()));
2171 if (dis && !act && styleHint(SH_EtchDisabledText, option, widget)) {
2172 p->setPen(menuitem->palette.light().color());
2173 p->drawText(vShortcutRect.adjusted(1,1,1,1), text_flags, s.mid(t + 1));
2174 p->setPen(textColor);
2175 }
2176 p->drawText(vShortcutRect, text_flags, s.mid(t + 1));
2177 s = s.left(t);
2178 }
2179 QFont font = menuitem->font;
2180 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
2181 font.setBold(true);
2182 p->setFont(font);
2183 if (dis && !act && styleHint(SH_EtchDisabledText, option, widget)) {
2184 p->setPen(menuitem->palette.light().color());
2185 p->drawText(vTextRect.adjusted(1,1,1,1), text_flags, s.left(t));
2186 p->setPen(textColor);
2187 }
2188 p->drawText(vTextRect, text_flags, s);
2189 p->restore();
2190 }
2191
2192 // draw sub menu arrow --------------------------------------------
2193 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
2194 int dim = (h - 2) / 2;
2195 PrimitiveElement arrow;
2196 arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
2197 xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
2198 QRect vSubMenuRect = visualRect(option->direction, option->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
2199 QStyleOptionMenuItem newMI = *menuitem;
2200 newMI.rect = vSubMenuRect;
2201 newMI.state = dis ? State_None : State_Enabled;
2202 if (act)
2203 newMI.palette.setColor(QPalette::ButtonText, newMI.palette.highlightedText().color());
2204 drawPrimitive(arrow, &newMI, p, widget);
2205 }
2206 }
2207 return;
2208
2209 case CE_MenuBarItem:
2210 if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
2211 {
2212 if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
2213 break;
2214
2215 bool act = mbi->state & State_Selected;
2216 bool dis = !(mbi->state & State_Enabled);
2217
2218 QBrush fill = mbi->palette.brush(act ? QPalette::Highlight : QPalette::Button);
2219 QPalette::ColorRole textRole = dis ? QPalette::Text:
2220 act ? QPalette::HighlightedText : QPalette::ButtonText;
2221 QPixmap pix = mbi->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
2222
2223 uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
2224 if (!styleHint(SH_UnderlineShortcut, mbi, widget))
2225 alignment |= Qt::TextHideMnemonic;
2226
2227 p->fillRect(rect, fill);
2228 if (!pix.isNull())
2229 drawItemPixmap(p, mbi->rect, alignment, pix);
2230 else
2231 drawItemText(p, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
2232 }
2233 return;
2234#ifndef QT_NO_DOCKWIDGET
2235 case CE_DockWidgetTitle:
2236 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option))
2237 {
2238 int buttonMargin = 4;
2239 int mw = pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
2240 int fw = pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget);
2241 bool isFloating = widget && widget->isWindow();
2242 bool isActive = dwOpt->state & State_Active;
2243
2244 const QStyleOptionDockWidgetV2 *v2
2245 = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(dwOpt);
2246 bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar;
2247
2248 if (verticalTitleBar) {
2249 QSize s = rect.size();
2250 s.transpose();
2251 rect.setSize(s);
2252
2253 p->translate(rect.left() - 1, rect.top() + rect.width());
2254 p->rotate(-90);
2255 p->translate(-rect.left() + 1, -rect.top());
2256 }
2257 QRect r = rect.adjusted(0, 2, -1, -3);
2258 QRect titleRect = r;
2259
2260 if (dwOpt->closable) {
2261 QSize sz = standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10));
2262 titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
2263 }
2264
2265 if (dwOpt->floatable) {
2266 QSize sz = standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10));
2267 titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
2268 }
2269
2270 if (isFloating) {
2271 titleRect.adjust(0, -fw, 0, 0);
2272 if (widget != 0 && widget->windowIcon().cacheKey() != qApp->windowIcon().cacheKey())
2273 titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
2274 } else {
2275 titleRect.adjust(mw, 0, 0, 0);
2276 if (!dwOpt->floatable && !dwOpt->closable)
2277 titleRect.adjust(0, 0, -mw, 0);
2278 }
2279
2280 if (!verticalTitleBar)
2281 titleRect = visualRect(dwOpt->direction, r, titleRect);
2282
2283 if (!isFloating) {
2284 QPen oldPen = p->pen();
2285 QString titleText = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
2286 p->setPen(dwOpt->palette.color(QPalette::Dark));
2287 p->drawRect(r);
2288
2289 if (!titleText.isEmpty()) {
2290 drawItemText(p, titleRect,
2291 Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, dwOpt->palette,
2292 dwOpt->state & State_Enabled, titleText,
2293 QPalette::WindowText);
2294 }
2295
2296 p->setPen(oldPen);
2297 } else {
2298 name = QLatin1String("WINDOW");
2299 if (isActive)
2300 stateId = CS_ACTIVE;
2301 else
2302 stateId = CS_INACTIVE;
2303
2304 int titleHeight = rect.height() - 2;
2305 rect = rect.adjusted(-fw, -fw, fw, 0);
2306
2307 XPThemeData theme(widget, p, name, 0, stateId);
2308 if (!theme.isValid())
2309 break;
2310
2311 // Draw small type title bar
2312 theme.rect = rect;
2313 theme.partId = WP_SMALLCAPTION;
2314 d->drawBackground(theme);
2315
2316 // Figure out maximal button space on title bar
2317
2318 QIcon ico = widget->windowIcon();
2319 bool hasIcon = (ico.cacheKey() != qApp->windowIcon().cacheKey());
2320 if (hasIcon) {
2321 QPixmap pxIco = ico.pixmap(titleHeight);
2322 if (!verticalTitleBar && QApplication::layoutDirection() == Qt::RightToLeft)
2323 p->drawPixmap(rect.width() - titleHeight - pxIco.width(), rect.bottom() - titleHeight - 2, pxIco);
2324 else
2325 p->drawPixmap(fw, rect.bottom() - titleHeight - 2, pxIco);
2326 }
2327 if (!dwOpt->title.isEmpty()) {
2328 QPen oldPen = p->pen();
2329 QFont oldFont = p->font();
2330 QFont titleFont = oldFont;
2331 titleFont.setBold(true);
2332 p->setFont(titleFont);
2333 QString titleText
2334 = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
2335
2336 int result = TST_NONE;
2337 pGetThemeEnumValue(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
2338 if (result != TST_NONE) {
2339 COLORREF textShadowRef;
2340 pGetThemeColor(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
2341 QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
2342 p->setPen(textShadow);
2343 drawItemText(p, titleRect.adjusted(1, 1, 1, 1),
2344 Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
2345 dwOpt->state & State_Enabled, titleText);
2346 }
2347
2348 COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
2349 QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
2350 p->setPen(textColor);
2351 drawItemText(p, titleRect,
2352 Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
2353 dwOpt->state & State_Enabled, titleText);
2354 p->setFont(oldFont);
2355 p->setPen(oldPen);
2356 }
2357
2358 }
2359
2360 return;
2361 }
2362 break;
2363#endif // QT_NO_DOCKWIDGET
2364#ifndef QT_NO_RUBBERBAND
2365 case CE_RubberBand:
2366 if (qstyleoption_cast<const QStyleOptionRubberBand *>(option)) {
2367 QColor highlight = option->palette.color(QPalette::Active, QPalette::Highlight);
2368 p->save();
2369 QRect r = option->rect;
2370 p->setPen(highlight.darker(120));
2371 QColor dimHighlight(qMin(highlight.red()/2 + 110, 255),
2372 qMin(highlight.green()/2 + 110, 255),
2373 qMin(highlight.blue()/2 + 110, 255),
2374 (widget && widget->isTopLevel())? 255 : 127);
2375 p->setBrush(dimHighlight);
2376 p->drawRect(option->rect.adjusted(0, 0, -1, -1));
2377 p->restore();
2378 return;
2379 }
2380#endif // QT_NO_RUBBERBAND
2381 case CE_HeaderEmptyArea:
2382 if (option->state & State_Horizontal)
2383 {
2384 name = QLatin1String("HEADER");
2385 stateId = HIS_NORMAL;
2386 }
2387 else {
2388 QWindowsStyle::drawControl(CE_HeaderEmptyArea, option, p, widget);
2389 return;
2390 }
2391 break;
2392 default:
2393 break;
2394 }
2395
2396 XPThemeData theme(widget, p, name, partId, stateId, rect);
2397 if (!theme.isValid()) {
2398 QWindowsStyle::drawControl(element, option, p, widget);
2399 return;
2400 }
2401
2402 theme.rotate = rotate;
2403 theme.mirrorHorizontally = hMirrored;
2404 theme.mirrorVertically = vMirrored;
2405 d->drawBackground(theme);
2406}
2407
2408
2409/*!
2410 \reimp
2411*/
2412void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option,
2413 QPainter *p, const QWidget *widget) const
2414{
2415 QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
2416
2417 if (!QWindowsXPStylePrivate::useXP()) {
2418 QWindowsStyle::drawComplexControl(cc, option, p, widget);
2419 return;
2420 }
2421
2422 State flags = option->state;
2423 SubControls sub = option->subControls;
2424 QRect r = option->rect;
2425
2426 int partId = 0;
2427 int stateId = 0;
2428 if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
2429 flags |= State_MouseOver;
2430
2431 switch (cc) {
2432#ifndef QT_NO_SPINBOX
2433 case CC_SpinBox:
2434 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option))
2435 {
2436 XPThemeData theme(widget, p, QLatin1String("SPIN"));
2437
2438 if (sb->frame && (sub & SC_SpinBoxFrame)) {
2439 partId = EP_EDITTEXT;
2440 if (!(flags & State_Enabled))
2441 stateId = ETS_DISABLED;
2442 else if (flags & State_HasFocus)
2443 stateId = ETS_FOCUSED;
2444 else
2445 stateId = ETS_NORMAL;
2446
2447 XPThemeData ftheme(widget, p, QLatin1String("EDIT"), partId, stateId, r);
2448 ftheme.noContent = true;
2449 d->drawBackground(ftheme);
2450 }
2451 if (sub & SC_SpinBoxUp) {
2452 theme.rect = subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget);
2453 partId = SPNP_UP;
2454 if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled))
2455 stateId = UPS_DISABLED;
2456 else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
2457 stateId = UPS_PRESSED;
2458 else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
2459 stateId = UPS_HOT;
2460 else
2461 stateId = UPS_NORMAL;
2462 theme.partId = partId;
2463 theme.stateId = stateId;
2464 d->drawBackground(theme);
2465 }
2466 if (sub & SC_SpinBoxDown) {
2467 theme.rect = subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
2468 partId = SPNP_DOWN;
2469 if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled))
2470 stateId = DNS_DISABLED;
2471 else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
2472 stateId = DNS_PRESSED;
2473 else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
2474 stateId = DNS_HOT;
2475 else
2476 stateId = DNS_NORMAL;
2477 theme.partId = partId;
2478 theme.stateId = stateId;
2479 d->drawBackground(theme);
2480 }
2481 }
2482 break;
2483#endif // QT_NO_SPINBOX
2484#ifndef QT_NO_COMBOBOX
2485 case CC_ComboBox:
2486 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option))
2487 {
2488 if (sub & SC_ComboBoxEditField) {
2489 if (cmb->frame) {
2490 partId = EP_EDITTEXT;
2491 if (!(flags & State_Enabled))
2492 stateId = ETS_DISABLED;
2493 else if (flags & State_HasFocus)
2494 stateId = ETS_FOCUSED;
2495 else
2496 stateId = ETS_NORMAL;
2497 XPThemeData theme(widget, p, QLatin1String("EDIT"), partId, stateId, r);
2498 d->drawBackground(theme);
2499 } else {
2500 QBrush editBrush = cmb->palette.brush(QPalette::Base);
2501 p->fillRect(option->rect, editBrush);
2502 }
2503 if (!cmb->editable) {
2504 QRect re = subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget);
2505 if (option->state & State_HasFocus) {
2506 p->fillRect(re, option->palette.highlight());
2507 p->setPen(option->palette.highlightedText().color());
2508 p->setBackground(option->palette.highlight());
2509 } else {
2510 p->fillRect(re, option->palette.base());
2511 p->setPen(option->palette.text().color());
2512 p->setBackground(option->palette.base());
2513 }
2514 }
2515 }
2516
2517 if (sub & SC_ComboBoxArrow) {
2518 XPThemeData theme(widget, p, QLatin1String("COMBOBOX"));
2519 theme.rect = subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
2520 partId = CP_DROPDOWNBUTTON;
2521 if (!(flags & State_Enabled))
2522 stateId = CBXS_DISABLED;
2523 else if (cmb->activeSubControls == SC_ComboBoxArrow && (cmb->state & State_Sunken))
2524 stateId = CBXS_PRESSED;
2525 else if (cmb->activeSubControls == SC_ComboBoxArrow && (cmb->state & State_MouseOver))
2526 stateId = CBXS_HOT;
2527 else
2528 stateId = CBXS_NORMAL;
2529 theme.partId = partId;
2530 theme.stateId = stateId;
2531 d->drawBackground(theme);
2532 }
2533 }
2534 break;
2535#endif // QT_NO_COMBOBOX
2536 case CC_ScrollBar:
2537 if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option))
2538 {
2539 XPThemeData theme(widget, p, QLatin1String("SCROLLBAR"));
2540 bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
2541 if (maxedOut)
2542 flags &= ~State_Enabled;
2543
2544 bool isHorz = flags & State_Horizontal;
2545 bool isRTL = option->direction == Qt::RightToLeft;
2546 if (sub & SC_ScrollBarAddLine) {
2547 theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
2548 partId = SBP_ARROWBTN;
2549 if (!(flags & State_Enabled))
2550 stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
2551 else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
2552 stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
2553 else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
2554 stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
2555 else
2556 stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
2557 theme.partId = partId;
2558 theme.stateId = stateId;
2559 d->drawBackground(theme);
2560 }
2561 if (sub & SC_ScrollBarSubLine) {
2562 theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
2563 partId = SBP_ARROWBTN;
2564 if (!(flags & State_Enabled))
2565 stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
2566 else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
2567 stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
2568 else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
2569 stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
2570 else
2571 stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
2572 theme.partId = partId;
2573 theme.stateId = stateId;
2574 d->drawBackground(theme);
2575 }
2576 if (maxedOut) {
2577 theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
2578 theme.rect = theme.rect.united(subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
2579 theme.rect = theme.rect.united(subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget));
2580 partId = scrollbar->orientation == Qt::Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
2581 stateId = SCRBS_DISABLED;
2582 theme.partId = partId;
2583 theme.stateId = stateId;
2584 d->drawBackground(theme);
2585 } else {
2586 if (sub & SC_ScrollBarSubPage) {
2587 theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget);
2588 partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
2589 if (!(flags & State_Enabled))
2590 stateId = SCRBS_DISABLED;
2591 else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
2592 stateId = SCRBS_PRESSED;
2593 else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
2594 stateId = SCRBS_HOT;
2595 else
2596 stateId = SCRBS_NORMAL;
2597 theme.partId = partId;
2598 theme.stateId = stateId;
2599 d->drawBackground(theme);
2600 }
2601 if (sub & SC_ScrollBarAddPage) {
2602 theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget);
2603 partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
2604 if (!(flags & State_Enabled))
2605 stateId = SCRBS_DISABLED;
2606 else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
2607 stateId = SCRBS_PRESSED;
2608 else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
2609 stateId = SCRBS_HOT;
2610 else
2611 stateId = SCRBS_NORMAL;
2612 theme.partId = partId;
2613 theme.stateId = stateId;
2614 d->drawBackground(theme);
2615 }
2616 if (sub & SC_ScrollBarSlider) {
2617 theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
2618 if (!(flags & State_Enabled))
2619 stateId = SCRBS_DISABLED;
2620 else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
2621 stateId = SCRBS_PRESSED;
2622 else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
2623 stateId = SCRBS_HOT;
2624 else
2625 stateId = SCRBS_NORMAL;
2626
2627 // Draw handle
2628 theme.rect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
2629 theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
2630 theme.stateId = stateId;
2631 d->drawBackground(theme);
2632
2633 // Calculate rect of gripper
2634 const int swidth = theme.rect.width();
2635 const int sheight = theme.rect.height();
2636
2637 MARGINS contentsMargin;
2638 RECT rect = theme.toRECT(theme.rect);
2639 pGetThemeMargins(theme.handle(), 0, theme.partId, theme.stateId, TMT_SIZINGMARGINS, &rect, &contentsMargin);
2640
2641 SIZE size;
2642 theme.partId = flags & State_Horizontal ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
2643 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
2644 int gw = size.cx, gh = size.cy;
2645
2646
2647 QRect gripperBounds;
2648 if (flags & State_Horizontal && ((swidth - contentsMargin.cxLeftWidth - contentsMargin.cxRightWidth) > gw)) {
2649 gripperBounds.setLeft(theme.rect.left() + swidth/2 - gw/2);
2650 gripperBounds.setTop(theme.rect.top() + sheight/2 - gh/2);
2651 gripperBounds.setWidth(gw);
2652 gripperBounds.setHeight(gh);
2653 } else if ((sheight - contentsMargin.cyTopHeight - contentsMargin.cyBottomHeight) > gh) {
2654 gripperBounds.setLeft(theme.rect.left() + swidth/2 - gw/2);
2655 gripperBounds.setTop(theme.rect.top() + sheight/2 - gh/2);
2656 gripperBounds.setWidth(gw);
2657 gripperBounds.setHeight(gh);
2658 }
2659
2660 // Draw gripper if there is enough space
2661 if (!gripperBounds.isEmpty()) {
2662 p->save();
2663 XPThemeData grippBackground = theme;
2664 grippBackground.partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
2665 theme.rect = gripperBounds;
2666 p->setClipRegion(d->region(theme));// Only change inside the region of the gripper
2667 d->drawBackground(grippBackground);// The gutter is the grippers background
2668 d->drawBackground(theme); // Transparent gripper ontop of background
2669 p->restore();
2670 }
2671 }
2672 }
2673 }
2674 break;
2675
2676#ifndef QT_NO_SLIDER
2677 case CC_Slider:
2678 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option))
2679 {
2680 XPThemeData theme(widget, p, QLatin1String("TRACKBAR"));
2681 QRect slrect = slider->rect;
2682 QRegion tickreg = slrect;
2683 if (sub & SC_SliderGroove) {
2684 theme.rect = subControlRect(CC_Slider, option, SC_SliderGroove, widget);
2685 if (slider->orientation == Qt::Horizontal) {
2686 partId = TKP_TRACK;
2687 stateId = TRS_NORMAL;
2688 theme.rect = QRect(slrect.left(), theme.rect.center().y() - 2, slrect.width(), 4);
2689 } else {
2690 partId = TKP_TRACKVERT;
2691 stateId = TRVS_NORMAL;
2692 theme.rect = QRect(theme.rect.center().x() - 2, slrect.top(), 4, slrect.height());
2693 }
2694 theme.partId = partId;
2695 theme.stateId = stateId;
2696 d->drawBackground(theme);
2697 tickreg -= theme.rect;
2698 }
2699 if (sub & SC_SliderTickmarks) {
2700 int tickOffset = pixelMetric(PM_SliderTickmarkOffset, slider, widget);
2701 int ticks = slider->tickPosition;
2702 int thickness = pixelMetric(PM_SliderControlThickness, slider, widget);
2703 int len = pixelMetric(PM_SliderLength, slider, widget);
2704 int available = pixelMetric(PM_SliderSpaceAvailable, slider, widget);
2705 int interval = slider->tickInterval;
2706 if (interval <= 0) {
2707 interval = slider->singleStep;
2708 if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
2709 available)
2710 - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
2711 0, available) < 3)
2712 interval = slider->pageStep;
2713 }
2714 if (!interval)
2715 interval = 1;
2716 int fudge = len / 2;
2717 int pos;
2718 int bothOffset = (ticks & QSlider::TicksAbove && ticks & QSlider::TicksBelow) ? 1 : 0;
2719 p->setPen(d->sliderTickColor);
2720 QVarLengthArray<QLine, 32> lines;
2721 int v = slider->minimum;
2722 while (v <= slider->maximum + 1) {
2723 if (v == slider->maximum + 1 && interval == 1)
2724 break;
2725 const int v_ = qMin(v, slider->maximum);
2726 int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
2727 pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
2728 v_, available) + fudge;
2729 if (slider->orientation == Qt::Horizontal) {
2730 if (ticks & QSlider::TicksAbove)
2731 lines.append(QLine(pos, tickOffset - 1 - bothOffset,
2732 pos, tickOffset - 1 - bothOffset - tickLength));
2733
2734 if (ticks & QSlider::TicksBelow)
2735 lines.append(QLine(pos, tickOffset + thickness + bothOffset,
2736 pos, tickOffset + thickness + bothOffset + tickLength));
2737 } else {
2738 if (ticks & QSlider::TicksAbove)
2739 lines.append(QLine(tickOffset - 1 - bothOffset, pos,
2740 tickOffset - 1 - bothOffset - tickLength, pos));
2741
2742 if (ticks & QSlider::TicksBelow)
2743 lines.append(QLine(tickOffset + thickness + bothOffset, pos,
2744 tickOffset + thickness + bothOffset + tickLength, pos));
2745 }
2746 // in the case where maximum is max int
2747 int nextInterval = v + interval;
2748 if (nextInterval < v)
2749 break;
2750 v = nextInterval;
2751 }
2752 if (lines.size() > 0) {
2753 p->save();
2754 p->translate(slrect.topLeft());
2755 p->drawLines(lines.constData(), lines.size());
2756 p->restore();
2757 }
2758 }
2759 if (sub & SC_SliderHandle) {
2760 theme.rect = subControlRect(CC_Slider, option, SC_SliderHandle, widget);
2761 if (slider->orientation == Qt::Horizontal) {
2762 if (slider->tickPosition == QSlider::TicksAbove)
2763 partId = TKP_THUMBTOP;
2764 else if (slider->tickPosition == QSlider::TicksBelow)
2765 partId = TKP_THUMBBOTTOM;
2766 else
2767 partId = TKP_THUMB;
2768
2769 if (!(slider->state & State_Enabled))
2770 stateId = TUS_DISABLED;
2771 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
2772 stateId = TUS_PRESSED;
2773 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
2774 stateId = TUS_HOT;
2775 else if (flags & State_HasFocus)
2776 stateId = TUS_FOCUSED;
2777 else
2778 stateId = TUS_NORMAL;
2779 } else {
2780 if (slider->tickPosition == QSlider::TicksLeft)
2781 partId = TKP_THUMBLEFT;
2782 else if (slider->tickPosition == QSlider::TicksRight)
2783 partId = TKP_THUMBRIGHT;
2784 else
2785 partId = TKP_THUMBVERT;
2786
2787 if (!(slider->state & State_Enabled))
2788 stateId = TUVS_DISABLED;
2789 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
2790 stateId = TUVS_PRESSED;
2791 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
2792 stateId = TUVS_HOT;
2793 else if (flags & State_HasFocus)
2794 stateId = TUVS_FOCUSED;
2795 else
2796 stateId = TUVS_NORMAL;
2797 }
2798 theme.partId = partId;
2799 theme.stateId = stateId;
2800 d->drawBackground(theme);
2801 }
2802 if (slider->state & State_HasFocus) {
2803 QStyleOptionFocusRect fropt;
2804 fropt.QStyleOption::operator=(*slider);
2805 fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
2806 drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
2807 }
2808 }
2809 break;
2810#endif
2811#ifndef QT_NO_TOOLBUTTON
2812 case CC_ToolButton:
2813 if (const QStyleOptionToolButton *toolbutton
2814 = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
2815 QRect button, menuarea;
2816 button = subControlRect(cc, toolbutton, SC_ToolButton, widget);
2817 menuarea = subControlRect(cc, toolbutton, SC_ToolButtonMenu, widget);
2818
2819 State bflags = toolbutton->state & ~State_Sunken;
2820 State mflags = bflags;
2821
2822 if (bflags & State_AutoRaise) {
2823 if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) {
2824 bflags &= ~State_Raised;
2825 }
2826 }
2827
2828 if (toolbutton->state & State_Sunken) {
2829 if (toolbutton->activeSubControls & SC_ToolButton) {
2830 bflags |= State_Sunken;
2831 mflags |= State_MouseOver | State_Sunken;
2832 } else if (toolbutton->activeSubControls & SC_ToolButtonMenu) {
2833 mflags |= State_Sunken;
2834 bflags |= State_MouseOver;
2835 }
2836 }
2837
2838 QStyleOption tool(0);
2839 tool.palette = toolbutton->palette;
2840 if (toolbutton->subControls & SC_ToolButton) {
2841 if (flags & (State_Sunken | State_On | State_Raised) || !(flags & State_AutoRaise)) {
2842 if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup) {
2843 XPThemeData theme(widget, p, QLatin1String("TOOLBAR"));
2844 theme.partId = TP_SPLITBUTTON;
2845 theme.rect = button;
2846 if (!(bflags & State_Enabled))
2847 stateId = TS_DISABLED;
2848 else if (bflags & State_Sunken)
2849 stateId = TS_PRESSED;
2850 else if (bflags & State_MouseOver || !(flags & State_AutoRaise))
2851 stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
2852 else if (bflags & State_On)
2853 stateId = TS_CHECKED;
2854 else
2855 stateId = TS_NORMAL;
2856 if (option->direction == Qt::RightToLeft)
2857 theme.mirrorHorizontally = true;
2858 theme.stateId = stateId;
2859 d->drawBackground(theme);
2860 } else {
2861 tool.rect = button;
2862 tool.state = bflags;
2863 if (widget && !qobject_cast<QToolBar*>(widget->parentWidget())
2864 && !(bflags & State_AutoRaise))
2865 drawPrimitive(PE_PanelButtonBevel, &tool, p, widget);
2866 else
2867 drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
2868 }
2869 }
2870 }
2871
2872 if (toolbutton->state & State_HasFocus) {
2873 QStyleOptionFocusRect fr;
2874 fr.QStyleOption::operator=(*toolbutton);
2875 fr.rect.adjust(3, 3, -3, -3);
2876 if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
2877 fr.rect.adjust(0, 0, -pixelMetric(QStyle::PM_MenuButtonIndicator,
2878 toolbutton, widget), 0);
2879 drawPrimitive(PE_FrameFocusRect, &fr, p, widget);
2880 }
2881 QStyleOptionToolButton label = *toolbutton;
2882 label.state = bflags;
2883 int fw = 2;
2884 label.rect = button.adjusted(fw, fw, -fw, -fw);
2885 drawControl(CE_ToolButtonLabel, &label, p, widget);
2886
2887 if (toolbutton->subControls & SC_ToolButtonMenu) {
2888 tool.rect = menuarea;
2889 tool.state = mflags;
2890 drawPrimitive(PE_IndicatorButtonDropDown, &tool, p, widget);
2891 } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
2892 int mbi = pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
2893 QRect ir = toolbutton->rect;
2894 QStyleOptionToolButton newBtn = *toolbutton;
2895 newBtn.rect = QRect(ir.right() + 4 - mbi, ir.height() - mbi + 4, mbi - 5, mbi - 5);
2896 drawPrimitive(PE_IndicatorArrowDown, &newBtn, p, widget);
2897 }
2898 }
2899 break;
2900#endif // QT_NO_TOOLBUTTON
2901
2902 case CC_TitleBar:
2903 {
2904 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option))
2905 {
2906 bool isActive = tb->titleBarState & QStyle::State_Active;
2907 XPThemeData theme(widget, p, QLatin1String("WINDOW"));
2908 if (sub & SC_TitleBarLabel) {
2909
2910#ifdef QT3_SUPPORT
2911 if (widget && widget->inherits("Q3DockWindowTitleBar")) {
2912 partId = WP_SMALLCAPTION;
2913 } else
2914#endif
2915 partId = (tb->titleBarState & Qt::WindowMinimized) ? WP_MINCAPTION : WP_CAPTION;
2916 theme.rect = option->rect;
2917 if (widget && !widget->isEnabled())
2918 stateId = CS_DISABLED;
2919 else if (isActive)
2920 stateId = CS_ACTIVE;
2921 else
2922 stateId = CS_INACTIVE;
2923
2924 theme.partId = partId;
2925 theme.stateId = stateId;
2926 d->drawBackground(theme);
2927
2928 QRect ir = subControlRect(CC_TitleBar, tb, SC_TitleBarLabel, widget);
2929
2930 int result = TST_NONE;
2931 pGetThemeEnumValue(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
2932 if (result != TST_NONE) {
2933 COLORREF textShadowRef;
2934 pGetThemeColor(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
2935 QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
2936 p->setPen(textShadow);
2937 p->drawText(ir.x() + 3, ir.y() + 2, ir.width() - 1, ir.height(),
2938 Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
2939 }
2940 COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
2941 QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
2942 p->setPen(textColor);
2943 p->drawText(ir.x() + 2, ir.y() + 1, ir.width() - 2, ir.height(),
2944 Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
2945 }
2946 if (sub & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
2947 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarSysMenu, widget);
2948 partId = WP_SYSBUTTON;
2949 if ((widget && !widget->isEnabled()) || !isActive)
2950 stateId = SBS_DISABLED;
2951 else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_Sunken))
2952 stateId = SBS_PUSHED;
2953 else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_MouseOver))
2954 stateId = SBS_HOT;
2955 else
2956 stateId = SBS_NORMAL;
2957 if (!tb->icon.isNull()) {
2958 tb->icon.paint(p, theme.rect);
2959 } else {
2960 theme.partId = partId;
2961 theme.stateId = stateId;
2962 SIZE sz;
2963 pGetThemePartSize(theme.handle(), qt_win_display_dc(), theme.partId, theme.stateId, 0, TS_TRUE, &sz);
2964 if (sz.cx == 0 || sz.cy == 0) {
2965 int iconSize = pixelMetric(PM_SmallIconSize, tb, widget);
2966 QPixmap pm = standardIcon(SP_TitleBarMenuButton, tb, widget).pixmap(iconSize, iconSize);
2967 p->save();
2968 drawItemPixmap(p, theme.rect, Qt::AlignCenter, pm);
2969 p->restore();
2970 } else {
2971 d->drawBackground(theme);
2972 }
2973 }
2974 }
2975
2976 if (sub & SC_TitleBarMinButton && tb->titleBarFlags & Qt::WindowMinimizeButtonHint
2977 && !(tb->titleBarState & Qt::WindowMinimized)) {
2978 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarMinButton, widget);
2979 partId = WP_MINBUTTON;
2980 if (widget && !widget->isEnabled())
2981 stateId = MINBS_DISABLED;
2982 else if (option->activeSubControls == SC_TitleBarMinButton && (option->state & State_Sunken))
2983 stateId = MINBS_PUSHED;
2984 else if (option->activeSubControls == SC_TitleBarMinButton && (option->state & State_MouseOver))
2985 stateId = MINBS_HOT;
2986 else if (!isActive)
2987 stateId = MINBS_INACTIVE;
2988 else
2989 stateId = MINBS_NORMAL;
2990 theme.partId = partId;
2991 theme.stateId = stateId;
2992 d->drawBackground(theme);
2993 }
2994 if (sub & SC_TitleBarMaxButton && tb->titleBarFlags & Qt::WindowMaximizeButtonHint
2995 && !(tb->titleBarState & Qt::WindowMaximized)) {
2996 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarMaxButton, widget);
2997 partId = WP_MAXBUTTON;
2998 if (widget && !widget->isEnabled())
2999 stateId = MAXBS_DISABLED;
3000 else if (option->activeSubControls == SC_TitleBarMaxButton && (option->state & State_Sunken))
3001 stateId = MAXBS_PUSHED;
3002 else if (option->activeSubControls == SC_TitleBarMaxButton && (option->state & State_MouseOver))
3003 stateId = MAXBS_HOT;
3004 else if (!isActive)
3005 stateId = MAXBS_INACTIVE;
3006 else
3007 stateId = MAXBS_NORMAL;
3008 theme.partId = partId;
3009 theme.stateId = stateId;
3010 d->drawBackground(theme);
3011 }
3012 if (sub & SC_TitleBarContextHelpButton
3013 && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
3014 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarContextHelpButton, widget);
3015 partId = WP_HELPBUTTON;
3016 if (widget && !widget->isEnabled())
3017 stateId = MINBS_DISABLED;
3018 else if (option->activeSubControls == SC_TitleBarContextHelpButton && (option->state & State_Sunken))
3019 stateId = MINBS_PUSHED;
3020 else if (option->activeSubControls == SC_TitleBarContextHelpButton && (option->state & State_MouseOver))
3021 stateId = MINBS_HOT;
3022 else if (!isActive)
3023 stateId = MINBS_INACTIVE;
3024 else
3025 stateId = MINBS_NORMAL;
3026 theme.partId = partId;
3027 theme.stateId = stateId;
3028 d->drawBackground(theme);
3029 }
3030 bool drawNormalButton = (sub & SC_TitleBarNormalButton)
3031 && (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
3032 && (tb->titleBarState & Qt::WindowMinimized))
3033 || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
3034 && (tb->titleBarState & Qt::WindowMaximized)));
3035 if (drawNormalButton) {
3036 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarNormalButton, widget);
3037 partId = WP_RESTOREBUTTON;
3038 if (widget && !widget->isEnabled())
3039 stateId = RBS_DISABLED;
3040 else if (option->activeSubControls == SC_TitleBarNormalButton && (option->state & State_Sunken))
3041 stateId = RBS_PUSHED;
3042 else if (option->activeSubControls == SC_TitleBarNormalButton && (option->state & State_MouseOver))
3043 stateId = RBS_HOT;
3044 else if (!isActive)
3045 stateId = RBS_INACTIVE;
3046 else
3047 stateId = RBS_NORMAL;
3048 theme.partId = partId;
3049 theme.stateId = stateId;
3050 d->drawBackground(theme);
3051 }
3052 if (sub & SC_TitleBarShadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
3053 && !(tb->titleBarState & Qt::WindowMinimized)) {
3054 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarShadeButton, widget);
3055 partId = WP_MINBUTTON;
3056 if (widget && !widget->isEnabled())
3057 stateId = MINBS_DISABLED;
3058 else if (option->activeSubControls == SC_TitleBarShadeButton && (option->state & State_Sunken))
3059 stateId = MINBS_PUSHED;
3060 else if (option->activeSubControls == SC_TitleBarShadeButton && (option->state & State_MouseOver))
3061 stateId = MINBS_HOT;
3062 else if (!isActive)
3063 stateId = MINBS_INACTIVE;
3064 else
3065 stateId = MINBS_NORMAL;
3066 theme.partId = partId;
3067 theme.stateId = stateId;
3068 d->drawBackground(theme);
3069 }
3070 if (sub & SC_TitleBarUnshadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
3071 && tb->titleBarState & Qt::WindowMinimized) {
3072 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarUnshadeButton, widget);
3073 partId = WP_RESTOREBUTTON;
3074 if (widget && !widget->isEnabled())
3075 stateId = RBS_DISABLED;
3076 else if (option->activeSubControls == SC_TitleBarUnshadeButton && (option->state & State_Sunken))
3077 stateId = RBS_PUSHED;
3078 else if (option->activeSubControls == SC_TitleBarUnshadeButton && (option->state & State_MouseOver))
3079 stateId = RBS_HOT;
3080 else if (!isActive)
3081 stateId = RBS_INACTIVE;
3082 else
3083 stateId = RBS_NORMAL;
3084 theme.partId = partId;
3085 theme.stateId = stateId;
3086 d->drawBackground(theme);
3087 }
3088 if (sub & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
3089 theme.rect = subControlRect(CC_TitleBar, option, SC_TitleBarCloseButton, widget);
3090 //partId = titlebar->testWFlags(Qt::WA_WState_Tool) ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
3091 partId = WP_CLOSEBUTTON;
3092 if (widget && !widget->isEnabled())
3093 stateId = CBS_DISABLED;
3094 else if (option->activeSubControls == SC_TitleBarCloseButton && (option->state & State_Sunken))
3095 stateId = CBS_PUSHED;
3096 else if (option->activeSubControls == SC_TitleBarCloseButton && (option->state & State_MouseOver))
3097 stateId = CBS_HOT;
3098 else if (!isActive)
3099 stateId = CBS_INACTIVE;
3100 else
3101 stateId = CBS_NORMAL;
3102 theme.partId = partId;
3103 theme.stateId = stateId;
3104 d->drawBackground(theme);
3105 }
3106 }
3107 }
3108 break;
3109
3110#ifndef QT_NO_WORKSPACE
3111 case CC_MdiControls:
3112 {
3113 QRect buttonRect;
3114 XPThemeData theme(widget, p, QLatin1String("WINDOW"), WP_MDICLOSEBUTTON, CBS_NORMAL);
3115
3116 if (option->subControls & SC_MdiCloseButton) {
3117 buttonRect = subControlRect(CC_MdiControls, option, SC_MdiCloseButton, widget);
3118 if (theme.isValid()) {
3119 theme.partId = WP_MDICLOSEBUTTON;
3120 theme.rect = buttonRect;
3121 if (!(flags & State_Enabled))
3122 theme.stateId = CBS_INACTIVE;
3123 else if (flags & State_Sunken && (option->activeSubControls & SC_MdiCloseButton))
3124 theme.stateId = CBS_PUSHED;
3125 else if (flags & State_MouseOver && (option->activeSubControls & SC_MdiCloseButton))
3126 theme.stateId = CBS_HOT;
3127 else
3128 theme.stateId = CBS_NORMAL;
3129 d->drawBackground(theme);
3130 }
3131 }
3132 if (option->subControls & SC_MdiNormalButton) {
3133 buttonRect = subControlRect(CC_MdiControls, option, SC_MdiNormalButton, widget);
3134 if (theme.isValid()) {
3135 theme.partId = WP_MDIRESTOREBUTTON;
3136 theme.rect = buttonRect;
3137 if (!(flags & State_Enabled))
3138 theme.stateId = CBS_INACTIVE;
3139 else if (flags & State_Sunken && (option->activeSubControls & SC_MdiNormalButton))
3140 theme.stateId = CBS_PUSHED;
3141 else if (flags & State_MouseOver && (option->activeSubControls & SC_MdiNormalButton))
3142 theme.stateId = CBS_HOT;
3143 else
3144 theme.stateId = CBS_NORMAL;
3145 d->drawBackground(theme);
3146 }
3147 }
3148 if (option->subControls & QStyle::SC_MdiMinButton) {
3149 buttonRect = subControlRect(CC_MdiControls, option, SC_MdiMinButton, widget);
3150 if (theme.isValid()) {
3151 theme.partId = WP_MDIMINBUTTON;
3152 theme.rect = buttonRect;
3153 if (!(flags & State_Enabled))
3154 theme.stateId = CBS_INACTIVE;
3155 else if (flags & State_Sunken && (option->activeSubControls & SC_MdiMinButton))
3156 theme.stateId = CBS_PUSHED;
3157 else if (flags & State_MouseOver && (option->activeSubControls & SC_MdiMinButton))
3158 theme.stateId = CBS_HOT;
3159 else
3160 theme.stateId = CBS_NORMAL;
3161 d->drawBackground(theme);
3162 }
3163 }
3164 }
3165 break;
3166#endif //QT_NO_WORKSPACE
3167 default:
3168 QWindowsStyle::drawComplexControl(cc, option, p, widget);
3169 break;
3170 }
3171}
3172
3173/*! \reimp */
3174int QWindowsXPStyle::pixelMetric(PixelMetric pm, const QStyleOption *option, const QWidget *widget) const
3175{
3176 if (!QWindowsXPStylePrivate::useXP())
3177 return QWindowsStyle::pixelMetric(pm, option, widget);
3178
3179 int res = 0;
3180 switch (pm) {
3181 case PM_MenuBarPanelWidth:
3182 res = 0;
3183 break;
3184
3185 case PM_DefaultFrameWidth:
3186 if (qobject_cast<const QListView*>(widget))
3187 res = 2;
3188 else
3189 res = 1;
3190 break;
3191 case PM_MenuPanelWidth:
3192 case PM_SpinBoxFrameWidth:
3193 res = 1;
3194 break;
3195
3196 case PM_TabBarTabOverlap:
3197 case PM_MenuHMargin:
3198 case PM_MenuVMargin:
3199 res = 2;
3200 break;
3201
3202 case PM_TabBarBaseOverlap:
3203 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
3204 switch (tab->shape) {
3205 case QTabBar::RoundedNorth:
3206 case QTabBar::TriangularNorth:
3207 res = 1;
3208 break;
3209 case QTabBar::RoundedSouth:
3210 case QTabBar::TriangularSouth:
3211 res = 2;
3212 break;
3213 case QTabBar::RoundedEast:
3214 case QTabBar::TriangularEast:
3215 res = 3;
3216 break;
3217 case QTabBar::RoundedWest:
3218 case QTabBar::TriangularWest:
3219 res = 1;
3220 break;
3221 }
3222 }
3223 break;
3224
3225 case PM_SplitterWidth:
3226 res = qMax(5, QApplication::globalStrut().width());
3227 break;
3228
3229 case PM_IndicatorWidth:
3230 case PM_IndicatorHeight:
3231 {
3232 XPThemeData theme(widget, 0, QLatin1String("BUTTON"), BP_CHECKBOX, CBS_UNCHECKEDNORMAL);
3233 if (theme.isValid()) {
3234 SIZE size;
3235 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
3236 res = (pm == PM_IndicatorWidth ? size.cx+2 : res = size.cy+2);
3237 }
3238 }
3239 break;
3240
3241 case PM_ExclusiveIndicatorWidth:
3242 case PM_ExclusiveIndicatorHeight:
3243 {
3244 XPThemeData theme(widget, 0, QLatin1String("BUTTON"), BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL);
3245 if (theme.isValid()) {
3246 SIZE size;
3247 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
3248 res = (pm == PM_ExclusiveIndicatorWidth ? size.cx+2 : res = size.cy+2);
3249 }
3250 }
3251 break;
3252
3253 case PM_ProgressBarChunkWidth:
3254 {
3255 Qt::Orientation orient = Qt::Horizontal;
3256 if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option))
3257 orient = pb2->orientation;
3258 XPThemeData theme(widget, 0, QLatin1String("PROGRESS"), (orient == Qt::Horizontal) ? PP_CHUNK : PP_CHUNKVERT);
3259 if (theme.isValid()) {
3260 SIZE size;
3261 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
3262 res = (orient == Qt::Horizontal) ? size.cx : size.cy;
3263 }
3264 }
3265 break;
3266
3267 case PM_SliderThickness:
3268 {
3269 XPThemeData theme(widget, 0, QLatin1String("TRACKBAR"), TKP_THUMB);
3270 if (theme.isValid()) {
3271 SIZE size;
3272 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
3273 res = size.cy;
3274 }
3275 }
3276 break;
3277
3278 case PM_MenuButtonIndicator:
3279 {
3280 XPThemeData theme(widget, 0, QLatin1String("TOOLBAR"), TP_SPLITBUTTONDROPDOWN);
3281 if (theme.isValid()) {
3282 SIZE size;
3283 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
3284 res = size.cx;
3285 }
3286 }
3287 break;
3288
3289 case PM_TitleBarHeight:
3290 {
3291#ifdef QT3_SUPPORT
3292 if (widget && widget->inherits("Q3DockWindowTitleBar")) {
3293 res = GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME);
3294 } else
3295#endif
3296 if (widget && (widget->windowType() == Qt::Tool))
3297 res = GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME);
3298 else
3299 res = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME);
3300 }
3301 break;
3302
3303 case PM_MdiSubWindowFrameWidth:
3304 {
3305 XPThemeData theme(widget, 0, QLatin1String("WINDOW"), WP_FRAMELEFT, FS_ACTIVE);
3306 if (theme.isValid()) {
3307 SIZE size;
3308 pGetThemePartSize(theme.handle(), 0, WP_FRAMELEFT, FS_ACTIVE, 0, TS_TRUE, &size);
3309 res = size.cx-1;
3310 }
3311 }
3312 break;
3313
3314 case PM_MdiSubWindowMinimizedWidth:
3315 res = 160;
3316 break;
3317
3318#ifndef QT_NO_TOOLBAR
3319 case PM_ToolBarHandleExtent:
3320 res = 8;
3321 break;
3322
3323#endif // QT_NO_TOOLBAR
3324 case PM_DockWidgetFrameWidth:
3325 {
3326 XPThemeData theme(widget, 0, QLatin1String("WINDOW"), WP_SMALLFRAMERIGHT, FS_ACTIVE);
3327 if (theme.isValid()) {
3328 SIZE size;
3329 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
3330 res = size.cx;
3331 }
3332 }
3333 break;
3334 case PM_DockWidgetSeparatorExtent:
3335 res = 4;
3336 break;
3337 case PM_DockWidgetTitleMargin:
3338 res = 4;
3339 break;
3340
3341 case PM_ButtonShiftHorizontal:
3342 case PM_ButtonShiftVertical:
3343 if (qstyleoption_cast<const QStyleOptionToolButton *>(option))
3344 res = 1;
3345 else
3346 res = 0;
3347 break;
3348
3349 default:
3350 res = QWindowsStyle::pixelMetric(pm, option, widget);
3351 }
3352
3353 return res;
3354}
3355
3356/*
3357 This function is used by subControlRect to check if a button
3358 should be drawn for the given subControl given a set of window flags.
3359*/
3360static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){
3361
3362 bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
3363 bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
3364 const uint flags = tb->titleBarFlags;
3365 bool retVal = false;
3366 switch (sc) {
3367 case QStyle::SC_TitleBarContextHelpButton:
3368 if (flags & Qt::WindowContextHelpButtonHint)
3369 retVal = true;
3370 break;
3371 case QStyle::SC_TitleBarMinButton:
3372 if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
3373 retVal = true;
3374 break;
3375 case QStyle::SC_TitleBarNormalButton:
3376 if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
3377 retVal = true;
3378 else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
3379 retVal = true;
3380 break;
3381 case QStyle::SC_TitleBarMaxButton:
3382 if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
3383 retVal = true;
3384 break;
3385 case QStyle::SC_TitleBarShadeButton:
3386 if (!isMinimized && flags & Qt::WindowShadeButtonHint)
3387 retVal = true;
3388 break;
3389 case QStyle::SC_TitleBarUnshadeButton:
3390 if (isMinimized && flags & Qt::WindowShadeButtonHint)
3391 retVal = true;
3392 break;
3393 case QStyle::SC_TitleBarCloseButton:
3394 if (flags & Qt::WindowSystemMenuHint)
3395 retVal = true;
3396 break;
3397 case QStyle::SC_TitleBarSysMenu:
3398 if (flags & Qt::WindowSystemMenuHint)
3399 retVal = true;
3400 break;
3401 default :
3402 retVal = true;
3403 }
3404 return retVal;
3405}
3406
3407/*!
3408 \reimp
3409*/
3410QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *option,
3411 SubControl subControl, const QWidget *widget) const
3412{
3413 if (!QWindowsXPStylePrivate::useXP())
3414 return QWindowsStyle::subControlRect(cc, option, subControl, widget);
3415
3416 QRect rect;
3417
3418 switch (cc) {
3419 case CC_TitleBar:
3420 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
3421 if (!buttonVisible(subControl, tb))
3422 return rect;
3423 const bool isToolTitle = false;
3424 const int height = tb->rect.height();
3425 const int width = tb->rect.width();
3426 int buttonHeight = GetSystemMetrics(SM_CYSIZE) - 4;
3427 int buttonWidth = GetSystemMetrics(SM_CXSIZE) - 4;
3428 const int delta = buttonWidth + 2;
3429 int controlTop = option->rect.bottom() - buttonHeight - 2;
3430 const int frameWidth = pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
3431 const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
3432 const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
3433 const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
3434 const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
3435 const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
3436 bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
3437 bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
3438 int offset = 0;
3439
3440 switch (subControl) {
3441 case SC_TitleBarLabel:
3442 rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
3443 if (isToolTitle) {
3444 if (sysmenuHint) {
3445 rect.adjust(0, 0, -buttonWidth - 3, 0);
3446 }
3447 if (minimizeHint || maximizeHint)
3448 rect.adjust(0, 0, -buttonWidth - 2, 0);
3449 } else {
3450 if (sysmenuHint) {
3451 const int leftOffset = height - 8;
3452 rect.adjust(leftOffset, 0, 0, 0);
3453 }
3454 if (minimizeHint)
3455 rect.adjust(0, 0, -buttonWidth - 2, 0);
3456 if (maximizeHint)
3457 rect.adjust(0, 0, -buttonWidth - 2, 0);
3458 if (contextHint)
3459 rect.adjust(0, 0, -buttonWidth - 2, 0);
3460 if (shadeHint)
3461 rect.adjust(0, 0, -buttonWidth - 2, 0);
3462 }
3463 break;
3464
3465 case SC_TitleBarContextHelpButton:
3466 if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
3467 offset += delta;
3468 //fall through
3469 case SC_TitleBarMinButton:
3470 if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
3471 offset += delta;
3472 else if (subControl == SC_TitleBarMinButton)
3473 break;
3474 //fall through
3475 case SC_TitleBarNormalButton:
3476 if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
3477 offset += delta;
3478 else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
3479 offset += delta;
3480 else if (subControl == SC_TitleBarNormalButton)
3481 break;
3482 //fall through
3483 case SC_TitleBarMaxButton:
3484 if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
3485 offset += delta;
3486 else if (subControl == SC_TitleBarMaxButton)
3487 break;
3488 //fall through
3489 case SC_TitleBarShadeButton:
3490 if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
3491 offset += delta;
3492 else if (subControl == SC_TitleBarShadeButton)
3493 break;
3494 //fall through
3495 case SC_TitleBarUnshadeButton:
3496 if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
3497 offset += delta;
3498 else if (subControl == SC_TitleBarUnshadeButton)
3499 break;
3500 //fall through
3501 case SC_TitleBarCloseButton:
3502 if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
3503 offset += delta;
3504 else if (subControl == SC_TitleBarCloseButton)
3505 break;
3506
3507 rect.setRect(width - offset - controlTop + 1, controlTop,
3508 buttonWidth, buttonHeight);
3509 break;
3510
3511 case SC_TitleBarSysMenu:
3512 {
3513 const int controlTop = 6;
3514 const int controlHeight = height - controlTop - 3;
3515 const int iconExtent = pixelMetric(PM_SmallIconSize);
3516 QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
3517 if (tb->icon.isNull())
3518 iconSize = QSize(controlHeight, controlHeight);
3519 int hPad = (controlHeight - iconSize.height())/2;
3520 int vPad = (controlHeight - iconSize.width())/2;
3521 rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
3522 }
3523 break;
3524 }
3525 }
3526 break;
3527
3528 case CC_ComboBox:
3529 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
3530 int x = cmb->rect.x(), y = cmb->rect.y(), wi = cmb->rect.width(), he = cmb->rect.height();
3531 int xpos = x;
3532 xpos += wi - 1 - 16;
3533
3534 switch (subControl) {
3535 case SC_ComboBoxFrame:
3536 rect = cmb->rect;
3537 break;
3538
3539 case SC_ComboBoxArrow:
3540 rect = QRect(xpos, y+1, 16, he-2);
3541 break;
3542
3543 case SC_ComboBoxEditField:
3544 rect = QRect(x+2, y+2, wi-3-16, he-4);
3545 break;
3546
3547 case SC_ComboBoxListBoxPopup:
3548 rect = cmb->rect;
3549 break;
3550 }
3551 }
3552 break;
3553#ifndef QT_NO_WORKSPACE
3554 case CC_MdiControls:
3555 {
3556 int numSubControls = 0;
3557 if (option->subControls & SC_MdiCloseButton)
3558 ++numSubControls;
3559 if (option->subControls & SC_MdiMinButton)
3560 ++numSubControls;
3561 if (option->subControls & SC_MdiNormalButton)
3562 ++numSubControls;
3563 if (numSubControls == 0)
3564 break;
3565
3566 int buttonWidth = option->rect.width()/ numSubControls;
3567 int offset = 0;
3568 switch (subControl) {
3569 case SC_MdiCloseButton:
3570 // Only one sub control, no offset needed.
3571 if (numSubControls == 1)
3572 break;
3573 offset += buttonWidth;
3574 //FALL THROUGH
3575 case SC_MdiNormalButton:
3576 // No offset needed if
3577 // 1) There's only one sub control
3578 // 2) We have a close button and a normal button (offset already added in SC_MdiClose)
3579 if (numSubControls == 1 || (numSubControls == 2 && !(option->subControls & SC_MdiMinButton)))
3580 break;
3581 if (option->subControls & SC_MdiNormalButton)
3582 offset += buttonWidth;
3583 break;
3584 default:
3585 break;
3586 }
3587 rect = QRect(offset, 0, buttonWidth, option->rect.height());
3588 break;
3589 }
3590#endif // QT_NO_WORKSPACE
3591
3592 default:
3593 rect = visualRect(option->direction, option->rect,
3594 QWindowsStyle::subControlRect(cc, option, subControl, widget));
3595 break;
3596 }
3597 return visualRect(option->direction, option->rect, rect);
3598}
3599
3600/*!
3601 \reimp
3602*/
3603QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *option,
3604 const QSize &contentsSize, const QWidget *widget) const
3605{
3606 if (!QWindowsXPStylePrivate::useXP())
3607 return QWindowsStyle::sizeFromContents(ct, option, contentsSize, widget);
3608
3609 QSize sz(contentsSize);
3610 switch (ct) {
3611 case CT_LineEdit:
3612 case CT_ComboBox:
3613 {
3614 HTHEME theme = pOpenThemeData(QWindowsXPStylePrivate::winId(widget), L"Button");
3615 MARGINS borderSize;
3616 if (theme) {
3617 int result = pGetThemeMargins(theme,
3618 NULL,
3619 BP_PUSHBUTTON,
3620 PBS_NORMAL,
3621 TMT_CONTENTMARGINS,
3622 NULL,
3623 &borderSize);
3624 if (result == S_OK) {
3625 sz += QSize(borderSize.cxLeftWidth + borderSize.cxRightWidth - 2,
3626 borderSize.cyBottomHeight + borderSize.cyTopHeight - 2);
3627 }
3628 sz += QSize(23, 0); //arrow button
3629 }
3630 }
3631 break;
3632 case CT_SpinBox:
3633 {
3634 //Spinbox adds frame twice
3635 sz = QWindowsStyle::sizeFromContents(ct, option, contentsSize, widget);
3636 int border = pixelMetric(PM_SpinBoxFrameWidth, option, widget);
3637 sz -= QSize(2*border, 2*border);
3638 }
3639 break;
3640 case CT_TabWidget:
3641 sz += QSize(6, 6);
3642 break;
3643 case CT_Menu:
3644 sz += QSize(1, 0);
3645 break;
3646#ifndef QT_NO_MENUBAR
3647 case CT_MenuBarItem:
3648 if (!sz.isEmpty())
3649 sz += QSize(windowsItemHMargin * 5 + 1, 6);
3650 break;
3651#endif
3652 case CT_MenuItem:
3653 if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
3654 {
3655 if (menuitem->menuItemType != QStyleOptionMenuItem::Separator) {
3656 sz = QWindowsStyle::sizeFromContents(ct, option, sz, widget);
3657 sz.setHeight(sz.height() - 2);
3658 return sz;
3659 }
3660 }
3661 sz = QWindowsStyle::sizeFromContents(ct, option, sz, widget);
3662 break;
3663
3664 case CT_MdiControls:
3665 if (const QStyleOptionComplex *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(option)) {
3666 int width = 0;
3667 if (styleOpt->subControls & SC_MdiMinButton)
3668 width += 17 + 1;
3669 if (styleOpt->subControls & SC_MdiNormalButton)
3670 width += 17 + 1;
3671 if (styleOpt->subControls & SC_MdiCloseButton)
3672 width += 17 + 1;
3673 sz = QSize(width, 19);
3674 } else {
3675 sz = QSize(54, 19);
3676 }
3677 break;
3678
3679 default:
3680 sz = QWindowsStyle::sizeFromContents(ct, option, sz, widget);
3681 break;
3682 }
3683
3684 return sz;
3685}
3686
3687
3688/*! \reimp */
3689int QWindowsXPStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
3690 QStyleHintReturn *returnData) const
3691{
3692 QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
3693 if (!QWindowsXPStylePrivate::useXP())
3694 return QWindowsStyle::styleHint(hint, option, widget, returnData);
3695
3696 int res = 0;
3697 switch (hint) {
3698
3699 case SH_EtchDisabledText:
3700 res = (qobject_cast<const QLabel*>(widget) != 0);
3701 break;
3702
3703 case SH_SpinControls_DisableOnBounds:
3704 res = 0;
3705 break;
3706
3707 case SH_TitleBar_AutoRaise:
3708 case SH_TitleBar_NoBorder:
3709 res = 1;
3710 break;
3711
3712 case SH_GroupBox_TextLabelColor:
3713 if (!widget || (widget && widget->isEnabled()))
3714 res = d->groupBoxTextColor;
3715 else
3716 res = d->groupBoxTextColorDisabled;
3717 break;
3718
3719 case SH_Table_GridLineColor:
3720 res = 0xC0C0C0;
3721 break;
3722
3723 case SH_WindowFrame_Mask:
3724 {
3725 res = 1;
3726 QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData);
3727 const QStyleOptionTitleBar *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option);
3728 if (mask && titlebar) {
3729 XPThemeData themeData;
3730 if (titlebar->titleBarState & Qt::WindowMinimized) {
3731 themeData = XPThemeData(widget, 0, QLatin1String("WINDOW"), WP_MINCAPTION, CS_ACTIVE, option->rect);
3732 } else
3733 themeData = XPThemeData(widget, 0, QLatin1String("WINDOW"), WP_CAPTION, CS_ACTIVE, option->rect);
3734 mask->region = d->region(themeData);
3735 }
3736 }
3737 break;
3738#ifndef QT_NO_RUBBERBAND
3739 case SH_RubberBand_Mask:
3740 if (qstyleoption_cast<const QStyleOptionRubberBand *>(option)) {
3741 res = 0;
3742 break;
3743 }
3744#endif // QT_NO_RUBBERBAND
3745
3746 case SH_ItemView_DrawDelegateFrame:
3747 res = 1;
3748 break;
3749
3750 default:
3751 res =QWindowsStyle::styleHint(hint, option, widget, returnData);
3752 }
3753
3754 return res;
3755}
3756
3757/*! \reimp */
3758QPalette QWindowsXPStyle::standardPalette() const
3759{
3760 if (QWindowsXPStylePrivate::useXP() && QApplicationPrivate::sys_pal)
3761 return *QApplicationPrivate::sys_pal;
3762 else
3763 return QWindowsStyle::standardPalette();
3764}
3765
3766/*!
3767 \reimp
3768*/
3769QPixmap QWindowsXPStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option,
3770 const QWidget *widget) const
3771{
3772 if (!QWindowsXPStylePrivate::useXP())
3773 return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
3774
3775 switch(standardPixmap) {
3776 case SP_TitleBarMaxButton:
3777 case SP_TitleBarCloseButton:
3778 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
3779 {
3780 if (widget && widget->isWindow()) {
3781 XPThemeData theme(widget, 0, QLatin1String("WINDOW"), WP_SMALLCLOSEBUTTON, CBS_NORMAL);
3782 if (theme.isValid()) {
3783 SIZE sz;
3784 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &sz);
3785 return QIcon(QWindowsStyle::standardPixmap(standardPixmap, option, widget)).pixmap(QSize(sz.cx, sz.cy));
3786 }
3787 }
3788 }
3789 break;
3790 }
3791 return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
3792}
3793
3794/*!
3795 \internal
3796*/
3797QIcon QWindowsXPStyle::standardIconImplementation(StandardPixmap standardIcon,
3798 const QStyleOption *option,
3799 const QWidget *widget) const
3800{
3801 if (!QWindowsXPStylePrivate::useXP()) {
3802 return QWindowsStyle::standardIconImplementation(standardIcon, option, widget);
3803 }
3804
3805 QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
3806 switch(standardIcon) {
3807 case SP_TitleBarMaxButton:
3808 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
3809 {
3810 if (d->dockFloat.isNull()) {
3811 XPThemeData themeSize(0, 0, QLatin1String("WINDOW"), WP_SMALLCLOSEBUTTON, CBS_NORMAL);
3812 XPThemeData theme(0, 0, QLatin1String("WINDOW"), WP_MAXBUTTON, MAXBS_NORMAL);
3813 if (theme.isValid()) {
3814 SIZE size;
3815 pGetThemePartSize(themeSize.handle(), 0, themeSize.partId, themeSize.stateId, 0, TS_TRUE, &size);
3816 QPixmap pm = QPixmap(size.cx, size.cy);
3817 pm.fill(Qt::transparent);
3818 QPainter p(&pm);
3819 theme.painter = &p;
3820 theme.rect = QRect(0, 0, size.cx, size.cy);
3821 d->drawBackground(theme);
3822 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
3823 pm.fill(Qt::transparent);
3824 theme.stateId = MAXBS_PUSHED;
3825 d->drawBackground(theme);
3826 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
3827 pm.fill(Qt::transparent);
3828 theme.stateId = MAXBS_HOT;
3829 d->drawBackground(theme);
3830 d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
3831 pm.fill(Qt::transparent);
3832 theme.stateId = MAXBS_INACTIVE;
3833 d->drawBackground(theme);
3834 d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
3835 }
3836 }
3837 if (widget && widget->isWindow())
3838 return d->dockFloat;
3839
3840 }
3841 break;
3842 case SP_TitleBarCloseButton:
3843 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
3844 {
3845 if (d->dockClose.isNull()) {
3846 XPThemeData theme(0, 0, QLatin1String("WINDOW"), WP_SMALLCLOSEBUTTON, CBS_NORMAL);
3847 if (theme.isValid()) {
3848 SIZE size;
3849 pGetThemePartSize(theme.handle(), 0, theme.partId, theme.stateId, 0, TS_TRUE, &size);
3850 QPixmap pm = QPixmap(size.cx, size.cy);
3851 pm.fill(Qt::transparent);
3852 QPainter p(&pm);
3853 theme.painter = &p;
3854 theme.partId = WP_CLOSEBUTTON; // ####
3855 theme.rect = QRect(0, 0, size.cx, size.cy);
3856 d->drawBackground(theme);
3857 d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
3858 pm.fill(Qt::transparent);
3859 theme.stateId = CBS_PUSHED;
3860 d->drawBackground(theme);
3861 d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
3862 pm.fill(Qt::transparent);
3863 theme.stateId = CBS_HOT;
3864 d->drawBackground(theme);
3865 d->dockClose.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
3866 pm.fill(Qt::transparent);
3867 theme.stateId = CBS_INACTIVE;
3868 d->drawBackground(theme);
3869 d->dockClose.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
3870 }
3871 }
3872 if (widget && widget->isWindow())
3873 return d->dockClose;
3874 }
3875 break;
3876 case SP_TitleBarNormalButton:
3877 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
3878 {
3879 if (d->dockFloat.isNull()) {
3880 XPThemeData themeSize(0, 0, QLatin1String("WINDOW"), WP_SMALLCLOSEBUTTON, CBS_NORMAL);
3881 XPThemeData theme(0, 0, QLatin1String("WINDOW"), WP_RESTOREBUTTON, RBS_NORMAL);
3882 if (theme.isValid()) {
3883 SIZE size;
3884 pGetThemePartSize(themeSize.handle(), 0, themeSize.partId, themeSize.stateId, 0, TS_TRUE, &size);
3885 QPixmap pm = QPixmap(size.cx, size.cy);
3886 pm.fill(Qt::transparent);
3887 QPainter p(&pm);
3888 theme.painter = &p;
3889 theme.rect = QRect(0, 0, size.cx, size.cy);
3890 d->drawBackground(theme);
3891 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
3892 pm.fill(Qt::transparent);
3893 theme.stateId = RBS_PUSHED;
3894 d->drawBackground(theme);
3895 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
3896 pm.fill(Qt::transparent);
3897 theme.stateId = RBS_HOT;
3898 d->drawBackground(theme);
3899 d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
3900 pm.fill(Qt::transparent);
3901 theme.stateId = RBS_INACTIVE;
3902 d->drawBackground(theme);
3903 d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
3904 }
3905 }
3906 if (widget && widget->isWindow())
3907 return d->dockFloat;
3908
3909 }
3910 break;
3911 }
3912
3913 return QWindowsStyle::standardIconImplementation(standardIcon, option, widget);
3914}
3915
3916/*!
3917 \internal
3918
3919 Constructs a QWindowsXPStyle object.
3920*/
3921QWindowsXPStyle::QWindowsXPStyle(QWindowsXPStylePrivate &dd) : QWindowsStyle(dd)
3922{
3923}
3924
3925
3926// Debugging code ---------------------------------------------------------------------[ START ]---
3927// The code for this point on is not compiled by default, but only used as assisting
3928// debugging code when you uncomment the DEBUG_XP_STYLE define at the top of the file.
3929
3930#ifdef DEBUG_XP_STYLE
3931// The schema file expects these to be defined by the user.
3932#define TMT_ENUMDEF 8
3933#define TMT_ENUMVAL TEXT('A')
3934#define TMT_ENUM TEXT('B')
3935#define SCHEMA_STRINGS // For 2nd pass on schema file
3936QT_BEGIN_INCLUDE_NAMESPACE
3937#include <tmschema.h>
3938QT_END_INCLUDE_NAMESPACE
3939
3940// A property's value, type and name combo
3941struct PropPair {
3942 int propValue;
3943 int propType;
3944 LPCWSTR propName;
3945};
3946
3947// Operator for sorting of PropPairs
3948bool operator<(PropPair a, PropPair b) {
3949 return wcscmp(a.propName, b.propName) < 0;
3950}
3951
3952// Our list of all possible properties
3953static QList<PropPair> all_props;
3954
3955
3956/*! \internal
3957 Dumps a portion of the full native DIB section double buffer.
3958 The DIB section double buffer is only used when doing special
3959 transformations to the theme part, or when the real double
3960 buffer in the paintengine does not have an HDC we may use
3961 directly.
3962 Since we cannot rely on the pixel data we get from Microsoft
3963 when drawing into the DIB section, we use this function to
3964 see the actual data we got, and can determin the appropriate
3965 action.
3966*/
3967void QWindowsXPStylePrivate::dumpNativeDIB(int w, int h)
3968{
3969 if (w && h) {
3970 static int pCount = 0;
3971 DWORD *bufPix = (DWORD*)bufferPixels;
3972
3973 char *bufferDump = new char[bufferH * bufferW * 16];
3974 char *bufferPos = bufferDump;
3975
3976 memset(bufferDump, 0, sizeof(bufferDump));
3977 bufferPos += sprintf(bufferPos, "const int pixelBufferW%d = %d;\n", pCount, w);
3978 bufferPos += sprintf(bufferPos, "const int pixelBufferH%d = %d;\n", pCount, h);
3979 bufferPos += sprintf(bufferPos, "const unsigned DWORD pixelBuffer%d[] = {", pCount);
3980 for (int iy = 0; iy < h; ++iy) {
3981 bufferPos += sprintf(bufferPos, "\n ");
3982 bufPix = (DWORD*)(bufferPixels + (iy * bufferW * 4));
3983 for (int ix = 0; ix < w; ++ix) {
3984 bufferPos += sprintf(bufferPos, "0x%08x, ", *bufPix);
3985 ++bufPix;
3986 }
3987 }
3988 bufferPos += sprintf(bufferPos, "\n};\n\n");
3989 printf(bufferDump);
3990
3991 delete bufferDump;
3992 ++pCount;
3993 }
3994}
3995
3996/*! \internal
3997 Shows the value of a given property for a part.
3998*/
3999static void showProperty(XPThemeData &themeData, const PropPair &prop)
4000{
4001 PROPERTYORIGIN origin = PO_NOTFOUND;
4002 pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
4003 const char *originStr;
4004 switch(origin) {
4005 case PO_STATE:
4006 originStr = "State ";
4007 break;
4008 case PO_PART:
4009 originStr = "Part ";
4010 break;
4011 case PO_CLASS:
4012 originStr = "Class ";
4013 break;
4014 case PO_GLOBAL:
4015 originStr = "Globl ";
4016 break;
4017 case PO_NOTFOUND:
4018 default:
4019 originStr = "Unkwn ";
4020 break;
4021 }
4022
4023 switch(prop.propType) {
4024 case TMT_STRING:
4025 {
4026 wchar_t buffer[512];
4027 pGetThemeString(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, buffer, 512);
4028 printf(" (%sString) %-20S: %S\n", originStr, prop.propName, buffer);
4029 }
4030 break;
4031 case TMT_ENUM:
4032 {
4033 int result = -1;
4034 pGetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
4035 printf(" (%sEnum) %-20S: %d\n", originStr, prop.propName, result);
4036 }
4037 break;
4038 case TMT_INT:
4039 {
4040 int result = -1;
4041 pGetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
4042 printf(" (%sint) %-20S: %d\n", originStr, prop.propName, result);
4043 }
4044 break;
4045 case TMT_BOOL:
4046 {
4047 BOOL result = false;
4048 pGetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
4049 printf(" (%sbool) %-20S: %d\n", originStr, prop.propName, result);
4050 }
4051 break;
4052 case TMT_COLOR:
4053 {
4054 COLORREF result = 0;
4055 pGetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
4056 printf(" (%scolor) %-20S: 0x%08X\n", originStr, prop.propName, result);
4057 }
4058 break;
4059 case TMT_MARGINS:
4060 {
4061 MARGINS result;
4062 memset(&result, 0, sizeof(result));
4063 pGetThemeMargins(themeData.handle(), 0, themeData.partId, themeData.stateId, prop.propValue, 0, &result);
4064 printf(" (%smargins) %-20S: (%d, %d, %d, %d)\n", originStr,
4065 prop.propName, result.cxLeftWidth, result.cyTopHeight, result.cxRightWidth, result.cyBottomHeight);
4066 }
4067 break;
4068 case TMT_FILENAME:
4069 {
4070 wchar_t buffer[512];
4071 pGetThemeFilename(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, buffer, 512);
4072 printf(" (%sfilename)%-20S: %S\n", originStr, prop.propName, buffer);
4073 }
4074 break;
4075 case TMT_SIZE:
4076 {
4077 SIZE result1;
4078 SIZE result2;
4079 SIZE result3;
4080 memset(&result1, 0, sizeof(result1));
4081 memset(&result2, 0, sizeof(result2));
4082 memset(&result3, 0, sizeof(result3));
4083 pGetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_MIN, &result1);
4084 pGetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_TRUE, &result2);
4085 pGetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_DRAW, &result3);
4086 printf(" (%ssize) %-20S: Min (%d, %d), True(%d, %d), Draw(%d, %d)\n", originStr, prop.propName,
4087 result1.cx, result1.cy, result2.cx, result2.cy, result3.cx, result3.cy);
4088 }
4089 break;
4090 case TMT_POSITION:
4091 {
4092 POINT result;
4093 memset(&result, 0, sizeof(result));
4094 pGetThemePosition(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
4095 printf(" (%sPosition)%-20S: (%d, %d)\n", originStr, prop.propName, result.x, result.y);
4096 }
4097 break;
4098 case TMT_RECT:
4099 {
4100 RECT result;
4101 memset(&result, 0, sizeof(result));
4102 pGetThemeRect(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
4103 printf(" (%sRect) %-20S: (%d, %d, %d, %d)\n", originStr, prop.propName, result.left, result.top, result.right, result.bottom);
4104 }
4105 break;
4106 case TMT_FONT:
4107 {
4108 LOGFONT result;
4109 memset(&result, 0, sizeof(result));
4110 pGetThemeFont(themeData.handle(), 0, themeData.partId, themeData.stateId, prop.propValue, &result);
4111 printf(" (%sFont) %-20S: %S height(%d) width(%d) weight(%d)\n", originStr, prop.propName,
4112 result.lfFaceName, result.lfHeight, result.lfWidth, result.lfWeight);
4113 }
4114 break;
4115 case TMT_INTLIST:
4116 {
4117 INTLIST result;
4118 memset(&result, 0, sizeof(result));
4119 pGetThemeIntList(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
4120 printf(" (%sInt list)%-20S: { ", originStr, prop.propName);
4121 for (int i = 0; i < result.iValueCount; ++i)
4122 printf("%d ", result.iValues[i]);
4123 printf("}\n");
4124 }
4125 break;
4126 default:
4127 printf(" %s%S : Unknown property type (%d)!\n", originStr, prop.propName, prop.propType);
4128 }
4129}
4130
4131/*! \internal
4132 Dump all valid properties for a part.
4133 If it's the first time this function is called, then the name,
4134 enum value and documentation of all properties are shown, as
4135 well as all global properties.
4136*/
4137void QWindowsXPStylePrivate::showProperties(XPThemeData &themeData)
4138{
4139 if (!all_props.count()) {
4140 const TMSCHEMAINFO *infoTable = GetSchemaInfo();
4141 for (int i = 0; i < infoTable->iPropCount; ++i) {
4142 int propType = infoTable->pPropTable[i].bPrimVal;
4143 int propValue = infoTable->pPropTable[i].sEnumVal;
4144 LPCWSTR propName = infoTable->pPropTable[i].pszName;
4145
4146 switch(propType) {
4147 case TMT_ENUMDEF:
4148 case TMT_ENUMVAL:
4149 continue;
4150 default:
4151 if (propType != propValue) {
4152 PropPair prop;
4153 prop.propValue = propValue;
4154 prop.propName = propName;
4155 prop.propType = propType;
4156 all_props.append(prop);
4157 }
4158 }
4159 }
4160 qSort(all_props);
4161
4162 {// List all properties
4163 printf("part properties count = %d:\n", all_props.count());
4164 printf(" Enum Property Name Description\n");
4165 printf("-----------------------------------------------------------\n");
4166 wchar_t themeName[256];
4167 pGetCurrentThemeName(themeName, 256, 0, 0, 0, 0);
4168 for (int j = 0; j < all_props.count(); ++j) {
4169 PropPair prop = all_props.at(j);
4170 wchar_t buf[500];
4171 pGetThemeDocumentationProperty(themeName, prop.propName, buf, 500);
4172 printf("%3d: (%4d) %-20S %S\n", j, prop.propValue, prop.propName, buf);
4173 }
4174 }
4175
4176 {// Show Global values
4177 printf("Global Properties:\n");
4178 for (int j = 0; j < all_props.count(); ++j) {
4179 PropPair prop = all_props.at(j);
4180 PROPERTYORIGIN origin = PO_NOTFOUND;
4181 pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
4182 if (origin == PO_GLOBAL) {
4183 showProperty(themeData, prop);
4184 }
4185 }
4186 }
4187 }
4188
4189 for (int j = 0; j < all_props.count(); ++j) {
4190 PropPair prop = all_props.at(j);
4191 PROPERTYORIGIN origin = PO_NOTFOUND;
4192 pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
4193 if (origin != PO_NOTFOUND)
4194 {
4195 showProperty(themeData, prop);
4196 }
4197 }
4198}
4199#endif
4200// Debugging code -----------------------------------------------------------------------[ END ]---
4201
4202
4203QT_END_NAMESPACE
4204
4205#endif //QT_NO_WINDOWSXP
Note: See TracBrowser for help on using the repository browser.