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);
1376 QPainterStateGuard psg(
painter);
1377 painter->setRenderHint(QPainter::Antialiasing);
1379 case QStyle::CE_ComboBoxLabel:
1380#if QT_CONFIG(combobox)
1381 if (
const QStyleOptionComboBox *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
1382 painter->setPen(controlTextColor(option,
true));
1383 QStyleOptionComboBox newOption = *cb;
1384 newOption.rect.adjust(4,0,-4,0);
1385 QCommonStyle::drawControl(element, &newOption, painter, widget);
1389#if QT_CONFIG(tabbar)
1390 case CE_TabBarTabShape:
1391 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1392 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1393 const bool isSelected = tab->state.testFlag(State_Selected);
1394 const auto clipRegion = painter->clipRegion();
1395 const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab
1396 || tab->position == QStyleOptionTab::Moving;
1397 auto leftMargin = (tab->position == QStyleOptionTab::Beginning || onlyOne) ? 1 : 0;
1398 auto rightMargin = (tab->position == QStyleOptionTab::End || onlyOne) ? 1 : 0;
1399 if (QCommonStylePrivate::rtl(option))
1400 std::swap(leftMargin, rightMargin);
1402 QRectF tabRect = tab->rect.marginsRemoved(QMargins(leftMargin, 1, rightMargin, -3));
1403 painter->setPen(highContrastTheme ? tab->palette.buttonText().color() : winUI3Color(frameColorLight));
1404 painter->setBrush(tab->palette.base());
1406 painter->setBrush(winUI3Color(fillMicaAltDefault));
1408 if (tab->state.testFlag(State_Sunken))
1409 painter->setBrush(winUI3Color(fillMicaAltDefault));
1410 else if (tab->state.testFlag(State_MouseOver))
1411 painter->setBrush(winUI3Color(fillMicaAltSecondary));
1413 painter->setBrush(winUI3Color(fillMicaAltTransparent));
1415 QRect upperRect = tab->rect;
1416 upperRect.setHeight(tab->rect.height() / 2.);
1417 QRect lowerRect = tab->rect;
1418 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2.);
1419 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1420 painter->drawRoundedRect(tabRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1421 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1422 painter->drawRect(tabRect);
1425 case CE_TabBarTabLabel:
1426 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1427 const bool isEnabled = tab->state.testFlags(State_Enabled);
1428 const bool isSelected = tab->state.testFlags(State_Selected);
1430 QRect tr = tab->rect;
1431 bool verticalTabs = tab->shape == QTabBar::RoundedEast
1432 || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast
1433 || tab->shape == QTabBar::TriangularWest;
1435 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1436 if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget))
1437 alignment |= Qt::TextHideMnemonic;
1439 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1442 int newX, newY, newRot;
1443 if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
1444 newX = tr.width() + tr.x();
1449 newY = tr.y() + tr.height();
1452 QTransform m = QTransform::fromTranslate(newX, newY);
1454 painter->setTransform(m,
true);
1457 d->tabLayout(tab, widget, &tr, &iconRect);
1460 if (tab->position != QStyleOptionTab::TabPosition::Moving)
1461 tr = proxy()->subElementRect(SE_TabBarTabText, option, widget);
1463 if (!tab->icon.isNull()) {
1464 const auto mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
1465 const auto state = isSelected ? QIcon::On : QIcon::Off;
1466 tab->icon.paint(painter, iconRect, Qt::AlignCenter, mode, state);
1469 painter->setPen(winUI3Color(isSelected ? textPrimary : textSecondary));
1470 proxy()->drawItemText(painter, tr, alignment, tab->palette, isEnabled, tab->text);
1474 case CE_ToolButtonLabel:
1475#if QT_CONFIG(toolbutton)
1476 if (
const QStyleOptionToolButton *toolbutton
1477 = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
1478 QRect rect = toolbutton->rect;
1481 if (toolbutton->state & (State_Sunken | State_On)) {
1482 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
1483 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
1486 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1487 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1488 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1489 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1490 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1491 alignment |= Qt::TextHideMnemonic;
1492 rect.translate(shiftX, shiftY);
1493 painter->setFont(toolbutton->font);
1494 const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
1495 painter->setPen(controlTextColor(option));
1496 proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
1497 toolbutton->state & State_Enabled, text);
1500 QSize pmSize = toolbutton->iconSize;
1501 if (!toolbutton->icon.isNull()) {
1502 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1504 if (!(toolbutton->state & State_Enabled))
1505 mode = QIcon::Disabled;
1506 else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
1507 mode = QIcon::Active;
1509 mode = QIcon::Normal;
1510 pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
1512 pmSize = pm.size() / pm.devicePixelRatio();
1515 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1516 painter->setFont(toolbutton->font);
1519 int alignment = Qt::TextShowMnemonic | Qt::AlignCenter;
1520 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1521 alignment |= Qt::TextHideMnemonic;
1523 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1524 pr.setHeight(pmSize.height() + 4);
1525 tr.adjust(0, pr.height() - 1, 0, -1);
1527 pr.setWidth(pmSize.width() + 4);
1528 tr.adjust(pr.width(), 0, 0, 0);
1530 pr.translate(shiftX, shiftY);
1532 drawArrow(proxy(), toolbutton, pr, painter, widget);
1534 const auto vr = QStyle::visualRect(toolbutton->direction, rect, pr);
1535 proxy()->drawItemPixmap(painter, vr, Qt::AlignCenter, pm);
1537 tr.translate(shiftX, shiftY);
1538 painter->setPen(controlTextColor(option));
1539 const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
1540 const auto vr = QStyle::visualRect(toolbutton->direction, rect, tr);
1541 proxy()->drawItemText(painter, vr, alignment, toolbutton->palette,
1542 toolbutton->state & State_Enabled, text);
1544 rect.translate(shiftX, shiftY);
1546 drawArrow(proxy(), toolbutton, rect, painter, widget);
1548 proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
1555 case QStyle::CE_ShapedFrame:
1556 if (
const QStyleOptionFrame *f = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1557 int frameShape = f->frameShape;
1558 int frameShadow = QFrame::Plain;
1559 if (f->state & QStyle::State_Sunken)
1560 frameShadow = QFrame::Sunken;
1561 else if (f->state & QStyle::State_Raised)
1562 frameShadow = QFrame::Raised;
1564 int lw = f->lineWidth;
1565 int mlw = f->midLineWidth;
1567 switch (frameShape) {
1569 if (frameShadow == QFrame::Plain)
1570 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1572 qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
1575 if (frameShadow == QFrame::Plain)
1576 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1578 qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
1581 QWindowsVistaStyle::drawControl(element, option, painter, widget);
1585#if QT_CONFIG(progressbar)
1586 case CE_ProgressBarGroove:
1587 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar*>(option)) {
1588 QRect rect = option->rect;
1589 QPointF center = rect.center();
1590 if (baropt->state & QStyle::State_Horizontal) {
1592 rect.moveTop(center.y());
1595 rect.moveLeft(center.x());
1597 painter->setPen(Qt::NoPen);
1598 painter->setBrush(Qt::gray);
1599 painter->drawRect(rect);
1602 case CE_ProgressBarContents:
1603 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1604 QPainterStateGuard psg(painter);
1605 QRectF rect = option->rect;
1606 painter->translate(rect.topLeft());
1607 rect.translate(-rect.topLeft());
1609 constexpr qreal progressBarThickness = 3;
1610 constexpr qreal progressBarHalfThickness = progressBarThickness / 2.0;
1612 const auto isIndeterminate = baropt->maximum == 0 && baropt->minimum == 0;
1613 const auto orientation =
1614 (baropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
1615 const auto inverted = baropt->invertedAppearance;
1616 const auto reverse = (baropt->direction == Qt::RightToLeft) ^ inverted;
1620 if (orientation == Qt::Vertical) {
1621 rect = QRectF(rect.left(), rect.top(), rect.height(),
1626 m.translate(0, -rect.height() + 1);
1629 m.translate(-rect.width(), 0);
1631 painter->setTransform(m,
true);
1632 }
else if (reverse) {
1633 QTransform m = QTransform::fromScale(-1, 1);
1634 m.translate(-rect.width(), 0);
1635 painter->setTransform(m,
true);
1637 const qreal offset = (
int(rect.height()) % 2 == 0) ? 0.5f : 0.0f;
1639 if (isIndeterminate) {
1640#if QT_CONFIG(animation)
1641 auto anim = d->animation(option->styleObject);
1643 auto anim =
new QStyleAnimation(option->styleObject);
1644 anim->setFrameRate(QStyleAnimation::SixtyFps);
1645 d->startAnimation(anim);
1647 constexpr auto loopDurationMSec = 4000;
1648 const auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(
1649 std::chrono::system_clock::now());
1650 const auto elapsed = elapsedTime.time_since_epoch().count();
1651 const auto handleCenter = (elapsed % loopDurationMSec) /
float(loopDurationMSec);
1652 const auto isLongHandle = (elapsed / loopDurationMSec) % 2 == 0;
1653 const auto lengthFactor = (isLongHandle ? 33.0f : 25.0f) / 100.0f;
1655 constexpr auto handleCenter = 0.5f;
1656 constexpr auto lengthFactor = 1;
1658 const auto begin = qMax(handleCenter * (1 + lengthFactor) - lengthFactor, 0.0f);
1659 const auto end = qMin(handleCenter * (1 + lengthFactor), 1.0f);
1660 const auto barBegin = begin * rect.width();
1661 const auto barEnd = end * rect.width();
1662 rect = QRectF(QPointF(rect.left() + barBegin, rect.top()),
1663 QPointF(rect.left() + barEnd, rect.bottom()));
1665#if QT_CONFIG(animation)
1666 d->stopAnimation(option->styleObject);
1668 const auto fillPercentage = (
float(baropt->progress - baropt->minimum))
1669 / (
float(baropt->maximum - baropt->minimum));
1670 rect.setWidth(rect.width() * fillPercentage);
1672 const QPointF center = rect.center();
1673 rect.setHeight(progressBarThickness);
1674 rect.moveTop(center.y() - progressBarHalfThickness - offset);
1675 drawRoundedRect(painter, rect, Qt::NoPen, baropt->palette.accent());
1678 case CE_ProgressBarLabel:
1679 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1680 const bool vertical = !(baropt->state & QStyle::State_Horizontal);
1682 proxy()->drawItemText(painter, baropt->rect, Qt::AlignCenter | Qt::TextSingleLine,
1683 baropt->palette, baropt->state & State_Enabled, baropt->text,
1689 case CE_PushButtonLabel:
1690 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1691 QStyleOptionButton btnCopy(*btn);
1692 btnCopy.rect = btn->rect.marginsRemoved(QMargins(contentHMargin, 0, contentHMargin, 0));
1693 btnCopy.palette.setBrush(QPalette::ButtonText, controlTextColor(option));
1694 QCommonStyle::drawControl(element, &btnCopy, painter, widget);
1697 case CE_PushButtonBevel:
1698 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1699 using namespace StyleOptionHelper;
1700 QPainterStateGuard psg(
painter);
1702 const auto rect = QRectF(btn->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1703 if (btn->features.testFlag(QStyleOptionButton::Flat)) {
1704 const QBrush brush = isPressed(option)
1705 ? winUI3Color(subtlePressedColor)
1706 : (isHover(option) ? winUI3Color(subtleHighlightColor) : Qt::transparent);
1707 drawRoundedRect(painter, rect, Qt::NoPen, brush);
1709 const bool defaultButton = btn->features.testFlag(QStyleOptionButton::DefaultButton);
1710 const QPen pen = defaultButton ? option->palette.color(QPalette::Accent)
1711 : winUI3Color(controlStrokePrimary);
1712 drawRoundedRect(painter, rect, pen, controlFillBrush(option, ControlType::Control));
1714 if (btn->features.testFlag(QStyleOptionButton::HasMenu)) {
1716 const auto indSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
1717 const auto indRect =
1720 const auto vindRect = visualRect(btn->direction, btn->rect, indRect);
1721 textRect.setWidth(textRect.width() - indSize);
1723 int fontSize = painter->font().pointSize();
1724 QFont f(d->assetFont);
1725 f.setPointSize(qRound(fontSize * 0.9f));
1726 painter->setFont(f);
1727 painter->setPen(controlTextColor(option));
1728 painter->drawText(vindRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
1732 case CE_MenuBarItem:
1733 if (
const auto *mbi = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1734 using namespace StyleOptionHelper;
1736 constexpr int hPadding = 11;
1737 constexpr int topPadding = 4;
1738 constexpr int bottomPadding = 6;
1739 QStyleOptionMenuItem newMbi = *mbi;
1741 if (
auto mbiV2 = qstyleoption_cast<
const QStyleOptionMenuItemV2 *>(option))
1742 newMbi.state.setFlag(State_Sunken, mbiV2->mouseDown);
1744 newMbi.font.setPointSize(10);
1745 newMbi.palette.setColor(QPalette::ButtonText, controlTextColor(&newMbi));
1746 if (!isDisabled(&newMbi)) {
1747 QPen pen(Qt::NoPen);
1748 QBrush brush(Qt::NoBrush);
1749 if (highContrastTheme) {
1750 pen = QPen(newMbi.palette.highlight().color(), 2);
1751 brush = newMbi.palette.window();
1752 }
else if (isPressed(&newMbi)) {
1753 brush = winUI3Color(subtlePressedColor);
1754 }
else if (isHover(&newMbi)) {
1755 brush = winUI3Color(subtleHighlightColor);
1757 if (pen != Qt::NoPen || brush != Qt::NoBrush) {
1758 const QRect rect = mbi->rect.marginsRemoved(QMargins(5, 0, 5, 0));
1759 drawRoundedRect(painter, rect, pen, brush);
1762 newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
1763 painter->setFont(newMbi.font);
1764 QCommonStyle::drawControl(element, &newMbi, painter, widget);
1769 case CE_MenuEmptyArea:
1773 if (
const auto *menuitem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1774 using namespace StyleOptionHelper;
1776 const auto visualMenuRect = [&](
const QRect &rect) {
1777 return visualRect(option->direction, menuitem->rect, rect);
1780 const bool checked =
1781 menuitem->checkType != QStyleOptionMenuItem::NotCheckable && menuitem->checked;
1783 const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2));
1784 if (!isDisabled(menuitem)) {
1785 QPen pen(Qt::NoPen);
1786 QBrush brush(Qt::NoBrush);
1787 if (highContrastTheme) {
1788 pen = QPen(menuitem->palette.highlight().color(), 2);
1789 brush = menuitem->palette.window();
1790 }
else if (isPressed(menuitem)) {
1791 brush = winUI3Color(subtlePressedColor);
1792 }
else if (isSelected(menuitem)) {
1793 brush = winUI3Color(subtleHighlightColor);
1795 if (pen != Qt::NoPen || brush != Qt::NoBrush)
1796 drawRoundedRect(painter, rect, pen, brush);
1798 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
1799 constexpr int yoff = 1;
1800 painter->setPen(highContrastTheme ? menuitem->palette.buttonText().color() : winUI3Color(dividerStrokeDefault));
1801 painter->drawLine(menuitem->rect.topLeft() + QPoint(0, yoff),
1802 menuitem->rect.topRight() + QPoint(0, yoff));
1806 int xOffset = contentHMargin;
1808 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
1810 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset, rect.y(),
1811 checkMarkWidth, rect.height())));
1812 QPainterStateGuard psg(painter);
1813 painter->setFont(d->assetFont);
1814 painter->setPen(option->palette.text().color());
1815 painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
1817 if (menuitem->menuHasCheckableItems)
1818 xOffset += checkMarkWidth + contentItemHMargin;
1819 if (!menuitem->icon.isNull()) {
1821 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset,
1823 menuitem->maxIconWidth - 4,
1825 const auto mode = isDisabled(menuitem)
1827 : (isSelected(menuitem) ? QIcon::Active : QIcon::Normal);
1828 const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
1829 QRect pmr(QPoint(0, 0), QSize(size, size));
1830 pmr.moveCenter(vRect.center());
1831 menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode,
1832 checked ? QIcon::On : QIcon::Off);
1834 if (menuitem->maxIconWidth > 0)
1835 xOffset += menuitem->maxIconWidth - 4 + contentItemHMargin;
1837 QStringView s(menuitem->text);
1839 QPoint tl(rect.left() + xOffset, rect.top());
1840 QPoint br(rect.right() - menuitem->reservedShortcutWidth - contentHMargin,
1842 QRect textRect(tl, br);
1843 QRect vRect(visualMenuRect(textRect));
1846 if (highContrastTheme) {
1847 penColor = menuitem->palette.color(
1848 isSelected(menuitem) ? QPalette::HighlightedText : QPalette::Text);
1850 QStyleOption tmpOpt(*option);
1851 tmpOpt.state.setFlag(State_Sunken,
false);
1852 penColor = controlTextColor(&tmpOpt);
1854 painter->setPen(penColor);
1856 qsizetype t = s.indexOf(u'\t');
1857 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1858 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
1859 text_flags |= Qt::TextHideMnemonic;
1860 text_flags |= Qt::AlignLeft;
1862 if (t >= 0 && menuitem->menuItemType != QStyleOptionMenuItem::SubMenu) {
1863 QRect shortcutRect(QPoint(textRect.right(), textRect.top()),
1864 QPoint(rect.right(), textRect.bottom()));
1865 QRect vShortcutRect(visualMenuRect(shortcutRect));
1866 const QString textToDraw = s.mid(t + 1).toString();
1867 painter->drawText(vShortcutRect, text_flags, textToDraw);
1870 QFont font = menuitem->font;
1871 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1873 painter->setFont(font);
1874 const QString textToDraw = s.left(t).toString();
1875 painter->drawText(vRect, text_flags, textToDraw);
1877 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
1878 int fontSize = menuitem->font.pointSize();
1879 QFont f(d->assetFont);
1880 f.setPointSize(qRound(fontSize * 0.9f));
1881 painter->setFont(f);
1882 int yOfs = qRound(fontSize / 3.0f);
1883 QPoint tl(rect.right() - 2 * QWindowsStylePrivate::windowsArrowHMargin - contentItemHMargin,
1885 QRect submenuRect(tl, rect.bottomRight());
1886 QRect vSubMenuRect = visualMenuRect(submenuRect);
1887 painter->setPen(option->palette.text().color());
1888 const bool isReverse = option->direction == Qt::RightToLeft;
1889 const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
1890 painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
1895 case CE_MenuBarEmptyArea: {
1898 case CE_HeaderEmptyArea:
1900 case CE_HeaderSection: {
1901 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1902 painter->setPen(Qt::NoPen);
1903 painter->setBrush(header->palette.button());
1904 painter->drawRect(header->rect);
1905 const bool isRtl = option->direction == Qt::RightToLeft;
1906 const QPointF tr = isRtl ? option->rect.topLeft() : option->rect.topRight();
1907 const QPointF br = isRtl ? option->rect.bottomLeft() : option->rect.bottomRight();
1908 const QPointF bl = isRtl ? option->rect.bottomRight() : option->rect.bottomLeft();
1909 constexpr QPointF trOfs = QPointF(0.5, 0.0);
1910 constexpr QPointF brOfs = QPointF(0.5, 0.5);
1911 constexpr QPointF blOfs = QPointF(0.0, 0.5);
1912 const std::array<
QPointF, 3> points = { tr + trOfs, br + brOfs, bl + blOfs };
1913 QPen pen(highContrastTheme ? header->palette.buttonText().color()
1914 : winUI3Color(frameColorLight));
1915 pen.setJoinStyle(Qt::MiterJoin);
1916 painter->setPen(pen);
1917 painter->drawPolyline(points.data(),
int(points.size()));
1921 case CE_ItemViewItem: {
1922 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1923 const auto p = proxy();
1924 QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
1925 QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
1926 QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget);
1929 proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
1931 const QRect &rect = vopt->rect;
1932 const bool isRtl = option->direction == Qt::RightToLeft;
1933 bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1934 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1935 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1936 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1938 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1939 if (qobject_cast<
const QTableView *>(view)) {
1943 if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
1944 vopt->showDecorationSelected) {
1956 }
else if (isLast) {
1963 const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
1964 if (highlightCurrent) {
1965 if (highContrastTheme) {
1966 painter->setBrush(vopt->palette.highlight());
1968 painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
1969 ? calculateAccentColor(option)
1970 : winUI3Color(subtleHighlightColor));
1973 painter->setBrush(vopt->backgroundBrush);
1975 painter->setPen(Qt::NoPen);
1978 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
1979 secondLevelRoundingRadius, secondLevelRoundingRadius);
1980 }
else if (isFirst) {
1981 QPainterStateGuard psg(
painter);
1982 painter->setClipRect(rect);
1983 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1984 secondLevelRoundingRadius, secondLevelRoundingRadius);
1985 }
else if (isLast) {
1986 QPainterStateGuard psg(
painter);
1987 painter->setClipRect(rect);
1988 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1989 secondLevelRoundingRadius, secondLevelRoundingRadius);
1991 painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1995 if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
1996 QStyleOptionViewItem option(*vopt);
1997 option.rect = checkRect;
1998 option.state = option.state & ~QStyle::State_HasFocus;
2000 switch (vopt->checkState) {
2002 option.state |= QStyle::State_Off;
2004 case Qt::PartiallyChecked:
2005 option.state |= QStyle::State_NoChange;
2008 option.state |= QStyle::State_On;
2011 proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
2015 if (iconRect.isValid()) {
2016 QIcon::Mode mode = QIcon::Normal;
2017 if (!(vopt->state & QStyle::State_Enabled))
2018 mode = QIcon::Disabled;
2019 else if (vopt->state & QStyle::State_Selected)
2020 mode = QIcon::Selected;
2021 QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
2022 vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
2025 if (highlightCurrent && highContrastTheme) {
2026 painter->setPen(vopt->palette.base().color());
2027 }
else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
2028 painter->setPen(winUI3Color(textOnAccentPrimary));
2030 painter->setPen(vopt->palette.text().color());
2032 d->viewItemDrawText(painter, vopt, textRect);
2035 if (vopt->state & State_Selected && !highContrastTheme) {
2036 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2037 lv && lv->viewMode() != QListView::IconMode) {
2038 const auto col = vopt->palette.accent().color();
2039 painter->setBrush(col);
2040 painter->setPen(col);
2041 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
2042 const auto yOfs = rect.height() / 4.;
2043 QRectF r(
QPointF(xPos, rect.y() + yOfs),
2044 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
2045 painter->drawRoundedRect(r, 1, 1);
2052 QWindowsVistaStyle::drawControl(element, option, painter, widget);
2225QRect QWindows11Style::subControlRect(ComplexControl control,
const QStyleOptionComplex *option,
2226 SubControl subControl,
const QWidget *widget)
const
2231#if QT_CONFIG(spinbox)
2233 if (
const QStyleOptionSpinBox *spinbox = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2234 const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
2235 const int fw = spinbox->frame
2236 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
2238 const int buttonHeight = hasButtons
2239 ? qMin(spinbox->rect.height() - 3 * fw, spinbox->fontMetrics.height() * 5 / 4)
2241 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2242 const int textFieldLength = spinbox->rect.width() - 2 * fw - 2 * buttonSize.width();
2243 const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
2244 switch (subControl) {
2246 case SC_SpinBoxDown: {
2249 const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2250 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2251 buttonSize.height());
2252 if (subControl == SC_SpinBoxDown)
2253 ret.moveRight(ret.right() + buttonSize.width());
2256 case SC_SpinBoxEditField:
2257 ret = QRect(topLeft,
2258 spinbox->rect.bottomRight() - QPoint(fw + 2 * buttonSize.width(), fw));
2260 case SC_SpinBoxFrame:
2261 ret = spinbox->rect;
2265 ret = visualRect(spinbox->direction, spinbox->rect, ret);
2269 if (
const QStyleOptionTitleBar *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(option)) {
2270 SubControl sc = subControl;
2271 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2272 static constexpr int indent = 3;
2273 static constexpr int controlWidthMargin = 2;
2274 const int controlHeight = titlebar->rect.height();
2275 const int controlWidth = 46;
2276 const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
2277 int offset = -(controlWidthMargin + indent);
2279 bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
2280 bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
2283 case SC_TitleBarLabel:
2284 if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
2285 ret = titlebar->rect;
2286 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2287 ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
2288 if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
2289 ret.adjust(0, 0, -controlWidth, 0);
2290 if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
2291 ret.adjust(0, 0, -controlWidth, 0);
2292 if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
2293 ret.adjust(0, 0, -controlWidth, 0);
2294 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2295 ret.adjust(0, 0, -controlWidth, 0);
2298 case SC_TitleBarContextHelpButton:
2299 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2300 offset += controlWidth;
2302 case SC_TitleBarMinButton:
2303 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2304 offset += controlWidth;
2305 else if (sc == SC_TitleBarMinButton)
2308 case SC_TitleBarNormalButton:
2309 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2310 offset += controlWidth;
2311 else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2312 offset += controlWidth;
2313 else if (sc == SC_TitleBarNormalButton)
2316 case SC_TitleBarMaxButton:
2317 if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2318 offset += controlWidth;
2319 else if (sc == SC_TitleBarMaxButton)
2322 case SC_TitleBarShadeButton:
2323 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2324 offset += controlWidth;
2325 else if (sc == SC_TitleBarShadeButton)
2328 case SC_TitleBarUnshadeButton:
2329 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2330 offset += controlWidth;
2331 else if (sc == SC_TitleBarUnshadeButton)
2334 case SC_TitleBarCloseButton:
2335 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2336 offset += controlWidth;
2337 else if (sc == SC_TitleBarCloseButton)
2339 ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
2340 controlWidth, controlHeight);
2342 case SC_TitleBarSysMenu:
2343 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
2344 const auto yOfs = titlebar->rect.top() + (titlebar->rect.height() - iconSize) / 2;
2345 ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, yOfs, iconSize,
2352 if (widget && isMinimized && titlebar->rect.width() < offset)
2353 const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
2354 ret = visualRect(titlebar->direction, titlebar->rect, ret);
2360 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2362 if (subControl == SC_ScrollBarAddLine || subControl == SC_ScrollBarSubLine) {
2363 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
2364 if (scrollbar->orientation == Qt::Vertical)
2365 ret = ret.adjusted(2,2,-2,-3);
2367 ret = ret.adjusted(3,2,-2,-2);
2373 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2374 const auto indicatorWidth =
2375 proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2376 switch (subControl) {
2377 case SC_ComboBoxArrow: {
2379 cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
2380 const int buttonHeight =
2381 qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
2382 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2383 const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
2384 const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
2385 const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2386 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2387 buttonSize.height());
2388 ret = visualRect(option->direction, option->rect, ret);
2391 case SC_ComboBoxEditField: {
2394 const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
2395 ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
2397 ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
2398 ret = visualRect(option->direction, option->rect, ret);
2402 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2408#if QT_CONFIG(groupbox)
2410 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2411 switch (subControl) {
2412 case SC_GroupBoxCheckBox:
2422 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2430QSize QWindows11Style::sizeFromContents(ContentsType type,
const QStyleOption *option,
2431 const QSize &size,
const QWidget *widget)
const
2433 QSize contentSize(size);
2437#if QT_CONFIG(menubar)
2438 case CT_MenuBarItem:
2439 if (!contentSize.isEmpty()) {
2440 constexpr int hMargin = 2 * 6;
2441 constexpr int hPadding = 2 * 11;
2442 constexpr int itemHeight = 32;
2443 contentSize.setWidth(contentSize.width() + hMargin + hPadding);
2444#if QT_CONFIG(tabwidget)
2445 if (widget->parent() && !qobject_cast<
const QTabWidget *>(widget->parent()))
2447 contentSize.setHeight(itemHeight);
2453 if (
const auto *menuItem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
2454 int width = size.width();
2456 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
2460 height = menuItem->fontMetrics.height() + 8;
2461 if (!menuItem->icon.isNull()) {
2462 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
2463 height = qMax(height,
2464 menuItem->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
2467 if (menuItem->text.contains(u'\t'))
2468 width += contentItemHMargin;
2469 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
2470 width += 2 * QWindowsStylePrivate::windowsArrowHMargin + contentItemHMargin;
2471 if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
2472 const QFontMetrics fm(menuItem->font);
2473 QFont fontBold = menuItem->font;
2474 fontBold.setBold(
true);
2475 const QFontMetrics fmBold(fontBold);
2476 width += fmBold.horizontalAdvance(menuItem->text) - fm.horizontalAdvance(menuItem->text);
2479 if (menuItem->menuHasCheckableItems) {
2480 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
2481 width += checkMarkWidth + contentItemHMargin * 2;
2485 if (menuItem->maxIconWidth > 0)
2486 width += contentItemHMargin * 2 + menuItem->maxIconWidth - 4;
2488 width += 2 * contentHMargin;
2491 contentSize = QSize(width, height);
2495#if QT_CONFIG(spinbox)
2497 if (
const auto *spinBoxOpt = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2499 const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
2500 const int margins = 8;
2501 const int buttonWidth = hasButtons ? 16 + contentItemHMargin : 0;
2502 const int frameWidth = spinBoxOpt->frame
2503 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
2506 contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
2511#if QT_CONFIG(combobox)
2513 if (
const auto *comboBoxOpt = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2514 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2515 contentSize += QSize(0, 4);
2516 if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
2517 const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2518 contentSize.rwidth() += w + contentItemHMargin;
2524 if (qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
2525 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2526 contentSize += QSize(0, 4);
2530 case CT_HeaderSection:
2533 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2535 case CT_RadioButton:
2537 if (
const auto *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
2538 const auto p = proxy();
2539 const bool isRadio = (type == CT_RadioButton);
2541 const int width = p->pixelMetric(
2542 isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, option, widget);
2543 const int height = p->pixelMetric(
2544 isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, option, widget);
2547 if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
2548 margins += p->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
2549 : PM_CheckBoxLabelSpacing,
2553 contentSize += QSize(width + margins, 4);
2554 contentSize.setHeight(qMax(size.height(), height + 2 * contentItemHMargin));
2560 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2561 if (size.width() == 0)
2562 contentSize.rwidth() += 2;
2564 case CT_PushButton: {
2565 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2567 const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
2568 contentSize.rwidth() += 2 * contentHMargin - oldMargin;
2571 case CT_ToolButton: {
2573 if (
const auto tb = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
2575 if (!tb->subControls.testFlag(SC_ToolButtonMenu)) {
2576 if (tb->features.testFlag(QStyleOptionToolButton::HasMenu))
2577 contentSize.rwidth() += 2;
2579 if (tb->toolButtonStyle == Qt::ToolButtonTextBesideIcon
2580 || tb->toolButtonStyle == Qt::ToolButtonIconOnly) {
2581 contentSize.rheight() = qMax(contentSize.height(), tb->iconSize.height() + 4);
2584 const auto fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
2585 contentSize += QSize(contentHMargin + 2 * fw, 2 * fw);
2588 case CT_ItemViewItem: {
2589 if (
const auto *viewItemOpt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
2590 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2591 lv && lv->viewMode() != QListView::IconMode) {
2592 QStyleOptionViewItem vOpt(*viewItemOpt);
2596 vOpt.rect.setRight(vOpt.rect.right() - contentHMargin);
2597 contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget);
2598 contentSize.rwidth() += contentHMargin;
2599 contentSize.rheight() += 2 * contentHMargin;
2602 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2608 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);