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