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)));
1269 case QStyle::PE_Widget: {
1270 if (widget && widget->palette().isBrushSet(QPalette::Active, widget->backgroundRole())) {
1271 const QBrush bg = widget->palette().brush(widget->backgroundRole());
1272 auto wp = QWidgetPrivate::get(widget);
1273 QPainterStateGuard psg(
painter);
1274 wp->updateBrushOrigin(painter, bg);
1275 painter->fillRect(option->rect, bg);
1279 case QStyle::PE_FrameWindow:
1280 if (
const auto *frm = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1282 QRectF rect= option->rect;
1283 int fwidth =
int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
1285 QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
1286 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1287 secondLevelRoundingRadius,
1288 secondLevelRoundingRadius);
1289 QRectF bottomRightCorner = QRectF(rect.right() - 1.0 - secondLevelRoundingRadius,
1290 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1291 secondLevelRoundingRadius,
1292 secondLevelRoundingRadius);
1295 if (widget !=
nullptr) {
1296 QBitmap mask(widget->width(), widget->height());
1300 maskPainter.setRenderHint(QPainter::Antialiasing);
1301 maskPainter.setBrush(Qt::color1);
1302 maskPainter.setPen(Qt::NoPen);
1303 maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
1304 const_cast<QWidget*>(widget)->setMask(mask);
1308 painter->setPen(QPen(frm->palette.base(), fwidth));
1309 painter->drawLine(QPointF(rect.left(), rect.top()),
1310 QPointF(rect.left(), rect.bottom() - fwidth));
1311 painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
1312 QPointF(rect.right() - fwidth, rect.bottom()));
1313 painter->drawLine(QPointF(rect.right(), rect.top()),
1314 QPointF(rect.right(), rect.bottom() - fwidth));
1316 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1317 painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
1318 QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1319 painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
1320 QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
1321 painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
1322 QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1324 painter->setPen(Qt::NoPen);
1325 painter->setBrush(frm->palette.base());
1326 painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
1328 painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
1331 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1332 painter->setBrush(Qt::NoBrush);
1333 painter->drawArc(bottomRightCorner,
1335 painter->drawArc(bottomLeftCorner,
1339#if QT_CONFIG(tabbar)
1340 case PE_FrameTabBarBase:
1341 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTabBarBase *>(option)) {
1342 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1343 const auto clipRegion = painter->clipRegion();
1345 painter->setPen(highContrastTheme ? tab->palette.buttonText().color()
1346 : winUI3Color(frameColorLight));
1347 painter->setBrush(tab->palette.base());
1348 QRect upperRect = tab->rect;
1349 upperRect.setHeight(tab->rect.height() / 2);
1350 QRect lowerRect = tab->rect;
1351 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2);
1352 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1353 painter->drawRoundedRect(tab->rect, secondLevelRoundingRadius,
1354 secondLevelRoundingRadius);
1355 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1356 painter->drawRect(tab->rect);
1360 case PE_IndicatorTabTearLeft:
1361 case PE_IndicatorTabTearRight:
1364 QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
1371void QWindows11Style::drawControl(ControlElement element,
const QStyleOption *option,
1372 QPainter *painter,
const QWidget *widget)
const
1374 Q_D(
const QWindows11Style);
1375 State flags = option->state;
1377 QPainterStateGuard psg(
painter);
1378 painter->setRenderHint(QPainter::Antialiasing);
1380 case QStyle::CE_ComboBoxLabel:
1381#if QT_CONFIG(combobox)
1382 if (
const QStyleOptionComboBox *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
1383 painter->setPen(controlTextColor(option,
true));
1384 QStyleOptionComboBox newOption = *cb;
1385 newOption.rect.adjust(4,0,-4,0);
1386 QCommonStyle::drawControl(element, &newOption, painter, widget);
1390#if QT_CONFIG(tabbar)
1391 case CE_TabBarTabShape:
1392 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1393 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1394 const bool isSelected = tab->state.testFlag(State_Selected);
1395 const auto clipRegion = painter->clipRegion();
1396 const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab
1397 || tab->position == QStyleOptionTab::Moving;
1398 auto leftMargin = (tab->position == QStyleOptionTab::Beginning || onlyOne) ? 1 : 0;
1399 auto rightMargin = (tab->position == QStyleOptionTab::End || onlyOne) ? 1 : 0;
1400 if (QCommonStylePrivate::rtl(option))
1401 std::swap(leftMargin, rightMargin);
1403 QRectF tabRect = tab->rect.marginsRemoved(QMargins(leftMargin, 1, rightMargin, -3));
1404 painter->setPen(highContrastTheme ? tab->palette.buttonText().color() : winUI3Color(frameColorLight));
1405 painter->setBrush(tab->palette.base());
1407 painter->setBrush(winUI3Color(fillMicaAltDefault));
1409 if (tab->state.testFlag(State_Sunken))
1410 painter->setBrush(winUI3Color(fillMicaAltDefault));
1411 else if (tab->state.testFlag(State_MouseOver))
1412 painter->setBrush(winUI3Color(fillMicaAltSecondary));
1414 painter->setBrush(winUI3Color(fillMicaAltTransparent));
1416 QRect upperRect = tab->rect;
1417 upperRect.setHeight(tab->rect.height() / 2.);
1418 QRect lowerRect = tab->rect;
1419 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2.);
1420 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1421 painter->drawRoundedRect(tabRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1422 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1423 painter->drawRect(tabRect);
1426 case CE_TabBarTabLabel:
1427 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1428 const bool isEnabled = tab->state.testFlags(State_Enabled);
1429 const bool isSelected = tab->state.testFlags(State_Selected);
1431 QRect tr = tab->rect;
1432 bool verticalTabs = tab->shape == QTabBar::RoundedEast
1433 || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast
1434 || tab->shape == QTabBar::TriangularWest;
1436 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1437 if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget))
1438 alignment |= Qt::TextHideMnemonic;
1440 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1443 int newX, newY, newRot;
1444 if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
1445 newX = tr.width() + tr.x();
1450 newY = tr.y() + tr.height();
1453 QTransform m = QTransform::fromTranslate(newX, newY);
1455 painter->setTransform(m,
true);
1458 d->tabLayout(tab, widget, &tr, &iconRect);
1461 if (tab->position != QStyleOptionTab::TabPosition::Moving)
1462 tr = proxy()->subElementRect(SE_TabBarTabText, option, widget);
1464 if (!tab->icon.isNull()) {
1465 const auto mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
1466 const auto state = isSelected ? QIcon::On : QIcon::Off;
1467 tab->icon.paint(painter, iconRect, Qt::AlignCenter, mode, state);
1470 painter->setPen(winUI3Color(isSelected ? textPrimary : textSecondary));
1471 proxy()->drawItemText(painter, tr, alignment, tab->palette, isEnabled, tab->text);
1475 case CE_ToolButtonLabel:
1476#if QT_CONFIG(toolbutton)
1477 if (
const QStyleOptionToolButton *toolbutton
1478 = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
1479 QRect rect = toolbutton->rect;
1482 if (toolbutton->state & (State_Sunken | State_On)) {
1483 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
1484 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
1487 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1488 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1489 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1490 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1491 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1492 alignment |= Qt::TextHideMnemonic;
1493 rect.translate(shiftX, shiftY);
1494 painter->setFont(toolbutton->font);
1495 const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
1496 painter->setPen(controlTextColor(option));
1497 proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
1498 toolbutton->state & State_Enabled, text);
1501 QSize pmSize = toolbutton->iconSize;
1502 if (!toolbutton->icon.isNull()) {
1503 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1505 if (!(toolbutton->state & State_Enabled))
1506 mode = QIcon::Disabled;
1507 else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
1508 mode = QIcon::Active;
1510 mode = QIcon::Normal;
1511 pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
1513 pmSize = pm.size() / pm.devicePixelRatio();
1516 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1517 painter->setFont(toolbutton->font);
1520 int alignment = Qt::TextShowMnemonic | Qt::AlignCenter;
1521 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1522 alignment |= Qt::TextHideMnemonic;
1524 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1525 pr.setHeight(pmSize.height() + 4);
1526 tr.adjust(0, pr.height() - 1, 0, -1);
1528 pr.setWidth(pmSize.width() + 4);
1529 tr.adjust(pr.width(), 0, 0, 0);
1531 pr.translate(shiftX, shiftY);
1533 drawArrow(proxy(), toolbutton, pr, painter, widget);
1535 const auto vr = QStyle::visualRect(toolbutton->direction, rect, pr);
1536 proxy()->drawItemPixmap(painter, vr, Qt::AlignCenter, pm);
1538 tr.translate(shiftX, shiftY);
1539 painter->setPen(controlTextColor(option));
1540 const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
1541 const auto vr = QStyle::visualRect(toolbutton->direction, rect, tr);
1542 proxy()->drawItemText(painter, vr, alignment, toolbutton->palette,
1543 toolbutton->state & State_Enabled, text);
1545 rect.translate(shiftX, shiftY);
1547 drawArrow(proxy(), toolbutton, rect, painter, widget);
1549 proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
1556 case QStyle::CE_ShapedFrame:
1557 if (
const QStyleOptionFrame *f = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1558 int frameShape = f->frameShape;
1559 int frameShadow = QFrame::Plain;
1560 if (f->state & QStyle::State_Sunken)
1561 frameShadow = QFrame::Sunken;
1562 else if (f->state & QStyle::State_Raised)
1563 frameShadow = QFrame::Raised;
1565 int lw = f->lineWidth;
1566 int mlw = f->midLineWidth;
1568 switch (frameShape) {
1570 if (frameShadow == QFrame::Plain)
1571 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1573 qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
1576 if (frameShadow == QFrame::Plain)
1577 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1579 qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
1582 QWindowsVistaStyle::drawControl(element, option, painter, widget);
1586#if QT_CONFIG(progressbar)
1587 case CE_ProgressBarGroove:
1588 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar*>(option)) {
1589 QRect rect = option->rect;
1590 QPointF center = rect.center();
1591 if (baropt->state & QStyle::State_Horizontal) {
1593 rect.moveTop(center.y());
1596 rect.moveLeft(center.x());
1598 painter->setPen(Qt::NoPen);
1599 painter->setBrush(Qt::gray);
1600 painter->drawRect(rect);
1603 case CE_ProgressBarContents:
1604 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1605 QPainterStateGuard psg(painter);
1606 QRectF rect = option->rect;
1607 painter->translate(rect.topLeft());
1608 rect.translate(-rect.topLeft());
1610 constexpr qreal progressBarThickness = 3;
1611 constexpr qreal progressBarHalfThickness = progressBarThickness / 2.0;
1613 const auto isIndeterminate = baropt->maximum == 0 && baropt->minimum == 0;
1614 const auto orientation =
1615 (baropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
1616 const auto inverted = baropt->invertedAppearance;
1617 const auto reverse = (baropt->direction == Qt::RightToLeft) ^ inverted;
1621 if (orientation == Qt::Vertical) {
1622 rect = QRectF(rect.left(), rect.top(), rect.height(),
1627 m.translate(0, -rect.height() + 1);
1630 m.translate(-rect.width(), 0);
1632 painter->setTransform(m,
true);
1633 }
else if (reverse) {
1634 QTransform m = QTransform::fromScale(-1, 1);
1635 m.translate(-rect.width(), 0);
1636 painter->setTransform(m,
true);
1638 const qreal offset = (
int(rect.height()) % 2 == 0) ? 0.5f : 0.0f;
1640 if (isIndeterminate) {
1641#if QT_CONFIG(animation)
1642 auto anim = d->animation(option->styleObject);
1644 auto anim =
new QStyleAnimation(option->styleObject);
1645 anim->setFrameRate(QStyleAnimation::SixtyFps);
1646 d->startAnimation(anim);
1648 constexpr auto loopDurationMSec = 4000;
1649 const auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(
1650 std::chrono::system_clock::now());
1651 const auto elapsed = elapsedTime.time_since_epoch().count();
1652 const auto handleCenter = (elapsed % loopDurationMSec) /
float(loopDurationMSec);
1653 const auto isLongHandle = (elapsed / loopDurationMSec) % 2 == 0;
1654 const auto lengthFactor = (isLongHandle ? 33.0f : 25.0f) / 100.0f;
1656 constexpr auto handleCenter = 0.5f;
1657 constexpr auto lengthFactor = 1;
1659 const auto begin = qMax(handleCenter * (1 + lengthFactor) - lengthFactor, 0.0f);
1660 const auto end = qMin(handleCenter * (1 + lengthFactor), 1.0f);
1661 const auto barBegin = begin * rect.width();
1662 const auto barEnd = end * rect.width();
1663 rect = QRectF(QPointF(rect.left() + barBegin, rect.top()),
1664 QPointF(rect.left() + barEnd, rect.bottom()));
1666#if QT_CONFIG(animation)
1667 d->stopAnimation(option->styleObject);
1669 const auto fillPercentage = (
float(baropt->progress - baropt->minimum))
1670 / (
float(baropt->maximum - baropt->minimum));
1671 rect.setWidth(rect.width() * fillPercentage);
1673 const QPointF center = rect.center();
1674 rect.setHeight(progressBarThickness);
1675 rect.moveTop(center.y() - progressBarHalfThickness - offset);
1676 drawRoundedRect(painter, rect, Qt::NoPen, baropt->palette.accent());
1679 case CE_ProgressBarLabel:
1680 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1681 const bool vertical = !(baropt->state & QStyle::State_Horizontal);
1683 proxy()->drawItemText(painter, baropt->rect, Qt::AlignCenter | Qt::TextSingleLine,
1684 baropt->palette, baropt->state & State_Enabled, baropt->text,
1690 case CE_PushButtonLabel:
1691 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1692 QStyleOptionButton btnCopy(*btn);
1693 btnCopy.rect = btn->rect.marginsRemoved(QMargins(contentHMargin, 0, contentHMargin, 0));
1694 btnCopy.palette.setBrush(QPalette::ButtonText, controlTextColor(option));
1695 QCommonStyle::drawControl(element, &btnCopy, painter, widget);
1698 case CE_PushButtonBevel:
1699 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1700 using namespace StyleOptionHelper;
1702 QRectF rect = btn->rect.marginsRemoved(QMargins(2, 2, 2, 2));
1703 painter->setPen(Qt::NoPen);
1704 if (btn->features.testFlag(QStyleOptionButton::Flat)) {
1705 painter->setBrush(btn->palette.button());
1706 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1707 if (flags & (State_Sunken | State_On)) {
1708 painter->setBrush(WINUI3Colors[colorSchemeIndex][subtlePressedColor]);
1710 else if (flags & State_MouseOver) {
1711 painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
1713 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1715 painter->setBrush(controlFillBrush(option, ControlType::Control));
1716 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1718 rect.adjust(0.5,0.5,-0.5,-0.5);
1719 const bool defaultButton = btn->features.testFlag(QStyleOptionButton::DefaultButton);
1720 painter->setBrush(Qt::NoBrush);
1721 painter->setPen(defaultButton ? option->palette.accent().color()
1722 : WINUI3Colors[colorSchemeIndex][controlStrokePrimary]);
1723 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1725 painter->setPen(defaultButton ? WINUI3Colors[colorSchemeIndex][controlStrokeOnAccentSecondary]
1726 : WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]);
1728 if (btn->features.testFlag(QStyleOptionButton::HasMenu)) {
1729 QPainterStateGuard psg(
painter);
1732 const auto indSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
1733 const auto indRect =
1736 const auto vindRect = visualRect(btn->direction, btn->rect, indRect);
1737 textRect.setWidth(textRect.width() - indSize);
1739 int fontSize = painter->font().pointSize();
1740 QFont f(d->assetFont);
1741 f.setPointSize(qRound(fontSize * 0.9f));
1742 painter->setFont(f);
1743 painter->setPen(controlTextColor(option));
1744 painter->drawText(vindRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
1748 case CE_MenuBarItem:
1749 if (
const auto *mbi = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1750 using namespace StyleOptionHelper;
1752 constexpr int hPadding = 11;
1753 constexpr int topPadding = 4;
1754 constexpr int bottomPadding = 6;
1755 QStyleOptionMenuItem newMbi = *mbi;
1757 if (
auto mbiV2 = qstyleoption_cast<
const QStyleOptionMenuItemV2 *>(option))
1758 newMbi.state.setFlag(State_Sunken, mbiV2->mouseDown);
1760 newMbi.font.setPointSize(10);
1761 newMbi.palette.setColor(QPalette::ButtonText, controlTextColor(&newMbi));
1762 if (!isDisabled(&newMbi)) {
1763 QPen pen(Qt::NoPen);
1764 QBrush brush(Qt::NoBrush);
1765 if (highContrastTheme) {
1766 pen = QPen(newMbi.palette.highlight().color(), 2);
1767 brush = newMbi.palette.window();
1768 }
else if (isPressed(&newMbi)) {
1769 brush = winUI3Color(subtlePressedColor);
1770 }
else if (isHover(&newMbi)) {
1771 brush = winUI3Color(subtleHighlightColor);
1773 if (pen != Qt::NoPen || brush != Qt::NoBrush) {
1774 const QRect rect = mbi->rect.marginsRemoved(QMargins(5, 0, 5, 0));
1775 drawRoundedRect(painter, rect, pen, brush);
1778 newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
1779 painter->setFont(newMbi.font);
1780 QCommonStyle::drawControl(element, &newMbi, painter, widget);
1785 case CE_MenuEmptyArea:
1789 if (
const auto *menuitem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1790 using namespace StyleOptionHelper;
1792 const auto visualMenuRect = [&](
const QRect &rect) {
1793 return visualRect(option->direction, menuitem->rect, rect);
1796 const bool checked =
1797 menuitem->checkType != QStyleOptionMenuItem::NotCheckable && menuitem->checked;
1799 const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2));
1800 if (!isDisabled(menuitem)) {
1801 QPen pen(Qt::NoPen);
1802 QBrush brush(Qt::NoBrush);
1803 if (highContrastTheme) {
1804 pen = QPen(menuitem->palette.highlight().color(), 2);
1805 brush = menuitem->palette.window();
1806 }
else if (isPressed(menuitem)) {
1807 brush = winUI3Color(subtlePressedColor);
1808 }
else if (isSelected(menuitem)) {
1809 brush = winUI3Color(subtleHighlightColor);
1811 if (pen != Qt::NoPen || brush != Qt::NoBrush)
1812 drawRoundedRect(painter, rect, pen, brush);
1814 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
1815 constexpr int yoff = 1;
1816 painter->setPen(highContrastTheme ? menuitem->palette.buttonText().color() : winUI3Color(dividerStrokeDefault));
1817 painter->drawLine(menuitem->rect.topLeft() + QPoint(0, yoff),
1818 menuitem->rect.topRight() + QPoint(0, yoff));
1822 int xOffset = contentHMargin;
1824 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
1826 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset, rect.y(),
1827 checkMarkWidth, rect.height())));
1828 QPainterStateGuard psg(painter);
1829 painter->setFont(d->assetFont);
1830 painter->setPen(option->palette.text().color());
1831 painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
1833 if (menuitem->menuHasCheckableItems)
1834 xOffset += checkMarkWidth + contentItemHMargin;
1835 if (!menuitem->icon.isNull()) {
1837 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset,
1839 menuitem->maxIconWidth - 4,
1841 const auto mode = isDisabled(menuitem)
1843 : (isSelected(menuitem) ? QIcon::Active : QIcon::Normal);
1844 const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
1845 QRect pmr(QPoint(0, 0), QSize(size, size));
1846 pmr.moveCenter(vRect.center());
1847 menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode,
1848 checked ? QIcon::On : QIcon::Off);
1850 if (menuitem->maxIconWidth > 0)
1851 xOffset += menuitem->maxIconWidth - 4 + contentItemHMargin;
1853 QStringView s(menuitem->text);
1855 QPoint tl(rect.left() + xOffset, rect.top());
1856 QPoint br(rect.right() - menuitem->reservedShortcutWidth - contentHMargin,
1858 QRect textRect(tl, br);
1859 QRect vRect(visualMenuRect(textRect));
1862 if (highContrastTheme) {
1863 penColor = menuitem->palette.color(
1864 isSelected(menuitem) ? QPalette::HighlightedText : QPalette::Text);
1866 QStyleOption tmpOpt(*option);
1867 tmpOpt.state.setFlag(State_Sunken,
false);
1868 penColor = controlTextColor(&tmpOpt);
1870 painter->setPen(penColor);
1872 qsizetype t = s.indexOf(u'\t');
1873 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1874 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
1875 text_flags |= Qt::TextHideMnemonic;
1876 text_flags |= Qt::AlignLeft;
1878 if (t >= 0 && menuitem->menuItemType != QStyleOptionMenuItem::SubMenu) {
1879 QRect shortcutRect(QPoint(textRect.right(), textRect.top()),
1880 QPoint(rect.right(), textRect.bottom()));
1881 QRect vShortcutRect(visualMenuRect(shortcutRect));
1882 const QString textToDraw = s.mid(t + 1).toString();
1883 painter->drawText(vShortcutRect, text_flags, textToDraw);
1886 QFont font = menuitem->font;
1887 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1889 painter->setFont(font);
1890 const QString textToDraw = s.left(t).toString();
1891 painter->drawText(vRect, text_flags, textToDraw);
1893 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
1894 int fontSize = menuitem->font.pointSize();
1895 QFont f(d->assetFont);
1896 f.setPointSize(qRound(fontSize * 0.9f));
1897 painter->setFont(f);
1898 int yOfs = qRound(fontSize / 3.0f);
1899 QPoint tl(rect.right() - 2 * QWindowsStylePrivate::windowsArrowHMargin - contentItemHMargin,
1901 QRect submenuRect(tl, rect.bottomRight());
1902 QRect vSubMenuRect = visualMenuRect(submenuRect);
1903 painter->setPen(option->palette.text().color());
1904 const bool isReverse = option->direction == Qt::RightToLeft;
1905 const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
1906 painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
1911 case CE_MenuBarEmptyArea: {
1914 case CE_HeaderEmptyArea:
1916 case CE_HeaderSection: {
1917 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1918 painter->setPen(Qt::NoPen);
1919 painter->setBrush(header->palette.button());
1920 painter->drawRect(header->rect);
1921 const bool isRtl = option->direction == Qt::RightToLeft;
1922 const QPointF tr = isRtl ? option->rect.topLeft() : option->rect.topRight();
1923 const QPointF br = isRtl ? option->rect.bottomLeft() : option->rect.bottomRight();
1924 const QPointF bl = isRtl ? option->rect.bottomRight() : option->rect.bottomLeft();
1925 constexpr QPointF trOfs = QPointF(0.5, 0.0);
1926 constexpr QPointF brOfs = QPointF(0.5, 0.5);
1927 constexpr QPointF blOfs = QPointF(0.0, 0.5);
1928 const std::array<
QPointF, 3> points = { tr + trOfs, br + brOfs, bl + blOfs };
1929 QPen pen(highContrastTheme ? header->palette.buttonText().color()
1930 : winUI3Color(frameColorLight));
1931 pen.setJoinStyle(Qt::MiterJoin);
1932 painter->setPen(pen);
1933 painter->drawPolyline(points.data(),
int(points.size()));
1937 case CE_ItemViewItem: {
1938 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1939 const auto p = proxy();
1940 QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
1941 QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
1942 QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget);
1945 proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
1947 const QRect &rect = vopt->rect;
1948 const bool isRtl = option->direction == Qt::RightToLeft;
1949 bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1950 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1951 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1952 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1954 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1955 if (qobject_cast<
const QTableView *>(view)) {
1959 if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
1960 vopt->showDecorationSelected) {
1972 }
else if (isLast) {
1979 const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
1980 if (highlightCurrent) {
1981 if (highContrastTheme) {
1982 painter->setBrush(vopt->palette.highlight());
1984 painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
1985 ? calculateAccentColor(option)
1986 : winUI3Color(subtleHighlightColor));
1989 painter->setBrush(vopt->backgroundBrush);
1991 painter->setPen(Qt::NoPen);
1994 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
1995 secondLevelRoundingRadius, secondLevelRoundingRadius);
1996 }
else if (isFirst) {
1997 QPainterStateGuard psg(
painter);
1998 painter->setClipRect(rect);
1999 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
2000 secondLevelRoundingRadius, secondLevelRoundingRadius);
2001 }
else if (isLast) {
2002 QPainterStateGuard psg(
painter);
2003 painter->setClipRect(rect);
2004 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
2005 secondLevelRoundingRadius, secondLevelRoundingRadius);
2007 painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
2011 if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
2012 QStyleOptionViewItem option(*vopt);
2013 option.rect = checkRect;
2014 option.state = option.state & ~QStyle::State_HasFocus;
2016 switch (vopt->checkState) {
2018 option.state |= QStyle::State_Off;
2020 case Qt::PartiallyChecked:
2021 option.state |= QStyle::State_NoChange;
2024 option.state |= QStyle::State_On;
2027 proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
2031 if (iconRect.isValid()) {
2032 QIcon::Mode mode = QIcon::Normal;
2033 if (!(vopt->state & QStyle::State_Enabled))
2034 mode = QIcon::Disabled;
2035 else if (vopt->state & QStyle::State_Selected)
2036 mode = QIcon::Selected;
2037 QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
2038 vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
2041 if (highlightCurrent && highContrastTheme) {
2042 painter->setPen(vopt->palette.base().color());
2043 }
else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
2044 painter->setPen(winUI3Color(textOnAccentPrimary));
2046 painter->setPen(vopt->palette.text().color());
2048 d->viewItemDrawText(painter, vopt, textRect);
2051 if (vopt->state & State_Selected && !highContrastTheme) {
2052 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2053 lv && lv->viewMode() != QListView::IconMode) {
2054 const auto col = vopt->palette.accent().color();
2055 painter->setBrush(col);
2056 painter->setPen(col);
2057 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
2058 const auto yOfs = rect.height() / 4.;
2059 QRectF r(
QPointF(xPos, rect.y() + yOfs),
2060 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
2061 painter->drawRoundedRect(r, 1, 1);
2068 QWindowsVistaStyle::drawControl(element, option, painter, widget);
2241QRect QWindows11Style::subControlRect(ComplexControl control,
const QStyleOptionComplex *option,
2242 SubControl subControl,
const QWidget *widget)
const
2247#if QT_CONFIG(spinbox)
2249 if (
const QStyleOptionSpinBox *spinbox = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2250 const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
2251 const int fw = spinbox->frame
2252 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
2254 const int buttonHeight = hasButtons
2255 ? qMin(spinbox->rect.height() - 3 * fw, spinbox->fontMetrics.height() * 5 / 4)
2257 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2258 const int textFieldLength = spinbox->rect.width() - 2 * fw - 2 * buttonSize.width();
2259 const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
2260 switch (subControl) {
2262 case SC_SpinBoxDown: {
2265 const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2266 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2267 buttonSize.height());
2268 if (subControl == SC_SpinBoxDown)
2269 ret.moveRight(ret.right() + buttonSize.width());
2272 case SC_SpinBoxEditField:
2273 ret = QRect(topLeft,
2274 spinbox->rect.bottomRight() - QPoint(fw + 2 * buttonSize.width(), fw));
2276 case SC_SpinBoxFrame:
2277 ret = spinbox->rect;
2281 ret = visualRect(spinbox->direction, spinbox->rect, ret);
2285 if (
const QStyleOptionTitleBar *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(option)) {
2286 SubControl sc = subControl;
2287 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2288 static constexpr int indent = 3;
2289 static constexpr int controlWidthMargin = 2;
2290 const int controlHeight = titlebar->rect.height();
2291 const int controlWidth = 46;
2292 const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
2293 int offset = -(controlWidthMargin + indent);
2295 bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
2296 bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
2299 case SC_TitleBarLabel:
2300 if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
2301 ret = titlebar->rect;
2302 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2303 ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
2304 if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
2305 ret.adjust(0, 0, -controlWidth, 0);
2306 if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
2307 ret.adjust(0, 0, -controlWidth, 0);
2308 if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
2309 ret.adjust(0, 0, -controlWidth, 0);
2310 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2311 ret.adjust(0, 0, -controlWidth, 0);
2314 case SC_TitleBarContextHelpButton:
2315 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2316 offset += controlWidth;
2318 case SC_TitleBarMinButton:
2319 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2320 offset += controlWidth;
2321 else if (sc == SC_TitleBarMinButton)
2324 case SC_TitleBarNormalButton:
2325 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2326 offset += controlWidth;
2327 else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2328 offset += controlWidth;
2329 else if (sc == SC_TitleBarNormalButton)
2332 case SC_TitleBarMaxButton:
2333 if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2334 offset += controlWidth;
2335 else if (sc == SC_TitleBarMaxButton)
2338 case SC_TitleBarShadeButton:
2339 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2340 offset += controlWidth;
2341 else if (sc == SC_TitleBarShadeButton)
2344 case SC_TitleBarUnshadeButton:
2345 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2346 offset += controlWidth;
2347 else if (sc == SC_TitleBarUnshadeButton)
2350 case SC_TitleBarCloseButton:
2351 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2352 offset += controlWidth;
2353 else if (sc == SC_TitleBarCloseButton)
2355 ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
2356 controlWidth, controlHeight);
2358 case SC_TitleBarSysMenu:
2359 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
2360 const auto yOfs = titlebar->rect.top() + (titlebar->rect.height() - iconSize) / 2;
2361 ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, yOfs, iconSize,
2368 if (widget && isMinimized && titlebar->rect.width() < offset)
2369 const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
2370 ret = visualRect(titlebar->direction, titlebar->rect, ret);
2376 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2378 if (subControl == SC_ScrollBarAddLine || subControl == SC_ScrollBarSubLine) {
2379 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
2380 if (scrollbar->orientation == Qt::Vertical)
2381 ret = ret.adjusted(2,2,-2,-3);
2383 ret = ret.adjusted(3,2,-2,-2);
2389 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2390 const auto indicatorWidth =
2391 proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2392 switch (subControl) {
2393 case SC_ComboBoxArrow: {
2395 cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
2396 const int buttonHeight =
2397 qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
2398 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2399 const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
2400 const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
2401 const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2402 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2403 buttonSize.height());
2404 ret = visualRect(option->direction, option->rect, ret);
2407 case SC_ComboBoxEditField: {
2410 const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
2411 ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
2413 ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
2414 ret = visualRect(option->direction, option->rect, ret);
2418 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2424#if QT_CONFIG(groupbox)
2426 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2427 switch (subControl) {
2428 case SC_GroupBoxCheckBox:
2438 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2446QSize QWindows11Style::sizeFromContents(ContentsType type,
const QStyleOption *option,
2447 const QSize &size,
const QWidget *widget)
const
2449 QSize contentSize(size);
2453#if QT_CONFIG(menubar)
2454 case CT_MenuBarItem:
2455 if (!contentSize.isEmpty()) {
2456 constexpr int hMargin = 2 * 6;
2457 constexpr int hPadding = 2 * 11;
2458 constexpr int itemHeight = 32;
2459 contentSize.setWidth(contentSize.width() + hMargin + hPadding);
2460#if QT_CONFIG(tabwidget)
2461 if (widget->parent() && !qobject_cast<
const QTabWidget *>(widget->parent()))
2463 contentSize.setHeight(itemHeight);
2469 if (
const auto *menuItem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
2470 int width = size.width();
2472 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
2476 height = menuItem->fontMetrics.height() + 8;
2477 if (!menuItem->icon.isNull()) {
2478 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
2479 height = qMax(height,
2480 menuItem->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
2483 if (menuItem->text.contains(u'\t'))
2484 width += contentItemHMargin;
2485 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
2486 width += 2 * QWindowsStylePrivate::windowsArrowHMargin + contentItemHMargin;
2487 if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
2488 const QFontMetrics fm(menuItem->font);
2489 QFont fontBold = menuItem->font;
2490 fontBold.setBold(
true);
2491 const QFontMetrics fmBold(fontBold);
2492 width += fmBold.horizontalAdvance(menuItem->text) - fm.horizontalAdvance(menuItem->text);
2495 if (menuItem->menuHasCheckableItems) {
2496 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
2497 width += checkMarkWidth + contentItemHMargin * 2;
2501 if (menuItem->maxIconWidth > 0)
2502 width += contentItemHMargin * 2 + menuItem->maxIconWidth - 4;
2504 width += 2 * contentHMargin;
2507 contentSize = QSize(width, height);
2511#if QT_CONFIG(spinbox)
2513 if (
const auto *spinBoxOpt = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2515 const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
2516 const int margins = 8;
2517 const int buttonWidth = hasButtons ? 16 + contentItemHMargin : 0;
2518 const int frameWidth = spinBoxOpt->frame
2519 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
2522 contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
2527#if QT_CONFIG(combobox)
2529 if (
const auto *comboBoxOpt = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2530 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2531 contentSize += QSize(0, 4);
2532 if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
2533 const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2534 contentSize.rwidth() += w + contentItemHMargin;
2540 if (qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
2541 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2542 contentSize += QSize(0, 4);
2546 case CT_HeaderSection:
2549 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2551 case CT_RadioButton:
2553 if (
const auto *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
2554 const auto p = proxy();
2555 const bool isRadio = (type == CT_RadioButton);
2557 const int width = p->pixelMetric(
2558 isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, option, widget);
2559 const int height = p->pixelMetric(
2560 isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, option, widget);
2563 if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
2564 margins += p->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
2565 : PM_CheckBoxLabelSpacing,
2569 contentSize += QSize(width + margins, 4);
2570 contentSize.setHeight(qMax(size.height(), height + 2 * contentItemHMargin));
2576 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2577 if (size.width() == 0)
2578 contentSize.rwidth() += 2;
2580 case CT_PushButton: {
2581 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2583 const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
2584 contentSize.rwidth() += 2 * contentHMargin - oldMargin;
2587 case CT_ToolButton: {
2589 if (
const auto tb = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
2591 if (!tb->subControls.testFlag(SC_ToolButtonMenu)) {
2592 if (tb->features.testFlag(QStyleOptionToolButton::HasMenu))
2593 contentSize.rwidth() += 2;
2595 if (tb->toolButtonStyle == Qt::ToolButtonTextBesideIcon
2596 || tb->toolButtonStyle == Qt::ToolButtonIconOnly) {
2597 contentSize.rheight() = qMax(contentSize.height(), tb->iconSize.height() + 4);
2600 const auto fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
2601 contentSize += QSize(contentHMargin + 2 * fw, 2 * fw);
2604 case CT_ItemViewItem: {
2605 if (
const auto *viewItemOpt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
2606 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2607 lv && lv->viewMode() != QListView::IconMode) {
2608 QStyleOptionViewItem vOpt(*viewItemOpt);
2612 vOpt.rect.setRight(vOpt.rect.right() - contentHMargin);
2613 contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget);
2614 contentSize.rwidth() += contentHMargin;
2615 contentSize.rheight() += 2 * contentHMargin;
2618 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2624 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);