diff --git a/sources/palettegraphicsview.cpp b/sources/palettegraphicsview.cpp index bb05d7657..04eb77039 100644 --- a/sources/palettegraphicsview.cpp +++ b/sources/palettegraphicsview.cpp @@ -20,6 +20,7 @@ #include "qetpalette.h" #include +#include #include #include #include @@ -29,11 +30,13 @@ PaletteGraphicsView::PaletteGraphicsView(QWidget *parent) : QGraphicsView(parent) { + qApp->installEventFilter(this); } PaletteGraphicsView::PaletteGraphicsView(QGraphicsScene *scene, QWidget *parent) : QGraphicsView(scene, parent) { + qApp->installEventFilter(this); listenToScene(scene); } @@ -78,6 +81,23 @@ void PaletteGraphicsView::listenToScene(QGraphicsScene *scene) connect(scene, &QGraphicsScene::changed, this, [](const QList &) {}); } +/** + @brief PaletteGraphicsView::eventFilter + Repaint the whole viewport when the application palette changes. Qt + sends that change to the application object and then repaints only + the widgets whose own palette changed with it, which under a style + sheet is not the case (see invertsLightness()): the scene would then + repaint only what it updates itself, and the viewport around the + sheet would keep the colors of the previous palette. The filter sits + on the application object, the one receiver Qt always notifies. +*/ +bool PaletteGraphicsView::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == qApp && event->type() == QEvent::ApplicationPaletteChange) + viewport()->update(); + return QGraphicsView::eventFilter(watched, event); +} + /** @brief PaletteGraphicsView::paintEvent Paints as QGraphicsView on a light palette, inverted on a dark one. diff --git a/sources/palettegraphicsview.h b/sources/palettegraphicsview.h index 13ad26077..c8d512e30 100644 --- a/sources/palettegraphicsview.h +++ b/sources/palettegraphicsview.h @@ -52,6 +52,7 @@ class PaletteGraphicsView : public QGraphicsView bool invertsLightness() const; protected: + bool eventFilter(QObject *watched, QEvent *event) override; void paintEvent(QPaintEvent *event) override; /** Called with true right before the scene is rendered for an diff --git a/tests/qttest/tst_qetpalette.cpp b/tests/qttest/tst_qetpalette.cpp index bf20fe33d..5a6f4fddb 100644 --- a/tests/qttest/tst_qetpalette.cpp +++ b/tests/qttest/tst_qetpalette.cpp @@ -546,12 +546,22 @@ namespace { { public: int paints = 0; + QList paint_rects; QList inverted_calls; using PaletteGraphicsView::PaletteGraphicsView; + /// True when a paint since index \a from covered the whole viewport. + bool fullyRepaintedSince(int from) const + { + for (int i = from; i < paint_rects.size(); ++i) + if (paint_rects.at(i).contains(viewport()->rect())) + return true; + return false; + } protected: void paintEvent(QPaintEvent *event) override { ++paints; + paint_rects << event->rect(); PaletteGraphicsView::paintEvent(event); } void paintingInverted(bool inverted) override @@ -728,7 +738,11 @@ void tst_qetpalette::paletteViewDrawsTheRubberBand() such a sheet). The view's own palette() is therefore stale after a live switch, and the view must follow the application palette instead: inside a tab widget with a style sheet, switching the - application to dark and back still changes the sheet. + application to dark and back still changes the sheet. Qt also skips + the repaint of a widget whose palette did not change, so the view + has to repaint its whole viewport by itself on each switch, without + anyone asking for a rendering: otherwise the area around the sheet + keeps the old colors. */ void tst_qetpalette::paletteViewFollowsTheApplicationUnderAStyleSheet() { @@ -748,13 +762,17 @@ void tst_qetpalette::paletteViewFollowsTheApplicationUnderAStyleSheet() QVERIFY(QTest::qWaitForWindowExposed(&tabs)); QCOMPARE(sheetColor(view->viewport()->grab().toImage()), QColor(Qt::white)); + int since = view->paint_rects.size(); QApplication::setPalette(QET::Palette::fusionDark()); QTRY_VERIFY(view->invertsLightness()); + QTRY_VERIFY2(view->fullyRepaintedSince(since), "no full repaint after the switch to dark"); const QColor base = QET::Palette::fusionDark().color(QPalette::Active, QPalette::Base); QCOMPARE(sheetColor(view->viewport()->grab().toImage()), base); + since = view->paint_rects.size(); QApplication::setPalette(QET::Palette::fusionLight()); QTRY_VERIFY(!view->invertsLightness()); + QTRY_VERIFY2(view->fullyRepaintedSince(since), "no full repaint after the switch to light"); QCOMPARE(sheetColor(view->viewport()->grab().toImage()), QColor(Qt::white)); }