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