# 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 | 编辑多边形顶点等 |

---

## PropertyEditor 系统架构深度剖析

### 概述

PropertyEditor 是一个第三方属性编辑器库（位于 `PropertyEditor/` 子目录），受虚幻引擎属性面板启发，借助 Qt 反射系统自动构建 QObject 的属性编辑 UI。核心亮点：

- **基于 QML GPU 渲染**：使用 `QQuickWidget` 嵌套 QML TreeView + Delegate 实现
- **自动反射**：通过 `Q_PROPERTY` 宏声明的属性自动生成编辑器行
- **类型驱动编辑器选择**：根据 `QMetaType` 自动匹配对应的 ValueEditor QML 组件
- **可扩展定制**：通过 `IPropertyTypeCustomization` 接口为特定类型自定义整行布局和子项结构

### 完整数据流

```
CMainWindow::onSignal_selectionChanged()
    │
    ▼
QDetailsView::setObject(QObject*)                    ← 设置被检查的 QObject
    │
    ▼
QQuickDetailsView::setObject(QObject*)               ← QML 端的入口
    │
    ▼
QQuickDetailsViewModel::setObject(QObject*)           ← QAbstractItemModel
    │  └─ 创建根 QPropertyHandle (FindOrCreate)
    │  └─ 创建根 QDetailsViewRow_Property(mRoot)
    │  └─ mRoot->invalidateChildren()
    │       │
    │       ▼
    │  QDetailsViewRow_Property::attachChildren()
    │       │
    │       ├── 有 IPropertyTypeCustomization？
    │       │   YES → customizeChildren(handle, layoutBuilder)
    │       │   NO  → PropertyTypeCustomization_ObjectDefault::customizeChildren()
    │       │          ├─ 检查 objectHandle 是否实现 IPropertyGroupProvider
    │       │          │   YES → 按 group 名称收集属性 → addGroup() + 子 LayoutBuilder
    │       │          │   NO  → 遍历 metaObject->propertyCount() 平铺属性
    │       │          └─ layoutBuilder->addProperty(childHandle)
    │       │
    │       ▼
    │  QQuickTreeViewEx (QML TableView) 为每行创建 Delegate
    │       │
    │       ▼
    │  QQuickDetailsViewPrivate::initItemCallback()
    │       │
    │       ▼
    │  QDetailsViewRow_Property::setupItem(QQuickItem* inParent)
    │       │
    │       ├── 有 IPropertyTypeCustomization？
    │       │   YES → customizeHeaderRow(handle, rowBuilder)
    │       │   NO  → rowBuilder->makePropertyRow(handle)
    │       │           │
    │       │           ├── makeNameValueSlot()
    │       │           │   └─ 创建 QML Row: [展开箭头] [名称区] [分隔条] [值编辑区]
    │       │           │
    │       │           ├── handle->setupNameEditor(nameSlot)
    │       │           │   └─ IPropertyHandleImpl::createNameEditor()
    │       │           │       └─ 创建 Text { text: model.name } QML 组件
    │       │           │
    │       │           └── handle->steupValueEditor(valueSlot)
    │       │               └─ IPropertyHandleImpl::createValueEditor()
    │       │                   └─ 根据类型查找注册的编辑器 QML 组件
    │       │
    │       ▼
    │  [最终渲染为带颜色的行，左侧名称 + 右侧编辑器控件]
```

### 核心类详解

#### 1. QDetailsView（C++ 侧的 QWidget 包装器）
```cpp
// source/PropertyEditor/source/src/QDetailsView.cpp
class QDetailsView : public QWidget {
    QQuickWidget* mQuickWidget;          // 嵌入 QML 引擎
    QQuickDetailsView* mQuickDetailsView; // QML 端的 DetailsView 对象
    void setObject(QObject* inObject);   // 关键入口：设置被检查的对象
};
```

#### 2. QQuickDetailsViewModel（QAbstractItemModel 的树形实现）
```cpp
// source/PropertyEditor/source/src/QQuickDetailsViewModel.cpp
class QQuickDetailsViewModel : public QAbstractItemModel {
    QSharedPointer<QDetailsViewRow_Property> mRoot;  // 根行（不可见）
    QObject* mObject;                                  // 被检查的对象
    
    void setObject(QObject* inObject) {
        mObject = inObject;
        mRoot->setHandle(QPropertyHandle::FindOrCreate(mObject));  // 创建根 Handle
        mRoot->invalidateChildren();  // 触发递归构建属性树
    }
};
```

**模型的树结构**（带分组示例）：
```
mRoot (QDetailsViewRow_Property, 不可见)
  ├── QDetailsViewRow_Group("数值")                          ← 分组标题（可折叠）
  │     ├── QDetailsViewRow_Property("Int")                  ← QMetaProperty
  │     ├── QDetailsViewRow_Property("Float")
  │     └── QDetailsViewRow_Property("LimitedDouble")
  ├── QDetailsViewRow_Group("文本")                          ← 分组标题（可折叠）
  │     ├── QDetailsViewRow_Property("String")
  │     └── QDetailsViewRow_Property("Directory")
  ├── QDetailsViewRow_Group("自定义类型")                    ← 分组标题（可折叠）
  │     ├── QDetailsViewRow_Property("CustomEnum")
  │     ├── QDetailsViewRow_Property("CustomType")           ← IPropertyTypeCustomization
  │     │     ├── QDetailsViewRow_Property("ArraySize")
  │     │     └── QDetailsViewRow_Property("Array")
  │     │           ├── QDetailsViewRow_Property("[0]")
  │     │           └── QDetailsViewRow_Property("[1]")
  │     └── QDetailsViewRow_Property("CustomGadget")
  │           ├── QDetailsViewRow_Property("LimitedDouble")
  │           └── QDetailsViewRow_Property("Desc")
  └── QDetailsViewRow_Property("m_lastBoudingRectF")         ← 未分组属性（直接挂根）
```

#### 3. QPropertyHandle（属性操作的统一入口）
```cpp
// source/PropertyEditor/source/include/QPropertyHandle.h
// source/PropertyEditor/source/src/QPropertyHandle.cpp
class QPropertyHandle : public QObject {
    Q_OBJECT
    Q_PROPERTY(QVariant Var READ getVar WRITE setVar NOTIFY asVarChanged)
    
    using Getter = std::function<QVariant()>;
    using Setter = std::function<void(QVariant)>;
    
    QMetaType mType;                   // 属性的 QMetaType
    PropertyType mPropertyType;        // RawType | Enum | Sequential | Associative | Object
    QString mPropertyPath;             // 属性路径（如 "SubObject.LimitedDouble"）
    Getter mGetter;                    // 获取属性值的 lambda
    Setter mSetter;                    // 设置属性值的 lambda
    QVariantHash mMetaData;            // 从 Q_CLASSINFO 解析的元数据（Min, Max, Step, Precision）
    QSharedPointer<IPropertyHandleImpl> mImpl;  // 根据 PropertyType 选择的实现策略
};
```

**关键接口**：
- `static FindOrCreate(parent, type, path, getter, setter)` — 在父对象中查找已有 Handle，找不到则创建新的。Handle 作为 `parent` 的子 QObject 存储，生命周期跟随父对象
- `getVar()` / `setVar()` — 通过 Getter/Setter lambda 读写实际属性值
- `setVar()` 的 rollback 机制：设置后重新读取，如果值不匹配则发射 `asRequestRollback` 信号通知编辑器回滚显示值
- `parserType(QMetaType)` — 根据 QMetaType 自动分类：
  - 可转为 QVariantList 且不可转为 QString → Sequential（列表）
  - 可转为 QVariantMap → Associative（映射）
  - IsEnumeration flag → Enum
  - 有 metaObject（QObject 或 QSharedPointer<QObject>）→ Object
  - 否则 → RawType（基本类型）
- `findOrCreateChild()` — 为 Object 类型的属性创建子 Handle，自动连接到父 Handle 的 `asVarChanged` 信号以触发子项刷新

#### 4. IPropertyHandleImpl（编辑器创建策略）
```
IPropertyHandleImpl
  ├── QPropertyHandleImpl_RawType  → 调用 QQuickDetailsViewManager::createValueEditor() 
  │                                  查找已注册的 TypeEditor
  ├── QPropertyHandleImpl_Enum     → 创建 ComboBox 选择器
  ├── QPropertyHandleImpl_Object   → createValueEditor() 返回 nullptr（Object 类型本身不显示值编辑器）
  │   ├── getObject() / getGadget() — 区分 QObject* 和 Q_GADGET 值类型
  │   ├── refreshObjectPtr() — 从 Handle 重新读取对象指针
  │   └── 核心作用：作为属性树的内部节点，展开显示子属性
  ├── QPropertyHandleImpl_Sequential  → 展开为 index-based 子行（[0], [1], ...）
  └── QPropertyHandleImpl_Associative → 展开为 key-value 子行
```

#### 5. IDetailsViewRow（模型树节点）
```
IDetailsViewRow (抽象基类)
  ├── QDetailsViewRow_Property  ← 包装一个 QPropertyHandle
  │   setupItem(): 如果有 IPropertyTypeCustomization → customizeHeaderRow()
  │                否则 → makePropertyRow(handle)（默认的名称+值编辑器布局）
  │   attachChildren(): 如果有 IPropertyTypeCustomization → customizeChildren()
  │                     否则 → PropertyTypeCustomization_ObjectDefault（遍历 metaObject->propertyCount()）
  ├── QDetailsViewRow_Custom     ← 支持通过 lambda 创建自定义行
  │   setupItem(): 调用 mRowCreator(&builder) 直接构造 QML
  └── QDetailsViewRow_Group      ← 可折叠的属性分组标题行
      isGroup() 返回 true，setupItem() 渲染粗体分组标题 + 折叠时显示子项计数 "(N)"
```

**QDetailsViewRow_Group**:
- `isGroup()` 返回 `true`，通过 model 的 `isGroup` role 暴露给 QML delegate
- `setupItem()` 使用 `makeNameValueSlot()` 构建行布局：
  - **名称区**：粗体 (`font.bold: true`) 文本显示分组名（如"数值"、"颜色"）
  - **值区**：折叠时显示 `"(N)"` 表示子属性数量（通过 `groupChildCount` 属性绑定）
  - 高度固定 25px，颜色使用 `ColorPalette.theme.labelPrimary`
- 展开/折叠由 delegate 模板中的 `TapHandler` 触发 `detailsView.toggleExpanded(row)`
- `setObject()` 时 C++ 侧自动展开所有 group 行（一次性，避免 delegate 重建时的重复展开循环）

#### 6. IPropertyTypeCustomization（类型自定义扩展接口）
```cpp
class IPropertyTypeCustomization {
    virtual void customizeHeaderRow(QPropertyHandle*, QQuickDetailsViewRowBuilder*);
    virtual void customizeChildren(QPropertyHandle*, QQuickDetailsViewLayoutBuilder*);
};
```
- `customizeHeaderRow`: 自定义该属性行本身的 UI（替换默认的 name + value editor）
- `customizeChildren`: 自定义该属性展开后的子行结构
- 注册方式：`QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization<QCustomType, MyCustomization>()`

**内置 Customization**：
- `PropertyTypeCustomization_ObjectDefault`：默认的 QObject 处理，遍历 `metaObject->propertyCount()`，为每个 QMetaProperty 创建子 Handle（使用 `prop.read()`/`prop.write()`）。Gadget 类型从索引 0 开始，QObject 类型从索引 1 开始（跳过 `objectName`）
- `PropertyTypeCustomization_Sequential`：展开 QList/QVector 等顺序容器
- `PropertyTypeCustomization_Associative`：展开 QMap 等关联容器
- `PropertyTypeCustomization_Matrix4x4`：4×4 矩阵编辑器

#### 7. QQuickDetailsViewManager（全局注册中心，Singleton）
```cpp
QHash<const QMetaObject*, PropertyTypeCustomizationCreator> mClassCustomizationMap;   // QObject 类型 → 自定义
QHash<QMetaType, PropertyTypeCustomizationCreator> mMetaTypeCustomizationMap;         // 值类型 → 自定义
QHash<QMetaType, TypeEditorCreator> mTypeEditorCreatorMap;                            // 基本类型 → 编辑器 QML 组件
```
- 内置注册的基本类型编辑器：`int/unsigned int/size_t`, `float`, `double`, `QString`, `QVector2D/3D/4D`, `QColor`, `QDir`
- 内置注册的类型自定义：`QMatrix4x4` → `PropertyTypeCustomization_Matrix4x4`
- QML 模块注册：`DetailsView` (1.0), `ColorPalette` (单例)
- `getCustomPropertyType()` 查找逻辑：
  1. Sequential → PropertyTypeCustomization_Sequential
  2. Associative → PropertyTypeCustomization_Associative
  3. Object → 查找 mClassCustomizationMap（精确匹配 + 继承匹配），fallback 到 ObjectDefault
  4. RawType → 查找 mMetaTypeCustomizationMap（精确匹配 + 继承匹配）

#### 8. QQuickDetailsViewRowBuilder / QQuickDetailsViewLayoutBuilder（QML 布局构建器）
- **RowBuilder**：构建单行 UI
  - `makeNameValueSlot()` — 创建标准的 [名称区域 | 分隔条 | 值区域] QML 布局
  - `setupItem(parent, qmlCode)` — 在父 QML Item 中创建子 QML 组件
  - `setupLabel(parent, text)` — 创建文本标签
  - `makePropertyRow(handle)` — 默认属性行：name slot + value slot
- **LayoutBuilder**：管理子行结构
  - `addProperty(handle, overrideName)` — 添加属性子行
  - `addCustomRow(lambda, overrideName)` — 添加自定义行
  - `addGroup(groupName)` — 创建 `QDetailsViewRow_Group` 分组标题行，返回其指针供后续向组内添加子行
  - `addObject(QObject*)` — 添加对象作为属性行

### Q_CLASSINFO 元数据系统

通过 `Q_CLASSINFO` 宏向属性编辑器传递校验约束，格式为逗号分隔的 `key=value` 对：

```cpp
Q_CLASSINFO("LimitedDouble", "Min=0,Max=10,Step=0.5,Precision=2")
```

`QPropertyHandle::resloveMetaData()` 解析 `metaObject->classInfo()` 中与属性名匹配的项，将键值对存入 `mMetaData`。ValueEditor 从 `mMetaData` 中读取约束（`Min`, `Max`, `Step`, `Precision`）来配置输入控件。

### Q_PROPERTY_VAR 宏（BayTemplate 项目封装）

```cpp
// include/CommonInclude.h
#define Q_PROPERTY_VAR(Type, Name)\
    Q_PROPERTY(Type Name READ get##Name WRITE set##Name)\
    Type get##Name() { return Name; }\
    void set##Name(Type var) {\
        Name = var;\
        qDebug() << "Set" << #Name << ": " << var;\
    }\
    Type Name
```

这个宏将属性声明、getter/setter 实现、成员变量声明合并为一行，大大简化 Q_PROPERTY 的使用。

### 当前 BayTemplate 集成状态

**初始化流程**（`source/mainwindow.cpp:118-128`）：
```cpp
// 1. 注册自定义类型编辑器
QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization<QCustomType, PropertyTypeCustomization_CustomType>();

// 2. 创建 QDetailsView 并挂载到右侧 Dock
m_pPropertiesEditorView = new QDetailsView();
m_pPropertiesEditorView->setObject(m_pDrawingPanel->getQGraphicsScene());
```

**选择变化处理**（`source/mainwindow.cpp:226-235`）：
```cpp
void CMainWindow::onSignal_selectionChanged() {
    QList<QGraphicsItem*> selectedItems = scene->selectedItems();
    if (selectedItems.count() != 1) {
        m_pPropertiesEditorView->setObject(scene);   // 多选/无选 → 显示场景属性
        return;
    }
    m_pPropertiesEditorView->setObject(static_cast<QObject*>(selectedItems.first()));
}
```

**当前图元的 Q_PROPERTY 状态**：
- `GraphicsBusSectionItem`：唯一完整声明了 Q_PROPERTY 的图元（Int, Float, LimitedDouble, String, Directory, Vec2-4, Mat4, Color, ColorList, ColorMap, CustomEnum, CustomType, CustomGadget, CustomGadgetPtr, CustomGadgetSharedPtr 等） — 同时重写 `getPropertyGroup()` 将属性分入 5 个可折叠分组（数值、文本、向量/矩阵、颜色、自定义类型）
- `GraphicsBaseItem` 实现了 `IPropertyGroupProvider` 接口，默认返回空字符串（无分组），子类可重写
- `GraphicsRectItem`、`GraphicsPolygonItem`、`GraphicsItemGroup`：**无 Q_PROPERTY 声明** — 因此属性编辑器不会显示任何属性行

**BayTemplate 自定义类型**：
- `QCustomType` (结构体)：`{ unsigned int ArraySize; QVector<int> Array; }` — 通过 `PropertyTypeCustomization_CustomType` 定制，header 显示 Sort 按钮，children 展开为 ArraySize + Array
- `QCustomGadget` (Q_GADGET)：`{ double LimitedDouble; QString Desc; }` — 会被属性编辑器递归展开子属性

### 属性编辑器的值读写循环

```
用户修改 QML 编辑器中的值
    │
    ▼
QML 编辑器 emit valueChanged(QVariant)
    │ (通过 connect 连接)
    ▼
QPropertyHandle::setVar(var)
    ├── mSetter(var)                    ← 写入实际对象属性
    ├── emit asVarChanged(var)           ← 通知其他监听者
    ├── QVariant currVar = mGetter()     ← 重新读取验证
    └── if (currVar != var) emit asRequestRollback(currVar)  ← 值被拦截时通知编辑器回滚
```

### 属性分组系统 (Property Grouping)

属性分组允许 QObject 子类将 Q_PROPERTY 属性归类到可折叠的分组标题下，使属性编辑器在有大量属性时更易浏览。

#### IPropertyGroupProvider 接口

```cpp
// PropertyEditor/source/include/IPropertyGroupProvider.h
class IPropertyGroupProvider {
public:
    virtual ~IPropertyGroupProvider() = default;
    virtual QString getPropertyGroup(const QString& propertyName) const = 0;
};
```

- 返回空字符串表示属性不分组（默认行为）
- 返回非空字符串表示属性属于该名称的分组
- 同名分组的属性会被收集到同一个 group 下，按分组调用顺序排列
- **不属于 PropertyEditor 库本身**，而是由使用方（如 BayTemplate 的 GraphicsBaseItem）实现

#### 分组构建流程

```
PropertyTypeCustomization_ObjectDefault::customizeChildren(handle, builder)
    │
    ├── 检查 objectHandle->getObject() 是否实现 IPropertyGroupProvider？
    │   NO → 原有逻辑：遍历 metaObject->propertyCount() 平铺所有属性
    │
    │   YES → 新分组逻辑：
    │       1. 遍历所有 QMetaProperty
    │       2. 调用 groupProvider->getPropertyGroup(prop.name()) 获取分组名
    │       3. 空字符串 → 加入 ungroupedProps 列表
    │       4. 非空     → 加入对应 groupedProps[groupName] 列表
    │       5. 遍历 groupedProps：
    │          ├── builder->addGroup(groupName) → 创建 QDetailsViewRow_Group
    │          └── 在 group 内用子 LayoutBuilder 添加该组的属性
    │       6. 遍历 ungroupedProps：
    │          └── builder->addProperty() 直接添加到根（不分组）
```

#### QDetailsViewRow_Group 渲染

在 QML delegate 中通过 `isGroup` role 区分 group 行和普通属性行：

- **已展开**：显示粗体分组标题（如"颜色"），右侧无内容
- **已折叠**：显示粗体分组标题 + 右侧 `"(N)"` 显示子属性数量
- 展开/折叠箭头由 `makeNameValueSlot()` 中的图标控制（根据 `detailsDelegate.expanded` 选择 expand.png / unexpand.png）
- 点击行触发 `TapHandler { onTapped: detailsView.toggleExpanded(row) }`

**折叠计数实现**（`QQuickDetailsViewRow.cpp`）：
```qml
// 在 value slot 区域创建 countLabel
Item {
    property int groupChildCount: 0
    visible: !detailsDelegate.expanded    // 仅折叠时可见
    Text {
        anchors.right: parent.right
        text: "(" + groupChildCount + ")"
        color: ColorPalette.theme.textPrimary
    }
}
```
`groupChildCount` 在 C++ 侧通过 `countLabel->setProperty("groupChildCount", childCount)` 设置。

#### Model 角色扩展

ViewModel 新增 `isGroup` role：

```cpp
// QQuickDetailsViewModel
enum Roles { name = 0, isGroup };
// roleNames() 返回 { { Roles::isGroup, "isGroup" } }

// data() 分发
case Roles::isGroup: return node->isGroup();
```

`QQuickDetailsViewPrivate::updateRequiredProperties()` 在每个 delegate 初始化时通过 `setRequiredProperty("isGroup", ...)` 将值推送到 QML delegate。

#### setObject() 自动展开

`QQuickDetailsView::setObject()` 在切换检查对象后，遍历顶层 model 行，对所有 `isGroup()` 为 true 的行调用 `expand(row)`。这是一次性的 C++ 侧操作，在 delegate 创建之前完成，避免 delegate 重建时的重复展开循环。

#### BayTemplate 集成

**GraphicsBaseItem** 实现 `IPropertyGroupProvider`，默认返回空字符串（无分组）：

```cpp
class GraphicsBaseItem : public QObject, public AbstractShape, public IPropertyGroupProvider {
    QString getPropertyGroup(const QString&) const override { return {}; }
};
```

**GraphicsBusSectionItem** 重写 `getPropertyGroup()` 作为使用示例（`source/graphicsItem/graphicsBusSectionItem.cpp`）：

| 分组名 | 包含属性 |
|--------|---------|
| 数值 | Int, Float, LimitedDouble |
| 文本 | String, Directory |
| 向量/矩阵 | Vec2, Vec3, Vec4, Mat4 |
| 颜色 | Color, ColorList, ColorMap |
| 自定义类型 | CustomEnum, CustomType, CustomGadget, CustomGadgetPtr, CustomGadgetSharedPtr |

不分组（返回空）的属性：`m_lastBoudingRectF`, `m_lastBoudingPointF`, `m_dRatioX`, `m_dRatioY`（内部状态属性）。

**扩展方式**：任意 QObject 子类只需实现 `IPropertyGroupProvider` 接口并重写 `getPropertyGroup()`，PropertyEditor 的 `PropertyTypeCustomization_ObjectDefault` 会自动检测并使用分组布局。

### 关键文件索引

| 文件 | 角色 |
|------|------|
| `PropertyEditor/source/include/QDetailsView.h` | C++ QWidget 包装器 |
| `PropertyEditor/source/src/QDetailsView.cpp` | 创建 QQuickWidget，加载 QML DetailsView |
| `PropertyEditor/source/include/QQuickDetailsView.h` | QML 类型定义（Q_PROPERTY Object, SpliterPencent）|
| `PropertyEditor/source/src/QQuickDetailsView.cpp` | 设置 Delegate 模板 |
| `PropertyEditor/source/include/QQuickDetailsViewModel.h` | QAbstractItemModel 实现 |
| `PropertyEditor/source/src/QQuickDetailsViewModel.cpp` | setObject() 入口，构建根 Handle |
| `PropertyEditor/source/include/QPropertyHandle.h` | 属性操作统一入口（核心抽象）|
| `PropertyEditor/source/src/QPropertyHandle.cpp` | getter/setter 绑定，类型解析，子 Handle 创建 |
| `PropertyEditor/source/include/PropertyHandleImpl/IPropertyHandleImpl.h` | Impl 策略基类 |
| `PropertyEditor/source/src/PropertyHandleImpl/QPropertyHandleImpl_Object.cpp` | QObject/QGadget 的属性展开逻辑 |
| `PropertyEditor/source/src/PropertyHandleImpl/QPropertyHandleImpl_RawType.cpp` | 基本类型的值编辑器委托 |
| `PropertyEditor/source/src/QQuickDetailsViewRow.cpp` | 模型行节点（setupItem + attachChildren）|
| `PropertyEditor/source/src/QQuickDetailsViewLayoutBuilder.cpp` | QML 布局构建器 |
| `PropertyEditor/source/include/IPropertyTypeCustomization.h` | 类型定制接口 |
| `PropertyEditor/source/include/IPropertyGroupProvider.h` | 属性分组接口（QObject 声明属性所属分组）|
| `PropertyEditor/source/src/Customization/PropertyTypeCustomization_ObjectDefault.cpp` | 默认 QObject 属性展开（含分组检测逻辑）|
| `PropertyEditor/source/include/QQuickDetailsViewMananger.h` | 全局注册中心单例 |
| `PropertyEditor/source/src/QQuickDetailsViewMananger.cpp` | 类型编辑器注册、自定义类型查找 |
| `PropertyEditor/source/src/QQuickDetailsViewBasicTypeEditor.cpp` | 基本类型编辑器注册（int, float, QString, QColor 等）|
| `PropertyEditor/source/src/QQuickDetailsViewPrivate.h` | 内部的 Model + Delegate 回调 |
| `PropertyEditor/source/src/QQuickFunctionLibrary.cpp` | QML 辅助函数库 |
| `include/propertyType/CustomType.h` | BayTemplate 自定义测试类型 |
| `include/propertyType/CustomGadget.h` | BayTemplate 自定义测试 Gadget |
| `include/CommonInclude.h` | Q_PROPERTY_VAR 宏 |
| `source/propertyType/PropertyTypeCustomization_CustomType.cpp` | BayTemplate 对 QCustomType 的编辑器定制 |
| `include/graphicsItem/graphicsBusSectionItem.h` | 唯一声明了 Q_PROPERTY 的图元（测试用途）|
