# 画面設計書: カーブエディタ

## 基本情報

| 項目 | 内容 |
|------|------|
| 画面ID | 46 |
| 画面名 | カーブエディタ |
| ファイルパス | `editor/scene/curve_editor_plugin.h`, `editor/scene/curve_editor_plugin.cpp` |
| 主要クラス | `CurveEdit`, `CurveEditor`, `EditorInspectorPluginCurve`, `CurveEditorPlugin`, `CurvePreviewGenerator` |
| 基底クラス | `Control`, `VBoxContainer`, `EditorInspectorPlugin`, `EditorPlugin`, `EditorResourcePreviewGenerator` |

## 概要

カーブエディタはCurveリソースを編集するためのインスペクタプラグインです。インスペクタパネル内に直接描画され、ポイントの追加・削除・移動、タンジェント（接線）の調整、プリセットカーブの適用などを行えます。グリッドスナップ機能やプレビュー生成機能も備えています。

### 主な機能

1. **ポイント編集**: カーブ上のポイントを追加・削除・移動
2. **タンジェント編集**: 左右のタンジェント（接線）を個別または同期して調整
3. **プリセット適用**: Constant, Linear, Ease In, Ease Out, Smoothstep
4. **グリッドスナップ**: 設定可能なグリッドへのスナップ
5. **プレビュー生成**: リソースプレビュー用サムネイル生成

## 画面構成

### レイアウト構造

```
+------------------------------------------------------------------+
| CurveEditor (VBoxContainer)                                       |
+------------------------------------------------------------------+
| HFlowContainer (toolbar)                                          |
| +--------+-----+--------------+---------------------------+       |
| |SnapBtn |Sep  |SnapCount     | Presets                   |       |
| |[toggle]|     |[___10_]      | [Presets v]               |       |
| +--------+-----+--------------+---------------------------+       |
+------------------------------------------------------------------+
| CurveEdit (Control)                                               |
| +--------------------------------------------------------------+ |
| |  1.0 +------------------------------------------------+       | |
| |      |                    *---------*                 |       | |
| |  0.5 |               *                                |       | |
| |      |          *                                     |       | |
| |  0.0 |     *                                          |       | |
| |      +------------------------------------------------+       | |
| |      0.0        0.25       0.5        0.75       1.0          | |
| +--------------------------------------------------------------+ |
+------------------------------------------------------------------+
| Control (empty_space - spacing)                                   |
+------------------------------------------------------------------+
```

## 表示項目

### ツールバー

| 項目 | 種類 | 説明 | ソースコード参照 |
|------|------|------|------------------|
| snap_button | Button | グリッドスナップ切替 | L156, L998-1002 |
| snap_count_edit | EditorSpinSlider | スナップ分割数（2-100） | L157, L1006-1013 |
| presets_button | MenuButton | プリセットメニュー | L158, L1015-1020 |

### カーブ編集領域（CurveEdit）

| 項目 | 種類 | 説明 | ソースコード参照 |
|------|------|------|------------------|
| curve | Ref<Curve> | 編集対象のカーブリソース | L113 |
| selected_index | int | 選択中のポイントインデックス | L115 |
| hovered_index | int | ホバー中のポイントインデックス | L116 |
| selected_tangent_index | TangentIndex | 選択中のタンジェント | L117 |
| hovered_tangent_index | TangentIndex | ホバー中のタンジェント | L118 |

### 描画パラメータ

| パラメータ | 基本値 | 説明 | ソースコード参照 |
|-----------|--------|------|------------------|
| ASPECT_RATIO | 6.0/13.0 | アスペクト比 | L107 |
| LINE_WIDTH | 0.5 | 線幅 | L108 |
| STEP_SIZE | 2 | プロットステップ（ピクセル） | L109 |
| BASE_POINT_RADIUS | 4 | ポイント半径 | L121 |
| BASE_HOVER_RADIUS | 10 | ホバー判定半径 | L122 |
| BASE_TANGENT_RADIUS | 3 | タンジェント半径 | L123 |
| BASE_TANGENT_HOVER_RADIUS | 8 | タンジェントホバー判定半径 | L124 |
| BASE_TANGENT_LENGTH | 36 | タンジェント線長 | L125 |

## プリセット

| ID | 名前 | 説明 | ソースコード参照 |
|----|------|------|------------------|
| PRESET_CONSTANT | Constant | 水平な一定値カーブ | L58, L376-381 |
| PRESET_LINEAR | Linear | 左下から右上への直線 | L59, L383-388 |
| PRESET_EASE_IN | Ease In | ゆっくり始まり急加速 | L60, L390-393 |
| PRESET_EASE_OUT | Ease Out | 急に始まりゆっくり終了 | L61, L395-398 |
| PRESET_SMOOTHSTEP | Smoothstep | S字カーブ | L62, L400-403 |

## タンジェントタイプ

| ID | 名前 | 説明 | ソースコード参照 |
|----|------|------|------------------|
| TANGENT_NONE | なし | タンジェント未選択 | L67 |
| TANGENT_LEFT | 左 | 左側タンジェント | L68 |
| TANGENT_RIGHT | 右 | 右側タンジェント | L69 |

## グラブモード

| モード | 説明 | ソースコード参照 |
|--------|------|------------------|
| GRAB_NONE | 何も掴んでいない | L134 |
| GRAB_ADD | 新しいポイントを追加中 | L135 |
| GRAB_MOVE | ポイントを移動中 | L136 |

## イベント仕様

### マウス操作

| 操作 | 処理 | ソースコード参照 |
|------|------|------------------|
| 左クリック（空白） | 新規ポイント追加 | L237-252 |
| 左クリック（ポイント） | ポイント選択 | L217-224 |
| 左クリック（タンジェント） | タンジェント選択 | L219-222 |
| 左ドラッグ | ポイント/タンジェント移動 | L286-352 |
| 左ボタン解放 | 編集確定（Undo/Redo登録） | L256-278 |
| 右クリック（ポイント） | ポイント削除 | L199-211 |
| 右クリック（タンジェント） | リニアモード切替 | L196-197 |
| 中クリック（ポイント） | ポイント削除 | L185-213 |
| 移動中に右クリック | 移動キャンセル（元位置に戻る） | L186-192 |

### キーボード操作

| キー | 処理 | ソースコード参照 |
|------|------|------------------|
| Delete | ポイント削除 / タンジェントをリニアに | L159-174 |
| Shift（押下中） | 軸方向に制約（縦または横移動のみ） | L297-304 |
| Alt（押下中） | 隣接ポイント間に制約 | L307-311 |
| Ctrl/Cmd（押下中） | スナップ有効/無効切替 | L240-243, L291-294 |

### タンジェント編集

| 操作 | 処理 | ソースコード参照 |
|------|------|------------------|
| タンジェントドラッグ | タンジェント角度変更 | L324-351 |
| Shift+タンジェントドラッグ | 反対側タンジェントを初期角度維持 | L341-350 |

## Undo/Redo アクション

| アクション名 | 処理内容 | ソースコード参照 |
|-------------|----------|------------------|
| "Load Curve Preset" | プリセット適用 | L410 |
| "Add Curve Point" | ポイント追加 | L514 |
| "Remove Curve Point" | ポイント削除 | L538 |
| "Modify Curve Point" | ポイント位置変更 | L559 |
| "Modify Curve Point's Tangents" | 両タンジェント変更 | L584 |
| "Modify Curve Point's Left Tangent" | 左タンジェント変更 | L604 |
| "Modify Curve Point's Right Tangent" | 右タンジェント変更 | L622 |
| "Toggle Linear Curve Point's Tangent" | リニアモード切替 | L639 |

## メッセージ仕様

| メッセージ | 表示条件 | ソースコード参照 |
|------------|----------|------------------|
| "Toggle Grid Snap" | スナップボタンツールチップ | L999 |
| "Hold Shift to edit tangents individually" | タンジェントホバー時 | L912 |
| "(%.2f, %.2f)" | ポイント選択時（座標表示） | L919 |
| "%.1f °" | タンジェント選択時（角度表示） | L926 |

## アイコン設定

| アイコン名 | 用途 | ソースコード参照 |
|------------|------|------------------|
| SnapGrid | スナップボタン | L971 |
| CurveConstant | Constantプリセット | L974 |
| CurveLinear | Linearプリセット | L975 |
| CurveIn | Ease Inプリセット | L976 |
| CurveOut | Ease Outプリセット | L977 |
| CurveInOut | Smoothstepプリセット | L978 |

## 描画処理

### グリッド描画

```
1. 背景描画（Tree panelスタイルボックス）
2. プライマリグリッド描画（境界線）
3. セカンダリグリッド描画（4x2分割）
4. 数値ラベル描画（X: 0.0-1.0、Y: 範囲に応じて）
```

### カーブ描画

```
1. エッジライン描画（最初と最後のポイントから境界まで）
2. セクションごとにプロット（精度を優先）
3. 非選択ポイント描画（四角形）
4. ホバーポイントハイライト描画
5. 選択ポイント描画
6. タンジェント線描画
7. タンジェントコントロール描画（円：Free、四角：Linear）
8. ヘルプテキスト描画
9. 制約線描画（Shift/Alt押下時）
```

## スナップ設定

| 設定 | デフォルト値 | 範囲 | メタキー |
|------|-------------|------|----------|
| snap_enabled | false | - | _snap_enabled |
| snap_count | 10 | 2-100 | _snap_count |

スナップ設定はカーブリソースのメタデータとして保存されます。

## 座標変換

| 関数 | 処理 | ソースコード参照 |
|------|------|------------------|
| get_view_pos() | ワールド座標からビュー座標へ変換 | L724-726 |
| get_world_pos() | ビュー座標からワールド座標へ変換 | L728-730 |
| update_view_transform() | 変換行列を更新 | L666-690 |

## プレビュー生成

CurvePreviewGeneratorはCurveリソースのサムネイルを生成します。

| 処理 | 説明 | ソースコード参照 |
|------|------|------------------|
| handles() | "Curve"タイプのみ処理 | L1061-1063 |
| generate() | Bresenhamアルゴリズムでカーブ描画 | L1065-1098 |

## コードリーディングガイド

### 推奨読解順序

1. **データ構造** (curve_editor_plugin.h L42-146)
   - CurveEditクラス: 描画とインタラクション
   - PresetID, TangentIndex, GrabMode enum

2. **CurveEditorクラス** (curve_editor_plugin.h L148-173)
   - ツールバー構成
   - CurveEditとの連携

3. **インスペクタプラグイン** (curve_editor_plugin.h L175-198)
   - EditorInspectorPluginCurve
   - CurveEditorPlugin
   - CurvePreviewGenerator

4. **コンストラクタ** (curve_editor_plugin.cpp L994-1033)
   - UI構築
   - シグナル接続

5. **入力処理** (curve_editor_plugin.cpp L150-361)
   - gui_input()メソッド
   - マウス/キーボードイベント

6. **描画処理** (curve_editor_plugin.cpp L775-944)
   - _redraw()メソッド
   - グリッド、カーブ、ポイント描画

7. **Undo/Redo操作** (curve_editor_plugin.cpp L506-657)
   - add_point(), remove_point()
   - set_point_position(), set_point_tangents()

### プログラム呼び出し階層図

```
EditorInspectorPluginCurve::parse_begin()
└── CurveEditor::set_curve()
    └── CurveEdit::set_curve()
        ├── curve->connect_changed()
        └── queue_redraw()

CurveEdit::gui_input() [マウス左クリック]
├── get_point_at() / get_tangent_at()
├── [空白クリック] add_point()
│   └── EditorUndoRedoManager::create_action("Add Curve Point")
├── [ポイント選択] set_selected_index()
│   └── queue_redraw()
└── [ドラッグ終了] set_point_position()
    └── EditorUndoRedoManager::create_action("Modify Curve Point")

CurveEditor::_on_preset_item_selected()
└── CurveEdit::use_preset()
    └── EditorUndoRedoManager::create_action("Load Curve Preset")
        ├── curve->clear_points()
        ├── curve->add_point() [preset points]
        └── commit_action()

CurveEdit::_notification(NOTIFICATION_DRAW)
└── _redraw()
    ├── update_view_transform()
    ├── draw_style_box() [背景]
    ├── draw_line() [グリッド]
    ├── draw_string() [数値ラベル]
    ├── plot_curve_accurate() [カーブ線]
    ├── draw_rect() / draw_circle() [ポイント/タンジェント]
    └── draw_multiline_string() [ヘルプテキスト]
```

### データフロー図

```
[Curveリソース]
    |
    | (set_curve)
    v
[CurveEdit]
    |
    +----> [描画] --> [ビューポート表示]
    |        ^
    |        | (queue_redraw)
    |        |
    +----> [入力処理]
    |        |
    |        v
    +----> [Undo/Redo] --> [EditorUndoRedoManager]
    |        |
    |        v
    +<---- [カーブ更新] <---- [curve->set_point_*()]
```

### 関連ファイル一覧

| ファイル | 役割 |
|----------|------|
| `editor/scene/curve_editor_plugin.h` | エディタクラス定義 |
| `editor/scene/curve_editor_plugin.cpp` | エディタ実装 |
| `scene/resources/curve.h` | Curveリソース定義 |
| `scene/resources/curve.cpp` | Curveリソース実装 |
| `editor/inspector/editor_inspector.h` | インスペクタプラグイン基底 |
| `editor/inspector/editor_resource_preview.h` | プレビュー生成基底 |
| `editor/gui/editor_spin_slider.h` | スピンスライダー |
| `editor/editor_undo_redo_manager.h` | Undo/Redo管理 |
