308void QWindows11Style::drawComplexControl(ComplexControl control,
const QStyleOptionComplex *option,
309 QPainter *painter,
const QWidget *widget)
const
313 const auto drawTitleBarButton = [&](ComplexControl control, SubControl sc, Icon ico) {
315 const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
316 if (buttonRect.isValid()) {
317 const bool hover = option->activeSubControls == sc && isHover(option);
320 painter->setPen(option->palette.color(QPalette::WindowText));
321 painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
324 const auto drawTitleBarCloseButton = [&](ComplexControl control, SubControl sc, Icon ico) {
326 const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
327 if (buttonRect.isValid()) {
328 const auto state = (option->activeSubControls == sc) ? calcControlState(option)
329 : ControlState::Normal;
333 painter->fillRect(buttonRect, shellCaptionCloseFillColorPrimary);
334 pen = shellCaptionCloseTextFillColorPrimary;
337 painter->fillRect(buttonRect, shellCaptionCloseFillColorSecondary);
338 pen = shellCaptionCloseTextFillColorSecondary;
340 case ControlState::Disabled:
341 case ControlState::Normal:
342 pen = option->palette.color(QPalette::WindowText);
346 painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
351 State state = option->state;
352 SubControls sub = option->subControls;
353 State flags = option->state;
354 if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
355 flags |= State_MouseOver;
357 QPainterStateGuard psg(
painter);
358 painter->setRenderHint(QPainter::Antialiasing);
359 if (d->transitionsEnabled() && option->styleObject) {
360 if (control == CC_Slider) {
361 if (
const auto *slider = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
362 QObject *styleObject = option->styleObject;
364 QRectF thumbRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
365 const qreal outerRadius = qMin(8.0, (slider->orientation == Qt::Horizontal ? thumbRect.height() / 2.0 : thumbRect.width() / 2.0) - 1);
366 bool isInsideHandle = option->activeSubControls == SC_SliderHandle;
368 bool oldIsInsideHandle = styleObject->property(
"_q_insidehandle").toBool();
369 State oldState = State(styleObject->property(
"_q_stylestate").toInt());
370 SubControls oldActiveControls = SubControls(styleObject->property(
"_q_stylecontrols").toInt());
372 QRectF oldRect = styleObject->property(
"_q_stylerect").toRect();
373 styleObject->setProperty(
"_q_insidehandle", isInsideHandle);
374 styleObject->setProperty(
"_q_stylestate",
int(state));
375 styleObject->setProperty(
"_q_stylecontrols",
int(option->activeSubControls));
376 styleObject->setProperty(
"_q_stylerect", option->rect);
377 if (option->styleObject->property(
"_q_end_radius").isNull())
378 option->styleObject->setProperty(
"_q_end_radius", outerRadius * 0.43);
380 bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
381 || (oldIsInsideHandle != isInsideHandle)
382 || (oldActiveControls != option->activeSubControls))
383 && state & State_Enabled);
385 if (oldRect != option->rect) {
386 doTransition =
false;
387 d->stopAnimation(styleObject);
388 styleObject->setProperty(
"_q_inner_radius", outerRadius * 0.43);
392 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
393 t->setStartValue(styleObject->property(
"_q_inner_radius").toFloat());
394 t->setEndValue(outerRadius * sliderInnerRadius(state, isInsideHandle));
395 styleObject->setProperty(
"_q_end_radius", t->endValue());
397 t->setStartTime(d->animationTime());
399 d->startAnimation(t);
402 }
else if (control == CC_ScrollBar) {
403 QObject *styleObject = option->styleObject;
404 State oldState = State(styleObject->property(
"_q_stylestate").toInt());
405 const bool wasMouseOver = oldState.testFlag(State_MouseOver);
406 const bool isMouseOver = state.testFlag(State_MouseOver);
408 if (wasMouseOver != isMouseOver) {
409 styleObject->setProperty(
"_q_stylestate",
int(state));
410 auto anim = qobject_cast<QNumberStyleAnimation *>(d->animation(styleObject));
411 constexpr int durationMS = 100;
412 qreal startValue = isMouseOver ? 0 : 1;
413 int curDurationMS = durationMS;
415 startValue = anim->currentValue();
416 curDurationMS = durationMS - (anim->duration() - anim->currentLoopTime());
417 d->stopAnimation(option->styleObject);
419 anim =
new QNumberStyleAnimation(styleObject);
420 anim->setStartValue(startValue);
421 anim->setEndValue(isMouseOver ? 1 : 0);
422 anim->setDuration(curDurationMS);
423 d->startAnimation(anim);
429#if QT_CONFIG(spinbox)
431 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
432 QCachedPainter cp(painter, QLatin1StringView(
"win11_spinbox") % HexString<uint8_t>(colorSchemeIndex),
433 sb, sb->rect.size());
434 if (cp.needsPainting()) {
435 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
436 drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, inputFillBrush(option, widget));
438 if (sb->frame && (sub & SC_SpinBoxFrame))
439 drawLineEditFrame(cp.painter(), frameRect, option);
441 const auto drawUpDown = [&](QStyle::SubControl sc,
442 QAbstractSpinBox::StepEnabledFlag flag) {
443 const bool isEnabled =
444 state.testFlag(QStyle::State_Enabled) && sb->stepEnabled.testFlag(flag);
445 const bool isUp = sc == SC_SpinBoxUp;
446 const QRect rect = proxy()->subControlRect(CC_SpinBox, option, sc, widget);
447 if (isEnabled && sb->activeSubControls & sc)
448 drawRoundedRect(cp.painter(), rect.adjusted(1, 1, -1, -2), Qt::NoPen,
449 winUI3Color(subtleHighlightColor));
451 cp->setFont(d->assetFont);
452 cp->setPen(sb->palette.color(isEnabled ? QPalette::Active : QPalette::Disabled,
453 QPalette::ButtonText));
454 cp->setBrush(Qt::NoBrush);
455 cp->drawText(rect, Qt::AlignCenter, fluentIcon(isUp ? Icon::ChevronUp : Icon::ChevronDown));
457 if (sub & SC_SpinBoxUp)
458 drawUpDown(SC_SpinBoxUp, QAbstractSpinBox::StepUpEnabled);
459 if (sub & SC_SpinBoxDown)
460 drawUpDown(SC_SpinBoxDown, QAbstractSpinBox::StepDownEnabled);
461 if (state & State_KeyboardFocusChange && state & State_HasFocus) {
462 QStyleOptionFocusRect fropt;
463 fropt.QStyleOption::operator=(*option);
464 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, cp.painter(), widget);
472 if (
const auto *slider = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
473 const auto &slrect = slider->rect;
474 const bool isHorizontal = slider->orientation == Qt::Horizontal;
475 const QRectF handleRect(proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget));
476 const QPointF handleCenter(handleRect.center());
478 if (sub & SC_SliderGroove) {
479 QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
484 rect = QRectF(rect.left() + 2, rect.center().y() - 2, rect.width() - 2, 4);
485 leftRect = QRectF(rect.left(), rect.top(), handleCenter.x() - rect.left(),
487 rightRect = QRectF(handleCenter.x(), rect.top(),
488 rect.width() - handleCenter.x(),
491 rect = QRect(rect.center().x() - 2, rect.top() + 2, 4, rect.height() - 2);
492 leftRect = QRectF(rect.left(), rect.top(), rect.width(),
493 handleCenter.y() - rect.top());
494 rightRect = QRectF(rect.left(), handleCenter.y(), rect.width(),
495 rect.height() - handleCenter.y());
497 if (slider->upsideDown)
498 qSwap(leftRect, rightRect);
500 painter->setPen(Qt::NoPen);
501 painter->setBrush(calculateAccentColor(option));
502 painter->drawRoundedRect(leftRect,1,1);
503 painter->setBrush(WINUI3Colors[colorSchemeIndex][controlStrongFill]);
504 painter->drawRoundedRect(rightRect,1,1);
506 if (sub & SC_SliderTickmarks) {
507 int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
508 int ticks = slider->tickPosition;
509 int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
510 int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
511 int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
512 int interval = slider->tickInterval;
514 interval = slider->singleStep;
515 if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
517 - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
519 interval = slider->pageStep;
524 painter->setPen(slider->palette.text().color());
525 QVarLengthArray<QLineF, 32> lines;
526 int v = slider->minimum;
527 while (v <= slider->maximum + 1) {
528 if (v == slider->maximum + 1 && interval == 1)
530 const int v_ = qMin(v, slider->maximum);
531 int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
532 int pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, v_,
533 available, slider->upsideDown);
536 if (ticks & QSlider::TicksAbove) {
537 lines.append(QLineF(pos, tickOffset - 0.5,
538 pos, tickOffset - tickLength - 0.5));
541 if (ticks & QSlider::TicksBelow) {
542 lines.append(QLineF(pos, tickOffset + thickness + 0.5,
543 pos, tickOffset + thickness + tickLength + 0.5));
546 if (ticks & QSlider::TicksAbove) {
547 lines.append(QLineF(tickOffset - 0.5, pos,
548 tickOffset - tickLength - 0.5, pos));
551 if (ticks & QSlider::TicksBelow) {
552 lines.append(QLineF(tickOffset + thickness + 0.5, pos,
553 tickOffset + thickness + tickLength + 0.5, pos));
557 int nextInterval = v + interval;
558 if (nextInterval < v)
562 if (!lines.isEmpty()) {
563 QPainterStateGuard psg(painter);
564 painter->translate(slrect.topLeft());
565 painter->drawLines(lines.constData(), lines.size());
568 if (sub & SC_SliderHandle) {
569 const qreal outerRadius = qMin(8.0, (isHorizontal ? handleRect.height() / 2.0 : handleRect.width() / 2.0) - 1);
570 float innerRadius = outerRadius * 0.43;
572 if (option->styleObject) {
573 const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
574 if (animation !=
nullptr) {
575 innerRadius = animation->currentValue();
576 option->styleObject->setProperty(
"_q_inner_radius", innerRadius);
578 bool isInsideHandle = option->activeSubControls == SC_SliderHandle;
579 innerRadius = outerRadius * sliderInnerRadius(state, isInsideHandle);
583 painter->setPen(Qt::NoPen);
584 painter->setBrush(winUI3Color(controlFillSolid));
585 painter->drawEllipse(handleCenter, outerRadius, outerRadius);
586 painter->setBrush(calculateAccentColor(option));
587 painter->drawEllipse(handleCenter, innerRadius, innerRadius);
589 painter->setPen(winUI3Color(controlStrokeSecondary));
590 painter->setBrush(Qt::NoBrush);
591 painter->drawEllipse(handleCenter, outerRadius + 0.5, outerRadius + 0.5);
593 if (slider->state & State_HasFocus) {
594 QStyleOptionFocusRect fropt;
595 fropt.QStyleOption::operator=(*slider);
596 fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
597 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
602#if QT_CONFIG(combobox)
604 if (
const QStyleOptionComboBox *combobox = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
605 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
606 QStyleOption opt(*option);
607 opt.state.setFlag(QStyle::State_On,
false);
608 drawRoundedRect(painter, frameRect, Qt::NoPen,
609 combobox->editable ? inputFillBrush(option, widget)
610 : controlFillBrush(&opt, ControlType::Control));
613 drawLineEditFrame(painter, frameRect, combobox, combobox->editable);
615 const bool hasFocus = state & State_HasFocus;
617 if (sub & SC_ComboBoxArrow) {
618 QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
619 painter->setFont(d->assetFont);
620 painter->setPen(controlTextColor(option,
true));
621 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
623 if (state & State_KeyboardFocusChange && hasFocus) {
624 QStyleOptionFocusRect fropt;
625 fropt.QStyleOption::operator=(*option);
626 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
632 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
633 const bool vertical = scrollbar->orientation == Qt::Vertical;
634 const bool isMouseOver = state & State_MouseOver;
635 const auto prx = proxy();
637 QPainterStateGuard psg(
painter);
639 const auto anim = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
640 qreal widthFactor = isMouseOver ? 1.0 : 0.0;
642 widthFactor = anim->currentValue();
644 if (widthFactor > 0.6) {
645 const bool isRtl = option->direction == Qt::RightToLeft;
647 QFont f = QFont(d->assetFont);
650 painter->setPen(winUI3Color(controlStrongFill));
652 const QRectF rectAdd =
653 prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
654 const auto strAdd = vertical
655 ? Icon::CaretDownSolid8
656 : (isRtl ? Icon::CaretLeftSolid8 : Icon::CaretRightSolid8);
657 painter->drawText(rectAdd, Qt::AlignCenter, fluentIcon(strAdd));
659 const QRectF rectSub =
660 prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
661 const auto strSub = vertical
662 ? Icon::CaretUpSolid8
663 : (isRtl ? Icon::CaretRightSolid8 : Icon::CaretLeftSolid8);
664 painter->drawText(rectSub, Qt::AlignCenter, fluentIcon(strSub));
666 if (sub & SC_ScrollBarSlider) {
667 QRectF rect = prx->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
668 const QPointF center = rect.center();
670 auto w = rect.width() / 2. * widthFactor;
673 const auto ofs = rect.width() / 2 - w;
675 rect.moveCenter(QPointF(center.x() + ofs, center.y()));
678 auto h = rect.height() / 2. * widthFactor;
681 const auto ofs = rect.height() / 2 - h;
683 rect.moveCenter(QPointF(center.x(), center.y() + ofs));
685 drawRoundedRect(painter, rect, Qt::NoPen, winUI3Color(controlStrongFill), 3);
689 case CC_MdiControls:{
690 QFont buttonFont = QFont(d->assetFont);
691 buttonFont.setPointSize(8);
692 painter->setFont(buttonFont);
693 drawTitleBarCloseButton(CC_MdiControls, SC_MdiCloseButton, Icon::ChromeClose);
694 drawTitleBarButton(CC_MdiControls, SC_MdiNormalButton, Icon::ChromeRestore);
695 drawTitleBarButton(CC_MdiControls, SC_MdiMinButton, Icon::ChromeMinimize);
699 if (
const auto* titlebar = qstyleoption_cast<
const QStyleOptionTitleBar*>(option)) {
700 painter->setPen(Qt::NoPen);
701 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
702 painter->setBrush(titlebar->palette.button());
703 painter->drawRect(titlebar->rect);
706 QRect textRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
707 QColor textColor = titlebar->palette.color(titlebar->titleBarState & Qt::WindowActive ? QPalette::Active : QPalette::Disabled,QPalette::WindowText);
708 painter->setPen(textColor);
710 QString title = painter->fontMetrics().elidedText(titlebar->text, Qt::ElideRight, textRect.width() - 14);
711 painter->drawText(textRect.adjusted(1, 1, -1, -1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
713 QFont buttonFont = QFont(d->assetFont);
714 buttonFont.setPointSize(8);
715 painter->setFont(buttonFont);
716 auto shouldDrawButton = [titlebar](SubControl sc, Qt::WindowType flag) {
717 return (titlebar->subControls & sc) && (titlebar->titleBarFlags & flag);
721 if (shouldDrawButton(SC_TitleBarMinButton, Qt::WindowMinimizeButtonHint) &&
722 !(titlebar->titleBarState & Qt::WindowMinimized)) {
723 drawTitleBarButton(CC_TitleBar, SC_TitleBarMinButton, Icon::ChromeMinimize);
727 if (shouldDrawButton(SC_TitleBarMaxButton, Qt::WindowMaximizeButtonHint) &&
728 !(titlebar->titleBarState & Qt::WindowMaximized)) {
729 drawTitleBarButton(CC_TitleBar, SC_TitleBarMaxButton, Icon::ChromeMaximize);
733 if (shouldDrawButton(SC_TitleBarCloseButton, Qt::WindowSystemMenuHint))
734 drawTitleBarCloseButton(CC_TitleBar, SC_TitleBarCloseButton, Icon::ChromeClose);
737 if ((titlebar->subControls & SC_TitleBarNormalButton) &&
738 (((titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
739 (titlebar->titleBarState & Qt::WindowMinimized)) ||
740 ((titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
741 (titlebar->titleBarState & Qt::WindowMaximized)))) {
742 drawTitleBarButton(CC_TitleBar, SC_TitleBarNormalButton, Icon::ChromeRestore);
746 if (shouldDrawButton(SC_TitleBarContextHelpButton, Qt::WindowContextHelpButtonHint))
747 drawTitleBarButton(CC_TitleBar, SC_TitleBarContextHelpButton, Icon::Help);
750 if (shouldDrawButton(SC_TitleBarShadeButton, Qt::WindowShadeButtonHint))
751 drawTitleBarButton(CC_TitleBar, SC_TitleBarShadeButton, Icon::ChevronUpSmall);
754 if (shouldDrawButton(SC_TitleBarUnshadeButton, Qt::WindowShadeButtonHint))
755 drawTitleBarButton(CC_TitleBar, SC_TitleBarUnshadeButton, Icon::ChevronDownSmall);
758 if (shouldDrawButton(SC_TitleBarSysMenu, Qt::WindowSystemMenuHint)) {
759 const QRect iconRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarSysMenu, widget);
760 if (iconRect.isValid()) {
761 if (!titlebar->icon.isNull()) {
762 titlebar->icon.paint(painter, iconRect);
764 QStyleOption tool = *titlebar;
765 const auto extent = proxy()->pixelMetric(PM_SmallIconSize, &tool, widget);
766 const auto dpr = QStyleHelper::getDpr(widget);
767 const auto icon = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget);
768 const auto pm = icon.pixmap(QSize(extent, extent), dpr);
769 proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm);
775#if QT_CONFIG(toolbutton)
777 if (
const auto toolbutton = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
779 const bool isSplitButton =
780 toolbutton->features.testFlag(QStyleOptionToolButton::MenuButtonPopup);
781 const auto fw = prx->pixelMetric(PM_DefaultFrameWidth, option, widget);
782 const auto buttonRect = prx->subControlRect(control, toolbutton, SC_ToolButton, widget);
783 const auto menuareaRect = isSplitButton
784 ? prx->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget)
787 State bflags = toolbutton->state;
788 State mflags = toolbutton->state;
789 if (toolbutton->activeSubControls.testFlag(SC_ToolButton)) {
790 mflags &= ~(State_Sunken | State_MouseOver);
791 if (bflags.testFlag(State_Sunken))
792 mflags |= State_Raised;
794 if (toolbutton->activeSubControls.testFlag(SC_ToolButtonMenu)) {
795 bflags &= ~(State_Sunken | State_MouseOver);
796 if (mflags.testFlag(State_Sunken))
797 bflags |= State_Raised;
800 QStyleOption tool = *toolbutton;
801 if (toolbutton->subControls.testFlag(SC_ToolButton)) {
802 QPainterStateGuard psg(painter);
804 painter->setClipRect(buttonRect);
806 prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
808 if (state.testFlag(State_Enabled)) {
809 painter->setPen(winUI3Color(controlStrokePrimary));
810 const auto top = buttonRect.topRight() + QPoint(0, fw + 1);
811 const auto btm = buttonRect.bottomRight() - QPoint(0, fw);
812 painter->drawLine(top, btm);
817 if (toolbutton->state.testFlag(State_HasFocus)) {
818 QStyleOptionFocusRect fr;
819 fr.QStyleOption::operator=(*toolbutton);
820 prx->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget);
822 QStyleOptionToolButton label = *toolbutton;
823 label.state = bflags;
824 label.rect = buttonRect.marginsRemoved(QMargins(fw, fw, fw, fw));
825 prx->drawControl(CE_ToolButtonLabel, &label, painter, widget);
827 if (toolbutton->subControls.testFlag(SC_ToolButtonMenu)) {
828 QPainterStateGuard psg(painter);
829 painter->setClipRect(menuareaRect);
831 prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
833 const int fontSize = painter->font().pointSize();
834 QFont f(d->assetFont);
835 f.setPointSize(qRound(fontSize * 0.9f));
837 painter->setPen(controlTextColor(option));
838 const QRect textRect(menuareaRect.topLeft(), menuareaRect.size() - QSize(fw, 0));
839 painter->drawText(textRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
841 }
else if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) {
842 const int mbi = prx->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget);
843 const QRect &ir = toolbutton->rect;
844 QRect rect(ir.right() + 5 - mbi, ir.y() + ir.height() - mbi + 4, mbi - 6 - fw,
846 rect = visualRect(toolbutton->direction, buttonRect, rect);
847 painter->setFont(QFont(d->assetFont));
848 painter->setPen(controlTextColor(option));
849 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
855 QWindowsVistaStyle::drawComplexControl(control, option, painter, widget);
859void QWindows11Style::drawPrimitive(PrimitiveElement element,
const QStyleOption *option,
861 const QWidget *widget)
const {
864 const State state = option->state;
865 QPainterStateGuard psg(
painter);
866 painter->setRenderHint(QPainter::Antialiasing);
867 if (d->transitionsEnabled() && option->styleObject && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) {
868 QObject *styleObject = option->styleObject;
869 int oldState = styleObject->property(
"_q_stylestate").toInt();
870 styleObject->setProperty(
"_q_stylestate",
int(option->state));
871 styleObject->setProperty(
"_q_stylerect", option->rect);
872 bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
873 || ((state & State_MouseOver) != (oldState & State_MouseOver))
874 || (state & State_On) != (oldState & State_On))
875 && state & State_Enabled);
877 if (element == PE_IndicatorRadioButton) {
878 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
879 t->setStartValue(styleObject->property(
"_q_inner_radius").toFloat());
880 t->setEndValue(radioButtonInnerRadius(state));
881 styleObject->setProperty(
"_q_end_radius", t->endValue());
882 t->setStartTime(d->animationTime());
884 d->startAnimation(t);
886 else if (element == PE_IndicatorCheckBox) {
887 if ((oldState & State_Off && state & State_On) || (oldState & State_NoChange && state & State_On)) {
888 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
889 t->setStartValue(0.0f);
890 t->setEndValue(1.0f);
891 t->setStartTime(d->animationTime());
893 d->startAnimation(t);
900 case PE_IndicatorArrowUp:
901 case PE_IndicatorArrowDown:
902 case PE_IndicatorArrowRight:
903 case PE_IndicatorArrowLeft: {
904 const QRect &r = option->rect;
905 if (r.width() <= 1 || r.height() <= 1)
907 Icon ico = Icon::Help;
909 case PE_IndicatorArrowUp:
910 ico = Icon::ChevronUpMed;
912 case PE_IndicatorArrowDown:
913 ico = Icon::ChevronDownMed;
915 case PE_IndicatorArrowLeft:
916 ico = Icon::ChevronLeftMed;
918 case PE_IndicatorArrowRight:
919 ico = Icon::ChevronRightMed;
924 QPainterStateGuard psg(
painter);
925 if (option->state.testFlag(State_Sunken)) {
926 const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget);
927 const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget);
928 if (bsx != 0 || bsy != 0)
929 painter->translate(bsx, bsy);
931 painter->setFont(d->assetFont);
932 painter->setPen(option->palette.buttonText().color());
933 painter->setBrush(option->palette.buttonText());
934 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
937 case PE_FrameFocusRect: {
938 if (
const QStyleOptionFocusRect *fropt = qstyleoption_cast<
const QStyleOptionFocusRect *>(option)) {
939 if (!(fropt->state & State_KeyboardFocusChange))
941 QRectF focusRect = option->rect;
942 focusRect = focusRect.marginsRemoved(QMarginsF(1.5,1.5,1.5,1.5));
943 painter->setPen(winUI3Color(focusFrameInnerStroke));
944 painter->drawRoundedRect(focusRect,4,4);
946 focusRect = focusRect.marginsAdded(QMarginsF(1.0,1.0,1.0,1.0));
947 painter->setPen(QPen(winUI3Color(focusFrameOuterStroke),1));
948 painter->drawRoundedRect(focusRect,4,4);
952 case PE_PanelTipLabel: {
953 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(0.5, 0.5, 0.5, 0.5));
954 const auto pen = highContrastTheme ? option->palette.buttonText().color()
955 : winUI3Color(frameColorLight);
956 drawRoundedRect(painter, rect, pen, option->palette.toolTipBase());
959 case PE_FrameTabWidget:
960#if QT_CONFIG(tabwidget)
961 if (
const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(option)) {
962 QPainterStateGuard psg(painter);
963 const auto clipRegion = painter->clipRegion();
965 painter->setPen(highContrastTheme ? frame->palette.buttonText().color()
966 : winUI3Color(frameColorLight));
967 painter->setBrush(frame->palette.base());
969 const auto &rect = option->rect;
970 QRect upperRect = rect;
971 upperRect.setHeight(rect.height() / 2);
972 QRect lowerRect = rect;
973 lowerRect.setY(lowerRect.y() + rect.height() / 2);
974 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
975 painter->drawRect(rect);
976 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
977 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
982 case PE_FrameGroupBox:
983 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
984 const auto pen = highContrastTheme ? frame->palette.buttonText().color()
985 : winUI3Color(frameColorStrong);
986 if (frame->features & QStyleOptionFrame::Flat) {
987 painter->setBrush(Qt::NoBrush);
988 painter->setPen(pen);
989 const QRect &fr = frame->rect;
990 QPoint p1(fr.x(), fr.y() + 1);
991 QPoint p2(fr.x() + fr.width(), p1.y());
992 painter->drawLine(p1, p2);
994 const auto frameRect = QRectF(frame->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
995 drawRoundedRect(painter, frameRect, pen, Qt::NoBrush);
999 case PE_IndicatorHeaderArrow:
1000 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1001 const auto indicator = header->sortIndicator;
1002 if (indicator != QStyleOptionHeader::None) {
1003 QPainterStateGuard psg(
painter);
1004 QFont f(d->assetFont);
1006 painter->setFont(f);
1007 painter->setPen(header->palette.text().color());
1008 const auto ico = indicator == QStyleOptionHeader::SortUp ? Icon::ChevronDown
1010 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1014 case PE_IndicatorCheckBox: {
1015 const bool isOn = option->state & State_On;
1016 const bool isPartial = option->state & State_NoChange;
1018 const QRectF rect = option->rect;
1019 const QPointF center = rect.center();
1021 drawRoundedRect(painter, option->rect, borderPenControlAlt(option),
1022 controlFillBrush(option, ControlType::ControlAlt));
1025 painter->setFont(d->assetFont);
1026 painter->setPen(controlTextColor(option));
1027 const auto *animation =
1028 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1029 const qreal clipWidth = animation ? animation->currentValue() : 1.0;
1030 const QString str = fluentIcon(Icon::AcceptMedium);
1031 QFontMetrics fm(d->assetFont);
1032 QRectF clipRect = fm.boundingRect(str);
1033 clipRect.moveCenter(center);
1034 clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0 + 0.5);
1035 clipRect.setWidth(clipWidth * clipRect.width());
1036 painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, str);
1037 }
else if (isPartial) {
1038 QFont f(d->assetFont);
1040 painter->setFont(f);
1041 painter->setPen(controlTextColor(option));
1042 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::Dash12));
1046 case PE_IndicatorBranch: {
1047 if (option->state & State_Children) {
1048 const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option);
1049 const bool isReverse = option->direction == Qt::RightToLeft;
1050 const bool isOpen = option->state & QStyle::State_Open;
1051 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1052 QFont f(d->assetFont);
1054 painter->setFont(f);
1055 if (view && view->alternatingRowColors() && vopt && vopt->state & State_Selected)
1056 painter->setPen(winUI3Color(textOnAccentPrimary));
1058 painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
1059 QPalette::WindowText));
1060 const auto ico = isOpen ? Icon::ChevronDownMed
1061 : (isReverse ? Icon::ChevronLeftMed
1062 : Icon::ChevronRightMed);
1063 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1067 case PE_IndicatorRadioButton: {
1068 const auto *animation =
1069 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1070 const qreal innerRadius =
1071 animation ? animation->currentValue() : radioButtonInnerRadius(state);
1072 const QRectF rect = option->rect;
1073 const QPointF center = rect.center();
1075 if (option->styleObject)
1076 option->styleObject->setProperty(
"_q_inner_radius", innerRadius);
1077 painter->setPen(borderPenControlAlt(option));
1078 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1079 if (option->state.testFlag(State_On)) {
1081 path.addEllipse(center, 7.5, 7.5);
1082 path.addEllipse(center, innerRadius, innerRadius);
1083 painter->drawPath(path);
1085 painter->setBrush(option->palette.window().color());
1086 painter->drawEllipse(center, innerRadius, innerRadius);
1088 painter->drawEllipse(center, 7.5, 7.5);
1092 case PE_PanelButtonTool:
1093 case PE_PanelButtonBevel:{
1094 const bool isEnabled = state & QStyle::State_Enabled;
1095 const bool isMouseOver = state & QStyle::State_MouseOver;
1096 const bool isRaised = state & QStyle::State_Raised;
1097 const int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
1098 const QRectF rect = option->rect.marginsRemoved(QMargins(fw, fw, fw, fw));
1099 if (element == PE_PanelButtonTool && ((!isMouseOver && !isRaised) || !isEnabled))
1100 painter->setPen(Qt::NoPen);
1102 painter->setPen(winUI3Color(controlStrokePrimary));
1103 painter->setBrush(controlFillBrush(option, ControlType::Control));
1104 if (element == PE_PanelButtonTool && widget) {
1105 const auto name = widget->objectName();
1106 if (name ==
"ScrollLeftButton"_L1 || name ==
"ScrollRightButton"_L1) {
1107 painter->setPen(Qt::NoPen);
1109 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1111 painter->setBrush(Qt::NoBrush);
1114 painter->drawRoundedRect(rect,
1115 secondLevelRoundingRadius, secondLevelRoundingRadius);
1118 case PE_FrameDefaultButton:
1119 painter->setPen(option->palette.accent().color());
1120 painter->setBrush(Qt::NoBrush);
1121 painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1125 case PE_PanelMenu: {
1126 if (!d->nativeRoundedTopLevelWindows) {
1127 const QRect rect = option->rect.marginsRemoved(QMargins(2, 2, 2, 2));
1128 painter->setPen(highContrastTheme ? QPen(option->palette.windowText().color(), 2)
1129 : winUI3Color(frameColorLight));
1130 painter->setBrush(winUI3Color(menuPanelFill));
1131 painter->drawRoundedRect(rect, topLevelRoundingRadius, topLevelRoundingRadius);
1135 case PE_PanelLineEdit:
1136 if (
const auto *panel = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1137 const bool isInSpinBox =
1138 widget && qobject_cast<
const QAbstractSpinBox *>(widget->parent()) !=
nullptr;
1139 const bool isInComboBox =
1140 widget && qobject_cast<
const QComboBox *>(widget->parent()) !=
nullptr;
1141 if (!isInSpinBox && !isInComboBox) {
1142 const auto frameRect =
1143 QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1144 drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
1145 if (panel->lineWidth > 0)
1146 proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
1150 case PE_FrameLineEdit: {
1151 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1152 drawLineEditFrame(painter, frameRect, option);
1153 if (state & State_KeyboardFocusChange && state & State_HasFocus) {
1154 QStyleOptionFocusRect fropt;
1155 fropt.QStyleOption::operator=(*option);
1156 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
1161 if (
const auto *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1162 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1163 if (qobject_cast<
const QComboBoxPrivateContainer *>(widget)) {
1164 if (d->nativeRoundedTopLevelWindows)
1167 if (highContrastTheme)
1168 pen = QPen(option->palette.windowText().color(), 2);
1171 drawRoundedRect(painter, rect, pen, WINUI3Colors[colorSchemeIndex][menuPanelFill]);
1173 drawRoundedRect(painter, rect, Qt::NoPen, option->palette.brush(QPalette::Base));
1175 if (frame->frameShape == QFrame::NoFrame)
1178 const bool isEditable = qobject_cast<
const QTextEdit *>(widget) !=
nullptr
1179 || qobject_cast<
const QPlainTextEdit *>(widget) !=
nullptr;
1180 drawLineEditFrame(painter, rect, option, isEditable);
1184 case PE_PanelItemViewItem:
1185 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1186 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
1187 QPainterStateGuard psg(
painter);
1188 painter->setBrushOrigin(vopt->rect.topLeft());
1189 painter->fillRect(vopt->rect, vopt->backgroundBrush);
1193 case PE_PanelItemViewRow:
1194 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1198 const QRect &rect = vopt->rect;
1199 const bool isRtl = option->direction == Qt::RightToLeft;
1200 if (rect.width() <= 0)
1203 if (vopt->features & QStyleOptionViewItem::Alternate) {
1204 QPalette::ColorGroup cg =
1205 (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
1207 : QPalette::Disabled;
1208 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
1209 cg = QPalette::Inactive;
1210 painter->fillRect(rect, option->palette.brush(cg, QPalette::AlternateBase));
1213 if (option->state & State_Selected && !highContrastTheme) {
1215 if (!qobject_cast<
const QTableView *>(widget)) {
1216 const auto col = option->palette.accent().color();
1217 painter->setBrush(col);
1218 painter->setPen(col);
1219 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
1220 const auto yOfs = rect.height() / 4.;
1221 QRectF r(
QPointF(xPos, rect.y() + yOfs),
1222 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
1223 painter->drawRoundedRect(r, 1, 1);
1227 const bool isTreeDecoration = vopt->features.testFlag(
1228 QStyleOptionViewItem::IsDecorationForRootColumn);
1229 if (isTreeDecoration && vopt->state.testAnyFlags(State_Selected | State_MouseOver) &&
1230 vopt->showDecorationSelected) {
1231 const bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1232 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1233 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1234 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1244 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1245 painter->setBrush(view->alternatingRowColors() && state & State_Selected ? calculateAccentColor(option) : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
1246 painter->setPen(Qt::NoPen);
1248 QPainterStateGuard psg(
painter);
1249 painter->setClipRect(rect);
1250 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1251 secondLevelRoundingRadius, secondLevelRoundingRadius);
1252 }
else if (isLast) {
1253 QPainterStateGuard psg(
painter);
1254 painter->setClipRect(rect);
1255 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1256 secondLevelRoundingRadius, secondLevelRoundingRadius);
1258 painter->drawRect(vopt->rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1263 case QStyle::PE_Widget: {
1264 if (widget && widget->palette().isBrushSet(QPalette::Active, widget->backgroundRole())) {
1265 const QBrush bg = widget->palette().brush(widget->backgroundRole());
1266 auto wp = QWidgetPrivate::get(widget);
1267 QPainterStateGuard psg(
painter);
1268 wp->updateBrushOrigin(painter, bg);
1269 painter->fillRect(option->rect, bg);
1273 case QStyle::PE_FrameWindow:
1274 if (
const auto *frm = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1276 QRectF rect= option->rect;
1277 int fwidth =
int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
1279 QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
1280 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1281 secondLevelRoundingRadius,
1282 secondLevelRoundingRadius);
1283 QRectF bottomRightCorner = QRectF(rect.right() - 1.0 - secondLevelRoundingRadius,
1284 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1285 secondLevelRoundingRadius,
1286 secondLevelRoundingRadius);
1289 if (widget !=
nullptr) {
1290 QBitmap mask(widget->width(), widget->height());
1294 maskPainter.setRenderHint(QPainter::Antialiasing);
1295 maskPainter.setBrush(Qt::color1);
1296 maskPainter.setPen(Qt::NoPen);
1297 maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
1298 const_cast<QWidget*>(widget)->setMask(mask);
1302 painter->setPen(QPen(frm->palette.base(), fwidth));
1303 painter->drawLine(QPointF(rect.left(), rect.top()),
1304 QPointF(rect.left(), rect.bottom() - fwidth));
1305 painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
1306 QPointF(rect.right() - fwidth, rect.bottom()));
1307 painter->drawLine(QPointF(rect.right(), rect.top()),
1308 QPointF(rect.right(), rect.bottom() - fwidth));
1310 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1311 painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
1312 QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1313 painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
1314 QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
1315 painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
1316 QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1318 painter->setPen(Qt::NoPen);
1319 painter->setBrush(frm->palette.base());
1320 painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
1322 painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
1325 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1326 painter->setBrush(Qt::NoBrush);
1327 painter->drawArc(bottomRightCorner,
1329 painter->drawArc(bottomLeftCorner,
1333#if QT_CONFIG(tabbar)
1334 case PE_FrameTabBarBase:
1335 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTabBarBase *>(option)) {
1336 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1337 const auto clipRegion = painter->clipRegion();
1339 painter->setPen(highContrastTheme ? tab->palette.buttonText().color()
1340 : winUI3Color(frameColorLight));
1341 painter->setBrush(tab->palette.base());
1342 QRect upperRect = tab->rect;
1343 upperRect.setHeight(tab->rect.height() / 2);
1344 QRect lowerRect = tab->rect;
1345 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2);
1346 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1347 painter->drawRoundedRect(tab->rect, secondLevelRoundingRadius,
1348 secondLevelRoundingRadius);
1349 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1350 painter->drawRect(tab->rect);
1354 case PE_IndicatorTabTearLeft:
1355 case PE_IndicatorTabTearRight:
1358 QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
1365void QWindows11Style::drawControl(ControlElement element,
const QStyleOption *option,
1366 QPainter *painter,
const QWidget *widget)
const
1368 Q_D(
const QWindows11Style);
1369 State flags = option->state;
1371 QPainterStateGuard psg(
painter);
1372 painter->setRenderHint(QPainter::Antialiasing);
1374 case QStyle::CE_ComboBoxLabel:
1375#if QT_CONFIG(combobox)
1376 if (
const QStyleOptionComboBox *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
1377 painter->setPen(controlTextColor(option,
true));
1378 QStyleOptionComboBox newOption = *cb;
1379 newOption.rect.adjust(4,0,-4,0);
1380 QCommonStyle::drawControl(element, &newOption, painter, widget);
1384#if QT_CONFIG(tabbar)
1385 case CE_TabBarTabShape:
1386 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1387 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1388 const bool isSelected = tab->state.testFlag(State_Selected);
1389 const auto clipRegion = painter->clipRegion();
1390 const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab
1391 || tab->position == QStyleOptionTab::Moving;
1392 auto leftMargin = (tab->position == QStyleOptionTab::Beginning || onlyOne) ? 1 : 0;
1393 auto rightMargin = (tab->position == QStyleOptionTab::End || onlyOne) ? 1 : 0;
1394 if (QCommonStylePrivate::rtl(option))
1395 std::swap(leftMargin, rightMargin);
1397 QRectF tabRect = tab->rect.marginsRemoved(QMargins(leftMargin, 1, rightMargin, -3));
1398 painter->setPen(highContrastTheme ? tab->palette.buttonText().color() : winUI3Color(frameColorLight));
1399 painter->setBrush(tab->palette.base());
1401 painter->setBrush(winUI3Color(fillMicaAltDefault));
1403 if (tab->state.testFlag(State_Sunken))
1404 painter->setBrush(winUI3Color(fillMicaAltDefault));
1405 else if (tab->state.testFlag(State_MouseOver))
1406 painter->setBrush(winUI3Color(fillMicaAltSecondary));
1408 painter->setBrush(winUI3Color(fillMicaAltTransparent));
1410 QRect upperRect = tab->rect;
1411 upperRect.setHeight(tab->rect.height() / 2.);
1412 QRect lowerRect = tab->rect;
1413 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2.);
1414 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1415 painter->drawRoundedRect(tabRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1416 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1417 painter->drawRect(tabRect);
1420 case CE_TabBarTabLabel:
1421 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1422 const bool isEnabled = tab->state.testFlags(State_Enabled);
1423 const bool isSelected = tab->state.testFlags(State_Selected);
1425 QRect tr = tab->rect;
1426 bool verticalTabs = tab->shape == QTabBar::RoundedEast
1427 || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast
1428 || tab->shape == QTabBar::TriangularWest;
1430 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1431 if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget))
1432 alignment |= Qt::TextHideMnemonic;
1434 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1437 int newX, newY, newRot;
1438 if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
1439 newX = tr.width() + tr.x();
1444 newY = tr.y() + tr.height();
1447 QTransform m = QTransform::fromTranslate(newX, newY);
1449 painter->setTransform(m,
true);
1452 d->tabLayout(tab, widget, &tr, &iconRect);
1455 if (tab->position != QStyleOptionTab::TabPosition::Moving)
1456 tr = proxy()->subElementRect(SE_TabBarTabText, option, widget);
1458 if (!tab->icon.isNull()) {
1459 const auto mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
1460 const auto state = isSelected ? QIcon::On : QIcon::Off;
1461 tab->icon.paint(painter, iconRect, Qt::AlignCenter, mode, state);
1464 painter->setPen(winUI3Color(isSelected ? textPrimary : textSecondary));
1465 proxy()->drawItemText(painter, tr, alignment, tab->palette, isEnabled, tab->text);
1469 case CE_ToolButtonLabel:
1470#if QT_CONFIG(toolbutton)
1471 if (
const QStyleOptionToolButton *toolbutton
1472 = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
1473 QRect rect = toolbutton->rect;
1476 if (toolbutton->state & (State_Sunken | State_On)) {
1477 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
1478 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
1481 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1482 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1483 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1484 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1485 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1486 alignment |= Qt::TextHideMnemonic;
1487 rect.translate(shiftX, shiftY);
1488 painter->setFont(toolbutton->font);
1489 const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
1490 painter->setPen(controlTextColor(option));
1491 proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
1492 toolbutton->state & State_Enabled, text);
1495 QSize pmSize = toolbutton->iconSize;
1496 if (!toolbutton->icon.isNull()) {
1497 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1499 if (!(toolbutton->state & State_Enabled))
1500 mode = QIcon::Disabled;
1501 else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
1502 mode = QIcon::Active;
1504 mode = QIcon::Normal;
1505 pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
1507 pmSize = pm.size() / pm.devicePixelRatio();
1510 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1511 painter->setFont(toolbutton->font);
1514 int alignment = Qt::TextShowMnemonic;
1515 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1516 alignment |= Qt::TextHideMnemonic;
1518 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1519 pr.setHeight(pmSize.height() + 4);
1520 tr.adjust(0, pr.height() - 1, 0, -1);
1521 pr.translate(shiftX, shiftY);
1523 proxy()->drawItemPixmap(painter, pr, Qt::AlignCenter, pm);
1525 drawArrow(proxy(), toolbutton, pr, painter, widget);
1527 alignment |= Qt::AlignCenter;
1529 pr.setWidth(pmSize.width() + 4);
1530 tr.adjust(pr.width(), 0, 0, 0);
1531 pr.translate(shiftX, shiftY);
1533 proxy()->drawItemPixmap(painter, QStyle::visualRect(toolbutton->direction, rect, pr), Qt::AlignCenter, pm);
1535 drawArrow(proxy(), toolbutton, pr, painter, widget);
1537 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
1539 tr.translate(shiftX, shiftY);
1540 const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
1541 painter->setPen(controlTextColor(option));
1542 proxy()->drawItemText(painter, QStyle::visualRect(toolbutton->direction, rect, tr), 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 const auto visualMenuRect = [&](
const QRect &rect) {
1791 return visualRect(option->direction, menuitem->rect, rect);
1793 bool dis = !(menuitem->state & State_Enabled);
1794 bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
1795 ? menuitem->checked :
false;
1796 bool act = menuitem->state & State_Selected;
1798 const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2));
1799 if (act && dis ==
false) {
1800 drawRoundedRect(painter, rect, Qt::NoPen, highContrastTheme ? menuitem->palette.brush(QPalette::Highlight)
1801 : QBrush(winUI3Color(subtleHighlightColor)));
1803 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
1804 constexpr int yoff = 1;
1805 painter->setPen(highContrastTheme ? menuitem->palette.buttonText().color() : winUI3Color(dividerStrokeDefault));
1806 painter->drawLine(menuitem->rect.topLeft() + QPoint(0, yoff),
1807 menuitem->rect.topRight() + QPoint(0, yoff));
1811 int xOffset = contentHMargin;
1813 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
1815 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset, rect.y(),
1816 checkMarkWidth, rect.height())));
1817 QPainterStateGuard psg(painter);
1818 painter->setFont(d->assetFont);
1819 painter->setPen(option->palette.text().color());
1820 painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
1822 if (menuitem->menuHasCheckableItems)
1823 xOffset += checkMarkWidth + contentItemHMargin;
1824 if (!menuitem->icon.isNull()) {
1826 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset,
1828 menuitem->maxIconWidth - 4,
1830 QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
1832 mode = QIcon::Active;
1833 const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
1834 QRect pmr(QPoint(0, 0), QSize(size, size));
1835 pmr.moveCenter(vRect.center());
1836 menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode,
1837 checked ? QIcon::On : QIcon::Off);
1839 if (menuitem->maxIconWidth > 0)
1840 xOffset += menuitem->maxIconWidth - 4 + contentItemHMargin;
1842 QStringView s(menuitem->text);
1844 QPoint tl(rect.left() + xOffset, rect.top());
1845 QPoint br(rect.right() - menuitem->reservedShortcutWidth - contentHMargin,
1847 QRect textRect(tl, br);
1848 QRect vRect(visualMenuRect(textRect));
1851 if (highContrastTheme) {
1852 penColor = menuitem->palette.color(act ? QPalette::HighlightedText
1855 penColor = controlTextColor(option);
1857 painter->setPen(penColor);
1859 qsizetype t = s.indexOf(u'\t');
1860 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1861 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
1862 text_flags |= Qt::TextHideMnemonic;
1863 text_flags |= Qt::AlignLeft;
1865 if (t >= 0 && menuitem->menuItemType != QStyleOptionMenuItem::SubMenu) {
1866 QRect shortcutRect(QPoint(textRect.right(), textRect.top()),
1867 QPoint(rect.right(), textRect.bottom()));
1868 QRect vShortcutRect(visualMenuRect(shortcutRect));
1869 const QString textToDraw = s.mid(t + 1).toString();
1870 painter->drawText(vShortcutRect, text_flags, textToDraw);
1873 QFont font = menuitem->font;
1874 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1876 painter->setFont(font);
1877 const QString textToDraw = s.left(t).toString();
1878 painter->drawText(vRect, text_flags, textToDraw);
1880 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
1881 int fontSize = menuitem->font.pointSize();
1882 QFont f(d->assetFont);
1883 f.setPointSize(qRound(fontSize * 0.9f));
1884 painter->setFont(f);
1885 int yOfs = qRound(fontSize / 3.0f);
1886 QPoint tl(rect.right() - 2 * QWindowsStylePrivate::windowsArrowHMargin - contentItemHMargin,
1888 QRect submenuRect(tl, rect.bottomRight());
1889 QRect vSubMenuRect = visualMenuRect(submenuRect);
1890 painter->setPen(option->palette.text().color());
1891 const bool isReverse = option->direction == Qt::RightToLeft;
1892 const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
1893 painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
1898 case CE_MenuBarEmptyArea: {
1901 case CE_HeaderEmptyArea:
1903 case CE_HeaderSection: {
1904 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1905 painter->setPen(Qt::NoPen);
1906 painter->setBrush(header->palette.button());
1907 painter->drawRect(header->rect);
1908 const bool isRtl = option->direction == Qt::RightToLeft;
1909 const QPointF tr = isRtl ? option->rect.topLeft() : option->rect.topRight();
1910 const QPointF br = isRtl ? option->rect.bottomLeft() : option->rect.bottomRight();
1911 const QPointF bl = isRtl ? option->rect.bottomRight() : option->rect.bottomLeft();
1912 constexpr QPointF trOfs = QPointF(0.5, 0.0);
1913 constexpr QPointF brOfs = QPointF(0.5, 0.5);
1914 constexpr QPointF blOfs = QPointF(0.0, 0.5);
1915 const std::array<
QPointF, 3> points = { tr + trOfs, br + brOfs, bl + blOfs };
1916 QPen pen(highContrastTheme ? header->palette.buttonText().color()
1917 : winUI3Color(frameColorLight));
1918 pen.setJoinStyle(Qt::MiterJoin);
1919 painter->setPen(pen);
1920 painter->drawPolyline(points.data(),
int(points.size()));
1924 case CE_ItemViewItem: {
1925 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1926 const auto p = proxy();
1927 QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
1928 QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
1929 QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget);
1932 proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
1934 const QRect &rect = vopt->rect;
1935 const bool isRtl = option->direction == Qt::RightToLeft;
1936 bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1937 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1938 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1939 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1941 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1942 if (qobject_cast<
const QTableView *>(view)) {
1946 if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
1947 vopt->showDecorationSelected) {
1959 }
else if (isLast) {
1966 const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
1967 if (highlightCurrent) {
1968 if (highContrastTheme) {
1969 painter->setBrush(vopt->palette.highlight());
1971 painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
1972 ? calculateAccentColor(option)
1973 : winUI3Color(subtleHighlightColor));
1976 painter->setBrush(vopt->backgroundBrush);
1978 painter->setPen(Qt::NoPen);
1981 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
1982 secondLevelRoundingRadius, secondLevelRoundingRadius);
1983 }
else if (isFirst) {
1984 QPainterStateGuard psg(
painter);
1985 painter->setClipRect(rect);
1986 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1987 secondLevelRoundingRadius, secondLevelRoundingRadius);
1988 }
else if (isLast) {
1989 QPainterStateGuard psg(
painter);
1990 painter->setClipRect(rect);
1991 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1992 secondLevelRoundingRadius, secondLevelRoundingRadius);
1994 painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1998 if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
1999 QStyleOptionViewItem option(*vopt);
2000 option.rect = checkRect;
2001 option.state = option.state & ~QStyle::State_HasFocus;
2003 switch (vopt->checkState) {
2005 option.state |= QStyle::State_Off;
2007 case Qt::PartiallyChecked:
2008 option.state |= QStyle::State_NoChange;
2011 option.state |= QStyle::State_On;
2014 proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
2018 if (iconRect.isValid()) {
2019 QIcon::Mode mode = QIcon::Normal;
2020 if (!(vopt->state & QStyle::State_Enabled))
2021 mode = QIcon::Disabled;
2022 else if (vopt->state & QStyle::State_Selected)
2023 mode = QIcon::Selected;
2024 QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
2025 vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
2028 if (highlightCurrent && highContrastTheme) {
2029 painter->setPen(vopt->palette.base().color());
2030 }
else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
2031 painter->setPen(winUI3Color(textOnAccentPrimary));
2033 painter->setPen(vopt->palette.text().color());
2035 d->viewItemDrawText(painter, vopt, textRect);
2038 if (vopt->state & State_Selected && !highContrastTheme) {
2039 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2040 lv && lv->viewMode() != QListView::IconMode) {
2041 const auto col = vopt->palette.accent().color();
2042 painter->setBrush(col);
2043 painter->setPen(col);
2044 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
2045 const auto yOfs = rect.height() / 4.;
2046 QRectF r(
QPointF(xPos, rect.y() + yOfs),
2047 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
2048 painter->drawRoundedRect(r, 1, 1);
2055 QWindowsVistaStyle::drawControl(element, option, painter, widget);
2215QRect QWindows11Style::subControlRect(ComplexControl control,
const QStyleOptionComplex *option,
2216 SubControl subControl,
const QWidget *widget)
const
2221#if QT_CONFIG(spinbox)
2223 if (
const QStyleOptionSpinBox *spinbox = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2224 const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
2225 const int fw = spinbox->frame
2226 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
2228 const int buttonHeight = hasButtons
2229 ? qMin(spinbox->rect.height() - 3 * fw, spinbox->fontMetrics.height() * 5 / 4)
2231 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2232 const int textFieldLength = spinbox->rect.width() - 2 * fw - 2 * buttonSize.width();
2233 const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
2234 switch (subControl) {
2236 case SC_SpinBoxDown: {
2239 const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2240 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2241 buttonSize.height());
2242 if (subControl == SC_SpinBoxDown)
2243 ret.moveRight(ret.right() + buttonSize.width());
2246 case SC_SpinBoxEditField:
2247 ret = QRect(topLeft,
2248 spinbox->rect.bottomRight() - QPoint(fw + 2 * buttonSize.width(), fw));
2250 case SC_SpinBoxFrame:
2251 ret = spinbox->rect;
2255 ret = visualRect(spinbox->direction, spinbox->rect, ret);
2259 if (
const QStyleOptionTitleBar *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(option)) {
2260 SubControl sc = subControl;
2261 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2262 static constexpr int indent = 3;
2263 static constexpr int controlWidthMargin = 2;
2264 const int controlHeight = titlebar->rect.height();
2265 const int controlWidth = 46;
2266 const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
2267 int offset = -(controlWidthMargin + indent);
2269 bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
2270 bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
2273 case SC_TitleBarLabel:
2274 if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
2275 ret = titlebar->rect;
2276 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2277 ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
2278 if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
2279 ret.adjust(0, 0, -controlWidth, 0);
2280 if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
2281 ret.adjust(0, 0, -controlWidth, 0);
2282 if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
2283 ret.adjust(0, 0, -controlWidth, 0);
2284 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2285 ret.adjust(0, 0, -controlWidth, 0);
2288 case SC_TitleBarContextHelpButton:
2289 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2290 offset += controlWidth;
2292 case SC_TitleBarMinButton:
2293 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2294 offset += controlWidth;
2295 else if (sc == SC_TitleBarMinButton)
2298 case SC_TitleBarNormalButton:
2299 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2300 offset += controlWidth;
2301 else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2302 offset += controlWidth;
2303 else if (sc == SC_TitleBarNormalButton)
2306 case SC_TitleBarMaxButton:
2307 if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2308 offset += controlWidth;
2309 else if (sc == SC_TitleBarMaxButton)
2312 case SC_TitleBarShadeButton:
2313 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2314 offset += controlWidth;
2315 else if (sc == SC_TitleBarShadeButton)
2318 case SC_TitleBarUnshadeButton:
2319 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2320 offset += controlWidth;
2321 else if (sc == SC_TitleBarUnshadeButton)
2324 case SC_TitleBarCloseButton:
2325 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2326 offset += controlWidth;
2327 else if (sc == SC_TitleBarCloseButton)
2329 ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
2330 controlWidth, controlHeight);
2332 case SC_TitleBarSysMenu:
2333 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
2334 const auto yOfs = titlebar->rect.top() + (titlebar->rect.height() - iconSize) / 2;
2335 ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, yOfs, iconSize,
2342 if (widget && isMinimized && titlebar->rect.width() < offset)
2343 const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
2344 ret = visualRect(titlebar->direction, titlebar->rect, ret);
2350 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2352 if (subControl == SC_ScrollBarAddLine || subControl == SC_ScrollBarSubLine) {
2353 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
2354 if (scrollbar->orientation == Qt::Vertical)
2355 ret = ret.adjusted(2,2,-2,-3);
2357 ret = ret.adjusted(3,2,-2,-2);
2363 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2364 const auto indicatorWidth =
2365 proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2366 switch (subControl) {
2367 case SC_ComboBoxArrow: {
2369 cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
2370 const int buttonHeight =
2371 qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
2372 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2373 const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
2374 const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
2375 const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2376 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2377 buttonSize.height());
2378 ret = visualRect(option->direction, option->rect, ret);
2381 case SC_ComboBoxEditField: {
2384 const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
2385 ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
2387 ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
2388 ret = visualRect(option->direction, option->rect, ret);
2392 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2398#if QT_CONFIG(groupbox)
2400 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2401 switch (subControl) {
2402 case SC_GroupBoxCheckBox:
2412 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2420QSize QWindows11Style::sizeFromContents(ContentsType type,
const QStyleOption *option,
2421 const QSize &size,
const QWidget *widget)
const
2423 QSize contentSize(size);
2427#if QT_CONFIG(menubar)
2428 case CT_MenuBarItem:
2429 if (!contentSize.isEmpty()) {
2430 constexpr int hMargin = 2 * 6;
2431 constexpr int hPadding = 2 * 11;
2432 constexpr int itemHeight = 32;
2433 contentSize.setWidth(contentSize.width() + hMargin + hPadding);
2434#if QT_CONFIG(tabwidget)
2435 if (widget->parent() && !qobject_cast<
const QTabWidget *>(widget->parent()))
2437 contentSize.setHeight(itemHeight);
2443 if (
const auto *menuItem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
2444 int width = size.width();
2446 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
2450 height = menuItem->fontMetrics.height() + 8;
2451 if (!menuItem->icon.isNull()) {
2452 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
2453 height = qMax(height,
2454 menuItem->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
2457 if (menuItem->text.contains(u'\t'))
2458 width += contentItemHMargin;
2459 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
2460 width += 2 * QWindowsStylePrivate::windowsArrowHMargin + contentItemHMargin;
2461 if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
2462 const QFontMetrics fm(menuItem->font);
2463 QFont fontBold = menuItem->font;
2464 fontBold.setBold(
true);
2465 const QFontMetrics fmBold(fontBold);
2466 width += fmBold.horizontalAdvance(menuItem->text) - fm.horizontalAdvance(menuItem->text);
2469 if (menuItem->menuHasCheckableItems) {
2470 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
2471 width += checkMarkWidth + contentItemHMargin * 2;
2475 if (menuItem->maxIconWidth > 0)
2476 width += contentItemHMargin * 2 + menuItem->maxIconWidth - 4;
2478 width += 2 * contentHMargin;
2481 contentSize = QSize(width, height);
2485#if QT_CONFIG(spinbox)
2487 if (
const auto *spinBoxOpt = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2489 const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
2490 const int margins = 8;
2491 const int buttonWidth = hasButtons ? 16 + contentItemHMargin : 0;
2492 const int frameWidth = spinBoxOpt->frame
2493 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
2496 contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
2501#if QT_CONFIG(combobox)
2503 if (
const auto *comboBoxOpt = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2504 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2505 contentSize += QSize(0, 4);
2506 if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
2507 const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2508 contentSize.rwidth() += w + contentItemHMargin;
2514 if (qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
2515 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2516 contentSize += QSize(0, 4);
2520 case CT_HeaderSection:
2523 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2525 case CT_RadioButton:
2527 if (
const auto *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
2528 const auto p = proxy();
2529 const bool isRadio = (type == CT_RadioButton);
2531 const int width = p->pixelMetric(
2532 isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, option, widget);
2533 const int height = p->pixelMetric(
2534 isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, option, widget);
2537 if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
2538 margins += p->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
2539 : PM_CheckBoxLabelSpacing,
2543 contentSize += QSize(width + margins, 4);
2544 contentSize.setHeight(qMax(size.height(), height + 2 * contentItemHMargin));
2550 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2551 if (size.width() == 0)
2552 contentSize.rwidth() += 2;
2554 case CT_PushButton: {
2555 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2557 const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
2558 contentSize.rwidth() += 2 * contentHMargin - oldMargin;
2561 case CT_ToolButton: {
2562 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2564 const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
2565 contentSize.rwidth() += 2 * contentHMargin - oldMargin;
2566 if (
const auto toolbutton = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
2567 if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu))
2568 contentSize.rwidth() += size.height();
2572 case CT_ItemViewItem: {
2573 if (
const auto *viewItemOpt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
2574 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2575 lv && lv->viewMode() != QListView::IconMode) {
2576 QStyleOptionViewItem vOpt(*viewItemOpt);
2580 vOpt.rect.setRight(vOpt.rect.right() - contentHMargin);
2581 contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget);
2582 contentSize.rwidth() += contentHMargin;
2583 contentSize.rheight() += 2 * contentHMargin;
2586 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2592 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);