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