Skip to content

fix(editor): enhance inertial scrolling with improved speed calculation#458

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
pppanghu77:release/eagle
May 6, 2026
Merged

fix(editor): enhance inertial scrolling with improved speed calculation#458
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
pppanghu77:release/eagle

Conversation

@pppanghu77
Copy link
Copy Markdown
Contributor

@pppanghu77 pppanghu77 commented May 6, 2026

  • Add inertial scrolling constants (MAX_INERTIAL_SPEED, MAX_INERTIAL_DURATION, INERTIAL_SPEED_MULTIPLIER, MAX_IDLE_TIME)
  • Replace per-move speed calculation with accumulated distance/time tracking for more accurate overall velocity
  • Implement idle time check to prevent inertia after pauses
  • Add duration limiting to maximum 2 seconds for better UX
  • Calculate average speeds based on total distance over total time
  • Apply font-based speed adjustment and log final parameters
  • Reset accumulation variables after releasing mouse button

Log: fix(editor): enhance inertial scrolling with improved speed calculation
Bug: https://pms.uniontech.com/bug-view-359379.html

Summary by Sourcery

Improve editor inertial scrolling behavior by basing inertia on accumulated movement metrics and enforcing limits for speed, duration, and idle time.

Bug Fixes:

  • Prevent unintended inertial scrolling when there is a pause before releasing the mouse button.

Enhancements:

  • Introduce configurable constants to cap inertial scroll speed, duration, and idle time for more controllable scrolling behavior.
  • Compute inertial scroll velocity from total drag distance and duration for smoother, more accurate inertia across X and Y axes.
  • Adjust inertial scroll speed based on font size and scale distance when duration is clamped, and reset accumulated state after each gesture.
  • Add logging of computed inertial scroll parameters to aid debugging and tuning.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 6, 2026

Reviewer's Guide

Refines the editor’s inertial scrolling by switching from per-move speed estimation to accumulated distance/time averaging, introducing configurable limits on speed and duration, adding idle-time checks to suppress unwanted inertia, and resetting new tracking state on mouse release.

Sequence diagram for the updated inertial scrolling on mouse release

sequenceDiagram
    actor User
    participant TextEdit
    participant TweenX
    participant TweenY

    User->>TextEdit: mousePressEvent
    activate TextEdit
    TextEdit-->>User: start slide gesture

    loop while dragging
        User->>TextEdit: mouseMoveEvent
        TextEdit->>TextEdit: update m_endX m_endY
        TextEdit->>TextEdit: compute diffXpos diffYpos diffTimeX diffTimeY
        TextEdit->>TextEdit: slideGestureX slideGestureY (realtime follow)
        TextEdit->>TextEdit: m_totalDistanceX += diffXpos
        TextEdit->>TextEdit: m_totalDistanceY += diffYpos
        TextEdit->>TextEdit: m_totalDurationX += diffTimeX
        TextEdit->>TextEdit: m_totalDurationY += diffTimeY
        TextEdit->>TextEdit: m_moveCount++
        TextEdit->>TextEdit: update m_lastMouseTimeY
    end

    User->>TextEdit: mouseReleaseEvent
    TextEdit->>TextEdit: check m_gestureAction == GA_slide
    TextEdit->>TextEdit: timeSinceLastMove = timestamp - m_lastMouseTimeY
    alt timeSinceLastMove < MAX_IDLE_TIME and m_moveCount > 0 and durations > 0
        TextEdit->>TextEdit: avgSpeedY = m_totalDistanceY / m_totalDurationY
        TextEdit->>TextEdit: avgSpeedX = m_totalDistanceX / m_totalDurationX
        TextEdit->>TextEdit: apply INERTIAL_SPEED_MULTIPLIER to avgSpeedY
        TextEdit->>TextEdit: clamp speeds to [-MAX_INERTIAL_SPEED, MAX_INERTIAL_SPEED]
        TextEdit->>TextEdit: compute durationY durationX (sqrt based)
        TextEdit->>TextEdit: cap durations by MAX_INERTIAL_DURATION
        TextEdit->>TextEdit: adjust speeds by font size
        TextEdit->>TextEdit: compute changeY changeX
        TextEdit->>TextEdit: log inertial parameters
        TextEdit->>TweenX: startX(0 0 changeX durationX callback)
        TextEdit->>TweenY: startY(0 0 changeY durationY callback)
    else no valid inertia
        TextEdit-->>User: no inertial scroll
    end
    TextEdit->>TextEdit: reset m_totalDistance* m_totalDuration* m_moveCount
    TextEdit->>TextEdit: m_gestureAction = GA_null
    deactivate TextEdit
Loading

Updated class diagram for TextEdit inertial scrolling members

classDiagram
    class TextEdit {
        // inertial state
        ulong m_lastMouseTimeY
        qreal m_stepSpeedY
        qreal m_stepSpeedX
        qreal m_totalDistanceY
        qreal m_totalDistanceX
        ulong m_totalDurationY
        ulong m_totalDurationX
        int m_moveCount

        // event handlers
        void mouseMoveEvent(QMouseEvent *e)
        void mouseReleaseEvent(QMouseEvent *e)

        // scrolling helpers
        void slideGestureX(qreal delta)
        void slideGestureY(qreal delta)
    }

    class InertialConfig {
        <<static>> qreal MAX_INERTIAL_SPEED
        <<static>> qreal MAX_INERTIAL_DURATION
        <<static>> qreal INERTIAL_SPEED_MULTIPLIER
        <<static>> ulong MAX_IDLE_TIME
    }

    TextEdit .. InertialConfig : uses
Loading

File-Level Changes

Change Details Files
Introduce shared inertial scrolling configuration constants and remove the per-event MAX_INERTIAL_SPEED definition.
  • Define MAX_INERTIAL_SPEED, MAX_INERTIAL_DURATION, INERTIAL_SPEED_MULTIPLIER, and MAX_IDLE_TIME at the top of dtextedit.cpp for global use within the file.
  • Remove the local MAX_INERTIAL_SPEED constant from mouseMoveEvent in favor of the new shared constant.
src/editor/dtextedit.cpp
Change inertial velocity computation from per-move instantaneous speed to accumulated distance and time tracking during drag.
  • During mouseMoveEvent, continue performing real-time slideGestureX/slideGestureY updates for visual tracking.
  • Accumulate total scroll deltas and elapsed times (m_totalDistanceX/Y, m_totalDurationX/Y) and increment m_moveCount on each move instead of calculating step speed and duration per event.
  • Remove the previous per-move calculations of m_stepSpeedX/Y, inertia duration, and distance within mouseMoveEvent.
src/editor/dtextedit.cpp
Rework mouseRelease inertial start logic to use averaged speed, enforce idle/debounce handling, and cap inertia duration.
  • On mouse release in GA_slide, compute time since last move and skip inertia if it exceeds MAX_IDLE_TIME or if there is insufficient movement/time data.
  • Compute average X/Y speeds from total distance over total duration, apply an INERTIAL_SPEED_MULTIPLIER on Y, clamp speeds to ±MAX_INERTIAL_SPEED, and derive inertia durations from the square root of the speed.
  • Cap inertia durations by MAX_INERTIAL_DURATION and proportionally scale the computed scroll distances when capping occurs to preserve perceived speed.
  • Adjust speeds by font size, compute final changeX/changeY, log the inertial scroll parameters with qWarning, and start tweenX/tweenY animations with the new change and duration values.
  • Reset all accumulation fields (m_totalDistanceX/Y, m_totalDurationX/Y, m_moveCount) after handling inertia to prepare for the next gesture.
src/editor/dtextedit.cpp
Add state to track cumulative inertial gesture metrics in the TextEdit class.
  • Declare new members m_totalDistanceX/Y, m_totalDurationX/Y, and m_moveCount in TextEdit to store accumulated motion metrics across the drag.
  • Initialize these new members with default values and rely on mouseReleaseEvent to clear them at the end of each inertial gesture.
src/editor/dtextedit.h

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
Copy Markdown

@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 found 1 issue, and left some high level feedback:

  • The inertia trigger condition m_totalDurationY > 0 && m_totalDurationX > 0 in mouseReleaseEvent prevents inertial scrolling when the user scrolls only vertically or only horizontally; consider allowing inertia when either axis has valid movement.
  • The Y-axis average speed is scaled by INERTIAL_SPEED_MULTIPLIER while the X-axis speed is not, which may lead to inconsistent inertial feel between axes; consider applying the multiplier consistently or documenting the intentional asymmetry.
  • The new qWarning() log for every inertial scroll start may be too noisy in normal use; consider downgrading it to a debug-level log or guarding it behind a verbosity flag.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The inertia trigger condition `m_totalDurationY > 0 && m_totalDurationX > 0` in `mouseReleaseEvent` prevents inertial scrolling when the user scrolls only vertically or only horizontally; consider allowing inertia when either axis has valid movement.
- The Y-axis average speed is scaled by `INERTIAL_SPEED_MULTIPLIER` while the X-axis speed is not, which may lead to inconsistent inertial feel between axes; consider applying the multiplier consistently or documenting the intentional asymmetry.
- The new `qWarning()` log for every inertial scroll start may be too noisy in normal use; consider downgrading it to a debug-level log or guarding it behind a verbosity flag.

## Individual Comments

### Comment 1
<location path="src/editor/dtextedit.cpp" line_range="6872" />
<code_context>
     //add for single refers to the sliding
     if (e->type() == QEvent::MouseButtonRelease && e->source() == Qt::MouseEventSynthesizedByQt) {
         if (m_gestureAction == GA_slide) {
+            // 检查最后一次移动到现在的时差,如果太长说明有停顿,不触发惯性
+            ulong timeSinceLastMove = e->timestamp() - m_lastMouseTimeY;
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the shared inertia math and state checks into reusable helpers to simplify mouseReleaseEvent and avoid duplicated per-axis logic.

You can keep all current behavior but reduce complexity and duplication by extracting the per-axis math and the trigger condition into helpers.

### 1. Extract per-axis inertia calculation

All the speed/duration/distance math for X/Y is nearly identical. Move it into a single pure helper:

```cpp
struct InertiaAxisResult {
    qreal distance = 0.0;
    qreal duration = 0.0;
};

static InertiaAxisResult computeInertiaAxis(qreal totalDistance,
                                            qreal totalDuration,
                                            qreal fontPointSize,
                                            bool amplifySpeed)
{
    if (totalDuration <= 0)
        return {};

    qreal avgSpeed = totalDistance / totalDuration;
    if (amplifySpeed)
        avgSpeed *= INERTIAL_SPEED_MULTIPLIER;

    avgSpeed = qBound(-MAX_INERTIAL_SPEED, avgSpeed, MAX_INERTIAL_SPEED);

    qreal duration = std::sqrt(std::abs(avgSpeed)) * 1000;
    const qreal originalDuration = duration;
    duration = std::min(duration, MAX_INERTIAL_DURATION);

    qreal adjustedSpeed = avgSpeed / std::sqrt(fontPointSize * 4.0);
    qreal distance = adjustedSpeed * std::sqrt(std::abs(adjustedSpeed)) * 100;

    if (duration < originalDuration && originalDuration > 0.0)
        distance *= (duration / originalDuration);

    return { distance, duration };
}
```

Usage in `mouseReleaseEvent`:

```cpp
if (m_gestureAction == GA_slide) {
    const ulong timeSinceLastMove = e->timestamp() - m_lastMouseTimeY;

    if (shouldTriggerInertia(timeSinceLastMove)) {
        const QFont font = this->font();
        const qreal fontPt = font.pointSizeF();

        InertiaAxisResult y = computeInertiaAxis(m_totalDistanceY, m_totalDurationY,
                                                 fontPt, /*amplifySpeed=*/true);
        InertiaAxisResult x = computeInertiaAxis(m_totalDistanceX, m_totalDurationX,
                                                 fontPt, /*amplifySpeed=*/false);

        qWarning() << "Inertial scroll started - Y: duration=" << y.duration
                   << "ms, distance=" << y.distance
                   << "px | X: duration=" << x.duration
                   << "ms, distance=" << x.distance << "px";

        tweenX.startX(0, 0, x.distance, x.duration,
                      std::bind(&TextEdit::slideGestureX, this, std::placeholders::_1));
        tweenY.startY(0, 0, y.distance, y.duration,
                      std::bind(&TextEdit::slideGestureY, this, std::placeholders::_1));
    }

    resetInertiaAccumulation();
    m_gestureAction = GA_null;
}
```

This removes the duplicated speed/duration/distance code and makes future tuning much less error-prone.

### 2. Extract the trigger condition and reset logic

The inline condition:

```cpp
if (timeSinceLastMove < MAX_IDLE_TIME && m_moveCount > 0 &&
    m_totalDurationY > 0 && m_totalDurationX > 0) {
    ...
}
```

can be named and reused:

```cpp
bool TextEdit::shouldTriggerInertia(ulong timeSinceLastMove) const
{
    return timeSinceLastMove < MAX_IDLE_TIME
        && m_moveCount > 0
        && m_totalDurationY > 0
        && m_totalDurationX > 0;
}

void TextEdit::resetInertiaAccumulation()
{
    m_totalDistanceY = 0.0;
    m_totalDistanceX = 0.0;
    m_totalDurationY = 0;
    m_totalDurationX = 0;
    m_moveCount = 0;
}
```

This keeps `mouseReleaseEvent` focused on control flow (press → maybe inertia → reset) instead of mixing it with detailed math and state management, while preserving all existing functionality.
</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/editor/dtextedit.cpp
- Add inertial scrolling constants (MAX_INERTIAL_SPEED,
  MAX_INERTIAL_DURATION, INERTIAL_SPEED_MULTIPLIER, MAX_IDLE_TIME)
- Replace per-move speed calculation with accumulated distance/time
  tracking for more accurate overall velocity
- Implement idle time check to prevent inertia after pauses
- Add duration limiting to maximum 2 seconds for better UX
- Calculate average speeds based on total distance over total time
- Apply font-based speed adjustment and log final parameters
- Reset accumulation variables after releasing mouse button

Log: fix(editor): enhance inertial scrolling with improved speed calculation
Bug: https://pms.uniontech.com/bug-view-359379.html
@pppanghu77
Copy link
Copy Markdown
Contributor Author

deepin pr auto review

这份代码修改主要针对文本编辑器的触摸板/触摸屏惯性滑动功能进行了重构。从"基于单次移动计算"改为"基于整体滑动累加计算",这是一个更符合物理直觉的改进。

以下是对该代码变更的详细审查意见,分为语法逻辑、代码质量、代码性能和代码安全四个方面:

1. 语法逻辑

  • 变量初始化与作用域

    • 问题:在 mouseReleaseEvent 中,计算惯性参数时使用了 m_totalDurationYm_totalDurationX,并且检查了它们 > 0。但在 mouseMoveEvent 中,仅当 m_gestureAction == GA_slide 时才累加这些值。如果用户只是轻微点击(未触发滑动判定),这些值可能保持为0。
    • 改进:逻辑上目前的判断 if (timeSinceLastMove < MAX_IDLE_TIME && m_moveCount > 0 ...) 已经比较完善,能避免除零错误。但需确保 m_gestureAction 状态机转换逻辑正确,防止在非滑动状态下意外累加数据。
  • 计算逻辑

    • 观察:代码使用 sqrt(abs(speed)) * 1000 来计算持续时间,使用 speed * sqrt(abs(speed)) * 100 来计算滑动距离。这种非线性关系是为了模拟摩擦力产生的减速效果。
    • 潜在问题avgSpeedY 的计算是 总距离 / 总时间,这是平均速度。然而,惯性滑动的初始速度通常应该是释放瞬间的瞬时速度。使用平均速度会抹平快速滑动过程中的速度峰值,导致"快速甩动"时的惯性效果不如预期强烈。
    • 建议:考虑在 mouseMoveEvent 中记录最后几次移动的瞬时速度,或者在释放时使用 (diffYpos / diffTimeY) 作为初始速度,而不是全程的平均速度。目前的修改虽然平滑,但可能会让惯性感觉"发肉"。

2. 代码质量

  • 魔法数字

    • 改进:你将 MAX_INERTIAL_SPEED 等常量提取到了文件顶部,这非常好。
    • 遗留:代码中仍存在一些魔法数字,例如 sqrt(font.pointSize() * 4.0) 中的 4.0,以及计算距离时的 100。建议将这些定义为常量(如 FONT_SIZE_FACTORDISTANCE_FACTOR),以便于后续调优。
  • 代码重复

    • 问题:X轴和Y轴的计算逻辑完全一致,代码存在大量重复(计算速度、限制范围、计算时长、计算距离、调整距离)。
    • 建议:可以提取一个私有辅助函数 calculateInertialParams(qreal totalDistance, ulong totalDuration, qreal& outChange, qreal& outDuration) 来封装这些逻辑,减少代码冗余,降低维护成本。
  • 调试日志

    • 问题:使用了 qWarning() 输出惯性滑动参数。
    • 建议qWarning 通常用于输出警告或错误信息。对于这种常规的调试信息,建议使用 qDebug() 并配合 QT_NO_DEBUG_OUTPUT 宏控制,或者使用专门的日志系统,避免在 Release 版本或用户环境中刷屏。

3. 代码性能

  • 除法运算

    • mouseMoveEvent 中,每次移动都进行了多次除法运算(diffYpos / diffTimeY 等)。虽然鼠标/触摸事件频率不是特别高,但这仍是相对昂贵的操作。
    • 现状:新代码在 mouseMoveEvent 中只做了加法,将除法移到了 mouseReleaseEvent。这是一个非常好的优化,减少了高频事件中的计算量。
  • 数学库函数

    • sqrt 调用次数合理,没有明显的性能瓶颈。

4. 代码安全

  • 除零保护

    • 旧代码使用了 + 0.000001 来防止除零。
    • 新代码通过 m_totalDurationY > 0 的前置检查避免了除零,逻辑更严谨,安全性更好。
  • 数值溢出

    • m_totalDistanceY/X 使用 qreal(通常为 double),m_totalDurationY/X 使用 ulong。在极长时间的拖动下,ulong 可能会溢出。
    • 风险评估:考虑到 MAX_IDLE_TIME 限制为 50ms,且 ulong 范围很大,正常用户操作很难触发溢出。但为了绝对安全,建议在累加前检查溢出,或者重置累加器时不仅是在 mouseReleaseEvent,也可以在检测到长时间停顿时重置。
  • 状态重置

    • 问题:累加变量(m_totalDistanceY 等)仅在 mouseReleaseEvent 中重置。如果发生异常情况导致 mouseReleaseEvent 没有被正确触发(例如被父组件拦截或窗口意外销毁),下次滑动时会使用脏数据。
    • 建议:在 mousePressEvent 开始新的一次交互时,也应重置这些累加变量,确保每次交互状态干净。

总结与修改建议

代码整体逻辑清晰,性能优化得当(将除法移至释放事件),安全性较好。主要改进点在于消除代码重复和优化物理计算模型。

建议修改后的伪代码片段(辅助函数封装):

// 在 dtextedit.h 中声明辅助函数
private:
    void calculateInertia(qreal totalDist, ulong totalDur, qreal &outChange, qreal &outDuration);

// 在 dtextedit.cpp 中实现
void TextEdit::calculateInertia(qreal totalDist, ulong totalDur, qreal &outChange, qreal &outDuration) {
    if (totalDur == 0) return; // 安全检查

    static const qreal FONT_FACTOR = 4.0;
    static const qreal DISTANCE_FACTOR = 100.0;
    
    qreal speed = totalDist / totalDur;
    speed *= INERTIAL_SPEED_MULTIPLIER;
    speed = qBound(-MAX_INERTIAL_SPEED, speed, MAX_INERTIAL_SPEED);

    qreal duration = sqrt(abs(speed)) * 1000;
    qreal originalDuration = duration;
    duration = qMin(duration, MAX_INERTIAL_DURATION);

    QFont font = this->font();
    qreal adjustedSpeed = speed / sqrt(font.pointSize() * FONT_FACTOR);
    outChange = adjustedSpeed * sqrt(abs(adjustedSpeed)) * DISTANCE_FACTOR;
    
    if (duration < originalDuration) {
        outChange *= (duration / originalDuration);
    }
    
    outDuration = duration;
}

// 在 mouseReleaseEvent 中调用
if (...) {
    qreal changeY, durationY, changeX, durationX;
    calculateInertia(m_totalDistanceY, m_totalDurationY, changeY, durationY);
    calculateInertia(m_totalDistanceX, m_totalDurationX, changeX, durationX);

    // 日志输出...
    // 启动动画...
}

额外建议: 在 mousePressEvent 中添加重置逻辑:

void TextEdit::mousePressEvent(QMouseEvent *e) {
    // ... 原有代码 ...
    
    // 重置惯性累加器,防止上次数据污染
    m_totalDistanceY = 0;
    m_totalDistanceX = 0;
    m_totalDurationY = 0;
    m_totalDurationX = 0;
    m_moveCount = 0;
    
    // ...
}

暂不需要,目前只有触控在使用这部分逻辑

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

代码审查意见

1. 语法和逻辑

1.1 变量初始化

  • 在头文件中,成员变量初始化使用了花括号语法 = {0.0},这是C++11特性,建议保持一致,但也可以使用 = 0.0 更简洁
  • 建议检查 m_totalDurationYm_totalDurationX 的类型是否合适,使用 ulong 可能导致溢出,考虑使用 qint64quint64

1.2 惯性滑动逻辑

  • 代码中计算惯性滑动速度时使用了累加方式,但未考虑滑动方向变化的情况。如果用户快速来回滑动,可能导致计算出的平均速度不准确
  • 建议添加方向变化的检测和处理逻辑

1.3 时间戳比较

ulong timeSinceLastMove = e->timestamp() - m_lastMouseTimeY;
  • 这行代码可能导致整数溢出,如果 e->timestamp() 小于 m_lastMouseTimeY(例如时间戳回绕)
  • 建议添加溢出检查或使用更安全的时间差计算方式

2. 代码质量

2.1 魔法数字

  • 代码中存在多个魔法数字,如 10004.0100
  • 建议将这些常量定义为有意义的命名常量,提高代码可读性

2.2 日志级别

qWarning() << "Inertial scroll started - Y: speed=" << avgSpeedY << "px/ms, duration=" << durationY << "ms, distance=" << changeY << "px | X: speed=" << avgSpeedX << "px/ms, duration=" << durationX << "ms, distance=" << changeX << "px";
  • 使用 qWarning() 输出调试信息不太合适,建议使用 qDebug() 或条件编译的调试输出

2.3 代码重复

  • Y轴和X轴的惯性计算逻辑几乎完全相同,存在大量重复代码
  • 建议提取为通用函数,减少重复

3. 代码性能

3.1 不必要的计算

qreal originalDurationY = durationY;
durationY = qMin(durationY, MAX_INERTIAL_DURATION);
// ...
if (durationY < originalDurationY) {
    changeY *= (durationY / originalDurationY);
}
  • 这段逻辑可以简化,直接计算调整后的距离,无需保存原始值再比较

3.2 频繁的数学计算

  • 代码中多次使用 sqrt()abs() 计算,考虑是否可以缓存或优化

4. 代码安全

4.1 边界检查

if (timeSinceLastMove < MAX_IDLE_TIME && m_moveCount > 0 && m_totalDurationY > 0 && m_totalDurationX > 0) {
  • 检查了 m_totalDurationYm_totalDurationX 大于0,但未检查它们是否过大可能导致除法结果异常
  • 建议添加最大值检查

4.2 类型转换

qreal avgSpeedY = static_cast<qreal>(m_totalDistanceY) / static_cast<qreal>(m_totalDurationY);
  • 虽然使用了显式类型转换,但未检查 m_totalDurationY 是否为0(虽然前面有检查,但为了健壮性可以再检查一次)

5. 改进建议

5.1 提取惯性计算为独立函数

struct InertialParams {
    qreal speed;
    qreal duration;
    qreal distance;
};

InertialParams calculateInertialParams(qreal totalDistance, ulong totalDuration, const QFont &font) {
    InertialParams params;
    // 计算逻辑...
    return params;
}

5.2 添加方向变化检测

// 在累加距离前检查方向变化
if ((m_totalDistanceY * diffYpos) < 0) {
    // 方向改变,重置累加值
    m_totalDistanceY = 0;
    m_totalDurationY = 0;
}
m_totalDistanceY += diffYpos;

5.3 优化时间差计算

// 使用更安全的时间差计算
qint64 timeSinceLastMove = static_cast<qint64>(e->timestamp()) - static_cast<qint64>(m_lastMouseTimeY);
if (timeSinceLastMove < 0) {
    // 处理时间戳回绕情况
    timeSinceLastMove += ULONG_MAX; // 或其他适当的处理
}

5.4 使用常量替代魔法数字

static const qreal INERTIAL_DISTANCE_FACTOR = 100.0;
static const qreal FONT_ADJUSTMENT_FACTOR = 4.0;
static const qreal TIME_SCALE_FACTOR = 1000.0;

总结

这段代码实现了文本编辑器的惯性滑动功能,整体逻辑基本正确,但在边界条件处理、代码复用和性能优化方面还有改进空间。建议主要关注以下几点:

  1. 添加更全面的边界检查和溢出处理
  2. 提取重复代码为独立函数
  3. 使用命名常量替代魔法数字
  4. 考虑滑动方向变化的情况
  5. 优化日志输出方式

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: max-lvs, pppanghu77

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

@pppanghu77
Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot
Copy link
Copy Markdown
Contributor

deepin-bot Bot commented May 6, 2026

This pr force merged! (status: unstable)

@deepin-bot deepin-bot Bot merged commit 0cd12fb into linuxdeepin:release/eagle May 6, 2026
21 of 22 checks passed
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