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