# 通知設計書 38-NOTIFICATION_FOCUS_EXIT

## 概要

本ドキュメントは、GodotエンジンのControlクラスにおけるNOTIFICATION_FOCUS_EXIT通知の設計仕様を記載する。この通知はUIコントロールがキーボードフォーカスを失った際に発火され、フォーカス状態の解除やキーボード入力の受け入れ終了を可能にする重要なイベントである。

### 本通知の処理概要

NOTIFICATION_FOCUS_EXITは、Controlノードがキーボードフォーカスを失った際に発行される通知である。NOTIFICATION_FOCUS_ENTER（値43）とペアで使用され、フォーカス状態の終了を検出するために使用される。

**業務上の目的・背景**：フォーカス解除時の処理は、データの検証・保存、入力モードの終了、視覚的なフィードバックの解除など、多くの重要な用途がある。テキスト入力フィールドでの編集完了処理、コンボボックスのドロップダウン非表示、バリデーションの実行などにこの通知が使用される。

**通知の送信タイミング**：別のコントロールがフォーカスを取得した際、release_focus()の呼び出し、コントロールの非表示化・削除時に発火される。フォーカスを持つコントロールが存在しなくなる場合もこの通知が発行される。

**通知の受信者**：現在フォーカスを持っているControlノード。LineEdit、TextEdit、Button、OptionButton、SpinBox、Slider、Treeなど、NOTIFICATION_FOCUS_ENTERを処理するすべてのUI要素が対応する受信者となる。

**通知内容の概要**：通知値は44（NOTIFICATION_FOCUS_EXIT = 44）として定義され、コントロールがキーボードフォーカスを失ったことを示す。

**期待されるアクション**：受信ノードはフォーカス状態を解除する。典型的な処理として、フォーカスリングの非表示、カーソルの非表示、入力データの確定・検証、キーボードイベント受け入れの終了がある。通知後には「focus_exited」シグナルとqueue_redraw()が呼び出される。

## 通知種別

ゲームエンジン内部通知（Object._notificationで受信）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（フォーカス変更時に即座に発行） |
| 優先度 | 高（データ整合性維持に重要） |
| リトライ | なし（一度のみ発行） |

### 送信先決定ロジック

1. 現在フォーカスを持っているコントロールであること
2. 別のコントロールがフォーカスを取得、またはrelease_focus()呼び出し
3. コントロールの非表示化、削除、またはウィンドウフォーカス喪失
4. 上記条件を満たすControlノードに対してnotification()が呼び出される

## 通知テンプレート

### 内部通知の場合

| 項目 | 内容 |
|-----|------|
| 通知定数名 | NOTIFICATION_FOCUS_EXIT |
| 通知値 | 44 |
| 逆順送信 | false（通常順） |
| 形式 | 整数値（int p_what） |

### 本文テンプレート

```cpp
// _notification()での受信例
void MyLineEdit::_notification(int p_what) {
    switch (p_what) {
        case NOTIFICATION_FOCUS_EXIT: {
            // フォーカスを失った
            caret_visible = false;
            // 入力データを検証・確定
            validate_input();
            // 通常状態の描画に切り替え
            queue_redraw();
        } break;
    }
}

// GDScriptでの例
func _notification(what):
    if what == NOTIFICATION_FOCUS_EXIT:
        # フォーカス喪失時の処理
        $FocusRing.visible = false
        validate_and_save()
```

### 添付ファイル

該当なし（内部通知のため）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| p_what | 通知種別 | notification()引数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 別コントロール取得 | 他のコントロールがgrab_focus() | 現在フォーカス中 | 通常のフォーカス移動 |
| Tab移動 | Tabキー押下 | 現在フォーカス中 | 次のコントロールへ移動 |
| Shift+Tab移動 | Shift+Tabキー押下 | 現在フォーカス中 | 前のコントロールへ移動 |
| プログラム解放 | release_focus() | 現在フォーカス中 | コードからのフォーカス解放 |
| コントロール非表示 | hide() | 現在フォーカス中 | 非表示によるフォーカス喪失 |
| コントロール削除 | queue_free() | 現在フォーカス中 | 削除によるフォーカス喪失 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 非フォーカス | そもそもフォーカスを持っていない場合 |
| 同一コントロール | 自身へのgrab_focus()（変更なし） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[フォーカス喪失トリガー] --> B{現在フォーカス中?}
    B -->|No| C[処理終了]
    B -->|Yes| D[NOTIFICATION_FOCUS_EXIT発行]
    D --> E[派生クラス_notification処理]
    E --> F[focus_exitedシグナル発行]
    F --> G[queue_redraw呼び出し]
    G --> H{新しいフォーカス先あり?}
    H -->|Yes| I[新コントロールにFOCUS_ENTER通知]
    H -->|No| C
    I --> C
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（ゲームエンジン内部処理のためデータベースは使用しない）

### テーブル別参照項目詳細

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 検証失敗 | フォーカス喪失時のデータ検証失敗 | エラー表示（フォーカスは既に移動済み） |
| 状態不整合 | ENTER無しでEXITが発生 | 状態フラグの防御的チェック |
| 再帰呼び出し | EXIT内でgrab_focus()呼び出し | 適切な順序で処理 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（ユーザー操作に依存） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

エンジン実行中、フォーカス変更時に発火。

## セキュリティ考慮事項

エンジン内部通知のため、外部からの直接的なセキュリティリスクはない。

## 備考

- NOTIFICATION_FOCUS_ENTER（値43）とペアで必ず使用
- コントロールが削除または非表示になった場合も発行される（状態整合性維持）
- release_focus()はhas_focus()がtrueの場合のみ効果がある
- _notification()処理後にfocus_exitedシグナルとqueue_redraw()が呼び出される（control.cpp 3949-3952行目）

---

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

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

### 推奨読解順序

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

まず、Controlクラスの構造と通知定数の定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | control.h | `scene/gui/control.h` | NOTIFICATION_FOCUS_EXIT = 44定義（430行目） |

**読解のコツ**: 値44はNOTIFICATION_FOCUS_ENTER（43）の直後に定義されている。

#### Step 2: エントリーポイントを理解する

フォーカス解放のメカニズムを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | control.cpp | `scene/gui/control.cpp` | release_focus()メソッド |
| 2-2 | control.cpp | `scene/gui/control.cpp` | _notification() NOTIFICATION_FOCUS_EXIT処理（3949-3952行目） |

**主要処理フロー**:
- **3950行目**: emit_signal(SceneStringName(focus_exited))
- **3951行目**: queue_redraw()

#### Step 3: 派生クラスでの処理例を理解する

LineEditなどの派生クラスでの具体的な処理パターンを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | line_edit.cpp | `scene/gui/line_edit.cpp` | NOTIFICATION_FOCUS_EXIT処理（キャレット非表示、検証） |
| 3-2 | text_edit.cpp | `scene/gui/text_edit.cpp` | NOTIFICATION_FOCUS_EXIT処理（編集モード終了） |
| 3-3 | spin_box.cpp | `scene/gui/spin_box.cpp` | NOTIFICATION_FOCUS_EXIT処理（値確定） |

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

```
Control::release_focus() / 他コントロールへの移動
    │
    └─ Viewport::gui_release_focus()
           │
           └─ 旧コントロール::notification(FOCUS_EXIT)
                  │
                  └─ Control::_notification(NOTIFICATION_FOCUS_EXIT)
                         │
                         ├─ emit_signal("focus_exited")
                         │
                         └─ queue_redraw()
```

### データフロー図

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

release_focus() ───▶ Viewport処理 ───▶ notification(44)
Tab/他コントロール     │                     │
                       ├─ フォーカス管理     ├─▶ 派生クラス処理
                       │                     │    (検証・確定)
                       └─ 状態更新          ├─▶ "focus_exited"シグナル
                                            │
                                            └─▶ queue_redraw()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| control.h | `scene/gui/control.h` | ヘッダ | Controlクラス定義、NOTIFICATION定数 |
| control.cpp | `scene/gui/control.cpp` | ソース | release_focus()、_notification()実装 |
| viewport.cpp | `scene/main/viewport.cpp` | ソース | フォーカス管理、通知発行 |
| line_edit.cpp | `scene/gui/line_edit.cpp` | ソース | 行エディタでの通知処理例 |
| text_edit.cpp | `scene/gui/text_edit.cpp` | ソース | テキストエディタでの通知処理例 |
| spin_box.cpp | `scene/gui/spin_box.cpp` | ソース | スピンボックスでの通知処理例 |
| option_button.cpp | `scene/gui/option_button.cpp` | ソース | オプションボタンでの通知処理例 |
| tree.cpp | `scene/gui/tree.cpp` | ソース | ツリーでの通知処理例 |
| item_list.cpp | `scene/gui/item_list.cpp` | ソース | アイテムリストでの通知処理例 |
| Control.xml | `doc/classes/Control.xml` | ドキュメント | 公式APIドキュメント |
