# 機能設計書 165-OpenPopup

## 概要

本ドキュメントは、Dear ImGuiライブラリにおける `OpenPopup` 関数の機能設計書である。この関数は、ポップアップの状態を「開いている」に設定し、次回の`BeginPopup`呼び出し時にポップアップが表示されるようにする。

### 本機能の処理概要

`OpenPopup`は、ポップアップウィンドウを開くためのトリガー関数である。この関数を呼び出すことでポップアップの状態が「開いている」にマークされ、同じIDスタックレベルで`BeginPopup`が呼び出されたときにポップアップが表示される。毎フレーム呼び出すのではなく、ポップアップを開きたいタイミング（ボタンクリック時など）で一度だけ呼び出す。

**業務上の目的・背景**：GUIアプリケーションにおいて、ポップアップの表示は通常ユーザーアクション（クリック、右クリック等）に応じて行われる。`OpenPopup`は、この「ポップアップを開く」というアクションと、実際のポップアップ表示（`BeginPopup`）を分離することで、柔軟なポップアップ制御を可能にする。これにより、ポップアップの開閉ロジックとコンテンツ定義を独立して記述できる。

**機能の利用シーン**：
- ボタンクリック時のポップアップ表示
- 右クリックによるコンテキストメニュー表示
- キーボードショートカットによるポップアップ表示
- 条件達成時の自動ポップアップ表示
- 他のポップアップからの遷移

**主要な処理内容**：
1. 文字列識別子からポップアップIDを計算
2. ImGuiPopupFlagsに基づいた開閉制御
3. ポップアップスタック（`g.OpenPopupStack`）への追加
4. フォーカス復元用のNavWindow情報の保存
5. 開いた位置（マウス位置またはナビゲーション位置）の記録

**関連システム・外部連携**：
- `BeginPopup`/`BeginPopupModal`: 開いたポップアップの表示に使用
- `CloseCurrentPopup`: ポップアップを閉じる
- `g.OpenPopupStack`: ポップアップの開状態を管理するスタック

**権限による制御**：なし。すべてのコンテキストで使用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | Popups | 主機能 | ポップアップを開く |

## 機能種別

UI制御機能（ポップアップ状態管理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| str_id | const char* | Yes | ポップアップの識別子文字列 | NULLポインタ禁止 |
| popup_flags | ImGuiPopupFlags | No | ポップアップフラグ（デフォルト: 0） | 有効なImGuiPopupFlagsの組み合わせ |

または

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | ImGuiID | Yes | ポップアップのID | 0は無効（ただしチェックなし） |
| popup_flags | ImGuiPopupFlags | No | ポップアップフラグ（デフォルト: 0） | 有効なImGuiPopupFlagsの組み合わせ |

### 入力データソース

- 呼び出し元コードから提供される識別子またはID
- 内部的に`g.CurrentWindow->IDStack`を参照してID計算

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (戻り値なし) | void | この関数は戻り値を持たない |

### 出力先

- `g.OpenPopupStack`にポップアップ情報を追加/更新

## 処理フロー

### 処理シーケンス

```
1. ID計算（文字列版の場合）
   └─ CurrentWindow->GetID(str_id) でIDを生成
2. 既存ポップアップチェック（NoOpenOverExistingPopupフラグ）
   └─ 既に同レベルにポップアップがあれば早期リターン
3. ImGuiPopupDataの作成
   └─ PopupId, Window(NULL), RestoreNavWindow, OpenFrameCount
   └─ OpenParentId, OpenPopupPos, OpenMousePos を設定
4. スタック処理
   └─ スタックサイズ < 現在のレベル + 1: 新規追加
   └─ 同じIDが既存: NoReopenフラグまたは連続呼び出し検出
   └─ 異なるID: ClosePopupToLevelで既存を閉じて追加
```

### フローチャート

```mermaid
flowchart TD
    A[OpenPopup開始] --> B[ID計算]
    B --> C{NoOpenOverExistingPopup && 既存あり?}
    C -->|Yes| D[return]
    C -->|No| E[ImGuiPopupData作成]
    E --> F{スタック < 現レベル+1?}
    F -->|Yes| G[スタックにpush]
    F -->|No| H{同じID?}
    H -->|Yes| I{NoReopen or 連続呼び出し?}
    I -->|Yes| J[OpenFrameCountのみ更新]
    I -->|No| K[ClosePopupToLevel + push]
    H -->|No| K
    G --> L[終了]
    J --> L
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-165-01 | 一度だけ呼び出し | ポップアップを開くときに一度だけ呼び出す（毎フレームではない） | 常時 |
| BR-165-02 | IDスタック一致 | OpenPopupとBeginPopupは同じIDスタックレベルで呼び出す | 常時 |
| BR-165-03 | NoReopen動作 | ImGuiPopupFlags_NoReopenフラグで再オープンを防止 | フラグ指定時 |
| BR-165-04 | NoOpenOverExisting | 既存ポップアップがある場合は開かない | フラグ指定時 |
| BR-165-05 | 連続呼び出し検出 | 連続フレームでの呼び出しは暗黙的にNoReopenとして扱う | 毎フレーム呼び出し時 |

### 計算ロジック

- ポップアップID: `CurrentWindow->IDStack`に基づいてstr_idからハッシュ計算
- 開位置: `NavCalcPreferredRefPos(ImGuiWindowFlags_Popup)`で計算

## データベース操作仕様

該当なし（データベース操作は行わない）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 未定義動作 | str_idがNULL | NULLを渡さない |
| - | 論理エラー | 毎フレームOpenPopupを呼び出す | 開くタイミングで一度だけ呼び出す |

### リトライ仕様

リトライ不要。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- 処理時間: 即時
- スタック操作のみで軽量

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

特になし。

## 備考

- 文字列版とID版の2つのオーバーロードが提供されている
- ID版はネストされたスタックからの呼び出しに便利
- `IsWindowAppearing()`を`BeginPopup`後に使用して、開いた直後かを判定可能
- 毎フレーム呼び出した場合、2フレーム目以降はNoReopenと同等の動作になる

---

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

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

### 推奨読解順序

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

ポップアップ状態を管理するデータ構造を理解する。

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

**読解のコツ**: `ImGuiPopupData`の各フィールドが何を記録しているか理解する。特に`OpenFrameCount`は連続呼び出し検出に使用される。

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

`OpenPopup`関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui.cpp | `imgui.cpp` | OpenPopup（文字列版）実装（12155-12161行目） |
| 2-2 | imgui.cpp | `imgui.cpp` | OpenPopup（ID版）実装（12163-12166行目） |

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

#### Step 3: 内部実装を理解する

`OpenPopupEx`の詳細な実装を確認する。

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

**主要処理フロー**:
- **12178-12180行目**: NoOpenOverExistingPopupフラグの処理
- **12182-12189行目**: ImGuiPopupDataの作成と初期化
- **12192-12222行目**: スタック追加と再オープン制御のロジック

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

```
OpenPopup(str_id, popup_flags)
    │
    ├─ CurrentWindow->GetID(str_id)
    │      └─ IDスタックからハッシュ計算
    │
    └─ OpenPopupEx(id, popup_flags)
           │
           ├─ IsPopupOpen(0, AnyPopupId)  [条件付き]
           │      └─ NoOpenOverExistingPopup判定
           │
           ├─ ImGuiPopupData作成
           │      ├─ PopupId = id
           │      ├─ OpenFrameCount = g.FrameCount
           │      ├─ OpenParentId = parent_window->IDStack.back()
           │      ├─ OpenPopupPos = NavCalcPreferredRefPos()
           │      └─ OpenMousePos = g.IO.MousePos
           │
           └─ g.OpenPopupStack操作
                  ├─ push_back()  [新規]
                  └─ ClosePopupToLevel() + push_back()  [置換]
```

### データフロー図

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

str_id (文字列) ───▶ OpenPopup()         ───▶ (なし)
popup_flags         │
                    ├─ ID計算
                    │   └─ GetID()
                    │
                    ├─ ImGuiPopupData作成
                    │   └─ フレーム/位置情報記録
                    │
                    └─ スタック更新
                        └─ g.OpenPopupStack
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダ | 関数宣言（856-857行目）、ImGuiPopupFlags定義 |
| imgui.cpp | `imgui.cpp` | ソース | OpenPopup実装（12155-12166行目）、OpenPopupEx実装（12172-12223行目） |
| imgui_internal.h | `imgui_internal.h` | 内部ヘッダ | ImGuiPopupData構造体、OpenPopupStack定義 |
| imgui_demo.cpp | `imgui_demo.cpp` | デモ | 使用例（5262行目、5316行目等） |
