From fc750cba379c81171b0e5065c844b850c0f8d97d Mon Sep 17 00:00:00 2001 From: zqq-dora <298592563+zqq-dora@users.noreply.github.com> Date: Thu, 3 Sep 2026 15:59:25 +0800 Subject: [PATCH] feat(DrawUtils): add drawInsetShadow for inner shadow rendering Add DDrawUtils::drawInsetShadow() parallel to the existing drawShadow(), for rendering inset (inner) shadows on QWidget controls. This mirrors the QML BoxInsetShadow component in dtkdeclarative, enabling consistent inset shadow effects across both frameworks. The implementation uses qt_blurImage (same as drawShadow) to blur a hole-punched alpha mask, then composites the shadow color and clips to the rounded-rect shape. --- include/widgets/dstyle.h | 1 + src/widgets/dstyle.cpp | 55 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/include/widgets/dstyle.h b/include/widgets/dstyle.h index 6c9b260fa..e24694acd 100644 --- a/include/widgets/dstyle.h +++ b/include/widgets/dstyle.h @@ -45,6 +45,7 @@ Q_DECLARE_FLAGS(Corners, Corner) void drawShadow(QPainter *pa, const QRect &rect, qreal xRadius, qreal yRadius, const QColor &sc, qreal radius, const QPoint &offset); void drawShadow(QPainter *pa, const QRect &rect, const QPainterPath &path, const QColor &sc, int radius, const QPoint &offset); +void drawInsetShadow(QPainter *pa, const QRect &rect, qreal xRadius, qreal yRadius, const QColor &sc, qreal radius, const QPoint &offset); void drawRoundedRect(QPainter *pa, const QRect &rect, qreal xRadius, qreal yRadius, Corners corners, Qt::SizeMode mode = Qt::AbsoluteSize); void drawFork(QPainter *pa, const QRectF &rect, const QColor &color, int width = 2); void drawMark(QPainter *pa, const QRectF &rect, const QColor &boxInside, const QColor &boxOutside, const int penWidth, const int outLineLeng = 2); diff --git a/src/widgets/dstyle.cpp b/src/widgets/dstyle.cpp index 92f9f9ca7..0ed7680b2 100644 --- a/src/widgets/dstyle.cpp +++ b/src/widgets/dstyle.cpp @@ -392,6 +392,61 @@ void drawShadow(QPainter *pa, const QRect &rect, const QPainterPath &path, const pa->drawPixmap(shadow_rect, shadow); } +void drawInsetShadow(QPainter *pa, const QRect &rect, qreal xRadius, qreal yRadius, const QColor &sc, qreal radius, const QPoint &offset) +{ + if (radius <= 0 || rect.isNull()) + return; + + qreal scale = pa->paintEngine()->paintDevice()->devicePixelRatioF(); + QSize size = rect.size() * scale; + xRadius *= scale; + yRadius *= scale; + radius *= scale; + QPoint scaledOffset(offset.x() * scale, offset.y() * scale); + + // Build an opaque image, then cut out a rounded-rect hole shifted by + // 'offset'. After blurring, the hole edges fade inward, producing an + // inset shadow. Positive offset.y() makes the shadow stronger at the + // top edge; negative at the bottom. + QImage shadow_base(size, QImage::Format_ARGB32_Premultiplied); + shadow_base.fill(Qt::black); + + QPainter holePainter(&shadow_base); + holePainter.setRenderHint(QPainter::Antialiasing, true); + holePainter.setPen(Qt::NoPen); + holePainter.setCompositionMode(QPainter::CompositionMode_Clear); + holePainter.setBrush(Qt::transparent); + QRectF holeRect = QRectF(shadow_base.rect()).translated(scaledOffset); + holeRect = holeRect.marginsRemoved(QMarginsF(radius, radius, radius, radius)); + holePainter.drawRoundedRect(holeRect, xRadius, yRadius); + holePainter.end(); + + // Blur the alpha channel so the hole edges become a soft gradient. + QImage blurred(size, QImage::Format_ARGB32_Premultiplied); + blurred.fill(0); + QPainter blurPainter(&blurred); + qt_blurImage(&blurPainter, shadow_base, radius, false, true); + blurPainter.end(); + + // Replace the placeholder black with the actual shadow color. + QPainter colorPainter(&blurred); + colorPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); + colorPainter.fillRect(blurred.rect(), sc); + colorPainter.end(); + + blurred.setDevicePixelRatio(scale); + + // Clip to the rounded-rect shape so the opaque outer area is hidden; + // only the inward-fading shadow at the edges is visible. + pa->save(); + pa->setRenderHint(QPainter::Antialiasing, true); + QPainterPath clipPath; + clipPath.addRoundedRect(rect, xRadius / scale, yRadius / scale); + pa->setClipPath(clipPath); + pa->drawImage(rect.topLeft(), blurred); + pa->restore(); +} + void drawFork(QPainter *pa, const QRectF &rect, const QColor &color, int width) { QPen pen;