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

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