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