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