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