Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qstylesheetstyle.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qglobal.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
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 { QStyle::SC_None, "" },
232 { QStyle::SC_None, "down-arrow" },
233 { QStyle::SC_None, "up-arrow" },
234 { QStyle::SC_None, "left-arrow" },
235 { QStyle::SC_None, "right-arrow" },
236 { QStyle::SC_None, "indicator" },
237 { QStyle::SC_None, "indicator" },
238 { QStyle::SC_None, "menu-indicator" },
239 { QStyle::SC_ComboBoxArrow, "drop-down" },
240 { QStyle::SC_ComboBoxArrow, "down-arrow" },
241 { QStyle::SC_None, "item" },
242 { QStyle::SC_SpinBoxUp, "up-button" },
243 { QStyle::SC_SpinBoxUp, "up-arrow" },
244 { QStyle::SC_SpinBoxDown, "down-button" },
245 { QStyle::SC_SpinBoxDown, "down-arrow" },
246 { QStyle::SC_GroupBoxLabel, "title" },
247 { QStyle::SC_GroupBoxCheckBox, "indicator" },
248 { QStyle::SC_ToolButtonMenu, "menu-button" },
249 { QStyle::SC_ToolButtonMenu, "menu-arrow" },
250 { QStyle::SC_None, "menu-indicator" },
251 { QStyle::SC_None, "tab" },
252 { QStyle::SC_ScrollBarSlider, "handle" },
253 { QStyle::SC_ScrollBarAddPage, "add-page" },
254 { QStyle::SC_ScrollBarSubPage, "sub-page" },
255 { QStyle::SC_ScrollBarAddLine, "add-line" },
256 { QStyle::SC_ScrollBarSubLine, "sub-line" },
257 { QStyle::SC_ScrollBarFirst, "first" },
258 { QStyle::SC_ScrollBarLast, "last" },
259 { QStyle::SC_ScrollBarSubLine, "up-arrow" },
260 { QStyle::SC_ScrollBarAddLine, "down-arrow" },
261 { QStyle::SC_ScrollBarSubLine, "left-arrow" },
262 { QStyle::SC_ScrollBarAddLine, "right-arrow" },
263 { QStyle::SC_None, "handle" },
264 { QStyle::SC_None, "handle" },
265 { QStyle::SC_None, "separator" },
266 { QStyle::SC_None, "scroller" },
267 { QStyle::SC_None, "tearoff" },
268 { QStyle::SC_None, "indicator" },
269 { QStyle::SC_None, "separator" },
270 { QStyle::SC_None, "icon" },
271 { QStyle::SC_None, "right-arrow" },
272 { QStyle::SC_None, "branch" },
273 { QStyle::SC_None, "section" },
274 { QStyle::SC_None, "down-arrow" },
275 { QStyle::SC_None, "up-arrow" },
276 { QStyle::SC_None, "chunk" },
277 { QStyle::SC_None, "tab" },
278 { QStyle::SC_None, "scroller" },
279 { QStyle::SC_None, "tear" },
280 { QStyle::SC_SliderGroove, "groove" },
281 { QStyle::SC_SliderHandle, "handle" },
282 { QStyle::SC_None, "add-page" },
283 { QStyle::SC_None, "sub-page"},
284 { QStyle::SC_SliderTickmarks, "tick-mark" },
285 { QStyle::SC_None, "pane" },
286 { QStyle::SC_None, "tab-bar" },
287 { QStyle::SC_None, "left-corner" },
288 { QStyle::SC_None, "right-corner" },
289 { QStyle::SC_None, "title" },
290 { QStyle::SC_None, "close-button" },
291 { QStyle::SC_None, "float-button" },
292 { QStyle::SC_None, "separator" },
293 { QStyle::SC_MdiCloseButton, "close-button" },
294 { QStyle::SC_MdiMinButton, "minimize-button" },
295 { QStyle::SC_MdiNormalButton, "normal-button" },
296 { QStyle::SC_TitleBarLabel, "title" },
297 { QStyle::SC_TitleBarCloseButton, "close-button" },
298 { QStyle::SC_TitleBarMinButton, "minimize-button" },
299 { QStyle::SC_TitleBarMaxButton, "maximize-button" },
300 { QStyle::SC_TitleBarShadeButton, "shade-button" },
301 { QStyle::SC_TitleBarUnshadeButton, "unshade-button" },
302 { QStyle::SC_TitleBarNormalButton, "normal-button" },
303 { QStyle::SC_TitleBarContextHelpButton, "contexthelp-button" },
304 { QStyle::SC_TitleBarSysMenu, "sys-menu" },
305 { QStyle::SC_None, "item" },
306 { QStyle::SC_None, "icon" },
307 { QStyle::SC_None, "text" },
308 { QStyle::SC_None, "indicator" },
309 { QStyle::SC_None, "corner" },
310 { QStyle::SC_None, "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];
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 }
341 QCss::Repeat repeat;
342 Qt::Alignment position;
343 QCss::Origin origin;
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;
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(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(contentsSize()); }
581 QSize size(const QSize &sz) const { return boxSize(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(QSize(geo->minWidth, geo->minHeight));
592 return csz;
593 }
594
595 bool hasStyleHint(const QString &sh) const { return styleHints.contains(sh); }
596 QVariant styleHint(const QString &sh) const { return styleHints.value(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};
626
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(PseudoElement_MdiMinButton);
728 buttons.append(PseudoElement_TitleBarMinButton);
729 break;
730 case 'M':
731 buttons.append(PseudoElement_TitleBarMaxButton);
732 break;
733 case 'X':
734 buttons.append(PseudoElement_MdiCloseButton);
735 buttons.append(PseudoElement_TitleBarCloseButton);
736 break;
737 case 'N':
738 buttons.append(PseudoElement_MdiNormalButton);
739 buttons.append(PseudoElement_TitleBarNormalButton);
740 break;
741 case 'I':
742 buttons.append(PseudoElement_TitleBarSysMenu);
743 break;
744 case 'T':
745 buttons.append(PseudoElement_TitleBar);
746 break;
747 case 'H':
748 buttons.append(PseudoElement_TitleBarContextHelpButton);
749 break;
750 case 'S':
751 buttons.append(PseudoElement_TitleBarShadeButton);
752 break;
753 default:
754 buttons.append(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(tb->rect);
779 QList<QVariant> layout = subRule.styleHint("button-layout"_L1).toList();
780 if (layout.isEmpty())
781 layout = subControlLayout("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(layout.size());
787 for (const QVariant &val : std::as_const(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(std::move(info));
844 }
845 }
846
847 for (const ButtonInfo &info : std::as_const(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(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(info.offset, 0);
861 lr.setWidth(info.width);
862 break;
863 case Right:
864 lr.moveLeft(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, info.rule, info.element, lr, 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 }
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, &h, &minw, &minh, &maxw, &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;
920 Qt::Alignment textAlignment;
921 if (v.extractPosition(&left, &top, &right, &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))
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, 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, radii, offsets))
947 ou = new QStyleSheetOutlineData(borders, colors, styles, radii, offsets);
948
950 QString uri;
951 Repeat repeat = Repeat_XY;
952 Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft;
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(uri, object);
958 if (!uri.isEmpty() && pixmap.isNull())
959 qWarning("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, &selectedForeground, &selectedBackground,
970 &alternateBackground, &placeHolderTextForeground, &accent)) {
971 pal = new QStyleSheetPaletteData(foreground, selectedForeground, selectedBackground,
972 alternateBackground, placeHolderTextForeground, accent);
973 }
974
975 QIcon imgIcon;
977 QSize imgSize;
978 if (v.extractImage(&imgIcon, &alignment, &imgSize))
979 img = new QStyleSheetImageData(imgIcon, alignment, imgSize);
980
981 QIcon icon;
982 QSize size;
983 if (v.extractIcon(&icon, &size))
984 iconPtr = new QStyleSheetImageData(icon, Qt::AlignCenter, size);
985
986 int adj = -255;
987 hasFont = v.extractFont(&font, &adj);
988
989#if QT_CONFIG(tooltip)
990 if (object && qstrcmp(object->metaObject()->className(), "QTipLabel") == 0)
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(&uri, cuts, &horizStretch, &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(uri, 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(0).variant.toInt();
1022 if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
1023 defaultBackground = palette.color((QPalette::ColorRole)(role-Value_FirstColorRole));
1024 } else if (decl.d->property.startsWith("qproperty-"_L1, 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(styleHint) == 0) {
1031 QString hintName = QString(styleHint);
1032 QVariant hintValue;
1033 if (hintName.endsWith("alignment"_L1)) {
1034 hintValue = (int) decl.alignmentValue();
1035 } else if (hintName.endsWith("color"_L1)) {
1036 hintValue = (int) decl.colorValue().rgba();
1037 } else if (hintName.endsWith("size"_L1)) {
1038 // Check only for the 'em' case
1039 const QString valueString = decl.d->values.at(0).variant.toString();
1040 const bool isEmSize = valueString.endsWith(u"em", Qt::CaseInsensitive);
1041 if (isEmSize || valueString.endsWith(u"ex", 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*>(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(&emexSize, isEmSize ? "em" : "ex") && emexSize > 0) {
1055 pixelSize *= emexSize;
1056 const QSizeF newSize(pixelSize, pixelSize);
1057 decl.d->parsed = QVariant::fromValue<QSizeF>(newSize);
1058 hintValue = newSize;
1059 } else {
1060 qWarning("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("icon"_L1)) {
1068 hintValue = decl.iconValue();
1069 } else if (hintName == "button-layout"_L1 && decl.d->values.size() != 0
1070 && decl.d->values.at(0).type == QCss::Value::String) {
1071 hintValue = subControlLayout(decl.d->values.at(0).variant.toString().toLatin1());
1072 } else {
1073 int integer;
1074 decl.intValue(&integer);
1075 hintValue = integer;
1076 }
1077 styleHints[decl.d->property] = hintValue;
1078 knownStyleHint = true;
1079 break;
1080 }
1081 }
1082 if (!knownStyleHint)
1083 qWarning("Unknown property %s", qPrintable(decl.d->property));
1084 }
1085 }
1086
1087 if (hasBorder()) {
1088 if (const QWidget *widget = qobject_cast<const QWidget *>(object)) {
1089 QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle);
1090 if (!style)
1091 style = qt_styleSheet(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(m[LeftEdge], m[TopEdge], -m[RightEdge], -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(b[LeftEdge], b[TopEdge], -b[RightEdge], -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(b[LeftEdge], b[TopEdge], -b[RightEdge], -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(p[LeftEdge], p[TopEdge], -p[RightEdge], -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(-m[LeftEdge], -m[TopEdge], m[RightEdge], m[BottomEdge]);
1142 }
1143 if (flags & Padding) {
1144 const int *p = box()->paddings;
1145 r.adjust(-p[LeftEdge], -p[TopEdge], p[RightEdge], p[BottomEdge]);
1146 }
1147 }
1148 if (hasBorder() && (flags & Border)) {
1149 const int *b = border()->borders;
1150 r.adjust(-b[LeftEdge], -b[TopEdge], b[RightEdge], b[BottomEdge]);
1151 }
1152 return r;
1153}
1154
1155QSize QRenderRule::boxSize(const QSize &cs, int flags) const
1156{
1157 QSize bs = boxRect(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[] = {
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(QPainter::SmoothPixmapTransform);
1222 qDrawBorderPixmap(p, rect, targetMargins, borderImageData->pixmap,
1223 QRect(QPoint(), borderImageData->pixmap.size()), sourceMargins,
1224 QTileRules(tileMode2TileRule[borderImageData->horizStretch], tileMode2TileRule[borderImageData->vertStretch]));
1225 p->setRenderHint(QPainter::SmoothPixmapTransform, 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(rect);
1234 case Origin_Border:
1235 return borderRect(rect);
1236 case Origin_Content:
1237 return contentsRect(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, borderRect(rect));
1254
1255 if (background()->origin != background()->clip) {
1256 p->save();
1257 p->setClipRect(originRect(rect, background()->clip), 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, background()->origin);
1267 QRect aligned = QStyle::alignedRect(Qt::LeftToRight, background()->position, bgpSize, r);
1268 QRect inter = aligned.translated(-off).intersected(r);
1269
1270 switch (background()->repeat) {
1271 case Repeat_Y:
1272 p->drawTiledPixmap(inter.x(), r.y(), inter.width(), r.height(), bgp,
1273 inter.x() - aligned.x() + off.x(),
1274 bgpHeight - int(aligned.y() - r.y()) % bgpHeight + off.y());
1275 break;
1276 case Repeat_X:
1277 p->drawTiledPixmap(r.x(), inter.y(), r.width(), inter.height(), bgp,
1278 bgpWidth - int(aligned.x() - r.x())%bgpWidth + off.x(),
1279 inter.y() - aligned.y() + off.y());
1280 break;
1281 case Repeat_XY:
1282 p->drawTiledPixmap(r, bgp,
1283 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(inter.x(), inter.y(), bgp, inter.x() - aligned.x() + off.x(),
1289 inter.y() - aligned.y() + off.y(), bgp.width() , 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(QPainter::Antialiasing);
1307 qDrawBorder(p, rect, ou->styles, ou->borders, ou->colors, ou->radii);
1308 p->setRenderHint(QPainter::Antialiasing, 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(QPainter::Antialiasing);
1323 qDrawBorder(p, rect, bd->styles, bd->borders, bd->colors, bd->radii);
1324 p->setRenderHint(QPainter::Antialiasing, wasAntialiased);
1325}
1326
1327QPainterPath QRenderRule::borderClip(QRect r)
1328{
1329 if (!hasBorder())
1330 return QPainterPath();
1331
1332 QSize tlr, trr, blr, brr;
1333 qNormalizeRadii(r, bd->radii, &tlr, &trr, &blr, &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;
1340 qreal curY = rect.y() + borders[TopEdge]/2.0;
1341 path.moveTo(rect.x() + tlr.width(), curY);
1342 path.lineTo(rect.right() - trr.width(), curY);
1343 qreal curX = rect.right() - borders[RightEdge]/2.0;
1344 path.arcTo(curX - 2*trr.width() + borders[RightEdge], curY,
1345 trr.width()*2 - borders[RightEdge], trr.height()*2 - borders[TopEdge], 90, -90);
1346
1347 path.lineTo(curX, rect.bottom() - brr.height());
1348 curY = rect.bottom() - borders[BottomEdge]/2.0;
1349 path.arcTo(curX - 2*brr.width() + borders[RightEdge], curY - 2*brr.height() + borders[BottomEdge],
1350 brr.width()*2 - borders[RightEdge], brr.height()*2 - borders[BottomEdge], 0, -90);
1351
1352 path.lineTo(rect.x() + blr.width(), curY);
1353 curX = rect.left() + borders[LeftEdge]/2.0;
1354 path.arcTo(curX, rect.bottom() - 2*blr.height() + borders[BottomEdge]/2.0,
1355 blr.width()*2 - borders[LeftEdge], blr.height()*2 - borders[BottomEdge], 270, -90);
1356
1357 path.lineTo(curX, rect.top() + tlr.height());
1358 path.arcTo(curX, rect.top() + borders[TopEdge]/2.0,
1359 tlr.width()*2 - borders[LeftEdge], tlr.height()*2 - borders[TopEdge], 180, -90);
1360
1361 path.closeSubpath();
1362 return path;
1363}
1364
1368void QRenderRule::setClip(QPainter *p, const QRect &rect)
1369{
1370 if (clipset++)
1371 return;
1372 clipPath = borderClip(rect);
1373 if (!clipPath.isEmpty()) {
1374 p->save();
1375 p->setClipPath(clipPath, 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(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(QPainter::Antialiasing);
1401 p->fillPath(borderPath, brush);
1402 p->setRenderHint(QPainter::Antialiasing, 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{
1414 if (hasBorder())
1415 drawBorder(p, borderRect(rect));
1416}
1417
1418void QRenderRule::drawImage(QPainter *p, const QRect &rect)
1419{
1420 if (!hasImage())
1421 return;
1422 img->icon.paint(p, rect, img->alignment);
1423}
1424
1425void QRenderRule::drawRule(QPainter *p, const QRect& rect)
1426{
1427 drawFrame(p, rect);
1428 drawImage(p, contentsRect(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(br, bg->brush);
1437 p->setBrush(QPalette::Window, bg->brush);
1438 if (bg->brush.style() == Qt::SolidPattern) {
1439 p->setBrush(QPalette::Light, bg->brush.color().lighter(115));
1440 p->setBrush(QPalette::Midlight, bg->brush.color().lighter(107));
1441 p->setBrush(QPalette::Dark, bg->brush.color().darker(150));
1442 p->setBrush(QPalette::Shadow, bg->brush.color().darker(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(fr, pal->foreground);
1452 p->setBrush(QPalette::WindowText, pal->foreground);
1453 p->setBrush(QPalette::Text, pal->foreground);
1454 }
1455 if (pal->selectionBackground.style() != Qt::NoBrush)
1456 p->setBrush(QPalette::Highlight, pal->selectionBackground);
1457 if (pal->selectionForeground.style() != Qt::NoBrush)
1458 p->setBrush(QPalette::HighlightedText, pal->selectionForeground);
1459 if (pal->alternateBackground.style() != Qt::NoBrush)
1460 p->setBrush(QPalette::AlternateBase, pal->alternateBackground);
1461}
1462
1464 const QBrush &defaultBrush, const QWidget *widget)
1465{
1466 const QPalette &widgetPalette = widget->palette();
1467 if (widgetPalette.isBrushSet(group, role))
1468 palette->setBrush(group, role, widgetPalette.brush(group, role));
1469 else
1470 palette->setBrush(group, role, 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, QPalette::Base, bg->brush); // for windows, windowxp
1477 p->setBrush(cg, QPalette::Button, bg->brush); // for plastique
1478 p->setBrush(cg, w->backgroundRole(), bg->brush);
1479 p->setBrush(cg, QPalette::Window, 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, w->backgroundRole(), Qt::NoBrush);
1488 }
1489
1490 if (!hasPalette())
1491 return;
1492
1493 if (pal->foreground.style() != Qt::NoBrush) {
1494 setDefault(p, cg, QPalette::ButtonText, pal->foreground, w);
1495 setDefault(p, cg, w->foregroundRole(), pal->foreground, w);
1496 setDefault(p, cg, QPalette::WindowText, pal->foreground, w);
1497 setDefault(p, cg, QPalette::Text, pal->foreground, 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(p, cg, QPalette::PlaceholderText, placeholder, w);
1503 }
1504 if (pal->selectionBackground.style() != Qt::NoBrush)
1505 p->setBrush(cg, QPalette::Highlight, pal->selectionBackground);
1506 if (pal->selectionForeground.style() != Qt::NoBrush)
1507 p->setBrush(cg, QPalette::HighlightedText, pal->selectionForeground);
1508 if (pal->alternateBackground.style() != Qt::NoBrush)
1509 p->setBrush(cg, QPalette::AlternateBase, pal->alternateBackground);
1510 if (pal->placeholderForeground.style() != Qt::NoBrush)
1511 p->setBrush(cg, QPalette::PlaceholderText, pal->placeholderForeground);
1512 if (pal->accent.style() != Qt::NoBrush)
1513 p->setBrush(cg, QPalette::Accent, 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
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 *>(obj) && qstrcmp(obj->metaObject()->className(), "QTipLabel") == 0) {
1539 QObject *p = qvariant_cast<QObject *>(obj->property("_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(metaObject->className(), "QTipLabel") == 0)
1559 return QStringList("QToolTip"_L1);
1560#endif
1562 do {
1563 result += QString::fromLatin1(metaObject->className()).replace(u':', 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)];
1576 if (cacheIt != cache.constEnd())
1577 return cacheIt.value();
1578
1580 QString valueStr;
1581 QObject *obj = OBJECT_PTR(node);
1582 const int propertyIndex = obj->metaObject()->indexOfProperty(name.toLatin1());
1583 if (propertyIndex == -1) {
1584 value = obj->property(name.toLatin1()); // might be a dynamic property
1585 if (!value.isValid()) {
1586 if (name == "class"_L1) {
1587 QString className = QString::fromLatin1(obj->metaObject()->className());
1588 if (className.contains(u':'))
1589 className.replace(u':', u'-');
1590 valueStr = className;
1591 } else if (name == "style"_L1) {
1593 QStyleSheetStyle *proxy = w ? qt_styleSheet(w->style()) : nullptr;
1594 if (proxy)
1595 valueStr = QString::fromLatin1(proxy->baseStyle()->metaObject()->className());
1596 }
1597 }
1598 } else {
1599 const QMetaProperty property = obj->metaObject()->property(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(&isNumber);
1605 if (isNumber)
1606 value.convert(QMetaType::fromType<int>());
1607 }
1608 }
1609 if (value.isValid()) {
1610 valueStr = (value.userType() == QMetaType::QStringList
1611 || value.userType() == QMetaType::QVariantList)
1612 ? value.toStringList().join(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(metaObject->className(), "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(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(baseStyle());
1675 if (defaultCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1676 defaultSs = getDefaultStyleSheet();
1677 QStyle *bs = baseStyle();
1678 styleSheetCaches->styleSheetCache.insert(bs, defaultSs);
1679 QObject::connect(bs, &QStyle::destroyed, styleSheetCaches,
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("file:///"_L1))
1692 ss.remove(0, 8);
1693 parser.init(ss, qApp->styleSheet() != ss);
1694 if (Q_UNLIKELY(!parser.parse(&appSs)))
1695 qWarning("Could not parse application stylesheet");
1696 appSs.origin = StyleSheetOrigin_Inline;
1697 appSs.depth = 1;
1698 styleSheetCaches->styleSheetCache.insert(qApp, 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(o)) {
1707 QString styleSheet = o->property("styleSheet").toString();
1708 if (styleSheet.isEmpty())
1709 continue;
1710 StyleSheet ss;
1711 QHash<const void *, StyleSheet>::const_iterator objCacheIt = styleSheetCaches->styleSheetCache.constFind(o);
1712 if (objCacheIt == styleSheetCaches->styleSheetCache.constEnd()) {
1713 parser.init(styleSheet);
1714 if (!parser.parse(&ss)) {
1715 parser.init("* {"_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(o, ss);
1721 } else {
1722 ss = objCacheIt.value();
1723 }
1724 objectSs.append(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
1733 n.ptr = const_cast<QObject *>(obj);
1734 QList<QCss::StyleRule> rules = styleSelector.styleRulesForNode(n);
1735 styleSheetCaches->styleRulesCache.insert(obj, rules);
1736 return rules;
1737}
1738
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(0);
1747 // Rules with pseudo elements don't cascade. This is an intentional
1748 // diversion for CSS
1749 if (part.compare(selector.pseudoElement(), Qt::CaseInsensitive) != 0)
1750 continue;
1751 quint64 negated = 0;
1752 quint64 cssClass = selector.pseudoClass(&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 *>(w))
1767#endif
1768
1769#if QT_CONFIG(combobox)
1770 if (qobject_cast<const QComboBox *>(w))
1772#endif
1773
1774#if QT_CONFIG(menu)
1775 if (qobject_cast<const QMenu *>(w))
1776 return base->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr, w);
1777#endif
1778
1779#if QT_CONFIG(menubar)
1780 if (qobject_cast<const QMenuBar *>(w))
1782#endif
1783#ifndef QT_NO_FRAME
1784 if (const QFrame *frame = qobject_cast<const QFrame *>(w)) {
1786 return 0;
1787 }
1788#endif
1789
1790 if (qstrcmp(w->metaObject()->className(), "QTipLabel") == 0)
1792
1794}
1795
1796static quint64 pseudoClass(QStyle::State state)
1797{
1798 quint64 pc = 0;
1800 pc |= PseudoClass_Enabled;
1802 pc |= PseudoClass_Hover;
1803 } else {
1805 }
1807 pc |= PseudoClass_Active;
1809 pc |= PseudoClass_Window;
1811 pc |= PseudoClass_Pressed;
1813 pc |= PseudoClass_Focus;
1814 if (state & QStyle::State_On)
1824 else
1827 pc |= PseudoClass_Open;
1828 else
1829 pc |= PseudoClass_Closed;
1833 pc |= PseudoClass_Sibling;
1837 pc |= PseudoClass_Item;
1838#ifdef QT_KEYPAD_NAVIGATION
1839 if (state & QStyle::State_HasEditFocus)
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((*obj)->metaObject()->className(), "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, &element);
1865 QHash<quint64, QRenderRule> &cache = styleSheetCaches->renderRulesCache[obj][element];
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(0);
1877 quint64 negated = 0;
1878 stateMask |= selector.pseudoClass(&negated);
1879 stateMask |= negated;
1880 }
1881
1882 cacheIt = cache.constFind(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(rules, part, 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))
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;
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)
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))) {
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)
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)
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) {
2018 extraClass |= PseudoClass_Top;
2019 break;
2022 extraClass |= PseudoClass_Bottom;
2023 break;
2026 extraClass |= PseudoClass_Right;
2027 break;
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) {
2055 extraClass |= PseudoClass_Top;
2056 break;
2059 extraClass |= PseudoClass_Bottom;
2060 break;
2063 extraClass |= PseudoClass_Right;
2064 break;
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)) {
2075 extraClass |= PseudoClass_Flat;
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 *>(obj)) {
2154 }
2155 else if (const QTextEdit *edit = qobject_cast<const QTextEdit *>(obj)) {
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 *>(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 *>(obj)) {
2171 if (frm->lineWidth() == 0)
2172 extraClass |= PseudoClass_Frameless;
2173 }
2174 }
2175
2176 return renderRule(obj, pseudoElement, 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(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(0);
2199 if (pseudoElement.compare(selector.pseudoElement(), 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:
2265
2266 case PseudoElement_ScrollBarAddLine:
2267 case PseudoElement_ScrollBarLast:
2268 case PseudoElement_SpinBoxDownButton:
2269 case PseudoElement_PushButtonMenuIndicator:
2270 case PseudoElement_ToolButtonMenuIndicator:
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:
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:
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(PM_IndicatorWidth, nullptr, w));
2320 if (sz.height() == -1)
2321 sz.setHeight(base->pixelMetric(PM_IndicatorHeight, nullptr, w));
2322 break;
2323
2324 case PseudoElement_ExclusiveIndicator:
2325 case PseudoElement_GroupBoxIndicator:
2326 if (sz.width() == -1)
2327 sz.setWidth(base->pixelMetric(PM_ExclusiveIndicatorWidth, nullptr, w));
2328 if (sz.height() == -1)
2329 sz.setHeight(base->pixelMetric(PM_ExclusiveIndicatorHeight, nullptr, w));
2330 break;
2331
2332 case PseudoElement_PushButtonMenuIndicator: {
2333 int pm = base->pixelMetric(PM_MenuButtonIndicator, nullptr, 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(PM_MenuButtonIndicator, nullptr, w));
2371 break;
2372
2373 case PseudoElement_HeaderViewUpArrow:
2374 case PseudoElement_HeaderViewDownArrow: {
2375 int pm = base->pixelMetric(PM_HeaderMargin, nullptr, 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(QStyle::PM_ScrollBarExtent, nullptr, 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(PM_SmallIconSize, nullptr, 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, rule2.size(), originRect, pe);
2444 sz = sz.expandedTo(rule2.minimumContentsSize());
2445 r = QStyle::alignedRect(dir, position, sz, 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(dir == Qt::LeftToRight ? left : -left, top);
2450 }
2451 } else {
2452 r = p ? originRect.adjusted(dir == Qt::LeftToRight ? p->left : p->right, p->top,
2453 dir == Qt::LeftToRight ? -p->right : -p->left, -p->bottom)
2454 : originRect;
2455 if (rule2.hasContentsSize()) {
2456 QSize sz = rule2.size().expandedTo(rule2.minimumContentsSize());
2457 if (sz.width() == -1) sz.setWidth(r.width());
2458 if (sz.height() == -1) sz.setHeight(r.height());
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
2479static QWidget *embeddedWidget(QWidget *w)
2480{
2481#if QT_CONFIG(combobox)
2482 if (QComboBox *cmb = qobject_cast<QComboBox *>(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 *>(w))
2492 return sb->findChild<QLineEdit *>();
2493#endif
2494
2495#if QT_CONFIG(scrollarea)
2496 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w))
2497 return sa->viewport();
2498#endif
2499
2500 return w;
2501}
2502
2511static QWidget *containerWidget(const QWidget *w)
2512{
2513#if QT_CONFIG(lineedit)
2514 if (qobject_cast<const QLineEdit *>(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 *>(w->parentWidget()))
2518 return w->parentWidget();
2519#endif
2520#if QT_CONFIG(spinbox)
2521 if (qobject_cast<const QAbstractSpinBox *>(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 *>(w->parentWidget())) {
2529 if (sa->viewport() == w)
2530 return w->parentWidget();
2531 }
2532#endif
2533
2534 return const_cast<QWidget *>(w);
2535}
2536
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 *>(w)) {
2554 if (0
2555#if QT_CONFIG(combobox)
2556 || qobject_cast<const QComboBox *>(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*>(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 *>(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 *>(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 *>(w)) {
2589 } else
2590#endif
2591#if QT_CONFIG(textedit)
2592 if (const QTextEdit *edit = qobject_cast<const QTextEdit *>(w)) {
2594 } else
2595 if (const QPlainTextEdit *edit = qobject_cast<const QPlainTextEdit *>(w)) {
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(w, PseudoElement_None, PseudoClass_Enabled | extendedPseudoClass(w));
2612 const QStyleSheetGeometryData *geo = rule.geometry();
2613 if (w->property("_q_stylesheet_minw").toBool()
2614 && ((!rule.hasGeometry() || geo->minWidth == -1))) {
2615 w->setMinimumWidth(0);
2616 w->setProperty("_q_stylesheet_minw", QVariant());
2617 }
2618 if (w->property("_q_stylesheet_minh").toBool()
2619 && ((!rule.hasGeometry() || geo->minHeight == -1))) {
2620 w->setMinimumHeight(0);
2621 w->setProperty("_q_stylesheet_minh", QVariant());
2622 }
2623 if (w->property("_q_stylesheet_maxw").toBool()
2624 && ((!rule.hasGeometry() || geo->maxWidth == -1))) {
2625 w->setMaximumWidth(QWIDGETSIZE_MAX);
2626 w->setProperty("_q_stylesheet_maxw", QVariant());
2627 }
2628 if (w->property("_q_stylesheet_maxh").toBool()
2629 && ((!rule.hasGeometry() || geo->maxHeight == -1))) {
2630 w->setMaximumHeight(QWIDGETSIZE_MAX);
2631 w->setProperty("_q_stylesheet_maxh", QVariant());
2632 }
2633
2634
2635 if (rule.hasGeometry()) {
2636 if (geo->minWidth != -1) {
2637 w->setProperty("_q_stylesheet_minw", true);
2638 w->setMinimumWidth(rule.boxSize(QSize(qMax(geo->width, geo->minWidth), 0)).width());
2639 }
2640 if (geo->minHeight != -1) {
2641 w->setProperty("_q_stylesheet_minh", true);
2642 w->setMinimumHeight(rule.boxSize(QSize(0, qMax(geo->height, geo->minHeight))).height());
2643 }
2644 if (geo->maxWidth != -1) {
2645 w->setProperty("_q_stylesheet_maxw", true);
2646 w->setMaximumWidth(rule.boxSize(QSize(qMin(geo->width == -1 ? QWIDGETSIZE_MAX : geo->width,
2647 geo->maxWidth == -1 ? QWIDGETSIZE_MAX : geo->maxWidth), 0)).width());
2648 }
2649 if (geo->maxHeight != -1) {
2650 w->setProperty("_q_stylesheet_maxh", true);
2651 w->setMaximumHeight(rule.boxSize(QSize(0, qMin(geo->height == -1 ? QWIDGETSIZE_MAX : geo->height,
2652 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(w), 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("qproperty-"_L1, Qt::CaseInsensitive))
2672 continue;
2673 if (!propertySet.hasSeen(property))
2674 finals.append(i);
2675 }
2676 }
2677
2678 for (int i = finals.size() - 1; i >= 0; --i) {
2679 const Declaration &decl = decls.at(finals[i]);
2680 QStringView property = decl.d->property;
2681 property = property.mid(10); // strip "qproperty-"
2682 const auto propertyL1 = property.toLatin1();
2683
2684 const QMetaObject *metaObject = w->metaObject();
2685 int index = metaObject->indexOfProperty(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(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(0).variant.toString()); break;
2708#endif
2709 default: v = decl.d->values.at(0).variant; break;
2710 }
2711
2712 if (propertyL1 == QByteArrayView("styleSheet") && value == v)
2713 continue;
2714
2715 w->setProperty(propertyL1, v);
2716 }
2717}
2718
2719void QStyleSheetStyle::setPalette(QWidget *w)
2720{
2721 struct RuleRoleMap {
2722 int state;
2724 } map[3] = {
2725 { int(PseudoClass_Active | PseudoClass_Enabled), QPalette::Active },
2728 };
2729
2730 const bool 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(w, PseudoElement_None, map[i].state | extendedPseudoClass(w));
2741 if (i == 0) {
2742 if (!w->property("_q_styleSheetWidgetFont").isValid()) {
2743 saveWidgetFont(w, w->d_func()->localFont());
2744 }
2746 if (ew != w)
2748 }
2749
2750 rule.configurePalette(&p, map[i].group, ew, ew != w);
2751 }
2752
2753 if (!useStyleSheetPropagationInWidgetStyles || p.resolveMask() != 0) {
2754 QPalette wp = w->palette();
2755 styleSheetCaches->customPaletteWidgets.insert(w, {wp, p.resolveMask()});
2756
2757 if (useStyleSheetPropagationInWidgetStyles) {
2758 p = p.resolve(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 =
2772
2773 const auto it = styleSheetCaches->customPaletteWidgets.find(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(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("_q_styleSheetWidgetFont");
2797 if (oldFont.isValid()) {
2798 w->setFont(qvariant_cast<QFont>(oldFont));
2799 }
2800 }
2801
2802 if (styleSheetCaches->autoFillDisabledWidgets.contains(w)) {
2803 embeddedWidget(w)->setAutoFillBackground(true);
2804 styleSheetCaches->autoFillDisabledWidgets.remove(w);
2805 }
2806}
2807
2808void QStyleSheetStyle::unsetStyleSheetFont(QWidget *w) const
2809{
2810 const auto it = styleSheetCaches->customFontWidgets.find(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(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(object);
2823 styleSheetCaches->hasStyleRuleCache.remove(object);
2824 styleSheetCaches->renderRulesCache.remove(object);
2825 }
2826 }
2827
2829 for (const QObject *object : objects) {
2830 if (auto widget = qobject_cast<QWidget*>(const_cast<QObject*>(object))) {
2833 QList<const QObject *> children;
2834 children.reserve(widget->children().size() + 1);
2835 for (auto child: std::as_const(widget->children()))
2836 children.append(child);
2837 updateObjects(children);
2838 }
2839 }
2840}
2841
2843// The stylesheet style
2845
2847 : QWindowsStyle(*new QStyleSheetStylePrivate), base(base), refcount(1)
2848{
2849 ++numinstances;
2850 if (numinstances == 1) {
2851 styleSheetCaches = new QStyleSheetStyleCaches;
2852 }
2853}
2854
2856{
2857 --numinstances;
2858 if (numinstances == 0) {
2859 delete styleSheetCaches;
2860 }
2861}
2863{
2864 if (base)
2865 return base;
2867 return me->base;
2868 return QApplication::style();
2869}
2870
2872{
2875 renderRulesCache.remove(o);
2876 customPaletteWidgets.remove((const QWidget *)o);
2877 customFontWidgets.remove(static_cast<QWidget *>(o));
2880}
2881
2883{
2885}
2886
2891bool QStyleSheetStyle::initObject(const QObject *obj) const
2892{
2893 if (!obj)
2894 return false;
2895 if (const QWidget *w = qobject_cast<const QWidget*>(obj)) {
2896 if (w->testAttribute(Qt::WA_StyleSheet))
2897 return true;
2898 if (unstylable(w))
2899 return false;
2900 const_cast<QWidget *>(w)->setAttribute(Qt::WA_StyleSheet, true);
2901 }
2902
2904 styleSheetCaches, &QStyleSheetStyleCaches::objectDestroyed,
2906 return true;
2907}
2908
2910{
2911 baseStyle()->polish(w);
2912 RECURSION_GUARD(return)
2913
2914 if (!initObject(w))
2915 return;
2916
2917 if (styleSheetCaches->styleRulesCache.contains(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(w);
2921 styleSheetCaches->hasStyleRuleCache.remove(w);
2922 styleSheetCaches->renderRulesCache.remove(w);
2923 styleSheetCaches->styleSheetCache.remove(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(w);
2932 for (int i = 0; i < rules.size(); i++) {
2933 const Selector& selector = rules.at(i).selectors.at(0);
2934 quint64 negated = 0;
2935 quint64 cssClass = selector.pseudoClass(&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 *>(w)) {
2946 QRenderRule rule = renderRule(sa, PseudoElement_None, PseudoClass_Enabled);
2947 if ((rule.hasBorder() && rule.border()->hasBorderImage())
2948 || (rule.hasBackground() && !rule.background()->pixmap.isNull())) {
2949 connect(sa->horizontalScrollBar(), &QScrollBar::valueChanged,
2950 sa, QOverload<>::of(&QAbstractScrollArea::update), Qt::UniqueConnection);
2951 connect(sa->verticalScrollBar(), &QScrollBar::valueChanged,
2952 sa, QOverload<>::of(&QAbstractScrollArea::update), Qt::UniqueConnection);
2953 }
2954 }
2955#endif
2956
2957 QRenderRule rule = renderRule(w, PseudoElement_None, PseudoClass_Any);
2958
2959 w->setAttribute(Qt::WA_StyleSheetTarget, rule.hasModification());
2960
2961 if (rule.hasDrawable() || rule.hasBox()) {
2962 if (w->metaObject() == &QWidget::staticMetaObject
2963#if QT_CONFIG(itemviews)
2964 || qobject_cast<QHeaderView *>(w)
2965#endif
2966#if QT_CONFIG(tabbar)
2967 || qobject_cast<QTabBar *>(w)
2968#endif
2969#ifndef QT_NO_FRAME
2970 || qobject_cast<QFrame *>(w)
2971#endif
2972#if QT_CONFIG(mainwindow)
2973 || qobject_cast<QMainWindow *>(w)
2974#endif
2975#if QT_CONFIG(mdiarea)
2976 || qobject_cast<QMdiSubWindow *>(w)
2977#endif
2978#if QT_CONFIG(menubar)
2979 || qobject_cast<QMenuBar *>(w)
2980#endif
2981#if QT_CONFIG(dialog)
2982 || qobject_cast<QDialog *>(w)
2983#endif
2984 ) {
2985 w->setAttribute(Qt::WA_StyledBackground, true);
2986 }
2987 QWidget *ew = embeddedWidget(w);
2988 if (ew->autoFillBackground()) {
2989 ew->setAutoFillBackground(false);
2990 styleSheetCaches->autoFillDisabledWidgets.insert(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, true);
2994 }
2995 }
2996 if (!rule.hasBackground() || rule.background()->isTransparent() || rule.hasBox()
2997 || (!rule.hasNativeBorder() && !rule.border()->isOpaque()))
2998 w->setAttribute(Qt::WA_OpaquePaintEvent, false);
2999 if (rule.hasBox() || !rule.hasNativeBorder()
3000#if QT_CONFIG(pushbutton)
3001 || (qobject_cast<QPushButton *>(w))
3002#endif
3003 )
3004 w->setAttribute(Qt::WA_MacShowFocusRect, false);
3005 }
3006}
3007
3009{
3010 baseStyle()->polish(app);
3011}
3012
3014{
3015 baseStyle()->polish(pal);
3016}
3017
3019{
3020 QList<const QObject *> children;
3021 children.reserve(w->children().size() + 1);
3022 for (auto child: std::as_const(w->children()))
3023 children.append(child);
3024 children.append(w);
3025 styleSheetCaches->styleSheetCache.remove(w);
3026 updateObjects(children);
3027}
3028
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(allObjects);
3038}
3039
3041{
3042 if (!w || !w->testAttribute(Qt::WA_StyleSheet)) {
3043 baseStyle()->unpolish(w);
3044 return;
3045 }
3046
3047 styleSheetCaches->styleRulesCache.remove(w);
3048 styleSheetCaches->hasStyleRuleCache.remove(w);
3049 styleSheetCaches->renderRulesCache.remove(w);
3050 styleSheetCaches->styleSheetCache.remove(w);
3051 unsetPalette(w);
3052 setGeometry(w);
3053 w->setAttribute(Qt::WA_StyleSheetTarget, false);
3054 w->setAttribute(Qt::WA_StyleSheet, false);
3055 w->disconnect(this);
3056#if QT_CONFIG(scrollarea)
3057 if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w)) {
3058 disconnect(sa->horizontalScrollBar(), &QScrollBar::valueChanged,
3059 sa, QOverload<>::of(&QAbstractScrollArea::update));
3060 disconnect(sa->verticalScrollBar(), &QScrollBar::valueChanged,
3061 sa, QOverload<>::of(&QAbstractScrollArea::update));
3062 }
3063#endif
3064 baseStyle()->unpolish(w);
3065}
3066
3068{
3070 RECURSION_GUARD(return)
3071 styleSheetCaches->styleRulesCache.clear();
3072 styleSheetCaches->hasStyleRuleCache.clear();
3073 styleSheetCaches->renderRulesCache.clear();
3074 styleSheetCaches->styleSheetCache.remove(qApp);
3075}
3076
3078 const QWidget *w) const
3079{
3080 RECURSION_GUARD(baseStyle()->drawComplexControl(cc, opt, p, w); return)
3081
3082 QRenderRule rule = renderRule(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(opt->rect);
3089 if (rule.hasNativeBorder()) {
3090 rule.drawBackgroundImage(p, cmbOpt.rect);
3091 rule.configurePalette(&cmbOpt.palette, QPalette::ButtonText, QPalette::Button);
3092 bool customDropDown = (opt->subControls & QStyle::SC_ComboBoxArrow)
3093 && (hasStyleRule(w, PseudoElement_ComboBoxDropDown) || hasStyleRule(w, PseudoElement_ComboBoxArrow));
3094 if (customDropDown)
3095 cmbOpt.subControls &= ~QStyle::SC_ComboBoxArrow;
3096 if (rule.baseStyleCanDraw()) {
3097 baseStyle()->drawComplexControl(cc, &cmbOpt, p, w);
3098 } else {
3099 QWindowsStyle::drawComplexControl(cc, &cmbOpt, p, w);
3100 }
3101 if (!customDropDown)
3102 return;
3103 } else {
3104 rule.drawRule(p, opt->rect);
3105 }
3106
3107 if (opt->subControls & QStyle::SC_ComboBoxArrow) {
3108 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
3109 if (subRule.hasDrawable()) {
3110 QRect r = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow, w);
3111 subRule.drawRule(p, r);
3112 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_ComboBoxArrow);
3113 r = positionRect(w, subRule, subRule2, PseudoElement_ComboBoxArrow, r, opt->direction);
3114 subRule2.drawRule(p, r);
3115 } else {
3116 rule.configurePalette(&cmbOpt.palette, QPalette::ButtonText, QPalette::Button);
3117 cmbOpt.subControls = QStyle::SC_ComboBoxArrow;
3118 QWindowsStyle::drawComplexControl(cc, &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(&spinOpt.palette, QPalette::ButtonText, QPalette::Button);
3131 rule.configurePalette(&spinOpt.palette, QPalette::Text, QPalette::Base);
3132 spinOpt.rect = rule.borderRect(opt->rect);
3133 bool customUp = true, customDown = true;
3134 QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
3135 QRenderRule downRule = renderRule(w, opt, 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, spinOpt.rect);
3140 customUp = (opt->subControls & QStyle::SC_SpinBoxUp)
3141 && (hasStyleRule(w, PseudoElement_SpinBoxUpButton) || hasStyleRule(w, PseudoElement_UpArrow));
3142 if (customUp)
3143 spinOpt.subControls &= ~QStyle::SC_SpinBoxUp;
3144 customDown = (opt->subControls & QStyle::SC_SpinBoxDown)
3145 && (hasStyleRule(w, PseudoElement_SpinBoxDownButton) || hasStyleRule(w, PseudoElement_DownArrow));
3146 if (customDown)
3147 spinOpt.subControls &= ~QStyle::SC_SpinBoxDown;
3148 if (rule.baseStyleCanDraw()) {
3149 baseStyle()->drawComplexControl(cc, &spinOpt, p, w);
3150 } else {
3151 QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3152 }
3153 if (!customUp && !customDown)
3154 return;
3155 } else {
3156 rule.drawRule(p, opt->rect);
3157 }
3158
3159 if ((opt->subControls & QStyle::SC_SpinBoxUp) && customUp) {
3160 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
3161 if (subRule.hasDrawable()) {
3162 QRect r = subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w);
3163 subRule.drawRule(p, r);
3164 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SpinBoxUpArrow);
3165 r = positionRect(w, subRule, subRule2, PseudoElement_SpinBoxUpArrow, r, opt->direction);
3166 subRule2.drawRule(p, r);
3167 } else {
3168 spinOpt.subControls = QStyle::SC_SpinBoxUp;
3169 QWindowsStyle::drawComplexControl(cc, &spinOpt, p, w);
3170 }
3171 }
3172
3173 if ((opt->subControls & QStyle::SC_SpinBoxDown) && customDown) {
3174 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
3175 if (subRule.hasDrawable()) {
3176 QRect r = subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w);
3177 subRule.drawRule(p, r);
3178 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SpinBoxDownArrow);
3179 r = positionRect(w, subRule, subRule2, PseudoElement_SpinBoxDownArrow, r, opt->direction);
3180 subRule2.drawRule(p, r);
3181 } else {
3182 spinOpt.subControls = QStyle::SC_SpinBoxDown;
3183 QWindowsStyle::drawComplexControl(cc, &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(w, PseudoElement_GroupBoxTitle))
3198 && !hasStyleRule(w, 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, opt->rect);
3203
3204 QRenderRule titleRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
3205 bool clipSet = false;
3206
3207 if (hasTitle) {
3208 labelRect = subControlRect(CC_GroupBox, opt, 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(ParentStyle::subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, w).size()));
3211 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3212 checkBoxRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxCheckBox, w);
3213 titleRect = titleRule.boxRect(checkBoxRect.united(labelRect));
3214 } else {
3215 titleRect = titleRule.boxRect(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_GroupBox, opt, SC_GroupBoxFrame, w);
3226 frame.QStyleOption::operator=(*gb);
3227 frame.features = gb->features;
3228 frame.lineWidth = gb->lineWidth;
3229 frame.midLineWidth = gb->midLineWidth;
3230 frame.rect = frameRect;
3231 drawPrimitive(PE_FrameGroupBox, &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, titleRect);
3239
3240 // draw the indicator
3241 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
3243 box.QStyleOption::operator=(*gb);
3244 box.rect = checkBoxRect;
3245 drawPrimitive(PE_IndicatorCheckBox, &box, p, w);
3246 }
3247
3248 // draw the text
3249 if (!gb->text.isEmpty()) {
3253 }
3254
3255 QPalette pal = gb->palette;
3256 if (gb->textColor.isValid())
3257 pal.setColor(QPalette::WindowText, gb->textColor);
3258 titleRule.configurePalette(&pal, QPalette::WindowText, QPalette::Window);
3259 drawItemText(p, labelRect, alignment, pal, gb->state & State_Enabled,
3260 gb->text, QPalette::WindowText);
3261
3262 if (gb->state & State_HasFocus) {
3264 fropt.QStyleOption::operator=(*gb);
3265 fropt.rect = labelRect;
3266 drawPrimitive(PE_FrameFocusRect, &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(&toolOpt.palette, QPalette::ButtonText, QPalette::Button);
3278 toolOpt.font = rule.font.resolve(toolOpt.font);
3279 toolOpt.rect = rule.borderRect(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(w, 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(w, 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(w, PseudoElement_ToolButtonMenuArrow);
3305 if (customDropDownArrow)
3307 }
3308 const bool customMenuIndicator = (!drawDropDown && drawMenuIndicator)
3309 && hasStyleRule(w, 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, 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)
3331 if (customDropDown || customDropDownArrow)
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, &nativeToolOpt, p, w);
3336 else
3337 QWindowsStyle::drawComplexControl(cc, &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, opt->rect);
3345 toolOpt.rect = rule.contentsRect(opt->rect);
3346 if (rule.hasFont)
3347 toolOpt.font = rule.font.resolve(toolOpt.font);
3348 drawControl(CE_ToolButtonLabel, &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(w, opt, PseudoElement_ToolButtonMenu);
3356 QRect menuButtonRect = subControlRect(CC_ToolButton, opt, QStyle::SC_ToolButtonMenu, w);
3357 if (subRule.hasDrawable()) {
3358 subRule.drawRule(p, menuButtonRect);
3359 } else {
3360 toolOpt.rect = menuButtonRect;
3361 baseStyle()->drawPrimitive(PE_IndicatorButtonDropDown, &toolOpt, p, w);
3362 }
3363
3364 if (customDropDownArrow || drawMenuIndicator) {
3365 QRenderRule arrowRule = renderRule(w, opt, PseudoElement_ToolButtonMenuArrow);
3366 QRect arrowRect = arrowRule.hasGeometry()
3367 ? positionRect(w, arrowRule, PseudoElement_ToolButtonMenuArrow, menuButtonRect, toolOpt.direction)
3368 : arrowRule.contentsRect(menuButtonRect);
3369 if (arrowRule.hasDrawable()) {
3370 arrowRule.drawRule(p, arrowRect);
3371 } else {
3372 toolOpt.rect = arrowRect;
3374 }
3375 }
3376 }
3377 } else if (drawMenuIndicator) {
3378 QRenderRule subRule = renderRule(w, opt, 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, rule, subRule, PseudoElement_ToolButtonMenuIndicator, opt->rect, toolOpt.direction);
3383 if (subRule.hasDrawable()) {
3384 subRule.drawRule(p, r);
3385 } else {
3386 toolOpt.rect = r;
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(w, opt, arrowElement);
3397 QRect arrowRect = subRule.hasGeometry() ? positionRect(w, subRule, arrowElement, toolOpt.rect, toolOpt.direction)
3398 : subRule.contentsRect(toolOpt.rect);
3399
3400 switch (toolOpt.toolButtonStyle) {
3402 break;
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(CE_ToolButtonLabel, &toolOpt, p, w);
3412 if (!subRule.hasGeometry())
3413 return;
3414 break;
3415 }
3417 // QToolButton handles this, so must never happen
3418 Q_ASSERT(false);
3419 break;
3420 }
3421 subRule.drawRule(p, 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(opt->rect);
3433 rule.drawBackgroundImage(p, opt->rect);
3434 baseStyle()->drawComplexControl(cc, &sbOpt, p, w);
3435 } else {
3436 rule.drawRule(p, 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, opt->rect);
3448
3449 QRenderRule grooveSubRule = renderRule(w, opt, PseudoElement_SliderGroove);
3450 QRenderRule handleSubRule = renderRule(w, opt, 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, &slOpt, p, w);
3458 if (!handleHasRule)
3459 return;
3460 }
3461
3462 QRect gr = subControlRect(cc, opt, SC_SliderGroove, w);
3463 if (slider->subControls & SC_SliderGroove) {
3464 grooveSubRule.drawRule(p, gr);
3465 }
3466
3467 if (slider->subControls & SC_SliderHandle) {
3468 QRect hr = subControlRect(cc, opt, SC_SliderHandle, w);
3469
3470 QRenderRule subRule1 = renderRule(w, opt, 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, r);
3477 }
3478
3479 QRenderRule subRule2 = renderRule(w, opt, 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, r);
3486 }
3487
3488 handleSubRule.drawRule(p, handleSubRule.boxRect(hr, 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(w, PseudoElement_MdiCloseButton)
3502 || hasStyleRule(w, PseudoElement_MdiNormalButton)
3503 || hasStyleRule(w, PseudoElement_MdiMinButton)) {
3504 QList<QVariant> layout = rule.styleHint("button-layout"_L1).toList();
3505 if (layout.isEmpty())
3506 layout = subControlLayout("mNX");
3507
3508 QStyleOptionComplex optCopy(*opt);
3509 optCopy.subControls = { };
3510 for (const QVariant &val : std::as_const(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(w, opt, layoutButton);
3519 if (subRule.hasDrawable()) {
3520 QRect rect = subRule.boxRect(subControlRect(CC_MdiControls, opt, control, w), Margin);
3521 subRule.drawRule(p, rect);
3522 QIcon icon = standardIcon(subControlIcon(layoutButton), opt);
3523 icon.paint(p, subRule.contentsRect(rect), Qt::AlignCenter);
3524 } else {
3525 optCopy.subControls |= control;
3526 }
3527 }
3528
3529 if (optCopy.subControls)
3530 baseStyle()->drawComplexControl(CC_MdiControls, &optCopy, p, 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(w, opt, PseudoElement_TitleBar);
3538 if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
3539 break;
3540 subRule.drawRule(p, 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(ir, Qt::white);
3550 p->drawText(ir.x(), ir.y(), ir.width(), ir.height(), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
3551 }
3552
3553 ir = layout[SC_TitleBarSysMenu];
3554 if (ir.isValid()) {
3555 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarSysMenu);
3556 subSubRule.drawRule(p, ir);
3557 ir = subSubRule.contentsRect(ir);
3558 if (!tb->icon.isNull()) {
3559 tb->icon.paint(p, ir);
3560 } else {
3561 int iconSize = pixelMetric(PM_SmallIconSize, tb, w);
3562 const QSize sz(iconSize, iconSize);
3563 const auto pm = standardIcon(SP_TitleBarMenuButton, nullptr, w)
3564 .pixmap(sz, paintDeviceDpr);
3566 }
3567 }
3568
3569 ir = layout[SC_TitleBarCloseButton];
3570 if (ir.isValid()) {
3571 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarCloseButton);
3572 subSubRule.drawRule(p, ir);
3573
3574 const QSize sz = subSubRule.contentsRect(ir).size();
3575 const auto type = ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool)
3576 ? SP_DockWidgetCloseButton : SP_TitleBarCloseButton;
3577 const auto pm = standardIcon(type, nullptr, w).pixmap(sz, paintDeviceDpr);
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(w, opt, pe);
3596 subSubRule.drawRule(p, ir);
3597 const QSize sz = subSubRule.contentsRect(ir).size();
3598 const auto pm = standardIcon(subControlIcon(pe), nullptr, w).pixmap(sz, paintDeviceDpr);
3600 }
3601
3602 return;
3603 }
3604 break;
3605
3606
3607 default:
3608 break;
3609 }
3610
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
3619 : QIcon::Disabled;
3620 const bool checked = mi->checkType != QStyleOptionMenuItem::NotCheckable && mi->checked;
3621 const auto iconSize = pixelMetric(PM_SmallIconSize, mi, w);
3622 const QSize sz(iconSize, iconSize);
3623 const QPixmap pixmap(mi->icon.pixmap(sz, p->device()->devicePixelRatio(), mode,
3624 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(w, mi, 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, subRule, iconRule, PseudoElement_MenuIcon, rect, mi->direction);
3635 if (mi->direction == Qt::LeftToRight)
3636 iconRect.moveLeft(iconRect.left());
3637 else
3638 iconRect.moveRight(iconRect.right());
3639 iconRule.drawRule(p, iconRect);
3640 QRect pmr(0, 0, pixw, pixh);
3641 pmr.moveCenter(iconRect.center());
3642 p->drawPixmap(pmr.topLeft(), 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(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(ce, opt, p, w);
3659 } else {
3660 QStyleOptionToolButton butOpt(*btn);
3661 rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3662 baseStyle()->drawControl(ce, &butOpt, p, w);
3663 }
3664 return;
3665 }
3666 break;
3667
3668 case CE_FocusFrame:
3669 if (!rule.hasNativeBorder()) {
3670 rule.drawBorder(p, 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(w, PseudoElement_PushButtonMenuIndicator))) {
3679 ParentStyle::drawControl(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(opt->rect);
3688 if (rule.hasNativeBorder()) {
3689 rule.drawBackgroundImage(p, btnOpt.rect);
3690 rule.configurePalette(&btnOpt.palette, QPalette::ButtonText, QPalette::Button);
3691 bool customMenu = (btn->features & QStyleOptionButton::HasMenu
3692 && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator));
3693 if (customMenu)
3694 btnOpt.features &= ~QStyleOptionButton::HasMenu;
3695 if (rule.baseStyleCanDraw()) {
3696 baseStyle()->drawControl(ce, &btnOpt, p, w);
3697 } else {
3698 QWindowsStyle::drawControl(ce, &btnOpt, p, w);
3699 }
3700 rule.drawImage(p, rule.contentsRect(opt->rect));
3701 if (!customMenu)
3702 return;
3703 } else {
3704 rule.drawRule(p, opt->rect);
3705 }
3706
3708 QRenderRule subRule = renderRule(w, opt, PseudoElement_PushButtonMenuIndicator);
3709 QRect ir = positionRect(w, rule, subRule, PseudoElement_PushButtonMenuIndicator,
3710 baseStyle()->subElementRect(SE_PushButtonBevel, btn, w), opt->direction);
3711 if (subRule.hasDrawable()) {
3712 subRule.drawRule(p, ir);
3713 } else {
3714 btnOpt.rect = ir;
3715 baseStyle()->drawPrimitive(PE_IndicatorArrowDown, &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(&butOpt.palette, QPalette::ButtonText, 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()) {
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_UnderlineShortcut, button, w))
3743 } else {
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)
3755 if (button->state & State_On)
3756 state = QIcon::On;
3757
3758 const auto paintDeviceDpr = p->device()->devicePixelRatio();
3759 QPixmap pixmap = icon.pixmap(button->iconSize, 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(opt->rect, tf, 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(button->direction, textRect, 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(pixelMetric(PM_ButtonShiftHorizontal, opt, w),
3796 pixelMetric(PM_ButtonShiftVertical, opt, w));
3797 p->drawPixmap(iconRect, pixmap);
3798 }
3799
3800 if (button->state & (State_On | State_Sunken))
3801 textRect.translate(pixelMetric(PM_ButtonShiftHorizontal, opt, w),
3802 pixelMetric(PM_ButtonShiftVertical, opt, w));
3803
3804 if (button->features & QStyleOptionButton::HasMenu) {
3805 int indicatorSize = pixelMetric(PM_MenuButtonIndicator, button, w);
3806 if (button->direction == Qt::LeftToRight)
3807 textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
3808 else
3809 textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
3810 }
3811 drawItemText(p, textRect, tf, butOpt.palette, (button->state & State_Enabled),
3813 } else {
3814 ParentStyle::drawControl(ce, &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(w, PseudoElement_Indicator)) {
3825 rule.drawRule(p, opt->rect);
3826 ParentStyle::drawControl(ce, opt, p, w);
3827 return;
3828 } else if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3829 QStyleOptionButton butOpt(*btn);
3830 rule.configurePalette(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3831 baseStyle()->drawControl(ce, &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(&butOpt.palette, QPalette::ButtonText, QPalette::Button);
3840 ParentStyle::drawControl(ce, &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, opt->rect);
3851 }
3852 if (rule.hasBorder()) {
3853 rule.drawBorder(p, rule.borderRect(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(opt->rect);
3859 baseStyle()->drawControl(ce, &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)) {
3877 int pe = ce == CE_MenuTearoff ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
3878 QRenderRule subRule = renderRule(w, opt, pe);
3879 mi.rect = subRule.contentsRect(opt->rect);
3880 rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3881 subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3882
3883 if (subRule.hasDrawable()) {
3884 subRule.drawRule(p, opt->rect);
3885 } else {
3886 baseStyle()->drawControl(ce, &mi, p, w);
3887 }
3888 }
3889 return;
3890
3891 case CE_MenuItem:
3892 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3894
3895 int pseudo = (mi.menuItemType == QStyleOptionMenuItem::Separator) ? PseudoElement_MenuSeparator : PseudoElement_Item;
3896 QRenderRule subRule = renderRule(w, opt, pseudo);
3897 mi.rect = subRule.contentsRect(opt->rect);
3898 rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3899 rule.configurePalette(&mi.palette, QPalette::HighlightedText, QPalette::Highlight);
3900 subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
3901 subRule.configurePalette(&mi.palette, QPalette::HighlightedText, 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(w, PseudoElement_Item, PseudoClass_Any);
3911
3912 if ((pseudo == PseudoElement_MenuSeparator) && subRule.hasDrawable()) {
3913 subRule.drawRule(p, 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, opt->rect);
3918 if (subRule.hasBackground()) {
3919 mi.palette.setBrush(QPalette::Highlight, Qt::NoBrush);
3920 mi.palette.setBrush(QPalette::Button, Qt::NoBrush);
3921 } else {
3922 mi.palette.setBrush(QPalette::Highlight, mi.palette.brush(QPalette::Button));
3923 }
3924 mi.palette.setBrush(QPalette::HighlightedText, mi.palette.brush(QPalette::ButtonText));
3925
3926 int textRectOffset = m->maxIconWidth;
3927 if (!mi.icon.isNull()) {
3928 renderMenuItemIcon(&mi, p, w, opt->rect, subRule);
3929 } else if (mi.menuHasCheckableItems) {
3930 const bool checkable = mi.checkType != QStyleOptionMenuItem::NotCheckable;
3931 const bool checked = checkable ? mi.checked : false;
3932
3933 const QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
3934 const QRect cmRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction);
3935 if (checkable && (subSubRule.hasDrawable() || checked)) {
3936 QStyleOptionMenuItem newMi = mi;
3938 newMi.state |= State_Enabled;
3939 if (mi.checked)
3940 newMi.state |= State_On;
3941 newMi.rect = cmRect;
3942 drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w);
3943 }
3944 textRectOffset = std::max(textRectOffset, cmRect.width());
3945 }
3946
3947 QRect textRect = subRule.contentsRect(opt->rect);
3948 textRect.setLeft(textRect.left() + textRectOffset);
3949 textRect.setWidth(textRect.width() - mi.reservedShortcutWidth);
3950 const QRect vTextRect = visualRect(opt->direction, m->rect, textRect);
3951
3952 QStringView s(mi.text);
3953 p->setPen(mi.palette.buttonText().color());
3954 if (!s.isEmpty()) {
3956 if (!styleHint(SH_UnderlineShortcut, &mi, w))
3957 text_flags |= Qt::TextHideMnemonic;
3958 qsizetype t = s.indexOf(u'\t');
3959 if (t >= 0) {
3960 QRect vShortcutRect = visualRect(opt->direction, mi.rect,
3961 QRect(textRect.topRight(), QPoint(mi.rect.right(), textRect.bottom())));
3962 p->drawText(vShortcutRect, text_flags, s.mid(t + 1).toString());
3963 s = s.left(t);
3964 }
3965 p->drawText(vTextRect, text_flags, s.left(t).toString());
3966 }
3967
3968 if (mi.menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
3969 PrimitiveElement arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
3970 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_MenuRightArrow);
3971 mi.rect = positionRect(w, subRule, subRule2, PseudoElement_MenuRightArrow, opt->rect, mi.direction);
3972 drawPrimitive(arrow, &mi, p, w);
3973 }
3974 } else if (!mi.icon.isNull() && hasStyleRule(w, PseudoElement_MenuIcon)) {
3975 // we wouldn't be here if the item itself would be styled, so now we only want
3976 // the text from the default style, and then draw the icon ourselves.
3977 QStyleOptionMenuItem newMi = mi;
3978 newMi.icon = {};
3979 newMi.checkType = QStyleOptionMenuItem::NotCheckable;
3980 if (rule.baseStyleCanDraw() && subRule.baseStyleCanDraw())
3981 baseStyle()->drawControl(ce, &newMi, p, w);
3982 else
3983 ParentStyle::drawControl(ce, &newMi, p, w);
3984 renderMenuItemIcon(&mi, p, w, opt->rect, subRule);
3985 } else if (hasStyleRule(w, PseudoElement_MenuCheckMark) || hasStyleRule(w, PseudoElement_MenuRightArrow)) {
3986 QWindowsStyle::drawControl(ce, &mi, p, w);
3987 if (mi.checkType != QStyleOptionMenuItem::NotCheckable && !mi.checked) {
3988 // We have a style defined, but QWindowsStyle won't draw anything if not checked.
3989 // So we mimic what QWindowsStyle would do.
3990 int checkcol = qMax<int>(mi.maxIconWidth, QWindowsStylePrivate::windowsCheckMarkWidth);
3991 QRect vCheckRect = visualRect(opt->direction, mi.rect, QRect(mi.rect.x(), mi.rect.y(), checkcol, mi.rect.height()));
3992 if (mi.state.testFlag(State_Enabled) && mi.state.testFlag(State_Selected)) {
3993 qDrawShadePanel(p, vCheckRect, mi.palette, true, 1, &mi.palette.brush(QPalette::Button));
3994 } else {
3995 QBrush fill(mi.palette.light().color(), Qt::Dense4Pattern);
3996 qDrawShadePanel(p, vCheckRect, mi.palette, true, 1, &fill);
3997 }
3998 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
3999 if (subSubRule.hasDrawable()) {
4000 QStyleOptionMenuItem newMi(mi);
4001 newMi.rect = visualRect(opt->direction, mi.rect, QRect(mi.rect.x() + QWindowsStylePrivate::windowsItemFrame,
4002 mi.rect.y() + QWindowsStylePrivate::windowsItemFrame,
4003 checkcol - 2 * QWindowsStylePrivate::windowsItemFrame,
4004 mi.rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame));
4005 drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w);
4006 }
4007 }
4008 } else {
4009 if (rule.hasDrawable() && !subRule.hasDrawable() && !(opt->state & QStyle::State_Selected)) {
4010 mi.palette.setColor(QPalette::Window, Qt::transparent);
4011 mi.palette.setColor(QPalette::Button, Qt::transparent);
4012 }
4013 if (rule.baseStyleCanDraw() && subRule.baseStyleCanDraw()) {
4014 baseStyle()->drawControl(ce, &mi, p, w);
4015 } else {
4016 ParentStyle::drawControl(ce, &mi, p, w);
4017 }
4018 }
4019
4020 p->setFont(oldFont);
4021
4022 return;
4023 }
4024 return;
4025
4026 case CE_MenuBarItem:
4027 if (const QStyleOptionMenuItem *m = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4029 QRenderRule subRule = renderRule(w, opt, PseudoElement_Item);
4030 mi.rect = subRule.contentsRect(opt->rect);
4031 rule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
4032 subRule.configurePalette(&mi.palette, QPalette::ButtonText, QPalette::Button);
4033
4034 if (subRule.hasDrawable()) {
4035 subRule.drawRule(p, opt->rect);
4036 QCommonStyle::drawControl(ce, &mi, p, w); // deliberate bypass of the base
4037 } else {
4038 if (rule.hasDrawable() && !(opt->state & QStyle::State_Selected)) {
4039 // So that the menu bar background is not hidden by the items
4040 mi.palette.setColor(QPalette::Window, Qt::transparent);
4041 mi.palette.setColor(QPalette::Button, Qt::transparent);
4042 }
4043 baseStyle()->drawControl(ce, &mi, p, w);
4044 }
4045 }
4046 return;
4047
4048#if QT_CONFIG(combobox)
4049 case CE_ComboBoxLabel:
4050 if (!rule.hasBox())
4051 break;
4052 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4053 QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, w);
4054 p->save();
4055 p->setClipRect(editRect);
4056 if (!cb->currentIcon.isNull()) {
4057 int spacing = rule.hasBox() ? rule.box()->spacing : -1;
4058 if (spacing == -1)
4059 spacing = 6;
4060 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
4061 const auto paintDeviceDpr = p->device()->devicePixelRatio();
4062 QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, paintDeviceDpr, mode);
4063 QRect iconRect(editRect);
4064 iconRect.setWidth(cb->iconSize.width());
4065 iconRect = alignedRect(cb->direction,
4067 iconRect.size(), editRect);
4069
4070 if (cb->direction == Qt::RightToLeft)
4071 editRect.translate(-spacing - cb->iconSize.width(), 0);
4072 else
4073 editRect.translate(cb->iconSize.width() + spacing, 0);
4074 }
4075 if (!cb->currentText.isEmpty() && !cb->editable) {
4076 QPalette styledPalette(cb->palette);
4077 rule.configurePalette(&styledPalette, QPalette::Text, QPalette::Base);
4078 drawItemText(p, editRect.adjusted(0, 0, 0, 0), cb->textAlignment, styledPalette,
4079 cb->state & State_Enabled, cb->currentText, QPalette::Text);
4080 }
4081 p->restore();
4082 return;
4083 }
4084 break;
4085#endif // QT_CONFIG(combobox)
4086
4087 case CE_Header:
4088 if (hasStyleRule(w, PseudoElement_HeaderViewUpArrow)
4089 || hasStyleRule(w, PseudoElement_HeaderViewDownArrow)) {
4090 ParentStyle::drawControl(ce, opt, p, w);
4091 return;
4092 }
4093 if (hasStyleRule(w, PseudoElement_HeaderViewSection)) {
4094 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
4095 if (!subRule.hasNativeBorder() || !subRule.baseStyleCanDraw()
4096 || subRule.hasBackground() || subRule.hasPalette() || subRule.hasFont || subRule.hasBorder()) {
4097 ParentStyle::drawControl(ce, opt, p, w);
4098 return;
4099 }
4100 }
4101 break;
4102 case CE_HeaderSection:
4103 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4104 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
4105 if (subRule.hasNativeBorder()) {
4107 subRule.configurePalette(&hdr.palette, QPalette::ButtonText, QPalette::Button);
4108
4109 if (subRule.baseStyleCanDraw()) {
4110 baseStyle()->drawControl(CE_HeaderSection, &hdr, p, w);
4111 } else {
4112 QWindowsStyle::drawControl(CE_HeaderSection, &hdr, p, w);
4113 }
4114 } else {
4115 subRule.drawRule(p, opt->rect);
4116 }
4117 return;
4118 }
4119 break;
4120
4121 case CE_HeaderLabel:
4122 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4124 QStyleOptionHeader &v1Copy = hdr;
4125 if (auto v2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(opt))
4126 hdr = *v2;
4127 else
4128 v1Copy = *header;
4129 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
4130 if (hasStyleRule(w, PseudoElement_HeaderViewUpArrow)
4131 || hasStyleRule(w, PseudoElement_HeaderViewDownArrow)) {
4133 const QRect arrowRect = subElementRect(SE_HeaderArrow, opt, w);
4134 if (hdr.orientation == Qt::Horizontal)
4135 hdr.rect.setWidth(hdr.rect.width() - arrowRect.width());
4136 else
4137 hdr.rect.setHeight(hdr.rect.height() - arrowRect.height());
4138 }
4139 }
4140 subRule.configurePalette(&hdr.palette, QPalette::ButtonText, QPalette::Button);
4141 if (subRule.hasFont) {
4142 QFont oldFont = p->font();
4143 p->setFont(subRule.font.resolve(p->font()));
4144 ParentStyle::drawControl(ce, &hdr, p, w);
4145 p->setFont(oldFont);
4146 } else {
4147 baseStyle()->drawControl(ce, &hdr, p, w);
4148 }
4149 return;
4150 }
4151 break;
4152
4153 case CE_HeaderEmptyArea:
4154 if (rule.hasDrawable()) {
4155 return;
4156 }
4157 break;
4158
4159 case CE_ProgressBar:
4160 QWindowsStyle::drawControl(ce, opt, p, w);
4161 return;
4162
4163 case CE_ProgressBarGroove:
4164 if (!rule.hasNativeBorder()) {
4165 rule.drawRule(p, rule.boxRect(opt->rect, Margin));
4166 return;
4167 }
4168 break;
4169
4170 case CE_ProgressBarContents: {
4171 QRenderRule subRule = renderRule(w, opt, PseudoElement_ProgressBarChunk);
4172 if (subRule.hasDrawable()) {
4173 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4174 p->save();
4175 p->setClipRect(pb->rect);
4176
4177 qint64 minimum = qint64(pb->minimum);
4178 qint64 maximum = qint64(pb->maximum);
4179 qint64 progress = qint64(pb->progress);
4180 bool vertical = !(pb->state & QStyle::State_Horizontal);
4181 bool inverted = pb->invertedAppearance;
4182
4183 QTransform m;
4184 QRect rect = pb->rect;
4185 if (vertical) {
4186 rect = QRect(rect.y(), rect.x(), rect.height(), rect.width());
4187 m.rotate(90);
4188 m.translate(0, -(rect.height() + rect.y()*2));
4189 }
4190
4191 bool reverse = ((!vertical && (pb->direction == Qt::RightToLeft)) || vertical);
4192 if (inverted)
4193 reverse = !reverse;
4194 const bool indeterminate = pb->minimum == pb->maximum;
4195 const auto fillRatio = indeterminate ? 0.50 : double(progress - minimum) / (maximum - minimum);
4196 const auto fillWidth = static_cast<int>(rect.width() * fillRatio);
4197 int chunkWidth = fillWidth;
4198 if (subRule.hasContentsSize()) {
4199 QSize sz = subRule.size();
4200 chunkWidth = (opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
4201 }
4202
4203 QRect r = rect;
4204#if QT_CONFIG(animation)
4205 Q_D(const QWindowsStyle);
4206#endif
4207 if (pb->minimum == 0 && pb->maximum == 0) {
4208 int chunkCount = fillWidth/chunkWidth;
4209 int offset = 0;
4210#if QT_CONFIG(animation)
4211 if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject)))
4212 offset = animation->animationStep() * 8 % rect.width();
4213 else
4214 d->startAnimation(new QProgressStyleAnimation(d->animationFps, opt->styleObject));
4215#endif
4216 int x = reverse ? r.left() + r.width() - offset - chunkWidth : r.x() + offset;
4217 while (chunkCount > 0) {
4218 r.setRect(x, rect.y(), chunkWidth, rect.height());
4219 r = m.mapRect(QRectF(r)).toRect();
4220 subRule.drawRule(p, r);
4221 x += reverse ? -chunkWidth : chunkWidth;
4222 if (reverse ? x < rect.left() : x > rect.right())
4223 break;
4224 --chunkCount;
4225 }
4226
4227 r = rect;
4228 x = reverse ? r.right() - (r.left() - x - chunkWidth)
4229 : r.left() + (x - r.right() - chunkWidth);
4230 while (chunkCount > 0) {
4231 r.setRect(x, rect.y(), chunkWidth, rect.height());
4232 r = m.mapRect(QRectF(r)).toRect();
4233 subRule.drawRule(p, r);
4234 x += reverse ? -chunkWidth : chunkWidth;
4235 --chunkCount;
4236 };
4237 } else if (chunkWidth > 0) {
4238 const auto ceil = [](qreal x) { return int(x) + (x > 0 && x != int(x)); };
4239 const int chunkCount = ceil(qreal(fillWidth)/chunkWidth);
4240 int x = reverse ? r.left() + r.width() - chunkWidth : r.x();
4241
4242 for (int i = 0; i < chunkCount; ++i) {
4243 r.setRect(x, rect.y(), chunkWidth, rect.height());
4244 r = m.mapRect(QRectF(r)).toRect();
4245 subRule.drawRule(p, r);
4246 x += reverse ? -chunkWidth : chunkWidth;
4247 }
4248#if QT_CONFIG(animation)
4249 d->stopAnimation(opt->styleObject);
4250#endif
4251 }
4252
4253 p->restore();
4254 return;
4255 }
4256 }
4257 }
4258 break;
4259
4260 case CE_ProgressBarLabel:
4261 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4262 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_ProgressBarChunk)) {
4263 drawItemText(p, pb->rect, pb->textAlignment | Qt::TextSingleLine, pb->palette,
4264 pb->state & State_Enabled, pb->text, QPalette::Text);
4265 } else {
4266 QStyleOptionProgressBar pbCopy(*pb);
4267 rule.configurePalette(&pbCopy.palette, QPalette::HighlightedText, QPalette::Highlight);
4268 baseStyle()->drawControl(ce, &pbCopy, p, w);
4269 }
4270 return;
4271 }
4272 break;
4273
4274 case CE_SizeGrip:
4275 if (const QStyleOptionSizeGrip *sgOpt = qstyleoption_cast<const QStyleOptionSizeGrip *>(opt)) {
4276 if (rule.hasDrawable()) {
4277 rule.drawFrame(p, opt->rect);
4278 p->save();
4279 static constexpr int rotation[] = { 180, 270, 90, 0 };
4280 if (rotation[sgOpt->corner]) {
4281 p->translate(opt->rect.center());
4282 p->rotate(rotation[sgOpt->corner]);
4283 p->translate(-opt->rect.center());
4284 }
4285 rule.drawImage(p, opt->rect);
4286 p->restore();
4287 } else {
4288 QStyleOptionSizeGrip sg(*sgOpt);
4289 sg.rect = rule.contentsRect(opt->rect);
4290 baseStyle()->drawControl(CE_SizeGrip, &sg, p, w);
4291 }
4292 return;
4293 }
4294 break;
4295
4296 case CE_ToolBoxTab:
4297 QWindowsStyle::drawControl(ce, opt, p, w);
4298 return;
4299
4300 case CE_ToolBoxTabShape: {
4301 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolBoxTab);
4302 if (subRule.hasDrawable()) {
4303 subRule.drawRule(p, opt->rect);
4304 return;
4305 }
4306 }
4307 break;
4308
4309 case CE_ToolBoxTabLabel:
4310 if (const QStyleOptionToolBox *box = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
4311 QStyleOptionToolBox boxCopy(*box);
4312 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolBoxTab);
4313 subRule.configurePalette(&boxCopy.palette, QPalette::ButtonText, QPalette::Button);
4314 QFont oldFont = p->font();
4315 if (subRule.hasFont)
4316 p->setFont(subRule.font.resolve(p->font()));
4317 boxCopy.rect = subRule.contentsRect(opt->rect);
4318 if (subRule.hasImage()) {
4319 // the image is already drawn with CE_ToolBoxTabShape, adjust rect here
4320 const int iconExtent = proxy()->pixelMetric(QStyle::PM_SmallIconSize, box, w);
4321 boxCopy.rect.setLeft(boxCopy.rect.left() + iconExtent);
4322 }
4323 QWindowsStyle::drawControl(ce, &boxCopy, p , w);
4324 if (subRule.hasFont)
4325 p->setFont(oldFont);
4326 return;
4327 }
4328 break;
4329
4330 case CE_ScrollBarAddPage:
4331 pe1 = PseudoElement_ScrollBarAddPage;
4332 break;
4333
4334 case CE_ScrollBarSubPage:
4335 pe1 = PseudoElement_ScrollBarSubPage;
4336 break;
4337
4338 case CE_ScrollBarAddLine:
4339 pe1 = PseudoElement_ScrollBarAddLine;
4340 pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarRightArrow : PseudoElement_ScrollBarDownArrow;
4341 fallback = true;
4342 break;
4343
4344 case CE_ScrollBarSubLine:
4345 pe1 = PseudoElement_ScrollBarSubLine;
4346 pe2 = (opt->state & QStyle::State_Horizontal) ? PseudoElement_ScrollBarLeftArrow : PseudoElement_ScrollBarUpArrow;
4347 fallback = true;
4348 break;
4349
4350 case CE_ScrollBarFirst:
4351 pe1 = PseudoElement_ScrollBarFirst;
4352 break;
4353
4354 case CE_ScrollBarLast:
4355 pe1 = PseudoElement_ScrollBarLast;
4356 break;
4357
4358 case CE_ScrollBarSlider:
4359 pe1 = PseudoElement_ScrollBarSlider;
4360 fallback = true;
4361 break;
4362
4363#if QT_CONFIG(itemviews)
4364 case CE_ItemViewItem:
4365 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4366 QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
4367 QStyleOptionViewItem optCopy(*vopt);
4368 if (subRule.hasDrawable()) {
4369 subRule.configurePalette(&optCopy.palette, vopt->state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text,
4370 vopt->state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base);
4371 QWindowsStyle::drawControl(ce, &optCopy, p, w);
4372 } else {
4373 p->save();
4374 if (hasStyleRule(w, PseudoElement_Indicator)) {
4375 // there is a rule for the indicator, but no rule for the item itself (otherwise
4376 // the previous path would have been taken); only draw the indicator using the
4377 // rule (via QWindows/QCommonStyle), then let the base style handle the rest.
4378 QStyleOptionViewItem optIndicator(*vopt);
4379 subRule.configurePalette(&optIndicator.palette,
4380 vopt->state & QStyle::State_Selected
4382 : QPalette::Text,
4383 vopt->state & QStyle::State_Selected
4385 : QPalette::Base);
4386 // only draw the indicator; no text, icon or background
4387 optIndicator.backgroundBrush = Qt::NoBrush; // no background
4388 optIndicator.text.clear();
4389 optIndicator.icon = QIcon();
4390 QWindowsStyle::drawControl(ce, &optIndicator, p, w);
4391
4392 // Now draw text, background,icon, and highlight, but not the indicator with
4393 // the base style. Since we can't turn off HasCheckIndicator to prevent the base
4394 // style from drawing the check indicator again (it would change how the item
4395 // gets laid out) we have to clip the indicator that's already been painted.
4397 &optIndicator, w);
4399 &optIndicator, w);
4400 const QRegion clipRegion = QRegion(p->hasClipping() ? p->clipRegion()
4401 : QRegion(optIndicator.rect))
4402 - crStyle.united(crBase);
4403 p->setClipRegion(clipRegion);
4404 }
4405 subRule.configurePalette(&optCopy.palette, QPalette::Text, QPalette::NoRole);
4406 baseStyle()->drawControl(ce, &optCopy, p, w);
4407 p->restore();
4408 }
4409 return;
4410 }
4411 break;
4412#endif // QT_CONFIG(itemviews)
4413
4414#if QT_CONFIG(tabbar)
4415 case CE_TabBarTab:
4416 if (hasStyleRule(w, PseudoElement_TabBarTab)) {
4417 QWindowsStyle::drawControl(ce, opt, p, w);
4418 return;
4419 }
4420 break;
4421
4422 case CE_TabBarTabLabel:
4423 case CE_TabBarTabShape:
4424 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4425 const auto foregroundRole = w ? w->foregroundRole() : QPalette::WindowText;
4426 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
4427 QRect r = positionRect(w, subRule, PseudoElement_TabBarTab, opt->rect, opt->direction);
4428 if (ce == CE_TabBarTabShape && subRule.hasDrawable() && tab->shape < QTabBar::TriangularNorth) {
4429 subRule.drawRule(p, r);
4430 return;
4431 }
4432 QStyleOptionTab tabCopy(*tab);
4433 subRule.configurePalette(&tabCopy.palette, foregroundRole, QPalette::Base);
4434 QFont oldFont = p->font();
4435 if (subRule.hasFont)
4436 p->setFont(subRule.font.resolve(p->font()));
4437 if (subRule.hasBox() || !subRule.hasNativeBorder()) {
4438 tabCopy.rect = ce == CE_TabBarTabShape ? subRule.borderRect(r)
4439 : subRule.contentsRect(r);
4440 QWindowsStyle::drawControl(ce, &tabCopy, p, w);
4441 } else {
4442 baseStyle()->drawControl(ce, &tabCopy, p, w);
4443 }
4444 if (subRule.hasFont)
4445 p->setFont(oldFont);
4446
4447 return;
4448 }
4449 break;
4450#endif // QT_CONFIG(tabbar)
4451
4452 case CE_ColumnViewGrip:
4453 if (rule.hasDrawable()) {
4454 rule.drawRule(p, opt->rect);
4455 return;
4456 }
4457 break;
4458
4459 case CE_DockWidgetTitle:
4460 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
4461 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
4462 if (!subRule.hasDrawable() && !subRule.hasPosition())
4463 break;
4464 if (subRule.hasDrawable()) {
4465 subRule.drawRule(p, opt->rect);
4466 } else {
4467 QStyleOptionDockWidget dwCopy(*dwOpt);
4468 dwCopy.title = QString();
4469 baseStyle()->drawControl(ce, &dwCopy, p, w);
4470 }
4471
4472 if (!dwOpt->title.isEmpty()) {
4473 QRect r = subElementRect(SE_DockWidgetTitleBarText, opt, w);
4474 if (dwOpt->verticalTitleBar) {
4475 r = r.transposed();
4476 p->save();
4477 p->translate(r.left(), r.top() + r.width());
4478 p->rotate(-90);
4479 p->translate(-r.left(), -r.top());
4480 }
4481 r = subRule.contentsRect(r);
4482
4483 Qt::Alignment alignment;
4484 if (subRule.hasPosition())
4485 alignment = subRule.position()->textAlignment;
4486 if (alignment == 0)
4488
4489 QString titleText = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, r.width());
4490 drawItemText(p, r,
4491 alignment | Qt::TextHideMnemonic, dwOpt->palette,
4492 dwOpt->state & State_Enabled, titleText,
4494
4495 if (dwOpt->verticalTitleBar)
4496 p->restore();
4497 }
4498
4499 return;
4500 }
4501 break;
4502 case CE_ShapedFrame:
4503 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4504 if (rule.hasNativeBorder()) {
4505 QStyleOptionFrame frmOpt(*frm);
4506 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4507 frmOpt.rect = rule.borderRect(frmOpt.rect);
4508 baseStyle()->drawControl(ce, &frmOpt, p, w);
4509 }
4510 // else, borders are already drawn in PE_Widget
4511 }
4512 return;
4513
4514
4515 default:
4516 break;
4517 }
4518
4519 if (pe1 != PseudoElement_None) {
4520 QRenderRule subRule = renderRule(w, opt, pe1);
4521 if (subRule.bg != nullptr || subRule.hasDrawable()) {
4522 //We test subRule.bg directly because hasBackground() would return false for background:none.
4523 //But we still don't want the default drawning in that case (example for QScrollBar::add-page) (task 198926)
4524 subRule.drawRule(p, opt->rect);
4525 } else if (fallback) {
4526 QWindowsStyle::drawControl(ce, opt, p, w);
4527 pe2 = PseudoElement_None;
4528 } else {
4529 baseStyle()->drawControl(ce, opt, p, w);
4530 }
4531 if (pe2 != PseudoElement_None) {
4532 QRenderRule subSubRule = renderRule(w, opt, pe2);
4533 QRect r = positionRect(w, subRule, subSubRule, pe2, opt->rect, opt->direction);
4534 subSubRule.drawRule(p, r);
4535 }
4536 return;
4537 }
4538
4539 baseStyle()->drawControl(ce, opt, p, w);
4540}
4541
4543 QPixmap &pixmap) const
4544{
4546}
4547
4549 bool enabled, const QString& text, QPalette::ColorRole textRole) const
4550{
4551 baseStyle()->drawItemText(painter, rect, alignment, pal, enabled, text, textRole);
4552}
4553
4554void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
4555 const QWidget *w) const
4556{
4557 RECURSION_GUARD(baseStyle()->drawPrimitive(pe, opt, p, w); return)
4558
4559 int pseudoElement = PseudoElement_None;
4560 QRenderRule rule = renderRule(w, opt);
4561 QRect rect = opt->rect;
4562
4563 switch (pe) {
4564
4565 case PE_FrameStatusBarItem: {
4566 QRenderRule subRule = renderRule(w ? w->parentWidget() : nullptr, opt, PseudoElement_Item);
4567 if (subRule.hasDrawable()) {
4568 subRule.drawRule(p, opt->rect);
4569 return;
4570 }
4571 break;
4572 }
4573
4574 case PE_IndicatorArrowDown:
4575 pseudoElement = PseudoElement_DownArrow;
4576 break;
4577
4578 case PE_IndicatorArrowUp:
4579 pseudoElement = PseudoElement_UpArrow;
4580 break;
4581
4582 case PE_IndicatorRadioButton:
4583 pseudoElement = PseudoElement_ExclusiveIndicator;
4584 break;
4585
4586 case PE_IndicatorItemViewItemCheck:
4587 pseudoElement = PseudoElement_ViewItemIndicator;
4588 break;
4589
4590 case PE_IndicatorCheckBox:
4591 pseudoElement = PseudoElement_Indicator;
4592 break;
4593
4594 case PE_IndicatorHeaderArrow:
4595 if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4596 pseudoElement = hdr->sortIndicator == QStyleOptionHeader::SortUp
4597 ? PseudoElement_HeaderViewUpArrow
4598 : PseudoElement_HeaderViewDownArrow;
4599 }
4600 break;
4601
4602 case PE_PanelButtonTool:
4603 case PE_PanelButtonCommand:
4604#if QT_CONFIG(abstractbutton)
4605 if (qobject_cast<const QAbstractButton *>(w) && rule.hasBackground() && rule.hasNativeBorder()) {
4606 //the window style will draw the borders
4607 ParentStyle::drawPrimitive(pe, opt, p, w);
4608 if (!rule.background()->pixmap.isNull() || rule.hasImage()) {
4609 rule.drawRule(p, rule.boxRect(opt->rect, QRenderRule::Margin).adjusted(1,1,-1,-1));
4610 }
4611 return;
4612 }
4613#endif
4614 if (!rule.hasNativeBorder()) {
4615 rule.drawRule(p, rule.boxRect(opt->rect, QRenderRule::Margin));
4616 return;
4617 }
4618 break;
4619
4620 case PE_IndicatorButtonDropDown: {
4621 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
4622 if (!subRule.hasNativeBorder()) {
4623 rule.drawBorder(p, opt->rect);
4624 return;
4625 }
4626 break;
4627 }
4628
4629 case PE_FrameDefaultButton:
4630 if (rule.hasNativeBorder()) {
4631 if (rule.baseStyleCanDraw())
4632 break;
4633 QWindowsStyle::drawPrimitive(pe, opt, p, w);
4634 }
4635 return;
4636
4637 case PE_FrameWindow:
4638 case PE_FrameDockWidget:
4639 case PE_Frame:
4640 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4641 if (rule.hasNativeBorder()) {
4642 QStyleOptionFrame frmOpt(*frm);
4643 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4644 baseStyle()->drawPrimitive(pe, &frmOpt, p, w);
4645 } else {
4646 rule.drawBorder(p, rule.borderRect(opt->rect));
4647 }
4648 }
4649 return;
4650
4651 case PE_PanelLineEdit:
4652 if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4653 // Fall back to container widget's render rule
4654 if (w) {
4655 if (QWidget *container = containerWidget(w); container != w) {
4656 QRenderRule containerRule = renderRule(container, opt);
4657 if (!containerRule.hasNativeBorder() || !containerRule.baseStyleCanDraw())
4658 return;
4659 rule = containerRule;
4660 }
4661 }
4662
4663 if (rule.hasNativeBorder()) {
4664 QStyleOptionFrame frmOpt(*frm);
4665 rule.configurePalette(&frmOpt.palette, QPalette::Text, QPalette::Base);
4666 frmOpt.rect = rule.borderRect(frmOpt.rect);
4667 if (rule.baseStyleCanDraw()) {
4668 rule.drawBackgroundImage(p, opt->rect);
4669 baseStyle()->drawPrimitive(pe, &frmOpt, p, w);
4670 } else {
4671 rule.drawBackground(p, opt->rect);
4672 if (frmOpt.lineWidth > 0)
4673 baseStyle()->drawPrimitive(PE_FrameLineEdit, &frmOpt, p, w);
4674 }
4675 } else {
4676 rule.drawRule(p, opt->rect);
4677 }
4678 }
4679 return;
4680
4681 case PE_Widget:
4682 if (w && !rule.hasDrawable()) {
4683 QWidget *container = containerWidget(w);
4684 if (styleSheetCaches->autoFillDisabledWidgets.contains(container)
4685 && (container == w || !renderRule(container, opt).hasBackground())) {
4686 //we do not have a background, but we disabled the autofillbackground anyway. so fill the background now.
4687 // (this may happen if we have rules like :focus)
4688 p->fillRect(opt->rect, opt->palette.brush(w->backgroundRole()));
4689 }
4690 break;
4691 }
4692#if QT_CONFIG(scrollarea)
4693 if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(w)) {
4694 const QAbstractScrollAreaPrivate *sap = sa->d_func();
4695 rule.drawBackground(p, opt->rect, sap->contentsOffset());
4696 if (rule.hasBorder()) {
4697 QRect brect = rule.borderRect(opt->rect);
4699 QRect r = brect.adjusted(0, 0, sa->verticalScrollBar()->isVisible() ? -sa->verticalScrollBar()->width() : 0,
4700 sa->horizontalScrollBar()->isVisible() ? -sa->horizontalScrollBar()->height() : 0);
4701 brect = QStyle::visualRect(opt->direction, brect, r);
4702 }
4703 rule.drawBorder(p, brect);
4704 }
4705 break;
4706 }
4707#endif
4708 Q_FALLTHROUGH();
4709 case PE_PanelMenu:
4710 case PE_PanelStatusBar:
4711 if (rule.hasDrawable()) {
4712 rule.drawRule(p, opt->rect);
4713 return;
4714 }
4715 break;
4716
4717 case PE_FrameMenu:
4718 if (rule.hasDrawable()) {
4719 // Drawn by PE_PanelMenu
4720 return;
4721 }
4722 break;
4723
4724 case PE_PanelMenuBar:
4725 if (rule.hasDrawable()) {
4726 // Drawn by PE_Widget
4727 return;
4728 }
4729 break;
4730
4731 case PE_IndicatorToolBarSeparator:
4732 case PE_IndicatorToolBarHandle: {
4733 PseudoElement ps = pe == PE_IndicatorToolBarHandle ? PseudoElement_ToolBarHandle : PseudoElement_ToolBarSeparator;
4734 QRenderRule subRule = renderRule(w, opt, ps);
4735 if (subRule.hasDrawable()) {
4736 subRule.drawRule(p, opt->rect);
4737 return;
4738 }
4739 }
4740 break;
4741
4742 case PE_IndicatorMenuCheckMark:
4743 pseudoElement = PseudoElement_MenuCheckMark;
4744 break;
4745
4746 case PE_IndicatorArrowLeft:
4747 pseudoElement = PseudoElement_LeftArrow;
4748 break;
4749
4750 case PE_IndicatorArrowRight:
4751 pseudoElement = PseudoElement_RightArrow;
4752 break;
4753
4754 case PE_IndicatorColumnViewArrow:
4755#if QT_CONFIG(itemviews)
4756 if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4757 bool reverse = (viewOpt->direction == Qt::RightToLeft);
4758 pseudoElement = reverse ? PseudoElement_LeftArrow : PseudoElement_RightArrow;
4759 } else
4760#endif
4761 {
4762 pseudoElement = PseudoElement_RightArrow;
4763 }
4764 break;
4765
4766#if QT_CONFIG(itemviews)
4767 case PE_IndicatorBranch:
4768 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4769 QRenderRule subRule = renderRule(w, opt, PseudoElement_TreeViewBranch);
4770 if (subRule.hasDrawable()) {
4771 proxy()->drawPrimitive(PE_PanelItemViewRow, vopt, p, w);
4772 subRule.drawRule(p, opt->rect);
4773 } else {
4774 baseStyle()->drawPrimitive(pe, vopt, p, w);
4775 }
4776 }
4777 return;
4778#endif // QT_CONFIG(itemviews)
4779
4780 case PE_PanelTipLabel:
4781 if (!rule.hasDrawable())
4782 break;
4783
4784 if (const QStyleOptionFrame *frmOpt = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
4785 if (rule.hasNativeBorder()) {
4786 rule.drawBackground(p, opt->rect);
4787 QStyleOptionFrame optCopy(*frmOpt);
4788 optCopy.rect = rule.borderRect(opt->rect);
4789 optCopy.palette.setBrush(QPalette::Window, Qt::NoBrush); // oh dear
4790 baseStyle()->drawPrimitive(pe, &optCopy, p, w);
4791 } else {
4792 rule.drawRule(p, opt->rect);
4793 }
4794 }
4795 return;
4796
4797 case PE_FrameGroupBox:
4798 if (rule.hasNativeBorder())
4799 break;
4800 rule.drawBorder(p, opt->rect);
4801 return;
4802
4803#if QT_CONFIG(tabwidget)
4804 case PE_FrameTabWidget:
4805 if (const QStyleOptionTabWidgetFrame *frm = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4806 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabWidgetPane);
4807 if (subRule.hasNativeBorder()) {
4808 subRule.drawBackground(p, opt->rect);
4809 QStyleOptionTabWidgetFrame frmCopy(*frm);
4810 subRule.configurePalette(&frmCopy.palette, QPalette::WindowText, QPalette::Window);
4811 baseStyle()->drawPrimitive(pe, &frmCopy, p, w);
4812 } else {
4813 subRule.drawRule(p, opt->rect);
4814 }
4815 return;
4816 }
4817 break;
4818#endif // QT_CONFIG(tabwidget)
4819
4820 case PE_IndicatorProgressChunk:
4821 pseudoElement = PseudoElement_ProgressBarChunk;
4822 break;
4823
4824 case PE_IndicatorTabTear:
4825 pseudoElement = PseudoElement_TabBarTear;
4826 break;
4827
4828 case PE_FrameFocusRect:
4829 if (!rule.hasNativeOutline()) {
4830 rule.drawOutline(p, opt->rect);
4831 return;
4832 }
4833 break;
4834
4835 case PE_IndicatorDockWidgetResizeHandle:
4836 pseudoElement = PseudoElement_DockWidgetSeparator;
4837 break;
4838
4839 case PE_PanelItemViewRow:
4840 // For compatibility reasons, QTreeView draws different parts of
4841 // the background of an item row separately, before calling the
4842 // delegate to draw the item. The row background of an item is
4843 // however not separately styleable through a style sheet, but
4844 // only indirectly through the background of the item. To get the
4845 // same background for all parts drawn by QTreeView, we have to
4846 // use the background rule for the item here.
4847 if (renderRule(w, opt, PseudoElement_ViewItem).hasBackground())
4848 pseudoElement = PseudoElement_ViewItem;
4849 break;
4850 case PE_PanelItemViewItem:
4851 pseudoElement = PseudoElement_ViewItem;
4852 break;
4853
4854 case PE_PanelScrollAreaCorner:
4855 pseudoElement = PseudoElement_ScrollAreaCorner;
4856 break;
4857
4858 case PE_IndicatorSpinDown:
4859 case PE_IndicatorSpinMinus:
4860 pseudoElement = PseudoElement_SpinBoxDownArrow;
4861 break;
4862
4863 case PE_IndicatorSpinUp:
4864 case PE_IndicatorSpinPlus:
4865 pseudoElement = PseudoElement_SpinBoxUpArrow;
4866 break;
4867#if QT_CONFIG(tabbar)
4868 case PE_IndicatorTabClose:
4869 if (w) {
4870 // QMacStyle needs a real widget, not its parent - to implement
4871 // 'document mode' properly, drawing nothing if a tab is not hovered.
4872 baseStyle()->setProperty("_q_styleSheetRealCloseButton", QVariant::fromValue((void *)w));
4873 w = w->parentWidget(); //match on the QTabBar instead of the CloseButton
4874 }
4875 pseudoElement = PseudoElement_TabBarTabCloseButton;
4876 break;
4877#endif
4878
4879 default:
4880 break;
4881 }
4882
4883 if (pseudoElement != PseudoElement_None) {
4884 QRenderRule subRule = renderRule(w, opt, pseudoElement);
4885 if (subRule.hasDrawable()) {
4886 subRule.drawRule(p, rect);
4887 } else {
4888 baseStyle()->drawPrimitive(pe, opt, p, w);
4889 }
4890 } else {
4891 baseStyle()->drawPrimitive(pe, opt, p, w);
4892 }
4893
4894 if (baseStyle()->property("_q_styleSheetRealCloseButton").toBool())
4895 baseStyle()->setProperty("_q_styleSheetRealCloseButton", QVariant());
4896}
4897
4899 const QStyleOption *option) const
4900{
4901 return baseStyle()->generatedIconPixmap(iconMode, pixmap, option);
4902}
4903
4905 const QPoint &pt, const QWidget *w) const
4906{
4907 RECURSION_GUARD(return baseStyle()->hitTestComplexControl(cc, opt, pt, w))
4908 switch (cc) {
4909 case CC_TitleBar:
4910 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4911 QRenderRule rule = renderRule(w, opt, PseudoElement_TitleBar);
4912 if (rule.hasDrawable() || rule.hasBox() || rule.hasBorder()) {
4913 QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
4914 QRect r;
4916 uint ctrl = SC_TitleBarSysMenu;
4917 while (ctrl <= SC_TitleBarLabel) {
4918 r = layout[QStyle::SubControl(ctrl)];
4919 if (r.isValid() && r.contains(pt)) {
4920 sc = QStyle::SubControl(ctrl);
4921 break;
4922 }
4923 ctrl <<= 1;
4924 }
4925 return sc;
4926 }
4927 }
4928 break;
4929
4930 case CC_MdiControls:
4931 if (hasStyleRule(w, PseudoElement_MdiCloseButton)
4932 || hasStyleRule(w, PseudoElement_MdiNormalButton)
4933 || hasStyleRule(w, PseudoElement_MdiMinButton))
4934 return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4935 break;
4936
4937 case CC_ScrollBar: {
4938 QRenderRule rule = renderRule(w, opt);
4939 if (!rule.hasDrawable() && !rule.hasBox())
4940 break;
4941 }
4942 Q_FALLTHROUGH();
4943 case CC_SpinBox:
4944 case CC_GroupBox:
4945 case CC_ComboBox:
4946 case CC_Slider:
4947 case CC_ToolButton:
4948 return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w);
4949 default:
4950 break;
4951 }
4952
4953 return baseStyle()->hitTestComplexControl(cc, opt, pt, w);
4954}
4955
4957{
4959}
4960
4962 bool enabled, const QString& text) const
4963{
4965}
4966
4967int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *w) const
4968{
4969 RECURSION_GUARD(return baseStyle()->pixelMetric(m, opt, w))
4970
4971 QRenderRule rule = renderRule(w, opt);
4972 QRenderRule subRule;
4973
4974 switch (m) {
4975 case PM_MenuButtonIndicator:
4976#if QT_CONFIG(toolbutton)
4977 // QToolButton adds this directly to the width
4978 if (qobject_cast<const QToolButton *>(w)) {
4979 if (rule.hasBox() || !rule.hasNativeBorder())
4980 return 0;
4981 if (const auto *tbOpt = qstyleoption_cast<const QStyleOptionToolButton*>(opt)) {
4982 if (tbOpt->features & QStyleOptionToolButton::MenuButtonPopup)
4983 subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
4984 else
4985 subRule = renderRule(w, opt, PseudoElement_ToolButtonMenuIndicator);
4986 if (subRule.hasContentsSize())
4987 return subRule.size().width();
4988 }
4989 break;
4990 }
4991#endif
4992 subRule = renderRule(w, opt, PseudoElement_PushButtonMenuIndicator);
4993 if (subRule.hasContentsSize())
4994 return subRule.size().width();
4995 break;
4996
4997 case PM_ButtonShiftHorizontal:
4998 case PM_ButtonShiftVertical:
4999 case PM_ButtonMargin:
5000 case PM_ButtonDefaultIndicator:
5001 if (rule.hasBox())
5002 return 0;
5003 break;
5004
5005 case PM_DefaultFrameWidth:
5006 if (!rule.hasNativeBorder())
5007 return rule.border()->borders[LeftEdge];
5008 break;
5009
5010 case PM_ExclusiveIndicatorWidth:
5011 case PM_IndicatorWidth:
5012 case PM_ExclusiveIndicatorHeight:
5013 case PM_IndicatorHeight:
5014 subRule = renderRule(w, opt, PseudoElement_Indicator);
5015 if (subRule.hasContentsSize()) {
5016 return (m == PM_ExclusiveIndicatorWidth) || (m == PM_IndicatorWidth)
5017 ? subRule.size().width() : subRule.size().height();
5018 }
5019 break;
5020
5021 case PM_DockWidgetFrameWidth:
5022 case PM_ToolTipLabelFrameWidth: // border + margin + padding (support only one width)
5023 if (!rule.hasDrawable())
5024 break;
5025
5026 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5027 + (rule.hasBox() ? rule.box()->margins[LeftEdge] + rule.box()->paddings[LeftEdge]: 0);
5028
5029 case PM_ToolBarFrameWidth:
5030 if (rule.hasBorder() || rule.hasBox())
5031 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5032 + (rule.hasBox() ? rule.box()->paddings[LeftEdge]: 0);
5033 break;
5034
5035 case PM_MenuPanelWidth:
5036 case PM_MenuBarPanelWidth:
5037 if (rule.hasBorder() || rule.hasBox())
5038 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5039 + (rule.hasBox() ? rule.box()->margins[LeftEdge]: 0);
5040 break;
5041
5042
5043 case PM_MenuHMargin:
5044 case PM_MenuBarHMargin:
5045 if (rule.hasBox())
5046 return rule.box()->paddings[LeftEdge];
5047 break;
5048
5049 case PM_MenuVMargin:
5050 case PM_MenuBarVMargin:
5051 if (rule.hasBox())
5052 return rule.box()->paddings[TopEdge];
5053 break;
5054
5055 case PM_DockWidgetTitleBarButtonMargin:
5056 case PM_ToolBarItemMargin:
5057 if (rule.hasBox())
5058 return rule.box()->margins[TopEdge];
5059 break;
5060
5061 case PM_ToolBarItemSpacing:
5062 case PM_MenuBarItemSpacing:
5063 if (rule.hasBox() && rule.box()->spacing != -1)
5064 return rule.box()->spacing;
5065 break;
5066
5067 case PM_MenuTearoffHeight:
5068 case PM_MenuScrollerHeight: {
5069 PseudoElement ps = m == PM_MenuTearoffHeight ? PseudoElement_MenuTearoff : PseudoElement_MenuScroller;
5070 subRule = renderRule(w, opt, ps);
5071 if (subRule.hasContentsSize())
5072 return subRule.size().height();
5073 break;
5074 }
5075
5076 case PM_ToolBarExtensionExtent:
5077 break;
5078
5079 case PM_SplitterWidth:
5080 case PM_ToolBarSeparatorExtent:
5081 case PM_ToolBarHandleExtent: {
5082 PseudoElement ps;
5083 if (m == PM_ToolBarHandleExtent) ps = PseudoElement_ToolBarHandle;
5084 else if (m == PM_SplitterWidth) ps = PseudoElement_SplitterHandle;
5085 else ps = PseudoElement_ToolBarSeparator;
5086 subRule = renderRule(w, opt, ps);
5087 if (subRule.hasContentsSize()) {
5088 QSize sz = subRule.size();
5089 return (opt && opt->state & QStyle::State_Horizontal) ? sz.width() : sz.height();
5090 }
5091 break;
5092 }
5093
5094 case PM_RadioButtonLabelSpacing:
5095 if (rule.hasBox() && rule.box()->spacing != -1)
5096 return rule.box()->spacing;
5097 break;
5098 case PM_CheckBoxLabelSpacing:
5099#if QT_CONFIG(checkbox)
5100 if (qobject_cast<const QCheckBox *>(w)) {
5101 if (rule.hasBox() && rule.box()->spacing != -1)
5102 return rule.box()->spacing;
5103 }
5104#endif
5105 // assume group box
5106 subRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
5107 if (subRule.hasBox() && subRule.box()->spacing != -1)
5108 return subRule.box()->spacing;
5109 break;
5110
5111#if QT_CONFIG(scrollbar)
5112 case PM_ScrollBarExtent:
5113 if (rule.hasContentsSize()) {
5114 QSize sz = rule.size();
5115 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5116 return sb->orientation == Qt::Horizontal ? sz.height() : sz.width();
5117 return sz.width() == -1 ? sz.height() : sz.width();
5118 }
5119 break;
5120
5121 case PM_ScrollBarSliderMin:
5122 if (hasStyleRule(w, PseudoElement_ScrollBarSlider)) {
5123 subRule = renderRule(w, opt, PseudoElement_ScrollBarSlider);
5124 QSize msz = subRule.minimumSize();
5125 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5126 return sb->orientation == Qt::Horizontal ? msz.width() : msz.height();
5127 return msz.width() == -1 ? msz.height() : msz.width();
5128 }
5129 break;
5130
5131 case PM_ScrollView_ScrollBarSpacing:
5132 if (!rule.hasNativeBorder() || rule.hasBox())
5133 return 0;
5134 break;
5135
5136 case PM_ScrollView_ScrollBarOverlap:
5137 if (!proxy()->styleHint(SH_ScrollBar_Transient, opt, w))
5138 return 0;
5139 break;
5140#endif // QT_CONFIG(scrollbar)
5141
5142
5143 case PM_ProgressBarChunkWidth:
5144 subRule = renderRule(w, opt, PseudoElement_ProgressBarChunk);
5145 if (subRule.hasContentsSize()) {
5146 QSize sz = subRule.size();
5148 ? sz.width() : sz.height();
5149 }
5150 break;
5151
5152#if QT_CONFIG(tabwidget)
5153 case PM_TabBarTabHSpace:
5154 case PM_TabBarTabVSpace:
5155 subRule = renderRule(w, opt, PseudoElement_TabBarTab);
5156 if (subRule.hasBox() || subRule.hasBorder())
5157 return 0;
5158 break;
5159
5160 case PM_TabBarScrollButtonWidth:
5161 subRule = renderRule(w, opt, PseudoElement_TabBarScroller);
5162 if (subRule.hasContentsSize()) {
5163 QSize sz = subRule.size();
5164 return (sz.width() != -1 ? sz.width() : sz.height()) / 2;
5165 }
5166 break;
5167
5168 case PM_TabBarTabShiftHorizontal:
5169 case PM_TabBarTabShiftVertical:
5170 subRule = renderRule(w, opt, PseudoElement_TabBarTab);
5171 if (subRule.hasBox())
5172 return 0;
5173 break;
5174
5175 case PM_TabBarBaseOverlap: {
5176 const QWidget *tabWidget = qobject_cast<const QTabWidget *>(w);
5177 if (!tabWidget && w)
5178 tabWidget = w->parentWidget();
5179 if (hasStyleRule(tabWidget, PseudoElement_TabWidgetPane)) {
5180 return 0;
5181 }
5182 break;
5183 }
5184#endif // QT_CONFIG(tabwidget)
5185
5186 case PM_SliderThickness: // horizontal slider's height (sizeHint)
5187 case PM_SliderLength: // minimum length of slider
5188 if (rule.hasContentsSize()) {
5189 bool horizontal = opt->state & QStyle::State_Horizontal;
5190 if (m == PM_SliderThickness) {
5191 QSize sz = rule.size();
5192 return horizontal ? sz.height() : sz.width();
5193 } else {
5194 QSize msz = rule.minimumContentsSize();
5195 return horizontal ? msz.width() : msz.height();
5196 }
5197 }
5198 break;
5199
5200 case PM_SliderControlThickness: {
5201 QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderHandle);
5202 if (!subRule.hasContentsSize())
5203 break;
5204 QSize size = subRule.size();
5205 return (opt->state & QStyle::State_Horizontal) ? size.height() : size.width();
5206 }
5207
5208 case PM_ToolBarIconSize:
5209 case PM_ListViewIconSize:
5210 case PM_IconViewIconSize:
5211 case PM_TabBarIconSize:
5212 case PM_MessageBoxIconSize:
5213 case PM_ButtonIconSize:
5214 case PM_SmallIconSize:
5215 if (rule.hasStyleHint("icon-size"_L1))
5216 return rule.styleHint("icon-size"_L1).toSize().width();
5217 break;
5218
5219 case PM_DockWidgetTitleMargin: {
5220 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
5221 if (!subRule.hasBox())
5222 break;
5223 return (subRule.border() ? subRule.border()->borders[TopEdge] : 0)
5224 + (subRule.hasBox() ? subRule.box()->margins[TopEdge] + subRule.box()->paddings[TopEdge]: 0);
5225 }
5226
5227 case PM_DockWidgetSeparatorExtent: {
5228 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetSeparator);
5229 if (!subRule.hasContentsSize())
5230 break;
5231 QSize sz = subRule.size();
5232 return qMax(sz.width(), sz.height());
5233 }
5234
5235 case PM_TitleBarHeight: {
5236 QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
5237 if (subRule.hasContentsSize())
5238 return subRule.size().height();
5239 else if (subRule.hasBox() || subRule.hasBorder()) {
5240 QFontMetrics fm = opt ? opt->fontMetrics : w->fontMetrics();
5241 return subRule.size(QSize(0, fm.height())).height();
5242 }
5243 break;
5244 }
5245
5246 case PM_MdiSubWindowFrameWidth:
5247 if (rule.hasBox() || rule.hasBorder()) {
5248 return (rule.border() ? rule.border()->borders[LeftEdge] : 0)
5249 + (rule.hasBox() ? rule.box()->paddings[LeftEdge]+rule.box()->margins[LeftEdge]: 0);
5250 }
5251 break;
5252
5253 case PM_MdiSubWindowMinimizedWidth: {
5254 QRenderRule subRule = renderRule(w, PseudoElement_None, PseudoClass_Minimized);
5255 int width = subRule.size().width();
5256 if (width != -1)
5257 return width;
5258 break;
5259 }
5260 default:
5261 break;
5262 }
5263
5264 return baseStyle()->pixelMetric(m, opt, w);
5265}
5266
5268 const QSize &csz, const QWidget *w) const
5269{
5270 RECURSION_GUARD(return baseStyle()->sizeFromContents(ct, opt, csz, w))
5271
5272 QRenderRule rule = renderRule(w, opt);
5273 QSize sz = rule.adjustSize(csz);
5274
5275 switch (ct) {
5276#if QT_CONFIG(spinbox)
5277 case CT_SpinBox:
5278 if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5279 if (spinbox->buttonSymbols != QAbstractSpinBox::NoButtons) {
5280 // Add some space for the up/down buttons
5281 QRenderRule subRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
5282 if (subRule.hasDrawable()) {
5283 QRect r = positionRect(w, rule, subRule, PseudoElement_SpinBoxUpButton,
5284 opt->rect, opt->direction);
5285 sz.rwidth() += r.width();
5286 } else {
5287 QSize defaultUpSize = defaultSize(w, subRule.size(), spinbox->rect, PseudoElement_SpinBoxUpButton);
5288 sz.rwidth() += defaultUpSize.width();
5289 }
5290 }
5291 if (rule.hasBox() || rule.hasBorder() || !rule.hasNativeBorder())
5292 sz = rule.boxSize(sz);
5293 return sz;
5294 }
5295 break;
5296#endif // QT_CONFIG(spinbox)
5297 case CT_ToolButton:
5298 if (rule.hasBox() || !rule.hasNativeBorder() || !rule.baseStyleCanDraw())
5299 sz += QSize(3, 3); // ### broken QToolButton
5300 Q_FALLTHROUGH();
5301 case CT_ComboBox:
5302 case CT_PushButton:
5303 if (rule.hasBox() || !rule.hasNativeBorder()) {
5304 if (ct == CT_ComboBox) {
5305 //add some space for the drop down.
5306 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5307 QRect comboRect = positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown, opt->rect, opt->direction);
5308 //+2 because there is hardcoded margins in QCommonStyle::drawControl(CE_ComboBoxLabel)
5309 sz += QSize(comboRect.width() + 2, 0);
5310 }
5311 return rule.boxSize(sz);
5312 }
5313 sz = rule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
5314 : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
5315 return rule.boxSize(sz, Margin);
5316
5317 case CT_HeaderSection: {
5318 if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
5319 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
5320 if (subRule.hasGeometry() || subRule.hasBox() || !subRule.hasNativeBorder() || subRule.hasFont) {
5321 sz = subRule.adjustSize(csz);
5322 if (!sz.isValid()) {
5323 // Try to set the missing values based on the base style.
5324 const auto baseSize = baseStyle()->sizeFromContents(ct, opt, sz, w);
5325 if (sz.width() < 0)
5326 sz.setWidth(baseSize.width());
5327 if (sz.height() < 0)
5328 sz.setHeight(baseSize.height());
5329 }
5330 if (!subRule.hasGeometry()) {
5331 QSize nativeContentsSize;
5332 bool nullIcon = hdr->icon.isNull();
5333 const int margin = pixelMetric(QStyle::PM_HeaderMargin, hdr, w);
5334 int iconSize = nullIcon ? 0 : pixelMetric(QStyle::PM_SmallIconSize, hdr, w);
5335 QFontMetrics fm = hdr->fontMetrics;
5336 if (subRule.hasFont) {
5337 QFont styleFont = w ? subRule.font.resolve(w->font()) : subRule.font;
5338 fm = QFontMetrics(styleFont);
5339 }
5340 const QSize txt = fm.size(0, hdr->text);
5341 nativeContentsSize.setHeight(margin + qMax(iconSize, txt.height()) + margin);
5342 nativeContentsSize.setWidth((nullIcon ? 0 : margin) + iconSize
5343 + (hdr->text.isNull() ? 0 : margin) + txt.width() + margin);
5344 sz = sz.expandedTo(nativeContentsSize);
5345 }
5346 return subRule.size(sz);
5347 }
5348 sz = subRule.baseStyleCanDraw() ? baseStyle()->sizeFromContents(ct, opt, sz, w)
5349 : QWindowsStyle::sizeFromContents(ct, opt, sz, w);
5350 if (hasStyleRule(w, PseudoElement_HeaderViewDownArrow)
5351 || hasStyleRule(w, PseudoElement_HeaderViewUpArrow)) {
5352 const QRect arrowRect = subElementRect(SE_HeaderArrow, opt, w);
5353 if (hdr->orientation == Qt::Horizontal)
5354 sz.rwidth() += arrowRect.width();
5355 else
5356 sz.rheight() += arrowRect.height();
5357 }
5358 return sz;
5359 }
5360 }
5361 break;
5362 case CT_GroupBox:
5363 case CT_LineEdit:
5364#if QT_CONFIG(spinbox)
5365 if (qobject_cast<QAbstractSpinBox *>(w ? w->parentWidget() : nullptr))
5366 return csz; // we only care about the size hint of the line edit
5367#endif
5368 if (rule.hasBox() || !rule.hasNativeBorder()) {
5369 return rule.boxSize(sz);
5370 }
5371 break;
5372
5373 case CT_CheckBox:
5374 case CT_RadioButton:
5375 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
5376 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
5377 bool isRadio = (ct == CT_RadioButton);
5378 int iw = pixelMetric(isRadio ? PM_ExclusiveIndicatorWidth
5379 : PM_IndicatorWidth, btn, w);
5380 int ih = pixelMetric(isRadio ? PM_ExclusiveIndicatorHeight
5381 : PM_IndicatorHeight, btn, w);
5382
5383 int spacing = pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
5384 : PM_CheckBoxLabelSpacing, btn, w);
5385 sz.setWidth(sz.width() + iw + spacing);
5386 sz.setHeight(qMax(sz.height(), ih));
5387 return rule.boxSize(sz);
5388 }
5389 }
5390 break;
5391
5392 case CT_Menu:
5393 case CT_MenuBar: // already has everything!
5394 case CT_ScrollBar:
5395 if (rule.hasBox() || rule.hasBorder())
5396 return sz;
5397 break;
5398
5399 case CT_MenuItem:
5400 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5401 PseudoElement pe = (mi->menuItemType == QStyleOptionMenuItem::Separator)
5402 ? PseudoElement_MenuSeparator : PseudoElement_Item;
5403 QRenderRule subRule = renderRule(w, opt, pe);
5404 if ((pe == PseudoElement_MenuSeparator) && subRule.hasContentsSize()) {
5405 return QSize(sz.width(), subRule.size().height());
5406 }
5407 if ((pe == PseudoElement_Item) && (subRule.hasBox() || subRule.hasBorder() || subRule.hasFont)) {
5408 QSize sz(csz);
5409 if (mi->text.contains(u'\t'))
5410 sz.rwidth() += 12; //as in QCommonStyle
5411 if (!mi->icon.isNull()) {
5412 const int pmSmall = pixelMetric(PM_SmallIconSize);
5413 const QSize pmSize = mi->icon.actualSize(QSize(pmSmall, pmSmall));
5414 sz.rwidth() += std::max(mi->maxIconWidth, pmSize.width()) + 4;
5415 } else if (mi->menuHasCheckableItems) {
5416 QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
5417 QRect checkmarkRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction);
5418 sz.rwidth() += std::max(mi->maxIconWidth, checkmarkRect.width()) + 4;
5419 } else {
5420 sz.rwidth() += mi->maxIconWidth;
5421 }
5422 if (subRule.hasFont) {
5423 QFontMetrics fm(subRule.font.resolve(mi->font));
5424 const QRect r = fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, mi->text);
5425 sz = sz.expandedTo(r.size());
5426 }
5427 return subRule.boxSize(subRule.adjustSize(sz));
5428 }
5429 }
5430 break;
5431
5432 case CT_Splitter:
5433 case CT_MenuBarItem: {
5434 PseudoElement pe = (ct == CT_Splitter) ? PseudoElement_SplitterHandle : PseudoElement_Item;
5435 QRenderRule subRule = renderRule(w, opt, pe);
5436 if (subRule.hasBox() || subRule.hasBorder())
5437 return subRule.boxSize(sz);
5438 break;
5439 }
5440
5441 case CT_ProgressBar:
5442 case CT_SizeGrip:
5443 return (rule.hasContentsSize())
5444 ? rule.size(sz)
5445 : rule.boxSize(baseStyle()->sizeFromContents(ct, opt, sz, w));
5446 break;
5447
5448 case CT_Slider:
5449 if (rule.hasBorder() || rule.hasBox() || rule.hasGeometry())
5450 return rule.boxSize(sz);
5451 break;
5452
5453#if QT_CONFIG(tabbar)
5454 case CT_TabBarTab: {
5455 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
5456 if (subRule.hasBox() || !subRule.hasNativeBorder() || subRule.hasFont) {
5457 int spaceForIcon = 0;
5458 bool vertical = false;
5459 QString text;
5460 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
5461 if (!tab->icon.isNull())
5462 spaceForIcon = 6 /* icon offset */ + 4 /* spacing */ + 2 /* magic */; // ###: hardcoded to match with common style
5463 vertical = verticalTabs(tab->shape);
5464 text = tab->text;
5465 }
5466 if (subRule.hasBox() || !subRule.hasNativeBorder())
5467 sz = csz + QSize(vertical ? 0 : spaceForIcon, vertical ? spaceForIcon : 0);
5468 if (subRule.hasFont) {
5469 // first we remove the space needed for the text using the default font
5470 const QSize oldTextSize = opt->fontMetrics.size(Qt::TextShowMnemonic, text);
5471 (vertical ? sz.rheight() : sz.rwidth()) -= oldTextSize.width();
5472
5473 // then we add the space needed when using the rule font to the relevant
5474 // dimension, and constraint the other dimension to the maximum to make
5475 // sure we don't grow, but also don't clip icons or buttons.
5476 const QFont ruleFont = subRule.font.resolve(w->font());
5477 const QFontMetrics fm(ruleFont);
5478 const QSize textSize = fm.size(Qt::TextShowMnemonic, text);
5479 if (vertical) {
5480 sz.rheight() += textSize.width();
5481 sz.rwidth() = qMax(textSize.height(), sz.width());
5482 } else {
5483 sz.rwidth() += textSize.width();
5484 sz.rheight() = qMax(textSize.height(), sz.height());
5485 }
5486 }
5487
5488 return subRule.boxSize(subRule.adjustSize(sz));
5489 }
5490 sz = subRule.adjustSize(csz);
5491 break;
5492 }
5493#endif // QT_CONFIG(tabbar)
5494
5495 case CT_MdiControls:
5496 if (const QStyleOptionComplex *ccOpt = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
5497 if (!hasStyleRule(w, PseudoElement_MdiCloseButton)
5498 && !hasStyleRule(w, PseudoElement_MdiNormalButton)
5499 && !hasStyleRule(w, PseudoElement_MdiMinButton))
5500 break;
5501
5502 QList<QVariant> layout = rule.styleHint("button-layout"_L1).toList();
5503 if (layout.isEmpty())
5504 layout = subControlLayout("mNX");
5505
5506 int width = 0, height = 0;
5507 for (const QVariant &val : std::as_const(layout)) {
5508 int layoutButton = val.toInt();
5509 if (layoutButton < PseudoElement_MdiCloseButton
5510 || layoutButton > PseudoElement_MdiNormalButton)
5511 continue;
5512 QStyle::SubControl sc = knownPseudoElements[layoutButton].subControl;
5513 if (!(ccOpt->subControls & sc))
5514 continue;
5515 QRenderRule subRule = renderRule(w, opt, layoutButton);
5516 QSize sz = subRule.size();
5517 width += sz.width();
5518 height = qMax(height, sz.height());
5519 }
5520
5521 return QSize(width, height);
5522 }
5523 break;
5524
5525#if QT_CONFIG(itemviews)
5526 case CT_ItemViewItem: {
5527 QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
5528 sz = baseStyle()->sizeFromContents(ct, opt, csz, w);
5529 sz = subRule.adjustSize(sz);
5530 if (subRule.hasBox() || subRule.hasBorder())
5531 sz = subRule.boxSize(sz);
5532 return sz;
5533 }
5534#endif // QT_CONFIG(itemviews)
5535
5536 default:
5537 break;
5538 }
5539
5540 return baseStyle()->sizeFromContents(ct, opt, sz, w);
5541}
5542
5546static QLatin1StringView propertyNameForStandardPixmap(QStyle::StandardPixmap sp)
5547{
5548 switch (sp) {
5549 case QStyle::SP_TitleBarMenuButton: return "titlebar-menu-icon"_L1;
5550 case QStyle::SP_TitleBarMinButton: return "titlebar-minimize-icon"_L1;
5551 case QStyle::SP_TitleBarMaxButton: return "titlebar-maximize-icon"_L1;
5552 case QStyle::SP_TitleBarCloseButton: return "titlebar-close-icon"_L1;
5553 case QStyle::SP_TitleBarNormalButton: return "titlebar-normal-icon"_L1;
5554 case QStyle::SP_TitleBarShadeButton: return "titlebar-shade-icon"_L1;
5555 case QStyle::SP_TitleBarUnshadeButton: return "titlebar-unshade-icon"_L1;
5556 case QStyle::SP_TitleBarContextHelpButton: return "titlebar-contexthelp-icon"_L1;
5557 case QStyle::SP_DockWidgetCloseButton: return "dockwidget-close-icon"_L1;
5558 case QStyle::SP_MessageBoxInformation: return "messagebox-information-icon"_L1;
5559 case QStyle::SP_MessageBoxWarning: return "messagebox-warning-icon"_L1;
5560 case QStyle::SP_MessageBoxCritical: return "messagebox-critical-icon"_L1;
5561 case QStyle::SP_MessageBoxQuestion: return "messagebox-question-icon"_L1;
5562 case QStyle::SP_DesktopIcon: return "desktop-icon"_L1;
5563 case QStyle::SP_TrashIcon: return "trash-icon"_L1;
5564 case QStyle::SP_ComputerIcon: return "computer-icon"_L1;
5565 case QStyle::SP_DriveFDIcon: return "floppy-icon"_L1;
5566 case QStyle::SP_DriveHDIcon: return "harddisk-icon"_L1;
5567 case QStyle::SP_DriveCDIcon: return "cd-icon"_L1;
5568 case QStyle::SP_DriveDVDIcon: return "dvd-icon"_L1;
5569 case QStyle::SP_DriveNetIcon: return "network-icon"_L1;
5570 case QStyle::SP_DirOpenIcon: return "directory-open-icon"_L1;
5571 case QStyle::SP_DirClosedIcon: return "directory-closed-icon"_L1;
5572 case QStyle::SP_DirLinkIcon: return "directory-link-icon"_L1;
5573 case QStyle::SP_FileIcon: return "file-icon"_L1;
5574 case QStyle::SP_FileLinkIcon: return "file-link-icon"_L1;
5575 case QStyle::SP_FileDialogStart: return "filedialog-start-icon"_L1;
5576 case QStyle::SP_FileDialogEnd: return "filedialog-end-icon"_L1;
5577 case QStyle::SP_FileDialogToParent: return "filedialog-parent-directory-icon"_L1;
5578 case QStyle::SP_FileDialogNewFolder: return "filedialog-new-directory-icon"_L1;
5579 case QStyle::SP_FileDialogDetailedView: return "filedialog-detailedview-icon"_L1;
5580 case QStyle::SP_FileDialogInfoView: return "filedialog-infoview-icon"_L1;
5581 case QStyle::SP_FileDialogContentsView: return "filedialog-contentsview-icon"_L1;
5582 case QStyle::SP_FileDialogListView: return "filedialog-listview-icon"_L1;
5583 case QStyle::SP_FileDialogBack: return "filedialog-backward-icon"_L1;
5584 case QStyle::SP_DirIcon: return "directory-icon"_L1;
5585 case QStyle::SP_DialogOkButton: return "dialog-ok-icon"_L1;
5586 case QStyle::SP_DialogCancelButton: return "dialog-cancel-icon"_L1;
5587 case QStyle::SP_DialogHelpButton: return "dialog-help-icon"_L1;
5588 case QStyle::SP_DialogOpenButton: return "dialog-open-icon"_L1;
5589 case QStyle::SP_DialogSaveButton: return "dialog-save-icon"_L1;
5590 case QStyle::SP_DialogCloseButton: return "dialog-close-icon"_L1;
5591 case QStyle::SP_DialogApplyButton: return "dialog-apply-icon"_L1;
5592 case QStyle::SP_DialogResetButton: return "dialog-reset-icon"_L1;
5593 case QStyle::SP_DialogDiscardButton: return "dialog-discard-icon"_L1;
5594 case QStyle::SP_DialogYesButton: return "dialog-yes-icon"_L1;
5595 case QStyle::SP_DialogNoButton: return "dialog-no-icon"_L1;
5596 case QStyle::SP_ArrowUp: return "uparrow-icon"_L1;
5597 case QStyle::SP_ArrowDown: return "downarrow-icon"_L1;
5598 case QStyle::SP_ArrowLeft: return "leftarrow-icon"_L1;
5599 case QStyle::SP_ArrowRight: return "rightarrow-icon"_L1;
5600 case QStyle::SP_ArrowBack: return "backward-icon"_L1;
5601 case QStyle::SP_ArrowForward: return "forward-icon"_L1;
5602 case QStyle::SP_DirHomeIcon: return "home-icon"_L1;
5603 case QStyle::SP_LineEditClearButton: return "lineedit-clear-button-icon"_L1;
5604 default: return ""_L1;
5605 }
5606}
5607
5608QIcon QStyleSheetStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *opt,
5609 const QWidget *w) const
5610{
5611 RECURSION_GUARD(return baseStyle()->standardIcon(standardIcon, opt, w))
5612 QString s = propertyNameForStandardPixmap(standardIcon);
5613 if (!s.isEmpty()) {
5614 QRenderRule rule = renderRule(w, opt);
5615 if (rule.hasStyleHint(s))
5616 return qvariant_cast<QIcon>(rule.styleHint(s));
5617 }
5619}
5620
5622{
5623 return baseStyle()->standardPalette();
5624}
5625
5626QPixmap QStyleSheetStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
5627 const QWidget *w) const
5628{
5629 RECURSION_GUARD(return baseStyle()->standardPixmap(standardPixmap, opt, w))
5630 QString s = propertyNameForStandardPixmap(standardPixmap);
5631 if (!s.isEmpty()) {
5632 QRenderRule rule = renderRule(w, opt);
5633 if (rule.hasStyleHint(s)) {
5634 QIcon icon = qvariant_cast<QIcon>(rule.styleHint(s));
5635 const auto dpr = w ? w->devicePixelRatio() : qApp->devicePixelRatio();
5636 return icon.pixmap(QSize(16, 16), dpr);
5637 }
5638 }
5640}
5641
5643 Qt::Orientation orientation, const QStyleOption *option,
5644 const QWidget *widget) const
5645{
5646 return baseStyle()->layoutSpacing(control1, control2, orientation, option, widget);
5647}
5648
5649int QStyleSheetStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
5650 QStyleHintReturn *shret) const
5651{
5652 RECURSION_GUARD(return baseStyle()->styleHint(sh, opt, w, shret))
5653 // Prevent endless loop if somebody use isActiveWindow property as selector.
5654 // QWidget::isActiveWindow uses this styleHint to determine if the window is active or not
5655 if (sh == SH_Widget_ShareActivation)
5656 return baseStyle()->styleHint(sh, opt, w, shret);
5657
5658 QRenderRule rule = renderRule(w, opt);
5659 QString s;
5660 switch (sh) {
5661 case SH_LineEdit_PasswordCharacter: s = "lineedit-password-character"_L1; break;
5662 case SH_LineEdit_PasswordMaskDelay: s = "lineedit-password-mask-delay"_L1; break;
5663 case SH_DitherDisabledText: s = "dither-disabled-text"_L1; break;
5664 case SH_EtchDisabledText: s = "etch-disabled-text"_L1; break;
5665 case SH_ItemView_ActivateItemOnSingleClick: s = "activate-on-singleclick"_L1; break;
5666 case SH_ItemView_ShowDecorationSelected: s = "show-decoration-selected"_L1; break;
5667 case SH_Table_GridLineColor: s = "gridline-color"_L1; break;
5668 case SH_DialogButtonLayout: s = "button-layout"_L1; break;
5669 case SH_ToolTipLabel_Opacity: s = "opacity"_L1; break;
5670 case SH_ComboBox_Popup: s = "combobox-popup"_L1; break;
5671 case SH_ComboBox_ListMouseTracking: s = "combobox-list-mousetracking"_L1; break;
5672 case SH_MenuBar_AltKeyNavigation: s = "menubar-altkey-navigation"_L1; break;
5673 case SH_Menu_Scrollable: s = "menu-scrollable"_L1; break;
5674 case SH_DrawMenuBarSeparator: s = "menubar-separator"_L1; break;
5675 case SH_MenuBar_MouseTracking: s = "mouse-tracking"_L1; break;
5676 case SH_SpinBox_ClickAutoRepeatRate: s = "spinbox-click-autorepeat-rate"_L1; break;
5677 case SH_SpinControls_DisableOnBounds: s = "spincontrol-disable-on-bounds"_L1; break;
5678 case SH_MessageBox_TextInteractionFlags: s = "messagebox-text-interaction-flags"_L1; break;
5679 case SH_ToolButton_PopupDelay: s = "toolbutton-popup-delay"_L1; break;
5680 case SH_ToolBox_SelectedPageTitleBold:
5681 if (renderRule(w, opt, PseudoElement_ToolBoxTab).hasFont)
5682 return 0;
5683 break;
5684 case SH_GroupBox_TextLabelColor:
5685 if (rule.hasPalette() && rule.palette()->foreground.style() != Qt::NoBrush)
5686 return rule.palette()->foreground.color().rgba();
5687 break;
5688 case SH_ScrollView_FrameOnlyAroundContents: s = "scrollview-frame-around-contents"_L1; break;
5689 case SH_ScrollBar_ContextMenu: s = "scrollbar-contextmenu"_L1; break;
5690 case SH_ScrollBar_LeftClickAbsolutePosition: s = "scrollbar-leftclick-absolute-position"_L1; break;
5691 case SH_ScrollBar_MiddleClickAbsolutePosition: s = "scrollbar-middleclick-absolute-position"_L1; break;
5692 case SH_ScrollBar_RollBetweenButtons: s = "scrollbar-roll-between-buttons"_L1; break;
5693 case SH_ScrollBar_ScrollWhenPointerLeavesControl: s = "scrollbar-scroll-when-pointer-leaves-control"_L1; break;
5694 case SH_TabBar_Alignment:
5695#if QT_CONFIG(tabwidget)
5696 if (qobject_cast<const QTabWidget *>(w)) {
5697 rule = renderRule(w, opt, PseudoElement_TabWidgetTabBar);
5698 if (rule.hasPosition())
5699 return rule.position()->position;
5700 }
5701#endif // QT_CONFIG(tabwidget)
5702 s = "alignment"_L1;
5703 break;
5704#if QT_CONFIG(tabbar)
5705 case SH_TabBar_CloseButtonPosition:
5706 rule = renderRule(w, opt, PseudoElement_TabBarTabCloseButton);
5707 if (rule.hasPosition()) {
5708 Qt::Alignment align = rule.position()->position;
5709 if (align & Qt::AlignLeft || align & Qt::AlignTop)
5710 return QTabBar::LeftSide;
5711 if (align & Qt::AlignRight || align & Qt::AlignBottom)
5712 return QTabBar::RightSide;
5713 }
5714 break;
5715#endif
5716 case SH_TabBar_ElideMode: s = "tabbar-elide-mode"_L1; break;
5717 case SH_TabBar_PreferNoArrows: s = "tabbar-prefer-no-arrows"_L1; break;
5718 case SH_ComboBox_PopupFrameStyle:
5719#if QT_CONFIG(combobox)
5720 if (qobject_cast<const QComboBox *>(w)) {
5722 if (view) {
5723 view->ensurePolished();
5724 QRenderRule subRule = renderRule(view, PseudoElement_None);
5725 if (subRule.hasBox() || !subRule.hasNativeBorder())
5726 return QFrame::NoFrame;
5727 }
5728 }
5729#endif // QT_CONFIG(combobox)
5730 break;
5731 case SH_DialogButtonBox_ButtonsHaveIcons: s = "dialogbuttonbox-buttons-have-icons"_L1; break;
5732 case SH_Workspace_FillSpaceOnMaximize: s = "mdi-fill-space-on-maximize"_L1; break;
5733 case SH_TitleBar_NoBorder:
5734 if (rule.hasBorder())
5735 return !rule.border()->borders[LeftEdge];
5736 break;
5737 case SH_TitleBar_AutoRaise: { // plain absurd
5738 QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
5739 if (subRule.hasDrawable())
5740 return 1;
5741 break;
5742 }
5743 case SH_ItemView_ArrowKeysNavigateIntoChildren: s = "arrow-keys-navigate-into-children"_L1; break;
5744 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea: s = "paint-alternating-row-colors-for-empty-area"_L1; break;
5745 case SH_TitleBar_ShowToolTipsOnButtons: s = "titlebar-show-tooltips-on-buttons"_L1; break;
5746 case SH_Widget_Animation_Duration: s = "widget-animation-duration"_L1; break;
5747 case SH_ScrollBar_Transient:
5748 if (!rule.hasNativeBorder() || rule.hasBox() || rule.hasDrawable())
5749 return 0;
5750 break;
5751 default: break;
5752 }
5753 if (!s.isEmpty() && rule.hasStyleHint(s)) {
5754 return rule.styleHint(s).toInt();
5755 }
5756
5757 return baseStyle()->styleHint(sh, opt, w, shret);
5758}
5759
5760QRect QStyleSheetStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5761 const QWidget *w) const
5762{
5763 RECURSION_GUARD(return baseStyle()->subControlRect(cc, opt, sc, w))
5764
5765 QRenderRule rule = renderRule(w, opt);
5766 switch (cc) {
5767 case CC_ComboBox:
5768 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5769 if (rule.hasBox() || !rule.hasNativeBorder()) {
5770 switch (sc) {
5771 case SC_ComboBoxFrame: return rule.borderRect(opt->rect);
5772 case SC_ComboBoxEditField:
5773 {
5774 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5775 QRect r = rule.contentsRect(opt->rect);
5776 QRect r2 = positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown,
5777 opt->rect, opt->direction);
5778 if (subRule.hasPosition() && subRule.position()->position & Qt::AlignLeft) {
5779 return visualRect(opt->direction, r, r.adjusted(r2.width(),0,0,0));
5780 } else {
5781 return visualRect(opt->direction, r, r.adjusted(0,0,-r2.width(),0));
5782 }
5783 }
5784 case SC_ComboBoxArrow: {
5785 QRenderRule subRule = renderRule(w, opt, PseudoElement_ComboBoxDropDown);
5786 return positionRect(w, rule, subRule, PseudoElement_ComboBoxDropDown, opt->rect, opt->direction);
5787 }
5788 case SC_ComboBoxListBoxPopup:
5789 default:
5790 return baseStyle()->subControlRect(cc, opt, sc, w);
5791 }
5792 }
5793
5794 QStyleOptionComboBox comboBox(*cb);
5795 comboBox.rect = rule.borderRect(opt->rect);
5796 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &comboBox, sc, w)
5797 : QWindowsStyle::subControlRect(cc, &comboBox, sc, w);
5798 }
5799 break;
5800
5801#if QT_CONFIG(spinbox)
5802 case CC_SpinBox:
5803 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5804 QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
5805 QRenderRule downRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
5806 bool ruleMatch = rule.hasBox() || !rule.hasNativeBorder();
5807 bool upRuleMatch = upRule.hasGeometry() || upRule.hasPosition();
5808 bool downRuleMatch = downRule.hasGeometry() || downRule.hasPosition();
5809 if (ruleMatch || upRuleMatch || downRuleMatch) {
5810 switch (sc) {
5811 case SC_SpinBoxFrame:
5812 return rule.borderRect(opt->rect);
5813 case SC_SpinBoxEditField:
5814 {
5815 QRect r = rule.contentsRect(opt->rect);
5816 // Use the widest button on each side to determine edit field size.
5817 Qt::Alignment upAlign, downAlign;
5818
5819 upAlign = upRule.hasPosition() ? upRule.position()->position
5820 : Qt::Alignment(Qt::AlignRight);
5821 upAlign = resolveAlignment(opt->direction, upAlign);
5822
5823 downAlign = downRule.hasPosition() ? downRule.position()->position
5824 : Qt::Alignment(Qt::AlignRight);
5825 downAlign = resolveAlignment(opt->direction, downAlign);
5826
5827 const bool hasButtons = (spin->buttonSymbols != QAbstractSpinBox::NoButtons);
5828 const int upSize = hasButtons
5829 ? subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w).width() : 0;
5830 const int downSize = hasButtons
5831 ? subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w).width() : 0;
5832
5833 int widestL = qMax((upAlign & Qt::AlignLeft) ? upSize : 0,
5834 (downAlign & Qt::AlignLeft) ? downSize : 0);
5835 int widestR = qMax((upAlign & Qt::AlignRight) ? upSize : 0,
5836 (downAlign & Qt::AlignRight) ? downSize : 0);
5837 r.setRight(r.right() - widestR);
5838 r.setLeft(r.left() + widestL);
5839 return r;
5840 }
5841 case SC_SpinBoxDown:
5842 if (downRuleMatch)
5843 return positionRect(w, rule, downRule, PseudoElement_SpinBoxDownButton,
5844 opt->rect, opt->direction);
5845 break;
5846 case SC_SpinBoxUp:
5847 if (upRuleMatch)
5848 return positionRect(w, rule, upRule, PseudoElement_SpinBoxUpButton,
5849 opt->rect, opt->direction);
5850 break;
5851 default:
5852 break;
5853 }
5854
5855 return baseStyle()->subControlRect(cc, opt, sc, w);
5856 }
5857
5858 QStyleOptionSpinBox spinBox(*spin);
5859 spinBox.rect = rule.borderRect(opt->rect);
5860 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &spinBox, sc, w)
5861 : QWindowsStyle::subControlRect(cc, &spinBox, sc, w);
5862 }
5863 break;
5864#endif // QT_CONFIG(spinbox)
5865
5866 case CC_GroupBox:
5867 if (const QStyleOptionGroupBox *gb = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5868 switch (sc) {
5869 case SC_GroupBoxFrame:
5870 case SC_GroupBoxContents: {
5871 if (rule.hasBox() || !rule.hasNativeBorder()) {
5872 return sc == SC_GroupBoxFrame ? rule.borderRect(opt->rect)
5873 : rule.contentsRect(opt->rect);
5874 }
5876 groupBox.rect = rule.borderRect(opt->rect);
5877 return baseStyle()->subControlRect(cc, &groupBox, sc, w);
5878 }
5879 default:
5880 case SC_GroupBoxLabel:
5881 case SC_GroupBoxCheckBox: {
5882 QRenderRule indRule = renderRule(w, opt, PseudoElement_GroupBoxIndicator);
5883 QRenderRule labelRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
5884 if (!labelRule.hasPosition() && !labelRule.hasGeometry() && !labelRule.hasBox()
5885 && !labelRule.hasBorder() && !indRule.hasContentsSize()) {
5887 groupBox.rect = rule.borderRect(opt->rect);
5888 return baseStyle()->subControlRect(cc, &groupBox, sc, w);
5889 }
5890 int tw = opt->fontMetrics.horizontalAdvance(gb->text);
5891 int th = opt->fontMetrics.height();
5895
5896 if (gb->subControls & QStyle::SC_GroupBoxCheckBox) {
5897 tw = tw + iw + spacing;
5898 th = qMax(th, ih);
5899 }
5900 if (!labelRule.hasGeometry()) {
5901 labelRule.geo = new QStyleSheetGeometryData(tw, th, tw, th, -1, -1);
5902 } else {
5903 labelRule.geo->width = tw;
5904 labelRule.geo->height = th;
5905 }
5906 if (!labelRule.hasPosition()) {
5907 labelRule.p = new QStyleSheetPositionData(0, 0, 0, 0, defaultOrigin(PseudoElement_GroupBoxTitle),
5908 gb->textAlignment, PositionMode_Static);
5909 }
5910 QRect r = positionRect(w, rule, labelRule, PseudoElement_GroupBoxTitle,
5911 opt->rect, opt->direction);
5912 if (gb->subControls & SC_GroupBoxCheckBox) {
5913 r = labelRule.contentsRect(r);
5914 if (sc == SC_GroupBoxLabel) {
5915 r.setLeft(r.left() + iw + spacing);
5916 r.setTop(r.center().y() - th/2);
5917 } else {
5918 r = QRect(r.left(), r.center().y() - ih/2, iw, ih);
5919 }
5920 return r;
5921 } else {
5922 return labelRule.contentsRect(r);
5923 }
5924 }
5925 } // switch
5926 }
5927 break;
5928
5929 case CC_ToolButton:
5930 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5931 if (rule.hasBox() || !rule.hasNativeBorder()) {
5932 switch (sc) {
5933 case SC_ToolButton: return rule.borderRect(opt->rect);
5934 case SC_ToolButtonMenu: {
5935 QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
5936 return positionRect(w, rule, subRule, PseudoElement_ToolButtonMenu, opt->rect, opt->direction);
5937 }
5938 default:
5939 break;
5940 }
5941 }
5942
5943 QStyleOptionToolButton tool(*tb);
5944 tool.rect = rule.borderRect(opt->rect);
5945 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &tool, sc, w)
5946 : QWindowsStyle::subControlRect(cc, &tool, sc, w);
5947 }
5948 break;
5949
5950#if QT_CONFIG(scrollbar)
5951 case CC_ScrollBar:
5952 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5953 QStyleOptionSlider styleOptionSlider(*sb);
5954 styleOptionSlider.rect = rule.borderRect(opt->rect);
5955 if (rule.hasDrawable() || rule.hasBox()) {
5956 QRect grooveRect;
5957 if (!rule.hasBox()) {
5958 grooveRect = rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, sb, SC_ScrollBarGroove, w)
5959 : QWindowsStyle::subControlRect(cc, sb, SC_ScrollBarGroove, w);
5960 } else {
5961 grooveRect = rule.contentsRect(opt->rect);
5962 }
5963
5964 PseudoElement pe = PseudoElement_None;
5965
5966 switch (sc) {
5967 case SC_ScrollBarGroove:
5968 return grooveRect;
5969 case SC_ScrollBarAddPage:
5970 case SC_ScrollBarSubPage:
5971 case SC_ScrollBarSlider: {
5972 QRect contentRect = grooveRect;
5973 if (hasStyleRule(w, PseudoElement_ScrollBarSlider)) {
5974 QRenderRule sliderRule = renderRule(w, opt, PseudoElement_ScrollBarSlider);
5975 Origin origin = sliderRule.hasPosition() ? sliderRule.position()->origin : defaultOrigin(PseudoElement_ScrollBarSlider);
5976 contentRect = rule.originRect(opt->rect, origin);
5977 }
5978 int maxlen = (styleOptionSlider.orientation == Qt::Horizontal) ? contentRect.width() : contentRect.height();
5979 int sliderlen;
5980 if (sb->maximum != sb->minimum) {
5981 uint range = sb->maximum - sb->minimum;
5982 sliderlen = (qint64(sb->pageStep) * maxlen) / (range + sb->pageStep);
5983
5984 int slidermin = pixelMetric(PM_ScrollBarSliderMin, sb, w);
5985 if (sliderlen < slidermin || range > INT_MAX / 2)
5986 sliderlen = slidermin;
5987 if (sliderlen > maxlen)
5988 sliderlen = maxlen;
5989 } else {
5990 sliderlen = maxlen;
5991 }
5992 int sliderstart = (styleOptionSlider.orientation == Qt::Horizontal ? contentRect.left() : contentRect.top())
5993 + sliderPositionFromValue(sb->minimum, sb->maximum, sb->sliderPosition,
5994 maxlen - sliderlen, sb->upsideDown);
5995
5996 QRect sr = (sb->orientation == Qt::Horizontal)
5997 ? QRect(sliderstart, contentRect.top(), sliderlen, contentRect.height())
5998 : QRect(contentRect.left(), sliderstart, contentRect.width(), sliderlen);
5999 if (sc == SC_ScrollBarSubPage)
6000 sr = QRect(contentRect.topLeft(), sb->orientation == Qt::Horizontal ? sr.bottomLeft() : sr.topRight());
6001 else if (sc == SC_ScrollBarAddPage)
6002 sr = QRect(sb->orientation == Qt::Horizontal ? sr.topRight() : sr.bottomLeft(), contentRect.bottomRight());
6003 return visualRect(styleOptionSlider.direction, grooveRect, sr);
6004 }
6005 case SC_ScrollBarAddLine: pe = PseudoElement_ScrollBarAddLine; break;
6006 case SC_ScrollBarSubLine: pe = PseudoElement_ScrollBarSubLine; break;
6007 case SC_ScrollBarFirst: pe = PseudoElement_ScrollBarFirst; break;
6008 case SC_ScrollBarLast: pe = PseudoElement_ScrollBarLast; break;
6009 default: break;
6010 }
6011 if (hasStyleRule(w,pe)) {
6012 QRenderRule subRule = renderRule(w, opt, pe);
6013 if (subRule.hasPosition() || subRule.hasGeometry() || subRule.hasBox()) {
6014 const QStyleSheetPositionData *pos = subRule.position();
6015 QRect originRect = grooveRect;
6016 if (rule.hasBox()) {
6017 Origin origin = (pos && pos->origin != Origin_Unknown) ? pos->origin : defaultOrigin(pe);
6018 originRect = rule.originRect(opt->rect, origin);
6019 }
6020 return positionRect(w, subRule, pe, originRect, styleOptionSlider.direction);
6021 }
6022 }
6023 }
6024 return rule.baseStyleCanDraw() ? baseStyle()->subControlRect(cc, &styleOptionSlider, sc, w)
6025 : QWindowsStyle::subControlRect(cc, &styleOptionSlider, sc, w);
6026 }
6027 break;
6028#endif // QT_CONFIG(scrollbar)
6029
6030#if QT_CONFIG(slider)
6031 case CC_Slider:
6032 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
6033 QRenderRule subRule = renderRule(w, opt, PseudoElement_SliderGroove);
6034 if (!subRule.hasDrawable())
6035 break;
6036 subRule.img = nullptr;
6037 QRect gr = positionRect(w, rule, subRule, PseudoElement_SliderGroove, opt->rect, opt->direction);
6038 switch (sc) {
6039 case SC_SliderGroove:
6040 return gr;
6041 case SC_SliderHandle: {
6042 bool horizontal = slider->orientation & Qt::Horizontal;
6043 QRect cr = subRule.contentsRect(gr);
6044 QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderHandle);
6045 int len = horizontal ? subRule2.size().width() : subRule2.size().height();
6046 subRule2.img = nullptr;
6047 subRule2.geo = nullptr;
6048 cr = positionRect(w, subRule2, PseudoElement_SliderHandle, cr, opt->direction);
6049 int thickness = horizontal ? cr.height() : cr.width();
6050 int sliderPos = sliderPositionFromValue(slider->minimum, slider->maximum, slider->sliderPosition,
6051 (horizontal ? cr.width() : cr.height()) - len, slider->upsideDown);
6052 cr = horizontal ? QRect(cr.x() + sliderPos, cr.y(), len, thickness)
6053 : QRect(cr.x(), cr.y() + sliderPos, thickness, len);
6054 return subRule2.borderRect(cr);
6055 break; }
6056 case SC_SliderTickmarks:
6057 // TODO...
6058 default:
6059 break;
6060 }
6061 }
6062 break;
6063#endif // QT_CONFIG(slider)
6064
6065 case CC_MdiControls:
6066 if (hasStyleRule(w, PseudoElement_MdiCloseButton)
6067 || hasStyleRule(w, PseudoElement_MdiNormalButton)
6068 || hasStyleRule(w, PseudoElement_MdiMinButton)) {
6069 QList<QVariant> layout = rule.styleHint("button-layout"_L1).toList();
6070 if (layout.isEmpty())
6071 layout = subControlLayout("mNX");
6072
6073 int x = 0, width = 0;
6074 QRenderRule subRule;
6075 for (const QVariant &val : std::as_const(layout)) {
6076 int layoutButton = val.toInt();
6077 if (layoutButton < PseudoElement_MdiCloseButton
6078 || layoutButton > PseudoElement_MdiNormalButton)
6079 continue;
6080 QStyle::SubControl control = knownPseudoElements[layoutButton].subControl;
6081 if (!(opt->subControls & control))
6082 continue;
6083 subRule = renderRule(w, opt, layoutButton);
6084 width = subRule.size().width();
6085 if (sc == control)
6086 break;
6087 x += width;
6088 }
6089
6090 return subRule.borderRect(QRect(x, opt->rect.top(), width, opt->rect.height()));
6091 }
6092 break;
6093
6094 case CC_TitleBar:
6095 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
6096 QRenderRule subRule = renderRule(w, opt, PseudoElement_TitleBar);
6097 if (!subRule.hasDrawable() && !subRule.hasBox() && !subRule.hasBorder())
6098 break;
6099 QHash<QStyle::SubControl, QRect> layoutRects = titleBarLayout(w, tb);
6100 return layoutRects.value(sc);
6101 }
6102 break;
6103
6104 default:
6105 break;
6106 }
6107
6108 return baseStyle()->subControlRect(cc, opt, sc, w);
6109}
6110
6111QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, const QWidget *w) const
6112{
6113 RECURSION_GUARD(return baseStyle()->subElementRect(se, opt, w))
6114
6115 QRenderRule rule = renderRule(w, opt);
6116#if QT_CONFIG(tabbar)
6117 int pe = PseudoElement_None;
6118#endif
6119
6120 switch (se) {
6121 case SE_PushButtonContents:
6122 case SE_PushButtonBevel:
6123 case SE_PushButtonFocusRect:
6124 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
6126 && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator)) {
6127 QStyleOptionButton btnOpt(*btn);
6128 btnOpt.features &= ~QStyleOptionButton::HasMenu;
6129 return rule.baseStyleCanDraw() ? baseStyle()->subElementRect(se, &btnOpt, w)
6130 : QWindowsStyle::subElementRect(se, &btnOpt, w);
6131 }
6132 if (rule.hasBox() || !rule.hasNativeBorder()) {
6133 return visualRect(opt->direction, opt->rect, se == SE_PushButtonBevel
6134 ? rule.borderRect(opt->rect)
6135 : rule.contentsRect(opt->rect));
6136 }
6137 return rule.baseStyleCanDraw() ? baseStyle()->subElementRect(se, btn, w)
6138 : QWindowsStyle::subElementRect(se, btn, w);
6139 }
6140 break;
6141
6142 case SE_LineEditContents:
6143 case SE_FrameContents:
6144 case SE_ShapedFrameContents:
6145 if (rule.hasBox() || !rule.hasNativeBorder()) {
6146 return visualRect(opt->direction, opt->rect, rule.contentsRect(opt->rect));
6147 }
6148 break;
6149
6150 case SE_CheckBoxIndicator:
6151 case SE_RadioButtonIndicator:
6152 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
6153 PseudoElement pe = se == SE_CheckBoxIndicator ? PseudoElement_Indicator : PseudoElement_ExclusiveIndicator;
6154 QRenderRule subRule = renderRule(w, opt, pe);
6155 return positionRect(w, rule, subRule, pe, opt->rect, opt->direction);
6156 }
6157 break;
6158
6159 case SE_CheckBoxContents:
6160 case SE_RadioButtonContents:
6161 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
6162 bool isRadio = se == SE_RadioButtonContents;
6163 QRect ir = subElementRect(isRadio ? SE_RadioButtonIndicator : SE_CheckBoxIndicator,
6164 opt, w);
6165 ir = visualRect(opt->direction, opt->rect, ir);
6166 int spacing = pixelMetric(isRadio ? PM_RadioButtonLabelSpacing : PM_CheckBoxLabelSpacing, nullptr, w);
6167 QRect cr = rule.contentsRect(opt->rect);
6168 ir.setRect(ir.left() + ir.width() + spacing, cr.y(),
6169 cr.width() - ir.width() - spacing, cr.height());
6170 return visualRect(opt->direction, opt->rect, ir);
6171 }
6172 break;
6173
6174 case SE_ToolBoxTabContents:
6175 if (w && hasStyleRule(w->parentWidget(), PseudoElement_ToolBoxTab)) {
6176 QRenderRule subRule = renderRule(w->parentWidget(), opt, PseudoElement_ToolBoxTab);
6177 return visualRect(opt->direction, opt->rect, subRule.contentsRect(opt->rect));
6178 }
6179 break;
6180
6181 case SE_RadioButtonFocusRect:
6182 case SE_RadioButtonClickRect: // focusrect | indicator
6183 if (rule.hasBox() || rule.hasBorder() || hasStyleRule(w, PseudoElement_Indicator)) {
6184 return opt->rect;
6185 }
6186 break;
6187
6188 case SE_CheckBoxFocusRect:
6189 case SE_CheckBoxClickRect: // relies on indicator and contents
6190 return ParentStyle::subElementRect(se, opt, w);
6191
6192#if QT_CONFIG(itemviews)
6193 case SE_ItemViewItemCheckIndicator:
6194 if (!qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
6195 return subElementRect(SE_CheckBoxIndicator, opt, w);
6196 }
6197 Q_FALLTHROUGH();
6198 case SE_ItemViewItemText:
6199 case SE_ItemViewItemDecoration:
6200 case SE_ItemViewItemFocusRect:
6201 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
6202 QRenderRule subRule = renderRule(w, opt, PseudoElement_ViewItem);
6203 PseudoElement pe = PseudoElement_None;
6204 if (se == SE_ItemViewItemText || se == SE_ItemViewItemFocusRect)
6205 pe = PseudoElement_ViewItemText;
6206 else if (se == SE_ItemViewItemDecoration && vopt->features & QStyleOptionViewItem::HasDecoration)
6207 pe = PseudoElement_ViewItemIcon;
6208 else if (se == SE_ItemViewItemCheckIndicator && vopt->features & QStyleOptionViewItem::HasCheckIndicator)
6209 pe = PseudoElement_ViewItemIndicator;
6210 else
6211 break;
6212 if (subRule.hasGeometry() || subRule.hasBox() || !subRule.hasNativeBorder() || hasStyleRule(w, pe)) {
6213 QRenderRule subRule2 = renderRule(w, opt, pe);
6214 QStyleOptionViewItem optCopy(*vopt);
6215 optCopy.rect = subRule.contentsRect(vopt->rect);
6216 QRect rect = ParentStyle::subElementRect(se, &optCopy, w);
6217 return positionRect(w, subRule2, pe, rect, opt->direction);
6218 }
6219 }
6220 break;
6221#endif // QT_CONFIG(itemviews)
6222
6223 case SE_HeaderArrow: {
6224 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewUpArrow);
6225 if (subRule.hasPosition() || subRule.hasGeometry())
6226 return positionRect(w, rule, subRule, PseudoElement_HeaderViewUpArrow, opt->rect, opt->direction);
6227 }
6228 break;
6229
6230 case SE_HeaderLabel: {
6231 QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
6232 if (subRule.hasBox() || !subRule.hasNativeBorder()) {
6233 auto r = subRule.contentsRect(opt->rect);
6234 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
6235 // Subtract width needed for arrow, if there is one
6236 if (header->sortIndicator != QStyleOptionHeader::None) {
6237 const auto arrowRect = subElementRect(SE_HeaderArrow, opt, w);
6238 if (arrowRect.isValid()) {
6239 if (opt->state & State_Horizontal)
6240 r.setWidth(r.width() - arrowRect.width());
6241 else
6242 r.setHeight(r.height() - arrowRect.height());
6243 }
6244 }
6245 }
6246 return r;
6247 }
6248 }
6249 break;
6250
6251 case SE_ProgressBarGroove:
6252 case SE_ProgressBarContents:
6253 case SE_ProgressBarLabel:
6254 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
6255 if (rule.hasBox() || !rule.hasNativeBorder() || rule.hasPosition() || hasStyleRule(w, PseudoElement_ProgressBarChunk)) {
6256 if (se == SE_ProgressBarGroove)
6257 return rule.borderRect(pb->rect);
6258 else if (se == SE_ProgressBarContents)
6259 return rule.contentsRect(pb->rect);
6260
6261 QSize sz = pb->fontMetrics.size(0, pb->text);
6262 return QStyle::alignedRect(Qt::LeftToRight, rule.hasPosition() ? rule.position()->textAlignment : pb->textAlignment,
6263 sz, pb->rect);
6264 }
6265 }
6266 break;
6267
6268#if QT_CONFIG(tabbar)
6269 case SE_TabWidgetLeftCorner:
6270 pe = PseudoElement_TabWidgetLeftCorner;
6271 Q_FALLTHROUGH();
6272 case SE_TabWidgetRightCorner:
6273 if (pe == PseudoElement_None)
6274 pe = PseudoElement_TabWidgetRightCorner;
6275 Q_FALLTHROUGH();
6276 case SE_TabWidgetTabBar:
6277 if (pe == PseudoElement_None)
6278 pe = PseudoElement_TabWidgetTabBar;
6279 Q_FALLTHROUGH();
6280 case SE_TabWidgetTabPane:
6281 case SE_TabWidgetTabContents:
6282 if (pe == PseudoElement_None)
6283 pe = PseudoElement_TabWidgetPane;
6284
6285 if (hasStyleRule(w, pe)) {
6286 QRect r = QWindowsStyle::subElementRect(pe == PseudoElement_TabWidgetPane ? SE_TabWidgetTabPane : se, opt, w);
6287 QRenderRule subRule = renderRule(w, opt, pe);
6288 r = positionRect(w, subRule, pe, r, opt->direction);
6289 if (pe == PseudoElement_TabWidgetTabBar) {
6290 Q_ASSERT(opt);
6291 r = opt->rect.intersected(r);
6292 }
6293 if (se == SE_TabWidgetTabContents)
6294 r = subRule.contentsRect(r);
6295 return r;
6296 }
6297 break;
6298
6299 case SE_TabBarScrollLeftButton:
6300 case SE_TabBarScrollRightButton:
6301 if (hasStyleRule(w, PseudoElement_TabBarScroller))
6302 return ParentStyle::subElementRect(se, opt, w);
6303 break;
6304
6305 case SE_TabBarTearIndicator: {
6306 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTear);
6307 if (subRule.hasContentsSize()) {
6308 QRect r;
6309 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
6310 switch (tab->shape) {
6315 r.setRect(tab->rect.left(), tab->rect.top(), subRule.size().width(), opt->rect.height());
6316 break;
6321 r.setRect(tab->rect.left(), tab->rect.top(), opt->rect.width(), subRule.size().height());
6322 break;
6323 default:
6324 break;
6325 }
6327 }
6328 return r;
6329 }
6330 break;
6331 }
6332 case SE_TabBarTabText:
6333 case SE_TabBarTabLeftButton:
6334 case SE_TabBarTabRightButton: {
6335 QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
6336 if (subRule.hasBox() || !subRule.hasNativeBorder() || subRule.hasFont) {
6337 if (se == SE_TabBarTabText) {
6338 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
6339 const QTabBar *bar = qobject_cast<const QTabBar *>(w);
6340 const QRect optRect = bar && tab->tabIndex != -1 ? bar->tabRect(tab->tabIndex) : opt->rect;
6341 const QRect r = positionRect(w, subRule, PseudoElement_TabBarTab, optRect, opt->direction);
6342 QStyleOptionTab tabCopy(*tab);
6343 if (subRule.hasFont) {
6344 const QFont ruleFont = w ? subRule.font.resolve(w->font()) : subRule.font;
6345 tabCopy.fontMetrics = QFontMetrics(ruleFont);
6346 }
6347 tabCopy.rect = subRule.contentsRect(r);
6348 return ParentStyle::subElementRect(se, &tabCopy, w);
6349 }
6350 }
6351 return ParentStyle::subElementRect(se, opt, w);
6352 }
6353 break;
6354 }
6355#endif // QT_CONFIG(tabbar)
6356
6357 case SE_DockWidgetCloseButton:
6358 case SE_DockWidgetFloatButton: {
6359 PseudoElement pe = (se == SE_DockWidgetCloseButton) ? PseudoElement_DockWidgetCloseButton : PseudoElement_DockWidgetFloatButton;
6360 QRenderRule subRule2 = renderRule(w, opt, pe);
6361 if (!subRule2.hasPosition())
6362 break;
6363 QRenderRule subRule = renderRule(w, opt, PseudoElement_DockWidgetTitle);
6364 return positionRect(w, subRule, subRule2, pe, opt->rect, opt->direction);
6365 }
6366
6367#if QT_CONFIG(toolbar)
6368 case SE_ToolBarHandle:
6369 if (hasStyleRule(w, PseudoElement_ToolBarHandle))
6370 return ParentStyle::subElementRect(se, opt, w);
6371 break;
6372#endif // QT_CONFIG(toolbar)
6373
6374 // On mac we make pixel adjustments to layouts which are not
6375 // desirable when you have custom style sheets on them
6376 case SE_CheckBoxLayoutItem:
6377 case SE_ComboBoxLayoutItem:
6378 case SE_DateTimeEditLayoutItem:
6379 case SE_LabelLayoutItem:
6380 case SE_ProgressBarLayoutItem:
6381 case SE_PushButtonLayoutItem:
6382 case SE_RadioButtonLayoutItem:
6383 case SE_SliderLayoutItem:
6384 case SE_SpinBoxLayoutItem:
6385 case SE_ToolButtonLayoutItem:
6386 case SE_FrameLayoutItem:
6387 case SE_GroupBoxLayoutItem:
6388 case SE_TabWidgetLayoutItem:
6389 if (!rule.hasNativeBorder())
6390 return opt->rect;
6391 break;
6392
6393 default:
6394 break;
6395 }
6396
6397 return baseStyle()->subElementRect(se, opt, w);
6398}
6399
6401{
6402 return (baseStyle()->event(e) && e->isAccepted()) || ParentStyle::event(e);
6403}
6404
6406{
6407 // Qt's fontDialog relies on the font of the sample edit for its selection,
6408 // we should never override it.
6409 if (w->objectName() == "qt_fontDialog_sampleEdit"_L1)
6410 return;
6411
6412 QWidget *container = containerWidget(w);
6413 QRenderRule rule = renderRule(container, PseudoElement_None,
6414 PseudoClass_Active | PseudoClass_Enabled | extendedPseudoClass(container));
6415
6416 const bool useStyleSheetPropagationInWidgetStyles =
6418
6419 if (useStyleSheetPropagationInWidgetStyles) {
6420 unsetStyleSheetFont(w);
6421
6422 if (rule.font.resolveMask()) {
6423 QFont wf = w->d_func()->localFont();
6424 styleSheetCaches->customFontWidgets.insert(w, {wf, rule.font.resolveMask()});
6425
6426 QFont font = rule.font.resolve(wf);
6427 font.setResolveMask(wf.resolveMask() | rule.font.resolveMask());
6428 w->setFont(font);
6429 }
6430 } else {
6431 QFont wf = w->d_func()->localFont();
6432 QFont font = rule.font.resolve(wf);
6433 font.setResolveMask(wf.resolveMask() | rule.font.resolveMask());
6434
6435 if ((!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
6436 && isNaturalChild(w) && qobject_cast<QWidget *>(w->parent())) {
6437
6438 font = font.resolve(static_cast<QWidget *>(w->parent())->font());
6439 }
6440
6441 if (wf.resolveMask() == font.resolveMask() && wf == font)
6442 return;
6443
6444 w->data->fnt = font;
6445 w->d_func()->directFontResolveMask = font.resolveMask();
6446
6449 }
6450}
6451
6453{
6454 w->setProperty("_q_styleSheetWidgetFont", font);
6455}
6456
6458{
6459 w->setProperty("_q_styleSheetWidgetFont", QVariant());
6460}
6461
6462// Polish palette that should be used for a particular widget, with particular states
6463// (eg. :focus, :hover, ...)
6464// this is called by widgets that paint themself in their paint event
6465// Returns \c true if there is a new palette in pal.
6467{
6468 if (!w || !opt || !pal)
6469 return false;
6470
6471 RECURSION_GUARD(return false)
6472
6473 w = containerWidget(w);
6474
6475 QRenderRule rule = renderRule(w, PseudoElement_None, pseudoClass(opt->state) | extendedPseudoClass(w));
6476 if (!rule.hasPalette())
6477 return false;
6478
6479 rule.configurePalette(pal, QPalette::NoRole, QPalette::NoRole);
6480 return true;
6481}
6482
6483Qt::Alignment QStyleSheetStyle::resolveAlignment(Qt::LayoutDirection layDir, Qt::Alignment src)
6484{
6485 if (layDir == Qt::LeftToRight || src & Qt::AlignAbsolute)
6486 return src;
6487
6488 if (src & Qt::AlignLeft) {
6489 src &= ~Qt::AlignLeft;
6491 } else if (src & Qt::AlignRight) {
6492 src &= ~Qt::AlignRight;
6493 src |= Qt::AlignLeft;
6494 }
6496 return src;
6497}
6498
6499// Returns whether the given QWidget has a "natural" parent, meaning that
6500// the parent contains this child as part of its normal operation.
6501// An example is the QTabBar inside a QTabWidget.
6502// This does not mean that any QTabBar which is a child of QTabWidget will
6503// match, only the one that was created by the QTabWidget initialization
6504// (and hence has the correct object name).
6505bool QStyleSheetStyle::isNaturalChild(const QObject *obj)
6506{
6507 if (obj->objectName().startsWith("qt_"_L1))
6508 return true;
6509
6510 return false;
6511}
6512
6513QPixmap QStyleSheetStyle::loadPixmap(const QString &fileName, const QObject *context)
6514{
6515 if (fileName.isEmpty())
6516 return {};
6517
6518 qreal ratio = -1.0;
6519 if (const QWidget *widget = qobject_cast<const QWidget *>(context)) {
6521 ratio = screen->devicePixelRatio();
6522 }
6523
6524 if (ratio < 0) {
6525 if (const QApplication *app = qApp)
6526 ratio = app->devicePixelRatio();
6527 else
6528 ratio = 1.0;
6529 }
6530
6531 qreal sourceDevicePixelRatio = 1.0;
6532 QString resolvedFileName = qt_findAtNxFile(fileName, ratio, &sourceDevicePixelRatio);
6533 QPixmap pixmap(resolvedFileName);
6534 pixmap.setDevicePixelRatio(sourceDevicePixelRatio);
6535 return pixmap;
6536}
6537
6539
6540#include "moc_qstylesheetstyle_p.cpp"
6541
6542#endif // QT_CONFIG(style_stylesheet)
QIcon icon
the icon shown on the button
QSize iconSize
the icon size used for this button.
QString text
the text shown on the button
The QAbstractItemView class provides the basic functionality for item view classes.
The QAbstractSlider class provides an integer value within a range.
void valueChanged(int value)
This signal is emitted when the slider value has changed, with the new slider value as argument.
The QAbstractSpinBox class provides a spinbox and a line edit to display values.
The QApplication class manages the GUI application's control flow and main settings.
static QStyle * style()
Returns the application's style object.
\inmodule QtGui
Definition qbrush.h:30
void setColor(const QColor &color)
Sets the brush color to the given color.
Definition qbrush.cpp:687
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QRgb rgba() const noexcept
Returns the RGB value of the color, including its alpha.
Definition qcolor.cpp:1376
The QComboBox widget combines a button with a dropdown list.
Definition qcombobox.h:24
void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const override
\reimp
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
void init(const QString &css, bool file=false)
bool parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity=Qt::CaseSensitive)
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
\inmodule QtCore
Definition qcoreevent.h:45
@ StyleChange
Definition qcoreevent.h:136
@ FontChange
Definition qcoreevent.h:133
bool isAccepted() const
Definition qcoreevent.h:308
\reentrant \inmodule QtGui
int height() const
Returns the height of the font.
QRect boundingRect(QChar) const
Returns the rectangle that is covered by ink if character ch were to be drawn at the origin of the co...
QSize size(int flags, const QString &str, int tabstops=0, int *tabarray=nullptr) const
Returns the size in pixels of text.
int horizontalAdvance(const QString &, int len=-1) const
Returns the horizontal advance in pixels of the first len characters of text.
\reentrant
Definition qfont.h:22
QFont resolve(const QFont &) const
Returns a new QFont that has attributes copied from other that have not been previously set on this f...
Definition qfont.cpp:1893
void setResolveMask(uint mask)
Definition qfont.h:313
uint resolveMask() const
Definition qfont.h:312
The QFrame class is the base class of widgets that can have a frame.
Definition qframe.h:17
int midLineWidth
the width of the mid-line
Definition qframe.h:23
@ NoFrame
Definition qframe.h:39
int lineWidth
the line width
Definition qframe.h:22
Shape frameShape
the frame shape value from the frame style
Definition qframe.h:20
static QPalette palette()
Returns the current application palette.
qreal devicePixelRatio() const
Returns the highest screen device pixel ratio found on the system.
static QScreen * screenAt(const QPoint &point)
Returns the screen at point, or \nullptr if outside of any screen.
\inmodule QtCore
Definition qhash.h:1145
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
void paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment=Qt::AlignCenter, Mode mode=Normal, State state=Off) const
Uses the painter to paint the icon with specified alignment, required mode, and state into the rectan...
Definition qicon.cpp:977
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:1019
Mode
This enum type describes the mode for which a pixmap is intended to be used.
Definition qicon.h:22
@ Disabled
Definition qicon.h:22
@ Normal
Definition qicon.h:22
@ Active
Definition qicon.h:22
State
This enum describes the state for which a pixmap is intended to be used.
Definition qicon.h:23
@ Off
Definition qicon.h:23
@ On
Definition qicon.h:23
QPixmap pixmap(const QSize &size, Mode mode=Normal, State state=Off) const
Returns a pixmap with the requested size, mode, and state, generating one if necessary.
Definition qicon.cpp:834
\inmodule QtGui
Definition qimage.h:37
The QKeySequence class encapsulates a key sequence as used by shortcuts.
bool isEmpty() const override
\reimp
Definition qlayout.cpp:422
The QLineEdit widget is a one-line text editor.
Definition qlineedit.h:28
bool hasFrame() const
bool isReadOnly() const
qsizetype size() const noexcept
Definition qlist.h:397
T value(qsizetype i) const
Definition qlist.h:664
\inmodule QtCore
Definition qmargins.h:24
\inmodule QtCore
QVariant read(const QObject *obj) const
Reads the property's value from the given object.
bool isDesignable() const
Returns false if the {Q_PROPERTY()}'s DESIGNABLE attribute is false; otherwise returns true.
bool isWritable() const
Returns true if this property is writable; otherwise returns false.
\inmodule QtCore
Definition qobject.h:103
T findChild(QAnyStringView aName, Qt::FindChildOptions options=Qt::FindChildrenRecursively) const
Returns the child of this object that can be cast into type T and that is called name,...
Definition qobject.h:155
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
qreal devicePixelRatio() const
\inmodule QtGui
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
@ SmoothPixmapTransform
Definition qpainter.h:54
@ Antialiasing
Definition qpainter.h:52
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
const QBrush & brush(ColorGroup cg, ColorRole cr) const
Returns the brush in the specified color group, used for the given color role.
Definition qpalette.cpp:748
void setBrush(ColorRole cr, const QBrush &brush)
Sets the brush for the given color role to the specified brush for all groups in the palette.
Definition qpalette.h:151
void setResolveMask(ResolveMask mask)
ResolveMask resolveMask() const
Definition qpalette.cpp:999
ColorGroup
\value Disabled \value Active \value Inactive \value Normal synonym for Active
Definition qpalette.h:49
@ Inactive
Definition qpalette.h:49
@ Disabled
Definition qpalette.h:49
QPalette resolve(const QPalette &other) const
Returns a new QPalette that is a union of this instance and other.
Definition qpalette.cpp:963
void setColor(ColorGroup cg, ColorRole cr, const QColor &color)
Sets the color in the specified color group, used for the given color role, to the specified solid co...
Definition qpalette.h:146
@ HighlightedText
Definition qpalette.h:53
@ AlternateBase
Definition qpalette.h:55
@ ButtonText
Definition qpalette.h:52
@ WindowText
Definition qpalette.h:51
@ Highlight
Definition qpalette.h:53
@ PlaceholderText
Definition qpalette.h:58
@ Midlight
Definition qpalette.h:51
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
int width() const
Returns the width of the pixmap.
Definition qpixmap.cpp:468
The QPlainTextEdit class provides a widget that is used to edit and display plain text.
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:167
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:373
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr void setRight(int pos) noexcept
Sets the right edge of the rectangle to the given x coordinate.
Definition qrect.h:197
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr QPoint topRight() const noexcept
Returns the position of the rectangle's top-right corner.
Definition qrect.h:227
constexpr void setLeft(int pos) noexcept
Sets the left edge of the rectangle to the given x coordinate.
Definition qrect.h:191
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr void setRect(int x, int y, int w, int h) noexcept
Sets the coordinates of the rectangle's top-left corner to ({x}, {y}), and its size to the given widt...
Definition qrect.h:346
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr void setWidth(int w) noexcept
Sets the width of the rectangle to the given width.
Definition qrect.h:381
constexpr void translate(int dx, int dy) noexcept
Moves the rectangle dx along the x axis and dy along the y axis, relative to the current position.
Definition qrect.h:245
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr QRect translated(int dx, int dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:261
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
constexpr void setHeight(int h) noexcept
Sets the height of the rectangle to the given height.
Definition qrect.h:384
constexpr QPoint center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:233
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:179
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
qreal devicePixelRatio
the screen's ratio between physical pixels and device-independent pixels
Definition qscreen.h:59
bool remove(const T &value)
Definition qset.h:63
iterator end()
Definition qset.h:140
iterator find(const T &value)
Definition qset.h:159
\inmodule QtCore
Definition qshareddata.h:19
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
constexpr QSize expandedTo(const QSize &) const noexcept
Returns a size holding the maximum width and height of this size and the given otherSize.
Definition qsize.h:192
constexpr void setWidth(int w) noexcept
Sets the width to the given width.
Definition qsize.h:136
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
constexpr void setHeight(int h) noexcept
Sets the height to the given height.
Definition qsize.h:139
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1246
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5506
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6664
\variable QStyleOptionGraphicsItem::exposedRect
\variable QStyleOptionHeaderV2::textElideMode
ButtonFeatures features
\variable QStyleOptionToolButton::features
\variable QStyleOptionMenuItem::menuItemType
\variable QStyleOptionComplex::subControls
\variable QStyleOption::palette
\variable QStyleOptionFocusRect::backgroundColor
\variable QStyleOptionFrame::features
The QStyleOptionHeaderV2 class is used to describe the parameters for drawing a header.
The QStyleOptionHeader class is used to describe the parameters for drawing a header.
Qt::Orientation orientation
SortIndicator sortIndicator
\variable QStyleOptionProgressBar::minimum
\variable QStyleOptionButton::features
\variable QStyleOptionToolBox::selectedPosition
\variable QStyleOptionComboBox::editable
\variable QStyleOptionDockWidget::title
The QStyleOption class stores the parameters used by QStyle functions.
QFontMetrics fontMetrics
QStyle::State state
QPalette palette
QObject * styleObject
Qt::LayoutDirection direction
QHash< const QObject *, QList< QCss::StyleRule > > styleRulesCache
QHash< const QWidget *, Tampered< QFont > > customFontWidgets
QHash< const QWidget *, Tampered< QPalette > > customPaletteWidgets
QHash< const void *, QCss::StyleSheet > styleSheetCache
void styleDestroyed(QObject *)
QHash< const QObject *, QRenderRules > renderRulesCache
QHash< const QObject *, QHash< int, bool > > hasStyleRuleCache
QSet< const QWidget * > autoFillDisabledWidgets
void objectDestroyed(QObject *)
void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const override
bool styleSheetPalette(const QWidget *w, const QStyleOption *opt, QPalette *pal)
void drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole=QPalette::NoRole) const override
void updateStyleSheetFont(QWidget *w) const
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr) const override
QStyleSheetStyle(QStyle *baseStyle)
QRect itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pixmap) const override
void unpolish(QWidget *widget) override
QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option=nullptr, const QWidget *w=nullptr) const override
int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const override
QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const override
int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const override
SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *w=nullptr) const override
void polish(QWidget *widget) override
void repolish(QWidget *widget)
QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize, const QWidget *widget=nullptr) const override
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *w=nullptr) const override
QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget=nullptr) const override
void saveWidgetFont(QWidget *w, const QFont &font) const
int styleHint(StyleHint sh, const QStyleOption *opt=nullptr, const QWidget *w=nullptr, QStyleHintReturn *shret=nullptr) const override
bool event(QEvent *e) override
void clearWidgetFont(QWidget *w) const
QPalette standardPalette() const override
void drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, const QPixmap &pixmap) const override
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *w=nullptr) const override
QRect itemTextRect(const QFontMetrics &metrics, const QRect &rect, int alignment, bool enabled, const QString &text) const override
QStyle * baseStyle() const
void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const override
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ State_Sibling
Definition qstyle.h:88
@ State_Window
Definition qstyle.h:84
@ State_MouseOver
Definition qstyle.h:80
@ State_Item
Definition qstyle.h:87
@ State_Sunken
Definition qstyle.h:69
@ State_HasFocus
Definition qstyle.h:75
@ State_Active
Definition qstyle.h:83
@ State_Off
Definition qstyle.h:70
@ State_Children
Definition qstyle.h:86
@ State_Open
Definition qstyle.h:85
@ State_NoChange
Definition qstyle.h:71
@ State_Enabled
Definition qstyle.h:67
@ State_ReadOnly
Definition qstyle.h:94
@ State_Horizontal
Definition qstyle.h:74
@ State_On
Definition qstyle.h:72
@ State_Selected
Definition qstyle.h:82
@ State_None
Definition qstyle.h:66
virtual void polish(QWidget *widget)
Initializes the appearance of the given widget.
Definition qstyle.cpp:436
virtual QRect itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const
Returns the area within the given rectangle in which to draw the specified pixmap according to the de...
Definition qstyle.cpp:534
virtual void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *widget=nullptr) const =0
Draws the given control using the provided painter with the style options specified by option.
virtual QPalette standardPalette() const
Returns the style's standard palette.
Definition qstyle.cpp:2301
virtual QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget=nullptr) const =0
Returns the rectangle containing the specified subControl of the given complex control (with the styl...
virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
virtual QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize, const QWidget *w=nullptr) const =0
Returns the size of the element described by the specified option and type, based on the provided con...
@ SH_ScrollView_FrameOnlyAroundContents
Definition qstyle.h:602
@ SH_UnderlineShortcut
Definition qstyle.h:626
virtual int styleHint(StyleHint stylehint, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr, QStyleHintReturn *returnData=nullptr) const =0
Returns an integer representing the specified style hint for the given widget described by the provid...
virtual void drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, const QPixmap &pixmap) const
Draws the given pixmap in the specified rectangle, according to the specified alignment,...
Definition qstyle.cpp:612
virtual QRect itemTextRect(const QFontMetrics &fm, const QRect &r, int flags, bool enabled, const QString &text) const
Returns the area within the given rectangle in which to draw the provided text according to the speci...
Definition qstyle.cpp:510
virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
StandardPixmap
This enum describes the available standard pixmaps.
Definition qstyle.h:716
@ SP_DockWidgetCloseButton
Definition qstyle.h:725
@ SP_DirIcon
Definition qstyle.h:755
@ SP_FileIcon
Definition qstyle.h:742
@ SP_ArrowForward
Definition qstyle.h:772
@ SP_DirLinkIcon
Definition qstyle.h:740
@ SP_DriveNetIcon
Definition qstyle.h:737
@ SP_TitleBarCloseButton
Definition qstyle.h:720
@ SP_ComputerIcon
Definition qstyle.h:732
@ SP_FileDialogBack
Definition qstyle.h:754
@ SP_DialogDiscardButton
Definition qstyle.h:764
@ SP_TitleBarMenuButton
Definition qstyle.h:717
@ SP_DesktopIcon
Definition qstyle.h:730
@ SP_DriveCDIcon
Definition qstyle.h:735
@ SP_TrashIcon
Definition qstyle.h:731
@ SP_DialogNoButton
Definition qstyle.h:766
@ SP_TitleBarMinButton
Definition qstyle.h:718
@ SP_DialogCloseButton
Definition qstyle.h:761
@ SP_TitleBarMaxButton
Definition qstyle.h:719
@ SP_FileDialogListView
Definition qstyle.h:753
@ SP_TitleBarContextHelpButton
Definition qstyle.h:724
@ SP_DirHomeIcon
Definition qstyle.h:773
@ SP_DialogOpenButton
Definition qstyle.h:759
@ SP_TitleBarNormalButton
Definition qstyle.h:721
@ SP_MessageBoxQuestion
Definition qstyle.h:729
@ SP_LineEditClearButton
Definition qstyle.h:787
@ SP_ArrowBack
Definition qstyle.h:771
@ SP_ArrowDown
Definition qstyle.h:768
@ SP_TitleBarShadeButton
Definition qstyle.h:722
@ SP_FileDialogNewFolder
Definition qstyle.h:749
@ SP_FileDialogEnd
Definition qstyle.h:747
@ SP_CustomBase
Definition qstyle.h:798
@ SP_FileDialogInfoView
Definition qstyle.h:751
@ SP_ArrowLeft
Definition qstyle.h:769
@ SP_DialogCancelButton
Definition qstyle.h:757
@ SP_FileDialogStart
Definition qstyle.h:746
@ SP_DriveHDIcon
Definition qstyle.h:734
@ SP_DriveDVDIcon
Definition qstyle.h:736
@ SP_DriveFDIcon
Definition qstyle.h:733
@ SP_DialogHelpButton
Definition qstyle.h:758
@ SP_DialogSaveButton
Definition qstyle.h:760
@ SP_FileDialogDetailedView
Definition qstyle.h:750
@ SP_MessageBoxCritical
Definition qstyle.h:728
@ SP_MessageBoxInformation
Definition qstyle.h:726
@ SP_DialogResetButton
Definition qstyle.h:763
@ SP_DialogOkButton
Definition qstyle.h:756
@ SP_ArrowUp
Definition qstyle.h:767
@ SP_FileDialogContentsView
Definition qstyle.h:752
@ SP_TitleBarUnshadeButton
Definition qstyle.h:723
@ SP_DialogYesButton
Definition qstyle.h:765
@ SP_FileDialogToParent
Definition qstyle.h:748
@ SP_FileLinkIcon
Definition qstyle.h:743
@ SP_DialogApplyButton
Definition qstyle.h:762
@ SP_MessageBoxWarning
Definition qstyle.h:727
@ SP_ArrowRight
Definition qstyle.h:770
@ SP_DirOpenIcon
Definition qstyle.h:738
@ SP_DirClosedIcon
Definition qstyle.h:739
static QRect alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
Returns a new rectangle of the specified size that is aligned to the given rectangle according to the...
Definition qstyle.cpp:2173
virtual QRect subElementRect(SubElement subElement, const QStyleOption *option, const QWidget *widget=nullptr) const =0
Returns the sub-area for the given element as described in the provided style option.
virtual SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *widget=nullptr) const =0
Returns the sub control at the given position in the given complex control (with the style options sp...
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Returns the given logicalRectangle converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2143
@ PM_MenuPanelWidth
Definition qstyle.h:453
@ PM_ScrollBarExtent
Definition qstyle.h:426
@ PM_DefaultFrameWidth
Definition qstyle.h:420
@ PM_IndicatorWidth
Definition qstyle.h:462
@ PM_CheckBoxLabelSpacing
Definition qstyle.h:502
@ PM_IndicatorHeight
Definition qstyle.h:463
@ PM_ComboBoxFrameWidth
Definition qstyle.h:422
@ PM_MenuBarPanelWidth
Definition qstyle.h:457
@ PM_HeaderMargin
Definition qstyle.h:476
@ PM_SmallIconSize
Definition qstyle.h:495
@ PM_SpinBoxFrameWidth
Definition qstyle.h:421
@ PM_ToolTipLabelFrameWidth
Definition qstyle.h:501
@ PE_IndicatorArrowDown
Definition qstyle.h:124
virtual void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const =0
Draws the given element with the provided painter with the style options specified by option.
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
Returns the value of the given pixel metric.
virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const =0
Returns a copy of the given pixmap, styled to conform to the specified iconMode and taking into accou...
virtual void drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole=QPalette::NoRole) const
Draws the given text in the specified rectangle using the provided painter and palette.
Definition qstyle.cpp:574
virtual QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr) const =0
virtual void unpolish(QWidget *widget)
Uninitialize the given {widget}'s appearance.
Definition qstyle.cpp:455
@ SE_ItemViewItemCheckIndicator
Definition qstyle.h:275
virtual void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const =0
Draws the given primitive element with the provided painter using the style options specified by opti...
SubControl
This enum describes the available sub controls.
Definition qstyle.h:347
@ SC_ScrollBarSubLine
Definition qstyle.h:351
@ SC_SliderGroove
Definition qstyle.h:369
@ SC_TitleBarMinButton
Definition qstyle.h:377
@ SC_ScrollBarAddPage
Definition qstyle.h:352
@ SC_ScrollBarLast
Definition qstyle.h:355
@ SC_TitleBarLabel
Definition qstyle.h:384
@ SC_TitleBarUnshadeButton
Definition qstyle.h:382
@ SC_MdiMinButton
Definition qstyle.h:395
@ SC_TitleBarNormalButton
Definition qstyle.h:380
@ SC_ScrollBarAddLine
Definition qstyle.h:350
@ SC_MdiNormalButton
Definition qstyle.h:396
@ SC_ScrollBarFirst
Definition qstyle.h:354
@ SC_ScrollBarSlider
Definition qstyle.h:356
@ SC_ScrollBarSubPage
Definition qstyle.h:353
@ SC_SpinBoxDown
Definition qstyle.h:360
@ SC_SpinBoxUp
Definition qstyle.h:359
@ SC_MdiCloseButton
Definition qstyle.h:397
@ SC_GroupBoxCheckBox
Definition qstyle.h:390
@ SC_TitleBarShadeButton
Definition qstyle.h:381
@ SC_GroupBoxLabel
Definition qstyle.h:391
@ SC_None
Definition qstyle.h:348
@ SC_ComboBoxEditField
Definition qstyle.h:365
@ SC_SliderTickmarks
Definition qstyle.h:371
@ SC_TitleBarSysMenu
Definition qstyle.h:376
@ SC_TitleBarMaxButton
Definition qstyle.h:378
@ SC_TitleBarCloseButton
Definition qstyle.h:379
@ SC_ComboBoxArrow
Definition qstyle.h:366
@ SC_TitleBarContextHelpButton
Definition qstyle.h:383
@ SC_SliderHandle
Definition qstyle.h:370
@ SC_ToolButtonMenu
Definition qstyle.h:374
The QTabBar class provides a tab bar, e.g.
Definition qtabbar.h:19
@ LeftSide
Definition qtabbar.h:48
@ RightSide
Definition qtabbar.h:49
QRect tabRect(int index) const
Returns the visual rectangle of the tab at position index, or a null rectangle if index is hidden,...
Definition qtabbar.cpp:1342
@ RoundedSouth
Definition qtabbar.h:42
@ RoundedNorth
Definition qtabbar.h:42
@ TriangularEast
Definition qtabbar.h:43
@ RoundedWest
Definition qtabbar.h:42
@ TriangularSouth
Definition qtabbar.h:43
@ RoundedEast
Definition qtabbar.h:42
@ TriangularWest
Definition qtabbar.h:43
@ TriangularNorth
Definition qtabbar.h:43
The QTextEdit class provides a widget that is used to edit and display both plain and rich text.
Definition qtextedit.h:27
static QPalette palette()
Returns the palette used to render tooltips.
Definition qtooltip.cpp:535
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
\inmodule QtCore
Definition qtypeinfo.h:100
\inmodule QtCore
Definition qvariant.h:65
T value() const &
Definition qvariant.h:516
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QPointF mapToGlobal(const QPointF &) const
Translates the widget coordinate pos to global screen coordinates.
QPalette palette
the widget's palette
Definition qwidget.h:132
QFontMetrics fontMetrics() const
Returns the font metrics for the widget's current font.
Definition qwidget.h:847
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
QStyle * style() const
Definition qwidget.cpp:2600
QFont font
the font currently set for the widget
Definition qwidget.h:133
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
QOpenGLWidget * widget
[1]
QMap< QString, QString > map
[6]
QString text
qreal spacing
QPushButton * button
[2]
list append(new Employee("Blackpool", "Stephen"))
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
opt iconSize
rect
[4]
uint alignment
QStyleOptionButton opt
fontMetrics
else opt state
[0]
QRect textRect
const QStyleOptionButton * btn
[3]
const quint64 PseudoClass_Floatable
const quint64 PseudoClass_Movable
const quint64 PseudoClass_Children
const quint64 PseudoClass_Disabled
const quint64 PseudoClass_Sibling
const quint64 PseudoClass_ReadOnly
const quint64 PseudoClass_Closed
const quint64 PseudoClass_Maximized
const quint64 PseudoClass_Default
@ Repeat_XY
@ Repeat_None
const quint64 PseudoClass_Bottom
const quint64 PseudoClass_EditFocus
const quint64 PseudoClass_Focus
const quint64 PseudoClass_Enabled
const quint64 PseudoClass_Editable
const quint64 PseudoClass_Vertical
const quint64 PseudoClass_Flat
const quint64 PseudoClass_NonExclusive
@ Origin_Padding
@ Origin_Content
@ Origin_Unknown
@ Origin_Margin
@ Origin_Border
const quint64 PseudoClass_Pressed
const quint64 PseudoClass_Item
const quint64 PseudoClass_Alternate
const quint64 PseudoClass_PreviousSelected
const quint64 PseudoClass_Closable
const quint64 PseudoClass_Horizontal
const quint64 PseudoClass_Off
const quint64 PseudoClass_Active
const quint64 PseudoClass_NextSelected
@ StyleFeature_BackgroundGradient
@ StyleFeature_BackgroundColor
const quint64 PseudoClass_Frameless
const quint64 PseudoClass_Checked
const quint64 PseudoClass_Selected
@ Attachment_Scroll
const quint64 PseudoClass_Right
@ Padding
const quint64 PseudoClass_Window
const quint64 PseudoClass_Minimized
@ TileMode_Unknown
@ StyleSheetOrigin_Inline
const quint64 PseudoClass_On
const quint64 PseudoClass_Unchecked
const quint64 PseudoClass_First
const quint64 PseudoClass_Indeterminate
const quint64 PseudoClass_Middle
@ PositionMode_Absolute
@ PositionMode_Unknown
@ PositionMode_Static
const quint64 PseudoClass_Top
const quint64 PseudoClass_Hover
@ BorderStyle_Dotted
@ BorderStyle_Native
@ BorderStyle_None
@ BorderStyle_DotDotDash
const quint64 PseudoClass_Left
const quint64 PseudoClass_Last
const quint64 PseudoClass_OnlyOne
const quint64 PseudoClass_Exclusive
QVector3D minimum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
Definition qssgutils_p.h:54
QVector3D maximum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
Definition qssgutils_p.h:55
Combined button and popup list for selecting options.
QSize adjustSize(const QSize &size, PixelFormat srcFmt, PixelFormat dstFmt)
bool isNull(const T &t)
Definition qcompare.h:63
@ WindowMinimized
Definition qnamespace.h:253
@ WindowMaximized
Definition qnamespace.h:254
@ AlignRight
Definition qnamespace.h:146
@ AlignBottom
Definition qnamespace.h:154
@ AlignVCenter
Definition qnamespace.h:155
@ AlignTop
Definition qnamespace.h:153
@ AlignHCenter
Definition qnamespace.h:148
@ AlignCenter
Definition qnamespace.h:163
@ AlignAbsolute
Definition qnamespace.h:150
@ AlignLeft
Definition qnamespace.h:144
@ WA_StyleSheet
Definition qnamespace.h:372
@ WA_WindowPropagation
Definition qnamespace.h:349
@ WA_Hover
Definition qnamespace.h:340
@ WA_MacShowFocusRect
Definition qnamespace.h:359
@ WA_StyledBackground
Definition qnamespace.h:366
@ WA_StyleSheetTarget
Definition qnamespace.h:417
@ WA_OpaquePaintEvent
Definition qnamespace.h:287
@ IntersectClip
@ LeftToolBarArea
@ BottomToolBarArea
@ TopToolBarArea
@ RightToolBarArea
LayoutDirection
@ LeftToRight
@ RightToLeft
Orientation
Definition qnamespace.h:98
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
@ UpArrow
@ RightArrow
@ LeftArrow
@ DownArrow
@ TextSingleLine
Definition qnamespace.h:170
@ TextDontClip
Definition qnamespace.h:171
@ TextHideMnemonic
Definition qnamespace.h:178
@ TextShowMnemonic
Definition qnamespace.h:173
TileRule
Definition qnamespace.h:133
@ RepeatTile
Definition qnamespace.h:135
@ RoundTile
Definition qnamespace.h:136
@ StretchTile
Definition qnamespace.h:134
@ white
Definition qnamespace.h:31
@ transparent
Definition qnamespace.h:47
@ AA_UseStyleSheetPropagationInWidgetStyles
Definition qnamespace.h:457
@ RightEdge
@ TopEdge
@ BottomEdge
@ LeftEdge
@ CaseInsensitive
@ SolidPattern
@ LinearGradientPattern
@ Dense4Pattern
@ NoBrush
@ ConicalGradientPattern
@ UniqueConnection
@ Desktop
Definition qnamespace.h:215
@ WindowContextHelpButtonHint
Definition qnamespace.h:231
@ WindowType_Mask
Definition qnamespace.h:220
@ WindowMaximizeButtonHint
Definition qnamespace.h:229
@ WindowMinimizeButtonHint
Definition qnamespace.h:228
@ WindowShadeButtonHint
Definition qnamespace.h:232
@ Tool
Definition qnamespace.h:212
@ WindowTitleHint
Definition qnamespace.h:226
@ WindowSystemMenuHint
Definition qnamespace.h:227
@ ElideRight
Definition qnamespace.h:190
@ ToolButtonTextOnly
@ ToolButtonTextUnderIcon
@ ToolButtonTextBesideIcon
@ ToolButtonIconOnly
@ ToolButtonFollowStyle
Definition brush.cpp:5
Definition image.cpp:4
static void * context
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
#define qApp
void qNormalizeRadii(const QRect &br, const QSize *radii, QSize *tlr, QSize *trr, QSize *blr, QSize *brr)
Definition qcssutil.cpp:279
void qDrawBorder(QPainter *p, const QRect &rect, const QCss::BorderStyle *styles, const int *borders, const QBrush *colors, const QSize *radii)
Definition qcssutil.cpp:313
DBusConnection const char * rule
static QString header(const QString &name)
void qDrawShadePanel(QPainter *p, int x, int y, int w, int h, const QPalette &pal, bool sunken, int lineWidth, const QBrush *fill)
Q_WIDGETS_EXPORT void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins, const QPixmap &pixmap, const QRect &sourceRect, const QMargins &sourceMargins, const QTileRules &rules=QTileRules(), QDrawBorderPixmap::DrawingHints hints=QDrawBorderPixmap::DrawingHints())
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static void setClip(QPainter *painter, QGraphicsItem *item)
static void visualRect(QRectF *geom, Qt::LayoutDirection dir, const QRectF &contentsRect)
QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio, qreal *sourceDevicePixelRatio)
Definition qicon.cpp:1984
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
static bool isNumber(char s)
GLint GLfloat GLfloat GLfloat v2
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLdouble GLdouble GLdouble GLdouble top
GLuint object
[3]
GLdouble GLdouble right
GLint GLenum GLsizei GLsizei GLsizei GLint border
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLenum src
GLsizei range
GLint GLsizei width
GLuint color
[2]
GLint left
GLenum type
GLboolean GLuint group
GLint GLint bottom
GLbitfield flags
GLenum GLuint GLintptr offset
GLenum attachment
GLuint name
GLfloat n
GLsizei const GLint * box
GLint y
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint GLfloat * val
GLint void * img
Definition qopenglext.h:233
GLuint GLsizei const GLuint const GLintptr * offsets
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLuint GLenum option
GLenum GLsizei len
@ Left
@ Right
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
static QRectF alignedRect(bool mirrored, Qt::Alignment alignment, const QSizeF &size, const QRectF &rectangle)
static QT_BEGIN_NAMESPACE const QRgb colors[][14]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Int aligned(Int v, Int byteAlign)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define qPrintable(string)
Definition qstring.h:1531
QStyleSheetStyle * qt_styleSheet(QStyle *style)
#define sp
constexpr bool verticalTabs(QTabBar::Shape shape) noexcept
Definition qtabbar_p.h:248
QScreen * screen
[1]
Definition main.cpp:29
#define QT_CONFIG(feature)
static void drawBackground(QPainter *p, const QTextCharFormat &chf, const QRectF &r)
#define Q_UNUSED(x)
@ Q_RELOCATABLE_TYPE
Definition qtypeinfo.h:158
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:180
unsigned char uchar
Definition qtypes.h:32
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
static const uint base
Definition qurlidna.cpp:20
#define QWIDGETSIZE_MAX
Definition qwidget.h:917
const QWidget * qobject_cast< const QWidget * >(const QObject *o)
Definition qwidget.h:791
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
const char property[13]
Definition qwizard.cpp:101
const char className[16]
[1]
Definition qwizard.cpp:100
p drawImage(offset, thumbnail)
QFileSelector selector
[1]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
obj metaObject() -> className()
QObject::connect nullptr
QVBoxLayout * layout
QLineEdit * lineEdit
myObject disconnect()
[26]
ba fill(true)
QPropertyAnimation animation
[0]
QRect r2(QPoint(100, 200), QSize(11, 16))
QString dir
[11]
Text files * txt
QFileDialog dialog(this)
[1]
edit isVisible()
app setAttribute(Qt::AA_DontShowIconsInMenus)
QApplication app(argc, argv)
[0]
QLayoutItem * child
[0]
widget render & pixmap
QPainter painter(this)
[7]
QFrame frame
[0]
QSpinBox * spinBox
[0]
QHostInfo info
[0]
QNetworkProxy proxy
[0]
QQuickView * view
[0]
QIcon iconValue() const
Qt::Alignment alignmentValue() const
bool realValue(qreal *r, const char *unit=nullptr) const
QExplicitlySharedDataPointer< DeclarationData > d
QColor colorValue(const QPalette &=QPalette()) const
void borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const
bool intValue(int *i, const char *unit=nullptr) const
QRect rectValue() const
QBrush brushValue(const QPalette &=QPalette()) const
QString uriValue() const
QSize sizeValue() const
\inmodule QtCore
int indexOfProperty(const char *name) const
Finds property name and returns its index; otherwise returns -1.
The QTileRules class provides the rules used to draw a pixmap or image split into nine segments.
Definition qdrawutil.h:88
QT_BEGIN_NAMESPACE bool toBool(const QString &str)
Definition utils.h:14