# 機能設計書 170-BeginPopupContextVoid

## 概要

本ドキュメントは、Dear ImGuiライブラリにおける `BeginPopupContextVoid` 関数の機能設計書である。この関数は、ウィンドウが存在しない空白領域（void）に対するコンテキストメニュー（右クリックメニュー）を実装するためのヘルパー関数である。

### 本機能の処理概要

`BeginPopupContextVoid`は、どのウィンドウもホバーされていない領域（アプリケーションの背景部分）がクリック（デフォルト: 右クリック）されたときにポップアップを開くヘルパー関数である。`BeginPopupContextWindow`がウィンドウ内を対象とするのに対し、この関数はウィンドウ外の空白領域を対象とする。

**業務上の目的・背景**：GUIアプリケーションにおいて、ウィンドウ以外の背景領域を右クリックしてメニューを表示するパターンが存在する。デスクトップアプリケーションの背景右クリックや、キャンバス外領域のメニュー表示などで使用される。`BeginPopupContextVoid`は、このパターンを実装するための専用ヘルパーを提供する。

**機能の利用シーン**：
- アプリケーション背景の右クリックメニュー
- 全ウィンドウ外領域での操作メニュー
- ウィンドウ配置/レイアウト関連のメニュー
- デバッグ用メニューの表示
- アプリケーション全体設定へのアクセス

**主要な処理内容**：
1. ポップアップIDを決定（str_idまたは"void_context"）
2. 指定されたマウスボタンがリリースされ、どのウィンドウもホバーされていない場合を検出
3. モーダルポップアップが開いていない場合のみポップアップを開く
4. OpenPopupExを呼び出してポップアップを開く
5. BeginPopupExを呼び出してポップアップを開始

**関連システム・外部連携**：
- `OpenPopupEx`: ポップアップを開く内部関数
- `BeginPopupEx`: ポップアップウィンドウを開始する内部関数
- `IsWindowHovered`: ウィンドウのホバー判定（AnyWindowフラグ）
- `GetTopMostPopupModal`: モーダルポップアップの存在確認

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 全体背景 | 主機能 | 空白領域コンテキストメニュー |

## 機能種別

UI制御機能（空白領域コンテキストメニューヘルパー）

## 入力仕様

### 入力パラメータ

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

### 入力データソース

- 呼び出し元コードから提供される識別子（オプション）
- 内部的に現在のウィンドウ情報（`g.CurrentWindow`）を参照
- マウス入力状態

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | bool | ポップアップが開いていてコンテンツを追加できる場合はtrue |

### 出力先

- 画面上にコンテキストメニューウィンドウとして表示
- `g.OpenPopupStack`/`g.BeginPopupStack`に情報追加

## 処理フロー

### 処理シーケンス

```
1. ポップアップID決定
   └─ str_id != NULL: str_idを使用
   └─ str_id == NULL: "void_context"をデフォルトとして使用
2. ID計算
   └─ window->GetID(str_id)
3. マウスボタン種類取得
   └─ GetMouseButtonFromPopupFlags(popup_flags)
4. ポップアップオープン判定
   └─ IsMouseReleased(mouse_button)
   └─ !IsWindowHovered(AnyWindow) （どのウィンドウもホバーされていない）
   └─ GetTopMostPopupModal() == NULL （モーダルが開いていない）
5. OpenPopupEx呼び出し（条件付き）
6. BeginPopupEx呼び出し
   └─ AlwaysAutoResize | NoTitleBar | NoSavedSettingsフラグ付き
```

### フローチャート

```mermaid
flowchart TD
    A[BeginPopupContextVoid開始] --> B{str_id != NULL?}
    B -->|Yes| C[str_idを使用]
    B -->|No| D[str_id = void_context]
    C --> E[id = GetID str_id]
    D --> E
    E --> F[マウスボタン種類取得]
    F --> G{IsMouseReleased?}
    G -->|No| H[BeginPopupEx id]
    G -->|Yes| I{!IsWindowHovered AnyWindow?}
    I -->|No| H
    I -->|Yes| J{GetTopMostPopupModal == NULL?}
    J -->|No| H
    J -->|Yes| K[OpenPopupEx id]
    K --> H
    H --> L{ポップアップが開いている?}
    L -->|Yes| M[return true]
    L -->|No| N[return false]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-170-01 | デフォルトID | str_id = NULLの場合、"void_context"がIDとして使用される | str_id未指定時 |
| BR-170-02 | デフォルト右クリック | popup_flags = 0の場合、右クリックがトリガー | フラグ未指定時 |
| BR-170-03 | AnyWindow判定 | どのウィンドウもホバーされていない場合のみトリガー | 常時 |
| BR-170-04 | モーダル優先 | モーダルポップアップが開いている場合は開かない | 常時 |
| BR-170-05 | 自動リサイズ | ポップアップウィンドウはコンテンツに応じて自動リサイズ | 常時 |

### 計算ロジック

- ポップアップID: `window->GetID(str_id)`で計算
- デフォルトstr_id: "void_context"

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 特になし | - | - |

### リトライ仕様

リトライ不要（毎フレーム呼び出し）。

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

該当なし。

## パフォーマンス要件

- 処理時間: 即時
- 毎フレーム呼び出されるが、ホバー/クリック状態の確認は軽量

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

特になし。

## 備考

- trueを返した場合は必ず`EndPopup`を呼び出す
- `BeginPopupContextWindow`との違い: この関数はウィンドウ外の空白領域を対象とする
- `BeginPopupContextItem`との違い: アイテム単位ではなく、ウィンドウが存在しない領域全体
- モーダルが開いている場合は開かないため、モーダルの排他制御が維持される

---

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

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

### 推奨読解順序

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

ポップアップフラグとモーダル判定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui.h | `imgui.h` | ImGuiHoveredFlags_AnyWindow定義 |
| 1-2 | imgui.cpp | `imgui.cpp` | GetTopMostPopupModal関数（12097-12105行目） |

**読解のコツ**: `IsWindowHovered(AnyWindow)`の否定で「どのウィンドウもホバーされていない」を判定。モーダル存在確認でモーダル優先を実装。

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

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

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

**主要処理フロー**:
1. **12529-12530行目**: str_id = NULLなら"void_context"を使用
2. **12531行目**: ID計算
3. **12532行目**: マウスボタン種類取得
4. **12533行目**: マウスリリース && ウィンドウ未ホバー判定
5. **12534行目**: モーダルが開いていないか確認
6. **12535行目**: OpenPopupEx呼び出し
7. **12536行目**: BeginPopupExを呼び出して結果を返す

#### Step 3: 関連関数を理解する

`IsWindowHovered`と`GetTopMostPopupModal`の動作を確認する。

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

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

```
BeginPopupContextVoid(str_id, popup_flags)
    │
    ├─ デフォルトID設定
    │      └─ str_id = str_id ? str_id : "void_context"
    │
    ├─ window->GetID(str_id)
    │      └─ ポップアップID計算
    │
    ├─ GetMouseButtonFromPopupFlags(popup_flags)
    │      └─ マウスボタン種類を計算
    │
    ├─ 条件判定
    │      ├─ IsMouseReleased(mouse_button)
    │      ├─ !IsWindowHovered(AnyWindow)
    │      └─ GetTopMostPopupModal() == NULL
    │
    ├─ OpenPopupEx(id, popup_flags)  [条件付き]
    │
    └─ BeginPopupEx(id, flags)
           └─ AlwaysAutoResize | NoTitleBar | NoSavedSettings
```

### データフロー図

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

str_id (文字列/NULL) ─▶ BeginPopupContextVoid() ─▶ bool (開いているか)
popup_flags            │
                       ├─ ID決定
                       │   └─ GetID()
                       │
                       ├─ 空白領域判定
                       │   ├─ IsWindowHovered(AnyWindow)
                       │   └─ GetTopMostPopupModal()
                       │
                       └─ ポップアップ処理
                           ├─ OpenPopupEx()
                           └─ BeginPopupEx()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダ | 関数宣言（872行目）、ImGuiPopupFlags定義 |
| imgui.cpp | `imgui.cpp` | ソース | BeginPopupContextVoid実装（12525-12537行目）、GetTopMostPopupModal（12097-12105行目） |
| imgui_internal.h | `imgui_internal.h` | 内部ヘッダ | 内部データ構造 |
