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