# 画面設計書: スプライトフレームエディタ

## 基本情報

| 項目 | 内容 |
|------|------|
| 画面ID | 45 |
| 画面名 | スプライトフレームエディタ |
| ファイルパス | `editor/scene/sprite_frames_editor_plugin.h`, `editor/scene/sprite_frames_editor_plugin.cpp` |
| 主要クラス | `SpriteFramesEditor`, `SpriteFramesEditorPlugin` |
| 基底クラス | `EditorDock`, `EditorPlugin` |

## 概要

スプライトフレームエディタはSpriteFramesリソースを編集するためのエディタです。AnimatedSprite2DやAnimatedSprite3Dで使用するスプライトアニメーションを作成・管理します。アニメーション一覧とフレーム一覧の2ペイン構成で、スプライトシートからのフレーム抽出機能や再生プレビュー機能を備えています。

### 主な機能

1. **アニメーション管理**: 複数のアニメーション（歩行、ジャンプ等）の作成・複製・削除
2. **フレーム編集**: フレームの追加・削除・並び替え・持続時間設定
3. **スプライトシート分割**: テクスチャからフレームを自動抽出
4. **アニメーション再生**: 前進/後退再生、自動再生設定
5. **ドラッグ&ドロップ**: ファイルシステムからの画像インポート

## 画面構成

### レイアウト構造

```
+------------------------------------------------------------------+
| EditorDock (SpriteFrames)                                         |
+------------------------------------------------------------------+
| HSplitContainer (main_split)                                      |
| +--------------------+-------------------------------------------+|
| | VBoxContainer      | VBoxContainer (anim_frames_vb)            ||
| | (vbc_animlist)     |                                           ||
| | +----------------+ | HFlowContainer (hfc)                       ||
| | |Animations:     | | +-------+-------+-------+-------+-------+ ||
| | +----------------+ | |Playback|Load  |Copy   |Empty  |Zoom   | ||
| | |HBoxContainer   | | +-------+-------+-------+-------+-------+ ||
| | |[+][D][X][C][V] | | Frame Duration: [x___]                    ||
| | |[Del][Sep]      | | +---------------------------------------+ ||
| | |[Loop][FPS]     | | | ItemList (frame_list)                 | ||
| | +----------------+ | |                                        | ||
| | |LineEdit Search | | |                                        | ||
| | +----------------+ | |                                        | ||
| | | Tree           | | |                                        | ||
| | | (animations)   | | +---------------------------------------+ ||
| | +----------------+ |                                           ||
| +--------------------+-------------------------------------------+|
+------------------------------------------------------------------+
```

## 表示項目

### アニメーションパネル（左側）

| 項目 | 種類 | 説明 | ソースコード参照 |
|------|------|------|------------------|
| add_anim | Button | アニメーション追加 | L138, L2144-2148 |
| duplicate_anim | Button | アニメーション複製 | L139, L2150-2155 |
| cut_anim | Button | アニメーション切り取り | L140, L2157-2161 |
| copy_anim | Button | アニメーションコピー | L141, L2163-2167 |
| paste_anim | Button | アニメーション貼り付け | L142, L2169-2173 |
| delete_anim | Button | アニメーション削除 | L143, L2175-2180 |
| autoplay | Button | 自動再生トグル | L148, L2187-2190 |
| anim_loop | Button | ループ設定 | L145, L2194-2199 |
| anim_speed | SpinBox | 再生速度(FPS) | L144, L2201-2211 |
| anim_search_box | LineEdit | アニメーション検索 | L150, L2213-2218 |
| animations | Tree | アニメーション一覧 | L151, L2220-2229 |
| missing_anim_label | Label | アニメーション未登録表示 | L153, L2244-2252 |

### フレームパネル（右側）

| 項目 | 種類 | 説明 | ソースコード参照 |
|------|------|------|------------------|
| playback_container | HBoxContainer | 再生コントロール | L114, L2265-2297 |
| stop | Button | 停止/一時停止 | L115, L2277-2279 |
| play | Button | 最初から再生 | L116, L2281-2283 |
| play_from | Button | 現在位置から再生 | L117, L2285-2287 |
| play_bw | Button | 逆再生（最初から） | L118, L2273-2275 |
| play_bw_from | Button | 逆再生（現在位置から） | L119, L2269-2271 |
| load | Button | 画像読み込み | L121, L2302-2305 |
| load_sheet | Button | スプライトシート読み込み | L122, L2307-2310 |
| copy | Button | フレームコピー | L124, L2314-2317 |
| paste | Button | フレーム貼り付け | L125, L2319-2322 |
| empty_before | Button | 空フレーム挿入（前） | L126, L2326-2329 |
| empty_after | Button | 空フレーム挿入（後） | L127, L2331-2334 |
| move_up | Button | フレーム左移動 | L128, L2338-2341 |
| move_down | Button | フレーム右移動 | L129, L2343-2346 |
| delete_frame | Button | フレーム削除 | L123, L2348-2351 |
| frame_duration | SpinBox | フレーム持続時間 | L133, L2362-2372 |
| zoom_out | Button | 縮小 | L130, L2383-2387 |
| zoom_reset | Button | ズームリセット | L131, L2389-2393 |
| zoom_in | Button | 拡大 | L132, L2395-2399 |
| frame_list | ItemList | フレーム一覧 | L134, L2405-2420 |

### スプライトシート分割ダイアログ

| 項目 | 種類 | 説明 | ソースコード参照 |
|------|------|------|------------------|
| split_sheet_dialog | ConfirmationDialog | スプライトシート選択ダイアログ | L166, L2476-2480 |
| split_sheet_preview | TextureRect | プレビュー表示 | L168, L2537-2542 |
| split_sheet_scroll | ScrollContainer | スクロールコンテナ | L167, L2544-2551 |
| split_sheet_h | SpinBox | 水平分割数 | L170, L2600-2609 |
| split_sheet_v | SpinBox | 垂直分割数 | L171, L2618-2627 |
| split_sheet_size_x | SpinBox | フレーム幅 | L172, L2639-2647 |
| split_sheet_size_y | SpinBox | フレーム高さ | L173, L2648-2656 |
| split_sheet_sep_x | SpinBox | 水平間隔 | L174, L2670-2677 |
| split_sheet_sep_y | SpinBox | 垂直間隔 | L175, L2678-2685 |
| split_sheet_offset_x | SpinBox | 水平オフセット | L176, L2699-2706 |
| split_sheet_offset_y | SpinBox | 垂直オフセット | L177, L2707-2714 |
| split_sheet_order | OptionButton | フレーム順序 | L183, L2496-2509 |
| split_sheet_zoom_out | Button | シートズームアウト | L178, L2562-2567 |
| split_sheet_zoom_reset | Button | シートズームリセット | L179, L2569-2574 |
| split_sheet_zoom_in | Button | シートズームイン | L180, L2576-2581 |
| split_sheet_zoom_fit | Button | フィットズーム | L181, L2583-2588 |
| toggle_settings_button | Button | 設定パネルトグル | L182, L2523-2528 |

## イベント仕様

### アニメーション操作

| イベント | 関数名 | 処理内容 |
|----------|--------|----------|
| アニメーション選択 | `_animation_selected()` | 選択されたアニメーションを編集対象に設定 |
| 名前編集完了 | `_animation_name_edited()` | アニメーション名をリネーム |
| 追加ボタン | `_animation_add()` | 新規アニメーション作成（"new_animation"） |
| 複製ボタン | `_animation_duplicate()` | 現在のアニメーションを複製 |
| 切り取りボタン | `_animation_cut()` | クリップボードにコピーして削除 |
| コピーボタン | `_animation_copy()` | クリップボードにコピー |
| 貼り付けボタン | `_animation_paste()` | クリップボードから貼り付け |
| 削除ボタン | `_animation_remove()` | 確認ダイアログ表示後削除 |
| ループ変更 | `_animation_loop_changed()` | ループフラグを切替 |
| 速度変更 | `_animation_speed_changed()` | 再生速度(FPS)を変更 |
| 検索テキスト変更 | `_animation_search_text_changed()` | アニメーション一覧をフィルタ |

### フレーム操作

| イベント | 関数名 | 処理内容 |
|----------|--------|----------|
| 画像読み込み | `_load_pressed()` | ファイルダイアログを開く |
| ファイル選択完了 | `_file_load_request()` | 選択された画像をフレームに追加 |
| コピー | `_copy_pressed()` | 選択フレームをクリップボードにコピー |
| 貼り付け | `_paste_pressed()` | クリップボードからフレームを追加 |
| 空フレーム挿入(前) | `_empty_pressed()` | 選択位置前に空フレームを挿入 |
| 空フレーム挿入(後) | `_empty2_pressed()` | 選択位置後に空フレームを挿入 |
| フレーム削除 | `_delete_pressed()` | 選択フレームを削除 |
| 上へ移動 | `_up_pressed()` | フレームを左（前）に移動 |
| 下へ移動 | `_down_pressed()` | フレームを右（後）に移動 |
| 持続時間変更 | `_frame_duration_changed()` | フレームの持続時間を変更 |
| フレーム選択 | `_frame_list_item_selected()` | 選択状態を更新、持続時間SpinBoxに反映 |
| 右クリック | `_frame_list_gui_input()` | コンテキストメニュー表示 |

### 再生操作

| イベント | 関数名 | 処理内容 |
|----------|--------|----------|
| 再生(最初から) | `_play_pressed()` | アニメーションを最初から再生 |
| 再生(現在位置) | `_play_from_pressed()` | 現在位置から再生を継続 |
| 逆再生(最初から) | `_play_bw_pressed()` | アニメーションを最後から逆再生 |
| 逆再生(現在位置) | `_play_bw_from_pressed()` | 現在位置から逆再生 |
| 停止 | `_stop_pressed()` | 再生中なら一時停止、そうでなければ停止 |
| 自動再生 | `_autoplay_pressed()` | 自動再生フラグを切替 |

### スプライトシート分割

| イベント | 関数名 | 処理内容 |
|----------|--------|----------|
| シート読み込み | `_open_sprite_sheet()` | ファイルダイアログを開く |
| シート準備 | `_prepare_sprite_sheet()` | テクスチャを読み込みダイアログ表示 |
| 自動分割 | `_auto_slice_sprite_sheet()` | 背景色を検出して自動分割 |
| フレーム選択 | `_sheet_preview_input()` | クリック/ドラッグでフレーム選択 |
| フレーム追加 | `_sheet_add_frames()` | 選択フレームをアニメーションに追加 |
| 順序変更 | `_sheet_order_selected()` | フレーム順序オプション変更 |
| 全選択 | `_sheet_select_all_frames()` | すべてのフレームを選択 |
| 選択解除 | `_sheet_clear_all_frames()` | すべての選択を解除 |
| ズーム | `_sheet_zoom_in/out/reset/fit()` | プレビューのズームを調整 |
| 設定トグル | `_toggle_show_settings()` | 設定パネルの表示/非表示切替 |

### ドラッグ&ドロップ

| イベント | 関数名 | 処理内容 |
|----------|--------|----------|
| ドラッグ開始 | `get_drag_data_fw()` | 選択フレームのドラッグデータ作成 |
| ドロップ判定 | `can_drop_data_fw()` | Texture2Dまたはファイルのドロップ可否 |
| ドロップ実行 | `drop_data_fw()` | フレームの追加または並び替え |

## キーボードショートカット

### アニメーション操作（animationsコンテキスト）

| キー | 機能 | ソースコード参照 |
|------|------|------------------|
| Ctrl+N | アニメーション追加 | L2232 |
| Ctrl+D | アニメーション複製 | L2234 |
| Ctrl+X | アニメーション切り取り | L2236 |
| Ctrl+C | アニメーションコピー | L2238 |
| Ctrl+V | アニメーション貼り付け | L2240 |
| Delete | アニメーション削除 | L2242 |

### フレーム操作（frame_listコンテキスト）

| キー | 機能 | ソースコード参照 |
|------|------|------------------|
| Ctrl+O | ファイルから追加 | L2441 |
| Ctrl+Shift+O | スプライトシートから追加 | L2443 |
| Delete | フレーム削除 | L2445 |
| Ctrl+C | フレームコピー | L2447 |
| Ctrl+V | フレーム貼り付け | L2449 |
| Alt+Left | 空フレーム挿入（前） | L2451 |
| Alt+Right | 空フレーム挿入（後） | L2453 |
| Ctrl+Left | フレーム左移動 | L2455 |
| Ctrl+Right | フレーム右移動 | L2457 |
| Ctrl+- | ズームアウト | L2460-2461 |
| Ctrl+= | ズームイン | L2463-2464 |

### 再生操作

| キー | 機能 | ソースコード参照 |
|------|------|------------------|
| A | 逆再生（現在位置） | L2435 |
| Shift+A | 逆再生（最後から） | L2436 |
| S | 停止/一時停止 | L2437 |
| D | 再生（現在位置） | L2439 |
| Shift+D | 再生（最初から） | L2438 |

## スプライトシートフレーム順序オプション

| ID | オプション名 | 説明 |
|----|--------------|------|
| FRAME_ORDER_SELECTION | As Selected | 選択順 |
| FRAME_ORDER_LEFT_RIGHT_TOP_BOTTOM | Left to Right, Top to Bottom | 左上から右下へ |
| FRAME_ORDER_LEFT_RIGHT_BOTTOM_TOP | Left to Right, Bottom to Top | 左下から右上へ |
| FRAME_ORDER_RIGHT_LEFT_TOP_BOTTOM | Right to Left, Top to Bottom | 右上から左下へ |
| FRAME_ORDER_RIGHT_LEFT_BOTTOM_TOP | Right to Left, Bottom to Top | 右下から左上へ |
| FRAME_ORDER_TOP_BOTTOM_LEFT_RIGHT | Top to Bottom, Left to Right | 左上から縦方向に |
| FRAME_ORDER_TOP_BOTTOM_RIGHT_LEFT | Top to Bottom, Right to Left | 右上から縦方向に |
| FRAME_ORDER_BOTTOM_TOP_LEFT_RIGHT | Bottom to Top, Left to Right | 左下から縦方向に |
| FRAME_ORDER_BOTTOM_TOP_RIGHT_LEFT | Bottom to Top, Right to Left | 右下から縦方向に |

## データ構造

### ClipboardSpriteFrames

```cpp
class ClipboardSpriteFrames : public Resource {
    struct Frame {
        Ref<Texture2D> texture;  // フレームテクスチャ
        float duration;          // 持続時間倍率
    };
    Vector<Frame> frames;        // フレーム配列
};
```

### ClipboardAnimation

```cpp
class ClipboardAnimation : public Resource {
    String name;                              // アニメーション名
    Vector<ClipboardSpriteFrames::Frame> frames;  // フレーム配列
    float speed = 1.0f;                       // 再生速度
    bool loop = false;                        // ループフラグ
};
```

## Undo/Redo アクション

| アクション名 | 処理内容 |
|-------------|----------|
| "Add Frame" | フレームを追加 |
| "Paste Frame(s)" | フレーム配列を貼り付け |
| "Paste Texture" | テクスチャを貼り付け |
| "Add Empty" | 空フレームを追加 |
| "Move Frame" | フレームを移動 |
| "Delete Resource" | フレームを削除 |
| "Set Frame Duration" | フレーム持続時間を設定 |
| "Add Animation" | アニメーションを追加 |
| "Duplicate Animation" | アニメーションを複製 |
| "Cut Animation" | アニメーションを切り取り |
| "Paste Animation" | アニメーションを貼り付け |
| "Remove Animation" | アニメーションを削除 |
| "Rename Animation" | アニメーションをリネーム |
| "Change Animation Loop" | ループ設定を変更 |
| "Change Animation FPS" | FPSを変更 |
| "Toggle Autoplay" | 自動再生を切替 |

## メッセージ仕様

| メッセージ | 表示条件 | ソースコード参照 |
|------------|----------|------------------|
| "ERROR: Couldn't load frame resource!" | 画像読み込み失敗時 | L780 |
| "Delete Animation?" | アニメーション削除確認 | L1353 |
| "This resource does not have any animations." | アニメーション未登録時 | L2246 |
| "No Frames Selected" | シートダイアログでフレーム未選択時 | L138 |
| "Add %d Frame(s)" | シートダイアログOKボタンテキスト | L174 |
| "Unable to load images" | スプライトシート読み込み失敗時 | L638 |

## アイコン設定

| アイコン名 | 用途 | ソースコード参照 |
|------------|------|------------------|
| AutoPlay | 自動再生アイコン | L695, L700 |
| Stop | 停止アイコン | L696 |
| Pause | 一時停止アイコン | L697 |
| Loop | ループアイコン | L701 |
| PlayStart | 最初から再生 | L702 |
| Play | 現在位置から再生 | L703 |
| PlayStartBackwards | 最後から逆再生 | L704 |
| PlayBackwards | 現在位置から逆再生 | L705 |
| Load | 画像読み込み | L707 |
| SpriteSheet | スプライトシート | L708 |
| ActionCopy | コピー | L709, L722 |
| ActionPaste | 貼り付け | L710, L723 |
| InsertBefore | 前に挿入 | L711 |
| InsertAfter | 後に挿入 | L712 |
| MoveLeft | 左移動 | L713 |
| MoveRight | 右移動 | L714 |
| Remove | 削除 | L715, L724 |
| ZoomLess | ズームアウト | L716, L726 |
| ZoomReset | ズームリセット | L717 |
| ZoomMore | ズームイン | L718, L727 |
| New | 新規 | L719 |
| Duplicate | 複製 | L720 |
| ActionCut | 切り取り | L721 |
| Search | 検索 | L725 |
| DistractionFree | フィットズーム | L728 |

## ズーム設定

| パラメータ | デフォルト値 | 説明 |
|-----------|-------------|------|
| scale_ratio | 1.2f | ズーム倍率 |
| thumbnail_default_size | 96 * EDSCALE | サムネイルデフォルトサイズ |
| thumbnail_zoom | MAX(1.0f, EDSCALE) | サムネイルズーム初期値 |
| max_thumbnail_zoom | 8.0f * EDSCALE | サムネイル最大ズーム |
| min_thumbnail_zoom | 0.1f * EDSCALE | サムネイル最小ズーム |
| sheet_zoom | MAX(1.0f, EDSCALE) | シートズーム初期値 |
| max_sheet_zoom | 128.0f * EDSCALE | シート最大ズーム |
| min_sheet_zoom | 0.01f * EDSCALE | シート最小ズーム |

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

### 推奨読解順序

1. **データ構造の理解** (sprite_frames_editor_plugin.h L49-70)
   - `ClipboardSpriteFrames`: フレームコピー用構造体
   - `ClipboardAnimation`: アニメーションコピー用構造体

2. **エディタクラス定義** (sprite_frames_editor_plugin.h L72-313)
   - メンバ変数（UI要素、状態管理）
   - メソッド宣言（イベントハンドラ）

3. **コンストラクタ** (sprite_frames_editor_plugin.cpp L2121-2748)
   - UI構築の流れを追う
   - EditorDock設定
   - シグナル接続

4. **アニメーション操作** (sprite_frames_editor_plugin.cpp L1094-1471)
   - 選択、追加、削除、リネーム

5. **フレーム操作** (sprite_frames_editor_plugin.cpp L770-1092)
   - 追加、削除、移動

6. **スプライトシート分割** (sprite_frames_editor_plugin.cpp L63-686)
   - プレビュー描画
   - フレーム選択
   - 自動分割アルゴリズム

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

```
SpriteFramesEditorPlugin::edit()
└── SpriteFramesEditor::edit()
    ├── _update_library()
    │   └── _update_library_impl()
    │       ├── animations->clear()
    │       ├── frame_list->clear()
    │       └── _fetch_sprite_node()
    └── _zoom_reset()

_animation_add()
└── EditorUndoRedoManager::create_action("Add Animation")
    ├── add_do_method(frames, "add_animation", name)
    ├── add_do_method(this, "_select_animation", name)
    └── commit_action()

_load_pressed()
└── file->popup_file_dialog()
    └── files_selected signal
        └── _file_load_request()
            └── EditorUndoRedoManager::create_action("Add Frame")
                ├── add_do_method(frames, "add_frame", ...)
                └── commit_action()

_open_sprite_sheet()
└── file_split_sheet->popup_file_dialog()
    └── file_selected signal
        └── _prepare_sprite_sheet()
            ├── ResourceLoader::load(texture)
            ├── split_sheet_preview->set_texture()
            └── split_sheet_dialog->popup_centered_ratio(0.65)

_sheet_preview_input() (マウスクリック)
├── _sheet_preview_position_to_frame_index()
├── frames_selected.insert(idx, selected_count)
└── split_sheet_preview->queue_redraw()
    └── _sheet_preview_draw() [draw signal]
        ├── 線描画（グリッド）
        └── 選択フレームハイライト描画

_sheet_add_frames() (OKボタン)
├── _sheet_sort_frames()
└── EditorUndoRedoManager::create_action("Add Frame")
    ├── AtlasTexture作成
    ├── add_do_method(frames, "add_frame", ...)
    └── commit_action()
```

### データフロー図

```
[ファイルシステム]
    |
    | (ファイル選択)
    v
[EditorFileDialog] --file_selected--> _file_load_request()
    |                                    |
    | (テクスチャ読み込み)              |
    v                                    v
[Texture2D] ------------------> [SpriteFrames リソース]
    |                               |
    | (add_frame)                   |
    v                               v
[フレーム配列] <---------> [ItemList表示]
    |                               |
    | (get_frame_texture)           |
    v                               v
[アニメーション再生] <---> [AnimatedSprite2D/3D]
```

### 関連ファイル一覧

| ファイル | 役割 |
|----------|------|
| `editor/scene/sprite_frames_editor_plugin.h` | エディタクラス定義 |
| `editor/scene/sprite_frames_editor_plugin.cpp` | エディタ実装 |
| `scene/resources/sprite_frames.h` | SpriteFramesリソース定義 |
| `scene/resources/sprite_frames.cpp` | SpriteFramesリソース実装 |
| `scene/2d/animated_sprite_2d.h` | AnimatedSprite2D定義 |
| `scene/3d/sprite_3d.h` | AnimatedSprite3D定義 |
| `scene/resources/atlas_texture.h` | AtlasTexture（シート分割用） |
| `editor/docks/editor_dock.h` | EditorDock基底クラス |
| `editor/plugins/editor_plugin.h` | EditorPlugin基底クラス |
| `editor/editor_undo_redo_manager.h` | Undo/Redo管理 |
