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