diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 5160243a916..717c8f986c6 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -2268,7 +2268,9 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, case CE_ItemViewItem: if (const QStyleOptionViewItem *vopt = qstyleoption_cast(opt)) { p->save(); - p->setClipRect(opt->rect); + // the style calling this might want to clip, so respect any region already set + const QRegion clipRegion = p->hasClipping() ? (p->clipRegion() & opt->rect) : opt->rect; + p->setClipRegion(clipRegion); QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget); QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget); diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 32ac64265a0..f48893f0db0 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -4368,13 +4368,37 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q vopt->state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base); QWindowsStyle::drawControl(ce, &optCopy, p, w); } else { + p->save(); if (hasStyleRule(w, PseudoElement_Indicator)) { - subRule.configurePalette(&optCopy.palette, vopt->state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text, - vopt->state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base); - } else { - subRule.configurePalette(&optCopy.palette, QPalette::Text, QPalette::NoRole); + // there is a rule for the indicator, but no rule for the item itself (otherwise + // the previous path would have been taken); only draw the indicator using the + // rule (via QWindows/QCommonStyle), then let the base style handle the rest. + QStyleOptionViewItem optIndicator(*vopt); + subRule.configurePalette(&optIndicator.palette, + vopt->state & QStyle::State_Selected + ? QPalette::HighlightedText + : QPalette::Text, + vopt->state & QStyle::State_Selected + ? QPalette::Highlight + : QPalette::Base); + // only draw the indicator; no text or background + optIndicator.backgroundBrush = Qt::NoBrush; // no background + optIndicator.text.clear(); + QWindowsStyle::drawControl(ce, &optIndicator, p, w); + // Now draw text, background, and highlight, but not the indicator with the + // base style. Since we can't turn off HasCheckIndicator to prevent the base + // style from drawing the check indicator again (it would change how the item + // gets laid out) we have to clip the indicator that's already been painted. + const QRect checkRect = subElementRect(QStyle::SE_ItemViewItemCheckIndicator, + &optIndicator, w); + const QRegion clipRegion = QRegion(p->hasClipping() ? p->clipRegion() + : QRegion(optIndicator.rect)) + - checkRect; + p->setClipRegion(clipRegion); } + subRule.configurePalette(&optCopy.palette, QPalette::Text, QPalette::NoRole); baseStyle()->drawControl(ce, &optCopy, p, w); + p->restore(); } return; } diff --git a/tests/baseline/stylesheet/qss/qtreeview/styledIndicators.qss b/tests/baseline/stylesheet/qss/qtreeview/styledIndicators.qss new file mode 100644 index 00000000000..02263ad6443 --- /dev/null +++ b/tests/baseline/stylesheet/qss/qtreeview/styledIndicators.qss @@ -0,0 +1,18 @@ +QTreeWidget::indicator:indeterminate { + background: red +} +QTreeWidget::indicator:indeterminate:disabled { + background: pink +} +QTreeWidget::indicator:checked { + background: green +} +QTreeWidget::indicator:checked:disabled { + background: lightgreen +} +QTreeWidget::indicator:unchecked { + background: blue +} +QTreeWidget::indicator:unchecked:disabled { + background: lightblue +}; diff --git a/tests/baseline/stylesheet/qss/qtreeview/styledItem.qss b/tests/baseline/stylesheet/qss/qtreeview/styledItem.qss new file mode 100644 index 00000000000..1da627881c3 --- /dev/null +++ b/tests/baseline/stylesheet/qss/qtreeview/styledItem.qss @@ -0,0 +1,7 @@ +QAbstractItemView::item +{ + background: grey; +} +QTreeWidget::indicator:checked { + background: green +} diff --git a/tests/baseline/stylesheet/tst_baseline_stylesheet.cpp b/tests/baseline/stylesheet/tst_baseline_stylesheet.cpp index 7430765e97e..e1afdc88aa5 100644 --- a/tests/baseline/stylesheet/tst_baseline_stylesheet.cpp +++ b/tests/baseline/stylesheet/tst_baseline_stylesheet.cpp @@ -49,6 +49,9 @@ private slots: void tst_QScrollArea_data(); void tst_QScrollArea(); + void tst_QTreeView_data(); + void tst_QTreeView(); + private: QDir styleSheetDir; }; @@ -170,6 +173,50 @@ void tst_Stylesheet::tst_QScrollArea() QBASELINE_TEST(takeSnapshot()); } +void tst_Stylesheet::tst_QTreeView_data() +{ + loadTestFiles(); +} + +void tst_Stylesheet::tst_QTreeView() +{ + QHBoxLayout *layout = new QHBoxLayout; + QTreeWidget *tw = new QTreeWidget(); + tw->header()->hide(); + layout->addWidget(tw); + + for (int i = 0; i < 6; ++i) { + QTreeWidgetItem *topLevelItem = new QTreeWidgetItem(tw, QStringList{QString("top %1").arg(i)}); + switch (i) { + case 0: + case 3: + topLevelItem->setCheckState(0, Qt::Unchecked); + break; + case 1: + case 4: + topLevelItem->setCheckState(0, Qt::Checked); + break; + case 2: + case 5: + topLevelItem->setCheckState(0, Qt::PartiallyChecked); + topLevelItem->setExpanded(true); + for (int j = 0; j < 2; ++j) { + QTreeWidgetItem *childItem = new QTreeWidgetItem(topLevelItem, QStringList{QString("child %1").arg(j)}); + childItem->setCheckState(0, j % 2 ? Qt::Unchecked : Qt::Checked); + } + break; + } + topLevelItem->setDisabled(i > 2); + } + testWindow()->setLayout(layout); + tw->setRootIsDecorated(true); + makeVisible(); + + QBASELINE_CHECK_DEFERRED(takeSnapshot(), "rootDecorated"); + tw->setRootIsDecorated(false); + QBASELINE_CHECK_DEFERRED(takeSnapshot(), "rootNotDecorated"); +} + #define main _realmain QTEST_MAIN(tst_Stylesheet) #undef main