# AutoUiPage 生成器

> 为 Godot UI 页面生成 `GetPage()` 样板，统一页面键与层级声明。

## 概述

`AutoUiPage` 面向 GFramework 的 UI 路由场景。
当一个 Godot `CanvasItem` 节点本质上就是一个页面时，开发者通常要重复声明：

- 页面 Key
- 页面所在 `UiLayer`
- `IUiPageBehavior` 缓存字段
- `GetPage()` 工厂包装

`AutoUiPage` 会把这部分样板迁移到编译期生成。
该特性当前位于 `GFramework.Godot.SourceGenerators.Abstractions.UI` 命名空间。

## 基础使用

```csharp
using GFramework.Godot.SourceGenerators.Abstractions.UI;
using GFramework.Game.Abstractions.Enums;
using Godot;

[AutoUiPage(nameof(UiKey.MainMenu), nameof(UiLayer.Page))]
public partial class MainMenu : Control
{
    public override void _Ready()
    {
        _ = GetPage();
    }
}
```

上面的 `nameof(UiKey.MainMenu)` 会生成字符串常量 `UiKeyStr`，`nameof(UiLayer.Page)` 则会在生成代码中解析为对应的枚举成员
`UiLayer.Page`，并传入页面行为工厂。

## 生成的代码

```csharp
// <auto-generated />
#nullable enable

partial class MainMenu
{
    private global::GFramework.Game.Abstractions.UI.IUiPageBehavior? __autoUiPageBehavior_Generated;

    public static string UiKeyStr => "MainMenu";

    public global::GFramework.Game.Abstractions.UI.IUiPageBehavior GetPage()
    {
        return __autoUiPageBehavior_Generated
            ??= global::GFramework.Godot.UI.UiPageBehaviorFactory.Create(
                this,
                UiKeyStr,
                global::GFramework.Game.Abstractions.Enums.UiLayer.Page);
    }
}
```

## 参数说明

`[AutoUiPage]` 需要两个字符串参数：

| 参数          | 类型       | 说明                          |
|-------------|----------|-----------------------------|
| `key`       | `string` | 页面 Key，例如 `"MainMenu"`      |
| `layerName` | `string` | `UiLayer` 枚举成员名，例如 `"Page"` |

推荐写法：

```csharp
[AutoUiPage(nameof(UiKey.Inventory), nameof(UiLayer.Overlay))]
```

这样可以避免硬编码字符串拼写错误。

## 适用场景

推荐用于：

- 主菜单、设置页、背包页、弹窗根节点
- Godot 场景中已经明确是“一个页面”的 `Control` / `CanvasLayer` / `Panel`
- 只需要标准页面行为包装，而不需要自定义复杂工厂逻辑的页面

不推荐用于：

- 临时子控件、列表项、纯视觉碎片节点
- 页面行为创建前必须注入额外上下文参数的节点
- 还未接入 GFramework UI 路由体系的老页面

## 使用约束

- 目标类型必须是 `partial class`
- 不支持嵌套类
- 目标类型必须继承 `Godot.CanvasItem`
- `layerName` 必须对应 `GFramework.Game.Abstractions.Enums.UiLayer` 上的有效成员名
- 不要自行声明同名 `GetPage()` 方法

## 生命周期边界

`AutoUiPage` 只生成页面行为样板，不会自动织入 Godot 生命周期。

它不会替你生成或调用：

- `_Ready()`
- `_ExitTree()`
- 页面打开关闭回调
- 节点注入或上下文注入

如果页面同时使用了 `[GetNode]`、`[BindNodeSignal]`、`[GetAll]` 等特性，仍然需要在你自己的生命周期方法中显式调用对应的生成方法。

## 诊断信息

| 诊断 ID                 | 含义                                 |
|-----------------------|------------------------------------|
| `GF_Common_Class_001` | 目标类型不是 `partial`，生成被跳过             |
| `GF_Common_Class_002` | 宿主类型已声明 `GetPage()`，与生成代码冲突        |
| `GF_AutoBehavior_001` | `AutoUiPage` 不支持嵌套类                |
| `GF_AutoBehavior_002` | 目标类型没有继承 `Godot.CanvasItem`        |
| `GF_AutoBehavior_003` | 提供的 `UiLayer` 名称无效                 |
| `GF_AutoBehavior_004` | `AutoUiPageAttribute` 参数数量或类型不符合要求 |

## 组合示例

```csharp
using GFramework.Godot.SourceGenerators.Abstractions.UI;
using GFramework.Game.Abstractions.Enums;
using GFramework.Core.SourceGenerators.Abstractions.Rule;
using Godot;

[ContextAware]
[GetAll]
[AutoUiPage(nameof(UiKey.PauseMenu), nameof(UiLayer.Modal))]
public partial class PauseMenu : Control
{
    [GetNode]
    private Button _resumeButton = null!;

    public override void _Ready()
    {
        __InjectGetNodes_Generated();
        __InjectContextBindings_Generated();

        _ = GetPage();
    }
}
```

## 相关文档

- [源码生成器总览](./index)
- [GetNode 生成器](./get-node-generator)
- [BindNodeSignal 生成器](./bind-node-signal-generator)
