Skip to content

Conversation

@wjyrich
Copy link
Contributor

@wjyrich wjyrich commented Feb 10, 2026

  1. Replaced simple text elision with a custom fade-out effect for better visual appearance
  2. Added gradient opacity mask to smoothly fade text instead of abrupt ellipsis cut-off
  3. Modified TextCalculator to return full text instead of elided text when space permits
  4. Added minimum character display check to ensure at least 2 characters can be shown
  5. Updated width calculation to use optimal width constraints

Log: Improved taskbar application title display with smooth fade-out effect instead of ellipsis

Influence:

  1. Test taskbar with long application titles to see smooth fade-out effect
  2. Verify titles display correctly in both light and dark themes
  3. Check that very short titles still display properly
  4. Test with multiple applications open to ensure consistent behavior
  5. Verify performance with many open applications

fix: 改进任务栏标题显示,实现平滑截断效果

  1. 使用自定义淡出效果替换简单的文本省略,提升视觉体验
  2. 添加渐变透明度遮罩,实现平滑淡出效果而非生硬的省略号截断
  3. 修改TextCalculator,在空间允许时返回完整文本而非省略文本
  4. 添加最小字符显示检查,确保至少能显示2个字符
  5. 更新宽度计算以使用最佳宽度约束

Log: 改进任务栏应用程序标题显示,使用平滑淡出效果替代省略号

Influence:

  1. 测试任务栏中长应用程序标题的平滑淡出效果
  2. 验证标题在浅色和深色主题下正确显示
  3. 检查非常短的标题是否仍能正常显示
  4. 测试多个应用程序打开时的行为一致性
  5. 验证在打开大量应用程序时的性能表现

PMS: BUG-350289

Summary by Sourcery

Improve dock taskbar application title display with smooth truncation and minimum visible characters.

New Features:

  • Add a gradient-based opacity mask to fade out overflowing taskbar titles instead of using ellipsis truncation.

Bug Fixes:

  • Ensure taskbar titles are only shown when at least two characters can fit within the available width.

Enhancements:

  • Update title width calculation to use the optimal single-text width constraint while capping it at the text's intrinsic width.
  • Return full, unelided title text when space permits, simplifying title rendering in the QML layer.

@wjyrich wjyrich requested a review from 18202781743 February 10, 2026 08:08
@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: wjyrich

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

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 10, 2026

Reviewer's Guide

Implements a smooth fade-out truncation effect for taskbar app titles by replacing ellipsis-based elision with a gradient opacity mask, and adjusts TextCalculator to return full text when at least two characters fit while respecting optimal width constraints.

Sequence diagram for taskbar title rendering with fade-out truncation

sequenceDiagram
    actor User
    participant Taskbar
    participant AppItemTitleQML
    participant TextCalculatorAttached
    participant TextCalculator
    participant TitleLoader
    participant TitleContainer
    participant OpacityMaskEffect

    User->>Taskbar: View taskbar
    Taskbar->>AppItemTitleQML: Create/update title for app item
    AppItemTitleQML->>TextCalculatorAttached: set text and calculator
    TextCalculatorAttached->>TextCalculatorAttached: updateElidedText()
    TextCalculatorAttached->>TextCalculator: font()
    TextCalculator->>TextCalculator: optimalSingleTextWidth()
    TextCalculatorAttached->>TextCalculatorAttached: canDisplayMinChars(text, fontMetrics, maxWidth)
    alt AtLeastTwoCharsFit
        TextCalculatorAttached->>TextCalculatorAttached: m_elidedText = full text
    else NotEnoughSpace
        TextCalculatorAttached->>TextCalculatorAttached: m_elidedText = empty
    end

    AppItemTitleQML->>TitleLoader: active = enabled && elidedText.length > 0
    TitleLoader->>TitleContainer: Instantiate when active
    TitleContainer->>TextCalculator: optimalSingleTextWidth()
    TitleContainer->>TitleContainer: width = min(titleText.implicitWidth, optimalSingleTextWidth)
    TitleContainer->>TitleContainer: layer.enabled = titleText.implicitWidth > width + 1
    alt NeedsFadeOut
        TitleContainer->>OpacityMaskEffect: Apply horizontal gradient mask
    else FitsWithoutFade
        TitleContainer->>TitleContainer: clip = false (no fade)
    end
    TitleContainer->>User: Display title with smooth fade-out when truncated
Loading

Class diagram for updated TextCalculator truncation logic

classDiagram
    class TextCalculator {
        +QFont m_font
        +qreal optimalSingleTextWidth()
        +QFont font()
        +qreal calculateElidedTextWidth(QString text, qreal maxWidth)
        +QStringList getApplicationTitles()
    }

    class TextCalculatorAttached {
        -TextCalculator *m_calculator
        -QString m_text
        -QString m_elidedText
        +void updateElidedText()
        +QString text()
        +QString elidedText()
        +TextCalculator* calculator()
    }

    class canDisplayMinChars {
        +static bool canDisplayMinChars(QString text, QFontMetricsF fontMetrics, qreal maxWidth)
    }

    TextCalculatorAttached --> TextCalculator : uses
    TextCalculator ..> canDisplayMinChars : calls
    TextCalculatorAttached ..> canDisplayMinChars : calls
Loading

File-Level Changes

Change Details Files
Replace ellipsis-based elided title Text with a container using a gradient opacity mask for smooth fade-out and dynamic width.
  • Wrap the title Text in an Item container that controls width using TextCalculator.optimalSingleTextWidth and the text’s implicit width.
  • Enable a layer-based OpacityMask only when the text is wider than the available space, clipping content accordingly.
  • Define a mask Rectangle sized from measured ellipsis width and positioned at the right edge, with a horizontal gradient from opaque to transparent for fade-out.
  • Switch the displayed text binding from pre-elided text to the raw root.text and make the font fallback-safe when TextCalculator.calculator is absent.
panels/dock/taskmanager/package/AppItemTitle.qml
Change TextCalculator to stop producing elided strings and instead validate minimum visible characters and compute constrained width.
  • Replace the isValidElidedText helper with canDisplayMinChars, which checks that at least two characters can be rendered within maxWidth using QFontMetricsF.
  • Update calculateElidedTextWidth to return 0 when fewer than two characters fit, otherwise return the lesser of the full text width and maxWidth instead of an elided-text width.
  • Modify TextCalculatorAttached::updateElidedText to set elidedText to the full source text only when canDisplayMinChars passes, otherwise clear it, effectively treating elidedText as a visibility flag rather than modified content.
panels/dock/taskmanager/textcalculator.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

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The OpacityMask's maskSource rectangle is only sized to ellipsisMetrics.width/height, which likely means most of the text is fully masked out; consider matching the mask rectangle to titleContainer's full size and applying the gradient only on the trailing portion instead.
  • In AppItemTitle.qml, the fade gradient is hard-coded with opaque white (#FFFFFFFF), which may not behave as expected if the text color or background changes; you might want to derive the mask color from the actual text color or use an alpha-only mask to avoid theme-dependent artifacts.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `OpacityMask`'s `maskSource` rectangle is only sized to `ellipsisMetrics.width/height`, which likely means most of the text is fully masked out; consider matching the mask rectangle to `titleContainer`'s full size and applying the gradient only on the trailing portion instead.
- In `AppItemTitle.qml`, the fade gradient is hard-coded with opaque white (`#FFFFFFFF`), which may not behave as expected if the text color or background changes; you might want to derive the mask color from the actual text color or use an alpha-only mask to avoid theme-dependent artifacts.

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.

1. Modified TextCalculator to track truncation status and ellipsis width
2. Added gradient fade effect for truncated text instead of ellipsis
character
3. Changed minimum character count from 1 to 2 for better readability
4. Added new properties isTruncated and ellipsisWidth to
TextCalculatorAttached
5. Implemented OpacityMask with gradient for smooth text fade-out

Log: Improved task manager app title display with gradient fade effect
for truncated text

Influence:
1. Test app titles with varying lengths to ensure proper truncation
2. Verify gradient fade effect appears only when text is truncated
3. Check text alignment and positioning with the new fade effect
4. Test with both light and dark themes to ensure color compatibility
5. Verify minimum character count of 2 is respected in all cases
6. Test performance with multiple app items displaying truncated titles

fix: 改进文本截断效果,添加渐变淡出

1. 修改TextCalculator以跟踪截断状态和省略号宽度
2. 为截断文本添加渐变淡出效果替代省略号字符
3. 将最小字符数从1改为2以提高可读性
4. 向TextCalculatorAttached添加isTruncated和ellipsisWidth属性
5. 实现带渐变的OpacityMask以实现平滑的文本淡出效果

Log: 改进任务管理器应用标题显示,为截断文本添加渐变淡出效果

Influence:
1. 测试不同长度的应用标题以确保正确截断
2. 验证渐变淡出效果仅在文本被截断时出现
3. 检查新淡出效果下的文本对齐和定位
4. 测试浅色和深色主题以确保颜色兼容性
5. 验证在所有情况下都遵守最小2个字符的限制
6. 测试多个应用项目显示截断标题时的性能表现
@deepin-ci-robot
Copy link

deepin pr auto review

这份代码 diff 主要是为了实现一个功能:在任务栏应用标题过长被截断时,增加一个渐隐的视觉效果,而不是生硬地切断。同时修改了文本截断计算的最小字符限制。

以下是对该代码的审查意见,包括语法逻辑、代码质量、性能和安全方面的建议:

1. 语法与逻辑审查

  • QML 中的 Gradient 颜色硬编码:
    AppItemTitle.qml 中:

    GradientStop { position: 1; color: "#00FFFFFF" }
    GradientStop { position: 0.6; color: "#FFFFFFFF" }

    问题:颜色被硬编码为白色 (#FFFFFFFF)。如果用户主题是深色模式,文字颜色是白色,这没问题;但在浅色模式下,文字颜色是黑色 (#000000),这里的遮罩依然是白色渐变,会导致文字边缘看起来像是"变白"而不是"变透明"。
    建议:遮罩的渐变颜色应该始终使用带透明度的白色或黑色,且 OpacityMask 的工作原理是:不透明的地方显示源内容,透明的地方不显示。因此,这里应该使用纯色(如白色)配合透明度渐变,或者确保遮罩源的颜色逻辑正确。
    修正思路:通常 OpacityMask 的 maskSource 应该是 Alpha 通道的映射。如果使用 Gradient,应该确保颜色是从不透明(如 #FFFFFFFF)到全透明(#00FFFFFF)。原代码中 position: 0.6 是全不透明,position: 1 是全透明,逻辑上是通的。但是,为了适应不同的文字颜色,Mask 本身通常应该是基于 Alpha 的。如果 Gradient 用于 Rectangle 的颜色,且该 Rectangle 没有设置 visible: false 等属性,可能会影响渲染。建议确认 OpacityMask 的行为是否符合预期。
    具体改进:建议将颜色统一改为 #FFFFFFFF#00FFFFFF 的变化,利用 Alpha 通道控制透明度,而不是混合颜色值。

  • C++ 中的字符串替换逻辑:
    textcalculator.cpp 中:

    m_isTruncated = (m_text != newElidedText);
    emit isTruncatedChanged();
    newElidedText.replace(QString::fromUtf8(""), "");

    问题:这里先判断是否截断,然后移除了省略号 ()。这意味着 m_elidedText 最终保存的文本是不带省略号的截断文本。但在 QML 中使用 elidedText 时,通常期望看到省略号。如果 QML 层(AppItemTitle.qml)的 titleText 绑定的是这个 elidedText,那么用户将看不到省略号,只能看到文字突然消失(配合渐变效果)。如果这是预期设计(即用渐变代替省略号),则逻辑没问题;如果不是,则 replace 操作可能导致显示异常。
    建议:确认业务逻辑。如果目的是用 QML 的渐变效果替代 C++ 的省略号,那么这里移除省略号是正确的。但需确保 QML 中的 layer.effect 确实能正确渲染出"省略"的视觉效果。

  • C++ 中的字符数限制修改:

    // Iterate from 7 characters to 2 characters, finding the optimal solution
    for (; charCount >= 2; --charCount) {

    问题:将最小字符数从 1 改为 2。
    分析:这通常是为了避免显示过短的文本(如单个字符)导致布局难看或无意义。这是一个合理的业务逻辑调整,但需确保 UI 上能容纳至少 2 个字符,否则可能出现布局挤压。

2. 代码质量

  • 初始化列表与成员变量:
    textcalculator.h 中:

    qreal m_ellipsisWidth = 0.0;
    bool m_isTruncated = false;

    建议:使用了类内初始化(C++11特性),这是好的做法,保证了构造时的确定性。

  • 信号发射:
    textcalculator.cpp 中:

    if (!isValidElidedText(newElidedText)) {
        newElidedText = {};
    } else {
        // ...
        m_isTruncated = (m_text != newElidedText);
        emit isTruncatedChanged();
        // ...
    }
    // ...
    if (m_isTruncated) { ... }

    问题:代码逻辑稍显分散。m_isTruncated 的更新和信号发射在 else 块中,而 m_ellipsisWidth 的更新在后续的 if 块中。
    建议:可以将状态更新逻辑集中处理,减少代码跳跃,提高可读性。例如,先计算所有状态,再统一发射信号。

  • 硬编码字符串:

    newElidedText.replace(QString::fromUtf8(""), "");
    m_ellipsisWidth = fontMetrics.horizontalAdvance(QString::fromUtf8(""));

    建议:省略号字符 (U+2026) 出现了多次。建议定义为一个常量,例如 static const QLatin1String ellipsisChar = QLatin1String("…");,方便统一管理和修改。

3. 性能

  • QML Layer 开销:

    layer.enabled: root.TextCalculator.isTruncated
    layer.effect: OpacityMask { ... }

    分析layer.enabled 会触发离屏渲染,消耗一定的 GPU 资源。但在 Dock 这种场景下,通常只有鼠标悬停或特定操作时才会显示标题,且数量有限,性能影响可控。
    建议:确保 isTruncated 状态变化不频繁,避免频繁切换 layer.enabled 导致的闪烁或性能抖动。

  • 字符串操作:
    fontMetrics.elidedTexthorizontalAdvance 涉及字体计算,虽然开销不大,但在高频更新(如窗口快速切换大小)时需注意。目前的实现是在 updateElidedText 中调用,通常由属性变化触发,频率尚可接受。

4. 安全性

  • 空指针检查:

    if (!m_calculator) { ... }

    已经有了很好的空指针检查,安全性良好。

  • 数据一致性:
    updateElidedText 中,如果 newElidedText 无效被设为 {},此时 m_isTruncatedm_ellipsisWidth 不会被更新(因为进入了 if 分支而非 else)。这可能导致状态残留(例如之前是截断状态,现在文本无效变为空,但 isTruncated 可能仍为 true)。
    建议:在 if (!isValidElidedText(newElidedText)) 分支中,也应当重置 m_isTruncatedm_ellipsisWidth,确保状态与内容一致。

修改建议汇总代码示例

textcalculator.cpp 优化片段:

void TextCalculatorAttached::updateElidedText()
{
    if (!m_calculator) {
        qCDebug(textCalculatorLog) << "No calculator available for elided text update";
        m_elidedText.clear();
        m_ellipsisWidth = 0.0;
        m_isTruncated = false;
        emit elidedTextChanged();
        emit ellipsisWidthChanged();
        emit isTruncatedChanged();
        return;
    }

    // ... (获取 maxWidth 等前置代码)

    const QLatin1String ellipsisChar("...");
    QString newElidedText = fontMetrics.elidedText(m_text, Qt::ElideRight, maxWidth);
    
    // 重置状态
    bool newIsTruncated = false;
    qreal newEllipsisWidth = 0.0;

    if (!isValidElidedText(newElidedText)) {
        newElidedText = {};
    } else {
        newIsTruncated = (m_text != newElidedText);
        if (newIsTruncated) {
            // 如果需要移除省略号以配合QML渐变
            newElidedText.replace(ellipsisChar, "");
            newEllipsisWidth = fontMetrics.horizontalAdvance(ellipsisChar);
        }
    }
    
    // 批量更新状态并发射信号
    if (m_elidedText != newElidedText) {
        m_elidedText = newElidedText;
        emit elidedTextChanged();
    }
    if (m_isTruncated != newIsTruncated) {
        m_isTruncated = newIsTruncated;
        emit isTruncatedChanged();
    }
    if (m_ellipsisWidth != newEllipsisWidth) {
        m_ellipsisWidth = newEllipsisWidth;
        emit ellipsisWidthChanged();
    }
}

AppItemTitle.qml 优化片段:

layer.enabled: root.TextCalculator.isTruncated
layer.effect: OpacityMask {
    maskSource: Rectangle {
        width: root.TextCalculator.ellipsisWidth > 0 ? root.TextCalculator.ellipsisWidth : 0
        height: titleText.height
        // 使用纯色配合透明度,确保只影响Alpha通道
        gradient: Gradient {
            orientation: Gradient.Horizontal
            GradientStop { position: 0.0; color: "#FFFFFFFF" } // 完全不透明(显示文字)
            GradientStop { position: 1.0; color: "#00FFFFFF" } // 完全透明(隐藏文字)
        }
    }
}

(注:Gradient 的 position 范围和具体颜色值需根据实际 UI 效果微调,上述代码仅示意逻辑)

}

if (m_isTruncated) {
m_ellipsisWidth = fontMetrics.horizontalAdvance(QString::fromUtf8("…"));
Copy link
Contributor

Choose a reason for hiding this comment

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

m_ellipsisWidth = maxWidth - 当前需要正常显示的字符的长度,
显示的字符 = 正常显示的字符 + 需要渐变的长度(例如省略号的长度),

newElidedText = {};
} else {
m_isTruncated = (m_text != newElidedText);
emit isTruncatedChanged();
Copy link
Contributor

Choose a reason for hiding this comment

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

这个加个判断来是否触发信号,

qCDebug(textCalculatorLog) << "No calculator available for elided text update";
m_elidedText.clear();
m_ellipsisWidth = 0.0;
m_isTruncated = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

m_ellipsisWidth 不为0是不是就是m_isTruncated

@18202781743
Copy link
Contributor

例如,现在能正常显示三个字符,当前应用为五个字符,那应该是第四个汉字开始渐隐吧,而不是第三个就开始了,能够显示的文本是四个字符或者更多,

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants