1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qfusionstyle_p.h"
5#include "qfusionstyle_p_p.h"
6
7#if QT_CONFIG(style_fusion) || defined(QT_PLUGIN)
8#include "qcommonstyle_p.h"
9#if QT_CONFIG(combobox)
10#include <qcombobox.h>
11#endif
12#if QT_CONFIG(pushbutton)
13#include <qpushbutton.h>
14#endif
15#if QT_CONFIG(abstractbutton)
16#include <qabstractbutton.h>
17#endif
18#include <qpainter.h>
19#include <qpainterpath.h>
20#include <qpainterstateguard.h>
21#include <qdir.h>
22#include <qstyleoption.h>
23#include <qapplication.h>
24#if QT_CONFIG(mainwindow)
25#include <qmainwindow.h>
26#endif
27#include <qfont.h>
28#if QT_CONFIG(groupbox)
29#include <qgroupbox.h>
30#endif
31#include <qpixmapcache.h>
32#if QT_CONFIG(scrollbar)
33#include <qscrollbar.h>
34#endif
35#if QT_CONFIG(spinbox)
36#include <qspinbox.h>
37#endif
38#if QT_CONFIG(abstractslider)
39#include <qabstractslider.h>
40#endif
41#if QT_CONFIG(slider)
42#include <qslider.h>
43#endif
44#if QT_CONFIG(splitter)
45#include <qsplitter.h>
46#endif
47#if QT_CONFIG(progressbar)
48#include <qprogressbar.h>
49#endif
50#if QT_CONFIG(wizard)
51#include <qwizard.h>
52#endif
53#include <qdrawutil.h>
54#include <private/qstylehelper_p.h>
55#include <private/qdrawhelper_p.h>
56#include <private/qapplication_p.h>
57#include <private/qwidget_p.h>
58
59QT_BEGIN_NAMESPACE
60
61using namespace Qt::StringLiterals;
62using namespace QStyleHelper;
63
64enum Direction {
65 TopDown,
66 FromLeft,
67 BottomUp,
68 FromRight
69};
70
71// from windows style
72static const int windowsItemFrame = 2; // menu item frame width
73static const int windowsItemVMargin = 8; // menu item ver text margin
74
75static const int groupBoxBottomMargin = 0; // space below the groupbox
76static const int groupBoxTopMargin = 3;
77
78#if QT_CONFIG(imageformat_xpm)
79static const char * const qt_titlebar_context_help[] = {
80 "10 10 3 1",
81 " c None",
82 "# c #000000",
83 "+ c #444444",
84 " +####+ ",
85 " ### ### ",
86 " ## ## ",
87 " +##+ ",
88 " +## ",
89 " ## ",
90 " ## ",
91 " ",
92 " ## ",
93 " ## "};
94#endif // QT_CONFIG(imageformat_xpm)
95
96static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50)
97{
98 const int maxFactor = 100;
99 QColor tmp = colorA;
100 tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
101 tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
102 tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
103 return tmp;
104}
105
106// The default button and handle gradient
107static QLinearGradient qt_fusion_gradient(const QRect &rect, const QBrush &baseColor, Direction direction = TopDown)
108{
109 int x = rect.center().x();
110 int y = rect.center().y();
111 QLinearGradient gradient;
112 switch (direction) {
113 case FromLeft:
114 gradient = QLinearGradient(rect.left(), y, rect.right(), y);
115 break;
116 case FromRight:
117 gradient = QLinearGradient(rect.right(), y, rect.left(), y);
118 break;
119 case BottomUp:
120 gradient = QLinearGradient(x, rect.bottom(), x, rect.top());
121 break;
122 case TopDown:
123 default:
124 gradient = QLinearGradient(x, rect.top(), x, rect.bottom());
125 break;
126 }
127 if (baseColor.gradient())
128 gradient.setStops(baseColor.gradient()->stops());
129 else {
130 QColor gradientStartColor = baseColor.color().lighter(f: 124);
131 QColor gradientStopColor = baseColor.color().lighter(f: 102);
132 gradient.setColorAt(pos: 0, color: gradientStartColor);
133 gradient.setColorAt(pos: 1, color: gradientStopColor);
134 // Uncomment for adding shiny shading
135 // QColor midColor1 = mergedColors(gradientStartColor, gradientStopColor, 55);
136 // QColor midColor2 = mergedColors(gradientStartColor, gradientStopColor, 45);
137 // gradient.setColorAt(0.5, midColor1);
138 // gradient.setColorAt(0.501, midColor2);
139 }
140 return gradient;
141}
142
143static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QStyleOption *option, const QRect &rect, const QColor &color)
144{
145 if (rect.isEmpty())
146 return;
147
148 const qreal dpi = QStyleHelper::dpi(option);
149 const int arrowWidth = int(QStyleHelper::dpiScaled(value: 14, dpi));
150 const int arrowHeight = int(QStyleHelper::dpiScaled(value: 8, dpi));
151
152 const int arrowMax = qMin(a: arrowHeight, b: arrowWidth);
153 const int rectMax = qMin(a: rect.height(), b: rect.width());
154 const int size = qMin(a: arrowMax, b: rectMax);
155
156 const QString pixmapName = "fusion-arrow"_L1
157 % HexString<uint>(type)
158 % HexString<uint>(color.rgba());
159 QCachedPainter cp(painter, pixmapName, option, rect.size(), rect);
160 if (cp.needsPainting()) {
161 QRectF arrowRect(0, 0, size, arrowHeight * size / arrowWidth);
162 if (type == Qt::LeftArrow || type == Qt::RightArrow)
163 arrowRect = arrowRect.transposed();
164 arrowRect.moveTo(ax: (rect.width() - arrowRect.width()) / 2.0,
165 ay: (rect.height() - arrowRect.height()) / 2.0);
166
167 std::array<QPointF, 3> triangle;
168 switch (type) {
169 case Qt::DownArrow:
170 triangle = {arrowRect.topLeft(), arrowRect.topRight(), QPointF(arrowRect.center().x(), arrowRect.bottom())};
171 break;
172 case Qt::RightArrow:
173 triangle = {arrowRect.topLeft(), arrowRect.bottomLeft(), QPointF(arrowRect.right(), arrowRect.center().y())};
174 break;
175 case Qt::LeftArrow:
176 triangle = {arrowRect.topRight(), arrowRect.bottomRight(), QPointF(arrowRect.left(), arrowRect.center().y())};
177 break;
178 default:
179 triangle = {arrowRect.bottomLeft(), arrowRect.bottomRight(), QPointF(arrowRect.center().x(), arrowRect.top())};
180 break;
181 }
182
183 cp->setPen(Qt::NoPen);
184 cp->setBrush(color);
185 cp->setRenderHint(hint: QPainter::Antialiasing);
186 cp->drawPolygon(points: triangle.data(), pointCount: int(triangle.size()));
187 }
188}
189
190static void qt_fusion_draw_mdibutton(QPainter *painter, const QStyleOptionTitleBar *option, const QRect &tmp, bool hover, bool sunken)
191{
192 bool active = (option->titleBarState & QStyle::State_Active);
193 const QColor dark = QColor::fromHsv(h: option->palette.button().color().hue(),
194 s: qMin(a: 255, b: option->palette.button().color().saturation()),
195 v: qMin(a: 255, b: int(option->palette.button().color().value() * 0.7)));
196 const QColor highlight = option->palette.highlight().color();
197 const QColor titleBarHighlight(sunken ? highlight.darker(f: 130) : QColor(255, 255, 255, 60));
198 const QColor mdiButtonBorderColor(active ? highlight.darker(f: 180): dark.darker(f: 110));
199
200 if (sunken)
201 painter->fillRect(tmp.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1), color: highlight.darker(f: 120));
202 else if (hover)
203 painter->fillRect(tmp.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1), color: QColor(255, 255, 255, 20));
204
205 const QColor mdiButtonGradientStartColor(0, 0, 0, 40);
206 const QColor mdiButtonGradientStopColor(255, 255, 255, 60);
207
208 QLinearGradient gradient(tmp.center().x(), tmp.top(), tmp.center().x(), tmp.bottom());
209 gradient.setColorAt(pos: 0, color: mdiButtonGradientStartColor);
210 gradient.setColorAt(pos: 1, color: mdiButtonGradientStopColor);
211
212 painter->setPen(mdiButtonBorderColor);
213 const QLine lines[4] = {
214 QLine(tmp.left() + 2, tmp.top(), tmp.right() - 2, tmp.top()),
215 QLine(tmp.left() + 2, tmp.bottom(), tmp.right() - 2, tmp.bottom()),
216 QLine(tmp.left(), tmp.top() + 2, tmp.left(), tmp.bottom() - 2),
217 QLine(tmp.right(), tmp.top() + 2, tmp.right(), tmp.bottom() - 2)
218 };
219 painter->drawLines(lines, lineCount: 4);
220 const QPoint points[4] = {
221 QPoint(tmp.left() + 1, tmp.top() + 1),
222 QPoint(tmp.right() - 1, tmp.top() + 1),
223 QPoint(tmp.left() + 1, tmp.bottom() - 1),
224 QPoint(tmp.right() - 1, tmp.bottom() - 1)
225 };
226 painter->drawPoints(points, pointCount: 4);
227
228 painter->setPen(titleBarHighlight);
229 painter->drawLine(x1: tmp.left() + 2, y1: tmp.top() + 1, x2: tmp.right() - 2, y2: tmp.top() + 1);
230 painter->drawLine(x1: tmp.left() + 1, y1: tmp.top() + 2, x2: tmp.left() + 1, y2: tmp.bottom() - 2);
231
232 painter->setPen(QPen(gradient, 1));
233 painter->drawLine(x1: tmp.right() + 1, y1: tmp.top() + 2, x2: tmp.right() + 1, y2: tmp.bottom() - 2);
234 painter->drawPoint(x: tmp.right() , y: tmp.top() + 1);
235
236 painter->drawLine(x1: tmp.left() + 2, y1: tmp.bottom() + 1, x2: tmp.right() - 2, y2: tmp.bottom() + 1);
237 painter->drawPoint(x: tmp.left() + 1, y: tmp.bottom());
238 painter->drawPoint(x: tmp.right() - 1, y: tmp.bottom());
239 painter->drawPoint(x: tmp.right() , y: tmp.bottom() - 1);
240}
241
242/*
243 \internal
244*/
245QFusionStylePrivate::QFusionStylePrivate()
246{
247 animationFps = 60;
248}
249
250/*!
251 \class QFusionStyle
252 \brief The QFusionStyle class provides a custom widget style
253
254 \inmodule QtWidgets
255 \internal
256
257 The Fusion style provides a custom look and feel that is not
258 tied to a particular platform.
259 //{Fusion Style Widget Gallery}
260 \sa QWindowsStyle, QWindowsVistaStyle, QMacStyle, QCommonStyle
261*/
262
263/*!
264 Constructs a QFusionStyle object.
265*/
266QFusionStyle::QFusionStyle() : QCommonStyle(*new QFusionStylePrivate)
267{
268 setObjectName("Fusion"_L1);
269}
270
271/*!
272 \internal
273
274 Constructs a QFusionStyle object.
275*/
276QFusionStyle::QFusionStyle(QFusionStylePrivate &dd) : QCommonStyle(dd)
277{
278}
279
280/*!
281 Destroys the QFusionStyle object.
282*/
283QFusionStyle::~QFusionStyle()
284{
285}
286
287/*!
288 \reimp
289*/
290void QFusionStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal,
291 bool enabled, const QString& text, QPalette::ColorRole textRole) const
292{
293 Q_UNUSED(enabled);
294 if (text.isEmpty())
295 return;
296
297 QPen savedPen = painter->pen();
298 if (textRole != QPalette::NoRole)
299 painter->setPen(QPen(pal.brush(cr: textRole), savedPen.widthF()));
300 painter->drawText(r: rect, flags: alignment, text);
301 painter->setPen(savedPen);
302}
303
304
305/*!
306 \reimp
307*/
308void QFusionStyle::drawPrimitive(PrimitiveElement elem,
309 const QStyleOption *option,
310 QPainter *painter, const QWidget *widget) const
311{
312 Q_ASSERT(option);
313 Q_D (const QFusionStyle);
314
315 const QColor outline = d->outline(pal: option->palette);
316 const QColor highlightedOutline = d->highlightedOutline(pal: option->palette);
317
318 switch (elem) {
319
320#if QT_CONFIG(groupbox)
321 // No frame drawn
322 case PE_FrameGroupBox:
323 {
324 const auto strFrameGroupBox = QStringLiteral(u"fusion_groupbox");
325 QPixmap pixmap;
326 if (!QPixmapCache::find(key: strFrameGroupBox, pixmap: &pixmap)) {
327 pixmap.load(fileName: ":/qt-project.org/styles/commonstyle/images/fusion_groupbox.png"_L1);
328 QPixmapCache::insert(key: strFrameGroupBox, pixmap);
329 }
330 qDrawBorderPixmap(painter, target: option->rect, margins: QMargins(6, 6, 6, 6), pixmap);
331 break;
332 }
333#endif // QT_CONFIG(groupbox)
334 case PE_IndicatorBranch: {
335 if (!(option->state & State_Children))
336 break;
337 if (option->state & State_Open)
338 drawPrimitive(elem: PE_IndicatorArrowDown, option, painter, widget);
339 else {
340 const bool reverse = (option->direction == Qt::RightToLeft);
341 drawPrimitive(elem: reverse ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight, option, painter, widget);
342 }
343 break;
344 }
345#if QT_CONFIG(tabbar)
346 case PE_FrameTabBarBase:
347 if (const QStyleOptionTabBarBase *tbb
348 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt: option)) {
349 painter->save();
350 painter->setPen(outline.lighter(f: 110));
351 switch (tbb->shape) {
352 case QTabBar::RoundedNorth: {
353 QRegion region(tbb->rect);
354 region -= tbb->selectedTabRect;
355 painter->drawLine(p1: tbb->rect.topLeft(), p2: tbb->rect.topRight());
356 painter->setClipRegion(region);
357 painter->setPen(option->palette.light().color());
358 painter->drawLine(p1: tbb->rect.topLeft() + QPoint(0, 1), p2: tbb->rect.topRight() + QPoint(0, 1));
359 }
360 break;
361 case QTabBar::RoundedWest:
362 painter->drawLine(x1: tbb->rect.left(), y1: tbb->rect.top(), x2: tbb->rect.left(), y2: tbb->rect.bottom());
363 break;
364 case QTabBar::RoundedSouth:
365 painter->drawLine(x1: tbb->rect.left(), y1: tbb->rect.bottom(),
366 x2: tbb->rect.right(), y2: tbb->rect.bottom());
367 break;
368 case QTabBar::RoundedEast:
369 painter->drawLine(p1: tbb->rect.topRight(), p2: tbb->rect.bottomRight());
370 break;
371 case QTabBar::TriangularNorth:
372 case QTabBar::TriangularEast:
373 case QTabBar::TriangularWest:
374 case QTabBar::TriangularSouth:
375 painter->restore();
376 QCommonStyle::drawPrimitive(pe: elem, opt: option, p: painter, w: widget);
377 return;
378 }
379 painter->restore();
380 }
381 return;
382#endif // QT_CONFIG(tabbar)
383 case PE_PanelScrollAreaCorner: {
384 painter->save();
385 QColor alphaOutline = outline;
386 alphaOutline.setAlpha(180);
387 painter->setPen(alphaOutline);
388 painter->setBrush(option->palette.brush(cr: QPalette::Window));
389 painter->drawRect(r: option->rect);
390 painter->restore();
391 } break;
392 case PE_IndicatorArrowUp:
393 case PE_IndicatorArrowDown:
394 case PE_IndicatorArrowRight:
395 case PE_IndicatorArrowLeft:
396 {
397 if (option->rect.width() <= 1 || option->rect.height() <= 1)
398 break;
399 QColor arrowColor = option->palette.windowText().color();
400 arrowColor.setAlpha(160);
401 Qt::ArrowType arrow = Qt::UpArrow;
402 switch (elem) {
403 case PE_IndicatorArrowDown:
404 arrow = Qt::DownArrow;
405 break;
406 case PE_IndicatorArrowRight:
407 arrow = Qt::RightArrow;
408 break;
409 case PE_IndicatorArrowLeft:
410 arrow = Qt::LeftArrow;
411 break;
412 default:
413 break;
414 }
415 qt_fusion_draw_arrow(type: arrow, painter, option, rect: option->rect, color: arrowColor);
416 }
417 break;
418 case PE_IndicatorItemViewItemCheck:
419 {
420 QStyleOptionButton button;
421 button.QStyleOption::operator=(other: *option);
422 button.state &= ~State_MouseOver;
423 proxy()->drawPrimitive(pe: PE_IndicatorCheckBox, opt: &button, p: painter, w: widget);
424 }
425 return;
426 case PE_IndicatorHeaderArrow:
427 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt: option)) {
428 const QRect r = header->rect.translated(dx: 0, dy: -2);
429 QColor arrowColor = header->palette.windowText().color();
430 arrowColor.setAlpha(180);
431
432 Qt::ArrowType arrowType = Qt::UpArrow;
433#if defined(Q_OS_LINUX)
434 if (header->sortIndicator & QStyleOptionHeader::SortDown)
435 arrowType = Qt::DownArrow;
436#else
437 if (header->sortIndicator & QStyleOptionHeader::SortUp)
438 arrowType = Qt::DownArrow;
439#endif
440 qt_fusion_draw_arrow(type: arrowType, painter, option, rect: r, color: arrowColor);
441 }
442 break;
443 case PE_IndicatorButtonDropDown:
444 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: option, p: painter, w: widget);
445 break;
446
447 case PE_IndicatorToolBarSeparator:
448 {
449 const QRect &rect = option->rect;
450 const int margin = 6;
451 const QColor col = option->palette.window().color();
452 painter->setPen(col.darker(f: 110));
453 if (option->state & State_Horizontal) {
454 const int offset = rect.width() / 2;
455 painter->drawLine(x1: rect.left() + offset, y1: rect.bottom() - margin,
456 x2: rect.left() + offset, y2: rect.top() + margin);
457 painter->setPen(col.lighter(f: 110));
458 painter->drawLine(x1: rect.left() + offset + 1, y1: rect.bottom() - margin,
459 x2: rect.left() + offset + 1, y2: rect.top() + margin);
460 } else { //Draw vertical separator
461 const int offset = rect.height() / 2;
462 painter->drawLine(x1: rect.left() + margin, y1: rect.top() + offset,
463 x2: rect.right() - margin, y2: rect.top() + offset);
464 painter->setPen(col.lighter(f: 110));
465 painter->drawLine(x1: rect.left() + margin, y1: rect.top() + offset + 1,
466 x2: rect.right() - margin, y2: rect.top() + offset + 1);
467 }
468 }
469 break;
470 case PE_Frame: {
471 if (widget && widget->inherits(classname: "QComboBoxPrivateContainer")){
472 QStyleOption copy = *option;
473 copy.state |= State_Raised;
474 proxy()->drawPrimitive(pe: PE_PanelMenu, opt: &copy, p: painter, w: widget);
475 break;
476 }
477 painter->save();
478 painter->setPen(outline.lighter(f: 108));
479 painter->drawRect(r: option->rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
480 painter->restore(); }
481 break;
482 case PE_FrameMenu:
483 painter->save();
484 {
485 painter->setPen(outline);
486 painter->drawRect(r: option->rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
487 QColor frameLight = option->palette.window().color().lighter(f: 160);
488 QColor frameShadow = option->palette.window().color().darker(f: 110);
489
490 //paint beveleffect
491 QRect frame = option->rect.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1);
492 painter->setPen(frameLight);
493 painter->drawLine(p1: frame.topLeft(), p2: frame.bottomLeft());
494 painter->drawLine(p1: frame.topLeft(), p2: frame.topRight());
495
496 painter->setPen(frameShadow);
497 painter->drawLine(p1: frame.topRight(), p2: frame.bottomRight());
498 painter->drawLine(p1: frame.bottomLeft(), p2: frame.bottomRight());
499 }
500 painter->restore();
501 break;
502 case PE_PanelButtonTool:
503 painter->save();
504 if ((option->state & State_Enabled || option->state & State_On) || !(option->state & State_AutoRaise)) {
505 if (widget && widget->inherits(classname: "QDockWidgetTitleButton")) {
506 if (option->state & State_MouseOver)
507 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: option, p: painter, w: widget);
508 } else {
509 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: option, p: painter, w: widget);
510 }
511 }
512 painter->restore();
513 break;
514 case PE_IndicatorDockWidgetResizeHandle:
515 {
516 QStyleOption dockWidgetHandle = *option;
517 bool horizontal = option->state & State_Horizontal;
518 dockWidgetHandle.state.setFlag(flag: State_Horizontal, on: !horizontal);
519 proxy()->drawControl(element: CE_Splitter, opt: &dockWidgetHandle, p: painter, w: widget);
520 }
521 break;
522 case PE_FrameDockWidget:
523 case PE_FrameWindow:
524 {
525 painter->save();
526 const QRect &rect = option->rect;
527 const QColor col = (elem == PE_FrameWindow) ? outline.darker(f: 150)
528 : option->palette.window().color().darker(f: 120);
529 painter->setPen(col);
530 painter->drawRect(r: rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
531 painter->setPen(QPen(option->palette.light(), 1));
532 painter->drawLine(x1: rect.left() + 1, y1: rect.top() + 1,
533 x2: rect.left() + 1, y2: rect.bottom() - 1);
534 painter->setPen(option->palette.window().color().darker(f: 120));
535 const QLine lines[2] = {{rect.left() + 1, rect.bottom() - 1,
536 rect.right() - 2, rect.bottom() - 1},
537 {rect.right() - 1, rect.top() + 1,
538 rect.right() - 1, rect.bottom() - 1}};
539 painter->drawLines(lines, lineCount: 2);
540 painter->restore();
541 break;
542 }
543 case PE_FrameLineEdit:
544 {
545 const QRect &r = option->rect;
546 bool hasFocus = option->state & State_HasFocus;
547
548 painter->save();
549
550 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
551 // ### highdpi painter bug.
552 painter->translate(dx: 0.5, dy: 0.5);
553
554 // Draw Outline
555 painter->setPen(hasFocus ? highlightedOutline : outline);
556 painter->drawRoundedRect(rect: r.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 2, yRadius: 2);
557
558 if (hasFocus) {
559 QColor softHighlight = highlightedOutline;
560 softHighlight.setAlpha(40);
561 painter->setPen(softHighlight);
562 painter->drawRoundedRect(rect: r.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2), xRadius: 1.7, yRadius: 1.7);
563 }
564 // Draw inner shadow
565 painter->setPen(QFusionStylePrivate::topShadow);
566 painter->drawLine(p1: QPoint(r.left() + 2, r.top() + 1), p2: QPoint(r.right() - 2, r.top() + 1));
567
568 painter->restore();
569
570 }
571 break;
572 case PE_IndicatorCheckBox:
573 painter->save();
574 if (const QStyleOptionButton *checkbox = qstyleoption_cast<const QStyleOptionButton*>(opt: option)) {
575 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
576 painter->translate(dx: 0.5, dy: 0.5);
577 const QRect rect = option->rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1);
578
579 QColor pressedColor = mergedColors(colorA: option->palette.base().color(), colorB: option->palette.windowText().color(), factor: 85);
580 painter->setBrush(Qt::NoBrush);
581
582 const auto state = option->state;
583 // Gradient fill
584 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
585 gradient.setColorAt(pos: 0, color: (state & State_Sunken) ? pressedColor : option->palette.base().color().darker(f: 115));
586 gradient.setColorAt(pos: 0.15, color: (state & State_Sunken) ? pressedColor : option->palette.base().color());
587 gradient.setColorAt(pos: 1, color: (state & State_Sunken) ? pressedColor : option->palette.base().color());
588
589 painter->setBrush((state & State_Sunken) ? QBrush(pressedColor) : gradient);
590
591 if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
592 painter->setPen(highlightedOutline);
593 else
594 painter->setPen(colorScheme() == Qt::ColorScheme::Dark ? outline.lighter(f: 240)
595 : outline.lighter(f: 110));
596 painter->drawRect(r: rect);
597
598 QColor checkMarkColor = option->palette.text().color().darker(f: 120);
599 const qreal checkMarkPadding = 1 + rect.width() * 0.13; // at least one pixel padding
600
601 if (checkbox->state & State_NoChange) {
602 gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft());
603 checkMarkColor.setAlpha(80);
604 gradient.setColorAt(pos: 0, color: checkMarkColor);
605 checkMarkColor.setAlpha(140);
606 gradient.setColorAt(pos: 1, color: checkMarkColor);
607 checkMarkColor.setAlpha(180);
608 painter->setPen(checkMarkColor);
609 painter->setBrush(gradient);
610 painter->drawRect(r: rect.adjusted(xp1: checkMarkPadding, yp1: checkMarkPadding, xp2: -checkMarkPadding, yp2: -checkMarkPadding));
611
612 } else if (checkbox->state & State_On) {
613 const qreal dpi = QStyleHelper::dpi(option);
614 qreal penWidth = QStyleHelper::dpiScaled(value: 1.5, dpi);
615 penWidth = qMax<qreal>(a: penWidth, b: 0.13 * rect.height());
616 penWidth = qMin<qreal>(a: penWidth, b: 0.20 * rect.height());
617 QPen checkPen = QPen(checkMarkColor, penWidth);
618 checkMarkColor.setAlpha(210);
619 painter->translate(dx: dpiScaled(value: -0.8, dpi), dy: dpiScaled(value: 0.5, dpi));
620 painter->setPen(checkPen);
621 painter->setBrush(Qt::NoBrush);
622
623 // Draw checkmark
624 QPainterPath path;
625 const qreal rectHeight = rect.height(); // assuming height equals width
626 path.moveTo(x: checkMarkPadding + rectHeight * 0.11, y: rectHeight * 0.47);
627 path.lineTo(x: rectHeight * 0.5, y: rectHeight - checkMarkPadding);
628 path.lineTo(x: rectHeight - checkMarkPadding, y: checkMarkPadding);
629 painter->drawPath(path: path.translated(offset: rect.topLeft()));
630 }
631 }
632 painter->restore();
633 break;
634 case PE_IndicatorRadioButton:
635 painter->save();
636 {
637 QColor pressedColor = mergedColors(colorA: option->palette.base().color(), colorB: option->palette.windowText().color(), factor: 85);
638 painter->setBrush((option->state & State_Sunken) ? pressedColor : option->palette.base().color());
639 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
640 QPainterPath circle;
641 const QRect &rect = option->rect;
642 const QPointF circleCenter = rect.center() + QPoint(1, 1);
643 const qreal outlineRadius = (rect.width() + (rect.width() + 1) % 2) / 2.0 - 1;
644 circle.addEllipse(center: circleCenter, rx: outlineRadius, ry: outlineRadius);
645 if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
646 painter->setPen(highlightedOutline);
647 else if (isHighContrast())
648 painter->setPen(outline);
649 else
650 painter->setPen(option->palette.window().color().darker(f: 150));
651 painter->drawPath(path: circle);
652
653 if (option->state & State_On) {
654 circle = QPainterPath();
655 const qreal checkmarkRadius = outlineRadius / 2.32;
656 circle.addEllipse(center: circleCenter, rx: checkmarkRadius, ry: checkmarkRadius);
657 QColor checkMarkColor = option->palette.text().color().darker(f: 120);
658 checkMarkColor.setAlpha(200);
659 painter->setPen(checkMarkColor);
660 checkMarkColor.setAlpha(180);
661 painter->setBrush(checkMarkColor);
662 painter->drawPath(path: circle);
663 }
664 }
665 painter->restore();
666 break;
667 case PE_IndicatorToolBarHandle:
668 {
669 const QPoint center = option->rect.center();
670 //draw grips
671 if (option->state & State_Horizontal) {
672 for (int i = -3 ; i < 2 ; i += 3) {
673 for (int j = -8 ; j < 10 ; j += 3) {
674 painter->fillRect(x: center.x() + i, y: center.y() + j, w: 2, h: 2, b: QFusionStylePrivate::lightShade);
675 painter->fillRect(x: center.x() + i, y: center.y() + j, w: 1, h: 1, b: QFusionStylePrivate::darkShade);
676 }
677 }
678 } else { //vertical toolbar
679 for (int i = -6 ; i < 12 ; i += 3) {
680 for (int j = -3 ; j < 2 ; j += 3) {
681 painter->fillRect(x: center.x() + i, y: center.y() + j, w: 2, h: 2, b: QFusionStylePrivate::lightShade);
682 painter->fillRect(x: center.x() + i, y: center.y() + j, w: 1, h: 1, b: QFusionStylePrivate::darkShade);
683 }
684 }
685 }
686 break;
687 }
688 case PE_FrameDefaultButton:
689 break;
690 case PE_FrameFocusRect:
691 if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt: option)) {
692 //### check for d->alt_down
693 if (!(fropt->state & State_KeyboardFocusChange))
694 return;
695 const QRect &rect = option->rect;
696
697 painter->save();
698 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
699 painter->translate(dx: 0.5, dy: 0.5);
700 QColor fillcolor = highlightedOutline;
701 fillcolor.setAlpha(80);
702 painter->setPen(fillcolor.darker(f: 120));
703 fillcolor.setAlpha(30);
704 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
705 gradient.setColorAt(pos: 0, color: fillcolor.lighter(f: 160));
706 gradient.setColorAt(pos: 1, color: fillcolor);
707 painter->setBrush(gradient);
708 painter->drawRoundedRect(rect: rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 1, yRadius: 1);
709 painter->restore();
710 }
711 break;
712 case PE_PanelButtonCommand:
713 {
714 bool isDefault = false;
715 bool isFlat = false;
716 bool isDown = (option->state & State_Sunken) || (option->state & State_On);
717
718 if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(opt: option)) {
719 isDefault = (button->features & QStyleOptionButton::DefaultButton) && (button->state & State_Enabled);
720 isFlat = (button->features & QStyleOptionButton::Flat);
721 }
722
723 if (isFlat && !isDown) {
724 if (isDefault) {
725 const QRect r = option->rect.adjusted(xp1: 0, yp1: 1, xp2: 0, yp2: -1);
726 painter->setPen(Qt::black);
727 const QLine lines[4] = {
728 QLine(QPoint(r.left() + 2, r.top()),
729 QPoint(r.right() - 2, r.top())),
730 QLine(QPoint(r.left(), r.top() + 2),
731 QPoint(r.left(), r.bottom() - 2)),
732 QLine(QPoint(r.right(), r.top() + 2),
733 QPoint(r.right(), r.bottom() - 2)),
734 QLine(QPoint(r.left() + 2, r.bottom()),
735 QPoint(r.right() - 2, r.bottom()))
736 };
737 painter->drawLines(lines, lineCount: 4);
738 const QPoint points[4] = {
739 QPoint(r.right() - 1, r.bottom() - 1),
740 QPoint(r.right() - 1, r.top() + 1),
741 QPoint(r.left() + 1, r.bottom() - 1),
742 QPoint(r.left() + 1, r.top() + 1)
743 };
744 painter->drawPoints(points, pointCount: 4);
745 }
746 return;
747 }
748
749
750 bool isEnabled = option->state & State_Enabled;
751 bool hasFocus = (option->state & State_HasFocus && option->state & State_KeyboardFocusChange);
752 QColor buttonColor = d->buttonColor(pal: option->palette);
753
754
755 if (isDefault)
756 buttonColor = mergedColors(colorA: buttonColor, colorB: highlightedOutline.lighter(f: 130), factor: 90);
757
758 QCachedPainter p(painter, u"pushbutton-" + buttonColor.name(format: QColor::HexArgb), option);
759 if (p.needsPainting()) {
760 const QRect rect = p.pixmapRect();
761 const QRect r = rect.adjusted(xp1: 0, yp1: 1, xp2: -1, yp2: 0);
762 const QColor &darkOutline = (hasFocus | isDefault) ? highlightedOutline : outline;
763
764 p->setRenderHint(hint: QPainter::Antialiasing, on: true);
765 p->translate(dx: 0.5, dy: -0.5);
766
767 QLinearGradient gradient = qt_fusion_gradient(rect, baseColor: (isEnabled && option->state & State_MouseOver ) ? buttonColor : buttonColor.darker(f: 104));
768 p->setPen(Qt::transparent);
769 p->setBrush(isDown ? QBrush(buttonColor.darker(f: 110)) : gradient);
770 p->drawRoundedRect(rect: r, xRadius: 2.0, yRadius: 2.0);
771 p->setBrush(Qt::NoBrush);
772
773 // Outline
774 p->setPen(!isEnabled ? darkOutline.lighter(f: 115) : darkOutline);
775 p->drawRoundedRect(rect: r, xRadius: 2.0, yRadius: 2.0);
776
777 p->setPen(QFusionStylePrivate::innerContrastLine);
778 p->drawRoundedRect(rect: r.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1), xRadius: 2.0, yRadius: 2.0);
779 }
780 }
781 break;
782 case PE_FrameTabWidget:
783 painter->save();
784 painter->fillRect(option->rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), color: d->tabFrameColor(pal: option->palette));
785#if QT_CONFIG(tabwidget)
786 if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt: option)) {
787 QRect rect = option->rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1);
788
789 // Shadow outline
790 if (twf->shape != QTabBar::RoundedSouth) {
791 rect.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -1);
792 QColor borderColor = outline.lighter(f: 110);
793 QColor alphaShadow(Qt::black);
794 alphaShadow.setAlpha(15);
795 painter->setPen(alphaShadow);
796 painter->drawLine(p1: option->rect.bottomLeft(), p2: option->rect.bottomRight());
797 painter->setPen(borderColor);
798 }
799
800 // outline
801 painter->setPen(outline);
802 painter->drawRect(r: rect);
803
804 // Inner frame highlight
805 painter->setPen(QFusionStylePrivate::innerContrastLine);
806 painter->drawRect(r: rect.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1));
807
808 }
809#endif // QT_CONFIG(tabwidget)
810 painter->restore();
811 break ;
812
813 case PE_FrameStatusBarItem:
814 break;
815 case PE_PanelMenu: {
816 painter->save();
817 const QBrush menuBackground = option->palette.base().color().lighter(f: 108);
818 QColor borderColor = option->palette.window().color().darker(f: 160);
819 qDrawPlainRect(p: painter, r: option->rect, borderColor, lineWidth: 1, fill: &menuBackground);
820 painter->restore();
821 }
822 break;
823
824 default:
825 QCommonStyle::drawPrimitive(pe: elem, opt: option, p: painter, w: widget);
826 break;
827 }
828}
829
830/*!
831 \reimp
832*/
833void QFusionStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter,
834 const QWidget *widget) const
835{
836 Q_D (const QFusionStyle);
837
838 switch (element) {
839 case CE_ComboBoxLabel:
840 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt: option)) {
841 QRect editRect = proxy()->subControlRect(cc: CC_ComboBox, opt: cb, sc: SC_ComboBoxEditField, widget);
842 painter->save();
843 painter->setClipRect(editRect);
844 if (!cb->currentIcon.isNull()) {
845 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
846 : QIcon::Disabled;
847 QPixmap pixmap = cb->currentIcon.pixmap(size: cb->iconSize, devicePixelRatio: QStyleHelper::getDpr(painter), mode);
848 QRect iconRect(editRect);
849 iconRect.setWidth(cb->iconSize.width() + 4);
850 iconRect = alignedRect(direction: cb->direction,
851 alignment: Qt::AlignLeft | Qt::AlignVCenter,
852 size: iconRect.size(), rectangle: editRect);
853 if (cb->editable)
854 painter->fillRect(iconRect, cb->palette.brush(cr: QPalette::Base));
855 proxy()->drawItemPixmap(painter, rect: iconRect, alignment: Qt::AlignCenter, pixmap);
856
857 if (cb->direction == Qt::RightToLeft)
858 editRect.translate(dx: -4 - cb->iconSize.width(), dy: 0);
859 else
860 editRect.translate(dx: cb->iconSize.width() + 4, dy: 0);
861 }
862 if (!cb->currentText.isEmpty() && !cb->editable) {
863 proxy()->drawItemText(painter, rect: editRect.adjusted(xp1: 1, yp1: 0, xp2: -1, yp2: 0),
864 flags: visualAlignment(direction: cb->direction, alignment: cb->textAlignment),
865 pal: cb->palette, enabled: cb->state & State_Enabled, text: cb->currentText,
866 textRole: cb->editable ? QPalette::Text : QPalette::ButtonText);
867 }
868 painter->restore();
869 }
870 break;
871 case CE_Splitter:
872 {
873 // Don't draw handle for single pixel splitters
874 if (option->rect.width() > 1 && option->rect.height() > 1) {
875 const QPoint center = option->rect.center();
876 //draw grips
877 if (option->state & State_Horizontal) {
878 for (int j = -6 ; j< 12 ; j += 3) {
879 painter->fillRect(x: center.x() + 1, y: center.y() + j, w: 2, h: 2, b: QFusionStylePrivate::lightShade);
880 painter->fillRect(x: center.x() + 1, y: center.y() + j, w: 1, h: 1, b: QFusionStylePrivate::darkShade);
881 }
882 } else {
883 for (int i = -6; i< 12 ; i += 3) {
884 painter->fillRect(x: center.x() + i, y: center.y(), w: 2, h: 2, b: QFusionStylePrivate::lightShade);
885 painter->fillRect(x: center.x() + i, y: center.y(), w: 1, h: 1, b: QFusionStylePrivate::darkShade);
886 }
887 }
888 }
889 break;
890 }
891#if QT_CONFIG(rubberband)
892 case CE_RubberBand:
893 if (qstyleoption_cast<const QStyleOptionRubberBand *>(opt: option)) {
894 const QRect &rect = option->rect;
895 QColor highlight = option->palette.color(cg: QPalette::Active, cr: QPalette::Highlight);
896 painter->save();
897 QColor penColor = highlight.darker(f: 120);
898 penColor.setAlpha(180);
899 painter->setPen(penColor);
900 QColor dimHighlight(qMin(a: highlight.red()/2 + 110, b: 255),
901 qMin(a: highlight.green()/2 + 110, b: 255),
902 qMin(a: highlight.blue()/2 + 110, b: 255));
903 dimHighlight.setAlpha(widget && widget->isWindow() ? 255 : 80);
904 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
905 gradient.setColorAt(pos: 0, color: dimHighlight.lighter(f: 120));
906 gradient.setColorAt(pos: 1, color: dimHighlight);
907 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
908 painter->translate(dx: 0.5, dy: 0.5);
909 painter->setBrush(dimHighlight);
910 painter->drawRoundedRect(rect: rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 1, yRadius: 1);
911 //when the rectangle we get is large enough, draw the inner rectangle.
912 if (rect.width() > 2 && rect.height() > 2) {
913 QColor innerLine = Qt::white;
914 innerLine.setAlpha(40);
915 painter->setPen(innerLine);
916 painter->drawRoundedRect(rect: rect.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2), xRadius: 1, yRadius: 1);
917 }
918 painter->restore();
919 }
920 break;
921#endif //QT_CONFIG(rubberband)
922 case CE_SizeGrip:
923 painter->save();
924 {
925 const QPoint center = option->rect.center();
926 //draw grips
927 for (int i = -6; i< 12 ; i += 3) {
928 for (int j = -6 ; j< 12 ; j += 3) {
929 if ((option->direction == Qt::LeftToRight && i > -j) || (option->direction == Qt::RightToLeft && j > i) ) {
930 painter->fillRect(x: center.x() + i, y: center.y() + j, w: 2, h: 2, b: QFusionStylePrivate::lightShade);
931 painter->fillRect(x: center.x() + i, y: center.y() + j, w: 1, h: 1, b: QFusionStylePrivate::darkShade);
932 }
933 }
934 }
935 }
936 painter->restore();
937 break;
938#if QT_CONFIG(toolbar)
939 case CE_ToolBar:
940 if (const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(opt: option)) {
941 // Reserve the beveled appearance only for mainwindow toolbars
942 if (widget && !(qobject_cast<const QMainWindow*> (object: widget->parentWidget())))
943 break;
944
945 const QRect &rect = option->rect;
946 // Draws the light line above and the dark line below menu bars and
947 // tool bars.
948 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
949 if (!(option->state & State_Horizontal))
950 gradient = QLinearGradient(rect.left(), rect.center().y(),
951 rect.right(), rect.center().y());
952 gradient.setColorAt(pos: 0, color: option->palette.window().color().lighter(f: 104));
953 gradient.setColorAt(pos: 1, color: option->palette.window().color());
954 painter->fillRect(rect, gradient);
955
956 constexpr QColor light = QFusionStylePrivate::lightShade;
957 constexpr QColor shadow = QFusionStylePrivate::darkShade;
958
959 QPen oldPen = painter->pen();
960 if (toolBar->toolBarArea == Qt::TopToolBarArea) {
961 if (toolBar->positionOfLine == QStyleOptionToolBar::End
962 || toolBar->positionOfLine == QStyleOptionToolBar::OnlyOne) {
963 // The end and onlyone top toolbar lines draw a double
964 // line at the bottom to blend with the central
965 // widget.
966 painter->setPen(light);
967 painter->drawLine(p1: rect.bottomLeft(), p2: rect.bottomRight());
968 painter->setPen(shadow);
969 painter->drawLine(x1: rect.left(), y1: rect.bottom() - 1,
970 x2: rect.right(), y2: rect.bottom() - 1);
971 } else {
972 // All others draw a single dark line at the bottom.
973 painter->setPen(shadow);
974 painter->drawLine(p1: rect.bottomLeft(), p2: rect.bottomRight());
975 }
976 // All top toolbar lines draw a light line at the top.
977 painter->setPen(light);
978 painter->drawLine(p1: rect.topLeft(), p2: rect.topRight());
979 } else if (toolBar->toolBarArea == Qt::BottomToolBarArea) {
980 if (toolBar->positionOfLine == QStyleOptionToolBar::End
981 || toolBar->positionOfLine == QStyleOptionToolBar::Middle) {
982 // The end and middle bottom tool bar lines draw a dark
983 // line at the bottom.
984 painter->setPen(shadow);
985 painter->drawLine(p1: rect.bottomLeft(), p2: rect.bottomRight());
986 }
987 if (toolBar->positionOfLine == QStyleOptionToolBar::Beginning
988 || toolBar->positionOfLine == QStyleOptionToolBar::OnlyOne) {
989 // The beginning and only one tool bar lines draw a
990 // double line at the bottom to blend with the
991 // status bar.
992 // ### The styleoption could contain whether the
993 // main window has a menu bar and a status bar, and
994 // possibly dock widgets.
995 painter->setPen(shadow);
996 painter->drawLine(x1: rect.left(), y1: rect.bottom() - 1,
997 x2: rect.right(), y2: rect.bottom() - 1);
998 painter->setPen(light);
999 painter->drawLine(p1: rect.bottomLeft(), p2: rect.bottomRight());
1000 }
1001 if (toolBar->positionOfLine == QStyleOptionToolBar::End) {
1002 painter->setPen(shadow);
1003 painter->drawLine(p1: rect.topLeft(), p2: rect.topRight());
1004 painter->setPen(light);
1005 painter->drawLine(x1: rect.left(), y1: rect.top() + 1,
1006 x2: rect.right(), y2: rect.top() + 1);
1007
1008 } else {
1009 // All other bottom toolbars draw a light line at the top.
1010 painter->setPen(light);
1011 painter->drawLine(p1: rect.topLeft(), p2: rect.topRight());
1012 }
1013 }
1014 if (toolBar->toolBarArea == Qt::LeftToolBarArea) {
1015 if (toolBar->positionOfLine == QStyleOptionToolBar::Middle
1016 || toolBar->positionOfLine == QStyleOptionToolBar::End) {
1017 // The middle and left end toolbar lines draw a light
1018 // line to the left.
1019 painter->setPen(light);
1020 painter->drawLine(p1: rect.topLeft(), p2: rect.bottomLeft());
1021 }
1022 if (toolBar->positionOfLine == QStyleOptionToolBar::End) {
1023 // All other left toolbar lines draw a dark line to the right
1024 painter->setPen(shadow);
1025 painter->drawLine(x1: rect.right() - 1, y1: rect.top(),
1026 x2: rect.right() - 1, y2: rect.bottom());
1027 painter->setPen(light);
1028 painter->drawLine(p1: rect.topRight(), p2: rect.bottomRight());
1029 } else {
1030 // All other left toolbar lines draw a dark line to the right
1031 painter->setPen(shadow);
1032 painter->drawLine(p1: rect.topRight(), p2: rect.bottomRight());
1033 }
1034 } else if (toolBar->toolBarArea == Qt::RightToolBarArea) {
1035 if (toolBar->positionOfLine == QStyleOptionToolBar::Middle
1036 || toolBar->positionOfLine == QStyleOptionToolBar::End) {
1037 // Right middle and end toolbar lines draw the dark right line
1038 painter->setPen(shadow);
1039 painter->drawLine(p1: rect.topRight(), p2: rect.bottomRight());
1040 }
1041 if (toolBar->positionOfLine == QStyleOptionToolBar::End
1042 || toolBar->positionOfLine == QStyleOptionToolBar::OnlyOne) {
1043 // The right end and single toolbar draws the dark
1044 // line on its left edge
1045 painter->setPen(shadow);
1046 painter->drawLine(p1: rect.topLeft(), p2: rect.bottomLeft());
1047 // And a light line next to it
1048 painter->setPen(light);
1049 painter->drawLine(x1: rect.left() + 1, y1: rect.top(),
1050 x2: rect.left() + 1, y2: rect.bottom());
1051 } else {
1052 // Other right toolbars draw a light line on its left edge
1053 painter->setPen(light);
1054 painter->drawLine(p1: rect.topLeft(), p2: rect.bottomLeft());
1055 }
1056 }
1057 painter->setPen(oldPen);
1058 }
1059 break;
1060#endif // QT_CONFIG(toolbar)
1061 case CE_DockWidgetTitle:
1062 painter->save();
1063 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt: option)) {
1064 bool verticalTitleBar = dwOpt->verticalTitleBar;
1065
1066 QRect titleRect = subElementRect(r: SE_DockWidgetTitleBarText, opt: option, widget);
1067 if (verticalTitleBar) {
1068 const QRect &rect = dwOpt->rect;
1069 const QRect r = rect.transposed();
1070 titleRect = QRect(r.left() + rect.bottom() - titleRect.bottom(),
1071 r.top() + titleRect.left() - rect.left(),
1072 titleRect.height(), titleRect.width());
1073
1074 painter->translate(dx: r.left(), dy: r.top() + r.width());
1075 painter->rotate(a: -90);
1076 painter->translate(dx: -r.left(), dy: -r.top());
1077 }
1078
1079 if (!dwOpt->title.isEmpty()) {
1080 QString titleText
1081 = painter->fontMetrics().elidedText(text: dwOpt->title,
1082 mode: Qt::ElideRight, width: titleRect.width());
1083 proxy()->drawItemText(painter,
1084 rect: titleRect,
1085 flags: Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, pal: dwOpt->palette,
1086 enabled: dwOpt->state & State_Enabled, text: titleText,
1087 textRole: QPalette::WindowText);
1088 }
1089 }
1090 painter->restore();
1091 break;
1092 case CE_HeaderSection:
1093 painter->save();
1094 // Draws the header in tables.
1095 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt: option)) {
1096 const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(opt: option);
1097 const bool isSectionDragTarget = headerV2 ? headerV2->isSectionDragTarget : false;
1098
1099 const QString pixmapName = "headersection-"_L1
1100 % HexString(header->position)
1101 % HexString(header->orientation)
1102 % QLatin1Char(isSectionDragTarget ? '1' : '0');
1103 QCachedPainter cp(painter, pixmapName, option);
1104 if (cp.needsPainting()) {
1105 const QRect pixmapRect = cp.pixmapRect();
1106 QColor buttonColor = d->buttonColor(pal: option->palette);
1107 QColor gradientStartColor = buttonColor.lighter(f: 104);
1108 QColor gradientStopColor = buttonColor.darker(f: 102);
1109 if (isSectionDragTarget) {
1110 gradientStopColor = gradientStartColor.darker(f: 130);
1111 gradientStartColor = gradientStartColor.darker(f: 130);
1112 }
1113 QLinearGradient gradient(pixmapRect.topLeft(), pixmapRect.bottomLeft());
1114
1115 if (option->palette.window().gradient()) {
1116 gradient.setStops(option->palette.window().gradient()->stops());
1117 } else {
1118 QColor midColor1 = mergedColors(colorA: gradientStartColor, colorB: gradientStopColor, factor: 60);
1119 QColor midColor2 = mergedColors(colorA: gradientStartColor, colorB: gradientStopColor, factor: 40);
1120 gradient.setColorAt(pos: 0, color: gradientStartColor);
1121 gradient.setColorAt(pos: 0.5, color: midColor1);
1122 gradient.setColorAt(pos: 0.501, color: midColor2);
1123 gradient.setColorAt(pos: 0.92, color: gradientStopColor);
1124 gradient.setColorAt(pos: 1, color: gradientStopColor.darker(f: 104));
1125 }
1126 cp->fillRect(pixmapRect, gradient);
1127 cp->setPen(QFusionStylePrivate::innerContrastLine);
1128 cp->setBrush(Qt::NoBrush);
1129 cp->drawLine(p1: pixmapRect.topLeft(), p2: pixmapRect.topRight());
1130 cp->setPen(d->outline(pal: option->palette));
1131 cp->drawLine(p1: pixmapRect.bottomLeft(), p2: pixmapRect.bottomRight());
1132
1133 if (header->orientation == Qt::Horizontal &&
1134 header->position != QStyleOptionHeader::End &&
1135 header->position != QStyleOptionHeader::OnlyOneSection) {
1136 cp->setPen(QColor(0, 0, 0, 40));
1137 cp->drawLine(p1: pixmapRect.topRight(), p2: pixmapRect.bottomRight() + QPoint(0, -1));
1138 cp->setPen(QFusionStylePrivate::innerContrastLine);
1139 cp->drawLine(p1: pixmapRect.topRight() + QPoint(-1, 0), p2: pixmapRect.bottomRight() + QPoint(-1, -1));
1140 } else if (header->orientation == Qt::Vertical) {
1141 cp->setPen(d->outline(pal: option->palette));
1142 cp->drawLine(p1: pixmapRect.topRight(), p2: pixmapRect.bottomRight());
1143 }
1144 }
1145 }
1146 painter->restore();
1147 break;
1148 case CE_ProgressBarGroove:
1149 painter->save();
1150 {
1151 const QRect &rect = option->rect;
1152 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
1153 painter->translate(dx: 0.5, dy: 0.5);
1154
1155 QColor shadowAlpha = Qt::black;
1156 shadowAlpha.setAlpha(16);
1157 painter->setPen(shadowAlpha);
1158 painter->drawLine(p1: rect.topLeft() - QPoint(0, 1), p2: rect.topRight() - QPoint(0, 1));
1159
1160 painter->setBrush(option->palette.base());
1161 painter->setPen(d->outline(pal: option->palette));
1162 painter->drawRoundedRect(rect: rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 2, yRadius: 2);
1163
1164 // Inner shadow
1165 painter->setPen(QFusionStylePrivate::topShadow);
1166 painter->drawLine(p1: QPoint(rect.left() + 1, rect.top() + 1),
1167 p2: QPoint(rect.right() - 1, rect.top() + 1));
1168 }
1169 painter->restore();
1170 break;
1171 case CE_ProgressBarContents:
1172 painter->save();
1173 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
1174 if (const QStyleOptionProgressBar *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(opt: option)) {
1175 QRect rect = option->rect;
1176 painter->translate(offset: rect.topLeft());
1177 rect.translate(p: -rect.topLeft());
1178 const auto indeterminate = (bar->minimum == 0 && bar->maximum == 0);
1179 const auto complete = bar->progress == bar->maximum;
1180 const auto vertical = !(bar->state & QStyle::State_Horizontal);
1181 const auto inverted = bar->invertedAppearance;
1182 const auto reverse = (bar->direction == Qt::RightToLeft) ^ inverted;
1183
1184 // If the orientation is vertical, we use a transform to rotate
1185 // the progress bar 90 degrees (counter)clockwise. This way we can use the
1186 // same rendering code for both orientations.
1187 if (vertical) {
1188 rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height
1189 QTransform m;
1190 if (inverted) {
1191 m.rotate(a: 90);
1192 m.translate(dx: 0, dy: -rect.height());
1193 } else {
1194 m.rotate(a: -90);
1195 m.translate(dx: -rect.width(), dy: 0);
1196 }
1197 painter->setTransform(transform: m, combine: true);
1198 } else if (reverse) {
1199 QTransform m = QTransform::fromScale(dx: -1, dy: 1);
1200 m.translate(dx: -rect.width(), dy: 0);
1201 painter->setTransform(transform: m, combine: true);
1202 }
1203 painter->translate(dx: 0.5, dy: 0.5);
1204
1205 const auto progress = qMax(a: bar->progress, b: bar->minimum); // workaround for bug in QProgressBar
1206 const auto totalSteps = qMax(Q_INT64_C(1), b: qint64(bar->maximum) - bar->minimum);
1207 const auto progressSteps = qint64(progress) - bar->minimum;
1208 const auto progressBarWidth = progressSteps * rect.width() / totalSteps;
1209 int width = indeterminate ? rect.width() : progressBarWidth;
1210
1211 int step = 0;
1212 QRect progressBar;
1213 QColor highlight = d->highlight(pal: option->palette);
1214 QColor highlightedoutline = highlight.darker(f: 140);
1215 QColor outline = d->outline(pal: option->palette);
1216 if (qGray(rgb: outline.rgb()) > qGray(rgb: highlightedoutline.rgb()))
1217 outline = highlightedoutline;
1218
1219 if (!indeterminate)
1220 progressBar.setRect(ax: rect.left(), ay: rect.top(), aw: width - 1, ah: rect.height() - 1);
1221 else
1222 progressBar.setRect(ax: rect.left(), ay: rect.top(), aw: rect.width() - 1, ah: rect.height() - 1);
1223
1224 if (indeterminate || bar->progress > bar->minimum) {
1225
1226 painter->setPen(outline);
1227
1228 QColor highlightedGradientStartColor = highlight.lighter(f: 120);
1229 QColor highlightedGradientStopColor = highlight;
1230 QLinearGradient gradient(rect.topLeft(), QPoint(rect.bottomLeft().x(), rect.bottomLeft().y()));
1231 gradient.setColorAt(pos: 0, color: highlightedGradientStartColor);
1232 gradient.setColorAt(pos: 1, color: highlightedGradientStopColor);
1233
1234 painter->setBrush(gradient);
1235
1236 painter->save();
1237 // 0.5 - half the width of a cosmetic pen (for vertical line below)
1238 if (!complete && !indeterminate)
1239 painter->setClipRect(QRectF(progressBar).adjusted(xp1: -1, yp1: -1, xp2: 0.5, yp2: 1));
1240
1241 QRect fillRect = progressBar;
1242 if (!indeterminate && !complete)
1243 fillRect.setWidth(std::min(a: fillRect.width() + 2, b: rect.width() - 1)); // avoid round borders at the right end
1244 painter->drawRoundedRect(rect: fillRect, xRadius: 2, yRadius: 2);
1245 painter->restore();
1246
1247 painter->setBrush(Qt::NoBrush);
1248 painter->setPen(QColor(255, 255, 255, 50));
1249 painter->drawRoundedRect(rect: progressBar.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1), xRadius: 1, yRadius: 1);
1250
1251 if (!indeterminate) {
1252#if QT_CONFIG(animation)
1253 (const_cast<QFusionStylePrivate*>(d))->stopAnimation(target: option->styleObject);
1254#endif
1255 } else {
1256 highlightedGradientStartColor.setAlpha(120);
1257 painter->setPen(QPen(highlightedGradientStartColor, 9.0));
1258 painter->setClipRect(progressBar.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1));
1259#if QT_CONFIG(animation)
1260 if (QProgressStyleAnimation *animation =
1261 qobject_cast<QProgressStyleAnimation*>(object: d->animation(target: option->styleObject))) {
1262 step = animation->animationStep() % 22;
1263 } else {
1264 (const_cast<QFusionStylePrivate*>(d))->startAnimation(
1265 animation: new QProgressStyleAnimation(d->animationFps, option->styleObject)
1266 );
1267 }
1268#endif
1269 QVarLengthArray<QLine, 40> lines;
1270 for (int x = progressBar.left() - rect.height(); x < rect.right() ; x += 22) {
1271 lines.emplace_back(args: x + step, args: progressBar.bottom() + 1,
1272 args: x + rect.height() + step, args: progressBar.top() - 2);
1273 }
1274 painter->drawLines(lines: lines.data(), lineCount: lines.count());
1275 }
1276 }
1277 if (!indeterminate && !complete) {
1278 QColor innerShadow(Qt::black);
1279 innerShadow.setAlpha(35);
1280 painter->setPen(innerShadow);
1281 painter->drawLine(p1: progressBar.topRight() + QPoint(2, 1), p2: progressBar.bottomRight() + QPoint(2, 0));
1282 painter->setPen(highlight.darker(f: 140));
1283 painter->drawLine(p1: progressBar.topRight() + QPoint(1, 1), p2: progressBar.bottomRight() + QPoint(1, 0));
1284 }
1285 }
1286 painter->restore();
1287 break;
1288 case CE_ProgressBarLabel:
1289 if (const QStyleOptionProgressBar *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(opt: option)) {
1290 const QRect &rect = bar->rect;
1291 QRect leftRect = rect;
1292 QRect rightRect = rect;
1293 QColor textColor = option->palette.text().color();
1294 QColor alternateTextColor = d->highlightedText(pal: option->palette);
1295
1296 painter->save();
1297 const auto vertical = !(bar->state & QStyle::State_Horizontal);
1298 const auto inverted = bar->invertedAppearance;
1299 const auto reverse = (bar->direction == Qt::RightToLeft) ^ inverted;
1300 const auto totalSteps = qMax(Q_INT64_C(1), b: qint64(bar->maximum) - bar->minimum);
1301 const auto progressSteps = qint64(bar->progress) - bar->minimum;
1302 const auto progressIndicatorPos = progressSteps * (vertical ? rect.height() : rect.width()) / totalSteps;
1303
1304 if (vertical) {
1305 if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.height()) {
1306 if (inverted) {
1307 leftRect.setHeight(progressIndicatorPos);
1308 rightRect.setY(progressIndicatorPos);
1309 } else {
1310 leftRect.setHeight(rect.height() - progressIndicatorPos);
1311 rightRect.setY(rect.height() - progressIndicatorPos);
1312 }
1313 }
1314 } else {
1315 if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.width()) {
1316 if (reverse) {
1317 leftRect.setWidth(rect.width() - progressIndicatorPos);
1318 rightRect.setX(rect.width() - progressIndicatorPos);
1319 } else {
1320 leftRect.setWidth(progressIndicatorPos);
1321 rightRect.setX(progressIndicatorPos);
1322 }
1323 }
1324 }
1325
1326 const auto firstIsAlternateColor = (vertical && !inverted) || (!vertical && reverse);
1327 painter->setClipRect(rightRect);
1328 painter->setPen(firstIsAlternateColor ? alternateTextColor : textColor);
1329 painter->drawText(r: rect, text: bar->text, o: QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
1330 painter->setPen(firstIsAlternateColor ? textColor : alternateTextColor);
1331 painter->setClipRect(leftRect);
1332 painter->drawText(r: rect, text: bar->text, o: QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
1333
1334 painter->restore();
1335 }
1336 break;
1337 case CE_MenuBarItem:
1338 painter->save();
1339 if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt: option))
1340 {
1341 const QRect &rect = option->rect;
1342 QStyleOptionMenuItem item = *mbi;
1343 item.rect = mbi->rect.adjusted(xp1: 0, yp1: 1, xp2: 0, yp2: -3);
1344 QColor highlightOutline = option->palette.highlight().color().darker(f: 125);
1345 painter->fillRect(rect, option->palette.window());
1346
1347 QCommonStyle::drawControl(element, opt: &item, p: painter, w: widget);
1348
1349 bool act = mbi->state & State_Selected && mbi->state & State_Sunken;
1350 bool dis = !(mbi->state & State_Enabled);
1351
1352 if (act) {
1353 painter->setBrush(option->palette.highlight());
1354 painter->setPen(highlightOutline);
1355 painter->drawRect(r: rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
1356
1357 // painter->drawRoundedRect(r.adjusted(1, 1, -1, -1), 2, 2);
1358
1359 //draw text
1360 QPalette::ColorRole textRole = dis ? QPalette::Text : QPalette::HighlightedText;
1361 uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1362 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt: mbi, widget))
1363 alignment |= Qt::TextHideMnemonic;
1364 proxy()->drawItemText(painter, rect: item.rect, flags: alignment, pal: mbi->palette, enabled: mbi->state & State_Enabled, text: mbi->text, textRole);
1365 } else {
1366 QColor shadow = mergedColors(colorA: option->palette.window().color().darker(f: 120),
1367 colorB: d->outline(pal: option->palette).lighter(f: 140), factor: 60);
1368 painter->setPen(shadow);
1369 painter->drawLine(p1: rect.bottomLeft(), p2: rect.bottomRight());
1370 }
1371 }
1372 painter->restore();
1373 break;
1374 case CE_MenuItem:
1375 painter->save();
1376 // Draws one item in a popup menu.
1377 if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt: option)) {
1378 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
1379 int w = 0;
1380 const int margin = int(QStyleHelper::dpiScaled(value: 5, option));
1381 if (!menuItem->text.isEmpty()) {
1382 painter->setFont(menuItem->font);
1383 proxy()->drawItemText(painter, rect: menuItem->rect.adjusted(xp1: margin, yp1: 0, xp2: -margin, yp2: 0),
1384 flags: Qt::AlignLeft | Qt::AlignVCenter,
1385 pal: menuItem->palette, enabled: menuItem->state & State_Enabled, text: menuItem->text,
1386 textRole: QPalette::Text);
1387 w = menuItem->fontMetrics.horizontalAdvance(menuItem->text) + margin;
1388 }
1389 painter->setPen(QFusionStylePrivate::darkShade.lighter(f: 106));
1390 const bool reverse = menuItem->direction == Qt::RightToLeft;
1391 qreal y = menuItem->rect.center().y() + 0.5f;
1392 painter->drawLine(p1: QPointF(menuItem->rect.left() + margin + (reverse ? 0 : w), y),
1393 p2: QPointF(menuItem->rect.right() - margin - (reverse ? w : 0), y));
1394 painter->restore();
1395 break;
1396 }
1397 const bool selected = menuItem->state & State_Selected && menuItem->state & State_Enabled;
1398 if (selected) {
1399 const QColor highlightOutline = d->highlightedOutline(pal: option->palette);
1400 const QColor highlight = option->palette.highlight().color();
1401 const QRect &r = option->rect;
1402 painter->fillRect(r, color: highlight);
1403 painter->setPen(highlightOutline);
1404 painter->drawRect(rect: QRectF(r).adjusted(xp1: 0.5, yp1: 0.5, xp2: -0.5, yp2: -0.5));
1405 }
1406 const bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable;
1407 const bool checked = menuItem->checked;
1408 const bool sunken = menuItem->state & State_Sunken;
1409 const bool enabled = menuItem->state & State_Enabled;
1410
1411 const int checkColHOffset = QFusionStylePrivate::menuItemHMargin + windowsItemFrame - 1;
1412 // icon checkbox's highlight column width
1413 int checkcol = qMax<int>(a: menuItem->rect.height() * 0.79,
1414 b: qMax<int>(a: menuItem->maxIconWidth, b: dpiScaled(value: 21, option)));
1415 bool ignoreCheckMark = false;
1416#if QT_CONFIG(combobox)
1417 if (qobject_cast<const QComboBox*>(object: widget))
1418 ignoreCheckMark = true; //ignore the checkmarks provided by the QComboMenuDelegate
1419#endif
1420 if (!ignoreCheckMark || menuItem->state & (State_On | State_Off)) {
1421 // Check, using qreal and QRectF to avoid error accumulation
1422 const qreal boxMargin = dpiScaled(value: 3.5, option);
1423 const qreal boxWidth = checkcol - 2 * boxMargin;
1424 QRect checkRect = QRectF(option->rect.left() + boxMargin + checkColHOffset,
1425 option->rect.center().y() - boxWidth/2 + 1, boxWidth,
1426 boxWidth).toRect();
1427 checkRect.setWidth(checkRect.height()); // avoid .toRect() round error results in non-perfect square
1428 checkRect = visualRect(direction: menuItem->direction, boundingRect: menuItem->rect, logicalRect: checkRect);
1429 if (checkable) {
1430 if (menuItem->checkType & QStyleOptionMenuItem::Exclusive) {
1431 // Radio button
1432 if (menuItem->state & State_On || checked || sunken) {
1433 painter->setRenderHint(hint: QPainter::Antialiasing);
1434 painter->setPen(Qt::NoPen);
1435
1436 QPalette::ColorRole textRole = !enabled
1437 ? QPalette::Text :
1438 selected ? QPalette::HighlightedText
1439 : QPalette::ButtonText;
1440 painter->setBrush(option->palette.brush( cg: option->palette.currentColorGroup(), cr: textRole));
1441 const int adjustment = checkRect.height() * 0.3;
1442 painter->drawEllipse(r: checkRect.adjusted(xp1: adjustment, yp1: adjustment, xp2: -adjustment, yp2: -adjustment));
1443 }
1444 } else {
1445 // Check box
1446 if (menuItem->icon.isNull()) {
1447 QStyleOptionButton box;
1448 box.QStyleOption::operator=(other: *option);
1449 box.rect = checkRect;
1450 if (checked || menuItem->state & State_On)
1451 box.state |= State_On;
1452 else
1453 box.state |= State_Off;
1454 proxy()->drawPrimitive(pe: PE_IndicatorCheckBox, opt: &box, p: painter, w: widget);
1455 }
1456 }
1457 }
1458 } else { //ignore checkmark
1459 if (menuItem->icon.isNull())
1460 checkcol = 0;
1461 else
1462 checkcol = menuItem->maxIconWidth;
1463 }
1464
1465 // Text and icon, ripped from windows style
1466 const bool dis = !(menuItem->state & State_Enabled);
1467 const bool act = menuItem->state & State_Selected;
1468 const QStyleOption *opt = option;
1469 const QStyleOptionMenuItem *menuitem = menuItem;
1470
1471 QPainter *p = painter;
1472 QRect vCheckRect = visualRect(direction: opt->direction, boundingRect: menuitem->rect,
1473 logicalRect: QRect(menuitem->rect.x() + checkColHOffset, menuitem->rect.y(),
1474 checkcol, menuitem->rect.height()));
1475 if (!menuItem->icon.isNull()) {
1476 QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
1477 if (act && !dis)
1478 mode = QIcon::Active;
1479 QPixmap pixmap;
1480
1481 int smallIconSize = proxy()->pixelMetric(metric: PM_SmallIconSize, option, widget);
1482 QSize iconSize(smallIconSize, smallIconSize);
1483#if QT_CONFIG(combobox)
1484 if (const QComboBox *combo = qobject_cast<const QComboBox*>(object: widget))
1485 iconSize = combo->iconSize();
1486#endif
1487 if (checked)
1488 pixmap = menuItem->icon.pixmap(size: iconSize, devicePixelRatio: QStyleHelper::getDpr(painter), mode, state: QIcon::On);
1489 else
1490 pixmap = menuItem->icon.pixmap(size: iconSize, devicePixelRatio: QStyleHelper::getDpr(painter), mode);
1491
1492 QRect pmr(QPoint(0, 0), pixmap.deviceIndependentSize().toSize());
1493 pmr.moveCenter(p: vCheckRect.center());
1494 painter->setPen(menuItem->palette.text().color());
1495 if (!ignoreCheckMark && checkable && checked) {
1496 QStyleOption opt = *option;
1497 if (act) {
1498 QColor activeColor = mergedColors(colorA: option->palette.window().color(),
1499 colorB: option->palette.highlight().color());
1500 opt.palette.setBrush(acr: QPalette::Button, abrush: activeColor);
1501 }
1502 opt.state |= State_Sunken;
1503 opt.rect = vCheckRect;
1504 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: &opt, p: painter, w: widget);
1505 }
1506 painter->drawPixmap(p: pmr.topLeft(), pm: pixmap);
1507 }
1508 if (selected) {
1509 painter->setPen(menuItem->palette.highlightedText().color());
1510 } else {
1511 painter->setPen(menuItem->palette.text().color());
1512 }
1513 int x, y, w, h;
1514 menuitem->rect.getRect(ax: &x, ay: &y, aw: &w, ah: &h);
1515 QColor discol;
1516 if (dis) {
1517 discol = menuitem->palette.text().color();
1518 p->setPen(discol);
1519 }
1520 const int xm = checkColHOffset + checkcol + QFusionStylePrivate::menuItemHMargin;
1521 const int xpos = menuitem->rect.x() + xm;
1522
1523 const QRect textRect(xpos, y + windowsItemVMargin,
1524 w - xm - QFusionStylePrivate::menuRightBorder - menuitem->reservedShortcutWidth + 2,
1525 h - 2 * windowsItemVMargin);
1526 const QRect vTextRect = visualRect(direction: opt->direction, boundingRect: menuitem->rect, logicalRect: textRect);
1527 QStringView s(menuitem->text);
1528 if (!s.isEmpty()) { // draw text
1529 p->save();
1530 const qsizetype tabIndex = s.indexOf(c: u'\t');
1531 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1532 if (!proxy()->styleHint(stylehint: SH_UnderlineShortcut, opt: menuitem, widget))
1533 text_flags |= Qt::TextHideMnemonic;
1534 text_flags |= Qt::AlignLeft;
1535 if (tabIndex >= 0) {
1536 QRect vShortcutRect = visualRect(direction: opt->direction, boundingRect: menuitem->rect,
1537 logicalRect: QRect(textRect.topRight(),
1538 QPoint(menuitem->rect.right(), textRect.bottom())));
1539 const QString textToDraw = s.mid(pos: tabIndex + 1).toString();
1540 if (dis && !act && proxy()->styleHint(stylehint: SH_EtchDisabledText, opt: option, widget)) {
1541 p->setPen(menuitem->palette.light().color());
1542 p->drawText(r: vShortcutRect.adjusted(xp1: 1, yp1: 1, xp2: 1, yp2: 1), flags: text_flags, text: textToDraw);
1543 p->setPen(discol);
1544 }
1545 p->drawText(r: vShortcutRect, flags: text_flags, text: textToDraw);
1546 s = s.left(n: tabIndex);
1547 }
1548 QFont font = menuitem->font;
1549 // font may not have any "hard" flags set. We override
1550 // the point size so that when it is resolved against the device, this font will win.
1551 // This is mainly to handle cases where someone sets the font on the window
1552 // and then the combo inherits it and passes it onward. At that point the resolve mask
1553 // is very, very weak. This makes it stonger.
1554 font.setPointSizeF(QFontInfo(menuItem->font).pointSizeF());
1555
1556 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1557 font.setBold(true);
1558
1559 p->setFont(font);
1560 const QFontMetricsF fontMetrics(font);
1561 const QString textToDraw = fontMetrics.elidedText(text: s.left(n: tabIndex).toString(),
1562 mode: Qt::ElideMiddle, width: vTextRect.width() + 0.5f,
1563 flags: text_flags);
1564 if (dis && !act && proxy()->styleHint(stylehint: SH_EtchDisabledText, opt: option, widget)) {
1565 p->setPen(menuitem->palette.light().color());
1566 p->drawText(r: vTextRect.adjusted(xp1: 1, yp1: 1, xp2: 1, yp2: 1), flags: text_flags, text: textToDraw);
1567 p->setPen(discol);
1568 }
1569 p->drawText(r: vTextRect, flags: text_flags, text: textToDraw);
1570 p->restore();
1571 }
1572
1573 // Arrow
1574 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
1575 const int dim = (menuItem->rect.height() - 4) / 2;
1576 PrimitiveElement arrow;
1577 arrow = option->direction == Qt::RightToLeft ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
1578 const int xpos = menuItem->rect.left() + menuItem->rect.width() - 3 - dim;
1579 QRect vSubMenuRect = visualRect(direction: option->direction, boundingRect: menuItem->rect,
1580 logicalRect: QRect(xpos, menuItem->rect.top() + menuItem->rect.height() / 2 - dim / 2, dim, dim));
1581 QStyleOptionMenuItem newMI = *menuItem;
1582 newMI.rect = vSubMenuRect;
1583 newMI.state = !enabled ? State_None : State_Enabled;
1584 if (selected)
1585 newMI.palette.setColor(acr: QPalette::WindowText,
1586 acolor: newMI.palette.highlightedText().color());
1587 proxy()->drawPrimitive(pe: arrow, opt: &newMI, p: painter, w: widget);
1588 }
1589 }
1590 painter->restore();
1591 break;
1592 case CE_MenuHMargin:
1593 case CE_MenuVMargin:
1594 break;
1595 case CE_MenuEmptyArea:
1596 break;
1597 case CE_PushButton:
1598 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt: option)) {
1599 proxy()->drawControl(element: CE_PushButtonBevel, opt: btn, p: painter, w: widget);
1600 QStyleOptionButton subopt = *btn;
1601 subopt.rect = subElementRect(r: SE_PushButtonContents, opt: btn, widget);
1602 proxy()->drawControl(element: CE_PushButtonLabel, opt: &subopt, p: painter, w: widget);
1603 }
1604 break;
1605 case CE_MenuBarEmptyArea:
1606 painter->save();
1607 {
1608 const QRect &rect = option->rect;
1609 painter->fillRect(rect, option->palette.window());
1610 QColor shadow = mergedColors(colorA: option->palette.window().color().darker(f: 120),
1611 colorB: d->outline(pal: option->palette).lighter(f: 140), factor: 60);
1612 painter->setPen(shadow);
1613 painter->drawLine(p1: rect.bottomLeft(), p2: rect.bottomRight());
1614 }
1615 painter->restore();
1616 break;
1617#if QT_CONFIG(tabbar)
1618 case CE_TabBarTabShape:
1619 painter->save();
1620 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt: option)) {
1621
1622 bool rtlHorTabs = (tab->direction == Qt::RightToLeft
1623 && (tab->shape == QTabBar::RoundedNorth
1624 || tab->shape == QTabBar::RoundedSouth));
1625 bool selected = tab->state & State_Selected;
1626 bool lastTab = ((!rtlHorTabs && tab->position == QStyleOptionTab::End)
1627 || (rtlHorTabs
1628 && tab->position == QStyleOptionTab::Beginning));
1629 bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
1630 int tabOverlap = pixelMetric(metric: PM_TabBarTabOverlap, option, widget);
1631 QRect rect = option->rect.adjusted(xp1: 0, yp1: 0, xp2: (onlyOne || lastTab) ? 0 : tabOverlap, yp2: 0);
1632
1633 QTransform rotMatrix;
1634 bool flip = false;
1635 painter->setPen(QFusionStylePrivate::darkShade);
1636
1637 switch (tab->shape) {
1638 case QTabBar::RoundedNorth:
1639 break;
1640 case QTabBar::RoundedSouth:
1641 rotMatrix.rotate(a: 180);
1642 rotMatrix.translate(dx: 0, dy: -rect.height() + 1);
1643 rotMatrix.scale(sx: -1, sy: 1);
1644 painter->setTransform(transform: rotMatrix, combine: true);
1645 break;
1646 case QTabBar::RoundedWest:
1647 rotMatrix.rotate(a: 180 + 90);
1648 rotMatrix.scale(sx: -1, sy: 1);
1649 flip = true;
1650 painter->setTransform(transform: rotMatrix, combine: true);
1651 break;
1652 case QTabBar::RoundedEast:
1653 rotMatrix.rotate(a: 90);
1654 rotMatrix.translate(dx: 0, dy: - rect.width() + 1);
1655 flip = true;
1656 painter->setTransform(transform: rotMatrix, combine: true);
1657 break;
1658 default:
1659 painter->restore();
1660 QCommonStyle::drawControl(element, opt: tab, p: painter, w: widget);
1661 return;
1662 }
1663
1664 if (flip)
1665 rect = QRect(rect.y(), rect.x(), rect.height(), rect.width());
1666
1667 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
1668 painter->translate(dx: 0.5, dy: 0.5);
1669
1670 QColor tabFrameColor = tab->features & QStyleOptionTab::HasFrame ?
1671 d->tabFrameColor(pal: option->palette) :
1672 option->palette.window().color();
1673
1674 QLinearGradient fillGradient(rect.topLeft(), rect.bottomLeft());
1675 QLinearGradient outlineGradient(rect.topLeft(), rect.bottomLeft());
1676 const QColor outline = d->outline(pal: option->palette);
1677 if (selected) {
1678 fillGradient.setColorAt(pos: 0, color: tabFrameColor.lighter(f: 104));
1679 fillGradient.setColorAt(pos: 1, color: tabFrameColor);
1680 outlineGradient.setColorAt(pos: 1, color: outline);
1681 painter->setPen(QPen(outlineGradient, 1));
1682 } else {
1683 fillGradient.setColorAt(pos: 0, color: tabFrameColor.darker(f: 108));
1684 fillGradient.setColorAt(pos: 0.85, color: tabFrameColor.darker(f: 108));
1685 fillGradient.setColorAt(pos: 1, color: tabFrameColor.darker(f: 116));
1686 painter->setPen(outline.lighter(f: 110));
1687 }
1688
1689 QRect drawRect = rect.adjusted(xp1: 0, yp1: selected ? 0 : 2, xp2: 0, yp2: 3);
1690 painter->save();
1691 painter->setClipRect(rect.adjusted(xp1: -1, yp1: -1, xp2: 1, yp2: selected ? -2 : -3));
1692 painter->setBrush(fillGradient);
1693 painter->drawRoundedRect(rect: drawRect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 2.0, yRadius: 2.0);
1694 painter->setBrush(Qt::NoBrush);
1695 painter->setPen(QFusionStylePrivate::innerContrastLine);
1696 painter->drawRoundedRect(rect: drawRect.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -1), xRadius: 2.0, yRadius: 2.0);
1697 painter->restore();
1698
1699 if (selected) {
1700 painter->fillRect(x: rect.left() + 1, y: rect.bottom() - 1, w: rect.width() - 2, h: rect.bottom() - 1, b: tabFrameColor);
1701 painter->fillRect(QRect(rect.bottomRight() + QPoint(-2, -1), QSize(1, 1)), color: QFusionStylePrivate::innerContrastLine);
1702 painter->fillRect(QRect(rect.bottomLeft() + QPoint(0, -1), QSize(1, 1)), color: QFusionStylePrivate::innerContrastLine);
1703 painter->fillRect(QRect(rect.bottomRight() + QPoint(-1, -1), QSize(1, 1)), color: QFusionStylePrivate::innerContrastLine);
1704 }
1705 }
1706 painter->restore();
1707 break;
1708#endif //QT_CONFIG(tabbar)
1709 default:
1710 QCommonStyle::drawControl(element,opt: option,p: painter,w: widget);
1711 break;
1712 }
1713}
1714
1715extern QPalette qt_fusionPalette();
1716
1717/*!
1718 \reimp
1719*/
1720QPalette QFusionStyle::standardPalette () const
1721{
1722 return qt_fusionPalette();
1723}
1724
1725/*!
1726 \reimp
1727*/
1728void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
1729 QPainter *painter, const QWidget *widget) const
1730{
1731
1732 Q_D (const QFusionStyle);
1733 const QColor outline = d->outline(pal: option->palette);
1734 switch (control) {
1735 case CC_GroupBox:
1736 painter->save();
1737 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt: option)) {
1738 // Draw frame
1739 QRect textRect = proxy()->subControlRect(cc: CC_GroupBox, opt: option, sc: SC_GroupBoxLabel, widget);
1740 QRect checkBoxRect = proxy()->subControlRect(cc: CC_GroupBox, opt: option, sc: SC_GroupBoxCheckBox, widget);
1741
1742 if (groupBox->subControls & QStyle::SC_GroupBoxFrame) {
1743 QStyleOptionFrame frame;
1744 frame.QStyleOption::operator=(other: *groupBox);
1745 frame.features = groupBox->features;
1746 frame.lineWidth = groupBox->lineWidth;
1747 frame.midLineWidth = groupBox->midLineWidth;
1748 frame.rect = proxy()->subControlRect(cc: CC_GroupBox, opt: option, sc: SC_GroupBoxFrame, widget);
1749 painter->save();
1750 QRegion region(groupBox->rect);
1751 if (!groupBox->text.isEmpty()) {
1752 bool ltr = groupBox->direction == Qt::LeftToRight;
1753 QRect finalRect;
1754 if (groupBox->subControls & QStyle::SC_GroupBoxCheckBox) {
1755 finalRect = checkBoxRect.united(r: textRect);
1756 finalRect.adjust(dx1: ltr ? -4 : -2, dy1: 0, dx2: ltr ? 2 : 4, dy2: 0);
1757 } else {
1758 finalRect = textRect;
1759 finalRect.adjust(dx1: -2, dy1: 0, dx2: 2, dy2: 0);
1760 }
1761 region -= finalRect.adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: 3 - textRect.height() / 2);
1762 }
1763 painter->setClipRegion(region);
1764 if (isHighContrast()) {
1765 painter->setPen(outline);
1766 QMargins margins(3, 3, 3, 3);
1767 painter->drawRoundedRect(rect: frame.rect.marginsRemoved(margins), xRadius: 2, yRadius: 2);
1768 } else {
1769 proxy()->drawPrimitive(pe: PE_FrameGroupBox, opt: &frame, p: painter, w: widget);
1770 }
1771 painter->restore();
1772 }
1773
1774 // Draw title
1775 if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) {
1776 // groupBox->textColor gets the incorrect palette here
1777 painter->setPen(QPen(option->palette.windowText(), 1));
1778 int alignment = int(groupBox->textAlignment);
1779 if (!proxy()->styleHint(stylehint: QStyle::SH_UnderlineShortcut, opt: option, widget))
1780 alignment |= Qt::TextHideMnemonic;
1781
1782 proxy()->drawItemText(painter, rect: textRect, flags: Qt::TextShowMnemonic | Qt::AlignLeft | alignment,
1783 pal: groupBox->palette, enabled: groupBox->state & State_Enabled, text: groupBox->text, textRole: QPalette::NoRole);
1784
1785 if (groupBox->state & State_HasFocus) {
1786 QStyleOptionFocusRect fropt;
1787 fropt.QStyleOption::operator=(other: *groupBox);
1788 fropt.rect = textRect.adjusted(xp1: -2, yp1: -1, xp2: 2, yp2: 1);
1789 proxy()->drawPrimitive(pe: PE_FrameFocusRect, opt: &fropt, p: painter, w: widget);
1790 }
1791 }
1792
1793 // Draw checkbox
1794 if (groupBox->subControls & SC_GroupBoxCheckBox) {
1795 QStyleOptionButton box;
1796 box.QStyleOption::operator=(other: *groupBox);
1797 box.rect = checkBoxRect;
1798 proxy()->drawPrimitive(pe: PE_IndicatorCheckBox, opt: &box, p: painter, w: widget);
1799 }
1800 }
1801 painter->restore();
1802 break;
1803#if QT_CONFIG(spinbox)
1804 case CC_SpinBox:
1805 if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt: option)) {
1806 QCachedPainter cp(painter, "spinbox"_L1, option);
1807 if (cp.needsPainting()) {
1808 const QRect pixmapRect = cp.pixmapRect();
1809 const QRect r = pixmapRect.adjusted(xp1: 0, yp1: 1, xp2: 0, yp2: -1);
1810 const QColor buttonColor = d->buttonColor(pal: option->palette);
1811 const QColor &gradientStopColor = buttonColor;
1812 QColor arrowColor = spinBox->palette.windowText().color();
1813 arrowColor.setAlpha(160);
1814
1815 bool isEnabled = (spinBox->state & State_Enabled);
1816 bool hover = isEnabled && (spinBox->state & State_MouseOver);
1817 bool sunken = (spinBox->state & State_Sunken);
1818 bool upIsActive = (spinBox->activeSubControls == SC_SpinBoxUp);
1819 bool downIsActive = (spinBox->activeSubControls == SC_SpinBoxDown);
1820 bool hasFocus = (option->state & State_HasFocus);
1821
1822 QStyleOptionSpinBox spinBoxCopy = *spinBox;
1823 spinBoxCopy.rect = pixmapRect;
1824 QRect upRect = proxy()->subControlRect(cc: CC_SpinBox, opt: &spinBoxCopy, sc: SC_SpinBoxUp, widget);
1825 QRect downRect = proxy()->subControlRect(cc: CC_SpinBox, opt: &spinBoxCopy, sc: SC_SpinBoxDown, widget);
1826
1827 if (spinBox->frame) {
1828 cp->save();
1829 cp->setRenderHint(hint: QPainter::Antialiasing, on: true);
1830 cp->translate(dx: 0.5, dy: 0.5);
1831
1832 // Fill background
1833 cp->setPen(Qt::NoPen);
1834 cp->setBrush(option->palette.base());
1835 cp->drawRoundedRect(rect: r.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 2, yRadius: 2);
1836
1837 // Draw inner shadow
1838 cp->setPen(QFusionStylePrivate::topShadow);
1839 cp->drawLine(p1: QPoint(r.left() + 2, r.top() + 1), p2: QPoint(r.right() - 2, r.top() + 1));
1840
1841 if (!upRect.isNull()) {
1842 // Draw button gradient
1843 const QRect updownRect = upRect.adjusted(xp1: 0, yp1: -2, xp2: 0, yp2: downRect.height() + 2);
1844 const QLinearGradient gradient = qt_fusion_gradient(rect: updownRect, baseColor: (isEnabled && option->state & State_MouseOver )
1845 ? buttonColor : buttonColor.darker(f: 104));
1846
1847 cp->setPen(Qt::NoPen);
1848 cp->setBrush(gradient);
1849
1850 cp->save();
1851 cp->setClipRect(updownRect);
1852 cp->drawRoundedRect(rect: r.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 2, yRadius: 2);
1853 cp->setPen(QFusionStylePrivate::innerContrastLine);
1854 cp->setBrush(Qt::NoBrush);
1855 cp->drawRoundedRect(rect: r.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2), xRadius: 2, yRadius: 2);
1856 cp->restore();
1857 }
1858
1859 if ((spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) && upIsActive) {
1860 if (sunken)
1861 cp->fillRect(upRect.adjusted(xp1: 0, yp1: -1, xp2: 0, yp2: 0), color: gradientStopColor.darker(f: 110));
1862 else if (hover)
1863 cp->fillRect(upRect.adjusted(xp1: 0, yp1: -1, xp2: 0, yp2: 0), color: QFusionStylePrivate::innerContrastLine);
1864 }
1865
1866 if ((spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) && downIsActive) {
1867 if (sunken)
1868 cp->fillRect(downRect.adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: 1), color: gradientStopColor.darker(f: 110));
1869 else if (hover)
1870 cp->fillRect(downRect.adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: 1), color: QFusionStylePrivate::innerContrastLine);
1871 }
1872
1873 cp->setPen(hasFocus ? d->highlightedOutline(pal: option->palette) : d->outline(pal: option->palette));
1874 cp->setBrush(Qt::NoBrush);
1875 cp->drawRoundedRect(rect: r.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 2, yRadius: 2);
1876 if (hasFocus) {
1877 QColor softHighlight = option->palette.highlight().color();
1878 softHighlight.setAlpha(40);
1879 cp->setPen(softHighlight);
1880 cp->drawRoundedRect(rect: r.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2), xRadius: 1.7, yRadius: 1.7);
1881 }
1882 cp->restore();
1883 }
1884
1885 if (spinBox->buttonSymbols != QAbstractSpinBox::NoButtons) {
1886 // buttonSymbols == NoButtons results in 'null' rects
1887 // and a tiny rect painted in the corner.
1888 cp->setPen(d->outline(pal: option->palette));
1889 if (spinBox->direction == Qt::RightToLeft)
1890 cp->drawLine(l: QLineF(upRect.right(), upRect.top() - 0.5, upRect.right(), downRect.bottom() + 1.5));
1891 else
1892 cp->drawLine(l: QLineF(upRect.left(), upRect.top() - 0.5, upRect.left(), downRect.bottom() + 1.5));
1893 }
1894
1895 if (upIsActive && sunken) {
1896 cp->setPen(gradientStopColor.darker(f: 130));
1897 cp->drawLine(x1: downRect.left() + 1, y1: downRect.top(), x2: downRect.right(), y2: downRect.top());
1898 cp->drawLine(x1: upRect.left() + 1, y1: upRect.top(), x2: upRect.left() + 1, y2: upRect.bottom());
1899 cp->drawLine(x1: upRect.left() + 1, y1: upRect.top() - 1, x2: upRect.right(), y2: upRect.top() - 1);
1900 }
1901
1902 if (downIsActive && sunken) {
1903 cp->setPen(gradientStopColor.darker(f: 130));
1904 cp->drawLine(x1: downRect.left() + 1, y1: downRect.top(), x2: downRect.left() + 1, y2: downRect.bottom() + 1);
1905 cp->drawLine(x1: downRect.left() + 1, y1: downRect.top(), x2: downRect.right(), y2: downRect.top());
1906 cp->setPen(gradientStopColor.darker(f: 110));
1907 cp->drawLine(x1: downRect.left() + 1, y1: downRect.bottom() + 1, x2: downRect.right(), y2: downRect.bottom() + 1);
1908 }
1909
1910 QColor disabledColor = mergedColors(colorA: arrowColor, colorB: option->palette.button().color());
1911 if (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) {
1912 int centerX = upRect.center().x();
1913 int centerY = upRect.center().y();
1914
1915 // plus/minus
1916 cp->setPen((spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) ? arrowColor : disabledColor);
1917 cp->drawLine(x1: centerX - 1, y1: centerY, x2: centerX + 3, y2: centerY);
1918 cp->drawLine(x1: centerX + 1, y1: centerY - 2, x2: centerX + 1, y2: centerY + 2);
1919
1920 centerX = downRect.center().x();
1921 centerY = downRect.center().y();
1922 cp->setPen((spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) ? arrowColor : disabledColor);
1923 cp->drawLine(x1: centerX - 1, y1: centerY, x2: centerX + 3, y2: centerY);
1924
1925 } else if (spinBox->buttonSymbols == QAbstractSpinBox::UpDownArrows){
1926 // arrows
1927 qt_fusion_draw_arrow(type: Qt::UpArrow, painter: cp.painter(), option, rect: upRect.adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: 1),
1928 color: (spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) ? arrowColor : disabledColor);
1929 qt_fusion_draw_arrow(type: Qt::DownArrow, painter: cp.painter(), option, rect: downRect,
1930 color: (spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) ? arrowColor : disabledColor);
1931 }
1932 }
1933 }
1934 break;
1935#endif // QT_CONFIG(spinbox)
1936 case CC_TitleBar:
1937 painter->save();
1938 if (const QStyleOptionTitleBar *titleBar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt: option)) {
1939 constexpr auto buttonMargins = QMargins(5, 5, 5, 5);
1940 const bool active = (titleBar->titleBarState & State_Active);
1941 const QRect &fullRect = titleBar->rect;
1942 const QPalette &palette = option->palette;
1943 const QColor highlight = palette.highlight().color();
1944 const QColor outline = d->outline(pal: palette);
1945 const QColor buttonPaintingsColor(active ? 0xffffff : 0xff000000);
1946
1947 {
1948 // Fill title bar gradient
1949 const QColor titlebarColor = active ? highlight : palette.window().color();
1950 QLinearGradient gradient(option->rect.center().x(), option->rect.top(),
1951 option->rect.center().x(), option->rect.bottom());
1952
1953 gradient.setColorAt(pos: 0, color: titlebarColor.lighter(f: 114));
1954 gradient.setColorAt(pos: 0.5, color: titlebarColor.lighter(f: 102));
1955 gradient.setColorAt(pos: 0.51, color: titlebarColor.darker(f: 104));
1956 gradient.setColorAt(pos: 1, color: titlebarColor);
1957 painter->fillRect(option->rect.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: 0), gradient);
1958
1959 // Frame and rounded corners
1960 painter->setPen(active ? highlight.darker(f: 180) : outline.darker(f: 110));
1961
1962 // top outline
1963 const QLine lines[2] = {{fullRect.left() + 5, fullRect.top(), fullRect.right() - 5, fullRect.top()},
1964 {fullRect.left(), fullRect.top() + 4, fullRect.left(), fullRect.bottom()}};
1965 const QPoint points[5] = {
1966 QPoint(fullRect.left() + 4, fullRect.top() + 1),
1967 QPoint(fullRect.left() + 3, fullRect.top() + 1),
1968 QPoint(fullRect.left() + 2, fullRect.top() + 2),
1969 QPoint(fullRect.left() + 1, fullRect.top() + 3),
1970 QPoint(fullRect.left() + 1, fullRect.top() + 4)
1971 };
1972 painter->drawLines(lines, lineCount: 2);
1973 painter->drawPoints(points, pointCount: 5);
1974
1975 painter->drawLine(x1: fullRect.right(), y1: fullRect.top() + 4, x2: fullRect.right(), y2: fullRect.bottom());
1976 const QPoint points2[5] = {
1977 QPoint(fullRect.right() - 3, fullRect.top() + 1),
1978 QPoint(fullRect.right() - 4, fullRect.top() + 1),
1979 QPoint(fullRect.right() - 2, fullRect.top() + 2),
1980 QPoint(fullRect.right() - 1, fullRect.top() + 3),
1981 QPoint(fullRect.right() - 1, fullRect.top() + 4)
1982 };
1983 painter->drawPoints(points: points2, pointCount: 5);
1984
1985 // draw bottomline
1986 painter->drawLine(x1: fullRect.right(), y1: fullRect.bottom(), x2: fullRect.left(), y2: fullRect.bottom());
1987
1988 // top highlight
1989 painter->setPen(active ? highlight.lighter(f: 120): palette.window().color().lighter(f: 120));
1990 painter->drawLine(x1: fullRect.left() + 6, y1: fullRect.top() + 1, x2: fullRect.right() - 6, y2: fullRect.top() + 1);
1991 }
1992 // draw title
1993 const QRect textRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc: SC_TitleBarLabel, widget);
1994 painter->setPen(active ? palette.text().color().lighter(f: 120) : palette.text().color());
1995 // Note workspace also does elliding but it does not use the correct font
1996 const QString title =
1997 painter->fontMetrics().elidedText(text: titleBar->text, mode: Qt::ElideRight, width: textRect.width() - 14);
1998 painter->drawText(r: textRect.adjusted(xp1: 1, yp1: 1, xp2: 1, yp2: 1), text: title, o: QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
1999 painter->setPen(Qt::white);
2000 if (active)
2001 painter->drawText(r: textRect, text: title, o: QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
2002
2003 const auto isHover = [option](SubControl sc)
2004 { return (option->activeSubControls & sc) && (option->state & State_MouseOver); };
2005 const auto isSunken = [option](SubControl sc)
2006 { return (option->activeSubControls & sc) && (option->state & State_Sunken); };
2007 // min button
2008 if ((titleBar->subControls & SC_TitleBarMinButton) && (titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
2009 !(titleBar->titleBarState& Qt::WindowMinimized)) {
2010 const auto sc = SC_TitleBarMinButton;
2011 const auto buttonRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc, widget);
2012 if (buttonRect.isValid()) {
2013 qt_fusion_draw_mdibutton(painter, option: titleBar, tmp: buttonRect, hover: isHover(sc), sunken: isSunken(sc));
2014
2015 const QRect rect = buttonRect.marginsRemoved(margins: buttonMargins);
2016 const QLine lines[2] = {{rect.left(), rect.bottom(), rect.right() - 1, rect.bottom()},
2017 {rect.left(), rect.bottom() - 1, rect.right() - 1, rect.bottom() - 1}};
2018 painter->setPen(buttonPaintingsColor);
2019 painter->drawLines(lines, lineCount: 2);
2020 }
2021 }
2022 // max button
2023 if ((titleBar->subControls & SC_TitleBarMaxButton) && (titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
2024 !(titleBar->titleBarState & Qt::WindowMaximized)) {
2025 const auto sc = SC_TitleBarMaxButton;
2026 const auto buttonRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc, widget);
2027 if (buttonRect.isValid()) {
2028 qt_fusion_draw_mdibutton(painter, option: titleBar, tmp: buttonRect, hover: isHover(sc), sunken: isSunken(sc));
2029
2030 const QRect rect = buttonRect.marginsRemoved(margins: buttonMargins);
2031 const QLine lines[5] = {{rect.left(), rect.top(), rect.right(), rect.top()},
2032 {rect.left(), rect.top() + 1, rect.right(), rect.top() + 1},
2033 {rect.left(), rect.bottom(), rect.right(), rect.bottom()},
2034 {rect.left(), rect.top(), rect.left(), rect.bottom()},
2035 {rect.right(), rect.top(), rect.right(), rect.bottom()}};
2036 painter->setPen(buttonPaintingsColor);
2037 painter->drawLines(lines, lineCount: 5);
2038 }
2039 }
2040
2041 // close button
2042 if ((titleBar->subControls & SC_TitleBarCloseButton) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) {
2043 const auto sc = SC_TitleBarCloseButton;
2044 const auto buttonRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc, widget);
2045 if (buttonRect.isValid()) {
2046 qt_fusion_draw_mdibutton(painter, option: titleBar, tmp: buttonRect, hover: isHover(sc), sunken: isSunken(sc));
2047 QRect rect = buttonRect.marginsRemoved(margins: buttonMargins);
2048 rect.setWidth((rect.width() / 2) * 2 + 1);
2049 rect.setHeight((rect.height() / 2) * 2 + 1);
2050 const QLine lines[2] = { { rect.topLeft(), rect.bottomRight() },
2051 { rect.topRight(), rect.bottomLeft() }, };
2052 const auto pen = QPen(buttonPaintingsColor, 2);
2053 painter->setPen(pen);
2054 painter->drawLines(lines, lineCount: 2);
2055 }
2056 }
2057
2058 // normalize button
2059 if ((titleBar->subControls & SC_TitleBarNormalButton) &&
2060 (((titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
2061 (titleBar->titleBarState & Qt::WindowMinimized)) ||
2062 ((titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
2063 (titleBar->titleBarState & Qt::WindowMaximized)))) {
2064 const auto sc = SC_TitleBarNormalButton;
2065 const auto buttonRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc, widget);
2066 if (buttonRect.isValid()) {
2067 qt_fusion_draw_mdibutton(painter, option: titleBar, tmp: buttonRect, hover: isHover(sc), sunken: isSunken(sc));
2068
2069 QRect normalButtonIconRect = buttonRect.marginsRemoved(margins: buttonMargins);
2070 painter->setPen(buttonPaintingsColor);
2071 {
2072 const QRect rect = normalButtonIconRect.adjusted(xp1: 0, yp1: 3, xp2: -3, yp2: 0);
2073 const QLine lines[5] = {{rect.left(), rect.top(), rect.right(), rect.top()},
2074 {rect.left(), rect.top() + 1, rect.right(), rect.top() + 1},
2075 {rect.left(), rect.bottom(), rect.right(), rect.bottom()},
2076 {rect.left(), rect.top(), rect.left(), rect.bottom()},
2077 {rect.right(), rect.top(), rect.right(), rect.bottom()}};
2078 painter->drawLines(lines, lineCount: 5);
2079 }
2080 {
2081 const QRect rect = normalButtonIconRect.adjusted(xp1: 3, yp1: 0, xp2: 0, yp2: -3);
2082 const QLine lines[5] = {{rect.left(), rect.top(), rect.right(), rect.top()},
2083 {rect.left(), rect.top() + 1, rect.right(), rect.top() + 1},
2084 {rect.left(), rect.bottom(), rect.right(), rect.bottom()},
2085 {rect.left(), rect.top(), rect.left(), rect.bottom()},
2086 {rect.right(), rect.top(), rect.right(), rect.bottom()}};
2087 painter->drawLines(lines, lineCount: 5);
2088 }
2089 }
2090 }
2091
2092 // context help button
2093 if (titleBar->subControls & SC_TitleBarContextHelpButton
2094 && (titleBar->titleBarFlags & Qt::WindowContextHelpButtonHint)) {
2095 const auto sc = SC_TitleBarContextHelpButton;
2096 const auto buttonRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc, widget);
2097 if (buttonRect.isValid()) {
2098 qt_fusion_draw_mdibutton(painter, option: titleBar, tmp: buttonRect, hover: isHover(sc), sunken: isSunken(sc));
2099#if QT_CONFIG(imageformat_xpm)
2100 QImage image(qt_titlebar_context_help);
2101 QColor alpha = buttonPaintingsColor;
2102 alpha.setAlpha(128);
2103 image.setColor(i: 1, c: buttonPaintingsColor.rgba());
2104 image.setColor(i: 2, c: alpha.rgba());
2105 painter->setRenderHint(hint: QPainter::SmoothPixmapTransform);
2106 painter->drawImage(r: buttonRect.adjusted(xp1: 4, yp1: 4, xp2: -4, yp2: -4), image);
2107#endif
2108 }
2109 }
2110
2111 // shade button
2112 if (titleBar->subControls & SC_TitleBarShadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) {
2113 const auto sc = SC_TitleBarShadeButton;
2114 const auto buttonRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc, widget);
2115 if (buttonRect.isValid()) {
2116 qt_fusion_draw_mdibutton(painter, option: titleBar, tmp: buttonRect, hover: isHover(sc), sunken: isSunken(sc));
2117 qt_fusion_draw_arrow(type: Qt::UpArrow, painter, option, rect: buttonRect.adjusted(xp1: 5, yp1: 7, xp2: -5, yp2: -7), color: buttonPaintingsColor);
2118 }
2119 }
2120
2121 // unshade button
2122 if (titleBar->subControls & SC_TitleBarUnshadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) {
2123 const auto sc = SC_TitleBarUnshadeButton;
2124 const auto buttonRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc, widget);
2125 if (buttonRect.isValid()) {
2126 qt_fusion_draw_mdibutton(painter, option: titleBar, tmp: buttonRect, hover: isHover(sc), sunken: isSunken(sc));
2127 qt_fusion_draw_arrow(type: Qt::DownArrow, painter, option, rect: buttonRect.adjusted(xp1: 5, yp1: 7, xp2: -5, yp2: -7), color: buttonPaintingsColor);
2128 }
2129 }
2130
2131 if ((titleBar->subControls & SC_TitleBarSysMenu) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) {
2132 QRect iconRect = proxy()->subControlRect(cc: CC_TitleBar, opt: titleBar, sc: SC_TitleBarSysMenu, widget);
2133 if (iconRect.isValid()) {
2134 if (!titleBar->icon.isNull()) {
2135 titleBar->icon.paint(painter, rect: iconRect);
2136 } else {
2137 QStyleOption tool = *titleBar;
2138 QPixmap pm = proxy()->standardIcon(standardIcon: SP_TitleBarMenuButton, option: &tool, widget)
2139 .pixmap(size: QSize(16, 16), devicePixelRatio: QStyleHelper::getDpr(painter));
2140 tool.rect = iconRect;
2141 painter->save();
2142 proxy()->drawItemPixmap(painter, rect: iconRect, alignment: Qt::AlignCenter, pixmap: pm);
2143 painter->restore();
2144 }
2145 }
2146 }
2147 }
2148 painter->restore();
2149 break;
2150#if QT_CONFIG(slider)
2151 case CC_ScrollBar:
2152 painter->save();
2153 if (const QStyleOptionSlider *scrollBar = qstyleoption_cast<const QStyleOptionSlider *>(opt: option)) {
2154 bool wasActive = false;
2155 qreal expandScale = 1.0;
2156 qreal expandOffset = -1.0;
2157 QObject *styleObject = option->styleObject;
2158 if (styleObject && proxy()->styleHint(stylehint: SH_ScrollBar_Transient, opt: option, widget)) {
2159#if QT_CONFIG(animation)
2160 qreal opacity = 0.0;
2161 bool shouldExpand = false;
2162 const qreal maxExpandScale = 13.0 / 9.0;
2163#endif
2164
2165 int oldPos = styleObject->property(name: "_q_stylepos").toInt();
2166 int oldMin = styleObject->property(name: "_q_stylemin").toInt();
2167 int oldMax = styleObject->property(name: "_q_stylemax").toInt();
2168 QRect oldRect = styleObject->property(name: "_q_stylerect").toRect();
2169 QStyle::State oldState = static_cast<QStyle::State>(qvariant_cast<QStyle::State::Int>(v: styleObject->property(name: "_q_stylestate")));
2170 uint oldActiveControls = styleObject->property(name: "_q_stylecontrols").toUInt();
2171
2172 // a scrollbar is transient when the scrollbar itself and
2173 // its sibling are both inactive (ie. not pressed/hovered/moved)
2174 bool transient = !option->activeSubControls && !(option->state & State_On);
2175
2176 if (!transient ||
2177 oldPos != scrollBar->sliderPosition ||
2178 oldMin != scrollBar->minimum ||
2179 oldMax != scrollBar->maximum ||
2180 oldRect != scrollBar->rect ||
2181 oldState != scrollBar->state ||
2182 oldActiveControls != scrollBar->activeSubControls) {
2183
2184 styleObject->setProperty(name: "_q_stylepos", value: scrollBar->sliderPosition);
2185 styleObject->setProperty(name: "_q_stylemin", value: scrollBar->minimum);
2186 styleObject->setProperty(name: "_q_stylemax", value: scrollBar->maximum);
2187 styleObject->setProperty(name: "_q_stylerect", value: scrollBar->rect);
2188 styleObject->setProperty(name: "_q_stylestate", value: static_cast<QStyle::State::Int>(scrollBar->state));
2189 styleObject->setProperty(name: "_q_stylecontrols", value: static_cast<uint>(scrollBar->activeSubControls));
2190
2191#if QT_CONFIG(animation)
2192 // if the scrollbar is transient or its attributes, geometry or
2193 // state has changed, the opacity is reset back to 100% opaque
2194 opacity = 1.0;
2195
2196 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(object: d->animation(target: styleObject));
2197 if (transient) {
2198 if (!anim) {
2199 anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating, styleObject);
2200 d->startAnimation(animation: anim);
2201 } else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
2202 // the scrollbar was already fading out while the
2203 // state changed -> restart the fade out animation
2204 anim->setCurrentTime(0);
2205 }
2206 } else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
2207 d->stopAnimation(target: styleObject);
2208 }
2209#endif // animation
2210 }
2211
2212#if QT_CONFIG(animation)
2213 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(object: d->animation(target: styleObject));
2214 if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
2215 // once a scrollbar was active (hovered/pressed), it retains
2216 // the active look even if it's no longer active while fading out
2217 if (oldActiveControls)
2218 anim->setActive(true);
2219
2220 wasActive = anim->wasActive();
2221 opacity = anim->currentValue();
2222 }
2223
2224 shouldExpand = (option->activeSubControls || wasActive);
2225 if (shouldExpand) {
2226 if (!anim && !oldActiveControls) {
2227 // Start expand animation only once and when entering
2228 anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating, styleObject);
2229 d->startAnimation(animation: anim);
2230 }
2231 if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
2232 expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
2233 expandOffset = 5.5 * anim->currentValue() - 1;
2234 } else {
2235 // Keep expanded state after the animation ends, and when fading out
2236 expandScale = maxExpandScale;
2237 expandOffset = 4.5;
2238 }
2239 }
2240 painter->setOpacity(opacity);
2241#endif // animation
2242 }
2243
2244 bool transient = proxy()->styleHint(stylehint: SH_ScrollBar_Transient, opt: option, widget);
2245 bool horizontal = scrollBar->orientation == Qt::Horizontal;
2246 bool sunken = scrollBar->state & State_Sunken;
2247
2248 QRect scrollBarSubLine = proxy()->subControlRect(cc: control, opt: scrollBar, sc: SC_ScrollBarSubLine, widget);
2249 QRect scrollBarAddLine = proxy()->subControlRect(cc: control, opt: scrollBar, sc: SC_ScrollBarAddLine, widget);
2250 QRect scrollBarSlider = proxy()->subControlRect(cc: control, opt: scrollBar, sc: SC_ScrollBarSlider, widget);
2251 QRect scrollBarGroove = proxy()->subControlRect(cc: control, opt: scrollBar, sc: SC_ScrollBarGroove, widget);
2252
2253 QRect rect = option->rect;
2254 QColor alphaOutline = d->outline(pal: option->palette);
2255 alphaOutline.setAlpha(180);
2256
2257 QColor arrowColor = option->palette.windowText().color();
2258 arrowColor.setAlpha(160);
2259
2260 const QColor bgColor = QStyleHelper::backgroundColor(pal: option->palette, widget);
2261 const bool isDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
2262
2263 if (transient) {
2264 if (horizontal) {
2265 rect.setY(rect.y() + 4.5 - expandOffset);
2266 scrollBarSlider.setY(scrollBarSlider.y() + 4.5 - expandOffset);
2267 scrollBarGroove.setY(scrollBarGroove.y() + 4.5 - expandOffset);
2268
2269 rect.setHeight(rect.height() * expandScale);
2270 scrollBarGroove.setHeight(scrollBarGroove.height() * expandScale);
2271 } else {
2272 rect.setX(rect.x() + 4.5 - expandOffset);
2273 scrollBarSlider.setX(scrollBarSlider.x() + 4.5 - expandOffset);
2274 scrollBarGroove.setX(scrollBarGroove.x() + 4.5 - expandOffset);
2275
2276 rect.setWidth(rect.width() * expandScale);
2277 scrollBarGroove.setWidth(scrollBarGroove.width() * expandScale);
2278 }
2279 }
2280
2281 // Paint groove
2282 if ((!transient || scrollBar->activeSubControls || wasActive) && scrollBar->subControls & SC_ScrollBarGroove) {
2283 QLinearGradient gradient(rect.center().x(), rect.top(),
2284 rect.center().x(), rect.bottom());
2285 if (!horizontal)
2286 gradient = QLinearGradient(rect.left(), rect.center().y(),
2287 rect.right(), rect.center().y());
2288 if (!transient || !isDarkBg) {
2289 QColor buttonColor = d->buttonColor(pal: option->palette);
2290 gradient.setColorAt(pos: 0, color: buttonColor.darker(f: 107));
2291 gradient.setColorAt(pos: 0.1, color: buttonColor.darker(f: 105));
2292 gradient.setColorAt(pos: 0.9, color: buttonColor.darker(f: 105));
2293 gradient.setColorAt(pos: 1, color: buttonColor.darker(f: 107));
2294 } else {
2295 gradient.setColorAt(pos: 0, color: bgColor.lighter(f: 157));
2296 gradient.setColorAt(pos: 0.1, color: bgColor.lighter(f: 155));
2297 gradient.setColorAt(pos: 0.9, color: bgColor.lighter(f: 155));
2298 gradient.setColorAt(pos: 1, color: bgColor.lighter(f: 157));
2299 }
2300
2301 painter->save();
2302 if (transient)
2303 painter->setOpacity(0.8);
2304 painter->fillRect(rect, gradient);
2305 painter->setPen(Qt::NoPen);
2306 if (transient)
2307 painter->setOpacity(0.4);
2308 painter->setPen(alphaOutline);
2309 if (horizontal)
2310 painter->drawLine(p1: rect.topLeft(), p2: rect.topRight());
2311 else
2312 painter->drawLine(p1: rect.topLeft(), p2: rect.bottomLeft());
2313
2314 QColor subtleEdge = alphaOutline;
2315 subtleEdge.setAlpha(40);
2316 painter->setPen(subtleEdge);
2317 painter->setBrush(Qt::NoBrush);
2318 painter->drawRect(r: scrollBarGroove.adjusted(xp1: horizontal ? 0 : 1, yp1: horizontal ? 1 : 0, xp2: -1, yp2: -1));
2319 painter->restore();
2320 }
2321
2322 QRect pixmapRect = scrollBarSlider;
2323 QLinearGradient gradient(pixmapRect.center().x(), pixmapRect.top(),
2324 pixmapRect.center().x(), pixmapRect.bottom());
2325 if (!horizontal)
2326 gradient = QLinearGradient(pixmapRect.left(), pixmapRect.center().y(),
2327 pixmapRect.right(), pixmapRect.center().y());
2328
2329 QLinearGradient highlightedGradient = gradient;
2330
2331 const QColor buttonColor = d->buttonColor(pal: option->palette);
2332 const QColor gradientStartColor = buttonColor.lighter(f: 118);
2333 const QColor &gradientStopColor = buttonColor;
2334 const QColor midColor2 = mergedColors(colorA: gradientStartColor, colorB: gradientStopColor, factor: 40);
2335 gradient.setColorAt(pos: 0, color: buttonColor.lighter(f: 108));
2336 gradient.setColorAt(pos: 1, color: buttonColor);
2337
2338 highlightedGradient.setColorAt(pos: 0, color: gradientStartColor.darker(f: 102));
2339 highlightedGradient.setColorAt(pos: 1, color: gradientStopColor.lighter(f: 102));
2340
2341 // Paint slider
2342 if (scrollBar->subControls & SC_ScrollBarSlider) {
2343 if (transient) {
2344 QRect rect = scrollBarSlider.adjusted(xp1: horizontal ? 1 : 2, yp1: horizontal ? 2 : 1, xp2: -1, yp2: -1);
2345 painter->setPen(Qt::NoPen);
2346 painter->setBrush(isDarkBg ? QFusionStylePrivate::lightShade : QFusionStylePrivate::darkShade);
2347 int r = qMin(a: rect.width(), b: rect.height()) / 2;
2348
2349 painter->save();
2350 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
2351 painter->drawRoundedRect(rect, xRadius: r, yRadius: r);
2352 painter->restore();
2353 } else {
2354 QRect pixmapRect = scrollBarSlider;
2355 painter->setPen(alphaOutline);
2356 if (option->state & State_Sunken && scrollBar->activeSubControls & SC_ScrollBarSlider)
2357 painter->setBrush(midColor2);
2358 else if (option->state & State_MouseOver && scrollBar->activeSubControls & SC_ScrollBarSlider)
2359 painter->setBrush(highlightedGradient);
2360 else if (!isDarkBg)
2361 painter->setBrush(gradient);
2362 else
2363 painter->setBrush(midColor2);
2364
2365 painter->drawRect(r: pixmapRect.adjusted(xp1: horizontal ? -1 : 0, yp1: horizontal ? 0 : -1, xp2: horizontal ? 0 : -1, yp2: horizontal ? -1 : 0));
2366
2367 painter->setPen(QFusionStylePrivate::innerContrastLine);
2368 painter->drawRect(r: scrollBarSlider.adjusted(xp1: horizontal ? 0 : 1, yp1: horizontal ? 1 : 0, xp2: -1, yp2: -1));
2369
2370 // Outer shadow
2371 // painter->setPen(subtleEdge);
2372 // if (horizontal) {
2373 //// painter->drawLine(scrollBarSlider.topLeft() + QPoint(-2, 0), scrollBarSlider.bottomLeft() + QPoint(2, 0));
2374 //// painter->drawLine(scrollBarSlider.topRight() + QPoint(-2, 0), scrollBarSlider.bottomRight() + QPoint(2, 0));
2375 // } else {
2376 //// painter->drawLine(pixmapRect.topLeft() + QPoint(0, -2), pixmapRect.bottomLeft() + QPoint(0, -2));
2377 //// painter->drawLine(pixmapRect.topRight() + QPoint(0, 2), pixmapRect.bottomRight() + QPoint(0, 2));
2378 // }
2379 }
2380 }
2381
2382 // The SubLine (up/left) buttons
2383 if (!transient && scrollBar->subControls & SC_ScrollBarSubLine) {
2384 if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken)
2385 painter->setBrush(gradientStopColor);
2386 else if ((scrollBar->activeSubControls & SC_ScrollBarSubLine))
2387 painter->setBrush(highlightedGradient);
2388 else
2389 painter->setBrush(gradient);
2390
2391 const QRect upRect = scrollBarSubLine.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1);
2392 painter->setPen(Qt::NoPen);
2393 painter->drawRect(r: upRect.adjusted(xp1: horizontal ? 0 : 1, yp1: horizontal ? 1 : 0, xp2: 0, yp2: 0));
2394 painter->setPen(alphaOutline);
2395 painter->drawRect(r: upRect);
2396
2397 painter->setBrush(Qt::NoBrush);
2398 painter->setPen(QFusionStylePrivate::innerContrastLine);
2399 painter->drawRect(r: upRect.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1));
2400
2401 // Arrows
2402 Qt::ArrowType arrowType = Qt::UpArrow;
2403 if (option->state & State_Horizontal)
2404 arrowType = option->direction == Qt::LeftToRight ? Qt::LeftArrow : Qt::RightArrow;
2405 qt_fusion_draw_arrow(type: arrowType, painter, option, rect: upRect.adjusted(xp1: 1, yp1: 1, xp2: 0, yp2: 0), color: arrowColor);
2406 }
2407
2408 // The AddLine (down/right) button
2409 if (!transient && scrollBar->subControls & SC_ScrollBarAddLine) {
2410 if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken)
2411 painter->setBrush(gradientStopColor);
2412 else if ((scrollBar->activeSubControls & SC_ScrollBarAddLine))
2413 painter->setBrush(midColor2);
2414 else
2415 painter->setBrush(gradient);
2416
2417 const QRect downRect = scrollBarAddLine.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1);
2418 painter->setPen(Qt::NoPen);
2419 painter->drawRect(r: downRect.adjusted(xp1: horizontal ? 0 : 1, yp1: horizontal ? 1 : 0, xp2: 0, yp2: 0));
2420 painter->setPen(alphaOutline);
2421 painter->drawRect(r: downRect);
2422
2423 painter->setBrush(Qt::NoBrush);
2424 painter->setPen(QFusionStylePrivate::innerContrastLine);
2425 painter->drawRect(r: downRect.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1));
2426
2427 Qt::ArrowType arrowType = Qt::DownArrow;
2428 if (option->state & State_Horizontal)
2429 arrowType = option->direction == Qt::LeftToRight ? Qt::RightArrow : Qt::LeftArrow;
2430 qt_fusion_draw_arrow(type: arrowType, painter, option, rect: downRect.adjusted(xp1: 1, yp1: 1, xp2: 0, yp2: 0), color: arrowColor);
2431 }
2432
2433 }
2434 painter->restore();
2435 break;
2436#endif // QT_CONFIG(slider)
2437 case CC_ComboBox:
2438 painter->save();
2439 if (const QStyleOptionComboBox *comboBox = qstyleoption_cast<const QStyleOptionComboBox *>(opt: option)) {
2440 bool hasFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange;
2441 bool sunken = comboBox->state & State_On; // play dead, if combobox has no items
2442 bool isEnabled = (comboBox->state & State_Enabled);
2443 const QString pixmapName = "combobox"_L1
2444 % QLatin1StringView(sunken ? "-sunken" : "")
2445 % QLatin1StringView(comboBox->editable ? "-editable" : "")
2446 % QLatin1StringView(isEnabled ? "-enabled" : "")
2447 % QLatin1StringView(!comboBox->frame ? "-frameless" : "");
2448 QCachedPainter cp(painter, pixmapName, option);
2449 if (cp.needsPainting()) {
2450 const QRect pixmapRect = cp.pixmapRect();
2451 QStyleOptionComboBox comboBoxCopy = *comboBox;
2452 comboBoxCopy.rect = pixmapRect;
2453
2454 QRect rect = pixmapRect;
2455 QRect downArrowRect = proxy()->subControlRect(cc: CC_ComboBox, opt: &comboBoxCopy,
2456 sc: SC_ComboBoxArrow, widget);
2457 // Draw a line edit
2458 if (comboBox->editable) {
2459 QStyleOptionFrame buttonOption;
2460 buttonOption.QStyleOption::operator=(other: *comboBox);
2461 buttonOption.rect = rect;
2462 buttonOption.state = (comboBox->state & (State_Enabled | State_MouseOver | State_HasFocus))
2463 | State_KeyboardFocusChange; // Always show hig
2464
2465 if (sunken) {
2466 buttonOption.state |= State_Sunken;
2467 buttonOption.state &= ~State_MouseOver;
2468 }
2469
2470 if (comboBox->frame) {
2471 cp->save();
2472 cp->setRenderHint(hint: QPainter::Antialiasing, on: true);
2473 cp->translate(dx: 0.5, dy: 0.5);
2474 cp->setPen(Qt::NoPen);
2475 cp->setBrush(buttonOption.palette.base());
2476 cp->drawRoundedRect(rect: rect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1), xRadius: 2, yRadius: 2);
2477 cp->restore();
2478 proxy()->drawPrimitive(pe: PE_FrameLineEdit, opt: &buttonOption, p: cp.painter(), w: widget);
2479 }
2480
2481 // Draw button clipped
2482 cp->save();
2483 cp->setClipRect(downArrowRect.adjusted(xp1: 0, yp1: 0, xp2: 1, yp2: 0));
2484 buttonOption.rect.setLeft(comboBox->direction == Qt::LeftToRight ?
2485 downArrowRect.left() - 6: downArrowRect.right() + 6);
2486 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: &buttonOption, p: cp.painter(), w: widget);
2487 cp->restore();
2488 cp->setPen(QPen(hasFocus ? option->palette.highlight() : d->outline(pal: option->palette).lighter(f: 110), 1));
2489
2490 if (!sunken) {
2491 int borderSize = 1;
2492 if (comboBox->direction == Qt::RightToLeft) {
2493 cp->drawLine(p1: QPoint(downArrowRect.right() - 1, downArrowRect.top() + borderSize ),
2494 p2: QPoint(downArrowRect.right() - 1, downArrowRect.bottom() - borderSize));
2495 } else {
2496 cp->drawLine(p1: QPoint(downArrowRect.left() , downArrowRect.top() + borderSize),
2497 p2: QPoint(downArrowRect.left() , downArrowRect.bottom() - borderSize));
2498 }
2499 } else {
2500 if (comboBox->direction == Qt::RightToLeft) {
2501 cp->drawLine(p1: QPoint(downArrowRect.right(), downArrowRect.top() + 2),
2502 p2: QPoint(downArrowRect.right(), downArrowRect.bottom() - 2));
2503
2504 } else {
2505 cp->drawLine(p1: QPoint(downArrowRect.left(), downArrowRect.top() + 2),
2506 p2: QPoint(downArrowRect.left(), downArrowRect.bottom() - 2));
2507 }
2508 }
2509 } else {
2510 QStyleOptionButton buttonOption;
2511 buttonOption.QStyleOption::operator=(other: *comboBox);
2512 buttonOption.rect = rect;
2513 buttonOption.state = comboBox->state & (State_Enabled | State_MouseOver | State_HasFocus | State_KeyboardFocusChange);
2514 if (sunken) {
2515 buttonOption.state |= State_Sunken;
2516 buttonOption.state &= ~State_MouseOver;
2517 }
2518 proxy()->drawPrimitive(pe: PE_PanelButtonCommand, opt: &buttonOption, p: cp.painter(), w: widget);
2519 }
2520 if (comboBox->subControls & SC_ComboBoxArrow) {
2521 // Draw the up/down arrow
2522 QColor arrowColor = option->palette.buttonText().color();
2523 arrowColor.setAlpha(160);
2524 qt_fusion_draw_arrow(type: Qt::DownArrow, painter: cp.painter(), option, rect: downArrowRect, color: arrowColor);
2525 }
2526 }
2527 }
2528 painter->restore();
2529 break;
2530#if QT_CONFIG(slider)
2531 case CC_Slider:
2532 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt: option)) {
2533 QPainterStateGuard psg(painter);
2534 QRect groove = proxy()->subControlRect(cc: CC_Slider, opt: option, sc: SC_SliderGroove, widget);
2535 QRect handle = proxy()->subControlRect(cc: CC_Slider, opt: option, sc: SC_SliderHandle, widget);
2536
2537 bool horizontal = slider->orientation == Qt::Horizontal;
2538 bool ticksAbove = slider->tickPosition & QSlider::TicksAbove;
2539 bool ticksBelow = slider->tickPosition & QSlider::TicksBelow;
2540 const QColor activeHighlight = d->highlight(pal: option->palette);
2541 const QColor shadowAlpha(0, 0, 0, 10); // Qt::black with 4% opacity
2542 const QColor outline = (option->state & State_HasFocus
2543 && option->state & State_KeyboardFocusChange)
2544 ? d->highlightedOutline(pal: option->palette)
2545 : d->outline(pal: option->palette);
2546
2547 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
2548 if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
2549 // draw background groove
2550 QCachedPainter cp(painter, "slider_groove"_L1, option, groove.size(), groove);
2551 if (cp.needsPainting()) {
2552 const QRect pixmapRect = cp.pixmapRect();
2553 const QColor buttonColor = d->buttonColor(pal: option->palette);
2554 const auto grooveColor =
2555 QColor::fromHsv(h: buttonColor.hue(),
2556 s: qMin(a: 255, b: (int)(buttonColor.saturation())),
2557 v: qMin(a: 255, b: (int)(buttonColor.value()*0.9)));
2558 cp->translate(dx: 0.5, dy: 0.5);
2559 QLinearGradient gradient;
2560 if (horizontal) {
2561 gradient.setStart(x: pixmapRect.center().x(), y: pixmapRect.top());
2562 gradient.setFinalStop(x: pixmapRect.center().x(), y: pixmapRect.bottom());
2563 }
2564 else {
2565 gradient.setStart(x: pixmapRect.left(), y: pixmapRect.center().y());
2566 gradient.setFinalStop(x: pixmapRect.right(), y: pixmapRect.center().y());
2567 }
2568 cp->setPen(outline);
2569 gradient.setColorAt(pos: 0, color: grooveColor.darker(f: 110));
2570 gradient.setColorAt(pos: 1, color: grooveColor.lighter(f: 110));//palette.button().color().darker(115));
2571 cp->setBrush(gradient);
2572 cp->drawRoundedRect(rect: pixmapRect.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2), xRadius: 1, yRadius: 1);
2573 }
2574 cp.finish();
2575
2576 // draw blue groove highlight
2577 QRect clipRect;
2578 if (horizontal) {
2579 if (slider->upsideDown)
2580 clipRect = QRect(handle.right(), groove.top(), groove.right() - handle.right(), groove.height());
2581 else
2582 clipRect = QRect(groove.left(), groove.top(),
2583 handle.left() - slider->rect.left(), groove.height());
2584 } else {
2585 if (slider->upsideDown)
2586 clipRect = QRect(groove.left(), handle.bottom(), groove.width(), groove.height() - (handle.bottom() - slider->rect.top()));
2587 else
2588 clipRect = QRect(groove.left(), groove.top(), groove.width(), handle.top() - groove.top());
2589 }
2590 painter->save();
2591 painter->setClipRect(clipRect.adjusted(xp1: 0, yp1: 0, xp2: 1, yp2: 1), op: Qt::IntersectClip);
2592
2593 QCachedPainter cpBlue(painter, "slider_groove_blue"_L1, option, groove.size(), groove);
2594 if (cpBlue.needsPainting()) {
2595 const QRect pixmapRect = cp.pixmapRect();
2596 QLinearGradient gradient;
2597 if (horizontal) {
2598 gradient.setStart(x: pixmapRect.center().x(), y: pixmapRect.top());
2599 gradient.setFinalStop(x: pixmapRect.center().x(), y: pixmapRect.bottom());
2600 }
2601 else {
2602 gradient.setStart(x: pixmapRect.left(), y: pixmapRect.center().y());
2603 gradient.setFinalStop(x: pixmapRect.right(), y: pixmapRect.center().y());
2604 }
2605 const QColor highlightedoutline = activeHighlight.darker(f: 140);
2606 QColor grooveOutline = outline;
2607 if (qGray(rgb: grooveOutline.rgb()) > qGray(rgb: highlightedoutline.rgb()))
2608 grooveOutline = highlightedoutline;
2609
2610 cpBlue->translate(dx: 0.5, dy: 0.5);
2611 cpBlue->setPen(grooveOutline);
2612 gradient.setColorAt(pos: 0, color: activeHighlight);
2613 gradient.setColorAt(pos: 1, color: activeHighlight.lighter(f: 130));
2614 cpBlue->setBrush(gradient);
2615 cpBlue->drawRoundedRect(rect: pixmapRect.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2), xRadius: 1, yRadius: 1);
2616 cpBlue->setPen(QFusionStylePrivate::innerContrastLine);
2617 cpBlue->setBrush(Qt::NoBrush);
2618 cpBlue->drawRoundedRect(rect: pixmapRect.adjusted(xp1: 2, yp1: 2, xp2: -3, yp2: -3), xRadius: 1, yRadius: 1);
2619 }
2620 cpBlue.finish();
2621 painter->restore();
2622 }
2623
2624 if (option->subControls & SC_SliderTickmarks) {
2625 painter->save();
2626 painter->translate(dx: slider->rect.x(), dy: slider->rect.y());
2627 painter->setRenderHint(hint: QPainter::Antialiasing, on: false);
2628 painter->setPen(outline);
2629 int tickSize = proxy()->pixelMetric(metric: PM_SliderTickmarkOffset, option, widget);
2630 int available = proxy()->pixelMetric(metric: PM_SliderSpaceAvailable, option: slider, widget);
2631 int interval = slider->tickInterval;
2632 if (interval <= 0) {
2633 interval = slider->singleStep;
2634 if (QStyle::sliderPositionFromValue(min: slider->minimum, max: slider->maximum, val: interval,
2635 space: available)
2636 - QStyle::sliderPositionFromValue(min: slider->minimum, max: slider->maximum,
2637 val: 0, space: available) < 3)
2638 interval = slider->pageStep;
2639 }
2640 if (interval <= 0)
2641 interval = 1;
2642
2643 int v = slider->minimum;
2644 int len = proxy()->pixelMetric(metric: PM_SliderLength, option: slider, widget);
2645 QVector<QLine> lines;
2646 while (v <= slider->maximum + 1) {
2647 if (v == slider->maximum + 1 && interval == 1)
2648 break;
2649 const int v_ = qMin(a: v, b: slider->maximum);
2650 int pos = sliderPositionFromValue(min: slider->minimum, max: slider->maximum,
2651 val: v_, space: (horizontal
2652 ? slider->rect.width()
2653 : slider->rect.height()) - len,
2654 upsideDown: slider->upsideDown) + len / 2;
2655 int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0);
2656
2657 if (horizontal) {
2658 if (ticksAbove) {
2659 lines += QLine(pos, slider->rect.top() + extra,
2660 pos, slider->rect.top() + tickSize);
2661 }
2662 if (ticksBelow) {
2663 lines += QLine(pos, slider->rect.bottom() - extra,
2664 pos, slider->rect.bottom() - tickSize);
2665 }
2666 } else {
2667 if (ticksAbove) {
2668 lines += QLine(slider->rect.left() + extra, pos,
2669 slider->rect.left() + tickSize, pos);
2670 }
2671 if (ticksBelow) {
2672 lines += QLine(slider->rect.right() - extra, pos,
2673 slider->rect.right() - tickSize, pos);
2674 }
2675 }
2676 // in the case where maximum is max int
2677 int nextInterval = v + interval;
2678 if (nextInterval < v)
2679 break;
2680 v = nextInterval;
2681 }
2682 painter->drawLines(lines);
2683 painter->restore();
2684 }
2685 // draw handle
2686 if ((option->subControls & SC_SliderHandle) ) {
2687 QCachedPainter cp(painter, "slider_handle"_L1, option, handle.size(), handle);
2688 if (cp.needsPainting()) {
2689 const QRect pixmapRect = cp.pixmapRect();
2690 QRect gradRect = pixmapRect.adjusted(xp1: 2, yp1: 2, xp2: -2, yp2: -2);
2691
2692 // gradient fill
2693 QRect r = pixmapRect.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2);
2694 QLinearGradient gradient = qt_fusion_gradient(rect: gradRect, baseColor: d->buttonColor(pal: option->palette),direction: horizontal ? TopDown : FromLeft);
2695
2696 cp->translate(dx: 0.5, dy: 0.5);
2697
2698 cp->setPen(Qt::NoPen);
2699 cp->setBrush(QColor(0, 0, 0, 40));
2700 cp->drawRect(r: horizontal ? r.adjusted(xp1: -1, yp1: 2, xp2: 1, yp2: -2) : r.adjusted(xp1: 2, yp1: -1, xp2: -2, yp2: 1));
2701
2702 cp->setPen(outline);
2703 cp->setBrush(gradient);
2704 cp->drawRoundedRect(rect: r, xRadius: 2, yRadius: 2);
2705 cp->setBrush(Qt::NoBrush);
2706 cp->setPen(QFusionStylePrivate::innerContrastLine);
2707 cp->drawRoundedRect(rect: r.adjusted(xp1: 1, yp1: 1, xp2: -1, yp2: -1), xRadius: 2, yRadius: 2);
2708
2709 QColor cornerAlpha = outline.darker(f: 120);
2710 cornerAlpha.setAlpha(80);
2711
2712 //handle shadow
2713 cp->setPen(shadowAlpha);
2714 cp->drawLine(p1: QPoint(r.left() + 2, r.bottom() + 1), p2: QPoint(r.right() - 2, r.bottom() + 1));
2715 cp->drawLine(p1: QPoint(r.right() + 1, r.bottom() - 3), p2: QPoint(r.right() + 1, r.top() + 4));
2716 cp->drawLine(p1: QPoint(r.right() - 1, r.bottom()), p2: QPoint(r.right() + 1, r.bottom() - 2));
2717 }
2718 }
2719 }
2720 break;
2721#endif // QT_CONFIG(slider)
2722#if QT_CONFIG(dial)
2723 case CC_Dial:
2724 if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt: option))
2725 QStyleHelper::drawDial(dial, painter);
2726 break;
2727#endif
2728 default:
2729 QCommonStyle::drawComplexControl(cc: control, opt: option, p: painter, w: widget);
2730 break;
2731 }
2732}
2733
2734/*!
2735 \reimp
2736*/
2737int QFusionStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
2738{
2739 int val = -1;
2740 switch (metric) {
2741 case PM_SliderTickmarkOffset:
2742 val = 4;
2743 break;
2744 case PM_HeaderMargin:
2745 case PM_ToolTipLabelFrameWidth:
2746 val = 2;
2747 break;
2748 case PM_ButtonDefaultIndicator:
2749 case PM_ButtonShiftHorizontal:
2750 case PM_ButtonShiftVertical:
2751 val = 0;
2752 break;
2753 case PM_MessageBoxIconSize:
2754 val = 48;
2755 break;
2756 case PM_ListViewIconSize:
2757 val = 24;
2758 break;
2759 case PM_ScrollBarSliderMin:
2760 val = 26;
2761 break;
2762 case PM_TitleBarHeight:
2763 val = 24;
2764 break;
2765 case PM_ScrollBarExtent:
2766 val = 14;
2767 break;
2768 case PM_SliderThickness:
2769 case PM_SliderLength:
2770 val = 15;
2771 break;
2772 case PM_DockWidgetTitleMargin:
2773 val = 1;
2774 break;
2775 case PM_SpinBoxFrameWidth:
2776 val = 3;
2777 break;
2778 case PM_MenuVMargin:
2779 case PM_MenuHMargin:
2780 case PM_MenuPanelWidth:
2781 val = 0;
2782 break;
2783 case PM_MenuBarItemSpacing:
2784 val = 6;
2785 break;
2786 case PM_MenuBarVMargin:
2787 case PM_MenuBarHMargin:
2788 case PM_MenuBarPanelWidth:
2789 val = 0;
2790 break;
2791 case PM_ToolBarHandleExtent:
2792 val = 9;
2793 break;
2794 case PM_ToolBarItemSpacing:
2795 val = 1;
2796 break;
2797 case PM_ToolBarFrameWidth:
2798 case PM_ToolBarItemMargin:
2799 val = 2;
2800 break;
2801 case PM_SmallIconSize:
2802 case PM_ButtonIconSize:
2803 val = 16;
2804 break;
2805 case PM_DockWidgetTitleBarButtonMargin:
2806 val = 2;
2807 break;
2808 case PM_ButtonMargin:
2809 val = 6;
2810 break;
2811 case PM_TitleBarButtonSize:
2812 val = 19;
2813 break;
2814 case PM_MaximumDragDistance:
2815 return -1; // Do not dpi-scale because the value is magic
2816 case PM_TabCloseIndicatorWidth:
2817 case PM_TabCloseIndicatorHeight:
2818 val = 20;
2819 break;
2820 case PM_TabBarTabVSpace:
2821 val = 12;
2822 break;
2823 case PM_TabBarTabOverlap:
2824 val = 1;
2825 break;
2826 case PM_TabBarBaseOverlap:
2827 val = 2;
2828 break;
2829 case PM_SubMenuOverlap:
2830 val = -1;
2831 break;
2832 case PM_DockWidgetHandleExtent:
2833 case PM_SplitterWidth:
2834 val = 4;
2835 break;
2836 case PM_IndicatorHeight:
2837 case PM_IndicatorWidth:
2838 case PM_ExclusiveIndicatorHeight:
2839 case PM_ExclusiveIndicatorWidth:
2840 val = 14;
2841 break;
2842 case PM_ScrollView_ScrollBarSpacing:
2843 val = 0;
2844 break;
2845 case PM_ScrollView_ScrollBarOverlap:
2846 if (proxy()->styleHint(stylehint: SH_ScrollBar_Transient, opt: option, widget))
2847 return proxy()->pixelMetric(metric: PM_ScrollBarExtent, option, widget);
2848 val = 0;
2849 break;
2850 case PM_DefaultFrameWidth:
2851 return 1; // Do not dpi-scale because the drawn frame is always exactly 1 pixel thick
2852 default:
2853 return QCommonStyle::pixelMetric(m: metric, opt: option, widget);
2854 }
2855 return QStyleHelper::dpiScaled(value: val, option);
2856}
2857
2858/*!
2859 \reimp
2860*/
2861QSize QFusionStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
2862 const QSize &size, const QWidget *widget) const
2863{
2864 QSize newSize = QCommonStyle::sizeFromContents(ct: type, opt: option, contentsSize: size, widget);
2865 switch (type) {
2866 case CT_PushButton:
2867 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt: option)) {
2868 const int horizontalMargin = pixelMetric(metric: PM_ButtonMargin, option: btn);
2869 newSize += QSize(horizontalMargin, 0);
2870 if (!btn->text.isEmpty() && newSize.width() < 80)
2871 newSize.setWidth(80);
2872 if (!btn->icon.isNull() && btn->iconSize.height() > 16)
2873 newSize -= QSize(0, 2);
2874 }
2875 break;
2876 case CT_GroupBox:
2877 if (option) {
2878 int topMargin = qMax(a: pixelMetric(metric: PM_IndicatorHeight, option, widget), b: option->fontMetrics.height()) + groupBoxTopMargin;
2879 newSize += QSize(10, topMargin); // Add some space below the groupbox
2880 }
2881 break;
2882 case CT_RadioButton:
2883 case CT_CheckBox:
2884 newSize += QSize(0, 1);
2885 break;
2886 case CT_ToolButton:
2887 newSize += QSize(2, 2);
2888 break;
2889 case CT_SpinBox:
2890 newSize += QSize(0, -3);
2891 break;
2892 case CT_ComboBox:
2893 newSize += QSize(2, 4);
2894 break;
2895 case CT_LineEdit:
2896 newSize += QSize(0, 4);
2897 break;
2898 case CT_MenuBarItem:
2899 newSize += QSize(8, 5);
2900 break;
2901 case CT_MenuItem:
2902 if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt: option)) {
2903 int w = size.width(); // Don't rely of QCommonStyle's width calculation here
2904 if (menuItem->text.contains(c: u'\t'))
2905 w += menuItem->reservedShortcutWidth;
2906 else if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
2907 w += 2 * QStyleHelper::dpiScaled(value: QFusionStylePrivate::menuArrowHMargin, option);
2908 else if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
2909 const QFontMetricsF fm(menuItem->font);
2910 QFont fontBold = menuItem->font;
2911 fontBold.setBold(true);
2912 const QFontMetricsF fmBold(fontBold);
2913 w += qCeil(v: fmBold.horizontalAdvance(string: menuItem->text) - fm.horizontalAdvance(string: menuItem->text));
2914 }
2915 const qreal dpi = QStyleHelper::dpi(option);
2916 // Windows always shows a check column
2917 const int checkcol = qMax<int>(a: menuItem->maxIconWidth,
2918 b: QStyleHelper::dpiScaled(value: QFusionStylePrivate::menuCheckMarkWidth, dpi));
2919 w += checkcol + windowsItemFrame;
2920 w += QStyleHelper::dpiScaled(value: int(QFusionStylePrivate::menuRightBorder) + 10, dpi);
2921 newSize.setWidth(w);
2922 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
2923 if (!menuItem->text.isEmpty()) {
2924 newSize.setHeight(menuItem->fontMetrics.height());
2925 }
2926 }
2927 else if (!menuItem->icon.isNull()) {
2928#if QT_CONFIG(combobox)
2929 if (const QComboBox *combo = qobject_cast<const QComboBox*>(object: widget)) {
2930 newSize.setHeight(qMax(a: combo->iconSize().height() + 2, b: newSize.height()));
2931 }
2932#endif
2933 }
2934 newSize.setWidth(newSize.width() + int(QStyleHelper::dpiScaled(value: 12, dpi)));
2935 newSize.setWidth(qMax<int>(a: newSize.width(), b: int(QStyleHelper::dpiScaled(value: 120, dpi))));
2936 }
2937 break;
2938 case CT_SizeGrip:
2939 newSize += QSize(4, 4);
2940 break;
2941 case CT_MdiControls:
2942 newSize -= QSize(1, 0);
2943 break;
2944 default:
2945 break;
2946 }
2947 return newSize;
2948}
2949
2950/*!
2951 \reimp
2952*/
2953void QFusionStyle::polish(QApplication *app)
2954{
2955 QCommonStyle::polish(app);
2956}
2957
2958/*!
2959 \reimp
2960*/
2961void QFusionStyle::polish(QWidget *widget)
2962{
2963 QCommonStyle::polish(widget);
2964 if (false
2965#if QT_CONFIG(abstractbutton)
2966 || qobject_cast<QAbstractButton*>(object: widget)
2967#endif
2968#if QT_CONFIG(combobox)
2969 || qobject_cast<QComboBox *>(object: widget)
2970#endif
2971#if QT_CONFIG(progressbar)
2972 || qobject_cast<QProgressBar *>(object: widget)
2973#endif
2974#if QT_CONFIG(scrollbar)
2975 || qobject_cast<QScrollBar *>(object: widget)
2976#endif
2977#if QT_CONFIG(splitter)
2978 || qobject_cast<QSplitterHandle *>(object: widget)
2979#endif
2980#if QT_CONFIG(abstractslider)
2981 || qobject_cast<QAbstractSlider *>(object: widget)
2982#endif
2983#if QT_CONFIG(spinbox)
2984 || qobject_cast<QAbstractSpinBox *>(object: widget)
2985#endif
2986 || (widget->inherits(classname: "QDockSeparator"))
2987 || (widget->inherits(classname: "QDockWidgetSeparator"))
2988 ) {
2989 widget->setAttribute(Qt::WA_Hover, on: true);
2990 widget->setAttribute(Qt::WA_OpaquePaintEvent, on: false);
2991 }
2992}
2993
2994/*!
2995 \reimp
2996*/
2997void QFusionStyle::polish(QPalette &pal)
2998{
2999 QCommonStyle::polish(pal);
3000}
3001
3002/*!
3003 \reimp
3004*/
3005void QFusionStyle::unpolish(QWidget *widget)
3006{
3007 QCommonStyle::unpolish(widget);
3008 if (false
3009#if QT_CONFIG(abstractbutton)
3010 || qobject_cast<QAbstractButton*>(object: widget)
3011#endif
3012#if QT_CONFIG(combobox)
3013 || qobject_cast<QComboBox *>(object: widget)
3014#endif
3015#if QT_CONFIG(progressbar)
3016 || qobject_cast<QProgressBar *>(object: widget)
3017#endif
3018#if QT_CONFIG(scrollbar)
3019 || qobject_cast<QScrollBar *>(object: widget)
3020#endif
3021#if QT_CONFIG(splitter)
3022 || qobject_cast<QSplitterHandle *>(object: widget)
3023#endif
3024#if QT_CONFIG(abstractslider)
3025 || qobject_cast<QAbstractSlider *>(object: widget)
3026#endif
3027#if QT_CONFIG(spinbox)
3028 || qobject_cast<QAbstractSpinBox *>(object: widget)
3029#endif
3030 || (widget->inherits(classname: "QDockSeparator"))
3031 || (widget->inherits(classname: "QDockWidgetSeparator"))
3032 ) {
3033 widget->setAttribute(Qt::WA_Hover, on: false);
3034 }
3035}
3036
3037/*!
3038 \reimp
3039*/
3040void QFusionStyle::unpolish(QApplication *app)
3041{
3042 QCommonStyle::unpolish(application: app);
3043}
3044
3045/*!
3046 \reimp
3047*/
3048QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
3049 SubControl subControl, const QWidget *widget) const
3050{
3051 QRect rect = QCommonStyle::subControlRect(cc: control, opt: option, sc: subControl, w: widget);
3052
3053 switch (control) {
3054#if QT_CONFIG(slider)
3055 case CC_Slider:
3056 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt: option)) {
3057 int tickSize = proxy()->pixelMetric(metric: PM_SliderTickmarkOffset, option, widget);
3058 switch (subControl) {
3059 case SC_SliderHandle: {
3060 const bool bothTicks = (slider->tickPosition & QSlider::TicksBothSides) == QSlider::TicksBothSides;
3061 if (slider->orientation == Qt::Horizontal) {
3062 rect.setHeight(proxy()->pixelMetric(metric: PM_SliderThickness, option, widget));
3063 rect.setWidth(proxy()->pixelMetric(metric: PM_SliderLength, option, widget));
3064 int centerY = slider->rect.center().y() - rect.height() / 2;
3065 if (!bothTicks) {
3066 if (slider->tickPosition & QSlider::TicksAbove)
3067 centerY += tickSize;
3068 if (slider->tickPosition & QSlider::TicksBelow)
3069 centerY -= tickSize - 1;
3070 }
3071 rect.moveTop(pos: centerY);
3072 } else {
3073 rect.setWidth(proxy()->pixelMetric(metric: PM_SliderThickness, option, widget));
3074 rect.setHeight(proxy()->pixelMetric(metric: PM_SliderLength, option, widget));
3075 int centerX = slider->rect.center().x() - rect.width() / 2;
3076 if (!bothTicks) {
3077 if (slider->tickPosition & QSlider::TicksAbove)
3078 centerX += tickSize;
3079 if (slider->tickPosition & QSlider::TicksBelow)
3080 centerX -= tickSize - 1;
3081 }
3082 rect.moveLeft(pos: centerX);
3083 }
3084 }
3085 break;
3086 case SC_SliderGroove: {
3087 QPoint grooveCenter = slider->rect.center();
3088 const int grooveThickness = QStyleHelper::dpiScaled(value: 7, option);
3089 const bool bothTicks = (slider->tickPosition & QSlider::TicksBothSides) == QSlider::TicksBothSides;
3090 if (slider->orientation == Qt::Horizontal) {
3091 rect.setHeight(grooveThickness);
3092 if (!bothTicks) {
3093 if (slider->tickPosition & QSlider::TicksAbove)
3094 grooveCenter.ry() += tickSize;
3095 if (slider->tickPosition & QSlider::TicksBelow)
3096 grooveCenter.ry() -= tickSize - 1;
3097 }
3098 } else {
3099 rect.setWidth(grooveThickness);
3100 if (!bothTicks) {
3101 if (slider->tickPosition & QSlider::TicksAbove)
3102 grooveCenter.rx() += tickSize;
3103 if (slider->tickPosition & QSlider::TicksBelow)
3104 grooveCenter.rx() -= tickSize - 1;
3105 }
3106 }
3107 rect.moveCenter(p: grooveCenter);
3108 break;
3109 }
3110 default:
3111 break;
3112 }
3113 }
3114 break;
3115#endif // QT_CONFIG(slider)
3116#if QT_CONFIG(spinbox)
3117 case CC_SpinBox:
3118 if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt: option)) {
3119 int center = spinbox->rect.height() / 2;
3120 int fw = spinbox->frame ? 3 : 0; // Is drawn with 3 pixels width in drawComplexControl, independently from PM_SpinBoxFrameWidth
3121 int y = fw;
3122 const int buttonWidth = QStyleHelper::dpiScaled(value: 14, option);
3123 int x, lx, rx;
3124 x = spinbox->rect.width() - y - buttonWidth + 2;
3125 lx = fw;
3126 rx = x - fw;
3127 switch (subControl) {
3128 case SC_SpinBoxUp:
3129 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
3130 return QRect();
3131 rect = QRect(x, fw, buttonWidth, center - fw);
3132 break;
3133 case SC_SpinBoxDown:
3134 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
3135 return QRect();
3136
3137 rect = QRect(x, center, buttonWidth, spinbox->rect.bottom() - center - fw + 1);
3138 break;
3139 case SC_SpinBoxEditField:
3140 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) {
3141 rect = QRect(lx, fw, spinbox->rect.width() - 2*fw, spinbox->rect.height() - 2*fw);
3142 } else {
3143 rect = QRect(lx, fw, rx - qMax(a: fw - 1, b: 0), spinbox->rect.height() - 2*fw);
3144 }
3145 break;
3146 case SC_SpinBoxFrame:
3147 rect = spinbox->rect;
3148 break;
3149 default:
3150 break;
3151 }
3152 rect = visualRect(direction: spinbox->direction, boundingRect: spinbox->rect, logicalRect: rect);
3153 }
3154 break;
3155#endif // QT_CONFIG(spinbox)
3156 case CC_GroupBox:
3157 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt: option)) {
3158 const int groupBoxTextAlignment = groupBox->textAlignment;
3159 const bool hasVerticalAlignment = (groupBoxTextAlignment & Qt::AlignVertical_Mask) == Qt::AlignVCenter;
3160 const int fontMetricsHeight = groupBox->text.isEmpty() ? 0 : groupBox->fontMetrics.height();
3161
3162 if (subControl == SC_GroupBoxFrame)
3163 return rect;
3164 else if (subControl == SC_GroupBoxContents) {
3165 QRect frameRect = option->rect.adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: -groupBoxBottomMargin);
3166 int margin = 3;
3167 int leftMarginExtension = 0;
3168 const int indicatorHeight = option->subControls.testFlag(flag: SC_GroupBoxCheckBox) ?
3169 pixelMetric(metric: PM_IndicatorHeight, option, widget) : 0;
3170 const int topMargin = qMax(a: indicatorHeight, b: fontMetricsHeight) +
3171 groupBoxTopMargin;
3172 return frameRect.adjusted(xp1: leftMarginExtension + margin, yp1: margin + topMargin, xp2: -margin, yp2: -margin - groupBoxBottomMargin);
3173 }
3174
3175 QSize textSize = option->fontMetrics.boundingRect(text: groupBox->text).size() + QSize(2, 2);
3176 int indicatorWidth = proxy()->pixelMetric(metric: PM_IndicatorWidth, option, widget);
3177 int indicatorHeight = proxy()->pixelMetric(metric: PM_IndicatorHeight, option, widget);
3178
3179 const int width = textSize.width()
3180 + (option->subControls & QStyle::SC_GroupBoxCheckBox ? indicatorWidth + 5 : 0);
3181
3182 rect = QRect();
3183
3184 if (option->rect.width() > width) {
3185 switch (groupBoxTextAlignment & Qt::AlignHorizontal_Mask) {
3186 case Qt::AlignHCenter:
3187 rect.moveLeft(pos: (option->rect.width() - width) / 2);
3188 break;
3189 case Qt::AlignRight:
3190 rect.moveLeft(pos: option->rect.width() - width
3191 - (hasVerticalAlignment ? proxy()->pixelMetric(metric: PM_LayoutRightMargin, option: groupBox, widget) : 0));
3192 break;
3193 case Qt::AlignLeft:
3194 if (hasVerticalAlignment)
3195 rect.moveLeft(pos: proxy()->pixelMetric(metric: PM_LayoutLeftMargin, option, widget));
3196 break;
3197 }
3198 }
3199
3200 if (subControl == SC_GroupBoxCheckBox) {
3201 rect.setWidth(indicatorWidth);
3202 rect.setHeight(indicatorHeight);
3203 rect.moveTop(pos: textSize.height() > indicatorHeight ? (textSize.height() - indicatorHeight) / 2 : 0);
3204 rect.translate(dx: 1, dy: 0);
3205 } else if (subControl == SC_GroupBoxLabel) {
3206 rect.setSize(textSize);
3207 rect.moveTop(pos: 1);
3208 if (option->subControls & QStyle::SC_GroupBoxCheckBox)
3209 rect.translate(dx: indicatorWidth + 5, dy: 0);
3210 }
3211 return visualRect(direction: option->direction, boundingRect: option->rect, logicalRect: rect);
3212 }
3213
3214 return rect;
3215
3216 case CC_ComboBox:
3217 switch (subControl) {
3218 case SC_ComboBoxArrow: {
3219 const qreal dpi = QStyleHelper::dpi(option);
3220 rect = visualRect(direction: option->direction, boundingRect: option->rect, logicalRect: rect);
3221 rect.setRect(ax: rect.right() - int(QStyleHelper::dpiScaled(value: 18, dpi)), ay: rect.top() - 2,
3222 aw: int(QStyleHelper::dpiScaled(value: 19, dpi)), ah: rect.height() + 4);
3223 rect = visualRect(direction: option->direction, boundingRect: option->rect, logicalRect: rect);
3224 }
3225 break;
3226 case SC_ComboBoxEditField: {
3227 int frameWidth = 2;
3228 rect = visualRect(direction: option->direction, boundingRect: option->rect, logicalRect: rect);
3229 rect.setRect(ax: option->rect.left() + frameWidth, ay: option->rect.top() + frameWidth,
3230 aw: option->rect.width() - int(QStyleHelper::dpiScaled(value: 19, option)) - 2 * frameWidth,
3231 ah: option->rect.height() - 2 * frameWidth);
3232 if (const QStyleOptionComboBox *box = qstyleoption_cast<const QStyleOptionComboBox *>(opt: option)) {
3233 if (!box->editable) {
3234 rect.adjust(dx1: 2, dy1: 0, dx2: 0, dy2: 0);
3235 if (box->state & (State_Sunken | State_On))
3236 rect.translate(dx: 1, dy: 1);
3237 }
3238 }
3239 rect = visualRect(direction: option->direction, boundingRect: option->rect, logicalRect: rect);
3240 break;
3241 }
3242 default:
3243 break;
3244 }
3245 break;
3246 case CC_TitleBar:
3247 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt: option)) {
3248 SubControl sc = subControl;
3249 QRect &ret = rect;
3250 const int indent = 3;
3251 const int controlTopMargin = 3;
3252 const int controlBottomMargin = 3;
3253 const int controlWidthMargin = 2;
3254 const int controlHeight = tb->rect.height() - controlTopMargin - controlBottomMargin ;
3255 const int delta = controlHeight + controlWidthMargin;
3256 int offset = 0;
3257
3258 bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
3259 bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
3260
3261 switch (sc) {
3262 case SC_TitleBarLabel:
3263 if (tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
3264 ret = tb->rect;
3265 if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
3266 ret.adjust(dx1: delta, dy1: 0, dx2: -delta, dy2: 0);
3267 if (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
3268 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
3269 if (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
3270 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
3271 if (tb->titleBarFlags & Qt::WindowShadeButtonHint)
3272 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
3273 if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
3274 ret.adjust(dx1: 0, dy1: 0, dx2: -delta, dy2: 0);
3275 }
3276 break;
3277 case SC_TitleBarContextHelpButton:
3278 if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
3279 offset += delta;
3280 Q_FALLTHROUGH();
3281 case SC_TitleBarMinButton:
3282 if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
3283 offset += delta;
3284 else if (sc == SC_TitleBarMinButton)
3285 break;
3286 Q_FALLTHROUGH();
3287 case SC_TitleBarNormalButton:
3288 if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
3289 offset += delta;
3290 else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
3291 offset += delta;
3292 else if (sc == SC_TitleBarNormalButton)
3293 break;
3294 Q_FALLTHROUGH();
3295 case SC_TitleBarMaxButton:
3296 if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
3297 offset += delta;
3298 else if (sc == SC_TitleBarMaxButton)
3299 break;
3300 Q_FALLTHROUGH();
3301 case SC_TitleBarShadeButton:
3302 if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
3303 offset += delta;
3304 else if (sc == SC_TitleBarShadeButton)
3305 break;
3306 Q_FALLTHROUGH();
3307 case SC_TitleBarUnshadeButton:
3308 if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
3309 offset += delta;
3310 else if (sc == SC_TitleBarUnshadeButton)
3311 break;
3312 Q_FALLTHROUGH();
3313 case SC_TitleBarCloseButton:
3314 if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
3315 offset += delta;
3316 else if (sc == SC_TitleBarCloseButton)
3317 break;
3318 ret.setRect(ax: tb->rect.right() - indent - offset, ay: tb->rect.top() + controlTopMargin,
3319 aw: controlHeight, ah: controlHeight);
3320 break;
3321 case SC_TitleBarSysMenu:
3322 if (tb->titleBarFlags & Qt::WindowSystemMenuHint) {
3323 ret.setRect(ax: tb->rect.left() + controlWidthMargin + indent, ay: tb->rect.top() + controlTopMargin,
3324 aw: controlHeight, ah: controlHeight);
3325 }
3326 break;
3327 default:
3328 break;
3329 }
3330 ret = visualRect(direction: tb->direction, boundingRect: tb->rect, logicalRect: ret);
3331 }
3332 break;
3333 default:
3334 break;
3335 }
3336
3337 return rect;
3338}
3339
3340
3341/*!
3342 \reimp
3343*/
3344QRect QFusionStyle::itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const
3345{
3346 return QCommonStyle::itemPixmapRect(r, flags, pixmap);
3347}
3348
3349/*!
3350 \reimp
3351*/
3352void QFusionStyle::drawItemPixmap(QPainter *painter, const QRect &rect,
3353 int alignment, const QPixmap &pixmap) const
3354{
3355 QCommonStyle::drawItemPixmap(painter, rect, alignment, pixmap);
3356}
3357
3358/*!
3359 \reimp
3360*/
3361QStyle::SubControl QFusionStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
3362 const QPoint &pt, const QWidget *w) const
3363{
3364 return QCommonStyle::hitTestComplexControl(cc, opt, pt, w);
3365}
3366
3367/*!
3368 \reimp
3369*/
3370QPixmap QFusionStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
3371 const QStyleOption *opt) const
3372{
3373 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
3374}
3375
3376/*!
3377 \reimp
3378*/
3379int QFusionStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
3380 QStyleHintReturn *returnData) const
3381{
3382 switch (hint) {
3383 case SH_Slider_SnapToValue:
3384 case SH_PrintDialog_RightAlignButtons:
3385 case SH_FontDialog_SelectAssociatedText:
3386 case SH_MenuBar_AltKeyNavigation:
3387 case SH_ComboBox_ListMouseTracking:
3388 case SH_Slider_StopMouseOverSlider:
3389 case SH_ScrollBar_MiddleClickAbsolutePosition:
3390 case SH_TitleBar_AutoRaise:
3391 case SH_TitleBar_NoBorder:
3392 case SH_ItemView_ShowDecorationSelected:
3393 case SH_ItemView_ArrowKeysNavigateIntoChildren:
3394 case SH_ItemView_ChangeHighlightOnFocus:
3395 case SH_MenuBar_MouseTracking:
3396 case SH_Menu_MouseTracking:
3397 case SH_Menu_SupportsSections:
3398 return 1;
3399
3400#if defined(QT_PLATFORM_UIKIT)
3401 case SH_ComboBox_UseNativePopup:
3402 return 1;
3403#endif
3404
3405 case SH_EtchDisabledText:
3406 case SH_ToolBox_SelectedPageTitleBold:
3407 case SH_ScrollView_FrameOnlyAroundContents:
3408 case SH_Menu_AllowActiveAndDisabled:
3409 case SH_MainWindow_SpaceBelowMenuBar:
3410 case SH_MessageBox_CenterButtons:
3411 case SH_RubberBand_Mask:
3412 return 0;
3413
3414 case SH_ComboBox_Popup:
3415 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt: option))
3416 return !cmb->editable;
3417 return 0;
3418
3419 case SH_Table_GridLineColor:
3420 return option ? option->palette.window().color().darker(f: 120).rgba() : 0;
3421
3422 case SH_MessageBox_TextInteractionFlags:
3423 return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse;
3424#if QT_CONFIG(wizard)
3425 case SH_WizardStyle:
3426 return QWizard::ClassicStyle;
3427#endif
3428 case SH_Menu_SubMenuPopupDelay:
3429 return 225; // default from GtkMenu
3430
3431 case SH_WindowFrame_Mask:
3432 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hint: returnData)) {
3433 //left rounded corner
3434 mask->region = option->rect;
3435 mask->region -= QRect(option->rect.left(), option->rect.top(), 5, 1);
3436 mask->region -= QRect(option->rect.left(), option->rect.top() + 1, 3, 1);
3437 mask->region -= QRect(option->rect.left(), option->rect.top() + 2, 2, 1);
3438 mask->region -= QRect(option->rect.left(), option->rect.top() + 3, 1, 2);
3439
3440 //right rounded corner
3441 mask->region -= QRect(option->rect.right() - 4, option->rect.top(), 5, 1);
3442 mask->region -= QRect(option->rect.right() - 2, option->rect.top() + 1, 3, 1);
3443 mask->region -= QRect(option->rect.right() - 1, option->rect.top() + 2, 2, 1);
3444 mask->region -= QRect(option->rect.right() , option->rect.top() + 3, 1, 2);
3445 return 1;
3446 }
3447 break;
3448 case SH_GroupBox_TextLabelVerticalAlignment: {
3449 if (const auto *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt: option)) {
3450 if (groupBox) {
3451 const auto vAlign = groupBox->textAlignment & Qt::AlignVertical_Mask;
3452 // default fusion style is AlignTop
3453 return vAlign == 0 ? Qt::AlignTop : vAlign;
3454 }
3455 }
3456 break;
3457 }
3458 default:
3459 break;
3460 }
3461 return QCommonStyle::styleHint(sh: hint, opt: option, w: widget, shret: returnData);
3462}
3463
3464/*! \reimp */
3465QRect QFusionStyle::subElementRect(SubElement sr, const QStyleOption *opt, const QWidget *w) const
3466{
3467 QRect r = QCommonStyle::subElementRect(r: sr, opt, widget: w);
3468 switch (sr) {
3469 case SE_ProgressBarLabel:
3470 case SE_ProgressBarContents:
3471 case SE_ProgressBarGroove:
3472 return opt->rect;
3473 case SE_PushButtonFocusRect:
3474 r.adjust(dx1: 0, dy1: 1, dx2: 0, dy2: -1);
3475 break;
3476 case SE_DockWidgetTitleBarText: {
3477 if (const QStyleOptionDockWidget *titlebar = qstyleoption_cast<const QStyleOptionDockWidget*>(opt)) {
3478 bool verticalTitleBar = titlebar->verticalTitleBar;
3479 if (verticalTitleBar) {
3480 r.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -4);
3481 } else {
3482 if (opt->direction == Qt::LeftToRight)
3483 r.adjust(dx1: 4, dy1: 0, dx2: 0, dy2: 0);
3484 else
3485 r.adjust(dx1: 0, dy1: 0, dx2: -4, dy2: 0);
3486 }
3487 }
3488
3489 break;
3490 }
3491 default:
3492 break;
3493 }
3494 return r;
3495}
3496
3497/*!
3498 \internal
3499*/
3500QIcon QFusionStyle::iconFromTheme(StandardPixmap standardIcon) const
3501{
3502 QIcon icon;
3503#if QT_CONFIG(imageformat_png)
3504 auto addIconFiles = [](QStringView prefix, QIcon &icon)
3505 {
3506 const auto fullPrefix = QStringLiteral(":/qt-project.org/styles/fusionstyle/images/") + prefix;
3507 static constexpr auto dockTitleIconSizes = {10, 16, 20, 32, 48, 64};
3508 for (int size : dockTitleIconSizes)
3509 icon.addFile(fileName: fullPrefix + QString::number(size) + QStringLiteral(".png"),
3510 size: QSize(size, size));
3511 };
3512 switch (standardIcon) {
3513 case SP_TitleBarNormalButton:
3514 addIconFiles(u"fusion_normalizedockup-", icon);
3515 break;
3516 case SP_TitleBarMinButton:
3517 addIconFiles(u"fusion_titlebar-min-", icon);
3518 break;
3519 case SP_TitleBarCloseButton:
3520 case SP_DockWidgetCloseButton:
3521 addIconFiles(u"fusion_closedock-", icon);
3522 break;
3523 default:
3524 break;
3525 }
3526#else // imageformat_png
3527 Q_UNUSED(standardIcon);
3528#endif // imageformat_png
3529 return icon;
3530}
3531
3532/*!
3533 \reimp
3534*/
3535QIcon QFusionStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option,
3536 const QWidget *widget) const
3537{
3538 const auto icon = iconFromTheme(standardIcon);
3539 if (!icon.availableSizes().isEmpty())
3540 return icon;
3541 return QCommonStyle::standardIcon(standardIcon, opt: option, widget);
3542}
3543
3544/*!
3545 \reimp
3546 */
3547QPixmap QFusionStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
3548 const QWidget *widget) const
3549{
3550 const auto icon = iconFromTheme(standardIcon: standardPixmap);
3551 if (!icon.availableSizes().isEmpty())
3552 return icon.pixmap(size: QSize(16, 16), devicePixelRatio: QStyleHelper::getDpr(widget));
3553 return QCommonStyle::standardPixmap(sp: standardPixmap, opt, widget);
3554}
3555
3556bool QFusionStyle::isHighContrast() const
3557{
3558 return QGuiApplicationPrivate::platformTheme()->contrastPreference()
3559 == Qt::ContrastPreference::HighContrast;
3560}
3561
3562Qt::ColorScheme QFusionStyle::colorScheme() const
3563{
3564 return QGuiApplicationPrivate::platformTheme()->colorScheme();
3565}
3566
3567QT_END_NAMESPACE
3568
3569#include "moc_qfusionstyle_p.cpp"
3570
3571#endif // style_fusion|| QT_PLUGIN
3572

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