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 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
437 drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
439 if (sb->frame && (sub & SC_SpinBoxFrame))
440 drawLineEditFrame(painter, frameRect, option);
442 const auto drawUpDown = [&](QStyle::SubControl sc,
443 QAbstractSpinBox::StepEnabledFlag flag) {
444 const bool isEnabled =
445 state.testFlag(QStyle::State_Enabled) && sb->stepEnabled.testFlag(flag);
446 const bool isUp = sc == SC_SpinBoxUp;
447 const QRect rect = proxy()->subControlRect(CC_SpinBox, option, sc, widget);
448 if (isEnabled && sb->activeSubControls & sc)
449 drawRoundedRect(painter, rect.adjusted(1, 1, -1, -2), Qt::NoPen,
450 winUI3Color(subtleHighlightColor));
451 painter->setFont(d->assetFont);
452 painter->setPen(sb->palette.color(isEnabled ? QPalette::Active : QPalette::Disabled,
453 QPalette::ButtonText));
454 painter->setBrush(Qt::NoBrush);
455 painter->drawText(rect, Qt::AlignCenter, fluentIcon(isUp ? Icon::ChevronUp : Icon::ChevronDown));
457 if (sub & SC_SpinBoxUp)
458 drawUpDown(SC_SpinBoxUp, QAbstractSpinBox::StepUpEnabled);
459 if (sub & SC_SpinBoxDown)
460 drawUpDown(SC_SpinBoxDown, QAbstractSpinBox::StepDownEnabled);
461 if (state & State_KeyboardFocusChange && state & State_HasFocus) {
462 QStyleOptionFocusRect fropt;
463 fropt.QStyleOption::operator=(*option);
464 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
471 if (
const auto *slider = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
472 const auto &slrect = slider->rect;
473 const bool isHorizontal = slider->orientation == Qt::Horizontal;
474 const QRectF handleRect(proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget));
475 const QPointF handleCenter(handleRect.center());
477 if (sub & SC_SliderGroove) {
478 QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
483 rect = QRectF(rect.left() + 2, rect.center().y() - 2, rect.width() - 2, 4);
484 leftRect = QRectF(rect.left(), rect.top(), handleCenter.x() - rect.left(),
486 rightRect = QRectF(handleCenter.x(), rect.top(),
487 rect.width() - handleCenter.x(),
490 rect = QRect(rect.center().x() - 2, rect.top() + 2, 4, rect.height() - 2);
491 leftRect = QRectF(rect.left(), rect.top(), rect.width(),
492 handleCenter.y() - rect.top());
493 rightRect = QRectF(rect.left(), handleCenter.y(), rect.width(),
494 rect.height() - handleCenter.y());
496 if (slider->upsideDown)
497 qSwap(leftRect, rightRect);
499 painter->setPen(Qt::NoPen);
500 painter->setBrush(calculateAccentColor(option));
501 painter->drawRoundedRect(leftRect,1,1);
502 painter->setBrush(WINUI3Colors[colorSchemeIndex][controlStrongFill]);
503 painter->drawRoundedRect(rightRect,1,1);
505 if (sub & SC_SliderTickmarks) {
506 int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
507 int ticks = slider->tickPosition;
508 int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
509 int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
510 int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
511 int interval = slider->tickInterval;
513 interval = slider->singleStep;
514 if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
516 - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
518 interval = slider->pageStep;
523 painter->setPen(slider->palette.text().color());
524 QVarLengthArray<QLineF, 32> lines;
525 int v = slider->minimum;
526 while (v <= slider->maximum + 1) {
527 if (v == slider->maximum + 1 && interval == 1)
529 const int v_ = qMin(v, slider->maximum);
530 int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
531 int pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, v_,
532 available, slider->upsideDown);
535 if (ticks & QSlider::TicksAbove) {
536 lines.append(QLineF(pos, tickOffset - 0.5,
537 pos, tickOffset - tickLength - 0.5));
540 if (ticks & QSlider::TicksBelow) {
541 lines.append(QLineF(pos, tickOffset + thickness + 0.5,
542 pos, tickOffset + thickness + tickLength + 0.5));
545 if (ticks & QSlider::TicksAbove) {
546 lines.append(QLineF(tickOffset - 0.5, pos,
547 tickOffset - tickLength - 0.5, pos));
550 if (ticks & QSlider::TicksBelow) {
551 lines.append(QLineF(tickOffset + thickness + 0.5, pos,
552 tickOffset + thickness + tickLength + 0.5, pos));
556 int nextInterval = v + interval;
557 if (nextInterval < v)
561 if (!lines.isEmpty()) {
562 QPainterStateGuard psg(painter);
563 painter->translate(slrect.topLeft());
564 painter->drawLines(lines.constData(), lines.size());
567 if (sub & SC_SliderHandle) {
568 const qreal outerRadius = qMin(8.0, (isHorizontal ? handleRect.height() / 2.0 : handleRect.width() / 2.0) - 1);
569 float innerRadius = outerRadius * 0.43;
571 if (option->styleObject) {
572 const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
573 if (animation !=
nullptr) {
574 innerRadius = animation->currentValue();
575 option->styleObject->setProperty(
"_q_inner_radius", innerRadius);
577 bool isInsideHandle = option->activeSubControls == SC_SliderHandle;
578 innerRadius = outerRadius * sliderInnerRadius(state, isInsideHandle);
582 painter->setPen(Qt::NoPen);
583 painter->setBrush(winUI3Color(controlFillSolid));
584 painter->drawEllipse(handleCenter, outerRadius, outerRadius);
585 painter->setBrush(calculateAccentColor(option));
586 painter->drawEllipse(handleCenter, innerRadius, innerRadius);
588 painter->setPen(winUI3Color(controlStrokeSecondary));
589 painter->setBrush(Qt::NoBrush);
590 painter->drawEllipse(handleCenter, outerRadius + 0.5, outerRadius + 0.5);
592 if (slider->state & State_HasFocus) {
593 QStyleOptionFocusRect fropt;
594 fropt.QStyleOption::operator=(*slider);
595 fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
596 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
601#if QT_CONFIG(combobox)
603 if (
const QStyleOptionComboBox *combobox = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
604 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
605 QStyleOption opt(*option);
606 opt.state.setFlag(QStyle::State_On,
false);
607 drawRoundedRect(painter, frameRect, Qt::NoPen,
608 combobox->editable ? inputFillBrush(option, widget)
609 : controlFillBrush(&opt, ControlType::Control));
612 drawLineEditFrame(painter, frameRect, combobox, combobox->editable);
614 const bool hasFocus = state & State_HasFocus;
616 if (sub & SC_ComboBoxArrow) {
617 QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
618 painter->setFont(d->assetFont);
619 painter->setPen(controlTextColor(option,
true));
620 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
622 if (state & State_KeyboardFocusChange && hasFocus) {
623 QStyleOptionFocusRect fropt;
624 fropt.QStyleOption::operator=(*option);
625 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
631 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
632 const bool vertical = scrollbar->orientation == Qt::Vertical;
633 const bool isMouseOver = state & State_MouseOver;
634 const auto prx = proxy();
636 QPainterStateGuard psg(
painter);
638 const auto anim = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
639 qreal widthFactor = isMouseOver ? 1.0 : 0.0;
641 widthFactor = anim->currentValue();
643 if (widthFactor > 0.6) {
644 const bool isRtl = option->direction == Qt::RightToLeft;
646 QFont f = QFont(d->assetFont);
649 painter->setPen(winUI3Color(controlStrongFill));
651 const QRectF rectAdd =
652 prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
653 const auto strAdd = vertical
654 ? Icon::CaretDownSolid8
655 : (isRtl ? Icon::CaretLeftSolid8 : Icon::CaretRightSolid8);
656 painter->drawText(rectAdd, Qt::AlignCenter, fluentIcon(strAdd));
658 const QRectF rectSub =
659 prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
660 const auto strSub = vertical
661 ? Icon::CaretUpSolid8
662 : (isRtl ? Icon::CaretRightSolid8 : Icon::CaretLeftSolid8);
663 painter->drawText(rectSub, Qt::AlignCenter, fluentIcon(strSub));
665 if (sub & SC_ScrollBarSlider) {
666 QRectF rect = prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
667 const QPointF center = rect.center();
669 auto w = rect.width() / 2. * widthFactor;
672 const auto ofs = rect.width() / 2 - w;
674 rect.moveCenter(QPointF(center.x() + ofs, center.y()));
677 auto h = rect.height() / 2. * widthFactor;
680 const auto ofs = rect.height() / 2 - h;
682 rect.moveCenter(QPointF(center.x(), center.y() + ofs));
684 drawRoundedRect(painter, rect, Qt::NoPen, winUI3Color(controlStrongFill), 3);
688 case CC_MdiControls:{
689 QFont buttonFont = QFont(d->assetFont);
690 buttonFont.setPointSize(8);
691 painter->setFont(buttonFont);
692 drawTitleBarCloseButton(CC_MdiControls, SC_MdiCloseButton, Icon::ChromeClose);
693 drawTitleBarButton(CC_MdiControls, SC_MdiNormalButton, Icon::ChromeRestore);
694 drawTitleBarButton(CC_MdiControls, SC_MdiMinButton, Icon::ChromeMinimize);
698 if (
const auto* titlebar = qstyleoption_cast<
const QStyleOptionTitleBar*>(option)) {
699 painter->setPen(Qt::NoPen);
700 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
701 painter->setBrush(titlebar->palette.button());
702 painter->drawRect(titlebar->rect);
705 QRect textRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
706 QColor textColor = titlebar->palette.color(titlebar->titleBarState & Qt::WindowActive ? QPalette::Active : QPalette::Disabled,QPalette::WindowText);
707 painter->setPen(textColor);
709 QString title = painter->fontMetrics().elidedText(titlebar->text, Qt::ElideRight, textRect.width() - 14);
710 painter->drawText(textRect.adjusted(1, 1, -1, -1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
712 QFont buttonFont = QFont(d->assetFont);
713 buttonFont.setPointSize(8);
714 painter->setFont(buttonFont);
715 auto shouldDrawButton = [titlebar](SubControl sc, Qt::WindowType flag) {
716 return (titlebar->subControls & sc) && (titlebar->titleBarFlags & flag);
720 if (shouldDrawButton(SC_TitleBarMinButton, Qt::WindowMinimizeButtonHint) &&
721 !(titlebar->titleBarState & Qt::WindowMinimized)) {
722 drawTitleBarButton(CC_TitleBar, SC_TitleBarMinButton, Icon::ChromeMinimize);
726 if (shouldDrawButton(SC_TitleBarMaxButton, Qt::WindowMaximizeButtonHint) &&
727 !(titlebar->titleBarState & Qt::WindowMaximized)) {
728 drawTitleBarButton(CC_TitleBar, SC_TitleBarMaxButton, Icon::ChromeMaximize);
732 if (shouldDrawButton(SC_TitleBarCloseButton, Qt::WindowSystemMenuHint))
733 drawTitleBarCloseButton(CC_TitleBar, SC_TitleBarCloseButton, Icon::ChromeClose);
736 if ((titlebar->subControls & SC_TitleBarNormalButton) &&
737 (((titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
738 (titlebar->titleBarState & Qt::WindowMinimized)) ||
739 ((titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
740 (titlebar->titleBarState & Qt::WindowMaximized)))) {
741 drawTitleBarButton(CC_TitleBar, SC_TitleBarNormalButton, Icon::ChromeRestore);
745 if (shouldDrawButton(SC_TitleBarContextHelpButton, Qt::WindowContextHelpButtonHint))
746 drawTitleBarButton(CC_TitleBar, SC_TitleBarContextHelpButton, Icon::Help);
749 if (shouldDrawButton(SC_TitleBarShadeButton, Qt::WindowShadeButtonHint))
750 drawTitleBarButton(CC_TitleBar, SC_TitleBarShadeButton, Icon::ChevronUpSmall);
753 if (shouldDrawButton(SC_TitleBarUnshadeButton, Qt::WindowShadeButtonHint))
754 drawTitleBarButton(CC_TitleBar, SC_TitleBarUnshadeButton, Icon::ChevronDownSmall);
757 if (shouldDrawButton(SC_TitleBarSysMenu, Qt::WindowSystemMenuHint)) {
758 const QRect iconRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarSysMenu, widget);
759 if (iconRect.isValid()) {
760 if (!titlebar->icon.isNull()) {
761 titlebar->icon.paint(painter, iconRect);
763 QStyleOption tool = *titlebar;
764 const auto extent = proxy()->pixelMetric(PM_SmallIconSize, &tool, widget);
765 const auto dpr = QStyleHelper::getDpr(widget);
766 const auto icon = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget);
767 const auto pm = icon.pixmap(QSize(extent, extent), dpr);
768 proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm);
774#if QT_CONFIG(toolbutton)
776 if (
const auto toolbutton = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
778 const bool isSplitButton =
779 toolbutton->features.testFlag(QStyleOptionToolButton::MenuButtonPopup);
780 const auto fw = prx->pixelMetric(PM_DefaultFrameWidth, option, widget);
781 const auto buttonRect = prx->subControlRect(control, toolbutton, SC_ToolButton, widget);
782 const auto menuareaRect = isSplitButton
783 ? prx->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget)
786 State bflags = toolbutton->state;
787 State mflags = toolbutton->state;
788 if (toolbutton->activeSubControls.testFlag(SC_ToolButton)) {
789 mflags &= ~(State_Sunken | State_MouseOver);
790 if (bflags.testFlag(State_Sunken))
791 mflags |= State_Raised;
793 if (toolbutton->activeSubControls.testFlag(SC_ToolButtonMenu)) {
794 bflags &= ~(State_Sunken | State_MouseOver);
795 if (mflags.testFlag(State_Sunken))
796 bflags |= State_Raised;
799 QStyleOption tool = *toolbutton;
800 if (toolbutton->subControls.testFlag(SC_ToolButton)) {
801 QPainterStateGuard psg(painter);
803 painter->setClipRect(buttonRect);
805 prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
807 if (state.testFlag(State_Enabled)) {
808 painter->setPen(winUI3Color(controlStrokePrimary));
809 const auto top = buttonRect.topRight() + QPoint(0, fw + 1);
810 const auto btm = buttonRect.bottomRight() - QPoint(0, fw);
811 painter->drawLine(top, btm);
816 if (toolbutton->state.testFlag(State_HasFocus)) {
817 QStyleOptionFocusRect fr;
818 fr.QStyleOption::operator=(*toolbutton);
819 prx->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget);
821 QStyleOptionToolButton label = *toolbutton;
822 label.state = bflags;
823 label.rect = buttonRect.marginsRemoved(QMargins(fw, fw, fw, fw));
825 if (toolbutton->subControls.testFlag(SC_ToolButtonMenu)) {
826 QPainterStateGuard psg(painter);
827 painter->setClipRect(menuareaRect);
829 prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
831 const int fontSize = painter->font().pointSize();
832 QFont f(d->assetFont);
833 f.setPointSize(qRound(fontSize * 0.9f));
835 painter->setPen(controlTextColor(option));
836 const QRect textRect(menuareaRect.topLeft(), menuareaRect.size() - QSize(fw, 0));
837 painter->drawText(textRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
839 }
else if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) {
840 const int mbi = qRound(prx->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget) * 0.3);
841 const QRect &ir = toolbutton->rect;
842 QRect rect(ir.right() - mbi - 2 * fw, ir.bottom() - mbi - fw, mbi,
844 rect = visualRect(toolbutton->direction, buttonRect, rect);
845 const QRect lblRect = label.rect - QMargins(0, 0, rect.width(), 0);
846 label.rect = visualRect(toolbutton->direction, buttonRect, lblRect);
847 painter->setFont(QFont(d->assetFont));
848 painter->setPen(controlTextColor(option));
849 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
851 prx->drawControl(CE_ToolButtonLabel, &label, painter, widget);
856 QWindowsVistaStyle::drawComplexControl(control, option, painter, widget);
860void QWindows11Style::drawPrimitive(PrimitiveElement element,
const QStyleOption *option,
862 const QWidget *widget)
const {
865 const State state = option->state;
866 QPainterStateGuard psg(
painter);
867 painter->setRenderHint(QPainter::Antialiasing);
868 if (d->transitionsEnabled() && option->styleObject && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) {
869 QObject *styleObject = option->styleObject;
870 int oldState = styleObject->property(
"_q_stylestate").toInt();
871 styleObject->setProperty(
"_q_stylestate",
int(option->state));
872 styleObject->setProperty(
"_q_stylerect", option->rect);
873 bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
874 || ((state & State_MouseOver) != (oldState & State_MouseOver))
875 || (state & State_On) != (oldState & State_On))
876 && state & State_Enabled);
878 if (element == PE_IndicatorRadioButton) {
879 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
880 t->setStartValue(styleObject->property(
"_q_inner_radius").toFloat());
881 t->setEndValue(radioButtonInnerRadius(state));
882 styleObject->setProperty(
"_q_end_radius", t->endValue());
883 t->setStartTime(d->animationTime());
885 d->startAnimation(t);
887 else if (element == PE_IndicatorCheckBox) {
888 if ((oldState & State_Off && state & State_On) || (oldState & State_NoChange && state & State_On)) {
889 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
890 t->setStartValue(0.0f);
891 t->setEndValue(1.0f);
892 t->setStartTime(d->animationTime());
894 d->startAnimation(t);
901 case PE_IndicatorArrowUp:
902 case PE_IndicatorArrowDown:
903 case PE_IndicatorArrowRight:
904 case PE_IndicatorArrowLeft: {
905 const QRect &r = option->rect;
906 if (r.width() <= 1 || r.height() <= 1)
908 Icon ico = Icon::Help;
910 case PE_IndicatorArrowUp:
911 ico = Icon::ChevronUpMed;
913 case PE_IndicatorArrowDown:
914 ico = Icon::ChevronDownMed;
916 case PE_IndicatorArrowLeft:
917 ico = Icon::ChevronLeftMed;
919 case PE_IndicatorArrowRight:
920 ico = Icon::ChevronRightMed;
925 QPainterStateGuard psg(
painter);
926 if (option->state.testFlag(State_Sunken)) {
927 const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget);
928 const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget);
929 if (bsx != 0 || bsy != 0)
930 painter->translate(bsx, bsy);
932 painter->setFont(d->assetFont);
933 painter->setPen(option->palette.buttonText().color());
934 painter->setBrush(option->palette.buttonText());
935 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
938 case PE_FrameFocusRect: {
939 if (
const QStyleOptionFocusRect *fropt = qstyleoption_cast<
const QStyleOptionFocusRect *>(option)) {
940 if (!(fropt->state & State_KeyboardFocusChange))
942 QRectF focusRect = option->rect;
943 focusRect = focusRect.marginsRemoved(QMarginsF(1.5,1.5,1.5,1.5));
944 painter->setPen(winUI3Color(focusFrameInnerStroke));
945 painter->drawRoundedRect(focusRect,4,4);
947 focusRect = focusRect.marginsAdded(QMarginsF(1.0,1.0,1.0,1.0));
948 painter->setPen(QPen(winUI3Color(focusFrameOuterStroke),1));
949 painter->drawRoundedRect(focusRect,4,4);
953 case PE_PanelTipLabel: {
954 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(0.5, 0.5, 0.5, 0.5));
955 const auto pen = highContrastTheme ? option->palette.buttonText().color()
956 : winUI3Color(frameColorLight);
957 drawRoundedRect(painter, rect, pen, option->palette.toolTipBase());
960 case PE_FrameTabWidget:
961#if QT_CONFIG(tabwidget)
962 if (
const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(option)) {
963 QPainterStateGuard psg(painter);
964 const auto clipRegion = painter->clipRegion();
966 painter->setPen(highContrastTheme ? frame->palette.buttonText().color()
967 : winUI3Color(frameColorLight));
968 painter->setBrush(frame->palette.base());
970 const auto &rect = option->rect;
971 QRect upperRect = rect;
972 upperRect.setHeight(rect.height() / 2);
973 QRect lowerRect = rect;
974 lowerRect.setY(lowerRect.y() + rect.height() / 2);
975 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
976 painter->drawRect(rect);
977 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
978 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
983 case PE_FrameGroupBox:
984 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
985 const auto pen = highContrastTheme ? frame->palette.buttonText().color()
986 : winUI3Color(frameColorStrong);
987 if (frame->features & QStyleOptionFrame::Flat) {
988 painter->setBrush(Qt::NoBrush);
989 painter->setPen(pen);
990 const QRect &fr = frame->rect;
991 QPoint p1(fr.x(), fr.y() + 1);
992 QPoint p2(fr.x() + fr.width(), p1.y());
993 painter->drawLine(p1, p2);
995 const auto frameRect = QRectF(frame->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
996 drawRoundedRect(painter, frameRect, pen, Qt::NoBrush);
1000 case PE_IndicatorHeaderArrow:
1001 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1002 const auto indicator = header->sortIndicator;
1003 if (indicator != QStyleOptionHeader::None) {
1004 QPainterStateGuard psg(
painter);
1005 QFont f(d->assetFont);
1006 f.setPointSize(option->rect.height());
1007 painter->setFont(f);
1008 painter->setPen(header->palette.text().color());
1009 const auto ico = indicator == QStyleOptionHeader::SortUp ? Icon::ChevronDown
1011 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1015 case PE_IndicatorCheckBox: {
1016 const bool isOn = option->state & State_On;
1017 const bool isPartial = option->state & State_NoChange;
1019 const QRectF rect = option->rect;
1020 const QPointF center = rect.center();
1022 drawRoundedRect(painter, option->rect, borderPenControlAlt(option),
1023 controlFillBrush(option, ControlType::ControlAlt));
1026 QFont f(d->assetFont);
1028 painter->setFont(f);
1029 painter->setPen(controlTextColor(option));
1030 const auto *animation =
1031 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1032 const qreal clipWidth = animation ? animation->currentValue() : 1.0;
1033 const QChar ico = fluentIcon(Icon::AcceptMedium);
1034 QFontMetrics fm(d->assetFont);
1035 QRectF clipRect = fm.boundingRect(ico);
1036 clipRect.moveCenter(center);
1037 clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0 + 0.5);
1038 clipRect.setWidth(clipWidth * clipRect.width());
1039 painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, ico);
1040 }
else if (isPartial) {
1041 QFont f(d->assetFont);
1043 painter->setFont(f);
1044 painter->setPen(controlTextColor(option));
1045 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::Dash12));
1049 case PE_IndicatorBranch: {
1050 if (option->state & State_Children) {
1051 const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option);
1052 const bool isReverse = option->direction == Qt::RightToLeft;
1053 const bool isOpen = option->state & QStyle::State_Open;
1054 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1055 QFont f(d->assetFont);
1057 painter->setFont(f);
1058 if (view && view->alternatingRowColors() && vopt && vopt->state & State_Selected)
1059 painter->setPen(winUI3Color(textOnAccentPrimary));
1061 painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
1062 QPalette::WindowText));
1063 const auto ico = isOpen ? Icon::ChevronDownMed
1064 : (isReverse ? Icon::ChevronLeftMed
1065 : Icon::ChevronRightMed);
1066 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1070 case PE_IndicatorRadioButton: {
1071 const auto *animation =
1072 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1073 const qreal innerRadius =
1074 animation ? animation->currentValue() : radioButtonInnerRadius(state);
1075 const QRectF rect = option->rect;
1076 const QPointF center = rect.center();
1078 if (option->styleObject)
1079 option->styleObject->setProperty(
"_q_inner_radius", innerRadius);
1080 painter->setPen(borderPenControlAlt(option));
1081 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1082 if (option->state.testFlag(State_On)) {
1084 path.addEllipse(center, 7.5, 7.5);
1085 path.addEllipse(center, innerRadius, innerRadius);
1086 painter->drawPath(path);
1088 painter->setBrush(option->palette.window().color());
1089 painter->drawEllipse(center, innerRadius, innerRadius);
1091 painter->drawEllipse(center, 7.5, 7.5);
1095 case PE_PanelButtonTool:
1096 case PE_PanelButtonBevel:{
1097 const bool isEnabled = state & QStyle::State_Enabled;
1098 const bool isMouseOver = state & QStyle::State_MouseOver;
1099 const bool isAutoRaise = state & QStyle::State_AutoRaise;
1100 const int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
1101 const QRectF rect = option->rect.marginsRemoved(QMargins(fw, fw, fw, fw));
1102 if (element == PE_PanelButtonTool && ((!isMouseOver && isAutoRaise) || !isEnabled))
1103 painter->setPen(Qt::NoPen);
1105 painter->setPen(winUI3Color(controlStrokePrimary));
1106 painter->setBrush(controlFillBrush(option, ControlType::Control));
1107 if (element == PE_PanelButtonTool && widget) {
1108 const auto name = widget->objectName();
1109 if (name ==
"ScrollLeftButton"_L1 || name ==
"ScrollRightButton"_L1) {
1110 painter->setPen(Qt::NoPen);
1112 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1114 painter->setBrush(Qt::NoBrush);
1117 painter->drawRoundedRect(rect,
1118 secondLevelRoundingRadius, secondLevelRoundingRadius);
1121 case PE_FrameDefaultButton:
1122 painter->setPen(option->palette.accent().color());
1123 painter->setBrush(Qt::NoBrush);
1124 painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1128 case PE_PanelMenu: {
1129 if (!d->nativeRoundedTopLevelWindows) {
1130 const QRect rect = option->rect.marginsRemoved(QMargins(2, 2, 2, 2));
1131 painter->setPen(highContrastTheme ? QPen(option->palette.windowText().color(), 2)
1132 : winUI3Color(frameColorLight));
1133 painter->setBrush(winUI3Color(menuPanelFill));
1134 painter->drawRoundedRect(rect, topLevelRoundingRadius, topLevelRoundingRadius);
1138 case PE_PanelLineEdit:
1139 if (
const auto *panel = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1140 const bool isInSpinBox =
1141 widget && qobject_cast<
const QAbstractSpinBox *>(widget->parent()) !=
nullptr;
1142 const bool isInComboBox =
1143 widget && qobject_cast<
const QComboBox *>(widget->parent()) !=
nullptr;
1144 if (!isInSpinBox && !isInComboBox) {
1145 const auto frameRect =
1146 QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1147 drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
1148 if (panel->lineWidth > 0)
1149 proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
1153 case PE_FrameLineEdit: {
1154 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1155 drawLineEditFrame(painter, frameRect, option);
1156 if (state & State_KeyboardFocusChange && state & State_HasFocus) {
1157 QStyleOptionFocusRect fropt;
1158 fropt.QStyleOption::operator=(*option);
1159 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
1164 if (
const auto *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1165 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1166 if (qobject_cast<
const QComboBoxPrivateContainer *>(widget)) {
1167 if (d->nativeRoundedTopLevelWindows)
1170 if (highContrastTheme)
1171 pen = QPen(option->palette.windowText().color(), 2);
1174 drawRoundedRect(painter, rect, pen, WINUI3Colors[colorSchemeIndex][menuPanelFill]);
1176 drawRoundedRect(painter, rect, Qt::NoPen, option->palette.brush(QPalette::Base));
1178 if (frame->frameShape == QFrame::NoFrame)
1181 const bool isEditable = qobject_cast<
const QTextEdit *>(widget) !=
nullptr
1182 || qobject_cast<
const QPlainTextEdit *>(widget) !=
nullptr;
1183 drawLineEditFrame(painter, rect, option, isEditable);
1187 case PE_PanelItemViewItem:
1188 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1189 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
1190 QPainterStateGuard psg(
painter);
1191 painter->setBrushOrigin(vopt->rect.topLeft());
1192 painter->fillRect(vopt->rect, vopt->backgroundBrush);
1196 case PE_PanelItemViewRow:
1197 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1201 const QRect &rect = vopt->rect;
1202 const bool isRtl = option->direction == Qt::RightToLeft;
1203 if (rect.width() <= 0)
1206 if (vopt->features & QStyleOptionViewItem::Alternate) {
1207 QPalette::ColorGroup cg =
1208 (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
1210 : QPalette::Disabled;
1211 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
1212 cg = QPalette::Inactive;
1213 painter->fillRect(rect, option->palette.brush(cg, QPalette::AlternateBase));
1216 if (option->state & State_Selected && !highContrastTheme) {
1218 if (!qobject_cast<
const QTableView *>(widget)) {
1219 const auto col = option->palette.accent().color();
1220 painter->setBrush(col);
1221 painter->setPen(col);
1222 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
1223 const auto yOfs = rect.height() / 4.;
1224 QRectF r(
QPointF(xPos, rect.y() + yOfs),
1225 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
1226 painter->drawRoundedRect(r, 1, 1);
1230 const bool isTreeDecoration = vopt->features.testFlag(
1231 QStyleOptionViewItem::IsDecorationForRootColumn);
1232 if (isTreeDecoration && vopt->state.testAnyFlags(State_Selected | State_MouseOver) &&
1233 vopt->showDecorationSelected) {
1234 const bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1235 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1236 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1237 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1247 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1248 painter->setBrush(view->alternatingRowColors() && state & State_Selected ? calculateAccentColor(option) : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
1249 painter->setPen(Qt::NoPen);
1251 QPainterStateGuard psg(
painter);
1252 painter->setClipRect(rect);
1253 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1254 secondLevelRoundingRadius, secondLevelRoundingRadius);
1255 }
else if (isLast) {
1256 QPainterStateGuard psg(
painter);
1257 painter->setClipRect(rect);
1258 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1259 secondLevelRoundingRadius, secondLevelRoundingRadius);
1261 painter->drawRect(vopt->rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1268 case QStyle::PE_FrameWindow:
1269 if (
const auto *frm = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1271 QRectF rect= option->rect;
1272 int fwidth =
int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
1274 QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
1275 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1276 secondLevelRoundingRadius,
1277 secondLevelRoundingRadius);
1278 QRectF bottomRightCorner = QRectF(rect.right() - 1.0 - secondLevelRoundingRadius,
1279 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1280 secondLevelRoundingRadius,
1281 secondLevelRoundingRadius);
1284 if (widget !=
nullptr) {
1285 QBitmap mask(widget->width(), widget->height());
1289 maskPainter.setRenderHint(QPainter::Antialiasing);
1290 maskPainter.setBrush(Qt::color1);
1291 maskPainter.setPen(Qt::NoPen);
1292 maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
1293 const_cast<QWidget*>(widget)->setMask(mask);
1297 painter->setPen(QPen(frm->palette.base(), fwidth));
1298 painter->drawLine(QPointF(rect.left(), rect.top()),
1299 QPointF(rect.left(), rect.bottom() - fwidth));
1300 painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
1301 QPointF(rect.right() - fwidth, rect.bottom()));
1302 painter->drawLine(QPointF(rect.right(), rect.top()),
1303 QPointF(rect.right(), rect.bottom() - fwidth));
1305 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1306 painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
1307 QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1308 painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
1309 QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
1310 painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
1311 QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1313 painter->setPen(Qt::NoPen);
1314 painter->setBrush(frm->palette.base());
1315 painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
1317 painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
1320 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1321 painter->setBrush(Qt::NoBrush);
1322 painter->drawArc(bottomRightCorner,
1324 painter->drawArc(bottomLeftCorner,
1328#if QT_CONFIG(tabbar)
1329 case PE_FrameTabBarBase:
1330 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTabBarBase *>(option)) {
1331 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1332 const auto clipRegion = painter->clipRegion();
1334 painter->setPen(highContrastTheme ? tab->palette.buttonText().color()
1335 : winUI3Color(frameColorLight));
1336 painter->setBrush(tab->palette.base());
1337 QRect upperRect = tab->rect;
1338 upperRect.setHeight(tab->rect.height() / 2);
1339 QRect lowerRect = tab->rect;
1340 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2);
1341 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1342 painter->drawRoundedRect(tab->rect, secondLevelRoundingRadius,
1343 secondLevelRoundingRadius);
1344 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1345 painter->drawRect(tab->rect);
1349 case PE_IndicatorTabTearLeft:
1350 case PE_IndicatorTabTearRight:
1353 QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
1360void QWindows11Style::drawControl(ControlElement element,
const QStyleOption *option,
1361 QPainter *painter,
const QWidget *widget)
const
1363 Q_D(
const QWindows11Style);
1365 QPainterStateGuard psg(
painter);
1366 painter->setRenderHint(QPainter::Antialiasing);
1368 case QStyle::CE_ComboBoxLabel:
1369#if QT_CONFIG(combobox)
1370 if (
const QStyleOptionComboBox *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
1371 painter->setPen(controlTextColor(option,
true));
1372 QStyleOptionComboBox newOption = *cb;
1373 newOption.rect.adjust(4,0,-4,0);
1374 QCommonStyle::drawControl(element, &newOption, painter, widget);
1378#if QT_CONFIG(tabbar)
1379 case CE_TabBarTabShape:
1380 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1381 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1382 const bool isSelected = tab->state.testFlag(State_Selected);
1383 const auto clipRegion = painter->clipRegion();
1384 const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab
1385 || tab->position == QStyleOptionTab::Moving;
1386 auto leftMargin = (tab->position == QStyleOptionTab::Beginning || onlyOne) ? 1 : 0;
1387 auto rightMargin = (tab->position == QStyleOptionTab::End || onlyOne) ? 1 : 0;
1388 if (QCommonStylePrivate::rtl(option))
1389 std::swap(leftMargin, rightMargin);
1391 QRectF tabRect = tab->rect.marginsRemoved(QMargins(leftMargin, 1, rightMargin, -3));
1392 painter->setPen(highContrastTheme ? tab->palette.buttonText().color() : winUI3Color(frameColorLight));
1393 painter->setBrush(tab->palette.base());
1395 painter->setBrush(winUI3Color(fillMicaAltDefault));
1397 if (tab->state.testFlag(State_Sunken))
1398 painter->setBrush(winUI3Color(fillMicaAltDefault));
1399 else if (tab->state.testFlag(State_MouseOver))
1400 painter->setBrush(winUI3Color(fillMicaAltSecondary));
1402 painter->setBrush(winUI3Color(fillMicaAltTransparent));
1404 QRect upperRect = tab->rect;
1405 upperRect.setHeight(tab->rect.height() / 2.);
1406 QRect lowerRect = tab->rect;
1407 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2.);
1408 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1409 painter->drawRoundedRect(tabRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1410 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1411 painter->drawRect(tabRect);
1414 case CE_TabBarTabLabel:
1415 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1416 const bool isEnabled = tab->state.testFlags(State_Enabled);
1417 const bool isSelected = tab->state.testFlags(State_Selected);
1419 QRect tr = tab->rect;
1420 bool verticalTabs = tab->shape == QTabBar::RoundedEast
1421 || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast
1422 || tab->shape == QTabBar::TriangularWest;
1424 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1425 if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget))
1426 alignment |= Qt::TextHideMnemonic;
1428 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1431 int newX, newY, newRot;
1432 if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
1433 newX = tr.width() + tr.x();
1438 newY = tr.y() + tr.height();
1441 QTransform m = QTransform::fromTranslate(newX, newY);
1443 painter->setTransform(m,
true);
1446 d->tabLayout(tab, widget, &tr, &iconRect);
1449 if (tab->position != QStyleOptionTab::TabPosition::Moving)
1450 tr = proxy()->subElementRect(SE_TabBarTabText, option, widget);
1452 if (!tab->icon.isNull()) {
1453 const auto mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
1454 const auto state = isSelected ? QIcon::On : QIcon::Off;
1455 tab->icon.paint(painter, iconRect, Qt::AlignCenter, mode, state);
1458 const auto textRole = widget ? widget->foregroundRole() : QPalette::WindowText;
1459 if (tab->palette.isBrushSet(QPalette::Current, textRole))
1460 painter->setPen(tab->palette.color(QPalette::Current, textRole));
1462 painter->setPen(winUI3Color(isSelected ? textPrimary : textSecondary));
1463 proxy()->drawItemText(painter, tr, alignment, tab->palette, isEnabled, tab->text);
1467 case CE_ToolButtonLabel:
1468#if QT_CONFIG(toolbutton)
1469 if (
const QStyleOptionToolButton *toolbutton
1470 = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
1471 QRect rect = toolbutton->rect;
1474 if (toolbutton->state & (State_Sunken | State_On)) {
1475 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
1476 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
1479 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1480 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1481 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1482 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1483 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1484 alignment |= Qt::TextHideMnemonic;
1485 rect.translate(shiftX, shiftY);
1486 painter->setFont(toolbutton->font);
1487 const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
1488 painter->setPen(controlTextColor(option));
1489 proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
1490 toolbutton->state & State_Enabled, text);
1493 QSize pmSize = toolbutton->iconSize;
1494 if (!toolbutton->icon.isNull()) {
1495 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1497 if (!(toolbutton->state & State_Enabled))
1498 mode = QIcon::Disabled;
1499 else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
1500 mode = QIcon::Active;
1502 mode = QIcon::Normal;
1503 pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
1505 pmSize = pm.size() / pm.devicePixelRatio();
1508 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1509 painter->setFont(toolbutton->font);
1512 int alignment = Qt::TextShowMnemonic | Qt::AlignCenter;
1513 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1514 alignment |= Qt::TextHideMnemonic;
1516 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1517 pr.setHeight(pmSize.height() + 4);
1518 tr.adjust(0, pr.height() - 1, 0, -1);
1520 pr.setWidth(pmSize.width() + 4);
1521 tr.adjust(pr.width(), 0, 0, 0);
1523 pr.translate(shiftX, shiftY);
1525 drawArrow(proxy(), toolbutton, pr, painter, widget);
1527 const auto vr = QStyle::visualRect(toolbutton->direction, rect, pr);
1528 proxy()->drawItemPixmap(painter, vr, Qt::AlignCenter, pm);
1530 tr.translate(shiftX, shiftY);
1531 painter->setPen(controlTextColor(option));
1532 const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
1533 const auto vr = QStyle::visualRect(toolbutton->direction, rect, tr);
1534 proxy()->drawItemText(painter, vr, alignment, toolbutton->palette,
1535 toolbutton->state & State_Enabled, text);
1537 rect.translate(shiftX, shiftY);
1539 drawArrow(proxy(), toolbutton, rect, painter, widget);
1541 proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
1548 case QStyle::CE_ShapedFrame:
1549 if (
const QStyleOptionFrame *f = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1550 int frameShape = f->frameShape;
1551 int frameShadow = QFrame::Plain;
1552 if (f->state & QStyle::State_Sunken)
1553 frameShadow = QFrame::Sunken;
1554 else if (f->state & QStyle::State_Raised)
1555 frameShadow = QFrame::Raised;
1557 int lw = f->lineWidth;
1558 int mlw = f->midLineWidth;
1560 switch (frameShape) {
1562 if (frameShadow == QFrame::Plain)
1563 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1565 qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
1568 if (frameShadow == QFrame::Plain)
1569 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1571 qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
1574 QWindowsVistaStyle::drawControl(element, option, painter, widget);
1578#if QT_CONFIG(progressbar)
1579 case CE_ProgressBarGroove:
1580 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar*>(option)) {
1581 QRect rect = option->rect;
1582 QPointF center = rect.center();
1583 if (baropt->state & QStyle::State_Horizontal) {
1585 rect.moveTop(center.y());
1588 rect.moveLeft(center.x());
1590 painter->setPen(Qt::NoPen);
1591 painter->setBrush(Qt::gray);
1592 painter->drawRect(rect);
1595 case CE_ProgressBarContents:
1596 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1597 QPainterStateGuard psg(painter);
1598 QRectF rect = option->rect;
1599 painter->translate(rect.topLeft());
1600 rect.translate(-rect.topLeft());
1602 constexpr qreal progressBarThickness = 3;
1603 constexpr qreal progressBarHalfThickness = progressBarThickness / 2.0;
1605 const auto isIndeterminate = baropt->maximum == 0 && baropt->minimum == 0;
1606 const auto orientation =
1607 (baropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
1608 const auto inverted = baropt->invertedAppearance;
1609 const auto reverse = (baropt->direction == Qt::RightToLeft) ^ inverted;
1613 if (orientation == Qt::Vertical) {
1614 rect = QRectF(rect.left(), rect.top(), rect.height(),
1619 m.translate(0, -rect.height() + 1);
1622 m.translate(-rect.width(), 0);
1624 painter->setTransform(m,
true);
1625 }
else if (reverse) {
1626 QTransform m = QTransform::fromScale(-1, 1);
1627 m.translate(-rect.width(), 0);
1628 painter->setTransform(m,
true);
1630 const qreal offset = (
int(rect.height()) % 2 == 0) ? 0.5f : 0.0f;
1632 if (isIndeterminate) {
1633#if QT_CONFIG(animation)
1634 auto anim = d->animation(option->styleObject);
1636 auto anim =
new QStyleAnimation(option->styleObject);
1637 anim->setFrameRate(QStyleAnimation::SixtyFps);
1638 d->startAnimation(anim);
1640 constexpr auto loopDurationMSec = 4000;
1641 const auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(
1642 std::chrono::system_clock::now());
1643 const auto elapsed = elapsedTime.time_since_epoch().count();
1644 const auto handleCenter = (elapsed % loopDurationMSec) /
float(loopDurationMSec);
1645 const auto isLongHandle = (elapsed / loopDurationMSec) % 2 == 0;
1646 const auto lengthFactor = (isLongHandle ? 33.0f : 25.0f) / 100.0f;
1648 constexpr auto handleCenter = 0.5f;
1649 constexpr auto lengthFactor = 1;
1651 const auto begin = qMax(handleCenter * (1 + lengthFactor) - lengthFactor, 0.0f);
1652 const auto end = qMin(handleCenter * (1 + lengthFactor), 1.0f);
1653 const auto barBegin = begin * rect.width();
1654 const auto barEnd = end * rect.width();
1655 rect = QRectF(QPointF(rect.left() + barBegin, rect.top()),
1656 QPointF(rect.left() + barEnd, rect.bottom()));
1658#if QT_CONFIG(animation)
1659 d->stopAnimation(option->styleObject);
1661 const auto fillPercentage = (
float(baropt->progress - baropt->minimum))
1662 / (
float(baropt->maximum - baropt->minimum));
1663 rect.setWidth(rect.width() * fillPercentage);
1665 const QPointF center = rect.center();
1666 rect.setHeight(progressBarThickness);
1667 rect.moveTop(center.y() - progressBarHalfThickness - offset);
1668 drawRoundedRect(painter, rect, Qt::NoPen, baropt->palette.accent());
1671 case CE_ProgressBarLabel:
1672 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1673 const bool vertical = !(baropt->state & QStyle::State_Horizontal);
1675 proxy()->drawItemText(painter, baropt->rect, Qt::AlignCenter | Qt::TextSingleLine,
1676 baropt->palette, baropt->state & State_Enabled, baropt->text,
1682 case CE_PushButtonLabel:
1683 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1684 QStyleOptionButton btnCopy(*btn);
1685 btnCopy.rect = btn->rect.marginsRemoved(QMargins(contentHMargin, 0, contentHMargin, 0));
1686 btnCopy.palette.setBrush(QPalette::ButtonText, controlTextColor(option));
1687 QCommonStyle::drawControl(element, &btnCopy, painter, widget);
1690 case CE_PushButtonBevel:
1691 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1692 using namespace StyleOptionHelper;
1693 QPainterStateGuard psg(
painter);
1695 const auto rect = QRectF(btn->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1696 if (btn->features.testFlag(QStyleOptionButton::Flat)) {
1697 const QBrush brush = isPressed(option)
1698 ? winUI3Color(subtlePressedColor)
1699 : (isHover(option) ? winUI3Color(subtleHighlightColor) : Qt::transparent);
1700 drawRoundedRect(painter, rect, Qt::NoPen, brush);
1702 const bool defaultButton = btn->features.testFlag(QStyleOptionButton::DefaultButton);
1703 const QPen pen = defaultButton ? option->palette.color(QPalette::Accent)
1704 : winUI3Color(controlStrokePrimary);
1705 drawRoundedRect(painter, rect, pen, controlFillBrush(option, ControlType::Control));
1707 if (btn->features.testFlag(QStyleOptionButton::HasMenu)) {
1709 const auto indSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
1710 const auto indRect =
1713 const auto vindRect = visualRect(btn->direction, btn->rect, indRect);
1714 textRect.setWidth(textRect.width() - indSize);
1716 int fontSize = painter->font().pointSize();
1717 QFont f(d->assetFont);
1718 f.setPointSize(qRound(fontSize * 0.9f));
1719 painter->setFont(f);
1720 painter->setPen(controlTextColor(option));
1721 painter->drawText(vindRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
1725 case CE_MenuBarItem:
1726 if (
const auto *mbi = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1727 using namespace StyleOptionHelper;
1729 constexpr int hPadding = 11;
1730 constexpr int topPadding = 4;
1731 constexpr int bottomPadding = 6;
1732 QStyleOptionMenuItem newMbi = *mbi;
1734 if (
auto mbiV2 = qstyleoption_cast<
const QStyleOptionMenuItemV2 *>(option))
1735 newMbi.state.setFlag(State_Sunken, mbiV2->mouseDown);
1737 newMbi.font.setPointSize(10);
1738 newMbi.palette.setColor(QPalette::ButtonText, controlTextColor(&newMbi));
1739 if (!isDisabled(&newMbi)) {
1740 QPen pen(Qt::NoPen);
1741 QBrush brush(Qt::NoBrush);
1742 if (highContrastTheme) {
1743 pen = QPen(newMbi.palette.highlight().color(), 2);
1744 brush = newMbi.palette.window();
1745 }
else if (isPressed(&newMbi)) {
1746 brush = winUI3Color(subtlePressedColor);
1747 }
else if (isHover(&newMbi)) {
1748 brush = winUI3Color(subtleHighlightColor);
1750 if (pen != Qt::NoPen || brush != Qt::NoBrush) {
1751 const QRect rect = mbi->rect.marginsRemoved(QMargins(5, 0, 5, 0));
1752 drawRoundedRect(painter, rect, pen, brush);
1755 newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
1756 painter->setFont(newMbi.font);
1757 QCommonStyle::drawControl(element, &newMbi, painter, widget);
1762 case CE_MenuEmptyArea:
1766 if (
const auto *menuitem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1767 using namespace StyleOptionHelper;
1769 const auto visualMenuRect = [&](
const QRect &rect) {
1770 return visualRect(option->direction, menuitem->rect, rect);
1773 const bool checked =
1774 menuitem->checkType != QStyleOptionMenuItem::NotCheckable && menuitem->checked;
1776 const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2));
1777 if (!isDisabled(menuitem)) {
1778 QPen pen(Qt::NoPen);
1779 QBrush brush(Qt::NoBrush);
1780 if (highContrastTheme) {
1781 pen = QPen(menuitem->palette.highlight().color(), 2);
1782 brush = menuitem->palette.window();
1783 }
else if (isPressed(menuitem)) {
1784 brush = winUI3Color(subtlePressedColor);
1785 }
else if (isSelected(menuitem)) {
1786 brush = winUI3Color(subtleHighlightColor);
1788 if (pen != Qt::NoPen || brush != Qt::NoBrush)
1789 drawRoundedRect(painter, rect, pen, brush);
1791 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
1792 constexpr int yoff = 1;
1793 painter->setPen(highContrastTheme ? menuitem->palette.buttonText().color() : winUI3Color(dividerStrokeDefault));
1794 painter->drawLine(menuitem->rect.topLeft() + QPoint(0, yoff),
1795 menuitem->rect.topRight() + QPoint(0, yoff));
1799 int xOffset = contentHMargin;
1801 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
1803 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset, rect.y(),
1804 checkMarkWidth, rect.height())));
1805 QPainterStateGuard psg(painter);
1806 painter->setFont(d->assetFont);
1807 painter->setPen(option->palette.text().color());
1808 painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
1810 if (menuitem->menuHasCheckableItems)
1811 xOffset += checkMarkWidth + contentItemHMargin;
1812 if (!menuitem->icon.isNull()) {
1814 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset,
1816 menuitem->maxIconWidth - 4,
1818 const auto mode = isDisabled(menuitem)
1820 : (isSelected(menuitem) ? QIcon::Active : QIcon::Normal);
1821 const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
1822 QRect pmr(QPoint(0, 0), QSize(size, size));
1823 pmr.moveCenter(vRect.center());
1824 menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode,
1825 checked ? QIcon::On : QIcon::Off);
1827 if (menuitem->maxIconWidth > 0)
1828 xOffset += menuitem->maxIconWidth - 4 + contentItemHMargin;
1830 QStringView s(menuitem->text);
1832 QPoint tl(rect.left() + xOffset, rect.top());
1833 QPoint br(rect.right() - menuitem->reservedShortcutWidth - contentHMargin,
1835 QRect textRect(tl, br);
1836 QRect vRect(visualMenuRect(textRect));
1839 if (highContrastTheme) {
1840 penColor = menuitem->palette.color(
1841 isSelected(menuitem) ? QPalette::HighlightedText : QPalette::Text);
1843 QStyleOption tmpOpt(*option);
1844 tmpOpt.state.setFlag(State_Sunken,
false);
1845 penColor = controlTextColor(&tmpOpt);
1847 painter->setPen(penColor);
1849 qsizetype t = s.indexOf(u'\t');
1850 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1851 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
1852 text_flags |= Qt::TextHideMnemonic;
1853 text_flags |= Qt::AlignLeft;
1855 if (t >= 0 && menuitem->menuItemType != QStyleOptionMenuItem::SubMenu) {
1856 QRect shortcutRect(QPoint(textRect.right(), textRect.top()),
1857 QPoint(rect.right(), textRect.bottom()));
1858 QRect vShortcutRect(visualMenuRect(shortcutRect));
1859 const QString textToDraw = s.mid(t + 1).toString();
1860 painter->drawText(vShortcutRect, text_flags, textToDraw);
1863 QFont font = menuitem->font;
1864 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1866 painter->setFont(font);
1867 const QString textToDraw = s.left(t).toString();
1868 painter->drawText(vRect, text_flags, textToDraw);
1870 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
1871 int fontSize = menuitem->font.pointSize();
1872 QFont f(d->assetFont);
1873 f.setPointSize(qRound(fontSize * 0.9f));
1874 painter->setFont(f);
1875 int yOfs = qRound(fontSize / 3.0f);
1876 QPoint tl(rect.right() - 2 * QWindowsStylePrivate::windowsArrowHMargin - contentItemHMargin,
1878 QRect submenuRect(tl, rect.bottomRight());
1879 QRect vSubMenuRect = visualMenuRect(submenuRect);
1880 painter->setPen(option->palette.text().color());
1881 const bool isReverse = option->direction == Qt::RightToLeft;
1882 const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
1883 painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
1888 case CE_MenuBarEmptyArea: {
1891 case CE_HeaderEmptyArea:
1893 case CE_HeaderSection: {
1894 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1895 painter->setPen(Qt::NoPen);
1896 painter->setBrush(header->palette.button());
1897 painter->drawRect(header->rect);
1898 const bool isRtl = option->direction == Qt::RightToLeft;
1899 const QPointF tr = isRtl ? option->rect.topLeft() : option->rect.topRight();
1900 const QPointF br = isRtl ? option->rect.bottomLeft() : option->rect.bottomRight();
1901 const QPointF bl = isRtl ? option->rect.bottomRight() : option->rect.bottomLeft();
1902 constexpr QPointF trOfs = QPointF(0.5, 0.0);
1903 constexpr QPointF brOfs = QPointF(0.5, 0.5);
1904 constexpr QPointF blOfs = QPointF(0.0, 0.5);
1905 const std::array<
QPointF, 3> points = { tr + trOfs, br + brOfs, bl + blOfs };
1906 QPen pen(highContrastTheme ? header->palette.buttonText().color()
1907 : winUI3Color(frameColorLight));
1908 pen.setJoinStyle(Qt::MiterJoin);
1909 painter->setPen(pen);
1910 painter->drawPolyline(points.data(),
int(points.size()));
1914 case CE_ItemViewItem: {
1915 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1916 const auto p = proxy();
1917 QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
1918 QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
1919 QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget);
1922 proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
1924 const QRect &rect = vopt->rect;
1925 const bool isRtl = option->direction == Qt::RightToLeft;
1926 bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1927 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1928 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1929 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1931 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1932 if (qobject_cast<
const QTableView *>(view)) {
1936 if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
1937 vopt->showDecorationSelected) {
1949 }
else if (isLast) {
1956 const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
1957 if (highlightCurrent) {
1958 if (highContrastTheme) {
1959 painter->setBrush(vopt->palette.highlight());
1961 painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
1962 ? calculateAccentColor(option)
1963 : winUI3Color(subtleHighlightColor));
1966 painter->setBrush(vopt->backgroundBrush);
1968 painter->setPen(Qt::NoPen);
1971 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
1972 secondLevelRoundingRadius, secondLevelRoundingRadius);
1973 }
else if (isFirst) {
1974 QPainterStateGuard psg(
painter);
1975 painter->setClipRect(rect);
1976 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1977 secondLevelRoundingRadius, secondLevelRoundingRadius);
1978 }
else if (isLast) {
1979 QPainterStateGuard psg(
painter);
1980 painter->setClipRect(rect);
1981 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1982 secondLevelRoundingRadius, secondLevelRoundingRadius);
1984 painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1988 if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
1989 QStyleOptionViewItem option(*vopt);
1990 option.rect = checkRect;
1991 option.state = option.state & ~QStyle::State_HasFocus;
1993 switch (vopt->checkState) {
1995 option.state |= QStyle::State_Off;
1997 case Qt::PartiallyChecked:
1998 option.state |= QStyle::State_NoChange;
2001 option.state |= QStyle::State_On;
2004 proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
2008 if (iconRect.isValid()) {
2009 QIcon::Mode mode = QIcon::Normal;
2010 if (!(vopt->state & QStyle::State_Enabled))
2011 mode = QIcon::Disabled;
2012 else if (vopt->state & QStyle::State_Selected)
2013 mode = QIcon::Selected;
2014 QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
2015 vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
2018 if (highlightCurrent && highContrastTheme) {
2019 painter->setPen(vopt->palette.base().color());
2020 }
else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
2021 painter->setPen(winUI3Color(textOnAccentPrimary));
2023 painter->setPen(vopt->palette.text().color());
2025 d->viewItemDrawText(painter, vopt, textRect);
2028 if (vopt->state & State_Selected && !highContrastTheme) {
2029 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2030 lv && lv->viewMode() != QListView::IconMode) {
2031 const auto col = vopt->palette.accent().color();
2032 painter->setBrush(col);
2033 painter->setPen(col);
2034 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
2035 const auto yOfs = rect.height() / 4.;
2036 QRectF r(
QPointF(xPos, rect.y() + yOfs),
2037 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
2038 painter->drawRoundedRect(r, 1, 1);
2045 QWindowsVistaStyle::drawControl(element, option, painter, widget);
2218QRect QWindows11Style::subControlRect(ComplexControl control,
const QStyleOptionComplex *option,
2219 SubControl subControl,
const QWidget *widget)
const
2224#if QT_CONFIG(spinbox)
2226 if (
const QStyleOptionSpinBox *spinbox = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2227 const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
2228 const int fw = spinbox->frame
2229 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
2231 int textFieldLength = spinbox->rect.width() - 2 * fw;
2232 int buttonHeight = 0;
2233 int buttonWidth = 0;
2235 const QWidget *w = qobject_cast<QWidget *>(spinbox->styleObject);
2237 ? widthFromChar(w->font(), Icon::ChevronUp, m_fontPoint2ChevronUpWidth)
2238 : spinbox->fontMetrics.horizontalAdvance(fluentIcon(Icon::ChevronUp));
2239 buttonHeight = spinbox->rect.height() - 4 * fw;
2240 textFieldLength -= 2 * (buttonWidth + fw) + 2 * fw;
2242 const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
2243 switch (subControl) {
2245 case SC_SpinBoxDown: {
2248 const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonHeight) / 2;
2249 ret = QRect(topLeft.x() + textFieldLength + fw, topLeft.y() + yOfs, buttonWidth,
2251 if (subControl == SC_SpinBoxDown)
2252 ret.moveRight(ret.right() + buttonWidth + fw);
2255 case SC_SpinBoxEditField:
2256 ret = QRect(topLeft,
2257 QPoint(topLeft.x() + textFieldLength, spinbox->rect.bottom() - fw));
2259 case SC_SpinBoxFrame:
2260 ret = spinbox->rect;
2264 ret = visualRect(spinbox->direction, spinbox->rect, ret);
2268 if (
const QStyleOptionTitleBar *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(option)) {
2269 SubControl sc = subControl;
2270 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2271 static constexpr int indent = 3;
2272 static constexpr int controlWidthMargin = 2;
2273 const int controlHeight = titlebar->rect.height();
2274 const int controlWidth = 46;
2275 const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
2276 int offset = -(controlWidthMargin + indent);
2278 bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
2279 bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
2282 case SC_TitleBarLabel:
2283 if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
2284 ret = titlebar->rect;
2285 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2286 ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
2287 if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
2288 ret.adjust(0, 0, -controlWidth, 0);
2289 if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
2290 ret.adjust(0, 0, -controlWidth, 0);
2291 if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
2292 ret.adjust(0, 0, -controlWidth, 0);
2293 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2294 ret.adjust(0, 0, -controlWidth, 0);
2297 case SC_TitleBarContextHelpButton:
2298 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2299 offset += controlWidth;
2301 case SC_TitleBarMinButton:
2302 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2303 offset += controlWidth;
2304 else if (sc == SC_TitleBarMinButton)
2307 case SC_TitleBarNormalButton:
2308 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2309 offset += controlWidth;
2310 else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2311 offset += controlWidth;
2312 else if (sc == SC_TitleBarNormalButton)
2315 case SC_TitleBarMaxButton:
2316 if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2317 offset += controlWidth;
2318 else if (sc == SC_TitleBarMaxButton)
2321 case SC_TitleBarShadeButton:
2322 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2323 offset += controlWidth;
2324 else if (sc == SC_TitleBarShadeButton)
2327 case SC_TitleBarUnshadeButton:
2328 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2329 offset += controlWidth;
2330 else if (sc == SC_TitleBarUnshadeButton)
2333 case SC_TitleBarCloseButton:
2334 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2335 offset += controlWidth;
2336 else if (sc == SC_TitleBarCloseButton)
2338 ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
2339 controlWidth, controlHeight);
2341 case SC_TitleBarSysMenu:
2342 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
2343 const auto yOfs = titlebar->rect.top() + (titlebar->rect.height() - iconSize) / 2;
2344 ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, yOfs, iconSize,
2351 if (widget && isMinimized && titlebar->rect.width() < offset)
2352 const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
2353 ret = visualRect(titlebar->direction, titlebar->rect, ret);
2359 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2361 if (subControl == SC_ScrollBarAddLine || subControl == SC_ScrollBarSubLine) {
2362 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
2363 if (scrollbar->orientation == Qt::Vertical)
2364 ret = ret.adjusted(2,2,-2,-3);
2366 ret = ret.adjusted(3,2,-2,-2);
2372 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2373 const auto indicatorWidth =
2374 proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2375 switch (subControl) {
2376 case SC_ComboBoxArrow: {
2378 cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
2379 const int buttonHeight =
2380 qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
2381 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2382 const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
2383 const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
2384 const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2385 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2386 buttonSize.height());
2387 ret = visualRect(option->direction, option->rect, ret);
2390 case SC_ComboBoxEditField: {
2393 const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
2394 ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
2396 ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
2397 ret = visualRect(option->direction, option->rect, ret);
2401 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2407#if QT_CONFIG(groupbox)
2409 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2410 switch (subControl) {
2411 case SC_GroupBoxCheckBox:
2421 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2429QSize QWindows11Style::sizeFromContents(ContentsType type,
const QStyleOption *option,
2430 const QSize &size,
const QWidget *widget)
const
2432 QSize contentSize(size);
2436#if QT_CONFIG(menubar)
2437 case CT_MenuBarItem:
2438 if (!contentSize.isEmpty()) {
2439 constexpr int hMargin = 2 * 6;
2440 constexpr int hPadding = 2 * 11;
2441 constexpr int itemHeight = 32;
2442 contentSize.setWidth(contentSize.width() + hMargin + hPadding);
2443#if QT_CONFIG(tabwidget)
2444 if (widget->parent() && !qobject_cast<
const QTabWidget *>(widget->parent()))
2446 contentSize.setHeight(itemHeight);
2452 if (
const auto *menuItem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
2453 int width = size.width();
2455 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
2459 height = menuItem->fontMetrics.height() + 8;
2460 if (!menuItem->icon.isNull()) {
2461 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
2462 height = qMax(height,
2463 menuItem->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
2466 if (menuItem->text.contains(u'\t'))
2467 width += contentItemHMargin;
2468 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
2469 width += 2 * QWindowsStylePrivate::windowsArrowHMargin + contentItemHMargin;
2470 if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
2471 const QFontMetrics fm(menuItem->font);
2472 QFont fontBold = menuItem->font;
2473 fontBold.setBold(
true);
2474 const QFontMetrics fmBold(fontBold);
2475 width += fmBold.horizontalAdvance(menuItem->text) - fm.horizontalAdvance(menuItem->text);
2478 if (menuItem->menuHasCheckableItems) {
2479 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
2480 width += checkMarkWidth + contentItemHMargin * 2;
2484 if (menuItem->maxIconWidth > 0)
2485 width += contentItemHMargin * 2 + menuItem->maxIconWidth - 4;
2487 width += 2 * contentHMargin;
2490 contentSize = QSize(width, height);
2494#if QT_CONFIG(spinbox)
2496 if (
const auto *spinbox = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2498 const bool hasButtons = (spinbox->buttonSymbols != QAbstractSpinBox::NoButtons);
2499 const int margins = 0;
2500 int buttonWidth = 0;
2502 buttonWidth = widget
2503 ? widthFromChar(widget->font(), Icon::ChevronUp, m_fontPoint2ChevronUpWidth)
2504 : spinbox->fontMetrics.horizontalAdvance(fluentIcon(Icon::ChevronUp));
2506 const int frameWidth = spinbox->frame
2507 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
2510 contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
2515#if QT_CONFIG(combobox)
2517 if (
const auto *comboBoxOpt = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2518 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2519 contentSize += QSize(0, 4);
2520 if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
2521 const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2522 contentSize.rwidth() += w + contentItemHMargin;
2528 if (qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
2529 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2530 contentSize += QSize(0, 4);
2534 case CT_HeaderSection:
2537 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2539 case CT_RadioButton:
2541 if (
const auto *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
2542 const auto p = proxy();
2543 const bool isRadio = (type == CT_RadioButton);
2545 const int width = p->pixelMetric(
2546 isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, option, widget);
2547 const int height = p->pixelMetric(
2548 isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, option, widget);
2551 if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
2552 margins += p->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
2553 : PM_CheckBoxLabelSpacing,
2557 contentSize += QSize(width + margins, 4);
2558 contentSize.setHeight(qMax(size.height(), height + 2 * contentItemHMargin));
2564 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2565 if (size.width() == 0)
2566 contentSize.rwidth() += 2;
2568 case CT_PushButton: {
2569 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2571 const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
2572 contentSize.rwidth() += 2 * contentHMargin - oldMargin;
2575 case CT_ToolButton: {
2577 if (
const auto tb = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
2579 if (!tb->subControls.testFlag(SC_ToolButtonMenu)) {
2580 if (tb->features.testFlag(QStyleOptionToolButton::HasMenu))
2581 contentSize.rwidth() += 2;
2583 if (tb->toolButtonStyle == Qt::ToolButtonTextBesideIcon
2584 || tb->toolButtonStyle == Qt::ToolButtonIconOnly) {
2585 contentSize.rheight() = qMax(contentSize.height(), tb->iconSize.height() + 4);
2588 const auto fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
2589 contentSize += QSize(contentHMargin + 2 * fw, 2 * fw);
2592 case CT_ItemViewItem: {
2593 if (
const auto *viewItemOpt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
2594 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2595 lv && lv->viewMode() != QListView::IconMode) {
2596 QStyleOptionViewItem vOpt(*viewItemOpt);
2600 vOpt.rect.setRight(vOpt.rect.right() - contentHMargin);
2601 contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget);
2602 contentSize.rwidth() += contentHMargin;
2603 contentSize.rheight() += 2 * contentHMargin;
2606 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2612 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);