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