perf(ui): replace animated-sidebar drop shadows with pre-baked 9-patch overlay
QGraphicsDropShadowEffect forces the host widget through an off-screen software Gaussian blur on every repaint. On the floating sidebar (HomeView, blur 25) and the player right sidebar (PlayerView, blur 35), the blur was re-rasterized on every frame of the 350ms slide animation, the main source of UI jank. Bake the blur once into a 9-patch PNG (cached to CacheLocation/shadows via QGraphicsBlurEffect) and render it at runtime as a cheap 9-slice stretch with zero per-frame blur cost: - utils/shadowpixmap: off-screen bake + on-disk cache, dpr-aware. - components/shadowoverlay: mouse-transparent sibling widget, lazy-baked, paints the 9-patch; optional body cutout for semi-transparent targets so the shadow does not bleed through the body. - homeview/playerview: drop the effect; the overlay tracks the sidebar geometry via the existing eventFilter (Move/Resize/Show/Hide), so every setGeometry/move site and the slide animation drive it for free.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "../../components/playerosdlayer.h"
|
||||
#include "../../components/playerstatisticsoverlay.h"
|
||||
#include "../../components/playersubtitlesettingsdialog.h"
|
||||
#include "../../components/shadowoverlay.h"
|
||||
#include "../../utils/mediaitemutils.h"
|
||||
#include "../../utils/mediasourcepreferenceutils.h"
|
||||
#include "../../utils/playerpreferenceutils.h"
|
||||
@@ -26,7 +27,6 @@
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFontMetrics>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
#include <QHBoxLayout>
|
||||
#include <QListWidget>
|
||||
#include <QMainWindow>
|
||||
@@ -1611,6 +1611,8 @@ void PlayerView::setupUi()
|
||||
updateDanmakuButtonState();
|
||||
updateMediaSwitcherButton();
|
||||
m_rightSidebar->raise();
|
||||
if (m_rightSidebarShadow)
|
||||
m_rightSidebarShadow->stackUnder(m_rightSidebar);
|
||||
}
|
||||
|
||||
|
||||
@@ -1633,9 +1635,11 @@ void PlayerView::updateLoadingState()
|
||||
|
||||
m_topHUD->raise();
|
||||
m_bottomHUD->raise();
|
||||
m_logoLabel->raise();
|
||||
m_networkSpeedLabel->raise();
|
||||
m_logoLabel->raise();
|
||||
m_networkSpeedLabel->raise();
|
||||
m_rightSidebar->raise();
|
||||
if (m_rightSidebarShadow)
|
||||
m_rightSidebarShadow->stackUnder(m_rightSidebar);
|
||||
m_rightTrigger->raise();
|
||||
if (m_activePopup)
|
||||
m_activePopup->raise();
|
||||
@@ -2224,11 +2228,15 @@ void PlayerView::setupRightSidebar()
|
||||
m_rightSidebar->setFixedWidth(220);
|
||||
m_rightSidebar->setGeometry(20000, 0, 220, 100);
|
||||
|
||||
auto *shadow = new QGraphicsDropShadowEffect(this);
|
||||
shadow->setBlurRadius(35);
|
||||
shadow->setColor(QColor(0, 0, 0, 150));
|
||||
shadow->setOffset(-5, 0);
|
||||
m_rightSidebar->setGraphicsEffect(shadow);
|
||||
// Drop shadow via a pre-baked 9-patch overlay instead of
|
||||
// QGraphicsDropShadowEffect, which would re-run a software Gaussian blur on
|
||||
// every frame of the 350ms slide. Body cutout is on because the sidebar
|
||||
// background is semi-transparent (the shadow must not bleed through it).
|
||||
// The overlay tracks the sidebar's geometry in syncRightSidebarShadow().
|
||||
m_rightSidebarShadow = new ShadowOverlay(this);
|
||||
m_rightSidebarShadow->setShadow(35, 0, QColor(0, 0, 0, 150));
|
||||
m_rightSidebarShadow->setBodyCutout(true);
|
||||
m_rightSidebarShadow->hide();
|
||||
|
||||
auto *layout = new QVBoxLayout(m_rightSidebar);
|
||||
layout->setContentsMargins(0, 15, 0, 15);
|
||||
@@ -2374,6 +2382,26 @@ void PlayerView::hideRightSidebar(bool immediate)
|
||||
m_rightSidebarAnim->start();
|
||||
}
|
||||
|
||||
void PlayerView::syncRightSidebarShadow()
|
||||
{
|
||||
if (!m_rightSidebarShadow || !m_rightSidebar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_rightSidebar->isVisible())
|
||||
{
|
||||
m_rightSidebarShadow->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
const int reach = m_rightSidebarShadow->reach();
|
||||
m_rightSidebarShadow->setGeometry(
|
||||
m_rightSidebar->geometry().adjusted(-reach, -reach, reach, reach));
|
||||
m_rightSidebarShadow->stackUnder(m_rightSidebar);
|
||||
m_rightSidebarShadow->show();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PlayerView::stopAndReport()
|
||||
@@ -2874,6 +2902,16 @@ bool PlayerView::eventFilter(QObject *watched, QEvent *event)
|
||||
return BaseView::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
// Keep the drop-shadow overlay glued to the sidebar. The slide animation
|
||||
// and layout both move/resize it, landing here as Move/Resize events, so the
|
||||
// shadow follows every frame with no per-frame blur.
|
||||
if (watched == m_rightSidebar &&
|
||||
(event->type() == QEvent::Move || event->type() == QEvent::Resize ||
|
||||
event->type() == QEvent::Show || event->type() == QEvent::Hide))
|
||||
{
|
||||
syncRightSidebarShadow();
|
||||
}
|
||||
|
||||
if (watched == m_mpvWidget || watched == this || watched == m_topHUD || watched == m_titleLabel ||
|
||||
watched == m_bottomHUD)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user