# 通知設計書 9-OpenPopup

## 概要

本ドキュメントは、Dear ImGuiライブラリにおけるOpenPopup API関数の設計・動作仕様を記載したものである。OpenPopupはポップアップを開く状態にマークするAPI関数であり、BeginPopup()で使用されるポップアップの状態を制御する。

### 本通知の処理概要

OpenPopupは、指定されたIDのポップアップを「開いている」状態にマークする。この関数は毎フレーム呼び出してはならず、ボタンクリックなどのイベント発生時に一度だけ呼び出す。ポップアップの可視性状態はImGuiライブラリ内部で管理され、BeginPopup()でそのポップアップにアクセスできるようになる。

**業務上の目的・背景**：ポップアップ（コンテキストメニュー、ドロップダウン、ダイアログなど）を表示するためには、まずポップアップを「開く」必要がある。OpenPopupはその状態遷移を制御する関数であり、ユーザーアクション（ボタンクリック等）に応じてポップアップを開くトリガーとして機能する。

**通知の送信タイミング**：ユーザーアクション（ボタンクリック、右クリックなど）が発生した時点で一度だけ呼び出される。毎フレーム呼び出すとポップアップが正常に動作しない。

**通知の受信者**：Dear ImGuiの内部ポップアップスタック管理システム（OpenPopupStack）。OpenPopupを呼び出すと、指定されたIDがOpenPopupStackに追加または更新される。

**通知内容の概要**：ポップアップオープンリクエスト。文字列IDまたは数値IDでポップアップを識別し、ImGuiPopupFlagsでオープンオプションを指定可能。

**期待されるアクション**：ポップアップがOpenPopupStackに登録され、次回のBeginPopup()呼び出しでtrueを返すようになる。ポップアップの初期位置はマウスカーソルまたはナビゲーション位置に設定される。

## 通知種別

UI内部通知（ImGuiポップアップスタック状態変更通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無 |

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

OpenPopupの呼び出しは、OpenPopupStackの現在のレベル（BeginPopupStack.Size）に対して行われる。ポップアップIDは現在のIDスタックに対して相対的に計算される。

## 通知テンプレート

### API関数シグネチャ

| 項目 | 内容 |
|-----|------|
| 関数名 | OpenPopup（2つのオーバーロード） |
| 戻り値 | void |
| 引数1 | const char* str_id, ImGuiPopupFlags popup_flags = 0 |
| 引数2 | ImGuiID id, ImGuiPopupFlags popup_flags = 0 |
| 定義場所 | imgui.h:856-857 |

### 本文テンプレート

```cpp
// 基本的な使用パターン（文字列ID）
if (ImGui::Button("ポップアップを開く"))
    ImGui::OpenPopup("my_popup");

if (ImGui::BeginPopup("my_popup"))
{
    ImGui::Text("ポップアップの内容");
    ImGui::EndPopup();
}

// 数値IDを使用（ネストしたスタックで便利）
ImGuiID popup_id = ImGui::GetID("my_popup");
if (ImGui::Button("ポップアップを開く"))
    ImGui::OpenPopup(popup_id);

// ImGuiPopupFlagsを使用
if (ImGui::Button("ポップアップを開く"))
    ImGui::OpenPopup("my_popup", ImGuiPopupFlags_NoOpenOverExistingPopup);
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| str_id / id | ポップアップ識別子 | 呼び出し元から渡される | Yes |
| popup_flags | ポップアップフラグ | 呼び出し元から渡される | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | OpenPopup()呼び出し | イベント発生時に一度だけ | ボタンクリック等 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ImGuiPopupFlags_NoOpenOverExistingPopup + 既存ポップアップあり | 同レベルにポップアップが存在する場合は開かない |
| 連続フレームでの呼び出し | 自動的に再オープンが抑制される（NoReopenフラグなしでも） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[OpenPopup呼び出し] --> B{str_id版?}
    B -->|Yes| C[GetID計算]
    B -->|No| D[ID直接使用]
    C --> E[OpenPopupEx呼び出し]
    D --> E
    E --> F{NoOpenOverExistingPopup<br/>フラグあり?}
    F -->|Yes| G{既存ポップアップあり?}
    F -->|No| H[ImGuiPopupData作成]
    G -->|Yes| I[処理終了（開かない）]
    G -->|No| H
    H --> J[ポップアップ位置計算]
    J --> K{OpenPopupStack.Size <<br/>current_stack_size + 1?}
    K -->|Yes| L[push_back]
    K -->|No| M{同一ポップアップで<br/>連続フレーム?}
    M -->|Yes| N[OpenFrameCount更新のみ]
    M -->|No| O[ClosePopupToLevel + push_back]
    L --> P[終了]
    N --> P
    O --> P
    I --> P
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| ImGuiContext (GImGui) | グローバルコンテキスト | ポップアップスタック管理 |

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

#### ImGuiContext

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| CurrentWindow | 現在のウィンドウ | ID計算用 |
| BeginPopupStack | Begin済みポップアップのスタック | サイズ確認 |
| OpenPopupStack | 開いているポップアップのスタック | 状態確認・更新 |
| FrameCount | 現在のフレーム番号 | 連続呼び出し検出 |
| NavWindow | ナビゲーションウィンドウ | フォーカス復元用 |
| IO.MousePos | マウス位置 | ポップアップ位置設定 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| OpenPopupStack | PUSH/UPDATE | ポップアップ参照の追加・更新 |

#### ポップアップスタック操作

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| PUSH | OpenPopupStack | ImGuiPopupData | 新規ポップアップ |
| UPDATE | OpenFrameCount | g.FrameCount | 連続呼び出し時 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| なし | - | OpenPopupは常に安全に動作する |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（ただし毎フレーム呼び出しは非推奨） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（即座に実行される同期処理）

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

特になし。ローカルUIレンダリング処理のため、外部通信やデータ永続化は行わない。

## 備考

- 毎フレーム呼び出さないこと（イベント発生時に一度だけ）
- ポップアップIDは現在のIDスタックに対して相対的
- OpenPopupとBeginPopupは同じレベルのIDスタックで呼び出す必要がある
- IsWindowAppearing()をBeginPopup()後に使用してウィンドウが開いたばかりかを確認可能
- ImGuiPopupFlags_NoOpenOverExistingPopupで既存ポップアップ上での開きを防止
- ImGuiPopupFlags_NoReopenで再オープンを防止（位置変更・ナビゲーション初期化なし）
- 連続フレームでの呼び出しは自動的に抑制される（プログラミングミス対策）

---

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

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

### 推奨読解順序

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

ポップアップ管理に関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui_internal.h | `imgui_internal.h` | ImGuiPopupData構造体（1471-1483行目） |
| 1-2 | imgui.h | `imgui.h` | ImGuiPopupFlags定義（1337-1352行目） |

**読解のコツ**: ImGuiPopupDataのフィールド（PopupId, Window, OpenFrameCount, OpenPopupPos, OpenMousePos）の役割を理解する。

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

OpenPopupの宣言と実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui.h | `imgui.h` | OpenPopup API宣言（856-857行目） |
| 2-2 | imgui.h | `imgui.h` | ポップアップセクションコメント（849-855行目） |
| 2-3 | imgui.cpp | `imgui.cpp` | OpenPopup(str_id)実装（12155-12161行目） |
| 2-4 | imgui.cpp | `imgui.cpp` | OpenPopup(id)実装（12163-12166行目） |

**主要処理フロー**:
1. **12158行目**: GetID(str_id)でID計算
2. **12159行目**: デバッグログ出力
3. **12160行目**: OpenPopupEx呼び出し

#### Step 3: OpenPopupExの詳細を理解する

OpenPopupExの内部実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui.cpp | `imgui.cpp` | OpenPopupEx実装（12172-12223行目） |

**主要処理フロー**:
- **12178-12180行目**: NoOpenOverExistingPopupフラグ処理
- **12182-12189行目**: ImGuiPopupData作成
- **12192-12222行目**: OpenPopupStack更新ロジック

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

```
OpenPopup(str_id, flags) [imgui.cpp:12155]
    │
    ├─ CurrentWindow->GetID(str_id) [ID計算]
    │
    └─ OpenPopupEx(id, flags) [imgui.cpp:12172]
           │
           ├─ IsPopupOpen(0, AnyPopupId) [条件付き: NoOpenOverExistingPopup]
           │
           ├─ ImGuiPopupData作成
           │       │
           │       ├─ PopupId = id
           │       ├─ RestoreNavWindow = g.NavWindow
           │       ├─ OpenFrameCount = g.FrameCount
           │       ├─ OpenParentId = parent_window->IDStack.back()
           │       ├─ OpenPopupPos = NavCalcPreferredRefPos()
           │       └─ OpenMousePos = g.IO.MousePos
           │
           └─ OpenPopupStack更新
                  │
                  ├─ [新規] push_back(popup_ref)
                  │
                  └─ [既存] OpenFrameCount更新 or ClosePopupToLevel + push_back
```

### データフロー図

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

str_id / id        ───▶ OpenPopup()              ───▶ void
popup_flags               │
                          ▼
CurrentWindow      ───▶ GetID(str_id)            ───▶ ImGuiID
  │                       │
  └─ IDStack              ▼
                     OpenPopupEx()
                          │
                          ▼
g.NavWindow        ───▶ ImGuiPopupData作成
g.IO.MousePos             │
g.FrameCount              ▼
                     OpenPopupStack更新          ───▶ ポップアップ登録
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ソース | API宣言・フラグ定義 |
| imgui.cpp | `imgui.cpp` | ソース | 実装本体 |
| imgui_internal.h | `imgui_internal.h` | ソース | ImGuiPopupData構造体定義 |
