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