# 機能設計書 103-BeginCombo

## 概要

本ドキュメントは、ImGuiライブラリにおける`BeginCombo`関数の機能設計を記載する。

### 本機能の処理概要

`BeginCombo`関数は、コンボボックス（ドロップダウンリスト）ウィジェットの開始処理を行う関数である。`BeginCombo`/`EndCombo`のペアを使用することで、コンボボックス内にSelectable等の任意のウィジェットを配置でき、完全にカスタマイズ可能なドロップダウンメニューを実現する。

**業務上の目的・背景**：コンボボックスは、多数の選択肢から一つを選択するための標準的なUIコンポーネントである。BeginCombo/EndCombo APIは、単純な文字列リストの選択から、アイコン付きアイテム、カテゴリ分類、検索フィルタリング付きの選択など、様々なカスタムドロップダウンを実装するための柔軟な基盤を提供する。旧Combo APIのヘルパー関数は内部的にこのAPIを使用している。

**機能の利用シーン**：
- 設定画面でのオプション選択
- フォント・色・スタイルの選択
- ファイル形式やエンコーディングの選択
- カスタムアイテム（アイコン+テキスト）の選択
- 検索可能なドロップダウンリスト

**主要な処理内容**：
1. ウィンドウ状態とパラメータの検証
2. コンボボックスのサイズとレイアウトを計算
3. ボタン動作を処理してポップアップの開閉を制御
4. コンボボックスのフレームと矢印を描画
5. プレビュー値を描画
6. ポップアップが開いている場合はBeginComboPopupを呼び出し

**関連システム・外部連携**：
- ポップアップシステム: OpenPopupEx, IsPopupOpen, BeginComboPopup
- スタイルシステム: FramePadding, FrameRounding
- ウィンドウシステム: NextWindowData, SetNextWindowSizeConstraints

**権限による制御**：特になし（GUI描画機能のため）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | Style Editor | 補助機能 | スタイル選択コンボボックス |
| 16 | Constrained Resize | 補助機能 | 制約モード選択コンボ |
| 23 | Widgets | 主機能 | コンボボックスのデモ |

## 機能種別

ウィジェット描画処理 / ポップアップ制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | const char* | Yes | コンボボックスのラベル（右側に表示） | NULL不可 |
| preview_value | const char* | No | プレビュー領域に表示するテキスト | NULLで非表示 |
| flags | ImGuiComboFlags | No | コンボボックスの動作フラグ（デフォルト: 0） | 有効なフラグ組み合わせ |

### ImGuiComboFlags

| フラグ | 値 | 説明 |
|--------|-----|------|
| ImGuiComboFlags_None | 0 | デフォルト動作 |
| ImGuiComboFlags_PopupAlignLeft | 1 << 0 | ポップアップを左寄せ |
| ImGuiComboFlags_HeightSmall | 1 << 1 | 最大約4アイテム表示 |
| ImGuiComboFlags_HeightRegular | 1 << 2 | 最大約8アイテム表示（デフォルト） |
| ImGuiComboFlags_HeightLarge | 1 << 3 | 最大約20アイテム表示 |
| ImGuiComboFlags_HeightLargest | 1 << 4 | 可能な限り多くのアイテム表示 |
| ImGuiComboFlags_NoArrowButton | 1 << 5 | 矢印ボタンなし |
| ImGuiComboFlags_NoPreview | 1 << 6 | プレビュー領域なし（矢印のみ） |
| ImGuiComboFlags_WidthFitPreview | 1 << 7 | プレビュー内容に幅を合わせる |

### 入力データソース

- ユーザー指定のパラメータ（関数引数）
- ImGuiスタイル設定（FramePadding, FrameRounding）
- 現在のウィンドウ状態（CursorPos, SkipItems）
- NextWindowData（サイズ制約等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | bool | ポップアップが開いている場合true（EndCombo呼び出し必要） |

### 出力先

- ImDrawList（描画コマンドリスト）
  - コンボボックスフレーム
  - 矢印ボタン
  - プレビューテキスト
  - ラベル
- ポップアップウィンドウ（開いている場合）

## 処理フロー

### 処理シーケンス

```
1. 前処理
   └─ NextWindowDataのバックアップとクリア
   └─ SkipItems確認
2. パラメータ検証
   └─ 無効なフラグ組み合わせをアサート
3. サイズ計算
   └─ arrow_size, preview_width, 全体幅を計算
4. バウンディングボックス計算
   └─ コンボボックス領域とラベル込み領域
5. アイテム登録
   └─ ItemSize(), ItemAdd()
6. ポップアップ開閉処理
   └─ ButtonBehaviorでクリック判定
   └─ クリック時にOpenPopupEx呼び出し
7. 描画
   └─ フレーム背景、矢印ボタン、フレーム境界線
   └─ カスタムプレビュー設定（フラグ使用時）
   └─ プレビュー値とラベル
8. ポップアップ処理
   └─ popup_openがfalseならfalseを返す
   └─ trueならBeginComboPopupを呼び出して結果を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{SkipItems?}
    B -->|Yes| C[return false]
    B -->|No| D[パラメータ検証]
    D --> E[サイズ計算]
    E --> F[バウンディングボックス計算]
    F --> G[ItemSize/ItemAdd]
    G --> H{ItemAdd成功?}
    H -->|No| C
    H -->|Yes| I[ButtonBehavior]
    I --> J{pressed && !popup_open?}
    J -->|Yes| K[OpenPopupEx]
    J -->|No| L[描画処理]
    K --> L
    L --> M[フレーム・矢印描画]
    M --> N[プレビュー・ラベル描画]
    N --> O{popup_open?}
    O -->|No| C
    O -->|Yes| P[BeginComboPopup]
    P --> Q[return 結果]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-103-1 | 排他フラグ | NoArrowButtonとNoPreviewは同時使用不可 | 常時（アサート） |
| BR-103-2 | WidthFitPreview制約 | WidthFitPreviewはNoPreviewと併用不可 | 常時（アサート） |
| BR-103-3 | 高さフラグ | HeightMask_のうち1つのみ有効（デフォルト: HeightRegular） | 常時 |
| BR-103-4 | EndCombo呼び出し | 戻り値がtrueの場合のみEndComboを呼び出す | 常時 |

### 計算ロジック

幅計算:
```
arrow_size = (NoArrowButton) ? 0 : GetFrameHeight()
preview_width = (WidthFitPreview && preview_value) ? CalcTextSize(preview_value).x : 0
w = (NoPreview) ? arrow_size :
    (WidthFitPreview) ? (arrow_size + preview_width + FramePadding.x * 2) :
    CalcItemWidth()
```

ポップアップ最大高さ計算:
```
HeightSmall: 4アイテム分
HeightRegular: 8アイテム分（デフォルト）
HeightLarge: 20アイテム分
HeightLargest: 制限なし
```

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

該当なし（GUI描画機能のためデータベース操作は行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | アサート失敗 | NoArrowButton && NoPreview | 開発時にフラグ組み合わせを修正 |
| - | アサート失敗 | WidthFitPreview && NoPreview | 開発時にフラグ組み合わせを修正 |
| - | 描画スキップ | window->SkipItemsがtrue | falseを返して終了 |

### リトライ仕様

リトライなし（フレーム単位の描画・インタラクション処理のため）

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

該当なし

## パフォーマンス要件

- 単一フレーム内で複数のコンボボックスを作成可能
- ポップアップはBeginComboDepthで管理され、最大16段のネストをサポート
- ListClipperと組み合わせることで大量のアイテムを効率的に描画可能

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

- 特になし（GUI描画機能のため）

## 備考

- BeginCombo/EndComboは旧Combo APIより柔軟なカスタマイズが可能
- ポップアップウィンドウは"##Combo_XX"形式の内部名を持つ
- SetNextWindowSizeConstraints()で事前にサイズ制約を設定可能
- CustomPreviewフラグ使用時はBeginComboPreview/EndComboPreviewを使用

---

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

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

### 推奨読解順序

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

まず、コンボボックスに関連するフラグと構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui.h | `imgui.h` | 1374-1386行目: ImGuiComboFlags_列挙型 |
| 1-2 | imgui_internal.h | `imgui_internal.h` | ImGuiComboPreviewData構造体 |

**読解のコツ**: HeightMask_は高さフラグのビットマスクで、複数選択を防ぐために使用される。

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

処理の起点となる関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui.h | `imgui.h` | 659行目: BeginCombo関数の宣言 |
| 2-2 | imgui_widgets.cpp | `imgui_widgets.cpp` | 1905-1981行目: BeginCombo関数の実装 |

**主要処理フロー**:
1. **1910-1913行目**: NextWindowDataバックアップとSkipItems確認
2. **1917-1919行目**: フラグの検証（アサート）
3. **1921-1929行目**: サイズ計算とアイテム登録
4. **1931-1940行目**: ボタン動作とポップアップ開閉
5. **1942-1974行目**: 描画処理（フレーム、矢印、プレビュー、ラベル）
6. **1976-1980行目**: ポップアップ処理

#### Step 3: ポップアップ処理を理解する

BeginComboPopupの詳細を追跡する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 1983-2047行目: BeginComboPopup実装 |

**主要処理フロー**:
- **1993-2013行目**: ポップアップサイズの計算と制約設定
- **2016-2017行目**: ポップアップウィンドウ名の生成
- **2022-2031行目**: ポップアップ位置の計算
- **2034-2046行目**: ポップアップウィンドウの開始

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

```
ImGui::BeginCombo()
    │
    ├─ GetCurrentWindow()
    ├─ g.NextWindowData.ClearFlags()
    ├─ window->GetID()
    ├─ CalcTextSize() ... プレビュー幅計算
    ├─ CalcItemWidth() ... コンボ幅計算
    ├─ ItemSize()
    ├─ ItemAdd()
    ├─ ButtonBehavior()
    │      └─ hovered, held, pressed を計算
    ├─ OpenPopupEx() ... クリック時
    ├─ 描画処理
    │      ├─ AddRectFilled() ... フレーム背景
    │      ├─ RenderArrow() ... 矢印
    │      ├─ RenderFrameBorder()
    │      ├─ RenderTextClipped() ... プレビュー
    │      └─ RenderText() ... ラベル
    │
    └─ BeginComboPopup()
           ├─ SetNextWindowSizeConstraints()
           ├─ FindBestWindowPosForPopupEx()
           ├─ SetNextWindowPos()
           ├─ Begin() ... ポップアップウィンドウ
           └─ BeginComboDepth++
```

### データフロー図

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

label       ───┐
preview_value ─┼──▶ BeginCombo()   ───┬──▶ bool (popup_open)
flags       ───┘         │            │
                         │            └──▶ ImDrawList
マウス状態  ────────────▶│                 (描画コマンド)
                         │
NextWindowData ────────▶│            ┌──▶ ポップアップウィンドウ
                         ▼            │    (trueの場合)
                    BeginComboPopup()─┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダー | 関数宣言、ImGuiComboFlags定義 |
| imgui_widgets.cpp | `imgui_widgets.cpp` | ソース | BeginCombo, BeginComboPopup実装 |
| imgui_internal.h | `imgui_internal.h` | ヘッダー | ImGuiComboPreviewData, 内部関数 |
