Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwindowsvistastyle.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
8#include <qscreen.h>
9#include <qstylehints.h>
10#include <qwindow.h>
11#include <private/qstyleanimation_p.h>
12#include <private/qstylehelper_p.h>
13#include <qpa/qplatformnativeinterface.h>
14#include <private/qapplication_p.h>
15#include <private/qsystemlibrary_p.h>
16
17#include "qdrawutil.h" // for now
18#include <qbackingstore.h>
19
20
22
23using namespace Qt::StringLiterals;
24
25static const int windowsItemFrame = 2; // menu item frame width
26static const int windowsItemHMargin = 3; // menu item hor text margin
27static const int windowsItemVMargin = 4; // menu item ver text margin
28static const int windowsArrowHMargin = 6; // arrow horizontal margin
29static const int windowsRightBorder = 15; // right border on windows
30
31#ifndef TMT_CONTENTMARGINS
32# define TMT_CONTENTMARGINS 3602
33#endif
34#ifndef TMT_SIZINGMARGINS
35# define TMT_SIZINGMARGINS 3601
36#endif
37#ifndef LISS_NORMAL
38# define LISS_NORMAL 1
39# define LISS_HOT 2
40# define LISS_SELECTED 3
41# define LISS_DISABLED 4
42# define LISS_SELECTEDNOTFOCUS 5
43# define LISS_HOTSELECTED 6
44#endif
45#ifndef BP_COMMANDLINK
46# define BP_COMMANDLINK 6
47# define BP_COMMANDLINKGLYPH 7
48# define CMDLGS_NORMAL 1
49# define CMDLGS_HOT 2
50# define CMDLGS_PRESSED 3
51# define CMDLGS_DISABLED 4
52#endif
53
54/* \internal
55 Checks if we should use Vista style , or if we should
56 fall back to Windows style.
57*/
58// Theme names matching the QWindowsVistaStylePrivate::Theme enumeration.
60{
61 L"BUTTON", L"COMBOBOX", L"EDIT", L"HEADER", L"LISTVIEW",
62 L"MENU", L"PROGRESS", L"REBAR", L"SCROLLBAR", L"SPIN",
63 L"TAB", L"TASKDIALOG", L"TOOLBAR", L"TOOLTIP", L"TRACKBAR",
64 L"WINDOW", L"STATUS", L"TREEVIEW"
65};
66
67// QWindowsVistaStylePrivate -------------------------------------------------------------------------
68// Static initializations
69HWND QWindowsVistaStylePrivate::m_vistaTreeViewHelper = nullptr;
70HTHEME QWindowsVistaStylePrivate::m_themes[NThemes];
71bool QWindowsVistaStylePrivate::useVistaTheme = false;
72Q_CONSTINIT QBasicAtomicInt QWindowsVistaStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting
73
74static void qt_add_rect(HRGN &winRegion, QRect r)
75{
76 HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
77 if (rgn) {
78 HRGN dest = CreateRectRgn(0,0,0,0);
79 int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
80 if (result) {
81 DeleteObject(winRegion);
82 winRegion = dest;
83 }
84 DeleteObject(rgn);
85 }
86}
87
88static HRGN qt_hrgn_from_qregion(const QRegion &region)
89{
90 HRGN hRegion = CreateRectRgn(0,0,0,0);
91 if (region.rectCount() == 1) {
92 qt_add_rect(hRegion, region.boundingRect());
93 return hRegion;
94 }
95 for (const QRect &rect : region)
96 qt_add_rect(hRegion, rect);
97 return hRegion;
98}
99
101{
102 if (const auto *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
104 return Qt::Horizontal;
105}
106
107/* In order to obtain the correct VistaTreeViewTheme (arrows for PE_IndicatorBranch),
108 * we need to set the windows "explorer" theme explicitly on a native
109 * window and open the "TREEVIEW" theme handle passing its window handle
110 * in order to get Vista-style item view themes (particularly drawBackground()
111 * for selected items needs this).
112 * We invoke a service of the native Windows interface to create
113 * a non-visible window handle, open the theme on it and insert it into
114 * the cache so that it is found by QWindowsThemeData::handle() first.
115 */
116static inline HWND createTreeViewHelperWindow()
117{
119
120 HWND result = nullptr;
121 if (auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration()))
122 result = nativeWindowsApp->createMessageWindow(QStringLiteral("QTreeViewThemeHelperWindowClass"),
123 QStringLiteral("QTreeViewThemeHelperWindow"));
124 return result;
125}
126
128
129static inline TransformType transformType(const QTransform &transform, qreal devicePixelRatio)
130{
132 return SimpleTransform;
133 if (transform.type() > QTransform::TxScale)
134 return ComplexTransform;
135 return qFuzzyCompare(transform.m11(), devicePixelRatio)
136 && qFuzzyCompare(transform.m22(), devicePixelRatio)
138}
139
140// QTBUG-60571: Exclude known fully opaque theme parts which produce values
141// invalid in ARGB32_Premultiplied (for example, 0x00ffffff).
142static inline bool isFullyOpaque(const QWindowsThemeData &themeData)
143{
144 return themeData.theme == QWindowsVistaStylePrivate::TaskDialogTheme && themeData.partId == TDLG_PRIMARYPANEL;
145}
146
147static inline QRectF scaleRect(const QRectF &r, qreal factor)
148{
149 return r.isValid() && factor > 1
150 ? QRectF(r.topLeft() * factor, r.size() * factor) : r;
151}
152
153static QRegion scaleRegion(const QRegion &region, qreal factor)
154{
155 if (region.isEmpty() || qFuzzyCompare(factor, qreal(1)))
156 return region;
158 for (const QRect &rect : region)
159 result += QRectF(QPointF(rect.topLeft()) * factor, QSizeF(rect.size() * factor)).toRect();
160 return result;
161}
162
163
164/* \internal
165 Checks if the theme engine can/should be used, or if we should fall back
166 to Windows style. For Windows 10, this will still return false for the
167 High Contrast themes.
168*/
170{
171 if (update)
172 useVistaTheme = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance());
173 return useVistaTheme;
174}
175
176/* \internal
177 Handles refcounting, and queries the theme engine for usage.
178*/
180{
181 if (ref.ref() && !force)
182 return;
183 if (!force) // -1 based atomic refcounting
184 ref.ref();
185
186 useVista(true);
187 std::fill(m_themes, m_themes + NThemes, nullptr);
188}
189
190/* \internal
191 Cleans up all static data.
192*/
194{
195 if (bufferBitmap) {
196 if (bufferDC && nullBitmap)
197 SelectObject(bufferDC, nullBitmap);
198 DeleteObject(bufferBitmap);
199 bufferBitmap = nullptr;
200 }
201
202 if (bufferDC)
203 DeleteDC(bufferDC);
204 bufferDC = nullptr;
205
206 if (ref.deref() && !force)
207 return;
208 if (!force) // -1 based atomic refcounting
209 ref.deref();
210
211 useVistaTheme = false;
213}
214
216{
217 BOOL animEnabled = false;
218 if (SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0))
219 {
220 if (animEnabled)
221 return true;
222 }
223 return false;
224}
225
227{
228 // We want to call OpenThemeDataForDpi, but it won't link with MinGW (11.2.0), so we
229 // dynamically load this.
230 // Only try to initialize pOpenThemeDataForDpi once. If it fails, it will likely keep failing.
231 static const auto pOpenThemeDataForDpi =
232 reinterpret_cast<decltype(&::OpenThemeDataForDpi)>(
233 QSystemLibrary::resolve(u"uxtheme"_s, "OpenThemeDataForDpi"));
234
235 // If we have screens and the OpenThemeDataForDpi function then use it :).
236 if (pOpenThemeDataForDpi && QGuiApplication::primaryScreen()) {
237 const int dpi = qRound(QGuiApplication::primaryScreen()->handle()->logicalDpi().first);
238 return pOpenThemeDataForDpi(hwnd, name, dpi);
239 }
240
241 // In case of any issues we fall back to use the plain/old OpenThemeData.
242 return OpenThemeData(hwnd, name);
243}
244
246{
247 switch (pm) {
249 return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).width();
251 return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).height();
253 return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).width();
255 return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).height();
263 return widget && (widget->windowType() == Qt::Tool)
264 ? GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME)
265 : GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME);
266 }
268 return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::WindowTheme, WP_FRAMELEFT, FS_ACTIVE).width();
270 return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::WindowTheme, WP_SMALLFRAMERIGHT, FS_ACTIVE).width();
271 default:
272 break;
273 }
274 return QWindowsVistaStylePrivate::InvalidMetric;
275}
276
278{
279 switch (pm) {
281 return 5;
283 return 18;
286 return 0;
288 return 3;
289 default:
290 break;
291 }
292
293 return QWindowsVistaStylePrivate::InvalidMetric;
294}
295
296bool QWindowsVistaStylePrivate::initVistaTreeViewTheming()
297{
298 if (m_vistaTreeViewHelper)
299 return true;
300
301 m_vistaTreeViewHelper = createTreeViewHelperWindow();
302 if (!m_vistaTreeViewHelper) {
303 qWarning("Unable to create the treeview helper window.");
304 return false;
305 }
306 if (FAILED(SetWindowTheme(m_vistaTreeViewHelper, L"explorer", nullptr))) {
307 qErrnoWarning("SetWindowTheme() failed.");
308 cleanupVistaTreeViewTheming();
309 return false;
310 }
311 return true;
312}
313
314void QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming()
315{
316 if (m_vistaTreeViewHelper) {
317 DestroyWindow(m_vistaTreeViewHelper);
318 m_vistaTreeViewHelper = nullptr;
319 }
320}
321
322/* \internal
323 Closes all open theme data handles to ensure that we don't leak
324 resources, and that we don't refer to old handles when for
325 example the user changes the theme style.
326*/
328{
329 for (auto &theme : m_themes) {
330 if (theme) {
331 CloseThemeData(theme);
332 theme = nullptr;
333 }
334 }
335 QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming();
336}
337
338HTHEME QWindowsVistaStylePrivate::createTheme(int theme, HWND hwnd)
339{
340 if (Q_UNLIKELY(theme < 0 || theme >= NThemes || !hwnd)) {
341 qWarning("Invalid parameters #%d, %p", theme, hwnd);
342 return nullptr;
343 }
344 if (!m_themes[theme]) {
345 const wchar_t *name = themeNames[theme];
346 if (theme == VistaTreeViewTheme && QWindowsVistaStylePrivate::initVistaTreeViewTheming())
347 hwnd = QWindowsVistaStylePrivate::m_vistaTreeViewHelper;
348 // Use dpi from primary screen in theme.
349 m_themes[theme] = openThemeForPrimaryScreenDpi(hwnd, name);
350 if (Q_UNLIKELY(!m_themes[theme]))
351 qErrnoWarning("OpenThemeData() failed for theme %d (%s).",
352 theme, qPrintable(themeName(theme)));
353 }
354 return m_themes[theme];
355}
356
358{
359 if (QBackingStore *backingStore = widget->backingStore())
360 return backingStore;
361 if (const QWidget *topLevel = widget->nativeParentWidget())
362 if (QBackingStore *topLevelBackingStore = topLevel->backingStore())
363 return topLevelBackingStore;
364 return nullptr;
365}
366
368{
369 if (QBackingStore *backingStore = backingStoreForWidget(widget)) {
371 if (nativeInterface)
372 return static_cast<HDC>(nativeInterface->nativeResourceForBackingStore(QByteArrayLiteral("getDC"), backingStore));
373 }
374 return nullptr;
375}
376
378{
379 return theme >= 0 && theme < NThemes
381}
382
384{
385 if (!widget)
386 return false;
387 const QWidget *parent1 = widget->parentWidget();
388 // Exclude dialogs or other toplevels parented on item views.
389 if (!parent1 || parent1->isWindow())
390 return false;
391 const QWidget *parent2 = parent1->parentWidget();
392 return parent2 && widget->inherits("QLineEdit")
393 && parent2->inherits("QAbstractItemView");
394}
395
396// Returns whether base color is set for this widget
398{
399 uint resolveMask = option->palette.resolveMask();
400 if (widget) {
401 // Since spin box includes a line edit we need to resolve the palette mask also from
402 // the parent, as while the color is always correct on the palette supplied by panel,
403 // the mask can still be empty. If either mask specifies custom base color, use that.
404#if QT_CONFIG(spinbox)
405 if (const QAbstractSpinBox *spinbox = qobject_cast<QAbstractSpinBox*>(widget->parentWidget()))
406 resolveMask |= spinbox->palette().resolveMask();
407#endif // QT_CONFIG(spinbox)
408 }
409 return (resolveMask & (1 << QPalette::Base)) != 0;
410}
411
419{
420 if (widget) {
421 if (const HWND hwnd = QApplicationPrivate::getHWNDForWidget(const_cast<QWidget *>(widget)))
422 return hwnd;
423 }
424
425 // Find top level with native window (there might be dialogs that do not have one).
426 const auto allWindows = QGuiApplication::allWindows();
427 for (const QWindow *window : allWindows) {
428 if (window->isTopLevel() && window->type() != Qt::Desktop && window->handle() != nullptr)
429 return reinterpret_cast<HWND>(window->winId());
430 }
431
432 return GetDesktopWindow();
433}
434
441{
442 // If we already have a HBITMAP which is of adequate size, just return that
443 if (bufferBitmap) {
444 if (bufferW >= w && bufferH >= h)
445 return bufferBitmap;
446 // Not big enough, discard the old one
447 if (bufferDC && nullBitmap)
448 SelectObject(bufferDC, nullBitmap);
449 DeleteObject(bufferBitmap);
450 bufferBitmap = nullptr;
451 }
452
453 w = qMax(bufferW, w);
454 h = qMax(bufferH, h);
455
456 if (!bufferDC) {
457 HDC displayDC = GetDC(nullptr);
458 bufferDC = CreateCompatibleDC(displayDC);
459 ReleaseDC(nullptr, displayDC);
460 }
461
462 // Define the header
463 BITMAPINFO bmi;
464 memset(&bmi, 0, sizeof(bmi));
465 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
466 bmi.bmiHeader.biWidth = w;
467 bmi.bmiHeader.biHeight = -h;
468 bmi.bmiHeader.biPlanes = 1;
469 bmi.bmiHeader.biBitCount = 32;
470 bmi.bmiHeader.biCompression = BI_RGB;
471
472 // Create the pixmap
473 bufferPixels = nullptr;
474 bufferBitmap = CreateDIBSection(bufferDC, &bmi, DIB_RGB_COLORS, reinterpret_cast<void **>(&bufferPixels), nullptr, 0);
475 GdiFlush();
476 nullBitmap = static_cast<HBITMAP>(SelectObject(bufferDC, bufferBitmap));
477
478 if (Q_UNLIKELY(!bufferBitmap)) {
479 qErrnoWarning("QWindowsVistaStylePrivate::buffer(%dx%d), CreateDIBSection() failed.", w, h);
480 bufferW = 0;
481 bufferH = 0;
482 return nullptr;
483 }
484 if (Q_UNLIKELY(!bufferPixels)) {
485 qErrnoWarning("QWindowsVistaStylePrivate::buffer(%dx%d), CreateDIBSection() did not allocate pixel data.", w, h);
486 bufferW = 0;
487 bufferH = 0;
488 return nullptr;
489 }
490 bufferW = w;
491 bufferH = h;
492#ifdef DEBUG_XP_STYLE
493 qDebug("Creating new dib section (%d, %d)", w, h);
494#endif
495 return bufferBitmap;
496}
497
505{
506 return IsThemeBackgroundPartiallyTransparent(themeData.handle(), themeData.partId,
507 themeData.stateId);
508}
509
510
515{
516 HRGN hRgn = nullptr;
517 const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(themeData.widget);
518 RECT rect = themeData.toRECT(QRect(themeData.rect.topLeft() / factor, themeData.rect.size() / factor));
519 if (!SUCCEEDED(GetThemeBackgroundRegion(themeData.handle(), bufferHDC(), themeData.partId,
520 themeData.stateId, &rect, &hRgn))) {
521 return QRegion();
522 }
523
524 HRGN dest = CreateRectRgn(0, 0, 0, 0);
525 const bool success = CombineRgn(dest, hRgn, nullptr, RGN_COPY) != ERROR;
526
528
529 if (success) {
531 RGNDATA *rd = reinterpret_cast<RGNDATA *>(buf.data());
532 if (GetRegionData(dest, buf.size(), rd) == 0) {
533 const auto numBytes = GetRegionData(dest, 0, nullptr);
534 if (numBytes > 0) {
535 buf.resize(numBytes);
536 rd = reinterpret_cast<RGNDATA *>(buf.data());
537 if (GetRegionData(dest, numBytes, rd) == 0)
538 rd = nullptr;
539 } else {
540 rd = nullptr;
541 }
542 }
543 if (rd) {
544 RECT *r = reinterpret_cast<RECT *>(rd->Buffer);
545 for (uint i = 0; i < rd->rdh.nCount; ++i) {
546 QRect rect;
547 rect.setCoords(int(r->left * factor), int(r->top * factor),
548 int((r->right - 1) * factor), int((r->bottom - 1) * factor));
549 ++r;
550 region |= rect;
551 }
552 }
553 }
554
555 DeleteObject(hRgn);
556 DeleteObject(dest);
557
558 return region;
559}
560
566{
567 const int startX = rect.left();
568 const int startY = rect.top();
569 const int w = rect.width();
570 const int h = rect.height();
571
572 int firstAlpha = -1;
573 for (int y = startY; y < h/2; ++y) {
574 auto buffer = reinterpret_cast<const DWORD *>(bufferPixels) + (y * bufferW);
575 for (int x = startX; x < w; ++x, ++buffer) {
576 int alpha = (*buffer) >> 24;
577 if (firstAlpha == -1)
578 firstAlpha = alpha;
579 else if (alpha != firstAlpha)
580 return true;
581 }
582 }
583 return false;
584}
585
595{
596 const int startX = rect.left();
597 const int startY = rect.top();
598 const int w = rect.width();
599 const int h = rect.height();
600 bool hasFixedAlphaValue = false;
601
602 for (int y = startY; y < h; ++y) {
603 auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
604 for (int x = startX; x < w; ++x, ++buffer) {
605 uint pixel = *buffer;
606 int alpha = qAlpha(pixel);
607 if (qRed(pixel) > alpha || qGreen(pixel) > alpha || qBlue(pixel) > alpha) {
608 *buffer |= 0xff000000;
609 hasFixedAlphaValue = true;
610 }
611 }
612 }
613 return hasFixedAlphaValue;
614}
615
626{
627 const int startX = rect.left();
628 const int startY = rect.top();
629 const int w = rect.width();
630 const int h = rect.height();
631 bool valueChange = false;
632
633 // Flip the alphas, so that 255-alpha pixels are 0, and 0-alpha are 255.
634 for (int y = startY; y < h; ++y) {
635 auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
636 for (int x = startX; x < w; ++x, ++buffer) {
637 if (allPixels) {
638 *buffer |= 0xFF000000;
639 continue;
640 }
641 unsigned int alphaValue = (*buffer) & 0xFF000000;
642 if (alphaValue == 0xFF000000) {
643 *buffer = 0;
644 valueChange = true;
645 } else if (alphaValue == 0) {
646 *buffer |= 0xFF000000;
647 valueChange = true;
648 }
649 }
650 }
651 return valueChange;
652}
653
666{
667 if (themeData.rect.isEmpty())
668 return true;
669
670 QPainter *painter = themeData.painter;
671 Q_ASSERT_X(painter != nullptr, "QWindowsVistaStylePrivate::drawBackground()", "Trying to draw a theme part without a painter");
672 if (!painter || !painter->isActive())
673 return false;
674
675 painter->save();
676
677 // Access paintDevice via engine since the painter may
678 // return the clip device which can still be a widget device in case of grabWidget().
679
680 bool translucentToplevel = false;
681 const QPaintDevice *paintDevice = painter->device();
682 const qreal aditionalDevicePixelRatio = themeData.widget ? themeData.widget->devicePixelRatio() : qreal(1);
683 if (paintDevice->devType() == QInternal::Widget) {
684 const QWidget *window = static_cast<const QWidget *>(paintDevice)->window();
685 translucentToplevel = window->testAttribute(Qt::WA_TranslucentBackground);
686 }
687
688 const TransformType tt = transformType(painter->deviceTransform(), aditionalDevicePixelRatio);
689
690 bool canDrawDirectly = false;
691 if (themeData.widget && painter->opacity() == 1.0 && !themeData.rotate
692 && !isFullyOpaque(themeData)
693 && tt != ComplexTransform && !themeData.mirrorVertically && !themeData.invertPixels
694 && !translucentToplevel) {
695 // Draw on backing store DC only for real widgets or backing store images.
696 const QPaintDevice *enginePaintDevice = painter->paintEngine()->paintDevice();
697 switch (enginePaintDevice->devType()) {
699 canDrawDirectly = true;
700 break;
701 case QInternal::Image:
702 // Ensure the backing store has received as resize and is initialized.
703 if (QBackingStore *bs = backingStoreForWidget(themeData.widget)) {
704 if (bs->size().isValid() && bs->paintDevice() == enginePaintDevice)
705 canDrawDirectly = true;
706 }
707 break;
708 }
709 }
710
711 const HDC dc = canDrawDirectly ? hdcForWidgetBackingStore(themeData.widget) : nullptr;
712 const bool result = dc && qFuzzyCompare(correctionFactor, qreal(1))
713 ? drawBackgroundDirectly(dc, themeData, aditionalDevicePixelRatio)
714 : drawBackgroundThruNativeBuffer(themeData, aditionalDevicePixelRatio, correctionFactor);
715 painter->restore();
716 return result;
717}
718
724bool QWindowsVistaStylePrivate::drawBackgroundDirectly(HDC dc, QWindowsThemeData &themeData, qreal additionalDevicePixelRatio)
725{
726 QPainter *painter = themeData.painter;
727
728 const auto &deviceTransform = painter->deviceTransform();
729 const QPointF redirectionDelta(deviceTransform.dx(), deviceTransform.dy());
730 const QRect area = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio).translated(redirectionDelta).toRect();
731
732 QRegion sysRgn = painter->paintEngine()->systemClip();
733 if (sysRgn.isEmpty())
734 sysRgn = area;
735 else
736 sysRgn &= area;
737 if (painter->hasClipping())
738 sysRgn &= scaleRegion(painter->clipRegion(), additionalDevicePixelRatio).translated(redirectionDelta.toPoint());
739 HRGN hrgn = qt_hrgn_from_qregion(sysRgn);
740 SelectClipRgn(dc, hrgn);
741
742#ifdef DEBUG_XP_STYLE
743 printf("---[ DIRECT PAINTING ]------------------> Name(%-10s) Part(%d) State(%d)\n",
744 qPrintable(themeData.name), themeData.partId, themeData.stateId);
745 showProperties(themeData);
746#endif
747
748 RECT drawRECT = themeData.toRECT(area);
749 DTBGOPTS drawOptions;
750 memset(&drawOptions, 0, sizeof(drawOptions));
751 drawOptions.dwSize = sizeof(drawOptions);
752 drawOptions.rcClip = themeData.toRECT(sysRgn.boundingRect());
753 drawOptions.dwFlags = DTBG_CLIPRECT
754 | (themeData.noBorder ? DTBG_OMITBORDER : 0)
755 | (themeData.noContent ? DTBG_OMITCONTENT : 0)
756 | (themeData.mirrorHorizontally ? DTBG_MIRRORDC : 0);
757
758 const HRESULT result = DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &drawOptions);
759 SelectClipRgn(dc, nullptr);
760 DeleteObject(hrgn);
761 return SUCCEEDED(result);
762}
763
777 qreal additionalDevicePixelRatio,
778 qreal correctionFactor)
779{
780 QPainter *painter = themeData.painter;
781 QRectF rectF = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio);
782
783 if ((themeData.rotate + 90) % 180 == 0) { // Catch 90,270,etc.. degree flips.
784 rectF = QRectF(0, 0, rectF.height(), rectF.width());
785 }
786 rectF.moveTo(0, 0);
787
788 const bool hasCorrectionFactor = !qFuzzyCompare(correctionFactor, qreal(1));
789 QRect rect = rectF.toRect();
790 const QRect drawRect = hasCorrectionFactor
791 ? QRectF(rectF.topLeft() / correctionFactor, rectF.size() / correctionFactor).toRect()
792 : rect;
793 int partId = themeData.partId;
794 int stateId = themeData.stateId;
795 int w = rect.width();
796 int h = rect.height();
797
798 // Values initialized later, either from cached values, or from function calls
799 AlphaChannelType alphaType = UnknownAlpha;
800 bool stateHasData = true; // We assume so;
801 bool hasAlpha = false;
802 bool partIsTransparent;
803 bool potentialInvalidAlpha;
804
805 QString pixmapCacheKey = QStringLiteral("$qt_xp_");
806 pixmapCacheKey.append(themeName(themeData.theme));
807 pixmapCacheKey.append(QLatin1Char('p'));
808 pixmapCacheKey.append(QString::number(partId));
809 pixmapCacheKey.append(QLatin1Char('s'));
810 pixmapCacheKey.append(QString::number(stateId));
811 pixmapCacheKey.append(QLatin1Char('s'));
812 pixmapCacheKey.append(themeData.noBorder ? QLatin1Char('0') : QLatin1Char('1'));
813 pixmapCacheKey.append(QLatin1Char('b'));
814 pixmapCacheKey.append(themeData.noContent ? QLatin1Char('0') : QLatin1Char('1'));
815 pixmapCacheKey.append(QString::number(w));
816 pixmapCacheKey.append(QLatin1Char('w'));
817 pixmapCacheKey.append(QString::number(h));
818 pixmapCacheKey.append(QLatin1Char('h'));
819 pixmapCacheKey.append(QString::number(additionalDevicePixelRatio));
820 pixmapCacheKey.append(QLatin1Char('d'));
821 if (hasCorrectionFactor) {
822 pixmapCacheKey.append(QLatin1Char('c'));
823 pixmapCacheKey.append(QString::number(correctionFactor));
824 }
825
826 QPixmap cachedPixmap;
827 ThemeMapKey key(themeData);
828 ThemeMapData data = alphaCache.value(key);
829
830 bool haveCachedPixmap = false;
831 bool isCached = data.dataValid;
832 if (isCached) {
833 partIsTransparent = data.partIsTransparent;
834 hasAlpha = data.hasAlphaChannel;
835 alphaType = data.alphaType;
836 potentialInvalidAlpha = data.hadInvalidAlpha;
837
838 haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, &cachedPixmap);
839
840#ifdef DEBUG_XP_STYLE
841 char buf[25];
842 ::sprintf(buf, "+ Pixmap(%3d, %3d) ]", w, h);
843 printf("---[ CACHED %s--------> Name(%-10s) Part(%d) State(%d)\n",
844 haveCachedPixmap ? buf : "]-------------------",
845 qPrintable(themeData.name), themeData.partId, themeData.stateId);
846#endif
847 } else {
848 // Not cached, so get values from Theme Engine
849 BOOL tmt_borderonly = false;
850 COLORREF tmt_transparentcolor = 0x0;
851 PROPERTYORIGIN proporigin = PO_NOTFOUND;
852 GetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERONLY, &tmt_borderonly);
853 GetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, TMT_TRANSPARENTCOLOR, &tmt_transparentcolor);
854 GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_CAPTIONMARGINS, &proporigin);
855
856 partIsTransparent = isTransparent(themeData);
857
858 potentialInvalidAlpha = false;
859 GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &proporigin);
860 if (proporigin == PO_PART || proporigin == PO_STATE) {
861 int tmt_glyphtype = GT_NONE;
862 GetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &tmt_glyphtype);
863 potentialInvalidAlpha = partIsTransparent && tmt_glyphtype == GT_IMAGEGLYPH;
864 }
865
866#ifdef DEBUG_XP_STYLE
867 printf("---[ NOT CACHED ]-----------------------> Name(%-10s) Part(%d) State(%d)\n",
868 qPrintable(themeData.name), themeData.partId, themeData.stateId);
869 printf("-->partIsTransparen = %d\n", partIsTransparent);
870 printf("-->potentialInvalidAlpha = %d\n", potentialInvalidAlpha);
871 showProperties(themeData);
872#endif
873 }
874 bool wasAlphaSwapped = false;
875 bool wasAlphaFixed = false;
876
877 // OLD PSDK Workaround ------------------------------------------------------------------------
878 // See if we need extra clipping for the older PSDK, which does
879 // not have a DrawThemeBackgroundEx function for DTGB_OMITBORDER
880 // and DTGB_OMITCONTENT
881 bool addBorderContentClipping = false;
882 QRegion extraClip;
883 QRect area = drawRect;
884 if (themeData.noBorder || themeData.noContent) {
885 extraClip = area;
886 // We are running on a system where the uxtheme.dll does not have
887 // the DrawThemeBackgroundEx function, so we need to clip away
888 // borders or contents manually.
889
890 int borderSize = 0;
891 PROPERTYORIGIN origin = PO_NOTFOUND;
892 GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin);
893 GetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize);
894 borderSize *= additionalDevicePixelRatio;
895
896 // Clip away border region
897 if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) {
898 if (themeData.noBorder) {
899 extraClip &= area;
900 area = area.adjusted(-borderSize, -borderSize, borderSize, borderSize);
901 }
902
903 // Clip away content region
904 if (themeData.noContent) {
905 QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize);
906 extraClip ^= content;
907 }
908 }
909 addBorderContentClipping = (themeData.noBorder | themeData.noContent);
910 }
911
912 QImage img;
913 if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! -------------------------
914 if (!buffer(drawRect.width(), drawRect.height())) // Ensure a buffer of at least (w, h) in size
915 return false;
916 HDC dc = bufferHDC();
917
918 // Clear the buffer
919 if (alphaType != NoAlpha) {
920 // Consider have separate "memset" function for small chunks for more speedup
921 memset(bufferPixels, 0x00, bufferW * drawRect.height() * 4);
922 }
923
924 // Difference between area and rect
925 int dx = area.x() - drawRect.x();
926 int dy = area.y() - drawRect.y();
927
928 // Adjust so painting rect starts from Origo
929 rect.moveTo(0,0);
930 area.moveTo(dx,dy);
931 DTBGOPTS drawOptions;
932 drawOptions.dwSize = sizeof(drawOptions);
933 drawOptions.rcClip = themeData.toRECT(rect);
934 drawOptions.dwFlags = DTBG_CLIPRECT
935 | (themeData.noBorder ? DTBG_OMITBORDER : 0)
936 | (themeData.noContent ? DTBG_OMITCONTENT : 0);
937
938 // Drawing the part into the backing store
939 RECT wRect(themeData.toRECT(area));
940 DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &wRect, &drawOptions);
941
942 // If not cached, analyze the buffer data to figure
943 // out alpha type, and if it contains data
944 if (!isCached) {
945 // SHORTCUT: If the part's state has no data, cache it for NOOP later
946 if (!stateHasData) {
947 memset(static_cast<void *>(&data), 0, sizeof(data));
948 data.dataValid = true;
949 alphaCache.insert(key, data);
950 return true;
951 }
953 if (!hasAlpha && partIsTransparent)
954 potentialInvalidAlpha = true;
955#if defined(DEBUG_XP_STYLE) && 1
956 dumpNativeDIB(drawRect.width(), drawRect.height());
957#endif
958 }
959
960 // Fix alpha values, if needed
961 if (potentialInvalidAlpha)
962 wasAlphaFixed = fixAlphaChannel(drawRect);
963
965 if ((partIsTransparent && !wasAlphaSwapped) || (!partIsTransparent && hasAlpha)) {
967 alphaType = RealAlpha;
968 } else if (wasAlphaSwapped) {
970 alphaType = MaskAlpha;
971 } else {
973 // The image data we got from the theme engine does not have any transparency,
974 // thus the alpha channel is set to 0.
975 // However, Format_RGB32 requires the alpha part to be set to 0xff, thus
976 // we must flip it from 0x00 to 0xff
977 swapAlphaChannel(rect, true);
978 alphaType = NoAlpha;
979 }
980#if defined(DEBUG_XP_STYLE) && 1
981 printf("Image format is: %s\n", alphaType == RealAlpha ? "Real Alpha" : alphaType == MaskAlpha ? "Masked Alpha" : "No Alpha");
982#endif
983 img = QImage(bufferPixels, bufferW, bufferH, format);
984 if (themeData.invertPixels)
985 img.invertPixels();
986
987 if (hasCorrectionFactor)
988 img = img.scaled(img.size() * correctionFactor, Qt::KeepAspectRatio, Qt::SmoothTransformation);
989 img.setDevicePixelRatio(additionalDevicePixelRatio);
990 }
991
992 // Blitting backing store
993 bool useRegion = partIsTransparent && !hasAlpha && !wasAlphaSwapped;
994
995 QRegion newRegion;
996 QRegion oldRegion;
997 if (useRegion) {
998 newRegion = region(themeData);
999 oldRegion = painter->clipRegion();
1000 painter->setClipRegion(newRegion);
1001#if defined(DEBUG_XP_STYLE) && 0
1002 printf("Using region:\n");
1003 for (const QRect &r : newRegion)
1004 printf(" (%d, %d, %d, %d)\n", r.x(), r.y(), r.right(), r.bottom());
1005#endif
1006 }
1007
1008 if (addBorderContentClipping)
1009 painter->setClipRegion(scaleRegion(extraClip, 1.0 / additionalDevicePixelRatio), Qt::IntersectClip);
1010
1011 if (!themeData.mirrorHorizontally && !themeData.mirrorVertically && !themeData.rotate) {
1012 if (!haveCachedPixmap)
1013 painter->drawImage(themeData.rect, img, rect);
1014 else
1015 painter->drawPixmap(themeData.rect, cachedPixmap);
1016 } else {
1017 // This is _slow_!
1018 // Make a copy containing only the necessary data, and mirror
1019 // on all wanted axes. Then draw the copy.
1020 // If cached, the normal pixmap is cached, instead of caching
1021 // all possible orientations for each part and state.
1022 QImage imgCopy;
1023 if (!haveCachedPixmap)
1024 imgCopy = img.copy(rect);
1025 else
1026 imgCopy = cachedPixmap.toImage();
1027
1028 if (themeData.rotate) {
1029 QTransform rotMatrix;
1030 rotMatrix.rotate(themeData.rotate);
1031 imgCopy = imgCopy.transformed(rotMatrix);
1032 }
1033 if (themeData.mirrorHorizontally || themeData.mirrorVertically)
1034 imgCopy = imgCopy.mirrored(themeData.mirrorHorizontally, themeData.mirrorVertically);
1035 painter->drawImage(themeData.rect, imgCopy);
1036 }
1037
1038 if (useRegion || addBorderContentClipping) {
1039 if (oldRegion.isEmpty())
1040 painter->setClipping(false);
1041 else
1042 painter->setClipRegion(oldRegion);
1043 }
1044
1045 // Cache the pixmap to avoid expensive swapAlphaChannel() calls
1046 if (!haveCachedPixmap && w && h) {
1048 QPixmapCache::insert(pixmapCacheKey, pix);
1049#ifdef DEBUG_XP_STYLE
1050 printf("+++Adding pixmap to cache, size(%d, %d), wasAlphaSwapped(%d), wasAlphaFixed(%d), name(%s)\n",
1051 w, h, wasAlphaSwapped, wasAlphaFixed, qPrintable(pixmapCacheKey));
1052#endif
1053 }
1054
1055 // Add to theme part cache
1056 if (!isCached) {
1057 memset(static_cast<void *>(&data), 0, sizeof(data));
1058 data.dataValid = true;
1059 data.partIsTransparent = partIsTransparent;
1060 data.alphaType = alphaType;
1061 data.hasAlphaChannel = hasAlpha;
1062 data.wasAlphaSwapped = wasAlphaSwapped;
1063 data.hadInvalidAlpha = wasAlphaFixed;
1064 alphaCache.insert(key, data);
1065 }
1066 return true;
1067}
1068
1077{
1078 Q_Q(const QWindowsVistaStyle);
1079 static bool animationTimeOverride = q->dynamicPropertyNames().contains("_qt_animation_time");
1080 if (animationTimeOverride)
1081 return q->property("_qt_animation_time").toTime();
1082 return QTime::currentTime();
1083}
1084
1085/* \internal
1086 Checks and returns the style object
1087*/
1089 return option ? option->styleObject : nullptr;
1090}
1091
1092/* \internal
1093 Checks if we can animate on a style option
1094*/
1096 return option
1097 && option->styleObject
1098 && !option->styleObject->property("_q_no_animation").toBool();
1099}
1100
1102{
1103 const qreal devicePixelRatio = widget
1104 ? widget->devicePixelRatioF() : qApp->devicePixelRatio();
1105 QImage result(option->rect.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
1106 result.setDevicePixelRatio(devicePixelRatio);
1107 result.fill(0);
1108 return result;
1109}
1110
1111/* \internal
1112 Used by animations to clone a styleoption and shift its offset
1113*/
1115 QStyleOption *styleOption = nullptr;
1116 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
1117 styleOption = new QStyleOptionSlider(*slider);
1118 else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
1119 styleOption = new QStyleOptionSpinBox(*spinbox);
1120 else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
1121 styleOption = new QStyleOptionGroupBox(*groupBox);
1122 else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
1123 styleOption = new QStyleOptionComboBox(*combo);
1124 else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
1125 styleOption = new QStyleOptionButton(*button);
1126 else
1127 styleOption = new QStyleOption(*option);
1128 styleOption->rect = QRect(QPoint(0,0), option->rect.size());
1129 return styleOption;
1130}
1131
1132/* \internal
1133 Used by animations to delete cloned styleoption
1134*/
1136{
1137 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
1138 delete slider;
1139 else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
1140 delete spinbox;
1141 else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
1142 delete groupBox;
1143 else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
1144 delete combo;
1145 else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
1146 delete button;
1147 else
1148 delete option;
1149}
1150
1153 QStyle::SubControl subControl,
1154 bool isTitleBarActive, int part,
1155 QWindowsThemeData *theme)
1156{
1157 theme->rect = proxy->subControlRect(QStyle::CC_TitleBar, option, subControl, widget);
1158 theme->partId = part;
1159 if (widget && !widget->isEnabled())
1160 theme->stateId = RBS_DISABLED;
1161 else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_Sunken))
1162 theme->stateId = RBS_PUSHED;
1163 else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_MouseOver))
1164 theme->stateId = RBS_HOT;
1165 else if (!isTitleBarActive)
1166 theme->stateId = RBS_INACTIVE;
1167 else
1168 theme->stateId = RBS_NORMAL;
1169}
1170
1171#if QT_CONFIG(mdiarea)
1172// Helper for drawing MDI buttons into the corner widget of QMenuBar in case a
1173// QMdiSubWindow is maximized.
1174static void populateMdiButtonTheme(const QStyle *proxy, const QWidget *widget,
1176 QStyle::SubControl subControl, int part,
1177 QWindowsThemeData *theme)
1178{
1179 theme->partId = part;
1180 theme->rect = proxy->subControlRect(QStyle::CC_MdiControls, option, subControl, widget);
1181 if (!option->state.testFlag(QStyle::State_Enabled))
1182 theme->stateId = CBS_INACTIVE;
1183 else if (option->state.testFlag(QStyle::State_Sunken) && option->activeSubControls.testFlag(subControl))
1184 theme->stateId = CBS_PUSHED;
1185 else if (option->state.testFlag(QStyle::State_MouseOver) && option->activeSubControls.testFlag(subControl))
1186 theme->stateId = CBS_HOT;
1187 else
1188 theme->stateId = CBS_NORMAL;
1189}
1190
1191// Calculate an small (max 2), empirical correction factor for scaling up
1192// WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON, which are too
1193// small on High DPI screens (QTBUG-75927).
1194static qreal mdiButtonCorrectionFactor(QWindowsThemeData &theme, const QPaintDevice *pd = nullptr)
1195{
1196 const auto dpr = pd ? pd->devicePixelRatio() : qApp->devicePixelRatio();
1197 const QSizeF nativeSize = QSizeF(theme.size()) / dpr;
1198 const QSizeF requestedSize(theme.rect.size());
1199 const auto rawFactor = qMin(requestedSize.width() / nativeSize.width(),
1200 requestedSize.height() / nativeSize.height());
1201 const auto factor = rawFactor >= qreal(2) ? qreal(2) : qreal(1);
1202 return factor;
1203}
1204#endif // QT_CONFIG(mdiarea)
1205
1206/*
1207 This function is used by subControlRect to check if a button
1208 should be drawn for the given subControl given a set of window flags.
1209*/
1211
1212 bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
1213 bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
1214 const auto flags = tb->titleBarFlags;
1215 bool retVal = false;
1216 switch (sc) {
1219 retVal = true;
1220 break;
1222 if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
1223 retVal = true;
1224 break;
1226 if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
1227 retVal = true;
1228 else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
1229 retVal = true;
1230 break;
1232 if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
1233 retVal = true;
1234 break;
1236 if (!isMinimized && flags & Qt::WindowShadeButtonHint)
1237 retVal = true;
1238 break;
1240 if (isMinimized && flags & Qt::WindowShadeButtonHint)
1241 retVal = true;
1242 break;
1245 retVal = true;
1246 break;
1249 retVal = true;
1250 break;
1251 default :
1252 retVal = true;
1253 }
1254 return retVal;
1255}
1256
1257//convert Qt state flags to uxtheme button states
1258static int buttonStateId(int flags, int partId)
1259{
1260 int stateId = 0;
1261 if (partId == BP_RADIOBUTTON || partId == BP_CHECKBOX) {
1263 stateId = RBS_UNCHECKEDDISABLED;
1264 else if (flags & QStyle::State_Sunken)
1265 stateId = RBS_UNCHECKEDPRESSED;
1266 else if (flags & QStyle::State_MouseOver)
1267 stateId = RBS_UNCHECKEDHOT;
1268 else
1269 stateId = RBS_UNCHECKEDNORMAL;
1270
1271 if (flags & QStyle::State_On)
1272 stateId += RBS_CHECKEDNORMAL-1;
1273
1274 } else if (partId == BP_PUSHBUTTON) {
1276 stateId = PBS_DISABLED;
1278 stateId = PBS_PRESSED;
1279 else if (flags & QStyle::State_MouseOver)
1280 stateId = PBS_HOT;
1281 else
1282 stateId = PBS_NORMAL;
1283 } else {
1284 Q_ASSERT(1);
1285 }
1286 return stateId;
1287}
1288
1290 const QStyleOption *option,
1291 const QWidget *widget)
1292{
1293 bool result = false;
1294 switch (element) {
1297 result = true;
1298 break;
1299 // QTBUG-40634, do not animate when color is set in palette for PE_PanelLineEdit.
1302 break;
1303 default:
1304 break;
1305 }
1306 return result;
1307}
1308
1327{
1328}
1329
1334
1335
1366void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
1367 QPainter *painter, const QWidget *widget) const
1368{
1370 QWindowsStyle::drawPrimitive(element, option, painter, widget);
1371 return;
1372 }
1373
1374 QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
1375
1376 int state = option->state;
1377 QRect rect = option->rect;
1378
1379 if ((state & State_Enabled) && d->transitionsEnabled() && canAnimate(option)) {
1380 if (supportsStateTransition(element, option, widget)) {
1381 // Retrieve and update the dynamic properties tracking
1382 // the previous state of the widget:
1383 QObject *styleObject = option->styleObject;
1384 styleObject->setProperty("_q_no_animation", true);
1385 int oldState = styleObject->property("_q_stylestate").toInt();
1386 QRect oldRect = styleObject->property("_q_stylerect").toRect();
1387 QRect newRect = rect;
1388 styleObject->setProperty("_q_stylestate", int(option->state));
1389 styleObject->setProperty("_q_stylerect", option->rect);
1390
1391 bool doTransition = oldState &&
1392 ((state & State_Sunken) != (oldState & State_Sunken) ||
1393 (state & State_On) != (oldState & State_On) ||
1394 (state & State_MouseOver) != (oldState & State_MouseOver));
1395
1396 if (oldRect != newRect ||
1397 (state & State_Enabled) != (oldState & State_Enabled) ||
1398 (state & State_Active) != (oldState & State_Active))
1399 d->stopAnimation(styleObject);
1400
1401 if (state & State_ReadOnly && element == PE_FrameLineEdit) // Do not animate read only line edits
1402 doTransition = false;
1403
1404 if (doTransition) {
1406 styleOption->state = QStyle::State(oldState);
1407
1408 QWindowsVistaAnimation *animate = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
1410
1411 // We create separate images for the initial and final transition states and store them in the
1412 // Transition object.
1414 QPainter startPainter(&startImage);
1415
1417 QPainter endPainter(&endImage);
1418
1419 // If we have a running animation on the widget already, we will use that to paint the initial
1420 // state of the new transition, this ensures a smooth transition from a current animation such as a
1421 // pulsating default button into the intended target state.
1422 if (!animate)
1423 proxy()->drawPrimitive(element, styleOption, &startPainter, widget);
1424 else
1425 animate->paint(&startPainter, styleOption);
1426
1427 transition->setStartImage(startImage);
1428
1429 // The end state of the transition is simply the result we would have painted
1430 // if the style was not animated.
1431 styleOption->styleObject = nullptr;
1432 styleOption->state = option->state;
1433 proxy()->drawPrimitive(element, styleOption, &endPainter, widget);
1434
1435 transition->setEndImage(endImage);
1436
1437 HTHEME theme;
1438 int partId;
1439 DWORD duration;
1440 int fromState = 0;
1441 int toState = 0;
1442
1443 //translate state flags to UXTHEME states :
1444 if (element == PE_FrameLineEdit) {
1445 theme = OpenThemeData(nullptr, L"Edit");
1446 partId = EP_EDITBORDER_NOSCROLL;
1447
1448 if (oldState & State_MouseOver)
1449 fromState = ETS_HOT;
1450 else if (oldState & State_HasFocus)
1451 fromState = ETS_FOCUSED;
1452 else
1453 fromState = ETS_NORMAL;
1454
1455 if (state & State_MouseOver)
1456 toState = ETS_HOT;
1457 else if (state & State_HasFocus)
1458 toState = ETS_FOCUSED;
1459 else
1460 toState = ETS_NORMAL;
1461
1462 } else {
1463 theme = OpenThemeData(nullptr, L"Button");
1464 if (element == PE_IndicatorRadioButton)
1465 partId = BP_RADIOBUTTON;
1466 else if (element == PE_IndicatorCheckBox)
1467 partId = BP_CHECKBOX;
1468 else
1469 partId = BP_PUSHBUTTON;
1470
1471 fromState = buttonStateId(oldState, partId);
1472 toState = buttonStateId(option->state, partId);
1473 }
1474
1475 // Retrieve the transition time between the states from the system.
1476 if (theme
1477 && SUCCEEDED(GetThemeTransitionDuration(theme, partId, fromState, toState,
1478 TMT_TRANSITIONDURATIONS, &duration))) {
1479 transition->setDuration(int(duration));
1480 }
1481 transition->setStartTime(d->animationTime());
1482
1484 d->startAnimation(transition);
1485 }
1486 styleObject->setProperty("_q_no_animation", false);
1487 }
1488 }
1489
1490 int themeNumber = -1;
1491 int partId = 0;
1492 int stateId = 0;
1493 bool hMirrored = false;
1494 bool vMirrored = false;
1495 bool noBorder = false;
1496 bool noContent = false;
1497 int rotate = 0;
1498
1499 switch (element) {
1500 case PE_PanelButtonCommand:
1501 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
1502 QBrush fill;
1503 if (!(state & State_Sunken) && (state & State_On))
1504 fill = QBrush(option->palette.light().color(), Qt::Dense4Pattern);
1505 else
1506 fill = option->palette.brush(QPalette::Button);
1507 if (btn->features & QStyleOptionButton::DefaultButton && state & State_Sunken) {
1508 painter->setPen(option->palette.dark().color());
1510 painter->drawRect(rect.adjusted(0, 0, -1, -1));
1511 } else if (state & (State_Raised | State_On | State_Sunken)) {
1512 qDrawWinButton(painter, rect, option->palette, state & (State_Sunken | State_On),
1513 &fill);
1514 } else {
1516 }
1517 }
1518 break;
1519
1520 case PE_PanelButtonTool:
1521#if QT_CONFIG(dockwidget)
1522 if (widget && widget->inherits("QDockWidgetTitleButton")) {
1523 if (const QWidget *dw = widget->parentWidget())
1524 if (dw->isWindow()) {
1525 return;
1526 }
1527 }
1528#endif // QT_CONFIG(dockwidget)
1530 partId = TP_BUTTON;
1531 if (!(option->state & State_Enabled))
1532 stateId = TS_DISABLED;
1533 else if (option->state & State_Sunken)
1534 stateId = TS_PRESSED;
1535 else if (option->state & State_MouseOver)
1536 stateId = option->state & State_On ? TS_HOTCHECKED : TS_HOT;
1537 else if (option->state & State_On)
1538 stateId = TS_CHECKED;
1539 else if (!(option->state & State_AutoRaise))
1540 stateId = TS_HOT;
1541 else
1542 stateId = TS_NORMAL;
1543
1544 break;
1545
1546 case PE_IndicatorHeaderArrow:
1547 if (const auto *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
1548 int stateId = HSAS_SORTEDDOWN;
1549 if (header->sortIndicator & QStyleOptionHeader::SortDown)
1550 stateId = HSAS_SORTEDUP; //note that the uxtheme sort down indicator is the inverse of ours
1553 HP_HEADERSORTARROW, stateId, option->rect);
1554 d->drawBackground(theme);
1555 return;
1556 }
1557 break;
1558
1559 case PE_IndicatorCheckBox:
1560 if (auto *animate =
1561 qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
1562 animate->paint(painter, option);
1563 return;
1564 } else {
1566 partId = BP_CHECKBOX;
1567
1568 if (!(option->state & State_Enabled))
1569 stateId = CBS_UNCHECKEDDISABLED;
1570 else if (option->state & State_Sunken)
1571 stateId = CBS_UNCHECKEDPRESSED;
1572 else if (option->state & State_MouseOver)
1573 stateId = CBS_UNCHECKEDHOT;
1574 else
1575 stateId = CBS_UNCHECKEDNORMAL;
1576
1577 if (option->state & State_On)
1578 stateId += CBS_CHECKEDNORMAL-1;
1579 else if (option->state & State_NoChange)
1580 stateId += CBS_MIXEDNORMAL-1;
1581 }
1582 break;
1583
1584 case PE_IndicatorItemViewItemCheck: {
1586 button.QStyleOption::operator=(*option);
1587 button.state &= ~State_MouseOver;
1588 proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget);
1589 return;
1590 }
1591
1592 case PE_IndicatorBranch: {
1594 static int decoration_size = 0;
1595 if (!decoration_size && theme.isValid()) {
1596 QWindowsThemeData themeSize = theme;
1597 themeSize.partId = TVP_HOTGLYPH;
1598 themeSize.stateId = GLPS_OPENED;
1599 const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
1600 decoration_size = qRound(qMax(size.width(), size.height()));
1601 }
1602 int mid_h = option->rect.x() + option->rect.width() / 2;
1603 int mid_v = option->rect.y() + option->rect.height() / 2;
1604 if (option->state & State_Children) {
1605 int delta = decoration_size / 2;
1606 theme.rect = QRect(mid_h - delta, mid_v - delta, decoration_size, decoration_size);
1607 theme.partId = option->state & State_MouseOver ? TVP_HOTGLYPH : TVP_GLYPH;
1608 theme.stateId = option->state & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
1609 if (option->direction == Qt::RightToLeft)
1610 theme.mirrorHorizontally = true;
1611 d->drawBackground(theme);
1612 }
1613 return;
1614 }
1615
1616 case PE_PanelButtonBevel:
1617 if (QWindowsVistaAnimation *animate =
1618 qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
1619 animate->paint(painter, option);
1620 return;
1621 }
1622
1624 partId = BP_PUSHBUTTON;
1625 if (!(option->state & State_Enabled))
1626 stateId = PBS_DISABLED;
1627 else if ((option->state & State_Sunken) || (option->state & State_On))
1628 stateId = PBS_PRESSED;
1629 else if (option->state & State_MouseOver)
1630 stateId = PBS_HOT;
1631 else
1632 stateId = PBS_NORMAL;
1633 break;
1634
1635 case PE_IndicatorRadioButton:
1636 if (QWindowsVistaAnimation *animate =
1637 qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
1638 animate->paint(painter, option);
1639 return;
1640 } else {
1642 partId = BP_RADIOBUTTON;
1643
1644 if (!(option->state & State_Enabled))
1645 stateId = RBS_UNCHECKEDDISABLED;
1646 else if (option->state & State_Sunken)
1647 stateId = RBS_UNCHECKEDPRESSED;
1648 else if (option->state & State_MouseOver)
1649 stateId = RBS_UNCHECKEDHOT;
1650 else
1651 stateId = RBS_UNCHECKEDNORMAL;
1652
1653 if (option->state & State_On)
1654 stateId += RBS_CHECKEDNORMAL-1;
1655 }
1656 break;
1657
1658 case PE_Frame:
1659#if QT_CONFIG(accessibility)
1660 if (QStyleHelper::isInstanceOf(option->styleObject, QAccessible::EditableText)
1661 || QStyleHelper::isInstanceOf(option->styleObject, QAccessible::StaticText) ||
1662#else
1663 if (
1664#endif
1665 (widget && widget->inherits("QTextEdit"))) {
1666 painter->save();
1667 int stateId = ETS_NORMAL;
1668 if (!(state & State_Enabled))
1669 stateId = ETS_DISABLED;
1670 else if (state & State_ReadOnly)
1671 stateId = ETS_READONLY;
1672 else if (state & State_HasFocus)
1673 stateId = ETS_SELECTED;
1674 QWindowsThemeData theme(widget, painter,
1675 QWindowsVistaStylePrivate::EditTheme,
1676 EP_EDITBORDER_HVSCROLL, stateId, option->rect);
1677 // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping
1678 int borderSize = 1;
1679 GetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize);
1680 QRegion clipRegion = option->rect;
1681 QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize);
1682 clipRegion ^= content;
1683 painter->setClipRegion(clipRegion);
1684 d->drawBackground(theme);
1685 painter->restore();
1686 return;
1687 } else {
1688 if (option->state & State_Raised)
1689 return;
1690
1691 themeNumber = QWindowsVistaStylePrivate::ListViewTheme;
1692 partId = LVP_LISTGROUP;
1693 QWindowsThemeData theme(widget, nullptr, themeNumber, partId);
1694
1695 if (!(option->state & State_Enabled))
1696 stateId = ETS_DISABLED;
1697 else
1698 stateId = ETS_NORMAL;
1699
1700 int fillType;
1701
1702 if (GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &fillType) == S_OK) {
1703 if (fillType == BT_BORDERFILL) {
1704 COLORREF bcRef;
1705 GetThemeColor(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &bcRef);
1706 QColor bordercolor(qRgb(GetRValue(bcRef), GetGValue(bcRef), GetBValue(bcRef)));
1707 QPen oldPen = painter->pen();
1708
1709 // Inner white border
1710 painter->setPen(QPen(option->palette.base().color(), 0));
1711 const qreal dpi = QStyleHelper::dpi(option);
1712 const auto topLevelAdjustment = QStyleHelper::dpiScaled(0.5, dpi);
1713 const auto bottomRightAdjustment = QStyleHelper::dpiScaled(-1, dpi);
1714 painter->drawRect(QRectF(option->rect).adjusted(topLevelAdjustment, topLevelAdjustment,
1715 bottomRightAdjustment, bottomRightAdjustment));
1716 // Outer dark border
1717 painter->setPen(QPen(bordercolor, 0));
1718 painter->drawRect(QRectF(option->rect).adjusted(0, 0, -topLevelAdjustment, -topLevelAdjustment));
1719 painter->setPen(oldPen);
1720 }
1721
1722 if (fillType == BT_BORDERFILL || fillType == BT_NONE)
1723 return;
1724 }
1725 }
1726 break;
1727
1728 case PE_FrameMenu: {
1729 int stateId = option->state & State_Active ? MB_ACTIVE : MB_INACTIVE;
1732 MENU_POPUPBORDERS, stateId, option->rect);
1733 d->drawBackground(theme);
1734 return;
1735 }
1736
1737 case PE_PanelMenuBar:
1738 break;
1739
1740#if QT_CONFIG(dockwidget)
1741 case PE_IndicatorDockWidgetResizeHandle:
1742 return;
1743
1744 case PE_FrameDockWidget:
1745 if (const auto *frm = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1747 if (option->state & State_Active)
1748 stateId = FS_ACTIVE;
1749 else
1750 stateId = FS_INACTIVE;
1751
1752 int fwidth = proxy()->pixelMetric(PM_DockWidgetFrameWidth, frm, widget);
1753
1754 QWindowsThemeData theme(widget, painter, themeNumber, 0, stateId);
1755
1756 if (!theme.isValid())
1757 break;
1758
1759 theme.rect = QRect(frm->rect.x(), frm->rect.y(), frm->rect.x()+fwidth, frm->rect.height()-fwidth);
1760 theme.partId = WP_SMALLFRAMELEFT;
1761 d->drawBackground(theme);
1762 theme.rect = QRect(frm->rect.width()-fwidth, frm->rect.y(), fwidth, frm->rect.height()-fwidth);
1763 theme.partId = WP_SMALLFRAMERIGHT;
1764 d->drawBackground(theme);
1765 theme.rect = QRect(frm->rect.x(), frm->rect.bottom()-fwidth+1, frm->rect.width(), fwidth);
1766 theme.partId = WP_SMALLFRAMEBOTTOM;
1767 d->drawBackground(theme);
1768 return;
1769 }
1770 break;
1771#endif // QT_CONFIG(dockwidget)
1772
1773 case PE_FrameTabWidget:
1774 if (const auto *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
1776 partId = TABP_PANE;
1777
1778 if (widget) {
1779 bool useGradient = true;
1780 const int maxlength = 256;
1781 wchar_t themeFileName[maxlength];
1782 wchar_t themeColor[maxlength];
1783 // Due to a a scaling issue with the XP Silver theme, tab gradients are not used with it
1784 if (GetCurrentThemeName(themeFileName, maxlength, themeColor, maxlength, nullptr, 0) == S_OK) {
1785 wchar_t *offset = nullptr;
1786 if ((offset = wcsrchr(themeFileName, QChar(QLatin1Char('\\')).unicode())) != nullptr) {
1787 offset++;
1788 if (!lstrcmp(offset, L"Luna.msstyles") && !lstrcmp(offset, L"Metallic"))
1789 useGradient = false;
1790 }
1791 }
1792 // This should work, but currently there's an error in the ::drawBackgroundDirectly()
1793 // code, when using the HDC directly..
1794 if (useGradient) {
1795 QStyleOptionTabWidgetFrame frameOpt = *tab;
1796 frameOpt.rect = widget->rect();
1797 QRect contentsRect = subElementRect(SE_TabWidgetTabContents, &frameOpt, widget);
1798 QRegion reg = option->rect;
1799 reg -= contentsRect;
1800 painter->setClipRegion(reg);
1801 QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
1802 theme.mirrorHorizontally = hMirrored;
1803 theme.mirrorVertically = vMirrored;
1804 d->drawBackground(theme);
1805 painter->setClipRect(contentsRect);
1806 partId = TABP_BODY;
1807 }
1808 }
1809 switch (tab->shape) {
1812 break;
1815 vMirrored = true;
1816 break;
1819 rotate = 90;
1820 break;
1823 rotate = 90;
1824 hMirrored = true;
1825 break;
1826 default:
1827 break;
1828 }
1829 }
1830 break;
1831
1832 case PE_FrameStatusBarItem:
1834 partId = SP_PANE;
1835 break;
1836
1837 case PE_FrameWindow:
1838 if (const auto *frm = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1840 if (option->state & State_Active)
1841 stateId = FS_ACTIVE;
1842 else
1843 stateId = FS_INACTIVE;
1844
1845 int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
1846
1847 QWindowsThemeData theme(widget, painter, themeNumber, 0, stateId);
1848 if (!theme.isValid())
1849 break;
1850
1851 // May fail due to too-large buffers for large widgets, fall back to Windows style.
1852 theme.rect = QRect(option->rect.x(), option->rect.y()+fwidth, option->rect.x()+fwidth, option->rect.height()-fwidth);
1853 theme.partId = WP_FRAMELEFT;
1854 if (!d->drawBackground(theme)) {
1855 QWindowsStyle::drawPrimitive(element, option, painter, widget);
1856 return;
1857 }
1858 theme.rect = QRect(option->rect.width()-fwidth, option->rect.y()+fwidth, fwidth, option->rect.height()-fwidth);
1859 theme.partId = WP_FRAMERIGHT;
1860 if (!d->drawBackground(theme)) {
1861 QWindowsStyle::drawPrimitive(element, option, painter, widget);
1862 return;
1863 }
1864 theme.rect = QRect(option->rect.x(), option->rect.height()-fwidth, option->rect.width(), fwidth);
1865 theme.partId = WP_FRAMEBOTTOM;
1866 if (!d->drawBackground(theme)) {
1867 QWindowsStyle::drawPrimitive(element, option, painter, widget);
1868 return;
1869 }
1870 theme.rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.y()+fwidth);
1871 theme.partId = WP_CAPTION;
1872 if (!d->drawBackground(theme))
1873 QWindowsStyle::drawPrimitive(element, option, painter, widget);
1874 return;
1875 }
1876 break;
1877
1878 case PE_PanelLineEdit:
1879 if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1880 bool isEnabled = state & State_Enabled;
1883 } else {
1884 int partId = EP_BACKGROUND;
1885 int stateId = EBS_NORMAL;
1886 if (!isEnabled)
1887 stateId = EBS_DISABLED;
1888 else if (option->state & State_ReadOnly)
1889 stateId = EBS_READONLY;
1890 else if (option->state & State_MouseOver)
1891 stateId = EBS_HOT;
1892
1894 partId, stateId, rect);
1895 if (!theme.isValid()) {
1896 QWindowsStyle::drawPrimitive(element, option, painter, widget);
1897 return;
1898 }
1899 int bgType;
1900 GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &bgType);
1901 if (bgType == BT_IMAGEFILE) {
1902 d->drawBackground(theme);
1903 } else {
1904 QBrush fillColor = option->palette.brush(QPalette::Base);
1905 if (!isEnabled) {
1906 PROPERTYORIGIN origin = PO_NOTFOUND;
1907 GetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
1908 // Use only if the fill property comes from our part
1909 if ((origin == PO_PART || origin == PO_STATE)) {
1910 COLORREF bgRef;
1911 GetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
1912 fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
1913 }
1914 }
1915 painter->fillRect(option->rect, fillColor);
1916 }
1917 }
1918 if (panel->lineWidth > 0)
1919 proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
1920 }
1921 return;
1922
1923 case PE_IndicatorButtonDropDown:
1925 partId = TP_SPLITBUTTONDROPDOWN;
1926 if (!(option->state & State_Enabled))
1927 stateId = TS_DISABLED;
1928 else if (option->state & State_Sunken)
1929 stateId = TS_PRESSED;
1930 else if (option->state & State_MouseOver)
1931 stateId = option->state & State_On ? TS_HOTCHECKED : TS_HOT;
1932 else if (option->state & State_On)
1933 stateId = TS_CHECKED;
1934 else if (!(option->state & State_AutoRaise))
1935 stateId = TS_HOT;
1936 else
1937 stateId = TS_NORMAL;
1938 if (option->direction == Qt::RightToLeft)
1939 hMirrored = true;
1940 break;
1941
1942 case PE_FrameLineEdit:
1943 if (QWindowsVistaAnimation *animate = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
1944 animate->paint(painter, option);
1945 } else {
1947 // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
1948 QPen oldPen = painter->pen();
1949 // Inner white border
1950 painter->setPen(QPen(option->palette.base().color(), 1));
1951 painter->drawRect(option->rect.adjusted(1, 1, -2, -2));
1952 // Outer dark border
1953 painter->setPen(QPen(option->palette.shadow().color(), 1));
1954 painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
1955 painter->setPen(oldPen);
1956 return;
1957 }
1958 int stateId = ETS_NORMAL;
1959 if (!(state & State_Enabled))
1960 stateId = ETS_DISABLED;
1961 else if (state & State_ReadOnly)
1962 stateId = ETS_READONLY;
1963 else if (state & State_MouseOver)
1964 stateId = ETS_HOT;
1965 else if (state & State_HasFocus)
1966 stateId = ETS_SELECTED;
1969 EP_EDITBORDER_NOSCROLL, stateId, option->rect);
1970 theme.noContent = true;
1971 painter->save();
1972 QRegion clipRegion = option->rect;
1973 clipRegion -= option->rect.adjusted(2, 2, -2, -2);
1974 painter->setClipRegion(clipRegion);
1975 d->drawBackground(theme);
1976 painter->restore();
1977 }
1978 return;
1979
1980 case PE_FrameGroupBox:
1982 partId = BP_GROUPBOX;
1983 if (!(option->state & State_Enabled))
1984 stateId = GBS_DISABLED;
1985 else
1986 stateId = GBS_NORMAL;
1987 if (const auto *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1988 if (frame->features & QStyleOptionFrame::Flat) {
1989 // Windows XP does not have a theme part for a flat GroupBox, paint it with the windows style
1990 QRect fr = frame->rect;
1991 QPoint p1(fr.x(), fr.y() + 1);
1992 QPoint p2(fr.x() + fr.width(), p1.y() + 1);
1993 rect = QRect(p1, p2);
1994 themeNumber = -1;
1995 }
1996 }
1997 break;
1998
1999 case PE_IndicatorToolBarHandle: {
2000 QWindowsThemeData theme;
2001 QRect rect;
2002 if (option->state & State_Horizontal) {
2005 RP_GRIPPER, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
2006 rect = option->rect.adjusted(0, 1, 0, -2);
2007 rect.setWidth(4);
2008 } else {
2010 RP_GRIPPERVERT, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
2011 rect = option->rect.adjusted(1, 0, -1, 0);
2012 rect.setHeight(4);
2013 }
2014 theme.rect = rect;
2015 d->drawBackground(theme);
2016 return;
2017 }
2018
2019 case PE_IndicatorToolBarSeparator: {
2020 QPen pen = painter->pen();
2021 int margin = 3;
2022 painter->setPen(option->palette.window().color().darker(114));
2023 if (option->state & State_Horizontal) {
2024 int x1 = option->rect.center().x();
2025 painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin));
2026 } else {
2027 int y1 = option->rect.center().y();
2028 painter->drawLine(QPoint(option->rect.left() + margin, y1), QPoint(option->rect.right() - margin, y1));
2029 }
2030 painter->setPen(pen);
2031 return;
2032 }
2033
2034 case PE_PanelTipLabel: {
2037 TTP_STANDARD, TTSS_NORMAL, option->rect);
2038 d->drawBackground(theme);
2039 return;
2040 }
2041
2042 case PE_FrameTabBarBase:
2043 if (const auto *tbb = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
2044 painter->save();
2045 switch (tbb->shape) {
2047 painter->setPen(QPen(tbb->palette.dark(), 0));
2048 painter->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
2049 break;
2051 painter->setPen(QPen(tbb->palette.dark(), 0));
2052 painter->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom());
2053 break;
2055 painter->setPen(QPen(tbb->palette.dark(), 0));
2056 painter->drawLine(tbb->rect.left(), tbb->rect.top(),
2057 tbb->rect.right(), tbb->rect.top());
2058 break;
2060 painter->setPen(QPen(tbb->palette.dark(), 0));
2061 painter->drawLine(tbb->rect.topLeft(), tbb->rect.bottomLeft());
2062 break;
2067 painter->restore();
2068 QWindowsStyle::drawPrimitive(element, option, painter, widget);
2069 return;
2070 }
2071 painter->restore();
2072 }
2073 return;
2074
2075 case PE_Widget: {
2076#if QT_CONFIG(dialogbuttonbox)
2077 const QDialogButtonBox *buttonBox = nullptr;
2078 if (qobject_cast<const QMessageBox *> (widget))
2079 buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
2080#if QT_CONFIG(inputdialog)
2081 else if (qobject_cast<const QInputDialog *> (widget))
2082 buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
2083#endif // QT_CONFIG(inputdialog)
2084 if (buttonBox) {
2085 //draw white panel part
2088 TDLG_PRIMARYPANEL, 0, option->rect);
2089 QRect toprect = option->rect;
2090 toprect.setBottom(buttonBox->geometry().top());
2091 theme.rect = toprect;
2092 d->drawBackground(theme);
2093
2094 //draw bottom panel part
2095 QRect buttonRect = option->rect;
2096 buttonRect.setTop(buttonBox->geometry().top());
2097 theme.rect = buttonRect;
2098 theme.partId = TDLG_SECONDARYPANEL;
2099 d->drawBackground(theme);
2100 }
2101#endif
2102 return;
2103 }
2104
2105 case PE_PanelItemViewItem: {
2106 const QStyleOptionViewItem *vopt;
2107 bool newStyle = true;
2110 if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
2111 newStyle = !qobject_cast<const QTableView*>(view);
2112 selectionBehavior = view->selectionBehavior();
2113 selectionMode = view->selectionMode();
2114#if QT_CONFIG(accessibility)
2115 } else if (!widget) {
2116 newStyle = !QStyleHelper::hasAncestor(option->styleObject, QAccessible::MenuItem) ;
2117#endif
2118 }
2119
2120 if (newStyle && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
2121 bool selected = vopt->state & QStyle::State_Selected;
2122 const bool hover = selectionMode != QAbstractItemView::NoSelection && (vopt->state & QStyle::State_MouseOver);
2123 bool active = vopt->state & QStyle::State_Active;
2124
2125 if (vopt->features & QStyleOptionViewItem::Alternate)
2126 painter->fillRect(vopt->rect, vopt->palette.alternateBase());
2127
2130 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
2131 cg = QPalette::Inactive;
2132
2134 itemRect.setTop(vopt->rect.top());
2135 itemRect.setBottom(vopt->rect.bottom());
2136
2137 QSize sectionSize = itemRect.size();
2138 if (vopt->showDecorationSelected)
2139 sectionSize = vopt->rect.size();
2140
2141 if (selectionBehavior == QAbstractItemView::SelectRows)
2142 sectionSize.setWidth(vopt->rect.width());
2144
2145 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
2146 const QPointF oldBrushOrigin = painter->brushOrigin();
2147 painter->setBrushOrigin(vopt->rect.topLeft());
2148 painter->fillRect(vopt->rect, vopt->backgroundBrush);
2149 painter->setBrushOrigin(oldBrushOrigin);
2150 }
2151
2152 if (hover || selected) {
2153 if (sectionSize.width() > 0 && sectionSize.height() > 0) {
2154 QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width())
2155 .arg(sectionSize.height()).arg(selected).arg(active).arg(hover);
2156 if (!QPixmapCache::find(key, &pixmap)) {
2157 pixmap = QPixmap(sectionSize);
2158 pixmap.fill(Qt::transparent);
2159
2160 int state;
2161 if (selected && hover)
2163 else if (selected && !active)
2165 else if (selected)
2167 else
2168 state = LISS_HOT;
2169
2170 QPainter pixmapPainter(&pixmap);
2171
2172 QWindowsThemeData theme(widget, &pixmapPainter,
2174 LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height()));
2175
2176 if (!theme.isValid())
2177 break;
2178
2179 d->drawBackground(theme);
2181 }
2182 }
2183
2184 if (vopt->showDecorationSelected) {
2185 const int frame = 2; //Assumes a 2 pixel pixmap border
2186 QRect srcRect = QRect(0, 0, sectionSize.width(), sectionSize.height());
2187 QRect pixmapRect = vopt->rect;
2188 bool reverse = vopt->direction == Qt::RightToLeft;
2189 bool leftSection = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
2190 bool rightSection = vopt->viewItemPosition == QStyleOptionViewItem::End;
2191 if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne
2192 || vopt->viewItemPosition == QStyleOptionViewItem::Invalid)
2193 painter->drawPixmap(pixmapRect.topLeft(), pixmap);
2194 else if (reverse ? rightSection : leftSection){
2195 painter->drawPixmap(QRect(pixmapRect.topLeft(),
2196 QSize(frame, pixmapRect.height())), pixmap,
2197 QRect(QPoint(0, 0), QSize(frame, pixmapRect.height())));
2198 painter->drawPixmap(pixmapRect.adjusted(frame, 0, 0, 0),
2199 pixmap, srcRect.adjusted(frame, 0, -frame, 0));
2200 } else if (reverse ? leftSection : rightSection) {
2201 painter->drawPixmap(QRect(pixmapRect.topRight() - QPoint(frame - 1, 0),
2202 QSize(frame, pixmapRect.height())), pixmap,
2203 QRect(QPoint(pixmapRect.width() - frame, 0),
2204 QSize(frame, pixmapRect.height())));
2205 painter->drawPixmap(pixmapRect.adjusted(0, 0, -frame, 0),
2206 pixmap, srcRect.adjusted(frame, 0, -frame, 0));
2207 } else if (vopt->viewItemPosition == QStyleOptionViewItem::Middle)
2208 painter->drawPixmap(pixmapRect, pixmap,
2209 srcRect.adjusted(frame, 0, -frame, 0));
2210 } else {
2211 if (vopt->text.isEmpty() && vopt->icon.isNull())
2212 break;
2213 painter->drawPixmap(itemRect.topLeft(), pixmap);
2214 }
2215 }
2216 return;
2217 }
2218 break;
2219 }
2220
2221 default:
2222 break;
2223 }
2224
2225 QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
2226
2227 if (!theme.isValid()) {
2228 QWindowsStyle::drawPrimitive(element, option, painter, widget);
2229 return;
2230 }
2231
2232 theme.mirrorHorizontally = hMirrored;
2233 theme.mirrorVertically = vMirrored;
2234 theme.noBorder = noBorder;
2235 theme.noContent = noContent;
2236 theme.rotate = rotate;
2237
2238 d->drawBackground(theme);
2239}
2240
2243 QStyleHintReturn *returnData) const
2244{
2245 QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
2246
2247 int ret = 0;
2248 switch (hint) {
2249 case SH_EtchDisabledText:
2250 ret = (qobject_cast<const QLabel*>(widget) != 0);
2251 break;
2252
2253 case SH_SpinControls_DisableOnBounds:
2254 ret = 0;
2255 break;
2256
2257 case SH_TitleBar_AutoRaise:
2258 case SH_TitleBar_NoBorder:
2259 ret = 1;
2260 break;
2261
2262 case SH_GroupBox_TextLabelColor:
2263 if (!widget || widget->isEnabled())
2264 ret = d->groupBoxTextColor;
2265 else
2266 ret = d->groupBoxTextColorDisabled;
2267 break;
2268
2269 case SH_WindowFrame_Mask: {
2270 ret = 1;
2271 auto *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData);
2272 const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option);
2273 if (mask && titlebar) {
2274 // Note certain themes will not return the whole window frame but only the titlebar part when
2275 // queried This function needs to return the entire window mask, hence we will only fetch the mask for the
2276 // titlebar itself and add the remaining part of the window rect at the bottom.
2277 int tbHeight = proxy()->pixelMetric(PM_TitleBarHeight, option, widget);
2278 QRect titleBarRect = option->rect;
2279 titleBarRect.setHeight(tbHeight);
2280 QWindowsThemeData themeData;
2281 if (titlebar->titleBarState & Qt::WindowMinimized) {
2282 themeData = QWindowsThemeData(widget, nullptr,
2284 WP_MINCAPTION, CS_ACTIVE, titleBarRect);
2285 } else
2286 themeData = QWindowsThemeData(widget, nullptr,
2288 WP_CAPTION, CS_ACTIVE, titleBarRect);
2289 mask->region = d->region(themeData) +
2290 QRect(0, tbHeight, option->rect.width(), option->rect.height() - tbHeight);
2291 }
2292 break;
2293 }
2294
2295#if QT_CONFIG(rubberband)
2296 case SH_RubberBand_Mask:
2297 if (qstyleoption_cast<const QStyleOptionRubberBand *>(option))
2298 ret = 0;
2299 break;
2300#endif // QT_CONFIG(rubberband)
2301
2302 case SH_MessageBox_CenterButtons:
2303 ret = false;
2304 break;
2305
2306 case SH_ToolTip_Mask:
2307 if (option) {
2308 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(returnData)) {
2309 ret = true;
2310 QWindowsThemeData themeData(widget, nullptr,
2312 TTP_STANDARD, TTSS_NORMAL, option->rect);
2313 mask->region = d->region(themeData);
2314 }
2315 }
2316 break;
2317
2318 case SH_Table_GridLineColor:
2319 if (option)
2320 ret = int(option->palette.color(QPalette::Base).darker(118).rgba());
2321 else
2322 ret = -1;
2323 break;
2324
2325 case SH_Header_ArrowAlignment:
2327 break;
2328
2329 case SH_ItemView_DrawDelegateFrame:
2330 ret = 1;
2331 break;
2332
2333 default:
2334 ret = QWindowsStyle::styleHint(hint, option, widget, returnData);
2335 break;
2336 }
2337
2338 return ret;
2339}
2340
2341
2347void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption *option,
2348 QPainter *painter, const QWidget *widget) const
2349{
2351 QWindowsStyle::drawControl(element, option, painter, widget);
2352 return;
2353 }
2354
2355 QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
2356
2357 bool selected = option->state & State_Selected;
2358 bool pressed = option->state & State_Sunken;
2359 bool disabled = !(option->state & State_Enabled);
2360
2361 int state = option->state;
2362 int themeNumber = -1;
2363
2364 QRect rect(option->rect);
2365 State flags = option->state;
2366 int partId = 0;
2367 int stateId = 0;
2368
2369 if (d->transitionsEnabled() && canAnimate(option)) {
2370 if (element == CE_PushButtonBevel) {
2371 QRect oldRect;
2372 QRect newRect;
2373
2374 QObject *styleObject = option->styleObject;
2375
2376 int oldState = styleObject->property("_q_stylestate").toInt();
2377 oldRect = styleObject->property("_q_stylerect").toRect();
2378 newRect = option->rect;
2379 styleObject->setProperty("_q_stylestate", int(option->state));
2380 styleObject->setProperty("_q_stylerect", option->rect);
2381
2382 bool wasDefault = false;
2383 bool isDefault = false;
2384 if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
2385 wasDefault = styleObject->property("_q_isdefault").toBool();
2386 isDefault = button->features & QStyleOptionButton::DefaultButton;
2387 styleObject->setProperty("_q_isdefault", isDefault);
2388 }
2389
2390 bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) ||
2391 (state & State_On) != (oldState & State_On) ||
2392 (state & State_MouseOver) != (oldState & State_MouseOver));
2393
2394 if (oldRect != newRect || (wasDefault && !isDefault)) {
2395 doTransition = false;
2396 d->stopAnimation(styleObject);
2397 }
2398
2399 if (doTransition) {
2400 styleObject->setProperty("_q_no_animation", true);
2401
2403 QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
2405 styleOption->state = QStyle::State(oldState);
2406
2408 QPainter startPainter(&startImage);
2409
2410 // Use current state of existing animation if already one is running
2411 if (!anim) {
2412 proxy()->drawControl(element, styleOption, &startPainter, widget);
2413 } else {
2414 anim->paint(&startPainter, styleOption);
2415 d->stopAnimation(styleObject);
2416 }
2417
2418 t->setStartImage(startImage);
2420 QPainter endPainter(&endImage);
2421 styleOption->state = option->state;
2422 proxy()->drawControl(element, styleOption, &endPainter, widget);
2423 t->setEndImage(endImage);
2424
2425
2426 DWORD duration = 0;
2427 const HTHEME theme = OpenThemeData(nullptr, L"Button");
2428
2429 int fromState = buttonStateId(oldState, BP_PUSHBUTTON);
2430 int toState = buttonStateId(option->state, BP_PUSHBUTTON);
2431 if (GetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK)
2432 t->setDuration(int(duration));
2433 else
2434 t->setDuration(0);
2435 t->setStartTime(d->animationTime());
2436 styleObject->setProperty("_q_no_animation", false);
2437
2439 d->startAnimation(t);
2440 }
2441
2442 QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
2443 if (anim) {
2444 anim->paint(painter, option);
2445 return;
2446 }
2447
2448 }
2449 }
2450
2451 bool hMirrored = false;
2452 bool vMirrored = false;
2453 int rotate = 0;
2454
2455 switch (element) {
2456 case CE_PushButtonBevel:
2457 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
2459 partId = BP_PUSHBUTTON;
2461 partId = BP_COMMANDLINK;
2462 bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken));
2463 if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
2464 stateId = PBS_DISABLED;
2465 else if (justFlat)
2466 ;
2467 else if (flags & (State_Sunken | State_On))
2468 stateId = PBS_PRESSED;
2469 else if (flags & State_MouseOver)
2470 stateId = PBS_HOT;
2471 else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active))
2472 stateId = PBS_DEFAULTED;
2473 else
2474 stateId = PBS_NORMAL;
2475
2476 if (!justFlat) {
2477
2478 if (d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) &&
2479 !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) &&
2480 (state & State_Enabled) && (state & State_Active))
2481 {
2482 QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)));
2483
2484 if (!anim) {
2486 QImage alternateImage = createAnimationBuffer(option, widget);
2487
2489
2490 QPainter startPainter(&startImage);
2491 stateId = PBS_DEFAULTED;
2492 QWindowsThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect);
2493 d->drawBackground(theme);
2494
2495 QPainter alternatePainter(&alternateImage);
2496 theme.stateId = PBS_DEFAULTED_ANIMATING;
2497 theme.painter = &alternatePainter;
2498 d->drawBackground(theme);
2499
2500 pulse->setStartImage(startImage);
2501 pulse->setEndImage(alternateImage);
2502 pulse->setStartTime(d->animationTime());
2503 pulse->setDuration(2000);
2504 d->startAnimation(pulse);
2505 anim = pulse;
2506 }
2507
2508 if (anim)
2509 anim->paint(painter, option);
2510 else {
2511 QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
2512 d->drawBackground(theme);
2513 }
2514 }
2515 else {
2516 QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
2517 d->drawBackground(theme);
2518 }
2519 }
2520
2522 int mbiw = 0, mbih = 0;
2524 TP_DROPDOWNBUTTON);
2525 if (theme.isValid()) {
2526 const QSizeF size = theme.size() * QStyleHelper::dpiScaled(1, option);
2527 if (!size.isEmpty()) {
2528 mbiw = qRound(size.width());
2529 mbih = qRound(size.height());
2530 }
2531 }
2532 QRect ir = subElementRect(SE_PushButtonContents, option, nullptr);
2533 QStyleOptionButton newBtn = *btn;
2534 newBtn.rect = QStyle::visualRect(option->direction, option->rect,
2535 QRect(ir.right() - mbiw - 2,
2536 option->rect.top() + (option->rect.height()/2) - (mbih/2),
2537 mbiw + 1, mbih + 1));
2538 proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
2539 }
2540 }
2541 return;
2542
2543 case CE_SizeGrip: {
2545 partId = SP_GRIPPER;
2546 QWindowsThemeData theme(nullptr, painter, themeNumber, partId);
2547 QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
2548 size.rheight()--;
2549 if (const auto *sg = qstyleoption_cast<const QStyleOptionSizeGrip *>(option)) {
2550 switch (sg->corner) {
2552 rect = QRect(QPoint(rect.right() - size.width(), rect.bottom() - size.height()), size);
2553 break;
2555 rect = QRect(QPoint(rect.left() + 1, rect.bottom() - size.height()), size);
2556 hMirrored = true;
2557 break;
2558 case Qt::TopRightCorner:
2559 rect = QRect(QPoint(rect.right() - size.width(), rect.top() + 1), size);
2560 vMirrored = true;
2561 break;
2562 case Qt::TopLeftCorner:
2563 rect = QRect(rect.topLeft() + QPoint(1, 1), size);
2564 hMirrored = vMirrored = true;
2565 }
2566 }
2567 break;
2568 }
2569
2570 case CE_Splitter:
2571 painter->eraseRect(option->rect);
2572 return;
2573
2574 case CE_TabBarTab:
2575 if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
2576 stateId = tab->state & State_Enabled ? TIS_NORMAL : TIS_DISABLED;
2577 break;
2578
2579 case CE_TabBarTabShape:
2580 if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
2582 const bool isDisabled = !(tab->state & State_Enabled);
2583 const bool hasFocus = tab->state & State_HasFocus;
2584 const bool isHot = tab->state & State_MouseOver;
2585 const bool selected = tab->state & State_Selected;
2586 bool lastTab = tab->position == QStyleOptionTab::End;
2587 bool firstTab = tab->position == QStyleOptionTab::Beginning;
2588 const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
2589 const bool leftAligned = proxy()->styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignLeft;
2590 const bool centerAligned = proxy()->styleHint(SH_TabBar_Alignment, tab, widget) == Qt::AlignCenter;
2591 const int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
2592 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, option, widget);
2593
2594 if (isDisabled)
2595 stateId = TIS_DISABLED;
2596 else if (selected)
2597 stateId = TIS_SELECTED;
2598 else if (hasFocus)
2599 stateId = TIS_FOCUSED;
2600 else if (isHot)
2601 stateId = TIS_HOT;
2602 else
2603 stateId = TIS_NORMAL;
2604
2605 // Selecting proper part depending on position
2606 if (firstTab || onlyOne) {
2607 if (leftAligned)
2608 partId = TABP_TABITEMLEFTEDGE;
2609 else if (centerAligned)
2610 partId = TABP_TABITEM;
2611 else // rightAligned
2612 partId = TABP_TABITEMRIGHTEDGE;
2613 } else {
2614 partId = TABP_TABITEM;
2615 }
2616
2617 if (tab->direction == Qt::RightToLeft
2618 && (tab->shape == QTabBar::RoundedNorth || tab->shape == QTabBar::RoundedSouth)) {
2619 bool temp = firstTab;
2620 firstTab = lastTab;
2621 lastTab = temp;
2622 }
2623
2624 const bool begin = firstTab || onlyOne;
2625 const bool end = lastTab || onlyOne;
2626
2627 switch (tab->shape) {
2629 if (selected)
2630 rect.adjust(begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap, borderThickness);
2631 else
2632 rect.adjust(begin? tabOverlap : 0, tabOverlap, end ? -tabOverlap : 0, 0);
2633 break;
2635 //vMirrored = true;
2636 rotate = 180; // Not 100% correct, but works
2637 if (selected)
2638 rect.adjust(begin ? 0 : -tabOverlap , -borderThickness, end ? 0 : tabOverlap, 0);
2639 else
2640 rect.adjust(begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0 , -tabOverlap);
2641 break;
2643 rotate = 90;
2644 if (selected)
2645 rect.adjust(-borderThickness, begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap);
2646 else
2647 rect.adjust(0, begin ? tabOverlap : 0, -tabOverlap, end ? -tabOverlap : 0);
2648 break;
2650 hMirrored = true;
2651 rotate = 90;
2652 if (selected)
2653 rect.adjust(0, begin ? 0 : -tabOverlap, borderThickness, end ? 0 : tabOverlap);
2654 else
2655 rect.adjust(tabOverlap, begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0);
2656 break;
2657 default:
2658 themeNumber = -1; // Do our own painting for triangular
2659 break;
2660 }
2661
2662 if (!selected) {
2663 switch (tab->shape) {
2665 rect.adjust(0,0, 0,-1);
2666 break;
2668 rect.adjust(0,1, 0,0);
2669 break;
2671 rect.adjust( 1,0, 0,0);
2672 break;
2674 rect.adjust(0,0, -1,0);
2675 break;
2676 default:
2677 break;
2678 }
2679 }
2680 }
2681 break;
2682
2683 case CE_ProgressBarGroove: {
2685 if (const auto *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
2686 if (!(pb->state & QStyle::State_Horizontal))
2687 orient = Qt::Vertical;
2688
2689 partId = (orient == Qt::Horizontal) ? PP_BAR : PP_BARVERT;
2691 stateId = 1;
2692 break;
2693 }
2694
2695 case CE_ProgressBarContents:
2696 if (const auto *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
2697 bool isIndeterminate = (bar->minimum == 0 && bar->maximum == 0);
2698 const bool vertical = !(bar->state & QStyle::State_Horizontal);
2699 const bool inverted = bar->invertedAppearance;
2700
2701 if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) {
2702 if (!d->animation(styleObject(option)))
2703 d->startAnimation(new QProgressStyleAnimation(d->animationFps, styleObject(option)));
2704 } else {
2705 d->stopAnimation(styleObject(option));
2706 }
2707
2710 vertical ? PP_FILLVERT : PP_FILL);
2711 theme.rect = option->rect;
2712 bool reverse = (bar->direction == Qt::LeftToRight && inverted) || (bar->direction == Qt::RightToLeft && !inverted);
2713 QTime current = d->animationTime();
2714
2715 if (isIndeterminate) {
2716 if (auto *progressAnimation = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
2717 int glowSize = 120;
2718 int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
2719 int animOffset = progressAnimation->startTime().msecsTo(current) / 4;
2720 if (animOffset > animationWidth)
2721 progressAnimation->setStartTime(d->animationTime());
2722 painter->save();
2723 painter->setClipRect(theme.rect);
2724 QRect animRect;
2725 QSize pixmapSize(14, 14);
2726 if (vertical) {
2727 animRect = QRect(theme.rect.left(),
2728 inverted ? rect.top() - glowSize + animOffset :
2729 rect.bottom() + glowSize - animOffset,
2730 rect.width(), glowSize);
2731 pixmapSize.setHeight(animRect.height());
2732 } else {
2733 animRect = QRect(rect.left() - glowSize + animOffset,
2734 rect.top(), glowSize, rect.height());
2735 animRect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
2736 option->rect, animRect);
2737 pixmapSize.setWidth(animRect.width());
2738 }
2739 QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height());
2741 if (!QPixmapCache::find(name, &pixmap)) {
2742 QImage image(pixmapSize, QImage::Format_ARGB32);
2743 image.fill(Qt::transparent);
2744 QPainter imagePainter(&image);
2745 theme.painter = &imagePainter;
2746 theme.partId = vertical ? PP_FILLVERT : PP_FILL;
2747 theme.rect = QRect(QPoint(0,0), animRect.size());
2748 QLinearGradient alphaGradient(0, 0, vertical ? 0 : image.width(),
2749 vertical ? image.height() : 0);
2750 alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
2751 alphaGradient.setColorAt(0.5, QColor(0, 0, 0, 220));
2752 alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
2753 imagePainter.fillRect(image.rect(), alphaGradient);
2755 d->drawBackground(theme);
2756 imagePainter.end();
2759 }
2760 painter->drawPixmap(animRect, pixmap);
2761 painter->restore();
2762 }
2763 } else {
2764 qint64 progress = qMax<qint64>(bar->progress, bar->minimum); // workaround for bug in QProgressBar
2765
2766 if (vertical) {
2767 int maxHeight = option->rect.height();
2768 int minHeight = 0;
2769 double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxHeight);
2770 int height = isIndeterminate ? maxHeight: qMax(int(vc6_workaround), minHeight);
2771 theme.rect.setHeight(height);
2772 if (!inverted)
2773 theme.rect.moveTop(rect.height() - theme.rect.height());
2774 } else {
2775 int maxWidth = option->rect.width();
2776 int minWidth = 0;
2777 double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth);
2778 int width = isIndeterminate ? maxWidth : qMax(int(vc6_workaround), minWidth);
2779 theme.rect.setWidth(width);
2781 option->rect, theme.rect);
2782 }
2783 d->drawBackground(theme);
2784
2785 if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
2786 int glowSize = 140;
2787 int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
2788 int animOffset = a->startTime().msecsTo(current) / 4;
2789 theme.partId = vertical ? PP_MOVEOVERLAYVERT : PP_MOVEOVERLAY;
2790 if (animOffset > animationWidth) {
2791 if (bar->progress < bar->maximum)
2792 a->setStartTime(d->animationTime());
2793 else
2794 d->stopAnimation(styleObject(option)); //we stop the glow motion only after it has
2795 //moved out of view
2796 }
2797 painter->save();
2798 painter->setClipRect(theme.rect);
2799 if (vertical) {
2800 theme.rect = QRect(theme.rect.left(),
2801 inverted ? rect.top() - glowSize + animOffset :
2802 rect.bottom() + glowSize - animOffset,
2803 rect.width(), glowSize);
2804 } else {
2805 theme.rect = QRect(rect.left() - glowSize + animOffset,rect.top(), glowSize, rect.height());
2806 theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, option->rect, theme.rect);
2807 }
2808 d->drawBackground(theme);
2809 painter->restore();
2810 }
2811 }
2812 }
2813 return;
2814
2815 case CE_MenuBarItem:
2816 if (const auto *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
2817 if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
2818 break;
2819
2821 QPixmap pix = mbi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
2822
2824 if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
2826
2827 if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls
2828 //The rect adjustment is a workaround for the menu not really filling its background.
2831 MENU_BARBACKGROUND, 0, option->rect.adjusted(-1, 0, 2, 1));
2832 d->drawBackground(theme);
2833
2834 int stateId = MBI_NORMAL;
2835 if (disabled)
2836 stateId = MBI_DISABLED;
2837 else if (pressed)
2838 stateId = MBI_PUSHED;
2839 else if (selected)
2840 stateId = MBI_HOT;
2841
2844 MENU_BARITEM, stateId, option->rect);
2845 d->drawBackground(theme2);
2846 }
2847
2848 if (!pix.isNull())
2849 drawItemPixmap(painter, mbi->rect, alignment, pix);
2850 else
2851 drawItemText(painter, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
2852 }
2853 return;
2854
2855#if QT_CONFIG(menu)
2856 case CE_MenuEmptyArea:
2857 if (const auto *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
2858 QBrush fill = menuitem->palette.brush((menuitem->state & State_Selected) ?
2861 break;
2862 }
2863 return;
2864
2865 case CE_MenuItem:
2866 if (const auto *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
2867 // windows always has a check column, regardless whether we have an icon or not
2868 const qreal factor = QWindowsVistaStylePrivate::nativeMetricScaleFactor(widget);
2869 int checkcol = qRound(qreal(25) * factor);
2870 const int gutterWidth = qRound(qreal(3) * factor);
2871 {
2873 MENU_POPUPCHECKBACKGROUND, MBI_HOT);
2874 QWindowsThemeData themeSize = theme;
2875 themeSize.partId = MENU_POPUPCHECK;
2876 themeSize.stateId = 0;
2877 const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
2878 const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
2879 checkcol = qMax(menuitem->maxIconWidth, qRound(gutterWidth + size.width() + margins.left() + margins.right()));
2880 }
2881 QRect rect = option->rect;
2882
2883 //draw vertical menu line
2884 if (option->direction == Qt::LeftToRight)
2885 checkcol += rect.x();
2886 QPoint p1 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.top()));
2887 QPoint p2 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.bottom()));
2888 QRect gutterRect(p1.x(), p1.y(), gutterWidth, p2.y() - p1.y() + 1);
2890 MENU_POPUPGUTTER, stateId, gutterRect);
2891 d->drawBackground(theme2);
2892
2893 int x, y, w, h;
2894 menuitem->rect.getRect(&x, &y, &w, &h);
2895 int tab = menuitem->reservedShortcutWidth;
2896 bool dis = !(menuitem->state & State_Enabled);
2897 bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
2898 ? menuitem->checked : false;
2899 bool act = menuitem->state & State_Selected;
2900
2901 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
2902 int yoff = y-2 + h / 2;
2903 const int separatorSize = qRound(qreal(6) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
2904 QPoint p1 = QPoint(x + checkcol, yoff);
2905 QPoint p2 = QPoint(x + w + separatorSize, yoff);
2906 stateId = MBI_HOT;
2907 QRect subRect(p1.x() + (gutterWidth - menuitem->rect.x()), p1.y(),
2908 p2.x() - p1.x(), separatorSize);
2909 subRect = QStyle::visualRect(option->direction, option->rect, subRect );
2912 MENU_POPUPSEPARATOR, stateId, subRect);
2913 d->drawBackground(theme2);
2914 return;
2915 }
2916
2917 QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(),
2918 menuitem->rect.y(), checkcol - (gutterWidth + menuitem->rect.x()), menuitem->rect.height()));
2919
2920 if (act) {
2921 stateId = dis ? MBI_DISABLED : MBI_HOT;
2924 MENU_POPUPITEM, stateId, option->rect);
2925 d->drawBackground(theme2);
2926 }
2927
2928 if (checked) {
2931 MENU_POPUPCHECKBACKGROUND,
2932 menuitem->icon.isNull() ? MBI_HOT : MBI_PUSHED, vCheckRect);
2933 QWindowsThemeData themeSize = theme;
2934 themeSize.partId = MENU_POPUPCHECK;
2935 themeSize.stateId = 0;
2936 const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
2937 const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
2938 QRect checkRect(0, 0, qRound(size.width() + margins.left() + margins.right()),
2939 qRound(size.height() + margins.bottom() + margins.top()));
2940 checkRect.moveCenter(vCheckRect.center());
2941 theme.rect = checkRect;
2942
2943 d->drawBackground(theme);
2944
2945 if (menuitem->icon.isNull()) {
2946 checkRect = QRect(QPoint(0, 0), size.toSize());
2947 checkRect.moveCenter(theme.rect.center());
2948 theme.rect = checkRect;
2949
2950 theme.partId = MENU_POPUPCHECK;
2951 bool bullet = menuitem->checkType & QStyleOptionMenuItem::Exclusive;
2952 if (dis)
2953 theme.stateId = bullet ? MC_BULLETDISABLED: MC_CHECKMARKDISABLED;
2954 else
2955 theme.stateId = bullet ? MC_BULLETNORMAL: MC_CHECKMARKNORMAL;
2956 d->drawBackground(theme);
2958 && !act) {
2959 painter->fillRect(checkRect, menuitem->palette.highlight().color().lighter(200));
2960 }
2961 }
2962
2963 if (!menuitem->icon.isNull()) {
2965 if (act && !dis)
2967 const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
2968 const auto dpr = painter->device()->devicePixelRatio();
2969 const auto pixmap = menuitem->icon.pixmap({size, size}, dpr, mode,
2970 checked ? QIcon::On : QIcon::Off);
2971 QRect pmr(QPoint(0, 0), pixmap.deviceIndependentSize().toSize());
2972 pmr.moveCenter(vCheckRect.center());
2973 painter->setPen(menuitem->palette.text().color());
2975 }
2976
2977 painter->setPen(menuitem->palette.buttonText().color());
2978
2979 const QColor textColor = menuitem->palette.text().color();
2980 if (dis)
2981 painter->setPen(textColor);
2982
2983 int xm = windowsItemFrame + checkcol + windowsItemHMargin + (gutterWidth - menuitem->rect.x()) - 1;
2984 int xpos = menuitem->rect.x() + xm;
2985 QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
2986 QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
2987 QString s = menuitem->text;
2988 if (!s.isEmpty()) { // draw text
2989 painter->save();
2990 int t = s.indexOf(QLatin1Char('\t'));
2992 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
2993 text_flags |= Qt::TextHideMnemonic;
2994 text_flags |= Qt::AlignLeft;
2995 if (t >= 0) {
2996 QRect vShortcutRect = visualRect(option->direction, menuitem->rect,
2997 QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
2998 painter->drawText(vShortcutRect, text_flags, s.mid(t + 1));
2999 s = s.left(t);
3000 }
3001 QFont font = menuitem->font;
3002 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
3003 font.setBold(true);
3005 painter->setPen(textColor);
3006 painter->drawText(vTextRect, text_flags, s.left(t));
3007 painter->restore();
3008 }
3009 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
3010 int dim = (h - 2 * windowsItemFrame) / 2;
3011 PrimitiveElement arrow;
3012 arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
3013 xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
3014 QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
3015 QStyleOptionMenuItem newMI = *menuitem;
3016 newMI.rect = vSubMenuRect;
3017 newMI.state = dis ? State_None : State_Enabled;
3018 proxy()->drawPrimitive(arrow, &newMI, painter, widget);
3019 }
3020 }
3021 return;
3022#endif // QT_CONFIG(menu)
3023
3024 case CE_HeaderSection:
3025 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
3026 partId = HP_HEADERITEM;
3027 if (flags & State_Sunken)
3028 stateId = HIS_PRESSED;
3029 else if (flags & State_MouseOver)
3030 stateId = HIS_HOT;
3031 else
3032 stateId = HIS_NORMAL;
3033
3034 if (header->sortIndicator != QStyleOptionHeader::None)
3035 stateId += 3;
3036
3039 partId, stateId, option->rect);
3040 d->drawBackground(theme);
3041 }
3042 return;
3043
3044 case CE_MenuBarEmptyArea: {
3045 stateId = MBI_NORMAL;
3046 if (!(state & State_Enabled))
3047 stateId = MBI_DISABLED;
3049 MENU_BARBACKGROUND, stateId, option->rect);
3050 d->drawBackground(theme);
3051 return;
3052 }
3053
3054 case CE_ToolBar:
3055 if (const auto *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) {
3056 QPalette pal = option->palette;
3057 pal.setColor(QPalette::Dark, option->palette.window().color().darker(130));
3058 QStyleOptionToolBar copyOpt = *toolbar;
3059 copyOpt.palette = pal;
3060 QWindowsStyle::drawControl(element, &copyOpt, painter, widget);
3061 }
3062 return;
3063
3064#if QT_CONFIG(dockwidget)
3065 case CE_DockWidgetTitle:
3066 if (const auto *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
3067 QRect rect = option->rect;
3068 const QDockWidget *dw = qobject_cast<const QDockWidget *>(widget);
3069 bool isFloating = dw && dw->isFloating();
3070 int buttonMargin = 4;
3071 int mw = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
3072 int fw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget);
3073
3074 const bool verticalTitleBar = dwOpt->verticalTitleBar;
3075
3076 if (verticalTitleBar) {
3077 rect = rect.transposed();
3078
3079 painter->translate(rect.left() - 1, rect.top() + rect.width());
3080 painter->rotate(-90);
3081 painter->translate(-rect.left() + 1, -rect.top());
3082 }
3083
3084 QRect r = option->rect.adjusted(0, 2, -1, -3);
3085 QRect titleRect = r;
3086
3087 if (dwOpt->closable) {
3088 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10));
3089 titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
3090 }
3091
3092 if (dwOpt->floatable) {
3093 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10));
3094 titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
3095 }
3096
3097 if (isFloating) {
3098 titleRect.adjust(0, -fw, 0, 0);
3100 titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
3101 } else {
3102 titleRect.adjust(mw, 0, 0, 0);
3103 if (!dwOpt->floatable && !dwOpt->closable)
3104 titleRect.adjust(0, 0, -mw, 0);
3105 }
3106
3107 if (!verticalTitleBar)
3108 titleRect = visualRect(dwOpt->direction, r, titleRect);
3109
3110 if (isFloating) {
3111 const bool isActive = dwOpt->state & State_Active;
3113 if (isActive)
3114 stateId = CS_ACTIVE;
3115 else
3116 stateId = CS_INACTIVE;
3117
3118 int titleHeight = rect.height() - 2;
3119 rect = rect.adjusted(-fw, -fw, fw, 0);
3120
3121 QWindowsThemeData theme(widget, painter, themeNumber, 0, stateId);
3122 if (!theme.isValid())
3123 break;
3124
3125 // Draw small type title bar
3126 theme.rect = rect;
3127 theme.partId = WP_SMALLCAPTION;
3128 d->drawBackground(theme);
3129
3130 // Figure out maximal button space on title bar
3131
3132 QIcon ico = widget->windowIcon();
3133 bool hasIcon = (ico.cacheKey() != QApplication::windowIcon().cacheKey());
3134 if (hasIcon) {
3135 QPixmap pxIco = ico.pixmap(titleHeight);
3136 if (!verticalTitleBar && dwOpt->direction == Qt::RightToLeft)
3137 painter->drawPixmap(rect.width() - titleHeight - pxIco.width(), rect.bottom() - titleHeight - 2, pxIco);
3138 else
3139 painter->drawPixmap(fw, rect.bottom() - titleHeight - 2, pxIco);
3140 }
3141 if (!dwOpt->title.isEmpty()) {
3142 QPen oldPen = painter->pen();
3143 QFont oldFont = painter->font();
3144 QFont titleFont = oldFont;
3145 titleFont.setBold(true);
3146 painter->setFont(titleFont);
3147 QString titleText
3148 = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
3149
3150 int result = TST_NONE;
3151 GetThemeEnumValue(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
3152 if (result != TST_NONE) {
3153 COLORREF textShadowRef;
3154 GetThemeColor(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
3155 QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
3156 painter->setPen(textShadow);
3157 drawItemText(painter, titleRect.adjusted(1, 1, 1, 1),
3158 Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
3159 dwOpt->state & State_Enabled, titleText);
3160 }
3161
3162 COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
3163 QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
3164 painter->setPen(textColor);
3165 drawItemText(painter, titleRect,
3166 Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
3167 dwOpt->state & State_Enabled, titleText);
3168 painter->setFont(oldFont);
3169 painter->setPen(oldPen);
3170 }
3171 } else {
3172 painter->setBrush(option->palette.window().color().darker(110));
3173 painter->setPen(option->palette.window().color().darker(130));
3174 painter->drawRect(rect.adjusted(0, 1, -1, -3));
3175
3176 if (!dwOpt->title.isEmpty()) {
3177 QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
3178 verticalTitleBar ? titleRect.height() : titleRect.width());
3179 const int indent = 4;
3180 drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1),
3182 dwOpt->palette,
3183 dwOpt->state & State_Enabled, titleText,
3185 }
3186 }
3187 }
3188 return;
3189#endif // QT_CONFIG(dockwidget)
3190
3191#if QT_CONFIG(rubberband)
3192 case CE_RubberBand:
3193 if (qstyleoption_cast<const QStyleOptionRubberBand *>(option)) {
3194 QColor highlight = option->palette.color(QPalette::Active, QPalette::Highlight);
3195 painter->save();
3196 painter->setPen(highlight.darker(120));
3197 QColor dimHighlight(qMin(highlight.red()/2 + 110, 255),
3198 qMin(highlight.green()/2 + 110, 255),
3199 qMin(highlight.blue()/2 + 110, 255),
3200 (widget && widget->isWindow())? 255 : 127);
3201 painter->setBrush(dimHighlight);
3202 painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
3203 painter->restore();
3204 return;
3205 }
3206 break;
3207#endif // QT_CONFIG(rubberband)
3208
3209 case CE_HeaderEmptyArea:
3210 if (option->state & State_Horizontal) {
3212 stateId = HIS_NORMAL;
3213 } else {
3214 QWindowsStyle::drawControl(CE_HeaderEmptyArea, option, painter, widget);
3215 return;
3216 }
3217 break;
3218
3219#if QT_CONFIG(itemviews)
3220 case CE_ItemViewItem: {
3221 const QStyleOptionViewItem *vopt;
3222 const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
3223 bool newStyle = true;
3224
3225 if (qobject_cast<const QTableView*>(widget))
3226 newStyle = false;
3227
3228 QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
3229
3230 if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
3231 /*
3232 // We cannot currently get the correct selection color for "explorer style" views
3233 COLORREF cref = 0;
3234 QWindowsThemeData theme(d->treeViewHelper(), 0, QLatin1String("LISTVIEW"), 0, 0);
3235 unsigned int res = GetThemeColor(theme.handle(), LVP_LISTITEM, LISS_SELECTED, TMT_TEXTCOLOR, &cref);
3236 QColor textColor(GetRValue(cref), GetGValue(cref), GetBValue(cref));
3237 */
3238 QPalette palette = vopt->palette;
3240 // Note that setting a saturated color here results in ugly XOR colors in the focus rect
3241 palette.setColor(QPalette::All, QPalette::Highlight, palette.base().color().darker(108));
3242 QStyleOptionViewItem adjustedOption = *vopt;
3243 adjustedOption.palette = palette;
3244 // We hide the focusrect in singleselection as it is not required
3245 if ((view->selectionMode() == QAbstractItemView::SingleSelection)
3246 && !(vopt->state & State_KeyboardFocusChange))
3247 adjustedOption.state &= ~State_HasFocus;
3248 if (!theme.isValid()) {
3249 QWindowsStyle::drawControl(element, &adjustedOption, painter, widget);
3250 return;
3251 }
3252 } else {
3253 if (!theme.isValid()) {
3254 QWindowsStyle::drawControl(element, option, painter, widget);
3255 return;
3256 }
3257 }
3258
3259 theme.rotate = rotate;
3260 theme.mirrorHorizontally = hMirrored;
3261 theme.mirrorVertically = vMirrored;
3262 d->drawBackground(theme);
3263 return;
3264 }
3265#endif // QT_CONFIG(itemviews)
3266
3267#if QT_CONFIG(combobox)
3268 case CE_ComboBoxLabel:
3270 return;
3271#endif // QT_CONFIG(combobox)
3272
3273 default:
3274 break;
3275 }
3276
3277 QWindowsThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
3278
3279 if (!theme.isValid()) {
3280 QWindowsStyle::drawControl(element, option, painter, widget);
3281 return;
3282 }
3283
3284 theme.rotate = rotate;
3285 theme.mirrorHorizontally = hMirrored;
3286 theme.mirrorVertically = vMirrored;
3287
3288 d->drawBackground(theme);
3289}
3290
3297 QPainter *painter, const QWidget *widget) const
3298{
3299 QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
3300
3302 QWindowsStyle::drawComplexControl(control, option, painter, widget);
3303 return;
3304 }
3305
3306 State state = option->state;
3307 SubControls sub = option->subControls;
3308 QRect r = option->rect;
3309
3310 int partId = 0;
3311 int stateId = 0;
3312
3313 State flags = option->state;
3315 flags |= State_MouseOver;
3316
3317 if (d->transitionsEnabled() && canAnimate(option))
3318 {
3319 if (control == CC_ScrollBar || control == CC_SpinBox || control == CC_ComboBox) {
3320 QObject *styleObject = option->styleObject; // Can be widget or qquickitem
3321
3322 int oldState = styleObject->property("_q_stylestate").toInt();
3323 int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
3324
3325 QRect oldRect = styleObject->property("_q_stylerect").toRect();
3326 styleObject->setProperty("_q_stylestate", int(option->state));
3327 styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
3328 styleObject->setProperty("_q_stylerect", option->rect);
3329
3330 bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken)
3331 || (state & State_On) != (oldState & State_On)
3332 || (state & State_MouseOver) != (oldState & State_MouseOver)
3333 || oldActiveControls != int(option->activeSubControls));
3334
3335 if (qstyleoption_cast<const QStyleOptionSlider *>(option)) {
3336 QRect oldSliderPos = styleObject->property("_q_stylesliderpos").toRect();
3337 QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
3338 styleObject->setProperty("_q_stylesliderpos", currentPos);
3339 if (oldSliderPos != currentPos) {
3340 doTransition = false;
3341 d->stopAnimation(styleObject);
3342 }
3343 } else if (control == CC_SpinBox) {
3344 //spinboxes have a transition when focus changes
3345 if (!doTransition)
3346 doTransition = (state & State_HasFocus) != (oldState & State_HasFocus);
3347 }
3348
3349 if (oldRect != option->rect) {
3350 doTransition = false;
3351 d->stopAnimation(styleObject);
3352 }
3353
3354 if (doTransition) {
3356 QPainter startPainter(&startImage);
3357
3359 QPainter endPainter(&endImage);
3360
3361 QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
3363
3364 // Draw the image that ends the animation by using the current styleoption
3365 QStyleOptionComplex *styleOption = qstyleoption_cast<QStyleOptionComplex*>(clonedAnimationStyleOption(option));
3366
3367 styleObject->setProperty("_q_no_animation", true);
3368
3369 // Draw transition source
3370 if (!anim) {
3371 styleOption->state = QStyle::State(oldState);
3372 styleOption->activeSubControls = QStyle::SubControl(oldActiveControls);
3373 proxy()->drawComplexControl(control, styleOption, &startPainter, widget);
3374 } else {
3375 anim->paint(&startPainter, option);
3376 }
3377 t->setStartImage(startImage);
3378
3379 // Draw transition target
3380 styleOption->state = option->state;
3381 styleOption->activeSubControls = option->activeSubControls;
3382 proxy()->drawComplexControl(control, styleOption, &endPainter, widget);
3383
3384 styleObject->setProperty("_q_no_animation", false);
3385
3386 t->setEndImage(endImage);
3387 t->setStartTime(d->animationTime());
3388
3389 if (option->state & State_MouseOver || option->state & State_Sunken)
3390 t->setDuration(150);
3391 else
3392 t->setDuration(500);
3393
3395 d->startAnimation(t);
3396 }
3397 if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject))) {
3398 anim->paint(painter, option);
3399 return;
3400 }
3401 }
3402 }
3403
3404 switch (control) {
3405
3406#if QT_CONFIG(slider)
3407 case CC_Slider:
3408 if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
3410 QRect slrect = slider->rect;
3411 QRegion tickreg = slrect;
3412 if (sub & SC_SliderGroove) {
3413 theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
3414 if (slider->orientation == Qt::Horizontal) {
3415 partId = TKP_TRACK;
3416 stateId = TRS_NORMAL;
3417 theme.rect = QRect(slrect.left(), theme.rect.center().y() - 2, slrect.width(), 4);
3418 } else {
3419 partId = TKP_TRACKVERT;
3420 stateId = TRVS_NORMAL;
3421 theme.rect = QRect(theme.rect.center().x() - 2, slrect.top(), 4, slrect.height());
3422 }
3423 theme.partId = partId;
3424 theme.stateId = stateId;
3425 d->drawBackground(theme);
3426 tickreg -= theme.rect;
3427 }
3428 if (sub & SC_SliderTickmarks) {
3429 int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
3430 int ticks = slider->tickPosition;
3431 int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
3432 int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
3433 int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
3434 int interval = slider->tickInterval;
3435 if (interval <= 0) {
3436 interval = slider->singleStep;
3437 if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
3438 available)
3439 - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
3440 0, available) < 3)
3441 interval = slider->pageStep;
3442 }
3443 if (!interval)
3444 interval = 1;
3445 int fudge = len / 2;
3446 int pos;
3447 int bothOffset = (ticks & QSlider::TicksAbove && ticks & QSlider::TicksBelow) ? 1 : 0;
3448 painter->setPen(d->sliderTickColor);
3450 int v = slider->minimum;
3451 while (v <= slider->maximum + 1) {
3452 if (v == slider->maximum + 1 && interval == 1)
3453 break;
3454 const int v_ = qMin(v, slider->maximum);
3455 int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
3456 pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
3457 v_, available) + fudge;
3458 if (slider->orientation == Qt::Horizontal) {
3459 if (ticks & QSlider::TicksAbove) {
3460 lines.append(QLine(pos, tickOffset - 1 - bothOffset,
3461 pos, tickOffset - 1 - bothOffset - tickLength));
3462 }
3463
3464 if (ticks & QSlider::TicksBelow) {
3465 lines.append(QLine(pos, tickOffset + thickness + bothOffset,
3466 pos, tickOffset + thickness + bothOffset + tickLength));
3467 }
3468 } else {
3469 if (ticks & QSlider::TicksAbove) {
3470 lines.append(QLine(tickOffset - 1 - bothOffset, pos,
3471 tickOffset - 1 - bothOffset - tickLength, pos));
3472 }
3473
3474 if (ticks & QSlider::TicksBelow) {
3475 lines.append(QLine(tickOffset + thickness + bothOffset, pos,
3476 tickOffset + thickness + bothOffset + tickLength, pos));
3477 }
3478 }
3479 // in the case where maximum is max int
3480 int nextInterval = v + interval;
3481 if (nextInterval < v)
3482 break;
3483 v = nextInterval;
3484 }
3485 if (!lines.isEmpty()) {
3486 painter->save();
3487 painter->translate(slrect.topLeft());
3488 painter->drawLines(lines.constData(), lines.size());
3489 painter->restore();
3490 }
3491 }
3492 if (sub & SC_SliderHandle) {
3493 theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
3494 if (slider->orientation == Qt::Horizontal) {
3495 if (slider->tickPosition == QSlider::TicksAbove)
3496 partId = TKP_THUMBTOP;
3497 else if (slider->tickPosition == QSlider::TicksBelow)
3498 partId = TKP_THUMBBOTTOM;
3499 else
3500 partId = TKP_THUMB;
3501
3502 if (!(slider->state & State_Enabled))
3503 stateId = TUS_DISABLED;
3504 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
3505 stateId = TUS_PRESSED;
3506 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
3507 stateId = TUS_HOT;
3508 else if (flags & State_HasFocus)
3509 stateId = TUS_FOCUSED;
3510 else
3511 stateId = TUS_NORMAL;
3512 } else {
3513 if (slider->tickPosition == QSlider::TicksLeft)
3514 partId = TKP_THUMBLEFT;
3515 else if (slider->tickPosition == QSlider::TicksRight)
3516 partId = TKP_THUMBRIGHT;
3517 else
3518 partId = TKP_THUMBVERT;
3519
3520 if (!(slider->state & State_Enabled))
3521 stateId = TUVS_DISABLED;
3522 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
3523 stateId = TUVS_PRESSED;
3524 else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
3525 stateId = TUVS_HOT;
3526 else if (flags & State_HasFocus)
3527 stateId = TUVS_FOCUSED;
3528 else
3529 stateId = TUVS_NORMAL;
3530 }
3531 theme.partId = partId;
3532 theme.stateId = stateId;
3533 d->drawBackground(theme);
3534 }
3535 if (slider->state & State_HasFocus) {
3537 fropt.QStyleOption::operator=(*slider);
3538 fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
3539 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
3540 }
3541 }
3542 break;
3543#endif
3544
3545#if QT_CONFIG(toolbutton)
3546 case CC_ToolButton:
3547 if (const auto *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
3548 QRect button, menuarea;
3549 button = proxy()->subControlRect(control, toolbutton, SC_ToolButton, widget);
3550 menuarea = proxy()->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget);
3551
3552 State bflags = toolbutton->state & ~State_Sunken;
3553 State mflags = bflags;
3554 bool autoRaise = flags & State_AutoRaise;
3555 if (autoRaise) {
3556 if (!(bflags & State_MouseOver) || !(bflags & State_Enabled))
3557 bflags &= ~State_Raised;
3558 }
3559
3560 if (toolbutton->state & State_Sunken) {
3561 if (toolbutton->activeSubControls & SC_ToolButton) {
3562 bflags |= State_Sunken;
3563 mflags |= State_MouseOver | State_Sunken;
3564 } else if (toolbutton->activeSubControls & SC_ToolButtonMenu) {
3565 mflags |= State_Sunken;
3566 bflags |= State_MouseOver;
3567 }
3568 }
3569
3570 QStyleOption tool = *toolbutton;
3571 if (toolbutton->subControls & SC_ToolButton) {
3572 if (flags & (State_Sunken | State_On | State_Raised) || !autoRaise) {
3573 if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup && autoRaise) {
3575 theme.partId = TP_SPLITBUTTON;
3576 theme.rect = button;
3577 if (!(bflags & State_Enabled))
3578 stateId = TS_DISABLED;
3579 else if (bflags & State_Sunken)
3580 stateId = TS_PRESSED;
3581 else if (bflags & State_MouseOver || !(flags & State_AutoRaise))
3582 stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
3583 else if (bflags & State_On)
3584 stateId = TS_CHECKED;
3585 else
3586 stateId = TS_NORMAL;
3587 if (option->direction == Qt::RightToLeft)
3588 theme.mirrorHorizontally = true;
3589 theme.stateId = stateId;
3590 d->drawBackground(theme);
3591 } else {
3592 tool.rect = option->rect;
3593 tool.state = bflags;
3594 if (autoRaise) // for tool bars
3595 proxy()->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
3596 else
3597 proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, painter, widget);
3598 }
3599 }
3600 }
3601
3602 if (toolbutton->state & State_HasFocus) {
3604 fr.QStyleOption::operator=(*toolbutton);
3605 fr.rect.adjust(3, 3, -3, -3);
3606 if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
3608 toolbutton, widget), 0);
3609 proxy()->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget);
3610 }
3611 QStyleOptionToolButton label = *toolbutton;
3612 label.state = bflags;
3613 int fw = 2;
3614 if (!autoRaise)
3615 label.state &= ~State_Sunken;
3616 label.rect = button.adjusted(fw, fw, -fw, -fw);
3617 proxy()->drawControl(CE_ToolButtonLabel, &label, painter, widget);
3618
3619 if (toolbutton->subControls & SC_ToolButtonMenu) {
3620 tool.rect = menuarea;
3621 tool.state = mflags;
3622 if (autoRaise) {
3623 proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, painter, widget);
3624 } else {
3625 tool.state = mflags;
3626 menuarea.adjust(-2, 0, 0, 0);
3627 // Draw menu button
3628 if ((bflags & State_Sunken) != (mflags & State_Sunken)){
3629 painter->save();
3630 painter->setClipRect(menuarea);
3631 tool.rect = option->rect;
3632 proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, painter, nullptr);
3633 painter->restore();
3634 }
3635 // Draw arrow
3636 painter->save();
3637 painter->setPen(option->palette.dark().color());
3638 painter->drawLine(menuarea.left(), menuarea.top() + 3,
3639 menuarea.left(), menuarea.bottom() - 3);
3640 painter->setPen(option->palette.light().color());
3641 painter->drawLine(menuarea.left() - 1, menuarea.top() + 3,
3642 menuarea.left() - 1, menuarea.bottom() - 3);
3643
3644 tool.rect = menuarea.adjusted(2, 3, -2, -1);
3645 proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget);
3646 painter->restore();
3647 }
3648 } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
3649 int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
3650 QRect ir = toolbutton->rect;
3651 QStyleOptionToolButton newBtn = *toolbutton;
3652 newBtn.rect = QRect(ir.right() + 4 - mbi, ir.height() - mbi + 4, mbi - 5, mbi - 5);
3653 proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
3654 }
3655 }
3656 break;
3657#endif // QT_CONFIG(toolbutton)
3658
3659 case CC_TitleBar:
3660 if (const auto *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
3661 const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
3662 bool isActive = tb->titleBarState & QStyle::State_Active;
3664 if (sub & SC_TitleBarLabel) {
3665 partId = (tb->titleBarState & Qt::WindowMinimized) ? WP_MINCAPTION : WP_CAPTION;
3666 theme.rect = option->rect;
3667 if (widget && !widget->isEnabled())
3668 stateId = CS_DISABLED;
3669 else if (isActive)
3670 stateId = CS_ACTIVE;
3671 else
3672 stateId = CS_INACTIVE;
3673
3674 theme.partId = partId;
3675 theme.stateId = stateId;
3676 d->drawBackground(theme);
3677
3678 QRect ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarLabel, widget);
3679
3680 int result = TST_NONE;
3681 GetThemeEnumValue(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
3682 if (result != TST_NONE) {
3683 COLORREF textShadowRef;
3684 GetThemeColor(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
3685 QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
3686 painter->setPen(textShadow);
3687 painter->drawText(int(ir.x() + 3 * factor), int(ir.y() + 2 * factor),
3688 int(ir.width() - 1 * factor), ir.height(),
3690 }
3691 COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
3692 QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
3693 painter->setPen(textColor);
3694 painter->drawText(int(ir.x() + 2 * factor), int(ir.y() + 1 * factor),
3695 int(ir.width() - 2 * factor), ir.height(),
3697 }
3698 if (sub & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
3699 theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarSysMenu, widget);
3700 partId = WP_SYSBUTTON;
3701 if ((widget && !widget->isEnabled()) || !isActive)
3702 stateId = SBS_DISABLED;
3703 else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_Sunken))
3704 stateId = SBS_PUSHED;
3705 else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_MouseOver))
3706 stateId = SBS_HOT;
3707 else
3708 stateId = SBS_NORMAL;
3709 if (!tb->icon.isNull()) {
3710 tb->icon.paint(painter, theme.rect);
3711 } else {
3712 theme.partId = partId;
3713 theme.stateId = stateId;
3714 if (theme.size().isEmpty()) {
3715 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, tb, widget);
3716 QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, tb, widget).pixmap(iconSize, iconSize);
3717 painter->save();
3718 drawItemPixmap(painter, theme.rect, Qt::AlignCenter, pm);
3719 painter->restore();
3720 } else {
3721 d->drawBackground(theme);
3722 }
3723 }
3724 }
3725
3726 if (sub & SC_TitleBarMinButton && tb->titleBarFlags & Qt::WindowMinimizeButtonHint
3727 && !(tb->titleBarState & Qt::WindowMinimized)) {
3728 populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMinButton, isActive, WP_MINBUTTON, &theme);
3729 d->drawBackground(theme);
3730 }
3731 if (sub & SC_TitleBarMaxButton && tb->titleBarFlags & Qt::WindowMaximizeButtonHint
3732 && !(tb->titleBarState & Qt::WindowMaximized)) {
3733 populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMaxButton, isActive, WP_MAXBUTTON, &theme);
3734 d->drawBackground(theme);
3735 }
3736 if (sub & SC_TitleBarContextHelpButton
3737 && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
3738 populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarContextHelpButton, isActive, WP_HELPBUTTON, &theme);
3739 d->drawBackground(theme);
3740 }
3741 bool drawNormalButton = (sub & SC_TitleBarNormalButton)
3742 && (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
3743 && (tb->titleBarState & Qt::WindowMinimized))
3744 || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
3745 && (tb->titleBarState & Qt::WindowMaximized)));
3746 if (drawNormalButton) {
3747 populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarNormalButton, isActive, WP_RESTOREBUTTON, &theme);
3748 d->drawBackground(theme);
3749 }
3750 if (sub & SC_TitleBarShadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
3751 && !(tb->titleBarState & Qt::WindowMinimized)) {
3752 populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarShadeButton, isActive, WP_MINBUTTON, &theme);
3753 d->drawBackground(theme);
3754 }
3755 if (sub & SC_TitleBarUnshadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
3756 && tb->titleBarState & Qt::WindowMinimized) {
3757 populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarUnshadeButton, isActive, WP_RESTOREBUTTON, &theme);
3758 d->drawBackground(theme);
3759 }
3760 if (sub & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
3761 populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarCloseButton, isActive, WP_CLOSEBUTTON, &theme);
3762 d->drawBackground(theme);
3763 }
3764 }
3765 break;
3766
3767#if QT_CONFIG(mdiarea)
3768 case CC_MdiControls: {
3769 QWindowsThemeData theme(widget, painter, QWindowsVistaStylePrivate::WindowTheme, WP_MDICLOSEBUTTON, CBS_NORMAL);
3770 if (Q_UNLIKELY(!theme.isValid()))
3771 return;
3772
3773 if (option->subControls.testFlag(SC_MdiCloseButton)) {
3774 populateMdiButtonTheme(proxy(), widget, option, SC_MdiCloseButton, WP_MDICLOSEBUTTON, &theme);
3775 d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
3776 }
3777 if (option->subControls.testFlag(SC_MdiNormalButton)) {
3778 populateMdiButtonTheme(proxy(), widget, option, SC_MdiNormalButton, WP_MDIRESTOREBUTTON, &theme);
3779 d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
3780 }
3781 if (option->subControls.testFlag(QStyle::SC_MdiMinButton)) {
3782 populateMdiButtonTheme(proxy(), widget, option, SC_MdiMinButton, WP_MDIMINBUTTON, &theme);
3783 d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget));
3784 }
3785 break;
3786 }
3787#endif // QT_CONFIG(mdiarea)
3788
3789#if QT_CONFIG(dial)
3790 case CC_Dial:
3791 if (const auto *dial = qstyleoption_cast<const QStyleOptionSlider *>(option))
3792 QStyleHelper::drawDial(dial, painter);
3793 break;
3794#endif // QT_CONFIG(dial)
3795
3796 case CC_ComboBox:
3797 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
3798 if (cmb->editable) {
3799 if (sub & SC_ComboBoxEditField) {
3800 partId = EP_EDITBORDER_NOSCROLL;
3801 if (!(flags & State_Enabled))
3802 stateId = ETS_DISABLED;
3803 else if (flags & State_MouseOver)
3804 stateId = ETS_HOT;
3805 else if (flags & State_HasFocus)
3806 stateId = ETS_FOCUSED;
3807 else
3808 stateId = ETS_NORMAL;
3809
3812 partId, stateId, r);
3813
3814 d->drawBackground(theme);
3815 }
3816 if (sub & SC_ComboBoxArrow) {
3817 QRect subRect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
3819 theme.rect = subRect;
3820 partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
3821
3822 if (!(cmb->state & State_Enabled))
3823 stateId = CBXS_DISABLED;
3824 else if (cmb->state & State_Sunken || cmb->state & State_On)
3825 stateId = CBXS_PRESSED;
3826 else if (cmb->state & State_MouseOver && option->activeSubControls & SC_ComboBoxArrow)
3827 stateId = CBXS_HOT;
3828 else
3829 stateId = CBXS_NORMAL;
3830
3831 theme.partId = partId;
3832 theme.stateId = stateId;
3833 d->drawBackground(theme);
3834 }
3835
3836 } else {
3837 if (sub & SC_ComboBoxFrame) {
3839 theme.rect = option->rect;
3840 theme.partId = CP_READONLY;
3841 if (!(cmb->state & State_Enabled))
3842 theme.stateId = CBXS_DISABLED;
3843 else if (cmb->state & State_Sunken || cmb->state & State_On)
3844 theme.stateId = CBXS_PRESSED;
3845 else if (cmb->state & State_MouseOver)
3846 theme.stateId = CBXS_HOT;
3847 else
3848 theme.stateId = CBXS_NORMAL;
3849 d->drawBackground(theme);
3850 }
3851 if (sub & SC_ComboBoxArrow) {
3853 theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
3854 theme.partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
3855 if (!(cmb->state & State_Enabled))
3856 theme.stateId = CBXS_DISABLED;
3857 else
3858 theme.stateId = CBXS_NORMAL;
3859 d->drawBackground(theme);
3860 }
3861 if ((sub & SC_ComboBoxEditField) && (flags & State_HasFocus)) {
3863 fropt.QStyleOption::operator=(*cmb);
3864 fropt.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget);
3865 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
3866 }
3867 }
3868 }
3869 break;
3870
3871 case CC_ScrollBar:
3872 if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
3874 bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
3875 if (maxedOut)
3876 flags &= ~State_Enabled;
3877
3878 bool isHorz = flags & State_Horizontal;
3879 bool isRTL = option->direction == Qt::RightToLeft;
3880 if (sub & SC_ScrollBarAddLine) {
3881 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
3882 partId = SBP_ARROWBTN;
3883 if (!(flags & State_Enabled))
3884 stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
3885 else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
3886 stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
3887 else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
3888 stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
3889 else if (scrollbar->state & State_MouseOver)
3890 stateId = (isHorz ? (isRTL ? ABS_LEFTHOVER : ABS_RIGHTHOVER) : ABS_DOWNHOVER);
3891 else
3892 stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
3893 theme.partId = partId;
3894 theme.stateId = stateId;
3895 d->drawBackground(theme);
3896 }
3897 if (sub & SC_ScrollBarSubLine) {
3898 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
3899 partId = SBP_ARROWBTN;
3900 if (!(flags & State_Enabled))
3901 stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
3902 else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
3903 stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
3904 else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
3905 stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
3906 else if (scrollbar->state & State_MouseOver)
3907 stateId = (isHorz ? (isRTL ? ABS_RIGHTHOVER : ABS_LEFTHOVER) : ABS_UPHOVER);
3908 else
3909 stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
3910 theme.partId = partId;
3911 theme.stateId = stateId;
3912 d->drawBackground(theme);
3913 }
3914 if (maxedOut) {
3915 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
3916 theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
3917 theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget));
3918 partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
3919 stateId = SCRBS_DISABLED;
3920 theme.partId = partId;
3921 theme.stateId = stateId;
3922 d->drawBackground(theme);
3923 } else {
3924 if (sub & SC_ScrollBarSubPage) {
3925 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget);
3926 partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
3927 if (!(flags & State_Enabled))
3928 stateId = SCRBS_DISABLED;
3929 else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
3930 stateId = SCRBS_PRESSED;
3931 else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
3932 stateId = SCRBS_HOT;
3933 else
3934 stateId = SCRBS_NORMAL;
3935 theme.partId = partId;
3936 theme.stateId = stateId;
3937 d->drawBackground(theme);
3938 }
3939 if (sub & SC_ScrollBarAddPage) {
3940 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget);
3941 partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
3942 if (!(flags & State_Enabled))
3943 stateId = SCRBS_DISABLED;
3944 else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
3945 stateId = SCRBS_PRESSED;
3946 else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
3947 stateId = SCRBS_HOT;
3948 else
3949 stateId = SCRBS_NORMAL;
3950 theme.partId = partId;
3951 theme.stateId = stateId;
3952 d->drawBackground(theme);
3953 }
3954 if (sub & SC_ScrollBarSlider) {
3955 theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
3956 if (!(flags & State_Enabled))
3957 stateId = SCRBS_DISABLED;
3958 else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
3959 stateId = SCRBS_PRESSED;
3960 else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
3961 stateId = SCRBS_HOT;
3962 else if (option->state & State_MouseOver)
3963 stateId = SCRBS_HOVER;
3964 else
3965 stateId = SCRBS_NORMAL;
3966
3967 // Draw handle
3968 theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
3969 theme.stateId = stateId;
3970 d->drawBackground(theme);
3971 }
3972 }
3973 }
3974 break;
3975
3976#if QT_CONFIG(spinbox)
3977 case CC_SpinBox:
3978 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
3980 if (sb->frame && (sub & SC_SpinBoxFrame)) {
3981 partId = EP_EDITBORDER_NOSCROLL;
3982 if (!(flags & State_Enabled))
3983 stateId = ETS_DISABLED;
3984 else if (flags & State_MouseOver)
3985 stateId = ETS_HOT;
3986 else if (flags & State_HasFocus)
3987 stateId = ETS_SELECTED;
3988 else
3989 stateId = ETS_NORMAL;
3990
3993 partId, stateId, r);
3994 // The spinbox in Windows QStyle is drawn with frameless QLineEdit inside it
3995 // That however breaks with QtQuickControls where this results in transparent
3996 // spinbox background, so if there's no "widget" passed (QtQuickControls case),
3997 // let ftheme.noContent be false, which fixes the spinbox rendering in QQC
3998 ftheme.noContent = (widget != nullptr);
3999 d->drawBackground(ftheme);
4000 }
4001 if (sub & SC_SpinBoxUp) {
4002 theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1);
4003 partId = SPNP_UP;
4004 if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled))
4005 stateId = UPS_DISABLED;
4006 else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
4007 stateId = UPS_PRESSED;
4008 else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
4009 stateId = UPS_HOT;
4010 else
4011 stateId = UPS_NORMAL;
4012 theme.partId = partId;
4013 theme.stateId = stateId;
4014 d->drawBackground(theme);
4015 }
4016 if (sub & SC_SpinBoxDown) {
4017 theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
4018 partId = SPNP_DOWN;
4019 if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled))
4020 stateId = DNS_DISABLED;
4021 else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
4022 stateId = DNS_PRESSED;
4023 else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
4024 stateId = DNS_HOT;
4025 else
4026 stateId = DNS_NORMAL;
4027 theme.partId = partId;
4028 theme.stateId = stateId;
4029 d->drawBackground(theme);
4030 }
4031 }
4032 break;
4033#endif // QT_CONFIG(spinbox)
4034
4035 default:
4036 QWindowsStyle::drawComplexControl(control, option, painter, widget);
4037 break;
4038 }
4039}
4040
4045 const QSize &size, const QWidget *widget) const
4046{
4048 return QWindowsStyle::sizeFromContents(type, option, size, widget);
4049
4050 QSize contentSize(size);
4051
4052 switch (type) {
4053 case CT_LineEdit:
4054 case CT_ComboBox: {
4055 QWindowsThemeData buttontheme(widget, nullptr, QWindowsVistaStylePrivate::ButtonTheme, BP_PUSHBUTTON, PBS_NORMAL);
4056 if (buttontheme.isValid()) {
4057 const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
4058 const QMarginsF borderSize = buttontheme.margins() * factor;
4059 if (!borderSize.isNull()) {
4060 const qreal margin = qreal(2) * factor;
4061 contentSize.rwidth() += qRound(borderSize.left() + borderSize.right() - margin);
4062 contentSize.rheight() += int(borderSize.bottom() + borderSize.top() - margin
4063 + qreal(1) / factor - 1);
4064 }
4065 const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, option) + 1);
4067 + textMargins, 23), 0); //arrow button
4068 }
4069 break;
4070 }
4071
4072 case CT_TabWidget:
4073 contentSize += QSize(6, 6);
4074 break;
4075
4076 case CT_Menu:
4077 contentSize += QSize(1, 0);
4078 break;
4079
4080#if QT_CONFIG(menubar)
4081 case CT_MenuBarItem:
4082 if (!contentSize.isEmpty())
4083 contentSize += QSize(windowsItemHMargin * 5 + 1, 5);
4084 break;
4085#endif
4086
4087 case CT_MenuItem: {
4088 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
4089 QWindowsThemeData theme(widget, nullptr,
4091 MENU_POPUPCHECKBACKGROUND, MBI_HOT);
4092 QWindowsThemeData themeSize = theme;
4093 themeSize.partId = MENU_POPUPCHECK;
4094 themeSize.stateId = 0;
4095 const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
4096 const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
4097 int minimumHeight = qMax(qRound(size.height() + margins.bottom() + margins.top()), contentSize.height());
4098 contentSize.rwidth() += qRound(size.width() + margins.left() + margins.right());
4099 if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
4100 if (menuitem->menuItemType != QStyleOptionMenuItem::Separator)
4101 contentSize.setHeight(minimumHeight);
4102 }
4103 break;
4104 }
4105
4106 case CT_MdiControls: {
4107 contentSize.setHeight(int(QStyleHelper::dpiScaled(19, option)));
4108 int width = 54;
4109 if (const auto *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(option)) {
4110 width = 0;
4111 if (styleOpt->subControls & SC_MdiMinButton)
4112 width += 17 + 1;
4113 if (styleOpt->subControls & SC_MdiNormalButton)
4114 width += 17 + 1;
4115 if (styleOpt->subControls & SC_MdiCloseButton)
4116 width += 17 + 1;
4117 }
4118 contentSize.setWidth(int(QStyleHelper::dpiScaled(width, option)));
4119 break;
4120 }
4121
4122 case CT_ItemViewItem:
4123 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
4124 contentSize.rheight() += 2;
4125 break;
4126
4127 case CT_SpinBox: {
4128 //Spinbox adds frame twice
4129 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
4130 int border = proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget);
4131 contentSize -= QSize(2*border, 2*border);
4132 break;
4133 }
4134
4135 case CT_HeaderSection:
4136 // When there is a sort indicator it adds to the width but it is shown
4137 // above the text natively and not on the side
4138 if (QStyleOptionHeader *hdr = qstyleoption_cast<QStyleOptionHeader *>(const_cast<QStyleOption *>(option))) {
4139 QStyleOptionHeader::SortIndicator sortInd = hdr->sortIndicator;
4140 hdr->sortIndicator = QStyleOptionHeader::None;
4141 contentSize = QWindowsStyle::sizeFromContents(type, hdr, size, widget);
4142 hdr->sortIndicator = sortInd;
4143 }
4144 break;
4145
4146 default:
4147 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
4148 break;
4149 }
4150
4151 return contentSize;
4152}
4153
4158{
4160 return QWindowsStyle::subElementRect(element, option, widget);
4161
4162 QRect rect(option->rect);
4163
4164 switch (element) {
4165 case SE_PushButtonContents:
4166 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
4167 MARGINS borderSize;
4168 const HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"Button");
4169 if (theme) {
4170 int stateId = PBS_NORMAL;
4171 if (!(option->state & State_Enabled))
4172 stateId = PBS_DISABLED;
4173 else if (option->state & State_Sunken)
4174 stateId = PBS_PRESSED;
4175 else if (option->state & State_MouseOver)
4176 stateId = PBS_HOT;
4178 stateId = PBS_DEFAULTED;
4179
4180 int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn, widget);
4181 rect = option->rect.adjusted(border, border, -border, -border);
4182
4183 if (SUCCEEDED(GetThemeMargins(theme, nullptr, BP_PUSHBUTTON, stateId, TMT_CONTENTMARGINS, nullptr, &borderSize))) {
4184 rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
4185 -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
4186 rect = visualRect(option->direction, option->rect, rect);
4187 }
4188 }
4189 }
4190 break;
4191
4192 case SE_DockWidgetCloseButton:
4193 case SE_DockWidgetFloatButton:
4194 rect = QWindowsStyle::subElementRect(element, option, widget);
4195 return rect.translated(0, 1);
4196
4197 case SE_TabWidgetTabContents:
4198 rect = QWindowsStyle::subElementRect(element, option, widget);
4199 if (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
4200 rect = QWindowsStyle::subElementRect(element, option, widget);
4201 if (const QTabWidget *tabWidget = qobject_cast<const QTabWidget *>(widget)) {
4202 if (tabWidget->documentMode())
4203 break;
4204 rect.adjust(0, 0, -2, -2);
4205 }
4206 }
4207 break;
4208
4209 case SE_TabWidgetTabBar: {
4210 rect = QWindowsStyle::subElementRect(element, option, widget);
4211 const auto *twfOption = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option);
4212 if (twfOption && twfOption->direction == Qt::RightToLeft
4213 && (twfOption->shape == QTabBar::RoundedNorth
4214 || twfOption->shape == QTabBar::RoundedSouth))
4215 {
4216 QStyleOptionTab otherOption;
4217 otherOption.shape = (twfOption->shape == QTabBar::RoundedNorth
4219 int overlap = proxy()->pixelMetric(PM_TabBarBaseOverlap, &otherOption, widget);
4220 int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
4221 rect.adjust(-overlap + borderThickness, 0, -overlap + borderThickness, 0);
4222 }
4223 break;
4224 }
4225
4226 case SE_HeaderArrow: {
4227 rect = QWindowsStyle::subElementRect(element, option, widget);
4228 QRect r = rect;
4229 int h = option->rect.height();
4230 int w = option->rect.width();
4231 int x = option->rect.x();
4232 int y = option->rect.y();
4233 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
4234
4235 QWindowsThemeData theme(widget, nullptr,
4237 HP_HEADERSORTARROW, HSAS_SORTEDDOWN, option->rect);
4238
4239 int arrowWidth = 13;
4240 int arrowHeight = 5;
4241 if (theme.isValid()) {
4242 const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
4243 if (!size.isEmpty()) {
4244 arrowWidth = qRound(size.width());
4245 arrowHeight = qRound(size.height());
4246 }
4247 }
4248 if (option->state & State_Horizontal) {
4249 r.setRect(x + w/2 - arrowWidth/2, y , arrowWidth, arrowHeight);
4250 } else {
4251 int vert_size = w / 2;
4252 r.setRect(x + 5, y + h - margin * 2 - vert_size,
4253 w - margin * 2 - 5, vert_size);
4254 }
4255 rect = visualRect(option->direction, option->rect, r);
4256 break;
4257 }
4258
4259 case SE_HeaderLabel: {
4260 rect = QWindowsStyle::subElementRect(element, option, widget);
4261 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
4262 QRect r = option->rect;
4263 r.setRect(option->rect.x() + margin, option->rect.y() + margin,
4264 option->rect.width() - margin * 2, option->rect.height() - margin * 2);
4265 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
4266 // Subtract width needed for arrow, if there is one
4267 if (header->sortIndicator != QStyleOptionHeader::None) {
4268 if (!(option->state & State_Horizontal)) //horizontal arrows are positioned on top
4269 r.setHeight(r.height() - (option->rect.width() / 2) - (margin * 2));
4270 }
4271 }
4272 rect = visualRect(option->direction, option->rect, r);
4273 break;
4274 }
4275
4276 case SE_ProgressBarContents:
4277 rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget);
4278 break;
4279
4280 case SE_ItemViewItemDecoration:
4281 rect = QWindowsStyle::subElementRect(element, option, widget);
4282 if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
4283 rect.adjust(-2, 0, 2, 0);
4284 break;
4285
4286 case SE_ItemViewItemFocusRect:
4287 rect = QWindowsStyle::subElementRect(element, option, widget);
4288 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
4291 if (!vopt->icon.isNull())
4292 rect = textRect.united(displayRect);
4293 else
4294 rect = textRect;
4295 rect = rect.adjusted(1, 0, -1, 0);
4296 }
4297 break;
4298
4299 default:
4300 rect = QWindowsStyle::subElementRect(element, option, widget);
4301 break;
4302 }
4303
4304 return rect;
4305}
4306
4311 SubControl subControl, const QWidget *widget) const
4312{
4314 return QWindowsStyle::subControlRect(control, option, subControl, widget);
4315
4316 QRect rect;
4317
4318 switch (control) {
4319#if QT_CONFIG(combobox)
4320 case CC_ComboBox:
4321 if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
4322 const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height();
4323 const int margin = cb->frame ? 3 : 0;
4324 const int bmarg = cb->frame ? 2 : 0;
4325 const int arrowWidth = qRound(QStyleHelper::dpiScaled(16, option));
4326 const int arrowButtonWidth = bmarg + arrowWidth;
4327 const int xpos = x + wi - arrowButtonWidth;
4328
4329 switch (subControl) {
4330 case SC_ComboBoxFrame:
4331 case SC_ComboBoxListBoxPopup:
4332 rect = cb->rect;
4333 break;
4334
4335 case SC_ComboBoxArrow: {
4336 rect.setRect(xpos, y , arrowButtonWidth, he);
4337 }
4338 break;
4339
4340 case SC_ComboBoxEditField: {
4341 rect.setRect(x + margin, y + margin, wi - 2 * margin - arrowWidth, he - 2 * margin);
4342 }
4343 break;
4344
4345 default:
4346 break;
4347 }
4348 }
4349 break;
4350#endif // QT_CONFIG(combobox)
4351
4352 case CC_TitleBar:
4353 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
4354 if (!buttonVisible(subControl, tb))
4355 return rect;
4356 const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
4357 const bool isToolTitle = false;
4358 const int height = tb->rect.height();
4359 const int width = tb->rect.width();
4360
4361 const int buttonMargin = int(QStyleHelper::dpiScaled(4, option));
4362 int buttonHeight = qRound(qreal(GetSystemMetrics(SM_CYSIZE)) * factor)
4363 - buttonMargin;
4364 const int buttonWidth =
4365 qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor - QStyleHelper::dpiScaled(4, option));
4366
4367 const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
4368 const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
4369 const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
4370 const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
4371 const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
4372 const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
4373
4374 bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
4375 bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
4376 int offset = 0;
4377 const int delta = buttonWidth + 2;
4378 int controlTop = option->rect.bottom() - buttonHeight - 2;
4379
4380 switch (subControl) {
4381 case SC_TitleBarLabel: {
4382 rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
4383 if (isToolTitle) {
4384 if (sysmenuHint) {
4385 rect.adjust(0, 0, int(-buttonWidth - 3 * factor), 0);
4386 }
4387 if (minimizeHint || maximizeHint)
4388 rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
4389 } else {
4390 if (sysmenuHint) {
4391 const int leftOffset = int(height - 8 * factor);
4392 rect.adjust(leftOffset, 0, 0, int(4 * factor));
4393 }
4394 if (minimizeHint)
4395 rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
4396 if (maximizeHint)
4397 rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
4398 if (contextHint)
4399 rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
4400 if (shadeHint)
4401 rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
4402 }
4403 rect.translate(0, int(2 * factor));
4404 }
4405 break;
4406
4407 case SC_TitleBarContextHelpButton:
4408 if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
4409 offset += delta;
4410 Q_FALLTHROUGH();
4411 case SC_TitleBarMinButton:
4412 if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
4413 offset += delta;
4414 else if (subControl == SC_TitleBarMinButton)
4415 break;
4416 Q_FALLTHROUGH();
4417 case SC_TitleBarNormalButton:
4418 if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
4419 offset += delta;
4420 else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
4421 offset += delta;
4422 else if (subControl == SC_TitleBarNormalButton)
4423 break;
4424 Q_FALLTHROUGH();
4425 case SC_TitleBarMaxButton:
4426 if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
4427 offset += delta;
4428 else if (subControl == SC_TitleBarMaxButton)
4429 break;
4430 Q_FALLTHROUGH();
4431 case SC_TitleBarShadeButton:
4432 if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
4433 offset += delta;
4434 else if (subControl == SC_TitleBarShadeButton)
4435 break;
4436 Q_FALLTHROUGH();
4437 case SC_TitleBarUnshadeButton:
4438 if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
4439 offset += delta;
4440 else if (subControl == SC_TitleBarUnshadeButton)
4441 break;
4442 Q_FALLTHROUGH();
4443 case SC_TitleBarCloseButton:
4444 if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
4445 offset += delta;
4446 else if (subControl == SC_TitleBarCloseButton)
4447 break;
4448
4449 rect.setRect(width - offset - controlTop + 1, controlTop,
4450 buttonWidth, buttonHeight);
4451 break;
4452
4453 case SC_TitleBarSysMenu: {
4454 const int controlTop = int(6 * factor);
4455 const int controlHeight = int(height - controlTop - 3 * factor);
4456 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option);
4457 QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
4458 if (tb->icon.isNull())
4459 iconSize = QSize(controlHeight, controlHeight);
4460 int hPad = (controlHeight - iconSize.height())/2;
4461 int vPad = (controlHeight - iconSize.width())/2;
4462 rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
4463 rect.translate(0, int(3 * factor));
4464 }
4465 break;
4466
4467 default:
4468 break;
4469 }
4470 }
4471 break;
4472
4473#if QT_CONFIG(mdiarea)
4474 case CC_MdiControls: {
4475 int numSubControls = 0;
4476 if (option->subControls & SC_MdiCloseButton)
4477 ++numSubControls;
4478 if (option->subControls & SC_MdiMinButton)
4479 ++numSubControls;
4480 if (option->subControls & SC_MdiNormalButton)
4481 ++numSubControls;
4482 if (numSubControls == 0)
4483 break;
4484
4485 int buttonWidth = option->rect.width() / numSubControls;
4486 int offset = 0;
4487
4488 switch (subControl) {
4489 case SC_MdiCloseButton:
4490 // Only one sub control, no offset needed.
4491 if (numSubControls == 1)
4492 break;
4493 offset += buttonWidth;
4494 Q_FALLTHROUGH();
4495 case SC_MdiNormalButton:
4496 // No offset needed if
4497 // 1) There's only one sub control
4498 // 2) We have a close button and a normal button (offset already added in SC_MdiClose)
4499 if (numSubControls == 1 || (numSubControls == 2 && !(option->subControls & SC_MdiMinButton)))
4500 break;
4501 if (option->subControls & SC_MdiNormalButton)
4502 offset += buttonWidth;
4503 break;
4504 default:
4505 break;
4506 }
4507
4508 rect = QRect(offset, 0, buttonWidth, option->rect.height());
4509 break;
4510 }
4511#endif // QT_CONFIG(mdiarea)
4512
4513 default:
4514 return visualRect(option->direction, option->rect,
4515 QWindowsStyle::subControlRect(control, option, subControl, widget));
4516 }
4517
4518 return visualRect(option->direction, option->rect, rect);
4519}
4520
4525 const QPoint &pos, const QWidget *widget) const
4526{
4527 return QWindowsStyle::hitTestComplexControl(control, option, pos, widget);
4528}
4529
4533int QWindowsVistaStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
4534{
4536 return QWindowsStyle::pixelMetric(metric, option, widget);
4537
4539 if (ret != QWindowsStylePrivate::InvalidMetric)
4540 return int(QStyleHelper::dpiScaled(ret, option));
4541
4543 if (res != QWindowsStylePrivate::InvalidMetric)
4544 return qRound(qreal(res) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
4545
4546 res = 0;
4547
4548 switch (metric) {
4549 case PM_MenuBarPanelWidth:
4550 case PM_ButtonDefaultIndicator:
4551 res = 0;
4552 break;
4553
4554 case PM_DefaultFrameWidth:
4555 res = qobject_cast<const QListView*>(widget) ? 2 : 1;
4556 break;
4557 case PM_MenuPanelWidth:
4558 case PM_SpinBoxFrameWidth:
4559 res = 1;
4560 break;
4561
4562 case PM_TabBarTabOverlap:
4563 case PM_MenuHMargin:
4564 case PM_MenuVMargin:
4565 res = 2;
4566 break;
4567
4568 case PM_TabBarBaseOverlap:
4569 if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
4570 switch (tab->shape) {
4575 res = 1;
4576 break;
4579 res = 2;
4580 break;
4583 res = 3;
4584 break;
4585 }
4586 }
4587 break;
4588
4589 case PM_SplitterWidth:
4591 break;
4592
4593 case PM_MdiSubWindowMinimizedWidth:
4594 res = 160;
4595 break;
4596
4597#if QT_CONFIG(toolbar)
4598 case PM_ToolBarHandleExtent:
4600 break;
4601
4602#endif // QT_CONFIG(toolbar)
4603 case PM_DockWidgetSeparatorExtent:
4604 case PM_DockWidgetTitleMargin:
4606 break;
4607
4608 case PM_ButtonShiftHorizontal:
4609 case PM_ButtonShiftVertical:
4610 res = qstyleoption_cast<const QStyleOptionToolButton *>(option) ? 1 : 0;
4611 break;
4612
4613 default:
4614 res = QWindowsStyle::pixelMetric(metric, option, widget);
4615 }
4616
4617 return res;
4618}
4619
4624{
4625 QWindowsStyle::polish(widget);
4627 return;
4628
4629 if (false
4630#if QT_CONFIG(abstractbutton)
4631 || qobject_cast<QAbstractButton*>(widget)
4632#endif // QT_CONFIG(abstractbutton)
4633 || qobject_cast<QToolButton*>(widget)
4634 || qobject_cast<QTabBar*>(widget)
4635#if QT_CONFIG(combobox)
4636 || qobject_cast<QComboBox*>(widget)
4637#endif // QT_CONFIG(combobox)
4638 || qobject_cast<QScrollBar*>(widget)
4639 || qobject_cast<QSlider*>(widget)
4640 || qobject_cast<QHeaderView*>(widget)
4641#if QT_CONFIG(spinbox)
4642 || qobject_cast<QAbstractSpinBox*>(widget)
4643 || qobject_cast<QSpinBox*>(widget)
4644#endif // QT_CONFIG(spinbox)
4645 ) {
4647 }
4648
4649#if QT_CONFIG(rubberband)
4650 if (qobject_cast<QRubberBand*>(widget))
4652#endif
4653
4654#if QT_CONFIG(lineedit)
4655 if (qobject_cast<QLineEdit*>(widget))
4657 else
4658#endif // QT_CONFIG(lineedit)
4659 if (qobject_cast<QGroupBox*>(widget))
4661#if QT_CONFIG(commandlinkbutton)
4662 else if (qobject_cast<QCommandLinkButton*>(widget)) {
4663 widget->setProperty("_qt_usingVistaStyle", true);
4664 QFont buttonFont = widget->font();
4665 buttonFont.setFamilies(QStringList{QLatin1String("Segoe UI")});
4666 widget->setFont(buttonFont);
4667 QPalette pal = widget->palette();
4668 pal.setColor(QPalette::ButtonText, QColor(21, 28, 85));
4669 pal.setColor(QPalette::BrightText, QColor(7, 64, 229));
4670 widget->setPalette(pal);
4671 }
4672#endif // QT_CONFIG(commandlinkbutton)
4673 else if (widget->inherits("QTipLabel")) {
4674 //note that since tooltips are not reused
4675 //we do not have to care about unpolishing
4676 widget->setContentsMargins(3, 0, 4, 0);
4677 COLORREF bgRef;
4678 HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"TOOLTIP");
4679 if (theme && SUCCEEDED(GetThemeColor(theme, TTP_STANDARD, TTSS_NORMAL, TMT_TEXTCOLOR, &bgRef))) {
4680 QColor textColor = QColor::fromRgb(bgRef);
4681 QPalette pal;
4683 widget->setPalette(pal);
4684 }
4685 } else if (qobject_cast<QMessageBox *> (widget)) {
4687#if QT_CONFIG(dialogbuttonbox)
4688 QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
4689 if (buttonBox)
4690 buttonBox->setContentsMargins(0, 9, 0, 0);
4691#endif
4692 }
4693#if QT_CONFIG(inputdialog)
4694 else if (qobject_cast<QInputDialog *> (widget)) {
4696#if QT_CONFIG(dialogbuttonbox)
4697 QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
4698 if (buttonBox)
4699 buttonBox->setContentsMargins(0, 9, 0, 0);
4700#endif
4701 }
4702#endif // QT_CONFIG(inputdialog)
4703 else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
4704 tree->viewport()->setAttribute(Qt::WA_Hover);
4705 }
4706 else if (QListView *list = qobject_cast<QListView *> (widget)) {
4707 list->viewport()->setAttribute(Qt::WA_Hover);
4708 }
4709}
4710
4715{
4716 Q_D(QWindowsVistaStyle);
4717
4718#if QT_CONFIG(rubberband)
4719 if (qobject_cast<QRubberBand*>(widget))
4721#endif
4722
4723 // Unpolish of widgets is the first thing that
4724 // happens when a theme changes, or the theme
4725 // engine is turned off. So we detect it here.
4726 bool oldState = QWindowsVistaStylePrivate::useVista();
4728 if ((oldState != newState) && newState) {
4729 d->cleanup(true);
4730 d->init(true);
4731 } else {
4732 // Cleanup handle map, if just changing style,
4733 // or turning it on. In both cases the values
4734 // already in the map might be old (other style).
4735 d->cleanupHandleMap();
4736 }
4737 if (false
4738 #if QT_CONFIG(abstractbutton)
4739 || qobject_cast<QAbstractButton*>(widget)
4740 #endif
4741 || qobject_cast<QToolButton*>(widget)
4742 || qobject_cast<QTabBar*>(widget)
4743 #if QT_CONFIG(combobox)
4744 || qobject_cast<QComboBox*>(widget)
4745 #endif // QT_CONFIG(combobox)
4746 || qobject_cast<QScrollBar*>(widget)
4747 || qobject_cast<QSlider*>(widget)
4748 || qobject_cast<QHeaderView*>(widget)
4749 #if QT_CONFIG(spinbox)
4750 || qobject_cast<QAbstractSpinBox*>(widget)
4751 || qobject_cast<QSpinBox*>(widget)
4752 #endif // QT_CONFIG(spinbox)
4753 ) {
4755 }
4756
4757 QWindowsStyle::unpolish(widget);
4758
4759 d->stopAnimation(widget);
4760
4761#if QT_CONFIG(lineedit)
4762 if (qobject_cast<QLineEdit*>(widget))
4764 else {
4765#endif // QT_CONFIG(lineedit)
4766 if (qobject_cast<QGroupBox*>(widget))
4768 else if (qobject_cast<QMessageBox *> (widget)) {
4770#if QT_CONFIG(dialogbuttonbox)
4771 QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
4772 if (buttonBox)
4773 buttonBox->setContentsMargins(0, 0, 0, 0);
4774#endif
4775 }
4776#if QT_CONFIG(inputdialog)
4777 else if (qobject_cast<QInputDialog *> (widget)) {
4779#if QT_CONFIG(dialogbuttonbox)
4780 QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
4781 if (buttonBox)
4782 buttonBox->setContentsMargins(0, 0, 0, 0);
4783#endif
4784 }
4785#endif // QT_CONFIG(inputdialog)
4786 else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
4787 tree->viewport()->setAttribute(Qt::WA_Hover, false);
4788 }
4789#if QT_CONFIG(commandlinkbutton)
4790 else if (qobject_cast<QCommandLinkButton*>(widget)) {
4791 QFont font = QApplication::font("QCommandLinkButton");
4792 QFont widgetFont = widget->font();
4793 widgetFont.setFamilies(font.families()); //Only family set by polish
4794 widget->setFont(widgetFont);
4795 }
4796#endif // QT_CONFIG(commandlinkbutton)
4797 }
4798}
4799
4804{
4805 Q_D(QWindowsVistaStyle);
4806
4808 // System runs in dark mode, but the Vista style cannot use a dark palette.
4809 // Overwrite with the light system palette.
4811 if (auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration()))
4812 nativeWindowsApp->populateLightSystemPalette(pal);
4813 }
4814
4816 d->alphaCache.clear();
4817 d->hasInitColors = false;
4818
4819 if (!d->hasInitColors) {
4820 // Get text color for group box labels
4821 QWindowsThemeData theme(nullptr, nullptr, QWindowsVistaStylePrivate::ButtonTheme, 0, 0);
4822 COLORREF cref;
4823 GetThemeColor(theme.handle(), BP_GROUPBOX, GBS_NORMAL, TMT_TEXTCOLOR, &cref);
4824 d->groupBoxTextColor = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
4825 GetThemeColor(theme.handle(), BP_GROUPBOX, GBS_DISABLED, TMT_TEXTCOLOR, &cref);
4826 d->groupBoxTextColorDisabled = qRgb(GetRValue(cref), GetGValue(cref), GetBValue(cref));
4827 // Where does this color come from?
4828 //GetThemeColor(theme.handle(), TKP_TICS, TSS_NORMAL, TMT_COLOR, &cref);
4829 d->sliderTickColor = qRgb(165, 162, 148);
4830 d->hasInitColors = true;
4831 }
4832
4833 QWindowsStyle::polish(pal);
4835}
4836
4841{
4842 // Override windows theme palettes to light
4843 if (qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
4844 static const char* themedWidgets[] = {
4845 "QToolButton",
4846 "QAbstractButton",
4847 "QCheckBox",
4848 "QRadioButton",
4849 "QHeaderView",
4850 "QAbstractItemView",
4851 "QMessageBoxLabel",
4852 "QTabBar",
4853 "QLabel",
4854 "QGroupBox",
4855 "QMenu",
4856 "QMenuBar",
4857 "QTextEdit",
4858 "QTextControl",
4859 "QLineEdit"
4860 };
4861 for (const auto& themedWidget : std::as_const(themedWidgets)) {
4862 auto defaultResolveMask = QApplication::palette().resolveMask();
4863 auto widgetResolveMask = QApplication::palette(themedWidget).resolveMask();
4864 if (widgetResolveMask != defaultResolveMask)
4866 }
4867 }
4868
4869 QWindowsStyle::polish(app);
4870}
4871
4876 const QWidget *widget) const
4877{
4879 return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
4880 }
4881
4882 switch (standardPixmap) {
4883 case SP_TitleBarMaxButton:
4884 case SP_TitleBarCloseButton:
4885 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
4886 if (widget && widget->isWindow()) {
4887 QWindowsThemeData theme(widget, nullptr, QWindowsVistaStylePrivate::WindowTheme, WP_SMALLCLOSEBUTTON, CBS_NORMAL);
4888 if (theme.isValid()) {
4889 const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
4890 return QIcon(QWindowsStyle::standardPixmap(standardPixmap, option, widget)).pixmap(size);
4891 }
4892 }
4893 }
4894 break;
4895
4896 default:
4897 break;
4898 }
4899
4900 return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
4901}
4902
4906QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon,
4907 const QStyleOption *option,
4908 const QWidget *widget) const
4909{
4911 return QWindowsStyle::standardIcon(standardIcon, option, widget);
4912 }
4913
4914 auto *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
4915
4916 switch (standardIcon) {
4917 case SP_TitleBarMaxButton:
4918 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
4919 if (d->dockFloat.isNull()) {
4921 WP_SMALLCLOSEBUTTON, CBS_NORMAL);
4923 WP_MAXBUTTON, MAXBS_NORMAL);
4924 if (theme.isValid()) {
4925 const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
4926 QPixmap pm(size);
4928 QPainter p(&pm);
4929 theme.painter = &p;
4930 theme.rect = QRect(QPoint(0, 0), size);
4931 d->drawBackground(theme);
4932 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
4934 theme.stateId = MAXBS_PUSHED;
4935 d->drawBackground(theme);
4936 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
4938 theme.stateId = MAXBS_HOT;
4939 d->drawBackground(theme);
4940 d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
4942 theme.stateId = MAXBS_INACTIVE;
4943 d->drawBackground(theme);
4944 d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
4945 }
4946 }
4947 if (widget && widget->isWindow())
4948 return d->dockFloat;
4949 }
4950 break;
4951
4952 case SP_TitleBarCloseButton:
4953 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
4954 if (d->dockClose.isNull()) {
4956 WP_SMALLCLOSEBUTTON, CBS_NORMAL);
4957 if (theme.isValid()) {
4958 const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
4959 QPixmap pm(size);
4961 QPainter p(&pm);
4962 theme.painter = &p;
4963 theme.partId = WP_CLOSEBUTTON; // ####
4964 theme.rect = QRect(QPoint(0, 0), size);
4965 d->drawBackground(theme);
4966 d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
4968 theme.stateId = CBS_PUSHED;
4969 d->drawBackground(theme);
4970 d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
4972 theme.stateId = CBS_HOT;
4973 d->drawBackground(theme);
4974 d->dockClose.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
4976 theme.stateId = CBS_INACTIVE;
4977 d->drawBackground(theme);
4978 d->dockClose.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
4979 }
4980 }
4981 if (widget && widget->isWindow())
4982 return d->dockClose;
4983 }
4984 break;
4985
4986 case SP_TitleBarNormalButton:
4987 if (qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
4988 if (d->dockFloat.isNull()) {
4990 WP_SMALLCLOSEBUTTON, CBS_NORMAL);
4992 WP_RESTOREBUTTON, RBS_NORMAL);
4993 if (theme.isValid()) {
4994 const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
4995 QPixmap pm(size);
4997 QPainter p(&pm);
4998 theme.painter = &p;
4999 theme.rect = QRect(QPoint(0, 0), size);
5000 d->drawBackground(theme);
5001 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
5003 theme.stateId = RBS_PUSHED;
5004 d->drawBackground(theme);
5005 d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
5007 theme.stateId = RBS_HOT;
5008 d->drawBackground(theme);
5009 d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
5011 theme.stateId = RBS_INACTIVE;
5012 d->drawBackground(theme);
5013 d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
5014 }
5015 }
5016 if (widget && widget->isWindow())
5017 return d->dockFloat;
5018 }
5019 break;
5020
5021 case SP_CommandLink: {
5024 if (theme.isValid()) {
5025 const QSize size = theme.size().toSize();
5026 QIcon linkGlyph;
5027 QPixmap pm(size);
5029 QPainter p(&pm);
5030 theme.painter = &p;
5031 theme.rect = QRect(QPoint(0, 0), size);
5032 d->drawBackground(theme);
5033 linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
5035
5036 theme.stateId = CMDLGS_PRESSED;
5037 d->drawBackground(theme);
5038 linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
5040
5041 theme.stateId = CMDLGS_HOT;
5042 d->drawBackground(theme);
5043 linkGlyph.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
5045
5046 theme.stateId = CMDLGS_DISABLED;
5047 d->drawBackground(theme);
5048 linkGlyph.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
5049 return linkGlyph;
5050 }
5051 break;
5052 }
5053
5054 default:
5055 break;
5056 }
5057
5058 return QWindowsStyle::standardIcon(standardIcon, option, widget);
5059}
5060
bool isActive
The QAbstractItemView class provides the basic functionality for item view classes.
SelectionMode
This enum indicates how the view responds to user selections:
SelectionBehavior
\value SelectItems Selecting single items.
The QAbstractSpinBox class provides a spinbox and a line edit to display values.
\inmodule QtGui
The QApplication class manages the GUI application's control flow and main settings.
static void setPalette(const QPalette &, const char *className=nullptr)
Changes the application palette to palette.
static QPalette palette()
Returns the current application palette.
static QFont font()
Returns the default application font.
The QBackingStore class provides a drawing area for QWindow.
void setEndImage(const QImage &image)
void setStartImage(const QImage &image)
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
\inmodule QtCore
Definition qchar.h:48
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QColor darker(int f=200) const noexcept
Definition qcolor.cpp:2857
static QColor fromRgb(QRgb rgb) noexcept
Static convenience function that returns a QColor constructed from the given QRgb value rgb.
Definition qcolor.cpp:2369
int red() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1528
int blue() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1583
int green() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1555
QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget=nullptr) const override
\reimp
void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const override
\reimp
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
The QDialogButtonBox class is a widget that presents buttons in a layout that is appropriate to the c...
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-l...
Definition qdockwidget.h:20
bool isFloating() const
Definition qdockwidget.h:56
QString elidedText(const QString &text, Qt::TextElideMode mode, int width, int flags=0) const
\reentrant
Definition qfont.h:20
void setFamilies(const QStringList &)
Definition qfont.cpp:2491
QStringList families() const
Definition qfont.cpp:2469
void setBold(bool)
If enable is true sets the font's weight to \l{Weight}{QFont::Bold}; otherwise sets the weight to \l{...
Definition qfont.h:312
void setColorAt(qreal pos, const QColor &color)
Creates a stop point at the given position with the given color.
Definition qbrush.cpp:1563
static QPlatformIntegration * platformIntegration()
static Qt::ColorScheme colorScheme()
QGuiApplicationPrivate::colorScheme.
static QPlatformNativeInterface * platformNativeInterface()
static QWindowList allWindows()
Returns a list of all the windows in the application.
QScreen * primaryScreen
the primary (or default) screen of the application.
QIcon windowIcon
the default window icon
T value(const Key &key) const noexcept
Definition qhash.h:1044
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
void addPixmap(const QPixmap &pixmap, Mode mode=Normal, State state=Off)
Adds pixmap to the icon, as a specialization for mode and state.
Definition qicon.cpp:1014
Mode
This enum type describes the mode for which a pixmap is intended to be used.
Definition qicon.h:22
@ Disabled
Definition qicon.h:22
@ Normal
Definition qicon.h:22
@ Active
Definition qicon.h:22
qint64 cacheKey() const
Returns a number that identifies the contents of this QIcon object.
Definition qicon.cpp:773
@ Off
Definition qicon.h:23
@ On
Definition qicon.h:23
QPixmap pixmap(const QSize &size, Mode mode=Normal, State state=Off) const
Returns a pixmap with the requested size, mode, and state, generating one if necessary.
Definition qicon.cpp:788
\inmodule QtGui
Definition qimage.h:37
QImage transformed(const QTransform &matrix, Qt::TransformationMode mode=Qt::FastTransformation) const
QImage copy(const QRect &rect=QRect()) const
Returns a sub-area of the image as a new image.
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_RGB32
Definition qimage.h:46
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_ARGB32
Definition qimage.h:47
QImage mirrored(bool horizontally=false, bool vertically=true) const &
Definition qimage.h:218
\inmodule QtCore
Definition qline.h:18
\inmodule QtGui
Definition qbrush.h:394
The QListView class provides a list or icon view onto a model.
Definition qlistview.h:17
\inmodule QtCore
Definition qmargins.h:274
constexpr qreal right() const noexcept
Returns the right margin.
Definition qmargins.h:370
constexpr qreal left() const noexcept
Returns the left margin.
Definition qmargins.h:364
constexpr qreal top() const noexcept
Returns the top margin.
Definition qmargins.h:367
constexpr bool isNull() const noexcept
Returns true if all margins are very close to 0; otherwise returns false.
Definition qmargins.h:361
constexpr qreal bottom() const noexcept
Returns the bottom margin.
Definition qmargins.h:373
Native interface to QGuiApplication, to be retrieved from QPlatformIntegration. \inmodule QtGui.
\inmodule QtCore
Definition qobject.h:90
T findChild(const QString &aName=QString(), Qt::FindChildOptions options=Qt::FindChildrenRecursively) const
Returns the child of this object that can be cast into type T and that is called name,...
Definition qobject.h:133
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4187
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
bool inherits(const char *classname) const
Returns true if this object is an instance of a class that inherits className or a QObject subclass t...
Definition qobject.h:313
static QOperatingSystemVersion current()
[0]
static constexpr QOperatingSystemVersionBase Windows11
\variable QOperatingSystemVersion::Windows11
qreal devicePixelRatio() const
virtual int devType() const
qreal devicePixelRatioF() const
QRegion systemClip() const
QPaintDevice * paintDevice() const
Returns the device that this engine is painting on, if painting is active; otherwise returns \nullptr...
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
const QPen & pen() const
Returns the painter's current pen.
void setClipping(bool enable)
Enables clipping if enable is true, or disables clipping if enable is false.
void drawRect(const QRectF &rect)
Draws the current rectangle with the current pen and brush.
Definition qpainter.h:519
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
qreal opacity() const
void setClipRect(const QRectF &, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip region to the given rectangle using the given clip operation.
void setPen(const QColor &color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawLine(const QLineF &line)
Draws a line defined by line.
Definition qpainter.h:442
QPaintEngine * paintEngine() const
Returns the paint engine that the painter is currently operating on if the painter is active; otherwi...
void setBrushOrigin(int x, int y)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qpainter.h:698
const QFont & font() const
Returns the currently set font used for drawing text.
void restore()
Restores the current painter state (pops a saved state off the stack).
void rotate(qreal a)
Rotates the coordinate system clockwise.
QFontMetrics fontMetrics() const
Returns the font metrics for the painter if the painter is active.
void drawLines(const QLineF *lines, int lineCount)
Draws the first lineCount lines in the array lines using the current pen.
void setCompositionMode(CompositionMode mode)
Sets the composition mode to the given mode.
void save()
Saves the current painter state (pushes the state onto a stack).
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Draws the rectangular portion source of the given image into the target rectangle in the paint device...
void setFont(const QFont &f)
Sets the painter's font to the given font.
QRegion clipRegion() const
Returns the currently set clip region.
void drawText(const QPointF &p, const QString &s)
Draws the given text with the currently defined text direction, beginning at the given position.
const QTransform & deviceTransform() const
Returns the matrix that transforms from logical coordinates to device coordinates of the platform dep...
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
void eraseRect(const QRectF &)
Erases the area inside the given rectangle.
QPoint brushOrigin() const
Returns the currently set brush origin.
void setBrush(const QBrush &brush)
Sets the painter's brush to the given brush.
bool end()
Ends painting.
@ CompositionMode_SourceIn
Definition qpainter.h:103
bool isActive() const
Returns true if begin() has been called and end() has not yet been called; otherwise returns false.
void translate(const QPointF &offset)
Translates the coordinate system by the given offset; i.e.
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
bool hasClipping() const
Returns true if clipping has been set; otherwise returns false.
void setClipRegion(const QRegion &, Qt::ClipOperation op=Qt::ReplaceClip)
Sets the clip region to the given region using the specified clip operation.
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
const QBrush & brush(ColorGroup cg, ColorRole cr) const
Returns the brush in the specified color group, used for the given color role.
Definition qpalette.cpp:794
const QColor & color(ColorGroup cg, ColorRole cr) const
Returns the color in the specified color group, used for the given color role.
Definition qpalette.h:66
void setBrush(ColorRole cr, const QBrush &brush)
Sets the brush for the given color role to the specified brush for all groups in the palette.
Definition qpalette.h:150
ResolveMask resolveMask() const
ColorGroup
\value Disabled \value Active \value Inactive \value Normal synonym for Active
Definition qpalette.h:48
@ Inactive
Definition qpalette.h:48
@ Disabled
Definition qpalette.h:48
void setColor(ColorGroup cg, ColorRole cr, const QColor &color)
Sets the color in the specified color group, used for the given color role, to the specified solid co...
Definition qpalette.h:145
const QBrush & base() const
Returns the base brush of the current color group.
Definition qpalette.h:88
@ HighlightedText
Definition qpalette.h:52
@ BrightText
Definition qpalette.h:51
@ AlternateBase
Definition qpalette.h:54
@ ButtonText
Definition qpalette.h:51
@ WindowText
Definition qpalette.h:50
@ Highlight
Definition qpalette.h:52
@ ToolTipText
Definition qpalette.h:56
\inmodule QtGui
Definition qpen.h:25
static bool find(const QString &key, QPixmap *pixmap)
Looks for a cached pixmap associated with the given key in the cache.
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
static void clear()
Removes all pixmaps from the cache.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QImage toImage() const
Converts the pixmap to a QImage.
Definition qpixmap.cpp:412
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition qpixmap.cpp:460
int width() const
Returns the width of the pixmap.
Definition qpixmap.cpp:472
QPixmap copy(int x, int y, int width, int height) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qpixmap.h:153
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
Definition qpixmap.cpp:854
static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Converts the given image to a pixmap using the specified flags to control the conversion.
Definition qpixmap.cpp:1445
The QPlatformNativeInterface class provides an abstraction for retrieving native resource handles.
virtual void * nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *backingStore)
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:394
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr void moveTo(qreal x, qreal y) noexcept
Moves the rectangle, leaving the top-left corner at the given position (x, y).
Definition qrect.h:736
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr QRectF translated(qreal dx, qreal dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:748
constexpr QPointF topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:510
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:721
constexpr QRect toRect() const noexcept
Returns a QRect based on the values of this rectangle.
Definition qrect.h:845
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:652
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:166
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:372
constexpr void moveCenter(const QPoint &p) noexcept
Moves the rectangle, leaving the center point at the given position.
Definition qrect.h:327
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:181
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:369
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:175
constexpr QPoint topRight() const noexcept
Returns the position of the rectangle's top-right corner.
Definition qrect.h:226
constexpr void setBottom(int pos) noexcept
Sets the bottom edge of the rectangle to the given y coordinate.
Definition qrect.h:199
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:172
constexpr void setRect(int x, int y, int w, int h) noexcept
Sets the coordinates of the rectangle's top-left corner to ({x}, {y}), and its size to the given widt...
Definition qrect.h:345
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:184
constexpr void setWidth(int w) noexcept
Sets the width of the rectangle to the given width.
Definition qrect.h:380
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:241
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
QRect united(const QRect &other) const noexcept
Definition qrect.h:419
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:187
constexpr void setHeight(int h) noexcept
Sets the height of the rectangle to the given height.
Definition qrect.h:383
constexpr void moveTop(int pos) noexcept
Moves the rectangle vertically, leaving the rectangle's top edge at the given y coordinate.
Definition qrect.h:288
constexpr QPoint center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:232
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:178
constexpr void setTop(int pos) noexcept
Sets the top edge of the rectangle to the given y coordinate.
Definition qrect.h:193
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
int rectCount() const noexcept
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
QRegion translated(int dx, int dy) const
Definition qregion.cpp:593
\inmodule QtCore
Definition qsize.h:207
constexpr QSize toSize() const noexcept
Returns an integer based copy of this size.
Definition qsize.h:390
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:321
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:315
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:324
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:156
constexpr void setWidth(int w) noexcept
Sets the width to the given width.
Definition qsize.h:135
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:153
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
constexpr void setHeight(int h) noexcept
Sets the height to the given height.
Definition qsize.h:138
@ TicksAbove
Definition qslider.h:27
@ TicksRight
Definition qslider.h:30
@ TicksBelow
Definition qslider.h:29
@ TicksLeft
Definition qslider.h:28
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1164
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString & append(QChar c)
Definition qstring.cpp:3227
void setDuration(int duration)
void setStartTime(QTime time)
The QStyleHintReturnMask class provides style hints that return a QRegion.
\variable QStyleOptionGraphicsItem::exposedRect
\variable QStyleOptionHeaderV2::textElideMode
ButtonFeatures features
\variable QStyleOptionToolButton::features
\variable QStyleOptionMenuItem::menuItemType
QStyle::SubControls activeSubControls
\variable QStyleOption::palette
\variable QStyleOptionFrame::features
The QStyleOptionHeader class is used to describe the parameters for drawing a header.
SortIndicator
Indicates which direction the sort indicator should be drawn.
\variable QStyleOptionProgressBar::minimum
\variable QStyleOptionToolBox::selectedPosition
Qt::WindowFlags titleBarFlags
\variable QStyleOptionDockWidget::title
The QStyleOption class stores the parameters used by QStyle functions.
QStyle::State state
QObject * styleObject
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ State_MouseOver
Definition qstyle.h:80
@ State_Sunken
Definition qstyle.h:69
@ State_Active
Definition qstyle.h:83
@ State_Open
Definition qstyle.h:85
@ State_Enabled
Definition qstyle.h:67
@ State_Horizontal
Definition qstyle.h:74
@ State_On
Definition qstyle.h:72
@ State_Selected
Definition qstyle.h:82
@ SP_TitleBarCloseButton
Definition qstyle.h:718
@ SP_TitleBarMaxButton
Definition qstyle.h:717
static int sliderPositionFromValue(int min, int max, int val, int space, bool upsideDown=false)
Converts the given logicalValue to a pixel position.
Definition qstyle.cpp:2223
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Returns the given logicalRectangle converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2144
PixelMetric
This enum describes the various available pixel metrics.
Definition qstyle.h:413
@ PM_MenuVMargin
Definition qstyle.h:452
@ PM_MenuPanelWidth
Definition qstyle.h:453
@ PM_ScrollBarExtent
Definition qstyle.h:426
@ PM_DockWidgetFrameWidth
Definition qstyle.h:437
@ PM_TitleBarHeight
Definition qstyle.h:448
@ PM_DockWidgetTitleMargin
Definition qstyle.h:503
@ PM_ExclusiveIndicatorHeight
Definition qstyle.h:465
@ PM_MdiSubWindowFrameWidth
Definition qstyle.h:471
@ PM_DockWidgetTitleBarButtonMargin
Definition qstyle.h:507
@ PM_IndicatorWidth
Definition qstyle.h:462
@ PM_IndicatorHeight
Definition qstyle.h:463
@ PM_MenuButtonIndicator
Definition qstyle.h:416
@ PM_HeaderMargin
Definition qstyle.h:474
@ PM_MenuHMargin
Definition qstyle.h:451
@ PM_ProgressBarChunkWidth
Definition qstyle.h:445
@ PM_SliderThickness
Definition qstyle.h:429
@ PM_ExclusiveIndicatorWidth
Definition qstyle.h:464
@ PM_ScrollBarSliderMin
Definition qstyle.h:427
@ CC_MdiControls
Definition qstyle.h:340
@ CC_TitleBar
Definition qstyle.h:337
PrimitiveElement
This enum describes the various primitive elements.
Definition qstyle.h:102
@ PE_FrameLineEdit
Definition qstyle.h:108
@ PE_IndicatorCheckBox
Definition qstyle.h:131
@ PE_IndicatorRadioButton
Definition qstyle.h:136
@ SE_ItemViewItemDecoration
Definition qstyle.h:304
@ SE_ItemViewItemFocusRect
Definition qstyle.h:306
@ SE_ItemViewItemText
Definition qstyle.h:305
SubControl
This enum describes the available sub controls.
Definition qstyle.h:347
@ SC_TitleBarMinButton
Definition qstyle.h:377
@ SC_TitleBarUnshadeButton
Definition qstyle.h:382
@ SC_MdiMinButton
Definition qstyle.h:395
@ SC_TitleBarNormalButton
Definition qstyle.h:380
@ SC_TitleBarShadeButton
Definition qstyle.h:381
@ SC_TitleBarSysMenu
Definition qstyle.h:376
@ SC_TitleBarMaxButton
Definition qstyle.h:378
@ SC_TitleBarCloseButton
Definition qstyle.h:379
@ SC_TitleBarContextHelpButton
Definition qstyle.h:383
static QPoint visualPos(Qt::LayoutDirection direction, const QRect &boundingRect, const QPoint &logicalPos)
Returns the given logicalPosition converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2163
@ RoundedSouth
Definition qtabbar.h:42
@ RoundedNorth
Definition qtabbar.h:42
@ TriangularEast
Definition qtabbar.h:43
@ RoundedWest
Definition qtabbar.h:42
@ TriangularSouth
Definition qtabbar.h:43
@ RoundedEast
Definition qtabbar.h:42
@ TriangularWest
Definition qtabbar.h:43
@ TriangularNorth
Definition qtabbar.h:43
The QTabWidget class provides a stack of tabbed widgets.
Definition qtabwidget.h:20
\inmodule QtCore \reentrant
Definition qdatetime.h:189
static QTime currentTime()
Returns the current time as reported by the system clock.
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & rotate(qreal a, Qt::Axis axis=Qt::ZAxis, qreal distanceToPlane=1024.0f)
The QTreeView class provides a default model/view implementation of a tree view.
Definition qtreeview.h:20
constexpr size_type size() const noexcept
bool isEmpty() const
void append(const T &t)
const T * constData() const
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
bool toBool() const
Returns the variant as a bool if the variant has userType() Bool.
QRect toRect() const
Returns the variant as a QRect if the variant has userType() \l QMetaType::QRect; otherwise returns a...
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setAttribute(Qt::WidgetAttribute, bool on=true)
Sets the attribute attribute on this widget if on is true; otherwise clears the attribute.
QWidget * nativeParentWidget() const
Definition qwidget.cpp:4340
void setContentsMargins(int left, int top, int right, int bottom)
Sets the margins around the contents of the widget to have the sizes left, top, right,...
Definition qwidget.cpp:7676
void setWindowOpacity(qreal level)
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition qwidget.h:106
void setPalette(const QPalette &)
Definition qwidget.cpp:4537
QPalette palette
the widget's palette
Definition qwidget.h:132
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
bool isEnabled() const
Definition qwidget.h:814
QIcon windowIcon
the widget's icon
Definition qwidget.h:152
void setFont(const QFont &)
Definition qwidget.cpp:4674
QFont font
the font currently set for the widget
Definition qwidget.h:133
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
bool isWindow() const
Returns true if the widget is an independent window, otherwise returns false.
Definition qwidget.h:811
QBackingStore * backingStore() const
bool isActiveWindow
whether this widget's window is the active window
Definition qwidget.h:139
Qt::WindowType windowType() const
Returns the window type of this widget.
Definition qwidget.h:801
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition qwidget.h:910
\inmodule QtGui
Definition qwindow.h:63
QMarginsF margins(const QRect &rect, int propId=TMT_CONTENTMARGINS)
const QWidget * widget
static RECT toRECT(const QRect &qr)
static QSizeF themeSize(const QWidget *w=nullptr, QPainter *p=nullptr, int themeIn=-1, int part=0, int state=0)
void paint(QPainter *painter, const QStyleOption *option)
HBITMAP buffer(int w=0, int h=0)
static int fixedPixelMetric(QStyle::PixelMetric pm)
static HDC hdcForWidgetBackingStore(const QWidget *widget)
static QBackingStore * backingStoreForWidget(const QWidget *widget)
bool swapAlphaChannel(const QRect &rect, bool allPixels=false)
bool drawBackgroundThruNativeBuffer(QWindowsThemeData &QWindowsThemeData, qreal aditionalDevicePixelRatio, qreal correctionFactor)
static HWND winId(const QWidget *widget)
static HTHEME openThemeForPrimaryScreenDpi(HWND hwnd, const wchar_t *name)
void init(bool force=false)
static bool isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget)
bool drawBackgroundDirectly(HDC dc, QWindowsThemeData &QWindowsThemeData, qreal aditionalDevicePixelRatio)
static bool isItemViewDelegateLineEdit(const QWidget *widget)
static bool useVista(bool update=false)
static HTHEME createTheme(int theme, HWND hwnd)
bool fixAlphaChannel(const QRect &rect)
void cleanup(bool force=false)
bool isTransparent(QWindowsThemeData &QWindowsThemeData)
bool hasAlphaChannel(const QRect &rect)
QRegion region(QWindowsThemeData &QWindowsThemeData)
bool drawBackground(QWindowsThemeData &QWindowsThemeData, qreal correctionFactor=1)
static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option=nullptr, const QWidget *widget=nullptr)
static QString themeName(int theme)
The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows ...
QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const override
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const override
int styleHint(StyleHint hint, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr, QStyleHintReturn *returnData=nullptr) const override
SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget=nullptr) const override
void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override
void polish(QWidget *widget) override
int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const override
QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget=nullptr) const override
QWindowsVistaStyle()
Constructs a QWindowsVistaStyle object.
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const override
\reimp
~QWindowsVistaStyle() override
Destructor.
void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget=nullptr) const override
QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const override
void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const override
void unpolish(QWidget *widget) override
QOpenGLWidget * widget
[1]
QPixmap p2
QPixmap p1
[0]
QPushButton * button
[2]
opt iconSize
rect
[4]
QPixmap pix
uint alignment
else opt state
[0]
QRect textRect
const QStyleOptionButton * btn
[3]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
void qErrnoWarning(const char *msg,...)
Q_WIDGETS_EXPORT qreal dpiScaled(qreal value, qreal dpi)
Combined button and popup list for selecting options.
@ WindowMinimized
Definition qnamespace.h:252
@ WindowMaximized
Definition qnamespace.h:253
@ BottomLeftCorner
@ TopRightCorner
@ TopLeftCorner
@ BottomRightCorner
@ AlignBottom
Definition qnamespace.h:153
@ AlignVCenter
Definition qnamespace.h:154
@ AlignTop
Definition qnamespace.h:152
@ AlignHCenter
Definition qnamespace.h:147
@ AlignCenter
Definition qnamespace.h:162
@ AlignLeft
Definition qnamespace.h:143
@ SmoothTransformation
@ WA_UnderMouse
Definition qnamespace.h:283
@ WA_Hover
Definition qnamespace.h:339
@ WA_TranslucentBackground
Definition qnamespace.h:401
@ WA_StyledBackground
Definition qnamespace.h:365
@ IntersectClip
@ LeftToRight
@ RightToLeft
@ KeepAspectRatio
Orientation
Definition qnamespace.h:97
@ Horizontal
Definition qnamespace.h:98
@ Vertical
Definition qnamespace.h:99
@ TextSingleLine
Definition qnamespace.h:169
@ TextDontClip
Definition qnamespace.h:170
@ TextHideMnemonic
Definition qnamespace.h:177
@ TextShowMnemonic
Definition qnamespace.h:172
@ transparent
Definition qnamespace.h:46
@ Dense4Pattern
@ NoBrush
@ Desktop
Definition qnamespace.h:214
@ WindowContextHelpButtonHint
Definition qnamespace.h:230
@ WindowMaximizeButtonHint
Definition qnamespace.h:228
@ WindowMinimizeButtonHint
Definition qnamespace.h:227
@ WindowShadeButtonHint
Definition qnamespace.h:231
@ Tool
Definition qnamespace.h:211
@ WindowSystemMenuHint
Definition qnamespace.h:226
@ ElideRight
Definition qnamespace.h:189
Definition image.cpp:4
QVector3D Q_QUICK3DUTILS_EXPORT rotate(const QMatrix4x4 &m, const QVector3D &v)
Definition qssgutils.cpp:75
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
#define qApp
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter * sub
static QString header(const QString &name)
void qDrawWinButton(QPainter *p, int x, int y, int w, int h, const QPalette &pal, bool sunken, const QBrush *fill)
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
static void visualRect(QRectF *geom, Qt::LayoutDirection dir, const QRectF &contentsRect)
static int area(const QSize &s)
Definition qicon.cpp:152
static const double leftOffset
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
return ret
static const QStyle::SubControl SubControls[]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
static QString themeName()
GLsizei const GLfloat * v
[13]
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLuint GLfloat GLfloat GLfloat x1
GLint GLenum GLsizei GLsizei GLsizei GLint border
GLenum GLuint buffer
GLint GLsizei width
GLenum type
GLuint GLsizei const GLchar * label
[43]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint ref
GLuint name
GLint first
GLuint GLenum transformType
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
GLuint res
GLint void * img
Definition qopenglext.h:233
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLuint GLenum option
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy)
static bool hasAlpha(const QImage &image)
#define ERROR(description)
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define QT_CONFIG(feature)
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
long HRESULT
#define disabled
#define RBS_INACTIVE
#define TMT_TEXTSHADOWCOLOR
@ UnknownAlpha
#define MAXBS_INACTIVE
#define CBS_INACTIVE
#define TST_NONE
static bool isFullyOpaque(const QWindowsThemeData &themeData)
#define BP_COMMANDLINK
#define CMDLGS_NORMAL
static QRectF scaleRect(const QRectF &r, qreal factor)
#define LISS_HOTSELECTED
static const int windowsItemFrame
#define TMT_CONTENTMARGINS
static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb)
#define LISS_SELECTEDNOTFOCUS
static const int windowsItemHMargin
bool canAnimate(const QStyleOption *option)
#define LISS_HOT
QStyleOption * clonedAnimationStyleOption(const QStyleOption *option)
static void qt_add_rect(HRGN &winRegion, QRect r)
#define CMDLGS_PRESSED
static int buttonStateId(int flags, int partId)
#define LISS_SELECTED
static const int windowsArrowHMargin
static QRegion scaleRegion(const QRegion &region, qreal factor)
static const int windowsItemVMargin
static void populateTitleBarButtonTheme(const QStyle *proxy, const QWidget *widget, const QStyleOptionComplex *option, QStyle::SubControl subControl, bool isTitleBarActive, int part, QWindowsThemeData *theme)
QObject * styleObject(const QStyleOption *option)
#define BP_COMMANDLINKGLYPH
static Qt::Orientation progressBarOrientation(const QStyleOption *option=nullptr)
static HRGN qt_hrgn_from_qregion(const QRegion &region)
void deleteClonedAnimationStyleOption(const QStyleOption *option)
@ SimpleTransform
@ HighDpiScalingTransform
@ ComplexTransform
static QImage createAnimationBuffer(const QStyleOption *option, const QWidget *widget)
static HWND createTreeViewHelperWindow()
#define CMDLGS_DISABLED
static const wchar_t * themeNames[QWindowsVistaStylePrivate::NThemes]
#define CMDLGS_HOT
static bool supportsStateTransition(QStyle::PrimitiveElement element, const QStyleOption *option, const QWidget *widget)
static const int windowsRightBorder
QWidget * panel
Definition settings.cpp:7
QList< int > list
[14]
if(qFloatDistance(a, b)<(1<< 7))
[0]
QRandomGenerator64 rd
[10]
ba fill(true)
QLinearGradient alphaGradient(rect.topLeft(), rect.bottomLeft())
[1]
rect deviceTransform(view->viewportTransform()).map(QPointF(0
QApplication app(argc, argv)
[0]
widget render & pixmap
QPainter painter(this)
[7]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
QNetworkProxy proxy
[0]
QQuickView * view
[0]
\inmodule QtCore \reentrant
Definition qchar.h:17