# TransformGizmo 事件钩子使用说明

本文档说明如何在 `TransformGizmo` 初始化时注入拖拽事件回调（类似 C# 委托），以及各事件的负载字段。

## 事件常量

所有事件名集中在 `TransformGizmo.events.GizmoEvent`，避免拼写错误：

```python
from src.TransformGizmo.events import GizmoEvent

GizmoEvent.DRAG_START  # "drag_start"
GizmoEvent.DRAG_MOVE  # "drag_move"
GizmoEvent.DRAG_END  # "drag_end"
GizmoEvent.ALL  # ("drag_start", "drag_move", "drag_end")
```

## 基础用法示例

在构造 `TransformGizmo` 时传入 `event_hooks`，按 handle 类型分组（`"move"`, `"rotate"`, `"scale"` 或对应 `TransformGizmoMode` 值），每组里是事件名到回调列表的映射：

```python
from src.TransformGizmo.transform_gizmo import TransformGizmo, TransformGizmoMode
from src.TransformGizmo.events import GizmoEvent


def on_move_start(info):
    print("[move] start", "axis", info["axis"], "plane", info["plane"])


def on_move_drag(info):
    print("[move] pos ->", info["new_pos"])


def on_rotate_drag(info):
    print("[rotate] delta_deg =", info["delta_deg"])


def on_scale_end(info):
    print("[scale] final_scale =", info["final_scale"])


hooks = {
    TransformGizmoMode.MOVE: {
        GizmoEvent.DRAG_START: [on_move_start],
        GizmoEvent.DRAG_MOVE: [on_move_drag],
    },
    TransformGizmoMode.ROTATE: {
        GizmoEvent.DRAG_MOVE: [on_rotate_drag],
    },
    TransformGizmoMode.SCALE: {
        GizmoEvent.DRAG_END: [on_scale_end],
    },
}

# world: 你的 Panda3DWorld 实例
gizmo = TransformGizmo(world, event_hooks=hooks)
```

### 运行时追加 / 移除

初始化后也可以直接操作子 gizmo 的钩子列表：

```python
from src.TransformGizmo.events import GizmoEvent

gizmo.move_gizmo._event_hooks[GizmoEvent.DRAG_MOVE].append(on_move_drag)
# 移除同理，用 list.remove(on_move_drag)
```

## 回调负载字段

各事件都会传入一个 `dict`，常见字段如下（不存在的字段将为 `None` 或缺省）：

### Move
- `axis`：0/1/2（X/Y/Z），平面拖拽时为 `None`
- `plane`：0/1/2（XY/YZ/ZX），轴拖拽时为 `None`
- `mouse`：`Point2`，拖拽开始/过程中鼠标 NDC 坐标
- `start_pos` / `new_pos` / `final_pos`：世界坐标 `Vec3`
- `target`：当前绑定的 `NodePath`
- `gizmo`：字符串 `"move"`

### Rotate
- `mode`：`"axis"` 或 `"trackball"`
- `axis`：0/1/2（X/Y/Z），轨迹球时为 `None`
- `delta_deg`：本次 `drag_move` 的角度增量（度）
- `start_quat`：拖拽开始时的世界四元数
- `final_hpr`：拖拽结束时的世界 HPR（仅 `drag_end`）
- `center`：gizmo 中心点（世界坐标）
- `axis_world`：当前旋转轴的世界方向
- `mouse`：`Point2`
- `target`，`gizmo` 同上

### Scale
- `axis`：0/1/2 对应 X/Y/Z，3 表示中心均匀缩放
- `scale_factor`：本次 `drag_move` 计算出的缩放倍率
- `start_scale` / `new_scale` / `final_scale`：`Vec3`
- `mouse`：`Point2`
- `target`，`gizmo` 同上

## 小贴士
- 事件字典的键可以用字符串 `"move"`/`"rotate"`/`"scale"`，也可以用 `TransformGizmoMode` 的对应值，内部都会匹配。
- 每个事件支持多个回调（列表），内部对单个回调异常做了 try/except，互不影响。
- 如果只想监听部分事件，留空即可，内部会自动填充为空列表。
