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));
826 if (toolbutton->subControls.testFlag(SC_ToolButtonMenu)) {
827 QPainterStateGuard psg(painter);
828 painter->setClipRect(menuareaRect);
830 prx->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
832 const int fontSize = painter->font().pointSize();
833 QFont f(d->assetFont);
834 f.setPointSize(qRound(fontSize * 0.9f));
836 painter->setPen(controlTextColor(option));
837 const QRect textRect(menuareaRect.topLeft(), menuareaRect.size() - QSize(fw, 0));
838 painter->drawText(textRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
840 }
else if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) {
841 const int mbi = qRound(prx->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget) * 0.3);
842 const QRect &ir = toolbutton->rect;
843 QRect rect(ir.right() - mbi - 2 * fw, ir.bottom() - mbi - fw, mbi,
845 rect = visualRect(toolbutton->direction, buttonRect, rect);
846 const QRect lblRect = label.rect - QMargins(0, 0, rect.width(), 0);
847 label.rect = visualRect(toolbutton->direction, buttonRect, lblRect);
848 painter->setFont(QFont(d->assetFont));
849 painter->setPen(controlTextColor(option));
850 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
852 prx->drawControl(CE_ToolButtonLabel, &label, painter, widget);
857 QWindowsVistaStyle::drawComplexControl(control, option, painter, widget);
861void QWindows11Style::drawPrimitive(PrimitiveElement element,
const QStyleOption *option,
863 const QWidget *widget)
const {
866 const State state = option->state;
867 QPainterStateGuard psg(
painter);
868 painter->setRenderHint(QPainter::Antialiasing);
869 if (d->transitionsEnabled() && option->styleObject && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) {
870 QObject *styleObject = option->styleObject;
871 int oldState = styleObject->property(
"_q_stylestate").toInt();
872 styleObject->setProperty(
"_q_stylestate",
int(option->state));
873 styleObject->setProperty(
"_q_stylerect", option->rect);
874 bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
875 || ((state & State_MouseOver) != (oldState & State_MouseOver))
876 || (state & State_On) != (oldState & State_On))
877 && state & State_Enabled);
879 if (element == PE_IndicatorRadioButton) {
880 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
881 t->setStartValue(styleObject->property(
"_q_inner_radius").toFloat());
882 t->setEndValue(radioButtonInnerRadius(state));
883 styleObject->setProperty(
"_q_end_radius", t->endValue());
884 t->setStartTime(d->animationTime());
886 d->startAnimation(t);
888 else if (element == PE_IndicatorCheckBox) {
889 if ((oldState & State_Off && state & State_On) || (oldState & State_NoChange && state & State_On)) {
890 QNumberStyleAnimation *t =
new QNumberStyleAnimation(styleObject);
891 t->setStartValue(0.0f);
892 t->setEndValue(1.0f);
893 t->setStartTime(d->animationTime());
895 d->startAnimation(t);
902 case PE_IndicatorArrowUp:
903 case PE_IndicatorArrowDown:
904 case PE_IndicatorArrowRight:
905 case PE_IndicatorArrowLeft: {
906 const QRect &r = option->rect;
907 if (r.width() <= 1 || r.height() <= 1)
909 Icon ico = Icon::Help;
911 case PE_IndicatorArrowUp:
912 ico = Icon::ChevronUpMed;
914 case PE_IndicatorArrowDown:
915 ico = Icon::ChevronDownMed;
917 case PE_IndicatorArrowLeft:
918 ico = Icon::ChevronLeftMed;
920 case PE_IndicatorArrowRight:
921 ico = Icon::ChevronRightMed;
926 QPainterStateGuard psg(
painter);
927 if (option->state.testFlag(State_Sunken)) {
928 const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget);
929 const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget);
930 if (bsx != 0 || bsy != 0)
931 painter->translate(bsx, bsy);
933 painter->setFont(d->assetFont);
934 painter->setPen(option->palette.buttonText().color());
935 painter->setBrush(option->palette.buttonText());
936 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
939 case PE_FrameFocusRect: {
940 if (
const QStyleOptionFocusRect *fropt = qstyleoption_cast<
const QStyleOptionFocusRect *>(option)) {
941 if (!(fropt->state & State_KeyboardFocusChange))
943 QRectF focusRect = option->rect;
944 focusRect = focusRect.marginsRemoved(QMarginsF(1.5,1.5,1.5,1.5));
945 painter->setPen(winUI3Color(focusFrameInnerStroke));
946 painter->drawRoundedRect(focusRect,4,4);
948 focusRect = focusRect.marginsAdded(QMarginsF(1.0,1.0,1.0,1.0));
949 painter->setPen(QPen(winUI3Color(focusFrameOuterStroke),1));
950 painter->drawRoundedRect(focusRect,4,4);
954 case PE_PanelTipLabel: {
955 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(0.5, 0.5, 0.5, 0.5));
956 const auto pen = highContrastTheme ? option->palette.buttonText().color()
957 : winUI3Color(frameColorLight);
958 drawRoundedRect(painter, rect, pen, option->palette.toolTipBase());
961 case PE_FrameTabWidget:
962#if QT_CONFIG(tabwidget)
963 if (
const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(option)) {
964 QPainterStateGuard psg(painter);
965 const auto clipRegion = painter->clipRegion();
967 painter->setPen(highContrastTheme ? frame->palette.buttonText().color()
968 : winUI3Color(frameColorLight));
969 painter->setBrush(frame->palette.base());
971 const auto &rect = option->rect;
972 QRect upperRect = rect;
973 upperRect.setHeight(rect.height() / 2);
974 QRect lowerRect = rect;
975 lowerRect.setY(lowerRect.y() + rect.height() / 2);
976 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
977 painter->drawRect(rect);
978 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
979 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
984 case PE_FrameGroupBox:
985 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
986 const auto pen = highContrastTheme ? frame->palette.buttonText().color()
987 : winUI3Color(frameColorStrong);
988 if (frame->features & QStyleOptionFrame::Flat) {
989 painter->setBrush(Qt::NoBrush);
990 painter->setPen(pen);
991 const QRect &fr = frame->rect;
992 QPoint p1(fr.x(), fr.y() + 1);
993 QPoint p2(fr.x() + fr.width(), p1.y());
994 painter->drawLine(p1, p2);
996 const auto frameRect = QRectF(frame->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
997 drawRoundedRect(painter, frameRect, pen, Qt::NoBrush);
1001 case PE_IndicatorHeaderArrow:
1002 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1003 const auto indicator = header->sortIndicator;
1004 if (indicator != QStyleOptionHeader::None) {
1005 QPainterStateGuard psg(
painter);
1006 QFont f(d->assetFont);
1008 painter->setFont(f);
1009 painter->setPen(header->palette.text().color());
1010 const auto ico = indicator == QStyleOptionHeader::SortUp ? Icon::ChevronDown
1012 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1016 case PE_IndicatorCheckBox: {
1017 const bool isOn = option->state & State_On;
1018 const bool isPartial = option->state & State_NoChange;
1020 const QRectF rect = option->rect;
1021 const QPointF center = rect.center();
1023 drawRoundedRect(painter, option->rect, borderPenControlAlt(option),
1024 controlFillBrush(option, ControlType::ControlAlt));
1027 painter->setFont(d->assetFont);
1028 painter->setPen(controlTextColor(option));
1029 const auto *animation =
1030 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1031 const qreal clipWidth = animation ? animation->currentValue() : 1.0;
1032 const QString str = fluentIcon(Icon::AcceptMedium);
1033 QFontMetrics fm(d->assetFont);
1034 QRectF clipRect = fm.boundingRect(str);
1035 clipRect.moveCenter(center);
1036 clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0 + 0.5);
1037 clipRect.setWidth(clipWidth * clipRect.width());
1038 painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, str);
1039 }
else if (isPartial) {
1040 QFont f(d->assetFont);
1042 painter->setFont(f);
1043 painter->setPen(controlTextColor(option));
1044 painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::Dash12));
1048 case PE_IndicatorBranch: {
1049 if (option->state & State_Children) {
1050 const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option);
1051 const bool isReverse = option->direction == Qt::RightToLeft;
1052 const bool isOpen = option->state & QStyle::State_Open;
1053 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1054 QFont f(d->assetFont);
1056 painter->setFont(f);
1057 if (view && view->alternatingRowColors() && vopt && vopt->state & State_Selected)
1058 painter->setPen(winUI3Color(textOnAccentPrimary));
1060 painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
1061 QPalette::WindowText));
1062 const auto ico = isOpen ? Icon::ChevronDownMed
1063 : (isReverse ? Icon::ChevronLeftMed
1064 : Icon::ChevronRightMed);
1065 painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
1069 case PE_IndicatorRadioButton: {
1070 const auto *animation =
1071 qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
1072 const qreal innerRadius =
1073 animation ? animation->currentValue() : radioButtonInnerRadius(state);
1074 const QRectF rect = option->rect;
1075 const QPointF center = rect.center();
1077 if (option->styleObject)
1078 option->styleObject->setProperty(
"_q_inner_radius", innerRadius);
1079 painter->setPen(borderPenControlAlt(option));
1080 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1081 if (option->state.testFlag(State_On)) {
1083 path.addEllipse(center, 7.5, 7.5);
1084 path.addEllipse(center, innerRadius, innerRadius);
1085 painter->drawPath(path);
1087 painter->setBrush(option->palette.window().color());
1088 painter->drawEllipse(center, innerRadius, innerRadius);
1090 painter->drawEllipse(center, 7.5, 7.5);
1094 case PE_PanelButtonTool:
1095 case PE_PanelButtonBevel:{
1096 const bool isEnabled = state & QStyle::State_Enabled;
1097 const bool isMouseOver = state & QStyle::State_MouseOver;
1098 const bool isRaised = state & QStyle::State_Raised;
1099 const int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
1100 const QRectF rect = option->rect.marginsRemoved(QMargins(fw, fw, fw, fw));
1101 if (element == PE_PanelButtonTool && ((!isMouseOver && !isRaised) || !isEnabled))
1102 painter->setPen(Qt::NoPen);
1104 painter->setPen(winUI3Color(controlStrokePrimary));
1105 painter->setBrush(controlFillBrush(option, ControlType::Control));
1106 if (element == PE_PanelButtonTool && widget) {
1107 const auto name = widget->objectName();
1108 if (name ==
"ScrollLeftButton"_L1 || name ==
"ScrollRightButton"_L1) {
1109 painter->setPen(Qt::NoPen);
1111 painter->setBrush(controlFillBrush(option, ControlType::ControlAlt));
1113 painter->setBrush(Qt::NoBrush);
1116 painter->drawRoundedRect(rect,
1117 secondLevelRoundingRadius, secondLevelRoundingRadius);
1120 case PE_FrameDefaultButton:
1121 painter->setPen(option->palette.accent().color());
1122 painter->setBrush(Qt::NoBrush);
1123 painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1127 case PE_PanelMenu: {
1128 if (!d->nativeRoundedTopLevelWindows) {
1129 const QRect rect = option->rect.marginsRemoved(QMargins(2, 2, 2, 2));
1130 painter->setPen(highContrastTheme ? QPen(option->palette.windowText().color(), 2)
1131 : winUI3Color(frameColorLight));
1132 painter->setBrush(winUI3Color(menuPanelFill));
1133 painter->drawRoundedRect(rect, topLevelRoundingRadius, topLevelRoundingRadius);
1137 case PE_PanelLineEdit:
1138 if (
const auto *panel = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1139 const bool isInSpinBox =
1140 widget && qobject_cast<
const QAbstractSpinBox *>(widget->parent()) !=
nullptr;
1141 const bool isInComboBox =
1142 widget && qobject_cast<
const QComboBox *>(widget->parent()) !=
nullptr;
1143 if (!isInSpinBox && !isInComboBox) {
1144 const auto frameRect =
1145 QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1146 drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
1147 if (panel->lineWidth > 0)
1148 proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
1152 case PE_FrameLineEdit: {
1153 const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1154 drawLineEditFrame(painter, frameRect, option);
1155 if (state & State_KeyboardFocusChange && state & State_HasFocus) {
1156 QStyleOptionFocusRect fropt;
1157 fropt.QStyleOption::operator=(*option);
1158 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
1163 if (
const auto *frame = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1164 const auto rect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
1165 if (qobject_cast<
const QComboBoxPrivateContainer *>(widget)) {
1166 if (d->nativeRoundedTopLevelWindows)
1169 if (highContrastTheme)
1170 pen = QPen(option->palette.windowText().color(), 2);
1173 drawRoundedRect(painter, rect, pen, WINUI3Colors[colorSchemeIndex][menuPanelFill]);
1175 drawRoundedRect(painter, rect, Qt::NoPen, option->palette.brush(QPalette::Base));
1177 if (frame->frameShape == QFrame::NoFrame)
1180 const bool isEditable = qobject_cast<
const QTextEdit *>(widget) !=
nullptr
1181 || qobject_cast<
const QPlainTextEdit *>(widget) !=
nullptr;
1182 drawLineEditFrame(painter, rect, option, isEditable);
1186 case PE_PanelItemViewItem:
1187 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1188 if (vopt->backgroundBrush.style() != Qt::NoBrush) {
1189 QPainterStateGuard psg(
painter);
1190 painter->setBrushOrigin(vopt->rect.topLeft());
1191 painter->fillRect(vopt->rect, vopt->backgroundBrush);
1195 case PE_PanelItemViewRow:
1196 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1200 const QRect &rect = vopt->rect;
1201 const bool isRtl = option->direction == Qt::RightToLeft;
1202 if (rect.width() <= 0)
1205 if (vopt->features & QStyleOptionViewItem::Alternate) {
1206 QPalette::ColorGroup cg =
1207 (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled))
1209 : QPalette::Disabled;
1210 if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
1211 cg = QPalette::Inactive;
1212 painter->fillRect(rect, option->palette.brush(cg, QPalette::AlternateBase));
1215 if (option->state & State_Selected && !highContrastTheme) {
1217 if (!qobject_cast<
const QTableView *>(widget)) {
1218 const auto col = option->palette.accent().color();
1219 painter->setBrush(col);
1220 painter->setPen(col);
1221 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
1222 const auto yOfs = rect.height() / 4.;
1223 QRectF r(
QPointF(xPos, rect.y() + yOfs),
1224 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
1225 painter->drawRoundedRect(r, 1, 1);
1229 const bool isTreeDecoration = vopt->features.testFlag(
1230 QStyleOptionViewItem::IsDecorationForRootColumn);
1231 if (isTreeDecoration && vopt->state.testAnyFlags(State_Selected | State_MouseOver) &&
1232 vopt->showDecorationSelected) {
1233 const bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1234 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1235 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1236 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1246 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1247 painter->setBrush(view->alternatingRowColors() && state & State_Selected ? calculateAccentColor(option) : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
1248 painter->setPen(Qt::NoPen);
1250 QPainterStateGuard psg(
painter);
1251 painter->setClipRect(rect);
1252 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1253 secondLevelRoundingRadius, secondLevelRoundingRadius);
1254 }
else if (isLast) {
1255 QPainterStateGuard psg(
painter);
1256 painter->setClipRect(rect);
1257 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1258 secondLevelRoundingRadius, secondLevelRoundingRadius);
1260 painter->drawRect(vopt->rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1265 case QStyle::PE_Widget: {
1266 if (widget && widget->palette().isBrushSet(QPalette::Active, widget->backgroundRole())) {
1267 const QBrush bg = widget->palette().brush(widget->backgroundRole());
1268 auto wp = QWidgetPrivate::get(widget);
1269 QPainterStateGuard psg(
painter);
1270 wp->updateBrushOrigin(painter, bg);
1271 painter->fillRect(option->rect, bg);
1275 case QStyle::PE_FrameWindow:
1276 if (
const auto *frm = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1278 QRectF rect= option->rect;
1279 int fwidth =
int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
1281 QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
1282 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1283 secondLevelRoundingRadius,
1284 secondLevelRoundingRadius);
1285 QRectF bottomRightCorner = QRectF(rect.right() - 1.0 - secondLevelRoundingRadius,
1286 rect.bottom() - 1.0 - secondLevelRoundingRadius,
1287 secondLevelRoundingRadius,
1288 secondLevelRoundingRadius);
1291 if (widget !=
nullptr) {
1292 QBitmap mask(widget->width(), widget->height());
1296 maskPainter.setRenderHint(QPainter::Antialiasing);
1297 maskPainter.setBrush(Qt::color1);
1298 maskPainter.setPen(Qt::NoPen);
1299 maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
1300 const_cast<QWidget*>(widget)->setMask(mask);
1304 painter->setPen(QPen(frm->palette.base(), fwidth));
1305 painter->drawLine(QPointF(rect.left(), rect.top()),
1306 QPointF(rect.left(), rect.bottom() - fwidth));
1307 painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
1308 QPointF(rect.right() - fwidth, rect.bottom()));
1309 painter->drawLine(QPointF(rect.right(), rect.top()),
1310 QPointF(rect.right(), rect.bottom() - fwidth));
1312 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1313 painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
1314 QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1315 painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
1316 QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
1317 painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
1318 QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
1320 painter->setPen(Qt::NoPen);
1321 painter->setBrush(frm->palette.base());
1322 painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
1324 painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
1327 painter->setPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]);
1328 painter->setBrush(Qt::NoBrush);
1329 painter->drawArc(bottomRightCorner,
1331 painter->drawArc(bottomLeftCorner,
1335#if QT_CONFIG(tabbar)
1336 case PE_FrameTabBarBase:
1337 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTabBarBase *>(option)) {
1338 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1339 const auto clipRegion = painter->clipRegion();
1341 painter->setPen(highContrastTheme ? tab->palette.buttonText().color()
1342 : winUI3Color(frameColorLight));
1343 painter->setBrush(tab->palette.base());
1344 QRect upperRect = tab->rect;
1345 upperRect.setHeight(tab->rect.height() / 2);
1346 QRect lowerRect = tab->rect;
1347 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2);
1348 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1349 painter->drawRoundedRect(tab->rect, secondLevelRoundingRadius,
1350 secondLevelRoundingRadius);
1351 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1352 painter->drawRect(tab->rect);
1356 case PE_IndicatorTabTearLeft:
1357 case PE_IndicatorTabTearRight:
1360 QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
1367void QWindows11Style::drawControl(ControlElement element,
const QStyleOption *option,
1368 QPainter *painter,
const QWidget *widget)
const
1370 Q_D(
const QWindows11Style);
1371 State flags = option->state;
1373 QPainterStateGuard psg(
painter);
1374 painter->setRenderHint(QPainter::Antialiasing);
1376 case QStyle::CE_ComboBoxLabel:
1377#if QT_CONFIG(combobox)
1378 if (
const QStyleOptionComboBox *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
1379 painter->setPen(controlTextColor(option,
true));
1380 QStyleOptionComboBox newOption = *cb;
1381 newOption.rect.adjust(4,0,-4,0);
1382 QCommonStyle::drawControl(element, &newOption, painter, widget);
1386#if QT_CONFIG(tabbar)
1387 case CE_TabBarTabShape:
1388 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1389 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1390 const bool isSelected = tab->state.testFlag(State_Selected);
1391 const auto clipRegion = painter->clipRegion();
1392 const bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab
1393 || tab->position == QStyleOptionTab::Moving;
1394 auto leftMargin = (tab->position == QStyleOptionTab::Beginning || onlyOne) ? 1 : 0;
1395 auto rightMargin = (tab->position == QStyleOptionTab::End || onlyOne) ? 1 : 0;
1396 if (QCommonStylePrivate::rtl(option))
1397 std::swap(leftMargin, rightMargin);
1399 QRectF tabRect = tab->rect.marginsRemoved(QMargins(leftMargin, 1, rightMargin, -3));
1400 painter->setPen(highContrastTheme ? tab->palette.buttonText().color() : winUI3Color(frameColorLight));
1401 painter->setBrush(tab->palette.base());
1403 painter->setBrush(winUI3Color(fillMicaAltDefault));
1405 if (tab->state.testFlag(State_Sunken))
1406 painter->setBrush(winUI3Color(fillMicaAltDefault));
1407 else if (tab->state.testFlag(State_MouseOver))
1408 painter->setBrush(winUI3Color(fillMicaAltSecondary));
1410 painter->setBrush(winUI3Color(fillMicaAltTransparent));
1412 QRect upperRect = tab->rect;
1413 upperRect.setHeight(tab->rect.height() / 2.);
1414 QRect lowerRect = tab->rect;
1415 lowerRect.setY(lowerRect.y() + tab->rect.height() / 2.);
1416 painter->setClipRegion(clipRegion.isNull() ? upperRect : clipRegion & upperRect);
1417 painter->drawRoundedRect(tabRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1418 painter->setClipRegion(clipRegion.isNull() ? lowerRect : clipRegion & lowerRect);
1419 painter->drawRect(tabRect);
1422 case CE_TabBarTabLabel:
1423 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(option)) {
1424 const bool isEnabled = tab->state.testFlags(State_Enabled);
1425 const bool isSelected = tab->state.testFlags(State_Selected);
1427 QRect tr = tab->rect;
1428 bool verticalTabs = tab->shape == QTabBar::RoundedEast
1429 || tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularEast
1430 || tab->shape == QTabBar::TriangularWest;
1432 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1433 if (!proxy()->styleHint(SH_UnderlineShortcut, option, widget))
1434 alignment |= Qt::TextHideMnemonic;
1436 QPainterStateGuard psg(painter, QPainterStateGuard::InitialState::NoSave);
1439 int newX, newY, newRot;
1440 if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
1441 newX = tr.width() + tr.x();
1446 newY = tr.y() + tr.height();
1449 QTransform m = QTransform::fromTranslate(newX, newY);
1451 painter->setTransform(m,
true);
1454 d->tabLayout(tab, widget, &tr, &iconRect);
1457 if (tab->position != QStyleOptionTab::TabPosition::Moving)
1458 tr = proxy()->subElementRect(SE_TabBarTabText, option, widget);
1460 if (!tab->icon.isNull()) {
1461 const auto mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
1462 const auto state = isSelected ? QIcon::On : QIcon::Off;
1463 tab->icon.paint(painter, iconRect, Qt::AlignCenter, mode, state);
1466 painter->setPen(winUI3Color(isSelected ? textPrimary : textSecondary));
1467 proxy()->drawItemText(painter, tr, alignment, tab->palette, isEnabled, tab->text);
1471 case CE_ToolButtonLabel:
1472#if QT_CONFIG(toolbutton)
1473 if (
const QStyleOptionToolButton *toolbutton
1474 = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
1475 QRect rect = toolbutton->rect;
1478 if (toolbutton->state & (State_Sunken | State_On)) {
1479 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
1480 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
1483 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
1484 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
1485 || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
1486 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
1487 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1488 alignment |= Qt::TextHideMnemonic;
1489 rect.translate(shiftX, shiftY);
1490 painter->setFont(toolbutton->font);
1491 const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
1492 painter->setPen(controlTextColor(option));
1493 proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
1494 toolbutton->state & State_Enabled, text);
1497 QSize pmSize = toolbutton->iconSize;
1498 if (!toolbutton->icon.isNull()) {
1499 QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
1501 if (!(toolbutton->state & State_Enabled))
1502 mode = QIcon::Disabled;
1503 else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
1504 mode = QIcon::Active;
1506 mode = QIcon::Normal;
1507 pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
1509 pmSize = pm.size() / pm.devicePixelRatio();
1512 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
1513 painter->setFont(toolbutton->font);
1516 int alignment = Qt::TextShowMnemonic | Qt::AlignCenter;
1517 if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
1518 alignment |= Qt::TextHideMnemonic;
1520 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
1521 pr.setHeight(pmSize.height() + 4);
1522 tr.adjust(0, pr.height() - 1, 0, -1);
1524 pr.setWidth(pmSize.width() + 4);
1525 tr.adjust(pr.width(), 0, 0, 0);
1527 pr.translate(shiftX, shiftY);
1529 drawArrow(proxy(), toolbutton, pr, painter, widget);
1531 const auto vr = QStyle::visualRect(toolbutton->direction, rect, pr);
1532 proxy()->drawItemPixmap(painter, vr, Qt::AlignCenter, pm);
1534 tr.translate(shiftX, shiftY);
1535 painter->setPen(controlTextColor(option));
1536 const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
1537 const auto vr = QStyle::visualRect(toolbutton->direction, rect, tr);
1538 proxy()->drawItemText(painter, vr, alignment, toolbutton->palette,
1539 toolbutton->state & State_Enabled, text);
1541 rect.translate(shiftX, shiftY);
1543 drawArrow(proxy(), toolbutton, rect, painter, widget);
1545 proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
1552 case QStyle::CE_ShapedFrame:
1553 if (
const QStyleOptionFrame *f = qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
1554 int frameShape = f->frameShape;
1555 int frameShadow = QFrame::Plain;
1556 if (f->state & QStyle::State_Sunken)
1557 frameShadow = QFrame::Sunken;
1558 else if (f->state & QStyle::State_Raised)
1559 frameShadow = QFrame::Raised;
1561 int lw = f->lineWidth;
1562 int mlw = f->midLineWidth;
1564 switch (frameShape) {
1566 if (frameShadow == QFrame::Plain)
1567 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1569 qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
1572 if (frameShadow == QFrame::Plain)
1573 qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme ==
true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
1575 qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
1578 QWindowsVistaStyle::drawControl(element, option, painter, widget);
1582#if QT_CONFIG(progressbar)
1583 case CE_ProgressBarGroove:
1584 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar*>(option)) {
1585 QRect rect = option->rect;
1586 QPointF center = rect.center();
1587 if (baropt->state & QStyle::State_Horizontal) {
1589 rect.moveTop(center.y());
1592 rect.moveLeft(center.x());
1594 painter->setPen(Qt::NoPen);
1595 painter->setBrush(Qt::gray);
1596 painter->drawRect(rect);
1599 case CE_ProgressBarContents:
1600 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1601 QPainterStateGuard psg(painter);
1602 QRectF rect = option->rect;
1603 painter->translate(rect.topLeft());
1604 rect.translate(-rect.topLeft());
1606 constexpr qreal progressBarThickness = 3;
1607 constexpr qreal progressBarHalfThickness = progressBarThickness / 2.0;
1609 const auto isIndeterminate = baropt->maximum == 0 && baropt->minimum == 0;
1610 const auto orientation =
1611 (baropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
1612 const auto inverted = baropt->invertedAppearance;
1613 const auto reverse = (baropt->direction == Qt::RightToLeft) ^ inverted;
1617 if (orientation == Qt::Vertical) {
1618 rect = QRectF(rect.left(), rect.top(), rect.height(),
1623 m.translate(0, -rect.height() + 1);
1626 m.translate(-rect.width(), 0);
1628 painter->setTransform(m,
true);
1629 }
else if (reverse) {
1630 QTransform m = QTransform::fromScale(-1, 1);
1631 m.translate(-rect.width(), 0);
1632 painter->setTransform(m,
true);
1634 const qreal offset = (
int(rect.height()) % 2 == 0) ? 0.5f : 0.0f;
1636 if (isIndeterminate) {
1637#if QT_CONFIG(animation)
1638 auto anim = d->animation(option->styleObject);
1640 auto anim =
new QStyleAnimation(option->styleObject);
1641 anim->setFrameRate(QStyleAnimation::SixtyFps);
1642 d->startAnimation(anim);
1644 constexpr auto loopDurationMSec = 4000;
1645 const auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(
1646 std::chrono::system_clock::now());
1647 const auto elapsed = elapsedTime.time_since_epoch().count();
1648 const auto handleCenter = (elapsed % loopDurationMSec) /
float(loopDurationMSec);
1649 const auto isLongHandle = (elapsed / loopDurationMSec) % 2 == 0;
1650 const auto lengthFactor = (isLongHandle ? 33.0f : 25.0f) / 100.0f;
1652 constexpr auto handleCenter = 0.5f;
1653 constexpr auto lengthFactor = 1;
1655 const auto begin = qMax(handleCenter * (1 + lengthFactor) - lengthFactor, 0.0f);
1656 const auto end = qMin(handleCenter * (1 + lengthFactor), 1.0f);
1657 const auto barBegin = begin * rect.width();
1658 const auto barEnd = end * rect.width();
1659 rect = QRectF(QPointF(rect.left() + barBegin, rect.top()),
1660 QPointF(rect.left() + barEnd, rect.bottom()));
1662#if QT_CONFIG(animation)
1663 d->stopAnimation(option->styleObject);
1665 const auto fillPercentage = (
float(baropt->progress - baropt->minimum))
1666 / (
float(baropt->maximum - baropt->minimum));
1667 rect.setWidth(rect.width() * fillPercentage);
1669 const QPointF center = rect.center();
1670 rect.setHeight(progressBarThickness);
1671 rect.moveTop(center.y() - progressBarHalfThickness - offset);
1672 drawRoundedRect(painter, rect, Qt::NoPen, baropt->palette.accent());
1675 case CE_ProgressBarLabel:
1676 if (
const auto baropt = qstyleoption_cast<
const QStyleOptionProgressBar *>(option)) {
1677 const bool vertical = !(baropt->state & QStyle::State_Horizontal);
1679 proxy()->drawItemText(painter, baropt->rect, Qt::AlignCenter | Qt::TextSingleLine,
1680 baropt->palette, baropt->state & State_Enabled, baropt->text,
1686 case CE_PushButtonLabel:
1687 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1688 QStyleOptionButton btnCopy(*btn);
1689 btnCopy.rect = btn->rect.marginsRemoved(QMargins(contentHMargin, 0, contentHMargin, 0));
1690 btnCopy.palette.setBrush(QPalette::ButtonText, controlTextColor(option));
1691 QCommonStyle::drawControl(element, &btnCopy, painter, widget);
1694 case CE_PushButtonBevel:
1695 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
1696 using namespace StyleOptionHelper;
1698 QRectF rect = btn->rect.marginsRemoved(QMargins(2, 2, 2, 2));
1699 painter->setPen(Qt::NoPen);
1700 if (btn->features.testFlag(QStyleOptionButton::Flat)) {
1701 painter->setBrush(btn->palette.button());
1702 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1703 if (flags & (State_Sunken | State_On)) {
1704 painter->setBrush(WINUI3Colors[colorSchemeIndex][subtlePressedColor]);
1706 else if (flags & State_MouseOver) {
1707 painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
1709 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1711 painter->setBrush(controlFillBrush(option, ControlType::Control));
1712 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1714 rect.adjust(0.5,0.5,-0.5,-0.5);
1715 const bool defaultButton = btn->features.testFlag(QStyleOptionButton::DefaultButton);
1716 painter->setBrush(Qt::NoBrush);
1717 painter->setPen(defaultButton ? option->palette.accent().color()
1718 : WINUI3Colors[colorSchemeIndex][controlStrokePrimary]);
1719 painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
1721 painter->setPen(defaultButton ? WINUI3Colors[colorSchemeIndex][controlStrokeOnAccentSecondary]
1722 : WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]);
1724 if (btn->features.testFlag(QStyleOptionButton::HasMenu)) {
1725 QPainterStateGuard psg(
painter);
1728 const auto indSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
1729 const auto indRect =
1732 const auto vindRect = visualRect(btn->direction, btn->rect, indRect);
1733 textRect.setWidth(textRect.width() - indSize);
1735 int fontSize = painter->font().pointSize();
1736 QFont f(d->assetFont);
1737 f.setPointSize(qRound(fontSize * 0.9f));
1738 painter->setFont(f);
1739 painter->setPen(controlTextColor(option));
1740 painter->drawText(vindRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
1744 case CE_MenuBarItem:
1745 if (
const auto *mbi = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1746 using namespace StyleOptionHelper;
1748 constexpr int hPadding = 11;
1749 constexpr int topPadding = 4;
1750 constexpr int bottomPadding = 6;
1751 QStyleOptionMenuItem newMbi = *mbi;
1753 if (
auto mbiV2 = qstyleoption_cast<
const QStyleOptionMenuItemV2 *>(option))
1754 newMbi.state.setFlag(State_Sunken, mbiV2->mouseDown);
1756 newMbi.font.setPointSize(10);
1757 newMbi.palette.setColor(QPalette::ButtonText, controlTextColor(&newMbi));
1758 if (!isDisabled(&newMbi)) {
1759 QPen pen(Qt::NoPen);
1760 QBrush brush(Qt::NoBrush);
1761 if (highContrastTheme) {
1762 pen = QPen(newMbi.palette.highlight().color(), 2);
1763 brush = newMbi.palette.window();
1764 }
else if (isPressed(&newMbi)) {
1765 brush = winUI3Color(subtlePressedColor);
1766 }
else if (isHover(&newMbi)) {
1767 brush = winUI3Color(subtleHighlightColor);
1769 if (pen != Qt::NoPen || brush != Qt::NoBrush) {
1770 const QRect rect = mbi->rect.marginsRemoved(QMargins(5, 0, 5, 0));
1771 drawRoundedRect(painter, rect, pen, brush);
1774 newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
1775 painter->setFont(newMbi.font);
1776 QCommonStyle::drawControl(element, &newMbi, painter, widget);
1781 case CE_MenuEmptyArea:
1785 if (
const auto *menuitem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
1786 const auto visualMenuRect = [&](
const QRect &rect) {
1787 return visualRect(option->direction, menuitem->rect, rect);
1789 bool dis = !(menuitem->state & State_Enabled);
1790 bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
1791 ? menuitem->checked :
false;
1792 bool act = menuitem->state & State_Selected;
1794 const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2));
1795 if (act && dis ==
false) {
1796 drawRoundedRect(painter, rect, Qt::NoPen, highContrastTheme ? menuitem->palette.brush(QPalette::Highlight)
1797 : QBrush(winUI3Color(subtleHighlightColor)));
1799 if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
1800 constexpr int yoff = 1;
1801 painter->setPen(highContrastTheme ? menuitem->palette.buttonText().color() : winUI3Color(dividerStrokeDefault));
1802 painter->drawLine(menuitem->rect.topLeft() + QPoint(0, yoff),
1803 menuitem->rect.topRight() + QPoint(0, yoff));
1807 int xOffset = contentHMargin;
1809 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
1811 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset, rect.y(),
1812 checkMarkWidth, rect.height())));
1813 QPainterStateGuard psg(painter);
1814 painter->setFont(d->assetFont);
1815 painter->setPen(option->palette.text().color());
1816 painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
1818 if (menuitem->menuHasCheckableItems)
1819 xOffset += checkMarkWidth + contentItemHMargin;
1820 if (!menuitem->icon.isNull()) {
1822 QRect vRect(visualMenuRect(QRect(rect.x() + xOffset,
1824 menuitem->maxIconWidth - 4,
1826 QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
1828 mode = QIcon::Active;
1829 const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
1830 QRect pmr(QPoint(0, 0), QSize(size, size));
1831 pmr.moveCenter(vRect.center());
1832 menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode,
1833 checked ? QIcon::On : QIcon::Off);
1835 if (menuitem->maxIconWidth > 0)
1836 xOffset += menuitem->maxIconWidth - 4 + contentItemHMargin;
1838 QStringView s(menuitem->text);
1840 QPoint tl(rect.left() + xOffset, rect.top());
1841 QPoint br(rect.right() - menuitem->reservedShortcutWidth - contentHMargin,
1843 QRect textRect(tl, br);
1844 QRect vRect(visualMenuRect(textRect));
1847 if (highContrastTheme) {
1848 penColor = menuitem->palette.color(act ? QPalette::HighlightedText
1851 penColor = controlTextColor(option);
1853 painter->setPen(penColor);
1855 qsizetype t = s.indexOf(u'\t');
1856 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
1857 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
1858 text_flags |= Qt::TextHideMnemonic;
1859 text_flags |= Qt::AlignLeft;
1861 if (t >= 0 && menuitem->menuItemType != QStyleOptionMenuItem::SubMenu) {
1862 QRect shortcutRect(QPoint(textRect.right(), textRect.top()),
1863 QPoint(rect.right(), textRect.bottom()));
1864 QRect vShortcutRect(visualMenuRect(shortcutRect));
1865 const QString textToDraw = s.mid(t + 1).toString();
1866 painter->drawText(vShortcutRect, text_flags, textToDraw);
1869 QFont font = menuitem->font;
1870 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
1872 painter->setFont(font);
1873 const QString textToDraw = s.left(t).toString();
1874 painter->drawText(vRect, text_flags, textToDraw);
1876 if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
1877 int fontSize = menuitem->font.pointSize();
1878 QFont f(d->assetFont);
1879 f.setPointSize(qRound(fontSize * 0.9f));
1880 painter->setFont(f);
1881 int yOfs = qRound(fontSize / 3.0f);
1882 QPoint tl(rect.right() - 2 * QWindowsStylePrivate::windowsArrowHMargin - contentItemHMargin,
1884 QRect submenuRect(tl, rect.bottomRight());
1885 QRect vSubMenuRect = visualMenuRect(submenuRect);
1886 painter->setPen(option->palette.text().color());
1887 const bool isReverse = option->direction == Qt::RightToLeft;
1888 const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
1889 painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
1894 case CE_MenuBarEmptyArea: {
1897 case CE_HeaderEmptyArea:
1899 case CE_HeaderSection: {
1900 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(option)) {
1901 painter->setPen(Qt::NoPen);
1902 painter->setBrush(header->palette.button());
1903 painter->drawRect(header->rect);
1904 const bool isRtl = option->direction == Qt::RightToLeft;
1905 const QPointF tr = isRtl ? option->rect.topLeft() : option->rect.topRight();
1906 const QPointF br = isRtl ? option->rect.bottomLeft() : option->rect.bottomRight();
1907 const QPointF bl = isRtl ? option->rect.bottomRight() : option->rect.bottomLeft();
1908 constexpr QPointF trOfs = QPointF(0.5, 0.0);
1909 constexpr QPointF brOfs = QPointF(0.5, 0.5);
1910 constexpr QPointF blOfs = QPointF(0.0, 0.5);
1911 const std::array<
QPointF, 3> points = { tr + trOfs, br + brOfs, bl + blOfs };
1912 QPen pen(highContrastTheme ? header->palette.buttonText().color()
1913 : winUI3Color(frameColorLight));
1914 pen.setJoinStyle(Qt::MiterJoin);
1915 painter->setPen(pen);
1916 painter->drawPolyline(points.data(),
int(points.size()));
1920 case CE_ItemViewItem: {
1921 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
1922 const auto p = proxy();
1923 QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
1924 QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
1925 QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget);
1928 proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
1930 const QRect &rect = vopt->rect;
1931 const bool isRtl = option->direction == Qt::RightToLeft;
1932 bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
1933 vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
1934 bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
1935 bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
1937 const QAbstractItemView *view = qobject_cast<
const QAbstractItemView *>(widget);
1938 if (qobject_cast<
const QTableView *>(view)) {
1942 if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
1943 vopt->showDecorationSelected) {
1955 }
else if (isLast) {
1962 const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
1963 if (highlightCurrent) {
1964 if (highContrastTheme) {
1965 painter->setBrush(vopt->palette.highlight());
1967 painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
1968 ? calculateAccentColor(option)
1969 : winUI3Color(subtleHighlightColor));
1972 painter->setBrush(vopt->backgroundBrush);
1974 painter->setPen(Qt::NoPen);
1977 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
1978 secondLevelRoundingRadius, secondLevelRoundingRadius);
1979 }
else if (isFirst) {
1980 QPainterStateGuard psg(
painter);
1981 painter->setClipRect(rect);
1982 painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
1983 secondLevelRoundingRadius, secondLevelRoundingRadius);
1984 }
else if (isLast) {
1985 QPainterStateGuard psg(
painter);
1986 painter->setClipRect(rect);
1987 painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
1988 secondLevelRoundingRadius, secondLevelRoundingRadius);
1990 painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
1994 if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
1995 QStyleOptionViewItem option(*vopt);
1996 option.rect = checkRect;
1997 option.state = option.state & ~QStyle::State_HasFocus;
1999 switch (vopt->checkState) {
2001 option.state |= QStyle::State_Off;
2003 case Qt::PartiallyChecked:
2004 option.state |= QStyle::State_NoChange;
2007 option.state |= QStyle::State_On;
2010 proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
2014 if (iconRect.isValid()) {
2015 QIcon::Mode mode = QIcon::Normal;
2016 if (!(vopt->state & QStyle::State_Enabled))
2017 mode = QIcon::Disabled;
2018 else if (vopt->state & QStyle::State_Selected)
2019 mode = QIcon::Selected;
2020 QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
2021 vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
2024 if (highlightCurrent && highContrastTheme) {
2025 painter->setPen(vopt->palette.base().color());
2026 }
else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
2027 painter->setPen(winUI3Color(textOnAccentPrimary));
2029 painter->setPen(vopt->palette.text().color());
2031 d->viewItemDrawText(painter, vopt, textRect);
2034 if (vopt->state & State_Selected && !highContrastTheme) {
2035 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2036 lv && lv->viewMode() != QListView::IconMode) {
2037 const auto col = vopt->palette.accent().color();
2038 painter->setBrush(col);
2039 painter->setPen(col);
2040 const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
2041 const auto yOfs = rect.height() / 4.;
2042 QRectF r(
QPointF(xPos, rect.y() + yOfs),
2043 QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
2044 painter->drawRoundedRect(r, 1, 1);
2051 QWindowsVistaStyle::drawControl(element, option, painter, widget);
2211QRect QWindows11Style::subControlRect(ComplexControl control,
const QStyleOptionComplex *option,
2212 SubControl subControl,
const QWidget *widget)
const
2217#if QT_CONFIG(spinbox)
2219 if (
const QStyleOptionSpinBox *spinbox = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2220 const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
2221 const int fw = spinbox->frame
2222 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
2224 const int buttonHeight = hasButtons
2225 ? qMin(spinbox->rect.height() - 3 * fw, spinbox->fontMetrics.height() * 5 / 4)
2227 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2228 const int textFieldLength = spinbox->rect.width() - 2 * fw - 2 * buttonSize.width();
2229 const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
2230 switch (subControl) {
2232 case SC_SpinBoxDown: {
2235 const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2236 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2237 buttonSize.height());
2238 if (subControl == SC_SpinBoxDown)
2239 ret.moveRight(ret.right() + buttonSize.width());
2242 case SC_SpinBoxEditField:
2243 ret = QRect(topLeft,
2244 spinbox->rect.bottomRight() - QPoint(fw + 2 * buttonSize.width(), fw));
2246 case SC_SpinBoxFrame:
2247 ret = spinbox->rect;
2251 ret = visualRect(spinbox->direction, spinbox->rect, ret);
2255 if (
const QStyleOptionTitleBar *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(option)) {
2256 SubControl sc = subControl;
2257 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2258 static constexpr int indent = 3;
2259 static constexpr int controlWidthMargin = 2;
2260 const int controlHeight = titlebar->rect.height();
2261 const int controlWidth = 46;
2262 const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
2263 int offset = -(controlWidthMargin + indent);
2265 bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
2266 bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
2269 case SC_TitleBarLabel:
2270 if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
2271 ret = titlebar->rect;
2272 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2273 ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
2274 if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
2275 ret.adjust(0, 0, -controlWidth, 0);
2276 if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
2277 ret.adjust(0, 0, -controlWidth, 0);
2278 if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
2279 ret.adjust(0, 0, -controlWidth, 0);
2280 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2281 ret.adjust(0, 0, -controlWidth, 0);
2284 case SC_TitleBarContextHelpButton:
2285 if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
2286 offset += controlWidth;
2288 case SC_TitleBarMinButton:
2289 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2290 offset += controlWidth;
2291 else if (sc == SC_TitleBarMinButton)
2294 case SC_TitleBarNormalButton:
2295 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
2296 offset += controlWidth;
2297 else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2298 offset += controlWidth;
2299 else if (sc == SC_TitleBarNormalButton)
2302 case SC_TitleBarMaxButton:
2303 if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
2304 offset += controlWidth;
2305 else if (sc == SC_TitleBarMaxButton)
2308 case SC_TitleBarShadeButton:
2309 if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2310 offset += controlWidth;
2311 else if (sc == SC_TitleBarShadeButton)
2314 case SC_TitleBarUnshadeButton:
2315 if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
2316 offset += controlWidth;
2317 else if (sc == SC_TitleBarUnshadeButton)
2320 case SC_TitleBarCloseButton:
2321 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
2322 offset += controlWidth;
2323 else if (sc == SC_TitleBarCloseButton)
2325 ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
2326 controlWidth, controlHeight);
2328 case SC_TitleBarSysMenu:
2329 if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
2330 const auto yOfs = titlebar->rect.top() + (titlebar->rect.height() - iconSize) / 2;
2331 ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, yOfs, iconSize,
2338 if (widget && isMinimized && titlebar->rect.width() < offset)
2339 const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
2340 ret = visualRect(titlebar->direction, titlebar->rect, ret);
2346 ret = QCommonStyle::subControlRect(control, option, subControl, widget);
2348 if (subControl == SC_ScrollBarAddLine || subControl == SC_ScrollBarSubLine) {
2349 if (
const QStyleOptionSlider *scrollbar = qstyleoption_cast<
const QStyleOptionSlider *>(option)) {
2350 if (scrollbar->orientation == Qt::Vertical)
2351 ret = ret.adjusted(2,2,-2,-3);
2353 ret = ret.adjusted(3,2,-2,-2);
2359 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2360 const auto indicatorWidth =
2361 proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2362 switch (subControl) {
2363 case SC_ComboBoxArrow: {
2365 cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
2366 const int buttonHeight =
2367 qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
2368 const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
2369 const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
2370 const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
2371 const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
2372 ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
2373 buttonSize.height());
2374 ret = visualRect(option->direction, option->rect, ret);
2377 case SC_ComboBoxEditField: {
2380 const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
2381 ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
2383 ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
2384 ret = visualRect(option->direction, option->rect, ret);
2388 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2394#if QT_CONFIG(groupbox)
2396 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2397 switch (subControl) {
2398 case SC_GroupBoxCheckBox:
2408 ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
2416QSize QWindows11Style::sizeFromContents(ContentsType type,
const QStyleOption *option,
2417 const QSize &size,
const QWidget *widget)
const
2419 QSize contentSize(size);
2423#if QT_CONFIG(menubar)
2424 case CT_MenuBarItem:
2425 if (!contentSize.isEmpty()) {
2426 constexpr int hMargin = 2 * 6;
2427 constexpr int hPadding = 2 * 11;
2428 constexpr int itemHeight = 32;
2429 contentSize.setWidth(contentSize.width() + hMargin + hPadding);
2430#if QT_CONFIG(tabwidget)
2431 if (widget->parent() && !qobject_cast<
const QTabWidget *>(widget->parent()))
2433 contentSize.setHeight(itemHeight);
2439 if (
const auto *menuItem = qstyleoption_cast<
const QStyleOptionMenuItem *>(option)) {
2440 int width = size.width();
2442 if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
2446 height = menuItem->fontMetrics.height() + 8;
2447 if (!menuItem->icon.isNull()) {
2448 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
2449 height = qMax(height,
2450 menuItem->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
2453 if (menuItem->text.contains(u'\t'))
2454 width += contentItemHMargin;
2455 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
2456 width += 2 * QWindowsStylePrivate::windowsArrowHMargin + contentItemHMargin;
2457 if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
2458 const QFontMetrics fm(menuItem->font);
2459 QFont fontBold = menuItem->font;
2460 fontBold.setBold(
true);
2461 const QFontMetrics fmBold(fontBold);
2462 width += fmBold.horizontalAdvance(menuItem->text) - fm.horizontalAdvance(menuItem->text);
2465 if (menuItem->menuHasCheckableItems) {
2466 const auto checkMarkWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
2467 width += checkMarkWidth + contentItemHMargin * 2;
2471 if (menuItem->maxIconWidth > 0)
2472 width += contentItemHMargin * 2 + menuItem->maxIconWidth - 4;
2474 width += 2 * contentHMargin;
2477 contentSize = QSize(width, height);
2481#if QT_CONFIG(spinbox)
2483 if (
const auto *spinBoxOpt = qstyleoption_cast<
const QStyleOptionSpinBox *>(option)) {
2485 const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
2486 const int margins = 8;
2487 const int buttonWidth = hasButtons ? 16 + contentItemHMargin : 0;
2488 const int frameWidth = spinBoxOpt->frame
2489 ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
2492 contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
2497#if QT_CONFIG(combobox)
2499 if (
const auto *comboBoxOpt = qstyleoption_cast<
const QStyleOptionComboBox *>(option)) {
2500 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2501 contentSize += QSize(0, 4);
2502 if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
2503 const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
2504 contentSize.rwidth() += w + contentItemHMargin;
2510 if (qstyleoption_cast<
const QStyleOptionFrame *>(option)) {
2511 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2512 contentSize += QSize(0, 4);
2516 case CT_HeaderSection:
2519 contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget);
2521 case CT_RadioButton:
2523 if (
const auto *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(option)) {
2524 const auto p = proxy();
2525 const bool isRadio = (type == CT_RadioButton);
2527 const int width = p->pixelMetric(
2528 isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, option, widget);
2529 const int height = p->pixelMetric(
2530 isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, option, widget);
2533 if (!buttonOpt->icon.isNull() || !buttonOpt->text.isEmpty()) {
2534 margins += p->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
2535 : PM_CheckBoxLabelSpacing,
2539 contentSize += QSize(width + margins, 4);
2540 contentSize.setHeight(qMax(size.height(), height + 2 * contentItemHMargin));
2546 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2547 if (size.width() == 0)
2548 contentSize.rwidth() += 2;
2550 case CT_PushButton: {
2551 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2553 const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget);
2554 contentSize.rwidth() += 2 * contentHMargin - oldMargin;
2557 case CT_ToolButton: {
2559 if (
const auto tb = qstyleoption_cast<
const QStyleOptionToolButton *>(option)) {
2561 if (!tb->subControls.testFlag(SC_ToolButtonMenu)) {
2562 if (tb->features.testFlag(QStyleOptionToolButton::HasMenu))
2563 contentSize.rwidth() += 2;
2565 if (tb->toolButtonStyle == Qt::ToolButtonTextBesideIcon
2566 || tb->toolButtonStyle == Qt::ToolButtonIconOnly) {
2567 contentSize.rheight() = qMax(contentSize.height(), tb->iconSize.height() + 4);
2570 const auto fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
2571 contentSize += QSize(contentHMargin + 2 * fw, 2 * fw);
2574 case CT_ItemViewItem: {
2575 if (
const auto *viewItemOpt = qstyleoption_cast<
const QStyleOptionViewItem *>(option)) {
2576 if (
const QListView *lv = qobject_cast<
const QListView *>(widget);
2577 lv && lv->viewMode() != QListView::IconMode) {
2578 QStyleOptionViewItem vOpt(*viewItemOpt);
2582 vOpt.rect.setRight(vOpt.rect.right() - contentHMargin);
2583 contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget);
2584 contentSize.rwidth() += contentHMargin;
2585 contentSize.rheight() += 2 * contentHMargin;
2588 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
2594 contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);