Skip to content

fix(shot): clamp resized capture area to annotations - #942

Open
dengzhongyuan365-dev wants to merge 2 commits into
linuxdeepin:masterfrom
dengzhongyuan365-dev:newfeat-1008
Open

dengzhongyuan365-dev wants to merge 2 commits into
linuxdeepin:masterfrom
dengzhongyuan365-dev:newfeat-1008

Conversation

@dengzhongyuan365-dev

@dengzhongyuan365-dev dengzhongyuan365-dev commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

fix(shot): keep annotations inside screen while dragging
fix(shot): clamp resized capture area to annotations

Summary by Sourcery

Keep screenshot selections and annotations aligned by constraining selection resizing, expanding selections around edited content, and correcting annotation rendering offsets.

New Features:

  • Keep screenshot annotations within the screen and automatically expand the capture area when editing causes annotations to extend beyond it.
  • Support resizing the capture area during annotation editing while preserving existing annotation positions and preventing text-edit conflicts.

Bug Fixes:

  • Prevent annotations from being clipped or misaligned when the capture area is resized or screenshots are saved, including Treeland captures.
  • Preserve annotation-specific cursors and mouse interaction while editing and resizing the capture area.

Enhancements:

  • Centralize annotation geometry tracking and enforce annotation-aware selection bounds across drawing, dragging, resizing, rotation, and text editing.
  • Improve annotation movement constraints and screenshot rendering so saved images include only correctly positioned annotation content.

Tests:

  • Add unit coverage for expanding the capture area around annotations and preserving their screen position during left-side expansion.
  • Update paint coverage tests for the extended annotation rendering interface.

Clamp screenshot selection resizing by existing annotation bounds.

根据已有标注外接矩形限制截图选区缩放范围。

Log: 修复编辑后缩放选区裁剪标注
PMS: TASK-393987
Influence: 截图编辑后缩小选区时,边界不会越过已有标注外接矩形,避免保存结果裁剪标注内容。
Clamp shape dragging by its painted bounds and keep resize cursor stable.

拖动标注时按外接矩形限制屏幕边界,并稳定拉伸光标状态。

Log: 修复全屏下标注拖动越界和拉伸光标异常
PMS: TASK-393987
Influence: 全屏截图编辑时标注不会在拖动后越出屏幕,拉伸标注时光标状态正确;未满屏时仍可扩张选区。
@sourcery-ai

sourcery-ai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR reworks screenshot edit-mode event routing and geometry synchronization so capture-area resizing cannot clip existing annotations, while annotation edits can expand the selection within screen limits. It also adjusts annotation export offsets/scaling for Treeland and adds focused regression tests for expansion and coordinate preservation.

Sequence diagram for annotation-aware capture-area resizing

sequenceDiagram
    participant User
    participant MainWindow
    participant ShapesWidget

    User->>MainWindow: MouseButtonPress
    MainWindow->>MainWindow: getAction
    MainWindow->>MainWindow: shapesContentBoundingRectInWindow
    MainWindow->>MainWindow: constrainSelectionToShapes
    User->>MainWindow: MouseMove
    MainWindow->>MainWindow: resizeTop/resizeBottom/resizeLeft/resizeRight
    MainWindow->>MainWindow: constrainSelectionToShapes
    MainWindow->>MainWindow: translateShapesForSelectionResize
    MainWindow->>ShapesWidget: translateContents
    MainWindow->>MainWindow: updateSelectionRelatedWidgets
    User->>MainWindow: MouseButtonRelease
    MainWindow->>MainWindow: constrainSelectionToShapes
    MainWindow->>MainWindow: updateSelectionRelatedWidgets
Loading

Sequence diagram for annotation edits expanding the capture area

sequenceDiagram
    participant User
    participant ShapesWidget
    participant MainWindow

    User->>ShapesWidget: MouseMove
    ShapesWidget->>ShapesWidget: handleDrag
    ShapesWidget-->>MainWindow: contentsGeometryChanged
    MainWindow->>MainWindow: expandSelectionToContents
    MainWindow->>MainWindow: shapesContentBoundingRectInWindow
    MainWindow->>ShapesWidget: translateContents
    MainWindow->>MainWindow: updateSelectionRelatedWidgets
Loading

File-Level Changes

Change Details Files
Routes edit-mode mouse handling through MainWindow and clamps capture-area resizing around existing annotations.
  • Installs an event filter on ShapesWidget and selectively bypasses Treeland’s global filter behavior.
  • Uses window/global coordinates for resize hit testing and cursor handling.
  • Adds per-edge and final-pass constraints for minimum size, screen bounds, and annotation bounds.
  • Locks the annotation bounds during a resize and translates local annotation coordinates when the selection’s top or left edge moves.
  • Synchronizes the selection frame, toolbar, sidebar, size tips, and repaint state during resizing.
src/main_window.cpp
src/main_window.h
Tracks annotation geometry and automatically expands the selection when edits exceed its current bounds.
  • Computes padded content bounds for persisted, selected, hovered, and in-progress shapes.
  • Emits geometry-change notifications during drawing, moving, resizing, rotating, text resizing, pinch gestures, and micro-adjustments.
  • Expands the selection monotonically to contain annotations while respecting the screen boundary.
  • Constrains dragged annotations to the ShapesWidget’s available area.
  • Normalizes override-cursor updates to avoid redundant or invalid cursor changes.
src/widgets/shapeswidget.cpp
src/widgets/shapeswidget.h
Preserves annotation placement and crop correctness when exporting screenshots, including Treeland captures.
  • Crops Treeland capture frames using the intersection of the selection and capture region.
  • Passes image-origin offsets and pixel scale when painting annotations into the saved image.
  • Exports annotation content without selection or hover controls.
src/main_window.cpp
src/widgets/shapeswidget.cpp
src/widgets/shapeswidget.h
Adds regression coverage for selection expansion and updates paint-helper tests for the revised API.
  • Verifies right-side expansion, left-side expansion with stable screen coordinates, and idempotence.
  • Updates private accessors and calls for the new handlePaint signature.
tests/ut_screen_shot_recorder/ut_main_window_ef.h
tests/ut_screen_shot_recorder/widgets/ut_shapeswidget_paint_cov.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

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengzhongyuan365-dev

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 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 4 issues

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

## Individual Comments

### Comment 1
<location path="src/main_window.cpp" line_range="7601-7608" />
<code_context>
+            const QRect sourceRegion = context->captureRegion().toRect();
+            imageTopLeftInWindow = sourceRegion.topLeft();
+            const QRect currentRegion(recordX, recordY, recordWidth, recordHeight);
+            QRect cropRectInWindow = currentRegion.intersected(sourceRegion);
+            if (!cropRectInWindow.isEmpty()) {
+                imageTopLeftInWindow = cropRectInWindow.topLeft();
+                QRect cropRect = cropRectInWindow;
+                cropRect.translate(-sourceRegion.topLeft());
+                cropRect = cropRect.intersected(QRect(QPoint(0, 0), backgroundImage.size()));
+                if (!cropRect.isEmpty()) {
+                    saveImage = backgroundImage.copy(cropRect);
+                }
+            }
</code_context>
<issue_to_address>
**Saved images clip annotation content**

When a selection or annotation extends beyond Treeland’s original capture region, `paintImage` crops to the intersection with the original `captureRegion`, so content outside that region is omitted from the saved image.

Extend or refresh the source capture region before cropping so it covers the full selection and its annotations.

Also at `src/widgets/shapeswidget.cpp:1350-1361`.
</issue_to_address>

### Comment 2
<location path="src/main_window.cpp" line_range="5183-5185" />
<code_context>
         return DWidget::eventFilter(obj,event);

     bool needRepaint = false;
+    if (isShapesWidgetObject && !isMouseEvent) {
+        return false;
+    }

 #undef KeyPress
</code_context>
<issue_to_address>
**Shift resizing stops working**

When the ShapesWidget has focus and the user holds Shift while drawing or resizing an annotation, `eventFilter` returns before calling `keyPressEF` for ShapesWidget events, so `m_isShiftPressed` is never updated and ShapesWidget's key handler does not handle Shift; users cannot draw or resize annotations proportionally while holding Shift.

Keep routing Shift press and release events through the MainWindow handlers before allowing unhandled key events to reach ShapesWidget.
</issue_to_address>

### Comment 3
<location path="src/main_window.cpp" line_range="5304-5305" />
<code_context>
+        return;
+    }
+
+    m_shapesWidget->setFixedSize(qMax(recordWidth - 4, 1), qMax(recordHeight - 4, 1));
+    m_shapesWidget->move(recordX + 2, recordY + 2);
+
+    QRect t_rect(recordX, recordY, recordWidth, recordHeight);
</code_context>
<issue_to_address>
**Annotations shift during Treeland resizing**

When selection geometry is updated in Treeland mode after annotations have been created, `updateShapesWidgetGeometry` moves the ShapesWidget to `recordX + 2, recordY + 2`, although Treeland initially places it at the capture region’s exact origin. Existing annotation coordinates therefore shift relative to the captured content.

Preserve the widget’s original coordinate origin when updating its geometry, or compensate for the initial offset.
</issue_to_address>

### Comment 4
<location path="src/widgets/shapeswidget.cpp" line_range="307-311" />
<code_context>
+        bottom = qMax(bottom, point.y());
+    };
+
+    if (hasMainPoint) {
+        for (const QPointF &point : shape.mainPoints) {
+            unitePoint(point);
+        }
+    }
+    for (const QPointF &point : shape.points) {
</code_context>
<issue_to_address>
**Old annotation positions constrain later edits**

When an arrow or line is dragged from its original position, `handleDrag` moves `points` but leaves `mainPoints` unchanged, while `shapePointRect` and `shapeContentBoundingRect` include both. The stale points keep the old location in the bounds, constraining later dragging and selection resizing.

Make arrow and line bounds follow their moved geometry instead of retaining the old `mainPoints` locations.

Also at `src/widgets/shapeswidget.cpp:1349-1351`, `src/widgets/shapeswidget.cpp:1364-1369`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/main_window.cpp
Comment thread src/main_window.cpp
Comment thread src/main_window.cpp
Comment thread src/widgets/shapeswidget.cpp
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.

2 participants