# 画面設計書 38-プラグイン設定ダイアログ

## 概要

本ドキュメントは、Godot Engineエディタにおけるプラグイン設定ダイアログ（PluginConfigDialog）の画面設計を記述する。このダイアログはエディタプラグインの新規作成および既存プラグインの設定編集を行うために使用される。

### 本画面の処理概要

このダイアログ画面では、エディタプラグインに必要なメタデータ（名前、説明、作者、バージョン等）を入力し、plugin.cfgファイルとプラグインスクリプトを自動生成する。既存プラグインの編集モードでは、設定値の更新が可能。

**業務上の目的・背景**：Godot Engineでは、エディタ拡張機能をプラグインとして開発できる。プラグインには特定のディレクトリ構造とplugin.cfg設定ファイルが必要であり、このダイアログはその初期設定を支援する。

**画面へのアクセス方法**：プロジェクト設定のプラグインタブから「Create New Plugin」ボタンを押下、または既存プラグインの編集ボタンを押下してアクセスする。

**主要な操作・処理内容**：
1. プラグイン名の入力（必須）
2. サブフォルダ名の指定（オプション）
3. 説明、作者、バージョンの入力
4. スクリプト言語の選択
5. スクリプトファイル名の指定
6. plugin.cfgファイルとスクリプトの生成

**画面遷移**：
- 遷移元：プロジェクト設定 > プラグインタブ
- 遷移先（確定時）：プラグインが作成/更新され、ダイアログが閉じる
- 遷移先（キャンセル時）：変更なしでダイアログが閉じる

**権限による表示制御**：編集モード（_edit_mode）により、サブフォルダ入力欄の表示/非表示が制御される。新規作成時は表示、編集時は非表示。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| F-070 | プラグイン管理 | 主機能 | プラグインの作成・編集 |
| F-071 | スクリプト生成 | 補助機能 | EditorPluginテンプレートからのスクリプト生成 |

## 画面種別

登録・編集（モーダルダイアログ）

## URL/ルーティング

該当なし（デスクトップアプリケーションのモーダルダイアログ）

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 説明 |
|--------|----------|---------|------|------|
| プラグイン名 | 入力 | String | 必須 | プラグインの表示名 |
| サブフォルダ | 入力 | String | オプション | res://addons/以下のフォルダ名 |
| 説明 | 入力 | String | オプション | プラグインの説明文（5行以内推奨） |
| 作者 | 入力 | String | オプション | 作者名またはユーザー名 |
| バージョン | 入力 | String | オプション | バージョン識別子 |
| 言語 | 入力 | int | 必須 | スクリプト言語の選択 |
| スクリプト名 | 入力 | String | オプション | スクリプトファイル名 |
| 設定パス | 入力 | String | - | 編集時のplugin.cfgパス（config()で設定） |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| Plugin Name | テキスト入力 | プレースホルダー「MyPlugin」 |
| Subfolder | テキスト入力 | プレースホルダー「"my_plugin" → res://addons/my_plugin」 |
| Description | テキストエリア | 最小サイズ400*80*EDSCALE、行折り返し有効 |
| Author | テキスト入力 | プレースホルダー「Godette」 |
| Version | テキスト入力 | プレースホルダー「1.0」 |
| Language | ドロップダウン | ScriptServer登録言語、デフォルトGDScript |
| Script Name | テキスト入力 | プレースホルダー「"plugin.gd" → res://addons/my_plugin/plugin.gd」 |
| 検証パネル | EditorValidationPanel | エラー/警告/情報メッセージを表示 |

## イベント仕様

### 1-ダイアログ表示

config()が呼び出され、以下の処理が行われる：
1. p_config_pathが空でない場合（編集モード）：
   - ConfigFileからplugin.cfgを読み込み
   - 各フィールドに値を設定
   - _edit_mode = true
   - タイトルを「Edit a Plugin」に設定
2. p_config_pathが空の場合（新規作成モード）：
   - _clear_fields()で全フィールドをクリア
   - _edit_mode = false
   - タイトルを「Create a Plugin」に設定
3. plugin_edit_hidden_controlsの表示/非表示を切り替え
4. OKボタンテキストを「Update」または「Create」に設定

### 2-テキスト入力変更

_on_required_text_changed()が呼び出され、以下の検証が行われる：
1. プラグイン名が空の場合：MSG_ID_PLUGINにエラー
2. サブフォルダが無効なファイル名の場合：MSG_ID_SUBFOLDERにエラー
3. サブフォルダが既存の場合（新規作成時のみ）：MSG_ID_SUBFOLDERにエラー
4. スクリプト拡張子が言語と不一致の場合：MSG_ID_SCRIPTにエラー
5. GDScript選択時：MSG_ID_ENABLE_WARNINGSに警告情報

### 3-言語選択変更

script_option_editの選択が変更されると、validation_panel->update()が呼び出され、スクリプト拡張子の検証が再実行される。

### 4-OKボタン押下

_on_confirmed()が呼び出され、以下の処理が行われる：
1. res://addons/{subfolder}パスを生成
2. 新規作成時：DirAccessでディレクトリ作成
3. ConfigFileを作成/読み込み
4. plugin.cfgにname/description/author/version/scriptを設定
5. _create_script_for_plugin()でスクリプト生成
6. plugin.cfgを保存
7. ProjectSettings::update_plugins()を呼び出し
8. EditorFileSystem::scan()を実行
9. _clear_fields()でフィールドクリア

### 5-スクリプト生成

_create_script_for_plugin()が呼び出され、以下の処理が行われる：
1. 選択言語の拡張子を取得
2. スクリプト名を決定（空の場合はサブフォルダ名）
3. 拡張子が一致しない場合は追加
4. 新規作成かつファイルが存在しない場合：
   - EditorPluginのテンプレートを取得
   - language->make_template()でスクリプト生成
   - ResourceSaverで保存

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| プラグイン作成 | res://addons/{name}/plugin.cfg | CREATE | 設定ファイルを新規作成 |
| プラグイン作成 | res://addons/{name}/{script} | CREATE | スクリプトファイルを新規作成 |
| プラグイン編集 | res://addons/{name}/plugin.cfg | UPDATE | 設定ファイルを更新 |

### テーブル別更新項目詳細

#### plugin.cfg（プラグイン設定ファイル）

| 操作 | 項目 | 更新値・取得条件 | 備考 |
|-----|------|-----------------|------|
| SET | [plugin]/name | name_edit->get_text() | プラグイン表示名 |
| SET | [plugin]/description | desc_edit->get_text() | プラグイン説明 |
| SET | [plugin]/author | author_edit->get_text() | 作者名 |
| SET | [plugin]/version | version_edit->get_text() | バージョン |
| SET | [plugin]/script | script_name | スクリプトファイル名 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------:|
| MSG_ID_PLUGIN | エラー | Plugin name cannot be blank. | プラグイン名が空 |
| MSG_ID_PLUGIN | OK | Plugin name is valid. | プラグイン名が有効 |
| MSG_ID_SUBFOLDER | エラー | Subfolder name is not a valid folder name. | サブフォルダが無効 |
| MSG_ID_SUBFOLDER | エラー | Subfolder cannot be one which already exists. | サブフォルダが既存 |
| MSG_ID_SUBFOLDER | OK | Subfolder name is valid. | サブフォルダが有効 |
| MSG_ID_SCRIPT | エラー | Script extension must match chosen language extension (.%s). | 拡張子不一致 |
| MSG_ID_SCRIPT | OK | Script extension is valid. | 拡張子が有効 |
| MSG_ID_ENABLE_WARNINGS | INFO | Consider enabling GDScript warnings... | GDScript選択時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| ディレクトリ作成失敗 | _on_confirmed()が早期リターン |
| ConfigFile読み込みエラー | ERR_FAIL_COND_MSGでエラー出力 |
| スクリプト言語がnullptr | ERR_FAIL_COND()でエラー |
| 検証エラー | OKボタンが無効化される |

## 備考

- 新規作成時はset_hide_on_ok(true)でダイアログが自動的に閉じる
- サブフォルダが空の場合、プラグイン名をスネークケースに変換して使用
- スクリプト名が空の場合、サブフォルダ名を使用
- EditorValidationPanelでリアルタイム入力検証を実施
- GDScript選択時は警告設定の推奨メッセージを表示
- plugin_edit_hidden_controlsでサブフォルダ関連UIの表示制御

---

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

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

クラス定義とメンバ変数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | plugin_config_dialog.h | `editor/plugins/plugin_config_dialog.h` | MSG_ID列挙（45-51行目）、メンバ変数（53-65行目） |

**読解のコツ**: 5つのMSG_ID（PLUGIN, SUBFOLDER, SCRIPT, ACTIVE, ENABLE_WARNINGS）がEditorValidationPanelの行に対応。_edit_modeで作成/編集モードを切り替え。

#### Step 2: コンストラクタを理解する

UI構築とイベント接続を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | plugin_config_dialog.cpp | `editor/plugins/plugin_config_dialog.cpp` | コンストラクタ（197-331行目） |

**主要処理フロー**:
1. **206-222行目**: Plugin Name入力の初期化
2. **224-237行目**: Subfolder入力の初期化、plugin_edit_hidden_controlsへの追加
3. **239-252行目**: Description入力の初期化（TextEdit、400*80*EDSCALE）
4. **254-278行目**: Author/Version入力の初期化
5. **280-298行目**: Language選択の初期化（ScriptServer登録言語を列挙）
6. **300-311行目**: Script Name入力の初期化
7. **317-325行目**: EditorValidationPanelの初期化と行追加
8. **327-330行目**: イベント接続（text_changed→update）

#### Step 3: 設定読み込み処理を理解する

config()の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | plugin_config_dialog.cpp | `editor/plugins/plugin_config_dialog.cpp` | config()（162-191行目） |

**主要処理フロー**:
- **163-176行目**: 編集モード - ConfigFileから値を読み込み各フィールドに設定
- **177-181行目**: 新規作成モード - フィールドクリア
- **183-185行目**: plugin_edit_hidden_controlsの表示切り替え
- **189-190行目**: OKボタンの状態とテキスト設定

#### Step 4: 検証処理を理解する

_on_required_text_changed()の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | plugin_config_dialog.cpp | `editor/plugins/plugin_config_dialog.cpp` | _on_required_text_changed()（108-137行目） |

**主要処理フロー**:
- **109-111行目**: プラグイン名空チェック
- **112-123行目**: サブフォルダの検証（ファイル名有効性、既存チェック）
- **125-133行目**: スクリプト拡張子の検証
- **134-136行目**: GDScript警告メッセージ

#### Step 5: 確定処理を理解する

_on_confirmed()と_create_script_for_plugin()の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | plugin_config_dialog.cpp | `editor/plugins/plugin_config_dialog.cpp` | _on_confirmed()（53-77行目） |
| 5-2 | plugin_config_dialog.cpp | `editor/plugins/plugin_config_dialog.cpp` | _create_script_for_plugin()（79-102行目） |

**主要処理フロー**:
- **54-61行目**: ディレクトリ作成（新規作成時）
- **63-68行目**: ConfigFile作成と値設定
- **71行目**: スクリプト生成呼び出し
- **73-76行目**: 保存とエディタ更新
- **93-97行目**: EditorPluginテンプレートからスクリプト生成
- **98-99行目**: ResourceSaverでスクリプト保存

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

```
PluginConfigDialog (ConfirmationDialog)
    │
    ├─ config(p_config_path)              [初期化]
    │      ├─ ConfigFile::load()          [編集時]
    │      ├─ set_text()各フィールド
    │      └─ _clear_fields()             [新規作成時]
    │
    ├─ _on_required_text_changed()        [検証コールバック]
    │      ├─ name_edit->get_text()
    │      ├─ subfolder_edit->get_text()
    │      ├─ script_edit->get_text()
    │      ├─ DirAccess::exists()
    │      └─ validation_panel->set_message()
    │
    ├─ _on_confirmed()                    [確定]
    │      ├─ DirAccess::make_dir_recursive()
    │      ├─ ConfigFile::set_value()
    │      ├─ _create_script_for_plugin()
    │      ├─ ConfigFile::save()
    │      └─ EditorFileSystem::scan()
    │
    └─ _create_script_for_plugin()        [スクリプト生成]
           ├─ ScriptServer::get_language()
           ├─ language->get_built_in_templates()
           ├─ language->make_template()
           └─ ResourceSaver::save()
```

### データフロー図

```
[入力]                    [処理]                         [出力]

config(path) ──────────▶ ConfigFile::load() ──────────▶ フィールド表示
                              │                          (編集モード)
                              └─ cf->get_value()

テキスト入力 ───────────▶ text_changed ────────────────▶ validation_panel
各フィールド                  │                          メッセージ更新
                              └─ _on_required_text_changed()

言語選択 ──────────────▶ item_selected ───────────────▶ 拡張子検証
OptionButton                  │
                              └─ validation_panel->update()

OKボタン ──────────────▶ _on_confirmed() ──────────────▶ ファイル生成
                              │                          ├─ plugin.cfg
                              ├─ make_dir_recursive()    └─ {script}.gd
                              ├─ ConfigFile::save()
                              └─ _create_script_for_plugin()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| plugin_config_dialog.cpp | `editor/plugins/plugin_config_dialog.cpp` | ソース | ダイアログの実装 |
| plugin_config_dialog.h | `editor/plugins/plugin_config_dialog.h` | ヘッダ | クラス定義 |
| editor_validation_panel.h | `editor/gui/editor_validation_panel.h` | ヘッダ | 入力検証UI |
| config_file.h | `core/io/config_file.h` | ヘッダ | 設定ファイルI/O |
| script_language.h | `core/object/script_language.h` | ヘッダ | スクリプト言語インターフェース |
| resource_saver.h | `core/io/resource_saver.h` | ヘッダ | リソース保存 |
