# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

BayTemplate is a **Bay Template Designer of Grid Framework DesignTime** tool - a Qt-based application for designing electrical power grid structures. It features a dockable UI with a graphics canvas for placing and manipulating grid elements.

## Build Commands

### Build the Project

使用 CMake presets 进行配置和构建：

```bash
# Configure using preset
cmake --preset default

# Build with Ninja
ninja -C build/Debug
```

### Output Location

- Executable: `build/Debug/BayTemplate.app` (macOS)

## Architecture

### Core Components

#### 1. Docking System (Qt Advanced Docking System 4.3.1)
- **CDockManager** manages dockable panels
- **Left Dock**: 图元面板 (GraphicElementsPanel) - library of draggable grid elements
- **Center**: DrawingPanel - main canvas area with DesignerScene
- **Right Dock**: 属性编辑器 (PropertyEditor) - QDetailsView for editing selected item properties

#### 2. Graphics View Framework
- **DesignerView** (`QGraphicsView` subclass): Custom view with zoom (0.02-50x), pan (middle-button drag), checkerboard background
- **DesignerScene** (`QGraphicsScene` subclass): Custom scene with grid overlay (20px spacing), routes mouse events through SelectorManager

#### 3. Selector System
Selector hierarchy in `include/util/`:
- **BaseSelector**: Abstract base for all selectors
- **CreatingSelector**: Mode for creating new items from template
- **MovingSelector**: Mode for moving items
- **RotationSelector**: Mode for rotating items around origin
- **ScalingSelector**: Mode for scaling items
- **EditingSelector**: Mode for editing polygon vertex positions
- **SelectorManager**: Singleton that manages the active working selector

Mouse events flow: `DesignerScene` → `SelectorManager::getWorkingSelector()` → specific selector implementation

#### 4. Graphics Items (`include/graphicsItem/`)
- **GraphicsBaseItem**: Abstract base class for all grid elements
- **GraphicsRectItem**: Rectangle element
- **GraphicsPolygonItem**: Polygon element (editable vertices)
- **GraphicsItemGroup**: Container for grouped items (supports flattening to prevent nesting)
- **GraphicsBusSectionItem**: Bus section element
- **ItemControlHandle**: Visual handles for manipulation (rotation, scaling, editing)

#### 5. Property Editor (Qt PropertyEditor)
- **QDetailsView**: Qt Quick-based property editor in right dock
- **QCustomType**: Custom property type for graphics item properties
- **PropertyTypeCustomization_CustomType**: Custom property editor integration
- Property editor observes `QGraphicsScene` and displays properties of selected items

#### 6. Command Pattern (Undo/Redo)
- **QUndoStack** (`m_pUndoStack` in CMainWindow) manages undo/redo
- **OperationCommand**: Base command class
- **AddItemCommand**: Add item to scene
- **DeleteItemCommand**: Remove item from scene
- **CreateItemGoupCommand**: Group selected items (with flattening)
- **DestroyItemGoupCommand**: Ungroup items

### Signal Flow

1. **User drags from 图元面板** → `GraphicElementsPanel` emits signal → `DesignerScene::signalAddItem()` → creates item with `AddItemCommand`

2. **User clicks on canvas** → `DesignerView` → `DesignerScene` → `SelectorManager::getWorkingSelector()` → selector processes event

3. **User selects items** → `DesignerScene::selectionChanged()` → `CMainWindow::onSignal_selectionChanged()` → updates property editor

4. **User modifies property in 属性编辑器** → `QDetailsView` updates item property → scene updates

### Key Files and Relationships

```
source/main.cpp              # Entry point - creates CMainWindow
└── source/mainwindow.h/.cpp # Main window with CDockManager, initializes all components
    ├── initializeDockUi()   # Sets up docks (left, center, right)
    ├── initializeAction()   # Sets up QUndoStack and menu actions
    ├── initializeDocument() # Creates Document, associates with DesignerScene
    ├── Event handlers       # onSignal_addItem, onSignal_selectionChanged, etc.
    └── File operations      # onAction_new(), onAction_open(), onAction_save()

source/document.h/.cpp       # Document class - serialization and state management
    ├── serialize()/deserialize()    # Core JSON serialization
    ├── saveToFile()/loadFromFile()  # File I/O operations
    └── State management    # filename, modified, timestamps, meta data

source/drawingPanel.h/.cpp   # Central dock widget containing DesignerView
└── DesignerView + DesignerScene

source/designerView.h/.cpp   # QGraphicsView subclass - zoom, pan, middle-button navigation

source/designerScene.h/.cpp  # QGraphicsScene subclass - grid background, group operations
└── Delegates to SelectorManager for mouse events

source/util/selectorManager.h/.cpp  # Singleton managing active selector
└── Selector::mousePressEvent/ReleaseEvent/MoveEvent()

source/graphicsItem/         # Graphics item implementations
    ├── GraphicsBaseItem    # Base class with common functionality
    ├── GraphicsRectItem    # Rectangle
    ├── GraphicsPolygonItem # Editable polygon
    ├── GraphicsItemGroup   # Item grouping
    └── GraphicsBusSectionItem

source/propertyType/         # Custom property editor integration
    ├── CustomType.h
    ├── CustomGadget.h
    └── PropertyTypeCustomization_CustomType.cpp
```

### Third-Party Dependencies

1. **QtADS** (`QtADS/` subdirectory, v4.3.1): Advanced docking system - must be present as subdirectory
2. **PropertyEditor** (`PropertyEditor/` subdirectory): Qt Quick-based property editing system with QDetailsView

Both are added via `add_subdirectory()` in CMakeLists.txt and must exist in the repository root.

### Platform Support

- **Qt Version**: Qt5 or Qt6 (auto-detected, `find_package(QT NAMES Qt6 Qt5 ...)`)
- **Architectures**: x86, x64, arm64, aarch64 (auto-detected in CMakeLists.txt)
- **Platforms**: Windows, macOS, Linux, Android (Android uses shared library)

### Important Implementation Details

1. **CMAKE_AUTOUIC_SEARCH_PATHS**: Set to `"ui"` in CMakeLists.txt because .ui files are in separate directory from header files

2. **Group Flattening**: When creating a group that contains existing groups, the scene flattens nested groups first to prevent group nesting (see `DesignerScene::createGroup()`)

3. **Zoom Implementation**: Uses `QGraphicsView::zoom()` with smooth factor `qPow(1.0015, angleDelta.y())` per wheel event

4. **Wchar String Conversion**: Uses `QString::fromWCharArray(L"中文")` for Chinese UI strings

5. **Resource File**: `resource/BayTemplate.qrc` contains checkerboard background and icons, referenced in .ui files and CMakeLists.txt

---

## Graphics View Architecture Deep Dive

### MVC/MVVM Architecture Mapping

BayTemplate implements a classic **Model-View-Controller** pattern using Qt's Graphics View Framework:

| Layer | Qt Graphics View | BayTemplate Implementation | Responsibility |
|-------|------------------|---------------------------|----------------|
| **Model** | QGraphicsItem | GraphicsBaseItem, GraphicsRectItem, GraphicPolygonItem, GraphicsItemGroup | 数据模型：存储图元几何数据、样式属性（pen/brush）、变换信息（位置/旋转/缩放）|
| **Model Manager** | QGraphicsScene | DesignerScene | 模型管理：管理 item 生命周期、选择状态、碰撞检测、背景绘制（网格）|
| **View** | QGraphicsView | DesignerView | 视图呈现：坐标系变换、滚动条控制、鼠标事件捕获、缩放/平移 |
| **Controller** | (Qt 无内置) | SelectorManager + BaseSelector 体系 | 控制器：解释用户输入，转换为模型操作（创建/移动/旋转/缩放/编辑）|

**关键点：**
- Qt 的 Graphics View 框架提供了 MVC 中的 Model 和 View 层
- Controller 层需要开发者自行实现，BayTemplate 使用 SelectorManager 作为中枢
- DesignerScene 介于 Model Manager 和 Controller 之间，负责事件分发

### View-Scene-Item 三层架构详解

```
┌─────────────────────────────────────────────────────────────┐
│                     DesignerView                            │
│                   (Viewport / Presentation)                 │
├─────────────────────────────────────────────────────────────┤
│  • 坐标变换：Viewport Coordinates ↔ Scene Coordinates       │
│  • 缩放控制：0.02x - 50x (mouse wheel with smooth zoom)    │
│  • 平移控制：Middle-button drag (translate transform)       │
│  • 事件捕获：mousePressEvent/moveEvent/releaseEvent         │
│  • 无滚动条：setHorizontal/VerticalScrollBarPolicy(Off)     │
└─────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                    DesignerScene                            │
│                  (Scene Graph Manager)                      │
├─────────────────────────────────────────────────────────────┤
│  • Item 管理：addItem(), removeItem(), selectedItems()      │
│  • 背景绘制：drawBackground() 绘制 20px 间距的藏青色虚线网格     │
│  • 事件分发：将鼠标事件转发给 SelectorManager               │
│  • 组操作：createGroup() 实现扁平化打组                     │
│  • 信号发射：signalAddItem(), selectionChanged()            │
└─────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                     GraphicsItem                           │
│                     (Data Model)                            │
├─────────────────────────────────────────────────────────────┤
│  GraphicsBaseItem (AbstractShapeType<QGraphicsItem>)        │
│    ├── GraphicsRectItem (rectangle, 圆角矩形)               │
│    ├── GraphicPolygonItem (多点绘制，顶点编辑)               │
│    ├── GraphicsBusSectionItem (总线段)                      │
│    └── GraphicsItemGroup (AbstractShapeType<QGroup>)        │
└─────────────────────────────────────────────────────────────┘
```

### 坐标系与变换系统

BayTemplate 使用多层坐标系，理解它们对添加 Document 类至关重要：

```
1. Viewport Coordinates (像素坐标)
   └── DesignerView 的 viewport 矩形，(0,0) 在左上角
   └── 受窗口大小、缩放影响

2. Scene Coordinates (场景坐标)
   └── 全局坐标系，(0,0) 为场景原点
   └── 通过 mapToScene()/mapFromScene() 与 Viewport 互转
   └── 图元的位置 pos() 使用场景坐标

3. Item Coordinates (图元局部坐标)
   └── 每个 item 的局部坐标系，原点在 (0,0)
   └── BayTemplate 中，图元中心点通常与 (0,0) 重合
   └── boundingRect() 返回局部坐标中的边界

4. Parent Coordinates (父项坐标)
   └── 当 item 加入 group 后，使用 group 的局部坐标
   └── mapToParent()/mapFromParent() 用于转换
```

**变换链（Transform Chain）：**
```
Item Coordinates → Item Transform → Parent Coordinates → ... → Scene Coordinates → View Transform → Viewport Coordinates
```

- **Item Transform**: 由 `setPos()`, `setRotation()`, `setScale()` 控制的 3×3 变换矩阵
- **Transform Origin**: `setTransformOriginPoint()` 设置变换中心（BayTemplate 中通常为中心点）
- **View Transform**: DesignerView 的 zoom/pan 产生的变换，影响所有 item 的显示

**关键函数：**
- `item->mapToScene(point)`: Item 局部坐标 → 场景坐标
- `item->mapToView(point)`: Item 局部坐标 → Viewport 坐标
- `view->mapToScene(point)`: Viewport 坐标 → 场景坐标
- `view->mapSceneToViewport(rect)`: 场景矩形 → Viewport 矩形

### 操作模式与状态机（Selector 系统）

SelectorManager 实现了一个**状态机**，不同的 Selector 代表不同的操作模式：

```
                      ┌─────────────────┐
                      │   ST_base       │
                      │  (空闲状态)     │
                      └────────┬────────┘
                               │
            ┌──────────────────┼──────────────────┐
            │                  │                  │
            ▼                  ▼                  ▼
    ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
    │ ST_creating  │  │ ST_moving    │  │ ST_editing   │
    │ (创建模式)   │  │ (移动模式)   │  │ (顶点编辑)   │
    └──────────────┘  └──────────────┘  └──────────────┘
            │                  │
            │                  │
            ▼                  ▼
    ┌──────────────┐  ┌──────────────┐
    │ ST_scaling   │  │ ST_rotation  │
    │ (缩放模式)   │  │ (旋转模式)   │
    └──────────────┘  └──────────────┘
            │                  │
            └────────┬─────────┘
                     │
                     ▼
                ┌────────┐
                │ ST_base│ (操作完成后返回)
                └────────┘
```

**状态转换规则：**

| 触发条件 | 从状态 | 到状态 | 说明 |
|---------|--------|--------|------|
| 从图元面板拖拽 | ST_base | ST_creating | 设置 CreatingSelector 的 m_pCreatingItem |
| 点击选中 item（左键） | ST_base | ST_moving/ST_scaling/ST_rotation | 根据是否点击在 handle 上判断 |
| 点击空白处 | 任何 | ST_base | 取消选择，禁用 RubberBandDrag |
| mouseReleaseEvent | ST_moving/scaling/rotation | ST_base | 操作完成，返回空闲状态 |

**BaseSelector 静态成员（所有 Selector 共享）：**
```cpp
static QPointF ms_ptMouseDown;           // 鼠标按下位置（场景坐标）
static QPointF ms_ptMouseLast;          // 鼠标当前位置（场景坐标）
static double ms_dAngleMouseDownToItem; // 按下时鼠标与 item 中心的夹角（弧度→角度）
static int ms_nDragHandle;              // 当前拖拽的 handle 类型
```

### Handle 控制系统

ItemControlHandle 是围绕在选中 item 周围的视觉控件，用于精细操作：

```
    H_leftTop ──── H_top ──── H_rightTop
         │            │            │
         │            │            │
    ┌────┴────────────┴────────────┴────┐
    │                                   │
    │         Item Bounding             │
    │           Rect                    │
    │                                   │
    └────┬────────────┬────────────┬────┘
         │            │            │
    H_left ────── H_bottom ──── H_rightBottom
```

**Handle 类型枚举：**
```cpp
enum HandleTag {
    H_none = 0,           // 无 handle
    H_leftTop,            // 左上角（缩放）
    H_top,                // 上边中点（缩放）
    H_rightTop,           // 右上角（缩放）
    H_right,              // 右边中点（缩放）
    H_rightBottom,        // 右下角（缩放）
    H_bottom,             // 下边中点（缩放）
    H_leftBottom,         // 左下角（缩放）
    H_left,               // 左边中点（缩放）
    H_rotate_leftTop,     // 左上角外侧（旋转）
    H_rotate_rightTop,    // 右上角外侧（旋转）
    H_rotate_rightBottom, // 右下角外侧（旋转）
    H_rotate_leftBottom,  // 左下角外侧（旋转）
    H_edit,               // 自定义编辑点（多边形顶点、圆角控制点）
    // ... 更多编辑点
};
```

**Handle 工作机制：**
1. `AbstractShapeType::updateHandles()` 根据 boundingRect 计算 handle 位置
2. Handle 位置在 boundingRect 外扩 5px (nMargin = 5)
3. `collidesWithHandle()` 检测鼠标点击在哪个 handle 上
4. 不同操作模式对 handle 的响应不同

### 操作副本（Operation Copy）模式

移动和旋转操作使用"预览副本"技术，提供视觉反馈：

```cpp
// 1. mousePressEvent: 创建副本
void createOperationCopy() {
    m_pOperationCopy = new QGraphicsPathItem(this->shape());
    m_pOperationCopy->setPen(Qt::DashLine);  // 虚线表示预览
    m_pOperationCopy->setPos(this->pos());
    scene->addItem(m_pOperationCopy);
    m_movingIniPos = this->pos();
}

// 2. mouseMoveEvent: 移动副本（本体不动）
void moveOperationCopy(const QPointF& delta) {
    m_pOperationCopy->setPos(m_movingIniPos + delta);
}

// 3. mouseReleaseEvent: 副本位置应用到本体
void removeOperationCopy() {
    this->setPos(m_pOperationCopy->pos());  // 本体移动到副本位置
    scene->removeItem(m_pOperationCopy);
    delete m_pOperationCopy;
}
```

**优势：**
- 移动过程中保持原来的 selection state
- 可以拖出 boundingRect_selected 范围（否则会被误认为取消选择）
- 旋转/缩放同理

### 图元基类架构（AbstractShapeType 模板）

```cpp
// 使用模板继承，允许继承 QGraphicsItem 或 QGraphicsItemGroup
template <typename BaseType = QGraphicsItem>
class AbstractShapeType : public BaseType {
protected:
    ShapeType m_type;                    // T_undefined/T_item/T_group
    QPen m_pen;                          // 画笔（边框）
    QBrush m_brush;                      // 画刷（填充）
    double m_dWidth, m_dHeight;         // 宽高
    QRectF m_boundingRect;              // 局部坐标中的边界矩形
    QRectF m_boundingRect_selected;     // 选中框（外扩 5px）
    double m_dSyncRotationByParent;     // 父项旋转同步数据
    QVector<ItemControlHandle*> m_vecHanle;
    QGraphicsPathItem* m_pOperationCopy;
    QPointF m_movingIniPos;
};

// 具体类型定义
typedef AbstractShapeType<QGraphicsItem> AbstractShape;      // 单图元基类
// GraphicsBaseItem : QObject, AbstractShape

// GraphicsItemGroup : QObject, AbstractShapeType<QGraphicsItemGroup> // 组图元基类
```

**关键点：**
- `m_boundingRect` 的中心点与 item 的 (0,0) 原点重合，简化变换计算
- `updateCoordinate()` 在 resize/editShape 后重新校准原点
- `m_dSyncRotationByParent` 用于组内 item 跟踪父组的旋转（因为 item 的 rotation() 不会自动更新）

### 命令模式（Command Pattern）

所有可撤销操作都通过 QUndoCommand 实现：

```cpp
class AddItemCommand : public QUndoCommand {
    void undo() override { scene->removeItem(m_pItem); }
    void redo() override { 
        if(!m_pItem->scene()) scene->addItem(m_pItem); 
    }
};

class DeleteItemCommand : public QUndoCommand {
    void undo() override { 
        foreach(item, m_listItem) scene->addItem(item); 
    }
    void redo() override { 
        foreach(item, m_listItem) scene->removeItem(item); 
    }
};
```

**关键点：**
- `QUndoStack::push(command)` 会自动调用 `command->redo()`
- `DeleteItemCommand` 使用 `removeItem()` 而非 `delete`，确保 undo 能恢复
- 命令对象持有 item 的引用（非所有权）

### 组（Group）扁平化策略

`DesignerScene::createGroup()` 实现组扁平化：

```cpp
// 如果选中的 item 中包含已有的 group，先解散该 group，将子项加入新组
foreach (item, selectedItems) {
    if (item->getType() == T_group) {
        GraphicsItemGroup* group = qgraphicsitem_cast<GraphicsItemGroup*>(item);
        foreach (child, group->childItems()) {
            listItem.push_back(child);  // 将子项加入新列表
        }
        removeItem(group);
        delete group;  // 删除旧组
    }
}
// 创建新组，避免嵌套
```

**目的：**
- 简化场景图结构（无嵌套的树）
- 简化坐标计算和碰撞检测
- 统一 undo/redo 逻辑

---

## Document 类架构（持久化层）

### Document 类在 MVC 中的位置

Document 类作为**持久化层**插入现有架构，位于 Model 层之下：

```
┌─────────────────────────────────────────┐
│              Controller                 │
│        (SelectorManager + 各种 Selector) │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│                   View                  │
│          (DesignerView + UI)            │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│               Model Manager             │
│           (DesignerScene)               │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│                  Model                  │
│     (GraphicsItem 层次结构)              │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│               Document                  │
│           (序列化/状态管理)              │
└──────────────────────────────────────────┘
```

**设计原则：**
- **组合优于继承**：Document 持有 `DesignerScene*` 弱引用，不继承 Scene
- **单向依赖**：Document 只依赖 DesignerScene 的接口，不依赖 CMainWindow
- **信号槽通信**：通过信号与外部通信修改状态，避免紧耦合

### Document 类职责

1. **序列化/反序列化**（JSON 格式）
   - `serialize()` / `deserialize()`: 核心序列化为 QByteArray
   - `saveToFile()` / `loadFromFile()`: 文件 I/O 封装
   - 递归序列化/反序列化图元层次结构（支持组图元嵌套）

2. **状态管理**
   - `m_filename`: 文档文件名（空表示未保存的新文档）
   - `m_modified`: 是否被修改（通过 `setModified()` 和 `modifiedChanged` 信号通知）
   - `m_created` / `m_modifiedTime` / `m_lastSavedTime`: 时间戳
   - `m_metaData`: 可扩展的自定义元数据 (`QMap<QString, QVariant>`)

3. **与 CMainWindow 的集成**
   - `initializeDocument()`: 创建 Document 并关联 DesignerScene
   - 连接 `modifiedChanged` 信号来更新窗口标题（添加 * 标记）
   - `closeEvent()` 中检查 `isModified()` 提示用户保存
   - 文件操作：New/Open/Save 通过 Document 完成

### 序列化格式（v1.0）

```json
{
    "version": "1.0",
    "created": "2024-01-01T12:00:00",
    "modified": "2024-01-01T14:30:00",
    "filename": "/path/to/file.bay",
    "metaData": {
        "customKey": "customValue"
    },
    "items": [
        {
            "type": "GraphicsRectItem",
            "id": "140737488320",
            "pos": {"x": 100.0, "y": 200.0},
            "rotation": 45.0,
            "scale": {"x": 1.0, "y": 1.0},
            "pen": {"color": "#000000", "width": 1.0, "style": 0},
            "brush": {"color": "#FF0000"},
            "width": 100.0,
            "height": 50.0,
            "properties": {},
            "children": []
        },
        {
            "type": "GraphicsItemGroup",
            "pos": {"x": 300.0, "y": 150.0},
            "rotation": 0.0,
            "scale": {"x": 1.0, "y": 1.0},
            "width": 200.0,
            "height": 100.0,
            "children": [
                { "type": "GraphicsRectItem", ... },
                { "type": "GraphicsBusSectionItem", ... }
            ]
        }
    ]
}
```

### 实现细节

**类型识别：** 使用 `qobject_cast<T*>(item)` 配合 `getTypeString()` 函数识别图元类型（要求类型有 `Q_OBJECT` 宏）

**QVariant ↔ QJsonValue 转换：** 提供 `toJsonValue()` / `fromJsonValue()` 辅助函数处理元数据序列化

**坐标系统：** 图元使用中心原点，`pos()` 存储场景坐标，`boundingRect()` 使用局部坐标

**文件扩展名：** `.bay` 作为 BayTemplate 专用格式

### 关键文件

- `include/document.h`: Document 类声明
- `source/document.cpp`: 序列化/反序列化实现
- `source/mainwindow.cpp`: `initializeDocument()`, `onAction_new()`, `onAction_open()`, `onAction_save()`

---

## Selector 系统设计模式总结

### 状态模式（State Pattern）

SelectorManager 实现状态模式，不同的 Selector 子类代表不同的状态：

```cpp
// Context
class SelectorManager {
    BaseSelector* getWorkingSelector();  // 返回当前状态的 Selector
    void setWorkingSelector(SelectorType);
};

// State 接口
class BaseSelector {
    virtual void mousePressEvent(...) = 0;
    virtual void mouseMoveEvent(...) = 0;
    virtual void mouseReleaseEvent(...) = 0;
};

// Concrete State
class MovingSelector : public BaseSelector { ... };
class ScalingSelector : public BaseSelector { ... };
// ...
```

**静态成员共享的原因：**
BaseSelector 的静态成员（ms_ptMouseDown 等）在所有 Selector 实例间共享，使得状态切换时无需传递上下文数据。

### 操作副本模式（Operation Preview Pattern）

移动、旋转、缩放都使用"操作副本"作为视觉预览：
1. mousePressEvent: 创建虚线副本
2. mouseMoveEvent: 移动副本（本体不动）
3. mouseReleaseEvent: 将副本的变换应用到本体，删除副本

### Handle 系统（Manipulator Pattern）

ItemControlHandle 实现操纵器模式，将抽象的变换操作（缩放、旋转）映射到可视化的交互控件。

---

## 坐标系转换速查表

| 转换 | 函数 | 说明 |
|------|------|------|
| Item → Scene | `item->mapToScene(point)` | 局部坐标转场景坐标 |
| Scene → Item | `item->mapFromScene(point)` | 场景坐标转局部坐标 |
| Item → Viewport | `item->mapToView(point)` | 局部坐标转屏幕像素 |
| Item → Parent | `item->mapToParent(point)` | 局部坐标转父项坐标 |
| Viewport → Scene | `view->mapToScene(point)` | 屏幕像素转场景坐标 |
| Scene Rect → Viewport Rect | `view->mapSceneToViewport(rect)` | 场景矩形转屏幕矩形 |

## Handle 类型速查表

| Handle 类型 | 位置 | 功能 |
|------------|------|------|
| H_leftTop ~ H_left | boundingRect 八方向 | 缩放 |
| H_rotate_leftTop ~ H_rotate_leftBottom | boundingRect 外扩 | 旋转 |
| H_edit + N | 自定义位置 | 形状编辑（多边形顶点、圆角控制点）|

## 操作模式速查表

| SelectorType | 触发方式 | 用途 |
|-------------|---------|------|
| ST_base | 默认 | 空闲状态，允许橡胶框选择 |
| ST_creating | 从图元面板拖拽 | 创建新图元 |
| ST_moving | 点击 item 主体 | 移动选中项 |
| ST_scaling | 点击缩放 handle | 缩放选中项 |
| ST_rotation | 点击旋转 handle | 旋转选中项 |
| ST_editing | 点击编辑 handle | 编辑多边形顶点等 |
