# 通知設計書 39-NOTIFICATION_THEME_CHANGED

## 概要

本ドキュメントは、GodotエンジンのControlクラスにおけるNOTIFICATION_THEME_CHANGED通知の設計仕様を記載する。この通知はUIコントロールに適用されるテーマが変更された際に発火され、テーマ依存の外観更新やリソース再取得を可能にする重要なライフサイクルイベントである。

### 本通知の処理概要

NOTIFICATION_THEME_CHANGEDは、Controlノードのテーマコンテキストが変更された際に発行される通知である。テーマの直接変更、親からのテーマ継承変更、テーマオーバーライドの追加/削除などがトリガーとなる。

**業務上の目的・背景**：現代のアプリケーションではダークモード対応やブランディングなど、テーマのカスタマイズが一般的である。この通知により、UIコントロールはテーマ変更に動的に対応し、フォント、色、スタイルボックス、アイコンなどのテーマリソースを再取得して外観を更新できる。

**通知の送信タイミング**：set_theme()によるテーマ設定、set_theme_type_variation()による変種設定、add_theme_*_override()によるオーバーライド追加、親ノードのテーマ変更（継承経由）、シーンツリーへの追加時（初期テーマコンテキスト取得）に発火される。

**通知の受信者**：Controlを継承するすべてのUIノード。特にテーマリソースを使用する要素（Label、Button、Panel、Tree、TextEdit等）が重要な受信者である。

**通知内容の概要**：通知値は45（NOTIFICATION_THEME_CHANGED = 45）として定義され、コントロールのテーマコンテキストが変更されたことを示す。

**期待されるアクション**：受信ノードはテーマキャッシュを無効化し、テーマリソースを再取得する。典型的な処理として、最小サイズの再計算（update_minimum_size()）、キャッシュのクリア、queue_redraw()による再描画がある。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（テーマ変更時に即座に発行） |
| 優先度 | 高（UI整合性維持に必須） |
| リトライ | なし（一度のみ発行） |

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

1. テーマコンテキストが変更されること
2. ノードがシーンツリー内に存在すること
3. bulk_theme_overrideモード中でないこと（バッチ処理中は遅延）
4. 上記条件を満たすControlノードに対してnotification()が呼び出される

## 通知テンプレート

### 内部通知の場合

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

### 本文テンプレート

```cpp
// _notification()での受信例
void MyCustomControl::_notification(int p_what) {
    switch (p_what) {
        case NOTIFICATION_THEME_CHANGED: {
            // テーマが変更された
            // キャッシュを無効化
            _invalidate_theme_cache();
            // 最小サイズを再計算
            update_minimum_size();
            // 再描画をリクエスト
            queue_redraw();
        } break;
    }
}

// GDScriptでの例
func _notification(what):
    if what == NOTIFICATION_THEME_CHANGED:
        # テーマ変更時の処理
        update_minimum_size()
        queue_redraw()
```

### 添付ファイル

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

## テンプレート変数

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

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| テーマ設定 | set_theme() | シーンツリー内 | 直接テーマ設定 |
| 変種設定 | set_theme_type_variation() | シーンツリー内 | テーマ変種の設定 |
| オーバーライド追加 | add_theme_*_override() | シーンツリー内、非バルクモード | 個別オーバーライド |
| オーバーライド削除 | remove_theme_*_override() | シーンツリー内、非バルクモード | オーバーライド削除 |
| 親テーマ変更 | 親ノードのテーマ変更 | テーマを継承している場合 | 継承による伝播 |
| ツリー追加 | add_child() | テーマコンテキスト取得時 | 初期テーマ設定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| バルクモード | begin_bulk_theme_override()中は通知が遅延される |
| ツリー外 | シーンツリーに追加されていないノード |
| 初期化前 | data.initializedがfalseの状態（POSTINITIALIZEで初期化） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[テーマ変更トリガー] --> B{bulk_theme_override中?}
    B -->|Yes| C[遅延処理に登録]
    B -->|No| D{is_inside_tree?}
    D -->|No| E[処理終了]
    D -->|Yes| F[notification NOTIFICATION_THEME_CHANGED発行]
    F --> G[Control::_notification処理]
    G --> H[theme_changedシグナル発行]
    H --> I[_invalidate_theme_cache呼び出し]
    I --> J[update_minimum_size呼び出し]
    J --> K[派生クラスの追加処理]
    K --> L[子ノードへのテーマ伝播]
    L --> E

    C --> M[end_bulk_theme_override呼び出し]
    M --> F
```

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

### 参照テーブル一覧

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

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

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 早期アクセス | NOTIFICATION_THEME_CHANGED前にテーマ項目アクセス | 警告出力、POSTINITIALIZE/THEME_CHANGED後にアクセス推奨 |
| 無限ループ | テーマ変更ハンドラ内でテーマを変更 | 変更検出による防御 |
| キャッシュ不整合 | テーマ変更後にキャッシュが更新されない | _invalidate_theme_cache()で強制無効化 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

エンジン実行中いつでも発火可能。テーマ変更時に即座に発火。

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

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

## 備考

- begin_bulk_theme_override()とend_bulk_theme_override()でバッチ処理が可能（複数オーバーライド時の通知を1回にまとめる）
- Control::_notification(NOTIFICATION_THEME_CHANGED)では、theme_changedシグナル発行、_invalidate_theme_cache()、update_minimum_size()が呼び出される（control.cpp 3954-3963行目）
- テーマ項目へのアクセスはNOTIFICATION_POSTINITIALIZEまたはNOTIFICATION_THEME_CHANGED後に行うべき（早期アクセス警告あり）
- 子ノードへのテーマ伝播は自動的に行われる

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | control.h | `scene/gui/control.h` | NOTIFICATION_THEME_CHANGED = 45定義（431行目） |
| 1-2 | control.h | `scene/gui/control.h` | theme_owner_id、bulk_theme_overrideフラグ |

**読解のコツ**: 値45はControl固有の通知定数。テーマキャッシュ管理が重要。

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

テーマ変更通知のトリガーメカニズムを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | control.cpp | `scene/gui/control.cpp` | _notify_theme_override_changed()メソッド（2932-2936行目） |
| 2-2 | control.cpp | `scene/gui/control.cpp` | set_theme_type_variation()メソッド（3013-3017行目） |

**主要処理フロー**:
- **2934行目**: bulk_theme_overrideチェック
- **2935行目**: notification(NOTIFICATION_THEME_CHANGED)発行

#### Step 3: 通知処理を理解する

_notification()でのNOTIFICATION_THEME_CHANGED処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | control.cpp | `scene/gui/control.cpp` | _notification() NOTIFICATION_THEME_CHANGED処理（3954-3963行目） |

**主要処理フロー**:
- **3955行目**: emit_signal(SceneStringName(theme_changed))
- **3957行目**: _invalidate_theme_cache()
- **3958行目**: update_minimum_size()

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

具体的なUI要素でのテーマ処理パターンを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | label.cpp | `scene/gui/label.cpp` | NOTIFICATION_THEME_CHANGED処理 |
| 4-2 | button.cpp | `scene/gui/button.cpp` | NOTIFICATION_THEME_CHANGED処理 |
| 4-3 | tree.cpp | `scene/gui/tree.cpp` | NOTIFICATION_THEME_CHANGED処理 |

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

```
Control::set_theme() / add_theme_*_override()
    │
    └─ _notify_theme_override_changed()
           │
           ├─ bulk_theme_overrideチェック
           │
           └─ notification(NOTIFICATION_THEME_CHANGED)
                  │
                  └─ Control::_notification(NOTIFICATION_THEME_CHANGED)
                         │
                         ├─ emit_signal("theme_changed")
                         │
                         ├─ _invalidate_theme_cache()
                         │
                         └─ update_minimum_size()
                                │
                                └─ 派生クラス処理
```

### データフロー図

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

set_theme() ───▶ _notify_theme_override ───▶ notification(45)
add_override()      changed()                   │
                        │                       ├─▶ "theme_changed"シグナル
                        ├─ bulk check           │
                        │                       ├─▶ キャッシュ無効化
                        └─ tree check           │
                                                └─▶ 最小サイズ再計算
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| control.h | `scene/gui/control.h` | ヘッダ | Controlクラス定義、NOTIFICATION定数 |
| control.cpp | `scene/gui/control.cpp` | ソース | テーマ関連メソッド、_notification()実装 |
| theme_owner.h | `scene/theme/theme_owner.h` | ヘッダ | テーマオーナー管理 |
| theme_owner.cpp | `scene/theme/theme_owner.cpp` | ソース | テーマコンテキスト管理 |
| theme_db.h | `scene/theme/theme_db.h` | ヘッダ | テーマデータベース |
| label.cpp | `scene/gui/label.cpp` | ソース | ラベルでの通知処理例 |
| button.cpp | `scene/gui/button.cpp` | ソース | ボタンでの通知処理例 |
| tree.cpp | `scene/gui/tree.cpp` | ソース | ツリーでの通知処理例 |
| text_edit.cpp | `scene/gui/text_edit.cpp` | ソース | テキストエディタでの通知処理例 |
| Control.xml | `doc/classes/Control.xml` | ドキュメント | 公式APIドキュメント |
