feat: implement image canvas with drag/scale/rotate and preview zoom

Replace placeholder ImageCanvas with full QGraphicsView/QGraphicsScene editor:

Layout: ImageCanvas(QWidget) = top bar + _CanvasView(QGraphicsView) + hint bar

Top bar: garment/print filenames, mode buttons (移动/缩放/旋转, context-aware),
zoom controls (−/% label/+, scroll wheel).

_CanvasView:
- drawBackground: checkerboard in garment area, gray outside
- wheelEvent: zoom in/out anchored at cursor
- mousePressEvent/mouseMoveEvent/mouseReleaseEvent: delegate to ImageCanvas

Scene (1:1 with garment pixel coords):
- garment QGraphicsPixmapItem at (0,0), not interactive
- print QGraphicsPixmapItem positioned/rotated from TransformState
- cosmetic selection rect (blue, 1.5px)
- 4 corner handles (white circle, blue border) for scaling
- rotation arm (dashed) + handle (blue circle) above top-center

Interaction:
- Hit test: rotation handle > corner handles > print body (priority order)
- Move: delta in scene coords added to TransformState.x/y
- Scale: _scene_to_local_xy() maps mouse to item local coords, computes
  new size keeping opposite corner fixed (_do_scale); supports aspect
  ratio lock via Shift or keep_aspect_ratio flag; correct with rotation
- Rotate: atan2(mouse - center) + angle offset at press

Coordinate helpers (static):
- _local_to_scene_xy(lx, ly, state): item-local → scene
- _scene_to_local_xy(sx, sy, state): scene → item-local (inverse rotation)
Both use TransformState snapshot, not live item state, to avoid stale-pixmap issues.

transform_changed signal fires on mouse release with final TransformState.
Preview zoom changes only QGraphicsView transform; TransformState is unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 09:01:15 +08:00
co-authored by Claude Sonnet 4.6
parent 94d30ab183
commit 3e3e06b7a1
2 changed files with 604 additions and 19 deletions
+16 -16
View File
@@ -318,25 +318,25 @@
任务:
- [ ] 先读取 `src/app/widgets/image_canvas.py` 现有内容
- [ ] 使用 `QGraphicsView / QGraphicsScene`
- [ ] 显示衣服底图(scene 坐标与原图像素坐标保持一致)
- [ ] 显示印花图层
- [ ] 实现印花拖动
- [ ] 实现缩放控制点(至少四角)
- [ ] 实现旋转控制点(顶部中心外侧)
- [ ] 实现预览缩放(通过 `QGraphicsView` view transform,不修改 scene 内容)
- [ ] 实现预览顶部栏:显示当前底图文件名、印花文件名、操作模式按钮(移动/缩放/旋转)、缩放比例控制
- [ ] 实现画布操作提示 Overlay(拖动移动 / 四角缩放 / 顶部旋转 / Shift 锁比例)
- [ ] 将交互结果同步为 `TransformState`
- [x] 先读取 `src/app/widgets/image_canvas.py` 现有内容
- [x] 使用 `QGraphicsView / QGraphicsScene`
- [x] 显示衣服底图(scene 坐标与原图像素坐标保持一致)
- [x] 显示印花图层
- [x] 实现印花拖动
- [x] 实现缩放控制点(至少四角)
- [x] 实现旋转控制点(顶部中心外侧)
- [x] 实现预览缩放(通过 `QGraphicsView` view transform,不修改 scene 内容)
- [x] 实现预览顶部栏:显示当前底图文件名、印花文件名、操作模式按钮(移动/缩放/旋转)、缩放比例控制
- [x] 实现画布操作提示 Overlay(拖动移动 / 四角缩放 / 顶部旋转 / Shift 锁比例)
- [x] 将交互结果同步为 `TransformState`
验收:
- [ ] 预览缩放不改变真实合成参数
- [ ] 拖动后坐标为衣服原图像素坐标
- [ ] 缩放后宽高同步
- [ ] 旋转后角度同步
- [ ] 不使用截图作为导出结果
- [x] 预览缩放不改变真实合成参数
- [x] 拖动后坐标为衣服原图像素坐标
- [x] 缩放后宽高同步
- [x] 旋转后角度同步
- [x] 不使用截图作为导出结果
## 10. 参数面板 UI