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