1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qcommonstyle.h"
5#include "qcommonstyle_p.h"
6
7#include <qfile.h>
8#if QT_CONFIG(itemviews)
9#include <qabstractitemview.h>
10#endif
11#include <qapplication.h>
12#include <private/qguiapplication_p.h>
13#include <qpa/qplatformtheme.h>
14#include <qbitmap.h>
15#include <qcache.h>
16#if QT_CONFIG(dockwidget)
17#include <qdockwidget.h>
18#endif
19#include <qdrawutil.h>
20#if QT_CONFIG(dialogbuttonbox)
21#include <qdialogbuttonbox.h>
22#endif
23#if QT_CONFIG(formlayout)
24#include <qformlayout.h>
25#else
26#include <qlayout.h>
27#endif
28#if QT_CONFIG(groupbox)
29#include <qgroupbox.h>
30#endif
31#include <qmath.h>
32#if QT_CONFIG(menu)
33#include <qmenu.h>
34#endif
35#include <qpainter.h>
36#include <qpaintengine.h>
37#include <qpainterpath.h>
38#if QT_CONFIG(slider)
39#include <qslider.h>
40#endif
41#include <qstyleoption.h>
42#if QT_CONFIG(tabbar)
43#include <qtabbar.h>
44#endif
45#if QT_CONFIG(tabwidget)
46#include <qtabwidget.h>
47#endif
48#if QT_CONFIG(toolbar)
49#include <qtoolbar.h>
50#endif
51#if QT_CONFIG(toolbutton)
52#include <qtoolbutton.h>
53#endif
54#if QT_CONFIG(rubberband)
55#include <qrubberband.h>
56#endif
57#if QT_CONFIG(treeview)
58#include "qtreeview.h"
59#endif
60#include <private/qcommonstylepixmaps_p.h>
61#include <private/qmath_p.h>
62#include <qdebug.h>
63#include <qtextformat.h>
64#if QT_CONFIG(wizard)
65#include <qwizard.h>
66#endif
67#if QT_CONFIG(filedialog)
68#include <qsidebar_p.h>
69#endif
70#include <qfileinfo.h>
71#include <qdir.h>
72#if QT_CONFIG(settings)
73#include <qsettings.h>
74#endif
75#include <qvariant.h>
76#include <qpixmapcache.h>
77#if QT_CONFIG(animation)
78#include <private/qstyleanimation_p.h>
79#endif
80
81#include <qloggingcategory.h>
82
83#include <limits.h>
84
85#include <private/qtextengine_p.h>
86#include <private/qstylehelper_p.h>
87
88QT_BEGIN_NAMESPACE
89
90Q_LOGGING_CATEGORY(lcCommonStyle, "qt.widgets.commonstyle");
91
92using namespace Qt::StringLiterals;
93
94static qreal qt_getDevicePixelRatio(const QWidget *widget)
95{
96 return widget ? widget->devicePixelRatio() : qApp->devicePixelRatio();
97}
98
99struct QPainterStateSaver
100{
101 QPainterStateSaver(QPainter *p, bool bSaveRestore = true)
102 : m_painter(p)
103 , m_bSaveRestore(bSaveRestore)
104 {
105 if (m_bSaveRestore)
106 m_painter->save();
107 }
108 ~QPainterStateSaver()
109 {
110 restore();
111 }
112 void restore()
113 {
114 if (m_bSaveRestore) {
115 m_bSaveRestore = false;
116 m_painter->restore();
117 }
118 }
119private:
120 QPainter *m_painter;
121 bool m_bSaveRestore;
122};
123
124/*!
125 \class QCommonStyle
126 \brief The QCommonStyle class encapsulates the common Look and Feel of a GUI.
127
128 \ingroup appearance
129 \inmodule QtWidgets
130
131 This abstract class implements some of the widget's look and feel
132 that is common to all GUI styles provided and shipped as part of
133 Qt.
134
135 Since QCommonStyle inherits QStyle, all of its functions are fully documented
136 in the QStyle documentation.
137 \omit
138 , although the
139 extra functions that QCommonStyle provides, e.g.
140 drawComplexControl(), drawControl(), drawPrimitive(),
141 hitTestComplexControl(), subControlRect(), sizeFromContents(), and
142 subElementRect() are documented here.
143 \endomit
144
145 \sa QStyle, QProxyStyle
146*/
147
148/*!
149 Constructs a QCommonStyle.
150*/
151QCommonStyle::QCommonStyle()
152 : QStyle(*new QCommonStylePrivate)
153{ }
154
155/*! \internal
156*/
157QCommonStyle::QCommonStyle(QCommonStylePrivate &dd)
158 : QStyle(dd)
159{ }
160
161/*!
162 Destroys the style.
163*/
164QCommonStyle::~QCommonStyle()
165{ }
166
167
168/*!
169 \reimp
170*/
171void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
172 const QWidget *widget) const
173{
174 Q_D(const QCommonStyle);
175 switch (pe) {
176 case PE_FrameButtonBevel:
177 case PE_FrameButtonTool:
178 qDrawShadeRect(p, r: opt->rect, pal: opt->palette,
179 sunken: opt->state & (State_Sunken | State_On), lineWidth: 1, midLineWidth: 0);
180 break;
181 case PE_PanelButtonCommand:
182 case PE_PanelButtonBevel:
183 case PE_PanelButtonTool:
184 case PE_IndicatorButtonDropDown:
185 qDrawShadePanel(p, r: opt->rect, pal: opt->palette,
186 sunken: opt->state & (State_Sunken | State_On), lineWidth: 1,
187 fill: &opt->palette.brush(cr: QPalette::Button));
188 break;
189 case PE_IndicatorItemViewItemCheck:
190 proxy()->drawPrimitive(pe: PE_IndicatorCheckBox, opt, p, w: widget);
191 break;
192 case PE_IndicatorCheckBox:
193 if (opt->state & State_NoChange) {
194 p->setPen(opt->palette.windowText().color());
195 p->fillRect(opt->rect, opt->palette.brush(cr: QPalette::Button));
196 p->drawRect(r: opt->rect);
197 p->drawLine(p1: opt->rect.topLeft(), p2: opt->rect.bottomRight());
198 } else {
199 qDrawShadePanel(p, x: opt->rect.x(), y: opt->rect.y(), w: opt->rect.width(), h: opt->rect.height(),
200 pal: opt->palette, sunken: opt->state & (State_Sunken | State_On), lineWidth: 1,
201 fill: &opt->palette.brush(cr: QPalette::Button));
202 }
203 break;
204 case PE_IndicatorRadioButton: {
205 QRect ir = opt->rect;
206 p->setPen(opt->palette.dark().color());
207 p->drawArc(r: opt->rect, a: 0, alen: 5760);
208 if (opt->state & (State_Sunken | State_On)) {
209 ir.adjust(dx1: 2, dy1: 2, dx2: -2, dy2: -2);
210 p->setBrush(opt->palette.windowText());
211 p->drawEllipse(r: ir);
212 }
213 break; }
214 case PE_FrameFocusRect:
215 if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt)) {
216 QColor bg = fropt->backgroundColor;
217 QColor color;
218 if (bg.isValid()) {
219 int h, s, v;
220 bg.getHsv(h: &h, s: &s, v: &v);
221 if (v >= 128)
222 color = Qt::black;
223 else
224 color = Qt::white;
225 } else {
226 color = opt->palette.windowText().color();
227 }
228 const QRect focusRect = opt->rect.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1);
229 qDrawPlainRect(p, r: focusRect, color, lineWidth: 1);
230 }
231 break;
232 case PE_IndicatorMenuCheckMark: {
233 const int markW = opt->rect.width() > 7 ? 7 : opt->rect.width();
234 const int markH = markW;
235 int posX = opt->rect.x() + (opt->rect.width() - markW)/2 + 1;
236 int posY = opt->rect.y() + (opt->rect.height() - markH)/2;
237
238 QList<QLineF> a;
239 a.reserve(asize: markH);
240
241 int i, xx, yy;
242 xx = posX;
243 yy = 3 + posY;
244 for (i = 0; i < markW/2; ++i) {
245 a << QLineF(xx, yy, xx, yy + 2);
246 ++xx;
247 ++yy;
248 }
249 yy -= 2;
250 for (; i < markH; ++i) {
251 a << QLineF(xx, yy, xx, yy + 2);
252 ++xx;
253 --yy;
254 }
255 if (!(opt->state & State_Enabled) && !(opt->state & State_On)) {
256 QPainterStateSaver pss(p);
257 p->translate(dx: 1, dy: 1);
258 p->setPen(opt->palette.light().color());
259 p->drawLines(lines: a);
260 }
261 p->setPen((opt->state & State_On) ? opt->palette.highlightedText().color() : opt->palette.text().color());
262 p->drawLines(lines: a);
263 break; }
264 case PE_Frame:
265 case PE_FrameMenu:
266 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
267 if (pe == PE_FrameMenu || (frame->state & State_Sunken) || (frame->state & State_Raised)) {
268 qDrawShadePanel(p, r: frame->rect, pal: frame->palette, sunken: frame->state & State_Sunken,
269 lineWidth: frame->lineWidth);
270 } else {
271 qDrawPlainRect(p, r: frame->rect, frame->palette.windowText().color(), lineWidth: frame->lineWidth);
272 }
273 }
274 break;
275#if QT_CONFIG(toolbar)
276 case PE_PanelMenuBar:
277 if (widget && qobject_cast<QToolBar *>(object: widget->parentWidget()))
278 break;
279 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)){
280 qDrawShadePanel(p, r: frame->rect, pal: frame->palette, sunken: false, lineWidth: frame->lineWidth,
281 fill: &frame->palette.brush(cr: QPalette::Button));
282
283 }
284 else if (const QStyleOptionToolBar *frame = qstyleoption_cast<const QStyleOptionToolBar *>(opt)){
285 qDrawShadePanel(p, r: frame->rect, pal: frame->palette, sunken: false, lineWidth: frame->lineWidth,
286 fill: &frame->palette.brush(cr: QPalette::Button));
287 }
288
289 break;
290 case PE_PanelMenu:
291 break;
292 case PE_PanelToolBar:
293 break;
294#endif // QT_CONFIG(toolbar)
295#if QT_CONFIG(progressbar)
296 case PE_IndicatorProgressChunk:
297 {
298 bool vertical = false;
299 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt))
300 vertical = !(pb->state & QStyle::State_Horizontal);
301 if (!vertical) {
302 p->fillRect(x: opt->rect.x(), y: opt->rect.y() + 3, w: opt->rect.width() -2, h: opt->rect.height() - 6,
303 b: opt->palette.brush(cr: QPalette::Highlight));
304 } else {
305 p->fillRect(x: opt->rect.x() + 2, y: opt->rect.y(), w: opt->rect.width() -6, h: opt->rect.height() - 2,
306 b: opt->palette.brush(cr: QPalette::Highlight));
307 }
308 }
309 break;
310#endif // QT_CONFIG(progressbar)
311 case PE_IndicatorBranch: {
312 static const int decoration_size = 9;
313 int mid_h = opt->rect.x() + opt->rect.width() / 2;
314 int mid_v = opt->rect.y() + opt->rect.height() / 2;
315 int bef_h = mid_h;
316 int bef_v = mid_v;
317 int aft_h = mid_h;
318 int aft_v = mid_v;
319 if (opt->state & State_Children) {
320 int delta = decoration_size / 2;
321 bef_h -= delta;
322 bef_v -= delta;
323 aft_h += delta;
324 aft_v += delta;
325 p->drawLine(x1: bef_h + 2, y1: bef_v + 4, x2: bef_h + 6, y2: bef_v + 4);
326 if (!(opt->state & State_Open))
327 p->drawLine(x1: bef_h + 4, y1: bef_v + 2, x2: bef_h + 4, y2: bef_v + 6);
328 QPen oldPen = p->pen();
329 p->setPen(opt->palette.dark().color());
330 p->drawRect(x: bef_h, y: bef_v, w: decoration_size - 1, h: decoration_size - 1);
331 p->setPen(oldPen);
332 }
333 QBrush brush(opt->palette.dark().color(), Qt::Dense4Pattern);
334 if (opt->state & State_Item) {
335 if (opt->direction == Qt::RightToLeft)
336 p->fillRect(x: opt->rect.left(), y: mid_v, w: bef_h - opt->rect.left(), h: 1, b: brush);
337 else
338 p->fillRect(x: aft_h, y: mid_v, w: opt->rect.right() - aft_h + 1, h: 1, b: brush);
339 }
340 if (opt->state & State_Sibling)
341 p->fillRect(x: mid_h, y: aft_v, w: 1, h: opt->rect.bottom() - aft_v + 1, b: brush);
342 if (opt->state & (State_Open | State_Children | State_Item | State_Sibling))
343 p->fillRect(x: mid_h, y: opt->rect.y(), w: 1, h: bef_v - opt->rect.y(), b: brush);
344 break; }
345 case PE_FrameStatusBarItem:
346 qDrawShadeRect(p, r: opt->rect, pal: opt->palette, sunken: true, lineWidth: 1, midLineWidth: 0, fill: nullptr);
347 break;
348 case PE_IndicatorHeaderArrow:
349 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
350 QPen oldPen = p->pen();
351 if (header->sortIndicator & QStyleOptionHeader::SortUp) {
352 p->setPen(QPen(opt->palette.light(), 0));
353 p->drawLine(x1: opt->rect.x() + opt->rect.width(), y1: opt->rect.y(),
354 x2: opt->rect.x() + opt->rect.width() / 2, y2: opt->rect.y() + opt->rect.height());
355 p->setPen(QPen(opt->palette.dark(), 0));
356 const QPoint points[] = {
357 QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y() + opt->rect.height()),
358 QPoint(opt->rect.x(), opt->rect.y()),
359 QPoint(opt->rect.x() + opt->rect.width(), opt->rect.y()),
360 };
361 p->drawPolyline(points, pointCount: sizeof points / sizeof *points);
362 } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
363 p->setPen(QPen(opt->palette.light(), 0));
364 const QPoint points[] = {
365 QPoint(opt->rect.x(), opt->rect.y() + opt->rect.height()),
366 QPoint(opt->rect.x() + opt->rect.width(), opt->rect.y() + opt->rect.height()),
367 QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y()),
368 };
369 p->drawPolyline(points, pointCount: sizeof points / sizeof *points);
370 p->setPen(QPen(opt->palette.dark(), 0));
371 p->drawLine(x1: opt->rect.x(), y1: opt->rect.y() + opt->rect.height(),
372 x2: opt->rect.x() + opt->rect.width() / 2, y2: opt->rect.y());
373 }
374 p->setPen(oldPen);
375 }
376 break;
377#if QT_CONFIG(tabbar)
378 case PE_FrameTabBarBase:
379 if (const QStyleOptionTabBarBase *tbb
380 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
381 QPainterStateSaver pss(p);
382 switch (tbb->shape) {
383 case QTabBar::RoundedNorth:
384 case QTabBar::TriangularNorth:
385 p->setPen(QPen(tbb->palette.light(), 0));
386 p->drawLine(p1: tbb->rect.topLeft(), p2: tbb->rect.topRight());
387 break;
388 case QTabBar::RoundedWest:
389 case QTabBar::TriangularWest:
390 p->setPen(QPen(tbb->palette.light(), 0));
391 p->drawLine(p1: tbb->rect.topLeft(), p2: tbb->rect.bottomLeft());
392 break;
393 case QTabBar::RoundedSouth:
394 case QTabBar::TriangularSouth:
395 p->setPen(QPen(tbb->palette.shadow(), 0));
396 p->drawLine(x1: tbb->rect.left(), y1: tbb->rect.bottom(),
397 x2: tbb->rect.right(), y2: tbb->rect.bottom());
398 p->setPen(QPen(tbb->palette.dark(), 0));
399 p->drawLine(x1: tbb->rect.left(), y1: tbb->rect.bottom() - 1,
400 x2: tbb->rect.right() - 1, y2: tbb->rect.bottom() - 1);
401 break;
402 case QTabBar::RoundedEast:
403 case QTabBar::TriangularEast:
404 p->setPen(QPen(tbb->palette.dark(), 0));
405 p->drawLine(p1: tbb->rect.topRight(), p2: tbb->rect.bottomRight());
406 break;
407 }
408 }
409 break;
410 case PE_IndicatorTabClose: {
411 if (d->tabBarcloseButtonIcon.isNull())
412 d->tabBarcloseButtonIcon = proxy()->standardIcon(standardIcon: QStyle::SP_TabCloseButton, option: opt, widget);
413
414 const int size = proxy()->pixelMetric(metric: QStyle::PM_SmallIconSize, option: opt, widget);
415 QIcon::Mode mode = opt->state & State_Enabled ?
416 (opt->state & State_Raised ? QIcon::Active : QIcon::Normal)
417 : QIcon::Disabled;
418 if (!(opt->state & State_Raised)
419 && !(opt->state & State_Sunken)
420 && !(opt->state & QStyle::State_Selected))
421 mode = QIcon::Disabled;
422
423 QIcon::State state = opt->state & State_Sunken ? QIcon::On : QIcon::Off;
424 QPixmap pixmap = d->tabBarcloseButtonIcon.pixmap(size: QSize(size, size), devicePixelRatio: p->device()->devicePixelRatio(), mode, state);
425 proxy()->drawItemPixmap(painter: p, rect: opt->rect, alignment: Qt::AlignCenter, pixmap);
426 break;
427 }
428#else
429 Q_UNUSED(d);
430#endif // QT_CONFIG(tabbar)
431 case PE_FrameTabWidget:
432 case PE_FrameWindow:
433 qDrawWinPanel(p, r: opt->rect, pal: opt->palette, sunken: false, fill: nullptr);
434 break;
435 case PE_FrameLineEdit:
436 proxy()->drawPrimitive(pe: PE_Frame, opt, p, w: widget);
437 break;
438#if QT_CONFIG(groupbox)
439 case PE_FrameGroupBox:
440 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
441 if (frame->features & QStyleOptionFrame::Flat) {
442 QRect fr = frame->rect;
443 QPoint p1(fr.x(), fr.y() + 1);
444 QPoint p2(fr.x() + fr.width(), p1.y());
445 qDrawShadeLine(p, p1, p2, pal: frame->palette, sunken: true,
446 lineWidth: frame->lineWidth, midLineWidth: frame->midLineWidth);
447 } else {
448 qDrawShadeRect(p, x: frame->rect.x(), y: frame->rect.y(), w: frame->rect.width(),
449 h: frame->rect.height(), pal: frame->palette, sunken: true,
450 lineWidth: frame->lineWidth, midLineWidth: frame->midLineWidth);
451 }
452 }
453 break;
454#endif // QT_CONFIG(groupbox)
455#if QT_CONFIG(dockwidget)
456 case PE_FrameDockWidget:
457 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
458 int lw = frame->lineWidth;
459 if (lw <= 0)
460 lw = proxy()->pixelMetric(metric: PM_DockWidgetFrameWidth, option: opt, widget);
461
462 qDrawShadePanel(p, r: frame->rect, pal: frame->palette, sunken: false, lineWidth: lw);
463 }
464 break;
465#endif // QT_CONFIG(dockwidget)
466#if QT_CONFIG(toolbar)
467 case PE_IndicatorToolBarHandle: {
468 QPainterStateSaver pss(p);
469 p->translate(dx: opt->rect.x(), dy: opt->rect.y());
470 if (opt->state & State_Horizontal) {
471 int x = opt->rect.width() / 3;
472 if (opt->direction == Qt::RightToLeft)
473 x -= 2;
474 if (opt->rect.height() > 4) {
475 qDrawShadePanel(p, x, y: 2, w: 3, h: opt->rect.height() - 4,
476 pal: opt->palette, sunken: false, lineWidth: 1, fill: nullptr);
477 qDrawShadePanel(p, x: x+3, y: 2, w: 3, h: opt->rect.height() - 4,
478 pal: opt->palette, sunken: false, lineWidth: 1, fill: nullptr);
479 }
480 } else {
481 if (opt->rect.width() > 4) {
482 int y = opt->rect.height() / 3;
483 qDrawShadePanel(p, x: 2, y, w: opt->rect.width() - 4, h: 3,
484 pal: opt->palette, sunken: false, lineWidth: 1, fill: nullptr);
485 qDrawShadePanel(p, x: 2, y: y+3, w: opt->rect.width() - 4, h: 3,
486 pal: opt->palette, sunken: false, lineWidth: 1, fill: nullptr);
487 }
488 }
489 break;
490 }
491 case PE_IndicatorToolBarSeparator:
492 {
493 QPoint p1, p2;
494 if (opt->state & State_Horizontal) {
495 p1 = QPoint(opt->rect.width()/2, 0);
496 p2 = QPoint(p1.x(), opt->rect.height());
497 } else {
498 p1 = QPoint(0, opt->rect.height()/2);
499 p2 = QPoint(opt->rect.width(), p1.y());
500 }
501 qDrawShadeLine(p, p1, p2, pal: opt->palette, sunken: 1, lineWidth: 1, midLineWidth: 0);
502 break;
503 }
504#endif // QT_CONFIG(toolbar)
505#if QT_CONFIG(spinbox)
506 case PE_IndicatorSpinPlus:
507 case PE_IndicatorSpinMinus: {
508 QRect r = opt->rect;
509 int fw = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: opt, widget);
510 QRect br = r.adjusted(xp1: fw, yp1: fw, xp2: -fw, yp2: -fw);
511 int x = br.x();
512 int y = br.y();
513 int w = br.width();
514 int h = br.height();
515 QPainterStateSaver pss(p);
516 const qreal devicePixelRatio = p->device()->devicePixelRatio();
517 if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) {
518 const qreal inverseScale = qreal(1) / devicePixelRatio;
519 p->scale(sx: inverseScale, sy: inverseScale);
520 x = qRound(d: devicePixelRatio * x);
521 y = qRound(d: devicePixelRatio * y);
522 w = qRound(d: devicePixelRatio * w);
523 h = qRound(d: devicePixelRatio * h);
524 p->translate(dx: 0.5, dy: 0.5);
525 }
526 int len = std::min(a: w, b: h);
527 if (len & 1)
528 ++len;
529 int step = (len + 4) / 5;
530 if (step & 1)
531 ++step;
532 const int step2 = step / 2;
533 QPoint center(x + w / 2, y + h / 2);
534 if (opt->state & State_Sunken) {
535 center += QPoint(proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget),
536 proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget));
537 }
538 p->translate(offset: center);
539 p->fillRect(x: -len / 2, y: -step2, w: len, h: step, b: opt->palette.buttonText());
540 if (pe == PE_IndicatorSpinPlus)
541 p->fillRect(x: -step2, y: -len / 2, w: step, h: len, b: opt->palette.buttonText());
542 break; }
543 case PE_IndicatorSpinUp:
544 case PE_IndicatorSpinDown: {
545 QRect r = opt->rect;
546 int fw = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: opt, widget);
547 // QRect br = r.adjusted(fw, fw, -fw, -fw);
548 int x = r.x();
549 int y = r.y();
550 int w = r.width();
551 int h = r.height();
552 QPainterStateSaver pss(p);
553 const qreal devicePixelRatio = p->device()->devicePixelRatio();
554 if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) {
555 const qreal inverseScale = qreal(1) / devicePixelRatio;
556 p->scale(sx: inverseScale, sy: inverseScale);
557 x = qRound(d: devicePixelRatio * x);
558 y = qRound(d: devicePixelRatio * y);
559 w = qRound(d: devicePixelRatio * w);
560 h = qRound(d: devicePixelRatio * h);
561 p->translate(dx: 0.5, dy: 0.5);
562 }
563 int sw = w-4;
564 if (sw < 3)
565 break;
566 else if (!(sw & 1))
567 sw--;
568 sw -= (sw / 7) * 2; // Empty border
569 int sh = sw/2 + 2; // Must have empty row at foot of arrow
570
571 int sx = x + w / 2 - sw / 2;
572 int sy = y + h / 2 - sh / 2;
573
574 if (pe == PE_IndicatorSpinUp && fw)
575 --sy;
576
577 int bsx = 0;
578 int bsy = 0;
579 if (opt->state & State_Sunken) {
580 bsx = proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget);
581 bsy = proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget);
582 }
583 p->translate(dx: sx + bsx, dy: sy + bsy);
584 p->setPen(opt->palette.buttonText().color());
585 p->setBrush(opt->palette.buttonText());
586 if (pe == PE_IndicatorSpinDown) {
587 const QPoint points[] = { QPoint(0, 1), QPoint(sw-1, 1), QPoint(sh-2, sh-1) };
588 p->drawPolygon(points, pointCount: sizeof points / sizeof *points);
589 } else {
590 const QPoint points[] = { QPoint(0, sh-1), QPoint(sw-1, sh-1), QPoint(sh-2, 1) };
591 p->drawPolygon(points, pointCount: sizeof points / sizeof *points);
592 }
593 break; }
594#endif // QT_CONFIG(spinbox)
595 case PE_PanelTipLabel: {
596 const QBrush brush(opt->palette.toolTipBase());
597 qDrawPlainRect(p, r: opt->rect, opt->palette.toolTipText().color(), lineWidth: 1, fill: &brush);
598 break;
599 }
600#if QT_CONFIG(tabbar)
601 case PE_IndicatorTabTear:
602 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
603 bool rtl = tab->direction == Qt::RightToLeft;
604 const bool horizontal = tab->rect.height() > tab->rect.width();
605 const int margin = 4;
606 QPainterPath path;
607
608 if (horizontal) {
609 QRect rect = tab->rect.adjusted(xp1: rtl ? margin : 0, yp1: 0, xp2: rtl ? 1 : -margin, yp2: 0);
610 rect.setTop(rect.top() + ((tab->state & State_Selected) ? 1 : 3));
611 rect.setBottom(rect.bottom() - ((tab->state & State_Selected) ? 0 : 2));
612
613 path.moveTo(p: QPoint(rtl ? rect.right() : rect.left(), rect.top()));
614 int count = 4;
615 for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
616 path.lineTo(p: QPoint(rtl ? rect.left() : rect.right(), rect.top() + jags * rect.height()/count));
617 } else {
618 QRect rect = tab->rect.adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: -margin);
619 rect.setLeft(rect.left() + ((tab->state & State_Selected) ? 1 : 3));
620 rect.setRight(rect.right() - ((tab->state & State_Selected) ? 0 : 2));
621
622 path.moveTo(p: QPoint(rect.left(), rect.top()));
623 int count = 4;
624 for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
625 path.lineTo(p: QPoint(rect.left() + jags * rect.width()/count, rtl ? rect.top() : rect.bottom()));
626 }
627
628 p->setPen(QPen(tab->palette.dark(), qreal(.8)));
629 p->setBrush(tab->palette.window());
630 p->setRenderHint(hint: QPainter::Antialiasing);
631 p->drawPath(path);
632 }
633 break;
634#endif // QT_CONFIG(tabbar)
635#if QT_CONFIG(lineedit)
636 case PE_PanelLineEdit:
637 if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
638 p->fillRect(panel->rect.adjusted(xp1: panel->lineWidth, yp1: panel->lineWidth, xp2: -panel->lineWidth, yp2: -panel->lineWidth),
639 panel->palette.brush(cr: QPalette::Base));
640
641 if (panel->lineWidth > 0)
642 proxy()->drawPrimitive(pe: PE_FrameLineEdit, opt: panel, p, w: widget);
643 }
644 break;
645#endif // QT_CONFIG(lineedit)
646#if QT_CONFIG(columnview)
647 case PE_IndicatorColumnViewArrow: {
648 if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
649 bool reverse = (viewOpt->direction == Qt::RightToLeft);
650 QPainterStateSaver pss(p);
651 QPainterPath path;
652 int x = viewOpt->rect.x() + 1;
653 int offset = (viewOpt->rect.height() / 3);
654 int height = (viewOpt->rect.height()) - offset * 2;
655 if (height % 2 == 1)
656 --height;
657 int x2 = x + height - 1;
658 if (reverse) {
659 x = viewOpt->rect.x() + viewOpt->rect.width() - 1;
660 x2 = x - height + 1;
661 }
662 path.moveTo(x, y: viewOpt->rect.y() + offset);
663 path.lineTo(x, y: viewOpt->rect.y() + offset + height);
664 path.lineTo(x: x2, y: viewOpt->rect.y() + offset+height/2);
665 path.closeSubpath();
666 if (viewOpt->state & QStyle::State_Selected ) {
667 if (viewOpt->showDecorationSelected) {
668 QColor color = viewOpt->palette.color(cg: QPalette::Active, cr: QPalette::HighlightedText);
669 p->setPen(color);
670 p->setBrush(color);
671 } else {
672 QColor color = viewOpt->palette.color(cg: QPalette::Active, cr: QPalette::WindowText);
673 p->setPen(color);
674 p->setBrush(color);
675 }
676
677 } else {
678 QColor color = viewOpt->palette.color(cg: QPalette::Active, cr: QPalette::Mid);
679 p->setPen(color);
680 p->setBrush(color);
681 }
682 p->drawPath(path);
683
684 // draw the vertical and top triangle line
685 if (!(viewOpt->state & QStyle::State_Selected)) {
686 QPainterPath lines;
687 lines.moveTo(x, y: viewOpt->rect.y() + offset);
688 lines.lineTo(x, y: viewOpt->rect.y() + offset + height);
689 lines.moveTo(x, y: viewOpt->rect.y() + offset);
690 lines.lineTo(x: x2, y: viewOpt->rect.y() + offset+height/2);
691 QColor color = viewOpt->palette.color(cg: QPalette::Active, cr: QPalette::Dark);
692 p->setPen(color);
693 p->drawPath(path: lines);
694 }
695 }
696 break; }
697#endif //QT_CONFIG(columnview)
698 case PE_IndicatorItemViewItemDrop: {
699 QRect rect = opt->rect;
700 if (opt->rect.height() == 0)
701 p->drawLine(p1: rect.topLeft(), p2: rect.topRight());
702 else
703 p->drawRect(r: rect);
704 break; }
705#if QT_CONFIG(itemviews)
706 case PE_PanelItemViewRow:
707 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
708 QPalette::ColorGroup cg = (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
709 ? QPalette::Normal : QPalette::Disabled;
710 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
711 cg = QPalette::Inactive;
712
713 if ((vopt->state & QStyle::State_Selected) && vopt->showDecorationSelected)
714 p->fillRect(vopt->rect, vopt->palette.brush(cg, cr: QPalette::Highlight));
715 else if (vopt->features & QStyleOptionViewItem::Alternate)
716 p->fillRect(vopt->rect, vopt->palette.brush(cg, cr: QPalette::AlternateBase));
717 }
718 break;
719 case PE_PanelItemViewItem:
720 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
721 QPalette::ColorGroup cg = (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
722 ? QPalette::Normal : QPalette::Disabled;
723 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
724 cg = QPalette::Inactive;
725
726 if (vopt->showDecorationSelected && (vopt->state & QStyle::State_Selected)) {
727 p->fillRect(vopt->rect, vopt->palette.brush(cg, cr: QPalette::Highlight));
728 } else {
729 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
730 QPointF oldBO = p->brushOrigin();
731 p->setBrushOrigin(vopt->rect.topLeft());
732 p->fillRect(vopt->rect, vopt->backgroundBrush);
733 p->setBrushOrigin(oldBO);
734 }
735
736 if (vopt->state & QStyle::State_Selected) {
737 QRect textRect = subElementRect(r: QStyle::SE_ItemViewItemText, opt, widget);
738 p->fillRect(textRect, vopt->palette.brush(cg, cr: QPalette::Highlight));
739 }
740 }
741 }
742 break;
743#endif // QT_CONFIG(itemviews)
744 case PE_PanelScrollAreaCorner: {
745 const QBrush brush(opt->palette.brush(cr: QPalette::Window));
746 p->fillRect(opt->rect, brush);
747 } break;
748 case PE_IndicatorArrowUp:
749 case PE_IndicatorArrowDown:
750 case PE_IndicatorArrowRight:
751 case PE_IndicatorArrowLeft:
752 {
753 const QRect &r = opt->rect;
754 if (r.width() <= 1 || r.height() <= 1)
755 break;
756 int size = qMin(a: r.height(), b: r.width());
757 QPixmap pixmap;
758 const qreal dpr = p->device()->devicePixelRatio();
759 const QString pixmapName = QStyleHelper::uniqueName(key: "$qt_ia-"_L1
760 % QLatin1StringView(metaObject()->className())
761 % HexString<uint>(pe),
762 option: opt, size: QSize(size, size), dpr);
763 if (!QPixmapCache::find(key: pixmapName, pixmap: &pixmap)) {
764 // dpr scaling does not work well on such small pixel sizes, do it on our own
765 const int border = 1 * dpr;
766 const int sizeDpr = size * dpr;
767 int width = sizeDpr - 2 * border - 1;
768 int height = width / 2;
769 const int add = ((width & 1) == 1);
770 if (pe == PE_IndicatorArrowRight || pe == PE_IndicatorArrowLeft)
771 std::swap(a&: width, b&: height);
772 pixmap = styleCachePixmap(size: QSize(sizeDpr, sizeDpr), pixelRatio: 1);
773
774 std::array<QPointF, 4> poly;
775 switch (pe) {
776 case PE_IndicatorArrowUp:
777 poly = {QPointF(0, height), QPointF(width, height),
778 QPointF(width / 2 + add, 0), QPointF(width / 2, 0)};
779 break;
780 case PE_IndicatorArrowDown:
781 poly = {QPointF(0, 0), QPointF(width, 0),
782 QPointF(width / 2 + add, height), QPointF(width / 2, height)};
783 break;
784 case PE_IndicatorArrowRight:
785 poly = {QPointF(0, 0), QPointF(0, height),
786 QPointF(width, height / 2 + add), QPointF(width, height / 2)};
787 break;
788 case PE_IndicatorArrowLeft:
789 poly = {QPointF(width, 0), QPointF(width, height),
790 QPointF(0, height / 2 + add), QPointF(0, height / 2)};
791 break;
792 default:
793 break;
794 }
795
796 QPainter imagePainter(&pixmap);
797 imagePainter.translate(dx: (sizeDpr - width) / 2, dy: (sizeDpr - height) / 2);
798 if (opt->state & State_Sunken) {
799 const auto bsx = proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget);
800 const auto bsy = proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget);
801 imagePainter.translate(dx: bsx, dy: bsy);
802 }
803 imagePainter.setPen(opt->palette.buttonText().color());
804 imagePainter.setBrush(opt->palette.buttonText());
805
806 if (!(opt->state & State_Enabled)) {
807 const int ofs = qRound(d: 1 * dpr);
808 imagePainter.translate(dx: ofs, dy: ofs);
809 imagePainter.setBrush(opt->palette.light().color());
810 imagePainter.setPen(opt->palette.light().color());
811 imagePainter.drawPolygon(points: poly.data(), pointCount: int(poly.size()));
812 imagePainter.drawPoints(points: poly.data(), pointCount: int(poly.size()));
813 imagePainter.translate(dx: -ofs, dy: -ofs);
814 imagePainter.setBrush(opt->palette.mid().color());
815 imagePainter.setPen(opt->palette.mid().color());
816 }
817 imagePainter.drawPolygon(points: poly.data(), pointCount: int(poly.size()));
818 // sometimes the corners are not drawn by drawPolygon for unknown reaons, so re-draw them again
819 imagePainter.drawPoints(points: poly.data(), pointCount: int(poly.size()));
820 imagePainter.end();
821 pixmap.setDevicePixelRatio(dpr);
822 QPixmapCache::insert(key: pixmapName, pixmap);
823 }
824 int xOffset = r.x() + (r.width() - size)/2;
825 int yOffset = r.y() + (r.height() - size)/2;
826 p->drawPixmap(x: xOffset, y: yOffset, pm: pixmap);
827 }
828 break;
829 default:
830 break;
831 }
832}
833
834#if QT_CONFIG(toolbutton)
835static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
836 const QRect &rect, QPainter *painter, const QWidget *widget = nullptr)
837{
838 QStyle::PrimitiveElement pe;
839 switch (toolbutton->arrowType) {
840 case Qt::LeftArrow:
841 pe = QStyle::PE_IndicatorArrowLeft;
842 break;
843 case Qt::RightArrow:
844 pe = QStyle::PE_IndicatorArrowRight;
845 break;
846 case Qt::UpArrow:
847 pe = QStyle::PE_IndicatorArrowUp;
848 break;
849 case Qt::DownArrow:
850 pe = QStyle::PE_IndicatorArrowDown;
851 break;
852 default:
853 return;
854 }
855 QStyleOption arrowOpt = *toolbutton;
856 arrowOpt.rect = rect;
857 style->drawPrimitive(pe, opt: &arrowOpt, p: painter, w: widget);
858}
859#endif // QT_CONFIG(toolbutton)
860
861static QSizeF viewItemTextLayout(QTextLayout &textLayout, int lineWidth, int maxHeight = -1, int *lastVisibleLine = nullptr)
862{
863 if (lastVisibleLine)
864 *lastVisibleLine = -1;
865 qreal height = 0;
866 qreal widthUsed = 0;
867 textLayout.beginLayout();
868 int i = 0;
869 while (true) {
870 QTextLine line = textLayout.createLine();
871 if (!line.isValid())
872 break;
873 line.setLineWidth(lineWidth);
874 line.setPosition(QPointF(0, height));
875 height += line.height();
876 widthUsed = qMax(a: widthUsed, b: line.naturalTextWidth());
877 // we assume that the height of the next line is the same as the current one
878 if (maxHeight > 0 && lastVisibleLine && height + line.height() > maxHeight) {
879 const QTextLine nextLine = textLayout.createLine();
880 *lastVisibleLine = nextLine.isValid() ? i : -1;
881 break;
882 }
883 ++i;
884 }
885 textLayout.endLayout();
886 return QSizeF(widthUsed, height);
887}
888
889QString QCommonStylePrivate::calculateElidedText(const QString &text, const QTextOption &textOption,
890 const QFont &font, const QRect &textRect, const Qt::Alignment valign,
891 Qt::TextElideMode textElideMode, int flags,
892 bool lastVisibleLineShouldBeElided, QPointF *paintStartPosition) const
893{
894 QTextLayout textLayout(text, font);
895 textLayout.setTextOption(textOption);
896
897 // In AlignVCenter mode when more than one line is displayed and the height only allows
898 // some of the lines it makes no sense to display those. From a users perspective it makes
899 // more sense to see the start of the text instead something inbetween.
900 const bool vAlignmentOptimization = paintStartPosition && valign.testFlag(flag: Qt::AlignVCenter);
901
902 int lastVisibleLine = -1;
903 viewItemTextLayout(textLayout, lineWidth: textRect.width(), maxHeight: vAlignmentOptimization ? textRect.height() : -1, lastVisibleLine: &lastVisibleLine);
904
905 const QRectF boundingRect = textLayout.boundingRect();
906 // don't care about LTR/RTL here, only need the height
907 const QRect layoutRect = QStyle::alignedRect(direction: Qt::LayoutDirectionAuto, alignment: valign,
908 size: boundingRect.size().toSize(), rectangle: textRect);
909
910 if (paintStartPosition)
911 *paintStartPosition = QPointF(textRect.x(), layoutRect.top());
912
913 QString ret;
914 qreal height = 0;
915 const int lineCount = textLayout.lineCount();
916 for (int i = 0; i < lineCount; ++i) {
917 const QTextLine line = textLayout.lineAt(i);
918 height += line.height();
919
920 // above visible rect
921 if (height + layoutRect.top() <= textRect.top()) {
922 if (paintStartPosition)
923 paintStartPosition->ry() += line.height();
924 continue;
925 }
926
927 const int start = line.textStart();
928 const int length = line.textLength();
929 const bool drawElided = line.naturalTextWidth() > textRect.width();
930 bool elideLastVisibleLine = lastVisibleLine == i;
931 if (!drawElided && i + 1 < lineCount && lastVisibleLineShouldBeElided) {
932 const QTextLine nextLine = textLayout.lineAt(i: i + 1);
933 const int nextHeight = height + nextLine.height() / 2;
934 // elide when less than the next half line is visible
935 if (nextHeight + layoutRect.top() > textRect.height() + textRect.top())
936 elideLastVisibleLine = true;
937 }
938
939 QString text = textLayout.text().mid(position: start, n: length);
940 if (drawElided || elideLastVisibleLine) {
941 if (elideLastVisibleLine) {
942 if (text.endsWith(c: QChar::LineSeparator))
943 text.chop(n: 1);
944 text += QChar(0x2026);
945 }
946 const QStackTextEngine engine(text, font);
947 ret += engine.elidedText(mode: textElideMode, width: textRect.width(), flags);
948
949 // no newline for the last line (last visible or real)
950 // sometimes drawElided is true but no eliding is done so the text ends
951 // with QChar::LineSeparator - don't add another one. This happened with
952 // arabic text in the testcase for QTBUG-72805
953 if (i < lineCount - 1 &&
954 !ret.endsWith(c: QChar::LineSeparator))
955 ret += QChar::LineSeparator;
956 } else {
957 ret += text;
958 }
959
960 // below visible text, can stop
961 if ((height + layoutRect.top() >= textRect.bottom()) ||
962 (lastVisibleLine >= 0 && lastVisibleLine == i))
963 break;
964 }
965 return ret;
966}
967
968#if QT_CONFIG(itemviews)
969
970QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int role) const
971{
972 const QWidget *widget = option->widget;
973 switch (role) {
974 case Qt::CheckStateRole:
975 if (option->features & QStyleOptionViewItem::HasCheckIndicator)
976 return QSize(proxyStyle->pixelMetric(metric: QStyle::PM_IndicatorWidth, option, widget),
977 proxyStyle->pixelMetric(metric: QStyle::PM_IndicatorHeight, option, widget));
978 break;
979 case Qt::DisplayRole:
980 if (option->features & QStyleOptionViewItem::HasDisplay) {
981 QTextOption textOption;
982 textOption.setWrapMode(QTextOption::WordWrap);
983 QTextLayout textLayout(option->text, option->font);
984 textLayout.setTextOption(textOption);
985 const bool wrapText = option->features & QStyleOptionViewItem::WrapText;
986 const int textMargin = proxyStyle->pixelMetric(metric: QStyle::PM_FocusFrameHMargin, option, widget) + 1;
987 QRect bounds = option->rect;
988 switch (option->decorationPosition) {
989 case QStyleOptionViewItem::Left:
990 case QStyleOptionViewItem::Right: {
991 if (wrapText && bounds.isValid()) {
992 int width = bounds.width() - 2 * textMargin;
993 if (option->features & QStyleOptionViewItem::HasDecoration)
994 width -= option->decorationSize.width() + 2 * textMargin;
995 bounds.setWidth(width);
996 } else
997 bounds.setWidth(QFIXED_MAX);
998 break;
999 }
1000 case QStyleOptionViewItem::Top:
1001 case QStyleOptionViewItem::Bottom: {
1002 int width;
1003 if (wrapText) {
1004 if (bounds.isValid())
1005 width = bounds.width() - 2 * textMargin;
1006 else if (option->features & QStyleOptionViewItem::HasDecoration)
1007 width = option->decorationSize.width();
1008 else
1009 width = 0;
1010 } else {
1011 width = QFIXED_MAX;
1012 }
1013 bounds.setWidth(width);
1014 break;
1015 }
1016 default:
1017 break;
1018 }
1019
1020 if (wrapText && option->features & QStyleOptionViewItem::HasCheckIndicator)
1021 bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(metric: QStyle::PM_IndicatorWidth, option, widget) - 2 * textMargin);
1022
1023 const int lineWidth = bounds.width();
1024 const QSizeF size = viewItemTextLayout(textLayout, lineWidth);
1025 return QSize(qCeil(v: size.width()) + 2 * textMargin, qCeil(v: size.height()));
1026 }
1027 break;
1028 case Qt::DecorationRole:
1029 if (option->features & QStyleOptionViewItem::HasDecoration) {
1030 return option->decorationSize;
1031 }
1032 break;
1033 default:
1034 break;
1035 }
1036
1037 return QSize(0, 0);
1038}
1039
1040void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewItem *option, const QRect &rect) const
1041{
1042 const QWidget *widget = option->widget;
1043 const int textMargin = proxyStyle->pixelMetric(metric: QStyle::PM_FocusFrameHMargin, option: nullptr, widget) + 1;
1044
1045 QRect textRect = rect.adjusted(xp1: textMargin, yp1: 0, xp2: -textMargin, yp2: 0); // remove width padding
1046 const bool wrapText = option->features & QStyleOptionViewItem::WrapText;
1047 QTextOption textOption;
1048 textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap);
1049 textOption.setTextDirection(option->direction);
1050 textOption.setAlignment(QStyle::visualAlignment(direction: option->direction, alignment: option->displayAlignment));
1051
1052 QPointF paintPosition;
1053 const QString newText = calculateElidedText(text: option->text, textOption,
1054 font: option->font, textRect, valign: option->displayAlignment,
1055 textElideMode: option->textElideMode, flags: 0,
1056 lastVisibleLineShouldBeElided: true, paintStartPosition: &paintPosition);
1057
1058 QTextLayout textLayout(newText, option->font);
1059 textLayout.setTextOption(textOption);
1060 viewItemTextLayout(textLayout, lineWidth: textRect.width());
1061 textLayout.draw(p, pos: paintPosition);
1062}
1063
1064/*! \internal
1065 compute the position for the different component of an item (pixmap, text, checkbox)
1066
1067 Set sizehint to false to layout the elements inside opt->rect. Set sizehint to true to ignore
1068 opt->rect and return rectangles in infinite space
1069
1070 Code duplicated in QItemDelegate::doLayout
1071*/
1072void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItem *opt, QRect *checkRect,
1073 QRect *pixmapRect, QRect *textRect, bool sizehint) const
1074{
1075 Q_ASSERT(checkRect && pixmapRect && textRect);
1076 *pixmapRect = QRect(QPoint(0, 0), viewItemSize(option: opt, role: Qt::DecorationRole));
1077 *textRect = QRect(QPoint(0, 0), viewItemSize(option: opt, role: Qt::DisplayRole));
1078 *checkRect = QRect(QPoint(0, 0), viewItemSize(option: opt, role: Qt::CheckStateRole));
1079
1080 const QWidget *widget = opt->widget;
1081 const bool hasCheck = checkRect->isValid();
1082 const bool hasPixmap = pixmapRect->isValid();
1083 const bool hasText = textRect->isValid();
1084 const bool hasMargin = (hasText | hasPixmap | hasCheck);
1085 const int frameHMargin = hasMargin ?
1086 proxyStyle->pixelMetric(metric: QStyle::PM_FocusFrameHMargin, option: opt, widget) + 1 : 0;
1087 const int textMargin = hasText ? frameHMargin : 0;
1088 const int pixmapMargin = hasPixmap ? frameHMargin : 0;
1089 const int checkMargin = hasCheck ? frameHMargin : 0;
1090 const int x = opt->rect.left();
1091 const int y = opt->rect.top();
1092 int w, h;
1093
1094 if (textRect->height() == 0 && (!hasPixmap || !sizehint)) {
1095 //if there is no text, we still want to have a decent height for the item sizeHint and the editor size
1096 textRect->setHeight(opt->fontMetrics.height());
1097 }
1098
1099 QSize pm(0, 0);
1100 if (hasPixmap) {
1101 pm = pixmapRect->size();
1102 pm.rwidth() += 2 * pixmapMargin;
1103 }
1104 if (sizehint) {
1105 h = qMax(a: checkRect->height(), b: qMax(a: textRect->height(), b: pm.height()));
1106 if (opt->decorationPosition == QStyleOptionViewItem::Left
1107 || opt->decorationPosition == QStyleOptionViewItem::Right) {
1108 w = textRect->width() + pm.width();
1109 } else {
1110 w = qMax(a: textRect->width(), b: pm.width());
1111 }
1112 } else {
1113 w = opt->rect.width();
1114 h = opt->rect.height();
1115 }
1116
1117 int cw = 0;
1118 QRect check;
1119 if (hasCheck) {
1120 cw = checkRect->width() + 2 * checkMargin;
1121 if (sizehint) w += cw;
1122 if (opt->direction == Qt::RightToLeft) {
1123 check.setRect(ax: x + w - cw, ay: y, aw: cw, ah: h);
1124 } else {
1125 check.setRect(ax: x, ay: y, aw: cw, ah: h);
1126 }
1127 }
1128
1129 QRect display;
1130 QRect decoration;
1131 switch (opt->decorationPosition) {
1132 case QStyleOptionViewItem::Top: {
1133 if (hasPixmap)
1134 pm.setHeight(pm.height() + pixmapMargin); // add space
1135 h = sizehint ? textRect->height() : h - pm.height();
1136
1137 if (opt->direction == Qt::RightToLeft) {
1138 decoration.setRect(ax: x, ay: y, aw: w - cw, ah: pm.height());
1139 display.setRect(ax: x, ay: y + pm.height(), aw: w - cw, ah: h);
1140 } else {
1141 decoration.setRect(ax: x + cw, ay: y, aw: w - cw, ah: pm.height());
1142 display.setRect(ax: x + cw, ay: y + pm.height(), aw: w - cw, ah: h);
1143 }
1144 break; }
1145 case QStyleOptionViewItem::Bottom: {
1146 if (hasText)
1147 textRect->setHeight(textRect->height() + textMargin); // add space
1148 h = sizehint ? textRect->height() + pm.height() : h;
1149
1150 if (opt->direction == Qt::RightToLeft) {
1151 display.setRect(ax: x, ay: y, aw: w - cw, ah: textRect->height());
1152 decoration.setRect(ax: x, ay: y + textRect->height(), aw: w - cw, ah: h - textRect->height());
1153 } else {
1154 display.setRect(ax: x + cw, ay: y, aw: w - cw, ah: textRect->height());
1155 decoration.setRect(ax: x + cw, ay: y + textRect->height(), aw: w - cw, ah: h - textRect->height());
1156 }
1157 break; }
1158 case QStyleOptionViewItem::Left: {
1159 if (opt->direction == Qt::LeftToRight) {
1160 decoration.setRect(ax: x + cw, ay: y, aw: pm.width(), ah: h);
1161 display.setRect(ax: decoration.right() + 1, ay: y, aw: w - pm.width() - cw, ah: h);
1162 } else {
1163 display.setRect(ax: x, ay: y, aw: w - pm.width() - cw, ah: h);
1164 decoration.setRect(ax: display.right() + 1, ay: y, aw: pm.width(), ah: h);
1165 }
1166 break; }
1167 case QStyleOptionViewItem::Right: {
1168 if (opt->direction == Qt::LeftToRight) {
1169 display.setRect(ax: x + cw, ay: y, aw: w - pm.width() - cw, ah: h);
1170 decoration.setRect(ax: display.right() + 1, ay: y, aw: pm.width(), ah: h);
1171 } else {
1172 decoration.setRect(ax: x, ay: y, aw: pm.width(), ah: h);
1173 display.setRect(ax: decoration.right() + 1, ay: y, aw: w - pm.width() - cw, ah: h);
1174 }
1175 break; }
1176 default:
1177 qCWarning(lcCommonStyle, "doLayout: decoration position is invalid");
1178 decoration = *pixmapRect;
1179 break;
1180 }
1181
1182 if (!sizehint) { // we only need to do the internal layout if we are going to paint
1183 *checkRect = QStyle::alignedRect(direction: opt->direction, alignment: Qt::AlignCenter,
1184 size: checkRect->size(), rectangle: check);
1185 *pixmapRect = QStyle::alignedRect(direction: opt->direction, alignment: opt->decorationAlignment,
1186 size: pixmapRect->size(), rectangle: decoration);
1187 // the textRect takes up all remaining size
1188 *textRect = display;
1189 } else {
1190 *checkRect = check;
1191 *pixmapRect = decoration;
1192 *textRect = display;
1193 }
1194}
1195#endif // QT_CONFIG(itemviews)
1196
1197#if QT_CONFIG(toolbutton)
1198QString QCommonStylePrivate::toolButtonElideText(const QStyleOptionToolButton *option,
1199 const QRect &textRect, int flags) const
1200{
1201 if (option->fontMetrics.horizontalAdvance(option->text) <= textRect.width())
1202 return option->text;
1203
1204 QString text = option->text;
1205 text.replace(before: u'\n', after: QChar::LineSeparator);
1206 QTextOption textOption;
1207 textOption.setWrapMode(QTextOption::ManualWrap);
1208 textOption.setTextDirection(option->direction);
1209
1210 return calculateElidedText(text, textOption,
1211 font: option->font, textRect, valign: Qt::AlignTop,
1212 textElideMode: Qt::ElideMiddle, flags,
1213 lastVisibleLineShouldBeElided: false, paintStartPosition: nullptr);
1214}
1215#endif // QT_CONFIG(toolbutton)
1216
1217#if QT_CONFIG(tabbar)
1218/*! \internal
1219 Compute the textRect and the pixmapRect from the opt rect
1220
1221 Uses the same computation than in QTabBar::tabSizeHint
1222 */
1223void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const
1224{
1225 Q_ASSERT(textRect);
1226 Q_ASSERT(iconRect);
1227 QRect tr = opt->rect;
1228 bool verticalTabs = opt->shape == QTabBar::RoundedEast
1229 || opt->shape == QTabBar::RoundedWest
1230 || opt->shape == QTabBar::TriangularEast
1231 || opt->shape == QTabBar::TriangularWest;
1232 if (verticalTabs)
1233 tr.setRect(ax: 0, ay: 0, aw: tr.height(), ah: tr.width()); // 0, 0 as we will have a translate transform
1234
1235 int verticalShift = proxyStyle->pixelMetric(metric: QStyle::PM_TabBarTabShiftVertical, option: opt, widget);
1236 int horizontalShift = proxyStyle->pixelMetric(metric: QStyle::PM_TabBarTabShiftHorizontal, option: opt, widget);
1237 int hpadding = proxyStyle->pixelMetric(metric: QStyle::PM_TabBarTabHSpace, option: opt, widget) / 2;
1238 int vpadding = proxyStyle->pixelMetric(metric: QStyle::PM_TabBarTabVSpace, option: opt, widget) / 2;
1239 if (opt->shape == QTabBar::RoundedSouth || opt->shape == QTabBar::TriangularSouth)
1240 verticalShift = -verticalShift;
1241 tr.adjust(dx1: hpadding, dy1: verticalShift - vpadding, dx2: horizontalShift - hpadding, dy2: vpadding);
1242 bool selected = opt->state & QStyle::State_Selected;
1243 if (selected) {
1244 tr.setTop(tr.top() - verticalShift);
1245 tr.setRight(tr.right() - horizontalShift);
1246 }
1247
1248 // left widget
1249 if (!opt->leftButtonSize.isEmpty()) {
1250 tr.setLeft(tr.left() + 4 +
1251 (verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width()));
1252 }
1253 // right widget
1254 if (!opt->rightButtonSize.isEmpty()) {
1255 tr.setRight(tr.right() - 4 -
1256 (verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width()));
1257 }
1258
1259 // icon
1260 if (!opt->icon.isNull()) {
1261 QSize iconSize = opt->iconSize;
1262 if (!iconSize.isValid()) {
1263 int iconExtent = proxyStyle->pixelMetric(metric: QStyle::PM_SmallIconSize, option: opt, widget);
1264 iconSize = QSize(iconExtent, iconExtent);
1265 }
1266 QSize tabIconSize = opt->icon.actualSize(size: iconSize,
1267 mode: (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
1268 state: (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
1269 // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
1270 tabIconSize = QSize(qMin(a: tabIconSize.width(), b: iconSize.width()), qMin(a: tabIconSize.height(), b: iconSize.height()));
1271
1272 const int offsetX = (iconSize.width() - tabIconSize.width()) / 2;
1273 *iconRect = QRect(tr.left() + offsetX, tr.center().y() - tabIconSize.height() / 2,
1274 tabIconSize.width(), tabIconSize.height());
1275 if (!verticalTabs)
1276 *iconRect = QStyle::visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: *iconRect);
1277 tr.setLeft(tr.left() + tabIconSize.width() + 4);
1278 }
1279
1280 if (!verticalTabs)
1281 tr = QStyle::visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: tr);
1282
1283 *textRect = tr;
1284}
1285#endif // QT_CONFIG(tabbar)
1286
1287#if QT_CONFIG(animation)
1288/*! \internal */
1289QStyleAnimation * QCommonStylePrivate::animation(const QObject *target) const
1290{
1291 return animations.value(key: target);
1292}
1293
1294/*! \internal */
1295void QCommonStylePrivate::startAnimation(QStyleAnimation *animation) const
1296{
1297 Q_Q(const QCommonStyle);
1298 const auto target = animation->target();
1299 stopAnimation(target);
1300 QObject::connect(sender: animation, signal: &QStyleAnimation::destroyed,
1301 context: q, slot: [this, target]() { removeAnimation(target); });
1302 animations.insert(key: target, value: animation);
1303 animation->start();
1304}
1305
1306/*! \internal */
1307void QCommonStylePrivate::stopAnimation(const QObject *target) const
1308{
1309 QStyleAnimation *animation = animations.take(key: target);
1310 if (animation) {
1311 animation->stop();
1312 delete animation;
1313 }
1314}
1315
1316/*! \internal */
1317void QCommonStylePrivate::removeAnimation(const QObject *target) const
1318{
1319 animations.remove(key: target);
1320}
1321#endif
1322
1323/*!
1324 \reimp
1325*/
1326void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
1327 QPainter *p, const QWidget *widget) const
1328{
1329 Q_D(const QCommonStyle);
1330 switch (element) {
1331
1332 case CE_PushButton:
1333 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1334 proxy()->drawControl(element: CE_PushButtonBevel, opt: btn, p, w: widget);
1335 QStyleOptionButton subopt = *btn;
1336 subopt.rect = subElementRect(r: SE_PushButtonContents, opt: btn, widget);
1337 proxy()->drawControl(element: CE_PushButtonLabel, opt: &subopt, p, w: widget);
1338 if (btn->state & State_HasFocus) {
1339 QStyleOptionFocusRect fropt;
1340 fropt.QStyleOption::operator=(other: *btn);
1341 fropt.rect = subElementRect(r: SE_PushButtonFocusRect, opt: btn, widget);
1342 proxy()->drawPrimitive(pe: PE_FrameFocusRect, opt: &fropt, p, w: widget);
1343 }
1344 }
1345 break;
1346 case CE_PushButtonBevel:
1347 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1348 QRect br = btn->rect;
1349 int dbi = proxy()->pixelMetric(metric: PM_ButtonDefaultIndicator, option: btn, widget);
1350 if (btn->features & QStyleOptionButton::DefaultButton)
1351 proxy()->drawPrimitive(pe: PE_FrameDefaultButton, opt, p, w: widget);
1352 if (btn->features & QStyleOptionButton::AutoDefaultButton)
1353 br.setCoords(xp1: br.left() + dbi, yp1: br.top() + dbi, xp2: br.right() - dbi, yp2: br.bottom() - dbi);
1354 if (!(btn->features & (QStyleOptionButton::Flat | QStyleOptionButton::CommandLinkButton))
1355 || btn->state & (State_Sunken | State_On)
1356 || (btn->features & QStyleOptionButton::CommandLinkButton && btn->state & State_MouseOver)) {
1357 QStyleOptionButton tmpBtn = *btn;
1358 tmpBtn.rect = br;
1359 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: &tmpBtn, p, w: widget);
1360 }
1361 if (btn->features & QStyleOptionButton::HasMenu) {
1362 int mbi = proxy()->pixelMetric(metric: PM_MenuButtonIndicator, option: btn, widget);
1363 QRect ir = btn->rect;
1364 QStyleOptionButton newBtn = *btn;
1365 newBtn.rect = QRect(ir.right() - mbi - 2, ir.height()/2 - mbi/2 + 3, mbi - 6, mbi - 6);
1366 newBtn.rect = visualRect(direction: btn->direction, boundingRect: br, logicalRect: newBtn.rect);
1367 proxy()->drawPrimitive(pe: PE_IndicatorArrowDown, opt: &newBtn, p, w: widget);
1368 }
1369 }
1370 break;
1371 case CE_PushButtonLabel:
1372 if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1373 QRect textRect = button->rect;
1374 int tf = Qt::AlignVCenter | Qt::TextShowMnemonic;
1375 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt: button, widget))
1376 tf |= Qt::TextHideMnemonic;
1377
1378 if (button->features & QStyleOptionButton::HasMenu) {
1379 int indicatorSize = proxy()->pixelMetric(metric: PM_MenuButtonIndicator, option: button, widget);
1380 if (button->direction == Qt::LeftToRight)
1381 textRect = textRect.adjusted(xp1: 0, yp1: 0, xp2: -indicatorSize, yp2: 0);
1382 else
1383 textRect = textRect.adjusted(xp1: indicatorSize, yp1: 0, xp2: 0, yp2: 0);
1384 }
1385
1386 if (!button->icon.isNull()) {
1387 //Center both icon and text
1388 QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
1389 if (mode == QIcon::Normal && button->state & State_HasFocus)
1390 mode = QIcon::Active;
1391 QIcon::State state = QIcon::Off;
1392 if (button->state & State_On)
1393 state = QIcon::On;
1394
1395 QPixmap pixmap = button->icon.pixmap(size: button->iconSize, devicePixelRatio: p->device()->devicePixelRatio(), mode, state);
1396 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
1397 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
1398 int labelWidth = pixmapWidth;
1399 int labelHeight = pixmapHeight;
1400 int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
1401 if (!button->text.isEmpty()) {
1402 int textWidth = button->fontMetrics.boundingRect(r: opt->rect, flags: tf, text: button->text).width();
1403 labelWidth += (textWidth + iconSpacing);
1404 }
1405
1406 QRect iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
1407 textRect.y() + (textRect.height() - labelHeight) / 2,
1408 pixmapWidth, pixmapHeight);
1409
1410 iconRect = visualRect(direction: button->direction, boundingRect: textRect, logicalRect: iconRect);
1411
1412 if (button->direction == Qt::RightToLeft)
1413 textRect.setRight(iconRect.left() - iconSpacing / 2);
1414 else
1415 textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing / 2);
1416
1417 // qt_format_text reverses again when painter->layoutDirection is also RightToLeft
1418 if (p->layoutDirection() == button->direction)
1419 tf |= Qt::AlignLeft;
1420 else
1421 tf |= Qt::AlignRight;
1422
1423 if (button->state & (State_On | State_Sunken))
1424 iconRect.translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget),
1425 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget));
1426 p->drawPixmap(r: iconRect, pm: pixmap);
1427 } else {
1428 tf |= Qt::AlignHCenter;
1429 }
1430 if (button->state & (State_On | State_Sunken))
1431 textRect.translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget),
1432 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget));
1433
1434 proxy()->drawItemText(painter: p, rect: textRect, flags: tf, pal: button->palette, enabled: (button->state & State_Enabled),
1435 text: button->text, textRole: QPalette::ButtonText);
1436 }
1437 break;
1438 case CE_RadioButton:
1439 case CE_CheckBox:
1440 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1441 bool isRadio = (element == CE_RadioButton);
1442 QStyleOptionButton subopt = *btn;
1443 subopt.rect = subElementRect(r: isRadio ? SE_RadioButtonIndicator
1444 : SE_CheckBoxIndicator, opt: btn, widget);
1445 proxy()->drawPrimitive(pe: isRadio ? PE_IndicatorRadioButton : PE_IndicatorCheckBox,
1446 opt: &subopt, p, w: widget);
1447 subopt.rect = subElementRect(r: isRadio ? SE_RadioButtonContents
1448 : SE_CheckBoxContents, opt: btn, widget);
1449 proxy()->drawControl(element: isRadio ? CE_RadioButtonLabel : CE_CheckBoxLabel, opt: &subopt, p, w: widget);
1450 if (btn->state & State_HasFocus) {
1451 QStyleOptionFocusRect fropt;
1452 fropt.QStyleOption::operator=(other: *btn);
1453 fropt.rect = subElementRect(r: isRadio ? SE_RadioButtonFocusRect
1454 : SE_CheckBoxFocusRect, opt: btn, widget);
1455 proxy()->drawPrimitive(pe: PE_FrameFocusRect, opt: &fropt, p, w: widget);
1456 }
1457 }
1458 break;
1459 case CE_RadioButtonLabel:
1460 case CE_CheckBoxLabel:
1461 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1462 int alignment = visualAlignment(direction: btn->direction, alignment: Qt::AlignLeft | Qt::AlignVCenter);
1463
1464 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt: btn, widget))
1465 alignment |= Qt::TextHideMnemonic;
1466 QPixmap pix;
1467 QRect textRect = btn->rect;
1468 if (!btn->icon.isNull()) {
1469 pix = btn->icon.pixmap(size: btn->iconSize, devicePixelRatio: p->device()->devicePixelRatio(), mode: btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled);
1470 proxy()->drawItemPixmap(painter: p, rect: btn->rect, alignment, pixmap: pix);
1471 if (btn->direction == Qt::RightToLeft)
1472 textRect.setRight(textRect.right() - btn->iconSize.width() - 4);
1473 else
1474 textRect.setLeft(textRect.left() + btn->iconSize.width() + 4);
1475 }
1476 if (!btn->text.isEmpty()){
1477 proxy()->drawItemText(painter: p, rect: textRect, flags: alignment | Qt::TextShowMnemonic,
1478 pal: btn->palette, enabled: btn->state & State_Enabled, text: btn->text, textRole: QPalette::WindowText);
1479 }
1480 }
1481 break;
1482#if QT_CONFIG(menu)
1483 case CE_MenuScroller: {
1484 QStyleOption arrowOpt = *opt;
1485 arrowOpt.state |= State_Enabled;
1486 proxy()->drawPrimitive(pe: ((opt->state & State_DownArrow) ? PE_IndicatorArrowDown : PE_IndicatorArrowUp),
1487 opt: &arrowOpt, p, w: widget);
1488 break; }
1489 case CE_MenuTearoff:
1490 if (opt->state & State_Selected)
1491 p->fillRect(opt->rect, opt->palette.brush(cr: QPalette::Highlight));
1492 else
1493 p->fillRect(opt->rect, opt->palette.brush(cr: QPalette::Button));
1494 p->setPen(QPen(opt->palette.dark().color(), 1, Qt::DashLine));
1495 p->drawLine(x1: opt->rect.x() + 2, y1: opt->rect.y() + opt->rect.height() / 2 - 1,
1496 x2: opt->rect.x() + opt->rect.width() - 4,
1497 y2: opt->rect.y() + opt->rect.height() / 2 - 1);
1498 p->setPen(QPen(opt->palette.light().color(), 1, Qt::DashLine));
1499 p->drawLine(x1: opt->rect.x() + 2, y1: opt->rect.y() + opt->rect.height() / 2,
1500 x2: opt->rect.x() + opt->rect.width() - 4, y2: opt->rect.y() + opt->rect.height() / 2);
1501 break;
1502#endif // QT_CONFIG(menu)
1503#if QT_CONFIG(menubar)
1504 case CE_MenuBarItem:
1505 if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
1506 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip
1507 | Qt::TextSingleLine;
1508 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt: mbi, widget))
1509 alignment |= Qt::TextHideMnemonic;
1510 int iconExtent = proxy()->pixelMetric(metric: PM_SmallIconSize, option: opt, widget);
1511 QPixmap pix = mbi->icon.pixmap(size: QSize(iconExtent, iconExtent), devicePixelRatio: p->device()->devicePixelRatio(), mode: (mbi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled);
1512 if (!pix.isNull())
1513 proxy()->drawItemPixmap(painter: p,rect: mbi->rect, alignment, pixmap: pix);
1514 else
1515 proxy()->drawItemText(painter: p, rect: mbi->rect, flags: alignment, pal: mbi->palette, enabled: mbi->state & State_Enabled,
1516 text: mbi->text, textRole: QPalette::ButtonText);
1517 }
1518 break;
1519 case CE_MenuBarEmptyArea:
1520 if (widget && !widget->testAttribute(attribute: Qt::WA_NoSystemBackground))
1521 p->eraseRect(rect: opt->rect);
1522 break;
1523#endif // QT_CONFIG(menubar)
1524#if QT_CONFIG(progressbar)
1525 case CE_ProgressBar:
1526 if (const QStyleOptionProgressBar *pb
1527 = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1528 QStyleOptionProgressBar subopt = *pb;
1529 subopt.rect = subElementRect(r: SE_ProgressBarGroove, opt: pb, widget);
1530 proxy()->drawControl(element: CE_ProgressBarGroove, opt: &subopt, p, w: widget);
1531 subopt.rect = subElementRect(r: SE_ProgressBarContents, opt: pb, widget);
1532 proxy()->drawControl(element: CE_ProgressBarContents, opt: &subopt, p, w: widget);
1533 if (pb->textVisible) {
1534 subopt.rect = subElementRect(r: SE_ProgressBarLabel, opt: pb, widget);
1535 proxy()->drawControl(element: CE_ProgressBarLabel, opt: &subopt, p, w: widget);
1536 }
1537 }
1538 break;
1539 case CE_ProgressBarGroove:
1540 if (opt->rect.isValid())
1541 qDrawShadePanel(p, r: opt->rect, pal: opt->palette, sunken: true, lineWidth: 1,
1542 fill: &opt->palette.brush(cr: QPalette::Window));
1543 break;
1544 case CE_ProgressBarLabel:
1545 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1546 const bool vertical = !(pb->state & QStyle::State_Horizontal);
1547 if (!vertical) {
1548 QPalette::ColorRole textRole = QPalette::NoRole;
1549 if ((pb->textAlignment & Qt::AlignCenter) && pb->textVisible
1550 && ((qint64(pb->progress) - qint64(pb->minimum)) * 2 >= (qint64(pb->maximum) - qint64(pb->minimum)))) {
1551 textRole = QPalette::HighlightedText;
1552 //Draw text shadow, This will increase readability when the background of same color
1553 QRect shadowRect(pb->rect);
1554 shadowRect.translate(dx: 1,dy: 1);
1555 QColor shadowColor = (pb->palette.color(cr: textRole).value() <= 128)
1556 ? QColor(255,255,255,160) : QColor(0,0,0,160);
1557 QPalette shadowPalette = pb->palette;
1558 shadowPalette.setColor(acr: textRole, acolor: shadowColor);
1559 proxy()->drawItemText(painter: p, rect: shadowRect, flags: Qt::AlignCenter | Qt::TextSingleLine, pal: shadowPalette,
1560 enabled: pb->state & State_Enabled, text: pb->text, textRole);
1561 }
1562 proxy()->drawItemText(painter: p, rect: pb->rect, flags: Qt::AlignCenter | Qt::TextSingleLine, pal: pb->palette,
1563 enabled: pb->state & State_Enabled, text: pb->text, textRole);
1564 }
1565 }
1566 break;
1567 case CE_ProgressBarContents:
1568 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1569
1570 QRect rect = pb->rect;
1571 const bool vertical = !(pb->state & QStyle::State_Horizontal);
1572 const bool inverted = pb->invertedAppearance;
1573 qint64 minimum = qint64(pb->minimum);
1574 qint64 maximum = qint64(pb->maximum);
1575 qint64 progress = qint64(pb->progress);
1576
1577 QTransform m;
1578
1579 if (vertical) {
1580 rect = QRect(rect.y(), rect.x(), rect.height(), rect.width()); // flip width and height
1581 m.rotate(a: 90);
1582 m.translate(dx: 0, dy: -(rect.height() + rect.y()*2));
1583 }
1584
1585 QPalette pal2 = pb->palette;
1586 // Correct the highlight color if it is the same as the background
1587 if (pal2.highlight() == pal2.window())
1588 pal2.setColor(acr: QPalette::Highlight, acolor: pb->palette.color(cg: QPalette::Active,
1589 cr: QPalette::Highlight));
1590 bool reverse = ((!vertical && (pb->direction == Qt::RightToLeft)) || vertical);
1591 if (inverted)
1592 reverse = !reverse;
1593 int w = rect.width();
1594 if (pb->minimum == 0 && pb->maximum == 0) {
1595 // draw busy indicator
1596 int x = (progress - minimum) % (w * 2);
1597 if (x > w)
1598 x = 2 * w - x;
1599 x = reverse ? rect.right() - x : x + rect.x();
1600 p->setPen(QPen(pal2.highlight().color(), 4));
1601 p->drawLine(x1: x, y1: rect.y(), x2: x, y2: rect.height());
1602 } else {
1603 const int unit_width = proxy()->pixelMetric(metric: PM_ProgressBarChunkWidth, option: pb, widget);
1604 if (!unit_width)
1605 return;
1606
1607 int u;
1608 if (unit_width > 1)
1609 u = ((rect.width() + unit_width) / unit_width);
1610 else
1611 u = w / unit_width;
1612 qint64 p_v = progress - minimum;
1613 qint64 t_s = (maximum - minimum) ? (maximum - minimum) : qint64(1);
1614
1615 if (u > 0 && p_v >= INT_MAX / u && t_s >= u) {
1616 // scale down to something usable.
1617 p_v /= u;
1618 t_s /= u;
1619 }
1620
1621 // nu < tnu, if last chunk is only a partial chunk
1622 int tnu, nu;
1623 tnu = nu = p_v * u / t_s;
1624
1625 if (nu * unit_width > w)
1626 --nu;
1627
1628 // Draw nu units out of a possible u of unit_width
1629 // width, each a rectangle bordered by background
1630 // color, all in a sunken panel with a percentage text
1631 // display at the end.
1632 int x = 0;
1633 int x0 = reverse ? rect.right() - ((unit_width > 1) ? unit_width : 0)
1634 : rect.x();
1635
1636 QStyleOptionProgressBar pbBits = *pb;
1637 pbBits.rect = rect;
1638 pbBits.palette = pal2;
1639 int myY = pbBits.rect.y();
1640 int myHeight = pbBits.rect.height();
1641 pbBits.state &= QStyle::State_Horizontal; // all other is irrelevant here
1642 for (int i = 0; i < nu; ++i) {
1643 pbBits.rect.setRect(ax: x0 + x, ay: myY, aw: unit_width, ah: myHeight);
1644 pbBits.rect = m.mapRect(QRectF(pbBits.rect)).toRect();
1645 proxy()->drawPrimitive(pe: PE_IndicatorProgressChunk, opt: &pbBits, p, w: widget);
1646 x += reverse ? -unit_width : unit_width;
1647 }
1648
1649 // Draw the last partial chunk to fill up the
1650 // progress bar entirely
1651 if (nu < tnu) {
1652 int pixels_left = w - (nu * unit_width);
1653 int offset = reverse ? x0 + x + unit_width-pixels_left : x0 + x;
1654 pbBits.rect.setRect(ax: offset, ay: myY, aw: pixels_left, ah: myHeight);
1655 pbBits.rect = m.mapRect(QRectF(pbBits.rect)).toRect();
1656 proxy()->drawPrimitive(pe: PE_IndicatorProgressChunk, opt: &pbBits, p, w: widget);
1657 }
1658 }
1659 }
1660 break;
1661#endif // QT_CONFIG(progressbar)
1662 case CE_HeaderLabel:
1663 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
1664 QRect rect = header->rect;
1665 if (!header->icon.isNull()) {
1666 int iconExtent = proxy()->pixelMetric(metric: PM_SmallIconSize, option: opt, widget);
1667 QPixmap pixmap
1668 = header->icon.pixmap(size: QSize(iconExtent, iconExtent), devicePixelRatio: p->device()->devicePixelRatio(), mode: (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled);
1669 int pixw = pixmap.width() / pixmap.devicePixelRatio();
1670
1671 QRect aligned = alignedRect(direction: header->direction, alignment: header->iconAlignment, size: pixmap.size() / pixmap.devicePixelRatio(), rectangle: rect);
1672 QRect inter = aligned.intersected(other: rect);
1673 p->drawPixmap(x: inter.x(), y: inter.y(), pm: pixmap,
1674 sx: inter.x() - aligned.x(), sy: inter.y() - aligned.y(),
1675 sw: aligned.width() * pixmap.devicePixelRatio(),
1676 sh: pixmap.height() * pixmap.devicePixelRatio());
1677
1678 const int margin = proxy()->pixelMetric(metric: QStyle::PM_HeaderMargin, option: opt, widget);
1679 if (header->direction == Qt::LeftToRight)
1680 rect.setLeft(rect.left() + pixw + margin);
1681 else
1682 rect.setRight(rect.right() - pixw - margin);
1683 }
1684 QFontMetrics fm(header->fontMetrics);
1685 if (header->state & QStyle::State_On) {
1686 QFont fnt = p->font();
1687 // the font already has a weight set; don't override that
1688 if (!(fnt.resolveMask() & QFont::WeightResolved)) {
1689 fnt.setBold(true);
1690 p->setFont(fnt);
1691 fm = QFontMetrics((p->font()));
1692 }
1693 }
1694 QString text = header->text;
1695 if (const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(opt: header)) {
1696 if (headerV2->textElideMode != Qt::ElideNone)
1697 text = fm.elidedText(text: header->text, mode: headerV2->textElideMode, width: rect.width());
1698 }
1699 proxy()->drawItemText(painter: p, rect, flags: header->textAlignment, pal: header->palette,
1700 enabled: header->state.testFlag(flag: State_Enabled), text, textRole: QPalette::ButtonText);
1701 }
1702 break;
1703#if QT_CONFIG(toolbutton)
1704 case CE_ToolButtonLabel:
1705 if (const QStyleOptionToolButton *toolbutton
1706 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
1707 QRect rect = toolbutton->rect;
1708 int shiftX = 0;
1709 int shiftY = 0;
1710 if (toolbutton->state & (State_Sunken | State_On)) {
1711 shiftX = proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: toolbutton, widget);
1712 shiftY = proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: toolbutton, widget);
1713 }
1714 // Arrow type always overrules and is always shown
1715 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1716 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1717 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1718 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1719 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt, widget))
1720 alignment |= Qt::TextHideMnemonic;
1721 rect.translate(dx: shiftX, dy: shiftY);
1722 p->setFont(toolbutton->font);
1723 const QString text = d->toolButtonElideText(option: toolbutton, textRect: rect, flags: alignment);
1724 proxy()->drawItemText(painter: p, rect, flags: alignment, pal: toolbutton->palette,
1725 enabled: opt->state & State_Enabled, text,
1726 textRole: QPalette::ButtonText);
1727 } else {
1728 QPixmap pm;
1729 QSize pmSize = toolbutton->iconSize;
1730 if (!toolbutton->icon.isNull()) {
1731 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1732 QIcon::Mode mode;
1733 if (!(toolbutton->state & State_Enabled))
1734 mode = QIcon::Disabled;
1735 else if ((opt->state & State_MouseOver) && (opt->state & State_AutoRaise))
1736 mode = QIcon::Active;
1737 else
1738 mode = QIcon::Normal;
1739 pm = toolbutton->icon.pixmap(size: toolbutton->rect.size().boundedTo(otherSize: toolbutton->iconSize), devicePixelRatio: p->device()->devicePixelRatio(),
1740 mode, state);
1741 pmSize = pm.size() / pm.devicePixelRatio();
1742 }
1743
1744 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1745 p->setFont(toolbutton->font);
1746 QRect pr = rect,
1747 tr = rect;
1748 int alignment = Qt::TextShowMnemonic;
1749 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt, widget))
1750 alignment |= Qt::TextHideMnemonic;
1751
1752 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1753 pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
1754 tr.adjust(dx1: 0, dy1: pr.height() - 1, dx2: 0, dy2: -1);
1755 pr.translate(dx: shiftX, dy: shiftY);
1756 if (!hasArrow) {
1757 proxy()->drawItemPixmap(painter: p, rect: pr, alignment: Qt::AlignCenter, pixmap: pm);
1758 } else {
1759 drawArrow(style: proxy(), toolbutton, rect: pr, painter: p, widget);
1760 }
1761 alignment |= Qt::AlignCenter;
1762 } else {
1763 pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
1764 tr.adjust(dx1: pr.width(), dy1: 0, dx2: 0, dy2: 0);
1765 pr.translate(dx: shiftX, dy: shiftY);
1766 if (!hasArrow) {
1767 proxy()->drawItemPixmap(painter: p, rect: QStyle::visualRect(direction: opt->direction, boundingRect: rect, logicalRect: pr), alignment: Qt::AlignCenter, pixmap: pm);
1768 } else {
1769 drawArrow(style: proxy(), toolbutton, rect: pr, painter: p, widget);
1770 }
1771 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
1772 }
1773 tr.translate(dx: shiftX, dy: shiftY);
1774 const QString text = d->toolButtonElideText(option: toolbutton, textRect: tr, flags: alignment);
1775 proxy()->drawItemText(painter: p, rect: QStyle::visualRect(direction: opt->direction, boundingRect: rect, logicalRect: tr), flags: alignment, pal: toolbutton->palette,
1776 enabled: toolbutton->state & State_Enabled, text,
1777 textRole: QPalette::ButtonText);
1778 } else {
1779 rect.translate(dx: shiftX, dy: shiftY);
1780 if (hasArrow) {
1781 drawArrow(style: proxy(), toolbutton, rect, painter: p, widget);
1782 } else {
1783 proxy()->drawItemPixmap(painter: p, rect, alignment: Qt::AlignCenter, pixmap: pm);
1784 }
1785 }
1786 }
1787 }
1788 break;
1789#endif // QT_CONFIG(toolbutton)
1790#if QT_CONFIG(toolbox)
1791 case CE_ToolBoxTab:
1792 if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
1793 proxy()->drawControl(element: CE_ToolBoxTabShape, opt: tb, p, w: widget);
1794 proxy()->drawControl(element: CE_ToolBoxTabLabel, opt: tb, p, w: widget);
1795 }
1796 break;
1797 case CE_ToolBoxTabShape:
1798 if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
1799 p->setPen(tb->palette.mid().color().darker(f: 150));
1800 int d = 20 + tb->rect.height() - 3;
1801 if (tb->direction != Qt::RightToLeft) {
1802 const QPoint points[] = {
1803 QPoint(-1, tb->rect.height() + 1),
1804 QPoint(-1, 1),
1805 QPoint(tb->rect.width() - d, 1),
1806 QPoint(tb->rect.width() - 20, tb->rect.height() - 2),
1807 QPoint(tb->rect.width() - 1, tb->rect.height() - 2),
1808 QPoint(tb->rect.width() - 1, tb->rect.height() + 1),
1809 QPoint(-1, tb->rect.height() + 1),
1810 };
1811 p->drawPolygon(points, pointCount: sizeof points / sizeof *points);
1812 } else {
1813 const QPoint points[] = {
1814 QPoint(tb->rect.width(), tb->rect.height() + 1),
1815 QPoint(tb->rect.width(), 1),
1816 QPoint(d - 1, 1),
1817 QPoint(20 - 1, tb->rect.height() - 2),
1818 QPoint(0, tb->rect.height() - 2),
1819 QPoint(0, tb->rect.height() + 1),
1820 QPoint(tb->rect.width(), tb->rect.height() + 1),
1821 };
1822 p->drawPolygon(points, pointCount: sizeof points / sizeof *points);
1823 }
1824 p->setPen(tb->palette.light().color());
1825 if (tb->direction != Qt::RightToLeft) {
1826 p->drawLine(x1: 0, y1: 2, x2: tb->rect.width() - d, y2: 2);
1827 p->drawLine(x1: tb->rect.width() - d - 1, y1: 2, x2: tb->rect.width() - 21, y2: tb->rect.height() - 1);
1828 p->drawLine(x1: tb->rect.width() - 20, y1: tb->rect.height() - 1,
1829 x2: tb->rect.width(), y2: tb->rect.height() - 1);
1830 } else {
1831 p->drawLine(x1: tb->rect.width() - 1, y1: 2, x2: d - 1, y2: 2);
1832 p->drawLine(x1: d, y1: 2, x2: 20, y2: tb->rect.height() - 1);
1833 p->drawLine(x1: 19, y1: tb->rect.height() - 1,
1834 x2: -1, y2: tb->rect.height() - 1);
1835 }
1836 p->setBrush(Qt::NoBrush);
1837 }
1838 break;
1839#endif // QT_CONFIG(toolbox)
1840#if QT_CONFIG(tabbar)
1841 case CE_TabBarTab:
1842 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
1843 proxy()->drawControl(element: CE_TabBarTabShape, opt: tab, p, w: widget);
1844 proxy()->drawControl(element: CE_TabBarTabLabel, opt: tab, p, w: widget);
1845 }
1846 break;
1847 case CE_TabBarTabShape:
1848 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
1849 QPainterStateSaver pss(p);
1850 QRect rect(tab->rect);
1851 bool selected = tab->state & State_Selected;
1852 bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
1853 int tabOverlap = onlyOne ? 0 : proxy()->pixelMetric(metric: PM_TabBarTabOverlap, option: opt, widget);
1854
1855 if (!selected) {
1856 switch (tab->shape) {
1857 case QTabBar::TriangularNorth:
1858 rect.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -tabOverlap);
1859 if (!selected)
1860 rect.adjust(dx1: 1, dy1: 1, dx2: -1, dy2: 0);
1861 break;
1862 case QTabBar::TriangularSouth:
1863 rect.adjust(dx1: 0, dy1: tabOverlap, dx2: 0, dy2: 0);
1864 if (!selected)
1865 rect.adjust(dx1: 1, dy1: 0, dx2: -1, dy2: -1);
1866 break;
1867 case QTabBar::TriangularEast:
1868 rect.adjust(dx1: tabOverlap, dy1: 0, dx2: 0, dy2: 0);
1869 if (!selected)
1870 rect.adjust(dx1: 0, dy1: 1, dx2: -1, dy2: -1);
1871 break;
1872 case QTabBar::TriangularWest:
1873 rect.adjust(dx1: 0, dy1: 0, dx2: -tabOverlap, dy2: 0);
1874 if (!selected)
1875 rect.adjust(dx1: 1, dy1: 1, dx2: 0, dy2: -1);
1876 break;
1877 default:
1878 break;
1879 }
1880 }
1881
1882 p->setPen(QPen(tab->palette.windowText(), 0));
1883 if (selected) {
1884 p->setBrush(tab->palette.base());
1885 } else {
1886 if (widget && widget->parentWidget())
1887 p->setBrush(widget->parentWidget()->palette().window());
1888 else
1889 p->setBrush(tab->palette.window());
1890 }
1891
1892 int y;
1893 int x;
1894 QPolygon a(10);
1895 switch (tab->shape) {
1896 case QTabBar::TriangularNorth:
1897 case QTabBar::TriangularSouth: {
1898 a.setPoint(index: 0, x: 0, y: -1);
1899 a.setPoint(index: 1, x: 0, y: 0);
1900 y = rect.height() - 2;
1901 x = y / 3;
1902 a.setPoint(index: 2, x: x++, y: y - 1);
1903 ++x;
1904 a.setPoint(index: 3, x: x++, y: y++);
1905 a.setPoint(index: 4, x, y);
1906
1907 int i;
1908 int right = rect.width() - 1;
1909 for (i = 0; i < 5; ++i)
1910 a.setPoint(index: 9 - i, x: right - a.point(index: i).x(), y: a.point(index: i).y());
1911 if (tab->shape == QTabBar::TriangularNorth)
1912 for (i = 0; i < 10; ++i)
1913 a.setPoint(index: i, x: a.point(index: i).x(), y: rect.height() - 1 - a.point(index: i).y());
1914
1915 a.translate(dx: rect.left(), dy: rect.top());
1916 p->setRenderHint(hint: QPainter::Antialiasing);
1917 p->translate(dx: 0, dy: 0.5);
1918
1919 QPainterPath path;
1920 path.addPolygon(polygon: a);
1921 p->drawPath(path);
1922 break; }
1923 case QTabBar::TriangularEast:
1924 case QTabBar::TriangularWest: {
1925 a.setPoint(index: 0, x: -1, y: 0);
1926 a.setPoint(index: 1, x: 0, y: 0);
1927 x = rect.width() - 2;
1928 y = x / 3;
1929 a.setPoint(index: 2, x: x - 1, y: y++);
1930 ++y;
1931 a.setPoint(index: 3, x: x++, y: y++);
1932 a.setPoint(index: 4, x, y);
1933 int i;
1934 int bottom = rect.height() - 1;
1935 for (i = 0; i < 5; ++i)
1936 a.setPoint(index: 9 - i, x: a.point(index: i).x(), y: bottom - a.point(index: i).y());
1937 if (tab->shape == QTabBar::TriangularWest)
1938 for (i = 0; i < 10; ++i)
1939 a.setPoint(index: i, x: rect.width() - 1 - a.point(index: i).x(), y: a.point(index: i).y());
1940 a.translate(dx: rect.left(), dy: rect.top());
1941 p->setRenderHint(hint: QPainter::Antialiasing);
1942 p->translate(dx: 0.5, dy: 0);
1943 QPainterPath path;
1944 path.addPolygon(polygon: a);
1945 p->drawPath(path);
1946 break; }
1947 default:
1948 break;
1949 }
1950 }
1951 break;
1952 case CE_ToolBoxTabLabel:
1953 if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
1954 bool enabled = tb->state & State_Enabled;
1955 bool selected = tb->state & State_Selected;
1956 int iconExtent = proxy()->pixelMetric(metric: QStyle::PM_SmallIconSize, option: tb, widget);
1957 QPixmap pm = tb->icon.pixmap(size: QSize(iconExtent, iconExtent), devicePixelRatio: p->device()->devicePixelRatio(),
1958 mode: enabled ? QIcon::Normal : QIcon::Disabled);
1959
1960 QRect cr = subElementRect(r: QStyle::SE_ToolBoxTabContents, opt: tb, widget);
1961 QRect tr, ir;
1962 int ih = 0;
1963 if (pm.isNull()) {
1964 tr = cr;
1965 tr.adjust(dx1: 4, dy1: 0, dx2: -8, dy2: 0);
1966 } else {
1967 int iw = pm.width() / pm.devicePixelRatio() + 4;
1968 ih = pm.height()/ pm.devicePixelRatio();
1969 ir = QRect(cr.left() + 4, cr.top(), iw + 2, ih);
1970 tr = QRect(ir.right(), cr.top(), cr.width() - ir.right() - 4, cr.height());
1971 }
1972
1973 if (selected && proxy()->styleHint(stylehint: QStyle::SH_ToolBox_SelectedPageTitleBold, opt: tb, widget)) {
1974 QFont f(p->font());
1975 f.setBold(true);
1976 p->setFont(f);
1977 }
1978
1979 QString txt = tb->fontMetrics.elidedText(text: tb->text, mode: Qt::ElideRight, width: tr.width());
1980
1981 if (ih)
1982 p->drawPixmap(x: ir.left(), y: (tb->rect.height() - ih) / 2, pm);
1983
1984 int alignment = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic;
1985 if (!proxy()->styleHint(stylehint: QStyle::SH_UnderlineShortcut, opt: tb, widget))
1986 alignment |= Qt::TextHideMnemonic;
1987 proxy()->drawItemText(painter: p, rect: tr, flags: alignment, pal: tb->palette, enabled, text: txt, textRole: QPalette::ButtonText);
1988
1989 if (!txt.isEmpty() && opt->state & State_HasFocus) {
1990 QStyleOptionFocusRect opt;
1991 opt.rect = tr;
1992 opt.palette = tb->palette;
1993 opt.state = QStyle::State_None;
1994 proxy()->drawPrimitive(pe: QStyle::PE_FrameFocusRect, opt: &opt, p, w: widget);
1995 }
1996 }
1997 break;
1998 case CE_TabBarTabLabel:
1999 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
2000 QRect tr = tab->rect;
2001 bool verticalTabs = tab->shape == QTabBar::RoundedEast
2002 || tab->shape == QTabBar::RoundedWest
2003 || tab->shape == QTabBar::TriangularEast
2004 || tab->shape == QTabBar::TriangularWest;
2005
2006 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
2007 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt, widget))
2008 alignment |= Qt::TextHideMnemonic;
2009
2010 QPainterStateSaver pss(p, verticalTabs);
2011 if (verticalTabs) {
2012 int newX, newY, newRot;
2013 if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
2014 newX = tr.width() + tr.x();
2015 newY = tr.y();
2016 newRot = 90;
2017 } else {
2018 newX = tr.x();
2019 newY = tr.y() + tr.height();
2020 newRot = -90;
2021 }
2022 QTransform m = QTransform::fromTranslate(dx: newX, dy: newY);
2023 m.rotate(a: newRot);
2024 p->setTransform(transform: m, combine: true);
2025 }
2026 QRect iconRect;
2027 d->tabLayout(opt: tab, widget, textRect: &tr, iconRect: &iconRect);
2028
2029 // compute tr again, unless tab is moving, because the style may override subElementRect
2030 if (tab->position != QStyleOptionTab::TabPosition::Moving)
2031 tr = proxy()->subElementRect(subElement: SE_TabBarTabText, option: opt, widget);
2032
2033 if (!tab->icon.isNull()) {
2034 QPixmap tabIcon = tab->icon.pixmap(size: tab->iconSize, devicePixelRatio: p->device()->devicePixelRatio(),
2035 mode: (tab->state & State_Enabled) ? QIcon::Normal
2036 : QIcon::Disabled,
2037 state: (tab->state & State_Selected) ? QIcon::On
2038 : QIcon::Off);
2039 p->drawPixmap(x: iconRect.x(), y: iconRect.y(), pm: tabIcon);
2040 }
2041
2042 proxy()->drawItemText(painter: p, rect: tr, flags: alignment, pal: tab->palette, enabled: tab->state & State_Enabled, text: tab->text,
2043 textRole: widget ? widget->foregroundRole() : QPalette::WindowText);
2044 pss.restore();
2045
2046 if (tab->state & State_HasFocus) {
2047 const int OFFSET = 1 + pixelMetric(m: PM_DefaultFrameWidth, opt, widget);
2048
2049 int x1, x2;
2050 x1 = tab->rect.left();
2051 x2 = tab->rect.right() - 1;
2052
2053 QStyleOptionFocusRect fropt;
2054 fropt.QStyleOption::operator=(other: *tab);
2055 fropt.rect.setRect(ax: x1 + 1 + OFFSET, ay: tab->rect.y() + OFFSET,
2056 aw: x2 - x1 - 2*OFFSET, ah: tab->rect.height() - 2*OFFSET);
2057 drawPrimitive(pe: PE_FrameFocusRect, opt: &fropt, p, widget);
2058 }
2059 }
2060 break;
2061#endif // QT_CONFIG(tabbar)
2062#if QT_CONFIG(sizegrip)
2063 case CE_SizeGrip: {
2064 QPainterStateSaver pss(p);
2065 int x, y, w, h;
2066 opt->rect.getRect(ax: &x, ay: &y, aw: &w, ah: &h);
2067
2068 int sw = qMin(a: h, b: w);
2069 if (h > w)
2070 p->translate(dx: 0, dy: h - w);
2071 else
2072 p->translate(dx: w - h, dy: 0);
2073
2074 int sx = x;
2075 int sy = y;
2076 int s = sw / 3;
2077
2078 Qt::Corner corner;
2079 if (const QStyleOptionSizeGrip *sgOpt = qstyleoption_cast<const QStyleOptionSizeGrip *>(opt))
2080 corner = sgOpt->corner;
2081 else if (opt->direction == Qt::RightToLeft)
2082 corner = Qt::BottomLeftCorner;
2083 else
2084 corner = Qt::BottomRightCorner;
2085
2086 if (corner == Qt::BottomLeftCorner) {
2087 sx = x + sw;
2088 for (int i = 0; i < 4; ++i) {
2089 p->setPen(QPen(opt->palette.light().color(), 1));
2090 p->drawLine(x1: x, y1: sy - 1 , x2: sx + 1, y2: sw);
2091 p->setPen(QPen(opt->palette.dark().color(), 1));
2092 p->drawLine(x1: x, y1: sy, x2: sx, y2: sw);
2093 p->setPen(QPen(opt->palette.dark().color(), 1));
2094 p->drawLine(x1: x, y1: sy + 1, x2: sx - 1, y2: sw);
2095 sx -= s;
2096 sy += s;
2097 }
2098 } else if (corner == Qt::BottomRightCorner) {
2099 for (int i = 0; i < 4; ++i) {
2100 p->setPen(QPen(opt->palette.light().color(), 1));
2101 p->drawLine(x1: sx - 1, y1: sw, x2: sw, y2: sy - 1);
2102 p->setPen(QPen(opt->palette.dark().color(), 1));
2103 p->drawLine(x1: sx, y1: sw, x2: sw, y2: sy);
2104 p->setPen(QPen(opt->palette.dark().color(), 1));
2105 p->drawLine(x1: sx + 1, y1: sw, x2: sw, y2: sy + 1);
2106 sx += s;
2107 sy += s;
2108 }
2109 } else if (corner == Qt::TopRightCorner) {
2110 sy = y + sw;
2111 for (int i = 0; i < 4; ++i) {
2112 p->setPen(QPen(opt->palette.light().color(), 1));
2113 p->drawLine(x1: sx - 1, y1: y, x2: sw, y2: sy + 1);
2114 p->setPen(QPen(opt->palette.dark().color(), 1));
2115 p->drawLine(x1: sx, y1: y, x2: sw, y2: sy);
2116 p->setPen(QPen(opt->palette.dark().color(), 1));
2117 p->drawLine(x1: sx + 1, y1: y, x2: sw, y2: sy - 1);
2118 sx += s;
2119 sy -= s;
2120 }
2121 } else if (corner == Qt::TopLeftCorner) {
2122 for (int i = 0; i < 4; ++i) {
2123 p->setPen(QPen(opt->palette.light().color(), 1));
2124 p->drawLine(x1: x, y1: sy - 1, x2: sx - 1, y2: y);
2125 p->setPen(QPen(opt->palette.dark().color(), 1));
2126 p->drawLine(x1: x, y1: sy, x2: sx, y2: y);
2127 p->setPen(QPen(opt->palette.dark().color(), 1));
2128 p->drawLine(x1: x, y1: sy + 1, x2: sx + 1, y2: y);
2129 sx += s;
2130 sy += s;
2131 }
2132 }
2133 break; }
2134#endif // QT_CONFIG(sizegrip)
2135#if QT_CONFIG(rubberband)
2136 case CE_RubberBand: {
2137 if (const QStyleOptionRubberBand *rbOpt = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
2138 QPixmap tiledPixmap(16, 16);
2139 QPainter pixmapPainter(&tiledPixmap);
2140 pixmapPainter.setPen(Qt::NoPen);
2141 pixmapPainter.setBrush(Qt::Dense4Pattern);
2142 pixmapPainter.setBackground(QBrush(opt->palette.base()));
2143 pixmapPainter.setBackgroundMode(Qt::OpaqueMode);
2144 pixmapPainter.drawRect(x: 0, y: 0, w: tiledPixmap.width(), h: tiledPixmap.height());
2145 pixmapPainter.end();
2146 // ### workaround for borked XRENDER
2147 tiledPixmap = QPixmap::fromImage(image: tiledPixmap.toImage());
2148
2149 QPainterStateSaver pss(p);
2150 QRect r = opt->rect;
2151 QStyleHintReturnMask mask;
2152 if (proxy()->styleHint(stylehint: QStyle::SH_RubberBand_Mask, opt, widget, returnData: &mask))
2153 p->setClipRegion(mask.region);
2154 p->drawTiledPixmap(x: r.x(), y: r.y(), w: r.width(), h: r.height(), pm: tiledPixmap);
2155 p->setPen(opt->palette.color(cg: QPalette::Active, cr: QPalette::WindowText));
2156 p->setBrush(Qt::NoBrush);
2157 p->drawRect(r: r.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
2158 if (rbOpt->shape == QRubberBand::Rectangle)
2159 p->drawRect(r: r.adjusted(xp1: 3, yp1: 3, xp2: -4, yp2: -4));
2160 }
2161 break; }
2162#endif // QT_CONFIG(rubberband)
2163#if QT_CONFIG(dockwidget)
2164 case CE_DockWidgetTitle:
2165 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
2166 QRect r = dwOpt->rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1);
2167 if (dwOpt->movable) {
2168 p->setPen(dwOpt->palette.color(cr: QPalette::Dark));
2169 p->drawRect(r);
2170 }
2171
2172 if (!dwOpt->title.isEmpty()) {
2173 const bool verticalTitleBar = dwOpt->verticalTitleBar;
2174
2175 QPainterStateSaver pss(p, verticalTitleBar);
2176 if (verticalTitleBar) {
2177 r = r.transposed();
2178
2179 p->translate(dx: r.left(), dy: r.top() + r.width());
2180 p->rotate(a: -90);
2181 p->translate(dx: -r.left(), dy: -r.top());
2182 }
2183
2184 const int indent = p->fontMetrics().descent();
2185 proxy()->drawItemText(painter: p, rect: r.adjusted(xp1: indent + 1, yp1: 1, xp2: -indent - 1, yp2: -1),
2186 flags: Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, pal: dwOpt->palette,
2187 enabled: dwOpt->state & State_Enabled, text: dwOpt->title,
2188 textRole: QPalette::WindowText);
2189 }
2190 }
2191 break;
2192#endif // QT_CONFIG(dockwidget)
2193 case CE_Header:
2194 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
2195 QRegion clipRegion = p->clipRegion();
2196 p->setClipRect(opt->rect);
2197 proxy()->drawControl(element: CE_HeaderSection, opt: header, p, w: widget);
2198 // opt can be a QStyleOptionHeaderV2 and we must pass it to the subcontrol drawings
2199 QStyleOptionHeaderV2 subopt;
2200 QStyleOptionHeader &v1Copy = subopt;
2201 if (auto v2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(opt))
2202 subopt = *v2;
2203 else
2204 v1Copy = *header;
2205 subopt.rect = subElementRect(r: SE_HeaderLabel, opt: header, widget);
2206 if (subopt.rect.isValid())
2207 proxy()->drawControl(element: CE_HeaderLabel, opt: &subopt, p, w: widget);
2208 if (header->sortIndicator != QStyleOptionHeader::None) {
2209 subopt.rect = subElementRect(r: SE_HeaderArrow, opt, widget);
2210 proxy()->drawPrimitive(pe: PE_IndicatorHeaderArrow, opt: &subopt, p, w: widget);
2211 }
2212 p->setClipRegion(clipRegion);
2213 }
2214 break;
2215 case CE_FocusFrame:
2216 p->fillRect(opt->rect, opt->palette.windowText());
2217 break;
2218 case CE_HeaderSection:
2219 qDrawShadePanel(p, r: opt->rect, pal: opt->palette,
2220 sunken: opt->state & State_Sunken, lineWidth: 1,
2221 fill: &opt->palette.brush(cr: QPalette::Button));
2222 break;
2223 case CE_HeaderEmptyArea:
2224 p->fillRect(opt->rect, opt->palette.window());
2225 break;
2226#if QT_CONFIG(combobox)
2227 case CE_ComboBoxLabel:
2228 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
2229 QRect editRect = proxy()->subControlRect(cc: CC_ComboBox, opt: cb, sc: SC_ComboBoxEditField, widget);
2230 QPainterStateSaver pss(p);
2231 p->setClipRect(editRect);
2232 if (!cb->currentIcon.isNull()) {
2233 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
2234 : QIcon::Disabled;
2235 QPixmap pixmap = cb->currentIcon.pixmap(size: cb->iconSize, devicePixelRatio: p->device()->devicePixelRatio(), mode);
2236 QRect iconRect(editRect);
2237 iconRect.setWidth(cb->iconSize.width() + 4);
2238 iconRect = alignedRect(direction: cb->direction,
2239 alignment: Qt::AlignLeft | Qt::AlignVCenter,
2240 size: iconRect.size(), rectangle: editRect);
2241 if (cb->editable)
2242 p->fillRect(iconRect, opt->palette.brush(cr: QPalette::Base));
2243 proxy()->drawItemPixmap(painter: p, rect: iconRect, alignment: Qt::AlignCenter, pixmap);
2244
2245 if (cb->direction == Qt::RightToLeft)
2246 editRect.translate(dx: -4 - cb->iconSize.width(), dy: 0);
2247 else
2248 editRect.translate(dx: cb->iconSize.width() + 4, dy: 0);
2249 }
2250 if (!cb->currentText.isEmpty() && !cb->editable) {
2251 // keep in sync with QLineEditPrivate::horizontalMargin = 2
2252 proxy()->drawItemText(painter: p, rect: editRect.adjusted(xp1: 2, yp1: 0, xp2: -2, yp2: 0),
2253 flags: visualAlignment(direction: cb->direction, alignment: cb->textAlignment),
2254 pal: cb->palette, enabled: cb->state & State_Enabled, text: cb->currentText);
2255 }
2256 }
2257 break;
2258#endif // QT_CONFIG(combobox)
2259#if QT_CONFIG(toolbar)
2260 case CE_ToolBar:
2261 if (const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
2262 // Compatibility with styles that use PE_PanelToolBar
2263 QStyleOptionFrame frame;
2264 frame.QStyleOption::operator=(other: *toolBar);
2265 frame.lineWidth = toolBar->lineWidth;
2266 frame.midLineWidth = toolBar->midLineWidth;
2267 proxy()->drawPrimitive(pe: PE_PanelToolBar, opt, p, w: widget);
2268
2269 if (widget && qobject_cast<QToolBar *>(object: widget->parentWidget()))
2270 break;
2271 qDrawShadePanel(p, r: toolBar->rect, pal: toolBar->palette, sunken: false, lineWidth: toolBar->lineWidth,
2272 fill: &toolBar->palette.brush(cr: QPalette::Button));
2273 }
2274 break;
2275#endif // QT_CONFIG(toolbar)
2276 case CE_ColumnViewGrip: {
2277 // draw background gradients
2278 QLinearGradient g(0, 0, opt->rect.width(), 0);
2279 g.setColorAt(pos: 0, color: opt->palette.color(cg: QPalette::Active, cr: QPalette::Mid));
2280 g.setColorAt(pos: 0.5, color: Qt::white);
2281 p->fillRect(QRect(0, 0, opt->rect.width(), opt->rect.height()), g);
2282
2283 // draw the two lines
2284 QPen pen(p->pen());
2285 pen.setWidth(opt->rect.width()/20);
2286 pen.setColor(opt->palette.color(cg: QPalette::Active, cr: QPalette::Dark));
2287 p->setPen(pen);
2288
2289 int line1starting = opt->rect.width()*8 / 20;
2290 int line2starting = opt->rect.width()*13 / 20;
2291 int top = opt->rect.height()*20/75;
2292 int bottom = opt->rect.height() - 1 - top;
2293 p->drawLine(x1: line1starting, y1: top, x2: line1starting, y2: bottom);
2294 p->drawLine(x1: line2starting, y1: top, x2: line2starting, y2: bottom);
2295 }
2296 break;
2297
2298#if QT_CONFIG(itemviews)
2299 case CE_ItemViewItem:
2300 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
2301 QPainterStateSaver pss(p);
2302 // the style calling this might want to clip, so respect any region already set
2303 const QRegion clipRegion = p->hasClipping() ? (p->clipRegion() & opt->rect) : opt->rect;
2304 p->setClipRegion(clipRegion);
2305
2306 QRect checkRect = proxy()->subElementRect(subElement: SE_ItemViewItemCheckIndicator, option: vopt, widget);
2307 QRect iconRect = proxy()->subElementRect(subElement: SE_ItemViewItemDecoration, option: vopt, widget);
2308 QRect textRect = proxy()->subElementRect(subElement: SE_ItemViewItemText, option: vopt, widget);
2309
2310 // draw the background
2311 proxy()->drawPrimitive(pe: PE_PanelItemViewItem, opt, p, w: widget);
2312
2313 // draw the check mark
2314 if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
2315 QStyleOptionViewItem option(*vopt);
2316 option.rect = checkRect;
2317 option.state = option.state & ~QStyle::State_HasFocus;
2318
2319 switch (vopt->checkState) {
2320 case Qt::Unchecked:
2321 option.state |= QStyle::State_Off;
2322 break;
2323 case Qt::PartiallyChecked:
2324 option.state |= QStyle::State_NoChange;
2325 break;
2326 case Qt::Checked:
2327 option.state |= QStyle::State_On;
2328 break;
2329 }
2330 proxy()->drawPrimitive(pe: QStyle::PE_IndicatorItemViewItemCheck, opt: &option, p, w: widget);
2331 }
2332
2333 // draw the icon
2334 QIcon::Mode mode = QIcon::Normal;
2335 if (!(vopt->state & QStyle::State_Enabled))
2336 mode = QIcon::Disabled;
2337 else if (vopt->state & QStyle::State_Selected)
2338 mode = QIcon::Selected;
2339 QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
2340 vopt->icon.paint(painter: p, rect: iconRect, alignment: vopt->decorationAlignment, mode, state);
2341
2342 // draw the text
2343 if (!vopt->text.isEmpty()) {
2344 QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled
2345 ? QPalette::Normal : QPalette::Disabled;
2346 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
2347 cg = QPalette::Inactive;
2348
2349 if (vopt->state & QStyle::State_Selected) {
2350 p->setPen(vopt->palette.color(cg, cr: QPalette::HighlightedText));
2351 } else {
2352 p->setPen(vopt->palette.color(cg, cr: QPalette::Text));
2353 }
2354 if (vopt->state & QStyle::State_Editing) {
2355 p->setPen(vopt->palette.color(cg, cr: QPalette::Text));
2356 p->drawRect(r: textRect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
2357 }
2358
2359 d->viewItemDrawText(p, option: vopt, rect: textRect);
2360 }
2361
2362 // draw the focus rect
2363 if (vopt->state & QStyle::State_HasFocus) {
2364 QStyleOptionFocusRect o;
2365 o.QStyleOption::operator=(other: *vopt);
2366 o.rect = proxy()->subElementRect(subElement: SE_ItemViewItemFocusRect, option: vopt, widget);
2367 o.state |= QStyle::State_KeyboardFocusChange;
2368 o.state |= QStyle::State_Item;
2369 QPalette::ColorGroup cg = (vopt->state & QStyle::State_Enabled)
2370 ? QPalette::Normal : QPalette::Disabled;
2371 o.backgroundColor = vopt->palette.color(cg, cr: (vopt->state & QStyle::State_Selected)
2372 ? QPalette::Highlight : QPalette::Window);
2373 proxy()->drawPrimitive(pe: QStyle::PE_FrameFocusRect, opt: &o, p, w: widget);
2374 }
2375 }
2376 break;
2377
2378#endif // QT_CONFIG(itemviews)
2379#ifndef QT_NO_FRAME
2380 case CE_ShapedFrame:
2381 if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2382 int frameShape = f->frameShape;
2383 int frameShadow = QFrame::Plain;
2384 if (f->state & QStyle::State_Sunken) {
2385 frameShadow = QFrame::Sunken;
2386 } else if (f->state & QStyle::State_Raised) {
2387 frameShadow = QFrame::Raised;
2388 }
2389
2390 int lw = f->lineWidth;
2391 int mlw = f->midLineWidth;
2392 QPalette::ColorRole foregroundRole = QPalette::WindowText;
2393 if (widget)
2394 foregroundRole = widget->foregroundRole();
2395
2396 switch (frameShape) {
2397 case QFrame::Box:
2398 if (frameShadow == QFrame::Plain) {
2399 qDrawPlainRect(p, r: f->rect, f->palette.color(cr: foregroundRole), lineWidth: lw);
2400 } else {
2401 qDrawShadeRect(p, r: f->rect, pal: f->palette, sunken: frameShadow == QFrame::Sunken, lineWidth: lw, midLineWidth: mlw);
2402 }
2403 break;
2404 case QFrame::StyledPanel:
2405 //keep the compatibility with Qt 4.4 if there is a proxy style.
2406 //be sure to call drawPrimitive(QStyle::PE_Frame) on the proxy style
2407 if (widget) {
2408 widget->style()->drawPrimitive(pe: QStyle::PE_Frame, opt, p, w: widget);
2409 } else {
2410 proxy()->drawPrimitive(pe: QStyle::PE_Frame, opt, p, w: widget);
2411 }
2412 break;
2413 case QFrame::Panel:
2414 if (frameShadow == QFrame::Plain) {
2415 qDrawPlainRect(p, r: f->rect, f->palette.color(cr: foregroundRole), lineWidth: lw);
2416 } else {
2417 qDrawShadePanel(p, r: f->rect, pal: f->palette, sunken: frameShadow == QFrame::Sunken, lineWidth: lw);
2418 }
2419 break;
2420 case QFrame::WinPanel:
2421 if (frameShadow == QFrame::Plain) {
2422 qDrawPlainRect(p, r: f->rect, f->palette.color(cr: foregroundRole), lineWidth: lw);
2423 } else {
2424 qDrawWinPanel(p, r: f->rect, pal: f->palette, sunken: frameShadow == QFrame::Sunken);
2425 }
2426 break;
2427 case QFrame::HLine:
2428 case QFrame::VLine: {
2429 QPoint p1, p2;
2430 if (frameShape == QFrame::HLine) {
2431 p1 = QPoint(opt->rect.x(), opt->rect.y() + opt->rect.height() / 2);
2432 p2 = QPoint(opt->rect.x() + opt->rect.width(), p1.y());
2433 } else {
2434 p1 = QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y());
2435 p2 = QPoint(p1.x(), p1.y() + opt->rect.height());
2436 }
2437 if (frameShadow == QFrame::Plain) {
2438 QPen oldPen = p->pen();
2439 p->setPen(QPen(opt->palette.brush(cr: foregroundRole), lw));
2440 p->drawLine(p1, p2);
2441 p->setPen(oldPen);
2442 } else {
2443 qDrawShadeLine(p, p1, p2, pal: f->palette, sunken: frameShadow == QFrame::Sunken, lineWidth: lw, midLineWidth: mlw);
2444 }
2445 break;
2446 }
2447 }
2448 }
2449 break;
2450#endif
2451 default:
2452 break;
2453 }
2454#if !QT_CONFIG(tabbar) && !QT_CONFIG(itemviews)
2455 Q_UNUSED(d);
2456#endif
2457}
2458
2459/*!
2460 \reimp
2461*/
2462QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt,
2463 const QWidget *widget) const
2464{
2465 Q_D(const QCommonStyle);
2466 QRect r;
2467 switch (sr) {
2468 case SE_PushButtonContents:
2469 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2470 int dx1, dx2;
2471 dx1 = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: btn, widget);
2472 if (btn->features & QStyleOptionButton::AutoDefaultButton)
2473 dx1 += proxy()->pixelMetric(metric: PM_ButtonDefaultIndicator, option: btn, widget);
2474 dx2 = dx1 * 2;
2475 r.setRect(ax: opt->rect.x() + dx1, ay: opt->rect.y() + dx1, aw: opt->rect.width() - dx2,
2476 ah: opt->rect.height() - dx2);
2477 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2478 }
2479 break;
2480 case SE_PushButtonFocusRect:
2481 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2482 int dbw1 = 0, dbw2 = 0;
2483 if (btn->features & QStyleOptionButton::AutoDefaultButton){
2484 dbw1 = proxy()->pixelMetric(metric: PM_ButtonDefaultIndicator, option: btn, widget);
2485 dbw2 = dbw1 * 2;
2486 }
2487
2488 int dfw1 = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: btn, widget) + 1,
2489 dfw2 = dfw1 * 2;
2490
2491 r.setRect(ax: btn->rect.x() + dfw1 + dbw1, ay: btn->rect.y() + dfw1 + dbw1,
2492 aw: btn->rect.width() - dfw2 - dbw2, ah: btn->rect.height()- dfw2 - dbw2);
2493 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2494 }
2495 break;
2496 case SE_PushButtonBevel:
2497 {
2498 r = opt->rect;
2499 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2500 }
2501 break;
2502 case SE_CheckBoxIndicator:
2503 {
2504 int h = proxy()->pixelMetric(metric: PM_IndicatorHeight, option: opt, widget);
2505 r.setRect(ax: opt->rect.x(), ay: opt->rect.y() + ((opt->rect.height() - h) / 2),
2506 aw: proxy()->pixelMetric(metric: PM_IndicatorWidth, option: opt, widget), ah: h);
2507 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2508 }
2509 break;
2510
2511 case SE_CheckBoxContents:
2512 {
2513 // Deal with the logical first, then convert it back to screen coords.
2514 QRect ir = visualRect(direction: opt->direction, boundingRect: opt->rect,
2515 logicalRect: subElementRect(sr: SE_CheckBoxIndicator, opt, widget));
2516 int spacing = proxy()->pixelMetric(metric: PM_CheckBoxLabelSpacing, option: opt, widget);
2517 r.setRect(ax: ir.right() + spacing, ay: opt->rect.y(), aw: opt->rect.width() - ir.width() - spacing,
2518 ah: opt->rect.height());
2519 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2520 }
2521 break;
2522
2523 case SE_CheckBoxFocusRect:
2524 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2525 if (btn->icon.isNull() && btn->text.isEmpty()) {
2526 r = subElementRect(sr: SE_CheckBoxIndicator, opt, widget);
2527 r.adjust(dx1: 1, dy1: 1, dx2: -1, dy2: -1);
2528 break;
2529 }
2530 // As above, deal with the logical first, then convert it back to screen coords.
2531 QRect cr = visualRect(direction: btn->direction, boundingRect: btn->rect,
2532 logicalRect: subElementRect(sr: SE_CheckBoxContents, opt: btn, widget));
2533
2534 QRect iconRect, textRect;
2535 if (!btn->text.isEmpty()) {
2536 textRect = itemTextRect(fm: opt->fontMetrics, r: cr, flags: Qt::AlignAbsolute | Qt::AlignLeft
2537 | Qt::AlignVCenter | Qt::TextShowMnemonic,
2538 enabled: btn->state & State_Enabled, text: btn->text);
2539 }
2540 if (!btn->icon.isNull()) {
2541 iconRect = itemPixmapRect(r: cr, flags: Qt::AlignAbsolute | Qt::AlignLeft | Qt::AlignVCenter
2542 | Qt::TextShowMnemonic,
2543 pixmap: btn->icon.pixmap(size: btn->iconSize, devicePixelRatio: qt_getDevicePixelRatio(widget), mode: QIcon::Normal));
2544 if (!textRect.isEmpty())
2545 textRect.translate(dx: iconRect.right() + 4, dy: 0);
2546 }
2547 r = iconRect | textRect;
2548 r.adjust(dx1: -3, dy1: -2, dx2: 3, dy2: 2);
2549 r = r.intersected(other: btn->rect);
2550 r = visualRect(direction: btn->direction, boundingRect: btn->rect, logicalRect: r);
2551 }
2552 break;
2553
2554 case SE_RadioButtonIndicator:
2555 {
2556 int h = proxy()->pixelMetric(metric: PM_ExclusiveIndicatorHeight, option: opt, widget);
2557 r.setRect(ax: opt->rect.x(), ay: opt->rect.y() + ((opt->rect.height() - h) / 2),
2558 aw: proxy()->pixelMetric(metric: PM_ExclusiveIndicatorWidth, option: opt, widget), ah: h);
2559 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2560 }
2561 break;
2562
2563 case SE_RadioButtonContents:
2564 {
2565 QRect ir = visualRect(direction: opt->direction, boundingRect: opt->rect,
2566 logicalRect: subElementRect(sr: SE_RadioButtonIndicator, opt, widget));
2567 int spacing = proxy()->pixelMetric(metric: PM_RadioButtonLabelSpacing, option: opt, widget);
2568 r.setRect(ax: ir.left() + ir.width() + spacing, ay: opt->rect.y(), aw: opt->rect.width() - ir.width() - spacing,
2569 ah: opt->rect.height());
2570 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2571 break;
2572 }
2573
2574 case SE_RadioButtonFocusRect:
2575 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2576 if (btn->icon.isNull() && btn->text.isEmpty()) {
2577 r = subElementRect(sr: SE_RadioButtonIndicator, opt, widget);
2578 r.adjust(dx1: 1, dy1: 1, dx2: -1, dy2: -1);
2579 break;
2580 }
2581 QRect cr = visualRect(direction: btn->direction, boundingRect: btn->rect,
2582 logicalRect: subElementRect(sr: SE_RadioButtonContents, opt, widget));
2583
2584 QRect iconRect, textRect;
2585 if (!btn->text.isEmpty()){
2586 textRect = itemTextRect(fm: opt->fontMetrics, r: cr, flags: Qt::AlignAbsolute | Qt::AlignLeft | Qt::AlignVCenter
2587 | Qt::TextShowMnemonic, enabled: btn->state & State_Enabled, text: btn->text);
2588 }
2589 if (!btn->icon.isNull()) {
2590 iconRect = itemPixmapRect(r: cr, flags: Qt::AlignAbsolute | Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
2591 pixmap: btn->icon.pixmap(size: btn->iconSize, devicePixelRatio: qt_getDevicePixelRatio(widget), mode: QIcon::Normal));
2592 if (!textRect.isEmpty())
2593 textRect.translate(dx: iconRect.right() + 4, dy: 0);
2594 }
2595 r = iconRect | textRect;
2596 r.adjust(dx1: -3, dy1: -2, dx2: 3, dy2: 2);
2597 r = r.intersected(other: btn->rect);
2598 r = visualRect(direction: btn->direction, boundingRect: btn->rect, logicalRect: r);
2599 }
2600 break;
2601#if QT_CONFIG(slider)
2602 case SE_SliderFocusRect:
2603 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
2604 int tickOffset = proxy()->pixelMetric(metric: PM_SliderTickmarkOffset, option: slider, widget);
2605 int thickness = proxy()->pixelMetric(metric: PM_SliderControlThickness, option: slider, widget);
2606 if (slider->orientation == Qt::Horizontal)
2607 r.setRect(ax: 0, ay: tickOffset - 1, aw: slider->rect.width(), ah: thickness + 2);
2608 else
2609 r.setRect(ax: tickOffset - 1, ay: 0, aw: thickness + 2, ah: slider->rect.height());
2610 r = r.intersected(other: slider->rect);
2611 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2612 }
2613 break;
2614#endif // QT_CONFIG(slider)
2615#if QT_CONFIG(progressbar)
2616 case SE_ProgressBarGroove:
2617 case SE_ProgressBarContents:
2618 case SE_ProgressBarLabel:
2619 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
2620 int textw = 0;
2621 const bool vertical = !(pb->state & QStyle::State_Horizontal);
2622 if (!vertical) {
2623 if (pb->textVisible)
2624 textw = qMax(a: pb->fontMetrics.horizontalAdvance(pb->text), b: pb->fontMetrics.horizontalAdvance("100%"_L1)) + 6;
2625 }
2626
2627 if ((pb->textAlignment & Qt::AlignCenter) == 0) {
2628 if (sr != SE_ProgressBarLabel)
2629 r.setCoords(xp1: pb->rect.left(), yp1: pb->rect.top(),
2630 xp2: pb->rect.right() - textw, yp2: pb->rect.bottom());
2631 else
2632 r.setCoords(xp1: pb->rect.right() - textw, yp1: pb->rect.top(),
2633 xp2: pb->rect.right(), yp2: pb->rect.bottom());
2634 } else {
2635 r = pb->rect;
2636 }
2637 r = visualRect(direction: pb->direction, boundingRect: pb->rect, logicalRect: r);
2638 }
2639 break;
2640#endif // QT_CONFIG(progressbar)
2641#if QT_CONFIG(combobox)
2642 case SE_ComboBoxFocusRect:
2643 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
2644 int margin = cb->frame ? 3 : 0;
2645 r.setRect(ax: opt->rect.left() + margin, ay: opt->rect.top() + margin,
2646 aw: opt->rect.width() - 2*margin - 16, ah: opt->rect.height() - 2*margin);
2647 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2648 }
2649 break;
2650#endif // QT_CONFIG(combobox)
2651#if QT_CONFIG(toolbox)
2652 case SE_ToolBoxTabContents:
2653 r = opt->rect;
2654 r.adjust(dx1: 0, dy1: 0, dx2: -30, dy2: 0);
2655 break;
2656#endif // QT_CONFIG(toolbox)
2657 case SE_HeaderLabel: {
2658 int margin = proxy()->pixelMetric(metric: QStyle::PM_HeaderMargin, option: opt, widget);
2659 r.setRect(ax: opt->rect.x() + margin, ay: opt->rect.y() + margin,
2660 aw: opt->rect.width() - margin * 2, ah: opt->rect.height() - margin * 2);
2661
2662 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
2663 // Subtract width needed for arrow, if there is one
2664 if (header->sortIndicator != QStyleOptionHeader::None) {
2665 if (opt->state & State_Horizontal)
2666 r.setWidth(r.width() - (opt->rect.height() / 2) - (margin * 2));
2667 else
2668 r.setHeight(r.height() - (opt->rect.width() / 2) - (margin * 2));
2669 }
2670 }
2671 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2672 break; }
2673 case SE_HeaderArrow: {
2674 int h = opt->rect.height();
2675 int w = opt->rect.width();
2676 int x = opt->rect.x();
2677 int y = opt->rect.y();
2678 int margin = proxy()->pixelMetric(metric: QStyle::PM_HeaderMargin, option: opt, widget);
2679
2680 if (opt->state & State_Horizontal) {
2681 int horiz_size = h / 2;
2682 r.setRect(ax: x + w - margin * 2 - horiz_size, ay: y + 5,
2683 aw: horiz_size, ah: h - margin * 2 - 5);
2684 } else {
2685 int vert_size = w / 2;
2686 r.setRect(ax: x + 5, ay: y + h - margin * 2 - vert_size,
2687 aw: w - margin * 2 - 5, ah: vert_size);
2688 }
2689 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2690 break; }
2691
2692 case SE_RadioButtonClickRect:
2693 r = subElementRect(sr: SE_RadioButtonFocusRect, opt, widget);
2694 r |= subElementRect(sr: SE_RadioButtonIndicator, opt, widget);
2695 break;
2696 case SE_CheckBoxClickRect:
2697 r = subElementRect(sr: SE_CheckBoxFocusRect, opt, widget);
2698 r |= subElementRect(sr: SE_CheckBoxIndicator, opt, widget);
2699 break;
2700#if QT_CONFIG(tabwidget)
2701 case SE_TabWidgetTabBar:
2702 if (const QStyleOptionTabWidgetFrame *twf
2703 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
2704 r.setSize(twf->tabBarSize);
2705 const uint alingMask = Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter;
2706 switch (twf->shape) {
2707 case QTabBar::RoundedNorth:
2708 case QTabBar::TriangularNorth:
2709 // Constrain the size now, otherwise, center could get off the page
2710 // This of course repeated for all the other directions
2711 r.setWidth(qMin(a: r.width(), b: twf->rect.width()
2712 - twf->leftCornerWidgetSize.width()
2713 - twf->rightCornerWidgetSize.width()));
2714 switch (proxy()->styleHint(stylehint: SH_TabBar_Alignment, opt: twf, widget) & alingMask) {
2715 default:
2716 case Qt::AlignLeft:
2717 r.moveTopLeft(p: QPoint(twf->leftCornerWidgetSize.width(), 0));
2718 break;
2719 case Qt::AlignHCenter:
2720 r.moveTopLeft(p: QPoint(twf->rect.center().x() - qRound(f: r.width() / 2.0f)
2721 + (twf->leftCornerWidgetSize.width() / 2)
2722 - (twf->rightCornerWidgetSize.width() / 2), 0));
2723 break;
2724 case Qt::AlignRight:
2725 r.moveTopLeft(p: QPoint(twf->rect.width() - twf->tabBarSize.width()
2726 - twf->rightCornerWidgetSize.width(), 0));
2727 break;
2728 }
2729 r = visualRect(direction: twf->direction, boundingRect: twf->rect, logicalRect: r);
2730 break;
2731 case QTabBar::RoundedSouth:
2732 case QTabBar::TriangularSouth:
2733 r.setWidth(qMin(a: r.width(), b: twf->rect.width()
2734 - twf->leftCornerWidgetSize.width()
2735 - twf->rightCornerWidgetSize.width()));
2736 switch (proxy()->styleHint(stylehint: SH_TabBar_Alignment, opt: twf, widget) & alingMask) {
2737 default:
2738 case Qt::AlignLeft:
2739 r.moveTopLeft(p: QPoint(twf->leftCornerWidgetSize.width(),
2740 twf->rect.height() - twf->tabBarSize.height()));
2741 break;
2742 case Qt::AlignHCenter:
2743 r.moveTopLeft(p: QPoint(twf->rect.center().x() - qRound(f: r.width() / 2.0f)
2744 + (twf->leftCornerWidgetSize.width() / 2)
2745 - (twf->rightCornerWidgetSize.width() / 2),
2746 twf->rect.height() - twf->tabBarSize.height()));
2747 break;
2748 case Qt::AlignRight:
2749 r.moveTopLeft(p: QPoint(twf->rect.width() - twf->tabBarSize.width()
2750 - twf->rightCornerWidgetSize.width(),
2751 twf->rect.height() - twf->tabBarSize.height()));
2752 break;
2753 }
2754 r = visualRect(direction: twf->direction, boundingRect: twf->rect, logicalRect: r);
2755 break;
2756 case QTabBar::RoundedEast:
2757 case QTabBar::TriangularEast:
2758 r.setHeight(qMin(a: r.height(), b: twf->rect.height()
2759 - twf->leftCornerWidgetSize.height()
2760 - twf->rightCornerWidgetSize.height()));
2761 switch (proxy()->styleHint(stylehint: SH_TabBar_Alignment, opt: twf, widget) & alingMask) {
2762 default:
2763 case Qt::AlignLeft:
2764 r.moveTopLeft(p: QPoint(twf->rect.width() - twf->tabBarSize.width(),
2765 twf->leftCornerWidgetSize.height()));
2766 break;
2767 case Qt::AlignHCenter:
2768 r.moveTopLeft(p: QPoint(twf->rect.width() - twf->tabBarSize.width(),
2769 twf->rect.center().y() - r.height() / 2));
2770 break;
2771 case Qt::AlignRight:
2772 r.moveTopLeft(p: QPoint(twf->rect.width() - twf->tabBarSize.width(),
2773 twf->rect.height() - twf->tabBarSize.height()
2774 - twf->rightCornerWidgetSize.height()));
2775 break;
2776 }
2777 break;
2778 case QTabBar::RoundedWest:
2779 case QTabBar::TriangularWest:
2780 r.setHeight(qMin(a: r.height(), b: twf->rect.height()
2781 - twf->leftCornerWidgetSize.height()
2782 - twf->rightCornerWidgetSize.height()));
2783 switch (proxy()->styleHint(stylehint: SH_TabBar_Alignment, opt: twf, widget) & alingMask) {
2784 default:
2785 case Qt::AlignLeft:
2786 r.moveTopLeft(p: QPoint(0, twf->leftCornerWidgetSize.height()));
2787 break;
2788 case Qt::AlignHCenter:
2789 r.moveTopLeft(p: QPoint(0, twf->rect.center().y() - r.height() / 2));
2790 break;
2791 case Qt::AlignRight:
2792 r.moveTopLeft(p: QPoint(0, twf->rect.height() - twf->tabBarSize.height()
2793 - twf->rightCornerWidgetSize.height()));
2794 break;
2795 }
2796 break;
2797 }
2798 }
2799 break;
2800 case SE_TabWidgetTabPane:
2801 case SE_TabWidgetTabContents:
2802 if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
2803 QStyleOptionTab tabopt;
2804 tabopt.shape = twf->shape;
2805 int overlap = proxy()->pixelMetric(metric: PM_TabBarBaseOverlap, option: &tabopt, widget);
2806 if (twf->lineWidth == 0)
2807 overlap = 0;
2808 switch (twf->shape) {
2809 case QTabBar::RoundedNorth:
2810 case QTabBar::TriangularNorth:
2811 r = QRect(QPoint(0,qMax(a: twf->tabBarSize.height() - overlap, b: 0)),
2812 QSize(twf->rect.width(), qMin(a: twf->rect.height() - twf->tabBarSize.height() + overlap, b: twf->rect.height())));
2813 break;
2814 case QTabBar::RoundedSouth:
2815 case QTabBar::TriangularSouth:
2816 r = QRect(QPoint(0,0), QSize(twf->rect.width(), qMin(a: twf->rect.height() - twf->tabBarSize.height() + overlap, b: twf->rect.height())));
2817 break;
2818 case QTabBar::RoundedEast:
2819 case QTabBar::TriangularEast:
2820 r = QRect(QPoint(0, 0), QSize(qMin(a: twf->rect.width() - twf->tabBarSize.width() + overlap, b: twf->rect.width()), twf->rect.height()));
2821 break;
2822 case QTabBar::RoundedWest:
2823 case QTabBar::TriangularWest:
2824 r = QRect(QPoint(qMax(a: twf->tabBarSize.width() - overlap, b: 0), 0),
2825 QSize(qMin(a: twf->rect.width() - twf->tabBarSize.width() + overlap, b: twf->rect.width()), twf->rect.height()));
2826 break;
2827 }
2828 if (sr == SE_TabWidgetTabContents && twf->lineWidth > 0)
2829 r.adjust(dx1: 2, dy1: 2, dx2: -2, dy2: -2);
2830 }
2831 break;
2832 case SE_TabWidgetLeftCorner:
2833 if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
2834 QRect paneRect = subElementRect(sr: SE_TabWidgetTabPane, opt: twf, widget);
2835 switch (twf->shape) {
2836 case QTabBar::RoundedNorth:
2837 case QTabBar::TriangularNorth:
2838 r = QRect(QPoint(paneRect.x(), paneRect.y() - twf->leftCornerWidgetSize.height()),
2839 twf->leftCornerWidgetSize);
2840 break;
2841 case QTabBar::RoundedSouth:
2842 case QTabBar::TriangularSouth:
2843 r = QRect(QPoint(paneRect.x(), paneRect.height()), twf->leftCornerWidgetSize);
2844 break;
2845 default:
2846 break;
2847 }
2848 r = visualRect(direction: twf->direction, boundingRect: twf->rect, logicalRect: r);
2849 }
2850 break;
2851 case SE_TabWidgetRightCorner:
2852 if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
2853 QRect paneRect = subElementRect(sr: SE_TabWidgetTabPane, opt: twf, widget);
2854 switch (twf->shape) {
2855 case QTabBar::RoundedNorth:
2856 case QTabBar::TriangularNorth:
2857 r = QRect(QPoint(paneRect.width() - twf->rightCornerWidgetSize.width(),
2858 paneRect.y() - twf->rightCornerWidgetSize.height()),
2859 twf->rightCornerWidgetSize);
2860 break;
2861 case QTabBar::RoundedSouth:
2862 case QTabBar::TriangularSouth:
2863 r = QRect(QPoint(paneRect.width() - twf->rightCornerWidgetSize.width(),
2864 paneRect.height()), twf->rightCornerWidgetSize);
2865 break;
2866 default:
2867 break;
2868 }
2869 r = visualRect(direction: twf->direction, boundingRect: twf->rect, logicalRect: r);
2870 }
2871 break;
2872 case SE_TabBarTabText:
2873 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
2874 QRect dummyIconRect;
2875 d->tabLayout(opt: tab, widget, textRect: &r, iconRect: &dummyIconRect);
2876 }
2877 break;
2878 case SE_TabBarTabLeftButton:
2879 case SE_TabBarTabRightButton:
2880 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
2881 bool selected = tab->state & State_Selected;
2882 int verticalShift = proxy()->pixelMetric(metric: QStyle::PM_TabBarTabShiftVertical, option: tab, widget);
2883 int horizontalShift = proxy()->pixelMetric(metric: QStyle::PM_TabBarTabShiftHorizontal, option: tab, widget);
2884 int hpadding = proxy()->pixelMetric(metric: QStyle::PM_TabBarTabHSpace, option: opt, widget) / 2;
2885 hpadding = qMax(a: hpadding, b: 4); //workaround KStyle returning 0 because they workaround an old bug in Qt
2886
2887 bool verticalTabs = tab->shape == QTabBar::RoundedEast
2888 || tab->shape == QTabBar::RoundedWest
2889 || tab->shape == QTabBar::TriangularEast
2890 || tab->shape == QTabBar::TriangularWest;
2891
2892 QRect tr = tab->rect;
2893 if (tab->shape == QTabBar::RoundedSouth || tab->shape == QTabBar::TriangularSouth)
2894 verticalShift = -verticalShift;
2895 if (verticalTabs) {
2896 qSwap(value1&: horizontalShift, value2&: verticalShift);
2897 horizontalShift *= -1;
2898 verticalShift *= -1;
2899 }
2900 if (tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularWest)
2901 horizontalShift = -horizontalShift;
2902
2903 tr.adjust(dx1: 0, dy1: 0, dx2: horizontalShift, dy2: verticalShift);
2904 if (selected)
2905 {
2906 tr.setBottom(tr.bottom() - verticalShift);
2907 tr.setRight(tr.right() - horizontalShift);
2908 }
2909
2910 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
2911 int w = size.width();
2912 int h = size.height();
2913 int midHeight = static_cast<int>(qCeil(v: float(tr.height() - h) / 2));
2914 int midWidth = ((tr.width() - w) / 2);
2915
2916 bool atTheTop = true;
2917 switch (tab->shape) {
2918 case QTabBar::RoundedWest:
2919 case QTabBar::TriangularWest:
2920 atTheTop = (sr == SE_TabBarTabLeftButton);
2921 break;
2922 case QTabBar::RoundedEast:
2923 case QTabBar::TriangularEast:
2924 atTheTop = (sr == SE_TabBarTabRightButton);
2925 break;
2926 default:
2927 if (sr == SE_TabBarTabLeftButton)
2928 r = QRect(tab->rect.x() + hpadding, midHeight, w, h);
2929 else
2930 r = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
2931 r = visualRect(direction: tab->direction, boundingRect: tab->rect, logicalRect: r);
2932 }
2933 if (verticalTabs) {
2934 if (atTheTop)
2935 r = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
2936 else
2937 r = QRect(midWidth, tr.y() + hpadding, w, h);
2938 }
2939 }
2940
2941 break;
2942#endif // QT_CONFIG(tabwidget)
2943#if QT_CONFIG(tabbar)
2944 case SE_TabBarTearIndicator:
2945 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
2946 switch (tab->shape) {
2947 case QTabBar::RoundedNorth:
2948 case QTabBar::TriangularNorth:
2949 case QTabBar::RoundedSouth:
2950 case QTabBar::TriangularSouth:
2951 r.setRect(ax: tab->rect.left(), ay: tab->rect.top(), aw: 8, ah: opt->rect.height());
2952 break;
2953 case QTabBar::RoundedWest:
2954 case QTabBar::TriangularWest:
2955 case QTabBar::RoundedEast:
2956 case QTabBar::TriangularEast:
2957 r.setRect(ax: tab->rect.left(), ay: tab->rect.top(), aw: opt->rect.width(), ah: 8);
2958 break;
2959 default:
2960 break;
2961 }
2962 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2963 }
2964 break;
2965 case SE_TabBarScrollLeftButton: {
2966 const bool vertical = opt->rect.width() < opt->rect.height();
2967 const Qt::LayoutDirection ld = widget->layoutDirection();
2968 const int buttonWidth = proxy()->pixelMetric(metric: QStyle::PM_TabBarScrollButtonWidth, option: nullptr, widget);
2969 const int buttonOverlap = proxy()->pixelMetric(metric: QStyle::PM_TabBar_ScrollButtonOverlap, option: nullptr, widget);
2970
2971 r = vertical ? QRect(0, opt->rect.height() - (buttonWidth * 2) + buttonOverlap, opt->rect.width(), buttonWidth)
2972 : QStyle::visualRect(direction: ld, boundingRect: opt->rect, logicalRect: QRect(opt->rect.width() - (buttonWidth * 2) + buttonOverlap, 0, buttonWidth, opt->rect.height()));
2973 break; }
2974 case SE_TabBarScrollRightButton: {
2975 const bool vertical = opt->rect.width() < opt->rect.height();
2976 const Qt::LayoutDirection ld = widget->layoutDirection();
2977 const int buttonWidth = proxy()->pixelMetric(metric: QStyle::PM_TabBarScrollButtonWidth, option: nullptr, widget);
2978
2979 r = vertical ? QRect(0, opt->rect.height() - buttonWidth, opt->rect.width(), buttonWidth)
2980 : QStyle::visualRect(direction: ld, boundingRect: opt->rect, logicalRect: QRect(opt->rect.width() - buttonWidth, 0, buttonWidth, opt->rect.height()));
2981 break; }
2982#endif
2983 case SE_TreeViewDisclosureItem:
2984 r = opt->rect;
2985 break;
2986 case SE_LineEditContents:
2987 if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2988 r = f->rect.adjusted(xp1: f->lineWidth, yp1: f->lineWidth, xp2: -f->lineWidth, yp2: -f->lineWidth);
2989 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2990 }
2991 break;
2992 case SE_FrameContents:
2993 if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2994 int fw = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: f, widget);
2995 r = opt->rect.adjusted(xp1: fw, yp1: fw, xp2: -fw, yp2: -fw);
2996 r = visualRect(direction: opt->direction, boundingRect: opt->rect, logicalRect: r);
2997 }
2998 break;
2999 case SE_ShapedFrameContents:
3000 if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3001 int frameShape = f->frameShape;
3002 int frameShadow = QFrame::Plain;
3003 if (f->state & QStyle::State_Sunken) {
3004 frameShadow = QFrame::Sunken;
3005 } else if (f->state & QStyle::State_Raised) {
3006 frameShadow = QFrame::Raised;
3007 }
3008
3009 int frameWidth = 0;
3010
3011 switch (frameShape) {
3012 case QFrame::NoFrame:
3013 frameWidth = 0;
3014 break;
3015
3016 case QFrame::Box:
3017 case QFrame::HLine:
3018 case QFrame::VLine:
3019 switch (frameShadow) {
3020 case QFrame::Plain:
3021 frameWidth = f->lineWidth;
3022 break;
3023 case QFrame::Raised:
3024 case QFrame::Sunken:
3025 frameWidth = (short)(f->lineWidth*2 + f->midLineWidth);
3026 break;
3027 }
3028 break;
3029
3030 case QFrame::StyledPanel:
3031 //keep the compatibility with Qt 4.4 if there is a proxy style.
3032 //be sure to call drawPrimitive(QStyle::SE_FrameContents) on the proxy style
3033 if (widget)
3034 return widget->style()->subElementRect(subElement: QStyle::SE_FrameContents, option: opt, widget);
3035 else
3036 return subElementRect(sr: QStyle::SE_FrameContents, opt, widget);
3037
3038 case QFrame::WinPanel:
3039 frameWidth = 2;
3040 break;
3041
3042 case QFrame::Panel:
3043 switch (frameShadow) {
3044 case QFrame::Plain:
3045 case QFrame::Raised:
3046 case QFrame::Sunken:
3047 frameWidth = f->lineWidth;
3048 break;
3049 }
3050 break;
3051 }
3052 r = f->rect.adjusted(xp1: frameWidth, yp1: frameWidth, xp2: -frameWidth, yp2: -frameWidth);
3053 }
3054 break;
3055#if QT_CONFIG(dockwidget)
3056 case SE_DockWidgetCloseButton:
3057 case SE_DockWidgetFloatButton:
3058 case SE_DockWidgetTitleBarText:
3059 case SE_DockWidgetIcon: {
3060 int iconSize = proxy()->pixelMetric(metric: PM_SmallIconSize, option: opt, widget);
3061 int buttonMargin = proxy()->pixelMetric(metric: PM_DockWidgetTitleBarButtonMargin, option: opt, widget);
3062 int margin = proxy()->pixelMetric(metric: QStyle::PM_DockWidgetTitleMargin, option: opt, widget);
3063 QRect rect = opt->rect;
3064
3065 const QStyleOptionDockWidget *dwOpt
3066 = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
3067 bool canClose = dwOpt == nullptr ? true : dwOpt->closable;
3068 bool canFloat = dwOpt == nullptr ? false : dwOpt->floatable;
3069
3070 const bool verticalTitleBar = dwOpt && dwOpt->verticalTitleBar;
3071
3072 // If this is a vertical titlebar, we transpose and work as if it was
3073 // horizontal, then transpose again.
3074
3075 if (verticalTitleBar)
3076 rect = rect.transposed();
3077
3078 do {
3079
3080 int right = rect.right();
3081 int left = rect.left();
3082
3083 QRect closeRect;
3084 if (canClose) {
3085 QSize sz = proxy()->standardIcon(standardIcon: QStyle::SP_TitleBarCloseButton,
3086 option: opt, widget).actualSize(size: QSize(iconSize, iconSize));
3087 sz += QSize(buttonMargin, buttonMargin);
3088 if (verticalTitleBar)
3089 sz = sz.transposed();
3090 closeRect = QRect(right - sz.width(),
3091 rect.center().y() - sz.height()/2,
3092 sz.width(), sz.height());
3093 right = closeRect.left() - 1;
3094 }
3095 if (sr == SE_DockWidgetCloseButton) {
3096 r = closeRect;
3097 break;
3098 }
3099
3100 QRect floatRect;
3101 if (canFloat) {
3102 QSize sz = proxy()->standardIcon(standardIcon: QStyle::SP_TitleBarNormalButton,
3103 option: opt, widget).actualSize(size: QSize(iconSize, iconSize));
3104 sz += QSize(buttonMargin, buttonMargin);
3105 if (verticalTitleBar)
3106 sz = sz.transposed();
3107 floatRect = QRect(right - sz.width(),
3108 rect.center().y() - sz.height()/2,
3109 sz.width(), sz.height());
3110 right = floatRect.left() - 1;
3111 }
3112 if (sr == SE_DockWidgetFloatButton) {
3113 r = floatRect;
3114 break;
3115 }
3116
3117 QRect iconRect;
3118 if (const QDockWidget *dw = qobject_cast<const QDockWidget*>(object: widget)) {
3119 QIcon icon;
3120 if (dw->isFloating())
3121 icon = dw->windowIcon();
3122 if (!icon.isNull()
3123 && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
3124 QSize sz = icon.actualSize(size: QSize(r.height(), r.height()));
3125 if (verticalTitleBar)
3126 sz = sz.transposed();
3127 iconRect = QRect(left, rect.center().y() - sz.height()/2,
3128 sz.width(), sz.height());
3129 left = iconRect.right() + margin;
3130 }
3131 }
3132 if (sr == SE_DockWidgetIcon) {
3133 r = iconRect;
3134 break;
3135 }
3136
3137 QRect textRect = QRect(left, rect.top(),
3138 right - left, rect.height());
3139 if (sr == SE_DockWidgetTitleBarText) {
3140 r = textRect;
3141 break;
3142 }
3143
3144 } while (false);
3145
3146 if (verticalTitleBar) {
3147 r = QRect(rect.left() + r.top() - rect.top(),
3148 rect.top() + rect.right() - r.right(),
3149 r.height(), r.width());
3150 } else {
3151 r = visualRect(direction: opt->direction, boundingRect: rect, logicalRect: r);
3152 }
3153 break;
3154 }
3155#endif
3156#if QT_CONFIG(itemviews)
3157 case SE_ItemViewItemCheckIndicator:
3158 if (!qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
3159 r = subElementRect(sr: SE_CheckBoxIndicator, opt, widget);
3160 break;
3161 }
3162 Q_FALLTHROUGH();
3163 case SE_ItemViewItemDecoration:
3164 case SE_ItemViewItemText:
3165 case SE_ItemViewItemFocusRect:
3166 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
3167 if (!d->isViewItemCached(option: *vopt)) {
3168 d->viewItemLayout(opt: vopt, checkRect: &d->checkRect, pixmapRect: &d->decorationRect, textRect: &d->displayRect, sizehint: false);
3169 if (d->cachedOption) {
3170 delete d->cachedOption;
3171 d->cachedOption = nullptr;
3172 }
3173 d->cachedOption = new QStyleOptionViewItem(*vopt);
3174 }
3175 if (sr == SE_ItemViewItemCheckIndicator)
3176 r = d->checkRect;
3177 else if (sr == SE_ItemViewItemDecoration)
3178 r = d->decorationRect;
3179 else if (sr == SE_ItemViewItemText || sr == SE_ItemViewItemFocusRect)
3180 r = d->displayRect;
3181 }
3182 break;
3183#endif // QT_CONFIG(itemviews)
3184#if QT_CONFIG(toolbar)
3185 case SE_ToolBarHandle:
3186 if (const QStyleOptionToolBar *tbopt = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
3187 if (tbopt->features & QStyleOptionToolBar::Movable) {
3188 ///we need to access the widget here because the style option doesn't
3189 //have all the information we need (ie. the layout's margin)
3190 const QToolBar *tb = qobject_cast<const QToolBar*>(object: widget);
3191 const QMargins margins = tb && tb->layout() ? tb->layout()->contentsMargins() : QMargins(2, 2, 2, 2);
3192 const int handleExtent = proxy()->pixelMetric(metric: QStyle::PM_ToolBarHandleExtent, option: opt, widget: tb);
3193 if (tbopt->state & QStyle::State_Horizontal) {
3194 r = QRect(margins.left(), margins.top(),
3195 handleExtent,
3196 tbopt->rect.height() - (margins.top() + margins.bottom()));
3197 r = QStyle::visualRect(direction: tbopt->direction, boundingRect: tbopt->rect, logicalRect: r);
3198 } else {
3199 r = QRect(margins.left(), margins.top(),
3200 tbopt->rect.width() - (margins.left() + margins.right()),
3201 handleExtent);
3202 }
3203 }
3204 }
3205 break;
3206#endif // QT_CONFIG(toolbar)
3207 default:
3208 break;
3209 }
3210 return r;
3211#if !QT_CONFIG(tabwidget) && !QT_CONFIG(itemviews)
3212 Q_UNUSED(d);
3213#endif
3214}
3215
3216#if QT_CONFIG(dial)
3217
3218// in lieu of std::array, minimal API
3219template <int N>
3220struct StaticPolygonF
3221{
3222 QPointF data[N];
3223
3224 constexpr int size() const { return N; }
3225 constexpr const QPointF *cbegin() const { return data; }
3226 constexpr const QPointF &operator[](int idx) const { return data[idx]; }
3227};
3228
3229static StaticPolygonF<3> calcArrow(const QStyleOptionSlider *dial, qreal &a)
3230{
3231 int width = dial->rect.width();
3232 int height = dial->rect.height();
3233 int r = qMin(a: width, b: height) / 2;
3234 int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition);
3235
3236 if (dial->maximum == dial->minimum)
3237 a = Q_PI / 2;
3238 else if (dial->dialWrapping)
3239 a = Q_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Q_PI
3240 / (dial->maximum - dial->minimum);
3241 else
3242 a = (Q_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * Q_PI
3243 / (dial->maximum - dial->minimum)) / 6;
3244
3245 int xc = width / 2 + dial->rect.left();
3246 int yc = height / 2 + dial->rect.top();
3247
3248 int len = r - QStyleHelper::calcBigLineSize(radius: r) - 5;
3249 if (len < 5)
3250 len = 5;
3251 int back = len / 2;
3252
3253 StaticPolygonF<3> arrow = {.data: {
3254 QPointF(0.5 + xc + len * qCos(v: a),
3255 0.5 + yc - len * qSin(v: a)),
3256 QPointF(0.5 + xc + back * qCos(v: a + Q_PI * 5 / 6),
3257 0.5 + yc - back * qSin(v: a + Q_PI * 5 / 6)),
3258 QPointF(0.5 + xc + back * qCos(v: a - Q_PI * 5 / 6),
3259 0.5 + yc - back * qSin(v: a - Q_PI * 5 / 6)),
3260 }};
3261 return arrow;
3262}
3263
3264#endif // QT_CONFIG(dial)
3265
3266/*!
3267 \reimp
3268*/
3269void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
3270 QPainter *p, const QWidget *widget) const
3271{
3272 switch (cc) {
3273#if QT_CONFIG(slider)
3274 case CC_Slider:
3275 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3276 if (slider->subControls == SC_SliderTickmarks) {
3277 int tickOffset = proxy()->pixelMetric(metric: PM_SliderTickmarkOffset, option: slider, widget);
3278 int ticks = slider->tickPosition;
3279 int thickness = proxy()->pixelMetric(metric: PM_SliderControlThickness, option: slider, widget);
3280 int len = proxy()->pixelMetric(metric: PM_SliderLength, option: slider, widget);
3281 int available = proxy()->pixelMetric(metric: PM_SliderSpaceAvailable, option: slider, widget);
3282 int interval = slider->tickInterval;
3283 if (interval <= 0) {
3284 interval = slider->singleStep;
3285 if (QStyle::sliderPositionFromValue(min: slider->minimum, max: slider->maximum, val: interval,
3286 space: available)
3287 - QStyle::sliderPositionFromValue(min: slider->minimum, max: slider->maximum,
3288 val: 0, space: available) < 3)
3289 interval = slider->pageStep;
3290 }
3291 if (!interval)
3292 interval = 1;
3293 int fudge = len / 2;
3294 int pos;
3295 // Since there is no subrect for tickmarks do a translation here.
3296 QPainterStateSaver pss(p);
3297 p->translate(dx: slider->rect.x(), dy: slider->rect.y());
3298 p->setPen(slider->palette.windowText().color());
3299 int v = slider->minimum;
3300 while (v <= slider->maximum + 1) {
3301 if (v == slider->maximum + 1 && interval == 1)
3302 break;
3303 const int v_ = qMin(a: v, b: slider->maximum);
3304 pos = QStyle::sliderPositionFromValue(min: slider->minimum, max: slider->maximum,
3305 val: v_, space: available) + fudge;
3306 if (slider->orientation == Qt::Horizontal) {
3307 if (ticks & QSlider::TicksAbove)
3308 p->drawLine(x1: pos, y1: 0, x2: pos, y2: tickOffset - 2);
3309 if (ticks & QSlider::TicksBelow)
3310 p->drawLine(x1: pos, y1: tickOffset + thickness + 1, x2: pos,
3311 y2: slider->rect.height()-1);
3312 } else {
3313 if (ticks & QSlider::TicksAbove)
3314 p->drawLine(x1: 0, y1: pos, x2: tickOffset - 2, y2: pos);
3315 if (ticks & QSlider::TicksBelow)
3316 p->drawLine(x1: tickOffset + thickness + 1, y1: pos,
3317 x2: slider->rect.width()-1, y2: pos);
3318 }
3319 // in the case where maximum is max int
3320 int nextInterval = v + interval;
3321 if (nextInterval < v)
3322 break;
3323 v = nextInterval;
3324 }
3325 }
3326 }
3327 break;
3328#endif // QT_CONFIG(slider)
3329#if QT_CONFIG(scrollbar)
3330 case CC_ScrollBar:
3331 if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3332 // Make a copy here and reset it for each primitive.
3333 QStyleOptionSlider newScrollbar = *scrollbar;
3334 State saveFlags = scrollbar->state;
3335
3336 if (scrollbar->subControls & SC_ScrollBarSubLine) {
3337 newScrollbar.state = saveFlags;
3338 newScrollbar.rect = proxy()->subControlRect(cc, opt: &newScrollbar, sc: SC_ScrollBarSubLine, widget);
3339 if (newScrollbar.rect.isValid()) {
3340 if (!(scrollbar->activeSubControls & SC_ScrollBarSubLine))
3341 newScrollbar.state &= ~(State_Sunken | State_MouseOver);
3342 proxy()->drawControl(element: CE_ScrollBarSubLine, opt: &newScrollbar, p, w: widget);
3343 }
3344 }
3345 if (scrollbar->subControls & SC_ScrollBarAddLine) {
3346 newScrollbar.rect = scrollbar->rect;
3347 newScrollbar.state = saveFlags;
3348 newScrollbar.rect = proxy()->subControlRect(cc, opt: &newScrollbar, sc: SC_ScrollBarAddLine, widget);
3349 if (newScrollbar.rect.isValid()) {
3350 if (!(scrollbar->activeSubControls & SC_ScrollBarAddLine))
3351 newScrollbar.state &= ~(State_Sunken | State_MouseOver);
3352 proxy()->drawControl(element: CE_ScrollBarAddLine, opt: &newScrollbar, p, w: widget);
3353 }
3354 }
3355 if (scrollbar->subControls & SC_ScrollBarSubPage) {
3356 newScrollbar.rect = scrollbar->rect;
3357 newScrollbar.state = saveFlags;
3358 newScrollbar.rect = proxy()->subControlRect(cc, opt: &newScrollbar, sc: SC_ScrollBarSubPage, widget);
3359 if (newScrollbar.rect.isValid()) {
3360 if (!(scrollbar->activeSubControls & SC_ScrollBarSubPage))
3361 newScrollbar.state &= ~(State_Sunken | State_MouseOver);
3362 proxy()->drawControl(element: CE_ScrollBarSubPage, opt: &newScrollbar, p, w: widget);
3363 }
3364 }
3365 if (scrollbar->subControls & SC_ScrollBarAddPage) {
3366 newScrollbar.rect = scrollbar->rect;
3367 newScrollbar.state = saveFlags;
3368 newScrollbar.rect = proxy()->subControlRect(cc, opt: &newScrollbar, sc: SC_ScrollBarAddPage, widget);
3369 if (newScrollbar.rect.isValid()) {
3370 if (!(scrollbar->activeSubControls & SC_ScrollBarAddPage))
3371 newScrollbar.state &= ~(State_Sunken | State_MouseOver);
3372 proxy()->drawControl(element: CE_ScrollBarAddPage, opt: &newScrollbar, p, w: widget);
3373 }
3374 }
3375 if (scrollbar->subControls & SC_ScrollBarFirst) {
3376 newScrollbar.rect = scrollbar->rect;
3377 newScrollbar.state = saveFlags;
3378 newScrollbar.rect = proxy()->subControlRect(cc, opt: &newScrollbar, sc: SC_ScrollBarFirst, widget);
3379 if (newScrollbar.rect.isValid()) {
3380 if (!(scrollbar->activeSubControls & SC_ScrollBarFirst))
3381 newScrollbar.state &= ~(State_Sunken | State_MouseOver);
3382 proxy()->drawControl(element: CE_ScrollBarFirst, opt: &newScrollbar, p, w: widget);
3383 }
3384 }
3385 if (scrollbar->subControls & SC_ScrollBarLast) {
3386 newScrollbar.rect = scrollbar->rect;
3387 newScrollbar.state = saveFlags;
3388 newScrollbar.rect = proxy()->subControlRect(cc, opt: &newScrollbar, sc: SC_ScrollBarLast, widget);
3389 if (newScrollbar.rect.isValid()) {
3390 if (!(scrollbar->activeSubControls & SC_ScrollBarLast))
3391 newScrollbar.state &= ~(State_Sunken | State_MouseOver);
3392 proxy()->drawControl(element: CE_ScrollBarLast, opt: &newScrollbar, p, w: widget);
3393 }
3394 }
3395 if (scrollbar->subControls & SC_ScrollBarSlider) {
3396 newScrollbar.rect = scrollbar->rect;
3397 newScrollbar.state = saveFlags;
3398 newScrollbar.rect = proxy()->subControlRect(cc, opt: &newScrollbar, sc: SC_ScrollBarSlider, widget);
3399 if (newScrollbar.rect.isValid()) {
3400 if (!(scrollbar->activeSubControls & SC_ScrollBarSlider))
3401 newScrollbar.state &= ~(State_Sunken | State_MouseOver);
3402 proxy()->drawControl(element: CE_ScrollBarSlider, opt: &newScrollbar, p, w: widget);
3403
3404 if (scrollbar->state & State_HasFocus) {
3405 QStyleOptionFocusRect fropt;
3406 fropt.QStyleOption::operator=(other: newScrollbar);
3407 fropt.rect.setRect(ax: newScrollbar.rect.x() + 2, ay: newScrollbar.rect.y() + 2,
3408 aw: newScrollbar.rect.width() - 5,
3409 ah: newScrollbar.rect.height() - 5);
3410 proxy()->drawPrimitive(pe: PE_FrameFocusRect, opt: &fropt, p, w: widget);
3411 }
3412 }
3413 }
3414 }
3415 break;
3416#endif // QT_CONFIG(scrollbar)
3417#if QT_CONFIG(spinbox)
3418 case CC_SpinBox:
3419 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
3420 QStyleOptionSpinBox copy = *sb;
3421 PrimitiveElement pe;
3422
3423 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
3424 QRect r = proxy()->subControlRect(cc: CC_SpinBox, opt: sb, sc: SC_SpinBoxFrame, widget);
3425 qDrawWinPanel(p, r, pal: sb->palette, sunken: true);
3426 }
3427
3428 if (sb->subControls & SC_SpinBoxUp) {
3429 copy.subControls = SC_SpinBoxUp;
3430 QPalette pal2 = sb->palette;
3431 if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled)) {
3432 pal2.setCurrentColorGroup(QPalette::Disabled);
3433 copy.state &= ~State_Enabled;
3434 }
3435
3436 copy.palette = pal2;
3437
3438 if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken)) {
3439 copy.state |= State_On;
3440 copy.state |= State_Sunken;
3441 } else {
3442 copy.state |= State_Raised;
3443 copy.state &= ~State_Sunken;
3444 }
3445 pe = (sb->buttonSymbols == QAbstractSpinBox::PlusMinus ? PE_IndicatorSpinPlus
3446 : PE_IndicatorSpinUp);
3447
3448 copy.rect = proxy()->subControlRect(cc: CC_SpinBox, opt: sb, sc: SC_SpinBoxUp, widget);
3449 proxy()->drawPrimitive(pe: PE_PanelButtonBevel, opt: &copy, p, w: widget);
3450 copy.rect.adjust(dx1: 3, dy1: 0, dx2: -4, dy2: 0);
3451 proxy()->drawPrimitive(pe, opt: &copy, p, w: widget);
3452 }
3453
3454 if (sb->subControls & SC_SpinBoxDown) {
3455 copy.subControls = SC_SpinBoxDown;
3456 copy.state = sb->state;
3457 QPalette pal2 = sb->palette;
3458 if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled)) {
3459 pal2.setCurrentColorGroup(QPalette::Disabled);
3460 copy.state &= ~State_Enabled;
3461 }
3462 copy.palette = pal2;
3463
3464 if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken)) {
3465 copy.state |= State_On;
3466 copy.state |= State_Sunken;
3467 } else {
3468 copy.state |= State_Raised;
3469 copy.state &= ~State_Sunken;
3470 }
3471 pe = (sb->buttonSymbols == QAbstractSpinBox::PlusMinus ? PE_IndicatorSpinMinus
3472 : PE_IndicatorSpinDown);
3473
3474 copy.rect = proxy()->subControlRect(cc: CC_SpinBox, opt: sb, sc: SC_SpinBoxDown, widget);
3475 proxy()->drawPrimitive(pe: PE_PanelButtonBevel, opt: &copy, p, w: widget);
3476 copy.rect.adjust(dx1: 3, dy1: 0, dx2: -4, dy2: 0);
3477 proxy()->drawPrimitive(pe, opt: &copy, p, w: widget);
3478 }
3479 }
3480 break;
3481#endif // QT_CONFIG(spinbox)
3482#if QT_CONFIG(toolbutton)
3483 case CC_ToolButton:
3484 if (const QStyleOptionToolButton *toolbutton
3485 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3486 QRect button, menuarea;
3487 button = proxy()->subControlRect(cc, opt: toolbutton, sc: SC_ToolButton, widget);
3488 menuarea = proxy()->subControlRect(cc, opt: toolbutton, sc: SC_ToolButtonMenu, widget);
3489
3490 State bflags = toolbutton->state & ~State_Sunken;
3491
3492 if (bflags & State_AutoRaise) {
3493 if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) {
3494 bflags &= ~State_Raised;
3495 }
3496 }
3497 State mflags = bflags;
3498 if (toolbutton->state & State_Sunken) {
3499 if (toolbutton->activeSubControls & SC_ToolButton)
3500 bflags |= State_Sunken;
3501 mflags |= State_Sunken;
3502 }
3503
3504 QStyleOption tool = *toolbutton;
3505 if (toolbutton->subControls & SC_ToolButton) {
3506 if (bflags & (State_Sunken | State_On | State_Raised)) {
3507 tool.rect = button;
3508 tool.state = bflags;
3509 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3510 }
3511 }
3512
3513 if (toolbutton->state & State_HasFocus) {
3514 QStyleOptionFocusRect fr;
3515 fr.QStyleOption::operator=(other: *toolbutton);
3516 fr.rect.adjust(dx1: 3, dy1: 3, dx2: -3, dy2: -3);
3517 if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
3518 fr.rect.adjust(dx1: 0, dy1: 0, dx2: -proxy()->pixelMetric(metric: QStyle::PM_MenuButtonIndicator,
3519 option: toolbutton, widget), dy2: 0);
3520 proxy()->drawPrimitive(pe: PE_FrameFocusRect, opt: &fr, p, w: widget);
3521 }
3522 QStyleOptionToolButton label = *toolbutton;
3523 label.state = bflags;
3524 int fw = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: opt, widget);
3525 label.rect = button.adjusted(xp1: fw, yp1: fw, xp2: -fw, yp2: -fw);
3526 proxy()->drawControl(element: CE_ToolButtonLabel, opt: &label, p, w: widget);
3527
3528 if (toolbutton->subControls & SC_ToolButtonMenu) {
3529 tool.rect = menuarea;
3530 tool.state = mflags;
3531 if (mflags & (State_Sunken | State_On | State_Raised))
3532 proxy()->drawPrimitive(pe: PE_IndicatorButtonDropDown, opt: &tool, p, w: widget);
3533 proxy()->drawPrimitive(pe: PE_IndicatorArrowDown, opt: &tool, p, w: widget);
3534 } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
3535 int mbi = proxy()->pixelMetric(metric: PM_MenuButtonIndicator, option: toolbutton, widget);
3536 QRect ir = toolbutton->rect;
3537 QStyleOptionToolButton newBtn = *toolbutton;
3538 newBtn.rect = QRect(ir.right() + 5 - mbi, ir.y() + ir.height() - mbi + 4, mbi - 6, mbi - 6);
3539 newBtn.rect = visualRect(direction: toolbutton->direction, boundingRect: button, logicalRect: newBtn.rect);
3540 proxy()->drawPrimitive(pe: PE_IndicatorArrowDown, opt: &newBtn, p, w: widget);
3541 }
3542 }
3543 break;
3544#endif // QT_CONFIG(toolbutton)
3545 case CC_TitleBar:
3546 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
3547 QRect ir;
3548 if (opt->subControls & SC_TitleBarLabel) {
3549 QColor left = tb->palette.highlight().color();
3550 QColor right = tb->palette.base().color();
3551
3552 QBrush fillBrush(left);
3553 if (left != right) {
3554 QPoint p1(tb->rect.x(), tb->rect.top() + tb->rect.height()/2);
3555 QPoint p2(tb->rect.right(), tb->rect.top() + tb->rect.height()/2);
3556 QLinearGradient lg(p1, p2);
3557 lg.setColorAt(pos: 0, color: left);
3558 lg.setColorAt(pos: 1, color: right);
3559 fillBrush = lg;
3560 }
3561
3562 p->fillRect(opt->rect, fillBrush);
3563
3564 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarLabel, widget);
3565
3566 p->setPen(tb->palette.highlightedText().color());
3567 p->drawText(x: ir.x() + 2, y: ir.y(), w: ir.width() - 2, h: ir.height(),
3568 flags: Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, str: tb->text);
3569 }
3570
3571 bool down = false;
3572 QPixmap pm;
3573
3574 QStyleOption tool = *tb;
3575 if (tb->subControls & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
3576 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarCloseButton, widget);
3577 down = tb->activeSubControls & SC_TitleBarCloseButton && (opt->state & State_Sunken);
3578 if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool
3579#if QT_CONFIG(dockwidget)
3580 || qobject_cast<const QDockWidget *>(object: widget)
3581#endif
3582 )
3583 pm = proxy()->standardIcon(standardIcon: SP_DockWidgetCloseButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3584 else
3585 pm = proxy()->standardIcon(standardIcon: SP_TitleBarCloseButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3586 tool.rect = ir;
3587 tool.state = down ? State_Sunken : State_Raised;
3588 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3589
3590 QPainterStateSaver pss(p, down);
3591 if (down)
3592 p->translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: tb, widget),
3593 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: tb, widget));
3594 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3595 }
3596
3597 if (tb->subControls & SC_TitleBarMaxButton
3598 && tb->titleBarFlags & Qt::WindowMaximizeButtonHint
3599 && !(tb->titleBarState & Qt::WindowMaximized)) {
3600 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarMaxButton, widget);
3601
3602 down = tb->activeSubControls & SC_TitleBarMaxButton && (opt->state & State_Sunken);
3603 pm = proxy()->standardIcon(standardIcon: SP_TitleBarMaxButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3604 tool.rect = ir;
3605 tool.state = down ? State_Sunken : State_Raised;
3606 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3607
3608 QPainterStateSaver pss(p, down);
3609 if (down)
3610 p->translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: tb, widget),
3611 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: tb, widget));
3612 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3613 }
3614
3615 if (tb->subControls & SC_TitleBarMinButton
3616 && tb->titleBarFlags & Qt::WindowMinimizeButtonHint
3617 && !(tb->titleBarState & Qt::WindowMinimized)) {
3618 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarMinButton, widget);
3619 down = tb->activeSubControls & SC_TitleBarMinButton && (opt->state & State_Sunken);
3620 pm = proxy()->standardIcon(standardIcon: SP_TitleBarMinButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3621 tool.rect = ir;
3622 tool.state = down ? State_Sunken : State_Raised;
3623 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3624
3625 QPainterStateSaver pss(p, down);
3626 if (down)
3627 p->translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: tb, widget),
3628 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: tb, widget));
3629 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3630 }
3631
3632 bool drawNormalButton = (tb->subControls & SC_TitleBarNormalButton)
3633 && (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
3634 && (tb->titleBarState & Qt::WindowMinimized))
3635 || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
3636 && (tb->titleBarState & Qt::WindowMaximized)));
3637
3638 if (drawNormalButton) {
3639 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarNormalButton, widget);
3640 down = tb->activeSubControls & SC_TitleBarNormalButton && (opt->state & State_Sunken);
3641 pm = proxy()->standardIcon(standardIcon: SP_TitleBarNormalButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3642 tool.rect = ir;
3643 tool.state = down ? State_Sunken : State_Raised;
3644 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3645
3646 QPainterStateSaver pss(p, down);
3647 if (down)
3648 p->translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: tb, widget),
3649 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: tb, widget));
3650 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3651 }
3652
3653 if (tb->subControls & SC_TitleBarShadeButton
3654 && tb->titleBarFlags & Qt::WindowShadeButtonHint
3655 && !(tb->titleBarState & Qt::WindowMinimized)) {
3656 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarShadeButton, widget);
3657 down = (tb->activeSubControls & SC_TitleBarShadeButton && (opt->state & State_Sunken));
3658 pm = proxy()->standardIcon(standardIcon: SP_TitleBarShadeButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3659 tool.rect = ir;
3660 tool.state = down ? State_Sunken : State_Raised;
3661 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3662 QPainterStateSaver pss(p, down);
3663 if (down)
3664 p->translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: tb, widget),
3665 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: tb, widget));
3666 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3667 }
3668
3669 if (tb->subControls & SC_TitleBarUnshadeButton
3670 && tb->titleBarFlags & Qt::WindowShadeButtonHint
3671 && tb->titleBarState & Qt::WindowMinimized) {
3672 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarUnshadeButton, widget);
3673
3674 down = tb->activeSubControls & SC_TitleBarUnshadeButton && (opt->state & State_Sunken);
3675 pm = proxy()->standardIcon(standardIcon: SP_TitleBarUnshadeButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3676 tool.rect = ir;
3677 tool.state = down ? State_Sunken : State_Raised;
3678 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3679 QPainterStateSaver pss(p, down);
3680 if (down)
3681 p->translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: tb, widget),
3682 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: tb, widget));
3683 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3684 }
3685 if (tb->subControls & SC_TitleBarContextHelpButton
3686 && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
3687 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarContextHelpButton, widget);
3688
3689 down = tb->activeSubControls & SC_TitleBarContextHelpButton && (opt->state & State_Sunken);
3690 pm = proxy()->standardIcon(standardIcon: SP_TitleBarContextHelpButton, option: &tool, widget).pixmap(size: QSize(10, 10), devicePixelRatio: p->device()->devicePixelRatio());
3691 tool.rect = ir;
3692 tool.state = down ? State_Sunken : State_Raised;
3693 proxy()->drawPrimitive(pe: PE_PanelButtonTool, opt: &tool, p, w: widget);
3694 QPainterStateSaver pss(p, down);
3695 if (down)
3696 p->translate(dx: proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: tb, widget),
3697 dy: proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: tb, widget));
3698 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3699 }
3700 if (tb->subControls & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
3701 ir = proxy()->subControlRect(cc: CC_TitleBar, opt: tb, sc: SC_TitleBarSysMenu, widget);
3702 if (!tb->icon.isNull()) {
3703 tb->icon.paint(painter: p, rect: ir);
3704 } else {
3705 int iconSize = proxy()->pixelMetric(metric: PM_SmallIconSize, option: tb, widget);
3706 pm = proxy()->standardIcon(standardIcon: SP_TitleBarMenuButton, option: &tool, widget).pixmap(size: QSize(iconSize, iconSize), devicePixelRatio: p->device()->devicePixelRatio());
3707 tool.rect = ir;
3708 QPainterStateSaver pss(p);
3709 proxy()->drawItemPixmap(painter: p, rect: ir, alignment: Qt::AlignCenter, pixmap: pm);
3710 }
3711 }
3712 }
3713 break;
3714#if QT_CONFIG(dial)
3715 case CC_Dial:
3716 if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3717 // OK, this is more a port of things over
3718 QPainterStateSaver pss(p);
3719
3720 // avoid dithering
3721 if (p->paintEngine()->hasFeature(feature: QPaintEngine::Antialiasing))
3722 p->setRenderHint(hint: QPainter::Antialiasing);
3723
3724 int width = dial->rect.width();
3725 int height = dial->rect.height();
3726 qreal r = qMin(a: width, b: height) / 2;
3727 qreal d_ = r / 6;
3728 qreal dx = dial->rect.x() + d_ + (width - 2 * r) / 2 + 1;
3729 qreal dy = dial->rect.y() + d_ + (height - 2 * r) / 2 + 1;
3730 QRect br = QRect(int(dx), int(dy), int(r * 2 - 2 * d_ - 2), int(r * 2 - 2 * d_ - 2));
3731
3732 QPalette pal = opt->palette;
3733 // draw notches
3734 if (dial->subControls & QStyle::SC_DialTickmarks) {
3735 p->setPen(pal.windowText().color());
3736 p->drawLines(pointPairs: QStyleHelper::calcLines(dial));
3737 }
3738
3739 if (dial->state & State_Enabled) {
3740 p->setBrush(pal.brush(cr: QPalette::ColorRole(proxy()->styleHint(stylehint: SH_Dial_BackgroundRole,
3741 opt: dial, widget))));
3742 p->setPen(Qt::NoPen);
3743 p->drawEllipse(r: br);
3744 p->setBrush(Qt::NoBrush);
3745 }
3746 p->setPen(QPen(pal.dark().color()));
3747 p->drawArc(r: br, a: 60 * 16, alen: 180 * 16);
3748 p->setPen(QPen(pal.light().color()));
3749 p->drawArc(r: br, a: 240 * 16, alen: 180 * 16);
3750
3751 qreal a;
3752 const StaticPolygonF<3> arrow = calcArrow(dial, a);
3753
3754 p->setPen(Qt::NoPen);
3755 p->setBrush(pal.button());
3756 p->drawPolygon(points: arrow.cbegin(), pointCount: arrow.size());
3757
3758 a = QStyleHelper::angle(p1: QPointF(width / 2, height / 2), p2: arrow[0]);
3759 p->setBrush(Qt::NoBrush);
3760
3761 if (a <= 0 || a > 200) {
3762 p->setPen(pal.light().color());
3763 p->drawLine(p1: arrow[2], p2: arrow[0]);
3764 p->drawLine(p1: arrow[1], p2: arrow[2]);
3765 p->setPen(pal.dark().color());
3766 p->drawLine(p1: arrow[0], p2: arrow[1]);
3767 } else if (a > 0 && a < 45) {
3768 p->setPen(pal.light().color());
3769 p->drawLine(p1: arrow[2], p2: arrow[0]);
3770 p->setPen(pal.dark().color());
3771 p->drawLine(p1: arrow[1], p2: arrow[2]);
3772 p->drawLine(p1: arrow[0], p2: arrow[1]);
3773 } else if (a >= 45 && a < 135) {
3774 p->setPen(pal.dark().color());
3775 p->drawLine(p1: arrow[2], p2: arrow[0]);
3776 p->drawLine(p1: arrow[1], p2: arrow[2]);
3777 p->setPen(pal.light().color());
3778 p->drawLine(p1: arrow[0], p2: arrow[1]);
3779 } else if (a >= 135 && a < 200) {
3780 p->setPen(pal.dark().color());
3781 p->drawLine(p1: arrow[2], p2: arrow[0]);
3782 p->setPen(pal.light().color());
3783 p->drawLine(p1: arrow[0], p2: arrow[1]);
3784 p->drawLine(p1: arrow[1], p2: arrow[2]);
3785 }
3786
3787 // draw focus rect around the dial
3788 QStyleOptionFocusRect fropt;
3789 fropt.rect = dial->rect;
3790 fropt.state = dial->state;
3791 fropt.palette = dial->palette;
3792 if (fropt.state & QStyle::State_HasFocus) {
3793 br.adjust(dx1: 0, dy1: 0, dx2: 2, dy2: 2);
3794 if (dial->subControls & SC_DialTickmarks) {
3795 int r = qMin(a: width, b: height) / 2;
3796 br.translate(dx: -r / 6, dy: - r / 6);
3797 br.setWidth(br.width() + r / 3);
3798 br.setHeight(br.height() + r / 3);
3799 }
3800 fropt.rect = br.adjusted(xp1: -2, yp1: -2, xp2: 2, yp2: 2);
3801 proxy()->drawPrimitive(pe: QStyle::PE_FrameFocusRect, opt: &fropt, p, w: widget);
3802 }
3803 }
3804 break;
3805#endif // QT_CONFIG(dial)
3806#if QT_CONFIG(groupbox)
3807 case CC_GroupBox:
3808 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
3809 // Draw frame
3810 QRect textRect = proxy()->subControlRect(cc: CC_GroupBox, opt, sc: SC_GroupBoxLabel, widget);
3811 QRect checkBoxRect = proxy()->subControlRect(cc: CC_GroupBox, opt, sc: SC_GroupBoxCheckBox, widget);
3812 if (groupBox->subControls & QStyle::SC_GroupBoxFrame) {
3813 QStyleOptionFrame frame;
3814 frame.QStyleOption::operator=(other: *groupBox);
3815 frame.features = groupBox->features;
3816 frame.lineWidth = groupBox->lineWidth;
3817 frame.midLineWidth = groupBox->midLineWidth;
3818 frame.rect = proxy()->subControlRect(cc: CC_GroupBox, opt, sc: SC_GroupBoxFrame, widget);
3819 QPainterStateSaver pss(p);
3820 QRegion region(groupBox->rect);
3821 if (!groupBox->text.isEmpty()) {
3822 bool ltr = groupBox->direction == Qt::LeftToRight;
3823 QRect finalRect;
3824 if (groupBox->subControls & QStyle::SC_GroupBoxCheckBox) {
3825 finalRect = checkBoxRect.united(r: textRect);
3826 finalRect.adjust(dx1: ltr ? -4 : 0, dy1: 0, dx2: ltr ? 0 : 4, dy2: 0);
3827 } else {
3828 finalRect = textRect;
3829 }
3830 region -= finalRect;
3831 }
3832 p->setClipRegion(region);
3833 proxy()->drawPrimitive(pe: PE_FrameGroupBox, opt: &frame, p, w: widget);
3834 }
3835
3836 // Draw title
3837 if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) {
3838 QColor textColor = groupBox->textColor;
3839 if (textColor.isValid())
3840 p->setPen(textColor);
3841 int alignment = int(groupBox->textAlignment);
3842 if (!proxy()->styleHint(stylehint: QStyle::SH_UnderlineShortcut, opt, widget))
3843 alignment |= Qt::TextHideMnemonic;
3844
3845 proxy()->drawItemText(painter: p, rect: textRect, flags: Qt::TextShowMnemonic | Qt::AlignHCenter | alignment,
3846 pal: groupBox->palette, enabled: groupBox->state & State_Enabled, text: groupBox->text,
3847 textRole: textColor.isValid() ? QPalette::NoRole : QPalette::WindowText);
3848
3849 if (groupBox->state & State_HasFocus) {
3850 QStyleOptionFocusRect fropt;
3851 fropt.QStyleOption::operator=(other: *groupBox);
3852 fropt.rect = textRect;
3853 proxy()->drawPrimitive(pe: PE_FrameFocusRect, opt: &fropt, p, w: widget);
3854 }
3855 }
3856
3857 // Draw checkbox
3858 if (groupBox->subControls & SC_GroupBoxCheckBox) {
3859 QStyleOptionButton box;
3860 box.QStyleOption::operator=(other: *groupBox);
3861 box.rect = checkBoxRect;
3862 proxy()->drawPrimitive(pe: PE_IndicatorCheckBox, opt: &box, p, w: widget);
3863 }
3864 }
3865 break;
3866#endif // QT_CONFIG(groupbox)
3867#if QT_CONFIG(mdiarea)
3868 case CC_MdiControls:
3869 {
3870 QStyleOptionButton btnOpt;
3871 btnOpt.QStyleOption::operator=(other: *opt);
3872 btnOpt.state &= ~State_MouseOver;
3873 int bsx = 0;
3874 int bsy = 0;
3875 const int buttonIconMetric = proxy()->pixelMetric(metric: PM_TitleBarButtonIconSize, option: &btnOpt, widget);
3876 const QSize buttonIconSize(buttonIconMetric, buttonIconMetric);
3877 if (opt->subControls & QStyle::SC_MdiCloseButton) {
3878 if (opt->activeSubControls & QStyle::SC_MdiCloseButton && (opt->state & State_Sunken)) {
3879 btnOpt.state |= State_Sunken;
3880 btnOpt.state &= ~State_Raised;
3881 bsx = proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget);
3882 bsy = proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget);
3883 } else {
3884 btnOpt.state |= State_Raised;
3885 btnOpt.state &= ~State_Sunken;
3886 bsx = 0;
3887 bsy = 0;
3888 }
3889 btnOpt.rect = proxy()->subControlRect(cc: CC_MdiControls, opt, sc: SC_MdiCloseButton, widget);
3890 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: &btnOpt, p, w: widget);
3891 QPixmap pm = proxy()->standardIcon(standardIcon: SP_TitleBarCloseButton).pixmap(size: buttonIconSize, devicePixelRatio: p->device()->devicePixelRatio());
3892 proxy()->drawItemPixmap(painter: p, rect: btnOpt.rect.translated(dx: bsx, dy: bsy), alignment: Qt::AlignCenter, pixmap: pm);
3893 }
3894 if (opt->subControls & QStyle::SC_MdiNormalButton) {
3895 if (opt->activeSubControls & QStyle::SC_MdiNormalButton && (opt->state & State_Sunken)) {
3896 btnOpt.state |= State_Sunken;
3897 btnOpt.state &= ~State_Raised;
3898 bsx = proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget);
3899 bsy = proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget);
3900 } else {
3901 btnOpt.state |= State_Raised;
3902 btnOpt.state &= ~State_Sunken;
3903 bsx = 0;
3904 bsy = 0;
3905 }
3906 btnOpt.rect = proxy()->subControlRect(cc: CC_MdiControls, opt, sc: SC_MdiNormalButton, widget);
3907 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: &btnOpt, p, w: widget);
3908 QPixmap pm = proxy()->standardIcon(standardIcon: SP_TitleBarNormalButton).pixmap(size: buttonIconSize, devicePixelRatio: p->device()->devicePixelRatio());
3909 proxy()->drawItemPixmap(painter: p, rect: btnOpt.rect.translated(dx: bsx, dy: bsy), alignment: Qt::AlignCenter, pixmap: pm);
3910 }
3911 if (opt->subControls & QStyle::SC_MdiMinButton) {
3912 if (opt->activeSubControls & QStyle::SC_MdiMinButton && (opt->state & State_Sunken)) {
3913 btnOpt.state |= State_Sunken;
3914 btnOpt.state &= ~State_Raised;
3915 bsx = proxy()->pixelMetric(metric: PM_ButtonShiftHorizontal, option: opt, widget);
3916 bsy = proxy()->pixelMetric(metric: PM_ButtonShiftVertical, option: opt, widget);
3917 } else {
3918 btnOpt.state |= State_Raised;
3919 btnOpt.state &= ~State_Sunken;
3920 bsx = 0;
3921 bsy = 0;
3922 }
3923 btnOpt.rect = proxy()->subControlRect(cc: CC_MdiControls, opt, sc: SC_MdiMinButton, widget);
3924 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: &btnOpt, p, w: widget);
3925 QPixmap pm = proxy()->standardIcon(standardIcon: SP_TitleBarMinButton).pixmap(size: buttonIconSize, devicePixelRatio: p->device()->devicePixelRatio());
3926 proxy()->drawItemPixmap(painter: p, rect: btnOpt.rect.translated(dx: bsx, dy: bsy), alignment: Qt::AlignCenter, pixmap: pm);
3927 }
3928 }
3929 break;
3930#endif // QT_CONFIG(mdiarea)
3931 default:
3932 qCWarning(lcCommonStyle, "QCommonStyle::drawComplexControl: Control %d not handled", cc);
3933 }
3934}
3935
3936/*!
3937 \reimp
3938*/
3939QStyle::SubControl QCommonStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
3940 const QPoint &pt, const QWidget *widget) const
3941{
3942 SubControl sc = SC_None;
3943 switch (cc) {
3944#if QT_CONFIG(slider)
3945 case CC_Slider:
3946 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3947 QRect r = proxy()->subControlRect(cc, opt: slider, sc: SC_SliderHandle, widget);
3948 if (r.isValid() && r.contains(p: pt)) {
3949 sc = SC_SliderHandle;
3950 } else {
3951 r = proxy()->subControlRect(cc, opt: slider, sc: SC_SliderGroove ,widget);
3952 if (r.isValid() && r.contains(p: pt))
3953 sc = SC_SliderGroove;
3954 }
3955 }
3956 break;
3957#endif // QT_CONFIG(slider)
3958#if QT_CONFIG(scrollbar)
3959 case CC_ScrollBar:
3960 if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
3961 QRect r;
3962 uint ctrl = SC_ScrollBarAddLine;
3963 while (ctrl <= SC_ScrollBarGroove) {
3964 r = proxy()->subControlRect(cc, opt: scrollbar, sc: QStyle::SubControl(ctrl), widget);
3965 if (r.isValid() && r.contains(p: pt)) {
3966 sc = QStyle::SubControl(ctrl);
3967 break;
3968 }
3969 ctrl <<= 1;
3970 }
3971 }
3972 break;
3973#endif // QT_CONFIG(scrollbar)
3974#if QT_CONFIG(toolbutton)
3975 case CC_ToolButton:
3976 if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3977 QRect r;
3978 uint ctrl = SC_ToolButton;
3979 while (ctrl <= SC_ToolButtonMenu) {
3980 r = proxy()->subControlRect(cc, opt: toolbutton, sc: QStyle::SubControl(ctrl), widget);
3981 if (r.isValid() && r.contains(p: pt)) {
3982 sc = QStyle::SubControl(ctrl);
3983 break;
3984 }
3985 ctrl <<= 1;
3986 }
3987 }
3988 break;
3989#endif // QT_CONFIG(toolbutton)
3990#if QT_CONFIG(spinbox)
3991 case CC_SpinBox:
3992 if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
3993 QRect r;
3994 uint ctrl = SC_SpinBoxUp;
3995 while (ctrl <= SC_SpinBoxEditField) {
3996 r = proxy()->subControlRect(cc, opt: spinbox, sc: QStyle::SubControl(ctrl), widget);
3997 if (r.isValid() && r.contains(p: pt)) {
3998 sc = QStyle::SubControl(ctrl);
3999 break;
4000 }
4001 ctrl <<= 1;
4002 }
4003 }
4004 break;
4005#endif // QT_CONFIG(spinbox)
4006 case CC_TitleBar:
4007 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4008 QRect r;
4009 uint ctrl = SC_TitleBarSysMenu;
4010
4011 while (ctrl <= SC_TitleBarLabel) {
4012 r = proxy()->subControlRect(cc, opt: tb, sc: QStyle::SubControl(ctrl), widget);
4013 if (r.isValid() && r.contains(p: pt)) {
4014 sc = QStyle::SubControl(ctrl);
4015 break;
4016 }
4017 ctrl <<= 1;
4018 }
4019 }
4020 break;
4021#if QT_CONFIG(combobox)
4022 case CC_ComboBox:
4023 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4024 QRect r;
4025 uint ctrl = SC_ComboBoxArrow; // Start here and go down.
4026 while (ctrl > 0) {
4027 r = proxy()->subControlRect(cc, opt: cb, sc: QStyle::SubControl(ctrl), widget);
4028 if (r.isValid() && r.contains(p: pt)) {
4029 sc = QStyle::SubControl(ctrl);
4030 break;
4031 }
4032 ctrl >>= 1;
4033 }
4034 }
4035 break;
4036#endif // QT_CONFIG(combobox)
4037#if QT_CONFIG(groupbox)
4038 case CC_GroupBox:
4039 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4040 QRect r;
4041 uint ctrl = SC_GroupBoxCheckBox;
4042 while (ctrl <= SC_GroupBoxFrame) {
4043 r = proxy()->subControlRect(cc, opt: groupBox, sc: QStyle::SubControl(ctrl), widget);
4044 if (r.isValid() && r.contains(p: pt)) {
4045 sc = QStyle::SubControl(ctrl);
4046 break;
4047 }
4048 ctrl <<= 1;
4049 }
4050 }
4051 break;
4052#endif // QT_CONFIG(groupbox)
4053 case CC_MdiControls:
4054 {
4055 QRect r;
4056 uint ctrl = SC_MdiMinButton;
4057 while (ctrl <= SC_MdiCloseButton) {
4058 r = proxy()->subControlRect(cc: CC_MdiControls, opt, sc: QStyle::SubControl(ctrl), widget);
4059 if (r.isValid() && r.contains(p: pt) && (opt->subControls & ctrl)) {
4060 sc = QStyle::SubControl(ctrl);
4061 return sc;
4062 }
4063 ctrl <<= 1;
4064 }
4065 }
4066 break;
4067 default:
4068 qCWarning(lcCommonStyle, "QCommonStyle::hitTestComplexControl: Case %d not handled", cc);
4069 }
4070 return sc;
4071}
4072
4073/*!
4074 \reimp
4075*/
4076QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,
4077 SubControl sc, const QWidget *widget) const
4078{
4079 QRect ret;
4080 switch (cc) {
4081#if QT_CONFIG(slider)
4082 case CC_Slider:
4083 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4084 int tickOffset = proxy()->pixelMetric(metric: PM_SliderTickmarkOffset, option: slider, widget);
4085 int thickness = proxy()->pixelMetric(metric: PM_SliderControlThickness, option: slider, widget);
4086
4087 switch (sc) {
4088 case SC_SliderHandle: {
4089 int sliderPos = 0;
4090 int len = proxy()->pixelMetric(metric: PM_SliderLength, option: slider, widget);
4091 bool horizontal = slider->orientation == Qt::Horizontal;
4092 sliderPos = sliderPositionFromValue(min: slider->minimum, max: slider->maximum,
4093 val: slider->sliderPosition,
4094 space: (horizontal ? slider->rect.width()
4095 : slider->rect.height()) - len,
4096 upsideDown: slider->upsideDown);
4097 if (horizontal)
4098 ret.setRect(ax: slider->rect.x() + sliderPos, ay: slider->rect.y() + tickOffset, aw: len, ah: thickness);
4099 else
4100 ret.setRect(ax: slider->rect.x() + tickOffset, ay: slider->rect.y() + sliderPos, aw: thickness, ah: len);
4101 break; }
4102 case SC_SliderGroove:
4103 if (slider->orientation == Qt::Horizontal)
4104 ret.setRect(ax: slider->rect.x(), ay: slider->rect.y() + tickOffset,
4105 aw: slider->rect.width(), ah: thickness);
4106 else
4107 ret.setRect(ax: slider->rect.x() + tickOffset, ay: slider->rect.y(),
4108 aw: thickness, ah: slider->rect.height());
4109 break;
4110 default:
4111 break;
4112 }
4113 ret = visualRect(direction: slider->direction, boundingRect: slider->rect, logicalRect: ret);
4114 }
4115 break;
4116#endif // QT_CONFIG(slider)
4117#if QT_CONFIG(scrollbar)
4118 case CC_ScrollBar:
4119 if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4120 const QRect scrollBarRect = scrollbar->rect;
4121 int sbextent = 0;
4122 if (!proxy()->styleHint(stylehint: SH_ScrollBar_Transient, opt: scrollbar, widget))
4123 sbextent = proxy()->pixelMetric(metric: PM_ScrollBarExtent, option: scrollbar, widget);
4124 int maxlen = ((scrollbar->orientation == Qt::Horizontal) ?
4125 scrollBarRect.width() : scrollBarRect.height()) - (sbextent * 2);
4126 int sliderlen;
4127
4128 // calculate slider length
4129 if (scrollbar->maximum != scrollbar->minimum) {
4130 uint range = scrollbar->maximum - scrollbar->minimum;
4131 sliderlen = (qint64(scrollbar->pageStep) * maxlen) / (range + scrollbar->pageStep);
4132
4133 int slidermin = proxy()->pixelMetric(metric: PM_ScrollBarSliderMin, option: scrollbar, widget);
4134 if (sliderlen < slidermin || range > INT_MAX / 2)
4135 sliderlen = slidermin;
4136 if (sliderlen > maxlen)
4137 sliderlen = maxlen;
4138 } else {
4139 sliderlen = maxlen;
4140 }
4141
4142 int sliderstart = sbextent + sliderPositionFromValue(min: scrollbar->minimum,
4143 max: scrollbar->maximum,
4144 val: scrollbar->sliderPosition,
4145 space: maxlen - sliderlen,
4146 upsideDown: scrollbar->upsideDown);
4147
4148 switch (sc) {
4149 case SC_ScrollBarSubLine: // top/left button
4150 if (scrollbar->orientation == Qt::Horizontal) {
4151 int buttonWidth = qMin(a: scrollBarRect.width() / 2, b: sbextent);
4152 ret.setRect(ax: 0, ay: 0, aw: buttonWidth, ah: scrollBarRect.height());
4153 } else {
4154 int buttonHeight = qMin(a: scrollBarRect.height() / 2, b: sbextent);
4155 ret.setRect(ax: 0, ay: 0, aw: scrollBarRect.width(), ah: buttonHeight);
4156 }
4157 break;
4158 case SC_ScrollBarAddLine: // bottom/right button
4159 if (scrollbar->orientation == Qt::Horizontal) {
4160 int buttonWidth = qMin(a: scrollBarRect.width()/2, b: sbextent);
4161 ret.setRect(ax: scrollBarRect.width() - buttonWidth, ay: 0, aw: buttonWidth, ah: scrollBarRect.height());
4162 } else {
4163 int buttonHeight = qMin(a: scrollBarRect.height()/2, b: sbextent);
4164 ret.setRect(ax: 0, ay: scrollBarRect.height() - buttonHeight, aw: scrollBarRect.width(), ah: buttonHeight);
4165 }
4166 break;
4167 case SC_ScrollBarSubPage: // between top/left button and slider
4168 if (scrollbar->orientation == Qt::Horizontal)
4169 ret.setRect(ax: sbextent, ay: 0, aw: sliderstart - sbextent, ah: scrollBarRect.height());
4170 else
4171 ret.setRect(ax: 0, ay: sbextent, aw: scrollBarRect.width(), ah: sliderstart - sbextent);
4172 break;
4173 case SC_ScrollBarAddPage: // between bottom/right button and slider
4174 if (scrollbar->orientation == Qt::Horizontal)
4175 ret.setRect(ax: sliderstart + sliderlen, ay: 0,
4176 aw: maxlen - sliderstart - sliderlen + sbextent, ah: scrollBarRect.height());
4177 else
4178 ret.setRect(ax: 0, ay: sliderstart + sliderlen, aw: scrollBarRect.width(),
4179 ah: maxlen - sliderstart - sliderlen + sbextent);
4180 break;
4181 case SC_ScrollBarGroove:
4182 if (scrollbar->orientation == Qt::Horizontal)
4183 ret.setRect(ax: sbextent, ay: 0, aw: scrollBarRect.width() - sbextent * 2,
4184 ah: scrollBarRect.height());
4185 else
4186 ret.setRect(ax: 0, ay: sbextent, aw: scrollBarRect.width(),
4187 ah: scrollBarRect.height() - sbextent * 2);
4188 break;
4189 case SC_ScrollBarSlider:
4190 if (scrollbar->orientation == Qt::Horizontal)
4191 ret.setRect(ax: sliderstart, ay: 0, aw: sliderlen, ah: scrollBarRect.height());
4192 else
4193 ret.setRect(ax: 0, ay: sliderstart, aw: scrollBarRect.width(), ah: sliderlen);
4194 break;
4195 default:
4196 break;
4197 }
4198 ret = visualRect(direction: scrollbar->direction, boundingRect: scrollBarRect, logicalRect: ret);
4199 }
4200 break;
4201#endif // QT_CONFIG(scrollbar)
4202#if QT_CONFIG(spinbox)
4203 case CC_SpinBox:
4204 if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
4205 QSize bs;
4206 int fw = spinbox->frame ? proxy()->pixelMetric(metric: PM_SpinBoxFrameWidth, option: spinbox, widget) : 0;
4207 bs.setHeight(qMax(a: 8, b: spinbox->rect.height()/2 - fw));
4208 // 1.6 -approximate golden mean
4209 bs.setWidth(qMax(a: 16, b: qMin(a: bs.height() * 8 / 5, b: spinbox->rect.width() / 4)));
4210 int y = fw + spinbox->rect.y();
4211 int x, lx, rx;
4212 x = spinbox->rect.x() + spinbox->rect.width() - fw - bs.width();
4213 lx = fw;
4214 rx = x - fw;
4215 switch (sc) {
4216 case SC_SpinBoxUp:
4217 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
4218 return QRect();
4219 ret = QRect(x, y, bs.width(), bs.height());
4220 break;
4221 case SC_SpinBoxDown:
4222 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
4223 return QRect();
4224
4225 ret = QRect(x, y + bs.height(), bs.width(), bs.height());
4226 break;
4227 case SC_SpinBoxEditField:
4228 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) {
4229 ret = QRect(lx, fw, spinbox->rect.width() - 2*fw, spinbox->rect.height() - 2*fw);
4230 } else {
4231 ret = QRect(lx, fw, rx, spinbox->rect.height() - 2*fw);
4232 }
4233 break;
4234 case SC_SpinBoxFrame:
4235 ret = spinbox->rect;
4236 break;
4237 default:
4238 break;
4239 }
4240 ret = visualRect(direction: spinbox->direction, boundingRect: spinbox->rect, logicalRect: ret);
4241 }
4242 break;
4243#endif // Qt_NO_SPINBOX
4244#if QT_CONFIG(toolbutton)
4245 case CC_ToolButton:
4246 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
4247 int mbi = proxy()->pixelMetric(metric: PM_MenuButtonIndicator, option: tb, widget);
4248 ret = tb->rect;
4249 switch (sc) {
4250 case SC_ToolButton:
4251 if ((tb->features
4252 & (QStyleOptionToolButton::MenuButtonPopup | QStyleOptionToolButton::PopupDelay))
4253 == QStyleOptionToolButton::MenuButtonPopup)
4254 ret.adjust(dx1: 0, dy1: 0, dx2: -mbi, dy2: 0);
4255 break;
4256 case SC_ToolButtonMenu:
4257 if ((tb->features
4258 & (QStyleOptionToolButton::MenuButtonPopup | QStyleOptionToolButton::PopupDelay))
4259 == QStyleOptionToolButton::MenuButtonPopup)
4260 ret.adjust(dx1: ret.width() - mbi, dy1: 0, dx2: 0, dy2: 0);
4261 break;
4262 default:
4263 break;
4264 }
4265 ret = visualRect(direction: tb->direction, boundingRect: tb->rect, logicalRect: ret);
4266 }
4267 break;
4268#endif // QT_CONFIG(toolbutton)
4269#if QT_CONFIG(combobox)
4270 case CC_ComboBox:
4271 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4272 const qreal dpi = QStyleHelper::dpi(option: opt);
4273 const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height();
4274 const int margin = cb->frame ? qRound(d: QStyleHelper::dpiScaled(value: 3, dpi)) : 0;
4275 const int bmarg = cb->frame ? qRound(d: QStyleHelper::dpiScaled(value: 2, dpi)) : 0;
4276 const int xpos = x + wi - bmarg - qRound(d: QStyleHelper::dpiScaled(value: 16, dpi));
4277
4278
4279 switch (sc) {
4280 case SC_ComboBoxFrame:
4281 ret = cb->rect;
4282 break;
4283 case SC_ComboBoxArrow:
4284 ret.setRect(ax: xpos, ay: y + bmarg, aw: qRound(d: QStyleHelper::dpiScaled(value: 16, option: opt)), ah: he - 2*bmarg);
4285 break;
4286 case SC_ComboBoxEditField:
4287 ret.setRect(ax: x + margin, ay: y + margin, aw: wi - 2 * margin - qRound(d: QStyleHelper::dpiScaled(value: 16, dpi)), ah: he - 2 * margin);
4288 break;
4289 case SC_ComboBoxListBoxPopup:
4290 ret = cb->rect;
4291 break;
4292 default:
4293 break;
4294 }
4295 ret = visualRect(direction: cb->direction, boundingRect: cb->rect, logicalRect: ret);
4296 }
4297 break;
4298#endif // QT_CONFIG(combobox)
4299 case CC_TitleBar:
4300 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4301 const int controlMargin = 2;
4302 const int controlHeight = tb->rect.height() - controlMargin *2;
4303 const int delta = controlHeight + controlMargin;
4304 int offset = 0;
4305
4306 bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
4307 bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
4308
4309 switch (sc) {
4310 case SC_TitleBarLabel:
4311 if (tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
4312 ret = tb->rect;
4313 if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
4314 ret.adjust(dx1: delta, dy1: 0, dx2: -delta, dy2: 0);
4315 if (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
4316 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
4317 if (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
4318 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
4319 if (tb->titleBarFlags & Qt::WindowShadeButtonHint)
4320 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
4321 if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
4322 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
4323 }
4324 break;
4325 case SC_TitleBarContextHelpButton:
4326 if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
4327 offset += delta;
4328 Q_FALLTHROUGH();
4329 case SC_TitleBarMinButton:
4330 if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
4331 offset += delta;
4332 else if (sc == SC_TitleBarMinButton)
4333 break;
4334 Q_FALLTHROUGH();
4335 case SC_TitleBarNormalButton:
4336 if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
4337 offset += delta;
4338 else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
4339 offset += delta;
4340 else if (sc == SC_TitleBarNormalButton)
4341 break;
4342 Q_FALLTHROUGH();
4343 case SC_TitleBarMaxButton:
4344 if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
4345 offset += delta;
4346 else if (sc == SC_TitleBarMaxButton)
4347 break;
4348 Q_FALLTHROUGH();
4349 case SC_TitleBarShadeButton:
4350 if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
4351 offset += delta;
4352 else if (sc == SC_TitleBarShadeButton)
4353 break;
4354 Q_FALLTHROUGH();
4355 case SC_TitleBarUnshadeButton:
4356 if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
4357 offset += delta;
4358 else if (sc == SC_TitleBarUnshadeButton)
4359 break;
4360 Q_FALLTHROUGH();
4361 case SC_TitleBarCloseButton:
4362 if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
4363 offset += delta;
4364 else if (sc == SC_TitleBarCloseButton)
4365 break;
4366 ret.setRect(ax: tb->rect.right() - offset, ay: tb->rect.top() + controlMargin,
4367 aw: controlHeight, ah: controlHeight);
4368 break;
4369 case SC_TitleBarSysMenu:
4370 if (tb->titleBarFlags & Qt::WindowSystemMenuHint) {
4371 ret.setRect(ax: tb->rect.left() + controlMargin, ay: tb->rect.top() + controlMargin,
4372 aw: controlHeight, ah: controlHeight);
4373 }
4374 break;
4375 default:
4376 break;
4377 }
4378 ret = visualRect(direction: tb->direction, boundingRect: tb->rect, logicalRect: ret);
4379 }
4380 break;
4381#if QT_CONFIG(groupbox)
4382 case CC_GroupBox: {
4383 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4384 switch (sc) {
4385 case SC_GroupBoxFrame:
4386 case SC_GroupBoxContents: {
4387 int topMargin = 0;
4388 int topHeight = 0;
4389 int verticalAlignment = proxy()->styleHint(stylehint: SH_GroupBox_TextLabelVerticalAlignment, opt: groupBox, widget);
4390 bool hasCheckBox = groupBox->subControls & QStyle::SC_GroupBoxCheckBox;
4391 if (groupBox->text.size() || hasCheckBox) {
4392 int checkBoxHeight = hasCheckBox ? proxy()->pixelMetric(metric: PM_IndicatorHeight, option: groupBox, widget) : 0;
4393 topHeight = qMax(a: groupBox->fontMetrics.height(), b: checkBoxHeight);
4394 if (verticalAlignment & Qt::AlignVCenter)
4395 topMargin = topHeight / 2;
4396 else if (verticalAlignment & Qt::AlignTop)
4397 topMargin = topHeight + proxy()->pixelMetric(metric: PM_FocusFrameVMargin, option: groupBox, widget);
4398 }
4399
4400 QRect frameRect = groupBox->rect;
4401 frameRect.setTop(topMargin);
4402
4403 if (sc == SC_GroupBoxFrame) {
4404 ret = frameRect;
4405 break;
4406 }
4407
4408 int frameWidth = 0;
4409 if ((groupBox->features & QStyleOptionFrame::Flat) == 0)
4410 frameWidth = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: groupBox, widget);
4411 ret = frameRect.adjusted(xp1: frameWidth, yp1: frameWidth + topHeight - topMargin,
4412 xp2: -frameWidth, yp2: -frameWidth);
4413 break;
4414 }
4415 case SC_GroupBoxCheckBox:
4416 case SC_GroupBoxLabel: {
4417 QFontMetrics fontMetrics = groupBox->fontMetrics;
4418 int th = fontMetrics.height();
4419 int tw = fontMetrics.size(flags: Qt::TextShowMnemonic, str: groupBox->text + u' ').width();
4420 int marg = (groupBox->features & QStyleOptionFrame::Flat) ? 0 : 8;
4421 ret = groupBox->rect.adjusted(xp1: marg, yp1: 0, xp2: -marg, yp2: 0);
4422
4423 int indicatorWidth = proxy()->pixelMetric(metric: PM_IndicatorWidth, option: opt, widget);
4424 int indicatorHeight = proxy()->pixelMetric(metric: PM_IndicatorHeight, option: opt, widget);
4425 int indicatorSpace = proxy()->pixelMetric(metric: PM_CheckBoxLabelSpacing, option: opt, widget) - 1;
4426 bool hasCheckBox = groupBox->subControls & QStyle::SC_GroupBoxCheckBox;
4427 int checkBoxWidth = hasCheckBox ? (indicatorWidth + indicatorSpace) : 0;
4428 int checkBoxHeight = hasCheckBox ? indicatorHeight : 0;
4429
4430 int h = qMax(a: th, b: checkBoxHeight);
4431 ret.setHeight(h);
4432
4433 // Adjusted rect for label + indicatorWidth + indicatorSpace
4434 QRect totalRect = alignedRect(direction: groupBox->direction, alignment: groupBox->textAlignment,
4435 size: QSize(tw + checkBoxWidth, h), rectangle: ret);
4436
4437 // Adjust totalRect if checkbox is set
4438 if (hasCheckBox) {
4439 bool ltr = groupBox->direction == Qt::LeftToRight;
4440 int left = 0;
4441 // Adjust for check box
4442 if (sc == SC_GroupBoxCheckBox) {
4443 left = ltr ? totalRect.left() : (totalRect.right() - indicatorWidth);
4444 int top = totalRect.top() + (h - checkBoxHeight) / 2;
4445 totalRect.setRect(ax: left, ay: top, aw: indicatorWidth, ah: indicatorHeight);
4446 // Adjust for label
4447 } else {
4448 left = ltr ? (totalRect.left() + checkBoxWidth - 2) : totalRect.left();
4449 int top = totalRect.top() + (h - th) / 2;
4450 totalRect.setRect(ax: left, ay: top, aw: totalRect.width() - checkBoxWidth, ah: th);
4451 }
4452 }
4453 ret = totalRect;
4454 break;
4455 }
4456 default:
4457 break;
4458 }
4459 }
4460 break;
4461 }
4462#endif // QT_CONFIG(groupbox)
4463#if QT_CONFIG(mdiarea)
4464 case CC_MdiControls:
4465 {
4466 int numSubControls = 0;
4467 if (opt->subControls & SC_MdiCloseButton)
4468 ++numSubControls;
4469 if (opt->subControls & SC_MdiMinButton)
4470 ++numSubControls;
4471 if (opt->subControls & SC_MdiNormalButton)
4472 ++numSubControls;
4473 if (numSubControls == 0)
4474 break;
4475
4476 int buttonWidth = opt->rect.width() / numSubControls - 1;
4477 int offset = 0;
4478 switch (sc) {
4479 case SC_MdiCloseButton:
4480 // Only one sub control, no offset needed.
4481 if (numSubControls == 1)
4482 break;
4483 offset += buttonWidth + 2;
4484 Q_FALLTHROUGH();
4485 case SC_MdiNormalButton:
4486 // No offset needed if
4487 // 1) There's only one sub control
4488 // 2) We have a close button and a normal button (offset already added in SC_MdiClose)
4489 if (numSubControls == 1 || (numSubControls == 2 && !(opt->subControls & SC_MdiMinButton)))
4490 break;
4491 if (opt->subControls & SC_MdiNormalButton)
4492 offset += buttonWidth;
4493 break;
4494 default:
4495 break;
4496 }
4497
4498 // Subtract one pixel if we only have one sub control. At this point
4499 // buttonWidth is the actual width + 1 pixel margin, but we don't want the
4500 // margin when there are no other controllers.
4501 if (numSubControls == 1)
4502 --buttonWidth;
4503 ret = QRect(offset, 0, buttonWidth, opt->rect.height());
4504 break;
4505 }
4506#endif // QT_CONFIG(mdiarea)
4507 default:
4508 qCWarning(lcCommonStyle, "QCommonStyle::subControlRect: Case %d not handled", cc);
4509 }
4510#if !QT_CONFIG(slider) && !QT_CONFIG(spinbox) && !QT_CONFIG(toolbutton) && !QT_CONFIG(groupbox)
4511 Q_UNUSED(widget);
4512#endif
4513 return ret;
4514}
4515
4516/*! \reimp */
4517int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *widget) const
4518{
4519 int ret;
4520
4521 switch (m) {
4522 case PM_FocusFrameVMargin:
4523 case PM_FocusFrameHMargin:
4524 ret = 2;
4525 break;
4526 case PM_MenuBarVMargin:
4527 case PM_MenuBarHMargin:
4528 ret = 0;
4529 break;
4530 case PM_TitleBarHeight:
4531 {
4532 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4533 if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool) {
4534 ret = qMax(a: widget ? widget->fontMetrics().height() : opt->fontMetrics.height(), b: 16);
4535#if QT_CONFIG(dockwidget)
4536 } else if (qobject_cast<const QDockWidget*>(object: widget)) {
4537 ret = qMax(a: widget->fontMetrics().height(), b: int(QStyleHelper::dpiScaled(value: 13, option: opt)));
4538#endif
4539 } else {
4540 ret = qMax(a: widget ? widget->fontMetrics().height() : opt->fontMetrics.height(), b: 18);
4541 }
4542 } else {
4543 ret = int(QStyleHelper::dpiScaled(value: 18., option: opt));
4544 }
4545 break;
4546 }
4547 case PM_TitleBarButtonSize:
4548 ret = int(QStyleHelper::dpiScaled(value: 16., option: opt));
4549 break;
4550 case PM_TitleBarButtonIconSize:
4551 ret = int(QStyleHelper::dpiScaled(value: 16., option: opt));
4552 break;
4553
4554 case PM_ScrollBarSliderMin:
4555 ret = int(QStyleHelper::dpiScaled(value: 9., option: opt));
4556 break;
4557
4558 case PM_ButtonMargin:
4559 ret = int(QStyleHelper::dpiScaled(value: 6., option: opt));
4560 break;
4561
4562 case PM_DockWidgetTitleBarButtonMargin:
4563 ret = int(QStyleHelper::dpiScaled(value: 2., option: opt));
4564 break;
4565
4566 case PM_ButtonDefaultIndicator:
4567 ret = 0;
4568 break;
4569
4570 case PM_MenuButtonIndicator:
4571 ret = int(QStyleHelper::dpiScaled(value: 12, option: opt));
4572 break;
4573
4574 case PM_ButtonShiftHorizontal:
4575 case PM_ButtonShiftVertical:
4576
4577 case PM_DefaultFrameWidth:
4578 ret = 2;
4579 break;
4580
4581 case PM_ComboBoxFrameWidth:
4582 case PM_SpinBoxFrameWidth:
4583 case PM_MenuPanelWidth:
4584 case PM_TabBarBaseOverlap:
4585 case PM_TabBarBaseHeight:
4586 ret = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: opt, widget);
4587 break;
4588
4589 case PM_MdiSubWindowFrameWidth:
4590 ret = int(QStyleHelper::dpiScaled(value: 4, option: opt));
4591 break;
4592
4593 case PM_MdiSubWindowMinimizedWidth:
4594 ret = int(QStyleHelper::dpiScaled(value: 196, option: opt));
4595 break;
4596
4597#if QT_CONFIG(scrollbar)
4598 case PM_ScrollBarExtent:
4599 if (qstyleoption_cast<const QStyleOptionSlider *>(opt))
4600 ret = 16;
4601 else
4602 ret = int(QStyleHelper::dpiScaled(value: 16, option: opt));
4603 break;
4604#endif
4605 case PM_MaximumDragDistance:
4606 ret = QGuiApplicationPrivate::platformTheme()->themeHint(hint: QPlatformTheme::MaximumScrollBarDragDistance).toInt();
4607 break;
4608
4609#if QT_CONFIG(slider)
4610 case PM_SliderThickness:
4611 ret = int(QStyleHelper::dpiScaled(value: 16, option: opt));
4612 break;
4613
4614 case PM_SliderTickmarkOffset:
4615 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4616 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height()
4617 : sl->rect.width();
4618 int thickness = proxy()->pixelMetric(metric: PM_SliderControlThickness, option: sl, widget);
4619 int ticks = sl->tickPosition;
4620
4621 if (ticks == QSlider::TicksBothSides)
4622 ret = (space - thickness) / 2;
4623 else if (ticks == QSlider::TicksAbove)
4624 ret = space - thickness;
4625 else
4626 ret = 0;
4627 } else {
4628 ret = 0;
4629 }
4630 break;
4631
4632 case PM_SliderSpaceAvailable:
4633 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4634 if (sl->orientation == Qt::Horizontal)
4635 ret = sl->rect.width() - proxy()->pixelMetric(metric: PM_SliderLength, option: sl, widget);
4636 else
4637 ret = sl->rect.height() - proxy()->pixelMetric(metric: PM_SliderLength, option: sl, widget);
4638 } else {
4639 ret = 0;
4640 }
4641 break;
4642#endif // QT_CONFIG(slider)
4643#if QT_CONFIG(dockwidget)
4644 case PM_DockWidgetSeparatorExtent:
4645 ret = int(QStyleHelper::dpiScaled(value: 6, option: opt));
4646 break;
4647
4648 case PM_DockWidgetHandleExtent:
4649 ret = int(QStyleHelper::dpiScaled(value: 8, option: opt));
4650 break;
4651 case PM_DockWidgetTitleMargin:
4652 ret = 0;
4653 break;
4654 case PM_DockWidgetFrameWidth:
4655 ret = 1;
4656 break;
4657#endif // QT_CONFIG(dockwidget)
4658
4659 case PM_SpinBoxSliderHeight:
4660 case PM_MenuBarPanelWidth:
4661 ret = 2;
4662 break;
4663
4664 case PM_MenuBarItemSpacing:
4665 ret = 0;
4666 break;
4667
4668#if QT_CONFIG(toolbar)
4669 case PM_ToolBarFrameWidth:
4670 ret = 1;
4671 break;
4672
4673 case PM_ToolBarItemMargin:
4674 ret = 0;
4675 break;
4676
4677 case PM_ToolBarItemSpacing:
4678 ret = int(QStyleHelper::dpiScaled(value: 4, option: opt));
4679 break;
4680
4681 case PM_ToolBarHandleExtent:
4682 ret = int(QStyleHelper::dpiScaled(value: 8, option: opt));
4683 break;
4684
4685 case PM_ToolBarSeparatorExtent:
4686 ret = int(QStyleHelper::dpiScaled(value: 6, option: opt));
4687 break;
4688
4689 case PM_ToolBarExtensionExtent:
4690 ret = int(QStyleHelper::dpiScaled(value: 12, option: opt));
4691 break;
4692#endif // QT_CONFIG(toolbar)
4693
4694#if QT_CONFIG(tabbar)
4695 case PM_TabBarTabOverlap:
4696 ret = 3;
4697 break;
4698
4699 case PM_TabBarTabHSpace:
4700 ret = int(QStyleHelper::dpiScaled(value: 24, option: opt));
4701 break;
4702
4703 case PM_TabBarTabShiftHorizontal:
4704 ret = 0;
4705 break;
4706
4707 case PM_TabBarTabShiftVertical:
4708 ret = 2;
4709 break;
4710
4711 case PM_TabBarTabVSpace:
4712 {
4713 const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(opt);
4714 if (tb && (tb->shape == QTabBar::RoundedNorth || tb->shape == QTabBar::RoundedSouth
4715 || tb->shape == QTabBar::RoundedWest || tb->shape == QTabBar::RoundedEast))
4716 ret = 8;
4717 else
4718 if (tb && (tb->shape == QTabBar::TriangularWest || tb->shape == QTabBar::TriangularEast))
4719 ret = 3;
4720 else
4721 ret = 2;
4722 break;
4723 }
4724#endif
4725
4726 case PM_ProgressBarChunkWidth:
4727 ret = 9;
4728 break;
4729
4730 case PM_IndicatorWidth:
4731 ret = int(QStyleHelper::dpiScaled(value: 13, option: opt));
4732 break;
4733
4734 case PM_IndicatorHeight:
4735 ret = int(QStyleHelper::dpiScaled(value: 13, option: opt));
4736 break;
4737
4738 case PM_ExclusiveIndicatorWidth:
4739 ret = int(QStyleHelper::dpiScaled(value: 12, option: opt));
4740 break;
4741
4742 case PM_ExclusiveIndicatorHeight:
4743 ret = int(QStyleHelper::dpiScaled(value: 12, option: opt));
4744 break;
4745
4746 case PM_MenuTearoffHeight:
4747 ret = int(QStyleHelper::dpiScaled(value: 10, option: opt));
4748 break;
4749
4750 case PM_MenuScrollerHeight:
4751 ret = int(QStyleHelper::dpiScaled(value: 10, option: opt));
4752 break;
4753
4754 case PM_MenuDesktopFrameWidth:
4755 case PM_MenuHMargin:
4756 case PM_MenuVMargin:
4757 ret = 0;
4758 break;
4759
4760 case PM_HeaderMargin:
4761 ret = int(QStyleHelper::dpiScaled(value: 4, option: opt));
4762 break;
4763 case PM_HeaderMarkSize:
4764 ret = int(QStyleHelper::dpiScaled(value: 16, option: opt));
4765 break;
4766 case PM_HeaderGripMargin:
4767 ret = int(QStyleHelper::dpiScaled(value: 4, option: opt));
4768 break;
4769 case PM_HeaderDefaultSectionSizeHorizontal:
4770 ret = int(QStyleHelper::dpiScaled(value: 100, option: opt));
4771 break;
4772 case PM_HeaderDefaultSectionSizeVertical:
4773 ret = int(QStyleHelper::dpiScaled(value: 30, option: opt));
4774 break;
4775 case PM_TabBarScrollButtonWidth:
4776 ret = int(QStyleHelper::dpiScaled(value: 16, option: opt));
4777 break;
4778 case PM_LayoutLeftMargin:
4779 case PM_LayoutTopMargin:
4780 case PM_LayoutRightMargin:
4781 case PM_LayoutBottomMargin:
4782 {
4783 bool isWindow = false;
4784 if (opt) {
4785 isWindow = (opt->state & State_Window);
4786 } else if (widget) {
4787 isWindow = widget->isWindow();
4788 }
4789 ret = int(QStyleHelper::dpiScaled(value: isWindow ? 11 : 9, option: opt));
4790 break;
4791 }
4792 case PM_LayoutHorizontalSpacing:
4793 case PM_LayoutVerticalSpacing:
4794 ret = int(QStyleHelper::dpiScaled(value: 6, option: opt));
4795 break;
4796
4797 case PM_ToolBarIconSize:
4798 ret = 0;
4799 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
4800 ret = theme->themeHint(hint: QPlatformTheme::ToolBarIconSize).toInt();
4801 if (ret <= 0)
4802 ret = int(QStyleHelper::dpiScaled(value: 24, option: opt));
4803 break;
4804
4805 case PM_TabBarIconSize:
4806 ret = proxy()->pixelMetric(metric: PM_SmallIconSize, option: opt, widget);
4807 break;
4808 case PM_ListViewIconSize:
4809#if QT_CONFIG(filedialog)
4810 if (qobject_cast<const QSidebar *>(object: widget))
4811 ret = int(QStyleHelper::dpiScaled(value: 24., option: opt));
4812 else
4813#endif
4814 ret = proxy()->pixelMetric(metric: PM_SmallIconSize, option: opt, widget);
4815 break;
4816
4817 case PM_ButtonIconSize:
4818 case PM_SmallIconSize:
4819 ret = int(QStyleHelper::dpiScaled(value: 16, option: opt));
4820 break;
4821 case PM_IconViewIconSize:
4822 ret = proxy()->pixelMetric(metric: PM_LargeIconSize, option: opt, widget);
4823 break;
4824 case PM_LineEditIconSize:
4825 ret = proxy()->pixelMetric(metric: PM_SmallIconSize, option: opt, widget);
4826 break;
4827 case PM_LineEditIconMargin:
4828 ret = proxy()->pixelMetric(metric: PM_LineEditIconSize, option: opt, widget) / 4;
4829 break;
4830
4831 case PM_LargeIconSize:
4832 ret = int(QStyleHelper::dpiScaled(value: 32, option: opt));
4833 break;
4834
4835 case PM_ToolTipLabelFrameWidth:
4836 ret = 1;
4837 break;
4838 case PM_CheckBoxLabelSpacing:
4839 case PM_RadioButtonLabelSpacing:
4840 ret = int(QStyleHelper::dpiScaled(value: 6, option: opt));
4841 break;
4842 case PM_SizeGripSize:
4843 ret = int(QStyleHelper::dpiScaled(value: 13, option: opt));
4844 break;
4845 case PM_MessageBoxIconSize:
4846#ifdef Q_OS_MAC
4847 if (QGuiApplication::desktopSettingsAware()) {
4848 ret = 64; // No DPI scaling, it's handled elsewhere.
4849 } else
4850#endif
4851 {
4852 ret = int(QStyleHelper::dpiScaled(value: 32, option: opt));
4853 }
4854 break;
4855 case PM_TextCursorWidth:
4856 ret = QGuiApplicationPrivate::platformTheme()->themeHint(hint: QPlatformTheme::TextCursorWidth).toInt();
4857 break;
4858 case PM_TabBar_ScrollButtonOverlap:
4859 ret = 1;
4860 break;
4861 case PM_TabCloseIndicatorWidth:
4862 case PM_TabCloseIndicatorHeight:
4863 ret = int(QStyleHelper::dpiScaled(value: 16, option: opt));
4864 break;
4865 case PM_ScrollView_ScrollBarSpacing:
4866 ret = 2 * proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: opt, widget);
4867 break;
4868 case PM_ScrollView_ScrollBarOverlap:
4869 ret = 0;
4870 break;
4871 case PM_SubMenuOverlap:
4872 ret = -proxy()->pixelMetric(metric: QStyle::PM_MenuPanelWidth, option: opt, widget);
4873 break;
4874 case PM_TreeViewIndentation:
4875 ret = int(QStyleHelper::dpiScaled(value: 20, option: opt));
4876 break;
4877 default:
4878 ret = 0;
4879 break;
4880 }
4881
4882 return ret;
4883}
4884
4885/*!
4886 \reimp
4887*/
4888QSize QCommonStyle::sizeFromContents(ContentsType contentsType, const QStyleOption *opt,
4889 const QSize &contentsSize, const QWidget *widget) const
4890{
4891 Q_D(const QCommonStyle);
4892 QSize size(contentsSize);
4893 switch (contentsType) {
4894 case CT_PushButton:
4895 if (const auto *buttonOpt = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4896 int width = contentsSize.width();
4897 int height = contentsSize.height();
4898 const int buttonMargin = proxy()->pixelMetric(metric: PM_ButtonMargin, option: buttonOpt, widget);
4899 const int defaultFrameWidth = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: buttonOpt, widget) * 2;
4900 width += buttonMargin + defaultFrameWidth;
4901 height += buttonMargin + defaultFrameWidth;
4902 if (buttonOpt->features.testFlag(flag: QStyleOptionButton::AutoDefaultButton)) {
4903 const int buttonIndicator = proxy()->pixelMetric(metric: PM_ButtonDefaultIndicator,
4904 option: buttonOpt,
4905 widget) * 2;
4906 width += buttonIndicator;
4907 height += buttonIndicator;
4908 }
4909 size = QSize(width, height);
4910 }
4911 break;
4912 case CT_RadioButton:
4913 case CT_CheckBox:
4914 if (const auto *buttonOpt = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4915 const bool isRadio = (contentsType == CT_RadioButton);
4916
4917 const int width = proxy()->pixelMetric(metric: isRadio ? PM_ExclusiveIndicatorWidth
4918 : PM_IndicatorWidth, option: buttonOpt, widget);
4919 const int height = proxy()->pixelMetric(metric: isRadio ? PM_ExclusiveIndicatorHeight
4920 : PM_IndicatorHeight, option: buttonOpt, widget);
4921
4922 int margins = 0;
4923
4924 // we add 4 pixels for label margins
4925 if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
4926 margins = 4 + proxy()->pixelMetric(metric: isRadio ? PM_RadioButtonLabelSpacing
4927 : PM_CheckBoxLabelSpacing, option: opt, widget);
4928 }
4929
4930 size += QSize(width + margins, 4);
4931 size.setHeight(qMax(a: size.height(), b: height));
4932 }
4933 break;
4934#if QT_CONFIG(menu)
4935 case CT_MenuItem:
4936 if (const auto *menuItemOpt = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4937 const bool checkable = menuItemOpt->menuHasCheckableItems;
4938 const int maxpmw = menuItemOpt->maxIconWidth;
4939 int width = size.width();
4940 int height;
4941 if (menuItemOpt->menuItemType == QStyleOptionMenuItem::Separator) {
4942 width = 10;
4943 height = 2;
4944 } else {
4945 height = menuItemOpt->fontMetrics.height() + 8;
4946 if (!menuItemOpt->icon.isNull()) {
4947 int iconExtent = proxy()->pixelMetric(metric: PM_SmallIconSize, option: opt, widget);
4948 height = qMax(a: height,
4949 b: menuItemOpt->icon.actualSize(size: QSize(iconExtent,
4950 iconExtent)).height() + 4);
4951 }
4952 }
4953 if (menuItemOpt->text.contains(c: u'\t'))
4954 width += 12;
4955 if (maxpmw > 0)
4956 width += maxpmw + 6;
4957 if (checkable && maxpmw < 20)
4958 width += 20 - maxpmw;
4959 if (checkable || maxpmw > 0)
4960 width += 2;
4961 width += 12;
4962 size = QSize(width, height);
4963 }
4964 break;
4965#endif // QT_CONFIG(menu)
4966#if QT_CONFIG(toolbutton)
4967 case CT_ToolButton:
4968 size = QSize(size.width() + 6, size.height() + 5);
4969 break;
4970#endif // QT_CONFIG(toolbutton)
4971#if QT_CONFIG(combobox)
4972 case CT_ComboBox:
4973 if (const auto *comboBoxOpt = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4974 const int frameWidth = comboBoxOpt->frame ? proxy()->pixelMetric(metric: PM_ComboBoxFrameWidth,
4975 option: opt,
4976 widget) * 2 : 0;
4977 const int textMargins = 2 * (proxy()->pixelMetric(metric: PM_FocusFrameHMargin, option: opt, widget) + 1);
4978
4979 // QItemDelegate::sizeHint expands the textMargins two times, thus the 2*textMargins...
4980 const int other = qMax(a: 23, b: 2 * textMargins
4981 + proxy()->pixelMetric(metric: QStyle::PM_ScrollBarExtent,
4982 option: opt, widget));
4983
4984 size = QSize(size.width() + frameWidth + other, size.height() + frameWidth);
4985 }
4986 break;
4987#endif // QT_CONFIG(combobox)
4988 case CT_HeaderSection:
4989 if (const auto *headerOpt = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4990 const bool nullIcon = headerOpt->icon.isNull();
4991 const int margin = proxy()->pixelMetric(metric: QStyle::PM_HeaderMargin, option: headerOpt, widget);
4992 const int iconSize = nullIcon ? 0 : proxy()->pixelMetric(metric: QStyle::PM_SmallIconSize,
4993 option: headerOpt,
4994 widget);
4995 const QSize textSize = headerOpt->fontMetrics.size(flags: 0, str: headerOpt->text);
4996 size.setHeight(margin + qMax(a: iconSize, b: textSize.height()) + margin);
4997 size.setWidth((nullIcon ? 0 : margin) + iconSize
4998 + (headerOpt->text.isNull() ? 0 : margin) + textSize.width() + margin);
4999 if (headerOpt->sortIndicator != QStyleOptionHeader::None) {
5000 const int margin = proxy()->pixelMetric(metric: QStyle::PM_HeaderMargin, option: headerOpt, widget);
5001 if (headerOpt->orientation == Qt::Horizontal)
5002 size.rwidth() += size.height() + margin;
5003 else
5004 size.rheight() += size.width() + margin;
5005 }
5006 }
5007 break;
5008 case CT_TabWidget:
5009 size += QSize(4, 4);
5010 break;
5011 case CT_LineEdit:
5012 if (const auto *frameOpt = qstyleoption_cast<const QStyleOptionFrame *>(opt))
5013 size += QSize(2 * frameOpt->lineWidth, 2 * frameOpt->lineWidth);
5014 break;
5015#if QT_CONFIG(groupbox)
5016 case CT_GroupBox:
5017 if (const auto *groupBoxOpt = qstyleoption_cast<const QStyleOptionGroupBox *>(opt))
5018 size += QSize(groupBoxOpt->features.testFlag(flag: QStyleOptionFrame::Flat) ? 0 : 16, 0);
5019 break;
5020#endif // QT_CONFIG(groupbox)
5021 case CT_MdiControls:
5022 if (const auto *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
5023 const int buttonSize = proxy()->pixelMetric(metric: PM_TitleBarButtonSize, option: styleOpt, widget);
5024 int width = 1;
5025 if (styleOpt->subControls & SC_MdiMinButton)
5026 width += buttonSize + 1;
5027 if (styleOpt->subControls & SC_MdiNormalButton)
5028 width += buttonSize + 1;
5029 if (styleOpt->subControls & SC_MdiCloseButton)
5030 width += buttonSize + 1;
5031 size = QSize(width, buttonSize);
5032 } else {
5033 const int buttonSize = proxy()->pixelMetric(metric: PM_TitleBarButtonSize, option: opt, widget);
5034 size = QSize(1 + 3 * (buttonSize + 1), buttonSize);
5035 }
5036 break;
5037#if QT_CONFIG(itemviews)
5038 case CT_ItemViewItem:
5039 if (const auto *viewItemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
5040 QRect decorationRect, displayRect, checkRect;
5041 d->viewItemLayout(opt: viewItemOpt, checkRect: &checkRect, pixmapRect: &decorationRect, textRect: &displayRect, sizehint: true);
5042 size = (decorationRect|displayRect|checkRect).size();
5043 if (decorationRect.isValid() && size.height() == decorationRect.height())
5044 size.rheight() += 2; // Prevent icons from overlapping.
5045 }
5046 break;
5047#else
5048 Q_UNUSED(d);
5049#endif // QT_CONFIG(itemviews)
5050#if QT_CONFIG(spinbox)
5051 case CT_SpinBox:
5052 if (const auto *spinBoxOpt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5053 const int frameWidth = spinBoxOpt->frame
5054 ? proxy()->pixelMetric(metric: PM_SpinBoxFrameWidth, option: spinBoxOpt, widget)
5055 : 0;
5056 size += QSize(2 * frameWidth, 2 * frameWidth);
5057 const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
5058 if (hasButtons) {
5059 const auto height = qMax(a: 8, b: size.height() / 2 - frameWidth);
5060 const auto buttonWidth = qMax(a: 16, b: qMin(a: height * 8 / 5, b: size.width() / 3));
5061 size.rwidth() += buttonWidth;
5062 }
5063 }
5064 break;
5065#endif
5066 case CT_ScrollBar:
5067 case CT_MenuBar:
5068 case CT_Menu:
5069 case CT_MenuBarItem:
5070 case CT_Slider:
5071 case CT_ProgressBar:
5072 case CT_TabBarTab:
5073 // just return the contentsSize for now
5074 Q_FALLTHROUGH();
5075 default:
5076 break;
5077 }
5078 return size;
5079}
5080
5081
5082/*! \reimp */
5083int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget,
5084 QStyleHintReturn *hret) const
5085{
5086 int ret = 0;
5087
5088 switch (sh) {
5089 case SH_Menu_KeyboardSearch:
5090 ret = false;
5091 break;
5092 case SH_Slider_AbsoluteSetButtons:
5093 ret = Qt::MiddleButton;
5094 break;
5095 case SH_Slider_PageSetButtons:
5096 ret = Qt::LeftButton;
5097 break;
5098 case SH_ScrollBar_ContextMenu:
5099 ret = true;
5100 break;
5101#if QT_CONFIG(dialogbuttonbox)
5102 case SH_DialogButtons_DefaultButton: // This value not used anywhere.
5103 ret = QDialogButtonBox::AcceptRole;
5104 break;
5105#endif
5106#if QT_CONFIG(groupbox)
5107 case SH_GroupBox_TextLabelVerticalAlignment:
5108 ret = Qt::AlignVCenter;
5109 break;
5110
5111 case SH_GroupBox_TextLabelColor:
5112 ret = opt ? int(opt->palette.color(cr: QPalette::Text).rgba()) : 0;
5113 break;
5114#endif // QT_CONFIG(groupbox)
5115
5116 case SH_ListViewExpand_SelectMouseType:
5117 case SH_TabBar_SelectMouseType:
5118 ret = QEvent::MouseButtonPress;
5119 break;
5120
5121
5122 case SH_TabBar_Alignment:
5123 ret = Qt::AlignLeft;
5124 break;
5125
5126 case SH_Header_ArrowAlignment:
5127 ret = Qt::AlignRight | Qt::AlignVCenter;
5128 break;
5129
5130 case SH_TitleBar_AutoRaise:
5131 ret = false;
5132 break;
5133
5134 case SH_Menu_SubMenuPopupDelay:
5135 ret = 256;
5136 break;
5137
5138 case SH_Menu_SloppySubMenus:
5139 ret = true;
5140 break;
5141
5142 case SH_Menu_SubMenuUniDirection:
5143 ret = false;
5144 break;
5145 case SH_Menu_SubMenuUniDirectionFailCount:
5146 ret = 1;
5147 break;
5148 case SH_Menu_SubMenuSloppySelectOtherActions:
5149 ret = true;
5150 break;
5151 case SH_Menu_SubMenuSloppyCloseTimeout:
5152 ret = 1000;
5153 break;
5154 case SH_Menu_SubMenuResetWhenReenteringParent:
5155 ret = false;
5156 break;
5157 case SH_Menu_SubMenuDontStartSloppyOnLeave:
5158 ret = false;
5159 break;
5160
5161 case SH_ProgressDialog_TextLabelAlignment:
5162 ret = Qt::AlignCenter;
5163 break;
5164
5165 case SH_BlinkCursorWhenTextSelected:
5166#if defined(Q_OS_DARWIN)
5167 ret = 0;
5168#else
5169 ret = 1;
5170#endif
5171 break;
5172
5173 case SH_Table_GridLineColor:
5174 if (opt)
5175 ret = opt->palette.color(cr: QPalette::Mid).rgba();
5176 else
5177 ret = -1;
5178 break;
5179 case SH_LineEdit_PasswordCharacter: {
5180 const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
5181 const QPlatformTheme::ThemeHint hintType = QPlatformTheme::PasswordMaskCharacter;
5182 const QVariant hint = theme ? theme->themeHint(hint: hintType) : QPlatformTheme::defaultThemeHint(hint: hintType);
5183 ret = hint.toChar().unicode();
5184 break;
5185 }
5186 case SH_LineEdit_PasswordMaskDelay:
5187 ret = QGuiApplicationPrivate::platformTheme()->themeHint(hint: QPlatformTheme::PasswordMaskDelay).toInt();
5188 break;
5189 case SH_ToolBox_SelectedPageTitleBold:
5190 ret = 1;
5191 break;
5192
5193 case SH_UnderlineShortcut: {
5194 const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
5195 ret = theme ? theme->themeHint(hint: QPlatformTheme::UnderlineShortcut).toInt()
5196 : QPlatformTheme::defaultThemeHint(hint: QPlatformTheme::UnderlineShortcut).toInt();
5197 break;
5198 }
5199
5200 case SH_SpinBox_ClickAutoRepeatRate:
5201 ret = 150;
5202 break;
5203
5204 case SH_SpinBox_ClickAutoRepeatThreshold:
5205 ret = 500;
5206 break;
5207
5208 case SH_SpinBox_KeyPressAutoRepeatRate:
5209 ret = 75;
5210 break;
5211
5212 case SH_Menu_SelectionWrap:
5213 ret = true;
5214 break;
5215
5216 case SH_Menu_FillScreenWithScroll:
5217 ret = true;
5218 break;
5219
5220 case SH_ToolTipLabel_Opacity:
5221 ret = 255;
5222 break;
5223
5224 case SH_Button_FocusPolicy:
5225 ret = Qt::StrongFocus;
5226 break;
5227
5228 case SH_MessageBox_UseBorderForButtonSpacing:
5229 ret = 0;
5230 break;
5231
5232 case SH_ToolButton_PopupDelay:
5233 ret = 600;
5234 break;
5235
5236 case SH_FocusFrame_Mask:
5237 ret = 1;
5238 if (widget) {
5239 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hint: hret)) {
5240 mask->region = widget->rect();
5241 const int vmargin = proxy()->pixelMetric(metric: QStyle::PM_FocusFrameVMargin, option: opt, widget);
5242 const int hmargin = proxy()->pixelMetric(metric: QStyle::PM_FocusFrameHMargin, option: opt, widget);
5243 mask->region -= QRect(widget->rect().adjusted(xp1: hmargin, yp1: vmargin, xp2: -hmargin, yp2: -vmargin));
5244 }
5245 }
5246 break;
5247#if QT_CONFIG(rubberband)
5248 case SH_RubberBand_Mask:
5249 if (const QStyleOptionRubberBand *rbOpt = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
5250 ret = 0;
5251 if (rbOpt->shape == QRubberBand::Rectangle) {
5252 ret = true;
5253 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hint: hret)) {
5254 mask->region = opt->rect;
5255 const int margin = proxy()->pixelMetric(metric: PM_DefaultFrameWidth, option: opt, widget) * 2;
5256 mask->region -= opt->rect.adjusted(xp1: margin, yp1: margin, xp2: -margin, yp2: -margin);
5257 }
5258 }
5259 }
5260 break;
5261#endif // QT_CONFIG(rubberband)
5262 case SH_SpinControls_DisableOnBounds:
5263 ret = 1;
5264 break;
5265
5266 case SH_Dial_BackgroundRole:
5267 ret = QPalette::Window;
5268 break;
5269
5270 case SH_ComboBox_LayoutDirection:
5271 ret = opt ? opt->direction : Qt::LeftToRight;
5272 break;
5273
5274 case SH_ItemView_EllipsisLocation:
5275 ret = Qt::AlignTrailing;
5276 break;
5277
5278 case SH_ItemView_ShowDecorationSelected:
5279 ret = false;
5280 break;
5281
5282 case SH_ItemView_ActivateItemOnSingleClick:
5283 ret = 0;
5284 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
5285 ret = theme->themeHint(hint: QPlatformTheme::ItemViewActivateItemOnSingleClick).toBool() ? 1 : 0;
5286 break;
5287 case SH_TitleBar_ModifyNotification:
5288 ret = true;
5289 break;
5290 case SH_ScrollBar_RollBetweenButtons:
5291 ret = false;
5292 break;
5293 case SH_TabBar_ElideMode:
5294 ret = Qt::ElideNone;
5295 break;
5296#if QT_CONFIG(dialogbuttonbox)
5297 case SH_DialogButtonLayout:
5298 ret = QDialogButtonBox::WinLayout;
5299 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
5300 ret = theme->themeHint(hint: QPlatformTheme::DialogButtonBoxLayout).toInt();
5301 break;
5302#endif
5303 case SH_ComboBox_PopupFrameStyle:
5304 ret = QFrame::StyledPanel | QFrame::Plain;
5305 break;
5306 case SH_MessageBox_TextInteractionFlags:
5307 ret = Qt::LinksAccessibleByMouse;
5308 break;
5309 case SH_DialogButtonBox_ButtonsHaveIcons:
5310 ret = 0;
5311 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
5312 ret = theme->themeHint(hint: QPlatformTheme::DialogButtonBoxButtonsHaveIcons).toBool() ? 1 : 0;
5313 break;
5314 case SH_MessageBox_CenterButtons:
5315 ret = true;
5316 break;
5317 case SH_ItemView_MovementWithoutUpdatingSelection:
5318 ret = true;
5319 break;
5320 case SH_FocusFrame_AboveWidget:
5321 ret = false;
5322 break;
5323#if QT_CONFIG(tabwidget)
5324 case SH_TabWidget_DefaultTabPosition:
5325 ret = QTabWidget::North;
5326 break;
5327#endif
5328 case SH_ToolBar_Movable:
5329 ret = true;
5330 break;
5331 case SH_TextControl_FocusIndicatorTextCharFormat:
5332 ret = true;
5333 if (QStyleHintReturnVariant *vret = qstyleoption_cast<QStyleHintReturnVariant*>(hint: hret)) {
5334 QPen outline(opt->palette.color(cr: QPalette::Text), 1, Qt::DotLine);
5335 QTextCharFormat fmt;
5336 fmt.setProperty(propertyId: QTextFormat::OutlinePen, value: outline);
5337 vret->variant = fmt;
5338 }
5339 break;
5340#if QT_CONFIG(wizard)
5341 case SH_WizardStyle:
5342 ret = QWizard::ClassicStyle;
5343 break;
5344#endif
5345#if QT_CONFIG(formlayout)
5346 case SH_FormLayoutWrapPolicy:
5347 ret = QFormLayout::DontWrapRows;
5348 break;
5349 case SH_FormLayoutFieldGrowthPolicy:
5350 ret = QFormLayout::AllNonFixedFieldsGrow;
5351 break;
5352#endif
5353 case SH_FormLayoutFormAlignment:
5354 ret = Qt::AlignLeft | Qt::AlignTop;
5355 break;
5356 case SH_FormLayoutLabelAlignment:
5357 ret = Qt::AlignLeft;
5358 break;
5359 case SH_ItemView_ArrowKeysNavigateIntoChildren:
5360 ret = false;
5361 break;
5362 case SH_ItemView_DrawDelegateFrame:
5363 ret = 0;
5364 break;
5365#if QT_CONFIG(tabbar)
5366 case SH_TabBar_CloseButtonPosition:
5367 ret = QTabBar::RightSide;
5368 break;
5369 case SH_TabBar_ChangeCurrentDelay:
5370 ret = 500;
5371 break;
5372#endif
5373 case SH_DockWidget_ButtonsHaveFrame:
5374 ret = true;
5375 break;
5376 case SH_ToolButtonStyle:
5377 ret = 0;
5378 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
5379 ret = theme->themeHint(hint: QPlatformTheme::ToolButtonStyle).toInt();
5380 break;
5381 case SH_RequestSoftwareInputPanel:
5382 ret = RSIP_OnMouseClick;
5383 break;
5384 case SH_ScrollBar_Transient:
5385 ret = false;
5386 break;
5387 case SH_Menu_SupportsSections:
5388 ret = false;
5389 break;
5390#if QT_CONFIG(tooltip)
5391 case SH_ToolTip_WakeUpDelay:
5392 ret = 700;
5393 break;
5394 case SH_ToolTip_FallAsleepDelay:
5395 ret = 2000;
5396 break;
5397#endif
5398 case SH_Widget_Animate:
5399 // TODO Qt6: move this code in the SH_Widget_Animation_Duration case
5400 // and replace false with 0 and true with 200.
5401#if QT_CONFIG(treeview)
5402 if (qobject_cast<const QTreeView*>(object: widget)) {
5403 ret = false;
5404 } else
5405#endif
5406 {
5407 ret = true;
5408 }
5409 break;
5410 case SH_Splitter_OpaqueResize:
5411 ret = true;
5412 break;
5413#if QT_CONFIG(itemviews)
5414 case SH_ItemView_ScrollMode:
5415 ret = QAbstractItemView::ScrollPerItem;
5416 break;
5417#endif
5418 case SH_TitleBar_ShowToolTipsOnButtons:
5419 ret = true;
5420 break;
5421 case SH_Widget_Animation_Duration:
5422 ret = styleHint(sh: SH_Widget_Animate, opt, widget, hret) ? 200 : 0;
5423 break;
5424 case SH_ComboBox_AllowWheelScrolling:
5425 ret = true;
5426 break;
5427 case SH_SpinBox_ButtonsInsideFrame:
5428 ret = true;
5429 break;
5430 case SH_SpinBox_StepModifier:
5431 ret = Qt::ControlModifier;
5432 break;
5433 case SH_TabBar_AllowWheelScrolling:
5434 ret = true;
5435 break;
5436 case SH_SpinBox_SelectOnStep:
5437 ret = true;
5438 break;
5439 case SH_EtchDisabledText:
5440 case SH_DitherDisabledText:
5441 case SH_ScrollBar_MiddleClickAbsolutePosition:
5442 case SH_ScrollBar_ScrollWhenPointerLeavesControl:
5443 case SH_Slider_SnapToValue:
5444 case SH_Slider_SloppyKeyEvents:
5445 case SH_ProgressDialog_CenterCancelButton:
5446 case SH_PrintDialog_RightAlignButtons:
5447 case SH_MainWindow_SpaceBelowMenuBar:
5448 case SH_FontDialog_SelectAssociatedText:
5449 case SH_Menu_AllowActiveAndDisabled:
5450 case SH_Menu_SpaceActivatesItem:
5451 case SH_ScrollView_FrameOnlyAroundContents:
5452 case SH_ComboBox_ListMouseTracking:
5453 case SH_Menu_MouseTracking:
5454 case SH_MenuBar_MouseTracking:
5455 case SH_ItemView_ChangeHighlightOnFocus:
5456 case SH_Widget_ShareActivation:
5457 case SH_Workspace_FillSpaceOnMaximize:
5458 case SH_ComboBox_Popup:
5459 case SH_TitleBar_NoBorder:
5460 case SH_Slider_StopMouseOverSlider:
5461 case SH_RichText_FullWidthSelection:
5462 case SH_Menu_Scrollable:
5463 case SH_TabBar_PreferNoArrows:
5464 case SH_ScrollBar_LeftClickAbsolutePosition:
5465 case SH_SpinBox_AnimateButton:
5466 case SH_DrawMenuBarSeparator:
5467 case SH_WindowFrame_Mask:
5468 case SH_ToolTip_Mask:
5469 case SH_Menu_Mask:
5470 case SH_Menu_FlashTriggeredItem:
5471 case SH_Menu_FadeOutOnHide:
5472 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
5473 case SH_ComboBox_UseNativePopup:
5474 case SH_Table_AlwaysDrawLeftTopGridLines:
5475 ret = false;
5476 break;
5477 case SH_MenuBar_AltKeyNavigation:
5478 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
5479 ret = theme->themeHint(hint: QPlatformTheme::MenuBarFocusOnAltPressRelease).toBool();
5480 break;
5481 case SH_CustomBase:
5482 // Added to get compiler errors when a style hint is missing
5483 ret = false;
5484 break;
5485 }
5486
5487 return ret;
5488}
5489
5490#if QT_CONFIG(imageformat_xpm)
5491static QPixmap cachedPixmapFromXPM(const char * const *xpm)
5492{
5493 QPixmap result;
5494 const QString tag = QString::asprintf(format: "xpm:0x%p", static_cast<const void*>(xpm));
5495 if (!QPixmapCache::find(key: tag, pixmap: &result)) {
5496 result = QPixmap(xpm);
5497 QPixmapCache::insert(key: tag, pixmap: result);
5498 }
5499 return result;
5500}
5501
5502static inline QPixmap titleBarMenuCachedPixmapFromXPM() { return cachedPixmapFromXPM(xpm: qt_menu_xpm); }
5503#endif // QT_CONFIG(imageformat_xpm)
5504
5505#if QT_CONFIG(imageformat_png)
5506static constexpr QLatin1StringView iconResourcePrefix() noexcept { return ":/qt-project.org/styles/commonstyle/images/"_L1; }
5507static constexpr QLatin1StringView iconPngSuffix() noexcept { return ".png"_L1; }
5508
5509template <typename T>
5510static void addIconFiles(QStringView prefix, std::initializer_list<T> sizes, QIcon &icon,
5511 QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off)
5512{
5513 const auto fullPrefix = iconResourcePrefix() + prefix;
5514 for (int size : sizes)
5515 icon.addFile(fileName: fullPrefix + QString::number(size) + iconPngSuffix(),
5516 size: QSize(size, size), mode, state);
5517}
5518
5519static constexpr auto dockTitleIconSizes = {10, 16, 20, 32, 48, 64};
5520static constexpr auto titleBarSizes = {16, 32, 48};
5521static constexpr auto toolBarExtHSizes = {8, 16, 32, 128};
5522static constexpr auto toolBarExtVSizes = {5, 10, 20, 80};
5523static constexpr auto pngIconSizes = {16, 32, 128};
5524#endif // imageformat_png
5525
5526/*! \reimp */
5527QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *option,
5528 const QWidget *widget) const
5529{
5530 Q_D(const QCommonStyle);
5531 QIcon icon;
5532
5533 icon = d->iconFromWindowsTheme(standardIcon: sp, option, widget);
5534 if (!icon.isNull())
5535 return icon.pixmap(size: QSize(16, 16), devicePixelRatio: qt_getDevicePixelRatio(widget));
5536
5537 icon = d->iconFromApplicationTheme(standardIcon: sp, option, widget);
5538 if (!icon.isNull())
5539 return icon.pixmap(size: QSize(16, 16), devicePixelRatio: qt_getDevicePixelRatio(widget));
5540
5541 icon = d->iconFromMacTheme(standardIcon: sp, option, widget);
5542 if (!icon.isNull())
5543 return icon.pixmap(size: QSize(16, 16), devicePixelRatio: qt_getDevicePixelRatio(widget));
5544
5545 icon = d->iconFromResourceTheme(standardIcon: sp, option, widget);
5546 if (!icon.isNull())
5547 return icon.pixmap(size: QSize(16, 16), devicePixelRatio: qt_getDevicePixelRatio(widget));
5548
5549#ifndef QT_NO_IMAGEFORMAT_XPM
5550 switch (sp) {
5551 case QStyle::SP_ToolBarHorizontalExtensionButton:
5552 if (d->rtl(option)) {
5553 auto im = QImage(tb_extension_arrow_h_xpm).convertToFormat(f: QImage::Format_ARGB32).mirrored(horizontally: true, vertically: false);
5554 return QPixmap::fromImage(image: std::move(im));
5555 }
5556 return cachedPixmapFromXPM(xpm: tb_extension_arrow_h_xpm);
5557 case QStyle::SP_ToolBarVerticalExtensionButton:
5558 return cachedPixmapFromXPM(xpm: tb_extension_arrow_v_xpm);
5559 case QStyle::SP_FileDialogStart:
5560 return cachedPixmapFromXPM(xpm: filedialog_start_xpm);
5561 case QStyle::SP_FileDialogEnd:
5562 return cachedPixmapFromXPM(xpm: filedialog_end_xpm);
5563 case QStyle::SP_TitleBarMenuButton:
5564 return titleBarMenuCachedPixmapFromXPM();
5565 case QStyle::SP_TitleBarShadeButton:
5566 return cachedPixmapFromXPM(xpm: qt_shade_xpm);
5567 case QStyle::SP_TitleBarUnshadeButton:
5568 return cachedPixmapFromXPM(xpm: qt_unshade_xpm);
5569 case QStyle::SP_TitleBarNormalButton:
5570 return cachedPixmapFromXPM(xpm: qt_normalizeup_xpm);
5571 case QStyle::SP_TitleBarMinButton:
5572 return cachedPixmapFromXPM(xpm: qt_minimize_xpm);
5573 case QStyle::SP_TitleBarMaxButton:
5574 return cachedPixmapFromXPM(xpm: qt_maximize_xpm);
5575 case QStyle::SP_TitleBarCloseButton:
5576 return cachedPixmapFromXPM(xpm: qt_close_xpm);
5577 case QStyle::SP_TitleBarContextHelpButton:
5578 return cachedPixmapFromXPM(xpm: qt_help_xpm);
5579 case QStyle::SP_DockWidgetCloseButton:
5580 return cachedPixmapFromXPM(xpm: dock_widget_close_xpm);
5581 case QStyle::SP_MessageBoxInformation:
5582 return cachedPixmapFromXPM(xpm: information_xpm);
5583 case QStyle::SP_MessageBoxWarning:
5584 return cachedPixmapFromXPM(xpm: warning_xpm);
5585 case QStyle::SP_MessageBoxCritical:
5586 return cachedPixmapFromXPM(xpm: critical_xpm);
5587 case QStyle::SP_MessageBoxQuestion:
5588 return cachedPixmapFromXPM(xpm: question_xpm);
5589 default:
5590 break;
5591 }
5592#endif //QT_NO_IMAGEFORMAT_XPM
5593
5594 return QPixmap();
5595}
5596
5597QIcon QCommonStylePrivate::iconFromWindowsTheme(QCommonStyle::StandardPixmap standardIcon,
5598 const QStyleOption *option,
5599 const QWidget *widget) const
5600{
5601 Q_UNUSED(option);
5602 Q_UNUSED(widget);
5603 QIcon icon;
5604#ifdef Q_OS_WIN
5605 switch (standardIcon) {
5606 case QStyle::SP_DriveCDIcon:
5607 case QStyle::SP_DriveDVDIcon:
5608 case QStyle::SP_DriveNetIcon:
5609 case QStyle::SP_DriveHDIcon:
5610 case QStyle::SP_DriveFDIcon:
5611 case QStyle::SP_FileIcon:
5612 case QStyle::SP_FileLinkIcon:
5613 case QStyle::SP_DesktopIcon:
5614 case QStyle::SP_ComputerIcon:
5615 case QStyle::SP_VistaShield:
5616 case QStyle::SP_MessageBoxInformation:
5617 case QStyle::SP_MessageBoxWarning:
5618 case QStyle::SP_MessageBoxCritical:
5619 case QStyle::SP_MessageBoxQuestion:
5620 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
5621 QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
5622 const auto dpr = qt_getDevicePixelRatio(widget);
5623 const QList<QSize> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<QSize>>();
5624 for (const QSize &size : sizes) {
5625 QPixmap pixmap = theme->standardPixmap(sp, size * dpr);
5626 pixmap.setDevicePixelRatio(dpr);
5627 icon.addPixmap(pixmap, QIcon::Normal);
5628 }
5629 }
5630 break;
5631 case QStyle::SP_DirIcon:
5632 case QStyle::SP_DirLinkIcon:
5633 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
5634 QPlatformTheme::StandardPixmap spOff = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
5635 QPlatformTheme::StandardPixmap spOn = standardIcon == QStyle::SP_DirIcon ? QPlatformTheme::DirOpenIcon
5636 : QPlatformTheme::DirLinkOpenIcon;
5637 const auto dpr = qt_getDevicePixelRatio(widget);
5638 const QList<QSize> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<QSize>>();
5639 for (const QSize &size : sizes) {
5640 const QSizeF pixSize = size * dpr;
5641 QPixmap pixmap = theme->standardPixmap(spOff, pixSize);
5642 pixmap.setDevicePixelRatio(dpr);
5643 icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off);
5644 pixmap = theme->standardPixmap(spOn, pixSize);
5645 pixmap.setDevicePixelRatio(dpr);
5646 icon.addPixmap(pixmap, QIcon::Normal, QIcon::On);
5647 }
5648 }
5649 break;
5650 default:
5651 break;
5652 }
5653#else
5654 Q_UNUSED(standardIcon)
5655#endif
5656 return icon;
5657}
5658
5659QIcon QCommonStylePrivate::iconFromApplicationTheme(QCommonStyle::StandardPixmap standardIcon,
5660 const QStyleOption *option,
5661 const QWidget *widget) const
5662{
5663 if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) {
5664 switch (standardIcon) {
5665 case QStyle::SP_DirHomeIcon:
5666 return QIcon::fromTheme(name: "user-home"_L1);
5667 case QStyle::SP_MessageBoxInformation:
5668 return QIcon::fromTheme(name: "dialog-information"_L1);
5669 case QStyle::SP_MessageBoxWarning:
5670 return QIcon::fromTheme(name: "dialog-warning"_L1);
5671 case QStyle::SP_MessageBoxCritical:
5672 return QIcon::fromTheme(name: "dialog-error"_L1);
5673 case QStyle::SP_MessageBoxQuestion:
5674 return QIcon::fromTheme(name: "dialog-question"_L1);
5675 case QStyle::SP_DialogOpenButton:
5676 case QStyle::SP_DirOpenIcon:
5677 return QIcon::fromTheme(name: "folder-open"_L1);
5678 case QStyle::SP_DialogSaveButton:
5679 return QIcon::fromTheme(name: "document-save"_L1);
5680 case QStyle::SP_DialogApplyButton:
5681 return QIcon::fromTheme(name: "dialog-ok-apply"_L1);
5682 case QStyle::SP_DialogYesButton:
5683 case QStyle::SP_DialogOkButton:
5684 return QIcon::fromTheme(name: "dialog-ok"_L1);
5685 case QStyle::SP_DialogDiscardButton:
5686 return QIcon::fromTheme(name: "edit-delete"_L1);
5687 case QStyle::SP_DialogResetButton:
5688 return QIcon::fromTheme(name: "edit-clear"_L1);
5689 case QStyle::SP_DialogHelpButton:
5690 return QIcon::fromTheme(name: "help-contents"_L1);
5691 case QStyle::SP_FileIcon:
5692 return QIcon::fromTheme(name: "text-x-generic"_L1);
5693 case QStyle::SP_DirClosedIcon:
5694 case QStyle::SP_DirIcon:
5695 return QIcon::fromTheme(name: "folder"_L1);
5696 case QStyle::SP_DriveFDIcon:
5697 return QIcon::fromTheme(name: "floppy_unmount"_L1);
5698 case QStyle::SP_ComputerIcon:
5699 return QIcon::fromTheme(name: "computer"_L1, fallback: QIcon::fromTheme(name: "system"_L1));
5700 case QStyle::SP_DesktopIcon:
5701 return QIcon::fromTheme(name: "user-desktop"_L1);
5702 case QStyle::SP_TrashIcon:
5703 return QIcon::fromTheme(name: "user-trash"_L1);
5704 case QStyle::SP_DriveCDIcon:
5705 case QStyle::SP_DriveDVDIcon:
5706 return QIcon::fromTheme(name: "media-optical"_L1);
5707 case QStyle::SP_DriveHDIcon:
5708 return QIcon::fromTheme(name: "drive-harddisk"_L1);
5709 case QStyle::SP_FileDialogToParent:
5710 return QIcon::fromTheme(name: "go-up"_L1);
5711 case QStyle::SP_FileDialogNewFolder:
5712 return QIcon::fromTheme(name: "folder-new"_L1);
5713 case QStyle::SP_ArrowUp:
5714 return QIcon::fromTheme(name: "go-up"_L1);
5715 case QStyle::SP_ArrowDown:
5716 return QIcon::fromTheme(name: "go-down"_L1);
5717 case QStyle::SP_ArrowRight:
5718 return QIcon::fromTheme(name: "go-next"_L1);
5719 case QStyle::SP_ArrowLeft:
5720 return QIcon::fromTheme(name: "go-previous"_L1);
5721 case QStyle::SP_DialogNoButton:
5722 case QStyle::SP_DialogCancelButton:
5723 return QIcon::fromTheme(name: "dialog-cancel"_L1, fallback: QIcon::fromTheme(name: "process-stop"_L1));
5724 case QStyle::SP_DialogCloseButton:
5725 return QIcon::fromTheme(name: "window-close"_L1);
5726 case QStyle::SP_FileDialogDetailedView:
5727 return QIcon::fromTheme(name: "view-list-details"_L1);
5728 case QStyle::SP_FileDialogListView:
5729 return QIcon::fromTheme(name: "view-list-icons"_L1);
5730 case QStyle::SP_BrowserReload:
5731 return QIcon::fromTheme(name: "view-refresh"_L1);
5732 case QStyle::SP_BrowserStop:
5733 return QIcon::fromTheme(name: "process-stop"_L1);
5734 case QStyle::SP_MediaPlay:
5735 return QIcon::fromTheme(name: "media-playback-start"_L1);
5736 case QStyle::SP_MediaPause:
5737 return QIcon::fromTheme(name: "media-playback-pause"_L1);
5738 case QStyle::SP_MediaStop:
5739 return QIcon::fromTheme(name: "media-playback-stop"_L1);
5740 case QStyle::SP_MediaSeekForward:
5741 return QIcon::fromTheme(name: "media-seek-forward"_L1);
5742 case QStyle::SP_MediaSeekBackward:
5743 return QIcon::fromTheme(name: "media-seek-backward"_L1);
5744 case QStyle::SP_MediaSkipForward:
5745 return QIcon::fromTheme(name: "media-skip-forward"_L1);
5746 case QStyle::SP_MediaSkipBackward:
5747 return QIcon::fromTheme(name: "media-skip-backward"_L1);
5748 case QStyle::SP_MediaVolume:
5749 return QIcon::fromTheme(name: "audio-volume-medium"_L1);
5750 case QStyle::SP_MediaVolumeMuted:
5751 return QIcon::fromTheme(name: "audio-volume-muted"_L1);
5752 case QStyle::SP_ArrowForward:
5753 return iconFromApplicationTheme(standardIcon: rtl(option) ? QStyle::SP_ArrowLeft
5754 : QStyle::SP_ArrowRight,
5755 option, widget);
5756 case QStyle::SP_ArrowBack:
5757 return iconFromApplicationTheme(standardIcon: rtl(option) ? QStyle::SP_ArrowRight
5758 : QStyle::SP_ArrowLeft,
5759 option, widget);
5760 case QStyle::SP_DirLinkIcon:
5761 case QStyle::SP_FileLinkIcon: {
5762 const auto si = (standardIcon == QStyle::SP_DirLinkIcon)
5763 ? QStyle::SP_DirIcon : QStyle::SP_FileIcon;
5764 QIcon icon;
5765 const QIcon linkIcon = QIcon::fromTheme(name: "emblem-symbolic-link"_L1);
5766 const QIcon baseIcon = iconFromApplicationTheme(standardIcon: si, option, widget);
5767 if (!linkIcon.isNull() || !baseIcon.isNull()) {
5768 const auto sizes = baseIcon.availableSizes(mode: QIcon::Normal, state: QIcon::Off);
5769 const auto dpr = qt_getDevicePixelRatio(widget);
5770 for (const auto size : sizes) {
5771 QPixmap basePixmap = baseIcon.pixmap(size, devicePixelRatio: dpr);
5772 QPixmap linkPixmap = linkIcon.pixmap(size: size / 2, devicePixelRatio: dpr);
5773 QPainter painter(&basePixmap);
5774 const auto w = size.width() / 2;
5775 painter.drawPixmap(x: w, y: w, pm: linkPixmap);
5776 icon.addPixmap(pixmap: basePixmap);
5777 }
5778 }
5779 return icon;
5780 }
5781 break;
5782 case QStyle::SP_LineEditClearButton: {
5783 const QString directionalThemeName = rtl(option)
5784 ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl");
5785 if (QIcon::hasThemeIcon(name: directionalThemeName))
5786 return QIcon::fromTheme(name: directionalThemeName);
5787 const QString themeName = QStringLiteral("edit-clear");
5788 if (QIcon::hasThemeIcon(name: themeName))
5789 return QIcon::fromTheme(name: themeName);
5790 break;
5791 }
5792 default:
5793 break;
5794 }
5795 } // if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty())
5796
5797 return {};
5798}
5799
5800QIcon QCommonStylePrivate::iconFromMacTheme(QCommonStyle::StandardPixmap standardIcon,
5801 const QStyleOption *option,
5802 const QWidget *widget) const
5803{
5804#ifdef Q_OS_DARWIN
5805 Q_Q(const QCommonStyle);
5806 if (QGuiApplication::desktopSettingsAware()) {
5807 switch (standardIcon) {
5808 case QStyle::SP_DirIcon: {
5809 // A rather special case
5810 QIcon closeIcon = q->standardIcon(QStyle::SP_DirClosedIcon, option, widget);
5811 QIcon openIcon = q->standardIcon(QStyle::SP_DirOpenIcon, option, widget);
5812 closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On);
5813 closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On);
5814 closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On);
5815 closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On);
5816 return closeIcon;
5817 }
5818
5819 case QStyle::SP_TitleBarNormalButton:
5820 case QStyle::SP_TitleBarCloseButton: {
5821 QIcon titleBarIcon;
5822 constexpr auto imagesPrefix = ":/qt-project.org/styles/macstyle/images/"_L1;
5823 const auto namePrefix = standardIcon == QStyle::SP_TitleBarCloseButton
5824 ? "closedock-"_L1
5825 : "dockdock-"_L1;
5826 for (const auto size : dockTitleIconSizes) {
5827 titleBarIcon.addFile(imagesPrefix + namePrefix + "macstyle-"_L1 + QString::number(size)
5828 + iconPngSuffix(), QSize(size, size), QIcon::Normal, QIcon::Off);
5829 titleBarIcon.addFile(imagesPrefix + namePrefix + "down-macstyle-"_L1 + QString::number(size)
5830 + iconPngSuffix(), QSize(size, size), QIcon::Normal, QIcon::On);
5831 }
5832 return titleBarIcon;
5833 }
5834
5835 case QStyle::SP_MessageBoxQuestion:
5836 case QStyle::SP_MessageBoxInformation:
5837 case QStyle::SP_MessageBoxWarning:
5838 case QStyle::SP_MessageBoxCritical:
5839 case QStyle::SP_DesktopIcon:
5840 case QStyle::SP_TrashIcon:
5841 case QStyle::SP_ComputerIcon:
5842 case QStyle::SP_DriveFDIcon:
5843 case QStyle::SP_DriveHDIcon:
5844 case QStyle::SP_DriveCDIcon:
5845 case QStyle::SP_DriveDVDIcon:
5846 case QStyle::SP_DriveNetIcon:
5847 case QStyle::SP_DirOpenIcon:
5848 case QStyle::SP_DirClosedIcon:
5849 case QStyle::SP_DirLinkIcon:
5850 case QStyle::SP_FileLinkIcon:
5851 case QStyle::SP_FileIcon:
5852 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
5853 QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
5854 QIcon retIcon;
5855 const QList<QSize> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<QSize> >();
5856 for (const QSize &size : sizes) {
5857 QPixmap mainIcon;
5858 const QString cacheKey = "qt_mac_constructQIconFromIconRef"_L1 + QString::number(standardIcon) + QString::number(size.width());
5859 if (standardIcon >= QStyle::SP_CustomBase) {
5860 mainIcon = theme->standardPixmap(sp, QSizeF(size));
5861 } else if (QPixmapCache::find(cacheKey, &mainIcon) == false) {
5862 mainIcon = theme->standardPixmap(sp, QSizeF(size));
5863 QPixmapCache::insert(cacheKey, mainIcon);
5864 }
5865
5866 retIcon.addPixmap(mainIcon);
5867 }
5868 return retIcon;
5869 }
5870
5871 default:
5872 break;
5873 }
5874 } // if (QGuiApplication::desktopSettingsAware())
5875#else // Q_OS_DARWIN
5876 Q_UNUSED(standardIcon);
5877 Q_UNUSED(option);
5878 Q_UNUSED(widget);
5879#endif // Q_OS_DARWIN
5880 return {};
5881}
5882
5883QIcon QCommonStylePrivate::iconFromResourceTheme(QCommonStyle::StandardPixmap standardIcon,
5884 const QStyleOption *option,
5885 const QWidget *widget) const
5886{
5887 Q_Q(const QCommonStyle);
5888 QIcon icon;
5889#ifndef QT_NO_IMAGEFORMAT_PNG
5890 switch (standardIcon) {
5891 case QStyle::SP_MessageBoxInformation:
5892 addIconFiles(prefix: u"information-", sizes: pngIconSizes, icon);
5893 break;
5894 case QStyle::SP_MessageBoxWarning:
5895 addIconFiles(prefix: u"warning-", sizes: pngIconSizes, icon);
5896 break;
5897 case QStyle::SP_MessageBoxCritical:
5898 addIconFiles(prefix: u"critical-", sizes: pngIconSizes, icon);
5899 break;
5900 case QStyle::SP_MessageBoxQuestion:
5901 addIconFiles(prefix: u"question-", sizes: pngIconSizes, icon);
5902 break;
5903 case QStyle::SP_FileDialogStart:
5904 addIconFiles(prefix: u"filedialog_start-", sizes: pngIconSizes, icon);
5905 break;
5906 case QStyle::SP_FileDialogEnd:
5907 addIconFiles(prefix: u"filedialog_end-", sizes: pngIconSizes, icon);
5908 break;
5909 case QStyle::SP_TitleBarMinButton:
5910 addIconFiles(prefix: u"titlebar-min-", sizes: titleBarSizes, icon);
5911 break;
5912 case QStyle::SP_TitleBarMaxButton:
5913 addIconFiles(prefix: u"titlebar-max-", sizes: titleBarSizes, icon);
5914 break;
5915 case QStyle::SP_TitleBarShadeButton:
5916 addIconFiles(prefix: u"titlebar-shade-", sizes: titleBarSizes, icon);
5917 break;
5918 case QStyle::SP_TitleBarUnshadeButton:
5919 addIconFiles(prefix: u"titlebar-unshade-", sizes: titleBarSizes, icon);
5920 break;
5921 case QStyle::SP_TitleBarContextHelpButton:
5922 addIconFiles(prefix: u"titlebar-contexthelp-", sizes: titleBarSizes, icon);
5923 break;
5924 case QStyle::SP_FileDialogNewFolder:
5925 addIconFiles(prefix: u"newdirectory-", sizes: pngIconSizes, icon);
5926 break;
5927 case QStyle::SP_FileDialogBack:
5928 return q->proxy()->standardIcon(standardIcon: QStyle::SP_ArrowBack, option, widget);
5929 case QStyle::SP_FileDialogToParent:
5930 return q->proxy()->standardIcon(standardIcon: QStyle::SP_ArrowUp, option, widget);
5931 case QStyle::SP_FileDialogDetailedView:
5932 addIconFiles(prefix: u"viewdetailed-", sizes: pngIconSizes, icon);
5933 break;
5934 case QStyle::SP_FileDialogInfoView:
5935 addIconFiles(prefix: u"fileinfo-", sizes: pngIconSizes, icon);
5936 break;
5937 case QStyle::SP_FileDialogContentsView:
5938 addIconFiles(prefix: u"filecontents-", sizes: pngIconSizes, icon);
5939 break;
5940 case QStyle::SP_FileDialogListView:
5941 addIconFiles(prefix: u"viewlist-", sizes: pngIconSizes, icon);
5942 break;
5943 case QStyle::SP_DialogOkButton:
5944 addIconFiles(prefix: u"standardbutton-ok-", sizes: pngIconSizes, icon);
5945 break;
5946 case QStyle::SP_DialogCancelButton:
5947 addIconFiles(prefix: u"standardbutton-cancel-", sizes: pngIconSizes, icon);
5948 break;
5949 case QStyle::SP_DialogHelpButton:
5950 addIconFiles(prefix: u"standardbutton-help-", sizes: pngIconSizes, icon);
5951 break;
5952 case QStyle::SP_DialogOpenButton:
5953 addIconFiles(prefix: u"standardbutton-open-", sizes: pngIconSizes, icon);
5954 break;
5955 case QStyle::SP_DialogSaveButton:
5956 addIconFiles(prefix: u"standardbutton-save-", sizes: pngIconSizes, icon);
5957 break;
5958 case QStyle::SP_DialogCloseButton:
5959 addIconFiles(prefix: u"standardbutton-close-", sizes: pngIconSizes, icon);
5960 break;
5961 case QStyle::SP_DialogApplyButton:
5962 addIconFiles(prefix: u"standardbutton-apply-", sizes: pngIconSizes, icon);
5963 break;
5964 case QStyle::SP_DialogResetButton:
5965 addIconFiles(prefix: u"standardbutton-clear-", sizes: pngIconSizes, icon);
5966 break;
5967 case QStyle::SP_DialogDiscardButton:
5968 addIconFiles(prefix: u"standardbutton-delete-", sizes: pngIconSizes, icon);
5969 break;
5970 case QStyle::SP_DialogYesButton:
5971 addIconFiles(prefix: u"standardbutton-yes-", sizes: pngIconSizes, icon);
5972 break;
5973 case QStyle::SP_DialogNoButton:
5974 addIconFiles(prefix: u"standardbutton-no-", sizes: pngIconSizes, icon);
5975 break;
5976 case QStyle::SP_CommandLink:
5977 case QStyle::SP_ArrowForward:
5978 return q->proxy()->standardIcon(standardIcon: rtl(option) ? QStyle::SP_ArrowLeft
5979 : QStyle::SP_ArrowRight,
5980 option, widget);
5981 case QStyle::SP_ArrowBack:
5982 return q->proxy()->standardIcon(standardIcon: rtl(option) ? QStyle::SP_ArrowRight
5983 : QStyle::SP_ArrowLeft,
5984 option, widget);
5985 case QStyle::SP_ArrowLeft:
5986 addIconFiles(prefix: u"left-", sizes: pngIconSizes, icon);
5987 break;
5988 case QStyle::SP_ArrowRight:
5989 addIconFiles(prefix: u"right-", sizes: pngIconSizes, icon);
5990 break;
5991 case QStyle::SP_ArrowUp:
5992 addIconFiles(prefix: u"up-", sizes: pngIconSizes, icon);
5993 break;
5994 case QStyle::SP_ArrowDown:
5995 addIconFiles(prefix: u"down-", sizes: pngIconSizes, icon);
5996 break;
5997 case QStyle::SP_DirHomeIcon:
5998 case QStyle::SP_DirIcon:
5999 addIconFiles(prefix: u"dirclosed-", sizes: pngIconSizes, icon, mode: QIcon::Normal, state: QIcon::Off);
6000 addIconFiles(prefix: u"diropen-", sizes: pngIconSizes, icon, mode: QIcon::Normal, state: QIcon::On);
6001 break;
6002 case QStyle::SP_DirOpenIcon:
6003 addIconFiles(prefix: u"diropen-", sizes: pngIconSizes, icon);
6004 break;
6005 case QStyle::SP_DirClosedIcon:
6006 addIconFiles(prefix: u"dirclosed-", sizes: pngIconSizes, icon);
6007 break;
6008 case QStyle::SP_DirLinkIcon:
6009 addIconFiles(prefix: u"dirlink-", sizes: pngIconSizes, icon);
6010 break;
6011 case QStyle::SP_DriveCDIcon:
6012 addIconFiles(prefix: u"cdr-", sizes: pngIconSizes, icon);
6013 break;
6014 case QStyle::SP_DriveFDIcon:
6015 addIconFiles(prefix: u"floppy-", sizes: pngIconSizes, icon);
6016 break;
6017 case QStyle::SP_DriveHDIcon:
6018 addIconFiles(prefix: u"harddrive-", sizes: pngIconSizes, icon);
6019 break;
6020 case QStyle::SP_DriveDVDIcon:
6021 addIconFiles(prefix: u"dvd-", sizes: pngIconSizes, icon);
6022 break;
6023 case QStyle::SP_DriveNetIcon:
6024 addIconFiles(prefix: u"networkdrive-", sizes: pngIconSizes, icon);
6025 break;
6026 case QStyle::SP_FileIcon:
6027 addIconFiles(prefix: u"file-", sizes: pngIconSizes, icon);
6028 break;
6029 case QStyle::SP_FileLinkIcon:
6030 addIconFiles(prefix: u"filelink-", sizes: pngIconSizes, icon);
6031 break;
6032 case QStyle::SP_DesktopIcon:
6033 addIconFiles(prefix: u"desktop-", sizes: {16, 32}, icon);
6034 break;
6035 case QStyle::SP_TrashIcon:
6036 addIconFiles(prefix: u"trash-", sizes: pngIconSizes, icon);
6037 break;
6038 case QStyle::SP_ComputerIcon:
6039 addIconFiles(prefix: u"computer-", sizes: {16, 32}, icon);
6040 break;
6041 case QStyle::SP_BrowserReload:
6042 addIconFiles(prefix: u"refresh-", sizes: {24, 32}, icon);
6043 break;
6044 case QStyle::SP_BrowserStop:
6045 addIconFiles(prefix: u"stop-", sizes: {24, 32}, icon);
6046 break;
6047 case QStyle::SP_MediaPlay:
6048 addIconFiles(prefix: u"media-play-", sizes: pngIconSizes, icon);
6049 break;
6050 case QStyle::SP_MediaPause:
6051 addIconFiles(prefix: u"media-pause-", sizes: pngIconSizes, icon);
6052 break;
6053 case QStyle::SP_MediaStop:
6054 addIconFiles(prefix: u"media-stop-", sizes: pngIconSizes, icon);
6055 break;
6056 case QStyle::SP_MediaSeekForward:
6057 addIconFiles(prefix: u"media-seek-forward-", sizes: pngIconSizes, icon);
6058 break;
6059 case QStyle::SP_MediaSeekBackward:
6060 addIconFiles(prefix: u"media-seek-backward-", sizes: pngIconSizes, icon);
6061 break;
6062 case QStyle::SP_MediaSkipForward:
6063 addIconFiles(prefix: u"media-skip-forward-", sizes: pngIconSizes, icon);
6064 break;
6065 case QStyle::SP_MediaSkipBackward:
6066 addIconFiles(prefix: u"media-skip-backward-", sizes: pngIconSizes, icon);
6067 break;
6068 case QStyle::SP_MediaVolume:
6069 addIconFiles(prefix: u"media-volume-", sizes: {16}, icon);
6070 break;
6071 case QStyle::SP_MediaVolumeMuted:
6072 addIconFiles(prefix: u"media-volume-muted-", sizes: {16}, icon);
6073 break;
6074 case QStyle::SP_TitleBarCloseButton:
6075 case QStyle::SP_DockWidgetCloseButton:
6076 addIconFiles(prefix: u"closedock-", sizes: dockTitleIconSizes, icon);
6077 break;
6078 case QStyle::SP_TitleBarMenuButton:
6079# ifndef QT_NO_IMAGEFORMAT_XPM
6080 icon.addPixmap(pixmap: titleBarMenuCachedPixmapFromXPM());
6081# endif
6082 icon.addFile(fileName: ":/qt-project.org/qmessagebox/images/qtlogo-64.png"_L1);
6083 break;
6084 case QStyle::SP_TitleBarNormalButton:
6085 addIconFiles(prefix: u"normalizedockup-", sizes: dockTitleIconSizes, icon);
6086 break;
6087 case QStyle::SP_ToolBarHorizontalExtensionButton:
6088 addIconFiles(prefix: rtl(option) ? u"toolbar-ext-h-rtl-" : u"toolbar-ext-h-", sizes: toolBarExtHSizes, icon);
6089 break;
6090 case QStyle::SP_ToolBarVerticalExtensionButton:
6091 addIconFiles(prefix: u"toolbar-ext-v-", sizes: toolBarExtVSizes, icon);
6092 break;
6093 case QStyle::SP_TabCloseButton:
6094 addIconFiles(prefix: u"standardbutton-closetab-", sizes: pngIconSizes, icon, mode: QIcon::Normal, state: QIcon::Off);
6095 addIconFiles(prefix: u"standardbutton-closetab-down-", sizes: pngIconSizes, icon, mode: QIcon::Normal, state: QIcon::On);
6096 addIconFiles(prefix: u"standardbutton-closetab-hover-", sizes: pngIconSizes, icon, mode: QIcon::Active, state: QIcon::Off);
6097 break;
6098 case QStyle::SP_LineEditClearButton:
6099 addIconFiles(prefix: u"cleartext-", sizes: pngIconSizes, icon);
6100 break;
6101 default:
6102 break;
6103 }
6104#else // QT_NO_IMAGEFORMAT_PNG
6105 Q_UNUSED(standardIcon);
6106 Q_UNUSED(option);
6107 Q_UNUSED(widget);
6108#endif // QT_NO_IMAGEFORMAT_PNG
6109 return icon;
6110}
6111
6112
6113/*!
6114 \internal
6115*/
6116QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option,
6117 const QWidget *widget) const
6118{
6119 Q_D(const QCommonStyle);
6120 QIcon icon;
6121
6122 icon = d->iconFromWindowsTheme(standardIcon, option, widget);
6123 if (!icon.isNull())
6124 return icon;
6125
6126 icon = d->iconFromApplicationTheme(standardIcon, option, widget);
6127 if (!icon.isNull())
6128 return icon;
6129
6130 icon = d->iconFromMacTheme(standardIcon, option, widget);
6131 if (!icon.isNull())
6132 return icon;
6133
6134 icon = d->iconFromResourceTheme(standardIcon, option, widget);
6135 if (!icon.isNull())
6136 return icon;
6137
6138#ifndef QT_NO_IMAGEFORMAT_XPM
6139 switch (standardIcon) {
6140 case QStyle::SP_TitleBarMenuButton:
6141 icon.addPixmap(pixmap: titleBarMenuCachedPixmapFromXPM());
6142 break;
6143 default:
6144 break;
6145 }
6146 if (!icon.isNull())
6147 return icon;
6148#endif
6149 icon = proxy()->standardPixmap(standardPixmap: standardIcon, opt: option, widget);
6150 return icon;
6151}
6152
6153static inline uint qt_intensity(uint r, uint g, uint b)
6154{
6155 // 30% red, 59% green, 11% blue
6156 return (77 * r + 150 * g + 28 * b) / 255;
6157}
6158
6159/*! \reimp */
6160QPixmap QCommonStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
6161 const QStyleOption *opt) const
6162{
6163 switch (iconMode) {
6164 case QIcon::Disabled: {
6165 QImage im = pixmap.toImage().convertToFormat(f: QImage::Format_ARGB32);
6166
6167 // Create a colortable based on the background (black -> bg -> white)
6168 QColor bg = opt->palette.color(cg: QPalette::Disabled, cr: QPalette::Window);
6169 int red = bg.red();
6170 int green = bg.green();
6171 int blue = bg.blue();
6172 uchar reds[256], greens[256], blues[256];
6173 for (int i=0; i<128; ++i) {
6174 reds[i] = uchar((red * (i<<1)) >> 8);
6175 greens[i] = uchar((green * (i<<1)) >> 8);
6176 blues[i] = uchar((blue * (i<<1)) >> 8);
6177 }
6178 for (int i=0; i<128; ++i) {
6179 reds[i+128] = uchar(qMin(a: red + (i << 1), b: 255));
6180 greens[i+128] = uchar(qMin(a: green + (i << 1), b: 255));
6181 blues[i+128] = uchar(qMin(a: blue + (i << 1), b: 255));
6182 }
6183
6184 int intensity = qt_intensity(r: red, g: green, b: blue);
6185 const int factor = 191;
6186
6187 // High intensity colors needs dark shifting in the color table, while
6188 // low intensity colors needs light shifting. This is to increase the
6189 // perceived contrast.
6190 if ((red - factor > green && red - factor > blue)
6191 || (green - factor > red && green - factor > blue)
6192 || (blue - factor > red && blue - factor > green))
6193 intensity = qMin(a: 255, b: intensity + 91);
6194 else if (intensity <= 128)
6195 intensity -= 51;
6196
6197 for (int y=0; y<im.height(); ++y) {
6198 QRgb *scanLine = (QRgb*)im.scanLine(y);
6199 for (int x=0; x<im.width(); ++x) {
6200 QRgb pixel = *scanLine;
6201 // Calculate color table index, taking intensity adjustment
6202 // and a magic offset into account.
6203 uint ci = uint(qGray(rgb: pixel)/3 + (130 - intensity / 3));
6204 *scanLine = qRgba(r: reds[ci], g: greens[ci], b: blues[ci], a: qAlpha(rgb: pixel));
6205 ++scanLine;
6206 }
6207 }
6208
6209 return QPixmap::fromImage(image: std::move(im));
6210 }
6211 case QIcon::Selected: {
6212 QImage img = pixmap.toImage().convertToFormat(f: QImage::Format_ARGB32_Premultiplied);
6213 QColor color = opt->palette.color(cg: QPalette::Normal, cr: QPalette::Highlight);
6214 color.setAlphaF(0.3f);
6215 QPainter painter(&img);
6216 painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
6217 painter.fillRect(x: 0, y: 0, w: img.width(), h: img.height(), b: color);
6218 painter.end();
6219 return QPixmap::fromImage(image: std::move(img)); }
6220 case QIcon::Active:
6221 return pixmap;
6222 default:
6223 break;
6224 }
6225 return pixmap;
6226}
6227
6228/*!
6229 \reimp
6230*/
6231int QCommonStyle::layoutSpacing(QSizePolicy::ControlType /* control1 */, QSizePolicy::ControlType /* control2 */,
6232 Qt::Orientation /* orientation */, const QStyleOption * /* option */,
6233 const QWidget * /* widget */) const
6234{
6235 return -1;
6236}
6237
6238/*!
6239 \reimp
6240*/
6241void QCommonStyle::polish(QPalette &pal)
6242{
6243 QStyle::polish(palette&: pal);
6244}
6245
6246/*!
6247 \reimp
6248 */
6249void QCommonStyle::polish(QWidget *widget)
6250{
6251 QStyle::polish(widget);
6252}
6253
6254/*!
6255 \reimp
6256 */
6257void QCommonStyle::unpolish(QWidget *widget)
6258{
6259 QStyle::unpolish(widget);
6260}
6261
6262/*!
6263 \reimp
6264*/
6265void QCommonStyle::polish(QApplication *app)
6266{
6267 QStyle::polish(application: app);
6268}
6269
6270/*!
6271 \reimp
6272 */
6273void QCommonStyle::unpolish(QApplication *application)
6274{
6275 Q_D(const QCommonStyle);
6276 d->tabBarcloseButtonIcon = QIcon();
6277 QStyle::unpolish(application);
6278}
6279
6280
6281QT_END_NAMESPACE
6282
6283#include "moc_qcommonstyle.cpp"
6284

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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