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
4#include <qglobal.h>
5#include "qstylesheetstyle_p.h"
6
7#if QT_CONFIG(style_stylesheet)
8
9#include "private/qcssutil_p.h"
10#include <qdebug.h>
11#include <qdir.h>
12#include <qapplication.h>
13#if QT_CONFIG(menu)
14#include <qmenu.h>
15#endif
16#if QT_CONFIG(menubar)
17#include <qmenubar.h>
18#endif
19#include <qpainter.h>
20#include <qstyleoption.h>
21#if QT_CONFIG(lineedit)
22#include <qlineedit.h>
23#endif
24#if QT_CONFIG(textedit)
25#include <qtextedit.h>
26#include <qplaintextedit.h>
27#endif
28#include <private/qwindowsstyle_p.h>
29#if QT_CONFIG(combobox)
30#include <qcombobox.h>
31#endif
32#include "private/qcssparser_p.h"
33#include "private/qmath_p.h"
34#include <qabstractscrollarea.h>
35#include "private/qabstractscrollarea_p.h"
36#if QT_CONFIG(tooltip)
37#include <qtooltip.h>
38#endif
39#include <qshareddata.h>
40#if QT_CONFIG(toolbutton)
41#include <qtoolbutton.h>
42#endif
43#if QT_CONFIG(scrollbar)
44#include <qscrollbar.h>
45#endif
46#if QT_CONFIG(abstractslider)
47#include <qabstractslider.h>
48#endif
49#include <qstring.h>
50#include <qfile.h>
51#if QT_CONFIG(checkbox)
52#include <qcheckbox.h>
53#endif
54#if QT_CONFIG(itemviews)
55#include <qheaderview.h>
56#endif
57#include <private/qwindowsstyle_p_p.h>
58#if QT_CONFIG(animation)
59#include <private/qstyleanimation_p.h>
60#endif
61#if QT_CONFIG(tabbar)
62#include <private/qtabbar_p.h>
63#endif
64#include <QMetaProperty>
65#if QT_CONFIG(mainwindow)
66#include <qmainwindow.h>
67#endif
68#if QT_CONFIG(dockwidget)
69#include <qdockwidget.h>
70#endif
71#if QT_CONFIG(mdiarea)
72#include <qmdisubwindow.h>
73#endif
74#if QT_CONFIG(dialog)
75#include <qdialog.h>
76#endif
77#include <private/qwidget_p.h>
78#if QT_CONFIG(spinbox)
79#include <QAbstractSpinBox>
80#endif
81#if QT_CONFIG(label)
82#include <QLabel>
83#endif
84#include "qdrawutil.h"
85
86#include <limits.h>
87#if QT_CONFIG(toolbar)
88#include <QtWidgets/qtoolbar.h>
89#endif
90#if QT_CONFIG(pushbutton)
91#include <QtWidgets/qpushbutton.h>
92#endif
93
94#include <QtGui/qpainterpath.h>
95#include <QtGui/qscreen.h>
96
97#include <QtCore/private/qduplicatetracker_p.h>
98
99QT_BEGIN_NAMESPACE
100
101using namespace Qt::StringLiterals;
102
103using namespace QCss;
104
105
106class QStyleSheetStylePrivate : public QWindowsStylePrivate
107{
108 Q_DECLARE_PUBLIC(QStyleSheetStyle)
109public:
110 QStyleSheetStylePrivate() { }
111};
112
113
114static QStyleSheetStyleCaches *styleSheetCaches = nullptr;
115
116/* RECURSION_GUARD:
117 * the QStyleSheetStyle is a proxy. If used with others proxy style, we may end up with something like:
118 * QStyleSheetStyle -> ProxyStyle -> QStyleSheetStyle -> OriginalStyle
119 * Recursion may happen if the style call the widget()->style() again.
120 * Not to mention the performance penalty of having two lookup of rules.
121 *
122 * The first instance of QStyleSheetStyle will set globalStyleSheetStyle to itself. The second one
123 * will notice the globalStyleSheetStyle is not istelf and call its base style directly.
124 */
125static const QStyleSheetStyle *globalStyleSheetStyle = nullptr;
126class QStyleSheetStyleRecursionGuard
127{
128 public:
129 QStyleSheetStyleRecursionGuard(const QStyleSheetStyle *that)
130 : guarded(globalStyleSheetStyle == nullptr)
131 {
132 if (guarded) globalStyleSheetStyle = that;
133 }
134 ~QStyleSheetStyleRecursionGuard() { if (guarded) globalStyleSheetStyle = nullptr; }
135 bool guarded;
136};
137#define RECURSION_GUARD(RETURN) \
138 if (globalStyleSheetStyle != 0 && globalStyleSheetStyle != this) { RETURN; } \
139 QStyleSheetStyleRecursionGuard recursion_guard(this);
140
141enum PseudoElement {
142 PseudoElement_None,
143 PseudoElement_DownArrow,
144 PseudoElement_UpArrow,
145 PseudoElement_LeftArrow,
146 PseudoElement_RightArrow,
147 PseudoElement_Indicator,
148 PseudoElement_ExclusiveIndicator,
149 PseudoElement_PushButtonMenuIndicator,
150 PseudoElement_ComboBoxDropDown,
151 PseudoElement_ComboBoxArrow,
152 PseudoElement_Item,
153 PseudoElement_SpinBoxUpButton,
154 PseudoElement_SpinBoxUpArrow,
155 PseudoElement_SpinBoxDownButton,
156 PseudoElement_SpinBoxDownArrow,
157 PseudoElement_GroupBoxTitle,
158 PseudoElement_GroupBoxIndicator,
159 PseudoElement_ToolButtonMenu,
160 PseudoElement_ToolButtonMenuArrow,
161 PseudoElement_ToolButtonMenuIndicator,
162 PseudoElement_ToolBoxTab,
163 PseudoElement_ScrollBarSlider,
164 PseudoElement_ScrollBarAddPage,
165 PseudoElement_ScrollBarSubPage,
166 PseudoElement_ScrollBarAddLine,
167 PseudoElement_ScrollBarSubLine,
168 PseudoElement_ScrollBarFirst,
169 PseudoElement_ScrollBarLast,
170 PseudoElement_ScrollBarUpArrow,
171 PseudoElement_ScrollBarDownArrow,
172 PseudoElement_ScrollBarLeftArrow,
173 PseudoElement_ScrollBarRightArrow,
174 PseudoElement_SplitterHandle,
175 PseudoElement_ToolBarHandle,
176 PseudoElement_ToolBarSeparator,
177 PseudoElement_MenuScroller,
178 PseudoElement_MenuTearoff,
179 PseudoElement_MenuCheckMark,
180 PseudoElement_MenuSeparator,
181 PseudoElement_MenuIcon,
182 PseudoElement_MenuRightArrow,
183 PseudoElement_TreeViewBranch,
184 PseudoElement_HeaderViewSection,
185 PseudoElement_HeaderViewUpArrow,
186 PseudoElement_HeaderViewDownArrow,
187 PseudoElement_ProgressBarChunk,
188 PseudoElement_TabBarTab,
189 PseudoElement_TabBarScroller,
190 PseudoElement_TabBarTear,
191 PseudoElement_SliderGroove,
192 PseudoElement_SliderHandle,
193 PseudoElement_SliderAddPage,
194 PseudoElement_SliderSubPage,
195 PseudoElement_SliderTickmark,
196 PseudoElement_TabWidgetPane,
197 PseudoElement_TabWidgetTabBar,
198 PseudoElement_TabWidgetLeftCorner,
199 PseudoElement_TabWidgetRightCorner,
200 PseudoElement_DockWidgetTitle,
201 PseudoElement_DockWidgetCloseButton,
202 PseudoElement_DockWidgetFloatButton,
203 PseudoElement_DockWidgetSeparator,
204 PseudoElement_MdiCloseButton,
205 PseudoElement_MdiMinButton,
206 PseudoElement_MdiNormalButton,
207 PseudoElement_TitleBar,
208 PseudoElement_TitleBarCloseButton,
209 PseudoElement_TitleBarMinButton,
210 PseudoElement_TitleBarMaxButton,
211 PseudoElement_TitleBarShadeButton,
212 PseudoElement_TitleBarUnshadeButton,
213 PseudoElement_TitleBarNormalButton,
214 PseudoElement_TitleBarContextHelpButton,
215 PseudoElement_TitleBarSysMenu,
216 PseudoElement_ViewItem,
217 PseudoElement_ViewItemIcon,
218 PseudoElement_ViewItemText,
219 PseudoElement_ViewItemIndicator,
220 PseudoElement_ScrollAreaCorner,
221 PseudoElement_TabBarTabCloseButton,
222 NumPseudoElements
223};
224
225struct PseudoElementInfo {
226 QStyle::SubControl subControl;
227 const char name[19];
228};
229
230static const PseudoElementInfo knownPseudoElements[NumPseudoElements] = {
231 { .subControl: QStyle::SC_None, .name: "" },
232 { .subControl: QStyle::SC_None, .name: "down-arrow" },
233 { .subControl: QStyle::SC_None, .name: "up-arrow" },
234 { .subControl: QStyle::SC_None, .name: "left-arrow" },
235 { .subControl: QStyle::SC_None, .name: "right-arrow" },
236 { .subControl: QStyle::SC_None, .name: "indicator" },
237 { .subControl: QStyle::SC_None, .name: "indicator" },
238 { .subControl: QStyle::SC_None, .name: "menu-indicator" },
239 { .subControl: QStyle::SC_ComboBoxArrow, .name: "drop-down" },
240 { .subControl: QStyle::SC_ComboBoxArrow, .name: "down-arrow" },
241 { .subControl: QStyle::SC_None, .name: "item" },
242 { .subControl: QStyle::SC_SpinBoxUp, .name: "up-button" },
243 { .subControl: QStyle::SC_SpinBoxUp, .name: "up-arrow" },
244 { .subControl: QStyle::SC_SpinBoxDown, .name: "down-button" },
245 { .subControl: QStyle::SC_SpinBoxDown, .name: "down-arrow" },
246 { .subControl: QStyle::SC_GroupBoxLabel, .name: "title" },
247 { .subControl: QStyle::SC_GroupBoxCheckBox, .name: "indicator" },
248 { .subControl: QStyle::SC_ToolButtonMenu, .name: "menu-button" },
249 { .subControl: QStyle::SC_ToolButtonMenu, .name: "menu-arrow" },
250 { .subControl: QStyle::SC_None, .name: "menu-indicator" },
251 { .subControl: QStyle::SC_None, .name: "tab" },
252 { .subControl: QStyle::SC_ScrollBarSlider, .name: "handle" },
253 { .subControl: QStyle::SC_ScrollBarAddPage, .name: "add-page" },
254 { .subControl: QStyle::SC_ScrollBarSubPage, .name: "sub-page" },
255 { .subControl: QStyle::SC_ScrollBarAddLine, .name: "add-line" },
256 { .subControl: QStyle::SC_ScrollBarSubLine, .name: "sub-line" },
257 { .subControl: QStyle::SC_ScrollBarFirst, .name: "first" },
258 { .subControl: QStyle::SC_ScrollBarLast, .name: "last" },
259 { .subControl: QStyle::SC_ScrollBarSubLine, .name: "up-arrow" },
260 { .subControl: QStyle::SC_ScrollBarAddLine, .name: "down-arrow" },
261 { .subControl: QStyle::SC_ScrollBarSubLine, .name: "left-arrow" },
262 { .subControl: QStyle::SC_ScrollBarAddLine, .name: "right-arrow" },
263 { .subControl: QStyle::SC_None, .name: "handle" },
264 { .subControl: QStyle::SC_None, .name: "handle" },
265 { .subControl: QStyle::SC_None, .name: "separator" },
266 { .subControl: QStyle::SC_None, .name: "scroller" },
267 { .subControl: QStyle::SC_None, .name: "tearoff" },
268 { .subControl: QStyle::SC_None, .name: "indicator" },
269 { .subControl: QStyle::SC_None, .name: "separator" },
270 { .subControl: QStyle::SC_None, .name: "icon" },
271 { .subControl: QStyle::SC_None, .name: "right-arrow" },
272 { .subControl: QStyle::SC_None, .name: "branch" },
273 { .subControl: QStyle::SC_None, .name: "section" },
274 { .subControl: QStyle::SC_None, .name: "down-arrow" },
275 { .subControl: QStyle::SC_None, .name: "up-arrow" },
276 { .subControl: QStyle::SC_None, .name: "chunk" },
277 { .subControl: QStyle::SC_None, .name: "tab" },
278 { .subControl: QStyle::SC_None, .name: "scroller" },
279 { .subControl: QStyle::SC_None, .name: "tear" },
280 { .subControl: QStyle::SC_SliderGroove, .name: "groove" },
281 { .subControl: QStyle::SC_SliderHandle, .name: "handle" },
282 { .subControl: QStyle::SC_None, .name: "add-page" },
283 { .subControl: QStyle::SC_None, .name: "sub-page"},
284 { .subControl: QStyle::SC_SliderTickmarks, .name: "tick-mark" },
285 { .subControl: QStyle::SC_None, .name: "pane" },
286 { .subControl: QStyle::SC_None, .name: "tab-bar" },
287 { .subControl: QStyle::SC_None, .name: "left-corner" },
288 { .subControl: QStyle::SC_None, .name: "right-corner" },
289 { .subControl: QStyle::SC_None, .name: "title" },
290 { .subControl: QStyle::SC_None, .name: "close-button" },
291 { .subControl: QStyle::SC_None, .name: "float-button" },
292 { .subControl: QStyle::SC_None, .name: "separator" },
293 { .subControl: QStyle::SC_MdiCloseButton, .name: "close-button" },
294 { .subControl: QStyle::SC_MdiMinButton, .name: "minimize-button" },
295 { .subControl: QStyle::SC_MdiNormalButton, .name: "normal-button" },
296 { .subControl: QStyle::SC_TitleBarLabel, .name: "title" },
297 { .subControl: QStyle::SC_TitleBarCloseButton, .name: "close-button" },
298 { .subControl: QStyle::SC_TitleBarMinButton, .name: "minimize-button" },
299 { .subControl: QStyle::SC_TitleBarMaxButton, .name: "maximize-button" },
300 { .subControl: QStyle::SC_TitleBarShadeButton, .name: "shade-button" },
301 { .subControl: QStyle::SC_TitleBarUnshadeButton, .name: "unshade-button" },
302 { .subControl: QStyle::SC_TitleBarNormalButton, .name: "normal-button" },
303 { .subControl: QStyle::SC_TitleBarContextHelpButton, .name: "contexthelp-button" },
304 { .subControl: QStyle::SC_TitleBarSysMenu, .name: "sys-menu" },
305 { .subControl: QStyle::SC_None, .name: "item" },
306 { .subControl: QStyle::SC_None, .name: "icon" },
307 { .subControl: QStyle::SC_None, .name: "text" },
308 { .subControl: QStyle::SC_None, .name: "indicator" },
309 { .subControl: QStyle::SC_None, .name: "corner" },
310 { .subControl: QStyle::SC_None, .name: "close-button" },
311};
312
313
314struct QStyleSheetBorderImageData : public QSharedData
315{
316 QStyleSheetBorderImageData()
317 : horizStretch(QCss::TileMode_Unknown), vertStretch(QCss::TileMode_Unknown)
318 {
319 for (int i = 0; i < 4; i++)
320 cuts[i] = -1;
321 }
322 int cuts[4];
323 QPixmap pixmap;
324 QImage image;
325 QCss::TileMode horizStretch, vertStretch;
326};
327
328struct QStyleSheetBackgroundData : public QSharedData
329{
330 QStyleSheetBackgroundData(const QBrush& b, const QPixmap& p, QCss::Repeat r,
331 Qt::Alignment a, QCss::Origin o, Attachment t, QCss::Origin c)
332 : brush(b), pixmap(p), repeat(r), position(a), origin(o), attachment(t), clip(c) { }
333
334 bool isTransparent() const {
335 if (brush.style() != Qt::NoBrush)
336 return !brush.isOpaque();
337 return pixmap.isNull() ? false : pixmap.hasAlpha();
338 }
339 QBrush brush;
340 QPixmap pixmap;
341 QCss::Repeat repeat;
342 Qt::Alignment position;
343 QCss::Origin origin;
344 QCss::Attachment attachment;
345 QCss::Origin clip;
346};
347
348struct QStyleSheetBorderData : public QSharedData
349{
350 QStyleSheetBorderData() : bi(nullptr)
351 {
352 for (int i = 0; i < 4; i++) {
353 borders[i] = 0;
354 styles[i] = QCss::BorderStyle_None;
355 }
356 }
357
358 QStyleSheetBorderData(int *b, QBrush *c, QCss::BorderStyle *s, QSize *r) : bi(nullptr)
359 {
360 for (int i = 0; i < 4; i++) {
361 borders[i] = b[i];
362 styles[i] = s[i];
363 colors[i] = c[i];
364 radii[i] = r[i];
365 }
366 }
367
368 int borders[4];
369 QBrush colors[4];
370 QCss::BorderStyle styles[4];
371 QSize radii[4]; // topleft, topright, bottomleft, bottomright
372
373 const QStyleSheetBorderImageData *borderImage() const
374 { return bi; }
375 bool hasBorderImage() const { return bi!=nullptr; }
376
377 QSharedDataPointer<QStyleSheetBorderImageData> bi;
378
379 bool isOpaque() const
380 {
381 for (int i = 0; i < 4; i++) {
382 if (styles[i] == QCss::BorderStyle_Native || styles[i] == QCss::BorderStyle_None)
383 continue;
384 if (styles[i] >= QCss::BorderStyle_Dotted && styles[i] <= QCss::BorderStyle_DotDotDash
385 && styles[i] != BorderStyle_Solid)
386 return false;
387 if (!colors[i].isOpaque())
388 return false;
389 if (!radii[i].isEmpty())
390 return false;
391 }
392 if (bi != nullptr && bi->pixmap.hasAlpha())
393 return false;
394 return true;
395 }
396};
397
398
399struct QStyleSheetOutlineData : public QStyleSheetBorderData
400{
401 QStyleSheetOutlineData()
402 {
403 for (int i = 0; i < 4; i++) {
404 offsets[i] = 0;
405 }
406 }
407
408 QStyleSheetOutlineData(int *b, QBrush *c, QCss::BorderStyle *s, QSize *r, int *o)
409 : QStyleSheetBorderData(b, c, s, r)
410 {
411 for (int i = 0; i < 4; i++) {
412 offsets[i] = o[i];
413 }
414 }
415
416 int offsets[4];
417};
418
419struct QStyleSheetBoxData : public QSharedData
420{
421 QStyleSheetBoxData(int *m, int *p, int s) : spacing(s)
422 {
423 for (int i = 0; i < 4; i++) {
424 margins[i] = m[i];
425 paddings[i] = p[i];
426 }
427 }
428
429 int margins[4];
430 int paddings[4];
431
432 int spacing;
433};
434
435struct QStyleSheetPaletteData : public QSharedData
436{
437 QStyleSheetPaletteData(const QBrush &foreground,
438 const QBrush &selectedForeground,
439 const QBrush &selectedBackground,
440 const QBrush &alternateBackground,
441 const QBrush &placeHolderTextForeground,
442 const QBrush &accent)
443 : foreground(foreground)
444 , selectionForeground(selectedForeground)
445 , selectionBackground(selectedBackground)
446 , alternateBackground(alternateBackground)
447 , placeholderForeground(placeHolderTextForeground)
448 , accent(accent)
449 { }
450
451 QBrush foreground;
452 QBrush selectionForeground;
453 QBrush selectionBackground;
454 QBrush alternateBackground;
455 QBrush placeholderForeground;
456 QBrush accent;
457};
458
459struct QStyleSheetGeometryData : public QSharedData
460{
461 QStyleSheetGeometryData(int w, int h, int minw, int minh, int maxw, int maxh)
462 : minWidth(minw), minHeight(minh), width(w), height(h), maxWidth(maxw), maxHeight(maxh) { }
463
464 int minWidth, minHeight, width, height, maxWidth, maxHeight;
465};
466
467struct QStyleSheetPositionData : public QSharedData
468{
469 QStyleSheetPositionData(int l, int t, int r, int b, Origin o, Qt::Alignment p, QCss::PositionMode m, Qt::Alignment a = { })
470 : left(l), top(t), bottom(b), right(r), origin(o), position(p), mode(m), textAlignment(a) { }
471
472 int left, top, bottom, right;
473 Origin origin;
474 Qt::Alignment position;
475 QCss::PositionMode mode;
476 Qt::Alignment textAlignment;
477};
478
479struct QStyleSheetImageData : public QSharedData
480{
481 QStyleSheetImageData(const QIcon &i, Qt::Alignment a, const QSize &sz)
482 : icon(i), alignment(a), size(sz) { }
483
484 QIcon icon;
485 Qt::Alignment alignment;
486 QSize size;
487};
488
489class QRenderRule
490{
491public:
492 QRenderRule() : features(0), hasFont(false), pal(nullptr), b(nullptr), bg(nullptr), bd(nullptr), ou(nullptr), geo(nullptr), p(nullptr), img(nullptr), clipset(0) { }
493 QRenderRule(const QList<QCss::Declaration> &, const QObject *);
494
495 QRect borderRect(const QRect &r) const;
496 QRect outlineRect(const QRect &r) const;
497 QRect paddingRect(const QRect &r) const;
498 QRect contentsRect(const QRect &r) const;
499
500 enum { Margin = 1, Border = 2, Padding = 4, All=Margin|Border|Padding };
501 QRect boxRect(const QRect &r, int flags = All) const;
502 QSize boxSize(const QSize &s, int flags = All) const;
503 QRect originRect(const QRect &rect, Origin origin) const;
504
505 QPainterPath borderClip(QRect rect);
506 void drawBorder(QPainter *, const QRect&);
507 void drawOutline(QPainter *, const QRect&);
508 void drawBorderImage(QPainter *, const QRect&);
509 void drawBackground(QPainter *, const QRect&, const QPoint& = QPoint(0, 0));
510 void drawBackgroundImage(QPainter *, const QRect&, QPoint = QPoint(0, 0));
511 void drawFrame(QPainter *, const QRect&);
512 void drawImage(QPainter *p, const QRect &rect);
513 void drawRule(QPainter *, const QRect&);
514 void configurePalette(QPalette *, QPalette::ColorGroup, const QWidget *, bool);
515 void configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette::ColorRole br);
516
517 const QStyleSheetPaletteData *palette() const { return pal; }
518 const QStyleSheetBoxData *box() const { return b; }
519 const QStyleSheetBackgroundData *background() const { return bg; }
520 const QStyleSheetBorderData *border() const { return bd; }
521 const QStyleSheetOutlineData *outline() const { return ou; }
522 const QStyleSheetGeometryData *geometry() const { return geo; }
523 const QStyleSheetPositionData *position() const { return p; }
524 const QStyleSheetImageData *icon() const { return iconPtr; }
525
526 bool hasModification() const;
527
528 bool hasPalette() const { return pal != nullptr; }
529 bool hasBackground() const { return bg != nullptr && (!bg->pixmap.isNull() || bg->brush.style() != Qt::NoBrush); }
530 bool hasGradientBackground() const { return bg && bg->brush.style() >= Qt::LinearGradientPattern
531 && bg->brush.style() <= Qt::ConicalGradientPattern; }
532
533 bool hasNativeBorder() const {
534 return bd == nullptr
535 || (!bd->hasBorderImage() && bd->styles[0] == BorderStyle_Native);
536 }
537
538 bool hasNativeOutline() const {
539 return (ou == nullptr
540 || (!ou->hasBorderImage() && ou->styles[0] == BorderStyle_Native));
541 }
542
543 bool baseStyleCanDraw() const {
544 if (!hasBackground() || (background()->brush.style() == Qt::NoBrush && bg->pixmap.isNull()))
545 return true;
546 if (bg && !bg->pixmap.isNull())
547 return false;
548 if (hasGradientBackground())
549 return features & StyleFeature_BackgroundGradient;
550 return features & StyleFeature_BackgroundColor;
551 }
552
553 bool hasBox() const { return b != nullptr; }
554 bool hasBorder() const { return bd != nullptr; }
555 bool hasOutline() const { return ou != nullptr; }
556 bool hasPosition() const { return p != nullptr; }
557 bool hasGeometry() const { return geo != nullptr; }
558 bool hasDrawable() const { return !hasNativeBorder() || hasBackground() || hasImage(); }
559 bool hasImage() const { return img != nullptr; }
560 bool hasIcon() const { return iconPtr != nullptr; }
561
562 QSize minimumContentsSize() const
563 { return geo ? QSize(geo->minWidth, geo->minHeight) : QSize(0, 0); }
564 QSize minimumSize() const
565 { return boxSize(s: minimumContentsSize()); }
566
567 QSize contentsSize() const
568 { return geo ? QSize(geo->width, geo->height)
569 : ((img && img->size.isValid()) ? img->size : QSize()); }
570 QSize contentsSize(const QSize &sz) const
571 {
572 QSize csz = contentsSize();
573 if (csz.width() == -1) csz.setWidth(sz.width());
574 if (csz.height() == -1) csz.setHeight(sz.height());
575 return csz;
576 }
577 bool hasContentsSize() const
578 { return (geo && (geo->width != -1 || geo->height != -1)) || (img && img->size.isValid()); }
579
580 QSize size() const { return boxSize(s: contentsSize()); }
581 QSize size(const QSize &sz) const { return boxSize(s: contentsSize(sz)); }
582 QSize adjustSize(const QSize &sz)
583 {
584 if (!geo)
585 return sz;
586 QSize csz = contentsSize();
587 if (csz.width() == -1) csz.setWidth(sz.width());
588 if (csz.height() == -1) csz.setHeight(sz.height());
589 if (geo->maxWidth != -1 && csz.width() > geo->maxWidth) csz.setWidth(geo->maxWidth);
590 if (geo->maxHeight != -1 && csz.height() > geo->maxHeight) csz.setHeight(geo->maxHeight);
591 csz=csz.expandedTo(otherSize: QSize(geo->minWidth, geo->minHeight));
592 return csz;
593 }
594
595 bool hasStyleHint(const QString &sh) const { return styleHints.contains(key: sh); }
596 QVariant styleHint(const QString &sh) const { return styleHints.value(key: sh); }
597
598 void fixupBorder(int);
599
600 // Shouldn't be here
601 void setClip(QPainter *p, const QRect &rect);
602 void unsetClip(QPainter *);
603
604public:
605 int features;
606 QBrush defaultBackground;
607 QFont font; // Be careful using this font directly. Prefer using font.resolve( )
608 bool hasFont;
609
610 QHash<QString, QVariant> styleHints;
611
612 QSharedDataPointer<QStyleSheetPaletteData> pal;
613 QSharedDataPointer<QStyleSheetBoxData> b;
614 QSharedDataPointer<QStyleSheetBackgroundData> bg;
615 QSharedDataPointer<QStyleSheetBorderData> bd;
616 QSharedDataPointer<QStyleSheetOutlineData> ou;
617 QSharedDataPointer<QStyleSheetGeometryData> geo;
618 QSharedDataPointer<QStyleSheetPositionData> p;
619 QSharedDataPointer<QStyleSheetImageData> img;
620 QSharedDataPointer<QStyleSheetImageData> iconPtr;
621
622 int clipset;
623 QPainterPath clipPath;
624};
625Q_DECLARE_TYPEINFO(QRenderRule, Q_RELOCATABLE_TYPE);
626
627///////////////////////////////////////////////////////////////////////////////////////////
628static constexpr std::array<const char*, 90> knownStyleHints = {
629 "activate-on-singleclick",
630 "alignment",
631 "arrow-keys-navigate-into-children",
632 "backward-icon",
633 "button-layout",
634 "cd-icon",
635 "combobox-list-mousetracking",
636 "combobox-popup",
637 "computer-icon",
638 "desktop-icon",
639 "dialog-apply-icon",
640 "dialog-cancel-icon",
641 "dialog-close-icon",
642 "dialog-discard-icon",
643 "dialog-help-icon",
644 "dialog-no-icon",
645 "dialog-ok-icon",
646 "dialog-open-icon",
647 "dialog-reset-icon",
648 "dialog-save-icon",
649 "dialog-yes-icon",
650 "dialogbuttonbox-buttons-have-icons",
651 "directory-closed-icon",
652 "directory-icon",
653 "directory-link-icon",
654 "directory-open-icon",
655 "dither-disable-text",
656 "dockwidget-close-icon",
657 "downarrow-icon",
658 "dvd-icon",
659 "etch-disabled-text",
660 "file-icon",
661 "file-link-icon",
662 "filedialog-backward-icon", // unused
663 "filedialog-contentsview-icon",
664 "filedialog-detailedview-icon",
665 "filedialog-end-icon",
666 "filedialog-infoview-icon",
667 "filedialog-listview-icon",
668 "filedialog-new-directory-icon",
669 "filedialog-parent-directory-icon",
670 "filedialog-start-icon",
671 "floppy-icon",
672 "forward-icon",
673 "gridline-color",
674 "harddisk-icon",
675 "home-icon",
676 "lineedit-clear-button-icon",
677 "icon-size",
678 "leftarrow-icon",
679 "lineedit-password-character",
680 "lineedit-password-mask-delay",
681 "mdi-fill-space-on-maximize",
682 "menu-scrollable",
683 "menubar-altkey-navigation",
684 "menubar-separator",
685 "messagebox-critical-icon",
686 "messagebox-information-icon",
687 "messagebox-question-icon",
688 "messagebox-text-interaction-flags",
689 "messagebox-warning-icon",
690 "mouse-tracking",
691 "network-icon",
692 "opacity",
693 "paint-alternating-row-colors-for-empty-area",
694 "rightarrow-icon",
695 "scrollbar-contextmenu",
696 "scrollbar-leftclick-absolute-position",
697 "scrollbar-middleclick-absolute-position",
698 "scrollbar-roll-between-buttons",
699 "scrollbar-scroll-when-pointer-leaves-control",
700 "scrollview-frame-around-contents",
701 "show-decoration-selected",
702 "spinbox-click-autorepeat-rate",
703 "spincontrol-disable-on-bounds",
704 "tabbar-elide-mode",
705 "tabbar-prefer-no-arrows",
706 "titlebar-close-icon",
707 "titlebar-contexthelp-icon",
708 "titlebar-maximize-icon",
709 "titlebar-menu-icon",
710 "titlebar-minimize-icon",
711 "titlebar-normal-icon",
712 "titlebar-shade-icon",
713 "titlebar-show-tooltips-on-buttons",
714 "titlebar-unshade-icon",
715 "toolbutton-popup-delay",
716 "trash-icon",
717 "uparrow-icon",
718 "widget-animation-duration"
719};
720
721static QList<QVariant> subControlLayout(QByteArrayView layout)
722{
723 QList<QVariant> buttons;
724 for (int button : layout) {
725 switch (button) {
726 case 'm':
727 buttons.append(t: PseudoElement_MdiMinButton);
728 buttons.append(t: PseudoElement_TitleBarMinButton);
729 break;
730 case 'M':
731 buttons.append(t: PseudoElement_TitleBarMaxButton);
732 break;
733 case 'X':
734 buttons.append(t: PseudoElement_MdiCloseButton);
735 buttons.append(t: PseudoElement_TitleBarCloseButton);
736 break;
737 case 'N':
738 buttons.append(t: PseudoElement_MdiNormalButton);
739 buttons.append(t: PseudoElement_TitleBarNormalButton);
740 break;
741 case 'I':
742 buttons.append(t: PseudoElement_TitleBarSysMenu);
743 break;
744 case 'T':
745 buttons.append(t: PseudoElement_TitleBar);
746 break;
747 case 'H':
748 buttons.append(t: PseudoElement_TitleBarContextHelpButton);
749 break;
750 case 'S':
751 buttons.append(t: PseudoElement_TitleBarShadeButton);
752 break;
753 default:
754 buttons.append(t: button);
755 break;
756 }
757 }
758 return buttons;
759}
760
761namespace {
762 struct ButtonInfo {
763 QRenderRule rule;
764 int element;
765 int offset;
766 int where;
767 int width;
768 };
769}
770template <> class QTypeInfo<ButtonInfo> : public QTypeInfoMerger<ButtonInfo, QRenderRule, int> {};
771
772QHash<QStyle::SubControl, QRect> QStyleSheetStyle::titleBarLayout(const QWidget *w, const QStyleOptionTitleBar *tb) const
773{
774 QHash<QStyle::SubControl, QRect> layoutRects;
775 const bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
776 const bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
777 QRenderRule subRule = renderRule(w, tb);
778 QRect cr = subRule.contentsRect(r: tb->rect);
779 QList<QVariant> layout = subRule.styleHint(sh: "button-layout"_L1).toList();
780 if (layout.isEmpty())
781 layout = subControlLayout(layout: "I(T)HSmMX"_L1);
782
783 int offsets[3] = { 0, 0, 0 };
784 enum Where { Left, Right, Center, NoWhere } where = Left;
785 QList<ButtonInfo> infos;
786 infos.reserve(size: layout.size());
787 for (const QVariant &val : std::as_const(t&: layout)) {
788 const int element = val.toInt();
789 if (element == '(') {
790 where = Center;
791 } else if (element == ')') {
792 where = Right;
793 } else {
794 ButtonInfo info;
795 info.element = element;
796 switch (element) {
797 case PseudoElement_TitleBar:
798 if (!(tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)))
799 continue;
800 break;
801 case PseudoElement_TitleBarContextHelpButton:
802 if (!(tb->titleBarFlags & Qt::WindowContextHelpButtonHint))
803 continue;
804 break;
805 case PseudoElement_TitleBarMinButton:
806 if (!(tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
807 continue;
808 if (isMinimized)
809 info.element = PseudoElement_TitleBarNormalButton;
810 break;
811 case PseudoElement_TitleBarMaxButton:
812 if (!(tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
813 continue;
814 if (isMaximized)
815 info.element = PseudoElement_TitleBarNormalButton;
816 break;
817 case PseudoElement_TitleBarShadeButton:
818 if (!(tb->titleBarFlags & Qt::WindowShadeButtonHint))
819 continue;
820 if (isMinimized)
821 info.element = PseudoElement_TitleBarUnshadeButton;
822 break;
823 case PseudoElement_TitleBarCloseButton:
824 case PseudoElement_TitleBarSysMenu:
825 if (!(tb->titleBarFlags & Qt::WindowSystemMenuHint))
826 continue;
827 break;
828 default:
829 continue;
830 }
831 if (info.element == PseudoElement_TitleBar) {
832 info.width = tb->fontMetrics.horizontalAdvance(tb->text) + 6;
833 subRule.geo = new QStyleSheetGeometryData(info.width, tb->fontMetrics.height(), -1, -1, -1, -1);
834 } else {
835 subRule = renderRule(w, tb, info.element);
836 info.width = subRule.size().width();
837 }
838 info.rule = subRule;
839 info.offset = offsets[where];
840 info.where = where;
841 offsets[where] += info.width;
842
843 infos.append(t: std::move(info));
844 }
845 }
846
847 for (const ButtonInfo &info : std::as_const(t&: infos)) {
848 QRect lr = cr;
849 switch (info.where) {
850 case Center: {
851 lr.setLeft(cr.left() + offsets[Left]);
852 lr.setRight(cr.right() - offsets[Right]);
853 QRect r(0, 0, offsets[Center], lr.height());
854 r.moveCenter(p: lr.center());
855 r.setLeft(r.left()+info.offset);
856 r.setWidth(info.width);
857 lr = r;
858 break; }
859 case Left:
860 lr.translate(dx: info.offset, dy: 0);
861 lr.setWidth(info.width);
862 break;
863 case Right:
864 lr.moveLeft(pos: cr.right() + 1 - offsets[Right] + info.offset);
865 lr.setWidth(info.width);
866 break;
867 default:
868 break;
869 }
870 QStyle::SubControl control = knownPseudoElements[info.element].subControl;
871 layoutRects[control] = positionRect(w, rule2: info.rule, pe: info.element, originRect: lr, dir: tb->direction);
872 }
873
874 return layoutRects;
875}
876
877static QStyle::StandardPixmap subControlIcon(int pe)
878{
879 switch (pe) {
880 case PseudoElement_MdiCloseButton: return QStyle::SP_TitleBarCloseButton;
881 case PseudoElement_MdiMinButton: return QStyle::SP_TitleBarMinButton;
882 case PseudoElement_MdiNormalButton: return QStyle::SP_TitleBarNormalButton;
883 case PseudoElement_TitleBarCloseButton: return QStyle::SP_TitleBarCloseButton;
884 case PseudoElement_TitleBarMinButton: return QStyle::SP_TitleBarMinButton;
885 case PseudoElement_TitleBarMaxButton: return QStyle::SP_TitleBarMaxButton;
886 case PseudoElement_TitleBarShadeButton: return QStyle::SP_TitleBarShadeButton;
887 case PseudoElement_TitleBarUnshadeButton: return QStyle::SP_TitleBarUnshadeButton;
888 case PseudoElement_TitleBarNormalButton: return QStyle::SP_TitleBarNormalButton;
889 case PseudoElement_TitleBarContextHelpButton: return QStyle::SP_TitleBarContextHelpButton;
890 default: break;
891 }
892 return QStyle::SP_CustomBase;
893}
894
895QRenderRule::QRenderRule(const QList<Declaration> &declarations, const QObject *object)
896 : features(0),
897 hasFont(false),
898 pal(nullptr),
899 b(nullptr),
900 bg(nullptr),
901 bd(nullptr),
902 ou(nullptr),
903 geo(nullptr),
904 p(nullptr),
905 img(nullptr),
906 clipset(0)
907{
908 QPalette palette = QGuiApplication::palette(); // ###: ideally widget's palette
909 ValueExtractor v(declarations, palette);
910 features = v.extractStyleFeatures();
911
912 int w = -1, h = -1, minw = -1, minh = -1, maxw = -1, maxh = -1;
913 if (v.extractGeometry(w: &w, h: &h, minw: &minw, minh: &minh, maxw: &maxw, maxh: &maxh))
914 geo = new QStyleSheetGeometryData(w, h, minw, minh, maxw, maxh);
915
916 int left = 0, top = 0, right = 0, bottom = 0;
917 Origin origin = Origin_Unknown;
918 Qt::Alignment position;
919 QCss::PositionMode mode = PositionMode_Unknown;
920 Qt::Alignment textAlignment;
921 if (v.extractPosition(l: &left, t: &top, r: &right, b: &bottom, &origin, &position, &mode, &textAlignment))
922 p = new QStyleSheetPositionData(left, top, right, bottom, origin, position, mode, textAlignment);
923
924 int margins[4], paddings[4], spacing = -1;
925 for (int i = 0; i < 4; i++)
926 margins[i] = paddings[i] = 0;
927 if (v.extractBox(margins, paddings, spacing: &spacing))
928 b = new QStyleSheetBoxData(margins, paddings, spacing);
929
930 int borders[4];
931 QBrush colors[4];
932 QCss::BorderStyle styles[4];
933 QSize radii[4];
934 for (int i = 0; i < 4; i++) {
935 borders[i] = 0;
936 styles[i] = BorderStyle_None;
937 }
938 if (v.extractBorder(borders, colors, Styles: styles, radii))
939 bd = new QStyleSheetBorderData(borders, colors, styles, radii);
940
941 int offsets[4];
942 for (int i = 0; i < 4; i++) {
943 borders[i] = offsets[i] = 0;
944 styles[i] = BorderStyle_None;
945 }
946 if (v.extractOutline(borders, colors, Styles: styles, radii, offsets))
947 ou = new QStyleSheetOutlineData(borders, colors, styles, radii, offsets);
948
949 QBrush brush;
950 QString uri;
951 Repeat repeat = Repeat_XY;
952 Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft;
953 Attachment attachment = Attachment_Scroll;
954 origin = Origin_Padding;
955 Origin clip = Origin_Border;
956 if (v.extractBackground(&brush, &uri, &repeat, &alignment, &origin, &attachment, &clip)) {
957 QPixmap pixmap = QStyleSheetStyle::loadPixmap(fileName: uri, context: object);
958 if (!uri.isEmpty() && pixmap.isNull())
959 qWarning(msg: "Could not create pixmap from %s", qPrintable(QDir::toNativeSeparators(uri)));
960 bg = new QStyleSheetBackgroundData(brush, pixmap, repeat, alignment, origin, attachment, clip);
961 }
962
963 QBrush foreground;
964 QBrush selectedForeground;
965 QBrush selectedBackground;
966 QBrush alternateBackground;
967 QBrush placeHolderTextForeground;
968 QBrush accent;
969 if (v.extractPalette(foreground: &foreground, selectedForeground: &selectedForeground, selectedBackground: &selectedBackground,
970 alternateBackground: &alternateBackground, placeHolderTextForeground: &placeHolderTextForeground, accent: &accent)) {
971 pal = new QStyleSheetPaletteData(foreground, selectedForeground, selectedBackground,
972 alternateBackground, placeHolderTextForeground, accent);
973 }
974
975 QIcon imgIcon;
976 alignment = Qt::AlignCenter;
977 QSize imgSize;
978 if (v.extractImage(icon: &imgIcon, a: &alignment, size: &imgSize))
979 img = new QStyleSheetImageData(imgIcon, alignment, imgSize);
980
981 QIcon icon;
982 QSize size;
983 if (v.extractIcon(icon: &icon, size: &size))
984 iconPtr = new QStyleSheetImageData(icon, Qt::AlignCenter, size);
985
986 int adj = -255;
987 hasFont = v.extractFont(font: &font, fontSizeAdjustment: &adj);
988
989#if QT_CONFIG(tooltip)
990 if (object && qstrcmp(str1: object->metaObject()->className(), str2: "QTipLabel") == 0)
991 palette = QToolTip::palette();
992#endif
993
994 for (int i = 0; i < declarations.size(); i++) {
995 const Declaration& decl = declarations.at(i);
996 if (decl.d->propertyId == BorderImage) {
997 QString uri;
998 QCss::TileMode horizStretch, vertStretch;
999 int cuts[4];
1000
1001 decl.borderImageValue(image: &uri, cuts, h: &horizStretch, v: &vertStretch);
1002 if (uri.isEmpty() || uri == "none"_L1) {
1003 if (bd && bd->bi)
1004 bd->bi->pixmap = QPixmap();
1005 } else {
1006 if (!bd)
1007 bd = new QStyleSheetBorderData;
1008 if (!bd->bi)
1009 bd->bi = new QStyleSheetBorderImageData;
1010
1011 QStyleSheetBorderImageData *bi = bd->bi;
1012 bi->pixmap = QStyleSheetStyle::loadPixmap(fileName: uri, context: object);
1013 for (int i = 0; i < 4; i++)
1014 bi->cuts[i] = cuts[i];
1015 bi->horizStretch = horizStretch;
1016 bi->vertStretch = vertStretch;
1017 }
1018 } else if (decl.d->propertyId == QtBackgroundRole) {
1019 if (bg && bg->brush.style() != Qt::NoBrush)
1020 continue;
1021 int role = decl.d->values.at(i: 0).variant.toInt();
1022 if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
1023 defaultBackground = palette.color(cr: (QPalette::ColorRole)(role-Value_FirstColorRole));
1024 } else if (decl.d->property.startsWith(s: "qproperty-"_L1, cs: Qt::CaseInsensitive)) {
1025 // intentionally left blank...
1026 } else if (decl.d->propertyId == UnknownProperty) {
1027 bool knownStyleHint = false;
1028 for (const auto sh : knownStyleHints) {
1029 QLatin1StringView styleHint(sh);
1030 if (decl.d->property.compare(other: styleHint) == 0) {
1031 QString hintName = QString(styleHint);
1032 QVariant hintValue;
1033 if (hintName.endsWith(s: "alignment"_L1)) {
1034 hintValue = (int) decl.alignmentValue();
1035 } else if (hintName.endsWith(s: "color"_L1)) {
1036 hintValue = (int) decl.colorValue().rgba();
1037 } else if (hintName.endsWith(s: "size"_L1)) {
1038 // Check only for the 'em' case
1039 const QString valueString = decl.d->values.at(i: 0).variant.toString();
1040 const bool isEmSize = valueString.endsWith(s: u"em", cs: Qt::CaseInsensitive);
1041 if (isEmSize || valueString.endsWith(s: u"ex", cs: Qt::CaseInsensitive)) {
1042 // 1em == size of font; 1ex == xHeight of font
1043 // See lengthValueFromData helper in qcssparser.cpp
1044 QFont fontForSize(font);
1045 // if no font is specified, then use the widget font if possible
1046 if (const QWidget *widget; !hasFont && (widget = qobject_cast<const QWidget*>(o: object)))
1047 fontForSize = widget->font();
1048
1049 const QFontMetrics fontMetrics(fontForSize);
1050 qreal pixelSize = isEmSize ? fontMetrics.height() : fontMetrics.xHeight();
1051
1052 // Transform size according to the 'em'/'ex' value
1053 qreal emexSize = {};
1054 if (decl.realValue(r: &emexSize, unit: isEmSize ? "em" : "ex") && emexSize > 0) {
1055 pixelSize *= emexSize;
1056 const QSizeF newSize(pixelSize, pixelSize);
1057 decl.d->parsed = QVariant::fromValue<QSizeF>(value: newSize);
1058 hintValue = newSize;
1059 } else {
1060 qWarning(msg: "Invalid '%s' size for %s. Skipping.",
1061 isEmSize ? "em" : "ex", qPrintable(valueString));
1062 }
1063 } else {
1064 // Normal case where we receive a 'px' or 'pt' unit
1065 hintValue = decl.sizeValue();
1066 }
1067 } else if (hintName.endsWith(s: "icon"_L1)) {
1068 hintValue = decl.iconValue();
1069 } else if (hintName == "button-layout"_L1 && decl.d->values.size() != 0
1070 && decl.d->values.at(i: 0).type == QCss::Value::String) {
1071 hintValue = subControlLayout(layout: decl.d->values.at(i: 0).variant.toString().toLatin1());
1072 } else {
1073 int integer;
1074 decl.intValue(i: &integer);
1075 hintValue = integer;
1076 }
1077 styleHints[decl.d->property] = hintValue;
1078 knownStyleHint = true;
1079 break;
1080 }
1081 }
1082 if (!knownStyleHint)
1083 qWarning(msg: "Unknown property %s", qPrintable(decl.d->property));
1084 }
1085 }
1086
1087 if (hasBorder()) {
1088 if (const QWidget *widget = qobject_cast<const QWidget *>(o: object)) {
1089 QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle);
1090 if (!style)
1091 style = qt_styleSheet(style: widget->style());
1092 if (style)
1093 fixupBorder(style->nativeFrameWidth(widget));
1094 }
1095 if (border()->hasBorderImage())
1096 defaultBackground = QBrush();
1097 }
1098}
1099
1100QRect QRenderRule::borderRect(const QRect& r) const
1101{
1102 if (!hasBox())
1103 return r;
1104 const int* m = box()->margins;
1105 return r.adjusted(xp1: m[LeftEdge], yp1: m[TopEdge], xp2: -m[RightEdge], yp2: -m[BottomEdge]);
1106}
1107
1108QRect QRenderRule::outlineRect(const QRect& r) const
1109{
1110 QRect br = borderRect(r);
1111 if (!hasOutline())
1112 return br;
1113 const int *b = outline()->borders;
1114 return r.adjusted(xp1: b[LeftEdge], yp1: b[TopEdge], xp2: -b[RightEdge], yp2: -b[BottomEdge]);
1115}
1116
1117QRect QRenderRule::paddingRect(const QRect& r) const
1118{
1119 QRect br = borderRect(r);
1120 if (!hasBorder())
1121 return br;
1122 const int *b = border()->borders;
1123 return br.adjusted(xp1: b[LeftEdge], yp1: b[TopEdge], xp2: -b[RightEdge], yp2: -b[BottomEdge]);
1124}
1125
1126QRect QRenderRule::contentsRect(const QRect& r) const
1127{
1128 QRect pr = paddingRect(r);
1129 if (!hasBox())
1130 return pr;
1131 const int *p = box()->paddings;
1132 return pr.adjusted(xp1: p[LeftEdge], yp1: p[TopEdge], xp2: -p[RightEdge], yp2: -p[BottomEdge]);
1133}
1134
1135QRect QRenderRule::boxRect(const QRect& cr, int flags) const
1136{
1137 QRect r = cr;
1138 if (hasBox()) {
1139 if (flags & Margin) {
1140 const int *m = box()->margins;
1141 r.adjust(dx1: -m[LeftEdge], dy1: -m[TopEdge], dx2: m[RightEdge], dy2: m[BottomEdge]);
1142 }
1143 if (flags & Padding) {
1144 const int *p = box()->paddings;
1145 r.adjust(dx1: -p[LeftEdge], dy1: -p[TopEdge], dx2: p[RightEdge], dy2: p[BottomEdge]);
1146 }
1147 }
1148 if (hasBorder() && (flags & Border)) {
1149 const int *b = border()->borders;
1150 r.adjust(dx1: -b[LeftEdge], dy1: -b[TopEdge], dx2: b[RightEdge], dy2: b[BottomEdge]);
1151 }
1152 return r;
1153}
1154
1155QSize QRenderRule::boxSize(const QSize &cs, int flags) const
1156{
1157 QSize bs = boxRect(cr: QRect(QPoint(0, 0), cs), flags).size();
1158 if (cs.width() < 0) bs.setWidth(-1);
1159 if (cs.height() < 0) bs.setHeight(-1);
1160 return bs;
1161}
1162
1163void QRenderRule::fixupBorder(int nativeWidth)
1164{
1165 if (bd == nullptr)
1166 return;
1167
1168 if (!bd->hasBorderImage() || bd->bi->pixmap.isNull()) {
1169 bd->bi = nullptr;
1170 // ignore the color, border of edges that have none border-style
1171 QBrush color = pal ? pal->foreground : QBrush();
1172 const bool hasRadius = bd->radii[0].isValid() || bd->radii[1].isValid()
1173 || bd->radii[2].isValid() || bd->radii[3].isValid();
1174 for (int i = 0; i < 4; i++) {
1175 if ((bd->styles[i] == BorderStyle_Native) && hasRadius)
1176 bd->styles[i] = BorderStyle_None;
1177
1178 switch (bd->styles[i]) {
1179 case BorderStyle_None:
1180 // border-style: none forces width to be 0
1181 bd->colors[i] = QBrush();
1182 bd->borders[i] = 0;
1183 break;
1184 case BorderStyle_Native:
1185 if (bd->borders[i] == 0)
1186 bd->borders[i] = nativeWidth;
1187 Q_FALLTHROUGH();
1188 default:
1189 if (bd->colors[i].style() == Qt::NoBrush) // auto-acquire 'color'
1190 bd->colors[i] = color;
1191 break;
1192 }
1193 }
1194
1195 return;
1196 }
1197
1198 // inspect the border image
1199 QStyleSheetBorderImageData *bi = bd->bi;
1200 if (bi->cuts[0] == -1) {
1201 for (int i = 0; i < 4; i++) // assume, cut = border
1202 bi->cuts[i] = int(border()->borders[i]);
1203 }
1204}
1205
1206void QRenderRule::drawBorderImage(QPainter *p, const QRect& rect)
1207{
1208 setClip(p, rect);
1209 static const Qt::TileRule tileMode2TileRule[] = {
1210 Qt::StretchTile, Qt::RoundTile, Qt::StretchTile, Qt::RepeatTile, Qt::StretchTile };
1211
1212 const QStyleSheetBorderImageData *borderImageData = border()->borderImage();
1213 const int *targetBorders = border()->borders;
1214 const int *sourceBorders = borderImageData->cuts;
1215 QMargins sourceMargins(sourceBorders[LeftEdge], sourceBorders[TopEdge],
1216 sourceBorders[RightEdge], sourceBorders[BottomEdge]);
1217 QMargins targetMargins(targetBorders[LeftEdge], targetBorders[TopEdge],
1218 targetBorders[RightEdge], targetBorders[BottomEdge]);
1219
1220 bool wasSmoothPixmapTransform = p->renderHints() & QPainter::SmoothPixmapTransform;
1221 p->setRenderHint(hint: QPainter::SmoothPixmapTransform);
1222 qDrawBorderPixmap(painter: p, targetRect: rect, targetMargins, pixmap: borderImageData->pixmap,
1223 sourceRect: QRect(QPoint(), borderImageData->pixmap.size()), sourceMargins,
1224 rules: QTileRules(tileMode2TileRule[borderImageData->horizStretch], tileMode2TileRule[borderImageData->vertStretch]));
1225 p->setRenderHint(hint: QPainter::SmoothPixmapTransform, on: wasSmoothPixmapTransform);
1226 unsetClip(p);
1227}
1228
1229QRect QRenderRule::originRect(const QRect &rect, Origin origin) const
1230{
1231 switch (origin) {
1232 case Origin_Padding:
1233 return paddingRect(r: rect);
1234 case Origin_Border:
1235 return borderRect(r: rect);
1236 case Origin_Content:
1237 return contentsRect(r: rect);
1238 case Origin_Margin:
1239 default:
1240 return rect;
1241 }
1242}
1243
1244void QRenderRule::drawBackgroundImage(QPainter *p, const QRect &rect, QPoint off)
1245{
1246 if (!hasBackground())
1247 return;
1248
1249 const QPixmap& bgp = background()->pixmap;
1250 if (bgp.isNull())
1251 return;
1252
1253 setClip(p, rect: borderRect(r: rect));
1254
1255 if (background()->origin != background()->clip) {
1256 p->save();
1257 p->setClipRect(originRect(rect, origin: background()->clip), op: Qt::IntersectClip);
1258 }
1259
1260 if (background()->attachment == Attachment_Fixed)
1261 off = QPoint(0, 0);
1262
1263 QSize bgpSize = bgp.size() / bgp.devicePixelRatio();
1264 int bgpHeight = bgpSize.height();
1265 int bgpWidth = bgpSize.width();
1266 QRect r = originRect(rect, origin: background()->origin);
1267 QRect aligned = QStyle::alignedRect(direction: Qt::LeftToRight, alignment: background()->position, size: bgpSize, rectangle: r);
1268 QRect inter = aligned.translated(p: -off).intersected(other: r);
1269
1270 switch (background()->repeat) {
1271 case Repeat_Y:
1272 p->drawTiledPixmap(x: inter.x(), y: r.y(), w: inter.width(), h: r.height(), pm: bgp,
1273 sx: inter.x() - aligned.x() + off.x(),
1274 sy: bgpHeight - int(aligned.y() - r.y()) % bgpHeight + off.y());
1275 break;
1276 case Repeat_X:
1277 p->drawTiledPixmap(x: r.x(), y: inter.y(), w: r.width(), h: inter.height(), pm: bgp,
1278 sx: bgpWidth - int(aligned.x() - r.x())%bgpWidth + off.x(),
1279 sy: inter.y() - aligned.y() + off.y());
1280 break;
1281 case Repeat_XY:
1282 p->drawTiledPixmap(rect: r, pm: bgp,
1283 offset: QPoint(bgpWidth - int(aligned.x() - r.x())% bgpWidth + off.x(),
1284 bgpHeight - int(aligned.y() - r.y())%bgpHeight + off.y()));
1285 break;
1286 case Repeat_None:
1287 default:
1288 p->drawPixmap(x: inter.x(), y: inter.y(), pm: bgp, sx: inter.x() - aligned.x() + off.x(),
1289 sy: inter.y() - aligned.y() + off.y(), sw: bgp.width() , sh: bgp.height());
1290 break;
1291 }
1292
1293
1294 if (background()->origin != background()->clip)
1295 p->restore();
1296
1297 unsetClip(p);
1298}
1299
1300void QRenderRule::drawOutline(QPainter *p, const QRect &rect)
1301{
1302 if (!hasOutline())
1303 return;
1304
1305 bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1306 p->setRenderHint(hint: QPainter::Antialiasing);
1307 qDrawBorder(p, rect, styles: ou->styles, borders: ou->borders, colors: ou->colors, radii: ou->radii);
1308 p->setRenderHint(hint: QPainter::Antialiasing, on: wasAntialiased);
1309}
1310
1311void QRenderRule::drawBorder(QPainter *p, const QRect& rect)
1312{
1313 if (!hasBorder())
1314 return;
1315
1316 if (border()->hasBorderImage()) {
1317 drawBorderImage(p, rect);
1318 return;
1319 }
1320
1321 bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1322 p->setRenderHint(hint: QPainter::Antialiasing);
1323 qDrawBorder(p, rect, styles: bd->styles, borders: bd->borders, colors: bd->colors, radii: bd->radii);
1324 p->setRenderHint(hint: QPainter::Antialiasing, on: wasAntialiased);
1325}
1326
1327QPainterPath QRenderRule::borderClip(QRect r)
1328{
1329 if (!hasBorder())
1330 return QPainterPath();
1331
1332 QSize tlr, trr, blr, brr;
1333 qNormalizeRadii(br: r, radii: bd->radii, tlr: &tlr, trr: &trr, blr: &blr, brr: &brr);
1334 if (tlr.isNull() && trr.isNull() && blr.isNull() && brr.isNull())
1335 return QPainterPath();
1336
1337 const QRectF rect(r);
1338 const int *borders = border()->borders;
1339 QPainterPath path;
1340 qreal curY = rect.y() + borders[TopEdge]/2.0;
1341 path.moveTo(x: rect.x() + tlr.width(), y: curY);
1342 path.lineTo(x: rect.right() - trr.width(), y: curY);
1343 qreal curX = rect.right() - borders[RightEdge]/2.0;
1344 path.arcTo(x: curX - 2*trr.width() + borders[RightEdge], y: curY,
1345 w: trr.width()*2 - borders[RightEdge], h: trr.height()*2 - borders[TopEdge], startAngle: 90, arcLength: -90);
1346
1347 path.lineTo(x: curX, y: rect.bottom() - brr.height());
1348 curY = rect.bottom() - borders[BottomEdge]/2.0;
1349 path.arcTo(x: curX - 2*brr.width() + borders[RightEdge], y: curY - 2*brr.height() + borders[BottomEdge],
1350 w: brr.width()*2 - borders[RightEdge], h: brr.height()*2 - borders[BottomEdge], startAngle: 0, arcLength: -90);
1351
1352 path.lineTo(x: rect.x() + blr.width(), y: curY);
1353 curX = rect.left() + borders[LeftEdge]/2.0;
1354 path.arcTo(x: curX, y: rect.bottom() - 2*blr.height() + borders[BottomEdge]/2.0,
1355 w: blr.width()*2 - borders[LeftEdge], h: blr.height()*2 - borders[BottomEdge], startAngle: 270, arcLength: -90);
1356
1357 path.lineTo(x: curX, y: rect.top() + tlr.height());
1358 path.arcTo(x: curX, y: rect.top() + borders[TopEdge]/2.0,
1359 w: tlr.width()*2 - borders[LeftEdge], h: tlr.height()*2 - borders[TopEdge], startAngle: 180, arcLength: -90);
1360
1361 path.closeSubpath();
1362 return path;
1363}
1364
1365/*! \internal
1366 Clip the painter to the border (in case we are using radius border)
1367 */
1368void QRenderRule::setClip(QPainter *p, const QRect &rect)
1369{
1370 if (clipset++)
1371 return;
1372 clipPath = borderClip(r: rect);
1373 if (!clipPath.isEmpty()) {
1374 p->save();
1375 p->setClipPath(path: clipPath, op: Qt::IntersectClip);
1376 }
1377}
1378
1379void QRenderRule::unsetClip(QPainter *p)
1380{
1381 if (--clipset)
1382 return;
1383 if (!clipPath.isEmpty())
1384 p->restore();
1385}
1386
1387void QRenderRule::drawBackground(QPainter *p, const QRect& rect, const QPoint& off)
1388{
1389 QBrush brush = hasBackground() ? background()->brush : QBrush();
1390 if (brush.style() == Qt::NoBrush)
1391 brush = defaultBackground;
1392
1393 if (brush.style() != Qt::NoBrush) {
1394 Origin origin = hasBackground() ? background()->clip : Origin_Border;
1395 // ### fix for gradients
1396 const QPainterPath &borderPath = borderClip(r: originRect(rect, origin));
1397 if (!borderPath.isEmpty()) {
1398 // Drawn instead of being used as clipping path for better visual quality
1399 bool wasAntialiased = p->renderHints() & QPainter::Antialiasing;
1400 p->setRenderHint(hint: QPainter::Antialiasing);
1401 p->fillPath(path: borderPath, brush);
1402 p->setRenderHint(hint: QPainter::Antialiasing, on: wasAntialiased);
1403 } else {
1404 p->fillRect(originRect(rect, origin), brush);
1405 }
1406 }
1407
1408 drawBackgroundImage(p, rect, off);
1409}
1410
1411void QRenderRule::drawFrame(QPainter *p, const QRect& rect)
1412{
1413 drawBackground(p, rect);
1414 if (hasBorder())
1415 drawBorder(p, rect: borderRect(r: rect));
1416}
1417
1418void QRenderRule::drawImage(QPainter *p, const QRect &rect)
1419{
1420 if (!hasImage())
1421 return;
1422 img->icon.paint(painter: p, rect, alignment: img->alignment);
1423}
1424
1425void QRenderRule::drawRule(QPainter *p, const QRect& rect)
1426{
1427 drawFrame(p, rect);
1428 drawImage(p, rect: contentsRect(r: rect));
1429}
1430
1431// *shudder* , *horror*, *whoa* <-- what you might feel when you see the functions below
1432void QRenderRule::configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette::ColorRole br)
1433{
1434 if (bg && bg->brush.style() != Qt::NoBrush) {
1435 if (br != QPalette::NoRole)
1436 p->setBrush(acr: br, abrush: bg->brush);
1437 p->setBrush(acr: QPalette::Window, abrush: bg->brush);
1438 if (bg->brush.style() == Qt::SolidPattern) {
1439 p->setBrush(acr: QPalette::Light, abrush: bg->brush.color().lighter(f: 115));
1440 p->setBrush(acr: QPalette::Midlight, abrush: bg->brush.color().lighter(f: 107));
1441 p->setBrush(acr: QPalette::Dark, abrush: bg->brush.color().darker(f: 150));
1442 p->setBrush(acr: QPalette::Shadow, abrush: bg->brush.color().darker(f: 300));
1443 }
1444 }
1445
1446 if (!hasPalette())
1447 return;
1448
1449 if (pal->foreground.style() != Qt::NoBrush) {
1450 if (fr != QPalette::NoRole)
1451 p->setBrush(acr: fr, abrush: pal->foreground);
1452 p->setBrush(acr: QPalette::WindowText, abrush: pal->foreground);
1453 p->setBrush(acr: QPalette::Text, abrush: pal->foreground);
1454 }
1455 if (pal->selectionBackground.style() != Qt::NoBrush)
1456 p->setBrush(acr: QPalette::Highlight, abrush: pal->selectionBackground);
1457 if (pal->selectionForeground.style() != Qt::NoBrush)
1458 p->setBrush(acr: QPalette::HighlightedText, abrush: pal->selectionForeground);
1459 if (pal->alternateBackground.style() != Qt::NoBrush)
1460 p->setBrush(acr: QPalette::AlternateBase, abrush: pal->alternateBackground);
1461}
1462
1463void setDefault(QPalette *palette, QPalette::ColorGroup group, QPalette::ColorRole role,
1464 const QBrush &defaultBrush, const QWidget *widget)
1465{
1466 const QPalette &widgetPalette = widget->palette();
1467 if (widgetPalette.isBrushSet(cg: group, cr: role))
1468 palette->setBrush(cg: group, cr: role, brush: widgetPalette.brush(cg: group, cr: role));
1469 else
1470 palette->setBrush(cg: group, cr: role, brush: defaultBrush);
1471}
1472
1473void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const QWidget *w, bool embedded)
1474{
1475 if (bg && bg->brush.style() != Qt::NoBrush) {
1476 p->setBrush(cg, cr: QPalette::Base, brush: bg->brush); // for windows, windowxp
1477 p->setBrush(cg, cr: QPalette::Button, brush: bg->brush); // for plastique
1478 p->setBrush(cg, cr: w->backgroundRole(), brush: bg->brush);
1479 p->setBrush(cg, cr: QPalette::Window, brush: bg->brush);
1480 }
1481
1482 if (embedded) {
1483 /* For embedded widgets (ComboBox, SpinBox and ScrollArea) we want the embedded widget
1484 * to be transparent when we have a transparent background or border image */
1485 if ((hasBackground() && background()->isTransparent())
1486 || (hasBorder() && border()->hasBorderImage() && !border()->borderImage()->pixmap.isNull()))
1487 p->setBrush(cg, cr: w->backgroundRole(), brush: Qt::NoBrush);
1488 }
1489
1490 if (!hasPalette())
1491 return;
1492
1493 if (pal->foreground.style() != Qt::NoBrush) {
1494 setDefault(palette: p, group: cg, role: QPalette::ButtonText, defaultBrush: pal->foreground, widget: w);
1495 setDefault(palette: p, group: cg, role: w->foregroundRole(), defaultBrush: pal->foreground, widget: w);
1496 setDefault(palette: p, group: cg, role: QPalette::WindowText, defaultBrush: pal->foreground, widget: w);
1497 setDefault(palette: p, group: cg, role: QPalette::Text, defaultBrush: pal->foreground, widget: w);
1498 QColor phColor(pal->foreground.color());
1499 phColor.setAlpha((phColor.alpha() + 1) / 2);
1500 QBrush placeholder = pal->foreground;
1501 placeholder.setColor(phColor);
1502 setDefault(palette: p, group: cg, role: QPalette::PlaceholderText, defaultBrush: placeholder, widget: w);
1503 }
1504 if (pal->selectionBackground.style() != Qt::NoBrush)
1505 p->setBrush(cg, cr: QPalette::Highlight, brush: pal->selectionBackground);
1506 if (pal->selectionForeground.style() != Qt::NoBrush)
1507 p->setBrush(cg, cr: QPalette::HighlightedText, brush: pal->selectionForeground);
1508 if (pal->alternateBackground.style() != Qt::NoBrush)
1509 p->setBrush(cg, cr: QPalette::AlternateBase, brush: pal->alternateBackground);
1510 if (pal->placeholderForeground.style() != Qt::NoBrush)
1511 p->setBrush(cg, cr: QPalette::PlaceholderText, brush: pal->placeholderForeground);
1512 if (pal->accent.style() != Qt::NoBrush)
1513 p->setBrush(cg, cr: QPalette::Accent, brush: pal->accent);
1514}
1515
1516bool QRenderRule::hasModification() const
1517{
1518 return hasPalette() ||
1519 hasBackground() ||
1520 hasGradientBackground() ||
1521 !hasNativeBorder() ||
1522 !hasNativeOutline() ||
1523 hasBox() ||
1524 hasPosition() ||
1525 hasGeometry() ||
1526 hasImage() ||
1527 hasFont ||
1528 !styleHints.isEmpty();
1529}
1530
1531///////////////////////////////////////////////////////////////////////////////
1532// Style rules
1533#define OBJECT_PTR(x) (static_cast<QObject *>(x.ptr))
1534
1535static inline QObject *parentObject(const QObject *obj)
1536{
1537#if QT_CONFIG(tooltip)
1538 if (qobject_cast<const QLabel *>(object: obj) && qstrcmp(str1: obj->metaObject()->className(), str2: "QTipLabel") == 0) {
1539 QObject *p = qvariant_cast<QObject *>(v: obj->property(name: "_q_stylesheet_parent"));
1540 if (p)
1541 return p;
1542 }
1543#endif
1544 return obj->parent();
1545}
1546
1547class QStyleSheetStyleSelector : public StyleSelector
1548{
1549public:
1550 QStyleSheetStyleSelector() { }
1551
1552 QStringList nodeNames(NodePtr node) const override
1553 {
1554 if (isNullNode(node))
1555 return QStringList();
1556 const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject();
1557#if QT_CONFIG(tooltip)
1558 if (qstrcmp(str1: metaObject->className(), str2: "QTipLabel") == 0)
1559 return QStringList("QToolTip"_L1);
1560#endif
1561 QStringList result;
1562 do {
1563 result += QString::fromLatin1(ba: metaObject->className()).replace(before: u':', after: u'-');
1564 metaObject = metaObject->superClass();
1565 } while (metaObject != nullptr);
1566 return result;
1567 }
1568 QString attributeValue(NodePtr node, const QCss::AttributeSelector& aSelector) const override
1569 {
1570 if (isNullNode(node))
1571 return QString();
1572
1573 const QString &name = aSelector.name;
1574 QHash<QString, QString> &cache = m_attributeCache[OBJECT_PTR(node)];
1575 QHash<QString, QString>::const_iterator cacheIt = cache.constFind(key: name);
1576 if (cacheIt != cache.constEnd())
1577 return cacheIt.value();
1578
1579 QVariant value;
1580 QString valueStr;
1581 QObject *obj = OBJECT_PTR(node);
1582 const int propertyIndex = obj->metaObject()->indexOfProperty(name: name.toLatin1());
1583 if (propertyIndex == -1) {
1584 value = obj->property(name: name.toLatin1()); // might be a dynamic property
1585 if (!value.isValid()) {
1586 if (name == "class"_L1) {
1587 QString className = QString::fromLatin1(ba: obj->metaObject()->className());
1588 if (className.contains(c: u':'))
1589 className.replace(before: u':', after: u'-');
1590 valueStr = className;
1591 } else if (name == "style"_L1) {
1592 QWidget *w = qobject_cast<QWidget *>(o: obj);
1593 QStyleSheetStyle *proxy = w ? qt_styleSheet(style: w->style()) : nullptr;
1594 if (proxy)
1595 valueStr = QString::fromLatin1(ba: proxy->baseStyle()->metaObject()->className());
1596 }
1597 }
1598 } else {
1599 const QMetaProperty property = obj->metaObject()->property(index: propertyIndex);
1600 value = property.read(obj);
1601 // support Qt 5 selector syntax, which required the integer enum value
1602 if (property.isEnumType()) {
1603 bool isNumber;
1604 aSelector.value.toInt(ok: &isNumber);
1605 if (isNumber)
1606 value.convert(type: QMetaType::fromType<int>());
1607 }
1608 }
1609 if (value.isValid()) {
1610 valueStr = (value.userType() == QMetaType::QStringList
1611 || value.userType() == QMetaType::QVariantList)
1612 ? value.toStringList().join(sep: u' ')
1613 : value.toString();
1614 }
1615 cache[name] = valueStr;
1616 return valueStr;
1617 }
1618 bool nodeNameEquals(NodePtr node, const QString& nodeName) const override
1619 {
1620 if (isNullNode(node))
1621 return false;
1622 const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject();
1623#if QT_CONFIG(tooltip)
1624 if (qstrcmp(str1: metaObject->className(), str2: "QTipLabel") == 0)
1625 return nodeName == "QToolTip"_L1;
1626#endif
1627 do {
1628 const auto *uc = reinterpret_cast<const char16_t *>(nodeName.constData());
1629 const auto *e = uc + nodeName.size();
1630 const uchar *c = (const uchar *)metaObject->className();
1631 while (*c && uc != e && (*uc == *c || (*c == ':' && *uc == '-'))) {
1632 ++uc;
1633 ++c;
1634 }
1635 if (uc == e && !*c)
1636 return true;
1637 metaObject = metaObject->superClass();
1638 } while (metaObject != nullptr);
1639 return false;
1640 }
1641 bool hasAttributes(NodePtr) const override
1642 { return true; }
1643 QStringList nodeIds(NodePtr node) const override
1644 { return isNullNode(node) ? QStringList() : QStringList(OBJECT_PTR(node)->objectName()); }
1645 bool isNullNode(NodePtr node) const override
1646 { return node.ptr == nullptr; }
1647 NodePtr parentNode(NodePtr node) const override
1648 { NodePtr n; n.ptr = isNullNode(node) ? nullptr : parentObject(OBJECT_PTR(node)); return n; }
1649 NodePtr previousSiblingNode(NodePtr) const override
1650 { NodePtr n; n.ptr = nullptr; return n; }
1651 NodePtr duplicateNode(NodePtr node) const override
1652 { return node; }
1653 void freeNode(NodePtr) const override
1654 { }
1655
1656private:
1657 mutable QHash<const QObject *, QHash<QString, QString> > m_attributeCache;
1658};
1659
1660QList<QCss::StyleRule> QStyleSheetStyle::styleRules(const QObject *obj) const
1661{
1662 QHash<const QObject *, QList<StyleRule>>::const_iterator cacheIt =
1663 styleSheetCaches->styleRulesCache.constFind(key: obj);
1664 if (cacheIt != styleSheetCaches->styleRulesCache.constEnd())
1665 return cacheIt.value();
1666
1667 if (!initObject(obj)) {
1668 return QList<StyleRule>();
1669 }
1670
1671 QStyleSheetStyleSelector styleSelector;
1672
1673 StyleSheet defaultSs;
1674 QHash<const void *, StyleSheet>::const_iterator defaultCacheIt = styleSheetCaches->styleSheetCache.constFind(key: baseStyle());
1675 if (defaultCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1676 defaultSs = getDefaultStyleSheet();
1677 QStyle *bs = baseStyle();
1678 styleSheetCaches->styleSheetCache.insert(key: bs, value: defaultSs);
1679 QObject::connect(sender: bs, signal: &QStyle::destroyed, context: styleSheetCaches,
1680 slot: &QStyleSheetStyleCaches::styleDestroyed);
1681 } else {
1682 defaultSs = defaultCacheIt.value();
1683 }
1684 styleSelector.styleSheets += defaultSs;
1685
1686 if (!qApp->styleSheet().isEmpty()) {
1687 StyleSheet appSs;
1688 QHash<const void *, StyleSheet>::const_iterator appCacheIt = styleSheetCaches->styleSheetCache.constFind(qApp);
1689 if (appCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1690 QString ss = qApp->styleSheet();
1691 if (ss.startsWith(s: "file:///"_L1))
1692 ss.remove(i: 0, len: 8);
1693 parser.init(css: ss, qApp->styleSheet() != ss);
1694 if (Q_UNLIKELY(!parser.parse(&appSs)))
1695 qWarning(msg: "Could not parse application stylesheet");
1696 appSs.origin = StyleSheetOrigin_Inline;
1697 appSs.depth = 1;
1698 styleSheetCaches->styleSheetCache.insert(qApp, value: appSs);
1699 } else {
1700 appSs = appCacheIt.value();
1701 }
1702 styleSelector.styleSheets += appSs;
1703 }
1704
1705 QList<QCss::StyleSheet> objectSs;
1706 for (const QObject *o = obj; o; o = parentObject(obj: o)) {
1707 QString styleSheet = o->property(name: "styleSheet").toString();
1708 if (styleSheet.isEmpty())
1709 continue;
1710 StyleSheet ss;
1711 QHash<const void *, StyleSheet>::const_iterator objCacheIt = styleSheetCaches->styleSheetCache.constFind(key: o);
1712 if (objCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1713 parser.init(css: styleSheet);
1714 if (!parser.parse(styleSheet: &ss)) {
1715 parser.init(css: "* {"_L1 + styleSheet + u'}');
1716 if (Q_UNLIKELY(!parser.parse(&ss)))
1717 qWarning() << "Could not parse stylesheet of object" << o;
1718 }
1719 ss.origin = StyleSheetOrigin_Inline;
1720 styleSheetCaches->styleSheetCache.insert(key: o, value: ss);
1721 } else {
1722 ss = objCacheIt.value();
1723 }
1724 objectSs.append(t: ss);
1725 }
1726
1727 for (int i = 0; i < objectSs.size(); i++)
1728 objectSs[i].depth = objectSs.size() - i + 2;
1729
1730 styleSelector.styleSheets += objectSs;
1731
1732 StyleSelector::NodePtr n;
1733 n.ptr = const_cast<QObject *>(obj);
1734 QList<QCss::StyleRule> rules = styleSelector.styleRulesForNode(node: n);
1735 styleSheetCaches->styleRulesCache.insert(key: obj, value: rules);
1736 return rules;
1737}
1738
1739/////////////////////////////////////////////////////////////////////////////////////////
1740// Rendering rules
1741static QList<Declaration> declarations(const QList<StyleRule> &styleRules, const QString &part,
1742 quint64 pseudoClass = PseudoClass_Unspecified)
1743{
1744 QList<Declaration> decls;
1745 for (int i = 0; i < styleRules.size(); i++) {
1746 const Selector& selector = styleRules.at(i).selectors.at(i: 0);
1747 // Rules with pseudo elements don't cascade. This is an intentional
1748 // diversion for CSS
1749 if (part.compare(s: selector.pseudoElement(), cs: Qt::CaseInsensitive) != 0)
1750 continue;
1751 quint64 negated = 0;
1752 quint64 cssClass = selector.pseudoClass(negated: &negated);
1753 if ((pseudoClass == PseudoClass_Any) || (cssClass == PseudoClass_Unspecified)
1754 || ((((cssClass & pseudoClass) == cssClass)) && ((negated & pseudoClass) == 0)))
1755 decls += styleRules.at(i).declarations;
1756 }
1757 return decls;
1758}
1759
1760int QStyleSheetStyle::nativeFrameWidth(const QWidget *w)
1761{
1762 QStyle *base = baseStyle();
1763
1764#if QT_CONFIG(spinbox)
1765 if (qobject_cast<const QAbstractSpinBox *>(object: w))
1766 return base->pixelMetric(metric: QStyle::PM_SpinBoxFrameWidth, option: nullptr, widget: w);
1767#endif
1768
1769#if QT_CONFIG(combobox)
1770 if (qobject_cast<const QComboBox *>(object: w))
1771 return base->pixelMetric(metric: QStyle::PM_ComboBoxFrameWidth, option: nullptr, widget: w);
1772#endif
1773
1774#if QT_CONFIG(menu)
1775 if (qobject_cast<const QMenu *>(object: w))
1776 return base->pixelMetric(metric: QStyle::PM_MenuPanelWidth, option: nullptr, widget: w);
1777#endif
1778
1779#if QT_CONFIG(menubar)
1780 if (qobject_cast<const QMenuBar *>(object: w))
1781 return base->pixelMetric(metric: QStyle::PM_MenuBarPanelWidth, option: nullptr, widget: w);
1782#endif
1783#ifndef QT_NO_FRAME
1784 if (const QFrame *frame = qobject_cast<const QFrame *>(object: w)) {
1785 if (frame->frameShape() == QFrame::NoFrame)
1786 return 0;
1787 }
1788#endif
1789
1790 if (qstrcmp(str1: w->metaObject()->className(), str2: "QTipLabel") == 0)
1791 return base->pixelMetric(metric: QStyle::PM_ToolTipLabelFrameWidth, option: nullptr, widget: w);
1792
1793 return base->pixelMetric(metric: QStyle::PM_DefaultFrameWidth, option: nullptr, widget: w);
1794}
1795
1796static quint64 pseudoClass(QStyle::State state)
1797{
1798 quint64 pc = 0;
1799 if (state & QStyle::State_Enabled) {
1800 pc |= PseudoClass_Enabled;
1801 if (state & QStyle::State_MouseOver)
1802 pc |= PseudoClass_Hover;
1803 } else {
1804 pc |= PseudoClass_Disabled;
1805 }
1806 if (state & QStyle::State_Active)
1807 pc |= PseudoClass_Active;
1808 if (state & QStyle::State_Window)
1809 pc |= PseudoClass_Window;
1810 if (state & QStyle::State_Sunken)
1811 pc |= PseudoClass_Pressed;
1812 if (state & QStyle::State_HasFocus)
1813 pc |= PseudoClass_Focus;
1814 if (state & QStyle::State_On)
1815 pc |= (PseudoClass_On | PseudoClass_Checked);
1816 if (state & QStyle::State_Off)
1817 pc |= (PseudoClass_Off | PseudoClass_Unchecked);
1818 if (state & QStyle::State_NoChange)
1819 pc |= PseudoClass_Indeterminate;
1820 if (state & QStyle::State_Selected)
1821 pc |= PseudoClass_Selected;
1822 if (state & QStyle::State_Horizontal)
1823 pc |= PseudoClass_Horizontal;
1824 else
1825 pc |= PseudoClass_Vertical;
1826 if (state & (QStyle::State_Open | QStyle::State_On | QStyle::State_Sunken))
1827 pc |= PseudoClass_Open;
1828 else
1829 pc |= PseudoClass_Closed;
1830 if (state & QStyle::State_Children)
1831 pc |= PseudoClass_Children;
1832 if (state & QStyle::State_Sibling)
1833 pc |= PseudoClass_Sibling;
1834 if (state & QStyle::State_ReadOnly)
1835 pc |= PseudoClass_ReadOnly;
1836 if (state & QStyle::State_Item)
1837 pc |= PseudoClass_Item;
1838#ifdef QT_KEYPAD_NAVIGATION
1839 if (state & QStyle::State_HasEditFocus)
1840 pc |= PseudoClass_EditFocus;
1841#endif
1842 return pc;
1843}
1844
1845static void qt_check_if_internal_object(const QObject **obj, int *element)
1846{
1847#if !QT_CONFIG(dockwidget)
1848 Q_UNUSED(obj);
1849 Q_UNUSED(element);
1850#else
1851 if (*obj && qstrcmp(str1: (*obj)->metaObject()->className(), str2: "QDockWidgetTitleButton") == 0) {
1852 if ((*obj)->objectName() == "qt_dockwidget_closebutton"_L1) {
1853 *element = PseudoElement_DockWidgetCloseButton;
1854 } else if ((*obj)->objectName() == "qt_dockwidget_floatbutton"_L1) {
1855 *element = PseudoElement_DockWidgetFloatButton;
1856 }
1857 *obj = (*obj)->parent();
1858 }
1859#endif
1860}
1861
1862QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, int element, quint64 state) const
1863{
1864 qt_check_if_internal_object(obj: &obj, element: &element);
1865 QHash<quint64, QRenderRule> &cache = styleSheetCaches->renderRulesCache[obj][element];
1866 QHash<quint64, QRenderRule>::const_iterator cacheIt = cache.constFind(key: state);
1867 if (cacheIt != cache.constEnd())
1868 return cacheIt.value();
1869
1870 if (!initObject(obj))
1871 return QRenderRule();
1872
1873 quint64 stateMask = 0;
1874 const QList<StyleRule> rules = styleRules(obj);
1875 for (int i = 0; i < rules.size(); i++) {
1876 const Selector& selector = rules.at(i).selectors.at(i: 0);
1877 quint64 negated = 0;
1878 stateMask |= selector.pseudoClass(negated: &negated);
1879 stateMask |= negated;
1880 }
1881
1882 cacheIt = cache.constFind(key: state & stateMask);
1883 if (cacheIt != cache.constEnd()) {
1884 QRenderRule newRule = cacheIt.value();
1885 cache[state] = newRule;
1886 return newRule;
1887 }
1888
1889
1890 const QString part = QLatin1StringView(knownPseudoElements[element].name);
1891 QList<Declaration> decls = declarations(styleRules: rules, part, pseudoClass: state);
1892 QRenderRule newRule(decls, obj);
1893 cache[state] = newRule;
1894 if ((state & stateMask) != state)
1895 cache[state&stateMask] = newRule;
1896 return newRule;
1897}
1898
1899QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption *opt, int pseudoElement) const
1900{
1901 quint64 extraClass = 0;
1902 QStyle::State state = opt ? opt->state : QStyle::State(QStyle::State_None);
1903
1904 if (const QStyleOptionComplex *complex = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
1905 if (pseudoElement != PseudoElement_None) {
1906 // if not an active subcontrol, just pass enabled/disabled
1907 QStyle::SubControl subControl = knownPseudoElements[pseudoElement].subControl;
1908
1909 if (!(complex->activeSubControls & subControl))
1910 state &= (QStyle::State_Enabled | QStyle::State_Horizontal | QStyle::State_HasFocus);
1911 }
1912
1913 switch (pseudoElement) {
1914 case PseudoElement_ComboBoxDropDown:
1915 case PseudoElement_ComboBoxArrow:
1916 state |= (complex->state & (QStyle::State_On|QStyle::State_ReadOnly));
1917 break;
1918 case PseudoElement_SpinBoxUpButton:
1919 case PseudoElement_SpinBoxDownButton:
1920 case PseudoElement_SpinBoxUpArrow:
1921 case PseudoElement_SpinBoxDownArrow:
1922#if QT_CONFIG(spinbox)
1923 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
1924 bool on = false;
1925 bool up = pseudoElement == PseudoElement_SpinBoxUpButton
1926 || pseudoElement == PseudoElement_SpinBoxUpArrow;
1927 if ((sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) && up)
1928 on = true;
1929 else if ((sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) && !up)
1930 on = true;
1931 state |= (on ? QStyle::State_On : QStyle::State_Off);
1932 }
1933#endif // QT_CONFIG(spinbox)
1934 break;
1935 case PseudoElement_GroupBoxTitle:
1936 state |= (complex->state & (QStyle::State_MouseOver | QStyle::State_Sunken));
1937 break;
1938 case PseudoElement_ToolButtonMenu:
1939 case PseudoElement_ToolButtonMenuArrow:
1940 case PseudoElement_ToolButtonMenuIndicator:
1941 state |= complex->state & QStyle::State_MouseOver;
1942 if (complex->state & QStyle::State_Sunken ||
1943 complex->activeSubControls & QStyle::SC_ToolButtonMenu)
1944 state |= QStyle::State_Sunken;
1945 break;
1946 case PseudoElement_SliderGroove:
1947 state |= complex->state & QStyle::State_MouseOver;
1948 break;
1949 default:
1950 break;
1951 }
1952
1953 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
1954 // QStyle::State_On is set when the popup is being shown
1955 // Propagate EditField Pressed state
1956 if (pseudoElement == PseudoElement_None
1957 && (complex->activeSubControls & QStyle::SC_ComboBoxEditField)
1958 && (!(state & QStyle::State_MouseOver))) {
1959 state |= QStyle::State_Sunken;
1960 }
1961
1962 if (!combo->frame)
1963 extraClass |= PseudoClass_Frameless;
1964 if (!combo->editable)
1965 extraClass |= PseudoClass_ReadOnly;
1966 else
1967 extraClass |= PseudoClass_Editable;
1968#if QT_CONFIG(spinbox)
1969 } else if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
1970 if (!spin->frame)
1971 extraClass |= PseudoClass_Frameless;
1972#endif // QT_CONFIG(spinbox)
1973 } else if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
1974 if (gb->features & QStyleOptionFrame::Flat)
1975 extraClass |= PseudoClass_Flat;
1976 if (gb->lineWidth == 0)
1977 extraClass |= PseudoClass_Frameless;
1978 } else if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
1979 if (tb->titleBarState & Qt::WindowMinimized) {
1980 extraClass |= PseudoClass_Minimized;
1981 }
1982 else if (tb->titleBarState & Qt::WindowMaximized)
1983 extraClass |= PseudoClass_Maximized;
1984 }
1985 } else {
1986 // handle simple style options
1987 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
1988 if (mi->menuItemType == QStyleOptionMenuItem::DefaultItem)
1989 extraClass |= PseudoClass_Default;
1990 if (mi->checkType == QStyleOptionMenuItem::Exclusive)
1991 extraClass |= PseudoClass_Exclusive;
1992 else if (mi->checkType == QStyleOptionMenuItem::NonExclusive)
1993 extraClass |= PseudoClass_NonExclusive;
1994 if (mi->checkType != QStyleOptionMenuItem::NotCheckable)
1995 extraClass |= (mi->checked) ? (PseudoClass_On|PseudoClass_Checked)
1996 : (PseudoClass_Off|PseudoClass_Unchecked);
1997 } else if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
1998 if (hdr->position == QStyleOptionHeader::OnlyOneSection)
1999 extraClass |= PseudoClass_OnlyOne;
2000 else if (hdr->position == QStyleOptionHeader::Beginning)
2001 extraClass |= PseudoClass_First;
2002 else if (hdr->position == QStyleOptionHeader::End)
2003 extraClass |= PseudoClass_Last;
2004 else if (hdr->position == QStyleOptionHeader::Middle)
2005 extraClass |= PseudoClass_Middle;
2006
2007 if (hdr->selectedPosition == QStyleOptionHeader::NextAndPreviousAreSelected)
2008 extraClass |= (PseudoClass_NextSelected | PseudoClass_PreviousSelected);
2009 else if (hdr->selectedPosition == QStyleOptionHeader::NextIsSelected)
2010 extraClass |= PseudoClass_NextSelected;
2011 else if (hdr->selectedPosition == QStyleOptionHeader::PreviousIsSelected)
2012 extraClass |= PseudoClass_PreviousSelected;
2013#if QT_CONFIG(tabwidget)
2014 } else if (const QStyleOptionTabWidgetFrame *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
2015 switch (tab->shape) {
2016 case QTabBar::RoundedNorth:
2017 case QTabBar::TriangularNorth:
2018 extraClass |= PseudoClass_Top;
2019 break;
2020 case QTabBar::RoundedSouth:
2021 case QTabBar::TriangularSouth:
2022 extraClass |= PseudoClass_Bottom;
2023 break;
2024 case QTabBar::RoundedEast:
2025 case QTabBar::TriangularEast:
2026 extraClass |= PseudoClass_Right;
2027 break;
2028 case QTabBar::RoundedWest:
2029 case QTabBar::TriangularWest:
2030 extraClass |= PseudoClass_Left;
2031 break;
2032 default:
2033 break;
2034 }
2035#endif
2036#if QT_CONFIG(tabbar)
2037 } else if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
2038 if (tab->position == QStyleOptionTab::OnlyOneTab)
2039 extraClass |= PseudoClass_OnlyOne;
2040 else if (tab->position == QStyleOptionTab::Beginning)
2041 extraClass |= PseudoClass_First;
2042 else if (tab->position == QStyleOptionTab::End)
2043 extraClass |= PseudoClass_Last;
2044 else if (tab->position == QStyleOptionTab::Middle)
2045 extraClass |= PseudoClass_Middle;
2046
2047 if (tab->selectedPosition == QStyleOptionTab::NextIsSelected)
2048 extraClass |= PseudoClass_NextSelected;
2049 else if (tab->selectedPosition == QStyleOptionTab::PreviousIsSelected)
2050 extraClass |= PseudoClass_PreviousSelected;
2051
2052 switch (tab->shape) {
2053 case QTabBar::RoundedNorth:
2054 case QTabBar::TriangularNorth:
2055 extraClass |= PseudoClass_Top;
2056 break;
2057 case QTabBar::RoundedSouth:
2058 case QTabBar::TriangularSouth:
2059 extraClass |= PseudoClass_Bottom;
2060 break;
2061 case QTabBar::RoundedEast:
2062 case QTabBar::TriangularEast:
2063 extraClass |= PseudoClass_Right;
2064 break;
2065 case QTabBar::RoundedWest:
2066 case QTabBar::TriangularWest:
2067 extraClass |= PseudoClass_Left;
2068 break;
2069 default:
2070 break;
2071 }
2072#endif // QT_CONFIG(tabbar)
2073 } else if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2074 if (btn->features & QStyleOptionButton::Flat)
2075 extraClass |= PseudoClass_Flat;
2076 if (btn->features & QStyleOptionButton::DefaultButton)
2077 extraClass |= PseudoClass_Default;
2078 } else if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2079 if (frm->lineWidth == 0)
2080 extraClass |= PseudoClass_Frameless;
2081 if (frm->features & QStyleOptionFrame::Flat)
2082 extraClass |= PseudoClass_Flat;
2083 }
2084#if QT_CONFIG(toolbar)
2085 else if (const QStyleOptionToolBar *tb = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
2086 if (tb->toolBarArea == Qt::LeftToolBarArea)
2087 extraClass |= PseudoClass_Left;
2088 else if (tb->toolBarArea == Qt::RightToolBarArea)
2089 extraClass |= PseudoClass_Right;
2090 else if (tb->toolBarArea == Qt::TopToolBarArea)
2091 extraClass |= PseudoClass_Top;
2092 else if (tb->toolBarArea == Qt::BottomToolBarArea)
2093 extraClass |= PseudoClass_Bottom;
2094
2095 if (tb->positionWithinLine == QStyleOptionToolBar::Beginning)
2096 extraClass |= PseudoClass_First;
2097 else if (tb->positionWithinLine == QStyleOptionToolBar::Middle)
2098 extraClass |= PseudoClass_Middle;
2099 else if (tb->positionWithinLine == QStyleOptionToolBar::End)
2100 extraClass |= PseudoClass_Last;
2101 else if (tb->positionWithinLine == QStyleOptionToolBar::OnlyOne)
2102 extraClass |= PseudoClass_OnlyOne;
2103 }
2104#endif // QT_CONFIG(toolbar)
2105#if QT_CONFIG(toolbox)
2106 else if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
2107 if (tb->position == QStyleOptionToolBox::OnlyOneTab)
2108 extraClass |= PseudoClass_OnlyOne;
2109 else if (tb->position == QStyleOptionToolBox::Beginning)
2110 extraClass |= PseudoClass_First;
2111 else if (tb->position == QStyleOptionToolBox::End)
2112 extraClass |= PseudoClass_Last;
2113 else if (tb->position == QStyleOptionToolBox::Middle)
2114 extraClass |= PseudoClass_Middle;
2115
2116 if (tb->selectedPosition == QStyleOptionToolBox::NextIsSelected)
2117 extraClass |= PseudoClass_NextSelected;
2118 else if (tb->selectedPosition == QStyleOptionToolBox::PreviousIsSelected)
2119 extraClass |= PseudoClass_PreviousSelected;
2120 }
2121#endif // QT_CONFIG(toolbox)
2122#if QT_CONFIG(dockwidget)
2123 else if (const QStyleOptionDockWidget *dw = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
2124 if (dw->verticalTitleBar)
2125 extraClass |= PseudoClass_Vertical;
2126 else
2127 extraClass |= PseudoClass_Horizontal;
2128 if (dw->closable)
2129 extraClass |= PseudoClass_Closable;
2130 if (dw->floatable)
2131 extraClass |= PseudoClass_Floatable;
2132 if (dw->movable)
2133 extraClass |= PseudoClass_Movable;
2134 }
2135#endif // QT_CONFIG(dockwidget)
2136#if QT_CONFIG(itemviews)
2137 else if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
2138 if (vopt->features & QStyleOptionViewItem::Alternate)
2139 extraClass |= PseudoClass_Alternate;
2140 if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne)
2141 extraClass |= PseudoClass_OnlyOne;
2142 else if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning)
2143 extraClass |= PseudoClass_First;
2144 else if (vopt->viewItemPosition == QStyleOptionViewItem::End)
2145 extraClass |= PseudoClass_Last;
2146 else if (vopt->viewItemPosition == QStyleOptionViewItem::Middle)
2147 extraClass |= PseudoClass_Middle;
2148
2149 }
2150#endif
2151#if QT_CONFIG(textedit)
2152 else if (const QPlainTextEdit *edit = qobject_cast<const QPlainTextEdit *>(object: obj)) {
2153 extraClass |= (edit->isReadOnly() ? PseudoClass_ReadOnly : PseudoClass_Editable);
2154 }
2155 else if (const QTextEdit *edit = qobject_cast<const QTextEdit *>(object: obj)) {
2156 extraClass |= (edit->isReadOnly() ? PseudoClass_ReadOnly : PseudoClass_Editable);
2157 }
2158#endif
2159#if QT_CONFIG(lineedit)
2160 // LineEdit sets Sunken flag to indicate Sunken frame (argh)
2161 if (const QLineEdit *lineEdit = qobject_cast<const QLineEdit *>(object: obj)) {
2162 state &= ~QStyle::State_Sunken;
2163 if (lineEdit->hasFrame()) {
2164 extraClass &= ~PseudoClass_Frameless;
2165 } else {
2166 extraClass |= PseudoClass_Frameless;
2167 }
2168 } else
2169#endif
2170 if (const QFrame *frm = qobject_cast<const QFrame *>(object: obj)) {
2171 if (frm->lineWidth() == 0)
2172 extraClass |= PseudoClass_Frameless;
2173 }
2174 }
2175
2176 return renderRule(obj, element: pseudoElement, state: pseudoClass(state) | extraClass);
2177}
2178
2179bool QStyleSheetStyle::hasStyleRule(const QObject *obj, int part) const
2180{
2181 QHash<int, bool> &cache = styleSheetCaches->hasStyleRuleCache[obj];
2182 QHash<int, bool>::const_iterator cacheIt = cache.constFind(key: part);
2183 if (cacheIt != cache.constEnd())
2184 return cacheIt.value();
2185
2186 if (!initObject(obj))
2187 return false;
2188
2189 const QList<StyleRule> &rules = styleRules(obj);
2190 if (part == PseudoElement_None) {
2191 bool result = obj && !rules.isEmpty();
2192 cache[part] = result;
2193 return result;
2194 }
2195
2196 auto pseudoElement = QLatin1StringView(knownPseudoElements[part].name);
2197 for (int i = 0; i < rules.size(); i++) {
2198 const Selector& selector = rules.at(i).selectors.at(i: 0);
2199 if (pseudoElement.compare(other: selector.pseudoElement(), cs: Qt::CaseInsensitive) == 0) {
2200 cache[part] = true;
2201 return true;
2202 }
2203 }
2204
2205 cache[part] = false;
2206 return false;
2207}
2208
2209static Origin defaultOrigin(int pe)
2210{
2211 switch (pe) {
2212 case PseudoElement_ScrollBarAddPage:
2213 case PseudoElement_ScrollBarSubPage:
2214 case PseudoElement_ScrollBarAddLine:
2215 case PseudoElement_ScrollBarSubLine:
2216 case PseudoElement_ScrollBarFirst:
2217 case PseudoElement_ScrollBarLast:
2218 case PseudoElement_GroupBoxTitle:
2219 case PseudoElement_GroupBoxIndicator: // never used
2220 case PseudoElement_ToolButtonMenu:
2221 case PseudoElement_SliderAddPage:
2222 case PseudoElement_SliderSubPage:
2223 return Origin_Border;
2224
2225 case PseudoElement_SpinBoxUpButton:
2226 case PseudoElement_SpinBoxDownButton:
2227 case PseudoElement_PushButtonMenuIndicator:
2228 case PseudoElement_ComboBoxDropDown:
2229 case PseudoElement_ToolButtonMenuIndicator:
2230 case PseudoElement_MenuCheckMark:
2231 case PseudoElement_MenuIcon:
2232 case PseudoElement_MenuRightArrow:
2233 return Origin_Padding;
2234
2235 case PseudoElement_Indicator:
2236 case PseudoElement_ExclusiveIndicator:
2237 case PseudoElement_ComboBoxArrow:
2238 case PseudoElement_ScrollBarSlider:
2239 case PseudoElement_ScrollBarUpArrow:
2240 case PseudoElement_ScrollBarDownArrow:
2241 case PseudoElement_ScrollBarLeftArrow:
2242 case PseudoElement_ScrollBarRightArrow:
2243 case PseudoElement_SpinBoxUpArrow:
2244 case PseudoElement_SpinBoxDownArrow:
2245 case PseudoElement_ToolButtonMenuArrow:
2246 case PseudoElement_HeaderViewUpArrow:
2247 case PseudoElement_HeaderViewDownArrow:
2248 case PseudoElement_SliderGroove:
2249 case PseudoElement_SliderHandle:
2250 return Origin_Content;
2251
2252 default:
2253 return Origin_Margin;
2254 }
2255}
2256
2257static Qt::Alignment defaultPosition(int pe)
2258{
2259 switch (pe) {
2260 case PseudoElement_Indicator:
2261 case PseudoElement_ExclusiveIndicator:
2262 case PseudoElement_MenuCheckMark:
2263 case PseudoElement_MenuIcon:
2264 return Qt::AlignLeft | Qt::AlignVCenter;
2265
2266 case PseudoElement_ScrollBarAddLine:
2267 case PseudoElement_ScrollBarLast:
2268 case PseudoElement_SpinBoxDownButton:
2269 case PseudoElement_PushButtonMenuIndicator:
2270 case PseudoElement_ToolButtonMenuIndicator:
2271 return Qt::AlignRight | Qt::AlignBottom;
2272
2273 case PseudoElement_ScrollBarSubLine:
2274 case PseudoElement_ScrollBarFirst:
2275 case PseudoElement_SpinBoxUpButton:
2276 case PseudoElement_ComboBoxDropDown:
2277 case PseudoElement_ToolButtonMenu:
2278 case PseudoElement_DockWidgetCloseButton:
2279 case PseudoElement_DockWidgetFloatButton:
2280 return Qt::AlignRight | Qt::AlignTop;
2281
2282 case PseudoElement_ScrollBarUpArrow:
2283 case PseudoElement_ScrollBarDownArrow:
2284 case PseudoElement_ScrollBarLeftArrow:
2285 case PseudoElement_ScrollBarRightArrow:
2286 case PseudoElement_SpinBoxUpArrow:
2287 case PseudoElement_SpinBoxDownArrow:
2288 case PseudoElement_ComboBoxArrow:
2289 case PseudoElement_DownArrow:
2290 case PseudoElement_UpArrow:
2291 case PseudoElement_LeftArrow:
2292 case PseudoElement_RightArrow:
2293 case PseudoElement_ToolButtonMenuArrow:
2294 case PseudoElement_SliderGroove:
2295 return Qt::AlignCenter;
2296
2297 case PseudoElement_GroupBoxTitle:
2298 case PseudoElement_GroupBoxIndicator: // never used
2299 return Qt::AlignLeft | Qt::AlignTop;
2300
2301 case PseudoElement_HeaderViewUpArrow:
2302 case PseudoElement_HeaderViewDownArrow:
2303 case PseudoElement_MenuRightArrow:
2304 return Qt::AlignRight | Qt::AlignVCenter;
2305
2306 default:
2307 return { };
2308 }
2309}
2310
2311QSize QStyleSheetStyle::defaultSize(const QWidget *w, QSize sz, const QRect& rect, int pe) const
2312{
2313 QStyle *base = baseStyle();
2314
2315 switch (pe) {
2316 case PseudoElement_Indicator:
2317 case PseudoElement_MenuCheckMark:
2318 if (sz.width() == -1)
2319 sz.setWidth(base->pixelMetric(metric: PM_IndicatorWidth, option: nullptr, widget: w));
2320 if (sz.height() == -1)
2321 sz.setHeight(base->pixelMetric(metric: PM_IndicatorHeight, option: nullptr, widget: w));
2322 break;
2323
2324 case PseudoElement_ExclusiveIndicator:
2325 case PseudoElement_GroupBoxIndicator:
2326 if (sz.width() == -1)
2327 sz.setWidth(base->pixelMetric(metric: PM_ExclusiveIndicatorWidth, option: nullptr, widget: w));
2328 if (sz.height() == -1)
2329 sz.setHeight(base->pixelMetric(metric: PM_ExclusiveIndicatorHeight, option: nullptr, widget: w));
2330 break;
2331
2332 case PseudoElement_PushButtonMenuIndicator: {
2333 int pm = base->pixelMetric(metric: PM_MenuButtonIndicator, option: nullptr, widget: w);
2334 if (sz.width() == -1)
2335 sz.setWidth(pm);
2336 if (sz.height() == -1)
2337 sz.setHeight(pm);
2338 }
2339 break;
2340
2341 case PseudoElement_ComboBoxDropDown:
2342 if (sz.width() == -1)
2343 sz.setWidth(16);
2344 break;
2345
2346 case PseudoElement_ComboBoxArrow:
2347 case PseudoElement_DownArrow:
2348 case PseudoElement_UpArrow:
2349 case PseudoElement_LeftArrow:
2350 case PseudoElement_RightArrow:
2351 case PseudoElement_ToolButtonMenuArrow:
2352 case PseudoElement_ToolButtonMenuIndicator:
2353 case PseudoElement_MenuRightArrow:
2354 if (sz.width() == -1)
2355 sz.setWidth(13);
2356 if (sz.height() == -1)
2357 sz.setHeight(13);
2358 break;
2359
2360 case PseudoElement_SpinBoxUpButton:
2361 case PseudoElement_SpinBoxDownButton:
2362 if (sz.width() == -1)
2363 sz.setWidth(16);
2364 if (sz.height() == -1)
2365 sz.setHeight(rect.height()/2);
2366 break;
2367
2368 case PseudoElement_ToolButtonMenu:
2369 if (sz.width() == -1)
2370 sz.setWidth(base->pixelMetric(metric: PM_MenuButtonIndicator, option: nullptr, widget: w));
2371 break;
2372
2373 case PseudoElement_HeaderViewUpArrow:
2374 case PseudoElement_HeaderViewDownArrow: {
2375 int pm = base->pixelMetric(metric: PM_HeaderMargin, option: nullptr, widget: w);
2376 if (sz.width() == -1)
2377 sz.setWidth(pm);
2378 if (sz.height() == 1)
2379 sz.setHeight(pm);
2380 break;
2381 }
2382
2383 case PseudoElement_ScrollBarFirst:
2384 case PseudoElement_ScrollBarLast:
2385 case PseudoElement_ScrollBarAddLine:
2386 case PseudoElement_ScrollBarSubLine:
2387 case PseudoElement_ScrollBarSlider: {
2388 int pm = pixelMetric(metric: QStyle::PM_ScrollBarExtent, option: nullptr, widget: w);
2389 if (sz.width() == -1)
2390 sz.setWidth(pm);
2391 if (sz.height() == -1)
2392 sz.setHeight(pm);
2393 break;
2394 }
2395
2396 case PseudoElement_DockWidgetCloseButton:
2397 case PseudoElement_DockWidgetFloatButton: {
2398 int iconSize = pixelMetric(metric: PM_SmallIconSize, option: nullptr, widget: w);
2399 return QSize(iconSize, iconSize);
2400 }
2401
2402 default:
2403 break;
2404 }
2405
2406 // expand to rectangle
2407 if (sz.height() == -1)
2408 sz.setHeight(rect.height());
2409 if (sz.width() == -1)
2410 sz.setWidth(rect.width());
2411
2412 return sz;
2413}
2414
2415static PositionMode defaultPositionMode(int pe)
2416{
2417 switch (pe) {
2418 case PseudoElement_ScrollBarFirst:
2419 case PseudoElement_ScrollBarLast:
2420 case PseudoElement_ScrollBarAddLine:
2421 case PseudoElement_ScrollBarSubLine:
2422 case PseudoElement_ScrollBarAddPage:
2423 case PseudoElement_ScrollBarSubPage:
2424 case PseudoElement_ScrollBarSlider:
2425 case PseudoElement_SliderGroove:
2426 case PseudoElement_SliderHandle:
2427 case PseudoElement_TabWidgetPane:
2428 return PositionMode_Absolute;
2429 default:
2430 return PositionMode_Static;
2431 }
2432}
2433
2434QRect QStyleSheetStyle::positionRect(const QWidget *w, const QRenderRule &rule2, int pe,
2435 const QRect &originRect, Qt::LayoutDirection dir) const
2436{
2437 const QStyleSheetPositionData *p = rule2.position();
2438 PositionMode mode = (p && p->mode != PositionMode_Unknown) ? p->mode : defaultPositionMode(pe);
2439 Qt::Alignment position = (p && p->position != 0) ? p->position : defaultPosition(pe);
2440 QRect r;
2441
2442 if (mode != PositionMode_Absolute) {
2443 QSize sz = defaultSize(w, sz: rule2.size(), rect: originRect, pe);
2444 sz = sz.expandedTo(otherSize: rule2.minimumContentsSize());
2445 r = QStyle::alignedRect(direction: dir, alignment: position, size: sz, rectangle: originRect);
2446 if (p) {
2447 int left = p->left ? p->left : -p->right;
2448 int top = p->top ? p->top : -p->bottom;
2449 r.translate(dx: dir == Qt::LeftToRight ? left : -left, dy: top);
2450 }
2451 } else {
2452 r = p ? originRect.adjusted(xp1: dir == Qt::LeftToRight ? p->left : p->right, yp1: p->top,
2453 xp2: dir == Qt::LeftToRight ? -p->right : -p->left, yp2: -p->bottom)
2454 : originRect;
2455 if (rule2.hasContentsSize()) {
2456 QSize sz = rule2.size().expandedTo(otherSize: rule2.minimumContentsSize());
2457 if (sz.width() == -1) sz.setWidth(r.width());
2458 if (sz.height() == -1) sz.setHeight(r.height());
2459 r = QStyle::alignedRect(direction: dir, alignment: position, size: sz, rectangle: r);
2460 }
2461 }
2462 return r;
2463}
2464
2465QRect QStyleSheetStyle::positionRect(const QWidget *w, const QRenderRule& rule1, const QRenderRule& rule2, int pe,
2466 const QRect& rect, Qt::LayoutDirection dir) const
2467{
2468 const QStyleSheetPositionData *p = rule2.position();
2469 Origin origin = (p && p->origin != Origin_Unknown) ? p->origin : defaultOrigin(pe);
2470 QRect originRect = rule1.originRect(rect, origin);
2471 return positionRect(w, rule2, pe, originRect, dir);
2472}
2473
2474
2475/** \internal
2476 For widget that have an embedded widget (such as combobox) return that embedded widget.
2477 otherwise return the widget itself
2478 */
2479static QWidget *embeddedWidget(QWidget *w)
2480{
2481#if QT_CONFIG(combobox)
2482 if (QComboBox *cmb = qobject_cast<QComboBox *>(object: w)) {
2483 if (cmb->isEditable())
2484 return cmb->lineEdit();
2485 else
2486 return cmb;
2487 }
2488#endif
2489
2490#if QT_CONFIG(spinbox)
2491 if (QAbstractSpinBox *sb = qobject_cast<QAbstractSpinBox *>(object: w))
2492 return sb->findChild<QLineEdit *>();
2493#endif
2494
2495#if QT_CONFIG(scrollarea)
2496 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(object: w))
2497 return sa->viewport();
2498#endif
2499
2500 return w;
2501}
2502
2503/** \internal
2504 Returns the widget whose style rules apply to \a w.
2505
2506 When \a w is an embedded widget, this is the container widget.
2507 For example, if w is a line edit embedded in a combobox, this returns the combobox.
2508 When \a w is not embedded, this function return \a w itself.
2509
2510*/
2511static QWidget *containerWidget(const QWidget *w)
2512{
2513#if QT_CONFIG(lineedit)
2514 if (qobject_cast<const QLineEdit *>(object: w)) {
2515 //if the QLineEdit is an embeddedWidget, we need the rule of the real widget
2516#if QT_CONFIG(combobox)
2517 if (qobject_cast<const QComboBox *>(object: w->parentWidget()))
2518 return w->parentWidget();
2519#endif
2520#if QT_CONFIG(spinbox)
2521 if (qobject_cast<const QAbstractSpinBox *>(object: w->parentWidget()))
2522 return w->parentWidget();
2523#endif
2524 }
2525#endif // QT_CONFIG(lineedit)
2526
2527#if QT_CONFIG(scrollarea)
2528 if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(object: w->parentWidget())) {
2529 if (sa->viewport() == w)
2530 return w->parentWidget();
2531 }
2532#endif
2533
2534 return const_cast<QWidget *>(w);
2535}
2536
2537/** \internal
2538 returns \c true if the widget can NOT be styled directly
2539 */
2540static bool unstylable(const QWidget *w)
2541{
2542 if (w->windowType() == Qt::Desktop)
2543 return true;
2544
2545 if (!w->styleSheet().isEmpty())
2546 return false;
2547
2548 if (containerWidget(w) != w)
2549 return true;
2550
2551#ifndef QT_NO_FRAME
2552 // detect QComboBoxPrivateContainer
2553 else if (qobject_cast<const QFrame *>(object: w)) {
2554 if (0
2555#if QT_CONFIG(combobox)
2556 || qobject_cast<const QComboBox *>(object: w->parentWidget())
2557#endif
2558 )
2559 return true;
2560 }
2561#endif
2562
2563#if QT_CONFIG(tabbar)
2564 if (w->metaObject() == &QWidget::staticMetaObject
2565 && qobject_cast<const QTabBar*>(object: w->parentWidget()))
2566 return true; // The moving tab of a QTabBar
2567#endif
2568
2569 return false;
2570}
2571
2572static quint64 extendedPseudoClass(const QWidget *w)
2573{
2574 quint64 pc = w->isWindow() ? quint64(PseudoClass_Window) : 0;
2575#if QT_CONFIG(abstractslider)
2576 if (const QAbstractSlider *slider = qobject_cast<const QAbstractSlider *>(object: w)) {
2577 pc |= ((slider->orientation() == Qt::Vertical) ? PseudoClass_Vertical : PseudoClass_Horizontal);
2578 } else
2579#endif
2580#if QT_CONFIG(combobox)
2581 if (const QComboBox *combo = qobject_cast<const QComboBox *>(object: w)) {
2582 if (combo->isEditable())
2583 pc |= (combo->isEditable() ? PseudoClass_Editable : PseudoClass_ReadOnly);
2584 } else
2585#endif
2586#if QT_CONFIG(lineedit)
2587 if (const QLineEdit *edit = qobject_cast<const QLineEdit *>(object: w)) {
2588 pc |= (edit->isReadOnly() ? PseudoClass_ReadOnly : PseudoClass_Editable);
2589 } else
2590#endif
2591#if QT_CONFIG(textedit)
2592 if (const QTextEdit *edit = qobject_cast<const QTextEdit *>(object: w)) {
2593 pc |= (edit->isReadOnly() ? PseudoClass_ReadOnly : PseudoClass_Editable);
2594 } else
2595 if (const QPlainTextEdit *edit = qobject_cast<const QPlainTextEdit *>(object: w)) {
2596 pc |= (edit->isReadOnly() ? PseudoClass_ReadOnly : PseudoClass_Editable);
2597 } else
2598#endif
2599 {}
2600 return pc;
2601}
2602
2603// sets up the geometry of the widget. We set a dynamic property when
2604// we modify the min/max size of the widget. The min/max size is restored
2605// to their original value when a new stylesheet that does not contain
2606// the CSS properties is set and when the widget has this dynamic property set.
2607// This way we don't trample on users who had setup a min/max size in code and
2608// don't use stylesheets at all.
2609void QStyleSheetStyle::setGeometry(QWidget *w)
2610{
2611 QRenderRule rule = renderRule(obj: w, element: PseudoElement_None, state: PseudoClass_Enabled | extendedPseudoClass(w));
2612 const QStyleSheetGeometryData *geo = rule.geometry();
2613 if (w->property(name: "_q_stylesheet_minw").toBool()
2614 && ((!rule.hasGeometry() || geo->minWidth == -1))) {
2615 w->setMinimumWidth(0);
2616 w->setProperty(name: "_q_stylesheet_minw", value: QVariant());
2617 }
2618 if (w->property(name: "_q_stylesheet_minh").toBool()
2619 && ((!rule.hasGeometry() || geo->minHeight == -1))) {
2620 w->setMinimumHeight(0);
2621 w->setProperty(name: "_q_stylesheet_minh", value: QVariant());
2622 }
2623 if (w->property(name: "_q_stylesheet_maxw").toBool()
2624 && ((!rule.hasGeometry() || geo->maxWidth == -1))) {
2625 w->setMaximumWidth(QWIDGETSIZE_MAX);
2626 w->setProperty(name: "_q_stylesheet_maxw", value: QVariant());
2627 }
2628 if (w->property(name: "_q_stylesheet_maxh").toBool()
2629 && ((!rule.hasGeometry() || geo->maxHeight == -1))) {
2630 w->setMaximumHeight(QWIDGETSIZE_MAX);
2631 w->setProperty(name: "_q_stylesheet_maxh", value: QVariant());
2632 }
2633
2634
2635 if (rule.hasGeometry()) {
2636 if (geo->minWidth != -1) {
2637 w->setProperty(name: "_q_stylesheet_minw", value: true);
2638 w->setMinimumWidth(rule.boxSize(cs: QSize(qMax(a: geo->width, b: geo->minWidth), 0)).width());
2639 }
2640 if (geo->minHeight != -1) {
2641 w->setProperty(name: "_q_stylesheet_minh", value: true);
2642 w->setMinimumHeight(rule.boxSize(cs: QSize(0, qMax(a: geo->height, b: geo->minHeight))).height());
2643 }
2644 if (geo->maxWidth != -1) {
2645 w->setProperty(name: "_q_stylesheet_maxw", value: true);
2646 w->setMaximumWidth(rule.boxSize(cs: QSize(qMin(a: geo->width == -1 ? QWIDGETSIZE_MAX : geo->width,
2647 b: geo->maxWidth == -1 ? QWIDGETSIZE_MAX : geo->maxWidth), 0)).width());
2648 }
2649 if (geo->maxHeight != -1) {
2650 w->setProperty(name: "_q_stylesheet_maxh", value: true);
2651 w->setMaximumHeight(rule.boxSize(cs: QSize(0, qMin(a: geo->height == -1 ? QWIDGETSIZE_MAX : geo->height,
2652 b: geo->maxHeight == -1 ? QWIDGETSIZE_MAX : geo->maxHeight))).height());
2653 }
2654 }
2655}
2656
2657void QStyleSheetStyle::setProperties(QWidget *w)
2658{
2659 // The final occurrence of each property is authoritative.
2660 // Set value for each property in the order of property final occurrence
2661 // since properties interact.
2662
2663 const QList<Declaration> decls = declarations(styleRules: styleRules(obj: w), part: QString());
2664 QList<int> finals; // indices in reverse order of each property's final occurrence
2665
2666 {
2667 // scan decls for final occurrence of each "qproperty"
2668 QDuplicateTracker<QString> propertySet(decls.size());
2669 for (int i = decls.size() - 1; i >= 0; --i) {
2670 const QString property = decls.at(i).d->property;
2671 if (!property.startsWith(s: "qproperty-"_L1, cs: Qt::CaseInsensitive))
2672 continue;
2673 if (!propertySet.hasSeen(s: property))
2674 finals.append(t: i);
2675 }
2676 }
2677
2678 for (int i = finals.size() - 1; i >= 0; --i) {
2679 const Declaration &decl = decls.at(i: finals[i]);
2680 QStringView property = decl.d->property;
2681 property = property.mid(pos: 10); // strip "qproperty-"
2682 const auto propertyL1 = property.toLatin1();
2683
2684 const QMetaObject *metaObject = w->metaObject();
2685 int index = metaObject->indexOfProperty(name: propertyL1);
2686 if (Q_UNLIKELY(index == -1)) {
2687 qWarning() << w << " does not have a property named " << property;
2688 continue;
2689 }
2690 const QMetaProperty metaProperty = metaObject->property(index);
2691 if (Q_UNLIKELY(!metaProperty.isWritable() || !metaProperty.isDesignable())) {
2692 qWarning() << w << " cannot design property named " << property;
2693 continue;
2694 }
2695
2696 QVariant v;
2697 const QVariant value = w->property(name: propertyL1);
2698 switch (value.userType()) {
2699 case QMetaType::QIcon: v = decl.iconValue(); break;
2700 case QMetaType::QImage: v = QImage(decl.uriValue()); break;
2701 case QMetaType::QPixmap: v = QPixmap(decl.uriValue()); break;
2702 case QMetaType::QRect: v = decl.rectValue(); break;
2703 case QMetaType::QSize: v = decl.sizeValue(); break;
2704 case QMetaType::QColor: v = decl.colorValue(); break;
2705 case QMetaType::QBrush: v = decl.brushValue(); break;
2706#ifndef QT_NO_SHORTCUT
2707 case QMetaType::QKeySequence: v = QKeySequence(decl.d->values.at(i: 0).variant.toString()); break;
2708#endif
2709 default: v = decl.d->values.at(i: 0).variant; break;
2710 }
2711
2712 if (propertyL1 == QByteArrayView("styleSheet") && value == v)
2713 continue;
2714
2715 w->setProperty(name: propertyL1, value: v);
2716 }
2717}
2718
2719void QStyleSheetStyle::setPalette(QWidget *w)
2720{
2721 struct RuleRoleMap {
2722 int state;
2723 QPalette::ColorGroup group;
2724 } map[3] = {
2725 { .state: int(PseudoClass_Active | PseudoClass_Enabled), .group: QPalette::Active },
2726 { .state: PseudoClass_Disabled, .group: QPalette::Disabled },
2727 { .state: PseudoClass_Enabled, .group: QPalette::Inactive }
2728 };
2729
2730 const bool useStyleSheetPropagationInWidgetStyles =
2731 QCoreApplication::testAttribute(attribute: Qt::AA_UseStyleSheetPropagationInWidgetStyles);
2732
2733 QPalette p;
2734 if (!useStyleSheetPropagationInWidgetStyles)
2735 p = w->palette();
2736
2737 QWidget *ew = embeddedWidget(w);
2738
2739 for (int i = 0; i < 3; i++) {
2740 QRenderRule rule = renderRule(obj: w, element: PseudoElement_None, state: map[i].state | extendedPseudoClass(w));
2741 if (i == 0) {
2742 if (!w->property(name: "_q_styleSheetWidgetFont").isValid()) {
2743 saveWidgetFont(w, font: w->d_func()->localFont());
2744 }
2745 updateStyleSheetFont(w);
2746 if (ew != w)
2747 updateStyleSheetFont(w: ew);
2748 }
2749
2750 rule.configurePalette(p: &p, cg: map[i].group, w: ew, embedded: ew != w);
2751 }
2752
2753 if (!useStyleSheetPropagationInWidgetStyles || p.resolveMask() != 0) {
2754 QPalette wp = w->palette();
2755 styleSheetCaches->customPaletteWidgets.insert(key: w, value: {.oldWidgetValue: wp, .resolveMask: p.resolveMask()});
2756
2757 if (useStyleSheetPropagationInWidgetStyles) {
2758 p = p.resolve(other: wp);
2759 p.setResolveMask(p.resolveMask() | wp.resolveMask());
2760 }
2761
2762 w->setPalette(p);
2763 if (ew != w)
2764 ew->setPalette(p);
2765 }
2766}
2767
2768void QStyleSheetStyle::unsetPalette(QWidget *w)
2769{
2770 const bool useStyleSheetPropagationInWidgetStyles =
2771 QCoreApplication::testAttribute(attribute: Qt::AA_UseStyleSheetPropagationInWidgetStyles);
2772
2773 const auto it = styleSheetCaches->customPaletteWidgets.find(key: w);
2774 if (it != styleSheetCaches->customPaletteWidgets.end()) {
2775 auto customizedPalette = std::move(*it);
2776 styleSheetCaches->customPaletteWidgets.erase(it);
2777
2778 QPalette original;
2779 if (useStyleSheetPropagationInWidgetStyles)
2780 original = std::move(customizedPalette).reverted(current: w->palette());
2781 else
2782 original = customizedPalette.oldWidgetValue;
2783
2784 w->setPalette(original);
2785 QWidget *ew = embeddedWidget(w);
2786 if (ew != w)
2787 ew->setPalette(original);
2788 }
2789
2790 if (useStyleSheetPropagationInWidgetStyles) {
2791 unsetStyleSheetFont(w);
2792 QWidget *ew = embeddedWidget(w);
2793 if (ew != w)
2794 unsetStyleSheetFont(ew);
2795 } else {
2796 QVariant oldFont = w->property(name: "_q_styleSheetWidgetFont");
2797 if (oldFont.isValid()) {
2798 w->setFont(qvariant_cast<QFont>(v: oldFont));
2799 }
2800 }
2801
2802 if (styleSheetCaches->autoFillDisabledWidgets.contains(value: w)) {
2803 embeddedWidget(w)->setAutoFillBackground(true);
2804 styleSheetCaches->autoFillDisabledWidgets.remove(value: w);
2805 }
2806}
2807
2808void QStyleSheetStyle::unsetStyleSheetFont(QWidget *w) const
2809{
2810 const auto it = styleSheetCaches->customFontWidgets.find(key: w);
2811 if (it != styleSheetCaches->customFontWidgets.end()) {
2812 auto customizedFont = std::move(*it);
2813 styleSheetCaches->customFontWidgets.erase(it);
2814 w->setFont(std::move(customizedFont).reverted(current: w->font()));
2815 }
2816}
2817
2818static void updateObjects(const QList<const QObject *>& objects)
2819{
2820 if (!styleSheetCaches->styleRulesCache.isEmpty() || !styleSheetCaches->hasStyleRuleCache.isEmpty() || !styleSheetCaches->renderRulesCache.isEmpty()) {
2821 for (const QObject *object : objects) {
2822 styleSheetCaches->styleRulesCache.remove(key: object);
2823 styleSheetCaches->hasStyleRuleCache.remove(key: object);
2824 styleSheetCaches->renderRulesCache.remove(key: object);
2825 }
2826 }
2827
2828 QEvent event(QEvent::StyleChange);
2829 for (const QObject *object : objects) {
2830 if (auto widget = qobject_cast<QWidget*>(o: const_cast<QObject*>(object))) {
2831 widget->style()->polish(widget);
2832 QCoreApplication::sendEvent(receiver: widget, event: &event);
2833 QList<const QObject *> children;
2834 children.reserve(size: widget->children().size() + 1);
2835 for (auto child: std::as_const(t: widget->children()))
2836 children.append(t: child);
2837 updateObjects(objects: children);
2838 }
2839 }
2840}
2841
2842/////////////////////////////////////////////////////////////////////////////////////////
2843// The stylesheet style
2844int QStyleSheetStyle::numinstances = 0;
2845
2846QStyleSheetStyle::QStyleSheetStyle(QStyle *base)
2847 : QWindowsStyle(*new QStyleSheetStylePrivate), base(base), refcount(1)
2848{
2849 ++numinstances;
2850 if (numinstances == 1) {
2851 styleSheetCaches = new QStyleSheetStyleCaches;
2852 }
2853}
2854
2855QStyleSheetStyle::~QStyleSheetStyle()
2856{
2857 --numinstances;
2858 if (numinstances == 0) {
2859 delete styleSheetCaches;
2860 }
2861}
2862QStyle *QStyleSheetStyle::baseStyle() const
2863{
2864 if (base)
2865 return base;
2866 if (QStyleSheetStyle *me = qt_styleSheet(style: QApplication::style()))
2867 return me->base;
2868 return QApplication::style();
2869}
2870
2871void QStyleSheetStyleCaches::objectDestroyed(QObject *o)
2872{
2873 styleRulesCache.remove(key: o);
2874 hasStyleRuleCache.remove(key: o);
2875 renderRulesCache.remove(key: o);
2876 customPaletteWidgets.remove(key: (const QWidget *)o);
2877 customFontWidgets.remove(key: static_cast<QWidget *>(o));
2878 styleSheetCache.remove(key: o);
2879 autoFillDisabledWidgets.remove(value: (const QWidget *)o);
2880}
2881
2882void QStyleSheetStyleCaches::styleDestroyed(QObject *o)
2883{
2884 styleSheetCache.remove(key: o);
2885}
2886
2887/*!
2888 * Make sure that the cache will be clean by connecting destroyed if needed.
2889 * return false if the widget is not stylable;
2890 */
2891bool QStyleSheetStyle::initObject(const QObject *obj) const
2892{
2893 if (!obj)
2894 return false;
2895 if (const QWidget *w = qobject_cast<const QWidget*>(o: obj)) {
2896 if (w->testAttribute(attribute: Qt::WA_StyleSheet))
2897 return true;
2898 if (unstylable(w))
2899 return false;
2900 const_cast<QWidget *>(w)->setAttribute(Qt::WA_StyleSheet, on: true);
2901 }
2902
2903 connect(sender: obj, signal: &QObject::destroyed,
2904 context: styleSheetCaches, slot: &QStyleSheetStyleCaches::objectDestroyed,
2905 type: Qt::UniqueConnection);
2906 return true;
2907}
2908
2909void QStyleSheetStyle::polish(QWidget *w)
2910{
2911 baseStyle()->polish(widget: w);
2912 RECURSION_GUARD(return)
2913
2914 if (!initObject(obj: w))
2915 return;
2916
2917 if (styleSheetCaches->styleRulesCache.contains(key: w)) {
2918 // the widget accessed its style pointer before polish (or repolish)
2919 // (example: the QAbstractSpinBox constructor ask for the stylehint)
2920 styleSheetCaches->styleRulesCache.remove(key: w);
2921 styleSheetCaches->hasStyleRuleCache.remove(key: w);
2922 styleSheetCaches->renderRulesCache.remove(key: w);
2923 styleSheetCaches->styleSheetCache.remove(key: w);
2924 }
2925 setGeometry(w);
2926 setProperties(w);
2927 unsetPalette(w);
2928 setPalette(w);
2929
2930 //set the WA_Hover attribute if one of the selector depends of the hover state
2931 QList<StyleRule> rules = styleRules(obj: w);
2932 for (int i = 0; i < rules.size(); i++) {
2933 const Selector& selector = rules.at(i).selectors.at(i: 0);
2934 quint64 negated = 0;
2935 quint64 cssClass = selector.pseudoClass(negated: &negated);
2936 if ( cssClass & PseudoClass_Hover || negated & PseudoClass_Hover) {
2937 w->setAttribute(Qt::WA_Hover);
2938 embeddedWidget(w)->setAttribute(Qt::WA_Hover);
2939 embeddedWidget(w)->setMouseTracking(true);
2940 }
2941 }
2942
2943
2944#if QT_CONFIG(scrollarea)
2945 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(object: w)) {
2946 QRenderRule rule = renderRule(obj: sa, element: PseudoElement_None, state: PseudoClass_Enabled);
2947 if ((rule.hasBorder() && rule.border()->hasBorderImage())
2948 || (rule.hasBackground() && !rule.background()->pixmap.isNull())) {
2949 connect(sender: sa->horizontalScrollBar(), signal: &QScrollBar::valueChanged,
2950 context: sa, slot: QOverload<>::of(ptr: &QAbstractScrollArea::update), type: Qt::UniqueConnection);
2951 connect(sender: sa->verticalScrollBar(), signal: &QScrollBar::valueChanged,
2952 context: sa, slot: QOverload<>::of(ptr: &QAbstractScrollArea::update), type: Qt::UniqueConnection);
2953 }
2954 }
2955#endif
2956
2957 QRenderRule rule = renderRule(obj: w, element: PseudoElement_None, state: PseudoClass_Any);
2958
2959 w->setAttribute(Qt::WA_StyleSheetTarget, on: rule.hasModification());
2960
2961 if (rule.hasDrawable() || rule.hasBox()) {
2962 if (w->metaObject() == &QWidget::staticMetaObject
2963#if QT_CONFIG(itemviews)
2964 || qobject_cast<QHeaderView *>(object: w)
2965#endif
2966#if QT_CONFIG(tabbar)
2967 || qobject_cast<QTabBar *>(object: w)
2968#endif
2969#ifndef QT_NO_FRAME
2970 || qobject_cast<QFrame *>(object: w)
2971#endif
2972#if QT_CONFIG(mainwindow)
2973 || qobject_cast<QMainWindow *>(object: w)
2974#endif
2975#if QT_CONFIG(mdiarea)
2976 || qobject_cast<QMdiSubWindow *>(object: w)
2977#endif
2978#if QT_CONFIG(menubar)
2979 || qobject_cast<QMenuBar *>(object: w)
2980#endif
2981#if QT_CONFIG(dialog)
2982 || qobject_cast<QDialog *>(object: w)
2983#endif
2984 ) {
2985 w->setAttribute(Qt::WA_StyledBackground, on: true);
2986 }
2987 QWidget *ew = embeddedWidget(w);
2988 if (ew->autoFillBackground()) {
2989 ew->setAutoFillBackground(false);
2990 styleSheetCaches->autoFillDisabledWidgets.insert(value: w);
2991 if (ew != w) { //eg. viewport of a scrollarea
2992 //(in order to draw the background anyway in case we don't.)
2993 ew->setAttribute(Qt::WA_StyledBackground, on: true);
2994 }
2995 }
2996 if (!rule.hasBackground() || rule.background()->isTransparent() || rule.hasBox()
2997 || (!rule.hasNativeBorder() && !rule.border()->isOpaque()))
2998 w->setAttribute(Qt::WA_OpaquePaintEvent, on: false);
2999 if (rule.hasBox() || !rule.hasNativeBorder()
3000#if QT_CONFIG(pushbutton)
3001 || (qobject_cast<QPushButton *>(object: w))
3002#endif
3003 )
3004 w->setAttribute(Qt::WA_MacShowFocusRect, on: false);
3005 }
3006}
3007
3008void QStyleSheetStyle::polish(QApplication *app)
3009{
3010 baseStyle()->polish(application: app);
3011}
3012
3013void QStyleSheetStyle::polish(QPalette &pal)
3014{
3015 baseStyle()->polish(palette&: pal);
3016}
3017
3018void QStyleSheetStyle::repolish(QWidget *w)
3019{
3020 QList<const QObject *> children;
3021 children.reserve(size: w->children().size() + 1);
3022 for (auto child: std::as_const(t: w->children()))
3023 children.append(t: child);
3024 children.append(t: w);
3025 styleSheetCaches->styleSheetCache.remove(key: w);
3026 updateObjects(objects: children);
3027}
3028
3029void QStyleSheetStyle::repolish(QApplication *app)
3030{
3031 Q_UNUSED(app);
3032 const QList<const QObject*> allObjects = styleSheetCaches->styleRulesCache.keys();
3033 styleSheetCaches->styleSheetCache.remove(qApp);
3034 styleSheetCaches->styleRulesCache.clear();
3035 styleSheetCaches->hasStyleRuleCache.clear();
3036 styleSheetCaches->renderRulesCache.clear();
3037 updateObjects(objects: allObjects);
3038}
3039
3040void QStyleSheetStyle::unpolish(QWidget *w)
3041{
3042 if (!w || !w->testAttribute(attribute: Qt::WA_StyleSheet)) {
3043 baseStyle()->unpolish(widget: w);
3044 return;
3045 }
3046
3047 styleSheetCaches->styleRulesCache.remove(key: w);
3048 styleSheetCaches->hasStyleRuleCache.remove(key: w);
3049 styleSheetCaches->renderRulesCache.remove(key: w);
3050 styleSheetCaches->styleSheetCache.remove(key: w);
3051 unsetPalette(w);
3052 setGeometry(w);
3053 w->setAttribute(Qt::WA_StyleSheetTarget, on: false);
3054 w->setAttribute(Qt::WA_StyleSheet, on: false);
3055 w->disconnect(receiver: this);
3056#if QT_CONFIG(scrollarea)
3057 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(object: w)) {
3058 disconnect(sender: sa->horizontalScrollBar(), signal: &QScrollBar::valueChanged,
3059 receiver: sa, slot: QOverload<>::of(ptr: &QAbstractScrollArea::update));
3060 disconnect(sender: sa->verticalScrollBar(), signal: &QScrollBar::valueChanged,
3061 receiver: sa, slot: QOverload<>::of(ptr: &QAbstractScrollArea::update));
3062 }
3063#endif
3064 baseStyle()->unpolish(widget: w);
3065}
3066
3067void QStyleSheetStyle::unpolish(QApplication *app)
3068{
3069 baseStyle()->unpolish(application: app);
3070 RECURSION_GUARD(return)
3071 styleSheetCaches->styleRulesCache.clear();
3072 styleSheetCaches->hasStyleRuleCache.clear();
3073 styleSheetCaches->renderRulesCache.clear();
3074 styleSheetCaches->styleSheetCache.remove(qApp);
3075}
3076
3077void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
3078 const QWidget *w) const
3079{
3080 RECURSION_GUARD(baseStyle()->drawComplexControl(cc, opt, p, w); return)
3081
3082 QRenderRule rule = renderRule(obj: w, opt);
3083
3084 switch (cc) {
3085 case CC_ComboBox:
3086 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3087 QStyleOptionComboBox cmbOpt(*cmb);
3088 cmbOpt.rect = rule.borderRect(r: opt->rect);
3089 if (rule.hasNativeBorder()) {
3090 rule.drawBackgroundImage(p, rect: cmbOpt.rect);
3091 rule.configurePalette(p: &cmbOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3092 bool customDropDown = (opt->subControls & QStyle::SC_ComboBoxArrow)
3093 && (hasStyleRule(obj: w, part: PseudoElement_ComboBoxDropDown) || hasStyleRule(obj: w, part: PseudoElement_ComboBoxArrow));
3094 if (customDropDown)
3095 cmbOpt.subControls &= ~QStyle::SC_ComboBoxArrow;
3096 if (rule.baseStyleCanDraw()) {
3097 baseStyle()->drawComplexControl(cc, opt: &cmbOpt, p, widget: w);
3098 } else {
3099 QWindowsStyle::drawComplexControl(cc, opt: &cmbOpt, p, w);
3100 }
3101 if (!customDropDown)
3102 return;
3103 } else {
3104 rule.drawRule(p, rect: opt->rect);
3105 }
3106
3107 if (opt->subControls & QStyle::SC_ComboBoxArrow) {
3108 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ComboBoxDropDown);
3109 if (subRule.hasDrawable()) {
3110 QRect r = subControlRect(cc: CC_ComboBox, opt, sc: SC_ComboBoxArrow, w);
3111 subRule.drawRule(p, rect: r);
3112 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: PseudoElement_ComboBoxArrow);
3113 r = positionRect(w, rule1: subRule, rule2: subRule2, pe: PseudoElement_ComboBoxArrow, rect: r, dir: opt->direction);
3114 subRule2.drawRule(p, rect: r);
3115 } else {
3116 rule.configurePalette(p: &cmbOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3117 cmbOpt.subControls = QStyle::SC_ComboBoxArrow;
3118 QWindowsStyle::drawComplexControl(cc, opt: &cmbOpt, p, w);
3119 }
3120 }
3121
3122 return;
3123 }
3124 break;
3125
3126#if QT_CONFIG(spinbox)
3127 case CC_SpinBox:
3128 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
3129 QStyleOptionSpinBox spinOpt(*spin);
3130 rule.configurePalette(p: &spinOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3131 rule.configurePalette(p: &spinOpt.palette, fr: QPalette::Text, br: QPalette::Base);
3132 spinOpt.rect = rule.borderRect(r: opt->rect);
3133 bool customUp = true, customDown = true;
3134 QRenderRule upRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxUpButton);
3135 QRenderRule downRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxDownButton);
3136 bool upRuleMatch = upRule.hasGeometry() || upRule.hasPosition();
3137 bool downRuleMatch = downRule.hasGeometry() || downRule.hasPosition();
3138 if (rule.hasNativeBorder() && !upRuleMatch && !downRuleMatch) {
3139 rule.drawBackgroundImage(p, rect: spinOpt.rect);
3140 customUp = (opt->subControls & QStyle::SC_SpinBoxUp)
3141 && (hasStyleRule(obj: w, part: PseudoElement_SpinBoxUpButton) || hasStyleRule(obj: w, part: PseudoElement_UpArrow));
3142 if (customUp)
3143 spinOpt.subControls &= ~QStyle::SC_SpinBoxUp;
3144 customDown = (opt->subControls & QStyle::SC_SpinBoxDown)
3145 && (hasStyleRule(obj: w, part: PseudoElement_SpinBoxDownButton) || hasStyleRule(obj: w, part: PseudoElement_DownArrow));
3146 if (customDown)
3147 spinOpt.subControls &= ~QStyle::SC_SpinBoxDown;
3148 if (rule.baseStyleCanDraw()) {
3149 baseStyle()->drawComplexControl(cc, opt: &spinOpt, p, widget: w);
3150 } else {
3151 QWindowsStyle::drawComplexControl(cc, opt: &spinOpt, p, w);
3152 }
3153 if (!customUp && !customDown)
3154 return;
3155 } else {
3156 rule.drawRule(p, rect: opt->rect);
3157 }
3158
3159 if ((opt->subControls & QStyle::SC_SpinBoxUp) && customUp) {
3160 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxUpButton);
3161 if (subRule.hasDrawable()) {
3162 QRect r = subControlRect(cc: CC_SpinBox, opt, sc: SC_SpinBoxUp, w);
3163 subRule.drawRule(p, rect: r);
3164 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxUpArrow);
3165 r = positionRect(w, rule1: subRule, rule2: subRule2, pe: PseudoElement_SpinBoxUpArrow, rect: r, dir: opt->direction);
3166 subRule2.drawRule(p, rect: r);
3167 } else {
3168 spinOpt.subControls = QStyle::SC_SpinBoxUp;
3169 QWindowsStyle::drawComplexControl(cc, opt: &spinOpt, p, w);
3170 }
3171 }
3172
3173 if ((opt->subControls & QStyle::SC_SpinBoxDown) && customDown) {
3174 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxDownButton);
3175 if (subRule.hasDrawable()) {
3176 QRect r = subControlRect(cc: CC_SpinBox, opt, sc: SC_SpinBoxDown, w);
3177 subRule.drawRule(p, rect: r);
3178 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxDownArrow);
3179 r = positionRect(w, rule1: subRule, rule2: subRule2, pe: PseudoElement_SpinBoxDownArrow, rect: r, dir: opt->direction);
3180 subRule2.drawRule(p, rect: r);
3181 } else {
3182 spinOpt.subControls = QStyle::SC_SpinBoxDown;
3183 QWindowsStyle::drawComplexControl(cc, opt: &spinOpt, p, w);
3184 }
3185 }
3186 return;
3187 }
3188 break;
3189#endif // QT_CONFIG(spinbox)
3190
3191 case CC_GroupBox:
3192 if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
3193
3194 QRect labelRect, checkBoxRect, titleRect, frameRect;
3195 bool hasTitle = (gb->subControls & QStyle::SC_GroupBoxCheckBox) || !gb->text.isEmpty();
3196
3197 if (!rule.hasDrawable() && (!hasTitle || !hasStyleRule(obj: w, part: PseudoElement_GroupBoxTitle))
3198 && !hasStyleRule(obj: w, part: PseudoElement_Indicator) && !rule.hasBox() && !rule.hasFont && !rule.hasPalette()) {
3199 // let the native style draw the combobox if there is no style for it.
3200 break;
3201 }
3202 rule.drawBackground(p, rect: opt->rect);
3203
3204 QRenderRule titleRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_GroupBoxTitle);
3205 bool clipSet = false;
3206
3207 if (hasTitle) {
3208 labelRect = subControlRect(cc: CC_GroupBox, opt, sc: SC_GroupBoxLabel, w);
3209 //Some native style (such as mac) may return a too small rectangle (because they use smaller fonts), so we may need to expand it a little bit.
3210 labelRect.setSize(labelRect.size().expandedTo(otherSize: ParentStyle::subControlRect(cc: CC_GroupBox, opt, sc: SC_GroupBoxLabel, w).size()));
3211 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3212 checkBoxRect = subControlRect(cc: CC_GroupBox, opt, sc: SC_GroupBoxCheckBox, w);
3213 titleRect = titleRule.boxRect(cr: checkBoxRect.united(r: labelRect));
3214 } else {
3215 titleRect = titleRule.boxRect(cr: labelRect);
3216 }
3217 if (!titleRule.hasBackground() || !titleRule.background()->isTransparent()) {
3218 clipSet = true;
3219 p->save();
3220 p->setClipRegion(QRegion(opt->rect) - titleRect);
3221 }
3222 }
3223
3224 frameRect = subControlRect(cc: CC_GroupBox, opt, sc: SC_GroupBoxFrame, w);
3225 QStyleOptionFrame frame;
3226 frame.QStyleOption::operator=(other: *gb);
3227 frame.features = gb->features;
3228 frame.lineWidth = gb->lineWidth;
3229 frame.midLineWidth = gb->midLineWidth;
3230 frame.rect = frameRect;
3231 drawPrimitive(pe: PE_FrameGroupBox, opt: &frame, p, w);
3232
3233 if (clipSet)
3234 p->restore();
3235
3236 // draw background and frame of the title
3237 if (hasTitle)
3238 titleRule.drawRule(p, rect: titleRect);
3239
3240 // draw the indicator
3241 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3242 QStyleOptionButton box;
3243 box.QStyleOption::operator=(other: *gb);
3244 box.rect = checkBoxRect;
3245 drawPrimitive(pe: PE_IndicatorCheckBox, opt: &box, p, w);
3246 }
3247
3248 // draw the text
3249 if (!gb->text.isEmpty()) {
3250 int alignment = int(Qt::AlignCenter | Qt::TextShowMnemonic);
3251 if (!styleHint(sh: QStyle::SH_UnderlineShortcut, opt, w)) {
3252 alignment |= Qt::TextHideMnemonic;
3253 }
3254
3255 QPalette pal = gb->palette;
3256 if (gb->textColor.isValid())
3257 pal.setColor(acr: QPalette::WindowText, acolor: gb->textColor);
3258 titleRule.configurePalette(p: &pal, fr: QPalette::WindowText, br: QPalette::Window);
3259 drawItemText(painter: p, rect: labelRect, alignment, pal, enabled: gb->state & State_Enabled,
3260 text: gb->text, textRole: QPalette::WindowText);
3261
3262 if (gb->state & State_HasFocus) {
3263 QStyleOptionFocusRect fropt;
3264 fropt.QStyleOption::operator=(other: *gb);
3265 fropt.rect = labelRect;
3266 drawPrimitive(pe: PE_FrameFocusRect, opt: &fropt, p, w);
3267 }
3268 }
3269
3270 return;
3271 }
3272 break;
3273
3274 case CC_ToolButton:
3275 if (const QStyleOptionToolButton *tool = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3276 QStyleOptionToolButton toolOpt(*tool);
3277 rule.configurePalette(p: &toolOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3278 toolOpt.font = rule.font.resolve(toolOpt.font);
3279 toolOpt.rect = rule.borderRect(r: opt->rect);
3280 const auto customArrowElement = [tool]{
3281 switch (tool->arrowType) {
3282 case Qt::DownArrow: return PseudoElement_DownArrow;
3283 case Qt::UpArrow: return PseudoElement_UpArrow;
3284 case Qt::LeftArrow: return PseudoElement_LeftArrow;
3285 case Qt::RightArrow: return PseudoElement_RightArrow;
3286 default: break;
3287 }
3288 return PseudoElement_None;
3289 };
3290 // if arrow/menu/indicators are requested, either draw them using the available rule,
3291 // or let the base style draw them; but not both
3292 const bool drawArrow = tool->features & QStyleOptionToolButton::Arrow;
3293 bool customArrow = drawArrow && hasStyleRule(obj: w, part: customArrowElement());
3294 if (customArrow) {
3295 toolOpt.features &= ~QStyleOptionToolButton::Arrow;
3296 toolOpt.text = QString(); // we need to draw the arrow and the text ourselves
3297 }
3298 bool drawDropDown = tool->features & QStyleOptionToolButton::MenuButtonPopup;
3299 bool customDropDown = drawDropDown && hasStyleRule(obj: w, part: PseudoElement_ToolButtonMenu);
3300 bool customDropDownArrow = false;
3301 bool drawMenuIndicator = tool->features & QStyleOptionToolButton::HasMenu;
3302 if (customDropDown) {
3303 toolOpt.subControls &= ~QStyle::SC_ToolButtonMenu;
3304 customDropDownArrow = hasStyleRule(obj: w, part: PseudoElement_ToolButtonMenuArrow);
3305 if (customDropDownArrow)
3306 toolOpt.features &= ~(QStyleOptionToolButton::Menu | QStyleOptionToolButton::HasMenu);
3307 }
3308 const bool customMenuIndicator = (!drawDropDown && drawMenuIndicator)
3309 && hasStyleRule(obj: w, part: PseudoElement_ToolButtonMenuIndicator);
3310 if (customMenuIndicator)
3311 toolOpt.features &= ~QStyleOptionToolButton::HasMenu;
3312
3313 if (rule.hasNativeBorder()) {
3314 if (tool->subControls & SC_ToolButton) {
3315 //in some case (eg. the button is "auto raised") the style doesn't draw the background
3316 //so we need to draw the background.
3317 // use the same condition as in QCommonStyle
3318 State bflags = tool->state & ~State_Sunken;
3319 if (bflags & State_AutoRaise && (!(bflags & State_MouseOver) || !(bflags & State_Enabled)))
3320 bflags &= ~State_Raised;
3321 if (tool->state & State_Sunken && tool->activeSubControls & SC_ToolButton)
3322 bflags |= State_Sunken;
3323 if (!(bflags & (State_Sunken | State_On | State_Raised)))
3324 rule.drawBackground(p, rect: toolOpt.rect);
3325 }
3326
3327 QStyleOptionToolButton nativeToolOpt(toolOpt);
3328 // don't draw natively if we have a custom rule for menu indicators and/or buttons
3329 if (customMenuIndicator)
3330 nativeToolOpt.features &= ~(QStyleOptionToolButton::Menu | QStyleOptionToolButton::HasMenu);
3331 if (customDropDown || customDropDownArrow)
3332 nativeToolOpt.features &= ~(QStyleOptionToolButton::Menu | QStyleOptionToolButton::HasMenu | QStyleOptionToolButton::MenuButtonPopup);
3333 // Let base or windows style draw the button, which will include the menu-button
3334 if (rule.baseStyleCanDraw() && !(tool->features & QStyleOptionToolButton::Arrow))
3335 baseStyle()->drawComplexControl(cc, opt: &nativeToolOpt, p, widget: w);
3336 else
3337 QWindowsStyle::drawComplexControl(cc, opt: &nativeToolOpt, p, w);
3338 // if we did draw natively, don't draw custom
3339 if (nativeToolOpt.features & (QStyleOptionToolButton::Menu | QStyleOptionToolButton::HasMenu))
3340 drawMenuIndicator = false;
3341 if (nativeToolOpt.features & QStyleOptionToolButton::MenuButtonPopup && !customDropDownArrow)
3342 drawDropDown = false;
3343 } else {
3344 rule.drawRule(p, rect: opt->rect);
3345 toolOpt.rect = rule.contentsRect(r: opt->rect);
3346 if (rule.hasFont)
3347 toolOpt.font = rule.font.resolve(toolOpt.font);
3348 drawControl(element: CE_ToolButtonLabel, opt: &toolOpt, p, w);
3349 }
3350
3351 const QRect cr = toolOpt.rect;
3352 // Draw DropDownButton unless drawn before
3353 if (drawDropDown) {
3354 if (opt->subControls & QStyle::SC_ToolButtonMenu) {
3355 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolButtonMenu);
3356 QRect menuButtonRect = subControlRect(cc: CC_ToolButton, opt, sc: QStyle::SC_ToolButtonMenu, w);
3357 if (subRule.hasDrawable()) {
3358 subRule.drawRule(p, rect: menuButtonRect);
3359 } else {
3360 toolOpt.rect = menuButtonRect;
3361 baseStyle()->drawPrimitive(pe: PE_IndicatorButtonDropDown, opt: &toolOpt, p, w);
3362 }
3363
3364 if (customDropDownArrow || drawMenuIndicator) {
3365 QRenderRule arrowRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolButtonMenuArrow);
3366 QRect arrowRect = arrowRule.hasGeometry()
3367 ? positionRect(w, rule2: arrowRule, pe: PseudoElement_ToolButtonMenuArrow, originRect: menuButtonRect, dir: toolOpt.direction)
3368 : arrowRule.contentsRect(r: menuButtonRect);
3369 if (arrowRule.hasDrawable()) {
3370 arrowRule.drawRule(p, rect: arrowRect);
3371 } else {
3372 toolOpt.rect = arrowRect;
3373 baseStyle()->drawPrimitive(pe: QStyle::PE_IndicatorArrowDown, opt: &toolOpt, p, w);
3374 }
3375 }
3376 }
3377 } else if (drawMenuIndicator) {
3378 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolButtonMenuIndicator);
3379
3380 // content padding does not impact the indicator, so use the original rect to
3381 // calculate position of the sub element within the toplevel rule
3382 QRect r = positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_ToolButtonMenuIndicator, rect: opt->rect, dir: toolOpt.direction);
3383 if (subRule.hasDrawable()) {
3384 subRule.drawRule(p, rect: r);
3385 } else {
3386 toolOpt.rect = r;
3387 baseStyle()->drawPrimitive(pe: QStyle::PE_IndicatorArrowDown, opt: &toolOpt, p, w);
3388 }
3389 }
3390 toolOpt.rect = cr;
3391
3392 // If we don't have a custom arrow, then the arrow will have been rendered
3393 // already by the base style when drawing the label.
3394 if (customArrow) {
3395 const auto arrowElement = customArrowElement();
3396 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: arrowElement);
3397 QRect arrowRect = subRule.hasGeometry() ? positionRect(w, rule2: subRule, pe: arrowElement, originRect: toolOpt.rect, dir: toolOpt.direction)
3398 : subRule.contentsRect(r: toolOpt.rect);
3399
3400 switch (toolOpt.toolButtonStyle) {
3401 case Qt::ToolButtonIconOnly:
3402 break;
3403 case Qt::ToolButtonTextOnly:
3404 case Qt::ToolButtonTextBesideIcon:
3405 case Qt::ToolButtonTextUnderIcon: {
3406 // The base style needs to lay out the contents and will render the styled
3407 // arrow icons, unless the geometry is defined in the style sheet.
3408 toolOpt.text = tool->text;
3409 if (!subRule.hasGeometry())
3410 toolOpt.features |= QStyleOptionToolButton::Arrow;
3411 drawControl(element: CE_ToolButtonLabel, opt: &toolOpt, p, w);
3412 if (!subRule.hasGeometry())
3413 return;
3414 break;
3415 }
3416 case Qt::ToolButtonFollowStyle:
3417 // QToolButton handles this, so must never happen
3418 Q_ASSERT(false);
3419 break;
3420 }
3421 subRule.drawRule(p, rect: arrowRect);
3422 }
3423 return;
3424 }
3425 break;
3426
3427#if QT_CONFIG(scrollbar)
3428 case CC_ScrollBar:
3429 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3430 if (!rule.hasDrawable()) {
3431 QStyleOptionSlider sbOpt(*sb);
3432 sbOpt.rect = rule.borderRect(r: opt->rect);
3433 rule.drawBackgroundImage(p, rect: opt->rect);
3434 baseStyle()->drawComplexControl(cc, opt: &sbOpt, p, widget: w);
3435 } else {
3436 rule.drawRule(p, rect: opt->rect);
3437 QWindowsStyle::drawComplexControl(cc, opt, p, w);
3438 }
3439 return;
3440 }
3441 break;
3442#endif // QT_CONFIG(scrollbar)
3443
3444#if QT_CONFIG(slider)
3445 case CC_Slider:
3446 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3447 rule.drawRule(p, rect: opt->rect);
3448
3449 QRenderRule grooveSubRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SliderGroove);
3450 QRenderRule handleSubRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SliderHandle);
3451 if (!grooveSubRule.hasDrawable()) {
3452 QStyleOptionSlider slOpt(*slider);
3453 bool handleHasRule = handleSubRule.hasDrawable();
3454 // If the style specifies a different handler rule, draw the groove without the handler.
3455 if (handleHasRule)
3456 slOpt.subControls &= ~SC_SliderHandle;
3457 baseStyle()->drawComplexControl(cc, opt: &slOpt, p, widget: w);
3458 if (!handleHasRule)
3459 return;
3460 }
3461
3462 QRect gr = subControlRect(cc, opt, sc: SC_SliderGroove, w);
3463 if (slider->subControls & SC_SliderGroove) {
3464 grooveSubRule.drawRule(p, rect: gr);
3465 }
3466
3467 if (slider->subControls & SC_SliderHandle) {
3468 QRect hr = subControlRect(cc, opt, sc: SC_SliderHandle, w);
3469
3470 QRenderRule subRule1 = renderRule(obj: w, opt, pseudoElement: PseudoElement_SliderSubPage);
3471 if (subRule1.hasDrawable()) {
3472 QRect r(gr.topLeft(),
3473 slider->orientation == Qt::Horizontal
3474 ? QPoint(hr.x()+hr.width()/2, gr.y()+gr.height() - 1)
3475 : QPoint(gr.x()+gr.width() - 1, hr.y()+hr.height()/2));
3476 subRule1.drawRule(p, rect: r);
3477 }
3478
3479 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: PseudoElement_SliderAddPage);
3480 if (subRule2.hasDrawable()) {
3481 QRect r(slider->orientation == Qt::Horizontal
3482 ? QPoint(hr.x()+hr.width()/2+1, gr.y())
3483 : QPoint(gr.x(), hr.y()+hr.height()/2+1),
3484 gr.bottomRight());
3485 subRule2.drawRule(p, rect: r);
3486 }
3487
3488 handleSubRule.drawRule(p, rect: handleSubRule.boxRect(cr: hr, flags: Margin));
3489 }
3490
3491 if (slider->subControls & SC_SliderTickmarks) {
3492 // TODO...
3493 }
3494
3495 return;
3496 }
3497 break;
3498#endif // QT_CONFIG(slider)
3499
3500 case CC_MdiControls:
3501 if (hasStyleRule(obj: w, part: PseudoElement_MdiCloseButton)
3502 || hasStyleRule(obj: w, part: PseudoElement_MdiNormalButton)
3503 || hasStyleRule(obj: w, part: PseudoElement_MdiMinButton)) {
3504 QList<QVariant> layout = rule.styleHint(sh: "button-layout"_L1).toList();
3505 if (layout.isEmpty())
3506 layout = subControlLayout(layout: "mNX");
3507
3508 QStyleOptionComplex optCopy(*opt);
3509 optCopy.subControls = { };
3510 for (const QVariant &val : std::as_const(t&: layout)) {
3511 int layoutButton = val.toInt();
3512 if (layoutButton < PseudoElement_MdiCloseButton
3513 || layoutButton > PseudoElement_MdiNormalButton)
3514 continue;
3515 QStyle::SubControl control = knownPseudoElements[layoutButton].subControl;
3516 if (!(opt->subControls & control))
3517 continue;
3518 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: layoutButton);
3519 if (subRule.hasDrawable()) {
3520 QRect rect = subRule.boxRect(cr: subControlRect(cc: CC_MdiControls, opt, sc: control, w), flags: Margin);
3521 subRule.drawRule(p, rect);
3522 QIcon icon = standardIcon(standardIcon: subControlIcon(pe: layoutButton), opt);
3523 icon.paint(painter: p, rect: subRule.contentsRect(r: rect), alignment: Qt::AlignCenter);
3524 } else {
3525 optCopy.subControls |= control;
3526 }
3527 }
3528
3529 if (optCopy.subControls)
3530 baseStyle()->drawComplexControl(cc: CC_MdiControls, opt: &optCopy, p, widget: w);
3531 return;
3532 }
3533 break;
3534
3535 case CC_TitleBar:
3536 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
3537 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TitleBar);
3538 if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
3539 break;
3540 subRule.drawRule(p, rect: opt->rect);
3541 QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
3542 const auto paintDeviceDpr = p->device()->devicePixelRatio();
3543
3544 QRect ir;
3545 ir = layout[SC_TitleBarLabel];
3546 if (ir.isValid()) {
3547 if (subRule.hasPalette())
3548 p->setPen(subRule.palette()->foreground.color());
3549 p->fillRect(r: ir, c: Qt::white);
3550 p->drawText(x: ir.x(), y: ir.y(), w: ir.width(), h: ir.height(), flags: Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, str: tb->text);
3551 }
3552
3553 ir = layout[SC_TitleBarSysMenu];
3554 if (ir.isValid()) {
3555 QRenderRule subSubRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TitleBarSysMenu);
3556 subSubRule.drawRule(p, rect: ir);
3557 ir = subSubRule.contentsRect(r: ir);
3558 if (!tb->icon.isNull()) {
3559 tb->icon.paint(painter: p, rect: ir);
3560 } else {
3561 int iconSize = pixelMetric(metric: PM_SmallIconSize, option: tb, widget: w);
3562 const QSize sz(iconSize, iconSize);
3563 const auto pm = standardIcon(standardIcon: SP_TitleBarMenuButton, opt: nullptr, widget: w)
3564 .pixmap(size: sz, devicePixelRatio: paintDeviceDpr);
3565 drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3566 }
3567 }
3568
3569 ir = layout[SC_TitleBarCloseButton];
3570 if (ir.isValid()) {
3571 QRenderRule subSubRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TitleBarCloseButton);
3572 subSubRule.drawRule(p, rect: ir);
3573
3574 const QSize sz = subSubRule.contentsRect(r: ir).size();
3575 const auto type = ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool)
3576 ? SP_DockWidgetCloseButton : SP_TitleBarCloseButton;
3577 const auto pm = standardIcon(standardIcon: type, opt: nullptr, widget: w).pixmap(size: sz, devicePixelRatio: paintDeviceDpr);
3578 drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3579 }
3580
3581 constexpr std::array<int, 6> pes = {
3582 PseudoElement_TitleBarMaxButton,
3583 PseudoElement_TitleBarMinButton,
3584 PseudoElement_TitleBarNormalButton,
3585 PseudoElement_TitleBarShadeButton,
3586 PseudoElement_TitleBarUnshadeButton,
3587 PseudoElement_TitleBarContextHelpButton
3588 };
3589
3590 for (int pe : pes) {
3591 QStyle::SubControl sc = knownPseudoElements[pe].subControl;
3592 ir = layout[sc];
3593 if (!ir.isValid())
3594 continue;
3595 QRenderRule subSubRule = renderRule(obj: w, opt, pseudoElement: pe);
3596 subSubRule.drawRule(p, rect: ir);
3597 const QSize sz = subSubRule.contentsRect(r: ir).size();
3598 const auto pm = standardIcon(standardIcon: subControlIcon(pe), opt: nullptr, widget: w).pixmap(size: sz, devicePixelRatio: paintDeviceDpr);
3599 drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3600 }
3601
3602 return;
3603 }
3604 break;
3605
3606
3607 default:
3608 break;
3609 }
3610
3611 baseStyle()->drawComplexControl(cc, opt, p, widget: w);
3612}
3613
3614void QStyleSheetStyle::renderMenuItemIcon(const QStyleOptionMenuItem *mi, QPainter *p, const QWidget *w,
3615 const QRect &rect, QRenderRule &subRule) const
3616{
3617 const QIcon::Mode mode = mi->state & QStyle::State_Enabled
3618 ? (mi->state & QStyle::State_Selected ? QIcon::Active : QIcon::Normal)
3619 : QIcon::Disabled;
3620 const bool checked = mi->checkType != QStyleOptionMenuItem::NotCheckable && mi->checked;
3621 const auto iconSize = pixelMetric(metric: PM_SmallIconSize, option: mi, widget: w);
3622 const QSize sz(iconSize, iconSize);
3623 const QPixmap pixmap(mi->icon.pixmap(size: sz, devicePixelRatio: p->device()->devicePixelRatio(), mode,
3624 state: checked ? QIcon::On : QIcon::Off));
3625 const int pixw = pixmap.width() / pixmap.devicePixelRatio();
3626 const int pixh = pixmap.height() / pixmap.devicePixelRatio();
3627 QRenderRule iconRule = renderRule(obj: w, opt: mi, pseudoElement: PseudoElement_MenuIcon);
3628 if (!iconRule.hasGeometry()) {
3629 iconRule.geo = new QStyleSheetGeometryData(pixw, pixh, pixw, pixh, -1, -1);
3630 } else {
3631 iconRule.geo->width = pixw;
3632 iconRule.geo->height = pixh;
3633 }
3634 QRect iconRect = positionRect(w, rule1: subRule, rule2: iconRule, pe: PseudoElement_MenuIcon, rect, dir: mi->direction);
3635 if (mi->direction == Qt::LeftToRight)
3636 iconRect.moveLeft(pos: iconRect.left());
3637 else
3638 iconRect.moveRight(pos: iconRect.right());
3639 iconRule.drawRule(p, rect: iconRect);
3640 QRect pmr(0, 0, pixw, pixh);
3641 pmr.moveCenter(p: iconRect.center());
3642 p->drawPixmap(p: pmr.topLeft(), pm: pixmap);
3643}
3644
3645void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3646 const QWidget *w) const
3647{
3648 RECURSION_GUARD(baseStyle()->drawControl(ce, opt, p, w); return)
3649
3650 QRenderRule rule = renderRule(obj: w, opt);
3651 int pe1 = PseudoElement_None, pe2 = PseudoElement_None;
3652 bool fallback = false;
3653
3654 switch (ce) {
3655 case CE_ToolButtonLabel:
3656 if (const QStyleOptionToolButton *btn = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3657 if (rule.hasBox() || btn->features & QStyleOptionToolButton::Arrow) {
3658 QWindowsStyle::drawControl(element: ce, opt, p, w);
3659 } else {
3660 QStyleOptionToolButton butOpt(*btn);
3661 rule.configurePalette(p: &butOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3662 baseStyle()->drawControl(element: ce, opt: &butOpt, p, w);
3663 }
3664 return;
3665 }
3666 break;
3667
3668 case CE_FocusFrame:
3669 if (!rule.hasNativeBorder()) {
3670 rule.drawBorder(p, rect: opt->rect);
3671 return;
3672 }
3673 break;
3674
3675 case CE_PushButton:
3676 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3677 if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() ||
3678 ((btn->features & QStyleOptionButton::HasMenu) && hasStyleRule(obj: w, part: PseudoElement_PushButtonMenuIndicator))) {
3679 ParentStyle::drawControl(element: ce, opt, p, w);
3680 return;
3681 }
3682 }
3683 break;
3684 case CE_PushButtonBevel:
3685 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3686 QStyleOptionButton btnOpt(*btn);
3687 btnOpt.rect = rule.borderRect(r: opt->rect);
3688 if (rule.hasNativeBorder()) {
3689 rule.drawBackgroundImage(p, rect: btnOpt.rect);
3690 rule.configurePalette(p: &btnOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3691 bool customMenu = (btn->features & QStyleOptionButton::HasMenu
3692 && hasStyleRule(obj: w, part: PseudoElement_PushButtonMenuIndicator));
3693 if (customMenu)
3694 btnOpt.features &= ~QStyleOptionButton::HasMenu;
3695 if (rule.baseStyleCanDraw()) {
3696 baseStyle()->drawControl(element: ce, opt: &btnOpt, p, w);
3697 } else {
3698 QWindowsStyle::drawControl(element: ce, opt: &btnOpt, p, w);
3699 }
3700 rule.drawImage(p, rect: rule.contentsRect(r: opt->rect));
3701 if (!customMenu)
3702 return;
3703 } else {
3704 rule.drawRule(p, rect: opt->rect);
3705 }
3706
3707 if (btn->features & QStyleOptionButton::HasMenu) {
3708 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_PushButtonMenuIndicator);
3709 QRect ir = positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_PushButtonMenuIndicator,
3710 rect: baseStyle()->subElementRect(subElement: SE_PushButtonBevel, option: btn, widget: w), dir: opt->direction);
3711 if (subRule.hasDrawable()) {
3712 subRule.drawRule(p, rect: ir);
3713 } else {
3714 btnOpt.rect = ir;
3715 baseStyle()->drawPrimitive(pe: PE_IndicatorArrowDown, opt: &btnOpt, p, w);
3716 }
3717 }
3718 }
3719 return;
3720
3721 case CE_PushButtonLabel:
3722 if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3723 QStyleOptionButton butOpt(*button);
3724 rule.configurePalette(p: &butOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3725
3726 const QFont oldFont = p->font();
3727 if (rule.hasFont)
3728 p->setFont(rule.font.resolve(p->font()));
3729
3730 if (rule.hasPosition() || rule.hasIcon()) {
3731 uint tf = Qt::TextShowMnemonic;
3732 QRect textRect = button->rect;
3733
3734 const uint horizontalAlignMask = Qt::AlignHCenter | Qt::AlignLeft | Qt::AlignRight;
3735 const uint verticalAlignMask = Qt::AlignVCenter | Qt::AlignTop | Qt::AlignBottom;
3736
3737 if (rule.hasPosition() && rule.position()->textAlignment != 0) {
3738 Qt::Alignment textAlignment = rule.position()->textAlignment;
3739 tf |= (textAlignment & verticalAlignMask) ? (textAlignment & verticalAlignMask) : Qt::AlignVCenter;
3740 tf |= (textAlignment & horizontalAlignMask) ? (textAlignment & horizontalAlignMask) : Qt::AlignHCenter;
3741 if (!styleHint(sh: SH_UnderlineShortcut, opt: button, w))
3742 tf |= Qt::TextHideMnemonic;
3743 } else {
3744 tf |= Qt::AlignVCenter | Qt::AlignHCenter;
3745 }
3746
3747 QIcon icon = rule.hasIcon() ? rule.icon()->icon : button->icon;
3748 if (!icon.isNull()) {
3749 //Group both icon and text
3750 QRect iconRect;
3751 QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3752 if (mode == QIcon::Normal && button->state & State_HasFocus)
3753 mode = QIcon::Active;
3754 QIcon::State state = QIcon::Off;
3755 if (button->state & State_On)
3756 state = QIcon::On;
3757
3758 const auto paintDeviceDpr = p->device()->devicePixelRatio();
3759 QPixmap pixmap = icon.pixmap(size: button->iconSize, devicePixelRatio: paintDeviceDpr, mode, state);
3760 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3761 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3762 int labelWidth = pixmapWidth;
3763 int labelHeight = pixmapHeight;
3764 int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
3765 int textWidth = button->fontMetrics.boundingRect(r: opt->rect, flags: tf, text: button->text).width();
3766 if (!button->text.isEmpty())
3767 labelWidth += (textWidth + iconSpacing);
3768
3769 //Determine label alignment:
3770 if (tf & Qt::AlignLeft) { /*left*/
3771 iconRect = QRect(textRect.x(), textRect.y() + (textRect.height() - labelHeight) / 2,
3772 pixmapWidth, pixmapHeight);
3773 } else if (tf & Qt::AlignHCenter) { /* center */
3774 iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
3775 textRect.y() + (textRect.height() - labelHeight) / 2,
3776 pixmapWidth, pixmapHeight);
3777 } else { /*right*/
3778 iconRect = QRect(textRect.x() + textRect.width() - labelWidth,
3779 textRect.y() + (textRect.height() - labelHeight) / 2,
3780 pixmapWidth, pixmapHeight);
3781 }
3782
3783 iconRect = visualRect(direction: button->direction, boundingRect: textRect, logicalRect: iconRect);
3784
3785 // Left align, adjust the text-rect according to the icon instead
3786 tf &= ~horizontalAlignMask;
3787 tf |= Qt::AlignLeft;
3788
3789 if (button->direction == Qt::RightToLeft)
3790 textRect.setRight(iconRect.left() - iconSpacing);
3791 else
3792 textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing);
3793
3794 if (button->state & (State_On | State_Sunken))
3795 iconRect.translate(dx: pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget: w),
3796 dy: pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget: w));
3797 p->drawPixmap(r: iconRect, pm: pixmap);
3798 }
3799
3800 if (button->state & (State_On | State_Sunken))
3801 textRect.translate(dx: pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget: w),
3802 dy: pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget: w));
3803
3804 if (button->features & QStyleOptionButton::HasMenu) {
3805 int indicatorSize = pixelMetric(metric: PM_MenuButtonIndicator, option: button, widget: w);
3806 if (button->direction == Qt::LeftToRight)
3807 textRect = textRect.adjusted(xp1: 0, yp1: 0, xp2: -indicatorSize, yp2: 0);
3808 else
3809 textRect = textRect.adjusted(xp1: indicatorSize, yp1: 0, xp2: 0, yp2: 0);
3810 }
3811 drawItemText(painter: p, rect: textRect, alignment: tf, pal: butOpt.palette, enabled: (button->state & State_Enabled),
3812 text: button->text, textRole: QPalette::ButtonText);
3813 } else {
3814 ParentStyle::drawControl(element: ce, opt: &butOpt, p, w);
3815 }
3816
3817 if (rule.hasFont)
3818 p->setFont(oldFont);
3819 }
3820 return;
3821
3822 case CE_RadioButton:
3823 case CE_CheckBox:
3824 if (rule.hasBox() || !rule.hasNativeBorder() || rule.hasDrawable() || hasStyleRule(obj: w, part: PseudoElement_Indicator)) {
3825 rule.drawRule(p, rect: opt->rect);
3826 ParentStyle::drawControl(element: ce, opt, p, w);
3827 return;
3828 } else if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3829 QStyleOptionButton butOpt(*btn);
3830 rule.configurePalette(p: &butOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3831 baseStyle()->drawControl(element: ce, opt: &butOpt, p, w);
3832 return;
3833 }
3834 break;
3835 case CE_RadioButtonLabel:
3836 case CE_CheckBoxLabel:
3837 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3838 QStyleOptionButton butOpt(*btn);
3839 rule.configurePalette(p: &butOpt.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3840 ParentStyle::drawControl(element: ce, opt: &butOpt, p, w);
3841 }
3842 return;
3843
3844 case CE_Splitter:
3845 pe1 = PseudoElement_SplitterHandle;
3846 break;
3847
3848 case CE_ToolBar:
3849 if (rule.hasBackground()) {
3850 rule.drawBackground(p, rect: opt->rect);
3851 }
3852 if (rule.hasBorder()) {
3853 rule.drawBorder(p, rect: rule.borderRect(r: opt->rect));
3854 } else {
3855#if QT_CONFIG(toolbar)
3856 if (const QStyleOptionToolBar *tb = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
3857 QStyleOptionToolBar newTb(*tb);
3858 newTb.rect = rule.borderRect(r: opt->rect);
3859 baseStyle()->drawControl(element: ce, opt: &newTb, p, w);
3860 }
3861#endif // QT_CONFIG(toolbar)
3862 }
3863 return;
3864
3865 case CE_MenuEmptyArea:
3866 case CE_MenuBarEmptyArea:
3867 if (rule.hasDrawable()) {
3868 // Drawn by PE_Widget
3869 return;
3870 }
3871 break;
3872
3873 case CE_MenuTearoff:
3874 case CE_MenuScroller:
3875 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3876 QStyleOptionMenuItem mi(*m);
3877 int pe = ce == CE_MenuTearoff ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
3878 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pe);
3879 mi.rect = subRule.contentsRect(r: opt->rect);
3880 rule.configurePalette(p: &mi.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3881 subRule.configurePalette(p: &mi.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3882
3883 if (subRule.hasDrawable()) {
3884 subRule.drawRule(p, rect: opt->rect);
3885 } else {
3886 baseStyle()->drawControl(element: ce, opt: &mi, p, w);
3887 }
3888 }
3889 return;
3890
3891 case CE_MenuItem:
3892 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3893 QStyleOptionMenuItem mi(*m);
3894
3895 int pseudo = (mi.menuItemType == QStyleOptionMenuItem::Separator) ? PseudoElement_MenuSeparator : PseudoElement_Item;
3896 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pseudo);
3897 mi.rect = subRule.contentsRect(r: opt->rect);
3898 rule.configurePalette(p: &mi.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3899 rule.configurePalette(p: &mi.palette, fr: QPalette::HighlightedText, br: QPalette::Highlight);
3900 subRule.configurePalette(p: &mi.palette, fr: QPalette::ButtonText, br: QPalette::Button);
3901 subRule.configurePalette(p: &mi.palette, fr: QPalette::HighlightedText, br: QPalette::Highlight);
3902 QFont oldFont = p->font();
3903 if (subRule.hasFont)
3904 p->setFont(subRule.font.resolve(mi.font));
3905 else
3906 p->setFont(mi.font);
3907
3908 // We fall back to drawing with the style sheet code whenever at least one of the
3909 // items are styled in an incompatible way, such as having a background image.
3910 QRenderRule allRules = renderRule(obj: w, element: PseudoElement_Item, state: PseudoClass_Any);
3911
3912 if ((pseudo == PseudoElement_MenuSeparator) && subRule.hasDrawable()) {
3913 subRule.drawRule(p, rect: opt->rect);
3914 } else if ((pseudo == PseudoElement_Item)
3915 && (allRules.hasBox() || allRules.hasBorder() || subRule.hasFont
3916 || (allRules.background() && !allRules.background()->pixmap.isNull()))) {
3917 subRule.drawRule(p, rect: opt->rect);
3918 if (subRule.hasBackground()) {
3919 mi.palette.setBrush(acr: QPalette::Highlight, abrush: Qt::NoBrush);
3920 mi.palette.setBrush(acr: QPalette::Button, abrush: Qt::NoBrush);
3921 } else {
3922 mi.palette.setBrush(acr: QPalette::Highlight, abrush: mi.palette.brush(cr: QPalette::Button));
3923 }
3924 mi.palette.setBrush(acr: QPalette::HighlightedText, abrush: mi.palette.brush(cr: QPalette::ButtonText));
3925
3926 bool drawCheckMark = mi.menuHasCheckableItems;
3927#if QT_CONFIG(combobox)
3928 if (qobject_cast<const QComboBox *>(object: w))
3929 drawCheckMark = false; // ignore the checkmarks provided by the QComboMenuDelegate
3930#endif
3931 int textRectOffset = m->maxIconWidth;
3932 if (!mi.icon.isNull()) {
3933 renderMenuItemIcon(mi: &mi, p, w, rect: opt->rect, subRule);
3934 } else if (drawCheckMark) {
3935 const bool checkable = mi.checkType != QStyleOptionMenuItem::NotCheckable;
3936 const bool checked = checkable ? mi.checked : false;
3937
3938 const QRenderRule subSubRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_MenuCheckMark);
3939 const QRect cmRect = positionRect(w, rule1: subRule, rule2: subSubRule, pe: PseudoElement_MenuCheckMark, rect: opt->rect, dir: opt->direction);
3940 if (checkable && (subSubRule.hasDrawable() || checked)) {
3941 QStyleOptionMenuItem newMi = mi;
3942 if (opt->state & QStyle::State_Enabled)
3943 newMi.state |= State_Enabled;
3944 if (mi.checked)
3945 newMi.state |= State_On;
3946 newMi.rect = cmRect;
3947 drawPrimitive(pe: PE_IndicatorMenuCheckMark, opt: &newMi, p, w);
3948 }
3949 textRectOffset = std::max(a: m->maxIconWidth, b: cmRect.width());
3950 }
3951
3952 QRect textRect = subRule.contentsRect(r: opt->rect);
3953 textRect.setLeft(textRect.left() + textRectOffset);
3954 textRect.setWidth(textRect.width() - mi.reservedShortcutWidth);
3955 const QRect vTextRect = visualRect(direction: opt->direction, boundingRect: m->rect, logicalRect: textRect);
3956
3957 QStringView s(mi.text);
3958 p->setPen(mi.palette.buttonText().color());
3959 if (!s.isEmpty()) {
3960 int text_flags = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
3961 if (!styleHint(sh: SH_UnderlineShortcut, opt: &mi, w))
3962 text_flags |= Qt::TextHideMnemonic;
3963 qsizetype t = s.indexOf(c: u'\t');
3964 if (t >= 0) {
3965 QRect vShortcutRect = visualRect(direction: opt->direction, boundingRect: mi.rect,
3966 logicalRect: QRect(textRect.topRight(), QPoint(mi.rect.right(), textRect.bottom())));
3967 p->drawText(r: vShortcutRect, flags: text_flags, text: s.mid(pos: t + 1).toString());
3968 s = s.left(n: t);
3969 }
3970 p->drawText(r: vTextRect, flags: text_flags, text: s.left(n: t).toString());
3971 }
3972
3973 if (mi.menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
3974 PrimitiveElement arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
3975 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: PseudoElement_MenuRightArrow);
3976 mi.rect = positionRect(w, rule1: subRule, rule2: subRule2, pe: PseudoElement_MenuRightArrow, rect: opt->rect, dir: mi.direction);
3977 drawPrimitive(pe: arrow, opt: &mi, p, w);
3978 }
3979 } else if (!mi.icon.isNull() && hasStyleRule(obj: w, part: PseudoElement_MenuIcon)) {
3980 // we wouldn't be here if the item itself would be styled, so now we only want
3981 // the text from the default style, and then draw the icon ourselves.
3982 QStyleOptionMenuItem newMi = mi;
3983 newMi.icon = {};
3984 newMi.checkType = QStyleOptionMenuItem::NotCheckable;
3985 if (rule.baseStyleCanDraw() && subRule.baseStyleCanDraw())
3986 baseStyle()->drawControl(element: ce, opt: &newMi, p, w);
3987 else
3988 ParentStyle::drawControl(element: ce, opt: &newMi, p, w);
3989 renderMenuItemIcon(mi: &mi, p, w, rect: opt->rect, subRule);
3990 } else if (hasStyleRule(obj: w, part: PseudoElement_MenuCheckMark) || hasStyleRule(obj: w, part: PseudoElement_MenuRightArrow)) {
3991 QWindowsStyle::drawControl(element: ce, opt: &mi, p, w);
3992 if (mi.checkType != QStyleOptionMenuItem::NotCheckable && !mi.checked) {
3993 // We have a style defined, but QWindowsStyle won't draw anything if not checked.
3994 // So we mimic what QWindowsStyle would do.
3995 int checkcol = qMax<int>(a: mi.maxIconWidth, b: QWindowsStylePrivate::windowsCheckMarkWidth);
3996 QRect vCheckRect = visualRect(direction: opt->direction, boundingRect: mi.rect, logicalRect: QRect(mi.rect.x(), mi.rect.y(), checkcol, mi.rect.height()));
3997 if (mi.state.testFlag(flag: State_Enabled) && mi.state.testFlag(flag: State_Selected)) {
3998 qDrawShadePanel(p, r: vCheckRect, pal: mi.palette, sunken: true, lineWidth: 1, fill: &mi.palette.brush(cr: QPalette::Button));
3999 } else {
4000 QBrush fill(mi.palette.light().color(), Qt::Dense4Pattern);
4001 qDrawShadePanel(p, r: vCheckRect, pal: mi.palette, sunken: true, lineWidth: 1, fill: &fill);
4002 }
4003 QRenderRule subSubRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_MenuCheckMark);
4004 if (subSubRule.hasDrawable()) {
4005 QStyleOptionMenuItem newMi(mi);
4006 newMi.rect = visualRect(direction: opt->direction, boundingRect: mi.rect, logicalRect: QRect(mi.rect.x() + QWindowsStylePrivate::windowsItemFrame,
4007 mi.rect.y() + QWindowsStylePrivate::windowsItemFrame,
4008 checkcol - 2 * QWindowsStylePrivate::windowsItemFrame,
4009 mi.rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame));
4010 drawPrimitive(pe: PE_IndicatorMenuCheckMark, opt: &newMi, p, w);
4011 }
4012 }
4013 } else {
4014 if (rule.hasDrawable() && !subRule.hasDrawable() && !(opt->state & QStyle::State_Selected)) {
4015 mi.palette.setColor(acr: QPalette::Window, acolor: Qt::transparent);
4016 mi.palette.setColor(acr: QPalette::Button, acolor: Qt::transparent);
4017 }
4018 if (rule.baseStyleCanDraw() && subRule.baseStyleCanDraw()) {
4019 baseStyle()->drawControl(element: ce, opt: &mi, p, w);
4020 } else {
4021 ParentStyle::drawControl(element: ce, opt: &mi, p, w);
4022 }
4023 }
4024
4025 p->setFont(oldFont);
4026
4027 return;
4028 }
4029 return;
4030
4031 case CE_MenuBarItem:
4032 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4033 QStyleOptionMenuItem mi(*m);
4034 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_Item);
4035 mi.rect = subRule.contentsRect(r: opt->rect);
4036 rule.configurePalette(p: &mi.palette, fr: QPalette::ButtonText, br: QPalette::Button);
4037 subRule.configurePalette(p: &mi.palette, fr: QPalette::ButtonText, br: QPalette::Button);
4038
4039 if (subRule.hasDrawable()) {
4040 subRule.drawRule(p, rect: opt->rect);
4041 QCommonStyle::drawControl(element: ce, opt: &mi, p, w); // deliberate bypass of the base
4042 } else {
4043 if (rule.hasDrawable() && !(opt->state & QStyle::State_Selected)) {
4044 // So that the menu bar background is not hidden by the items
4045 mi.palette.setColor(acr: QPalette::Window, acolor: Qt::transparent);
4046 mi.palette.setColor(acr: QPalette::Button, acolor: Qt::transparent);
4047 }
4048 baseStyle()->drawControl(element: ce, opt: &mi, p, w);
4049 }
4050 }
4051 return;
4052
4053#if QT_CONFIG(combobox)
4054 case CE_ComboBoxLabel:
4055 if (!rule.hasBox())
4056 break;
4057 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4058 QRect editRect = subControlRect(cc: CC_ComboBox, opt: cb, sc: SC_ComboBoxEditField, w);
4059 p->save();
4060 p->setClipRect(editRect);
4061 if (!cb->currentIcon.isNull()) {
4062 int spacing = rule.hasBox() ? rule.box()->spacing : -1;
4063 if (spacing == -1)
4064 spacing = 6;
4065 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
4066 const auto paintDeviceDpr = p->device()->devicePixelRatio();
4067 QPixmap pixmap = cb->currentIcon.pixmap(size: cb->iconSize, devicePixelRatio: paintDeviceDpr, mode);
4068 QRect iconRect(editRect);
4069 iconRect.setWidth(cb->iconSize.width());
4070 iconRect = alignedRect(direction: cb->direction,
4071 alignment: Qt::AlignLeft | Qt::AlignVCenter,
4072 size: iconRect.size(), rectangle: editRect);
4073 drawItemPixmap(painter: p, rect: iconRect, alignment: Qt::AlignCenter, pixmap);
4074
4075 if (cb->direction == Qt::RightToLeft)
4076 editRect.translate(dx: -spacing - cb->iconSize.width(), dy: 0);
4077 else
4078 editRect.translate(dx: cb->iconSize.width() + spacing, dy: 0);
4079 }
4080 if (!cb->currentText.isEmpty() && !cb->editable) {
4081 QPalette styledPalette(cb->palette);
4082 rule.configurePalette(p: &styledPalette, fr: QPalette::Text, br: QPalette::Base);
4083 drawItemText(painter: p, rect: editRect.adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: 0), alignment: cb->textAlignment, pal: styledPalette,
4084 enabled: cb->state & State_Enabled, text: cb->currentText, textRole: QPalette::Text);
4085 }
4086 p->restore();
4087 return;
4088 }
4089 break;
4090#endif // QT_CONFIG(combobox)
4091
4092 case CE_Header:
4093 if (hasStyleRule(obj: w, part: PseudoElement_HeaderViewUpArrow)
4094 || hasStyleRule(obj: w, part: PseudoElement_HeaderViewDownArrow)) {
4095 ParentStyle::drawControl(element: ce, opt, p, w);
4096 return;
4097 }
4098 if (hasStyleRule(obj: w, part: PseudoElement_HeaderViewSection)) {
4099 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_HeaderViewSection);
4100 if (!subRule.hasNativeBorder() || !subRule.baseStyleCanDraw()
4101 || subRule.hasBackground() || subRule.hasPalette() || subRule.hasFont || subRule.hasBorder()) {
4102 ParentStyle::drawControl(element: ce, opt, p, w);
4103 return;
4104 }
4105 }
4106 break;
4107 case CE_HeaderSection:
4108 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4109 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_HeaderViewSection);
4110 if (subRule.hasNativeBorder()) {
4111 QStyleOptionHeader hdr(*header);
4112 subRule.configurePalette(p: &hdr.palette, fr: QPalette::ButtonText, br: QPalette::Button);
4113
4114 if (subRule.baseStyleCanDraw()) {
4115 baseStyle()->drawControl(element: CE_HeaderSection, opt: &hdr, p, w);
4116 } else {
4117 QWindowsStyle::drawControl(element: CE_HeaderSection, opt: &hdr, p, w);
4118 }
4119 } else {
4120 subRule.drawRule(p, rect: opt->rect);
4121 }
4122 return;
4123 }
4124 break;
4125
4126 case CE_HeaderLabel:
4127 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4128 QStyleOptionHeaderV2 hdr;
4129 QStyleOptionHeader &v1Copy = hdr;
4130 if (auto v2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(opt))
4131 hdr = *v2;
4132 else
4133 v1Copy = *header;
4134 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_HeaderViewSection);
4135 if (hasStyleRule(obj: w, part: PseudoElement_HeaderViewUpArrow)
4136 || hasStyleRule(obj: w, part: PseudoElement_HeaderViewDownArrow)) {
4137 if (hdr.sortIndicator != QStyleOptionHeader::None) {
4138 const QRect arrowRect = subElementRect(r: SE_HeaderArrow, opt, widget: w);
4139 if (hdr.orientation == Qt::Horizontal)
4140 hdr.rect.setWidth(hdr.rect.width() - arrowRect.width());
4141 else
4142 hdr.rect.setHeight(hdr.rect.height() - arrowRect.height());
4143 }
4144 }
4145 subRule.configurePalette(p: &hdr.palette, fr: QPalette::ButtonText, br: QPalette::Button);
4146 if (subRule.hasFont) {
4147 QFont oldFont = p->font();
4148 p->setFont(subRule.font.resolve(p->font()));
4149 ParentStyle::drawControl(element: ce, opt: &hdr, p, w);
4150 p->setFont(oldFont);
4151 } else {
4152 baseStyle()->drawControl(element: ce, opt: &hdr, p, w);
4153 }
4154 return;
4155 }
4156 break;
4157
4158 case CE_HeaderEmptyArea:
4159 if (rule.hasDrawable()) {
4160 return;
4161 }
4162 break;
4163
4164 case CE_ProgressBar:
4165 QWindowsStyle::drawControl(element: ce, opt, p, w);
4166 return;
4167
4168 case CE_ProgressBarGroove:
4169 if (!rule.hasNativeBorder()) {
4170 rule.drawRule(p, rect: rule.boxRect(cr: opt->rect, flags: Margin));
4171 return;
4172 }
4173 break;
4174
4175 case CE_ProgressBarContents: {
4176 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ProgressBarChunk);
4177 if (subRule.hasDrawable()) {
4178 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4179 p->save();
4180 p->setClipRect(pb->rect);
4181
4182 qint64 minimum = qint64(pb->minimum);
4183 qint64 maximum = qint64(pb->maximum);
4184 qint64 progress = qint64(pb->progress);
4185 bool vertical = !(pb->state & QStyle::State_Horizontal);
4186 bool inverted = pb->invertedAppearance;
4187
4188 QTransform m;
4189 QRect rect = pb->rect;
4190 if (vertical) {
4191 rect = QRect(rect.y(), rect.x(), rect.height(), rect.width());
4192 m.rotate(a: 90);
4193 m.translate(dx: 0, dy: -(rect.height() + rect.y()*2));
4194 }
4195
4196 bool reverse = ((!vertical && (pb->direction == Qt::RightToLeft)) || vertical);
4197 if (inverted)
4198 reverse = !reverse;
4199 const bool indeterminate = pb->minimum == pb->maximum;
4200 const auto fillRatio = indeterminate ? 0.50 : double(progress - minimum) / (maximum - minimum);
4201 const auto fillWidth = static_cast<int>(rect.width() * fillRatio);
4202 int chunkWidth = fillWidth;
4203 if (subRule.hasContentsSize()) {
4204 QSize sz = subRule.size();
4205 chunkWidth = (opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
4206 }
4207
4208 QRect r = rect;
4209#if QT_CONFIG(animation)
4210 Q_D(const QWindowsStyle);
4211#endif
4212 if (pb->minimum == 0 && pb->maximum == 0) {
4213 int chunkCount = fillWidth/chunkWidth;
4214 int offset = 0;
4215#if QT_CONFIG(animation)
4216 if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(object: d->animation(target: opt->styleObject)))
4217 offset = animation->animationStep() * 8 % rect.width();
4218 else
4219 d->startAnimation(animation: new QProgressStyleAnimation(d->animationFps, opt->styleObject));
4220#endif
4221 int x = reverse ? r.left() + r.width() - offset - chunkWidth : r.x() + offset;
4222 while (chunkCount > 0) {
4223 r.setRect(ax: x, ay: rect.y(), aw: chunkWidth, ah: rect.height());
4224 r = m.mapRect(QRectF(r)).toRect();
4225 subRule.drawRule(p, rect: r);
4226 x += reverse ? -chunkWidth : chunkWidth;
4227 if (reverse ? x < rect.left() : x > rect.right())
4228 break;
4229 --chunkCount;
4230 }
4231
4232 r = rect;
4233 x = reverse ? r.right() - (r.left() - x - chunkWidth)
4234 : r.left() + (x - r.right() - chunkWidth);
4235 while (chunkCount > 0) {
4236 r.setRect(ax: x, ay: rect.y(), aw: chunkWidth, ah: rect.height());
4237 r = m.mapRect(QRectF(r)).toRect();
4238 subRule.drawRule(p, rect: r);
4239 x += reverse ? -chunkWidth : chunkWidth;
4240 --chunkCount;
4241 };
4242 } else if (chunkWidth > 0) {
4243 const auto ceil = [](qreal x) { return int(x) + (x > 0 && x != int(x)); };
4244 const int chunkCount = ceil(qreal(fillWidth)/chunkWidth);
4245 int x = reverse ? r.left() + r.width() - chunkWidth : r.x();
4246
4247 for (int i = 0; i < chunkCount; ++i) {
4248 r.setRect(ax: x, ay: rect.y(), aw: chunkWidth, ah: rect.height());
4249 r = m.mapRect(QRectF(r)).toRect();
4250 subRule.drawRule(p, rect: r);
4251 x += reverse ? -chunkWidth : chunkWidth;
4252 }
4253#if QT_CONFIG(animation)
4254 d->stopAnimation(target: opt->styleObject);
4255#endif
4256 }
4257
4258 p->restore();
4259 return;
4260 }
4261 }
4262 }
4263 break;
4264
4265 case CE_ProgressBarLabel:
4266 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4267 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(obj: w, part: PseudoElement_ProgressBarChunk)) {
4268 drawItemText(painter: p, rect: pb->rect, alignment: pb->textAlignment | Qt::TextSingleLine, pal: pb->palette,
4269 enabled: pb->state & State_Enabled, text: pb->text, textRole: QPalette::Text);
4270 } else {
4271 QStyleOptionProgressBar pbCopy(*pb);
4272 rule.configurePalette(p: &pbCopy.palette, fr: QPalette::HighlightedText, br: QPalette::Highlight);
4273 baseStyle()->drawControl(element: ce, opt: &pbCopy, p, w);
4274 }
4275 return;
4276 }
4277 break;
4278
4279 case CE_SizeGrip:
4280 if (const QStyleOptionSizeGrip *sgOpt = qstyleoption_cast<const QStyleOptionSizeGrip *>(opt)) {
4281 if (rule.hasDrawable()) {
4282 rule.drawFrame(p, rect: opt->rect);
4283 p->save();
4284 static constexpr int rotation[] = { 180, 270, 90, 0 };
4285 if (rotation[sgOpt->corner]) {
4286 p->translate(offset: opt->rect.center());
4287 p->rotate(a: rotation[sgOpt->corner]);
4288 p->translate(offset: -opt->rect.center());
4289 }
4290 rule.drawImage(p, rect: opt->rect);
4291 p->restore();
4292 } else {
4293 QStyleOptionSizeGrip sg(*sgOpt);
4294 sg.rect = rule.contentsRect(r: opt->rect);
4295 baseStyle()->drawControl(element: CE_SizeGrip, opt: &sg, p, w);
4296 }
4297 return;
4298 }
4299 break;
4300
4301 case CE_ToolBoxTab:
4302 QWindowsStyle::drawControl(element: ce, opt, p, w);
4303 return;
4304
4305 case CE_ToolBoxTabShape: {
4306 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolBoxTab);
4307 if (subRule.hasDrawable()) {
4308 subRule.drawRule(p, rect: opt->rect);
4309 return;
4310 }
4311 }
4312 break;
4313
4314 case CE_ToolBoxTabLabel:
4315 if (const QStyleOptionToolBox *box = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
4316 QStyleOptionToolBox boxCopy(*box);
4317 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolBoxTab);
4318 subRule.configurePalette(p: &boxCopy.palette, fr: QPalette::ButtonText, br: QPalette::Button);
4319 QFont oldFont = p->font();
4320 if (subRule.hasFont)
4321 p->setFont(subRule.font.resolve(p->font()));
4322 boxCopy.rect = subRule.contentsRect(r: opt->rect);
4323 if (subRule.hasImage()) {
4324 // the image is already drawn with CE_ToolBoxTabShape, adjust rect here
4325 const int iconExtent = proxy()->pixelMetric(metric: QStyle::PM_SmallIconSize, option: box, widget: w);
4326 boxCopy.rect.setLeft(boxCopy.rect.left() + iconExtent);
4327 }
4328 QWindowsStyle::drawControl(element: ce, opt: &boxCopy, p , w);
4329 if (subRule.hasFont)
4330 p->setFont(oldFont);
4331 return;
4332 }
4333 break;
4334
4335 case CE_ScrollBarAddPage:
4336 pe1 = PseudoElement_ScrollBarAddPage;
4337 break;
4338
4339 case CE_ScrollBarSubPage:
4340 pe1 = PseudoElement_ScrollBarSubPage;
4341 break;
4342
4343 case CE_ScrollBarAddLine:
4344 pe1 = PseudoElement_ScrollBarAddLine;
4345 pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarRightArrow : PseudoElement_ScrollBarDownArrow;
4346 fallback = true;
4347 break;
4348
4349 case CE_ScrollBarSubLine:
4350 pe1 = PseudoElement_ScrollBarSubLine;
4351 pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarLeftArrow : PseudoElement_ScrollBarUpArrow;
4352 fallback = true;
4353 break;
4354
4355 case CE_ScrollBarFirst:
4356 pe1 = PseudoElement_ScrollBarFirst;
4357 break;
4358
4359 case CE_ScrollBarLast:
4360 pe1 = PseudoElement_ScrollBarLast;
4361 break;
4362
4363 case CE_ScrollBarSlider:
4364 pe1 = PseudoElement_ScrollBarSlider;
4365 fallback = true;
4366 break;
4367
4368#if QT_CONFIG(itemviews)
4369 case CE_ItemViewItem:
4370 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4371 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ViewItem);
4372 QStyleOptionViewItem optCopy(*vopt);
4373 if (subRule.hasDrawable()) {
4374 subRule.configurePalette(p: &optCopy.palette, fr: vopt->state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text,
4375 br: vopt->state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base);
4376 QWindowsStyle::drawControl(element: ce, opt: &optCopy, p, w);
4377 } else {
4378 p->save();
4379 if (hasStyleRule(obj: w, part: PseudoElement_Indicator)) {
4380 // there is a rule for the indicator, but no rule for the item itself (otherwise
4381 // the previous path would have been taken); only draw the indicator using the
4382 // rule (via QWindows/QCommonStyle), then let the base style handle the rest.
4383 QStyleOptionViewItem optIndicator(*vopt);
4384 subRule.configurePalette(p: &optIndicator.palette,
4385 fr: vopt->state & QStyle::State_Selected
4386 ? QPalette::HighlightedText
4387 : QPalette::Text,
4388 br: vopt->state & QStyle::State_Selected
4389 ? QPalette::Highlight
4390 : QPalette::Base);
4391 // only draw the indicator; no text, icon or background
4392 optIndicator.backgroundBrush = Qt::NoBrush; // no background
4393 optIndicator.text.clear();
4394 optIndicator.icon = QIcon();
4395 QWindowsStyle::drawControl(element: ce, opt: &optIndicator, p, w);
4396
4397 // Now draw text, background,icon, and highlight, but not the indicator with
4398 // the base style. Since we can't turn off HasCheckIndicator to prevent the base
4399 // style from drawing the check indicator again (it would change how the item
4400 // gets laid out) we have to clip the indicator that's already been painted.
4401 const QRect crStyle = subElementRect(r: QStyle::SE_ItemViewItemCheckIndicator,
4402 opt: &optIndicator, widget: w);
4403 const QRect crBase = baseStyle()->subElementRect(subElement: QStyle::SE_ItemViewItemCheckIndicator,
4404 option: &optIndicator, widget: w);
4405 const QRegion clipRegion = QRegion(p->hasClipping() ? p->clipRegion()
4406 : QRegion(optIndicator.rect))
4407 - crStyle.united(r: crBase);
4408 p->setClipRegion(clipRegion);
4409 }
4410 subRule.configurePalette(p: &optCopy.palette, fr: QPalette::Text, br: QPalette::NoRole);
4411 baseStyle()->drawControl(element: ce, opt: &optCopy, p, w);
4412 p->restore();
4413 }
4414 return;
4415 }
4416 break;
4417#endif // QT_CONFIG(itemviews)
4418
4419#if QT_CONFIG(tabbar)
4420 case CE_TabBarTab:
4421 if (hasStyleRule(obj: w, part: PseudoElement_TabBarTab)) {
4422 QWindowsStyle::drawControl(element: ce, opt, p, w);
4423 return;
4424 }
4425 break;
4426
4427 case CE_TabBarTabLabel:
4428 case CE_TabBarTabShape:
4429 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4430 const auto foregroundRole = w ? w->foregroundRole() : QPalette::WindowText;
4431 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarTab);
4432 QRect r = positionRect(w, rule2: subRule, pe: PseudoElement_TabBarTab, originRect: opt->rect, dir: opt->direction);
4433 if (ce == CE_TabBarTabShape && subRule.hasDrawable() && tab->shape < QTabBar::TriangularNorth) {
4434 subRule.drawRule(p, rect: r);
4435 return;
4436 }
4437 QStyleOptionTab tabCopy(*tab);
4438 subRule.configurePalette(p: &tabCopy.palette, fr: foregroundRole, br: QPalette::Base);
4439 QFont oldFont = p->font();
4440 if (subRule.hasFont)
4441 p->setFont(subRule.font.resolve(p->font()));
4442 if (subRule.hasBox() || !subRule.hasNativeBorder()) {
4443 tabCopy.rect = ce == CE_TabBarTabShape ? subRule.borderRect(r)
4444 : subRule.contentsRect(r);
4445 QWindowsStyle::drawControl(element: ce, opt: &tabCopy, p, w);
4446 } else {
4447 baseStyle()->drawControl(element: ce, opt: &tabCopy, p, w);
4448 }
4449 if (subRule.hasFont)
4450 p->setFont(oldFont);
4451
4452 return;
4453 }
4454 break;
4455#endif // QT_CONFIG(tabbar)
4456
4457 case CE_ColumnViewGrip:
4458 if (rule.hasDrawable()) {
4459 rule.drawRule(p, rect: opt->rect);
4460 return;
4461 }
4462 break;
4463
4464 case CE_DockWidgetTitle:
4465 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
4466 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_DockWidgetTitle);
4467 if (!subRule.hasDrawable() && !subRule.hasPosition())
4468 break;
4469 if (subRule.hasDrawable()) {
4470 subRule.drawRule(p, rect: opt->rect);
4471 } else {
4472 QStyleOptionDockWidget dwCopy(*dwOpt);
4473 dwCopy.title = QString();
4474 baseStyle()->drawControl(element: ce, opt: &dwCopy, p, w);
4475 }
4476
4477 if (!dwOpt->title.isEmpty()) {
4478 QRect r = subElementRect(r: SE_DockWidgetTitleBarText, opt, widget: w);
4479 if (dwOpt->verticalTitleBar) {
4480 r = r.transposed();
4481 p->save();
4482 p->translate(dx: r.left(), dy: r.top() + r.width());
4483 p->rotate(a: -90);
4484 p->translate(dx: -r.left(), dy: -r.top());
4485 }
4486 r = subRule.contentsRect(r);
4487
4488 Qt::Alignment alignment;
4489 if (subRule.hasPosition())
4490 alignment = subRule.position()->textAlignment;
4491 if (alignment == 0)
4492 alignment = Qt::AlignLeft;
4493
4494 QString titleText = p->fontMetrics().elidedText(text: dwOpt->title, mode: Qt::ElideRight, width: r.width());
4495 drawItemText(painter: p, rect: r,
4496 alignment: alignment | Qt::TextHideMnemonic, pal: dwOpt->palette,
4497 enabled: dwOpt->state & State_Enabled, text: titleText,
4498 textRole: QPalette::WindowText);
4499
4500 if (dwOpt->verticalTitleBar)
4501 p->restore();
4502 }
4503
4504 return;
4505 }
4506 break;
4507 case CE_ShapedFrame:
4508 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4509 if (rule.hasNativeBorder()) {
4510 QStyleOptionFrame frmOpt(*frm);
4511 rule.configurePalette(p: &frmOpt.palette, fr: QPalette::Text, br: QPalette::Base);
4512 frmOpt.rect = rule.borderRect(r: frmOpt.rect);
4513 baseStyle()->drawControl(element: ce, opt: &frmOpt, p, w);
4514 }
4515 // else, borders are already drawn in PE_Widget
4516 }
4517 return;
4518
4519
4520 default:
4521 break;
4522 }
4523
4524 if (pe1 != PseudoElement_None) {
4525 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pe1);
4526 if (subRule.bg != nullptr || subRule.hasDrawable()) {
4527 //We test subRule.bg directly because hasBackground() would return false for background:none.
4528 //But we still don't want the default drawning in that case (example for QScrollBar::add-page) (task 198926)
4529 subRule.drawRule(p, rect: opt->rect);
4530 } else if (fallback) {
4531 QWindowsStyle::drawControl(element: ce, opt, p, w);
4532 pe2 = PseudoElement_None;
4533 } else {
4534 baseStyle()->drawControl(element: ce, opt, p, w);
4535 }
4536 if (pe2 != PseudoElement_None) {
4537 QRenderRule subSubRule = renderRule(obj: w, opt, pseudoElement: pe2);
4538 QRect r = positionRect(w, rule1: subRule, rule2: subSubRule, pe: pe2, rect: opt->rect, dir: opt->direction);
4539 subSubRule.drawRule(p, rect: r);
4540 }
4541 return;
4542 }
4543
4544 baseStyle()->drawControl(element: ce, opt, p, w);
4545}
4546
4547void QStyleSheetStyle::drawItemPixmap(QPainter *p, const QRect &rect, int alignment, const
4548 QPixmap &pixmap) const
4549{
4550 baseStyle()->drawItemPixmap(painter: p, rect, alignment, pixmap);
4551}
4552
4553void QStyleSheetStyle::drawItemText(QPainter *painter, const QRect& rect, int alignment, const QPalette &pal,
4554 bool enabled, const QString& text, QPalette::ColorRole textRole) const
4555{
4556 baseStyle()->drawItemText(painter, rect, flags: alignment, pal, enabled, text, textRole);
4557}
4558
4559void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
4560 const QWidget *w) const
4561{
4562 RECURSION_GUARD(baseStyle()->drawPrimitive(pe, opt, p, w); return)
4563
4564 int pseudoElement = PseudoElement_None;
4565 QRenderRule rule = renderRule(obj: w, opt);
4566 QRect rect = opt->rect;
4567
4568 switch (pe) {
4569
4570 case PE_FrameStatusBarItem: {
4571 QRenderRule subRule = renderRule(obj: w ? w->parentWidget() : nullptr, opt, pseudoElement: PseudoElement_Item);
4572 if (subRule.hasDrawable()) {
4573 subRule.drawRule(p, rect: opt->rect);
4574 return;
4575 }
4576 break;
4577 }
4578
4579 case PE_IndicatorArrowDown:
4580 pseudoElement = PseudoElement_DownArrow;
4581 break;
4582
4583 case PE_IndicatorArrowUp:
4584 pseudoElement = PseudoElement_UpArrow;
4585 break;
4586
4587 case PE_IndicatorRadioButton:
4588 pseudoElement = PseudoElement_ExclusiveIndicator;
4589 break;
4590
4591 case PE_IndicatorItemViewItemCheck:
4592 pseudoElement = PseudoElement_ViewItemIndicator;
4593 break;
4594
4595 case PE_IndicatorCheckBox:
4596 pseudoElement = PseudoElement_Indicator;
4597 break;
4598
4599 case PE_IndicatorHeaderArrow:
4600 if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4601 pseudoElement = hdr->sortIndicator == QStyleOptionHeader::SortUp
4602 ? PseudoElement_HeaderViewUpArrow
4603 : PseudoElement_HeaderViewDownArrow;
4604 }
4605 break;
4606
4607 case PE_PanelButtonTool:
4608 case PE_PanelButtonCommand:
4609#if QT_CONFIG(abstractbutton)
4610 if (qobject_cast<const QAbstractButton *>(object: w) && rule.hasBackground() && rule.hasNativeBorder()) {
4611 //the window style will draw the borders
4612 ParentStyle::drawPrimitive(pe, opt, p, w);
4613 if (!rule.background()->pixmap.isNull() || rule.hasImage()) {
4614 rule.drawRule(p, rect: rule.boxRect(cr: opt->rect, flags: QRenderRule::Margin).adjusted(xp1: 1,yp1: 1,xp2: -1,yp2: -1));
4615 }
4616 return;
4617 }
4618#endif
4619 if (!rule.hasNativeBorder()) {
4620 rule.drawRule(p, rect: rule.boxRect(cr: opt->rect, flags: QRenderRule::Margin));
4621 return;
4622 }
4623 break;
4624
4625 case PE_IndicatorButtonDropDown: {
4626 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolButtonMenu);
4627 if (!subRule.hasNativeBorder()) {
4628 rule.drawBorder(p, rect: opt->rect);
4629 return;
4630 }
4631 break;
4632 }
4633
4634 case PE_FrameDefaultButton:
4635 if (rule.hasNativeBorder()) {
4636 if (rule.baseStyleCanDraw())
4637 break;
4638 QWindowsStyle::drawPrimitive(pe, opt, p, w);
4639 }
4640 return;
4641
4642 case PE_FrameWindow:
4643 case PE_FrameDockWidget:
4644 case PE_Frame:
4645 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4646 if (rule.hasNativeBorder()) {
4647 QStyleOptionFrame frmOpt(*frm);
4648 rule.configurePalette(p: &frmOpt.palette, fr: QPalette::Text, br: QPalette::Base);
4649 baseStyle()->drawPrimitive(pe, opt: &frmOpt, p, w);
4650 } else {
4651 rule.drawBorder(p, rect: rule.borderRect(r: opt->rect));
4652 }
4653 }
4654 return;
4655
4656 case PE_PanelLineEdit:
4657 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4658 // Fall back to container widget's render rule
4659 if (w) {
4660 if (QWidget *container = containerWidget(w); container != w) {
4661 QRenderRule containerRule = renderRule(obj: container, opt);
4662 if (!containerRule.hasNativeBorder() || !containerRule.baseStyleCanDraw())
4663 return;
4664 rule = containerRule;
4665 }
4666 }
4667
4668 if (rule.hasNativeBorder()) {
4669 QStyleOptionFrame frmOpt(*frm);
4670 rule.configurePalette(p: &frmOpt.palette, fr: QPalette::Text, br: QPalette::Base);
4671 frmOpt.rect = rule.borderRect(r: frmOpt.rect);
4672 if (rule.baseStyleCanDraw()) {
4673 rule.drawBackgroundImage(p, rect: opt->rect);
4674 baseStyle()->drawPrimitive(pe, opt: &frmOpt, p, w);
4675 } else {
4676 rule.drawBackground(p, rect: opt->rect);
4677 if (frmOpt.lineWidth > 0)
4678 baseStyle()->drawPrimitive(pe: PE_FrameLineEdit, opt: &frmOpt, p, w);
4679 }
4680 } else {
4681 rule.drawRule(p, rect: opt->rect);
4682 }
4683 }
4684 return;
4685
4686 case PE_Widget:
4687 if (w && !rule.hasDrawable()) {
4688 QWidget *container = containerWidget(w);
4689 if (styleSheetCaches->autoFillDisabledWidgets.contains(value: container)
4690 && (container == w || !renderRule(obj: container, opt).hasBackground())) {
4691 //we do not have a background, but we disabled the autofillbackground anyway. so fill the background now.
4692 // (this may happen if we have rules like :focus)
4693 p->fillRect(opt->rect, opt->palette.brush(cr: w->backgroundRole()));
4694 }
4695 break;
4696 }
4697#if QT_CONFIG(scrollarea)
4698 if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(object: w)) {
4699 const QAbstractScrollAreaPrivate *sap = sa->d_func();
4700 rule.drawBackground(p, rect: opt->rect, off: sap->contentsOffset());
4701 if (rule.hasBorder()) {
4702 QRect brect = rule.borderRect(r: opt->rect);
4703 if (styleHint(sh: QStyle::SH_ScrollView_FrameOnlyAroundContents, opt, w)) {
4704 QRect r = brect.adjusted(xp1: 0, yp1: 0, xp2: sa->verticalScrollBar()->isVisible() ? -sa->verticalScrollBar()->width() : 0,
4705 yp2: sa->horizontalScrollBar()->isVisible() ? -sa->horizontalScrollBar()->height() : 0);
4706 brect = QStyle::visualRect(direction: opt->direction, boundingRect: brect, logicalRect: r);
4707 }
4708 rule.drawBorder(p, rect: brect);
4709 }
4710 break;
4711 }
4712#endif
4713 Q_FALLTHROUGH();
4714 case PE_PanelMenu:
4715 case PE_PanelStatusBar:
4716 if (rule.hasDrawable()) {
4717 rule.drawRule(p, rect: opt->rect);
4718 return;
4719 }
4720 break;
4721
4722 case PE_FrameMenu:
4723 if (rule.hasDrawable()) {
4724 // Drawn by PE_PanelMenu
4725 return;
4726 }
4727 break;
4728
4729 case PE_PanelMenuBar:
4730 if (rule.hasDrawable()) {
4731 // Drawn by PE_Widget
4732 return;
4733 }
4734 break;
4735
4736 case PE_IndicatorToolBarSeparator:
4737 case PE_IndicatorToolBarHandle: {
4738 PseudoElement ps = pe == PE_IndicatorToolBarHandle ? PseudoElement_ToolBarHandle : PseudoElement_ToolBarSeparator;
4739 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: ps);
4740 if (subRule.hasDrawable()) {
4741 subRule.drawRule(p, rect: opt->rect);
4742 return;
4743 }
4744 }
4745 break;
4746
4747 case PE_IndicatorMenuCheckMark:
4748 pseudoElement = PseudoElement_MenuCheckMark;
4749 break;
4750
4751 case PE_IndicatorArrowLeft:
4752 pseudoElement = PseudoElement_LeftArrow;
4753 break;
4754
4755 case PE_IndicatorArrowRight:
4756 pseudoElement = PseudoElement_RightArrow;
4757 break;
4758
4759 case PE_IndicatorColumnViewArrow:
4760#if QT_CONFIG(itemviews)
4761 if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4762 bool reverse = (viewOpt->direction == Qt::RightToLeft);
4763 pseudoElement = reverse ? PseudoElement_LeftArrow : PseudoElement_RightArrow;
4764 } else
4765#endif
4766 {
4767 pseudoElement = PseudoElement_RightArrow;
4768 }
4769 break;
4770
4771#if QT_CONFIG(itemviews)
4772 case PE_IndicatorBranch:
4773 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4774 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TreeViewBranch);
4775 if (subRule.hasDrawable()) {
4776 proxy()->drawPrimitive(pe: PE_PanelItemViewRow, opt: vopt, p, w);
4777 subRule.drawRule(p, rect: opt->rect);
4778 } else {
4779 baseStyle()->drawPrimitive(pe, opt: vopt, p, w);
4780 }
4781 }
4782 return;
4783#endif // QT_CONFIG(itemviews)
4784
4785 case PE_PanelTipLabel:
4786 if (!rule.hasDrawable())
4787 break;
4788
4789 if (const QStyleOptionFrame *frmOpt = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4790 if (rule.hasNativeBorder()) {
4791 rule.drawBackground(p, rect: opt->rect);
4792 QStyleOptionFrame optCopy(*frmOpt);
4793 optCopy.rect = rule.borderRect(r: opt->rect);
4794 optCopy.palette.setBrush(acr: QPalette::Window, abrush: Qt::NoBrush); // oh dear
4795 baseStyle()->drawPrimitive(pe, opt: &optCopy, p, w);
4796 } else {
4797 rule.drawRule(p, rect: opt->rect);
4798 }
4799 }
4800 return;
4801
4802 case PE_FrameGroupBox:
4803 if (rule.hasNativeBorder())
4804 break;
4805 rule.drawBorder(p, rect: opt->rect);
4806 return;
4807
4808#if QT_CONFIG(tabwidget)
4809 case PE_FrameTabWidget:
4810 if (const QStyleOptionTabWidgetFrame *frm = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4811 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabWidgetPane);
4812 if (subRule.hasNativeBorder()) {
4813 subRule.drawBackground(p, rect: opt->rect);
4814 QStyleOptionTabWidgetFrame frmCopy(*frm);
4815 subRule.configurePalette(p: &frmCopy.palette, fr: QPalette::WindowText, br: QPalette::Window);
4816 baseStyle()->drawPrimitive(pe, opt: &frmCopy, p, w);
4817 } else {
4818 subRule.drawRule(p, rect: opt->rect);
4819 }
4820 return;
4821 }
4822 break;
4823#endif // QT_CONFIG(tabwidget)
4824
4825 case PE_IndicatorProgressChunk:
4826 pseudoElement = PseudoElement_ProgressBarChunk;
4827 break;
4828
4829 case PE_IndicatorTabTear:
4830 pseudoElement = PseudoElement_TabBarTear;
4831 break;
4832
4833 case PE_FrameFocusRect:
4834 if (!rule.hasNativeOutline()) {
4835 rule.drawOutline(p, rect: opt->rect);
4836 return;
4837 }
4838 break;
4839
4840 case PE_IndicatorDockWidgetResizeHandle:
4841 pseudoElement = PseudoElement_DockWidgetSeparator;
4842 break;
4843
4844 case PE_PanelItemViewRow:
4845 // For compatibility reasons, QTreeView draws different parts of
4846 // the background of an item row separately, before calling the
4847 // delegate to draw the item. The row background of an item is
4848 // however not separately styleable through a style sheet, but
4849 // only indirectly through the background of the item. To get the
4850 // same background for all parts drawn by QTreeView, we have to
4851 // use the background rule for the item here.
4852 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4853 // default handling for drawing empty space
4854 if (vopt->viewItemPosition == QStyleOptionViewItem::Invalid)
4855 break;
4856 if (QRenderRule rule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ViewItem); rule.hasBackground()) {
4857 // if the item background is not fully opaque, then we have to paint the row
4858 if (rule.background()->brush.color().alpha() != 1.0)
4859 baseStyle()->drawPrimitive(pe, opt, p, w);
4860 // Skip border for the branch and draw only the brackground
4861 if (vopt->features & QStyleOptionViewItem::HasDecoration &&
4862 (vopt->viewItemPosition == QStyleOptionViewItem::Beginning ||
4863 vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne) && rule.hasBorder()) {
4864 if (rule.hasDrawable()) {
4865 rule.drawBackground(p, rect);
4866 rule.drawImage(p, rect: rule.contentsRect(r: rect));
4867 } else {
4868 baseStyle()->drawPrimitive(pe, opt, p, w);
4869 }
4870 return;
4871 }
4872 pseudoElement = PseudoElement_ViewItem;
4873 }
4874 }
4875 break;
4876 case PE_PanelItemViewItem:
4877 pseudoElement = PseudoElement_ViewItem;
4878 break;
4879
4880 case PE_PanelScrollAreaCorner:
4881 pseudoElement = PseudoElement_ScrollAreaCorner;
4882 break;
4883
4884 case PE_IndicatorSpinDown:
4885 case PE_IndicatorSpinMinus:
4886 pseudoElement = PseudoElement_SpinBoxDownArrow;
4887 break;
4888
4889 case PE_IndicatorSpinUp:
4890 case PE_IndicatorSpinPlus:
4891 pseudoElement = PseudoElement_SpinBoxUpArrow;
4892 break;
4893#if QT_CONFIG(tabbar)
4894 case PE_IndicatorTabClose:
4895 if (w) {
4896 // QMacStyle needs a real widget, not its parent - to implement
4897 // 'document mode' properly, drawing nothing if a tab is not hovered.
4898 baseStyle()->setProperty(name: "_q_styleSheetRealCloseButton", value: QVariant::fromValue(value: (void *)w));
4899 w = w->parentWidget(); //match on the QTabBar instead of the CloseButton
4900 }
4901 pseudoElement = PseudoElement_TabBarTabCloseButton;
4902 break;
4903#endif
4904
4905 default:
4906 break;
4907 }
4908
4909 if (pseudoElement != PseudoElement_None) {
4910 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement);
4911 if (subRule.hasDrawable()) {
4912 subRule.drawRule(p, rect);
4913 } else {
4914 baseStyle()->drawPrimitive(pe, opt, p, w);
4915 }
4916 } else {
4917 baseStyle()->drawPrimitive(pe, opt, p, w);
4918 }
4919
4920 if (baseStyle()->property(name: "_q_styleSheetRealCloseButton").toBool())
4921 baseStyle()->setProperty(name: "_q_styleSheetRealCloseButton", value: QVariant());
4922}
4923
4924QPixmap QStyleSheetStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap,
4925 const QStyleOption *option) const
4926{
4927 return baseStyle()->generatedIconPixmap(iconMode, pixmap, opt: option);
4928}
4929
4930QStyle::SubControl QStyleSheetStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
4931 const QPoint &pt, const QWidget *w) const
4932{
4933 RECURSION_GUARD(return baseStyle()->hitTestComplexControl(cc, opt, pt, w))
4934 switch (cc) {
4935 case CC_TitleBar:
4936 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4937 QRenderRule rule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TitleBar);
4938 if (rule.hasDrawable() || rule.hasBox() || rule.hasBorder()) {
4939 QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
4940 QRect r;
4941 QStyle::SubControl sc = QStyle::SC_None;
4942 uint ctrl = SC_TitleBarSysMenu;
4943 while (ctrl <= SC_TitleBarLabel) {
4944 r = layout[QStyle::SubControl(ctrl)];
4945 if (r.isValid() && r.contains(p: pt)) {
4946 sc = QStyle::SubControl(ctrl);
4947 break;
4948 }
4949 ctrl <<= 1;
4950 }
4951 return sc;
4952 }
4953 }
4954 break;
4955
4956 case CC_MdiControls:
4957 if (hasStyleRule(obj: w, part: PseudoElement_MdiCloseButton)
4958 || hasStyleRule(obj: w, part: PseudoElement_MdiNormalButton)
4959 || hasStyleRule(obj: w, part: PseudoElement_MdiMinButton))
4960 return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4961 break;
4962
4963 case CC_ScrollBar: {
4964 QRenderRule rule = renderRule(obj: w, opt);
4965 if (!rule.hasDrawable() && !rule.hasBox())
4966 break;
4967 }
4968 Q_FALLTHROUGH();
4969 case CC_SpinBox:
4970 case CC_GroupBox:
4971 case CC_ComboBox:
4972 case CC_Slider:
4973 case CC_ToolButton:
4974 return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4975 default:
4976 break;
4977 }
4978
4979 return baseStyle()->hitTestComplexControl(cc, opt, pt, widget: w);
4980}
4981
4982QRect QStyleSheetStyle::itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pixmap) const
4983{
4984 return baseStyle()->itemPixmapRect(r: rect, flags: alignment, pixmap);
4985}
4986
4987QRect QStyleSheetStyle::itemTextRect(const QFontMetrics &metrics, const QRect& rect, int alignment,
4988 bool enabled, const QString& text) const
4989{
4990 return baseStyle()->itemTextRect(fm: metrics, r: rect, flags: alignment, enabled, text);
4991}
4992
4993int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *w) const
4994{
4995 RECURSION_GUARD(return baseStyle()->pixelMetric(m, opt, w))
4996
4997 QRenderRule rule = renderRule(obj: w, opt);
4998 QRenderRule subRule;
4999
5000 switch (m) {
5001 case PM_MenuButtonIndicator:
5002#if QT_CONFIG(toolbutton)
5003 // QToolButton adds this directly to the width
5004 if (qobject_cast<const QToolButton *>(object: w)) {
5005 if (rule.hasBox() || !rule.hasNativeBorder())
5006 return 0;
5007 if (const auto *tbOpt = qstyleoption_cast<const QStyleOptionToolButton*>(opt)) {
5008 if (tbOpt->features & QStyleOptionToolButton::MenuButtonPopup)
5009 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolButtonMenu);
5010 else
5011 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolButtonMenuIndicator);
5012 if (subRule.hasContentsSize())
5013 return subRule.size().width();
5014 }
5015 break;
5016 }
5017#endif
5018 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_PushButtonMenuIndicator);
5019 if (subRule.hasContentsSize())
5020 return subRule.size().width();
5021 break;
5022
5023 case PM_ButtonShiftHorizontal:
5024 case PM_ButtonShiftVertical:
5025 case PM_ButtonMargin:
5026 case PM_ButtonDefaultIndicator:
5027 if (rule.hasBox())
5028 return 0;
5029 break;
5030
5031 case PM_DefaultFrameWidth:
5032 if (!rule.hasNativeBorder())
5033 return rule.border()->borders[LeftEdge];
5034 break;
5035
5036 case PM_ExclusiveIndicatorWidth:
5037 case PM_IndicatorWidth:
5038 case PM_ExclusiveIndicatorHeight:
5039 case PM_IndicatorHeight:
5040 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_Indicator);
5041 if (subRule.hasContentsSize()) {
5042 return (m == PM_ExclusiveIndicatorWidth) || (m == PM_IndicatorWidth)
5043 ? subRule.size().width() : subRule.size().height();
5044 }
5045 break;
5046
5047 case PM_DockWidgetFrameWidth:
5048 case PM_ToolTipLabelFrameWidth: // border + margin + padding (support only one width)
5049 if (!rule.hasDrawable())
5050 break;
5051
5052 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5053 + (rule.hasBox() ? rule.box()->margins[LeftEdge] + rule.box()->paddings[LeftEdge]: 0);
5054
5055 case PM_ToolBarFrameWidth:
5056 if (rule.hasBorder() || rule.hasBox())
5057 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5058 + (rule.hasBox() ? rule.box()->paddings[LeftEdge]: 0);
5059 break;
5060
5061 case PM_MenuPanelWidth:
5062 case PM_MenuBarPanelWidth:
5063 if (rule.hasBorder() || rule.hasBox())
5064 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5065 + (rule.hasBox() ? rule.box()->margins[LeftEdge]: 0);
5066 break;
5067
5068
5069 case PM_MenuHMargin:
5070 case PM_MenuBarHMargin:
5071 if (rule.hasBox())
5072 return rule.box()->paddings[LeftEdge];
5073 break;
5074
5075 case PM_MenuVMargin:
5076 case PM_MenuBarVMargin:
5077 if (rule.hasBox())
5078 return rule.box()->paddings[TopEdge];
5079 break;
5080
5081 case PM_DockWidgetTitleBarButtonMargin:
5082 case PM_ToolBarItemMargin:
5083 if (rule.hasBox())
5084 return rule.box()->margins[TopEdge];
5085 break;
5086
5087 case PM_ToolBarItemSpacing:
5088 case PM_MenuBarItemSpacing:
5089 if (rule.hasBox() && rule.box()->spacing != -1)
5090 return rule.box()->spacing;
5091 break;
5092
5093 case PM_MenuTearoffHeight:
5094 case PM_MenuScrollerHeight: {
5095 PseudoElement ps = m == PM_MenuTearoffHeight ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
5096 subRule = renderRule(obj: w, opt, pseudoElement: ps);
5097 if (subRule.hasContentsSize())
5098 return subRule.size().height();
5099 break;
5100 }
5101
5102 case PM_ToolBarExtensionExtent:
5103 break;
5104
5105 case PM_SplitterWidth:
5106 case PM_ToolBarSeparatorExtent:
5107 case PM_ToolBarHandleExtent: {
5108 PseudoElement ps;
5109 if (m == PM_ToolBarHandleExtent) ps = PseudoElement_ToolBarHandle;
5110 else if (m == PM_SplitterWidth) ps = PseudoElement_SplitterHandle;
5111 else ps = PseudoElement_ToolBarSeparator;
5112 subRule = renderRule(obj: w, opt, pseudoElement: ps);
5113 if (subRule.hasContentsSize()) {
5114 QSize sz = subRule.size();
5115 return (opt && opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
5116 }
5117 break;
5118 }
5119
5120 case PM_RadioButtonLabelSpacing:
5121 if (rule.hasBox() && rule.box()->spacing != -1)
5122 return rule.box()->spacing;
5123 break;
5124 case PM_CheckBoxLabelSpacing:
5125#if QT_CONFIG(checkbox)
5126 if (qobject_cast<const QCheckBox *>(object: w)) {
5127 if (rule.hasBox() && rule.box()->spacing != -1)
5128 return rule.box()->spacing;
5129 }
5130#endif
5131 // assume group box
5132 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_GroupBoxTitle);
5133 if (subRule.hasBox() && subRule.box()->spacing != -1)
5134 return subRule.box()->spacing;
5135 break;
5136
5137#if QT_CONFIG(scrollbar)
5138 case PM_ScrollBarExtent:
5139 if (rule.hasContentsSize()) {
5140 QSize sz = rule.size();
5141 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5142 return sb->orientation == Qt::Horizontal ? sz.height() : sz.width();
5143 return sz.width() == -1 ? sz.height() : sz.width();
5144 }
5145 break;
5146
5147 case PM_ScrollBarSliderMin:
5148 if (hasStyleRule(obj: w, part: PseudoElement_ScrollBarSlider)) {
5149 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ScrollBarSlider);
5150 QSize msz = subRule.minimumSize();
5151 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5152 return sb->orientation == Qt::Horizontal ? msz.width() : msz.height();
5153 return msz.width() == -1 ? msz.height() : msz.width();
5154 }
5155 break;
5156
5157 case PM_ScrollView_ScrollBarSpacing:
5158 if (!rule.hasNativeBorder() || rule.hasBox())
5159 return 0;
5160 break;
5161
5162 case PM_ScrollView_ScrollBarOverlap:
5163 if (!proxy()->styleHint(stylehint: SH_ScrollBar_Transient, opt, widget: w))
5164 return 0;
5165 break;
5166#endif // QT_CONFIG(scrollbar)
5167
5168
5169 case PM_ProgressBarChunkWidth:
5170 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ProgressBarChunk);
5171 if (subRule.hasContentsSize()) {
5172 QSize sz = subRule.size();
5173 return (opt->state & QStyle::State_Horizontal)
5174 ? sz.width() : sz.height();
5175 }
5176 break;
5177
5178#if QT_CONFIG(tabwidget)
5179 case PM_TabBarTabHSpace:
5180 case PM_TabBarTabVSpace:
5181 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarTab);
5182 if (subRule.hasBox() || subRule.hasBorder())
5183 return 0;
5184 break;
5185
5186 case PM_TabBarScrollButtonWidth:
5187 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarScroller);
5188 if (subRule.hasContentsSize()) {
5189 QSize sz = subRule.size();
5190 return (sz.width() != -1 ? sz.width() : sz.height()) / 2;
5191 }
5192 break;
5193
5194 case PM_TabBarTabShiftHorizontal:
5195 case PM_TabBarTabShiftVertical:
5196 subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarTab);
5197 if (subRule.hasBox())
5198 return 0;
5199 break;
5200
5201 case PM_TabBarBaseOverlap: {
5202 const QWidget *tabWidget = qobject_cast<const QTabWidget *>(object: w);
5203 if (!tabWidget && w)
5204 tabWidget = w->parentWidget();
5205 if (hasStyleRule(obj: tabWidget, part: PseudoElement_TabWidgetPane)) {
5206 return 0;
5207 }
5208 break;
5209 }
5210#endif // QT_CONFIG(tabwidget)
5211
5212 case PM_SliderThickness: // horizontal slider's height (sizeHint)
5213 case PM_SliderLength: // minimum length of slider
5214 if (rule.hasContentsSize()) {
5215 bool horizontal = opt->state & QStyle::State_Horizontal;
5216 if (m == PM_SliderThickness) {
5217 QSize sz = rule.size();
5218 return horizontal ? sz.height() : sz.width();
5219 } else {
5220 QSize msz = rule.minimumContentsSize();
5221 return horizontal ? msz.width() : msz.height();
5222 }
5223 }
5224 break;
5225
5226 case PM_SliderControlThickness: {
5227 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SliderHandle);
5228 if (!subRule.hasContentsSize())
5229 break;
5230 QSize size = subRule.size();
5231 return (opt->state & QStyle::State_Horizontal) ? size.height() : size.width();
5232 }
5233
5234 case PM_ToolBarIconSize:
5235 case PM_ListViewIconSize:
5236 case PM_IconViewIconSize:
5237 case PM_TabBarIconSize:
5238 case PM_MessageBoxIconSize:
5239 case PM_ButtonIconSize:
5240 case PM_SmallIconSize:
5241 if (rule.hasStyleHint(sh: "icon-size"_L1))
5242 return rule.styleHint(sh: "icon-size"_L1).toSize().width();
5243 break;
5244
5245 case PM_DockWidgetTitleMargin: {
5246 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_DockWidgetTitle);
5247 if (!subRule.hasBox())
5248 break;
5249 return (subRule.border() ? subRule.border()->borders[TopEdge] : 0)
5250 + (subRule.hasBox() ? subRule.box()->margins[TopEdge] + subRule.box()->paddings[TopEdge]: 0);
5251 }
5252
5253 case PM_DockWidgetSeparatorExtent: {
5254 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_DockWidgetSeparator);
5255 if (!subRule.hasContentsSize())
5256 break;
5257 QSize sz = subRule.size();
5258 return qMax(a: sz.width(), b: sz.height());
5259 }
5260
5261 case PM_TitleBarHeight: {
5262 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TitleBar);
5263 if (subRule.hasContentsSize())
5264 return subRule.size().height();
5265 else if (subRule.hasBox() || subRule.hasBorder()) {
5266 QFontMetrics fm = opt ? opt->fontMetrics : w->fontMetrics();
5267 return subRule.size(sz: QSize(0, fm.height())).height();
5268 }
5269 break;
5270 }
5271
5272 case PM_MdiSubWindowFrameWidth:
5273 if (rule.hasBox() || rule.hasBorder()) {
5274 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5275 + (rule.hasBox() ? rule.box()->paddings[LeftEdge]+rule.box()->margins[LeftEdge]: 0);
5276 }
5277 break;
5278
5279 case PM_MdiSubWindowMinimizedWidth: {
5280 QRenderRule subRule = renderRule(obj: w, element: PseudoElement_None, state: PseudoClass_Minimized);
5281 int width = subRule.size().width();
5282 if (width != -1)
5283 return width;
5284 break;
5285 }
5286 default:
5287 break;
5288 }
5289
5290 return baseStyle()->pixelMetric(metric: m, option: opt, widget: w);
5291}
5292
5293QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
5294 const QSize &csz, const QWidget *w) const
5295{
5296 RECURSION_GUARD(return baseStyle()->sizeFromContents(ct, opt, csz, w))
5297
5298 QRenderRule rule = renderRule(obj: w, opt);
5299 QSize sz = rule.adjustSize(sz: csz);
5300
5301 switch (ct) {
5302#if QT_CONFIG(spinbox)
5303 case CT_SpinBox:
5304 if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5305 if (rule.baseStyleCanDraw())
5306 return baseStyle()->sizeFromContents(ct, opt, contentsSize: sz, w);
5307 if (spinbox->buttonSymbols != QAbstractSpinBox::NoButtons) {
5308 // Add some space for the up/down buttons
5309 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxUpButton);
5310 if (subRule.hasDrawable()) {
5311 QRect r = positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_SpinBoxUpButton,
5312 rect: opt->rect, dir: opt->direction);
5313 sz.rwidth() += r.width();
5314 } else {
5315 QSize defaultUpSize = defaultSize(w, sz: subRule.size(), rect: spinbox->rect, pe: PseudoElement_SpinBoxUpButton);
5316 sz.rwidth() += defaultUpSize.width();
5317 }
5318 }
5319 if (rule.hasBox() || rule.hasBorder() || !rule.hasNativeBorder())
5320 sz = rule.boxSize(cs: sz);
5321 return sz;
5322 }
5323 break;
5324#endif // QT_CONFIG(spinbox)
5325 case CT_ToolButton:
5326 if (rule.hasBox() || !rule.hasNativeBorder() || !rule.baseStyleCanDraw())
5327 sz += QSize(3, 3); // ### broken QToolButton
5328 Q_FALLTHROUGH();
5329 case CT_ComboBox:
5330 case CT_PushButton:
5331 if (rule.hasBox() || !rule.hasNativeBorder()) {
5332 if (ct == CT_ComboBox) {
5333 //add some space for the drop down.
5334 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ComboBoxDropDown);
5335 QRect comboRect = positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_ComboBoxDropDown, rect: opt->rect, dir: opt->direction);
5336 //+2 because there is hardcoded margins in QCommonStyle::drawControl(CE_ComboBoxLabel)
5337 sz += QSize(comboRect.width() + 2, 0);
5338 }
5339 return rule.boxSize(cs: sz);
5340 }
5341 sz = rule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, contentsSize: sz, w)
5342 : QWindowsStyle::sizeFromContents(ct, opt, contentsSize: sz, widget: w);
5343 return rule.boxSize(cs: sz, flags: Margin);
5344
5345 case CT_HeaderSection: {
5346 if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
5347 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_HeaderViewSection);
5348 if (subRule.hasGeometry() || subRule.hasBox() || !subRule.hasNativeBorder() || subRule.hasFont) {
5349 sz = subRule.adjustSize(sz: csz);
5350 if (!sz.isValid()) {
5351 // Try to set the missing values based on the base style.
5352 const auto baseSize = baseStyle()->sizeFromContents(ct, opt, contentsSize: sz, w);
5353 if (sz.width() < 0)
5354 sz.setWidth(baseSize.width());
5355 if (sz.height() < 0)
5356 sz.setHeight(baseSize.height());
5357 }
5358 if (!subRule.hasGeometry()) {
5359 QSize nativeContentsSize;
5360 bool nullIcon = hdr->icon.isNull();
5361 const int margin = pixelMetric(m: QStyle::PM_HeaderMargin, opt: hdr, w);
5362 int iconSize = nullIcon ? 0 : pixelMetric(m: QStyle::PM_SmallIconSize, opt: hdr, w);
5363 QFontMetrics fm = hdr->fontMetrics;
5364 if (subRule.hasFont) {
5365 QFont styleFont = w ? subRule.font.resolve(w->font()) : subRule.font;
5366 fm = QFontMetrics(styleFont);
5367 }
5368 const QSize txt = fm.size(flags: 0, str: hdr->text);
5369 nativeContentsSize.setHeight(margin + qMax(a: iconSize, b: txt.height()) + margin);
5370 nativeContentsSize.setWidth((nullIcon ? 0 : margin) + iconSize
5371 + (hdr->text.isNull() ? 0 : margin) + txt.width() + margin);
5372 sz = sz.expandedTo(otherSize: nativeContentsSize);
5373 }
5374 return subRule.size(sz);
5375 }
5376 sz = subRule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, contentsSize: sz, w)
5377 : QWindowsStyle::sizeFromContents(ct, opt, contentsSize: sz, widget: w);
5378 if (hasStyleRule(obj: w, part: PseudoElement_HeaderViewDownArrow)
5379 || hasStyleRule(obj: w, part: PseudoElement_HeaderViewUpArrow)) {
5380 const QRect arrowRect = subElementRect(r: SE_HeaderArrow, opt, widget: w);
5381 if (hdr->orientation == Qt::Horizontal)
5382 sz.rwidth() += arrowRect.width();
5383 else
5384 sz.rheight() += arrowRect.height();
5385 }
5386 return sz;
5387 }
5388 }
5389 break;
5390 case CT_GroupBox:
5391 case CT_LineEdit:
5392#if QT_CONFIG(spinbox)
5393 if (qobject_cast<QAbstractSpinBox *>(object: w ? w->parentWidget() : nullptr))
5394 return csz; // we only care about the size hint of the line edit
5395#endif
5396 if (rule.hasBox() || !rule.hasNativeBorder()) {
5397 return rule.boxSize(cs: sz);
5398 }
5399 break;
5400
5401 case CT_CheckBox:
5402 case CT_RadioButton:
5403 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
5404 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(obj: w, part: PseudoElement_Indicator)) {
5405 bool isRadio = (ct == CT_RadioButton);
5406 int iw = pixelMetric(m: isRadio ? PM_ExclusiveIndicatorWidth
5407 : PM_IndicatorWidth, opt: btn, w);
5408 int ih = pixelMetric(m: isRadio ? PM_ExclusiveIndicatorHeight
5409 : PM_IndicatorHeight, opt: btn, w);
5410
5411 int spacing = pixelMetric(m: isRadio ? PM_RadioButtonLabelSpacing
5412 : PM_CheckBoxLabelSpacing, opt: btn, w);
5413 sz.setWidth(sz.width() + iw + spacing);
5414 sz.setHeight(qMax(a: sz.height(), b: ih));
5415 return rule.boxSize(cs: sz);
5416 }
5417 }
5418 break;
5419
5420 case CT_Menu:
5421 case CT_MenuBar: // already has everything!
5422 case CT_ScrollBar:
5423 if (rule.hasBox() || rule.hasBorder())
5424 return sz;
5425 break;
5426
5427 case CT_MenuItem:
5428 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5429 PseudoElement pe = (mi->menuItemType == QStyleOptionMenuItem::Separator)
5430 ? PseudoElement_MenuSeparator : PseudoElement_Item;
5431 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pe);
5432 if ((pe == PseudoElement_MenuSeparator) && subRule.hasContentsSize()) {
5433 return QSize(sz.width(), subRule.size().height());
5434 }
5435 if ((pe == PseudoElement_Item) && (subRule.hasBox() || subRule.hasBorder() || subRule.hasFont)) {
5436 bool drawCheckMark = mi->menuHasCheckableItems;
5437#if QT_CONFIG(combobox)
5438 if (qobject_cast<const QComboBox *>(object: w))
5439 drawCheckMark = false; // ignore the checkmarks provided by the QComboMenuDelegate
5440#endif
5441 QSize sz(csz);
5442 if (mi->text.contains(c: u'\t'))
5443 sz.rwidth() += 12; //as in QCommonStyle
5444 if (!mi->icon.isNull()) {
5445 const int pmSmall = pixelMetric(m: PM_SmallIconSize);
5446 const QSize pmSize = mi->icon.actualSize(size: QSize(pmSmall, pmSmall));
5447 sz.rwidth() += std::max(a: mi->maxIconWidth, b: pmSize.width()) + 4;
5448 } else if (drawCheckMark) {
5449 QRenderRule subSubRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_MenuCheckMark);
5450 QRect checkmarkRect = positionRect(w, rule1: subRule, rule2: subSubRule, pe: PseudoElement_MenuCheckMark, rect: opt->rect, dir: opt->direction);
5451 sz.rwidth() += std::max(a: mi->maxIconWidth, b: checkmarkRect.width()) + 4;
5452 } else {
5453 sz.rwidth() += mi->maxIconWidth;
5454 }
5455 if (subRule.hasFont) {
5456 QFontMetrics fm(subRule.font.resolve(mi->font));
5457 const QRect r = fm.boundingRect(r: QRect(), flags: Qt::TextSingleLine | Qt::TextShowMnemonic, text: mi->text);
5458 sz = sz.expandedTo(otherSize: r.size());
5459 }
5460 return subRule.boxSize(cs: subRule.adjustSize(sz));
5461 }
5462 }
5463 break;
5464
5465 case CT_Splitter:
5466 case CT_MenuBarItem: {
5467 PseudoElement pe = (ct == CT_Splitter) ? PseudoElement_SplitterHandle : PseudoElement_Item;
5468 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pe);
5469 if (subRule.hasBox() || subRule.hasBorder())
5470 return subRule.boxSize(cs: sz);
5471 break;
5472 }
5473
5474 case CT_ProgressBar:
5475 case CT_SizeGrip:
5476 return (rule.hasContentsSize())
5477 ? rule.size(sz)
5478 : rule.boxSize(cs: baseStyle()->sizeFromContents(ct, opt, contentsSize: sz, w));
5479 break;
5480
5481 case CT_Slider:
5482 if (rule.hasBorder() || rule.hasBox() || rule.hasGeometry())
5483 return rule.boxSize(cs: sz);
5484 break;
5485
5486#if QT_CONFIG(tabbar)
5487 case CT_TabBarTab: {
5488 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarTab);
5489 if (subRule.hasBox() || !subRule.hasNativeBorder() || subRule.hasFont) {
5490 int spaceForIcon = 0;
5491 bool vertical = false;
5492 QString text;
5493 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
5494 if (!tab->icon.isNull())
5495 spaceForIcon = 6 /* icon offset */ + 4 /* spacing */ + 2 /* magic */; // ###: hardcoded to match with common style
5496 vertical = verticalTabs(shape: tab->shape);
5497 text = tab->text;
5498 }
5499 if (subRule.hasBox() || !subRule.hasNativeBorder())
5500 sz = csz + QSize(vertical ? 0 : spaceForIcon, vertical ? spaceForIcon : 0);
5501 if (subRule.hasFont) {
5502 // first we remove the space needed for the text using the default font
5503 const QSize oldTextSize = opt->fontMetrics.size(flags: Qt::TextShowMnemonic, str: text);
5504 (vertical ? sz.rheight() : sz.rwidth()) -= oldTextSize.width();
5505
5506 // then we add the space needed when using the rule font to the relevant
5507 // dimension, and constraint the other dimension to the maximum to make
5508 // sure we don't grow, but also don't clip icons or buttons.
5509 const QFont ruleFont = subRule.font.resolve(w->font());
5510 const QFontMetrics fm(ruleFont);
5511 const QSize textSize = fm.size(flags: Qt::TextShowMnemonic, str: text);
5512 if (vertical) {
5513 sz.rheight() += textSize.width();
5514 sz.rwidth() = qMax(a: textSize.height(), b: sz.width());
5515 } else {
5516 sz.rwidth() += textSize.width();
5517 sz.rheight() = qMax(a: textSize.height(), b: sz.height());
5518 }
5519 }
5520
5521 return subRule.boxSize(cs: subRule.adjustSize(sz));
5522 }
5523 sz = subRule.adjustSize(sz: csz);
5524 break;
5525 }
5526#endif // QT_CONFIG(tabbar)
5527
5528 case CT_MdiControls:
5529 if (const QStyleOptionComplex *ccOpt = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
5530 if (!hasStyleRule(obj: w, part: PseudoElement_MdiCloseButton)
5531 && !hasStyleRule(obj: w, part: PseudoElement_MdiNormalButton)
5532 && !hasStyleRule(obj: w, part: PseudoElement_MdiMinButton))
5533 break;
5534
5535 QList<QVariant> layout = rule.styleHint(sh: "button-layout"_L1).toList();
5536 if (layout.isEmpty())
5537 layout = subControlLayout(layout: "mNX");
5538
5539 int width = 0, height = 0;
5540 for (const QVariant &val : std::as_const(t&: layout)) {
5541 int layoutButton = val.toInt();
5542 if (layoutButton < PseudoElement_MdiCloseButton
5543 || layoutButton > PseudoElement_MdiNormalButton)
5544 continue;
5545 QStyle::SubControl sc = knownPseudoElements[layoutButton].subControl;
5546 if (!(ccOpt->subControls & sc))
5547 continue;
5548 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: layoutButton);
5549 QSize sz = subRule.size();
5550 width += sz.width();
5551 height = qMax(a: height, b: sz.height());
5552 }
5553
5554 return QSize(width, height);
5555 }
5556 break;
5557
5558#if QT_CONFIG(itemviews)
5559 case CT_ItemViewItem: {
5560 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ViewItem);
5561 sz = baseStyle()->sizeFromContents(ct, opt, contentsSize: csz, w);
5562 sz = subRule.adjustSize(sz);
5563 if (subRule.hasBox() || subRule.hasBorder())
5564 sz = subRule.boxSize(cs: sz);
5565 return sz;
5566 }
5567#endif // QT_CONFIG(itemviews)
5568
5569 default:
5570 break;
5571 }
5572
5573 return baseStyle()->sizeFromContents(ct, opt, contentsSize: sz, w);
5574}
5575
5576/*!
5577 \internal
5578*/
5579static QLatin1StringView propertyNameForStandardPixmap(QStyle::StandardPixmap sp)
5580{
5581 switch (sp) {
5582 case QStyle::SP_TitleBarMenuButton: return "titlebar-menu-icon"_L1;
5583 case QStyle::SP_TitleBarMinButton: return "titlebar-minimize-icon"_L1;
5584 case QStyle::SP_TitleBarMaxButton: return "titlebar-maximize-icon"_L1;
5585 case QStyle::SP_TitleBarCloseButton: return "titlebar-close-icon"_L1;
5586 case QStyle::SP_TitleBarNormalButton: return "titlebar-normal-icon"_L1;
5587 case QStyle::SP_TitleBarShadeButton: return "titlebar-shade-icon"_L1;
5588 case QStyle::SP_TitleBarUnshadeButton: return "titlebar-unshade-icon"_L1;
5589 case QStyle::SP_TitleBarContextHelpButton: return "titlebar-contexthelp-icon"_L1;
5590 case QStyle::SP_DockWidgetCloseButton: return "dockwidget-close-icon"_L1;
5591 case QStyle::SP_MessageBoxInformation: return "messagebox-information-icon"_L1;
5592 case QStyle::SP_MessageBoxWarning: return "messagebox-warning-icon"_L1;
5593 case QStyle::SP_MessageBoxCritical: return "messagebox-critical-icon"_L1;
5594 case QStyle::SP_MessageBoxQuestion: return "messagebox-question-icon"_L1;
5595 case QStyle::SP_DesktopIcon: return "desktop-icon"_L1;
5596 case QStyle::SP_TrashIcon: return "trash-icon"_L1;
5597 case QStyle::SP_ComputerIcon: return "computer-icon"_L1;
5598 case QStyle::SP_DriveFDIcon: return "floppy-icon"_L1;
5599 case QStyle::SP_DriveHDIcon: return "harddisk-icon"_L1;
5600 case QStyle::SP_DriveCDIcon: return "cd-icon"_L1;
5601 case QStyle::SP_DriveDVDIcon: return "dvd-icon"_L1;
5602 case QStyle::SP_DriveNetIcon: return "network-icon"_L1;
5603 case QStyle::SP_DirOpenIcon: return "directory-open-icon"_L1;
5604 case QStyle::SP_DirClosedIcon: return "directory-closed-icon"_L1;
5605 case QStyle::SP_DirLinkIcon: return "directory-link-icon"_L1;
5606 case QStyle::SP_FileIcon: return "file-icon"_L1;
5607 case QStyle::SP_FileLinkIcon: return "file-link-icon"_L1;
5608 case QStyle::SP_FileDialogStart: return "filedialog-start-icon"_L1;
5609 case QStyle::SP_FileDialogEnd: return "filedialog-end-icon"_L1;
5610 case QStyle::SP_FileDialogToParent: return "filedialog-parent-directory-icon"_L1;
5611 case QStyle::SP_FileDialogNewFolder: return "filedialog-new-directory-icon"_L1;
5612 case QStyle::SP_FileDialogDetailedView: return "filedialog-detailedview-icon"_L1;
5613 case QStyle::SP_FileDialogInfoView: return "filedialog-infoview-icon"_L1;
5614 case QStyle::SP_FileDialogContentsView: return "filedialog-contentsview-icon"_L1;
5615 case QStyle::SP_FileDialogListView: return "filedialog-listview-icon"_L1;
5616 case QStyle::SP_FileDialogBack: return "filedialog-backward-icon"_L1;
5617 case QStyle::SP_DirIcon: return "directory-icon"_L1;
5618 case QStyle::SP_DialogOkButton: return "dialog-ok-icon"_L1;
5619 case QStyle::SP_DialogCancelButton: return "dialog-cancel-icon"_L1;
5620 case QStyle::SP_DialogHelpButton: return "dialog-help-icon"_L1;
5621 case QStyle::SP_DialogOpenButton: return "dialog-open-icon"_L1;
5622 case QStyle::SP_DialogSaveButton: return "dialog-save-icon"_L1;
5623 case QStyle::SP_DialogCloseButton: return "dialog-close-icon"_L1;
5624 case QStyle::SP_DialogApplyButton: return "dialog-apply-icon"_L1;
5625 case QStyle::SP_DialogResetButton: return "dialog-reset-icon"_L1;
5626 case QStyle::SP_DialogDiscardButton: return "dialog-discard-icon"_L1;
5627 case QStyle::SP_DialogYesButton: return "dialog-yes-icon"_L1;
5628 case QStyle::SP_DialogNoButton: return "dialog-no-icon"_L1;
5629 case QStyle::SP_ArrowUp: return "uparrow-icon"_L1;
5630 case QStyle::SP_ArrowDown: return "downarrow-icon"_L1;
5631 case QStyle::SP_ArrowLeft: return "leftarrow-icon"_L1;
5632 case QStyle::SP_ArrowRight: return "rightarrow-icon"_L1;
5633 case QStyle::SP_ArrowBack: return "backward-icon"_L1;
5634 case QStyle::SP_ArrowForward: return "forward-icon"_L1;
5635 case QStyle::SP_DirHomeIcon: return "home-icon"_L1;
5636 case QStyle::SP_LineEditClearButton: return "lineedit-clear-button-icon"_L1;
5637 default: return ""_L1;
5638 }
5639}
5640
5641QIcon QStyleSheetStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *opt,
5642 const QWidget *w) const
5643{
5644 RECURSION_GUARD(return baseStyle()->standardIcon(standardIcon, opt, w))
5645 QString s = propertyNameForStandardPixmap(sp: standardIcon);
5646 if (!s.isEmpty()) {
5647 QRenderRule rule = renderRule(obj: w, opt);
5648 if (rule.hasStyleHint(sh: s))
5649 return qvariant_cast<QIcon>(v: rule.styleHint(sh: s));
5650 }
5651 return baseStyle()->standardIcon(standardIcon, option: opt, widget: w);
5652}
5653
5654QPalette QStyleSheetStyle::standardPalette() const
5655{
5656 return baseStyle()->standardPalette();
5657}
5658
5659QPixmap QStyleSheetStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
5660 const QWidget *w) const
5661{
5662 RECURSION_GUARD(return baseStyle()->standardPixmap(standardPixmap, opt, w))
5663 QString s = propertyNameForStandardPixmap(sp: standardPixmap);
5664 if (!s.isEmpty()) {
5665 QRenderRule rule = renderRule(obj: w, opt);
5666 if (rule.hasStyleHint(sh: s)) {
5667 QIcon icon = qvariant_cast<QIcon>(v: rule.styleHint(sh: s));
5668 const auto dpr = w ? w->devicePixelRatio() : qApp->devicePixelRatio();
5669 return icon.pixmap(size: QSize(16, 16), devicePixelRatio: dpr);
5670 }
5671 }
5672 return baseStyle()->standardPixmap(standardPixmap, opt, widget: w);
5673}
5674
5675int QStyleSheetStyle::layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2,
5676 Qt::Orientation orientation, const QStyleOption *option,
5677 const QWidget *widget) const
5678{
5679 return baseStyle()->layoutSpacing(control1, control2, orientation, option, widget);
5680}
5681
5682int QStyleSheetStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
5683 QStyleHintReturn *shret) const
5684{
5685 RECURSION_GUARD(return baseStyle()->styleHint(sh, opt, w, shret))
5686 // Prevent endless loop if somebody use isActiveWindow property as selector.
5687 // QWidget::isActiveWindow uses this styleHint to determine if the window is active or not
5688 if (sh == SH_Widget_ShareActivation)
5689 return baseStyle()->styleHint(stylehint: sh, opt, widget: w, returnData: shret);
5690
5691 QRenderRule rule = renderRule(obj: w, opt);
5692 QString s;
5693 switch (sh) {
5694 case SH_LineEdit_PasswordCharacter: s = "lineedit-password-character"_L1; break;
5695 case SH_LineEdit_PasswordMaskDelay: s = "lineedit-password-mask-delay"_L1; break;
5696 case SH_DitherDisabledText: s = "dither-disabled-text"_L1; break;
5697 case SH_EtchDisabledText: s = "etch-disabled-text"_L1; break;
5698 case SH_ItemView_ActivateItemOnSingleClick: s = "activate-on-singleclick"_L1; break;
5699 case SH_ItemView_ShowDecorationSelected: s = "show-decoration-selected"_L1; break;
5700 case SH_Table_GridLineColor: s = "gridline-color"_L1; break;
5701 case SH_DialogButtonLayout: s = "button-layout"_L1; break;
5702 case SH_ToolTipLabel_Opacity: s = "opacity"_L1; break;
5703 case SH_ComboBox_Popup: s = "combobox-popup"_L1; break;
5704 case SH_ComboBox_ListMouseTracking: s = "combobox-list-mousetracking"_L1; break;
5705 case SH_MenuBar_AltKeyNavigation: s = "menubar-altkey-navigation"_L1; break;
5706 case SH_Menu_Scrollable: s = "menu-scrollable"_L1; break;
5707 case SH_DrawMenuBarSeparator: s = "menubar-separator"_L1; break;
5708 case SH_MenuBar_MouseTracking: s = "mouse-tracking"_L1; break;
5709 case SH_SpinBox_ClickAutoRepeatRate: s = "spinbox-click-autorepeat-rate"_L1; break;
5710 case SH_SpinControls_DisableOnBounds: s = "spincontrol-disable-on-bounds"_L1; break;
5711 case SH_MessageBox_TextInteractionFlags: s = "messagebox-text-interaction-flags"_L1; break;
5712 case SH_ToolButton_PopupDelay: s = "toolbutton-popup-delay"_L1; break;
5713 case SH_ToolBox_SelectedPageTitleBold:
5714 if (renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolBoxTab).hasFont)
5715 return 0;
5716 break;
5717 case SH_GroupBox_TextLabelColor:
5718 if (rule.hasPalette() && rule.palette()->foreground.style() != Qt::NoBrush)
5719 return rule.palette()->foreground.color().rgba();
5720 break;
5721 case SH_ScrollView_FrameOnlyAroundContents: s = "scrollview-frame-around-contents"_L1; break;
5722 case SH_ScrollBar_ContextMenu: s = "scrollbar-contextmenu"_L1; break;
5723 case SH_ScrollBar_LeftClickAbsolutePosition: s = "scrollbar-leftclick-absolute-position"_L1; break;
5724 case SH_ScrollBar_MiddleClickAbsolutePosition: s = "scrollbar-middleclick-absolute-position"_L1; break;
5725 case SH_ScrollBar_RollBetweenButtons: s = "scrollbar-roll-between-buttons"_L1; break;
5726 case SH_ScrollBar_ScrollWhenPointerLeavesControl: s = "scrollbar-scroll-when-pointer-leaves-control"_L1; break;
5727 case SH_TabBar_Alignment:
5728#if QT_CONFIG(tabwidget)
5729 if (qobject_cast<const QTabWidget *>(object: w)) {
5730 rule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabWidgetTabBar);
5731 if (rule.hasPosition())
5732 return rule.position()->position;
5733 }
5734#endif // QT_CONFIG(tabwidget)
5735 s = "alignment"_L1;
5736 break;
5737#if QT_CONFIG(tabbar)
5738 case SH_TabBar_CloseButtonPosition:
5739 rule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarTabCloseButton);
5740 if (rule.hasPosition()) {
5741 Qt::Alignment align = rule.position()->position;
5742 if (align & Qt::AlignLeft || align & Qt::AlignTop)
5743 return QTabBar::LeftSide;
5744 if (align & Qt::AlignRight || align & Qt::AlignBottom)
5745 return QTabBar::RightSide;
5746 }
5747 break;
5748#endif
5749 case SH_TabBar_ElideMode: s = "tabbar-elide-mode"_L1; break;
5750 case SH_TabBar_PreferNoArrows: s = "tabbar-prefer-no-arrows"_L1; break;
5751 case SH_ComboBox_PopupFrameStyle:
5752#if QT_CONFIG(combobox)
5753 if (qobject_cast<const QComboBox *>(object: w)) {
5754 QAbstractItemView *view = w->findChild<QAbstractItemView *>();
5755 if (view) {
5756 view->ensurePolished();
5757 QRenderRule subRule = renderRule(obj: view, element: PseudoElement_None);
5758 if (subRule.hasBox() || !subRule.hasNativeBorder())
5759 return QFrame::NoFrame;
5760 }
5761 }
5762#endif // QT_CONFIG(combobox)
5763 break;
5764 case SH_DialogButtonBox_ButtonsHaveIcons: s = "dialogbuttonbox-buttons-have-icons"_L1; break;
5765 case SH_Workspace_FillSpaceOnMaximize: s = "mdi-fill-space-on-maximize"_L1; break;
5766 case SH_TitleBar_NoBorder:
5767 if (rule.hasBorder())
5768 return !rule.border()->borders[LeftEdge];
5769 break;
5770 case SH_TitleBar_AutoRaise: { // plain absurd
5771 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TitleBar);
5772 if (subRule.hasDrawable())
5773 return 1;
5774 break;
5775 }
5776 case SH_ItemView_ArrowKeysNavigateIntoChildren: s = "arrow-keys-navigate-into-children"_L1; break;
5777 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea: s = "paint-alternating-row-colors-for-empty-area"_L1; break;
5778 case SH_TitleBar_ShowToolTipsOnButtons: s = "titlebar-show-tooltips-on-buttons"_L1; break;
5779 case SH_Widget_Animation_Duration: s = "widget-animation-duration"_L1; break;
5780 case SH_ScrollBar_Transient:
5781 if (!rule.hasNativeBorder() || rule.hasBox() || rule.hasDrawable())
5782 return 0;
5783 break;
5784 default: break;
5785 }
5786 if (!s.isEmpty() && rule.hasStyleHint(sh: s)) {
5787 return rule.styleHint(sh: s).toInt();
5788 }
5789
5790 return baseStyle()->styleHint(stylehint: sh, opt, widget: w, returnData: shret);
5791}
5792
5793QRect QStyleSheetStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5794 const QWidget *w) const
5795{
5796 RECURSION_GUARD(return baseStyle()->subControlRect(cc, opt, sc, w))
5797
5798 QRenderRule rule = renderRule(obj: w, opt);
5799 switch (cc) {
5800 case CC_ComboBox:
5801 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5802 if (rule.hasBox() || !rule.hasNativeBorder()) {
5803 switch (sc) {
5804 case SC_ComboBoxFrame: return rule.borderRect(r: opt->rect);
5805 case SC_ComboBoxEditField:
5806 {
5807 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ComboBoxDropDown);
5808 QRect r = rule.contentsRect(r: opt->rect);
5809 QRect r2 = positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_ComboBoxDropDown,
5810 rect: opt->rect, dir: opt->direction);
5811 if (subRule.hasPosition() && subRule.position()->position & Qt::AlignLeft) {
5812 return visualRect(direction: opt->direction, boundingRect: r, logicalRect: r.adjusted(xp1: r2.width(),yp1: 0,xp2: 0,yp2: 0));
5813 } else {
5814 return visualRect(direction: opt->direction, boundingRect: r, logicalRect: r.adjusted(xp1: 0,yp1: 0,xp2: -r2.width(),yp2: 0));
5815 }
5816 }
5817 case SC_ComboBoxArrow: {
5818 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ComboBoxDropDown);
5819 return positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_ComboBoxDropDown, rect: opt->rect, dir: opt->direction);
5820 }
5821 case SC_ComboBoxListBoxPopup:
5822 default:
5823 return baseStyle()->subControlRect(cc, opt, sc, widget: w);
5824 }
5825 }
5826
5827 QStyleOptionComboBox comboBox(*cb);
5828 comboBox.rect = rule.borderRect(r: opt->rect);
5829 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, opt: &comboBox, sc, widget: w)
5830 : QWindowsStyle::subControlRect(cc, opt: &comboBox, sc, w);
5831 }
5832 break;
5833
5834#if QT_CONFIG(spinbox)
5835 case CC_SpinBox:
5836 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5837 QRenderRule upRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxUpButton);
5838 QRenderRule downRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SpinBoxDownButton);
5839 bool ruleMatch = rule.hasBox() || !rule.hasNativeBorder();
5840 bool upRuleMatch = upRule.hasGeometry() || upRule.hasPosition();
5841 bool downRuleMatch = downRule.hasGeometry() || downRule.hasPosition();
5842 if (ruleMatch || upRuleMatch || downRuleMatch) {
5843 switch (sc) {
5844 case SC_SpinBoxFrame:
5845 return rule.borderRect(r: opt->rect);
5846 case SC_SpinBoxEditField:
5847 {
5848 QRect r = rule.contentsRect(r: opt->rect);
5849 // Use the widest button on each side to determine edit field size.
5850 Qt::Alignment upAlign, downAlign;
5851
5852 upAlign = upRule.hasPosition() ? upRule.position()->position
5853 : Qt::Alignment(Qt::AlignRight);
5854 upAlign = resolveAlignment(opt->direction, upAlign);
5855
5856 downAlign = downRule.hasPosition() ? downRule.position()->position
5857 : Qt::Alignment(Qt::AlignRight);
5858 downAlign = resolveAlignment(opt->direction, downAlign);
5859
5860 const bool hasButtons = (spin->buttonSymbols != QAbstractSpinBox::NoButtons);
5861 const int upSize = hasButtons
5862 ? subControlRect(cc: CC_SpinBox, opt, sc: SC_SpinBoxUp, w).width() : 0;
5863 const int downSize = hasButtons
5864 ? subControlRect(cc: CC_SpinBox, opt, sc: SC_SpinBoxDown, w).width() : 0;
5865
5866 int widestL = qMax(a: (upAlign & Qt::AlignLeft) ? upSize : 0,
5867 b: (downAlign & Qt::AlignLeft) ? downSize : 0);
5868 int widestR = qMax(a: (upAlign & Qt::AlignRight) ? upSize : 0,
5869 b: (downAlign & Qt::AlignRight) ? downSize : 0);
5870 r.setRight(r.right() - widestR);
5871 r.setLeft(r.left() + widestL);
5872 return r;
5873 }
5874 case SC_SpinBoxDown:
5875 if (downRuleMatch)
5876 return positionRect(w, rule1: rule, rule2: downRule, pe: PseudoElement_SpinBoxDownButton,
5877 rect: opt->rect, dir: opt->direction);
5878 break;
5879 case SC_SpinBoxUp:
5880 if (upRuleMatch)
5881 return positionRect(w, rule1: rule, rule2: upRule, pe: PseudoElement_SpinBoxUpButton,
5882 rect: opt->rect, dir: opt->direction);
5883 break;
5884 default:
5885 break;
5886 }
5887
5888 return baseStyle()->subControlRect(cc, opt, sc, widget: w);
5889 }
5890
5891 QStyleOptionSpinBox spinBox(*spin);
5892 spinBox.rect = rule.borderRect(r: opt->rect);
5893 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, opt: &spinBox, sc, widget: w)
5894 : QWindowsStyle::subControlRect(cc, opt: &spinBox, sc, w);
5895 }
5896 break;
5897#endif // QT_CONFIG(spinbox)
5898
5899 case CC_GroupBox:
5900 if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5901 switch (sc) {
5902 case SC_GroupBoxFrame:
5903 case SC_GroupBoxContents: {
5904 if (rule.hasBox() || !rule.hasNativeBorder()) {
5905 return sc == SC_GroupBoxFrame ? rule.borderRect(r: opt->rect)
5906 : rule.contentsRect(r: opt->rect);
5907 }
5908 QStyleOptionGroupBox groupBox(*gb);
5909 groupBox.rect = rule.borderRect(r: opt->rect);
5910 return baseStyle()->subControlRect(cc, opt: &groupBox, sc, widget: w);
5911 }
5912 default:
5913 case SC_GroupBoxLabel:
5914 case SC_GroupBoxCheckBox: {
5915 QRenderRule indRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_GroupBoxIndicator);
5916 QRenderRule labelRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_GroupBoxTitle);
5917 if (!labelRule.hasPosition() && !labelRule.hasGeometry() && !labelRule.hasBox()
5918 && !labelRule.hasBorder() && !indRule.hasContentsSize()) {
5919 QStyleOptionGroupBox groupBox(*gb);
5920 groupBox.rect = rule.borderRect(r: opt->rect);
5921 return baseStyle()->subControlRect(cc, opt: &groupBox, sc, widget: w);
5922 }
5923 int tw = opt->fontMetrics.horizontalAdvance(gb->text);
5924 int th = opt->fontMetrics.height();
5925 int spacing = pixelMetric(m: QStyle::PM_CheckBoxLabelSpacing, opt, w);
5926 int iw = pixelMetric(m: QStyle::PM_IndicatorWidth, opt, w);
5927 int ih = pixelMetric(m: QStyle::PM_IndicatorHeight, opt, w);
5928
5929 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
5930 tw = tw + iw + spacing;
5931 th = qMax(a: th, b: ih);
5932 }
5933 if (!labelRule.hasGeometry()) {
5934 labelRule.geo = new QStyleSheetGeometryData(tw, th, tw, th, -1, -1);
5935 } else {
5936 labelRule.geo->width = tw;
5937 labelRule.geo->height = th;
5938 }
5939 if (!labelRule.hasPosition()) {
5940 labelRule.p = new QStyleSheetPositionData(0, 0, 0, 0, defaultOrigin(pe: PseudoElement_GroupBoxTitle),
5941 gb->textAlignment, PositionMode_Static);
5942 }
5943 QRect r = positionRect(w, rule1: rule, rule2: labelRule, pe: PseudoElement_GroupBoxTitle,
5944 rect: opt->rect, dir: opt->direction);
5945 if (gb->subControls & SC_GroupBoxCheckBox) {
5946 r = labelRule.contentsRect(r);
5947 if (sc == SC_GroupBoxLabel) {
5948 r.setLeft(r.left() + iw + spacing);
5949 r.setTop(r.center().y() - th/2);
5950 } else {
5951 r = QRect(r.left(), r.center().y() - ih/2, iw, ih);
5952 }
5953 return r;
5954 } else {
5955 return labelRule.contentsRect(r);
5956 }
5957 }
5958 } // switch
5959 }
5960 break;
5961
5962 case CC_ToolButton:
5963 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5964 if (rule.hasBox() || !rule.hasNativeBorder()) {
5965 switch (sc) {
5966 case SC_ToolButton: return rule.borderRect(r: opt->rect);
5967 case SC_ToolButtonMenu: {
5968 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ToolButtonMenu);
5969 return positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_ToolButtonMenu, rect: opt->rect, dir: opt->direction);
5970 }
5971 default:
5972 break;
5973 }
5974 }
5975
5976 QStyleOptionToolButton tool(*tb);
5977 tool.rect = rule.borderRect(r: opt->rect);
5978 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, opt: &tool, sc, widget: w)
5979 : QWindowsStyle::subControlRect(cc, opt: &tool, sc, w);
5980 }
5981 break;
5982
5983#if QT_CONFIG(scrollbar)
5984 case CC_ScrollBar:
5985 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5986 QStyleOptionSlider styleOptionSlider(*sb);
5987 styleOptionSlider.rect = rule.borderRect(r: opt->rect);
5988 if (rule.hasDrawable() || rule.hasBox()) {
5989 QRect grooveRect;
5990 if (!rule.hasBox()) {
5991 grooveRect = rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, opt: sb, sc: SC_ScrollBarGroove, widget: w)
5992 : QWindowsStyle::subControlRect(cc, opt: sb, sc: SC_ScrollBarGroove, w);
5993 } else {
5994 grooveRect = rule.contentsRect(r: opt->rect);
5995 }
5996
5997 PseudoElement pe = PseudoElement_None;
5998
5999 switch (sc) {
6000 case SC_ScrollBarGroove:
6001 return grooveRect;
6002 case SC_ScrollBarAddPage:
6003 case SC_ScrollBarSubPage:
6004 case SC_ScrollBarSlider: {
6005 QRect contentRect = grooveRect;
6006 if (hasStyleRule(obj: w, part: PseudoElement_ScrollBarSlider)) {
6007 QRenderRule sliderRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ScrollBarSlider);
6008 Origin origin = sliderRule.hasPosition() ? sliderRule.position()->origin : defaultOrigin(pe: PseudoElement_ScrollBarSlider);
6009 contentRect = rule.originRect(rect: opt->rect, origin);
6010 }
6011 int maxlen = (styleOptionSlider.orientation == Qt::Horizontal) ? contentRect.width() : contentRect.height();
6012 int sliderlen;
6013 if (sb->maximum != sb->minimum) {
6014 uint range = sb->maximum - sb->minimum;
6015 sliderlen = (qint64(sb->pageStep) * maxlen) / (range + sb->pageStep);
6016
6017 int slidermin = pixelMetric(m: PM_ScrollBarSliderMin, opt: sb, w);
6018 if (sliderlen < slidermin || range > INT_MAX / 2)
6019 sliderlen = slidermin;
6020 if (sliderlen > maxlen)
6021 sliderlen = maxlen;
6022 } else {
6023 sliderlen = maxlen;
6024 }
6025 int sliderstart = (styleOptionSlider.orientation == Qt::Horizontal ? contentRect.left() : contentRect.top())
6026 + sliderPositionFromValue(min: sb->minimum, max: sb->maximum, val: sb->sliderPosition,
6027 space: maxlen - sliderlen, upsideDown: sb->upsideDown);
6028
6029 QRect sr = (sb->orientation == Qt::Horizontal)
6030 ? QRect(sliderstart, contentRect.top(), sliderlen, contentRect.height())
6031 : QRect(contentRect.left(), sliderstart, contentRect.width(), sliderlen);
6032 if (sc == SC_ScrollBarSubPage)
6033 sr = QRect(contentRect.topLeft(), sb->orientation == Qt::Horizontal ? sr.bottomLeft() : sr.topRight());
6034 else if (sc == SC_ScrollBarAddPage)
6035 sr = QRect(sb->orientation == Qt::Horizontal ? sr.topRight() : sr.bottomLeft(), contentRect.bottomRight());
6036 return visualRect(direction: styleOptionSlider.direction, boundingRect: grooveRect, logicalRect: sr);
6037 }
6038 case SC_ScrollBarAddLine: pe = PseudoElement_ScrollBarAddLine; break;
6039 case SC_ScrollBarSubLine: pe = PseudoElement_ScrollBarSubLine; break;
6040 case SC_ScrollBarFirst: pe = PseudoElement_ScrollBarFirst; break;
6041 case SC_ScrollBarLast: pe = PseudoElement_ScrollBarLast; break;
6042 default: break;
6043 }
6044 if (hasStyleRule(obj: w,part: pe)) {
6045 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pe);
6046 if (subRule.hasPosition() || subRule.hasGeometry() || subRule.hasBox()) {
6047 const QStyleSheetPositionData *pos = subRule.position();
6048 QRect originRect = grooveRect;
6049 if (rule.hasBox()) {
6050 Origin origin = (pos && pos->origin != Origin_Unknown) ? pos->origin : defaultOrigin(pe);
6051 originRect = rule.originRect(rect: opt->rect, origin);
6052 }
6053 return positionRect(w, rule2: subRule, pe, originRect, dir: styleOptionSlider.direction);
6054 }
6055 }
6056 }
6057 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, opt: &styleOptionSlider, sc, widget: w)
6058 : QWindowsStyle::subControlRect(cc, opt: &styleOptionSlider, sc, w);
6059 }
6060 break;
6061#endif // QT_CONFIG(scrollbar)
6062
6063#if QT_CONFIG(slider)
6064 case CC_Slider:
6065 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
6066 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_SliderGroove);
6067 if (!subRule.hasDrawable())
6068 break;
6069 subRule.img = nullptr;
6070 QRect gr = positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_SliderGroove, rect: opt->rect, dir: opt->direction);
6071 switch (sc) {
6072 case SC_SliderGroove:
6073 return gr;
6074 case SC_SliderHandle: {
6075 bool horizontal = slider->orientation & Qt::Horizontal;
6076 QRect cr = subRule.contentsRect(r: gr);
6077 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: PseudoElement_SliderHandle);
6078 int len = horizontal ? subRule2.size().width() : subRule2.size().height();
6079 subRule2.img = nullptr;
6080 subRule2.geo = nullptr;
6081 cr = positionRect(w, rule2: subRule2, pe: PseudoElement_SliderHandle, originRect: cr, dir: opt->direction);
6082 int thickness = horizontal ? cr.height() : cr.width();
6083 int sliderPos = sliderPositionFromValue(min: slider->minimum, max: slider->maximum, val: slider->sliderPosition,
6084 space: (horizontal ? cr.width() : cr.height()) - len, upsideDown: slider->upsideDown);
6085 cr = horizontal ? QRect(cr.x() + sliderPos, cr.y(), len, thickness)
6086 : QRect(cr.x(), cr.y() + sliderPos, thickness, len);
6087 return subRule2.borderRect(r: cr);
6088 break; }
6089 case SC_SliderTickmarks:
6090 // TODO...
6091 default:
6092 break;
6093 }
6094 }
6095 break;
6096#endif // QT_CONFIG(slider)
6097
6098 case CC_MdiControls:
6099 if (hasStyleRule(obj: w, part: PseudoElement_MdiCloseButton)
6100 || hasStyleRule(obj: w, part: PseudoElement_MdiNormalButton)
6101 || hasStyleRule(obj: w, part: PseudoElement_MdiMinButton)) {
6102 QList<QVariant> layout = rule.styleHint(sh: "button-layout"_L1).toList();
6103 if (layout.isEmpty())
6104 layout = subControlLayout(layout: "mNX");
6105
6106 int x = 0, width = 0;
6107 QRenderRule subRule;
6108 for (const QVariant &val : std::as_const(t&: layout)) {
6109 int layoutButton = val.toInt();
6110 if (layoutButton < PseudoElement_MdiCloseButton
6111 || layoutButton > PseudoElement_MdiNormalButton)
6112 continue;
6113 QStyle::SubControl control = knownPseudoElements[layoutButton].subControl;
6114 if (!(opt->subControls & control))
6115 continue;
6116 subRule = renderRule(obj: w, opt, pseudoElement: layoutButton);
6117 width = subRule.size().width();
6118 if (sc == control)
6119 break;
6120 x += width;
6121 }
6122
6123 return subRule.borderRect(r: QRect(x, opt->rect.top(), width, opt->rect.height()));
6124 }
6125 break;
6126
6127 case CC_TitleBar:
6128 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
6129 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TitleBar);
6130 if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
6131 break;
6132 QHash<QStyle::SubControl, QRect> layoutRects = titleBarLayout(w, tb);
6133 return layoutRects.value(key: sc);
6134 }
6135 break;
6136
6137 default:
6138 break;
6139 }
6140
6141 return baseStyle()->subControlRect(cc, opt, sc, widget: w);
6142}
6143
6144QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, const QWidget *w) const
6145{
6146 RECURSION_GUARD(return baseStyle()->subElementRect(se, opt, w))
6147
6148 QRenderRule rule = renderRule(obj: w, opt);
6149#if QT_CONFIG(tabbar)
6150 int pe = PseudoElement_None;
6151#endif
6152
6153 switch (se) {
6154 case SE_PushButtonContents:
6155 case SE_PushButtonBevel:
6156 case SE_PushButtonFocusRect:
6157 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
6158 if (btn->features & QStyleOptionButton::HasMenu
6159 && hasStyleRule(obj: w, part: PseudoElement_PushButtonMenuIndicator)) {
6160 QStyleOptionButton btnOpt(*btn);
6161 btnOpt.features &= ~QStyleOptionButton::HasMenu;
6162 return rule.baseStyleCanDraw() ? baseStyle()->subElementRect(subElement: se, option: &btnOpt, widget: w)
6163 : QWindowsStyle::subElementRect(r: se, opt: &btnOpt, widget: w);
6164 }
6165 if (rule.hasBox() || !rule.hasNativeBorder()) {
6166 return visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: se == SE_PushButtonBevel
6167 ? rule.borderRect(r: opt->rect)
6168 : rule.contentsRect(r: opt->rect));
6169 }
6170 return rule.baseStyleCanDraw() ? baseStyle()->subElementRect(subElement: se, option: btn, widget: w)
6171 : QWindowsStyle::subElementRect(r: se, opt: btn, widget: w);
6172 }
6173 break;
6174
6175 case SE_LineEditContents:
6176 case SE_FrameContents:
6177 case SE_ShapedFrameContents:
6178 if (rule.hasBox() || !rule.hasNativeBorder()) {
6179 return visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: rule.contentsRect(r: opt->rect));
6180 }
6181 break;
6182
6183 case SE_CheckBoxIndicator:
6184 case SE_RadioButtonIndicator:
6185 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(obj: w, part: PseudoElement_Indicator)) {
6186 PseudoElement pe = se == SE_CheckBoxIndicator ? PseudoElement_Indicator : PseudoElement_ExclusiveIndicator;
6187 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pe);
6188 return positionRect(w, rule1: rule, rule2: subRule, pe, rect: opt->rect, dir: opt->direction);
6189 }
6190 break;
6191
6192 case SE_CheckBoxContents:
6193 case SE_RadioButtonContents:
6194 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(obj: w, part: PseudoElement_Indicator)) {
6195 bool isRadio = se == SE_RadioButtonContents;
6196 QRect ir = subElementRect(se: isRadio ? SE_RadioButtonIndicator : SE_CheckBoxIndicator,
6197 opt, w);
6198 ir = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: ir);
6199 int spacing = pixelMetric(m: isRadio ? PM_RadioButtonLabelSpacing : PM_CheckBoxLabelSpacing, opt: nullptr, w);
6200 QRect cr = rule.contentsRect(r: opt->rect);
6201 ir.setRect(ax: ir.left() + ir.width() + spacing, ay: cr.y(),
6202 aw: cr.width() - ir.width() - spacing, ah: cr.height());
6203 return visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: ir);
6204 }
6205 break;
6206
6207 case SE_ToolBoxTabContents:
6208 if (w && hasStyleRule(obj: w->parentWidget(), part: PseudoElement_ToolBoxTab)) {
6209 QRenderRule subRule = renderRule(obj: w->parentWidget(), opt, pseudoElement: PseudoElement_ToolBoxTab);
6210 return visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: subRule.contentsRect(r: opt->rect));
6211 }
6212 break;
6213
6214 case SE_RadioButtonFocusRect:
6215 case SE_RadioButtonClickRect: // focusrect | indicator
6216 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(obj: w, part: PseudoElement_Indicator)) {
6217 return opt->rect;
6218 }
6219 break;
6220
6221 case SE_CheckBoxFocusRect:
6222 case SE_CheckBoxClickRect: // relies on indicator and contents
6223 return ParentStyle::subElementRect(r: se, opt, widget: w);
6224
6225#if QT_CONFIG(itemviews)
6226 case SE_ItemViewItemCheckIndicator:
6227 if (!qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
6228 return subElementRect(se: SE_CheckBoxIndicator, opt, w);
6229 }
6230 Q_FALLTHROUGH();
6231 case SE_ItemViewItemText:
6232 case SE_ItemViewItemDecoration:
6233 case SE_ItemViewItemFocusRect:
6234 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
6235 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_ViewItem);
6236 PseudoElement pe = PseudoElement_None;
6237 if (se == SE_ItemViewItemText || se == SE_ItemViewItemFocusRect)
6238 pe = PseudoElement_ViewItemText;
6239 else if (se == SE_ItemViewItemDecoration && vopt->features & QStyleOptionViewItem::HasDecoration)
6240 pe = PseudoElement_ViewItemIcon;
6241 else if (se == SE_ItemViewItemCheckIndicator && vopt->features & QStyleOptionViewItem::HasCheckIndicator)
6242 pe = PseudoElement_ViewItemIndicator;
6243 else
6244 break;
6245 if (subRule.hasGeometry() || subRule.hasBox() || !subRule.hasNativeBorder() || hasStyleRule(obj: w, part: pe)) {
6246 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: pe);
6247 QStyleOptionViewItem optCopy(*vopt);
6248 optCopy.rect = subRule.contentsRect(r: vopt->rect);
6249 QRect rect = ParentStyle::subElementRect(r: se, opt: &optCopy, widget: w);
6250 return positionRect(w, rule2: subRule2, pe, originRect: rect, dir: opt->direction);
6251 }
6252 }
6253 break;
6254#endif // QT_CONFIG(itemviews)
6255
6256 case SE_HeaderArrow: {
6257 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_HeaderViewUpArrow);
6258 if (subRule.hasPosition() || subRule.hasGeometry())
6259 return positionRect(w, rule1: rule, rule2: subRule, pe: PseudoElement_HeaderViewUpArrow, rect: opt->rect, dir: opt->direction);
6260 }
6261 break;
6262
6263 case SE_HeaderLabel: {
6264 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_HeaderViewSection);
6265 if (subRule.hasBox() || !subRule.hasNativeBorder()) {
6266 auto r = subRule.contentsRect(r: opt->rect);
6267 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
6268 // Subtract width needed for arrow, if there is one
6269 if (header->sortIndicator != QStyleOptionHeader::None) {
6270 const auto arrowRect = subElementRect(se: SE_HeaderArrow, opt, w);
6271 if (arrowRect.isValid()) {
6272 if (opt->state & State_Horizontal)
6273 r.setWidth(r.width() - arrowRect.width());
6274 else
6275 r.setHeight(r.height() - arrowRect.height());
6276 }
6277 }
6278 }
6279 return r;
6280 }
6281 }
6282 break;
6283
6284 case SE_ProgressBarGroove:
6285 case SE_ProgressBarContents:
6286 case SE_ProgressBarLabel:
6287 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
6288 if (rule.hasBox() || !rule.hasNativeBorder() || rule.hasPosition() || hasStyleRule(obj: w, part: PseudoElement_ProgressBarChunk)) {
6289 if (se == SE_ProgressBarGroove)
6290 return rule.borderRect(r: pb->rect);
6291 else if (se == SE_ProgressBarContents)
6292 return rule.contentsRect(r: pb->rect);
6293
6294 QSize sz = pb->fontMetrics.size(flags: 0, str: pb->text);
6295 return QStyle::alignedRect(direction: Qt::LeftToRight, alignment: rule.hasPosition() ? rule.position()->textAlignment : pb->textAlignment,
6296 size: sz, rectangle: pb->rect);
6297 }
6298 }
6299 break;
6300
6301#if QT_CONFIG(tabbar)
6302 case SE_TabWidgetLeftCorner:
6303 pe = PseudoElement_TabWidgetLeftCorner;
6304 Q_FALLTHROUGH();
6305 case SE_TabWidgetRightCorner:
6306 if (pe == PseudoElement_None)
6307 pe = PseudoElement_TabWidgetRightCorner;
6308 Q_FALLTHROUGH();
6309 case SE_TabWidgetTabBar:
6310 if (pe == PseudoElement_None)
6311 pe = PseudoElement_TabWidgetTabBar;
6312 Q_FALLTHROUGH();
6313 case SE_TabWidgetTabPane:
6314 case SE_TabWidgetTabContents:
6315 if (pe == PseudoElement_None)
6316 pe = PseudoElement_TabWidgetPane;
6317
6318 if (hasStyleRule(obj: w, part: pe)) {
6319 QRect r = QWindowsStyle::subElementRect(r: pe == PseudoElement_TabWidgetPane ? SE_TabWidgetTabPane : se, opt, widget: w);
6320 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: pe);
6321 r = positionRect(w, rule2: subRule, pe, originRect: r, dir: opt->direction);
6322 if (pe == PseudoElement_TabWidgetTabBar) {
6323 Q_ASSERT(opt);
6324 r = opt->rect.intersected(other: r);
6325 }
6326 if (se == SE_TabWidgetTabContents)
6327 r = subRule.contentsRect(r);
6328 return r;
6329 }
6330 break;
6331
6332 case SE_TabBarScrollLeftButton:
6333 case SE_TabBarScrollRightButton:
6334 if (hasStyleRule(obj: w, part: PseudoElement_TabBarScroller))
6335 return ParentStyle::subElementRect(r: se, opt, widget: w);
6336 break;
6337
6338 case SE_TabBarTearIndicator: {
6339 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarTear);
6340 if (subRule.hasContentsSize()) {
6341 QRect r;
6342 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
6343 switch (tab->shape) {
6344 case QTabBar::RoundedNorth:
6345 case QTabBar::TriangularNorth:
6346 case QTabBar::RoundedSouth:
6347 case QTabBar::TriangularSouth:
6348 r.setRect(ax: tab->rect.left(), ay: tab->rect.top(), aw: subRule.size().width(), ah: opt->rect.height());
6349 break;
6350 case QTabBar::RoundedWest:
6351 case QTabBar::TriangularWest:
6352 case QTabBar::RoundedEast:
6353 case QTabBar::TriangularEast:
6354 r.setRect(ax: tab->rect.left(), ay: tab->rect.top(), aw: opt->rect.width(), ah: subRule.size().height());
6355 break;
6356 default:
6357 break;
6358 }
6359 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
6360 }
6361 return r;
6362 }
6363 break;
6364 }
6365 case SE_TabBarTabText:
6366 case SE_TabBarTabLeftButton:
6367 case SE_TabBarTabRightButton: {
6368 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_TabBarTab);
6369 if (subRule.hasBox() || !subRule.hasNativeBorder() || subRule.hasFont) {
6370 if (se == SE_TabBarTabText) {
6371 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
6372 const QTabBar *bar = qobject_cast<const QTabBar *>(object: w);
6373 const QRect optRect = bar && tab->tabIndex != -1 ? bar->tabRect(index: tab->tabIndex) : opt->rect;
6374 const QRect r = positionRect(w, rule2: subRule, pe: PseudoElement_TabBarTab, originRect: optRect, dir: opt->direction);
6375 QStyleOptionTab tabCopy(*tab);
6376 if (subRule.hasFont) {
6377 const QFont ruleFont = w ? subRule.font.resolve(w->font()) : subRule.font;
6378 tabCopy.fontMetrics = QFontMetrics(ruleFont);
6379 }
6380 tabCopy.rect = subRule.contentsRect(r);
6381 return ParentStyle::subElementRect(r: se, opt: &tabCopy, widget: w);
6382 }
6383 }
6384 return ParentStyle::subElementRect(r: se, opt, widget: w);
6385 }
6386 break;
6387 }
6388#endif // QT_CONFIG(tabbar)
6389
6390 case SE_DockWidgetCloseButton:
6391 case SE_DockWidgetFloatButton: {
6392 PseudoElement pe = (se == SE_DockWidgetCloseButton) ? PseudoElement_DockWidgetCloseButton : PseudoElement_DockWidgetFloatButton;
6393 QRenderRule subRule2 = renderRule(obj: w, opt, pseudoElement: pe);
6394 if (!subRule2.hasPosition())
6395 break;
6396 QRenderRule subRule = renderRule(obj: w, opt, pseudoElement: PseudoElement_DockWidgetTitle);
6397 return positionRect(w, rule1: subRule, rule2: subRule2, pe, rect: opt->rect, dir: opt->direction);
6398 }
6399
6400#if QT_CONFIG(toolbar)
6401 case SE_ToolBarHandle:
6402 if (hasStyleRule(obj: w, part: PseudoElement_ToolBarHandle))
6403 return ParentStyle::subElementRect(r: se, opt, widget: w);
6404 break;
6405#endif // QT_CONFIG(toolbar)
6406
6407 // On mac we make pixel adjustments to layouts which are not
6408 // desirable when you have custom style sheets on them
6409 case SE_CheckBoxLayoutItem:
6410 case SE_ComboBoxLayoutItem:
6411 case SE_DateTimeEditLayoutItem:
6412 case SE_LabelLayoutItem:
6413 case SE_ProgressBarLayoutItem:
6414 case SE_PushButtonLayoutItem:
6415 case SE_RadioButtonLayoutItem:
6416 case SE_SliderLayoutItem:
6417 case SE_SpinBoxLayoutItem:
6418 case SE_ToolButtonLayoutItem:
6419 case SE_FrameLayoutItem:
6420 case SE_GroupBoxLayoutItem:
6421 case SE_TabWidgetLayoutItem:
6422 if (!rule.hasNativeBorder())
6423 return opt->rect;
6424 break;
6425
6426 default:
6427 break;
6428 }
6429
6430 return baseStyle()->subElementRect(subElement: se, option: opt, widget: w);
6431}
6432
6433bool QStyleSheetStyle::event(QEvent *e)
6434{
6435 return (baseStyle()->event(event: e) && e->isAccepted()) || ParentStyle::event(event: e);
6436}
6437
6438void QStyleSheetStyle::updateStyleSheetFont(QWidget* w) const
6439{
6440 // Qt's fontDialog relies on the font of the sample edit for its selection,
6441 // we should never override it.
6442 if (w->objectName() == "qt_fontDialog_sampleEdit"_L1)
6443 return;
6444
6445 QWidget *container = containerWidget(w);
6446 QRenderRule rule = renderRule(obj: container, element: PseudoElement_None,
6447 state: PseudoClass_Active | PseudoClass_Enabled | extendedPseudoClass(w: container));
6448
6449 const bool useStyleSheetPropagationInWidgetStyles =
6450 QCoreApplication::testAttribute(attribute: Qt::AA_UseStyleSheetPropagationInWidgetStyles);
6451
6452 if (useStyleSheetPropagationInWidgetStyles) {
6453 unsetStyleSheetFont(w);
6454
6455 if (rule.font.resolveMask()) {
6456 QFont wf = w->d_func()->localFont();
6457 styleSheetCaches->customFontWidgets.insert(key: w, value: {.oldWidgetValue: wf, .resolveMask: rule.font.resolveMask()});
6458
6459 QFont font = rule.font.resolve(wf);
6460 font.setResolveMask(wf.resolveMask() | rule.font.resolveMask());
6461 w->setFont(font);
6462 }
6463 } else {
6464 QFont wf = w->d_func()->localFont();
6465 QFont font = rule.font.resolve(wf);
6466 font.setResolveMask(wf.resolveMask() | rule.font.resolveMask());
6467
6468 if ((!w->isWindow() || w->testAttribute(attribute: Qt::WA_WindowPropagation))
6469 && isNaturalChild(obj: w) && qobject_cast<QWidget *>(o: w->parent())) {
6470
6471 font = font.resolve(static_cast<QWidget *>(w->parent())->font());
6472 }
6473
6474 if (wf.resolveMask() == font.resolveMask() && wf == font)
6475 return;
6476
6477 w->data->fnt = font;
6478 w->d_func()->directFontResolveMask = font.resolveMask();
6479
6480 QEvent e(QEvent::FontChange);
6481 QCoreApplication::sendEvent(receiver: w, event: &e);
6482 }
6483}
6484
6485void QStyleSheetStyle::saveWidgetFont(QWidget* w, const QFont& font) const
6486{
6487 w->setProperty(name: "_q_styleSheetWidgetFont", value: font);
6488}
6489
6490void QStyleSheetStyle::clearWidgetFont(QWidget* w) const
6491{
6492 w->setProperty(name: "_q_styleSheetWidgetFont", value: QVariant());
6493}
6494
6495// Polish palette that should be used for a particular widget, with particular states
6496// (eg. :focus, :hover, ...)
6497// this is called by widgets that paint themself in their paint event
6498// Returns \c true if there is a new palette in pal.
6499bool QStyleSheetStyle::styleSheetPalette(const QWidget* w, const QStyleOption* opt, QPalette* pal)
6500{
6501 if (!w || !opt || !pal)
6502 return false;
6503
6504 RECURSION_GUARD(return false)
6505
6506 w = containerWidget(w);
6507
6508 QRenderRule rule = renderRule(obj: w, element: PseudoElement_None, state: pseudoClass(state: opt->state) | extendedPseudoClass(w));
6509 if (!rule.hasPalette())
6510 return false;
6511
6512 rule.configurePalette(p: pal, fr: QPalette::NoRole, br: QPalette::NoRole);
6513 return true;
6514}
6515
6516Qt::Alignment QStyleSheetStyle::resolveAlignment(Qt::LayoutDirection layDir, Qt::Alignment src)
6517{
6518 if (layDir == Qt::LeftToRight || src & Qt::AlignAbsolute)
6519 return src;
6520
6521 if (src & Qt::AlignLeft) {
6522 src &= ~Qt::AlignLeft;
6523 src |= Qt::AlignRight;
6524 } else if (src & Qt::AlignRight) {
6525 src &= ~Qt::AlignRight;
6526 src |= Qt::AlignLeft;
6527 }
6528 src |= Qt::AlignAbsolute;
6529 return src;
6530}
6531
6532// Returns whether the given QWidget has a "natural" parent, meaning that
6533// the parent contains this child as part of its normal operation.
6534// An example is the QTabBar inside a QTabWidget.
6535// This does not mean that any QTabBar which is a child of QTabWidget will
6536// match, only the one that was created by the QTabWidget initialization
6537// (and hence has the correct object name).
6538bool QStyleSheetStyle::isNaturalChild(const QObject *obj)
6539{
6540 if (obj->objectName().startsWith(s: "qt_"_L1))
6541 return true;
6542
6543 return false;
6544}
6545
6546QPixmap QStyleSheetStyle::loadPixmap(const QString &fileName, const QObject *context)
6547{
6548 if (fileName.isEmpty())
6549 return {};
6550
6551 qreal ratio = -1.0;
6552 if (const QWidget *widget = qobject_cast<const QWidget *>(o: context)) {
6553 if (QScreen *screen = QApplication::screenAt(point: widget->mapToGlobal(QPoint(0, 0))))
6554 ratio = screen->devicePixelRatio();
6555 }
6556
6557 if (ratio < 0) {
6558 if (const QApplication *app = qApp)
6559 ratio = app->devicePixelRatio();
6560 else
6561 ratio = 1.0;
6562 }
6563
6564 qreal sourceDevicePixelRatio = 1.0;
6565 QString resolvedFileName = qt_findAtNxFile(baseFileName: fileName, targetDevicePixelRatio: ratio, sourceDevicePixelRatio: &sourceDevicePixelRatio);
6566 QPixmap pixmap(resolvedFileName);
6567 pixmap.setDevicePixelRatio(sourceDevicePixelRatio);
6568 return pixmap;
6569}
6570
6571QT_END_NAMESPACE
6572
6573#include "moc_qstylesheetstyle_p.cpp"
6574
6575#endif // QT_CONFIG(style_stylesheet)
6576

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/widgets/styles/qstylesheetstyle.cpp