summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Ehrlicher <[email protected]>2024-09-19 20:38:40 +0200
committerChristian Ehrlicher <[email protected]>2024-10-11 10:54:42 +0200
commitff9818135db28e287e7818defd9c1a9acdebacdc (patch)
treed504ef8fce41ccea3642e330e6b17b499ad83ca0
parent618b1faf37ddda4cdeff6934f5af7e699c9aad63 (diff)
Widgets/Style: add QCachedPainter
Add a helper class QCachedPainter to simplify the usage of QPixmapCache. Task-number: QTBUG-129680 Change-Id: Id6835ec05af2fff3fc43c36b5fedaec598cb580b Reviewed-by: Axel Spoerl <[email protected]>
-rw-r--r--src/widgets/styles/qcommonstyle.cpp1
-rw-r--r--src/widgets/styles/qstyle.cpp49
-rw-r--r--src/widgets/styles/qstyle_p.h38
3 files changed, 88 insertions, 0 deletions
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 701dc2c45da..24968128da3 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -6233,6 +6233,7 @@ int QCommonStyle::layoutSpacing(QSizePolicy::ControlType /* control1 */, QSizePo
void QCommonStyle::polish(QPalette &pal)
{
QStyle::polish(pal);
+ QCachedPainter::cleanupPixmapCache();
}
/*!
diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp
index 32a994f1114..183b0cbe0c9 100644
--- a/src/widgets/styles/qstyle.cpp
+++ b/src/widgets/styles/qstyle.cpp
@@ -7,8 +7,10 @@
#include "qwidget.h"
#include "qbitmap.h"
#include "qpixmapcache.h"
+#include "qset.h"
#include "qstyleoption.h"
#include "private/qstyle_p.h"
+#include "private/qstylehelper_p.h"
#include "private/qguiapplication_p.h"
#include <qpa/qplatformtheme.h>
#ifndef QT_NO_DEBUG
@@ -2422,6 +2424,53 @@ bool QStylePrivate::useFullScreenForPopup()
return theme && theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool();
}
+//
+// QCachedPainter
+QSet<QString> QCachedPainter::s_pixmapCacheKeys;
+QCachedPainter::QCachedPainter(QPainter *painter, const QString &cachePrefix,
+ const QStyleOption *option, QSize size, QRect paintRect)
+ : m_painter(painter)
+ , m_option(option)
+ , m_paintRect(paintRect)
+{
+ const auto sz = size.isNull() ? option->rect.size() : size;
+ const qreal dpr = QStyleHelper::getDpr(painter);
+ m_pixmapName = QStyleHelper::uniqueName(cachePrefix, option, sz, dpr);
+ m_alreadyCached = QPixmapCache::find(m_pixmapName, &m_pixmap);
+ if (!m_alreadyCached) {
+ m_pixmap = styleCachePixmap(sz, dpr);
+ m_pixmapPainter = std::make_unique<QPainter>(&m_pixmap);
+ m_pixmapPainter->setRenderHint(QPainter::Antialiasing);
+ s_pixmapCacheKeys += m_pixmapName;
+ }
+}
+
+QCachedPainter::~QCachedPainter()
+{
+ finish();
+ if (!m_alreadyCached)
+ QPixmapCache::insert(m_pixmapName, m_pixmap);
+}
+
+void QCachedPainter::finish()
+{
+ m_pixmapPainter.reset();
+ if (!m_pixmapDrawn) {
+ m_pixmapDrawn = true;
+ if (m_paintRect.isNull())
+ m_painter->drawPixmap(m_option->rect.topLeft(), m_pixmap);
+ else
+ m_painter->drawPixmap(m_paintRect, m_pixmap);
+ }
+}
+
+void QCachedPainter::cleanupPixmapCache()
+{
+ for (const auto &key : s_pixmapCacheKeys)
+ QPixmapCache::remove(key);
+ s_pixmapCacheKeys.clear();
+}
+
QT_END_NAMESPACE
#include "moc_qstyle.cpp"
diff --git a/src/widgets/styles/qstyle_p.h b/src/widgets/styles/qstyle_p.h
index d04dd491520..0412aca209b 100644
--- a/src/widgets/styles/qstyle_p.h
+++ b/src/widgets/styles/qstyle_p.h
@@ -72,6 +72,44 @@ inline QPixmap styleCachePixmap(const QSize &size, qreal pixelRatio)
} \
}
+// small helper to read out the pixmap to paint from QPixmapCache or re-draw
+// it and put it into the QPixmapCache for later usage
+class Q_WIDGETS_EXPORT QCachedPainter
+{
+public:
+ QCachedPainter(QPainter *painter, const QString &cachePrefix,
+ const QStyleOption *option, QSize size = {}, QRect paintRect = {});
+ ~QCachedPainter();
+ void finish();
+ bool needsPainting() const
+ {
+ return !m_alreadyCached;
+ }
+ QPainter *operator->()
+ {
+ return painter();
+ }
+ QPainter *painter()
+ {
+ Q_ASSERT_X(m_pixmapPainter, "painter()", "Must only be called when painting on a pixmap to cache");
+ return m_pixmapPainter.get();
+ }
+
+ // clean pixmap cache from all cached pixmaps (e.g. due to palette change)
+ // to make sure the widgets are painted correctly afterwards
+ static void cleanupPixmapCache();
+private:
+ QPainter *m_painter = nullptr;
+ const QStyleOption *m_option = nullptr;
+ std::unique_ptr<QPainter> m_pixmapPainter;
+ QString m_pixmapName;
+ QPixmap m_pixmap;
+ QRect m_paintRect;
+ bool m_alreadyCached;
+ bool m_pixmapDrawn = false;
+ static QSet<QString> s_pixmapCacheKeys;
+};
+
QT_END_NAMESPACE
#endif //QSTYLE_P_H