312void QWindows11Style::drawComplexControl(ComplexControl control,
const QStyleOptionComplex *option,
313 QPainter *painter,
const QWidget *widget)
const
317 const auto drawTitleBarButton = [&](ComplexControl control, SubControl sc, Icon ico) {
319 const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
320 if (buttonRect.isValid()) {
321 const bool hover = option->activeSubControls == sc && isHover(option);
324 painter->setPen(option->palette.color(QPalette::WindowText));
325 painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
328 const auto drawTitleBarCloseButton = [&](ComplexControl control, SubControl sc, Icon ico) {
330 const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
331 if (buttonRect.isValid()) {
332 const auto state = (option->activeSubControls == sc) ? calcControlState(option)
333 : ControlState::Normal;
337 painter->fillRect(buttonRect, shellCaptionCloseFillColorPrimary);
338 pen = shellCaptionCloseTextFillColorPrimary;
341 painter->fillRect(buttonRect, shellCaptionCloseFillColorSecondary);
342 pen = shellCaptionCloseTextFillColorSecondary;
344 case ControlState::Disabled:
345 case ControlState::Normal:
346 pen = option->palette.color(QPalette::WindowText);
350 painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
355 State state = option->state;
356 SubControls sub = option->subControls;
357 State flags = option->state;
358 if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
359 flags |= State_MouseOver;
361 QPainterStateGuard psg(
painter);
362 painter->setRenderHint(QPainter::Antialiasing);
363 if (d->transitionsEnabled() && option->styleObject) {
364 if (control == CC_Slider) {
365 if (
const auto *slider = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
366 QObject *styleObject = option->styleObject;
368 QRectF thumbRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
369 const qreal outerRadius = qMin(8.0, (slider->orientation == Qt::Horizontal ? thumbRect.height() / 2.0 : thumbRect.width() / 2.0) - 1);
370 bool isInsideHandle = option->activeSubControls == SC_SliderHandle;
372 bool oldIsInsideHandle = styleObject->property(
"_q_insidehandle").toBool();
373 State oldState = State(styleObject->property(
"_q_stylestate").toInt());
374 SubControls oldActiveControls = SubControls(styleObject->property(
"_q_stylecontrols").toInt());
376 QRectF oldRect = styleObject->property(
"_q_stylerect").toRect();
377 styleObject->setProperty(
"_q_insidehandle", isInsideHandle);
378 styleObject->setProperty(
"_q_stylestate",
int(state));
379 styleObject->setProperty(
"_q_stylecontrols",
int(option->activeSubControls));
380 styleObject->setProperty(
"_q_stylerect", option->rect);
381 if (option->styleObject->property(
"_q_end_radius").isNull())
382 option->styleObject->setProperty(
"_q_end_radius", outerRadius * 0.43);
384 bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
385 || (oldIsInsideHandle != isInsideHandle)
386 || (oldActiveControls != option->activeSubControls))
387 && state & State_Enabled);
389 if (oldRect != option->rect) {
390 doTransition =
false;
391 d->stopAnimation(styleObject);
392 styleObject->setProperty(
"_q_inner_radius", outerRadius * 0.43);
396 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
397 t->setStartValue(styleObject->property(
"_q_inner_radius").toFloat());
398 t->setEndValue(outerRadius * sliderInnerRadius(state, isInsideHandle));
399 styleObject->setProperty(
"_q_end_radius", t->endValue());
401 t->setStartTime(d->animationTime());
403 d->startAnimation(t);
406 }
else if (control == CC_ScrollBar) {
407 QObject *styleObject = option->styleObject;
408 State oldState = State(styleObject->property(
"_q_stylestate").toInt());
409 const bool wasMouseOver = oldState.testFlag(State_MouseOver);
410 const bool isMouseOver = state.testFlag(State_MouseOver);
412 if (wasMouseOver != isMouseOver) {
413 styleObject->setProperty(
"_q_stylestate",
int(state));
414 auto anim = qobject_cast<QNumberStyleAnimation *>(d->animation(styleObject));
415 constexpr int durationMS = 100;
416 qreal startValue = isMouseOver ? 0 : 1;
417 int curDurationMS = durationMS;
419 startValue = anim->currentValue();
420 curDurationMS = durationMS - (anim->duration() - anim->currentLoopTime());
421 d->stopAnimation(option->styleObject);
423 anim =
new QNumberStyleAnimation(styleObject);
424 anim->setStartValue(startValue);
425 anim->setEndValue(isMouseOver ? 1 : 0);
426 anim->setDuration(curDurationMS);
427 d->startAnimation(anim);
433#if QT_CONFIG(spinbox)
435 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
436 QCachedPainter cp(painter, QLatin1StringView(
"win11_spinbox") % HexString<uint8_t>(colorSchemeIndex),
437 sb, sb->rect.size());
438 if (cp.needsPainting()) {
439 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
440 drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, inputFillBrush(option, widget));
442 if (sb->frame && (sub & SC_SpinBoxFrame))
443 drawLineEditFrame(cp.painter(), frameRect, option);
445 const auto drawUpDown = [&](QStyle::SubControl sc,
446 QAbstractSpinBox::StepEnabledFlag flag) {
447 const bool isEnabled =
448 state.testFlag(QStyle::State_Enabled) && sb->stepEnabled.testFlag(flag);
449 const bool isUp = sc == SC_SpinBoxUp;
450 const QRect rect = proxy()->subControlRect(CC_SpinBox, option, sc, widget);
451 if (isEnabled && sb->activeSubControls & sc)
452 drawRoundedRect(cp.painter(), rect.adjusted(1, 1, -1, -2), Qt::NoPen,
453 winUI3Color(subtleHighlightColor));
455 cp->setFont(d->assetFont);
456 cp->setPen(sb->palette.color(isEnabled ? QPalette::Active : QPalette::Disabled,
457 QPalette::ButtonText));
458 cp->setBrush(Qt::NoBrush);
459 cp->drawText(rect, Qt::AlignCenter, fluentIcon(isUp ? Icon::ChevronUp : Icon::ChevronDown));
461 if (sub & SC_SpinBoxUp)
462 drawUpDown(SC_SpinBoxUp, QAbstractSpinBox::StepUpEnabled);
463 if (sub & SC_SpinBoxDown)
464 drawUpDown(SC_SpinBoxDown, QAbstractSpinBox::StepDownEnabled);
465 if (state & State_KeyboardFocusChange && state & State_HasFocus) {
466 QStyleOptionFocusRect fropt;
467 fropt.QStyleOption::operator=(*option);
468 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, cp.painter(), widget);
476 if (
const auto *slider = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
477 const auto &slrect = slider->rect;
478 const bool isHorizontal = slider->orientation == Qt::Horizontal;
479 const QRectF handleRect(proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget));
480 const QPointF handleCenter(handleRect.center());
482 if (sub & SC_SliderGroove) {
483 QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
488 rect = QRectF(rect.left() + 2, rect.center().y() - 2, rect.width() - 2, 4);
489 leftRect = QRectF(rect.left(), rect.top(), handleCenter.x() - rect.left(),
491 rightRect = QRectF(handleCenter.x(), rect.top(),
492 rect.width() - handleCenter.x(),
495 rect = QRect(rect.center().x() - 2, rect.top() + 2, 4, rect.height() - 2);
496 leftRect = QRectF(rect.left(), rect.top(), rect.width(),
497 handleCenter.y() - rect.top());
498 rightRect = QRectF(rect.left(), handleCenter.y(), rect.width(),
499 rect.height() - handleCenter.y());
501 if (slider->upsideDown)
502 qSwap(leftRect, rightRect);
504 painter->setPen(Qt::NoPen);
505 painter->setBrush(calculateAccentColor(option));
506 painter->drawRoundedRect(leftRect,1,1);
507 painter->setBrush(WINUI3Colors[colorSchemeIndex][controlStrongFill]);
508 painter->drawRoundedRect(rightRect,1,1);
510 if (sub & SC_SliderTickmarks) {
511 int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
512 int ticks = slider->tickPosition;
513 int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
514 int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
515 int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
516 int interval = slider->tickInterval;
518 interval = slider->singleStep;
519 if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
521 - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
523 interval = slider->pageStep;
528 painter->setPen(slider->palette.text().color());
529 QVarLengthArray<QLineF, 32> lines;
530 int v = slider->minimum;
531 while (v <= slider->maximum + 1) {
532 if (v == slider->maximum + 1 && interval == 1)
534 const int v_ = qMin(v, slider->maximum);
535 int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
536 int pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, v_,
537 available, slider->upsideDown);
540 if (ticks & QSlider::TicksAbove) {
541 lines.append(QLineF(pos, tickOffset - 0.5,
542 pos, tickOffset - tickLength - 0.5));
545 if (ticks & QSlider::TicksBelow) {
546 lines.append(QLineF(pos, tickOffset + thickness + 0.5,
547 pos, tickOffset + thickness + tickLength + 0.5));
550 if (ticks & QSlider::TicksAbove) {
551 lines.append(QLineF(tickOffset - 0.5, pos,
552 tickOffset - tickLength - 0.5, pos));
555 if (ticks & QSlider::TicksBelow) {
556 lines.append(QLineF(tickOffset + thickness + 0.5, pos,
557 tickOffset + thickness + tickLength + 0.5, pos));
561 int nextInterval = v + interval;
562 if (nextInterval < v)
566 if (!lines.isEmpty()) {
567 QPainterStateGuard psg(painter);
568 painter->translate(slrect.topLeft());
569 painter->drawLines(lines.constData(), lines.size());
572 if (sub & SC_SliderHandle) {
573 const qreal outerRadius = qMin(8.0, (isHorizontal ? handleRect.height() / 2.0 : handleRect.width() / 2.0) - 1);
574 float innerRadius = outerRadius * 0.43;
576 if (option->styleObject) {
577 const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
578 if (animation !=
nullptr) {
579 innerRadius = animation->currentValue();
580 option->styleObject->setProperty(
"_q_inner_radius", innerRadius);
582 bool isInsideHandle = option->activeSubControls == SC_SliderHandle;
583 innerRadius = outerRadius * sliderInnerRadius(state, isInsideHandle);
587 painter->setPen(Qt::NoPen);
588 painter->setBrush(winUI3Color(controlFillSolid));
589 painter->drawEllipse(handleCenter, outerRadius, outerRadius);
590 painter->setBrush(calculateAccentColor(option));
591 painter->drawEllipse(handleCenter, innerRadius, innerRadius);
593 painter->setPen(winUI3Color(controlStrokeSecondary));
594 painter->setBrush(Qt::NoBrush);
595 painter->drawEllipse(handleCenter, outerRadius + 0.5, outerRadius + 0.5);
597 if (slider->state & State_HasFocus) {
598 QStyleOptionFocusRect fropt;
599 fropt.QStyleOption::operator=(*slider);
600 fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
601 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
606#if QT_CONFIG(combobox)
608 if (
const QStyleOptionComboBox *combobox = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
609 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
610 QStyleOption opt(*option);
611 opt.state.setFlag(QStyle::State_On,
false);
612 drawRoundedRect(painter, frameRect, Qt::NoPen,
613 combobox->editable ? inputFillBrush(option, widget)
614 : controlFillBrush(&opt, ControlType::Control));
617 drawLineEditFrame(painter, frameRect, combobox, combobox->editable);
619 const bool hasFocus = state & State_HasFocus;
621 if (sub & SC_ComboBoxArrow) {
622 QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
623 painter->setFont(d->assetFont);
624 painter->setPen(controlTextColor(option,
true));
625 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
627 if (state & State_KeyboardFocusChange && hasFocus) {
628 QStyleOptionFocusRect fropt;
629 fropt.QStyleOption::operator=(*option);
630 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
636 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
637 const bool vertical = scrollbar->orientation == Qt::Vertical;
638 const bool isMouseOver = state & State_MouseOver;
639 const auto prx = proxy();
641 QPainterStateGuard psg(
painter);
643 const auto anim = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
644 qreal widthFactor = isMouseOver ? 1.0 : 0.0;
646 widthFactor = anim->currentValue();
648 if (widthFactor > 0.6) {
649 const bool isRtl = option->direction == Qt::RightToLeft;
651 QFont f = QFont(d->assetFont);
654 painter->setPen(winUI3Color(controlStrongFill));
656 const QRectF rectAdd =
657 prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
658 const auto strAdd = vertical
659 ? Icon::CaretDownSolid8
660 : (isRtl ? Icon::CaretLeftSolid8 : Icon::CaretRightSolid8);
661 painter->drawText(rectAdd, Qt::AlignCenter, fluentIcon(strAdd));
663 const QRectF rectSub =
664 prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
665 const auto strSub = vertical
666 ? Icon::CaretUpSolid8
667 : (isRtl ? Icon::CaretRightSolid8 : Icon::CaretLeftSolid8);
668 painter->drawText(rectSub, Qt::AlignCenter, fluentIcon(strSub));
670 if (sub & SC_ScrollBarSlider) {
671 QRectF rect = prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
672 const QPointF center = rect.center();
674 auto w = rect.width() / 2. * widthFactor;
677 const auto ofs = rect.width() / 2 - w;
679 rect.moveCenter(QPointF(center.x() + ofs, center.y()));
682 auto h = rect.height() / 2. * widthFactor;
685 const auto ofs = rect.height() / 2 - h;
687 rect.moveCenter(QPointF(center.x(), center.y() + ofs));
689 drawRoundedRect(painter, rect, Qt::NoPen, winUI3Color(controlStrongFill), 3);
693 case CC_MdiControls:{
694 QFont buttonFont = QFont(d->assetFont);
695 buttonFont.setPointSize(8);
696 painter->setFont(buttonFont);
697 drawTitleBarCloseButton(CC_MdiControls, SC_MdiCloseButton, Icon::ChromeClose);
698 drawTitleBarButton(CC_MdiControls, SC_MdiNormalButton, Icon::ChromeRestore);
699 drawTitleBarButton(CC_MdiControls, SC_MdiMinButton, Icon::ChromeMinimize);
703 if (
const auto* titlebar = qstyleoption_cast<
const QStyleOptionTitleBar*>(option)) {
704 painter->setPen(Qt::NoPen);
705 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
706 painter->setBrush(titlebar->palette.button());
707 painter->drawRect(titlebar->rect);
710 QRect textRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
711 QColor textColor = titlebar->palette.color(titlebar->titleBarState & Qt::WindowActive ? QPalette::Active : QPalette::Disabled,QPalette::WindowText);
712 painter->setPen(textColor);
714 QString title = painter->fontMetrics().elidedText(titlebar->text, Qt::ElideRight, textRect.width() - 14);
715 painter->drawText(textRect.adjusted(1, 1, -1, -1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
717 QFont buttonFont = QFont(d->assetFont);
718 buttonFont.setPointSize(8);
719 painter->setFont(buttonFont);
720 auto shouldDrawButton = [titlebar](SubControl sc, Qt::WindowType flag) {
721 return (titlebar->subControls & sc) && (titlebar->titleBarFlags & flag);
725 if (shouldDrawButton(SC_TitleBarMinButton, Qt::WindowMinimizeButtonHint) &&
726 !(titlebar->titleBarState & Qt::WindowMinimized)) {
727 drawTitleBarButton(CC_TitleBar, SC_TitleBarMinButton, Icon::ChromeMinimize);
731 if (shouldDrawButton(SC_TitleBarMaxButton, Qt::WindowMaximizeButtonHint) &&
732 !(titlebar->titleBarState & Qt::WindowMaximized)) {
733 drawTitleBarButton(CC_TitleBar, SC_TitleBarMaxButton, Icon::ChromeMaximize);
737 if (shouldDrawButton(SC_TitleBarCloseButton, Qt::WindowSystemMenuHint))
738 drawTitleBarCloseButton(CC_TitleBar, SC_TitleBarCloseButton, Icon::ChromeClose);
741 if ((titlebar->subControls & SC_TitleBarNormalButton) &&
742 (((titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
743 (titlebar->titleBarState & Qt::WindowMinimized)) ||
744 ((titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
745 (titlebar->titleBarState & Qt::WindowMaximized)))) {
746 drawTitleBarButton(CC_TitleBar, SC_TitleBarNormalButton, Icon::ChromeRestore);
750 if (shouldDrawButton(SC_TitleBarContextHelpButton, Qt::WindowContextHelpButtonHint))
751 drawTitleBarButton(CC_TitleBar, SC_TitleBarContextHelpButton, Icon::Help);
754 if (shouldDrawButton(SC_TitleBarShadeButton, Qt::WindowShadeButtonHint))
755 drawTitleBarButton(CC_TitleBar, SC_TitleBarShadeButton, Icon::ChevronUpSmall);
758 if (shouldDrawButton(SC_TitleBarUnshadeButton, Qt::WindowShadeButtonHint))
759 drawTitleBarButton(CC_TitleBar, SC_TitleBarUnshadeButton, Icon::ChevronDownSmall);
762 if (shouldDrawButton(SC_TitleBarSysMenu, Qt::WindowSystemMenuHint)) {
763 const QRect iconRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarSysMenu, widget);
764 if (iconRect.isValid()) {
765 if (!titlebar->icon.isNull()) {
766 titlebar->icon.paint(painter, iconRect);
768 QStyleOption tool = *titlebar;
769 const auto extent = proxy()->pixelMetric(PM_SmallIconSize, &tool, widget);
770 const auto dpr = QStyleHelper::getDpr(widget);
771 const auto icon = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget);
772 const auto pm = icon.pixmap(QSize(extent, extent), dpr);
773 proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm);
779#if QT_CONFIG(toolbutton)
781 if (
const auto toolbutton = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
783 const bool isSplitButton =
784 toolbutton->features.testFlag(QStyleOptionToolButton::MenuButtonPopup);
785 const auto fw = prx->pixelMetric(PM_DefaultFrameWidth, option, widget);
786 const auto buttonRect = prx->subControlRect(control, toolbutton, SC_ToolButton, widget);
787 const auto menuareaRect = isSplitButton
788 ? prx->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget)
791 State bflags = toolbutton->state;
792 State mflags = toolbutton->state;
793 if (toolbutton->activeSubControls.testFlag(SC_ToolButton)) {
794 mflags &= ~(State_Sunken | State_MouseOver);
795 if (bflags.testFlag(State_Sunken))
796 mflags |= State_Raised;
798 if (toolbutton->activeSubControls.testFlag(SC_ToolButtonMenu)) {
799 bflags &= ~(State_Sunken | State_MouseOver);
800 if (mflags.testFlag(State_Sunken))
801 bflags |= State_Raised;
804 QStyleOption tool = *toolbutton;
805 if (toolbutton->subControls.testFlag(SC_ToolButton)) {
806 QPainterStateGuard psg(painter);
808 painter->setClipRect(buttonRect);
810 prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
812 if (state.testFlag(State_Enabled)) {
813 painter->setPen(winUI3Color(controlStrokePrimary));
814 const auto top = buttonRect.topRight() + QPoint(0, fw + 1);
815 const auto btm = buttonRect.bottomRight() - QPoint(0, fw);
816 painter->drawLine(top, btm);
821 if (toolbutton->state.testFlag(State_HasFocus)) {
822 QStyleOptionFocusRect fr;
823 fr.QStyleOption::operator=(*toolbutton);
824 prx->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget);
826 QStyleOptionToolButton label = *toolbutton;
827 label.state = bflags;
828 label.rect = buttonRect.marginsRemoved(QMargins(fw, fw, fw, fw));
830 if (toolbutton->subControls.testFlag(SC_ToolButtonMenu)) {
831 QPainterStateGuard psg(painter);
832 painter->setClipRect(menuareaRect);
834 prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
836 const int fontSize = painter->font().pointSize();
837 QFont f(d->assetFont);
838 f.setPointSize(qRound(fontSize * 0.9f));
840 painter->setPen(controlTextColor(option));
841 const QRect textRect(menuareaRect.topLeft(), menuareaRect.size() - QSize(fw, 0));
842 painter->drawText(textRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
844 }
else if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) {
845 const int mbi = qRound(prx->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget) * 0.3);
846 const QRect &ir = toolbutton->rect;
847 QRect rect(ir.right() - mbi - 2 * fw, ir.bottom() - mbi - fw, mbi,
849 rect = visualRect(toolbutton->direction, buttonRect, rect);
850 const QRect lblRect = label.rect - QMargins(0, 0, rect.width(), 0);
851 label.rect = visualRect(toolbutton->direction, buttonRect, lblRect);
852 painter->setFont(QFont(d->assetFont));
853 painter->setPen(controlTextColor(option));
854 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
856 prx->drawControl(CE_ToolButtonLabel, &label, painter, widget);
861 QWindowsVistaStyle::drawComplexControl(control, option, painter, widget);
865void QWindows11Style::drawPrimitive(PrimitiveElement element,
const QStyleOption *option,
867 const QWidget *widget)
const {
870 const State state = option->state;
871 QPainterStateGuard psg(
painter);
872 painter->setRenderHint(QPainter::Antialiasing);
873 if (d->transitionsEnabled() && option->styleObject && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) {
874 QObject *styleObject = option->styleObject;
875 int oldState = styleObject->property(
"_q_stylestate").toInt();
876 styleObject->setProperty(
"_q_stylestate",
int(option->state));
877 styleObject->setProperty(
"_q_stylerect", option->rect);
878 bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
879 || ((state & State_MouseOver) != (oldState & State_MouseOver))
880 || (state & State_On) != (oldState & State_On))
881 && state & State_Enabled);
883 if (element == PE_IndicatorRadioButton) {
884 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
885 t->setStartValue(styleObject->property(
"_q_inner_radius").toFloat());
886 t->setEndValue(radioButtonInnerRadius(state));
887 styleObject->setProperty(
"_q_end_radius", t->endValue());
888 t->setStartTime(d->animationTime());
890 d->startAnimation(t);
892 else if (element == PE_IndicatorCheckBox) {
893 if ((oldState & State_Off && state & State_On) || (oldState & State_NoChange && state & State_On)) {
894 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
895 t->setStartValue(0.0f);
896 t->setEndValue(1.0f);
897 t->setStartTime(d->animationTime());
899 d->startAnimation(t);
906 case PE_IndicatorArrowUp:
907 case PE_IndicatorArrowDown:
908 case PE_IndicatorArrowRight:
909 case PE_IndicatorArrowLeft: {
910 const QRect &r = option->rect;
911 if (r.width() <= 1 || r.height() <= 1)
913 Icon ico = Icon::Help;
915 case PE_IndicatorArrowUp:
916 ico = Icon::ChevronUpMed;
918 case PE_IndicatorArrowDown:
919 ico = Icon::ChevronDownMed;
921 case PE_IndicatorArrowLeft:
922 ico = Icon::ChevronLeftMed;
924 case PE_IndicatorArrowRight:
925 ico = Icon::ChevronRightMed;
930 QPainterStateGuard psg(
painter);
931 if (option->state.testFlag(State_Sunken)) {
932 const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget);
933 const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget);
934 if (bsx != 0 || bsy != 0)
935 painter->translate(bsx, bsy);
937 painter->setFont(d->assetFont);
938 painter->setPen(option->palette.buttonText().color());
939 painter->setBrush(option->palette.buttonText());
940 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
943 case PE_FrameFocusRect: {
944 if (
const QStyleOptionFocusRect *fropt = qstyleoption_cast<
const QStyleOptionFocusRect *>(option)) {
945 if (!(fropt->state & State_KeyboardFocusChange))
947 QRectF focusRect = option->rect;
948 focusRect = focusRect.marginsRemoved(QMarginsF(1.5,1.5,1.5,1.5));
949 painter->setPen(winUI3Color(focusFrameInnerStroke));
950 painter->drawRoundedRect(focusRect,4,4);
952 focusRect = focusRect.marginsAdded(QMarginsF(1.0,1.0,1.0,1.0));
953 painter->setPen(QPen(winUI3Color(focusFrameOuterStroke),1));
954 painter->drawRoundedRect(focusRect,4,4);
958 case PE_PanelTipLabel: {
959 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(0.5, 0.5, 0.5, 0.5));
960 const auto pen = highContrastTheme ? option->palette.buttonText().color()
961 : winUI3Color(frameColorLight);
962 drawRoundedRect(painter, rect, pen, option->palette.toolTipBase());
965 case PE_FrameTabWidget:
966#if QT_CONFIG(tabwidget)
967 if (
const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(option)) {
968 QPainterStateGuard psg(painter);
969 const auto clipRegion = painter->clipRegion();
971 painter->setPen(highContrastTheme ? frame->palette.buttonText().color()
972 : winUI3Color(frameColorLight));
973 painter->setBrush(frame->palette.base());
975 const auto &rect = option->rect;
976 QRect upperRect = rect;
977 upperRect.setHeight(rect.height() / 2);
978 QRect lowerRect = rect;
979 lowerRect.setY(lowerRect.y() + rect.height() / 2);
980 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
981 painter->drawRect(rect);
982 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
983 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
988 case PE_FrameGroupBox:
989 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
990 const auto pen = highContrastTheme ? frame->palette.buttonText().color()
991 : winUI3Color(frameColorStrong);
992 if (frame->features & QStyleOptionFrame::Flat) {
993 painter->setBrush(Qt::NoBrush);
994 painter->setPen(pen);
995 const QRect &fr = frame->rect;
996 QPoint p1(fr.x(), fr.y() + 1);
997 QPoint p2(fr.x() + fr.width(), p1.y());
998 painter->drawLine(p1, p2);
1000 const auto frameRect = QRectF(frame->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1001 drawRoundedRect(painter, frameRect, pen, Qt::NoBrush);
1005 case PE_IndicatorHeaderArrow:
1006 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1007 const auto indicator = header->sortIndicator;
1008 if (indicator != QStyleOptionHeader::None) {
1009 QPainterStateGuard psg(
painter);
1010 QFont f(d->assetFont);
1011 f.setPointSize(option->rect.height());
1012 painter->setFont(f);
1013 painter->setPen(header->palette.text().color());
1014 const auto ico = indicator == QStyleOptionHeader::SortUp ? Icon::ChevronDown
1016 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1020 case PE_IndicatorCheckBox: {
1021 const bool isOn = option->state & State_On;
1022 const bool isPartial = option->state & State_NoChange;
1024 const QRectF rect = option->rect;
1025 const QPointF center = rect.center();
1027 drawRoundedRect(painter, option->rect, borderPenControlAlt(option),
1028 controlFillBrush(option, ControlType::ControlAlt));
1031 painter->setFont(d->assetFont);
1032 painter->setPen(controlTextColor(option));
1033 const auto *animation =
1034 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1035 const qreal clipWidth = animation ? animation->currentValue() : 1.0;
1036 const QString str = fluentIcon(Icon::AcceptMedium);
1037 QFontMetrics fm(d->assetFont);
1038 QRectF clipRect = fm.boundingRect(str);
1039 clipRect.moveCenter(center);
1040 clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0 + 0.5);
1041 clipRect.setWidth(clipWidth * clipRect.width());
1042 painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, str);
1043 }
else if (isPartial) {
1044 QFont f(d->assetFont);
1046 painter->setFont(f);
1047 painter->setPen(controlTextColor(option));
1048 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::Dash12));
1052 case PE_IndicatorBranch: {
1053 if (option->state & State_Children) {
1054 const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option);
1055 const bool isReverse = option->direction == Qt::RightToLeft;
1056 const bool isOpen = option->state & QStyle::State_Open;
1057 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1058 QFont f(d->assetFont);
1060 painter->setFont(f);
1061 if (view && view->alternatingRowColors() && vopt && vopt->state & State_Selected)
1062 painter->setPen(winUI3Color(textOnAccentPrimary));
1064 painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
1065 QPalette::WindowText));
1066 const auto ico = isOpen ? Icon::ChevronDownMed
1067 : (isReverse ? Icon::ChevronLeftMed
1068 : Icon::ChevronRightMed);
1069 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1073 case PE_IndicatorRadioButton: {
1074 const auto *animation =
1075 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1076 const qreal innerRadius =
1077 animation ? animation->currentValue() : radioButtonInnerRadius(state);
1078 const QRectF rect = option->rect;
1079 const QPointF center = rect.center();
1081 if (option->styleObject)
1082 option->styleObject->setProperty(
"_q_inner_radius", innerRadius);
1083 painter->setPen(borderPenControlAlt(option));
1084 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1085 if (option->state.testFlag(State_On)) {
1087 path.addEllipse(center, 7.5, 7.5);
1088 path.addEllipse(center, innerRadius, innerRadius);
1089 painter->drawPath(path);
1091 painter->setBrush(option->palette.window().color());
1092 painter->drawEllipse(center, innerRadius, innerRadius);
1094 painter->drawEllipse(center, 7.5, 7.5);
1098 case PE_PanelButtonTool:
1099 case PE_PanelButtonBevel:{
1100 const bool isEnabled = state & QStyle::State_Enabled;
1101 const bool isMouseOver = state & QStyle::State_MouseOver;
1102 const bool isAutoRaise = state & QStyle::State_AutoRaise;
1103 const int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
1104 const QRectF rect = option->rect.marginsRemoved(QMargins(fw, fw, fw, fw));
1105 if (element == PE_PanelButtonTool && ((!isMouseOver && isAutoRaise) || !isEnabled))
1106 painter->setPen(Qt::NoPen);
1108 painter->setPen(winUI3Color(controlStrokePrimary));
1109 painter->setBrush(controlFillBrush(option, ControlType::Control));
1110 if (element == PE_PanelButtonTool && widget) {
1111 const auto name = widget->objectName();
1112 if (name ==
"ScrollLeftButton"_L1 || name ==
"ScrollRightButton"_L1) {
1113 painter->setPen(Qt::NoPen);
1115 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1117 painter->setBrush(Qt::NoBrush);
1120 painter->drawRoundedRect(rect,
1121 secondLevelRoundingRadius, secondLevelRoundingRadius);
1124 case PE_FrameDefaultButton:
1125 painter->setPen(option->palette.accent().color());
1126 painter->setBrush(Qt::NoBrush);
1127 painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1131 case PE_PanelMenu: {
1132 if (!d->nativeRoundedTopLevelWindows) {
1133 const QRect rect = option->rect.marginsRemoved(QMargins(2, 2, 2, 2));
1134 painter->setPen(highContrastTheme ? QPen(option->palette.windowText().color(), 2)
1135 : winUI3Color(frameColorLight));
1136 painter->setBrush(winUI3Color(menuPanelFill));
1137 painter->drawRoundedRect(rect, topLevelRoundingRadius, topLevelRoundingRadius);
1141 case PE_PanelLineEdit:
1142 if (
const auto *panel = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1143 const bool isInSpinBox =
1144 widget && qobject_cast<
const QAbstractSpinBox *>(widget->parent()) !=
nullptr;
1145 const bool isInComboBox =
1146 widget && qobject_cast<
const QComboBox *>(widget->parent()) !=
nullptr;
1147 if (!isInSpinBox && !isInComboBox) {
1148 const auto frameRect =
1149 QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1150 drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
1151 if (panel->lineWidth > 0)
1152 proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
1156 case PE_FrameLineEdit: {
1157 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1158 drawLineEditFrame(painter, frameRect, option);
1159 if (state & State_KeyboardFocusChange && state & State_HasFocus) {
1160 QStyleOptionFocusRect fropt;
1161 fropt.QStyleOption::operator=(*option);
1162 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
1167 if (
const auto *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1168 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1169 if (qobject_cast<
const QComboBoxPrivateContainer *>(widget)) {
1170 if (d->nativeRoundedTopLevelWindows)
1173 if (highContrastTheme)
1174 pen = QPen(option->palette.windowText().color(), 2);
1177 drawRoundedRect(painter, rect, pen, WINUI3Colors[colorSchemeIndex][menuPanelFill]);
1179 drawRoundedRect(painter, rect, Qt::NoPen, option->palette.brush(QPalette::Base));
1181 if (frame->frameShape == QFrame::NoFrame)
1184 const bool isEditable = qobject_cast<
const QTextEdit *>(widget) !=
nullptr
1185 || qobject_cast<
const QPlainTextEdit *>(widget) !=
nullptr;
1186 drawLineEditFrame(painter, rect, option, isEditable);
1190 case PE_PanelItemViewItem:
1191 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1192 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
1193 QPainterStateGuard psg(
painter);
1194 painter->setBrushOrigin(vopt->rect.topLeft());
1195 painter->fillRect(vopt->rect, vopt->backgroundBrush);
1199 case PE_PanelItemViewRow:
1200 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1204 const QRect &rect = vopt->rect;
1205 const bool isRtl = option->direction == Qt::RightToLeft;
1206 if (rect.width() <= 0)
1209 if (vopt->features & QStyleOptionViewItem::Alternate) {
1210 QPalette::ColorGroup cg =
1211 (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
1213 : QPalette::Disabled;
1214 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
1215 cg = QPalette::Inactive;
1216 painter->fillRect(rect, option->palette.brush(cg, QPalette::AlternateBase));
1219 if (option->state & State_Selected && !highContrastTheme) {
1221 if (!qobject_cast<
const QTableView *>(widget)) {
1222 const auto col = option->palette.accent().color();
1223 painter->setBrush(col);
1224 painter->setPen(col);
1225 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
1226 const auto yOfs = rect.height() / 4.;
1227 QRectF r(
QPointF(xPos, rect.y() + yOfs),
1228 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
1229 painter->drawRoundedRect(r, 1, 1);
1233 const bool isTreeDecoration = vopt->features.testFlag(
1234 QStyleOptionViewItem::IsDecorationForRootColumn);
1235 if (isTreeDecoration && vopt->state.testAnyFlags(State_Selected | State_MouseOver) &&
1236 vopt->showDecorationSelected) {
1237 const bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1238 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1239 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1240 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1250 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1251 painter->setBrush(view->alternatingRowColors() && state & State_Selected ? calculateAccentColor(option) : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
1252 painter->setPen(Qt::NoPen);
1254 QPainterStateGuard psg(
painter);
1255 painter->setClipRect(rect);
1256 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1257 secondLevelRoundingRadius, secondLevelRoundingRadius);
1258 }
else if (isLast) {
1259 QPainterStateGuard psg(
painter);
1260 painter->setClipRect(rect);
1261 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1262 secondLevelRoundingRadius, secondLevelRoundingRadius);
1264 painter->drawRect(vopt->rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1271 case QStyle::PE_FrameWindow:
1272 if (
const auto *frm = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1274 QRectF rect= option->rect;
1275 int fwidth =
int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
1277 QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
1278 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1279 secondLevelRoundingRadius,
1280 secondLevelRoundingRadius);
1281 QRectF bottomRightCorner = QRectF(rect.right() - 1.0 - secondLevelRoundingRadius,
1282 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1283 secondLevelRoundingRadius,
1284 secondLevelRoundingRadius);
1287 if (widget !=
nullptr) {
1288 QBitmap mask(widget->width(), widget->height());
1292 maskPainter.setRenderHint(QPainter::Antialiasing);
1293 maskPainter.setBrush(Qt::color1);
1294 maskPainter.setPen(Qt::NoPen);
1295 maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
1296 const_cast<QWidget*>(widget)->setMask(mask);
1300 painter->setPen(QPen(frm->palette.base(), fwidth));
1301 painter->drawLine(QPointF(rect.left(), rect.top()),
1302 QPointF(rect.left(), rect.bottom() - fwidth));
1303 painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
1304 QPointF(rect.right() - fwidth, rect.bottom()));
1305 painter->drawLine(QPointF(rect.right(), rect.top()),
1306 QPointF(rect.right(), rect.bottom() - fwidth));
1308 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1309 painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
1310 QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1311 painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
1312 QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
1313 painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
1314 QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1316 painter->setPen(Qt::NoPen);
1317 painter->setBrush(frm->palette.base());
1318 painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
1320 painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
1323 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1324 painter->setBrush(Qt::NoBrush);
1325 painter->drawArc(bottomRightCorner,
1327 painter->drawArc(bottomLeftCorner,
1331#if QT_CONFIG(tabbar)
1332 case PE_FrameTabBarBase:
1333 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTabBarBase *>(option)) {
1334 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1335 const auto clipRegion = painter->clipRegion();
1337 painter->setPen(highContrastTheme ? tab->palette.buttonText().color()
1338 : winUI3Color(frameColorLight));
1339 painter->setBrush(tab->palette.base());
1340 QRect upperRect = tab->rect;
1341 upperRect.setHeight(tab->rect.height() / 2);
1342 QRect lowerRect = tab->rect;
1343 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2);
1344 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1345 painter->drawRoundedRect(tab->rect, secondLevelRoundingRadius,
1346 secondLevelRoundingRadius);
1347 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1348 painter->drawRect(tab->rect);
1352 case PE_IndicatorTabTearLeft:
1353 case PE_IndicatorTabTearRight:
1356 QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
1363void QWindows11Style::drawControl(ControlElement element,
const QStyleOption *option,
1364 QPainter *painter,
const QWidget *widget)
const
1366 Q_D(
const QWindows11Style);
1368 QPainterStateGuard psg(
painter);
1369 painter->setRenderHint(QPainter::Antialiasing);
1371 case QStyle::CE_ComboBoxLabel:
1372#if QT_CONFIG(combobox)
1373 if (
const QStyleOptionComboBox *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
1374 painter->setPen(controlTextColor(option,
true));
1375 QStyleOptionComboBox newOption = *cb;
1376 newOption.rect.adjust(4,0,-4,0);
1377 QCommonStyle::drawControl(element, &newOption, painter, widget);
1381#if QT_CONFIG(tabbar)
1382 case CE_TabBarTabShape:
1383 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1384 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1385 const bool isSelected = tab->state.testFlag(State_Selected);
1386 const auto clipRegion = painter->clipRegion();
1387 const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab
1388 || tab->position == QStyleOptionTab::Moving;
1389 auto leftMargin = (tab->position == QStyleOptionTab::Beginning || onlyOne) ? 1 : 0;
1390 auto rightMargin = (tab->position == QStyleOptionTab::End || onlyOne) ? 1 : 0;
1391 if (QCommonStylePrivate::rtl(option))
1392 std::swap(leftMargin, rightMargin);
1394 QRectF tabRect = tab->rect.marginsRemoved(QMargins(leftMargin, 1, rightMargin, -3));
1395 painter->setPen(highContrastTheme ? tab->palette.buttonText().color() : winUI3Color(frameColorLight));
1396 painter->setBrush(tab->palette.base());
1398 painter->setBrush(winUI3Color(fillMicaAltDefault));
1400 if (tab->state.testFlag(State_Sunken))
1401 painter->setBrush(winUI3Color(fillMicaAltDefault));
1402 else if (tab->state.testFlag(State_MouseOver))
1403 painter->setBrush(winUI3Color(fillMicaAltSecondary));
1405 painter->setBrush(winUI3Color(fillMicaAltTransparent));
1407 QRect upperRect = tab->rect;
1408 upperRect.setHeight(tab->rect.height() / 2.);
1409 QRect lowerRect = tab->rect;
1410 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2.);
1411 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1412 painter->drawRoundedRect(tabRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1413 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1414 painter->drawRect(tabRect);
1417 case CE_TabBarTabLabel:
1418 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1419 const bool isEnabled = tab->state.testFlags(State_Enabled);
1420 const bool isSelected = tab->state.testFlags(State_Selected);
1422 QRect tr = tab->rect;
1423 bool verticalTabs = tab->shape == QTabBar::RoundedEast
1424 || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast
1425 || tab->shape == QTabBar::TriangularWest;
1427 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1428 if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget))
1429 alignment |= Qt::TextHideMnemonic;
1431 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1434 int newX, newY, newRot;
1435 if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
1436 newX = tr.width() + tr.x();
1441 newY = tr.y() + tr.height();
1444 QTransform m = QTransform::fromTranslate(newX, newY);
1446 painter->setTransform(m,
true);
1449 d->tabLayout(tab, widget, &tr, &iconRect);
1452 if (tab->position != QStyleOptionTab::TabPosition::Moving)
1453 tr = proxy()->subElementRect(SE_TabBarTabText, option, widget);
1455 if (!tab->icon.isNull()) {
1456 const auto mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
1457 const auto state = isSelected ? QIcon::On : QIcon::Off;
1458 tab->icon.paint(painter, iconRect, Qt::AlignCenter, mode, state);
1461 painter->setPen(winUI3Color(isSelected ? textPrimary : textSecondary));
1462 proxy()->drawItemText(painter, tr, alignment, tab->palette, isEnabled, tab->text);
1466 case CE_ToolButtonLabel:
1467#if QT_CONFIG(toolbutton)
1468 if (
const QStyleOptionToolButton *toolbutton
1469 = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
1470 QRect rect = toolbutton->rect;
1473 if (toolbutton->state & (State_Sunken | State_On)) {
1474 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
1475 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
1478 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1479 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1480 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1481 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1482 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1483 alignment |= Qt::TextHideMnemonic;
1484 rect.translate(shiftX, shiftY);
1485 painter->setFont(toolbutton->font);
1486 const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
1487 painter->setPen(controlTextColor(option));
1488 proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
1489 toolbutton->state & State_Enabled, text);
1492 QSize pmSize = toolbutton->iconSize;
1493 if (!toolbutton->icon.isNull()) {
1494 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1496 if (!(toolbutton->state & State_Enabled))
1497 mode = QIcon::Disabled;
1498 else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
1499 mode = QIcon::Active;
1501 mode = QIcon::Normal;
1502 pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
1504 pmSize = pm.size() / pm.devicePixelRatio();
1507 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1508 painter->setFont(toolbutton->font);
1511 int alignment = Qt::TextShowMnemonic | Qt::AlignCenter;
1512 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1513 alignment |= Qt::TextHideMnemonic;
1515 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1516 pr.setHeight(pmSize.height() + 4);
1517 tr.adjust(0, pr.height() - 1, 0, -1);
1519 pr.setWidth(pmSize.width() + 4);
1520 tr.adjust(pr.width(), 0, 0, 0);
1522 pr.translate(shiftX, shiftY);
1524 drawArrow(proxy(), toolbutton, pr, painter, widget);
1526 const auto vr = QStyle::visualRect(toolbutton->direction, rect, pr);
1527 proxy()->drawItemPixmap(painter, vr, Qt::AlignCenter, pm);
1529 tr.translate(shiftX, shiftY);
1530 painter->setPen(controlTextColor(option));
1531 const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
1532 const auto vr = QStyle::visualRect(toolbutton->direction, rect, tr);
1533 proxy()->drawItemText(painter, vr, alignment, toolbutton->palette,
1534 toolbutton->state & State_Enabled, text);
1536 rect.translate(shiftX, shiftY);
1538 drawArrow(proxy(), toolbutton, rect, painter, widget);
1540 proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
1547 case QStyle::CE_ShapedFrame:
1548 if (
const QStyleOptionFrame *f = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1549 int frameShape = f->frameShape;
1550 int frameShadow = QFrame::Plain;
1551 if (f->state & QStyle::State_Sunken)
1552 frameShadow = QFrame::Sunken;
1553 else if (f->state & QStyle::State_Raised)
1554 frameShadow = QFrame::Raised;
1556 int lw = f->lineWidth;
1557 int mlw = f->midLineWidth;
1559 switch (frameShape) {
1561 if (frameShadow == QFrame::Plain)
1562 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1564 qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
1567 if (frameShadow == QFrame::Plain)
1568 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1570 qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
1573 QWindowsVistaStyle::drawControl(element, option, painter, widget);
1577#if QT_CONFIG(progressbar)
1578 case CE_ProgressBarGroove:
1579 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar*>(option)) {
1580 QRect rect = option->rect;
1581 QPointF center = rect.center();
1582 if (baropt->state & QStyle::State_Horizontal) {
1584 rect.moveTop(center.y());
1587 rect.moveLeft(center.x());
1589 painter->setPen(Qt::NoPen);
1590 painter->setBrush(Qt::gray);
1591 painter->drawRect(rect);
1594 case CE_ProgressBarContents:
1595 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1596 QPainterStateGuard psg(painter);
1597 QRectF rect = option->rect;
1598 painter->translate(rect.topLeft());
1599 rect.translate(-rect.topLeft());
1601 constexpr qreal progressBarThickness = 3;
1602 constexpr qreal progressBarHalfThickness = progressBarThickness / 2.0;
1604 const auto isIndeterminate = baropt->maximum == 0 && baropt->minimum == 0;
1605 const auto orientation =
1606 (baropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
1607 const auto inverted = baropt->invertedAppearance;
1608 const auto reverse = (baropt->direction == Qt::RightToLeft) ^ inverted;
1612 if (orientation == Qt::Vertical) {
1613 rect = QRectF(rect.left(), rect.top(), rect.height(),
1618 m.translate(0, -rect.height() + 1);
1621 m.translate(-rect.width(), 0);
1623 painter->setTransform(m,
true);
1624 }
else if (reverse) {
1625 QTransform m = QTransform::fromScale(-1, 1);
1626 m.translate(-rect.width(), 0);
1627 painter->setTransform(m,
true);
1629 const qreal offset = (
int(rect.height()) % 2 == 0) ? 0.5f : 0.0f;
1631 if (isIndeterminate) {
1632#if QT_CONFIG(animation)
1633 auto anim = d->animation(option->styleObject);
1635 auto anim =
new QStyleAnimation(option->styleObject);
1636 anim->setFrameRate(QStyleAnimation::SixtyFps);
1637 d->startAnimation(anim);
1639 constexpr auto loopDurationMSec = 4000;
1640 const auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(
1641 std::chrono::system_clock::now());
1642 const auto elapsed = elapsedTime.time_since_epoch().count();
1643 const auto handleCenter = (elapsed % loopDurationMSec) /
float(loopDurationMSec);
1644 const auto isLongHandle = (elapsed / loopDurationMSec) % 2 == 0;
1645 const auto lengthFactor = (isLongHandle ? 33.0f : 25.0f) / 100.0f;
1647 constexpr auto handleCenter = 0.5f;
1648 constexpr auto lengthFactor = 1;
1650 const auto begin = qMax(handleCenter * (1 + lengthFactor) - lengthFactor, 0.0f);
1651 const auto end = qMin(handleCenter * (1 + lengthFactor), 1.0f);
1652 const auto barBegin = begin * rect.width();
1653 const auto barEnd = end * rect.width();
1654 rect = QRectF(QPointF(rect.left() + barBegin, rect.top()),
1655 QPointF(rect.left() + barEnd, rect.bottom()));
1657#if QT_CONFIG(animation)
1658 d->stopAnimation(option->styleObject);
1660 const auto fillPercentage = (
float(baropt->progress - baropt->minimum))
1661 / (
float(baropt->maximum - baropt->minimum));
1662 rect.setWidth(rect.width() * fillPercentage);
1664 const QPointF center = rect.center();
1665 rect.setHeight(progressBarThickness);
1666 rect.moveTop(center.y() - progressBarHalfThickness - offset);
1667 drawRoundedRect(painter, rect, Qt::NoPen, baropt->palette.accent());
1670 case CE_ProgressBarLabel:
1671 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1672 const bool vertical = !(baropt->state & QStyle::State_Horizontal);
1674 proxy()->drawItemText(painter, baropt->rect, Qt::AlignCenter | Qt::TextSingleLine,
1675 baropt->palette, baropt->state & State_Enabled, baropt->text,
1681 case CE_PushButtonLabel:
1682 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1683 QStyleOptionButton btnCopy(*btn);
1684 btnCopy.rect = btn->rect.marginsRemoved(QMargins(contentHMargin, 0, contentHMargin, 0));
1685 btnCopy.palette.setBrush(QPalette::ButtonText, controlTextColor(option));
1686 QCommonStyle::drawControl(element, &btnCopy, painter, widget);
1689 case CE_PushButtonBevel:
1690 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1691 using namespace StyleOptionHelper;
1692 QPainterStateGuard psg(
painter);
1694 const auto rect = QRectF(btn->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1695 if (btn->features.testFlag(QStyleOptionButton::Flat)) {
1696 const QBrush brush = isPressed(option)
1697 ? winUI3Color(subtlePressedColor)
1698 : (isHover(option) ? winUI3Color(subtleHighlightColor) : Qt::transparent);
1699 drawRoundedRect(painter, rect, Qt::NoPen, brush);
1701 const bool defaultButton = btn->features.testFlag(QStyleOptionButton::DefaultButton);
1702 const QPen pen = defaultButton ? option->palette.color(QPalette::Accent)
1703 : winUI3Color(controlStrokePrimary);
1704 drawRoundedRect(painter, rect, pen, controlFillBrush(option, ControlType::Control));
1706 if (btn->features.testFlag(QStyleOptionButton::HasMenu)) {
1708 const auto indSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
1709 const auto indRect =
1712 const auto vindRect = visualRect(btn->direction, btn->rect, indRect);
1713 textRect.setWidth(textRect.width() - indSize);
1715 int fontSize = painter->font().pointSize();
1716 QFont f(d->assetFont);
1717 f.setPointSize(qRound(fontSize * 0.9f));
1718 painter->setFont(f);
1719 painter->setPen(controlTextColor(option));
1720 painter->drawText(vindRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
1724 case CE_MenuBarItem:
1725 if (
const auto *mbi = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1726 using namespace StyleOptionHelper;
1728 constexpr int hPadding = 11;
1729 constexpr int topPadding = 4;
1730 constexpr int bottomPadding = 6;
1731 QStyleOptionMenuItem newMbi = *mbi;
1733 if (
auto mbiV2 = qstyleoption_cast<
const QStyleOptionMenuItemV2 *>(option))
1734 newMbi.state.setFlag(State_Sunken, mbiV2->mouseDown);
1736 newMbi.font.setPointSize(10);
1737 newMbi.palette.setColor(QPalette::ButtonText, controlTextColor(&newMbi));
1738 if (!isDisabled(&newMbi)) {
1739 QPen pen(Qt::NoPen);
1740 QBrush brush(Qt::NoBrush);
1741 if (highContrastTheme) {
1742 pen = QPen(newMbi.palette.highlight().color(), 2);
1743 brush = newMbi.palette.window();
1744 }
else if (isPressed(&newMbi)) {
1745 brush = winUI3Color(subtlePressedColor);
1746 }
else if (isHover(&newMbi)) {
1747 brush = winUI3Color(subtleHighlightColor);
1749 if (pen != Qt::NoPen || brush != Qt::NoBrush) {
1750 const QRect rect = mbi->rect.marginsRemoved(QMargins(5, 0, 5, 0));
1751 drawRoundedRect(painter, rect, pen, brush);
1754 newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
1755 painter->setFont(newMbi.font);
1756 QCommonStyle::drawControl(element, &newMbi, painter, widget);
1761 case CE_MenuEmptyArea:
1765 if (
const auto *menuitem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1766 using namespace StyleOptionHelper;
1768 const auto visualMenuRect = [&](
const QRect &rect) {
1769 return visualRect(option->direction, menuitem->rect, rect);
1772 const bool checked =
1773 menuitem->checkType != QStyleOptionMenuItem::NotCheckable && menuitem->checked;
1775 const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2));
1776 if (!isDisabled(menuitem)) {
1777 QPen pen(Qt::NoPen);
1778 QBrush brush(Qt::NoBrush);
1779 if (highContrastTheme) {
1780 pen = QPen(menuitem->palette.highlight().color(), 2);
1781 brush = menuitem->palette.window();
1782 }
else if (isPressed(menuitem)) {
1783 brush = winUI3Color(subtlePressedColor);
1784 }
else if (isSelected(menuitem)) {
1785 brush = winUI3Color(subtleHighlightColor);
1787 if (pen != Qt::NoPen || brush != Qt::NoBrush)
1788 drawRoundedRect(painter, rect, pen, brush);
1790 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
1791 constexpr int yoff = 1;
1792 painter->setPen(highContrastTheme ? menuitem->palette.buttonText().color() : winUI3Color(dividerStrokeDefault));
1793 painter->drawLine(menuitem->rect.topLeft() + QPoint(0, yoff),
1794 menuitem->rect.topRight() + QPoint(0, yoff));
1798 int xOffset = contentHMargin;
1800 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
1802 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset, rect.y(),
1803 checkMarkWidth, rect.height())));
1804 QPainterStateGuard psg(painter);
1805 painter->setFont(d->assetFont);
1806 painter->setPen(option->palette.text().color());
1807 painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
1809 if (menuitem->menuHasCheckableItems)
1810 xOffset += checkMarkWidth + contentItemHMargin;
1811 if (!menuitem->icon.isNull()) {
1813 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset,
1815 menuitem->maxIconWidth - 4,
1817 const auto mode = isDisabled(menuitem)
1819 : (isSelected(menuitem) ? QIcon::Active : QIcon::Normal);
1820 const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
1821 QRect pmr(QPoint(0, 0), QSize(size, size));
1822 pmr.moveCenter(vRect.center());
1823 menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode,
1824 checked ? QIcon::On : QIcon::Off);
1826 if (menuitem->maxIconWidth > 0)
1827 xOffset += menuitem->maxIconWidth - 4 + contentItemHMargin;
1829 QStringView s(menuitem->text);
1831 QPoint tl(rect.left() + xOffset, rect.top());
1832 QPoint br(rect.right() - menuitem->reservedShortcutWidth - contentHMargin,
1834 QRect textRect(tl, br);
1835 QRect vRect(visualMenuRect(textRect));
1838 if (highContrastTheme) {
1839 penColor = menuitem->palette.color(
1840 isSelected(menuitem) ? QPalette::HighlightedText : QPalette::Text);
1842 QStyleOption tmpOpt(*option);
1843 tmpOpt.state.setFlag(State_Sunken,
false);
1844 penColor = controlTextColor(&tmpOpt);
1846 painter->setPen(penColor);
1848 qsizetype t = s.indexOf(u'\t');
1849 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1850 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
1851 text_flags |= Qt::TextHideMnemonic;
1852 text_flags |= Qt::AlignLeft;
1854 if (t >= 0 && menuitem->menuItemType != QStyleOptionMenuItem::SubMenu) {
1855 QRect shortcutRect(QPoint(textRect.right(), textRect.top()),
1856 QPoint(rect.right(), textRect.bottom()));
1857 QRect vShortcutRect(visualMenuRect(shortcutRect));
1858 const QString textToDraw = s.mid(t + 1).toString();
1859 painter->drawText(vShortcutRect, text_flags, textToDraw);
1862 QFont font = menuitem->font;
1863 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1865 painter->setFont(font);
1866 const QString textToDraw = s.left(t).toString();
1867 painter->drawText(vRect, text_flags, textToDraw);
1869 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
1870 int fontSize = menuitem->font.pointSize();
1871 QFont f(d->assetFont);
1872 f.setPointSize(qRound(fontSize * 0.9f));
1873 painter->setFont(f);
1874 int yOfs = qRound(fontSize / 3.0f);
1875 QPoint tl(rect.right() - 2 * QWindowsStylePrivate::windowsArrowHMargin - contentItemHMargin,
1877 QRect submenuRect(tl, rect.bottomRight());
1878 QRect vSubMenuRect = visualMenuRect(submenuRect);
1879 painter->setPen(option->palette.text().color());
1880 const bool isReverse = option->direction == Qt::RightToLeft;
1881 const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
1882 painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
1887 case CE_MenuBarEmptyArea: {
1890 case CE_HeaderEmptyArea:
1892 case CE_HeaderSection: {
1893 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1894 painter->setPen(Qt::NoPen);
1895 painter->setBrush(header->palette.button());
1896 painter->drawRect(header->rect);
1897 const bool isRtl = option->direction == Qt::RightToLeft;
1898 const QPointF tr = isRtl ? option->rect.topLeft() : option->rect.topRight();
1899 const QPointF br = isRtl ? option->rect.bottomLeft() : option->rect.bottomRight();
1900 const QPointF bl = isRtl ? option->rect.bottomRight() : option->rect.bottomLeft();
1901 constexpr QPointF trOfs = QPointF(0.5, 0.0);
1902 constexpr QPointF brOfs = QPointF(0.5, 0.5);
1903 constexpr QPointF blOfs = QPointF(0.0, 0.5);
1904 const std::array<
QPointF, 3> points = { tr + trOfs, br + brOfs, bl + blOfs };
1905 QPen pen(highContrastTheme ? header->palette.buttonText().color()
1906 : winUI3Color(frameColorLight));
1907 pen.setJoinStyle(Qt::MiterJoin);
1908 painter->setPen(pen);
1909 painter->drawPolyline(points.data(),
int(points.size()));
1913 case CE_ItemViewItem: {
1914 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1915 const auto p = proxy();
1916 QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
1917 QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
1918 QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget);
1921 proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
1923 const QRect &rect = vopt->rect;
1924 const bool isRtl = option->direction == Qt::RightToLeft;
1925 bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1926 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1927 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1928 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1930 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1931 if (qobject_cast<
const QTableView *>(view)) {
1935 if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
1936 vopt->showDecorationSelected) {
1948 }
else if (isLast) {
1955 const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
1956 if (highlightCurrent) {
1957 if (highContrastTheme) {
1958 painter->setBrush(vopt->palette.highlight());
1960 painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
1961 ? calculateAccentColor(option)
1962 : winUI3Color(subtleHighlightColor));
1965 painter->setBrush(vopt->backgroundBrush);
1967 painter->setPen(Qt::NoPen);
1970 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
1971 secondLevelRoundingRadius, secondLevelRoundingRadius);
1972 }
else if (isFirst) {
1973 QPainterStateGuard psg(
painter);
1974 painter->setClipRect(rect);
1975 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1976 secondLevelRoundingRadius, secondLevelRoundingRadius);
1977 }
else if (isLast) {
1978 QPainterStateGuard psg(
painter);
1979 painter->setClipRect(rect);
1980 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1981 secondLevelRoundingRadius, secondLevelRoundingRadius);
1983 painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1987 if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
1988 QStyleOptionViewItem option(*vopt);
1989 option.rect = checkRect;
1990 option.state = option.state & ~QStyle::State_HasFocus;
1992 switch (vopt->checkState) {
1994 option.state |= QStyle::State_Off;
1996 case Qt::PartiallyChecked:
1997 option.state |= QStyle::State_NoChange;
2000 option.state |= QStyle::State_On;
2003 proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
2007 if (iconRect.isValid()) {
2008 QIcon::Mode mode = QIcon::Normal;
2009 if (!(vopt->state & QStyle::State_Enabled))
2010 mode = QIcon::Disabled;
2011 else if (vopt->state & QStyle::State_Selected)
2012 mode = QIcon::Selected;
2013 QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
2014 vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
2017 if (highlightCurrent && highContrastTheme) {
2018 painter->setPen(vopt->palette.base().color());
2019 }
else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
2020 painter->setPen(winUI3Color(textOnAccentPrimary));
2022 painter->setPen(vopt->palette.text().color());
2024 d->viewItemDrawText(painter, vopt, textRect);
2027 if (vopt->state & State_Selected && !highContrastTheme) {
2028 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2029 lv && lv->viewMode() != QListView::IconMode) {
2030 const auto col = vopt->palette.accent().color();
2031 painter->setBrush(col);
2032 painter->setPen(col);
2033 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
2034 const auto yOfs = rect.height() / 4.;
2035 QRectF r(
QPointF(xPos, rect.y() + yOfs),
2036 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
2037 painter->drawRoundedRect(r, 1, 1);
2044 QWindowsVistaStyle::drawControl(element, option, painter, widget);
2217QRect QWindows11Style::subControlRect(ComplexControl control,
const QStyleOptionComplex *option,
2218 SubControl subControl,
const QWidget *widget)
const
2223#if QT_CONFIG(spinbox)
2225 if (
const QStyleOptionSpinBox *spinbox = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2226 const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
2227 const int fw = spinbox->frame
2228 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
2230 const int buttonHeight = hasButtons
2231 ? qMin(spinbox->rect.height() - 3 * fw, spinbox->fontMetrics.height() * 5 / 4)
2233 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2234 const int textFieldLength = spinbox->rect.width() - 2 * fw - 2 * buttonSize.width();
2235 const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
2236 switch (subControl) {
2238 case SC_SpinBoxDown: {
2241 const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2242 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2243 buttonSize.height());
2244 if (subControl == SC_SpinBoxDown)
2245 ret.moveRight(ret.right() + buttonSize.width());
2248 case SC_SpinBoxEditField:
2249 ret = QRect(topLeft,
2250 spinbox->rect.bottomRight() - QPoint(fw + 2 * buttonSize.width(), fw));
2252 case SC_SpinBoxFrame:
2253 ret = spinbox->rect;
2257 ret = visualRect(spinbox->direction, spinbox->rect, ret);
2261 if (
const QStyleOptionTitleBar *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(option)) {
2262 SubControl sc = subControl;
2263 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2264 static constexpr int indent = 3;
2265 static constexpr int controlWidthMargin = 2;
2266 const int controlHeight = titlebar->rect.height();
2267 const int controlWidth = 46;
2268 const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
2269 int offset = -(controlWidthMargin + indent);
2271 bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
2272 bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
2275 case SC_TitleBarLabel:
2276 if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
2277 ret = titlebar->rect;
2278 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2279 ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
2280 if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
2281 ret.adjust(0, 0, -controlWidth, 0);
2282 if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
2283 ret.adjust(0, 0, -controlWidth, 0);
2284 if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
2285 ret.adjust(0, 0, -controlWidth, 0);
2286 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2287 ret.adjust(0, 0, -controlWidth, 0);
2290 case SC_TitleBarContextHelpButton:
2291 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2292 offset += controlWidth;
2294 case SC_TitleBarMinButton:
2295 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2296 offset += controlWidth;
2297 else if (sc == SC_TitleBarMinButton)
2300 case SC_TitleBarNormalButton:
2301 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2302 offset += controlWidth;
2303 else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2304 offset += controlWidth;
2305 else if (sc == SC_TitleBarNormalButton)
2308 case SC_TitleBarMaxButton:
2309 if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2310 offset += controlWidth;
2311 else if (sc == SC_TitleBarMaxButton)
2314 case SC_TitleBarShadeButton:
2315 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2316 offset += controlWidth;
2317 else if (sc == SC_TitleBarShadeButton)
2320 case SC_TitleBarUnshadeButton:
2321 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2322 offset += controlWidth;
2323 else if (sc == SC_TitleBarUnshadeButton)
2326 case SC_TitleBarCloseButton:
2327 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2328 offset += controlWidth;
2329 else if (sc == SC_TitleBarCloseButton)
2331 ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
2332 controlWidth, controlHeight);
2334 case SC_TitleBarSysMenu:
2335 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
2336 const auto yOfs = titlebar->rect.top() + (titlebar->rect.height() - iconSize) / 2;
2337 ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, yOfs, iconSize,
2344 if (widget && isMinimized && titlebar->rect.width() < offset)
2345 const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
2346 ret = visualRect(titlebar->direction, titlebar->rect, ret);
2352 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2354 if (subControl == SC_ScrollBarAddLine || subControl == SC_ScrollBarSubLine) {
2355 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
2356 if (scrollbar->orientation == Qt::Vertical)
2357 ret = ret.adjusted(2,2,-2,-3);
2359 ret = ret.adjusted(3,2,-2,-2);
2365 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2366 const auto indicatorWidth =
2367 proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2368 switch (subControl) {
2369 case SC_ComboBoxArrow: {
2371 cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
2372 const int buttonHeight =
2373 qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
2374 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2375 const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
2376 const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
2377 const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2378 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2379 buttonSize.height());
2380 ret = visualRect(option->direction, option->rect, ret);
2383 case SC_ComboBoxEditField: {
2386 const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
2387 ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
2389 ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
2390 ret = visualRect(option->direction, option->rect, ret);
2394 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2400#if QT_CONFIG(groupbox)
2402 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2403 switch (subControl) {
2404 case SC_GroupBoxCheckBox:
2414 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2422QSize QWindows11Style::sizeFromContents(ContentsType type,
const QStyleOption *option,
2423 const QSize &size,
const QWidget *widget)
const
2425 QSize contentSize(size);
2429#if QT_CONFIG(menubar)
2430 case CT_MenuBarItem:
2431 if (!contentSize.isEmpty()) {
2432 constexpr int hMargin = 2 * 6;
2433 constexpr int hPadding = 2 * 11;
2434 constexpr int itemHeight = 32;
2435 contentSize.setWidth(contentSize.width() + hMargin + hPadding);
2436#if QT_CONFIG(tabwidget)
2437 if (widget->parent() && !qobject_cast<
const QTabWidget *>(widget->parent()))
2439 contentSize.setHeight(itemHeight);
2445 if (
const auto *menuItem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
2446 int width = size.width();
2448 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
2452 height = menuItem->fontMetrics.height() + 8;
2453 if (!menuItem->icon.isNull()) {
2454 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
2455 height = qMax(height,
2456 menuItem->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
2459 if (menuItem->text.contains(u'\t'))
2460 width += contentItemHMargin;
2461 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
2462 width += 2 * QWindowsStylePrivate::windowsArrowHMargin + contentItemHMargin;
2463 if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
2464 const QFontMetrics fm(menuItem->font);
2465 QFont fontBold = menuItem->font;
2466 fontBold.setBold(
true);
2467 const QFontMetrics fmBold(fontBold);
2468 width += fmBold.horizontalAdvance(menuItem->text) - fm.horizontalAdvance(menuItem->text);
2471 if (menuItem->menuHasCheckableItems) {
2472 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
2473 width += checkMarkWidth + contentItemHMargin * 2;
2477 if (menuItem->maxIconWidth > 0)
2478 width += contentItemHMargin * 2 + menuItem->maxIconWidth - 4;
2480 width += 2 * contentHMargin;
2483 contentSize = QSize(width, height);
2487#if QT_CONFIG(spinbox)
2489 if (
const auto *spinBoxOpt = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2491 const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
2492 const int margins = 8;
2493 const int buttonWidth = hasButtons ? 16 + contentItemHMargin : 0;
2494 const int frameWidth = spinBoxOpt->frame
2495 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
2498 contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
2503#if QT_CONFIG(combobox)
2505 if (
const auto *comboBoxOpt = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2506 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2507 contentSize += QSize(0, 4);
2508 if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
2509 const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2510 contentSize.rwidth() += w + contentItemHMargin;
2516 if (qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
2517 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2518 contentSize += QSize(0, 4);
2522 case CT_HeaderSection:
2525 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2527 case CT_RadioButton:
2529 if (
const auto *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
2530 const auto p = proxy();
2531 const bool isRadio = (type == CT_RadioButton);
2533 const int width = p->pixelMetric(
2534 isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, option, widget);
2535 const int height = p->pixelMetric(
2536 isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, option, widget);
2539 if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
2540 margins += p->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
2541 : PM_CheckBoxLabelSpacing,
2545 contentSize += QSize(width + margins, 4);
2546 contentSize.setHeight(qMax(size.height(), height + 2 * contentItemHMargin));
2552 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2553 if (size.width() == 0)
2554 contentSize.rwidth() += 2;
2556 case CT_PushButton: {
2557 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2559 const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
2560 contentSize.rwidth() += 2 * contentHMargin - oldMargin;
2563 case CT_ToolButton: {
2565 if (
const auto tb = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
2567 if (!tb->subControls.testFlag(SC_ToolButtonMenu)) {
2568 if (tb->features.testFlag(QStyleOptionToolButton::HasMenu))
2569 contentSize.rwidth() += 2;
2571 if (tb->toolButtonStyle == Qt::ToolButtonTextBesideIcon
2572 || tb->toolButtonStyle == Qt::ToolButtonIconOnly) {
2573 contentSize.rheight() = qMax(contentSize.height(), tb->iconSize.height() + 4);
2576 const auto fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
2577 contentSize += QSize(contentHMargin + 2 * fw, 2 * fw);
2580 case CT_ItemViewItem: {
2581 if (
const auto *viewItemOpt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
2582 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2583 lv && lv->viewMode() != QListView::IconMode) {
2584 QStyleOptionViewItem vOpt(*viewItemOpt);
2588 vOpt.rect.setRight(vOpt.rect.right() - contentHMargin);
2589 contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget);
2590 contentSize.rwidth() += contentHMargin;
2591 contentSize.rheight() += 2 * contentHMargin;
2594 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2600 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);