diff options
author | Volker Hilsheimer <[email protected]> | 2022-05-03 11:57:10 +0200 |
---|---|---|
committer | Volker Hilsheimer <[email protected]> | 2022-05-06 03:48:09 +0200 |
commit | 2b99a71b2297d5356b253c7907e28e011cf6fee9 (patch) | |
tree | b14e980fd8e250f5b318307a142f439deb855277 | |
parent | 58df315ad11361323ed0dee125b1ee58e5958dd8 (diff) |
Stylesheet: Don't ignore item check indicator styling
Amends cf52d725156811754cd4e094b0984864795d1d58, after which most
indicator styling was no longer taken into account unless some other
item aspects were styled. Calling the baseStyle to draw the entire item
doesn't call back into the style sheet style for the indicator itself.
The QCommonStyle code that breaks the item up into individual sub
elements cannot be called for each element. E.g. turning off the check
indicator feature changes the layout of the item.
So if the indicator is styled, then we have to draw an otherwise empty
item with the style sheet style, and then clip the already painted rect
before calling the base style to draw text and highlighting with the
correct palette.
Add baseline test for QTreeView with different style sheets.
Fixes: QTBUG-102820
Pick-to: 6.3 6.2
Change-Id: I1da5676cc63556230eac525bc550457ebd495a58
Reviewed-by: Richard Moe Gustavsen <[email protected]>
-rw-r--r-- | src/widgets/styles/qcommonstyle.cpp | 4 | ||||
-rw-r--r-- | src/widgets/styles/qstylesheetstyle.cpp | 32 | ||||
-rw-r--r-- | tests/baseline/stylesheet/qss/qtreeview/styledIndicators.qss | 18 | ||||
-rw-r--r-- | tests/baseline/stylesheet/qss/qtreeview/styledItem.qss | 7 | ||||
-rw-r--r-- | tests/baseline/stylesheet/tst_baseline_stylesheet.cpp | 47 |
5 files changed, 103 insertions, 5 deletions
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<const QStyleOptionViewItem *>(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 |