# 機能設計書 80-EndGroup

## 概要

本ドキュメントは、Dear ImGuiライブラリのEndGroup関数の機能設計を記述する。この関数は、水平開始位置のロックを解除し、グループ全体のバウンディングボックスを1つのアイテムとしてキャプチャするためのAPI関数である。

### 本機能の処理概要

EndGroup関数は、BeginGroup()で開始したグループを終了し、グループ内のすべてのウィジェットを1つの「アイテム」として扱えるようにする。グループのバウンディングボックスを計算し、IsItemHovered()、IsItemActive()、SameLine()などのアイテム系関数がグループ全体に適用可能になる。バックアップされたレイアウト状態を復元する。

**業務上の目的・背景**：BeginGroup()と対で使用され、グループ化の終了を宣言する。グループ内のウィジェット群を論理的な1単位として扱うことで、複雑なUIコンポーネントの構築が可能になる。グループ全体へのホバー検出、アクティブ状態の転送、編集状態の追跡など、高度なインタラクション管理を実現する。これにより、カスタムウィジェットや複合コントロールの実装が容易になり、一貫性のあるUI動作を提供できる。

**機能の利用シーン**：BeginGroup()で開始したグループの終了、グループ全体へのホバー/アクティブ状態の適用、グループのバウンディングボックス取得、グループ単位でのSameLine配置などで使用される。

**主要な処理内容**：
1. GroupStackからgroup_dataを取得する
2. グループのバウンディングボックスを計算する
3. バックアップしたレイアウト状態を復元する
4. ItemSize/ItemAddでグループをアイテムとして登録する
5. ActiveId、HoveredId等のステータスをLastItemDataに転送する
6. GroupStackからポップする

**関連システム・外部連携**：この関数は純粋にImGui内部のレイアウト管理に関わるため、外部システムとの連携はない。

**権限による制御**：権限による制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | Layout | 主機能 | グループの終了 |

## 機能種別

レイアウト制御 / グループ管理

## 入力仕様

### 入力パラメータ

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

### 入力データソース

BeginGroup()で保存されたGroupStackのデータを使用する。

## 出力仕様

### 出力データ

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

### 出力先

グローバルコンテキストのLastItemDataを更新し、GroupStackからポップする。

## 処理フロー

### 処理シーケンス

```
1. グローバルコンテキストとウィンドウを取得
   └─ g = *GImGui, window = g.CurrentWindow
2. GroupStackの検証
   └─ IM_ASSERT(g.GroupStack.Size > 0)
   └─ IM_ASSERT(group_data.WindowID == window->ID)
3. グループのバウンディングボックスを計算
   └─ group_bb = ImRect(BackupCursorPos, max(CursorMaxPos, LastItemRect.Max, BackupCursorPos))
4. バックアップした状態を復元
   └─ CursorPos, CursorPosPrevLine, CursorMaxPos, Indent, GroupOffset等
5. EmitItemがtrueの場合、アイテムとして登録
   └─ ItemSize(group_bb.GetSize())
   └─ ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop)
6. ステータスの転送
   └─ ActiveId、HoveredId、DeactivatedIdの状態をLastItemDataに反映
7. GroupStackからポップ
   └─ g.GroupStack.pop_back()
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ウィンドウ取得]
    B --> C[GroupStack検証]
    C --> D[バウンディングボックス計算]
    D --> E[状態復元]
    E --> F{EmitItem?}
    F -->|Yes| G[ItemSize/ItemAdd]
    F -->|No| H[GroupStack.pop_back]
    G --> I[ステータス転送]
    I --> H
    H --> J[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ペア使用 | 必ずBeginGroup()と対で使用する必要がある | 常時 |
| BR-02 | 同一ウィンドウ | BeginGroup()と同じウィンドウで呼び出す必要がある | 常時 |
| BR-03 | ステータス転送 | グループ内のActiveId等がLastItemDataに転送される | 条件に応じて |

### 計算ロジック

バウンディングボックスの計算：
```
group_bb = ImRect(
    group_data.BackupCursorPos,
    ImMax(ImMax(window->DC.CursorMaxPos, g.LastItemData.Rect.Max), group_data.BackupCursorPos)
)
```

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

該当なし（メモリ内操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | アサーション | GroupStack.Size <= 0（BeginGroup未呼び出し） | 必ずBeginGroup()を先に呼び出す |
| - | アサーション | group_data.WindowID != window->ID（異なるウィンドウ） | 同じウィンドウで呼び出す |

### リトライ仕様

該当なし

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

該当なし（フレーム単位の即座反映）

## パフォーマンス要件

軽量な操作。バウンディングボックス計算、状態復元、ItemSize/ItemAdd呼び出しのみ。

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

特になし（純粋なUI操作）

## 備考

- BeginGroup()と必ずペアで使用すること
- EndGroup()後、IsItemHovered()、IsItemActive()、GetItemRectMin/Max()がグループ全体に適用される
- グループ内でActiveIdやHoveredIdが変更された場合、その状態がLastItemDataに転送される
- デバッグ表示モードでグループの矩形が可視化される

---

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

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

### 推奨読解順序

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

グループ管理に関わるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui_internal.h | `imgui_internal.h` | ImGuiGroupData構造体の定義（1171-1187行目） |
| 1-2 | imgui_internal.h | `imgui_internal.h` | ImGuiLastItemData構造体（1376-1389行目） |

**読解のコツ**: EndGroup()はImGuiGroupDataからバックアップを復元し、ImGuiLastItemDataにグループの情報を設定する。この2つの構造体の関係を理解することが重要。

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

EndGroup関数の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui.cpp | `imgui.cpp` | EndGroup関数の実装（11640-11704行目） |

**主要処理フロー**:
1. **11642-11647行目**: コンテキスト取得とアサーション
2. **11649-11650行目**: IsSetPosのエラーチェック
3. **11653行目**: グループのバウンディングボックス計算
4. **11654-11661行目**: バックアップした状態を復元
5. **11665-11668行目**: EmitItem=falseの場合の早期リターン
6. **11672-11673行目**: ItemSize/ItemAddでアイテム登録
7. **11679-11700行目**: ステータス転送処理
8. **11701行目**: GroupStack.pop_back()

#### Step 3: ステータス転送の詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui.cpp | `imgui.cpp` | 11679-11684行目でActiveIdの転送を確認 |
| 3-2 | imgui.cpp | `imgui.cpp` | 11688-11690行目でHoveredIdの転送を確認 |
| 3-3 | imgui.cpp | `imgui.cpp` | 11693-11694行目でEdited状態の転送を確認 |

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

```
ImGui::EndGroup()
    │
    ├─ GImGui, CurrentWindow取得
    │
    ├─ アサーション
    │      ├─ GroupStack.Size > 0
    │      └─ group_data.WindowID == window->ID
    │
    ├─ バウンディングボックス計算
    │      └─ group_bb = ImRect(BackupCursorPos, max(...))
    │
    ├─ 状態復元
    │      ├─ CursorPos
    │      ├─ CursorPosPrevLine
    │      ├─ CursorMaxPos
    │      ├─ Indent
    │      ├─ GroupOffset
    │      ├─ CurrLineSize
    │      └─ CurrLineTextBaseOffset
    │
    ├─ [EmitItem=true の場合]
    │      │
    │      ├─ ItemSize(group_bb.GetSize())
    │      │
    │      ├─ ItemAdd(group_bb, 0, NULL, NoTabStop)
    │      │
    │      └─ ステータス転送
    │             ├─ ActiveId → LastItemData.ID
    │             ├─ HoveredId → StatusFlags
    │             └─ Edited → StatusFlags
    │
    └─ GroupStack.pop_back()
```

### データフロー図

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

GroupStack(top) ────────▶ EndGroup() ──────────▶ LastItemData
                                │                    (ID, Rect, StatusFlags)
ImGuiGroupData                  │
  ├─ BackupCursorPos            │
  ├─ BackupIndent               ├────────────────▶ DC
  └─ BackupActiveIdIsAlive      │                    (状態復元)
                                │
                                └────────────────▶ GroupStack
                                                     (pop_back)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダー | EndGroup関数の宣言（585行目） |
| imgui.cpp | `imgui.cpp` | ソース | EndGroup関数の実装（11640-11704行目） |
| imgui.cpp | `imgui.cpp` | ソース | BeginGroup関数の実装（11610-11638行目） |
| imgui_internal.h | `imgui_internal.h` | 内部ヘッダー | ImGuiGroupData構造体の定義（1171-1187行目） |
| imgui_internal.h | `imgui_internal.h` | 内部ヘッダー | ImGuiLastItemData構造体の定義（1376-1389行目） |
