// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default

#include "qwindows11style_p.h"
#include <qstylehints.h>
#include <private/qstyleanimation_p.h>
#include <private/qstyle_p.h>
#include <private/qstylehelper_p.h>
#include <private/qapplication_p.h>
#include <private/qcombobox_p.h>
#include <qstyleoption.h>
#include <qpainter.h>
#include <qpainterstateguard.h>
#include <QGraphicsDropShadowEffect>
#include <QLatin1StringView>
#include <QtCore/qoperatingsystemversion.h>
#include <QtWidgets/qcombobox.h>
#if QT_CONFIG(commandlinkbutton)
#include <QtWidgets/qcommandlinkbutton.h>
#endif
#include <QtWidgets/qgraphicsview.h>
#include <QtWidgets/qlistview.h>
#include <QtWidgets/qmenu.h>
#if QT_CONFIG(mdiarea)
#include <QtWidgets/qmdiarea.h>
#endif
#include <QtWidgets/qplaintextedit.h>
#include <QtWidgets/qtextedit.h>
#include <QtWidgets/qtreeview.h>
#if QT_CONFIG(datetimeedit)
#  include <QtWidgets/qdatetimeedit.h>
#endif
#if QT_CONFIG(tabwidget)
#  include <QtWidgets/qtabwidget.h>
#endif
#if QT_CONFIG(menubar)
#  include <QtWidgets/qmenubar.h>
#endif
#if QT_CONFIG(tooltip)
#include "private/qtooltip_p.h"
#endif
#include "qdrawutil.h"
#include <chrono>
#include <dwmapi.h>

QT_BEGIN_NAMESPACE

using namespace Qt::StringLiterals;

static constexpr int topLevelRoundingRadius    = 8; //Radius for toplevel items like popups for round corners
static constexpr int secondLevelRoundingRadius = 4; //Radius for second level items like hovered menu item round corners
static constexpr int contentItemHMargin = 4;        // margin between content items (e.g. text and icon)
static constexpr int contentHMargin = 2 * 3;        // margin between rounded border and content (= rounded border margin * 3)


namespace StyleOptionHelper
{
inline bool isChecked(const QStyleOption *option)
{
    return option->state.testAnyFlags(QStyle::State_On | QStyle::State_NoChange);
}
inline bool isDisabled(const QStyleOption *option)
{
    return !option->state.testFlag(QStyle::State_Enabled);
}
inline bool isPressed(const QStyleOption *option)
{
    return option->state.testFlag(QStyle::State_Sunken);
}
inline bool isSelected(const QStyleOption *option)
{
    return option->state.testFlag(QStyle::State_Selected);
}
inline bool isHover(const QStyleOption *option)
{
    return option->state.testFlag(QStyle::State_MouseOver);
}
inline bool isAutoRaise(const QStyleOption *option)
{
    return option->state.testFlag(QStyle::State_AutoRaise);
}
inline bool hasFocus(const QStyleOption *option)
{
    return option->state.testFlag(QStyle::State_HasFocus);
}
enum class ControlState { Normal, Hover, Pressed, Disabled };
inline ControlState calcControlState(const QStyleOption *option)
{
    if (isDisabled(option))
        return ControlState::Disabled;
    if (isPressed(option))
        return ControlState::Pressed;
    if (isHover(option))
        return ControlState::Hover;
    return ControlState::Normal;
};

} // namespace StyleOptionHelper

template <typename R, typename P, typename B>
static inline void drawRoundedRect(QPainter *p,
                                   R &&rect,
                                   P &&pen,
                                   B &&brush,
                                   int radius = secondLevelRoundingRadius)
{
    p->setPen(pen);
    p->setBrush(brush);
    p->drawRoundedRect(rect, radius, radius);
}

static constexpr int percentToAlpha(double percent)
{
    return qRound(percent * 255. / 100.);
}

static constexpr std::array<QColor, 37> WINUI3ColorsLight {
    QColor(0x00,0x00,0x00,percentToAlpha(3.73)), // subtleHighlightColor (fillSubtleSecondary)
    QColor(0x00,0x00,0x00,percentToAlpha(2.41)), // subtlePressedColor (fillSubtleTertiary)
    QColor(0x00,0x00,0x00,0x0F), //frameColorLight
    QColor(0x00,0x00,0x00,percentToAlpha(60.63)),   //frameColorStrong
    QColor(0x00,0x00,0x00,percentToAlpha(21.69)),   //frameColorStrongDisabled
    QColor(0x00,0x00,0x00,0x72), //controlStrongFill
    QColor(0x00,0x00,0x00,0x29), //controlStrokeSecondary
    QColor(0x00,0x00,0x00,0x14), //controlStrokePrimary
    QColor(0xFF,0xFF,0xFF,0xFF), //menuPanelFill
    QColor(0x00,0x00,0x00,0x66), //controlStrokeOnAccentSecondary
    QColor(0xFF,0xFF,0xFF,0xFF), //controlFillSolid
    QColor(0x75,0x75,0x75,0x66), //surfaceStroke
    QColor(0xFF,0xFF,0xFF,0xFF), //focusFrameInnerStroke
    QColor(0x00,0x00,0x00,0xFF), //focusFrameOuterStroke
    QColor(0xFF,0xFF,0xFF,percentToAlpha(70)),      // fillControlDefault
    QColor(0xF9,0xF9,0xF9,percentToAlpha(50)),      // fillControlSecondary
    QColor(0xF9,0xF9,0xF9,percentToAlpha(30)),      // fillControlTertiary
    QColor(0xF9,0xF9,0xF9,percentToAlpha(30)),      // fillControlDisabled
    QColor(0xFF,0xFF,0xFF,percentToAlpha(100)),     // fillControlInputActive
    QColor(0x00,0x00,0x00,percentToAlpha(2.41)),    // fillControlAltSecondary
    QColor(0x00,0x00,0x00,percentToAlpha(5.78)),    // fillControlAltTertiary
    QColor(0x00,0x00,0x00,percentToAlpha(9.24)),    // fillControlAltQuarternary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(0.00)),    // fillControlAltDisabled
    QColor(0x00,0x00,0x00,percentToAlpha(100)),     // fillAccentDefault
    QColor(0x00,0x00,0x00,percentToAlpha(90)),      // fillAccentSecondary
    QColor(0x00,0x00,0x00,percentToAlpha(80)),      // fillAccentTertiary
    QColor(0x00,0x00,0x00,percentToAlpha(21.69)),   // fillAccentDisabled
    QColor(0xFF,0xFF,0xFF,percentToAlpha(70)),      // fillMicaAltDefault
    QColor(0xFF,0xFF,0xFF,percentToAlpha(0)),       // fillMicaAltTransparent
    QColor(0x00,0x00,0x00,percentToAlpha(3.73)),    // fillMicaAltSecondary
    QColor(0x00,0x00,0x00,percentToAlpha(89.56)),   // textPrimary
    QColor(0x00,0x00,0x00,percentToAlpha(60.63)),   // textSecondary
    QColor(0x00,0x00,0x00,percentToAlpha(36.14)),   // textDisabled
    QColor(0xFF,0xFF,0xFF,percentToAlpha(100)),     // textOnAccentPrimary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(70)),      // textOnAccentSecondary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(100)),     // textOnAccentDisabled
    QColor(0x00,0x00,0x00,percentToAlpha(8.03)),    // dividerStrokeDefault
};

static constexpr std::array<QColor, 37> WINUI3ColorsDark {
    QColor(0xFF,0xFF,0xFF,percentToAlpha(6.05)), // subtleHighlightColor (fillSubtleSecondary)
    QColor(0xFF,0xFF,0xFF,percentToAlpha(4.19)), // subtlePressedColor (fillSubtleTertiary)
    QColor(0xFF,0xFF,0xFF,0x12), //frameColorLight
    QColor(0xFF,0xFF,0xFF,percentToAlpha(60.47)),   //frameColorStrong
    QColor(0xFF,0xFF,0xFF,percentToAlpha(15.81)),   //frameColorStrongDisabled
    QColor(0xFF,0xFF,0xFF,0x8B), //controlStrongFill
    QColor(0xFF,0xFF,0xFF,0x18), //controlStrokeSecondary
    QColor(0xFF,0xFF,0xFF,0x12), //controlStrokePrimary
    QColor(0x0F,0x0F,0x0F,0xFF), //menuPanelFill
    QColor(0xFF,0xFF,0xFF,0x14), //controlStrokeOnAccentSecondary
    QColor(0x45,0x45,0x45,0xFF), //controlFillSolid
    QColor(0x75,0x75,0x75,0x66), //surfaceStroke
    QColor(0x00,0x00,0x00,0xFF), //focusFrameInnerStroke
    QColor(0xFF,0xFF,0xFF,0xFF), //focusFrameOuterStroke
    QColor(0xFF,0xFF,0xFF,percentToAlpha(6.05)),    // fillControlDefault
    QColor(0xFF,0xFF,0xFF,percentToAlpha(8.37)),    // fillControlSecondary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(3.26)),    // fillControlTertiary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(4.19)),    // fillControlDisabled
    QColor(0x1E,0x1E,0x1E,percentToAlpha(70)),      // fillControlInputActive
    QColor(0x00,0x00,0x00,percentToAlpha(10.0)),    // fillControlAltDefault
    QColor(0xFF,0xFF,0xFF,percentToAlpha(4.19)),    // fillControlAltSecondary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(6.98)),    // fillControlAltTertiafillCy
    QColor(0xFF,0xFF,0xFF,percentToAlpha(0.00)),    // controlAltDisabled
    QColor(0x00,0x00,0x00,percentToAlpha(100)),     // fillAccentDefault
    QColor(0x00,0x00,0x00,percentToAlpha(90)),      // fillAccentSecondary
    QColor(0x00,0x00,0x00,percentToAlpha(80)),      // fillAccentTertiary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(15.81)),   // fillAccentDisabled
    QColor(0x3A,0x3A,0x3A,percentToAlpha(45)),      // fillMicaAltDefault
    QColor(0x00,0x00,0x00,percentToAlpha(0)),       // fillMicaAltTransparent
    QColor(0xFF,0xFF,0xFF,percentToAlpha(6.05)),    // fillMicaAltSecondary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(100)),     // textPrimary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(78.6)),    // textSecondary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(36.28)),   // textDisabled
    QColor(0x00,0x00,0x00,percentToAlpha(100)),     // textOnAccentPrimary
    QColor(0x00,0x00,0x00,percentToAlpha(70)),      // textOnAccentSecondary
    QColor(0xFF,0xFF,0xFF,percentToAlpha(53.02)),   // textOnAccentDisabled
    QColor(0xFF,0xFF,0xFF,percentToAlpha(8.37)),    // dividerStrokeDefault
};

static constexpr std::array<std::array<QColor,37>, 2> WINUI3Colors {
    WINUI3ColorsLight,
    WINUI3ColorsDark
};

// Color of close Button in Titlebar (default + hover)
static constexpr QColor shellCaptionCloseFillColorPrimary(0xC4,0x2B,0x1C,0xFF);
static constexpr QColor shellCaptionCloseTextFillColorPrimary(0xFF,0xFF,0xFF,0xFF);
// Color of close Button in Titlebar (pressed + disabled)
static constexpr QColor shellCaptionCloseFillColorSecondary(0xC4,0x2B,0x1C,0xE6);
static constexpr QColor shellCaptionCloseTextFillColorSecondary(0xFF,0xFF,0xFF,0xB3);


#if QT_CONFIG(toolbutton)
static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
                      const QRect &rect, QPainter *painter, const QWidget *widget = nullptr)
{
    QStyle::PrimitiveElement pe;
    switch (toolbutton->arrowType) {
    case Qt::LeftArrow:
        pe = QStyle::PE_IndicatorArrowLeft;
        break;
    case Qt::RightArrow:
        pe = QStyle::PE_IndicatorArrowRight;
        break;
    case Qt::UpArrow:
        pe = QStyle::PE_IndicatorArrowUp;
        break;
    case Qt::DownArrow:
        pe = QStyle::PE_IndicatorArrowDown;
        break;
    default:
        return;
    }
    QStyleOption arrowOpt = *toolbutton;
    arrowOpt.rect = rect;
    style->drawPrimitive(pe, &arrowOpt, painter, widget);
}
#endif // QT_CONFIG(toolbutton)

static qreal radioButtonInnerRadius(QStyle::State state)
{
    qreal radius = 7.0;
    if (state & QStyle::State_Sunken)
        radius = 4.0f;
    else if (state & QStyle::State_MouseOver && !(state & QStyle::State_On))
        radius = 7.0f;
    else if (state & QStyle::State_MouseOver && (state & QStyle::State_On))
        radius = 5.0f;
    else if (state & QStyle::State_On)
        radius = 4.0f;
    return radius;
}

static qreal sliderInnerRadius(QStyle::State state, bool insideHandle)
{
    const bool isEnabled = state & QStyle::State_Enabled;
    if (isEnabled) {
        if (state & QStyle::State_Sunken)
            return 0.29;
        else if (insideHandle)
            return 0.71;
    }
    return 0.43;
}
/*!
  \class QWindows11Style
  \brief The QWindows11Style class provides a look and feel suitable for applications on Microsoft Windows 11.
  \since 6.6
  \ingroup appearance
  \inmodule QtWidgets
  \internal

  \warning This style is only available on the Windows 11 platform and above.

  \sa QWindows11Style QWindowsVistaStyle, QMacStyle, QFusionStyle
*/
QWindows11StylePrivate::QWindows11StylePrivate()
{
    nativeRoundedTopLevelWindows =
            QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11_21H2;
}

/*!
  Constructs a QWindows11Style object.
*/
QWindows11Style::QWindows11Style() : QWindows11Style(*new QWindows11StylePrivate)
{
}

/*!
  \internal
  Constructs a QWindows11Style object.
*/
QWindows11Style::QWindows11Style(QWindows11StylePrivate &dd) : QWindowsVistaStyle(dd)
{
    Q_D(QWindows11Style);
    const QStringList assetFontFamilies{ "Segoe Fluent Icons"_L1, "Segoe MDL2 Assets"_L1 };
    d->assetFont = QFont(assetFontFamilies);
    d->assetFont.setStyleStrategy(QFont::NoFontMerging);
    highContrastTheme = QGuiApplicationPrivate::styleHints->colorScheme() == Qt::ColorScheme::Unknown;
    colorSchemeIndex = QGuiApplicationPrivate::styleHints->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
}

/*!
  Destructor.
*/
QWindows11Style::~QWindows11Style() = default;

/*!
  \internal
  see drawPrimitive for comments on the animation support

 */
void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
                                         QPainter *painter, const QWidget *widget) const
{
    QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func());

    const auto drawTitleBarButton = [&](ComplexControl control, SubControl sc, Icon ico) {
        using namespace StyleOptionHelper;
        const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
        if (buttonRect.isValid()) {
            const bool hover = option->activeSubControls == sc && isHover(option);
            if (hover)
                painter->fillRect(buttonRect, winUI3Color(subtleHighlightColor));
            painter->setPen(option->palette.color(QPalette::WindowText));
            painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
        }
    };
    const auto drawTitleBarCloseButton = [&](ComplexControl control, SubControl sc, Icon ico) {
        using namespace StyleOptionHelper;
        const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
        if (buttonRect.isValid()) {
            const auto state = (option->activeSubControls == sc) ? calcControlState(option)
                                                                 : ControlState::Normal;
            QPen pen;
            switch (state) {
            case ControlState::Hover:
                painter->fillRect(buttonRect, shellCaptionCloseFillColorPrimary);
                pen = shellCaptionCloseTextFillColorPrimary;
                break;
            case ControlState::Pressed:
                painter->fillRect(buttonRect, shellCaptionCloseFillColorSecondary);
                pen = shellCaptionCloseTextFillColorSecondary;
                break;
            case ControlState::Disabled:
            case ControlState::Normal:
                pen = option->palette.color(QPalette::WindowText);
                break;
            }
            painter->setPen(pen);
            painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
        }
    };


    State state = option->state;
    SubControls sub = option->subControls;
    State flags = option->state;
    if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
        flags |= State_MouseOver;

    QPainterStateGuard psg(painter);
    painter->setRenderHint(QPainter::Antialiasing);
    if (d->transitionsEnabled() && option->styleObject) {
        if (control == CC_Slider) {
            if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
                QObject *styleObject = option->styleObject; // Can be widget or qquickitem

                QRectF thumbRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
                const qreal outerRadius = qMin(8.0, (slider->orientation == Qt::Horizontal ? thumbRect.height() / 2.0 : thumbRect.width() / 2.0) - 1);
                bool isInsideHandle = option->activeSubControls == SC_SliderHandle;

                bool oldIsInsideHandle = styleObject->property("_q_insidehandle").toBool();
                State oldState = State(styleObject->property("_q_stylestate").toInt());
                SubControls oldActiveControls = SubControls(styleObject->property("_q_stylecontrols").toInt());

                QRectF oldRect = styleObject->property("_q_stylerect").toRect();
                styleObject->setProperty("_q_insidehandle", isInsideHandle);
                styleObject->setProperty("_q_stylestate", int(state));
                styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
                styleObject->setProperty("_q_stylerect", option->rect);
                if (option->styleObject->property("_q_end_radius").isNull())
                    option->styleObject->setProperty("_q_end_radius", outerRadius * 0.43);

                bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
                                     || (oldIsInsideHandle != isInsideHandle)
                                     || (oldActiveControls != option->activeSubControls))
                                     && state & State_Enabled);

                if (oldRect != option->rect) {
                    doTransition = false;
                    d->stopAnimation(styleObject);
                    styleObject->setProperty("_q_inner_radius", outerRadius * 0.43);
                }

                if (doTransition) {
                    QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
                    t->setStartValue(styleObject->property("_q_inner_radius").toFloat());
                    t->setEndValue(outerRadius * sliderInnerRadius(state, isInsideHandle));
                    styleObject->setProperty("_q_end_radius", t->endValue());

                    t->setStartTime(d->animationTime());
                    t->setDuration(150);
                    d->startAnimation(t);
                }
            }
        } else if (control == CC_ScrollBar) {
            QObject *styleObject = option->styleObject;
            State oldState = State(styleObject->property("_q_stylestate").toInt());
            const bool wasMouseOver = oldState.testFlag(State_MouseOver);
            const bool isMouseOver = state.testFlag(State_MouseOver);

            if (wasMouseOver != isMouseOver) {
                styleObject->setProperty("_q_stylestate", int(state));
                auto anim = qobject_cast<QNumberStyleAnimation *>(d->animation(styleObject));
                constexpr int durationMS = 100;
                qreal startValue = isMouseOver ? 0 : 1;
                int curDurationMS = durationMS;
                if (anim) {
                    startValue = anim->currentValue();
                    curDurationMS = durationMS - (anim->duration() - anim->currentLoopTime());
                    d->stopAnimation(option->styleObject);
                }
                anim = new QNumberStyleAnimation(styleObject);
                anim->setStartValue(startValue);
                anim->setEndValue(isMouseOver ? 1 : 0);
                anim->setDuration(curDurationMS);
                d->startAnimation(anim);
            }
        }
    }

    switch (control) {
#if QT_CONFIG(spinbox)
    case CC_SpinBox:
        if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
            QCachedPainter cp(painter, QLatin1StringView("win11_spinbox") % HexString<uint8_t>(colorSchemeIndex),
                              sb, sb->rect.size());
            if (cp.needsPainting()) {
                const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
                drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, inputFillBrush(option, widget));

                if (sb->frame && (sub & SC_SpinBoxFrame))
                    drawLineEditFrame(cp.painter(), frameRect, option);

                const auto drawUpDown = [&](QStyle::SubControl sc,
                                            QAbstractSpinBox::StepEnabledFlag flag) {
                    const bool isEnabled =
                            state.testFlag(QStyle::State_Enabled) && sb->stepEnabled.testFlag(flag);
                    const bool isUp = sc == SC_SpinBoxUp;
                    const QRect rect = proxy()->subControlRect(CC_SpinBox, option, sc, widget);
                    if (isEnabled && sb->activeSubControls & sc)
                        drawRoundedRect(cp.painter(), rect.adjusted(1, 1, -1, -2), Qt::NoPen,
                                        winUI3Color(subtleHighlightColor));

                    cp->setFont(d->assetFont);
                    cp->setPen(sb->palette.color(isEnabled ? QPalette::Active : QPalette::Disabled,
                                                 QPalette::ButtonText));
                    cp->setBrush(Qt::NoBrush);
                    cp->drawText(rect, Qt::AlignCenter, fluentIcon(isUp ? Icon::ChevronUp : Icon::ChevronDown));
                };
                if (sub & SC_SpinBoxUp)
                    drawUpDown(SC_SpinBoxUp, QAbstractSpinBox::StepUpEnabled);
                if (sub & SC_SpinBoxDown)
                    drawUpDown(SC_SpinBoxDown, QAbstractSpinBox::StepDownEnabled);
                if (state & State_KeyboardFocusChange && state & State_HasFocus) {
                    QStyleOptionFocusRect fropt;
                    fropt.QStyleOption::operator=(*option);
                    proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, cp.painter(), widget);
                }
            }
        }
        break;
#endif // QT_CONFIG(spinbox)
#if QT_CONFIG(slider)
    case CC_Slider:
        if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
            const auto &slrect = slider->rect;
            const bool isHorizontal = slider->orientation == Qt::Horizontal;
            const QRectF handleRect(proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget));
            const QPointF handleCenter(handleRect.center());

            if (sub & SC_SliderGroove) {
                QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
                QRectF leftRect;
                QRectF rightRect;

                if (isHorizontal) {
                    rect = QRectF(rect.left() + 2, rect.center().y() - 2, rect.width() - 2, 4);
                    leftRect = QRectF(rect.left(), rect.top(), handleCenter.x() - rect.left(),
                                      rect.height());
                    rightRect = QRectF(handleCenter.x(), rect.top(),
                                       rect.width() - handleCenter.x(),
                                       rect.height());
                } else {
                    rect = QRect(rect.center().x() - 2, rect.top() + 2, 4, rect.height() - 2);
                    leftRect = QRectF(rect.left(), rect.top(), rect.width(),
                                      handleCenter.y() - rect.top());
                    rightRect = QRectF(rect.left(), handleCenter.y(), rect.width(),
                                       rect.height() - handleCenter.y());
                }
                if (slider->upsideDown)
                    qSwap(leftRect, rightRect);

                painter->setPen(Qt::NoPen);
                painter->setBrush(calculateAccentColor(option));
                painter->drawRoundedRect(leftRect,1,1);
                painter->setBrush(WINUI3Colors[colorSchemeIndex][controlStrongFill]);
                painter->drawRoundedRect(rightRect,1,1);
            }
            if (sub & SC_SliderTickmarks) {
                int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
                int ticks = slider->tickPosition;
                int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
                int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
                int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
                int interval = slider->tickInterval;
                if (interval <= 0) {
                    interval = slider->singleStep;
                    if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
                                                        available)
                                - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
                                                                  0, available) < 3)
                        interval = slider->pageStep;
                }
                if (!interval)
                    interval = 1;
                int fudge = len / 2;
                painter->setPen(slider->palette.text().color());
                QVarLengthArray<QLineF, 32> lines;
                int v = slider->minimum;
                while (v <= slider->maximum + 1) {
                    if (v == slider->maximum + 1 && interval == 1)
                        break;
                    const int v_ = qMin(v, slider->maximum);
                    int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
                    int pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, v_,
                                                              available, slider->upsideDown);
                    pos += fudge;
                    if (isHorizontal) {
                        if (ticks & QSlider::TicksAbove) {
                            lines.append(QLineF(pos, tickOffset - 0.5,
                                                pos, tickOffset - tickLength - 0.5));
                        }

                        if (ticks & QSlider::TicksBelow) {
                            lines.append(QLineF(pos, tickOffset + thickness + 0.5,
                                                pos, tickOffset + thickness + tickLength + 0.5));
                        }
                    } else {
                        if (ticks & QSlider::TicksAbove) {
                            lines.append(QLineF(tickOffset - 0.5, pos,
                                                tickOffset - tickLength - 0.5, pos));
                        }

                        if (ticks & QSlider::TicksBelow) {
                            lines.append(QLineF(tickOffset + thickness + 0.5, pos,
                                                tickOffset + thickness + tickLength + 0.5, pos));
                        }
                    }
                    // in the case where maximum is max int
                    int nextInterval = v + interval;
                    if (nextInterval < v)
                        break;
                    v = nextInterval;
                }
                if (!lines.isEmpty()) {
                    QPainterStateGuard psg(painter);
                    painter->translate(slrect.topLeft());
                    painter->drawLines(lines.constData(), lines.size());
                }
            }
            if (sub & SC_SliderHandle) {
                const qreal outerRadius = qMin(8.0, (isHorizontal ? handleRect.height() / 2.0 : handleRect.width() / 2.0) - 1);
                float innerRadius = outerRadius * 0.43;

                if (option->styleObject) {
                    const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
                    if (animation != nullptr) {
                        innerRadius = animation->currentValue();
                        option->styleObject->setProperty("_q_inner_radius", innerRadius);
                    } else {
                        bool isInsideHandle = option->activeSubControls == SC_SliderHandle;
                        innerRadius = outerRadius * sliderInnerRadius(state, isInsideHandle);
                    }
                }

                painter->setPen(Qt::NoPen);
                painter->setBrush(winUI3Color(controlFillSolid));
                painter->drawEllipse(handleCenter, outerRadius, outerRadius);
                painter->setBrush(calculateAccentColor(option));
                painter->drawEllipse(handleCenter, innerRadius, innerRadius);

                painter->setPen(winUI3Color(controlStrokeSecondary));
                painter->setBrush(Qt::NoBrush);
                painter->drawEllipse(handleCenter, outerRadius + 0.5, outerRadius + 0.5);
            }
            if (slider->state & State_HasFocus) {
                QStyleOptionFocusRect fropt;
                fropt.QStyleOption::operator=(*slider);
                fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
                proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
            }
        }
        break;
#endif
#if QT_CONFIG(combobox)
    case CC_ComboBox:
        if (const QStyleOptionComboBox *combobox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
            const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
            QStyleOption opt(*option);
            opt.state.setFlag(QStyle::State_On, false);
            drawRoundedRect(painter, frameRect, Qt::NoPen,
                            combobox->editable ? inputFillBrush(option, widget)
                                               : controlFillBrush(&opt, ControlType::Control));

            if (combobox->frame)
                drawLineEditFrame(painter, frameRect, combobox, combobox->editable);

            const bool hasFocus = state & State_HasFocus;

            if (sub & SC_ComboBoxArrow) {
                QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
                painter->setFont(d->assetFont);
                painter->setPen(controlTextColor(option, true));
                painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
            }
            if (state & State_KeyboardFocusChange && hasFocus) {
                QStyleOptionFocusRect fropt;
                fropt.QStyleOption::operator=(*option);
                proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
            }
        }
        break;
#endif // QT_CONFIG(combobox)
    case CC_ScrollBar:
        if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
            const bool vertical = scrollbar->orientation == Qt::Vertical;
            const bool isMouseOver = state & State_MouseOver;
            const auto prx = proxy();

            QPainterStateGuard psg(painter);

            const auto anim = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
            qreal widthFactor = isMouseOver ? 1.0 : 0.0;
            if (anim)
                widthFactor = anim->currentValue();

            if (widthFactor > 0.6) {
                const bool isRtl = option->direction == Qt::RightToLeft;

                QFont f = QFont(d->assetFont);
                f.setPointSize(6);
                painter->setFont(f);
                painter->setPen(winUI3Color(controlStrongFill));

                const QRectF rectAdd =
                        prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
                const auto strAdd = vertical
                        ? Icon::CaretDownSolid8
                        : (isRtl ? Icon::CaretLeftSolid8 : Icon::CaretRightSolid8);
                painter->drawText(rectAdd, Qt::AlignCenter, fluentIcon(strAdd));

                const QRectF rectSub =
                        prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
                const auto strSub = vertical
                        ? Icon::CaretUpSolid8
                        : (isRtl ? Icon::CaretRightSolid8 : Icon::CaretLeftSolid8);
                painter->drawText(rectSub, Qt::AlignCenter, fluentIcon(strSub));
            }
            if (sub & SC_ScrollBarSlider) {
                QRectF rect = prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
                const QPointF center = rect.center();
                if (vertical) {
                    auto w = rect.width() / 2. * widthFactor;
                    if (w < 2)
                        w = 2;
                    const auto ofs = rect.width() / 2 - w;
                    rect.setWidth(w);
                    rect.moveCenter(QPointF(center.x() + ofs, center.y()));
                }
                else {
                    auto h = rect.height() / 2. * widthFactor;
                    if (h < 2)
                        h = 2;
                    const auto ofs = rect.height() / 2 - h;
                    rect.setHeight(h);
                    rect.moveCenter(QPointF(center.x(), center.y() + ofs));
                }
                drawRoundedRect(painter, rect, Qt::NoPen, winUI3Color(controlStrongFill), 3);
            }
        }
        break;
    case CC_MdiControls:{
            QFont buttonFont = QFont(d->assetFont);
            buttonFont.setPointSize(8);
            painter->setFont(buttonFont);
            drawTitleBarCloseButton(CC_MdiControls, SC_MdiCloseButton, Icon::ChromeClose);
            drawTitleBarButton(CC_MdiControls, SC_MdiNormalButton, Icon::ChromeRestore);
            drawTitleBarButton(CC_MdiControls, SC_MdiMinButton, Icon::ChromeMinimize);
        }
        break;
    case CC_TitleBar:
        if (const auto* titlebar = qstyleoption_cast<const QStyleOptionTitleBar*>(option)) {
            painter->setPen(Qt::NoPen);
            painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
            painter->setBrush(titlebar->palette.button());
            painter->drawRect(titlebar->rect);

            // draw title
            QRect textRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
            QColor textColor = titlebar->palette.color(titlebar->titleBarState & Qt::WindowActive ? QPalette::Active : QPalette::Disabled,QPalette::WindowText);
            painter->setPen(textColor);
            // Note workspace also does elliding but it does not use the correct font
            QString title = painter->fontMetrics().elidedText(titlebar->text, Qt::ElideRight, textRect.width() - 14);
            painter->drawText(textRect.adjusted(1, 1, -1, -1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));

            QFont buttonFont = QFont(d->assetFont);
            buttonFont.setPointSize(8);
            painter->setFont(buttonFont);
            auto shouldDrawButton = [titlebar](SubControl sc, Qt::WindowType flag) {
                return (titlebar->subControls & sc) && (titlebar->titleBarFlags & flag);
            };

            // min button
            if (shouldDrawButton(SC_TitleBarMinButton, Qt::WindowMinimizeButtonHint) &&
                !(titlebar->titleBarState & Qt::WindowMinimized)) {
                drawTitleBarButton(CC_TitleBar, SC_TitleBarMinButton, Icon::ChromeMinimize);
            }

            // max button
            if (shouldDrawButton(SC_TitleBarMaxButton, Qt::WindowMaximizeButtonHint) &&
                !(titlebar->titleBarState & Qt::WindowMaximized)) {
                drawTitleBarButton(CC_TitleBar, SC_TitleBarMaxButton, Icon::ChromeMaximize);
            }

            // close button
            if (shouldDrawButton(SC_TitleBarCloseButton, Qt::WindowSystemMenuHint))
                drawTitleBarCloseButton(CC_TitleBar, SC_TitleBarCloseButton, Icon::ChromeClose);

            // normalize button
            if ((titlebar->subControls & SC_TitleBarNormalButton) &&
                (((titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
                  (titlebar->titleBarState & Qt::WindowMinimized)) ||
                 ((titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
                  (titlebar->titleBarState & Qt::WindowMaximized)))) {
                drawTitleBarButton(CC_TitleBar, SC_TitleBarNormalButton, Icon::ChromeRestore);
            }

            // context help button
            if (shouldDrawButton(SC_TitleBarContextHelpButton, Qt::WindowContextHelpButtonHint))
                drawTitleBarButton(CC_TitleBar, SC_TitleBarContextHelpButton, Icon::Help);

            // shade button
            if (shouldDrawButton(SC_TitleBarShadeButton, Qt::WindowShadeButtonHint))
                drawTitleBarButton(CC_TitleBar, SC_TitleBarShadeButton, Icon::ChevronUpSmall);

             // unshade button
            if (shouldDrawButton(SC_TitleBarUnshadeButton, Qt::WindowShadeButtonHint))
                drawTitleBarButton(CC_TitleBar, SC_TitleBarUnshadeButton, Icon::ChevronDownSmall);

            // window icon for system menu
            if (shouldDrawButton(SC_TitleBarSysMenu, Qt::WindowSystemMenuHint)) {
                const QRect iconRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarSysMenu, widget);
                if (iconRect.isValid()) {
                    if (!titlebar->icon.isNull()) {
                        titlebar->icon.paint(painter, iconRect);
                    } else {
                        QStyleOption tool = *titlebar;
                        const auto extent = proxy()->pixelMetric(PM_SmallIconSize, &tool, widget);
                        const auto dpr = QStyleHelper::getDpr(widget);
                        const auto icon = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget);
                        const auto pm = icon.pixmap(QSize(extent, extent), dpr);
                        proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm);
                    }
                }
            }
        }
        break;
#if QT_CONFIG(toolbutton)
    case CC_ToolButton:
        if (const auto toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
            auto prx = proxy();
            const bool isSplitButton =
                    toolbutton->features.testFlag(QStyleOptionToolButton::MenuButtonPopup);
            const auto fw = prx->pixelMetric(PM_DefaultFrameWidth, option, widget);
            const auto buttonRect = prx->subControlRect(control, toolbutton, SC_ToolButton, widget);
            const auto menuareaRect = isSplitButton
                    ? prx->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget)
                    : QRect();

            State bflags = toolbutton->state;
            State mflags = toolbutton->state;
            if (toolbutton->activeSubControls.testFlag(SC_ToolButton)) {
                mflags &= ~(State_Sunken | State_MouseOver);
                if (bflags.testFlag(State_Sunken))
                    mflags |= State_Raised;
            }
            if (toolbutton->activeSubControls.testFlag(SC_ToolButtonMenu)) {
                bflags &= ~(State_Sunken | State_MouseOver);
                if (mflags.testFlag(State_Sunken))
                    bflags |= State_Raised;
            }

            QStyleOption tool = *toolbutton;
            if (toolbutton->subControls.testFlag(SC_ToolButton)) {
                QPainterStateGuard psg(painter);
                if (isSplitButton)
                    painter->setClipRect(buttonRect);
                tool.state = bflags;
                prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
                if (isSplitButton) {
                    if (state.testFlag(State_Enabled)) {
                        painter->setPen(winUI3Color(controlStrokePrimary));
                        const auto top = buttonRect.topRight() + QPoint(0, fw + 1);
                        const auto btm = buttonRect.bottomRight() - QPoint(0, fw);
                        painter->drawLine(top, btm);
                    }
                }
            }

            if (toolbutton->state.testFlag(State_HasFocus)) {
                QStyleOptionFocusRect fr;
                fr.QStyleOption::operator=(*toolbutton);
                prx->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget);
            }
            QStyleOptionToolButton label = *toolbutton;
            label.state = bflags;
            label.rect = buttonRect.marginsRemoved(QMargins(fw, fw, fw, fw));

            if (toolbutton->subControls.testFlag(SC_ToolButtonMenu)) {
                QPainterStateGuard psg(painter);
                painter->setClipRect(menuareaRect);
                tool.state = mflags;
                prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);

                const int fontSize = painter->font().pointSize();
                QFont f(d->assetFont);
                f.setPointSize(qRound(fontSize * 0.9f)); // a little bit smaller
                painter->setFont(f);
                painter->setPen(controlTextColor(option));
                const QRect textRect(menuareaRect.topLeft(), menuareaRect.size() - QSize(fw, 0));
                painter->drawText(textRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));

            } else if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) {
                const int mbi = qRound(prx->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget) * 0.3);
                const QRect &ir = toolbutton->rect;
                QRect rect(ir.right() - mbi - 2 * fw, ir.bottom() - mbi - fw, mbi,
                           mbi);
                rect = visualRect(toolbutton->direction, buttonRect, rect);
                const QRect lblRect = label.rect - QMargins(0, 0, rect.width(), 0);
                label.rect = visualRect(toolbutton->direction, buttonRect, lblRect);
                painter->setFont(QFont(d->assetFont));
                painter->setPen(controlTextColor(option));
                painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
            }
            prx->drawControl(CE_ToolButtonLabel, &label, painter, widget);
        }
        break;
#endif // QT_CONFIG(toolbutton)
    default:
        QWindowsVistaStyle::drawComplexControl(control, option, painter, widget);
    }
}

void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
                                    QPainter *painter,
                                    const QWidget *widget) const {
    QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func());

    const State state = option->state;
    QPainterStateGuard psg(painter);
    painter->setRenderHint(QPainter::Antialiasing);
    if (d->transitionsEnabled() && option->styleObject && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) {
        QObject *styleObject = option->styleObject; // Can be widget or qquickitem
        int oldState = styleObject->property("_q_stylestate").toInt();
        styleObject->setProperty("_q_stylestate", int(option->state));
        styleObject->setProperty("_q_stylerect", option->rect);
        bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
                             || ((state & State_MouseOver) != (oldState & State_MouseOver))
                             || (state & State_On) != (oldState & State_On))
                             && state & State_Enabled);
        if (doTransition) {
            if (element == PE_IndicatorRadioButton) {
                QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
                t->setStartValue(styleObject->property("_q_inner_radius").toFloat());
                t->setEndValue(radioButtonInnerRadius(state));
                styleObject->setProperty("_q_end_radius", t->endValue());
                t->setStartTime(d->animationTime());
                t->setDuration(150);
                d->startAnimation(t);
            }
            else if (element == PE_IndicatorCheckBox) {
                if ((oldState & State_Off && state & State_On) || (oldState & State_NoChange && state & State_On)) {
                    QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
                    t->setStartValue(0.0f);
                    t->setEndValue(1.0f);
                    t->setStartTime(d->animationTime());
                    t->setDuration(150);
                    d->startAnimation(t);
                }
            }
        }
    }

    switch (element) {
    case PE_IndicatorArrowUp:
    case PE_IndicatorArrowDown:
    case PE_IndicatorArrowRight:
    case PE_IndicatorArrowLeft: {
        const QRect &r = option->rect;
        if (r.width() <= 1 || r.height() <= 1)
            break;
        Icon ico = Icon::Help;
        switch (element) {
        case PE_IndicatorArrowUp:
            ico = Icon::ChevronUpMed;
            break;
        case PE_IndicatorArrowDown:
            ico = Icon::ChevronDownMed;
            break;
        case PE_IndicatorArrowLeft:
            ico = Icon::ChevronLeftMed;
            break;
        case PE_IndicatorArrowRight:
            ico = Icon::ChevronRightMed;
            break;
        default:
            break;
        }
        QPainterStateGuard psg(painter);
        if (option->state.testFlag(State_Sunken)) {
            const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget);
            const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget);
            if (bsx != 0 || bsy != 0)
                painter->translate(bsx, bsy);
        }
        painter->setFont(d->assetFont);
        painter->setPen(option->palette.buttonText().color());
        painter->setBrush(option->palette.buttonText());
        painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
        break;
    }
    case PE_FrameFocusRect: {
        if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(option)) {
            if (!(fropt->state & State_KeyboardFocusChange))
                break;
            QRectF focusRect = option->rect;
            focusRect = focusRect.marginsRemoved(QMarginsF(1.5,1.5,1.5,1.5));
            painter->setPen(winUI3Color(focusFrameInnerStroke));
            painter->drawRoundedRect(focusRect,4,4);

            focusRect = focusRect.marginsAdded(QMarginsF(1.0,1.0,1.0,1.0));
            painter->setPen(QPen(winUI3Color(focusFrameOuterStroke),1));
            painter->drawRoundedRect(focusRect,4,4);
        }
        break;
    }
    case PE_PanelTipLabel: {
        const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(0.5, 0.5, 0.5, 0.5));
        const auto pen = highContrastTheme ? option->palette.buttonText().color()
                                           : winUI3Color(frameColorLight);
        drawRoundedRect(painter, rect, pen, option->palette.toolTipBase());
        break;
    }
    case PE_FrameTabWidget:
#if QT_CONFIG(tabwidget)
        if (const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
            QPainterStateGuard psg(painter);
            const auto clipRegion = painter->clipRegion();

            painter->setPen(highContrastTheme ? frame->palette.buttonText().color()
                                              : winUI3Color(frameColorLight));
            painter->setBrush(frame->palette.base());

            const auto &rect = option->rect;
            QRect upperRect = rect;
            upperRect.setHeight(rect.height() / 2);
            QRect lowerRect = rect;
            lowerRect.setY(lowerRect.y() + rect.height() / 2);
            painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
            painter->drawRect(rect);
            painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
            painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);

        }
#endif  // QT_CONFIG(tabwidget)
        break;
    case PE_FrameGroupBox:
        if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
            const auto pen = highContrastTheme ? frame->palette.buttonText().color()
                                               : winUI3Color(frameColorStrong);
            if (frame->features & QStyleOptionFrame::Flat) {
                painter->setBrush(Qt::NoBrush);
                painter->setPen(pen);
                const QRect &fr = frame->rect;
                QPoint p1(fr.x(), fr.y() + 1);
                QPoint p2(fr.x() + fr.width(), p1.y());
                painter->drawLine(p1, p2);
            } else {
                const auto frameRect = QRectF(frame->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
                drawRoundedRect(painter, frameRect, pen, Qt::NoBrush);
            }
        }
        break;
    case PE_IndicatorHeaderArrow:
        if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
            const auto indicator = header->sortIndicator;
            if (indicator != QStyleOptionHeader::None) {
                QPainterStateGuard psg(painter);
                QFont f(d->assetFont);
                f.setPointSize(option->rect.height());
                painter->setFont(f);
                painter->setPen(header->palette.text().color());
                const auto ico = indicator == QStyleOptionHeader::SortUp ? Icon::ChevronDown
                                                                         : Icon::ChevronUp;
                painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
            }
        }
        break;
    case PE_IndicatorCheckBox: {
            const bool isOn = option->state & State_On;
            const bool isPartial = option->state & State_NoChange;

            const QRectF rect = option->rect;
            const QPointF center = rect.center();

            drawRoundedRect(painter, option->rect, borderPenControlAlt(option),
                            controlFillBrush(option, ControlType::ControlAlt));

            if (isOn) {
                painter->setFont(d->assetFont);
                painter->setPen(controlTextColor(option));
                const auto *animation =
                        qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
                const qreal clipWidth = animation ? animation->currentValue() : 1.0;
                const QString str = fluentIcon(Icon::AcceptMedium);
                QFontMetrics fm(d->assetFont);
                QRectF clipRect = fm.boundingRect(str);
                clipRect.moveCenter(center);
                clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0 + 0.5);
                clipRect.setWidth(clipWidth * clipRect.width());
                painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, str);
            } else if (isPartial) {
                QFont f(d->assetFont);
                f.setPointSize(6);
                painter->setFont(f);
                painter->setPen(controlTextColor(option));
                painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::Dash12));
            }
        }
        break;
    case PE_IndicatorBranch: {
            if (option->state & State_Children) {
                const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
                const bool isReverse = option->direction == Qt::RightToLeft;
                const bool isOpen = option->state & QStyle::State_Open;
                const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
                QFont f(d->assetFont);
                f.setPointSize(8);
                painter->setFont(f);
                if (view && view->alternatingRowColors() && vopt && vopt->state & State_Selected)
                    painter->setPen(winUI3Color(textOnAccentPrimary));
                else
                    painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
                                                      QPalette::WindowText));
                const auto ico = isOpen ? Icon::ChevronDownMed
                                        : (isReverse ? Icon::ChevronLeftMed
                                                     : Icon::ChevronRightMed);
                painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
            }
        }
        break;
    case PE_IndicatorRadioButton: {
            const auto *animation =
                    qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
            const qreal innerRadius =
                    animation ? animation->currentValue() : radioButtonInnerRadius(state);
            const QRectF rect = option->rect;
            const QPointF center = rect.center();

            if (option->styleObject)
                option->styleObject->setProperty("_q_inner_radius", innerRadius);
            painter->setPen(borderPenControlAlt(option));
            painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
            if (option->state.testFlag(State_On)) {
                QPainterPath path;
                path.addEllipse(center, 7.5, 7.5);
                path.addEllipse(center, innerRadius, innerRadius);
                painter->drawPath(path);
                // Text On Accent/Primary
                painter->setBrush(option->palette.window().color());
                painter->drawEllipse(center, innerRadius, innerRadius);
            } else {
                painter->drawEllipse(center, 7.5, 7.5);
            }
        }
        break;
    case PE_PanelButtonTool:
    case PE_PanelButtonBevel:{
            const bool isEnabled = state & QStyle::State_Enabled;
            const bool isMouseOver = state & QStyle::State_MouseOver;
            const bool isAutoRaise = state & QStyle::State_AutoRaise;
            const int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
            const QRectF rect = option->rect.marginsRemoved(QMargins(fw, fw, fw, fw));
            if (element == PE_PanelButtonTool && ((!isMouseOver && isAutoRaise) || !isEnabled))
                painter->setPen(Qt::NoPen);
            else
                painter->setPen(winUI3Color(controlStrokePrimary));
            painter->setBrush(controlFillBrush(option, ControlType::Control));
            if (element == PE_PanelButtonTool && widget) {
                const auto name = widget->objectName();
                if (name == "ScrollLeftButton"_L1 || name == "ScrollRightButton"_L1) {
                    painter->setPen(Qt::NoPen);
                    if (isMouseOver)
                        painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
                    else
                        painter->setBrush(Qt::NoBrush);
                }
            }
            painter->drawRoundedRect(rect,
                                     secondLevelRoundingRadius, secondLevelRoundingRadius);
        }
        break;
    case PE_FrameDefaultButton:
        painter->setPen(option->palette.accent().color());
        painter->setBrush(Qt::NoBrush);
        painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
        break;
    case PE_FrameMenu:
        break;
    case PE_PanelMenu: {
        if (!d->nativeRoundedTopLevelWindows) {
            const QRect rect = option->rect.marginsRemoved(QMargins(2, 2, 2, 2));
            painter->setPen(highContrastTheme ? QPen(option->palette.windowText().color(), 2)
                                              : winUI3Color(frameColorLight));
            painter->setBrush(winUI3Color(menuPanelFill));
            painter->drawRoundedRect(rect, topLevelRoundingRadius, topLevelRoundingRadius);
        }
        break;
    }
    case PE_PanelLineEdit:
        if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
            const bool isInSpinBox =
                    widget && qobject_cast<const QAbstractSpinBox *>(widget->parent()) != nullptr;
            const bool isInComboBox =
                    widget && qobject_cast<const QComboBox *>(widget->parent()) != nullptr;
            if (!isInSpinBox && !isInComboBox) {
                const auto frameRect =
                        QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
                drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
                if (panel->lineWidth > 0)
                    proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
            }
        }
        break;
    case PE_FrameLineEdit: {
        const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
        drawLineEditFrame(painter, frameRect, option);
        if (state & State_KeyboardFocusChange && state & State_HasFocus) {
            QStyleOptionFocusRect fropt;
            fropt.QStyleOption::operator=(*option);
            proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
        }
        break;
    }
    case PE_Frame: {
        if (const auto *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
            const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
            if (qobject_cast<const QComboBoxPrivateContainer *>(widget)) {
                if (d->nativeRoundedTopLevelWindows)
                    break;
                QPen pen;
                if (highContrastTheme)
                    pen = QPen(option->palette.windowText().color(), 2);
                else
                    pen = Qt::NoPen;
                drawRoundedRect(painter, rect, pen, WINUI3Colors[colorSchemeIndex][menuPanelFill]);
            } else
                drawRoundedRect(painter, rect, Qt::NoPen, option->palette.brush(QPalette::Base));

            if (frame->frameShape == QFrame::NoFrame)
                break;

            const bool isEditable = qobject_cast<const QTextEdit *>(widget) != nullptr
                    || qobject_cast<const QPlainTextEdit *>(widget) != nullptr;
            drawLineEditFrame(painter, rect, option, isEditable);
        }
        break;
    }
    case PE_PanelItemViewItem:
        if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
            if (vopt->backgroundBrush.style() != Qt::NoBrush) {
                QPainterStateGuard psg(painter);
                painter->setBrushOrigin(vopt->rect.topLeft());
                painter->fillRect(vopt->rect, vopt->backgroundBrush);
            }
        }
        break;
    case PE_PanelItemViewRow:
        if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
            // this is only called from a QTreeView to paint
            //  - the tree branch decoration (incl. selected/hovered or not)
            //  - the (alternate) background of the item in always unselected state
            const QRect &rect = vopt->rect;
            const bool isRtl = option->direction == Qt::RightToLeft;
            if (rect.width() <= 0)
                break;

            if (vopt->features & QStyleOptionViewItem::Alternate) {
                QPalette::ColorGroup cg =
                        (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
                        ? QPalette::Normal
                        : QPalette::Disabled;
                if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
                    cg = QPalette::Inactive;
                painter->fillRect(rect, option->palette.brush(cg, QPalette::AlternateBase));
            }

            if (option->state & State_Selected && !highContrastTheme) {
                // keep in sync with CE_ItemViewItem QListView indicator painting
                if (!qobject_cast<const QTableView *>(widget)) {
                    const auto col = option->palette.accent().color();
                    painter->setBrush(col);
                    painter->setPen(col);
                    const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
                    const auto yOfs = rect.height() / 4.;
                    QRectF r(QPointF(xPos, rect.y() + yOfs),
                             QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
                    painter->drawRoundedRect(r, 1, 1);
                }
            }

            const bool isTreeDecoration = vopt->features.testFlag(
                    QStyleOptionViewItem::IsDecorationForRootColumn);
            if (isTreeDecoration && vopt->state.testAnyFlags(State_Selected | State_MouseOver) &&
                vopt->showDecorationSelected) {
                const bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
                                     vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
                bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
                bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;

                if (onlyOne)
                    isFirst = true;

                if (isRtl) {
                    isFirst = !isFirst;
                    isLast = !isLast;
                }

                const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
                painter->setBrush(view->alternatingRowColors() && state & State_Selected ? calculateAccentColor(option) : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
                painter->setPen(Qt::NoPen);
                if (isFirst) {
                    QPainterStateGuard psg(painter);
                    painter->setClipRect(rect);
                    painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
                                             secondLevelRoundingRadius, secondLevelRoundingRadius);
                } else if (isLast) {
                    QPainterStateGuard psg(painter);
                    painter->setClipRect(rect);
                    painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
                                             secondLevelRoundingRadius, secondLevelRoundingRadius);
                } else {
                    painter->drawRect(vopt->rect.marginsRemoved(QMargins(0, 2, 0, 2)));
                }
            }
        }
        break;
    case QStyle::PE_Widget: {
        if (widget && widget->palette().isBrushSet(QPalette::Active, widget->backgroundRole())) {
            const QBrush bg = widget->palette().brush(widget->backgroundRole());
            auto wp = QWidgetPrivate::get(widget);
            QPainterStateGuard psg(painter);
            wp->updateBrushOrigin(painter, bg);
            painter->fillRect(option->rect, bg);
        }
        break;
    }
    case QStyle::PE_FrameWindow:
        if (const auto *frm = qstyleoption_cast<const QStyleOptionFrame *>(option)) {

            QRectF rect= option->rect;
            int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));

            QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
                                             rect.bottom() - 1.0 - secondLevelRoundingRadius,
                                             secondLevelRoundingRadius,
                                             secondLevelRoundingRadius);
            QRectF bottomRightCorner = QRectF(rect.right() - 1.0  - secondLevelRoundingRadius,
                                              rect.bottom() - 1.0  - secondLevelRoundingRadius,
                                              secondLevelRoundingRadius,
                                              secondLevelRoundingRadius);

            //Draw Mask
            if (widget != nullptr) {
                QBitmap mask(widget->width(), widget->height());
                mask.clear();

                QPainter maskPainter(&mask);
                maskPainter.setRenderHint(QPainter::Antialiasing);
                maskPainter.setBrush(Qt::color1);
                maskPainter.setPen(Qt::NoPen);
                maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
                const_cast<QWidget*>(widget)->setMask(mask);
            }

            //Draw Window
            painter->setPen(QPen(frm->palette.base(), fwidth));
            painter->drawLine(QPointF(rect.left(), rect.top()),
                              QPointF(rect.left(), rect.bottom() - fwidth));
            painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
                              QPointF(rect.right() - fwidth, rect.bottom()));
            painter->drawLine(QPointF(rect.right(), rect.top()),
                              QPointF(rect.right(), rect.bottom() - fwidth));

            painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
            painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
                              QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
            painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
                              QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
            painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
                              QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));

            painter->setPen(Qt::NoPen);
            painter->setBrush(frm->palette.base());
            painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
                             270 * 16,90 * 16);
            painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
                             -90 * 16,-90 * 16);

            painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
            painter->setBrush(Qt::NoBrush);
            painter->drawArc(bottomRightCorner,
                             0 * 16,-90 * 16);
            painter->drawArc(bottomLeftCorner,
                             -90 * 16,-90 * 16);
        }
        break;
#if QT_CONFIG(tabbar)
    case PE_FrameTabBarBase:
        if (const auto *tab = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
            QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
            const auto clipRegion = painter->clipRegion();

            painter->setPen(highContrastTheme ? tab->palette.buttonText().color()
                                              : winUI3Color(frameColorLight));
            painter->setBrush(tab->palette.base());
            QRect upperRect = tab->rect;
            upperRect.setHeight(tab->rect.height() / 2);
            QRect lowerRect = tab->rect;
            lowerRect.setY(lowerRect.y() + tab->rect.height() / 2);
            painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
            painter->drawRoundedRect(tab->rect, secondLevelRoundingRadius,
                                     secondLevelRoundingRadius);
            painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
            painter->drawRect(tab->rect);
        }
        break;
#endif // QT_CONFIG(tabbar)
    case PE_IndicatorTabTearLeft:
    case PE_IndicatorTabTearRight:
        break;
    default:
        QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
    }
}

/*!
    \internal
*/
void QWindows11Style::drawControl(ControlElement element, const QStyleOption *option,
                                  QPainter *painter, const QWidget *widget) const
{
    Q_D(const QWindows11Style);
    State flags = option->state;

    QPainterStateGuard psg(painter);
    painter->setRenderHint(QPainter::Antialiasing);
    switch (element) {
    case QStyle::CE_ComboBoxLabel:
#if QT_CONFIG(combobox)
        if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
            painter->setPen(controlTextColor(option, true));
            QStyleOptionComboBox newOption = *cb;
            newOption.rect.adjust(4,0,-4,0);
            QCommonStyle::drawControl(element, &newOption, painter, widget);
        }
#endif // QT_CONFIG(combobox)
        break;
#if QT_CONFIG(tabbar)
    case CE_TabBarTabShape:
        if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
            QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
            const bool isSelected = tab->state.testFlag(State_Selected);
            const auto clipRegion = painter->clipRegion();
            const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab
                    || tab->position == QStyleOptionTab::Moving;
            auto leftMargin = (tab->position == QStyleOptionTab::Beginning || onlyOne) ? 1 : 0;
            auto rightMargin = (tab->position == QStyleOptionTab::End || onlyOne) ? 1 : 0;
            if (QCommonStylePrivate::rtl(option))
                std::swap(leftMargin, rightMargin);

            QRectF tabRect = tab->rect.marginsRemoved(QMargins(leftMargin, 1, rightMargin, -3));
            painter->setPen(highContrastTheme ? tab->palette.buttonText().color() : winUI3Color(frameColorLight));
            painter->setBrush(tab->palette.base());
            if (isSelected) {
                painter->setBrush(winUI3Color(fillMicaAltDefault));
            } else {
                if (tab->state.testFlag(State_Sunken))
                    painter->setBrush(winUI3Color(fillMicaAltDefault));
                else if (tab->state.testFlag(State_MouseOver))
                    painter->setBrush(winUI3Color(fillMicaAltSecondary));
                else
                    painter->setBrush(winUI3Color(fillMicaAltTransparent));
            }
            QRect upperRect = tab->rect;
            upperRect.setHeight(tab->rect.height() / 2.);
            QRect lowerRect = tab->rect;
            lowerRect.setY(lowerRect.y() + tab->rect.height() / 2.);
            painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
            painter->drawRoundedRect(tabRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
            painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
            painter->drawRect(tabRect);
        }
        break;
    case CE_TabBarTabLabel:
        if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
            const bool isEnabled = tab->state.testFlags(State_Enabled);
            const bool isSelected = tab->state.testFlags(State_Selected);

            QRect tr = tab->rect;
            bool verticalTabs = tab->shape == QTabBar::RoundedEast
                    || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast
                    || tab->shape == QTabBar::TriangularWest;

            int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
            if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget))
                alignment |= Qt::TextHideMnemonic;

            QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
            if (verticalTabs) {
                psg.save();
                int newX, newY, newRot;
                if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
                    newX = tr.width() + tr.x();
                    newY = tr.y();
                    newRot = 90;
                } else {
                    newX = tr.x();
                    newY = tr.y() + tr.height();
                    newRot = -90;
                }
                QTransform m = QTransform::fromTranslate(newX, newY);
                m.rotate(newRot);
                painter->setTransform(m, true);
            }
            QRect iconRect;
            d->tabLayout(tab, widget, &tr, &iconRect);

            // compute tr again, unless tab is moving, because the style may override subElementRect
            if (tab->position != QStyleOptionTab::TabPosition::Moving)
                tr = proxy()->subElementRect(SE_TabBarTabText, option, widget);

            if (!tab->icon.isNull()) {
                const auto mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
                const auto state = isSelected ? QIcon::On : QIcon::Off;
                tab->icon.paint(painter, iconRect, Qt::AlignCenter, mode, state);
            }

            painter->setPen(winUI3Color(isSelected ? textPrimary : textSecondary));
            proxy()->drawItemText(painter, tr, alignment, tab->palette, isEnabled, tab->text);
        }
        break;
#endif // QT_CONFIG(tabbar)
    case CE_ToolButtonLabel:
#if QT_CONFIG(toolbutton)
        if (const QStyleOptionToolButton *toolbutton
            = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
            QRect rect = toolbutton->rect;
            int shiftX = 0;
            int shiftY = 0;
            if (toolbutton->state & (State_Sunken | State_On)) {
                shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
                shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
            }
            // Arrow type always overrules and is always shown
            bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
            if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
                || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
                int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
                if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
                    alignment |= Qt::TextHideMnemonic;
                rect.translate(shiftX, shiftY);
                painter->setFont(toolbutton->font);
                const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
                painter->setPen(controlTextColor(option));
                proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
                                      toolbutton->state & State_Enabled, text);
            } else {
                QPixmap pm;
                QSize pmSize = toolbutton->iconSize;
                if (!toolbutton->icon.isNull()) {
                    QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
                    QIcon::Mode mode;
                    if (!(toolbutton->state & State_Enabled))
                        mode = QIcon::Disabled;
                    else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
                        mode = QIcon::Active;
                    else
                        mode = QIcon::Normal;
                    pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
                                                 mode, state);
                    pmSize = pm.size() / pm.devicePixelRatio();
                }

                if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
                    painter->setFont(toolbutton->font);
                    QRect pr = rect,
                            tr = rect;
                    int alignment = Qt::TextShowMnemonic | Qt::AlignCenter;
                    if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
                        alignment |= Qt::TextHideMnemonic;

                    if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
                        pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
                        tr.adjust(0, pr.height() - 1, 0, -1);
                    } else {
                        pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
                        tr.adjust(pr.width(), 0, 0, 0);
                    }
                    pr.translate(shiftX, shiftY);
                    if (hasArrow) {
                        drawArrow(proxy(), toolbutton, pr, painter, widget);
                    } else {
                        const auto vr = QStyle::visualRect(toolbutton->direction, rect, pr);
                        proxy()->drawItemPixmap(painter, vr, Qt::AlignCenter, pm);
                    }
                    tr.translate(shiftX, shiftY);
                    painter->setPen(controlTextColor(option));
                    const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
                    const auto vr = QStyle::visualRect(toolbutton->direction, rect, tr);
                    proxy()->drawItemText(painter, vr, alignment, toolbutton->palette,
                                          toolbutton->state & State_Enabled, text);
                } else {
                    rect.translate(shiftX, shiftY);
                    if (hasArrow) {
                        drawArrow(proxy(), toolbutton, rect, painter, widget);
                    } else {
                        proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
                    }
                }
            }
        }
#endif  // QT_CONFIG(toolbutton)
        break;
    case QStyle::CE_ShapedFrame:
        if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
            int frameShape  = f->frameShape;
            int frameShadow = QFrame::Plain;
            if (f->state & QStyle::State_Sunken)
                frameShadow = QFrame::Sunken;
            else if (f->state & QStyle::State_Raised)
                frameShadow = QFrame::Raised;

            int lw = f->lineWidth;
            int mlw = f->midLineWidth;

            switch (frameShape) {
            case QFrame::Box:
                if (frameShadow == QFrame::Plain)
                    qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme == true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
                else
                    qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
                break;
            case QFrame::Panel:
                if (frameShadow == QFrame::Plain)
                    qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme == true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
                else
                    qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
                break;
            default:
                QWindowsVistaStyle::drawControl(element, option, painter, widget);
            }
        }
        break;
#if QT_CONFIG(progressbar)
    case CE_ProgressBarGroove:
        if (const auto baropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
            QRect rect = option->rect;
            QPointF center = rect.center();
            if (baropt->state & QStyle::State_Horizontal) {
                rect.setHeight(1);
                rect.moveTop(center.y());
            } else {
                rect.setWidth(1);
                rect.moveLeft(center.x());
            }
            painter->setPen(Qt::NoPen);
            painter->setBrush(Qt::gray);
            painter->drawRect(rect);
        }
        break;
    case CE_ProgressBarContents:
        if (const auto baropt = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
            QPainterStateGuard psg(painter);
            QRectF rect = option->rect;
            painter->translate(rect.topLeft());
            rect.translate(-rect.topLeft());

            constexpr qreal progressBarThickness = 3;
            constexpr qreal progressBarHalfThickness = progressBarThickness / 2.0;

            const auto isIndeterminate = baropt->maximum == 0 && baropt->minimum == 0;
            const auto orientation =
                    (baropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
            const auto inverted = baropt->invertedAppearance;
            const auto reverse = (baropt->direction == Qt::RightToLeft) ^ inverted;
            // If the orientation is vertical, we use a transform to rotate
            // the progress bar 90 degrees (counter)clockwise. This way we can use the
            // same rendering code for both orientations.
            if (orientation == Qt::Vertical) {
                rect = QRectF(rect.left(), rect.top(), rect.height(),
                              rect.width()); // flip width and height
                QTransform m;
                if (inverted) {
                    m.rotate(90);
                    m.translate(0, -rect.height() + 1);
                } else {
                    m.rotate(-90);
                    m.translate(-rect.width(), 0);
                }
                painter->setTransform(m, true);
            } else if (reverse) {
                QTransform m = QTransform::fromScale(-1, 1);
                m.translate(-rect.width(), 0);
                painter->setTransform(m, true);
            }
            const qreal offset = (int(rect.height()) % 2 == 0) ? 0.5f : 0.0f;

            if (isIndeterminate) {
#if QT_CONFIG(animation)
                auto anim = d->animation(option->styleObject);
                if (!anim) {
                    auto anim = new QStyleAnimation(option->styleObject);
                    anim->setFrameRate(QStyleAnimation::SixtyFps);
                    d->startAnimation(anim);
                }
                constexpr auto loopDurationMSec = 4000;
                const auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(
                        std::chrono::system_clock::now());
                const auto elapsed = elapsedTime.time_since_epoch().count();
                const auto handleCenter = (elapsed % loopDurationMSec) / float(loopDurationMSec);
                const auto isLongHandle = (elapsed / loopDurationMSec) % 2 == 0;
                const auto lengthFactor = (isLongHandle ? 33.0f : 25.0f) / 100.0f;
#else
                constexpr auto handleCenter = 0.5f;
                constexpr auto lengthFactor = 1;
#endif
                const auto begin = qMax(handleCenter * (1 + lengthFactor) - lengthFactor, 0.0f);
                const auto end = qMin(handleCenter * (1 + lengthFactor), 1.0f);
                const auto barBegin = begin * rect.width();
                const auto barEnd = end * rect.width();
                rect = QRectF(QPointF(rect.left() + barBegin, rect.top()),
                              QPointF(rect.left() + barEnd, rect.bottom()));
            } else {
#if QT_CONFIG(animation)
                d->stopAnimation(option->styleObject);
#endif
                const auto fillPercentage = (float(baropt->progress - baropt->minimum))
                        / (float(baropt->maximum - baropt->minimum));
                rect.setWidth(rect.width() * fillPercentage);
            }
            const QPointF center = rect.center();
            rect.setHeight(progressBarThickness);
            rect.moveTop(center.y() - progressBarHalfThickness - offset);
            drawRoundedRect(painter, rect, Qt::NoPen, baropt->palette.accent());
        }
        break;
    case CE_ProgressBarLabel:
        if (const auto baropt = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
            const bool vertical = !(baropt->state & QStyle::State_Horizontal);
            if (!vertical) {
                proxy()->drawItemText(painter, baropt->rect, Qt::AlignCenter | Qt::TextSingleLine,
                                      baropt->palette, baropt->state & State_Enabled, baropt->text,
                                      QPalette::Text);
            }
        }
        break;
#endif // QT_CONFIG(progressbar)
    case CE_PushButtonLabel:
        if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
            QStyleOptionButton btnCopy(*btn);
            btnCopy.rect = btn->rect.marginsRemoved(QMargins(contentHMargin, 0, contentHMargin, 0));
            btnCopy.palette.setBrush(QPalette::ButtonText, controlTextColor(option));
            QCommonStyle::drawControl(element, &btnCopy, painter, widget);
        }
        break;
    case CE_PushButtonBevel:
        if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))  {
            using namespace StyleOptionHelper;

            QRectF rect = btn->rect.marginsRemoved(QMargins(2, 2, 2, 2));
            painter->setPen(Qt::NoPen);
            if (btn->features.testFlag(QStyleOptionButton::Flat)) {
                painter->setBrush(btn->palette.button());
                painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
                if (flags & (State_Sunken | State_On)) {
                    painter->setBrush(WINUI3Colors[colorSchemeIndex][subtlePressedColor]);
                }
                else if (flags & State_MouseOver) {
                    painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
                }
                painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
            } else {
                painter->setBrush(controlFillBrush(option, ControlType::Control));
                painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);

                rect.adjust(0.5,0.5,-0.5,-0.5);
                const bool defaultButton = btn->features.testFlag(QStyleOptionButton::DefaultButton);
                painter->setBrush(Qt::NoBrush);
                painter->setPen(defaultButton ? option->palette.accent().color()
                                              : WINUI3Colors[colorSchemeIndex][controlStrokePrimary]);
                painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);

                painter->setPen(defaultButton ? WINUI3Colors[colorSchemeIndex][controlStrokeOnAccentSecondary]
                                              : WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]);
            }
            if (btn->features.testFlag(QStyleOptionButton::HasMenu)) {
                QPainterStateGuard psg(painter);

                QRect textRect = btn->rect.marginsRemoved(QMargins(contentHMargin, 0, contentHMargin, 0));
                const auto indSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
                const auto indRect =
                        QRect(btn->rect.right() - indSize - contentItemHMargin, textRect.top(),
                              indSize + contentItemHMargin, btn->rect.height());
                const auto vindRect = visualRect(btn->direction, btn->rect, indRect);
                textRect.setWidth(textRect.width() - indSize);

                int fontSize = painter->font().pointSize();
                QFont f(d->assetFont);
                f.setPointSize(qRound(fontSize * 0.9f)); // a little bit smaller
                painter->setFont(f);
                painter->setPen(controlTextColor(option));
                painter->drawText(vindRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
            }
        }
        break;
    case CE_MenuBarItem:
        if (const auto *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option))  {
            using namespace StyleOptionHelper;

            constexpr int hPadding = 11;
            constexpr int topPadding = 4;
            constexpr int bottomPadding = 6;
            QStyleOptionMenuItem newMbi = *mbi;

            if (auto mbiV2 = qstyleoption_cast<const QStyleOptionMenuItemV2 *>(option))
                newMbi.state.setFlag(State_Sunken, mbiV2->mouseDown);

            newMbi.font.setPointSize(10);
            newMbi.palette.setColor(QPalette::ButtonText, controlTextColor(&newMbi));
            if (!isDisabled(&newMbi)) {
                QPen pen(Qt::NoPen);
                QBrush brush(Qt::NoBrush);
                if (highContrastTheme) {
                    pen = QPen(newMbi.palette.highlight().color(), 2);
                    brush = newMbi.palette.window();
                } else if (isPressed(&newMbi)) {
                    brush = winUI3Color(subtlePressedColor);
                } else if (isHover(&newMbi)) {
                    brush = winUI3Color(subtleHighlightColor);
                }
                if (pen != Qt::NoPen || brush != Qt::NoBrush) {
                    const QRect rect = mbi->rect.marginsRemoved(QMargins(5, 0, 5, 0));
                    drawRoundedRect(painter, rect, pen, brush);
                }
            }
            newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
            painter->setFont(newMbi.font);
            QCommonStyle::drawControl(element, &newMbi, painter, widget);
        }
        break;

#if QT_CONFIG(menu)
    case CE_MenuEmptyArea:
        break;

    case CE_MenuItem:
        if (const auto *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
            using namespace StyleOptionHelper;

            const auto visualMenuRect = [&](const QRect &rect) {
                return visualRect(option->direction, menuitem->rect, rect);
            };

            const bool checked =
                    menuitem->checkType != QStyleOptionMenuItem::NotCheckable && menuitem->checked;

            const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2));
            if (!isDisabled(menuitem)) {
                QPen pen(Qt::NoPen);
                QBrush brush(Qt::NoBrush);
                if (highContrastTheme) {
                    pen = QPen(menuitem->palette.highlight().color(), 2);
                    brush = menuitem->palette.window();
                } else if (isPressed(menuitem)) {
                    brush = winUI3Color(subtlePressedColor);
                } else if (isSelected(menuitem)) { // == hover
                    brush = winUI3Color(subtleHighlightColor);
                }
                if (pen != Qt::NoPen || brush != Qt::NoBrush)
                    drawRoundedRect(painter, rect, pen, brush);
            }
            if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
                constexpr int yoff = 1;
                painter->setPen(highContrastTheme ? menuitem->palette.buttonText().color() : winUI3Color(dividerStrokeDefault));
                painter->drawLine(menuitem->rect.topLeft() + QPoint(0, yoff),
                                  menuitem->rect.topRight() + QPoint(0, yoff));
                break;
            }

            int xOffset = contentHMargin;
            // WinUI3 draws, in contrast to former windows styles, the checkmark and icon separately
            const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
            if (checked) {
                QRect vRect(visualMenuRect(QRect(rect.x() + xOffset, rect.y(),
                                                 checkMarkWidth, rect.height())));
                QPainterStateGuard psg(painter);
                painter->setFont(d->assetFont);
                painter->setPen(option->palette.text().color());
                painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
            }
            if (menuitem->menuHasCheckableItems)
                xOffset += checkMarkWidth + contentItemHMargin;
            if (!menuitem->icon.isNull()) {
                // 4 is added to maxIconWidth in qmenu.cpp to PM_SmallIconSize
                QRect vRect(visualMenuRect(QRect(rect.x() + xOffset,
                                                 rect.y(),
                                                 menuitem->maxIconWidth - 4,
                                                 rect.height())));
                const auto mode = isDisabled(menuitem)
                        ? QIcon::Disabled
                        : (isSelected(menuitem) ? QIcon::Active : QIcon::Normal);
                const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
                QRect pmr(QPoint(0, 0), QSize(size, size));
                pmr.moveCenter(vRect.center());
                menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode,
                                     checked ? QIcon::On : QIcon::Off);
            }
            if (menuitem->maxIconWidth > 0)
                xOffset += menuitem->maxIconWidth - 4 + contentItemHMargin;

            QStringView s(menuitem->text);
            if (!s.isEmpty()) {                     // draw text
                QPoint tl(rect.left() + xOffset, rect.top());
                QPoint br(rect.right() - menuitem->reservedShortcutWidth - contentHMargin,
                          rect.bottom());
                QRect textRect(tl, br);
                QRect vRect(visualMenuRect(textRect));

                QColor penColor;
                if (highContrastTheme) {
                    penColor = menuitem->palette.color(
                            isSelected(menuitem) ? QPalette::HighlightedText : QPalette::Text);
                } else {
                    QStyleOption tmpOpt(*option);
                    tmpOpt.state.setFlag(State_Sunken, false);
                    penColor = controlTextColor(&tmpOpt);
                }
                painter->setPen(penColor);

                qsizetype t = s.indexOf(u'\t');
                int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
                if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
                    text_flags |= Qt::TextHideMnemonic;
                text_flags |= Qt::AlignLeft;
                // a submenu doesn't paint a possible shortcut in WinUI3
                if (t >= 0 && menuitem->menuItemType != QStyleOptionMenuItem::SubMenu) {
                    QRect shortcutRect(QPoint(textRect.right(), textRect.top()),
                                       QPoint(rect.right(), textRect.bottom()));
                    QRect vShortcutRect(visualMenuRect(shortcutRect));
                    const QString textToDraw = s.mid(t + 1).toString();
                    painter->drawText(vShortcutRect, text_flags, textToDraw);
                    s = s.left(t);
                }
                QFont font = menuitem->font;
                if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
                    font.setBold(true);
                painter->setFont(font);
                const QString textToDraw = s.left(t).toString();
                painter->drawText(vRect, text_flags, textToDraw);
            }
            if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
                int fontSize = menuitem->font.pointSize();
                QFont f(d->assetFont);
                f.setPointSize(qRound(fontSize * 0.9f)); // a little bit smaller
                painter->setFont(f);
                int yOfs = qRound(fontSize / 3.0f); // an offset to align the '>' with the baseline of the text
                QPoint tl(rect.right() - 2 * QWindowsStylePrivate::windowsArrowHMargin - contentItemHMargin,
                          rect.top() + yOfs);
                QRect submenuRect(tl, rect.bottomRight());
                QRect vSubMenuRect = visualMenuRect(submenuRect);
                painter->setPen(option->palette.text().color());
                const bool isReverse = option->direction == Qt::RightToLeft;
                const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
                painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
            }
        }
        break;
#endif // QT_CONFIG(menu)
    case CE_MenuBarEmptyArea: {
        break;
    }
    case CE_HeaderEmptyArea:
        break;
    case CE_HeaderSection: {
        if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
            painter->setPen(Qt::NoPen);
            painter->setBrush(header->palette.button());
            painter->drawRect(header->rect);
            const bool isRtl = option->direction == Qt::RightToLeft;
            const QPointF tr = isRtl ? option->rect.topLeft() : option->rect.topRight();
            const QPointF br = isRtl ? option->rect.bottomLeft() : option->rect.bottomRight();
            const QPointF bl = isRtl ? option->rect.bottomRight() : option->rect.bottomLeft();
            constexpr QPointF trOfs = QPointF(0.5, 0.0);
            constexpr QPointF brOfs = QPointF(0.5, 0.5);
            constexpr QPointF blOfs = QPointF(0.0, 0.5);
            const std::array<QPointF, 3> points = { tr + trOfs, br + brOfs, bl + blOfs };
            QPen pen(highContrastTheme ? header->palette.buttonText().color()
                                       : winUI3Color(frameColorLight));
            pen.setJoinStyle(Qt::MiterJoin);
            painter->setPen(pen);
            painter->drawPolyline(points.data(), int(points.size()));
        }
        break;
    }
    case CE_ItemViewItem: {
        if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
            const auto p = proxy();
            QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
            QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
            QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget);

            // draw the background
            proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);

            const QRect &rect = vopt->rect;
            const bool isRtl = option->direction == Qt::RightToLeft;
            bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
                           vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
            bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
            bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;

            const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
            if (qobject_cast<const QTableView *>(view)) {
                onlyOne = true;
            } else {
                // the tree decoration already painted the left side of the rounded rect
                if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
                    vopt->showDecorationSelected) {
                    isFirst = false;
                    if (onlyOne) {
                        onlyOne = false;
                        isLast = true;
                    }
                }

                if (isRtl) {
                    if (isFirst) {
                        isFirst = false;
                        isLast = true;
                    } else if (isLast) {
                        isFirst = true;
                        isLast = false;
                    }
                }
            }

            const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
            if (highlightCurrent) {
                if (highContrastTheme) {
                    painter->setBrush(vopt->palette.highlight());
                } else {
                    painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
                                              ? calculateAccentColor(option)
                                              : winUI3Color(subtleHighlightColor));
                }
            } else {
                painter->setBrush(vopt->backgroundBrush);
            }
            painter->setPen(Qt::NoPen);

            if (onlyOne) {
                painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
                                         secondLevelRoundingRadius, secondLevelRoundingRadius);
            } else if (isFirst) {
                QPainterStateGuard psg(painter);
                painter->setClipRect(rect);
                painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
                                         secondLevelRoundingRadius, secondLevelRoundingRadius);
            } else if (isLast) {
                QPainterStateGuard psg(painter);
                painter->setClipRect(rect);
                painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
                                         secondLevelRoundingRadius, secondLevelRoundingRadius);
            } else {
                painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
            }

            // draw the check mark
            if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
                QStyleOptionViewItem option(*vopt);
                option.rect = checkRect;
                option.state = option.state & ~QStyle::State_HasFocus;

                switch (vopt->checkState) {
                case Qt::Unchecked:
                    option.state |= QStyle::State_Off;
                    break;
                case Qt::PartiallyChecked:
                    option.state |= QStyle::State_NoChange;
                    break;
                case Qt::Checked:
                    option.state |= QStyle::State_On;
                    break;
                }
                proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
            }

            // draw the icon
            if (iconRect.isValid()) {
                QIcon::Mode mode = QIcon::Normal;
                if (!(vopt->state & QStyle::State_Enabled))
                    mode = QIcon::Disabled;
                else if (vopt->state & QStyle::State_Selected)
                    mode = QIcon::Selected;
                QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
                vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
            }

            if (highlightCurrent && highContrastTheme) {
                painter->setPen(vopt->palette.base().color());
            } else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
                painter->setPen(winUI3Color(textOnAccentPrimary));
            } else {
                painter->setPen(vopt->palette.text().color());
            }
            d->viewItemDrawText(painter, vopt, textRect);

            // paint a vertical marker for QListView
            if (vopt->state & State_Selected && !highContrastTheme) {
                if (const QListView *lv = qobject_cast<const QListView *>(widget);
                    lv && lv->viewMode() != QListView::IconMode) {
                    const auto col = vopt->palette.accent().color();
                    painter->setBrush(col);
                    painter->setPen(col);
                    const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
                    const auto yOfs = rect.height() / 4.;
                    QRectF r(QPointF(xPos, rect.y() + yOfs),
                             QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
                    painter->drawRoundedRect(r, 1, 1);
                }
            }
        }
        break;
    }
    default:
        QWindowsVistaStyle::drawControl(element, option, painter, widget);
    }
}

int QWindows11Style::styleHint(StyleHint hint, const QStyleOption *opt,
              const QWidget *widget, QStyleHintReturn *returnData) const {
    switch (hint) {
    case QStyle::SH_Menu_AllowActiveAndDisabled:
        return 0;
    case SH_GroupBox_TextLabelColor:
        if (opt!=nullptr && widget!=nullptr)
            return opt->palette.text().color().rgba();
        return 0;
    case QStyle::SH_ItemView_ShowDecorationSelected:
        return 1;
    case QStyle::SH_Slider_AbsoluteSetButtons:
        return Qt::LeftButton;
    case QStyle::SH_Slider_PageSetButtons:
        return 0;
    case SH_SpinControls_DisableOnBounds:
        return 1;
    default:
        return QWindowsVistaStyle::styleHint(hint, opt, widget, returnData);
    }
}

QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOption *option,
                     const QWidget *widget) const
{
    QRect ret;
    switch (element) {
    case QStyle::SE_RadioButtonIndicator:
    case QStyle::SE_CheckBoxIndicator: {
        ret = QWindowsVistaStyle::subElementRect(element, option, widget);
        const auto ofs =
                QCommonStylePrivate::rtl(option) ? -contentItemHMargin : +contentItemHMargin;
        ret.moveLeft(ret.left() + ofs);
        break;
    }
    case QStyle::SE_ComboBoxFocusRect:
    case QStyle::SE_CheckBoxFocusRect:
    case QStyle::SE_RadioButtonFocusRect:
    case QStyle::SE_PushButtonFocusRect:
        ret = option->rect;
        break;
    case QStyle::SE_LineEditContents:
        ret = option->rect.adjusted(4,0,-4,0);
        break;
    case SE_ItemViewItemCheckIndicator:
    case SE_ItemViewItemDecoration:
    case SE_ItemViewItemText: {
        ret = QWindowsVistaStyle::subElementRect(element, option, widget);
        if (!ret.isValid() || highContrastTheme)
            return ret;

        if (const QListView *lv = qobject_cast<const QListView *>(widget);
            lv && lv->viewMode() != QListView::IconMode) {
            const int xOfs = contentHMargin;
            const bool isRtl = option->direction == Qt::RightToLeft;
            if (isRtl) {
                ret.moveRight(ret.right() - xOfs);
                if (ret.left() < option->rect.left())
                    ret.setLeft(option->rect.left());
            } else {
                ret.moveLeft(ret.left() + xOfs);
                if (ret.right() > option->rect.right())
                    ret.setRight(option->rect.right());
            }
        }
        break;
    }
#if QT_CONFIG(progressbar)
    case SE_ProgressBarGroove:
    case SE_ProgressBarContents:
    case SE_ProgressBarLabel:
        if (const auto *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
            QStyleOptionProgressBar optCopy(*pb);
            // we only support label right from content
            optCopy.textAlignment = Qt::AlignRight;
            return QWindowsVistaStyle::subElementRect(element, &optCopy, widget);
        }
        break;
#endif // QT_CONFIG(progressbar)
#if QT_CONFIG(toolbar)
    case SE_TabBarScrollLeftButton:
    case SE_TabBarScrollRightButton: {
        const bool isRightButton = element == SE_TabBarScrollRightButton;
        const bool vertical = option->rect.width() < option->rect.height();
        const int buttonWidth = proxy()->pixelMetric(PM_TabBarScrollButtonWidth, option, widget);

        if (vertical) {
            const int yOfs =
                    isRightButton ? option->rect.height() - buttonWidth : 0;
            const QSize sz(option->rect.width(), buttonWidth);
            const QPoint tl(option->rect.topLeft() + QPoint(0, yOfs));
            ret = QRect(tl, sz);
        } else {
            const int xOfs =
                    isRightButton ? option->rect.width() - buttonWidth : 0;
            const QSize sz(buttonWidth, option->rect.height());
            const QPoint tl(option->rect.topLeft() + QPoint(xOfs, 0));
            ret = QRect(tl, sz);
            ret = visualRect(widget->layoutDirection(), option->rect, ret);
        }
        break;
    }
    case SE_TabBarTearIndicatorLeft:
    case SE_TabBarTearIndicatorRight:
        if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
            const bool isRightButton = element == SE_TabBarTearIndicatorRight;
            const int buttonWidth =
                    proxy()->pixelMetric(PM_TabBarScrollButtonWidth, nullptr, widget);
            switch (tab->shape) {
            case QTabBar::RoundedNorth:
            case QTabBar::TriangularNorth:
            case QTabBar::RoundedSouth:
            case QTabBar::TriangularSouth: {
                const auto ofs = isRightButton
                        ? option->rect.width() - 2 - buttonWidth - contentItemHMargin
                        : 2 + buttonWidth + contentItemHMargin;
                const QPoint tl(tab->rect.topLeft() + QPoint(ofs, 0));
                ret = QRect(tl, QSize(1, option->rect.height()));
                break;
            }
            case QTabBar::RoundedWest:
            case QTabBar::TriangularWest:
            case QTabBar::RoundedEast:
            case QTabBar::TriangularEast: {
                const auto ofs = isRightButton
                        ? option->rect.height() - 2 - buttonWidth - contentItemHMargin
                        : 2 + buttonWidth + contentItemHMargin;
                const QPoint tl(tab->rect.topLeft() + QPoint(0, ofs));
                ret = QRect(tl, QSize(option->rect.width(), 1));
                break;
            }
            default:
                break;
            }
            ret = visualRect(option->direction, option->rect, ret);
        }
        break;
#endif // QT_CONFIG(toolbar)
    case SE_HeaderLabel: {
        const int margin = proxy()->pixelMetric(PM_HeaderMargin, option, widget);
        ret = option->rect.marginsRemoved({ margin, margin, margin, margin });
        break;
    }
    case SE_HeaderArrow: {
        ret = option->rect;
        if (const auto *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
            // the sort indicator is always show above in the win11 style
            if (header->sortIndicator != QStyleOptionHeader::None) {
                const int arrowSize = proxy()->pixelMetric(PM_HeaderMarkSize, option, widget);
                const int xCenter = ret.center().x();
                ret = QRect(xCenter - arrowSize / 2, ret.top(), arrowSize, arrowSize);
            }
        }
        break;
    }
    case SE_PushButtonContents: {
        int border = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
        ret = option->rect.marginsRemoved(QMargins(border, border, border, border));
        break;
    }
    default:
        ret = QWindowsVistaStyle::subElementRect(element, option, widget);
    }
    return ret;
}

/*!
 \internal
 */
QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
                                         SubControl subControl, const QWidget *widget) const
{
    QRect ret;

    switch (control) {
#if QT_CONFIG(spinbox)
    case CC_SpinBox:
        if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
            const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
            const int fw = spinbox->frame
                    ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
                    : 0;
            const int buttonHeight = hasButtons
                    ? qMin(spinbox->rect.height() - 3 * fw, spinbox->fontMetrics.height() * 5 / 4)
                    : 0;
            const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
            const int textFieldLength = spinbox->rect.width() - 2 * fw - 2 * buttonSize.width();
            const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
            switch (subControl) {
            case SC_SpinBoxUp:
            case SC_SpinBoxDown: {
                if (!hasButtons)
                    return QRect();
                const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonSize.height()) / 2;
                ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
                            buttonSize.height());
                if (subControl == SC_SpinBoxDown)
                    ret.moveRight(ret.right() + buttonSize.width());
                break;
            }
            case SC_SpinBoxEditField:
                ret = QRect(topLeft,
                            spinbox->rect.bottomRight() - QPoint(fw + 2 * buttonSize.width(), fw));
                break;
            case SC_SpinBoxFrame:
                ret = spinbox->rect;
            default:
                break;
            }
            ret = visualRect(spinbox->direction, spinbox->rect, ret);
        }
        break;
    case CC_TitleBar:
        if (const QStyleOptionTitleBar *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
            SubControl sc = subControl;
            ret = QCommonStyle::subControlRect(control, option, subControl, widget);
            static constexpr int indent = 3;
            static constexpr int controlWidthMargin = 2;
            const int controlHeight = titlebar->rect.height();
            const int controlWidth = 46;
            const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
            int offset = -(controlWidthMargin + indent);

            bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
            bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;

            switch (sc) {
            case SC_TitleBarLabel:
                if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
                    ret = titlebar->rect;
                    if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
                        ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
                    if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
                        ret.adjust(0, 0, -controlWidth, 0);
                    if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
                        ret.adjust(0, 0, -controlWidth, 0);
                    if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
                        ret.adjust(0, 0, -controlWidth, 0);
                    if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
                        ret.adjust(0, 0, -controlWidth, 0);
                }
                break;
            case SC_TitleBarContextHelpButton:
                if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
                    offset += controlWidth;
                Q_FALLTHROUGH();
            case SC_TitleBarMinButton:
                if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
                    offset += controlWidth;
                else if (sc == SC_TitleBarMinButton)
                    break;
                Q_FALLTHROUGH();
            case SC_TitleBarNormalButton:
                if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
                    offset += controlWidth;
                else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
                    offset += controlWidth;
                else if (sc == SC_TitleBarNormalButton)
                    break;
                Q_FALLTHROUGH();
            case SC_TitleBarMaxButton:
                if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
                    offset += controlWidth;
                else if (sc == SC_TitleBarMaxButton)
                    break;
                Q_FALLTHROUGH();
            case SC_TitleBarShadeButton:
                if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
                    offset += controlWidth;
                else if (sc == SC_TitleBarShadeButton)
                    break;
                Q_FALLTHROUGH();
            case SC_TitleBarUnshadeButton:
                if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
                    offset += controlWidth;
                else if (sc == SC_TitleBarUnshadeButton)
                    break;
                Q_FALLTHROUGH();
            case SC_TitleBarCloseButton:
                if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
                    offset += controlWidth;
                else if (sc == SC_TitleBarCloseButton)
                    break;
                ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
                            controlWidth, controlHeight);
                break;
            case SC_TitleBarSysMenu:
                if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
                    const auto yOfs = titlebar->rect.top() + (titlebar->rect.height() - iconSize) / 2;
                    ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, yOfs, iconSize,
                                iconSize);
                }
                break;
            default:
                break;
            }
            if (widget && isMinimized && titlebar->rect.width() < offset)
                const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
            ret = visualRect(titlebar->direction, titlebar->rect, ret);
        }
        break;
#endif // Qt_NO_SPINBOX
    case CC_ScrollBar:
    {
        ret = QCommonStyle::subControlRect(control, option, subControl, widget);

        if (subControl == SC_ScrollBarAddLine || subControl == SC_ScrollBarSubLine) {
            if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
                if (scrollbar->orientation == Qt::Vertical)
                    ret = ret.adjusted(2,2,-2,-3);
                else
                    ret = ret.adjusted(3,2,-2,-2);
            }
        }
        break;
    }
    case CC_ComboBox: {
        if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
            const auto indicatorWidth =
                    proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
            switch (subControl) {
            case SC_ComboBoxArrow: {
                const int fw =
                        cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
                const int buttonHeight =
                        qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
                const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
                const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
                const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
                const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
                ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
                            buttonSize.height());
                ret = visualRect(option->direction, option->rect, ret);
                break;
            }
            case SC_ComboBoxEditField: {
                ret = option->rect;
                if (cb->frame) {
                    const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
                    ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
                }
                ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
                ret = visualRect(option->direction, option->rect, ret);
                break;
            }
            default:
                ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
                break;
            }
        }
        break;
    }
#if QT_CONFIG(groupbox)
    case CC_GroupBox: {
        ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
        switch (subControl) {
        case SC_GroupBoxCheckBox:
            ret.moveTop(1);
            break;
        default:
            break;
        }
        break;
    }
#endif // QT_CONFIG(groupbox)
    default:
        ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
    }
    return ret;
}

/*!
 \internal
 */
QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *option,
                                           const QSize &size, const QWidget *widget) const
{
    QSize contentSize(size);

    switch (type) {

#if QT_CONFIG(menubar)
    case CT_MenuBarItem:
        if (!contentSize.isEmpty()) {
            constexpr int hMargin = 2 * 6;
            constexpr int hPadding = 2 * 11;
            constexpr int itemHeight = 32;
            contentSize.setWidth(contentSize.width() + hMargin + hPadding);
#if QT_CONFIG(tabwidget)
            if (widget->parent() && !qobject_cast<const QTabWidget *>(widget->parent()))
#endif
                contentSize.setHeight(itemHeight);
        }
        break;
#endif
#if QT_CONFIG(menu)
    case CT_MenuItem:
        if (const auto *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
            int width = size.width();
            int height;
            if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
                width = 10;
                height = 3;
            } else {
                height = menuItem->fontMetrics.height() + 8;
                if (!menuItem->icon.isNull()) {
                    int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
                    height = qMax(height,
                                  menuItem->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
                }
            }
            if (menuItem->text.contains(u'\t'))
                width += contentItemHMargin; // the text width is already in
            if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
                width += 2 * QWindowsStylePrivate::windowsArrowHMargin + contentItemHMargin;
            if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
                const QFontMetrics fm(menuItem->font);
                QFont fontBold = menuItem->font;
                fontBold.setBold(true);
                const QFontMetrics fmBold(fontBold);
                width += fmBold.horizontalAdvance(menuItem->text) - fm.horizontalAdvance(menuItem->text);
            }
            // in contrast to windowsvista, the checkmark and icon are drawn separately
            if (menuItem->menuHasCheckableItems) {
                const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
                width += checkMarkWidth + contentItemHMargin * 2;
            }
            // we have an icon and it's already in the given size, only add margins
            // 4 is added in qmenu.cpp to PM_SmallIconSize
            if (menuItem->maxIconWidth > 0)
                width += contentItemHMargin * 2 + menuItem->maxIconWidth - 4;
            width += 2 * 2; // margins for rounded border
            width += 2 * contentHMargin;
            if (width < 100)    // minimum size
                width = 100;
            contentSize = QSize(width, height);
        }
        break;
#endif // QT_CONFIG(menu)
#if QT_CONFIG(spinbox)
    case CT_SpinBox: {
        if (const auto *spinBoxOpt = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
            // Add button + frame widths
            const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
            const int margins = 8;
            const int buttonWidth = hasButtons ? 16 + contentItemHMargin : 0;
            const int frameWidth = spinBoxOpt->frame
                    ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
                    : 0;

            contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
        }
        break;
    }
#endif
#if QT_CONFIG(combobox)
    case CT_ComboBox:
        if (const auto *comboBoxOpt = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
            contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);  // don't rely on QWindowsThemeData
            contentSize += QSize(0, 4); // for the lineedit frame
            if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
                const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
                contentSize.rwidth() += w + contentItemHMargin;
            }
        }
        break;
#endif
    case CT_LineEdit: {
        if (qstyleoption_cast<const QStyleOptionFrame *>(option)) {
            contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget); // don't rely on QWindowsThemeData
            contentSize += QSize(0, 4); // for the lineedit frame
        }
        break;
    }
    case CT_HeaderSection:
        // windows vista does not honor the indicator (as it was drawn above the text, not on the
        // side) so call QWindowsStyle::styleHint directly to get the correct size hint
        contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
        break;
    case CT_RadioButton:
    case CT_CheckBox:
        if (const auto *buttonOpt = qstyleoption_cast<const QStyleOptionButton *>(option)) {
            const auto p = proxy();
            const bool isRadio = (type == CT_RadioButton);

            const int width = p->pixelMetric(
                    isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, option, widget);
            const int height = p->pixelMetric(
                    isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, option, widget);

            int margins = 2 * contentItemHMargin;
            if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
                margins += p->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
                                                  : PM_CheckBoxLabelSpacing,
                                          option, widget);
            }

            contentSize += QSize(width + margins, 4);
            contentSize.setHeight(qMax(size.height(), height + 2 * contentItemHMargin));
        }
        break;

        // the indicator needs 2px more in width when there is no text, not needed when
        // the style draws the text
        contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
        if (size.width() == 0)
            contentSize.rwidth() += 2;
        break;
    case CT_PushButton: {
        contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
        // we want our own horizontal spacing
        const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
        contentSize.rwidth() += 2 * contentHMargin - oldMargin;
        break;
    }
    case CT_ToolButton: {
        contentSize = size;
        if (const auto tb = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
            // no separate menu, only dropdown icon
            if (!tb->subControls.testFlag(SC_ToolButtonMenu)) {
                if (tb->features.testFlag(QStyleOptionToolButton::HasMenu))
                    contentSize.rwidth() += 2;
            }
            if (tb->toolButtonStyle == Qt::ToolButtonTextBesideIcon
                || tb->toolButtonStyle == Qt::ToolButtonIconOnly) {
                contentSize.rheight() = qMax(contentSize.height(), tb->iconSize.height() + 4);
            }
        }
        const auto fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
        contentSize += QSize(contentHMargin + 2 * fw, 2 * fw);
        break;
    }
    case CT_ItemViewItem: {
        if (const auto *viewItemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
            if (const QListView *lv = qobject_cast<const QListView *>(widget);
                lv && lv->viewMode() != QListView::IconMode) {
                QStyleOptionViewItem vOpt(*viewItemOpt);
                // viewItemSize only takes PM_FocusFrameHMargin into account but no additional
                // margin, therefore adjust it here for a correct width during layouting when
                // WrapText is enabled
                vOpt.rect.setRight(vOpt.rect.right() - contentHMargin);
                contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget);
                contentSize.rwidth() += contentHMargin;
                contentSize.rheight() += 2 * contentHMargin;

            } else {
                contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
            }
        }
        break;
    }
    default:
        contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
        break;
    }

    return contentSize;
}


/*!
 \internal
 */
int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
    Q_D(const QWindows11Style);
    int res = 0;

    switch (metric) {
    case QStyle::PM_IndicatorWidth:
    case QStyle::PM_IndicatorHeight:
    case QStyle::PM_ExclusiveIndicatorWidth:
    case QStyle::PM_ExclusiveIndicatorHeight:
        res = 16;
        break;
    case PM_SliderThickness:        // full height of a slider
        if (auto opt = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
            // hard-coded in qslider.cpp, but we need a little bit more
            constexpr auto TickSpace = 5;
            if (opt->tickPosition & QSlider::TicksAbove)
                res += 6 - TickSpace;
            if (opt->tickPosition & QSlider::TicksBelow)
                res += 6 - TickSpace;
        }
        Q_FALLTHROUGH();
    case PM_SliderControlThickness: // size of the control handle
    case PM_SliderLength:           // same because handle is a circle with r=8
        res += 2 * 8;
        break;
    case PM_RadioButtonLabelSpacing:
    case PM_CheckBoxLabelSpacing:
        res = 2 * contentItemHMargin;
        break;
    case QStyle::PM_TitleBarButtonIconSize:
        res = 16;
        break;
    case QStyle::PM_TitleBarButtonSize:
        res = 32;
        break;
#if QT_CONFIG(toolbar)
    case PM_TabBarScrollButtonWidth:
        res = 16 + contentItemHMargin;
        break;
    case PM_ToolBarExtensionExtent:
        res = int(QStyleHelper::dpiScaled(32., option));
        break;
    case PM_ToolBarHandleExtent:
        res = int(QStyleHelper::dpiScaled(8., option));
        break;
#endif // QT_CONFIG(toolbar)
    case QStyle::PM_ScrollBarExtent:
        res = 12;
        break;
    case QStyle::PM_SubMenuOverlap:
        res = -1;
        break;
    case PM_MenuButtonIndicator: {
        res = contentItemHMargin;
        if (widget) {
            const int fontSize = widget->font().pointSize();
            auto it = m_fontPoint2ChevronDownMedWidth.find(fontSize);
            if (it == m_fontPoint2ChevronDownMedWidth.end()) {
                QFont f(d->assetFont);
                f.setPointSize(qRound(fontSize * 0.9f)); // a little bit smaller
                QFontMetrics fm(f);
                const auto width = fm.horizontalAdvance(fluentIcon(Icon::ChevronDownMed));
                m_fontPoint2ChevronDownMedWidth.insert(fontSize, width);
                res += width;
            } else {
                res += it.value();
            }
        } else {
            res += 12;
        }
        break;
    }
    case PM_ComboBoxFrameWidth:
    case PM_SpinBoxFrameWidth:
    case PM_DefaultFrameWidth:
        res = 2;
        break;
    case PM_ButtonShiftHorizontal:
    case PM_ButtonShiftVertical:
    case PM_TabBarTabShiftHorizontal:
    case PM_TabBarTabShiftVertical:
    case PM_TabBarBaseOverlap:
    case PM_TabBarBaseHeight:
        res = 0;
        break;
    case PM_TreeViewIndentation:
        res = 30;
        break;
    case PM_ProgressBarChunkWidth:
        res = 0;    // no chunks on windows11
        break;
    case PM_HeaderMarkSize:
        res = 6;
        break;
    default:
        res = QWindowsVistaStyle::pixelMetric(metric, option, widget);
    }

    return res;
}

void QWindows11Style::polish(QWidget* widget)
{
    Q_D(QWindows11Style);

#if QT_CONFIG(commandlinkbutton)
    if (!qobject_cast<QCommandLinkButton *>(widget))
#endif // QT_CONFIG(commandlinkbutton)
        QWindowsVistaStyle::polish(widget);

    const bool isScrollBar = qobject_cast<QScrollBar *>(widget);
    const auto comboBoxContainer = qobject_cast<const QComboBoxPrivateContainer *>(widget);
    const auto isComboBoxContainer = !d->nativeRoundedTopLevelWindows && comboBoxContainer != nullptr;
    const auto isMenu = !d->nativeRoundedTopLevelWindows && qobject_cast<QMenu *>(widget) != nullptr;

#if QT_CONFIG(menubar)
    if (qobject_cast<QMenuBar *>(widget)) {
        constexpr int itemHeight = 32;
        if (widget->maximumHeight() < itemHeight) {
            widget->setProperty("_q_original_menubar_maxheight", widget->maximumHeight());
            widget->setMaximumHeight(itemHeight);
        }
    }
#endif
    if (comboBoxContainer && d->nativeRoundedTopLevelWindows) {
        auto view = comboBoxContainer->itemView();
        if (view && view->viewport())
            view->viewport()->setAutoFillBackground(false);
    }
    if (isScrollBar || isMenu || isComboBoxContainer) {
        bool wasCreated = widget->testAttribute(Qt::WA_WState_Created);
        bool layoutDirection = widget->testAttribute(Qt::WA_RightToLeft);
        widget->setAttribute(Qt::WA_OpaquePaintEvent,false);
        widget->setAttribute(Qt::WA_TranslucentBackground);
        if (!isScrollBar)
            widget->setWindowFlag(Qt::FramelessWindowHint);
        widget->setWindowFlag(Qt::NoDropShadowWindowHint);
        widget->setAttribute(Qt::WA_RightToLeft, layoutDirection);
        widget->setAttribute(Qt::WA_WState_Created, wasCreated);
        if (!isScrollBar) {
            bool inGraphicsView = widget->graphicsProxyWidget() != nullptr;
            if (!inGraphicsView && comboBoxContainer && comboBoxContainer->parentWidget())
                inGraphicsView = comboBoxContainer->parentWidget()->graphicsProxyWidget() != nullptr;
            if (!inGraphicsView) { // for menus and combobox containers...
                QGraphicsDropShadowEffect *dropshadow = new QGraphicsDropShadowEffect(widget);
                dropshadow->setBlurRadius(3);
                dropshadow->setXOffset(3);
                dropshadow->setYOffset(3);
                widget->setGraphicsEffect(dropshadow);
            }
        }
    } else if (QComboBox* cb = qobject_cast<QComboBox*>(widget)) {
        if (cb->isEditable()) {
            QLineEdit *le = cb->lineEdit();
            le->setFrame(false);
        }
    } else if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
               scrollarea
               && !qobject_cast<QGraphicsView *>(widget)
#if QT_CONFIG(mdiarea)
               && !qobject_cast<QMdiArea *>(widget)
#endif
        ) {
        if (scrollarea->frameShape() == QFrame::StyledPanel) {
            const auto vp = scrollarea->viewport();
            const bool isAutoFillBackground = vp->autoFillBackground();
            const bool isStyledBackground = vp->testAttribute(Qt::WA_StyledBackground);
            vp->setProperty("_q_original_autofill_background", isAutoFillBackground);
            vp->setProperty("_q_original_styled_background", isStyledBackground);
            vp->setAutoFillBackground(false);
            vp->setAttribute(Qt::WA_StyledBackground, true);
        }
        // QTreeView & QListView are already set in the base windowsvista style
        if (auto table = qobject_cast<QTableView *>(widget))
            table->viewport()->setAttribute(Qt::WA_Hover, true);
    }
}

void QWindows11Style::unpolish(QWidget *widget)
{
    Q_D(QWindows11Style);
#if QT_CONFIG(commandlinkbutton)
    if (!qobject_cast<QCommandLinkButton *>(widget))
#endif // QT_CONFIG(commandlinkbutton)
        QWindowsVistaStyle::unpolish(widget);

#if QT_CONFIG(menubar)
    if (qobject_cast<QMenuBar *>(widget) && !widget->property("_q_original_menubar_maxheight").isNull()) {
        widget->setMaximumHeight(widget->property("_q_original_menubar_maxheight").toInt());
        widget->setProperty("_q_original_menubar_maxheight", QVariant());
    }
#endif
    const bool isScrollBar = qobject_cast<QScrollBar *>(widget);
    const auto comboBoxContainer = qobject_cast<const QComboBoxPrivateContainer *>(widget);
    const auto isComboBoxContainer = !d->nativeRoundedTopLevelWindows && comboBoxContainer != nullptr;
    const auto isMenu = !d->nativeRoundedTopLevelWindows && qobject_cast<QMenu *>(widget) != nullptr;

    if (comboBoxContainer && d->nativeRoundedTopLevelWindows) {
        auto view = comboBoxContainer->itemView();
        // see QAbstractScrollAreaPrivate::init()
        if (view && view->viewport())
            view->viewport()->setAutoFillBackground(true);
    }
    if (isScrollBar || isMenu || isComboBoxContainer) {
        widget->setAttribute(Qt::WA_OpaquePaintEvent, true);
        widget->setAttribute(Qt::WA_TranslucentBackground, false);
        widget->setWindowFlag(Qt::FramelessWindowHint, false);
        widget->setWindowFlag(Qt::NoDropShadowWindowHint, false);
    }

    if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
        scrollarea
#if QT_CONFIG(mdiarea)
        && !qobject_cast<QMdiArea *>(widget)
#endif
        ) {
        const auto vp = scrollarea->viewport();
        const auto wasAutoFillBackground = vp->property("_q_original_autofill_background").toBool();
        vp->setAutoFillBackground(wasAutoFillBackground);
        vp->setProperty("_q_original_autofill_background", QVariant());
        const auto origStyledBackground = vp->property("_q_original_styled_background").toBool();
        vp->setAttribute(Qt::WA_StyledBackground, origStyledBackground);
        vp->setProperty("_q_original_styled_background", QVariant());
    }
    dwmSetWindowCornerPreference(widget, false);
}

void QWindows11Style::polish(QApplication *app)
{
    Q_D(const QWindows11Style);
    if (d->nativeRoundedTopLevelWindows)
        app->installEventFilter(this);
    QWindowsVistaStyle::polish(app);
}

void QWindows11Style::unpolish(QApplication *app)
{
    Q_D(const QWindows11Style);
    if (d->nativeRoundedTopLevelWindows)
        app->removeEventFilter(this);
    QWindowsVistaStyle::unpolish(app);
}

bool QWindows11Style::eventFilter(QObject *obj, QEvent *event)
{
    // QEvent::WinIdChange is to early so we have to wait for QEvent::Show
    if (event->type() == QEvent::Show)
        dwmSetWindowCornerPreference(qobject_cast<QWidget *>(obj), true);
    return QWindowsVistaStyle::eventFilter(obj, event);
}

void QWindows11Style::dwmSetWindowCornerPreference(const QWidget *widget, bool bSet) const
{
    Q_D(const QWindows11Style);
    if (!d->nativeRoundedTopLevelWindows)
        return;
#ifdef Q_CC_MSVC
    static constexpr auto dmwmaWindowCornerPreference = DWMWA_WINDOW_CORNER_PREFERENCE;
    static constexpr auto dwmcpRound = DWMWCP_ROUND;
    static constexpr auto dwmcpRoundSmall = DWMWCP_ROUNDSMALL;
    static constexpr auto dwmcpDefault = DWMWCP_DEFAULT;
#else
    // MinGW 13.1.0 does not provide this
    static constexpr auto dmwmaWindowCornerPreference = 33;
    static constexpr auto dwmcpRound = 2;
    static constexpr auto dwmcpRoundSmall = 3;
    static constexpr auto dwmcpDefault = 0;
#endif
    if (widget && widget->isWindow() && widget->testAttribute(Qt::WA_WState_Created)
        && !widget->windowFlags().testFlag(Qt::FramelessWindowHint)) {
        const auto window = widget->windowHandle();
        if (window && window->handle()) {
            const auto wId = reinterpret_cast<HWND>(widget->winId());
            if (wId != 0) {
                const bool isToolTip =
#if QT_CONFIG(tooltip)
                        qobject_cast<const QTipLabel *>(widget) != nullptr;
#else
                        false;
#endif
                uint32_t pref = bSet ? (isToolTip ? dwmcpRoundSmall : dwmcpRound) : dwmcpDefault;
                DwmSetWindowAttribute(wId, dmwmaWindowCornerPreference, &pref, sizeof(pref));
            }
        }
    }
}

/*
The colors for Windows 11 are taken from the official WinUI3 Figma style at
https://www.figma.com/community/file/1159947337437047524
*/
#define SET_IF_UNRESOLVED(GROUP, ROLE, VALUE) \
    if (!result.isBrushSet(QPalette::Inactive, ROLE) || styleSheetChanged) \
        result.setColor(GROUP, ROLE, VALUE)

static void populateLightSystemBasePalette(QPalette &result)
{
    static QString oldStyleSheet;
    const bool styleSheetChanged = oldStyleSheet != qApp->styleSheet();

    constexpr QColor textColor = QColor(0x00,0x00,0x00,0xE4);
    constexpr QColor textDisabled = QColor(0x00, 0x00, 0x00, 0x5C);
    constexpr QColor btnFace = QColor(0xFF, 0xFF, 0xFF, 0xB3);
    constexpr QColor base = QColor(0xFF, 0xFF, 0xFF, 0xFF);
    constexpr QColor alternateBase = QColor(0x00, 0x00, 0x00, 0x09);
    const QColor btnHighlight = result.accent().color();
    const QColor btnColor = result.button().color();

    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Highlight, btnHighlight);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::WindowText, textColor);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Button, btnFace);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Light, btnColor.lighter(150));
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Dark, btnColor.darker(200));
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Mid, btnColor.darker(150));
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Text, textColor);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::BrightText, btnHighlight);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Base, base);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF));
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::ButtonText, textColor);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Midlight, btnColor.lighter(125));
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::Shadow, Qt::black);
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::ToolTipBase, result.window().color());
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::ToolTipText, result.windowText().color());
    SET_IF_UNRESOLVED(QPalette::Active, QPalette::AlternateBase, alternateBase);

    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Highlight, btnHighlight);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::WindowText, textColor);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Button, btnFace);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Light, btnColor.lighter(150));
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Dark, btnColor.darker(200));
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Mid, btnColor.darker(150));
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Text, textColor);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::BrightText, btnHighlight);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Base, base);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF));
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::ButtonText, textColor);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Midlight, btnColor.lighter(125));
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Shadow, Qt::black);
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::ToolTipBase, result.window().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::ToolTipText, result.windowText().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::AlternateBase, alternateBase);

    result.setColor(QPalette::Disabled, QPalette::WindowText, textDisabled);

    if (result.midlight() == result.button())
        result.setColor(QPalette::Midlight, btnColor.lighter(110));
    oldStyleSheet = qApp->styleSheet();
}

static void populateDarkSystemBasePalette(QPalette &result)
{
    static QString oldStyleSheet;
    const bool styleSheetChanged = oldStyleSheet != qApp->styleSheet();

    constexpr QColor alternateBase = QColor(0xFF, 0xFF, 0xFF, 0x0F);

    SET_IF_UNRESOLVED(QPalette::Active, QPalette::AlternateBase, alternateBase);

    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::AlternateBase, alternateBase);

    oldStyleSheet = qApp->styleSheet();
}

/*!
 \internal
 */
void QWindows11Style::polish(QPalette& result)
{
    highContrastTheme = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Unknown;
    colorSchemeIndex = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;

    if (!highContrastTheme && colorSchemeIndex == 0)
        populateLightSystemBasePalette(result);
    else if (!highContrastTheme && colorSchemeIndex == 1)
        populateDarkSystemBasePalette(result);

    const bool styleSheetChanged = false; // so the macro works

    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Button, result.button().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Window, result.window().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Light, result.light().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Dark, result.dark().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Accent, result.accent().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Highlight, result.highlight().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::HighlightedText, result.highlightedText().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Text, result.text().color());
    SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::WindowText, result.windowText().color());

    auto *d = const_cast<QWindows11StylePrivate *>(d_func());
    d->m_standardIcons.clear();
}

QPixmap QWindows11Style::standardPixmap(StandardPixmap standardPixmap,
                                        const QStyleOption *option,
                                        const QWidget *widget) const
{
    switch (standardPixmap) {
    case SP_TabScrollLeftButton:
    case SP_TabScrollRightButton:
    case SP_TabScrollUpButton:
    case SP_TabScrollDownButton:
    case SP_ToolBarHorizontalExtensionButton:
    case SP_ToolBarVerticalExtensionButton: {
        const int size = proxy()->pixelMetric(PM_ToolBarExtensionExtent, option, widget);
        return standardIcon(standardPixmap, option, widget).pixmap(size);
    }
    default:
        break;
    }
    return QWindowsVistaStyle::standardPixmap(standardPixmap, option, widget);
}

QIcon QWindows11Style::standardIcon(StandardPixmap standardIcon,
                                    const QStyleOption *option,
                                    const QWidget *widget) const
{
    const auto getIcon = [&](Icon ico, double scale) {
        auto *d = const_cast<QWindows11StylePrivate *>(d_func());
        QIcon &icon = d->m_standardIcons[ico];
        if (icon.isNull()) {
            auto engine = new WinFontIconEngine(fluentIcon(ico), d->assetFont);
            engine->setScale(scale);
            icon = QIcon(engine);
        }
        return icon;
    };

    switch (standardIcon) {
    case SP_TitleBarMinButton:
        return getIcon(Icon::ChromeMinimize, 0.7);
    case SP_TitleBarMaxButton:
        return getIcon(Icon::ChromeMaximize, 0.7);
    case SP_TitleBarCloseButton:
        return getIcon(Icon::ChromeClose, 0.7);
    case SP_TitleBarNormalButton:
        return getIcon(Icon::ChromeRestore, 0.7);
    case SP_LineEditClearButton:
        return getIcon(Icon::Clear, 0.7);
    case SP_ToolBarHorizontalExtensionButton:
    case SP_ToolBarVerticalExtensionButton:
        return getIcon(Icon::More, 1.0);
    case SP_TabCloseButton:
        return getIcon(Icon::ChromeClose, 0.6);
    case SP_TabScrollLeftButton:
        return getIcon(Icon::CaretLeftSolid8, 0.5);
    case SP_TabScrollRightButton:
        return getIcon(Icon::CaretRightSolid8, 0.5);
    case SP_TabScrollUpButton:
        return getIcon(Icon::CaretUpSolid8, 0.5);
    case SP_TabScrollDownButton:
        return getIcon(Icon::CaretDownSolid8, 0.5);
    case SP_ArrowUp:
        return getIcon(Icon::ChevronUpMed, 1.0);
    case SP_ArrowDown:
        return getIcon(Icon::ChevronDownMed, 1.0);
    case SP_ArrowLeft:
        return getIcon(Icon::ChevronLeftMed, 1.0);
    case SP_ArrowRight:
        return getIcon(Icon::ChevronRightMed, 1.0);
    default:
        break;
    }
    return QWindowsVistaStyle::standardIcon(standardIcon, option, widget);
}

QPixmap QWindows11Style::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
                                             const QStyleOption *option) const
{
    if (iconMode == QIcon::Disabled)
        return QWindowsVistaStyle::generatedIconPixmap(iconMode, pixmap, option);
    return pixmap;
}


QColor QWindows11Style::calculateAccentColor(const QStyleOption *option) const
{
    using namespace StyleOptionHelper;
    if (isDisabled(option))
        return winUI3Color(fillAccentDisabled);
    const auto alphaColor = isPressed(option) ? fillAccentTertiary
                                              : isHover(option) ? fillAccentSecondary
                                                                : fillAccentDefault;
    const auto alpha = winUI3Color(alphaColor);
    QColor col = option->palette.accent().color();
    col.setAlpha(alpha.alpha());
    return col;
}

QPen QWindows11Style::borderPenControlAlt(const QStyleOption *option) const
{
    using namespace StyleOptionHelper;
    if (isChecked(option))
        return Qt::NoPen;   // same color as fill color, so no pen needed
    if (highContrastTheme)
        return option->palette.buttonText().color();
    if (isDisabled(option) || isPressed(option))
        return winUI3Color(frameColorStrongDisabled);
    return winUI3Color(frameColorStrong);
}

QBrush QWindows11Style::controlFillBrush(const QStyleOption *option, ControlType controlType) const
{
    using namespace StyleOptionHelper;
    static constexpr WINUI3Color colorEnums[2][4] = {
        // Light & Dark Control
        { fillControlDefault, fillControlSecondary,
          fillControlTertiary, fillControlDisabled },
        // Light & Dark Control Alt
        { fillControlAltSecondary, fillControlAltTertiary,
          fillControlAltQuarternary, fillControlAltDisabled },
    };

    if (option->palette.isBrushSet(QPalette::Current, QPalette::Button))
        return option->palette.brush(QPalette::Current, QPalette::Button);

    if (!isChecked(option) && isAutoRaise(option))
        return Qt::NoBrush;

    // checked is the same for Control (Buttons) and Control Alt (Radiobuttons/Checkboxes)
    if (isChecked(option))
        return calculateAccentColor(option);

    const auto state = calcControlState(option);
    return winUI3Color(colorEnums[int(controlType)][int(state)]);
}

QBrush QWindows11Style::inputFillBrush(const QStyleOption *option, const QWidget *widget) const
{
    // slightly different states than in controlFillBrush
    using namespace StyleOptionHelper;
    const auto role = widget ? widget->backgroundRole() : QPalette::Window;
    if (option->palette.isBrushSet(QPalette::Current, role))
        return option->palette.brush(QPalette::Current, role);

    if (isDisabled(option))
        return winUI3Color(fillControlDisabled);
    if (hasFocus(option))
        return winUI3Color(fillControlInputActive);
    if (isHover(option))
        return winUI3Color(fillControlSecondary);
    return winUI3Color(fillControlDefault);
}

QColor QWindows11Style::controlTextColor(const QStyleOption *option, bool ignoreIsChecked) const
{
    using namespace StyleOptionHelper;
    static constexpr WINUI3Color colorEnums[2][4] = {
        // Control, unchecked
        { textPrimary, textPrimary, textSecondary, textDisabled },
        // Control, checked
        { textOnAccentPrimary, textOnAccentPrimary, textOnAccentSecondary, textOnAccentDisabled },
    };

    if (option->palette.isBrushSet(QPalette::Current, QPalette::ButtonText))
        return option->palette.color(QPalette::Current, QPalette::ButtonText);

    const int colorIndex = !ignoreIsChecked && isChecked(option) ? 1 : 0;
    const auto state = calcControlState(option);
    return winUI3Color(colorEnums[colorIndex][int(state)]);
}

void QWindows11Style::drawLineEditFrame(QPainter *p, const QRectF &rect, const QStyleOption *o, bool isEditable) const
{
    const bool isHovered = o->state & State_MouseOver;
    const auto frameCol = highContrastTheme
            ? o->palette.color(isHovered ? QPalette::Accent
                                         : QPalette::ButtonText)
            : winUI3Color(frameColorLight);
    drawRoundedRect(p, rect, frameCol, Qt::NoBrush);

    if (!isEditable || StyleOptionHelper::isDisabled(o))
        return;

    const bool hasFocus = o->state & State_HasFocus;
    const auto underlineCol = hasFocus
            ? o->palette.color(QPalette::Accent)
            : colorSchemeIndex == 0 ? QColor(0x80, 0x80, 0x80)
                                    : QColor(0xa0, 0xa0, 0xa0);
    QPainterStateGuard psg(p);
    if (hasFocus) {
        p->setClipRect(rect.marginsRemoved(QMarginsF(0, rect.height() - 1.5, 0, -1)));
        const QRectF r(rect.top(), rect.left(), rect.width(), rect.height() - 1);
        drawRoundedRect(p, r, QPen(underlineCol, 2), Qt::NoBrush);
    } else {
        p->setClipRect(rect.marginsRemoved(QMarginsF(0, rect.height() - 0.5, 0, -1)));
        drawRoundedRect(p, rect, underlineCol, Qt::NoBrush);
    }
}

QColor QWindows11Style::winUI3Color(enum WINUI3Color col) const
{
    return WINUI3Colors[colorSchemeIndex][col];
}

#undef SET_IF_UNRESOLVED

QT_END_NAMESPACE
