/*
 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include "darkfusionstyle.h"

#include <QPainter>
#include <QStyleOption>
#include <QGroupBox>
#include <qdrawutil.h>
#include <QPainterPath>
#include <QCoreApplication>
#include <QPixmapCache>
#include <QApplication>
#include <QSvgRenderer>
#include "../settings.h"

#define BEGIN_STYLE_PIXMAPCACHE(a) \
    QRect rect = option->rect; \
    QPixmap internalPixmapCache; \
    QImage imageCache; \
    QPainter *p = painter; \
    QString unique = QStyleHelper::uniqueName((a), option, option->rect.size()); \
    int txType = painter->deviceTransform().type() | painter->worldTransform().type(); \
    bool doPixmapCache = (!option->rect.isEmpty()) \
            && ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); \
    if (doPixmapCache && QPixmapCache::find(unique, &internalPixmapCache)) { \
        painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
    } else { \
        if (doPixmapCache) { \
            rect.setRect(0, 0, option->rect.width(), option->rect.height()); \
            imageCache = styleCacheImage(option->rect.size()); \
            imageCache.fill(0); \
            p = new QPainter(&imageCache); \
        }



#define END_STYLE_PIXMAPCACHE \
        if (doPixmapCache) { \
            p->end(); \
            delete p; \
            internalPixmapCache = QPixmap::fromImage(imageCache); \
            painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
            QPixmapCache::insert(unique, internalPixmapCache); \
        } \
    }


namespace QStyleHelper {


static QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size)
{
    const QStyleOptionComplex *complexOption = qstyleoption_cast<const QStyleOptionComplex *>(option);
    QString tmp = QString("%1%2%3%4%5%6%7")
            .arg(key)
            .arg(option->state)
            .arg(option->direction)
            .arg(complexOption ? uint(complexOption->activeSubControls) : 0u)
            .arg(option->palette.cacheKey())
            .arg(size.width())
            .arg(size.height());

#if QT_CONFIG(spinbox)
    if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
        tmp = tmp + QString("%1%2%3")
                .arg(spinBox->buttonSymbols)
                .arg(spinBox->stepEnabled)
                .arg(QLatin1Char(spinBox->frame ? '1' : '0'));
    }
#endif // QT_CONFIG(spinbox)

    return tmp;
}

static qreal calcDpi() {
    return screenDPI();
}

static qreal calcDpiScaled(qreal value, qreal dpi) {
    return value*96/dpi;
}

}


enum Direction {
    TopDown,
    FromLeft,
    BottomUp,
    FromRight
};

// from windows style
static const int windowsItemFrame        =  2; // menu item frame width
static const int windowsItemHMargin      =  3; // menu item hor text margin
static const int windowsItemVMargin      =  8; // menu item ver text margin
static const int windowsRightBorder      = 15; // right border on windows

static const int groupBoxBottomMargin    =  0;  // space below the groupbox
static const int groupBoxTopMargin       =  3;

DarkFusionStyle::DarkFusionStyle():QProxyStyle("fusion")
{

}
// On mac we want a standard blue color used when the system palette is used
static bool isMacSystemPalette(const QPalette &pal){
    Q_UNUSED(pal);
#if defined(Q_OS_MACX)
    const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette();
    if (themePalette && themePalette->color(QPalette::Normal, QPalette::Highlight) ==
            pal.color(QPalette::Normal, QPalette::Highlight) &&
        themePalette->color(QPalette::Normal, QPalette::HighlightedText) ==
            pal.color(QPalette::Normal, QPalette::HighlightedText))
        return true;
#endif
    return false;
}

// Used for grip handles
static QColor calcDarkShade() {
    return QColor(255, 255, 255, 150);
}
static QColor calcLightShade() {
    return QColor(0, 0, 0, 60);
}

// The default button and handle gradient
static QLinearGradient qt_fusion_gradient(const QRect &rect, const QBrush &baseColor, Direction direction = TopDown)
{
    int x = rect.center().x();
    int y = rect.center().y();
    QLinearGradient gradient;
    switch (direction) {
    case FromLeft:
        gradient = QLinearGradient(rect.left(), y, rect.right(), y);
        break;
    case FromRight:
        gradient = QLinearGradient(rect.right(), y, rect.left(), y);
        break;
    case BottomUp:
        gradient = QLinearGradient(x, rect.bottom(), x, rect.top());
        break;
    case TopDown:
    default:
        gradient = QLinearGradient(x, rect.top(), x, rect.bottom());
        break;
    }
    if (baseColor.gradient())
        gradient.setStops(baseColor.gradient()->stops());
    else {
        QColor gradientStartColor = baseColor.color().lighter(124);
        QColor gradientStopColor = baseColor.color().lighter(102);
        gradient.setColorAt(0, gradientStartColor);
        gradient.setColorAt(1, gradientStopColor);
        //          Uncomment for adding shiny shading
        //            QColor midColor1 = mergedColors(gradientStartColor, gradientStopColor, 55);
        //            QColor midColor2 = mergedColors(gradientStartColor, gradientStopColor, 45);
        //            gradient.setColorAt(0.5, midColor1);
        //            gradient.setColorAt(0.501, midColor2);
    }
    return gradient;
}


static QColor calcHighlight(const QPalette &pal) {
    if (isMacSystemPalette(pal))
        return QColor(60, 140, 230);
    return pal.color(QPalette::Highlight);
}

static QColor calcOutline(const QPalette &pal) {
    if (pal.window().style() == Qt::TexturePattern)
        return QColor(255, 255, 255, 160);
    return pal.window().color().lighter(180);
}

static QColor calcHighlightedOutline(const QPalette &pal) {
    QColor highlightedOutline = calcHighlight(pal).lighter(125);
    if (highlightedOutline.value() > 160)
        highlightedOutline.setHsl(highlightedOutline.hue(), highlightedOutline.saturation(), 160);
    return highlightedOutline;
}

static QColor calcButtonColor(const QPalette &pal) {
    QColor buttonColor = pal.button().color();
    int val = qGray(buttonColor.rgb());
    buttonColor = buttonColor.darker(100 + qMax(1, (180 - val)/6));
    buttonColor.setHsv(buttonColor.hue(), buttonColor.saturation() * 0.75, buttonColor.value());
    return buttonColor;
}

static QColor calcTabFrameColor(const QPalette &pal) {
    if (pal.window().style() == Qt::TexturePattern)
        return QColor(255, 255, 255, 8);
    return calcButtonColor(pal).lighter(104);
}

static QColor calcTopShadow() {
    return QColor(255, 255, 255, 18);
}

static QColor calcInnerContrastLine() {
    return QColor(0, 0, 0, 30);
}

static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50)
{
    const int maxFactor = 100;
    QColor tmp = colorA;
    tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
    tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
    tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
    return tmp;
}

static QImage styleCacheImage(const QSize &size)
{
    const qreal pixelRatio = qApp->devicePixelRatio();
    QImage cacheImage = QImage(size * pixelRatio, QImage::Format_ARGB32_Premultiplied);
    cacheImage.setDevicePixelRatio(pixelRatio);
    return cacheImage;
}



void DarkFusionStyle::drawPrimitive(PrimitiveElement elem, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
    Q_ASSERT(option);

    QRect rect = option->rect;
    int state = option->state;

    QColor outline = calcOutline(option->palette);
    QColor highlightedOutline = calcHighlightedOutline(option->palette);

    QColor tabFrameColor = calcTabFrameColor(option->palette);

    switch (elem) {

//#if QT_CONFIG(groupbox)
//    // No frame drawn
//    case PE_FrameGroupBox:
//    {
//        QPixmap pixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_groupbox.png"));
//        int topMargin = 0;
//        auto control = qobject_cast<const QGroupBox *>(widget);
//        if (control && !control->isCheckable() && control->title().isEmpty()) {
//            // Shrinking the topMargin if Not checkable AND title is empty
//            topMargin = groupBoxTopMargin;
//        } else {
//            topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), option->fontMetrics.height()) + groupBoxTopMargin;
//        }
//        QRect frame = option->rect.adjusted(0, topMargin, 0, 0);
//        qDrawBorderPixmap(painter, frame, QMargins(6, 6, 6, 6), pixmap);
//        break;
//    }
//#endif // QT_CONFIG(groupbox)
//    case PE_IndicatorBranch: {
//        if (!(option->state & State_Children))
//            break;
//        if (option->state & State_Open)
//            drawPrimitive(PE_IndicatorArrowDown, option, painter, widget);
//        else {
//            const bool reverse = (option->direction == Qt::RightToLeft);
//            drawPrimitive(reverse ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight, option, painter, widget);
//        }
//        break;
//    }
#if QT_CONFIG(tabbar)
    case PE_FrameTabBarBase:
        if (const QStyleOptionTabBarBase *tbb
                = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
            painter->save();
            painter->setPen(QPen(outline.darker(110)));
            switch (tbb->shape) {
            case QTabBar::RoundedNorth: {
                QRegion region(tbb->rect);
                region -= tbb->selectedTabRect;
                painter->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
                painter->setClipRegion(region);
                painter->setPen(option->palette.light().color());
                painter->drawLine(tbb->rect.topLeft() + QPoint(0, 1), tbb->rect.topRight() + QPoint(0, 1));
            }
                break;
            case QTabBar::RoundedWest:
                painter->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom());
                break;
            case QTabBar::RoundedSouth:
                painter->drawLine(tbb->rect.left(), tbb->rect.bottom(),
                                  tbb->rect.right(), tbb->rect.bottom());
                break;
            case QTabBar::RoundedEast:
                painter->drawLine(tbb->rect.topRight(), tbb->rect.bottomRight());
                break;
            case QTabBar::TriangularNorth:
            case QTabBar::TriangularEast:
            case QTabBar::TriangularWest:
            case QTabBar::TriangularSouth:
                painter->restore();
                QCommonStyle::drawPrimitive(elem, option, painter, widget);
                return;
            }
            painter->restore();
        }
        return;
#endif // QT_CONFIG(tabbar)
    case PE_PanelScrollAreaCorner: {
        painter->save();
        QColor alphaOutline = outline;
        alphaOutline.setAlpha(180);
        painter->setPen(alphaOutline);
        painter->setBrush(option->palette.brush(QPalette::Window));
        painter->drawRect(option->rect);
        painter->restore();
    } break;
//    case PE_IndicatorArrowUp:
//    case PE_IndicatorArrowDown:
//    case PE_IndicatorArrowRight:
//    case PE_IndicatorArrowLeft:
//    {
//        if (option->rect.width() <= 1 || option->rect.height() <= 1)
//            break;
//        QColor arrowColor = option->palette.windowText().color();
//        arrowColor.setAlpha(160);
//        Qt::ArrowType arrow = Qt::UpArrow;
//        switch (elem) {
//        case PE_IndicatorArrowDown:
//            arrow = Qt::DownArrow;
//            break;
//        case PE_IndicatorArrowRight:
//            arrow = Qt::RightArrow;
//            break;
//        case PE_IndicatorArrowLeft:
//            arrow = Qt::LeftArrow;
//            break;
//        default:
//            break;
//        }
//        qt_fusion_draw_arrow(arrow, painter, option, option->rect, arrowColor);
//    }
//        break;
//    case PE_IndicatorItemViewItemCheck:
//    {
//        QStyleOptionButton button;
//        button.QStyleOption::operator=(*option);
//        button.state &= ~State_MouseOver;
//        proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget);
//    }
//        return;
//    case PE_IndicatorHeaderArrow:
//        if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
//            QRect r = header->rect;
//            QColor arrowColor = header->palette.windowText().color();
//            arrowColor.setAlpha(180);
//            QPoint offset = QPoint(0, -2);

//#if defined(Q_OS_LINUX)
//            if (header->sortIndicator & QStyleOptionHeader::SortUp) {
//                qt_fusion_draw_arrow(Qt::UpArrow, painter, option, r.translated(offset), arrowColor);
//            } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
//                qt_fusion_draw_arrow(Qt::DownArrow, painter, option, r.translated(offset), arrowColor);
//            }
//#else
//            if (header->sortIndicator & QStyleOptionHeader::SortUp) {
//                qt_fusion_draw_arrow(Qt::DownArrow, painter, option, r.translated(offset), arrowColor);
//            } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
//                qt_fusion_draw_arrow(Qt::UpArrow, painter, option, r.translated(offset), arrowColor);
//            }
//#endif
//        }
//        break;
//    case PE_IndicatorButtonDropDown:
//        proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
//        break;

    case PE_IndicatorToolBarSeparator:
    {
        QRect rect = option->rect;
        const int margin = 6;
        if (option->state & State_Horizontal) {
            const int offset = rect.width()/2;
            painter->setPen(QPen(option->palette.window().color().lighter(110)));
            painter->drawLine(rect.bottomLeft().x() + offset,
                              rect.bottomLeft().y() - margin,
                              rect.topLeft().x() + offset,
                              rect.topLeft().y() + margin);
            painter->setPen(QPen(option->palette.window().color().darker(110)));
            painter->drawLine(rect.bottomLeft().x() + offset + 1,
                              rect.bottomLeft().y() - margin,
                              rect.topLeft().x() + offset + 1,
                              rect.topLeft().y() + margin);
        } else { //Draw vertical separator
            const int offset = rect.height()/2;
            painter->setPen(QPen(option->palette.window().color().lighter(110)));
            painter->drawLine(rect.topLeft().x() + margin ,
                              rect.topLeft().y() + offset,
                              rect.topRight().x() - margin,
                              rect.topRight().y() + offset);
            painter->setPen(QPen(option->palette.window().color().darker(110)));
            painter->drawLine(rect.topLeft().x() + margin ,
                              rect.topLeft().y() + offset + 1,
                              rect.topRight().x() - margin,
                              rect.topRight().y() + offset + 1);
        }
    }
        break;
    case PE_Frame: {
        if (widget && widget->inherits("QComboBoxPrivateContainer")){
            QStyleOption copy = *option;
            copy.state |= State_Raised;
            proxy()->drawPrimitive(PE_PanelMenu, &copy, painter, widget);
            break;
        }
        painter->save();
        QPen thePen(outline.darker(108));
        thePen.setCosmetic(false);
        painter->setPen(thePen);
        painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
        painter->restore(); }
        break;
    case PE_FrameMenu:
        painter->save();
    {
        painter->setPen(QPen(outline));
        painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
        QColor frameLight = option->palette.window().color().darker(160);
        QColor frameShadow = option->palette.window().color().lighter(110);

        //paint beveleffect
        QRect frame = option->rect.adjusted(1, 1, -1, -1);
        painter->setPen(frameLight);
        painter->drawLine(frame.topLeft(), frame.bottomLeft());
        painter->drawLine(frame.topLeft(), frame.topRight());

        painter->setPen(frameShadow);
        painter->drawLine(frame.topRight(), frame.bottomRight());
        painter->drawLine(frame.bottomLeft(), frame.bottomRight());
    }
        painter->restore();
        break;
    case PE_FrameDockWidget:

        painter->save();
    {
        QColor softshadow = option->palette.window().color().lighter(120);

        QRect rect= option->rect;
        painter->setPen(softshadow);
        painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
        painter->setPen(QPen(option->palette.light(), 1));
        painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), QPoint(rect.left() + 1, rect.bottom() - 1));
        painter->setPen(QPen(option->palette.window().color().lighter(120)));
        painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1), QPoint(rect.right() - 2, rect.bottom() - 1));
        painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1), QPoint(rect.right() - 1, rect.bottom() - 1));

    }
        painter->restore();
        break;
//    case PE_PanelButtonTool:
//        painter->save();
//        if ((option->state & State_Enabled || option->state & State_On) || !(option->state & State_AutoRaise)) {
//            if (widget && widget->inherits("QDockWidgetTitleButton")) {
//                if (option->state & State_MouseOver)
//                    proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
//            } else {
//                proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
//            }
//        }
//        painter->restore();
//        break;
//    case PE_IndicatorDockWidgetResizeHandle:
//    {
//        QStyleOption dockWidgetHandle = *option;
//        bool horizontal = option->state & State_Horizontal;
//        dockWidgetHandle.state.setFlag(State_Horizontal, !horizontal);
//        proxy()->drawControl(CE_Splitter, &dockWidgetHandle, painter, widget);
//    }
//        break;
    case PE_FrameWindow:
        painter->save();
    {
        QRect rect= option->rect;
        painter->setPen(QPen(outline.lighter(150)));
        painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
        painter->setPen(QPen(option->palette.light(), 1));
        painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1),
                          QPoint(rect.left() + 1, rect.bottom() - 1));
        painter->setPen(QPen(option->palette.window().color().darker(120)));
        painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1),
                          QPoint(rect.right() - 2, rect.bottom() - 1));
        painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1),
                          QPoint(rect.right() - 1, rect.bottom() - 1));
    }
        painter->restore();
        break;
    case PE_FrameLineEdit:
    {
        QRect r = rect;
        bool hasFocus = option->state & State_HasFocus;

        painter->save();

        painter->setRenderHint(QPainter::Antialiasing, true);
        //  ### highdpi painter bug.
        painter->translate(0.5, 0.5);

        // Draw Outline
        painter->setPen( QPen(hasFocus ? highlightedOutline : outline));
        painter->drawRoundedRect(r.adjusted(0, 0, -1, -1), 2, 2);

        if (hasFocus) {
            QColor softHighlight = highlightedOutline;
            softHighlight.setAlpha(40);
            painter->setPen(softHighlight);
            painter->drawRoundedRect(r.adjusted(1, 1, -2, -2), 1.7, 1.7);
        }
        // Draw inner shadow
        painter->setPen(calcTopShadow());
        painter->drawLine(QPoint(r.left() + 2, r.top() + 1), QPoint(r.right() - 2, r.top() + 1));

        painter->restore();

    }
        break;
    case PE_IndicatorCheckBox:
        painter->save();
        if (const QStyleOptionButton *checkbox = qstyleoption_cast<const QStyleOptionButton*>(option)) {
            painter->setRenderHint(QPainter::Antialiasing, true);
            painter->translate(0.5, 0.5);
            rect = rect.adjusted(0, 0, -1, -1);

            QColor pressedColor = mergedColors(option->palette.base().color(), option->palette.windowText().color(), 85);
            painter->setBrush(Qt::NoBrush);

            // Gradient fill
            QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
            gradient.setColorAt(0, (state & State_Sunken) ? pressedColor : option->palette.base().color().lighter(115));
            gradient.setColorAt(0.15, (state & State_Sunken) ? pressedColor : option->palette.base().color());
            gradient.setColorAt(1, (state & State_Sunken) ? pressedColor : option->palette.base().color());

            painter->setBrush((state & State_Sunken) ? QBrush(pressedColor) : gradient);
            painter->setPen(QPen(outline.lighter(110)));

            if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
                painter->setPen(QPen(highlightedOutline));
            painter->drawRect(rect);

            QColor checkMarkColor = option->palette.text().color().lighter(120);
            const qreal checkMarkPadding = 1 + rect.width() * 0.13; // at least one pixel padding

            if (checkbox->state & State_NoChange) {
                gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft());
                checkMarkColor.setAlpha(80);
                gradient.setColorAt(0, checkMarkColor);
                checkMarkColor.setAlpha(140);
                gradient.setColorAt(1, checkMarkColor);
                checkMarkColor.setAlpha(180);
                painter->setPen(QPen(checkMarkColor, 1));
                painter->setBrush(gradient);
                painter->drawRect(rect.adjusted(checkMarkPadding, checkMarkPadding, -checkMarkPadding, -checkMarkPadding));

            } else if (checkbox->state & State_On) {

                const qreal dpi = QStyleHelper::calcDpi();

                qreal penWidth = QStyleHelper::calcDpiScaled(1.5, dpi);
                penWidth = qMax<qreal>(penWidth, 0.13 * rect.height());
                penWidth = qMin<qreal>(penWidth, 0.20 * rect.height());
                QPen checkPen = QPen(checkMarkColor, penWidth);
                checkMarkColor.setAlpha(210);
                painter->translate(QStyleHelper::calcDpiScaled(-0.8, dpi), QStyleHelper::calcDpiScaled(0.5, dpi));
                painter->setPen(checkPen);
                painter->setBrush(Qt::NoBrush);

                // Draw checkmark
                QPainterPath path;
                const qreal rectHeight = rect.height(); // assuming height equals width
                path.moveTo(checkMarkPadding + rectHeight * 0.11, rectHeight * 0.47);
                path.lineTo(rectHeight * 0.5, rectHeight - checkMarkPadding);
                path.lineTo(rectHeight - checkMarkPadding, checkMarkPadding);
                painter->drawPath(path.translated(rect.topLeft()));
            }
        }
        painter->restore();
        break;
    case PE_IndicatorRadioButton:
        painter->save();
    {
        QColor pressedColor = mergedColors(option->palette.base().color(), option->palette.windowText().color(), 85);
        painter->setBrush((state & State_Sunken) ? pressedColor : option->palette.base().color());
        painter->setRenderHint(QPainter::Antialiasing, true);
        QPainterPath circle;
        const QPointF circleCenter = rect.center() + QPoint(1, 1);
        const qreal outlineRadius = (rect.width() + (rect.width() + 1) % 2) / 2.0 - 1;
        circle.addEllipse(circleCenter, outlineRadius, outlineRadius);
        painter->setPen(QPen(option->palette.window().color().lighter(150)));
        if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
            painter->setPen(QPen(highlightedOutline));
        painter->drawPath(circle);

        if (state & (State_On )) {
            circle = QPainterPath();
            const qreal checkmarkRadius = outlineRadius / 2.32;
            circle.addEllipse(circleCenter, checkmarkRadius, checkmarkRadius);
            QColor checkMarkColor = option->palette.text().color().lighter(120);
            checkMarkColor.setAlpha(200);
            painter->setPen(checkMarkColor);
            checkMarkColor.setAlpha(180);
            painter->setBrush(checkMarkColor);
            painter->drawPath(circle);
        }
    }
        painter->restore();
        break;
    case PE_IndicatorToolBarHandle:
    {
        //draw grips
        if (option->state & State_Horizontal) {
            for (int i = -3 ; i < 2 ; i += 3) {
                for (int j = -8 ; j < 10 ; j += 3) {
                    painter->fillRect(rect.center().x() + i, rect.center().y() + j, 2, 2, calcLightShade());
                    painter->fillRect(rect.center().x() + i, rect.center().y() + j, 1, 1, calcDarkShade());
                }
            }
        } else { //vertical toolbar
            for (int i = -6 ; i < 12 ; i += 3) {
                for (int j = -3 ; j < 2 ; j += 3) {
                    painter->fillRect(rect.center().x() + i, rect.center().y() + j, 2, 2, calcLightShade());
                    painter->fillRect(rect.center().x() + i, rect.center().y() + j, 1, 1, calcDarkShade());
                }
            }
        }
        break;
    }
    case PE_FrameDefaultButton:
        break;
    case PE_FrameFocusRect:
        if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(option)) {
            //### check for d->alt_down
            if (!(fropt->state & State_KeyboardFocusChange))
                return;
            QRect rect = option->rect;

            painter->save();
            painter->setRenderHint(QPainter::Antialiasing, true);
            painter->translate(0.5, 0.5);
            QColor fillcolor = highlightedOutline;
            fillcolor.setAlpha(80);
            painter->setPen(fillcolor.lighter(120));
            fillcolor.setAlpha(30);
            QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
            gradient.setColorAt(0, fillcolor.darker(160));
            gradient.setColorAt(1, fillcolor);
            painter->setBrush(gradient);
            painter->drawRoundedRect(option->rect.adjusted(0, 0, -1, -1), 1, 1);
            painter->restore();
        }
        break;
    case PE_PanelButtonCommand:
    {
        bool isDefault = false;
        bool isFlat = false;
        bool isDown = (option->state & State_Sunken) || (option->state & State_On);
        QRect r;

        if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option)) {
            isDefault = (button->features & QStyleOptionButton::DefaultButton) && (button->state & State_Enabled);
            isFlat = (button->features & QStyleOptionButton::Flat);
        }

        if (isFlat && !isDown) {
            if (isDefault) {
                r = option->rect.adjusted(0, 1, 0, -1);
                painter->setPen(QPen(Qt::lightGray));
                const QLine lines[4] = {
                    QLine(QPoint(r.left() + 2, r.top()),
                    QPoint(r.right() - 2, r.top())),
                    QLine(QPoint(r.left(), r.top() + 2),
                    QPoint(r.left(), r.bottom() - 2)),
                    QLine(QPoint(r.right(), r.top() + 2),
                    QPoint(r.right(), r.bottom() - 2)),
                    QLine(QPoint(r.left() + 2, r.bottom()),
                    QPoint(r.right() - 2, r.bottom()))
                };
                painter->drawLines(lines, 4);
                const QPoint points[4] = {
                    QPoint(r.right() - 1, r.bottom() - 1),
                    QPoint(r.right() - 1, r.top() + 1),
                    QPoint(r.left() + 1, r.bottom() - 1),
                    QPoint(r.left() + 1, r.top() + 1)
                };
                painter->drawPoints(points, 4);
            }
            return;
        }


        bool isEnabled = option->state & State_Enabled;
        bool hasFocus = (option->state & State_HasFocus && option->state & State_KeyboardFocusChange);
        QColor buttonColor = calcButtonColor(option->palette);

        QColor darkOutline = outline;
        if (hasFocus | isDefault) {
            darkOutline = highlightedOutline;
        }

        if (isDefault)
            buttonColor = mergedColors(buttonColor, highlightedOutline.lighter(130), 90);

        BEGIN_STYLE_PIXMAPCACHE(QStringLiteral("pushbutton-") + buttonColor.name(QColor::HexArgb))
        r = rect.adjusted(0, 1, -1, 0);

        p->setRenderHint(QPainter::Antialiasing, true);
        p->translate(0.5, -0.5);

        QLinearGradient gradient = qt_fusion_gradient(rect, (isEnabled && option->state & State_MouseOver ) ? buttonColor : buttonColor.darker(104));
        p->setPen(Qt::transparent);
        p->setBrush(isDown ? QBrush(buttonColor.lighter(250)) : gradient);
        p->drawRoundedRect(r, 2.0, 2.0);
        p->setBrush(Qt::NoBrush);

        // Outline
        p->setPen(!isEnabled ? QPen(darkOutline.lighter(115)) : QPen(darkOutline));
        p->drawRoundedRect(r, 2.0, 2.0);

        p->setPen(calcInnerContrastLine());
        p->drawRoundedRect(r.adjusted(1, 1, -1, -1), 2.0, 2.0);

        END_STYLE_PIXMAPCACHE
        }
        break;
    case PE_FrameTabWidget:
        painter->save();
        painter->fillRect(option->rect.adjusted(0, 0, -1, -1), tabFrameColor);
#if QT_CONFIG(tabwidget)
        if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
            QColor borderColor = outline.lighter(110);
            QRect rect = option->rect.adjusted(0, 0, -1, -1);

            // Shadow outline
            if (twf->shape != QTabBar::RoundedSouth) {
                rect.adjust(0, 0, 0, -1);
                QColor alphaShadow(Qt::black);
                alphaShadow.setAlpha(15);
                painter->setPen(alphaShadow);
                painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight());            painter->setPen(borderColor);
            }

            // outline
            painter->setPen(outline);
            painter->drawRect(rect);

            // Inner frame highlight
            painter->setPen(calcInnerContrastLine());
            painter->drawRect(rect.adjusted(1, 1, -1, -1));

        }
#endif // QT_CONFIG(tabwidget)
        painter->restore();
        break ;

    case PE_FrameStatusBarItem:
        break;
    case PE_IndicatorTabClose:
    {
        QIcon closeIcon = proxy()->standardIcon(SP_DialogCloseButton, option, widget);
        if ((option->state & State_Enabled) && (option->state & State_MouseOver))
            proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget);
        int size = pointToPixel(pSettings->environment().interfaceFontSize());
        QPixmap pixmap = closeIcon.pixmap(QSize(size, size), QIcon::Normal, QIcon::On);
        proxy()->drawItemPixmap(painter, option->rect, Qt::AlignCenter, pixmap);
    }
        break;
    case PE_PanelMenu: {
        painter->save();
        const QBrush menuBackground = option->palette.base().color().darker(108);
        QColor borderColor = option->palette.window().color().lighter(160);
        qDrawPlainRect(painter, option->rect, borderColor, 1, &menuBackground);
        painter->restore();
    }
        break;
    default:
        QProxyStyle::drawPrimitive(elem, option, painter, widget);
        break;
    }
}

QIcon DarkFusionStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const
{
    switch (standardIcon) {
    case SP_TitleBarCloseButton:
    case SP_DockWidgetCloseButton:
    case SP_DialogCloseButton: {
        int size = pointToPixel(pSettings->environment().interfaceFontSize());
        QSvgRenderer renderer(QString(":/icons/images/dark-close.svg"));
        QPixmap pixmap(size,size);
        pixmap.fill(Qt::transparent);
        QPainter painter(&pixmap);
        renderer.render(&painter,pixmap.rect());
        return QIcon(pixmap);
    }
    default:
        break;
    }

    return QProxyStyle::standardIcon(standardIcon, option, widget);
}

void DarkFusionStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    QProxyStyle::drawComplexControl(control,option,painter,widget);
}

int DarkFusionStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
    switch ( metric ) {
    case QStyle::PM_SmallIconSize:
        return pointToPixel(pSettings->environment().interfaceFontSize());
    case QStyle::PM_TabCloseIndicatorHeight:
    case QStyle::PM_TabCloseIndicatorWidth:
        return 1.2*pointToPixel(pSettings->environment().interfaceFontSize());
    default:
        return QProxyStyle::pixelMetric( metric, option, widget );
    }
}

void DarkFusionStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter,
                               const QWidget *widget) const
{
    QRect rect = option->rect;
    QColor outline = calcOutline(option->palette);
    QColor highlightedOutline = calcHighlightedOutline(option->palette);
    QColor shadow = calcDarkShade();


    switch (element) {
    case CE_MenuItem:
        // Draws one item in a popup menu.
        if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
            //QColor highlightOutline = highlightedOutline;
            //QColor highlight = option->palette.highlight().color();
            if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
                painter->save();
                int w = 0;
                qreal dpi = QStyleHelper::calcDpi();
                const int margin = int(QStyleHelper::calcDpiScaled(5, dpi));
                if (!menuItem->text.isEmpty()) {
                    painter->setFont(menuItem->font);
                    proxy()->drawItemText(painter, menuItem->rect.adjusted(margin, 0, -margin, 0), Qt::AlignLeft | Qt::AlignVCenter,
                                          menuItem->palette, menuItem->state & State_Enabled, menuItem->text,
                                          QPalette::Text);
                    w = menuItem->fontMetrics.horizontalAdvance(menuItem->text) + margin;
                }
                painter->setPen(shadow.darker(150));
                bool reverse = menuItem->direction == Qt::RightToLeft;
                painter->drawLine(menuItem->rect.left() + margin + (reverse ? 0 : w), menuItem->rect.center().y(),
                                  menuItem->rect.right() - margin - (reverse ? w : 0), menuItem->rect.center().y());
                painter->restore();
                break;
            }
        }
        QProxyStyle::drawControl(element, option, painter, widget);
        break;
    case CE_TabBarTabShape:
        painter->save();
        if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {

            bool rtlHorTabs = (tab->direction == Qt::RightToLeft
                               && (tab->shape == QTabBar::RoundedNorth
                                   || tab->shape == QTabBar::RoundedSouth));
            bool selected = tab->state & State_Selected;
            bool lastTab = ((!rtlHorTabs && tab->position == QStyleOptionTab::End)
                            || (rtlHorTabs
                                && tab->position == QStyleOptionTab::Beginning));
            bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
            int tabOverlap = pixelMetric(PM_TabBarTabOverlap, option, widget);
            rect = option->rect.adjusted(0, 0, (onlyOne || lastTab) ? 0 : tabOverlap, 0);

            QRect r2(rect);
            int x1 = r2.left();
            int x2 = r2.right();
            int y1 = r2.top();
            int y2 = r2.bottom();

            painter->setPen(calcInnerContrastLine());

            QTransform rotMatrix;
            bool flip = false;
            painter->setPen(shadow);

            switch (tab->shape) {
            case QTabBar::RoundedNorth:
                break;
            case QTabBar::RoundedSouth:
                rotMatrix.rotate(180);
                rotMatrix.translate(0, -rect.height() + 1);
                rotMatrix.scale(-1, 1);
                painter->setTransform(rotMatrix, true);
                break;
            case QTabBar::RoundedWest:
                rotMatrix.rotate(180 + 90);
                rotMatrix.scale(-1, 1);
                flip = true;
                painter->setTransform(rotMatrix, true);
                break;
            case QTabBar::RoundedEast:
                rotMatrix.rotate(90);
                rotMatrix.translate(0, - rect.width() + 1);
                flip = true;
                painter->setTransform(rotMatrix, true);
                break;
            default:
                painter->restore();
                QCommonStyle::drawControl(element, tab, painter, widget);
                return;
            }

            if (flip) {
                QRect tmp = rect;
                rect = QRect(tmp.y(), tmp.x(), tmp.height(), tmp.width());
                int temp = x1;
                x1 = y1;
                y1 = temp;
                temp = x2;
                x2 = y2;
                y2 = temp;
            }

            painter->setRenderHint(QPainter::Antialiasing, true);
            painter->translate(0.5, 0.5);

            QColor tabFrameColor = tab->features & QStyleOptionTab::HasFrame ?
                        calcTabFrameColor(option->palette) :
                        option->palette.window().color();

            QLinearGradient fillGradient(rect.topLeft(), rect.bottomLeft());
            QLinearGradient outlineGradient(rect.topLeft(), rect.bottomLeft());
            QPen outlinePen = outline.lighter(110);
            if (selected) {
                fillGradient.setColorAt(0, tabFrameColor.lighter(250));
                //                QColor highlight = option->palette.highlight().color();
                //                if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) {
                //                    fillGradient.setColorAt(0, highlight.lighter(130));
                //                    outlineGradient.setColorAt(0, highlight.darker(130));
                //                    fillGradient.setColorAt(0.14, highlight);
                //                    outlineGradient.setColorAt(0.14, highlight.darker(130));
                //                    fillGradient.setColorAt(0.1401, tabFrameColor);
                //                    outlineGradient.setColorAt(0.1401, highlight.darker(130));
                //                }
                fillGradient.setColorAt(0.85, tabFrameColor.lighter(150));
                fillGradient.setColorAt(1, tabFrameColor);
                outlineGradient.setColorAt(1, outline);
                outlinePen = QPen(outlineGradient, 1);
            } else {
                fillGradient.setColorAt(0, tabFrameColor.darker(108));
                fillGradient.setColorAt(0.85, tabFrameColor.darker(108));
                fillGradient.setColorAt(1, tabFrameColor.darker(116));
            }

            QRect drawRect = rect.adjusted(0, selected ? 0 : 2, 0, 3);
            painter->setPen(outlinePen);
            painter->save();
            painter->setClipRect(rect.adjusted(-1, -1, 1, selected ? -2 : -3));
            painter->setBrush(fillGradient);
            painter->drawRoundedRect(drawRect.adjusted(0, 0, -1, -1), 2.0, 2.0);
            painter->setBrush(Qt::NoBrush);
            painter->setPen(calcInnerContrastLine());
            painter->drawRoundedRect(drawRect.adjusted(1, 1, -2, -1), 2.0, 2.0);
            painter->restore();

            if (selected) {
                painter->fillRect(rect.left() + 1, rect.bottom() - 1, rect.width() - 2, rect.bottom() - 1, tabFrameColor);
                painter->fillRect(QRect(rect.bottomRight() + QPoint(-2, -1), QSize(1, 1)), calcInnerContrastLine());
                painter->fillRect(QRect(rect.bottomLeft() + QPoint(0, -1), QSize(1, 1)), calcInnerContrastLine());
                painter->fillRect(QRect(rect.bottomRight() + QPoint(-1, -1), QSize(1, 1)), calcInnerContrastLine());
            }
        }
        painter->restore();
        break;
    default:
        QProxyStyle::drawControl(element, option, painter, widget);
        break;
    }
}