# 機能設計書 167-CloseCurrentPopup

## 概要

本ドキュメントは、Dear ImGuiライブラリにおける `CloseCurrentPopup` 関数の機能設計書である。この関数は、現在開いているポップアップを手動で閉じるために使用される。

### 本機能の処理概要

`CloseCurrentPopup`は、`BeginPopup`/`BeginPopupModal`のスコープ内から呼び出され、現在のポップアップを明示的に閉じる関数である。`Selectable`や`MenuItem`が選択されたときには自動的に呼び出されるが、カスタムボタンや条件付きでポップアップを閉じる場合には手動で呼び出す必要がある。

**業務上の目的・背景**：GUIアプリケーションにおいて、ポップアップやダイアログは特定のアクション（選択、確認、キャンセル等）の後に閉じられることが一般的である。`CloseCurrentPopup`は、この「ポップアップを閉じる」アクションをプログラムから制御するための手段を提供する。これにより、カスタムUI要素からポップアップを閉じたり、条件に基づいて閉じるタイミングを制御したりできる。

**機能の利用シーン**：
- カスタムボタンでのポップアップ閉じ
- モーダルダイアログの「OK」「キャンセル」ボタン処理
- 条件達成時の自動ポップアップ閉じ
- メニューアイテム選択時のカスタム閉じ処理
- 子メニューから親メニューまでの一括閉じ

**主要な処理内容**：
1. 現在のポップアップインデックスを`g.BeginPopupStack.Size - 1`から取得
2. スタックの整合性を検証
3. 子メニュー（`ImGuiWindowFlags_ChildMenu`）の場合は親までさかのぼる
4. `ClosePopupToLevel`を呼び出してポップアップを閉じる
5. ナビゲーションハイライトを一時的に非表示

**関連システム・外部連携**：
- `BeginPopup`/`BeginPopupModal`: ポップアップを開始（CloseCurrentPopupはこのスコープ内で使用）
- `ClosePopupToLevel`: 内部的に呼び出される実際のクローズ処理
- `g.BeginPopupStack`/`g.OpenPopupStack`: ポップアップスタックの管理

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | Popups | 主機能 | 現在のポップアップを閉じる |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| (なし) | - | - | パラメータなし | - |

### 入力データソース

- 内部的に`g.BeginPopupStack`（処理中のポップアップスタック）を参照
- 内部的に`g.OpenPopupStack`（開いているポップアップスタック）を参照

## 出力仕様

### 出力データ

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

### 出力先

- `g.OpenPopupStack`からポップアップ情報を削除
- フォーカスを適切なウィンドウに復元

## 処理フロー

### 処理シーケンス

```
1. ポップアップインデックス取得
   └─ popup_idx = g.BeginPopupStack.Size - 1
2. 整合性検証
   └─ popup_idx < 0: 早期リターン
   └─ popup_idx >= g.OpenPopupStack.Size: 早期リターン
   └─ BeginPopupStack[popup_idx].PopupId != OpenPopupStack[popup_idx].PopupId: 早期リターン
3. 子メニュー処理
   └─ popup_idxをさかのぼりながら
   └─ ChildMenuフラグを持ち、親がMenuBarでない場合は親まで閉じる
4. ClosePopupToLevel呼び出し
   └─ 決定したpopup_idxまでスタックを閉じる
5. ナビゲーションハイライト非表示
   └─ NavWindow->DC.NavHideHighlightOneFrame = true
```

### フローチャート

```mermaid
flowchart TD
    A[CloseCurrentPopup開始] --> B[popup_idx = BeginPopupStack.Size - 1]
    B --> C{popup_idx < 0?}
    C -->|Yes| D[return]
    C -->|No| E{popup_idx >= OpenPopupStack.Size?}
    E -->|Yes| D
    E -->|No| F{PopupId一致?}
    F -->|No| D
    F -->|Yes| G[子メニュー処理ループ]
    G --> H{ChildMenuフラグ && 親がMenuBarでない?}
    H -->|Yes| I[popup_idx--]
    I --> G
    H -->|No| J[ClosePopupToLevel popup_idx]
    J --> K[NavHideHighlightOneFrame = true]
    K --> L[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-167-01 | スコープ内呼び出し | BeginPopup/BeginPopupModalのスコープ内で呼び出す必要がある | 常時 |
| BR-167-02 | 子メニュー連鎖閉じ | 子メニューを閉じると、親メニューまで連鎖的に閉じる（モーダルは除く） | 子メニュー内 |
| BR-167-03 | 自動呼び出し | Selectable/MenuItemは選択時に自動的にCloseCurrentPopupを呼び出す | デフォルト動作 |
| BR-167-04 | フォーカス復元 | ポップアップを閉じるとフォーカスが適切なウィンドウに復元される | 常時 |

### 計算ロジック

- 閉じるレベル: 子メニューの場合は親メニュー（MenuBar直下を除く）まで遡上

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 早期リターン | ポップアップ外で呼び出した | ポップアップスコープ内で呼び出す |
| - | 早期リターン | スタック不整合 | 通常発生しない（内部エラー） |

### リトライ仕様

リトライ不要。

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

該当なし。

## パフォーマンス要件

- 処理時間: 即時
- スタック操作とフォーカス処理のみ

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

特になし。

## 備考

- `Selectable()`や`MenuItem()`はデフォルトでCloseCurrentPopupを呼び出す
- `ImGuiSelectableFlags_NoAutoClosePopups`フラグでこの動作を無効化できる
- モーダルダイアログでは「OK」「キャンセル」ボタンで明示的に呼び出すのが一般的
- 子メニューから呼び出すと親メニューも閉じる（メニューバー直下まで）

---

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

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

### 推奨読解順序

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

ポップアップスタックの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui_internal.h | `imgui_internal.h` | OpenPopupStack, BeginPopupStack定義（2308-2309行目） |
| 1-2 | imgui.h | `imgui.h` | ImGuiWindowFlags_ChildMenu定義 |

**読解のコツ**: `BeginPopupStack`は現在のフレームで処理中のポップアップ、`OpenPopupStack`は開いているすべてのポップアップを追跡する。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui.cpp | `imgui.cpp` | CloseCurrentPopup実装（12314-12342行目） |

**主要処理フロー**:
1. **12317行目**: popup_idx = BeginPopupStack.Size - 1
2. **12318行目**: 整合性検証（3条件）
3. **12322-12333行目**: 子メニュー処理ループ
4. **12334行目**: デバッグログ
5. **12335行目**: ClosePopupToLevel呼び出し
6. **12340-12341行目**: ナビゲーションハイライト非表示

#### Step 3: クローズ処理の詳細を理解する

`ClosePopupToLevel`の実装を確認する。

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

**主要処理フロー**:
- **12298-12299行目**: OpenPopupStackのリサイズ（trim）
- **12302-12310行目**: フォーカス復元処理

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

```
CloseCurrentPopup()
    │
    ├─ 整合性検証
    │      ├─ g.BeginPopupStack.Size
    │      ├─ g.OpenPopupStack.Size
    │      └─ PopupId一致確認
    │
    ├─ 子メニュー処理ループ
    │      ├─ OpenPopupStack[popup_idx].Window
    │      ├─ ChildMenuフラグ確認
    │      └─ 親のMenuBarフラグ確認
    │
    └─ ClosePopupToLevel(popup_idx, true)
           │
           ├─ g.OpenPopupStack.resize(remaining)
           │
           └─ FocusWindow/FocusTopMostWindowUnderOne
                  └─ フォーカス復元
```

### データフロー図

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

(なし)          ───▶ CloseCurrentPopup()  ───▶ (なし)
                     │
                     ├─ スタック検証
                     │   ├─ g.BeginPopupStack
                     │   └─ g.OpenPopupStack
                     │
                     ├─ 子メニュー遡上
                     │   └─ ChildMenu判定
                     │
                     └─ ClosePopupToLevel()
                         ├─ g.OpenPopupStack.resize()
                         └─ フォーカス復元
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダ | 関数宣言（859行目） |
| imgui.cpp | `imgui.cpp` | ソース | CloseCurrentPopup実装（12314-12342行目）、ClosePopupToLevel実装（12288-12311行目） |
| imgui_internal.h | `imgui_internal.h` | 内部ヘッダ | ポップアップスタック定義 |
| imgui_demo.cpp | `imgui_demo.cpp` | デモ | 使用例（5370行目、5453行目、5456行目等） |
