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