# 画面設計書 18-シェーダーエディタ

## 1. 画面概要

### 1.1 基本情報

| 項目 | 内容 |
|------|------|
| 画面名 | シェーダーエディタ (Shader Editor) |
| 画面ID | shader_editor |
| 主要クラス | ShaderEditorPlugin (EditorPlugin継承) |
| ソースファイル | editor/shader/shader_editor_plugin.cpp, editor/shader/shader_editor_plugin.h |
| 関連クラス | TextShaderEditor, ShaderTextEditor, ShaderEditor |
| ドック名 | "Shader Editor" |
| アイコン名 | "ShaderDock" |
| ショートカット | Alt+S |
| デフォルトスロット | DOCK_SLOT_BOTTOM |
| 対応レイアウト | 水平/フローティング |

### 1.2 機能概要

シェーダーエディタは、Godotシェーダー言語（GLSL風）で記述されたシェーダーファイル（.shader）およびシェーダーインクルードファイル（.gdshaderinc）を編集するための専用エディタである。シンタックスハイライト、コード補完、警告表示、検索・置換、ブックマーク機能など、コードエディタとしての基本機能を完備している。

## 2. クラス構造

### 2.1 クラス階層

```
EditorPlugin
  └── ShaderEditorPlugin
        ├── EditorDock (shader_dock)
        │     ├── HSplitContainer (files_split)
        │     │     ├── ItemList (shader_list)
        │     │     ├── TabContainer (shader_tabs)
        │     │     │     └── ShaderEditor* (各シェーダー用)
        │     │     └── MenuButton (file_menu)
        │     └── ShaderCreateDialog (shader_create_dialog)
        └── PopupMenu (context_menu)

Control
  └── ShaderEditor (抽象基底クラス)
        └── TextShaderEditor
              ├── ShaderTextEditor (code_editor) - CodeTextEditor継承
              ├── MenuButton (edit_menu, search_menu)
              ├── PopupMenu (context_menu, bookmarks_menu)
              ├── RichTextLabel (warnings_panel)
              ├── GotoLinePopup (goto_line_popup)
              └── ConfirmationDialog (disk_changed)

CodeTextEditor
  └── ShaderTextEditor
        ├── RichTextLabel (warnings_panel)
        └── GDShaderSyntaxHighlighter (syntax_highlighter)
```

### 2.2 EditedShader構造体

```cpp
struct EditedShader {
    Ref<Shader> shader;              // 編集中のシェーダー
    Ref<ShaderInclude> shader_inc;   // 編集中のシェーダーインクルード
    ShaderEditor *shader_editor;      // 対応するエディタインスタンス
    String path;                      // ファイルパス
    String name;                      // 表示名
};
```

## 3. UI構成

### 3.1 全体レイアウト

```
+-----------------------------------------------------------+
| [Shader Editor Dock]                                       |
+-----------------------------------------------------------+
| +---------------------------+-----------------------------+ |
| | [Shader List]             | [Shader Tabs]               | |
| | (ItemList)                | +---------------------------+ |
| | - shader1.shader         | | [File] [Edit] [Search]    | |
| | - shader2.shader (*)     | | [Go To]      [Online Docs]| |
| | - include.gdshaderinc    | +---------------------------+ |
| |                           | |                           | |
| |                           | | [Code Editor Area]        | |
| |                           | | (ShaderTextEditor)        | |
| |                           | |                           | |
| |                           | |                           | |
| |                           | |                           | |
| |                           | +---------------------------+ |
| |                           | | [Warnings Panel]          | |
| |                           | | (RichTextLabel)           | |
| +---------------------------+-----------------------------+ |
+-----------------------------------------------------------+
```

### 3.2 メインコンポーネント

| コンポーネント | タイプ | 説明 |
|---------------|--------|------|
| shader_dock | EditorDock | シェーダーエディタのドックコンテナ |
| files_split | HSplitContainer | ファイルリストとエディタを分割 |
| shader_list | ItemList | 開いているシェーダー一覧 |
| shader_tabs | TabContainer | 複数シェーダーのタブ管理（タブ非表示） |
| file_menu | MenuButton | ファイルメニュー |
| context_menu | PopupMenu | コンテキストメニュー |
| shader_create_dialog | ShaderCreateDialog | 新規シェーダー作成ダイアログ |

## 4. ファイルメニュー

### 4.1 FileMenu列挙型

```cpp
enum FileMenu {
    FILE_MENU_NEW,                      // 新規シェーダー
    FILE_MENU_NEW_INCLUDE,              // 新規シェーダーインクルード
    FILE_MENU_OPEN,                     // シェーダーを開く
    FILE_MENU_OPEN_INCLUDE,             // シェーダーインクルードを開く
    FILE_MENU_SAVE,                     // 保存
    FILE_MENU_SAVE_AS,                  // 名前を付けて保存
    FILE_MENU_INSPECT,                  // インスペクタで開く
    FILE_MENU_INSPECT_NATIVE_SHADER_CODE, // ネイティブシェーダーコード検査
    FILE_MENU_CLOSE,                    // 閉じる
    FILE_MENU_CLOSE_ALL,                // すべて閉じる
    FILE_MENU_CLOSE_OTHER_TABS,         // 他のタブを閉じる
    FILE_MENU_SHOW_IN_FILE_SYSTEM,      // ファイルシステムで表示
    FILE_MENU_COPY_PATH,                // パスをコピー
    FILE_MENU_TOGGLE_FILES_PANEL,       // ファイルパネル切り替え
};
```

### 4.2 ショートカット定義

| アクション | ショートカット |
|-----------|---------------|
| New Shader | Ctrl/Cmd+N |
| New Shader Include | Ctrl/Cmd+Shift+N |
| Load Shader File | Ctrl/Cmd+O |
| Load Shader Include File | Ctrl/Cmd+Shift+O |
| Make Floating | (カスタム設定) |
| Toggle Shader Editor Dock | Alt+S |

## 5. TextShaderEditor

### 5.1 編集メニュー項目

```cpp
enum {
    EDIT_UNDO,                // 元に戻す
    EDIT_REDO,                // やり直し
    EDIT_CUT,                 // 切り取り
    EDIT_COPY,                // コピー
    EDIT_PASTE,               // 貼り付け
    EDIT_SELECT_ALL,          // すべて選択
    EDIT_MOVE_LINE_UP,        // 行を上に移動
    EDIT_MOVE_LINE_DOWN,      // 行を下に移動
    EDIT_INDENT,              // インデント
    EDIT_UNINDENT,            // アンインデント
    EDIT_DELETE_LINE,         // 行を削除
    EDIT_DUPLICATE_SELECTION, // 選択範囲を複製
    EDIT_DUPLICATE_LINES,     // 行を複製
    EDIT_TOGGLE_WORD_WRAP,    // ワードラップ切り替え
    EDIT_TOGGLE_COMMENT,      // コメント切り替え
    EDIT_COMPLETE,            // コード補完
    SEARCH_FIND,              // 検索
    SEARCH_FIND_NEXT,         // 次を検索
    SEARCH_FIND_PREV,         // 前を検索
    SEARCH_REPLACE,           // 置換
    SEARCH_GOTO_LINE,         // 行へ移動
    BOOKMARK_TOGGLE,          // ブックマーク切り替え
    BOOKMARK_GOTO_NEXT,       // 次のブックマーク
    BOOKMARK_GOTO_PREV,       // 前のブックマーク
    BOOKMARK_REMOVE_ALL,      // 全ブックマーク削除
    HELP_DOCS,                // オンラインドキュメント
    EDIT_EMOJI_AND_SYMBOL,    // 絵文字・記号ピッカー
};
```

### 5.2 メニューバー構成

| メニュー | 主要項目 |
|---------|---------|
| File | New, Open, Save, Save As, Inspect, Close |
| Edit | Undo/Redo, Cut/Copy/Paste, Select All, Move Lines, Indent, Comment, Complete |
| Search | Find, Find Next/Prev, Replace |
| Go To | Go to Line, Bookmarks |
| Online Docs | 外部リンク（ボタン） |

## 6. シンタックスハイライト

### 6.1 GDShaderSyntaxHighlighter

CodeHighlighterを継承したシェーダー専用シンタックスハイライター。

```cpp
class GDShaderSyntaxHighlighter : public CodeHighlighter {
    Vector<Point2i> disabled_branch_regions; // 無効化されたプリプロセッサ分岐領域
    Color disabled_branch_color;             // 無効分岐の色

    void add_disabled_branch_region(const Point2i &p_region);
    void clear_disabled_branch_regions();
    void set_disabled_branch_color(const Color &p_color);
};
```

### 6.2 カラーリングルール

| 要素 | エディタ設定キー |
|------|-----------------|
| 数値 | text_editor/theme/highlighting/number_color |
| シンボル | text_editor/theme/highlighting/symbol_color |
| 関数 | text_editor/theme/highlighting/function_color |
| メンバ変数 | text_editor/theme/highlighting/member_variable_color |
| キーワード | text_editor/theme/highlighting/keyword_color |
| 制御フロー | text_editor/theme/highlighting/control_flow_keyword_color |
| ビルトイン | text_editor/theme/highlighting/user_type_color |
| コメント | text_editor/theme/highlighting/comment_color |
| ドキュメントコメント | text_editor/theme/highlighting/doc_comment_color |
| 文字列 | text_editor/theme/highlighting/string_color |
| マーク行 | text_editor/theme/highlighting/mark_color |

### 6.3 コメント領域

```cpp
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, true);
syntax_highlighter->add_color_region("/**", "*/", doc_comment_color, false);
syntax_highlighter->add_color_region("/**/", "", comment_color, true);
```

## 7. シェーダー検証

### 7.1 検証フロー

```
_validate_script()
    │
    ├── ShaderPreprocessor::preprocess()
    │   └── プリプロセッサ処理（#include解決、#if評価）
    │
    ├── ShaderLanguage::compile()
    │   └── シェーダーコンパイル
    │
    ├── エラー表示
    │   └── 行背景色変更、エラーメッセージ設定
    │
    └── 警告表示
        └── warnings_panel更新
```

### 7.2 シェーダーモード検出

```cpp
void ShaderTextEditor::_check_shader_mode() {
    String type = ShaderLanguage::get_shader_type(code);
    Shader::Mode mode;
    if (type == "canvas_item")      mode = Shader::MODE_CANVAS_ITEM;
    else if (type == "particles")   mode = Shader::MODE_PARTICLES;
    else if (type == "sky")         mode = Shader::MODE_SKY;
    else if (type == "fog")         mode = Shader::MODE_FOG;
    else                            mode = Shader::MODE_SPATIAL;
}
```

### 7.3 警告設定

```cpp
static bool saved_warnings_enabled;           // 警告有効化フラグ
static bool saved_treat_warning_as_errors;    // 警告をエラーとして扱う
static HashMap<ShaderWarning::Code, bool> saved_warnings; // 個別警告設定
static uint32_t saved_warning_flags;          // 警告フラグ（ビットマスク）
```

## 8. コード補完

### 8.1 補完処理フロー

```cpp
void ShaderTextEditor::_code_complete_script(
    const String &p_code,
    List<ScriptLanguage::CodeCompletionOption> *r_options
) {
    // 1. プリプロセッサ補完（#include パス等）
    ShaderPreprocessor preprocessor;
    preprocessor.preprocess(..., &pp_options, &pp_defines, _complete_include_paths);

    // 2. シェーダー言語補完
    ShaderLanguage sl;
    sl.complete(code, comp_info, r_options, calltip);
}
```

### 8.2 インクルードパス補完

```cpp
static void _complete_include_paths_search(
    EditorFileSystemDirectory *p_efsd,
    List<ScriptLanguage::CodeCompletionOption> *r_options
) {
    for (int i = 0; i < p_efsd->get_file_count(); i++) {
        if (p_efsd->get_file_type(i) == SNAME("ShaderInclude")) {
            r_options->push_back(CodeCompletionOption(path, CODE_COMPLETION_KIND_FILE_PATH));
        }
    }
}
```

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

### 9.1 対応データ型

| データ型 | 説明 |
|---------|------|
| shader_list_element | シェーダーリスト内での並べ替え |
| files | ファイルシステムからのドロップ（.shader, .gdshaderinc） |

### 9.2 ドラッグプレビュー

```cpp
Variant ShaderEditorPlugin::get_drag_data_fw(...) {
    HBoxContainer *drag_preview = memnew(HBoxContainer);
    TextureRect *tf = memnew(TextureRect);
    tf->set_texture(preview_icon);
    Label *label = memnew(Label(preview_name));
    drag_preview->add_child(tf);
    drag_preview->add_child(label);
    files_split->set_drag_preview(drag_preview);
}
```

## 10. レイアウト保存・復元

### 10.1 保存項目

| キー | 内容 |
|------|------|
| open_shaders | 開いているシェーダーのパス配列 |
| split_offset | ファイルリストとエディタの分割位置 |
| selected_shader | 選択中のシェーダーパス |
| text_shader_zoom_factor | テキストズーム倍率 |

### 10.2 復元処理

```cpp
void ShaderEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
    if (!EDITOR_GET("editors/shader_editor/behavior/files/restore_shaders_on_load")) {
        return;
    }
    Array shaders = p_layout->get_value("ShaderEditor", "open_shaders");
    for (int i = 0; i < shaders.size(); i++) {
        Ref<Resource> res = ResourceLoader::load(shaders[i]);
        if (res.is_valid()) {
            edit(res.ptr());
        }
    }
}
```

## 11. 外部ファイル変更検出

### 11.1 変更検出

```cpp
void TextShaderEditor::_check_for_external_edit() {
    bool use_autoreload = EDITOR_GET("text_editor/behavior/files/auto_reload_scripts_on_external_change");

    if (shader->get_last_modified_time() != FileAccess::get_modified_time(shader->get_path())) {
        if (use_autoreload) {
            _reload_shader_from_disk();
        } else {
            disk_changed->popup_centered();
        }
    }
}
```

### 11.2 リロードダイアログ

```cpp
disk_changed = memnew(ConfirmationDialog);
disk_changed->set_ok_button_text(TTR("Reload"));
disk_changed->add_button(TTR("Resave"), ...);
```

## 12. 言語プラグイン

### 12.1 登録されるプラグイン

```cpp
// テキストシェーダー言語プラグイン
Ref<TextShaderLanguagePlugin> text_shader_lang;
text_shader_lang.instantiate();
EditorShaderLanguagePlugin::register_shader_language(text_shader_lang);

// ビジュアルシェーダー言語プラグイン
Ref<VisualShaderLanguagePlugin> visual_shader_lang;
visual_shader_lang.instantiate();
EditorShaderLanguagePlugin::register_shader_language(visual_shader_lang);
```

### 12.2 シェーダー種別判定

```cpp
bool ShaderEditorPlugin::handles(Object *p_object) const {
    return Object::cast_to<Shader>(p_object) != nullptr ||
           Object::cast_to<ShaderInclude>(p_object) != nullptr;
}
```

## 13. 保存時処理

### 13.1 トリム設定

```cpp
bool trim_trailing_whitespace_on_save;  // 末尾空白削除
bool trim_final_newlines_on_save;       // 末尾改行削除
```

### 13.2 保存フロー

```cpp
void TextShaderEditor::save_external_data(const String &p_str) {
    if (trim_trailing_whitespace_on_save) {
        trim_trailing_whitespace();
    }
    if (trim_final_newlines_on_save) {
        trim_final_newlines();
    }
    apply_shaders();
    ResourceSaver::save(edited_shader);
    code_editor->get_text_editor()->tag_saved_version();
}
```

## 14. イベント処理

### 14.1 シグナル接続（ShaderEditorPlugin）

| シグナル送信元 | シグナル名 | ハンドラ |
|---------------|-----------|---------|
| EditorNode | resource_saved | _resource_saved |
| EditorNode | scene_closed | _close_builtin_shaders_from_scene |
| FileSystemDock | file_removed | _file_removed |
| EditorFileSystem | filesystem_changed | _update_shader_list |
| shader_list | item_selected | _shader_selected |
| shader_list | item_clicked | _shader_list_clicked |
| context_menu | id_pressed | _menu_item_pressed |
| file_menu->popup | id_pressed | _menu_item_pressed |
| shader_create_dialog | shader_created | _shader_created |
| shader_create_dialog | shader_include_created | _shader_include_created |

### 14.2 シグナル接続（TextShaderEditor）

| シグナル送信元 | シグナル名 | ハンドラ |
|---------------|-----------|---------|
| code_editor | script_validated | _script_validated |
| code_editor | show_warnings_panel | _show_warnings_panel |
| code_editor | script_changed | apply_shaders |
| EditorSettings | settings_changed | _editor_settings_changed |
| ProjectSettings | settings_changed | _project_settings_changed |
| warnings_panel | meta_clicked | _warning_clicked |
| context_menu | id_pressed | _menu_option |
| edit_menu->popup | id_pressed | _menu_option |
| search_menu->popup | id_pressed | _menu_option |
| bookmarks_menu | index_pressed | _bookmark_item_pressed |
| disk_changed | confirmed | _reload |

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

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

```
ShaderEditorPlugin (プラグイン管理)
    │
    ├── edit(Object*)
    │   ├── ShaderInclude判定
    │   │   └── EditorShaderLanguagePlugin::edit_shader_include()
    │   ├── Shader判定
    │   │   └── EditorShaderLanguagePlugin::edit_shader()
    │   └── TextShaderEditor セットアップ
    │       ├── validation_changed接続
    │       ├── zoomed接続
    │       └── shader_tabs追加
    │
    ├── _shader_selected(int)
    │   ├── _switch_to_editor()
    │   ├── validate_script()
    │   └── EditorNode::push_item_no_inspector()
    │
    ├── _menu_item_pressed(int)
    │   ├── FILE_MENU_NEW → shader_create_dialog
    │   ├── FILE_MENU_SAVE → EditorNode::save_resource()
    │   └── FILE_MENU_CLOSE → _close_shader()
    │
    └── _close_shader(int)
        ├── memdelete(shader_editor)
        ├── edited_shaders.remove_at()
        └── _update_shader_list()

TextShaderEditor (テキスト編集)
    │
    ├── edit_shader(Ref<Shader>)
    │   └── code_editor->set_edited_shader()
    │
    ├── _menu_option(int)
    │   ├── EDIT_* → code_editor操作
    │   ├── SEARCH_* → find_replace_bar操作
    │   └── BOOKMARK_* → ブックマーク操作
    │
    └── apply_shaders()
        └── shader->set_code(editor_code)

ShaderTextEditor (コード検証)
    │
    ├── _validate_script()
    │   ├── ShaderPreprocessor::preprocess()
    │   ├── ShaderLanguage::compile()
    │   ├── set_error() / set_error_pos()
    │   └── _update_warning_panel()
    │
    └── _code_complete_script()
        ├── preprocessor.preprocess() (pp_options)
        └── ShaderLanguage::complete()
```

### 15.2 データフロー図

```
[Shader Resource]
      │
      ▼
[ShaderEditorPlugin::edit()]
      │
      ├──────────────────────────┐
      ▼                          ▼
[EditedShader構造体]      [TextShaderEditor]
      │                          │
      │                          ▼
      │                   [ShaderTextEditor]
      │                          │
      │                          ├── CodeEdit (テキスト編集)
      │                          │
      │                          ├── _validate_script()
      │                          │   ├── プリプロセッサ
      │                          │   └── コンパイラ
      │                          │
      │                          ├── シンタックスハイライト
      │                          │   └── GDShaderSyntaxHighlighter
      │                          │
      │                          └── コード補完
      │                              └── ShaderLanguage::complete()
      │
      ▼
[shader_list] ─── 選択 ──→ [_shader_selected()]
      │                          │
      │                          ▼
      │                   [_switch_to_editor()]
      │                          │
      │                          ▼
      │                   [メニューバー更新]
      │
[保存] ─────────────────→ [apply_shaders()]
                                │
                                ▼
                         [ResourceSaver::save()]
```

### 15.3 関連ファイル一覧

| ファイルパス | 役割 |
|-------------|------|
| editor/shader/shader_editor_plugin.h | ShaderEditorPlugin クラス定義 |
| editor/shader/shader_editor_plugin.cpp | ShaderEditorPlugin 実装 |
| editor/shader/shader_editor.h | ShaderEditor 抽象基底クラス |
| editor/shader/text_shader_editor.h | TextShaderEditor クラス定義 |
| editor/shader/text_shader_editor.cpp | TextShaderEditor 実装（約1333行） |
| editor/shader/shader_create_dialog.h/cpp | シェーダー作成ダイアログ |
| editor/shader/text_shader_language_plugin.h/cpp | テキストシェーダー言語プラグイン |
| editor/shader/visual_shader_language_plugin.h/cpp | ビジュアルシェーダー言語プラグイン |
| editor/gui/code_editor.h/cpp | CodeTextEditor 基底クラス |
| servers/rendering/shader_language.h/cpp | シェーダー言語コンパイラ |
| servers/rendering/shader_preprocessor.h/cpp | シェーダープリプロセッサ |
| servers/rendering/shader_warnings.h/cpp | シェーダー警告定義 |
| scene/resources/shader.h/cpp | Shader リソースクラス |
| scene/resources/shader_include.h/cpp | ShaderInclude リソースクラス |

### 15.4 読解の推奨順序

1. **shader_editor.h** - 抽象基底クラスの仮想関数を理解
2. **shader_editor_plugin.h** - EditedShader構造体とFileMenu列挙型を確認
3. **shader_editor_plugin.cpp** - コンストラクタでUI構築、edit()でシェーダー編集開始
4. **text_shader_editor.h** - TextShaderEditorの編集メニュー列挙型を確認
5. **text_shader_editor.cpp** - コンストラクタでメニュー構築、_menu_option()で操作処理
6. **ShaderTextEditor** - _validate_script()でコンパイル・警告処理、_load_theme_settings()でハイライト設定
