Skip to content

feat(DrawUtils): add drawInsetShadow for inner shadow rendering - #779

Open
zqq-dora wants to merge 1 commit into
linuxdeepin:masterfrom
zqq-dora:feat/draw-inset-shadow
Open

feat(DrawUtils): add drawInsetShadow for inner shadow rendering#779
zqq-dora wants to merge 1 commit into
linuxdeepin:masterfrom
zqq-dora:feat/draw-inset-shadow

Conversation

@zqq-dora

@zqq-dora zqq-dora commented Sep 3, 2026

Copy link
Copy Markdown

Background

dtkdeclarative 的 PR #672 在 ToolButton 深色模式 hover 中使用了内阴影效果(BoxInsetShadow),该效果目前只在 QML 中有组件支持。为了保持 QWidget 和 QML 两端视觉一致,需要在 dtkwidget 中提供等价的内阴影绘制能力。

Changes

DDrawUtils 命名空间中新增 drawInsetShadow() 函数,与现有的 drawShadow() 接口风格平行:

void drawInsetShadow(QPainter *pa, const QRect &rect,
                     qreal xRadius, qreal yRadius,
                     const QColor &sc, qreal radius,
                     const QPoint &offset);

实现原理

  1. 创建与目标区域同大小的图片,填充不透明黑色
  2. CompositionMode_Clear 挖出按 offset 偏移的圆角矩形孔
  3. 调用 qt_blurImage 对 alpha 通道做高斯模糊(与 drawShadow 使用同一函数)
  4. CompositionMode_SourceIn 替换为实际阴影颜色
  5. 用圆角矩形路径 clip 后绘制,隐藏外圈不透明区域

与 QML BoxInsetShadow 的对应

QML BoxInsetShadow DDrawUtils::drawInsetShadow
cornerRadius xRadius / yRadius
shadowColor sc
shadowOffsetY: 1 (顶部高光) offset = (0, 1)
shadowOffsetY: -1 (底部暗角) offset = (0, -1)
shadowBlur radius

Files

File Change
include/widgets/dstyle.h 新增 drawInsetShadow 声明
src/widgets/dstyle.cpp 新增 drawInsetShadow 实现

Summary by Sourcery

Add inset-shadow rendering support to DDrawUtils for consistent inner-shadow effects across QWidget and QML interfaces.

New Features:

  • Add a QWidget drawing utility for rendering soft inset shadows with configurable corner radii, color, blur radius, and offset.

Enhancements:

  • Align QWidget shadow rendering capabilities with the existing QML inset-shadow visual effect.

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.
@deepin-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: zqq-dora

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@deepin-ci-robot

Copy link
Copy Markdown
Contributor

Hi @zqq-dora. Thanks for your PR. 😃

@deepin-ci-robot

Copy link
Copy Markdown
Contributor

Hi @zqq-dora. Thanks for your PR.

I'm waiting for a linuxdeepin member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@sourcery-ai

sourcery-ai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds DDrawUtils::drawInsetShadow for rendering clipped, blurred inner shadows in QWidget code, using the same blur pipeline as drawShadow and supporting high-DPI scaling, rounded corners, colors, blur radius, and directional offsets.

Sequence diagram for inset shadow rendering

sequenceDiagram
    participant Caller as QWidget caller
    participant DDrawUtils
    participant QImage as Shadow image
    participant QPainter
    participant qt_blurImage

    Caller->>DDrawUtils: drawInsetShadow(pa, rect, xRadius, yRadius, sc, radius, offset)
    DDrawUtils->>QImage: Create opaque black image
    DDrawUtils->>QPainter: CompositionMode_Clear rounded hole
    QPainter-->>QImage: Offset rounded-rect cutout
    DDrawUtils->>qt_blurImage: Blur alpha channel
    qt_blurImage-->>QImage: Soft inward gradient
    DDrawUtils->>QPainter: CompositionMode_SourceIn with sc
    QPainter-->>QImage: Apply shadow color
    DDrawUtils->>QPainter: Clip to rounded rect
    QPainter-->>Caller as QWidget caller: Draw clipped inset shadow
Loading

File-Level Changes

Change Details Files
Expose and implement a QWidget-side inset-shadow renderer that parallels the existing shadow API and matches QML BoxInsetShadow behavior.
  • Add the public drawInsetShadow declaration with radius, color, blur, and offset parameters.
  • Build a device-pixel-ratio-scaled ARGB image, clear an offset rounded-rectangle hole, and blur its alpha with qt_blurImage.
  • Apply the requested shadow color, clip rendering to the target rounded rectangle, and draw the resulting inward-fading shadow.
include/widgets/dstyle.h
src/widgets/dstyle.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/widgets/dstyle.cpp" line_range="405" />
<code_context>
+    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
</code_context>
<issue_to_address>
**issue (bug_risk):** The offset is multiplied by the device-pixel ratio and then truncated when constructing the `QPoint`, so a logical offset of 1 pixel becomes 1 physical pixel rather than 1.5 pixels on a 1.5x display. The inset shadow therefore has an incorrect offset on fractional-DPR devices.

**Triggers:** When the painter targets a device with a fractional device-pixel ratio and `offset` is nonzero.

**Suggested fix:** Use a `QPointF` for the scaled offset, or round the scaled components explicitly before drawing.

```suggestion
    QPointF scaledOffset(offset.x() * scale, offset.y() * scale);
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/widgets/dstyle.cpp
xRadius *= scale;
yRadius *= scale;
radius *= scale;
QPoint scaledOffset(offset.x() * scale, offset.y() * scale);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The offset is multiplied by the device-pixel ratio and then truncated when constructing the QPoint, so a logical offset of 1 pixel becomes 1 physical pixel rather than 1.5 pixels on a 1.5x display. The inset shadow therefore has an incorrect offset on fractional-DPR devices.

Triggers: When the painter targets a device with a fractional device-pixel ratio and offset is nonzero.

Suggested fix: Use a QPointF for the scaled offset, or round the scaled components explicitly before drawing.

Suggested change
QPoint scaledOffset(offset.x() * scale, offset.y() * scale);
QPointF scaledOffset(offset.x() * scale, offset.y() * scale);

@18202781743

Copy link
Copy Markdown
Contributor

这个pr,提交在https://github.com/linuxdeepin/dtkwidget/tree/v25-flowstyle 这个分支上吧,
另外,修下ci,注意license,

@18202781743

Copy link
Copy Markdown
Contributor

这个代码只在dtk6上提交,添加条件编译吧,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants