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

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