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

Last change on this file since 1147 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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