diff options
author | Christian Ehrlicher <[email protected]> | 2025-06-21 22:51:27 +0200 |
---|---|---|
committer | Christian Ehrlicher <[email protected]> | 2025-06-27 16:50:31 +0200 |
commit | b335784c25600cf7df20e67f45d0ab315e0a02b3 (patch) | |
tree | 6281150069a424c6f833086528f09fd6b6e4f544 | |
parent | 513f5a9b8a6855c3c8b6ff8a45fd219c6240bc21 (diff) |
Windows11Style: fix/cleanup QLineEdit/SpinBox/ComboBox painting
Fix style issues:
- paint lineedit indicator more like windows 11
- don't draw frame when not requested
- use same height for all three widget types when no frame is painted
Also cleanup the code:
- move frame painting into own function (drawLineEditFrame()) for all
three widgets
- sync the painting of the other paintings as it can not be merged into
one function due to PE_FrameLineEdit
- use helper functions drawRoundedRect() and winUI3Color() to avoid
code repetitions
Pick-to: 6.10
Fixes: QTBUG-137403
Change-Id: I50e6fc16f13e0c043965d1bbe9406e61dff4dac7
Reviewed-by: Volker Hilsheimer <[email protected]>
-rw-r--r-- | src/plugins/styles/modernwindows/qwindows11style.cpp | 172 | ||||
-rw-r--r-- | src/plugins/styles/modernwindows/qwindows11style_p.h | 25 |
2 files changed, 88 insertions, 109 deletions
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index ab6a636959f..c65a6222b9f 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -38,27 +38,13 @@ QT_BEGIN_NAMESPACE 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 - -enum WINUI3Color { - subtleHighlightColor, //Subtle highlight based on alpha used for hovered elements - subtlePressedColor, //Subtle highlight based on alpha used for pressed elements - frameColorLight, //Color of frame around flyouts and controls except for Checkbox and Radiobutton - frameColorStrong, //Color of frame around Checkbox and Radiobuttons - controlStrongFill, //Color of controls with strong filling such as the right side of a slider - controlStrokeSecondary, - controlStrokePrimary, - controlFillTertiary, //Color of filled sunken controls - controlFillSecondary, //Color of filled hovered controls - menuPanelFill, //Color of menu panel - textOnAccentPrimary, //Color of text on controls filled in accent color - textOnAccentSecondary, //Color of text of sunken controls in accent color - controlTextSecondary, //Color of text of sunken controls - controlStrokeOnAccentSecondary, //Color of frame around Buttons in accent color - controlFillSolid, //Color for solid fill - surfaceStroke, //Color of MDI window frames - controlAccentDisabled, - textAccentDisabled -}; +template <typename R, typename P, typename B> +static inline void drawRoundedRect(QPainter *p, R &&rect, P &&pen, B &&brush) +{ + p->setPen(pen); + p->setBrush(brush); + p->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius); +} static const QColor WINUI3ColorsLight [] { QColor(0x00,0x00,0x00,0x09), //subtleHighlightColor @@ -253,42 +239,24 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt QCachedPainter cp(painter, QLatin1StringView("win11_spinbox") % HexString<uint8_t>(colorSchemeIndex), sb, sb->rect.size()); if (cp.needsPainting()) { - if (sb->frame && (sub & SC_SpinBoxFrame)) { - const qreal sublineOffset = secondLevelRoundingRadius + 2.0; - cp->save(); - cp->setClipRect(option->rect.adjusted(-2, -2, 2, 2)); - cp->setPen(editSublineColor(option, colorSchemeIndex)); - cp->drawLine(option->rect.bottomLeft() + QPointF(sublineOffset, 0.5), - option->rect.bottomRight() + QPointF(-sublineOffset, 0.5)); - cp->restore(); - } - const QRectF frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); - cp->setBrush(option->palette.brush(QPalette::Base)); - cp->setPen(highContrastTheme == true ? sb->palette.buttonText().color() - : WINUI3Colors[colorSchemeIndex][frameColorLight]); - cp->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius); - const QPoint mousePos = widget ? widget->mapFromGlobal(QCursor::pos()) : QPoint(); - if (sub & SC_SpinBoxEditField) { - const QRect rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxEditField, - widget).adjusted(0, 0, 0, 1); - if (!(state & State_HasFocus) && rect.contains(mousePos)) { - cp->setPen(Qt::NoPen); - cp->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]); - cp->drawRoundedRect(option->rect.adjusted(2, 2, -2, -2), secondLevelRoundingRadius, - secondLevelRoundingRadius); - } - } + const auto frameRect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); + drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, option->palette.brush(QPalette::Base)); + + if (sb->frame && (sub & SC_SpinBoxFrame)) + drawLineEditFrame(cp.painter(), option); + + const bool isMouseOver = state & State_MouseOver; + const bool hasFocus = state & State_HasFocus; + if (isMouseOver && !hasFocus && !highContrastTheme) + drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, winUI3Color(subtleHighlightColor)); + const auto drawUpDown = [&](QStyle::SubControl sc) { const bool isUp = sc == SC_SpinBoxUp; - QRect rect = proxy()->subControlRect(CC_SpinBox, option, isUp ? SC_SpinBoxUp : SC_SpinBoxDown, widget); - if (isUp) - rect.adjust(0, 0, 0, 1); - if (rect.contains(mousePos)) { - cp->setPen(Qt::NoPen); - cp->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]); - cp->drawRoundedRect(rect.adjusted(1, 1, -1, -1), secondLevelRoundingRadius, - secondLevelRoundingRadius); - } + const QRect rect = proxy()->subControlRect(CC_SpinBox, option, sc, widget); + if (sb->activeSubControls & sc) + drawRoundedRect(cp.painter(), rect.adjusted(1, 1, -1, -2), Qt::NoPen, + winUI3Color(subtleHighlightColor)); + cp->setFont(assetFont); cp->setPen(sb->palette.buttonText().color()); cp->setBrush(Qt::NoBrush); @@ -441,36 +409,23 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt #if QT_CONFIG(combobox) case CC_ComboBox: if (const QStyleOptionComboBox *combobox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { - QRectF rect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); - painter->setBrush(combobox->palette.brush(QPalette::Base)); - painter->setPen(Qt::NoPen); - painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius); + const auto frameRect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); + drawRoundedRect(painter, frameRect, Qt::NoPen, option->palette.brush(QPalette::Base)); - const bool comboboxHovered = state & State_MouseOver; - // In case the QComboBox is hovered overdraw the background with a alpha mask to - // highlight the QComboBox. - if (comboboxHovered && !highContrastTheme) { - painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]); - painter->setPen(Qt::NoPen); - painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius); - } + if (combobox->frame) + drawLineEditFrame(painter, option); + + const bool isMouseOver = state & State_MouseOver; + const bool hasFocus = state & State_HasFocus; + if (isMouseOver && !hasFocus && !highContrastTheme) + drawRoundedRect(painter, frameRect, Qt::NoPen, winUI3Color(subtleHighlightColor)); - rect.adjust(0.5,0.5,-0.5,-0.5); - painter->setBrush(Qt::NoBrush); - painter->setPen(highContrastTheme ? (comboboxHovered ? combobox->palette.accent().color() : combobox->palette.buttonText().color()) : WINUI3Colors[colorSchemeIndex][frameColorLight]); - painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius); if (sub & SC_ComboBoxArrow) { QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget).adjusted(4, 0, -4, 1); painter->setFont(assetFont); painter->setPen(combobox->palette.text().color()); painter->drawText(rect, QStringLiteral(u"\uE70D"), Qt::AlignVCenter | Qt::AlignHCenter); } - - if (combobox->editable) { - const qreal sublineOffset = secondLevelRoundingRadius; - painter->setPen(editSublineColor(option, colorSchemeIndex)); - painter->drawLine(rect.bottomLeft() + QPointF(sublineOffset, 1.0), rect.bottomRight() + QPointF(-sublineOffset, 1.0)); - } } break; #endif // QT_CONFIG(combobox) @@ -951,36 +906,21 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption break; } case PE_PanelLineEdit: - if (widget && widget->objectName() == QStringLiteral(u"qt_spinbox_lineedit")) - break; if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) { - QRectF frameRect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); - painter->setBrush(option->palette.brush(QPalette::Base)); - painter->setPen(Qt::NoPen); - painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius); - // In case the QLineEdit is hovered overdraw the background with a alpha mask to - // highlight the QLineEdit. - if (state & State_MouseOver && !(state & State_HasFocus)) { - painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]); - painter->setPen(Qt::NoPen); - painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius); - } + const auto frameRect = option->rect.marginsRemoved(QMargins(1, 1, 1, 1)); + drawRoundedRect(painter, frameRect, Qt::NoPen, option->palette.brush(QPalette::Base)); + if (panel->lineWidth > 0) proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget); + + const bool isMouseOver = state & State_MouseOver; + const bool hasFocus = state & State_HasFocus; + if (isMouseOver && !hasFocus && !highContrastTheme) + drawRoundedRect(painter, frameRect, Qt::NoPen, winUI3Color(subtleHighlightColor)); } break; - case PE_FrameLineEdit: { - const qreal sublineOffset = secondLevelRoundingRadius + 1.5; - if (widget && widget->parent() && qobject_cast<QComboBox*>(widget->parent())) - break; - QRectF rect = option->rect; - rect.adjust(1.5, 1.5, -1.5, -1.5); - painter->setBrush(Qt::NoBrush); - painter->setPen(highContrastTheme == true ? option->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]); - painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius); - painter->setPen(editSublineColor(option, colorSchemeIndex)); - painter->drawLine(option->rect.bottomLeft() + QPointF(sublineOffset, 0.5), option->rect.bottomRight() + QPointF(-sublineOffset, 0.5)); - } + case PE_FrameLineEdit: + drawLineEditFrame(painter, option); break; case PE_Frame: { if (const auto *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) { @@ -2442,12 +2382,30 @@ QColor QWindows11Style::buttonLabelColor(const QStyleOption *option, int colorSc : option->palette.buttonText().color(); } -QColor QWindows11Style::editSublineColor(const QStyleOption *option, int colorSchemeIndex) +void QWindows11Style::drawLineEditFrame(QPainter *p, const QStyleOption *o) const +{ + const auto rect = QRectF(o->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5)); + 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); + + QPainterStateGuard psg(p); + p->setClipRect(rect.marginsRemoved(QMarginsF(0, rect.height() - 0.5, 0, -1))); + 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); + const auto penUnderline = QPen(underlineCol, hasFocus ? 2 : 1); + drawRoundedRect(p, rect, penUnderline, Qt::NoBrush); +} + +QColor QWindows11Style::winUI3Color(enum WINUI3Color col) const { - const State state = option->state; - return state & State_HasFocus ? option->palette.accent().color() - : (colorSchemeIndex == 0 ? QColor(0x80, 0x80, 0x80) - : QColor(0xa0, 0xa0, 0xa0)); + return WINUI3Colors[colorSchemeIndex][col]; } #undef SET_IF_UNRESOLVED diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h index 1be56fe3aa5..66343a02203 100644 --- a/src/plugins/styles/modernwindows/qwindows11style_p.h +++ b/src/plugins/styles/modernwindows/qwindows11style_p.h @@ -21,7 +21,27 @@ QT_BEGIN_NAMESPACE class QWindows11StylePrivate; -class QWindows11Style; + +enum WINUI3Color { + subtleHighlightColor, //Subtle highlight based on alpha used for hovered elements + subtlePressedColor, //Subtle highlight based on alpha used for pressed elements + frameColorLight, //Color of frame around flyouts and controls except for Checkbox and Radiobutton + frameColorStrong, //Color of frame around Checkbox and Radiobuttons + controlStrongFill, //Color of controls with strong filling such as the right side of a slider + controlStrokeSecondary, + controlStrokePrimary, + controlFillTertiary, //Color of filled sunken controls + controlFillSecondary, //Color of filled hovered controls + menuPanelFill, //Color of menu panel + textOnAccentPrimary, //Color of text on controls filled in accent color + textOnAccentSecondary, //Color of text of sunken controls in accent color + controlTextSecondary, //Color of text of sunken controls + controlStrokeOnAccentSecondary, //Color of frame around Buttons in accent color + controlFillSolid, //Color for solid fill + surfaceStroke, //Color of MDI window frames + controlAccentDisabled, + textAccentDisabled +}; class QWindows11Style : public QWindowsVistaStyle { @@ -55,7 +75,8 @@ protected: private: static inline QBrush buttonFillBrush(const QStyleOption *option); static inline QColor buttonLabelColor(const QStyleOption *option, int colorSchemeIndex); - static inline QColor editSublineColor(const QStyleOption *option, int colorSchemeIndex); + void drawLineEditFrame(QPainter *p, const QStyleOption *o) const; + inline QColor winUI3Color(enum WINUI3Color col) const; private: Q_DISABLE_COPY_MOVE(QWindows11Style) |