diff options
Diffstat (limited to 'src/plugins/styles/modernwindows/qwindows11style.cpp')
| -rw-r--r-- | src/plugins/styles/modernwindows/qwindows11style.cpp | 318 |
1 files changed, 245 insertions, 73 deletions
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index 27a944a33e2..c8cd7c26f61 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -107,7 +107,9 @@ inline ControlState calcControlState(const QStyleOption *option) #define ChromeRestore u"\uE923"_s #define ChromeClose u"\uE8BB"_s +#define More u"\uE712"_s #define Help u"\uE897"_s +#define Clear u"\uE894"_s template <typename R, typename P, typename B> static inline void drawRoundedRect(QPainter *p, R &&rect, P &&pen, B &&brush) @@ -579,21 +581,18 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt if (combobox->frame) drawLineEditFrame(painter, frameRect, combobox, combobox->editable); - const bool isMouseOver = state & State_MouseOver; const bool hasFocus = state & State_HasFocus; - if (isMouseOver && !hasFocus && !highContrastTheme) - drawRoundedRect(painter, frameRect, Qt::NoPen, winUI3Color(subtleHighlightColor)); + QStyleOption opt(*option); + opt.state.setFlag(QStyle::State_On, false); + drawRoundedRect(painter, frameRect, Qt::NoPen, controlFillBrush(&opt, ControlType::Control)); if (sub & SC_ComboBoxArrow) { QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget).adjusted(4, 0, -4, 1); painter->setFont(d->assetFont); - painter->setPen(combobox->palette.text().color()); + painter->setPen(controlTextColor(option)); painter->drawText(rect, Qt::AlignCenter, ChevronDownMed); } - if (state & State_HasFocus) { - drawPrimitive(PE_FrameFocusRect, option, painter, widget); - } - if (state & State_KeyboardFocusChange && state & State_HasFocus) { + if (state & State_KeyboardFocusChange && hasFocus) { QStyleOptionFocusRect fropt; fropt.QStyleOption::operator=(*option); proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); @@ -870,17 +869,13 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption } break; case PE_IndicatorCheckBox: { - const bool isRtl = option->direction == Qt::RightToLeft; const bool isOn = option->state & State_On; const bool isPartial = option->state & State_NoChange; - QRectF rect = isRtl ? option->rect.adjusted(0, 0, -2, 0) : option->rect.adjusted(2, 0, 0, 0); + const QRectF rect = option->rect; const QPointF center = rect.center(); - rect.setWidth(15); - rect.setHeight(15); - rect.moveCenter(center); - drawRoundedRect(painter, rect, borderPenControlAlt(option), + drawRoundedRect(painter, option->rect, borderPenControlAlt(option), controlFillBrush(option, ControlType::ControlAlt)); if (isOn) { @@ -924,7 +919,6 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption } break; case PE_IndicatorRadioButton: { - const bool isRtl = option->direction == Qt::RightToLeft; const bool isOn = option->state & State_On; qreal innerRadius = radioButtonInnerRadius(state); if (d->transitionsEnabled() && option->styleObject) { @@ -935,7 +929,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption option->styleObject->setProperty("_q_inner_radius", innerRadius); } - QRectF rect = isRtl ? option->rect.adjusted(0, 0, -2, 0) : option->rect.adjusted(2, 0, 0, 0); + const QRectF rect = option->rect; const QPointF center = rect.center(); painter->setPen(borderPenControlAlt(option)); @@ -1052,12 +1046,27 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption if (rect.width() <= 0) break; - painter->setPen(Qt::NoPen); - if (vopt->features & QStyleOptionViewItem::Alternate) - painter->setBrush(vopt->palette.alternateBase()); - else - painter->setBrush(vopt->palette.base()); - painter->drawRect(rect); + 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 + 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); @@ -1186,11 +1195,14 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op 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)); QStyleOptionComboBox newOption = *cb; newOption.rect.adjust(4,0,-4,0); QCommonStyle::drawControl(element, &newOption, painter, widget); } +#endif // QT_CONFIG(combobox) break; case QStyle::CE_TabBarTabShape: #if QT_CONFIG(tabbar) @@ -1433,26 +1445,6 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op if (!proxy()->styleHint(SH_UnderlineShortcut, btn, widget)) tf |= Qt::TextHideMnemonic; - if (btn->features & QStyleOptionButton::HasMenu) { - QPainterStateGuard psg(painter); - - 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); - QColor penColor = option->palette.color(isEnabled ? QPalette::Active : QPalette::Disabled, - QPalette::Text); - if (isEnabled) - penColor.setAlpha(percentToAlpha(60.63)); // fillColorTextSecondary - painter->setPen(penColor); - painter->drawText(vindRect, Qt::AlignCenter, ChevronDownMed); - } if (!btn->icon.isNull()) { //Center both icon and text QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled; @@ -1479,6 +1471,8 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op 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)) { @@ -1505,6 +1499,29 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op painter->setPen(defaultButton ? WINUI3Colors[colorSchemeIndex][controlStrokeOnAccentSecondary] : WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]); } + if (btn->features.testFlag(QStyleOptionButton::HasMenu)) { + QPainterStateGuard psg(painter); + + const bool isEnabled = !isDisabled(option); + 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); + QColor penColor = option->palette.color( + isEnabled ? QPalette::Active : QPalette::Disabled, QPalette::Text); + if (isEnabled) + penColor.setAlpha(percentToAlpha(60.63)); // fillColorTextSecondary + painter->setPen(penColor); + painter->drawText(vindRect, Qt::AlignCenter, ChevronDownMed); + } } break; case CE_MenuBarItem: @@ -1704,9 +1721,10 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op } case CE_ItemViewItem: { if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { - QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget); - QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget); - QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget); + 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); @@ -1807,16 +1825,17 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op d->viewItemDrawText(painter, vopt, textRect); // paint a vertical marker for QListView - if (vopt->state & State_Selected) { + if (vopt->state & State_Selected && !highContrastTheme) { if (const QListView *lv = qobject_cast<const QListView *>(widget); - lv && lv->viewMode() != QListView::IconMode && !highContrastTheme) { - painter->setPen(vopt->palette.accent().color()); - const auto xPos = isRtl ? rect.right() - 1 : rect.left(); - const QLineF lines[2] = { - QLineF(xPos, rect.y() + 2, xPos, rect.y() + rect.height() - 2), - QLineF(xPos + 1, rect.y() + 2, xPos + 1, rect.y() + rect.height() - 2), - }; - painter->drawLines(lines, 2); + 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); } } } @@ -1856,7 +1875,7 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp case QStyle::SE_RadioButtonIndicator: case QStyle::SE_CheckBoxIndicator: ret = QWindowsVistaStyle::subElementRect(element, option, widget); - ret = ret.marginsRemoved(QMargins(4,0,0,0)); + ret.moveLeft(ret.left() + contentItemHMargin); break; case QStyle::SE_ComboBoxFocusRect: case QStyle::SE_CheckBoxFocusRect: @@ -1867,22 +1886,29 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp case QStyle::SE_LineEditContents: ret = option->rect.adjusted(4,0,-4,0); break; - case QStyle::SE_ItemViewItemText: - if (const auto *item = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { - const int decorationOffset = item->features.testFlag(QStyleOptionViewItem::HasDecoration) ? item->decorationSize.width() : 0; - const int checkboxOffset = item->features.testFlag(QStyleOptionViewItem::HasCheckIndicator) ? 16 : 0; - if (widget && qobject_cast<QComboBoxPrivateContainer *>(widget->parentWidget())) { - if (option->direction == Qt::LeftToRight) - ret = option->rect.adjusted(decorationOffset + checkboxOffset + 5, 0, -5, 0); - else - ret = option->rect.adjusted(5, 0, decorationOffset - checkboxOffset - 5, 0); + 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 = QWindowsVistaStyle::subElementRect(element, option, widget); + ret.moveLeft(ret.left() + xOfs); + if (ret.right() > option->rect.right()) + ret.setRight(option->rect.right()); } - } else { - ret = QWindowsVistaStyle::subElementRect(element, option, widget); } break; + } #if QT_CONFIG(progressbar) case SE_ProgressBarGroove: case SE_ProgressBarContents: @@ -2061,6 +2087,33 @@ QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOption } break; } + case CC_ComboBox: { + if (subControl == SC_ComboBoxArrow) { + const auto indicatorWidth = + proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget); + const int endX = option->rect.right() - contentHMargin - 2; + const int startX = endX - indicatorWidth; + const QRect rect(QPoint(startX, option->rect.top()), + QPoint(endX, option->rect.bottom())); + ret = visualRect(option->direction, option->rect, rect); + } else { + ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget); + } + 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); } @@ -2151,14 +2204,18 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o 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(4, 4); // default win11 style margins - if (comboBoxOpt->subControls & SC_ComboBoxArrow) - contentSize += QSize(8, 0); // arrow margins + if (comboBoxOpt->subControls & SC_ComboBoxArrow) { + const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget); + contentSize.rwidth() += w + contentItemHMargin; + } } break; +#endif 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 @@ -2166,6 +2223,27 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o 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); @@ -2179,6 +2257,25 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o contentSize.rwidth() += 2 * contentHMargin - oldMargin; 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; @@ -2217,12 +2314,24 @@ int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option, 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_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; @@ -2233,10 +2342,17 @@ int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option, res = contentItemHMargin; if (widget) { const int fontSize = widget->font().pointSize(); - QFont f(d->assetFont); - f.setPointSize(qRound(fontSize * 0.9f)); // a little bit smaller - QFontMetrics fm(f); - res += fm.horizontalAdvance(ChevronDownMed); + 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(ChevronDownMed); + m_fontPoint2ChevronDownMedWidth.insert(fontSize, width); + res += width; + } else { + res += it.value(); + } } else { res += 12; } @@ -2249,6 +2365,9 @@ int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option, case PM_ButtonShiftVertical: res = 0; break; + case PM_TreeViewIndentation: + res = 30; + break; default: res = QWindowsVistaStyle::pixelMetric(metric, option, widget); } @@ -2336,6 +2455,13 @@ void QWindows11Style::unpolish(QWidget *widget) widget->setProperty("_q_original_menubar_maxheight", QVariant()); } #endif + const auto comboBoxContainer = qobject_cast<const QComboBoxPrivateContainer *>(widget); + if (comboBoxContainer) { + 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 @@ -2459,6 +2585,52 @@ void QWindows11Style::polish(QPalette& result) d->m_titleBarMaxIcon = QIcon(); d->m_titleBarCloseIcon = QIcon(); d->m_titleBarNormalIcon = QIcon(); + d->m_toolbarExtensionButton = QIcon(); + d->m_lineEditClearButton = QIcon(); +} + +QPixmap QWindows11Style::standardPixmap(StandardPixmap standardPixmap, + const QStyleOption *option, + const QWidget *widget) const +{ + switch (standardPixmap) { + 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 +{ + auto *d = const_cast<QWindows11StylePrivate*>(d_func()); + switch (standardIcon) { + case SP_LineEditClearButton: { + if (d->m_lineEditClearButton.isNull()) { + auto e = new WinFontIconEngine(Clear.at(0), d->assetFont); + d->m_lineEditClearButton = QIcon(e); + } + return d->m_lineEditClearButton; + } + case SP_ToolBarHorizontalExtensionButton: + case SP_ToolBarVerticalExtensionButton: { + if (d->m_toolbarExtensionButton.isNull()) { + auto e = new WinFontIconEngine(More, d->assetFont); + e->setScale(1.0); + d->m_toolbarExtensionButton = QIcon(e); + } + return d->m_toolbarExtensionButton; + } + default: + break; + } + return QWindowsVistaStyle::standardIcon(standardIcon, option, widget); } QColor QWindows11Style::calculateAccentColor(const QStyleOption *option) const |
