# 機能設計書 151-EndMenuBar

## 概要

本ドキュメントはImGuiのEndMenuBar機能について、その処理内容、入出力仕様、実装詳細を記述した機能設計書である。

### 本機能の処理概要

EndMenuBarは、BeginMenuBar()で開始されたメニューバー領域を終了するための関数である。メニューバーのレイアウト状態をリストアし、ナビゲーション処理を完了させ、通常のウィンドウコンテンツ描画モードに戻す。

**業務上の目的・背景**：GUIアプリケーションにおいて、ウィンドウ内にメニューバーを実装する際、BeginMenuBar()とEndMenuBar()のペアでメニュー領域を定義する。EndMenuBar()は、メニューバー領域で行われた各種の状態変更（クリップ領域、レイアウト方向、ナビゲーションレイヤー等）を元に戻し、メニューバー以降のウィンドウコンテンツが正しく描画されるようにする役割を担う。これにより、開発者はBegin/Endのシンプルなパターンでメニューバーを実装できる。

**機能の利用シーン**：ウィンドウ内メニューバーを実装する場合、BeginMenuBar()がtrueを返した後にメニュー項目（BeginMenu/MenuItem）を配置し、最後にEndMenuBar()を呼び出す。Demo WindowやSimple Layoutなどの画面で使用されている。

**主要な処理内容**：
1. ウィンドウのSkipItems状態をチェックする
2. メニューバー状態のアサーション検証を行う
3. 子メニューのナビゲーションリクエスト（左右移動）を処理する
4. クリップ矩形をポップする
5. IDスタックからポップする
6. メニューバーオフセットを保存する
7. グループを終了し、レイアウト状態をリストアする

**関連システム・外部連携**：ImGuiのナビゲーションシステムと連携し、キーボード/ゲームパッドによるメニュー操作をサポートする。

**権限による制御**：特になし。BeginMenuBar()が呼ばれていない状態での呼び出しはアサーションエラーとなる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | Demo Window | 主機能 | メニューバーの終了 |
| 12 | Simple Layout | 主機能 | メニューバーの終了 |

## 機能種別

レイアウト処理 / 状態管理

## 入力仕様

### 入力パラメータ

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

### 入力データソース

- ImGuiContext（グローバルコンテキスト）
- ImGuiWindow（現在のウィンドウ）
- グループスタック（GroupStack）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (なし) | void | 戻り値なし |

### 出力先

- ImGuiWindow::DC（描画コンテキストの状態更新）

## 処理フロー

### 処理シーケンス

```
1. ウィンドウ取得とSkipItemsチェック
   └─ GetCurrentWindow()で現在のウィンドウを取得
   └─ SkipItemsがtrueの場合は即座にreturn

2. アサーション検証
   └─ ImGuiWindowFlags_MenuBarフラグの確認
   └─ MenuBarAppendingフラグの確認

3. ナビゲーション処理
   └─ 子メニューからの左右移動リクエストを検出
   └─ メニュー間のナビゲーション転送を処理
   └─ ナビゲーションラップ処理を実行

4. 状態リストア
   └─ PopClipRect()でクリップ矩形をポップ
   └─ PopID()でIDスタックをポップ
   └─ メニューバーオフセットを保存

5. グループ終了とレイアウトリストア
   └─ グループデータのEmitItemをfalseに設定
   └─ EndGroup()を呼び出し
   └─ レイアウトをVerticalに戻す
   └─ ナビゲーションレイヤーをMainに戻す
   └─ MenuBarAppendingをfalseに設定
```

### フローチャート

```mermaid
flowchart TD
    A[開始: EndMenuBar] --> B[GetCurrentWindow]
    B --> C{SkipItems?}
    C -->|Yes| D[終了]
    C -->|No| E[アサーション検証]
    E --> F{子メニューからの<br/>NavMove要求?}
    F -->|Yes| G[メニュー間ナビゲーション処理]
    G --> H[フォーカス移動とNavID設定]
    H --> I[NavMoveRequestForward]
    F -->|No| J[NavMoveRequestTryWrapping]
    I --> K[PopClipRect]
    J --> K
    K --> L[PopID]
    L --> M[メニューバーオフセット保存]
    M --> N[グループ終了処理]
    N --> O[レイアウト状態リストア]
    O --> D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-151-01 | ペア呼び出し | BeginMenuBar()がtrueを返した場合のみ呼び出す | 常時 |
| BR-151-02 | ナビゲーション転送 | 子メニュー内での左右ナビゲーションが失敗した場合、親メニューバーに転送 | 子メニューが開いている場合 |
| BR-151-03 | レイアウト復元 | 終了時にレイアウトをVerticalに戻す | 常時 |

### 計算ロジック

- メニューバーオフセット: `window->DC.CursorPos.x - window->Pos.x`
- IdealMaxPos更新: `ImMax(window->DC.IdealMaxPos.x, window->DC.CursorMaxPos.x - window->Scroll.x)`

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

データベース操作なし（UI状態管理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 早期リターン | window->SkipItems == true | 処理をスキップ |
| - | アサーション | MenuBarフラグがない | デバッグビルドでアサート |
| - | アサーション | MenuBarAppendingがfalse | デバッグビルドでアサート |

### リトライ仕様

リトライ不要（フレームごとに再実行）

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

トランザクション管理なし（即時状態更新）

## パフォーマンス要件

- 単一フレーム内で複数回呼び出し可能
- 状態の復元処理のみのため軽量

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

- 特になし

## 備考

- BeginMenuBar()とEndMenuBar()は必ずペアで使用する
- BeginMenuBar()がfalseを返した場合はEndMenuBar()を呼び出してはならない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui.h | `imgui.h` | 809-810行目: BeginMenuBar/EndMenuBarのAPI宣言を確認 |
| 1-2 | imgui_internal.h | `imgui_internal.h` | ImGuiWindowのDC（DrawContext）メンバー、特にMenuBarAppending、NavLayerCurrentを確認 |

**読解のコツ**: EndMenuBarはBeginMenuBarで変更された複数の状態を元に戻す関数。BeginMenuBarで何が設定されているかを先に理解すると、EndMenuBarの処理が明確になる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 9028-9085行目: EndMenuBar関数の実装 |

**主要処理フロー**:
1. **9030-9032行目**: ウィンドウ取得とSkipItemsチェック
2. **9036-9037行目**: フラグとMenuBarAppending状態のアサーション
3. **9039-9067行目**: 子メニューからのナビゲーションリクエスト処理
4. **9069-9070行目**: クリップ矩形とIDのポップ
5. **9072行目**: メニューバーオフセットの保存
6. **9074-9084行目**: グループ終了とレイアウト状態の復元

#### Step 3: ナビゲーション処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 9040-9062行目: 子メニューからの左右移動処理 |

**主要処理フロー**:
- **9040行目**: NavMoveRequestButNoResultYet()で未処理のナビゲーション要求を検出
- **9044-9045行目**: nav_earliest_childを辿って最初の子メニューを特定
- **9052-9053行目**: フォーカスとNavIDを設定してナビゲーションを転送

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

```
ImGui::EndMenuBar()
    │
    ├─ GetCurrentWindow()
    │      └─ 現在のウィンドウコンテキストを取得
    │
    ├─ NavMoveRequestButNoResultYet()
    │      └─ 未処理のナビゲーション要求があるか確認
    │
    ├─ FocusWindow()
    │      └─ ウィンドウにフォーカスを移動
    │
    ├─ SetNavID()
    │      └─ ナビゲーションIDを設定
    │
    ├─ NavMoveRequestForward()
    │      └─ ナビゲーション要求を転送
    │
    ├─ NavMoveRequestTryWrapping()
    │      └─ メニューバー内でのラップナビゲーション
    │
    ├─ PopClipRect()
    │      └─ クリップ矩形をスタックからポップ
    │
    ├─ PopID()
    │      └─ IDをスタックからポップ
    │
    └─ EndGroup()
           └─ グループを終了し状態を復元
```

### データフロー図

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

window->SkipItems ─────────> SkipItemsチェック ──────────────> 早期リターン
                                  │
window->DC.MenuBarAppending ──> 状態検証
                                  │
g.NavMoveDir ─────────────────> ナビゲーション処理
g.NavWindow                       │
g.NavLayer                        │
                                  │
GroupStack ───────────────────> グループ終了
                                  │
                                  ├──────────────────────────> window->DC.LayoutType = Vertical
                                  ├──────────────────────────> window->DC.NavLayerCurrent = Main
                                  └──────────────────────────> window->DC.MenuBarAppending = false
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダー | EndMenuBar APIの宣言 |
| imgui_internal.h | `imgui_internal.h` | ヘッダー | 内部データ構造の定義 |
| imgui_widgets.cpp | `imgui_widgets.cpp` | ソース | EndMenuBarの実装（9028-9085行目） |
| imgui.cpp | `imgui.cpp` | ソース | PopClipRect、PopID、EndGroup等のコア関数 |
