1/*
2 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#include "darkfusionstyle.h"
18
19#include <QPainter>
20#include <QStyleOption>
21#include <QGroupBox>
22#include <qdrawutil.h>
23#include <QPainterPath>
24#include <QCoreApplication>
25#include <QPixmapCache>
26#include <QApplication>
27#include <QSvgRenderer>
28#include "../settings.h"
29
30#if defined(Q_OS_MACX)
31#include <QtGui/private/qguiapplication_p.h>
32#include <QtGui/qpa/qplatformtheme.h>
33#endif
34
35#define BEGIN_STYLE_PIXMAPCACHE(a) \
36 QRect rect = option->rect; \
37 QPixmap internalPixmapCache; \
38 QImage imageCache; \
39 QPainter *p = painter; \
40 QString unique = QStyleHelper::uniqueName((a), option, option->rect.size()); \
41 int txType = painter->deviceTransform().type() | painter->worldTransform().type(); \
42 bool doPixmapCache = (!option->rect.isEmpty()) \
43 && ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); \
44 if (doPixmapCache && QPixmapCache::find(unique, &internalPixmapCache)) { \
45 painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
46 } else { \
47 if (doPixmapCache) { \
48 rect.setRect(0, 0, option->rect.width(), option->rect.height()); \
49 imageCache = styleCacheImage(option->rect.size()); \
50 imageCache.fill(0); \
51 p = new QPainter(&imageCache); \
52 }
53
54
55
56#define END_STYLE_PIXMAPCACHE \
57 if (doPixmapCache) { \
58 p->end(); \
59 delete p; \
60 internalPixmapCache = QPixmap::fromImage(imageCache); \
61 painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
62 QPixmapCache::insert(unique, internalPixmapCache); \
63 } \
64 }
65
66
67namespace QStyleHelper {
68
69
70static QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size)
71{
72 const QStyleOptionComplex *complexOption = qstyleoption_cast<const QStyleOptionComplex *>(option);
73 QString tmp = QString("%1%2%3%4%5%6%7")
74 .arg(key)
75 .arg(option->state)
76 .arg(option->direction)
77 .arg(complexOption ? uint(complexOption->activeSubControls) : 0u)
78 .arg(option->palette.cacheKey())
79 .arg(size.width())
80 .arg(size.height());
81
82#if QT_CONFIG(spinbox)
83 if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
84 tmp = tmp + QString("%1%2%3")
85 .arg(spinBox->buttonSymbols)
86 .arg(spinBox->stepEnabled)
87 .arg(QLatin1Char(spinBox->frame ? '1' : '0'));
88 }
89#endif // QT_CONFIG(spinbox)
90
91 return tmp;
92}
93
94static qreal calcDpi() {
95 return screenDPI();
96}
97
98static qreal calcDpiScaled(qreal value, qreal dpi) {
99 return value*96/dpi;
100}
101
102}
103
104
105enum Direction {
106 TopDown,
107 FromLeft,
108 BottomUp,
109 FromRight
110};
111
112// from windows style
113//static const int windowsItemFrame = 2; // menu item frame width
114//static const int windowsItemHMargin = 3; // menu item hor text margin
115//static const int windowsItemVMargin = 8; // menu item ver text margin
116//static const int windowsRightBorder = 15; // right border on windows
117
118//static const int groupBoxBottomMargin = 0; // space below the groupbox
119//static const int groupBoxTopMargin = 3;
120
121DarkFusionStyle::DarkFusionStyle():QProxyStyle("fusion")
122{
123
124}
125// On mac we want a standard blue color used when the system palette is used
126static bool isMacSystemPalette(const QPalette &pal){
127 Q_UNUSED(pal);
128#if defined(Q_OS_MACX)
129 const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette();
130 if (themePalette && themePalette->color(QPalette::Normal, QPalette::Highlight) ==
131 pal.color(QPalette::Normal, QPalette::Highlight) &&
132 themePalette->color(QPalette::Normal, QPalette::HighlightedText) ==
133 pal.color(QPalette::Normal, QPalette::HighlightedText))
134 return true;
135#endif
136 return false;
137}
138
139// Used for grip handles
140static QColor calcDarkShade() {
141 return QColor(255, 255, 255, 150);
142}
143static QColor calcLightShade() {
144 return QColor(0, 0, 0, 60);
145}
146
147// The default button and handle gradient
148static QLinearGradient qt_fusion_gradient(const QRect &rect, const QBrush &baseColor, Direction direction = TopDown)
149{
150 int x = rect.center().x();
151 int y = rect.center().y();
152 QLinearGradient gradient;
153 switch (direction) {
154 case FromLeft:
155 gradient = QLinearGradient(rect.left(), y, rect.right(), y);
156 break;
157 case FromRight:
158 gradient = QLinearGradient(rect.right(), y, rect.left(), y);
159 break;
160 case BottomUp:
161 gradient = QLinearGradient(x, rect.bottom(), x, rect.top());
162 break;
163 case TopDown:
164 default:
165 gradient = QLinearGradient(x, rect.top(), x, rect.bottom());
166 break;
167 }
168 if (baseColor.gradient())
169 gradient.setStops(baseColor.gradient()->stops());
170 else {
171 QColor gradientStartColor = baseColor.color().lighter(124);
172 QColor gradientStopColor = baseColor.color().lighter(102);
173 gradient.setColorAt(0, gradientStartColor);
174 gradient.setColorAt(1, gradientStopColor);
175 // Uncomment for adding shiny shading
176 // QColor midColor1 = mergedColors(gradientStartColor, gradientStopColor, 55);
177 // QColor midColor2 = mergedColors(gradientStartColor, gradientStopColor, 45);
178 // gradient.setColorAt(0.5, midColor1);
179 // gradient.setColorAt(0.501, midColor2);
180 }
181 return gradient;
182}
183
184
185static QColor calcHighlight(const QPalette &pal) {
186 if (isMacSystemPalette(pal))
187 return QColor(60, 140, 230);
188 return pal.color(QPalette::Highlight);
189}
190
191static QColor calcOutline(const QPalette &pal) {
192 if (pal.window().style() == Qt::TexturePattern)
193 return QColor(255, 255, 255, 160);
194 return pal.window().color().lighter(180);
195}
196
197static QColor calcHighlightedOutline(const QPalette &pal) {
198 QColor highlightedOutline = calcHighlight(pal).lighter(125);
199 if (highlightedOutline.value() > 160)
200 highlightedOutline.setHsl(highlightedOutline.hue(), highlightedOutline.saturation(), 160);
201 return highlightedOutline;
202}
203
204static QColor calcButtonColor(const QPalette &pal) {
205 QColor buttonColor = pal.button().color();
206 int val = qGray(buttonColor.rgb());
207 buttonColor = buttonColor.darker(100 + qMax(1, (180 - val)/6));
208 buttonColor.setHsv(buttonColor.hue(), buttonColor.saturation() * 0.75, buttonColor.value());
209 return buttonColor;
210}
211
212static QColor calcTabFrameColor(const QPalette &pal) {
213 if (pal.window().style() == Qt::TexturePattern)
214 return QColor(255, 255, 255, 8);
215 return calcButtonColor(pal).lighter(104);
216}
217
218static QColor calcTopShadow() {
219 return QColor(255, 255, 255, 18);
220}
221
222static QColor calcInnerContrastLine() {
223 return QColor(0, 0, 0, 30);
224}
225
226static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50)
227{
228 const int maxFactor = 100;
229 QColor tmp = colorA;
230 tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
231 tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
232 tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
233 return tmp;
234}
235
236static QImage styleCacheImage(const QSize &size)
237{
238 const qreal pixelRatio = qApp->devicePixelRatio();
239 QImage cacheImage = QImage(size * pixelRatio, QImage::Format_ARGB32_Premultiplied);
240 cacheImage.setDevicePixelRatio(pixelRatio);
241 return cacheImage;
242}
243
244
245
246void DarkFusionStyle::drawPrimitive(PrimitiveElement elem, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
247{
248 Q_ASSERT(option);
249
250 QRect rect = option->rect;
251 int state = option->state;
252
253 QColor outline = calcOutline(option->palette);
254 QColor highlightedOutline = calcHighlightedOutline(option->palette);
255
256 QColor tabFrameColor = calcTabFrameColor(option->palette);
257
258 switch (elem) {
259
260//#if QT_CONFIG(groupbox)
261// // No frame drawn
262// case PE_FrameGroupBox:
263// {
264// QPixmap pixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_groupbox.png"));
265// int topMargin = 0;
266// auto control = qobject_cast<const QGroupBox *>(widget);
267// if (control && !control->isCheckable() && control->title().isEmpty()) {
268// // Shrinking the topMargin if Not checkable AND title is empty
269// topMargin = groupBoxTopMargin;
270// } else {
271// topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), option->fontMetrics.height()) + groupBoxTopMargin;
272// }
273// QRect frame = option->rect.adjusted(0, topMargin, 0, 0);
274// qDrawBorderPixmap(painter, frame, QMargins(6, 6, 6, 6), pixmap);
275// break;
276// }
277//#endif // QT_CONFIG(groupbox)
278// case PE_IndicatorBranch: {
279// if (!(option->state & State_Children))
280// break;
281// if (option->state & State_Open)
282// drawPrimitive(PE_IndicatorArrowDown, option, painter, widget);
283// else {
284// const bool reverse = (option->direction == Qt::RightToLeft);
285// drawPrimitive(reverse ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight, option, painter, widget);
286// }
287// break;
288// }
289#if QT_CONFIG(tabbar)
290 case PE_FrameTabBarBase:
291 if (const QStyleOptionTabBarBase *tbb
292 = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
293 painter->save();
294 painter->setPen(QPen(outline.darker(110)));
295 switch (tbb->shape) {
296 case QTabBar::RoundedNorth: {
297 QRegion region(tbb->rect);
298 region -= tbb->selectedTabRect;
299 painter->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
300 painter->setClipRegion(region);
301 painter->setPen(option->palette.light().color());
302 painter->drawLine(tbb->rect.topLeft() + QPoint(0, 1), tbb->rect.topRight() + QPoint(0, 1));
303 }
304 break;
305 case QTabBar::RoundedWest:
306 painter->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom());
307 break;
308 case QTabBar::RoundedSouth:
309 painter->drawLine(tbb->rect.left(), tbb->rect.bottom(),
310 tbb->rect.right(), tbb->rect.bottom());
311 break;
312 case QTabBar::RoundedEast:
313 painter->drawLine(tbb->rect.topRight(), tbb->rect.bottomRight());
314 break;
315 case QTabBar::TriangularNorth:
316 case QTabBar::TriangularEast:
317 case QTabBar::TriangularWest:
318 case QTabBar::TriangularSouth:
319 painter->restore();
320 QCommonStyle::drawPrimitive(elem, option, painter, widget);
321 return;
322 }
323 painter->restore();
324 }
325 return;
326#endif // QT_CONFIG(tabbar)
327 case PE_PanelScrollAreaCorner: {
328 painter->save();
329 QColor alphaOutline = outline;
330 alphaOutline.setAlpha(180);
331 painter->setPen(alphaOutline);
332 painter->setBrush(option->palette.brush(QPalette::Window));
333 painter->drawRect(option->rect);
334 painter->restore();
335 } break;
336// case PE_IndicatorArrowUp:
337// case PE_IndicatorArrowDown:
338// case PE_IndicatorArrowRight:
339// case PE_IndicatorArrowLeft:
340// {
341// if (option->rect.width() <= 1 || option->rect.height() <= 1)
342// break;
343// QColor arrowColor = option->palette.windowText().color();
344// arrowColor.setAlpha(160);
345// Qt::ArrowType arrow = Qt::UpArrow;
346// switch (elem) {
347// case PE_IndicatorArrowDown:
348// arrow = Qt::DownArrow;
349// break;
350// case PE_IndicatorArrowRight:
351// arrow = Qt::RightArrow;
352// break;
353// case PE_IndicatorArrowLeft:
354// arrow = Qt::LeftArrow;
355// break;
356// default:
357// break;
358// }
359// qt_fusion_draw_arrow(arrow, painter, option, option->rect, arrowColor);
360// }
361// break;
362// case PE_IndicatorItemViewItemCheck:
363// {
364// QStyleOptionButton button;
365// button.QStyleOption::operator=(*option);
366// button.state &= ~State_MouseOver;
367// proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget);
368// }
369// return;
370// case PE_IndicatorHeaderArrow:
371// if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
372// QRect r = header->rect;
373// QColor arrowColor = header->palette.windowText().color();
374// arrowColor.setAlpha(180);
375// QPoint offset = QPoint(0, -2);
376
377//#if defined(Q_OS_LINUX)
378// if (header->sortIndicator & QStyleOptionHeader::SortUp) {
379// qt_fusion_draw_arrow(Qt::UpArrow, painter, option, r.translated(offset), arrowColor);
380// } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
381// qt_fusion_draw_arrow(Qt::DownArrow, painter, option, r.translated(offset), arrowColor);
382// }
383//#else
384// if (header->sortIndicator & QStyleOptionHeader::SortUp) {
385// qt_fusion_draw_arrow(Qt::DownArrow, painter, option, r.translated(offset), arrowColor);
386// } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
387// qt_fusion_draw_arrow(Qt::UpArrow, painter, option, r.translated(offset), arrowColor);
388// }
389//#endif
390// }
391// break;
392// case PE_IndicatorButtonDropDown:
393// proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
394// break;
395
396 case PE_IndicatorToolBarSeparator:
397 {
398 QRect rect = option->rect;
399 const int margin = 6;
400 if (option->state & State_Horizontal) {
401 const int offset = rect.width()/2;
402 painter->setPen(QPen(option->palette.window().color().lighter(110)));
403 painter->drawLine(rect.bottomLeft().x() + offset,
404 rect.bottomLeft().y() - margin,
405 rect.topLeft().x() + offset,
406 rect.topLeft().y() + margin);
407 painter->setPen(QPen(option->palette.window().color().darker(110)));
408 painter->drawLine(rect.bottomLeft().x() + offset + 1,
409 rect.bottomLeft().y() - margin,
410 rect.topLeft().x() + offset + 1,
411 rect.topLeft().y() + margin);
412 } else { //Draw vertical separator
413 const int offset = rect.height()/2;
414 painter->setPen(QPen(option->palette.window().color().lighter(110)));
415 painter->drawLine(rect.topLeft().x() + margin ,
416 rect.topLeft().y() + offset,
417 rect.topRight().x() - margin,
418 rect.topRight().y() + offset);
419 painter->setPen(QPen(option->palette.window().color().darker(110)));
420 painter->drawLine(rect.topLeft().x() + margin ,
421 rect.topLeft().y() + offset + 1,
422 rect.topRight().x() - margin,
423 rect.topRight().y() + offset + 1);
424 }
425 }
426 break;
427 case PE_Frame: {
428 if (widget && widget->inherits("QComboBoxPrivateContainer")){
429 QStyleOption copy = *option;
430 copy.state |= State_Raised;
431 proxy()->drawPrimitive(PE_PanelMenu, &copy, painter, widget);
432 break;
433 }
434 painter->save();
435 QPen thePen(outline.darker(108));
436 thePen.setCosmetic(false);
437 painter->setPen(thePen);
438 painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
439 painter->restore(); }
440 break;
441 case PE_FrameMenu:
442 painter->save();
443 {
444 painter->setPen(QPen(outline));
445 painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
446 QColor frameLight = option->palette.window().color().darker(160);
447 QColor frameShadow = option->palette.window().color().lighter(110);
448
449 //paint beveleffect
450 QRect frame = option->rect.adjusted(1, 1, -1, -1);
451 painter->setPen(frameLight);
452 painter->drawLine(frame.topLeft(), frame.bottomLeft());
453 painter->drawLine(frame.topLeft(), frame.topRight());
454
455 painter->setPen(frameShadow);
456 painter->drawLine(frame.topRight(), frame.bottomRight());
457 painter->drawLine(frame.bottomLeft(), frame.bottomRight());
458 }
459 painter->restore();
460 break;
461 case PE_FrameDockWidget:
462
463 painter->save();
464 {
465 QColor softshadow = option->palette.window().color().lighter(120);
466
467 QRect rect= option->rect;
468 painter->setPen(softshadow);
469 painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
470 painter->setPen(QPen(option->palette.light(), 1));
471 painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), QPoint(rect.left() + 1, rect.bottom() - 1));
472 painter->setPen(QPen(option->palette.window().color().lighter(120)));
473 painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1), QPoint(rect.right() - 2, rect.bottom() - 1));
474 painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1), QPoint(rect.right() - 1, rect.bottom() - 1));
475
476 }
477 painter->restore();
478 break;
479// case PE_PanelButtonTool:
480// painter->save();
481// if ((option->state & State_Enabled || option->state & State_On) || !(option->state & State_AutoRaise)) {
482// if (widget && widget->inherits("QDockWidgetTitleButton")) {
483// if (option->state & State_MouseOver)
484// proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
485// } else {
486// proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
487// }
488// }
489// painter->restore();
490// break;
491// case PE_IndicatorDockWidgetResizeHandle:
492// {
493// QStyleOption dockWidgetHandle = *option;
494// bool horizontal = option->state & State_Horizontal;
495// dockWidgetHandle.state.setFlag(State_Horizontal, !horizontal);
496// proxy()->drawControl(CE_Splitter, &dockWidgetHandle, painter, widget);
497// }
498// break;
499 case PE_FrameWindow:
500 painter->save();
501 {
502 QRect rect= option->rect;
503 painter->setPen(QPen(outline.lighter(150)));
504 painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
505 painter->setPen(QPen(option->palette.light(), 1));
506 painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1),
507 QPoint(rect.left() + 1, rect.bottom() - 1));
508 painter->setPen(QPen(option->palette.window().color().darker(120)));
509 painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1),
510 QPoint(rect.right() - 2, rect.bottom() - 1));
511 painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1),
512 QPoint(rect.right() - 1, rect.bottom() - 1));
513 }
514 painter->restore();
515 break;
516 case PE_FrameLineEdit:
517 {
518 QRect r = rect;
519 bool hasFocus = option->state & State_HasFocus;
520
521 painter->save();
522
523 painter->setRenderHint(QPainter::Antialiasing, true);
524 // ### highdpi painter bug.
525 painter->translate(0.5, 0.5);
526
527 // Draw Outline
528 painter->setPen( QPen(hasFocus ? highlightedOutline : outline));
529 painter->drawRoundedRect(r.adjusted(0, 0, -1, -1), 2, 2);
530
531 if (hasFocus) {
532 QColor softHighlight = highlightedOutline;
533 softHighlight.setAlpha(40);
534 painter->setPen(softHighlight);
535 painter->drawRoundedRect(r.adjusted(1, 1, -2, -2), 1.7, 1.7);
536 }
537 // Draw inner shadow
538 painter->setPen(calcTopShadow());
539 painter->drawLine(QPoint(r.left() + 2, r.top() + 1), QPoint(r.right() - 2, r.top() + 1));
540
541 painter->restore();
542
543 }
544 break;
545 case PE_IndicatorCheckBox:
546 painter->save();
547 if (const QStyleOptionButton *checkbox = qstyleoption_cast<const QStyleOptionButton*>(option)) {
548 painter->setRenderHint(QPainter::Antialiasing, true);
549 painter->translate(0.5, 0.5);
550 rect = rect.adjusted(0, 0, -1, -1);
551
552 QColor pressedColor = mergedColors(option->palette.base().color(), option->palette.windowText().color(), 85);
553 painter->setBrush(Qt::NoBrush);
554
555 // Gradient fill
556 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
557 gradient.setColorAt(0, (state & State_Sunken) ? pressedColor : option->palette.base().color().lighter(115));
558 gradient.setColorAt(0.15, (state & State_Sunken) ? pressedColor : option->palette.base().color());
559 gradient.setColorAt(1, (state & State_Sunken) ? pressedColor : option->palette.base().color());
560
561 painter->setBrush((state & State_Sunken) ? QBrush(pressedColor) : gradient);
562 painter->setPen(QPen(outline.lighter(110)));
563
564 if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
565 painter->setPen(QPen(highlightedOutline));
566 painter->drawRect(rect);
567
568 QColor checkMarkColor = option->palette.text().color().lighter(120);
569 const qreal checkMarkPadding = 1 + rect.width() * 0.13; // at least one pixel padding
570
571 if (checkbox->state & State_NoChange) {
572 gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft());
573 checkMarkColor.setAlpha(80);
574 gradient.setColorAt(0, checkMarkColor);
575 checkMarkColor.setAlpha(140);
576 gradient.setColorAt(1, checkMarkColor);
577 checkMarkColor.setAlpha(180);
578 painter->setPen(QPen(checkMarkColor, 1));
579 painter->setBrush(gradient);
580 painter->drawRect(rect.adjusted(checkMarkPadding, checkMarkPadding, -checkMarkPadding, -checkMarkPadding));
581
582 } else if (checkbox->state & State_On) {
583
584 const qreal dpi = QStyleHelper::calcDpi();
585
586 qreal penWidth = QStyleHelper::calcDpiScaled(1.5, dpi);
587 penWidth = qMax<qreal>(penWidth, 0.13 * rect.height());
588 penWidth = qMin<qreal>(penWidth, 0.20 * rect.height());
589 QPen checkPen = QPen(checkMarkColor, penWidth);
590 checkMarkColor.setAlpha(210);
591 painter->translate(QStyleHelper::calcDpiScaled(-0.8, dpi), QStyleHelper::calcDpiScaled(0.5, dpi));
592 painter->setPen(checkPen);
593 painter->setBrush(Qt::NoBrush);
594
595 // Draw checkmark
596 QPainterPath path;
597 const qreal rectHeight = rect.height(); // assuming height equals width
598 path.moveTo(checkMarkPadding + rectHeight * 0.11, rectHeight * 0.47);
599 path.lineTo(rectHeight * 0.5, rectHeight - checkMarkPadding);
600 path.lineTo(rectHeight - checkMarkPadding, checkMarkPadding);
601 painter->drawPath(path.translated(rect.topLeft()));
602 }
603 }
604 painter->restore();
605 break;
606 case PE_IndicatorRadioButton:
607 painter->save();
608 {
609 QColor pressedColor = mergedColors(option->palette.base().color(), option->palette.windowText().color(), 85);
610 painter->setBrush((state & State_Sunken) ? pressedColor : option->palette.base().color());
611 painter->setRenderHint(QPainter::Antialiasing, true);
612 QPainterPath circle;
613 const QPointF circleCenter = rect.center() + QPoint(1, 1);
614 const qreal outlineRadius = (rect.width() + (rect.width() + 1) % 2) / 2.0 - 1;
615 circle.addEllipse(circleCenter, outlineRadius, outlineRadius);
616 painter->setPen(QPen(option->palette.window().color().lighter(150)));
617 if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
618 painter->setPen(QPen(highlightedOutline));
619 painter->drawPath(circle);
620
621 if (state & (State_On )) {
622 circle = QPainterPath();
623 const qreal checkmarkRadius = outlineRadius / 2.32;
624 circle.addEllipse(circleCenter, checkmarkRadius, checkmarkRadius);
625 QColor checkMarkColor = option->palette.text().color().lighter(120);
626 checkMarkColor.setAlpha(200);
627 painter->setPen(checkMarkColor);
628 checkMarkColor.setAlpha(180);
629 painter->setBrush(checkMarkColor);
630 painter->drawPath(circle);
631 }
632 }
633 painter->restore();
634 break;
635 case PE_IndicatorToolBarHandle:
636 {
637 //draw grips
638 if (option->state & State_Horizontal) {
639 for (int i = -3 ; i < 2 ; i += 3) {
640 for (int j = -8 ; j < 10 ; j += 3) {
641 painter->fillRect(rect.center().x() + i, rect.center().y() + j, 2, 2, calcLightShade());
642 painter->fillRect(rect.center().x() + i, rect.center().y() + j, 1, 1, calcDarkShade());
643 }
644 }
645 } else { //vertical toolbar
646 for (int i = -6 ; i < 12 ; i += 3) {
647 for (int j = -3 ; j < 2 ; j += 3) {
648 painter->fillRect(rect.center().x() + i, rect.center().y() + j, 2, 2, calcLightShade());
649 painter->fillRect(rect.center().x() + i, rect.center().y() + j, 1, 1, calcDarkShade());
650 }
651 }
652 }
653 break;
654 }
655 case PE_FrameDefaultButton:
656 break;
657 case PE_FrameFocusRect:
658 if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(option)) {
659 //### check for d->alt_down
660 if (!(fropt->state & State_KeyboardFocusChange))
661 return;
662 QRect rect = option->rect;
663
664 painter->save();
665 painter->setRenderHint(QPainter::Antialiasing, true);
666 painter->translate(0.5, 0.5);
667 QColor fillcolor = highlightedOutline;
668 fillcolor.setAlpha(80);
669 painter->setPen(fillcolor.lighter(120));
670 fillcolor.setAlpha(30);
671 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
672 gradient.setColorAt(0, fillcolor.darker(160));
673 gradient.setColorAt(1, fillcolor);
674 painter->setBrush(gradient);
675 painter->drawRoundedRect(option->rect.adjusted(0, 0, -1, -1), 1, 1);
676 painter->restore();
677 }
678 break;
679 case PE_PanelButtonCommand:
680 {
681 bool isDefault = false;
682 bool isFlat = false;
683 bool isDown = (option->state & State_Sunken) || (option->state & State_On);
684 QRect r;
685
686 if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option)) {
687 isDefault = (button->features & QStyleOptionButton::DefaultButton) && (button->state & State_Enabled);
688 isFlat = (button->features & QStyleOptionButton::Flat);
689 }
690
691 if (isFlat && !isDown) {
692 if (isDefault) {
693 r = option->rect.adjusted(0, 1, 0, -1);
694 painter->setPen(QPen(Qt::lightGray));
695 const QLine lines[4] = {
696 QLine(QPoint(r.left() + 2, r.top()),
697 QPoint(r.right() - 2, r.top())),
698 QLine(QPoint(r.left(), r.top() + 2),
699 QPoint(r.left(), r.bottom() - 2)),
700 QLine(QPoint(r.right(), r.top() + 2),
701 QPoint(r.right(), r.bottom() - 2)),
702 QLine(QPoint(r.left() + 2, r.bottom()),
703 QPoint(r.right() - 2, r.bottom()))
704 };
705 painter->drawLines(lines, 4);
706 const QPoint points[4] = {
707 QPoint(r.right() - 1, r.bottom() - 1),
708 QPoint(r.right() - 1, r.top() + 1),
709 QPoint(r.left() + 1, r.bottom() - 1),
710 QPoint(r.left() + 1, r.top() + 1)
711 };
712 painter->drawPoints(points, 4);
713 }
714 return;
715 }
716
717
718 bool isEnabled = option->state & State_Enabled;
719 bool hasFocus = (option->state & State_HasFocus && option->state & State_KeyboardFocusChange);
720 QColor buttonColor = calcButtonColor(option->palette);
721
722 QColor darkOutline = outline;
723 if (hasFocus | isDefault) {
724 darkOutline = highlightedOutline;
725 }
726
727 if (isDefault)
728 buttonColor = mergedColors(buttonColor, highlightedOutline.lighter(130), 90);
729
730 BEGIN_STYLE_PIXMAPCACHE(QStringLiteral("pushbutton-") + buttonColor.name(QColor::HexArgb))
731 r = rect.adjusted(0, 1, -1, 0);
732
733 p->setRenderHint(QPainter::Antialiasing, true);
734 p->translate(0.5, -0.5);
735
736 QLinearGradient gradient = qt_fusion_gradient(rect, (isEnabled && option->state & State_MouseOver ) ? buttonColor : buttonColor.darker(104));
737 p->setPen(Qt::transparent);
738 p->setBrush(isDown ? QBrush(buttonColor.lighter(250)) : gradient);
739 p->drawRoundedRect(r, 2.0, 2.0);
740 p->setBrush(Qt::NoBrush);
741
742 // Outline
743 p->setPen(!isEnabled ? QPen(darkOutline.lighter(115)) : QPen(darkOutline));
744 p->drawRoundedRect(r, 2.0, 2.0);
745
746 p->setPen(calcInnerContrastLine());
747 p->drawRoundedRect(r.adjusted(1, 1, -1, -1), 2.0, 2.0);
748
749 END_STYLE_PIXMAPCACHE
750 }
751 break;
752 case PE_FrameTabWidget:
753 painter->save();
754 painter->fillRect(option->rect.adjusted(0, 0, -1, -1), tabFrameColor);
755#if QT_CONFIG(tabwidget)
756 if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
757 QColor borderColor = outline.lighter(110);
758 QRect rect = option->rect.adjusted(0, 0, -1, -1);
759
760 // Shadow outline
761 if (twf->shape != QTabBar::RoundedSouth) {
762 rect.adjust(0, 0, 0, -1);
763 QColor alphaShadow(Qt::black);
764 alphaShadow.setAlpha(15);
765 painter->setPen(alphaShadow);
766 painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); painter->setPen(borderColor);
767 }
768
769 // outline
770 painter->setPen(outline);
771 painter->drawRect(rect);
772
773 // Inner frame highlight
774 painter->setPen(calcInnerContrastLine());
775 painter->drawRect(rect.adjusted(1, 1, -1, -1));
776
777 }
778#endif // QT_CONFIG(tabwidget)
779 painter->restore();
780 break ;
781
782 case PE_FrameStatusBarItem:
783 break;
784 case PE_IndicatorTabClose:
785 {
786 QIcon closeIcon = proxy()->standardIcon(SP_DialogCloseButton, option, widget);
787 if ((option->state & State_Enabled) && (option->state & State_MouseOver))
788 proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
789 int size = pointToPixel(pSettings->environment().interfaceFontSize());
790 QPixmap pixmap = closeIcon.pixmap(QSize(size, size), QIcon::Normal, QIcon::On);
791 proxy()->drawItemPixmap(painter, option->rect, Qt::AlignCenter, pixmap);
792 }
793 break;
794 case PE_PanelMenu: {
795 painter->save();
796 const QBrush menuBackground = option->palette.base().color().darker(108);
797 QColor borderColor = option->palette.window().color().lighter(160);
798 qDrawPlainRect(painter, option->rect, borderColor, 1, &menuBackground);
799 painter->restore();
800 }
801 break;
802 default:
803 QProxyStyle::drawPrimitive(elem, option, painter, widget);
804 break;
805 }
806}
807
808QIcon DarkFusionStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const
809{
810 switch (standardIcon) {
811 case SP_TitleBarCloseButton:
812 case SP_DockWidgetCloseButton:
813 case SP_DialogCloseButton: {
814 int size = pointToPixel(pSettings->environment().interfaceFontSize());
815 QSvgRenderer renderer(QString(":/icons/images/dark-close.svg"));
816 QPixmap pixmap(size,size);
817 pixmap.fill(Qt::transparent);
818 QPainter painter(&pixmap);
819 renderer.render(&painter,pixmap.rect());
820 return QIcon(pixmap);
821 }
822 default:
823 break;
824 }
825
826 return QProxyStyle::standardIcon(standardIcon, option, widget);
827}
828
829void DarkFusionStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
830{
831 QProxyStyle::drawComplexControl(control,option,painter,widget);
832}
833
834int DarkFusionStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
835{
836 switch ( metric ) {
837 case QStyle::PM_SmallIconSize:
838 return pointToPixel(pSettings->environment().interfaceFontSize());
839 case QStyle::PM_TabCloseIndicatorHeight:
840 case QStyle::PM_TabCloseIndicatorWidth:
841 return 1.2*pointToPixel(pSettings->environment().interfaceFontSize());
842 default:
843 return QProxyStyle::pixelMetric( metric, option, widget );
844 }
845}
846
847void DarkFusionStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter,
848 const QWidget *widget) const
849{
850 QRect rect = option->rect;
851 QColor outline = calcOutline(option->palette);
852 //QColor highlightedOutline = calcHighlightedOutline(option->palette);
853 QColor shadow = calcDarkShade();
854
855
856 switch (element) {
857 case CE_MenuItem:
858 // Draws one item in a popup menu.
859 if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
860 //QColor highlightOutline = highlightedOutline;
861 //QColor highlight = option->palette.highlight().color();
862 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
863 painter->save();
864 int w = 0;
865 qreal dpi = QStyleHelper::calcDpi();
866 const int margin = int(QStyleHelper::calcDpiScaled(5, dpi));
867 if (!menuItem->text.isEmpty()) {
868 painter->setFont(menuItem->font);
869 proxy()->drawItemText(painter, menuItem->rect.adjusted(margin, 0, -margin, 0), Qt::AlignLeft | Qt::AlignVCenter,
870 menuItem->palette, menuItem->state & State_Enabled, menuItem->text,
871 QPalette::Text);
872 w = menuItem->fontMetrics.horizontalAdvance(menuItem->text) + margin;
873 }
874 painter->setPen(shadow.darker(150));
875 bool reverse = menuItem->direction == Qt::RightToLeft;
876 painter->drawLine(menuItem->rect.left() + margin + (reverse ? 0 : w), menuItem->rect.center().y(),
877 menuItem->rect.right() - margin - (reverse ? w : 0), menuItem->rect.center().y());
878 painter->restore();
879 break;
880 }
881 }
882 QProxyStyle::drawControl(element, option, painter, widget);
883 break;
884 case CE_TabBarTabShape:
885 painter->save();
886 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
887
888 bool rtlHorTabs = (tab->direction == Qt::RightToLeft
889 && (tab->shape == QTabBar::RoundedNorth
890 || tab->shape == QTabBar::RoundedSouth));
891 bool selected = tab->state & State_Selected;
892 bool lastTab = ((!rtlHorTabs && tab->position == QStyleOptionTab::End)
893 || (rtlHorTabs
894 && tab->position == QStyleOptionTab::Beginning));
895 bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
896 int tabOverlap = pixelMetric(PM_TabBarTabOverlap, option, widget);
897 rect = option->rect.adjusted(0, 0, (onlyOne || lastTab) ? 0 : tabOverlap, 0);
898
899 QRect r2(rect);
900 int x1 = r2.left();
901 int x2 = r2.right();
902 int y1 = r2.top();
903 int y2 = r2.bottom();
904
905 painter->setPen(calcInnerContrastLine());
906
907 QTransform rotMatrix;
908 bool flip = false;
909 painter->setPen(shadow);
910
911 switch (tab->shape) {
912 case QTabBar::RoundedNorth:
913 break;
914 case QTabBar::RoundedSouth:
915 rotMatrix.rotate(180);
916 rotMatrix.translate(0, -rect.height() + 1);
917 rotMatrix.scale(-1, 1);
918 painter->setTransform(rotMatrix, true);
919 break;
920 case QTabBar::RoundedWest:
921 rotMatrix.rotate(180 + 90);
922 rotMatrix.scale(-1, 1);
923 flip = true;
924 painter->setTransform(rotMatrix, true);
925 break;
926 case QTabBar::RoundedEast:
927 rotMatrix.rotate(90);
928 rotMatrix.translate(0, - rect.width() + 1);
929 flip = true;
930 painter->setTransform(rotMatrix, true);
931 break;
932 default:
933 painter->restore();
934 QCommonStyle::drawControl(element, tab, painter, widget);
935 return;
936 }
937
938 if (flip) {
939 QRect tmp = rect;
940 rect = QRect(tmp.y(), tmp.x(), tmp.height(), tmp.width());
941 int temp = x1;
942 x1 = y1;
943 y1 = temp;
944 temp = x2;
945 x2 = y2;
946 y2 = temp;
947 }
948
949 painter->setRenderHint(QPainter::Antialiasing, true);
950 painter->translate(0.5, 0.5);
951
952 QColor tabFrameColor = tab->features & QStyleOptionTab::HasFrame ?
953 calcTabFrameColor(option->palette) :
954 option->palette.window().color();
955
956 QLinearGradient fillGradient(rect.topLeft(), rect.bottomLeft());
957 QLinearGradient outlineGradient(rect.topLeft(), rect.bottomLeft());
958 QPen outlinePen = outline.lighter(110);
959 if (selected) {
960 fillGradient.setColorAt(0, tabFrameColor.lighter(250));
961 // QColor highlight = option->palette.highlight().color();
962 // if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) {
963 // fillGradient.setColorAt(0, highlight.lighter(130));
964 // outlineGradient.setColorAt(0, highlight.darker(130));
965 // fillGradient.setColorAt(0.14, highlight);
966 // outlineGradient.setColorAt(0.14, highlight.darker(130));
967 // fillGradient.setColorAt(0.1401, tabFrameColor);
968 // outlineGradient.setColorAt(0.1401, highlight.darker(130));
969 // }
970 fillGradient.setColorAt(0.85, tabFrameColor.lighter(150));
971 fillGradient.setColorAt(1, tabFrameColor);
972 outlineGradient.setColorAt(1, outline);
973 outlinePen = QPen(outlineGradient, 1);
974 } else {
975 fillGradient.setColorAt(0, tabFrameColor.darker(108));
976 fillGradient.setColorAt(0.85, tabFrameColor.darker(108));
977 fillGradient.setColorAt(1, tabFrameColor.darker(116));
978 }
979
980 QRect drawRect = rect.adjusted(0, selected ? 0 : 2, 0, 3);
981 painter->setPen(outlinePen);
982 painter->save();
983 painter->setClipRect(rect.adjusted(-1, -1, 1, selected ? -2 : -3));
984 painter->setBrush(fillGradient);
985 painter->drawRoundedRect(drawRect.adjusted(0, 0, -1, -1), 2.0, 2.0);
986 painter->setBrush(Qt::NoBrush);
987 painter->setPen(calcInnerContrastLine());
988 painter->drawRoundedRect(drawRect.adjusted(1, 1, -2, -1), 2.0, 2.0);
989 painter->restore();
990
991 if (selected) {
992 painter->fillRect(rect.left() + 1, rect.bottom() - 1, rect.width() - 2, rect.bottom() - 1, tabFrameColor);
993 painter->fillRect(QRect(rect.bottomRight() + QPoint(-2, -1), QSize(1, 1)), calcInnerContrastLine());
994 painter->fillRect(QRect(rect.bottomLeft() + QPoint(0, -1), QSize(1, 1)), calcInnerContrastLine());
995 painter->fillRect(QRect(rect.bottomRight() + QPoint(-1, -1), QSize(1, 1)), calcInnerContrastLine());
996 }
997 }
998 painter->restore();
999 break;
1000 default:
1001 QProxyStyle::drawControl(element, option, painter, widget);
1002 break;
1003 }
1004}
1005