# 機能設計書 105-Combo

## 概要

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

### 本機能の処理概要

`Combo`関数は、コンボボックス（ドロップダウンリスト）ウィジェットを簡便に作成するためのヘルパー関数群である。`BeginCombo`/`EndCombo`の低レベルAPIを内部的に使用しながら、より簡潔なインターフェースで一般的なコンボボックスを作成できる。複数のオーバーロードがあり、配列、ゼロ区切り文字列、コールバック関数の3種類の方法でアイテムリストを指定できる。

**業務上の目的・背景**：多くのアプリケーションでは、単純な文字列リストからの選択で十分な場合が多い。Combo関数はそのような一般的なユースケースに対して、最小限のコードでコンボボックスを作成できる便利なヘルパーとして提供されている。カスタマイズが必要な場合はBeginCombo/EndComboを使用し、単純な選択の場合はComboを使用するという使い分けができる。

**機能の利用シーン**：
- 固定のオプションリストからの選択
- 列挙型の値の選択
- ファイル形式や言語の選択
- 設定値の選択
- 簡易的なドロップダウンメニュー

**主要な処理内容**：
1. getter関数またはアイテム配列から現在のアイテムのプレビュー文字列を取得
2. popup_max_height_in_itemsが指定されている場合、サイズ制約を設定
3. BeginComboを呼び出してポップアップを開始
4. ListClipperを使用して効率的にアイテムをループ
5. 各アイテムをSelectableで表示し、選択状態を管理
6. 選択されたアイテムでcurrent_itemを更新
7. EndComboを呼び出してポップアップを終了

**関連システム・外部連携**：
- BeginCombo/EndCombo: 低レベルコンボボックスAPI
- Selectable: アイテムの選択可能表示
- ListClipper: 大量アイテムの効率的な描画
- SetNextWindowSizeConstraints: ポップアップサイズ制約

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

## 関連画面

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

## 機能種別

ウィジェット描画処理 / ヘルパー関数

## 入力仕様

### 入力パラメータ（配列版）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | const char* | Yes | コンボボックスのラベル | NULL不可 |
| current_item | int* | Yes | 現在選択されているアイテムのインデックス | 有効なポインタ |
| items | const char* const[] | Yes | アイテム文字列の配列 | NULL不可 |
| items_count | int | Yes | アイテム数 | 0以上 |
| popup_max_height_in_items | int | No | ポップアップの最大表示アイテム数（デフォルト: -1） | -1で自動 |

### 入力パラメータ（ゼロ区切り文字列版）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | const char* | Yes | コンボボックスのラベル | NULL不可 |
| current_item | int* | Yes | 現在選択されているアイテムのインデックス | 有効なポインタ |
| items_separated_by_zeros | const char* | Yes | "\0"区切りの文字列（末尾は"\0\0"） | NULL不可 |
| popup_max_height_in_items | int | No | ポップアップの最大表示アイテム数（デフォルト: -1） | -1で自動 |

### 入力パラメータ（コールバック版）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | const char* | Yes | コンボボックスのラベル | NULL不可 |
| current_item | int* | Yes | 現在選択されているアイテムのインデックス | 有効なポインタ |
| getter | const char* (*)(void*, int) | Yes | アイテム文字列を返すコールバック | NULL不可 |
| user_data | void* | Yes | コールバックに渡すユーザーデータ | NULL可 |
| items_count | int | Yes | アイテム数 | 0以上 |
| popup_max_height_in_items | int | No | ポップアップの最大表示アイテム数（デフォルト: -1） | -1で自動 |

### 入力データソース

- ユーザー指定のパラメータ（関数引数）
- ImGuiスタイル設定（BeginCombo経由）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | bool | 選択が変更された場合true |
| current_item | int* | 選択されたアイテムのインデックス（変更時に更新） |

### 出力先

- current_itemパラメータ（選択インデックス）
- 戻り値によるユーザーコールバック

## 処理フロー

### 処理シーケンス

```
1. プレビュー値の取得
   └─ current_itemが有効範囲内ならgetter/配列から文字列取得
   └─ 範囲外ならNULL
2. サイズ制約の設定（popup_max_height_in_items != -1の場合）
   └─ SetNextWindowSizeConstraints()を呼び出し
   └─ CalcMaxPopupHeightFromItemCount()で高さを計算
3. BeginCombo呼び出し
   └─ falseならfalseを返して終了
4. アイテムループ
   └─ ListClipperを使用して効率的にループ
   └─ 現在のアイテムをIncludeItemByIndexで必ず含める
5. 各アイテムの処理
   └─ PushIDでアイテムIDを設定
   └─ Selectableでアイテムを表示
   └─ 選択されたらcurrent_itemを更新、value_changed = true
   └─ 選択中アイテムをSetItemDefaultFocusでフォーカス
   └─ PopIDでIDを復元
6. EndCombo呼び出し
7. 戻り値を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[プレビュー値取得]
    B --> C{height_in_items指定?}
    C -->|Yes| D[SetNextWindowSizeConstraints]
    C -->|No| E[BeginCombo]
    D --> E
    E --> F{BeginCombo true?}
    F -->|No| G[return false]
    F -->|Yes| H[ListClipper初期化]
    H --> I[clipper.IncludeItemByIndex]
    I --> J{clipper.Step?}
    J -->|Yes| K[アイテムループ]
    K --> L[Selectable表示]
    L --> M{選択された?}
    M -->|Yes| N[current_item更新]
    M -->|No| O{現在の選択?}
    N --> O
    O -->|Yes| P[SetItemDefaultFocus]
    O -->|No| Q[次のアイテム]
    P --> Q
    Q --> J
    J -->|No| R[EndCombo]
    R --> S[return value_changed]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-105-1 | インデックス範囲 | current_itemは0〜items_count-1の範囲 | 常時 |
| BR-105-2 | NULL文字列処理 | getterがNULLを返した場合"*Unknown item*"を表示 | アイテム取得時 |
| BR-105-3 | 選択変更判定 | current_itemが変更された場合のみtrueを返す | 常時 |
| BR-105-4 | ListClipper使用 | 大量アイテムの効率的な描画のためListClipperを使用 | 常時 |

### 計算ロジック

ゼロ区切り文字列のアイテム数計算:
```cpp
int items_count = 0;
const char* p = items_separated_by_zeros;
while (*p)
{
    p += ImStrlen(p) + 1;
    items_count++;
}
```

ポップアップ最大高さ計算:
```cpp
// CalcMaxPopupHeightFromItemCount()内
float height = (GetFrameHeightWithSpacing() * items_count) + GetStyle().WindowPadding.y * 2;
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | NULL表示 | getterがNULLを返す | "*Unknown item*"を表示 |
| - | 範囲外参照 | current_itemが範囲外 | プレビューをNULLに設定 |

### リトライ仕様

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

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

該当なし

## パフォーマンス要件

- ListClipperにより表示範囲外のアイテムはスキップ
- ゼロ区切り文字列版はアイテム数計算のオーバーヘッドあり

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

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

## 備考

- 旧API（1.90.0以前）のboolコールバック版は非推奨
- 現在のAPIはconst char*を返すコールバックを使用
- より柔軟なカスタマイズが必要な場合はBeginCombo/EndComboを使用

---

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

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

### 推奨読解順序

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

まず、Comboのヘルパー関数に関連する構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui.h | `imgui.h` | 661-663行目: Combo関数のオーバーロード宣言 |
| 1-2 | imgui_widgets.cpp | `imgui_widgets.cpp` | 2114-2134行目: ヘルパー関数（getter） |

**読解のコツ**: Items_ArrayGetterとItems_SingleStringGetterは配列/文字列からアイテムを取得する内部ヘルパー。

#### Step 2: メイン実装を理解する

処理の中核となる関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 2137-2183行目: Combo（コールバック版）実装 |

**主要処理フロー**:
1. **2142-2144行目**: プレビュー値の取得
2. **2147-2148行目**: サイズ制約の設定
3. **2150-2151行目**: BeginComboの呼び出し
4. **2155-2157行目**: ListClipperの初期化
5. **2159-2180行目**: アイテムのループと選択処理
6. **2181行目**: EndComboの呼び出し

#### Step 3: オーバーロード実装を理解する

他のオーバーロードがメイン関数をどう呼び出すかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 2185-2189行目: 配列版Combo |
| 3-2 | imgui_widgets.cpp | `imgui_widgets.cpp` | 2192-2203行目: ゼロ区切り文字列版Combo |

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

```
ImGui::Combo() [配列版]
    └─ ImGui::Combo() [コールバック版]
           │
           ├─ getter() ... プレビュー値取得
           ├─ SetNextWindowSizeConstraints() ... 高さ指定時
           ├─ BeginCombo()
           │      └─ ポップアップを開始
           ├─ ListClipper
           │      ├─ Begin()
           │      ├─ IncludeItemByIndex()
           │      └─ Step()
           ├─ for each item:
           │      ├─ PushID()
           │      ├─ getter() ... アイテム文字列取得
           │      ├─ Selectable()
           │      ├─ SetItemDefaultFocus()
           │      └─ PopID()
           └─ EndCombo()

ImGui::Combo() [ゼロ区切り文字列版]
    └─ ImGui::Combo() [コールバック版]
           └─ Items_SingleStringGetter()
```

### データフロー図

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

label       ───┐
current_item ──┼──▶ Combo()
items/getter ──┤         │
items_count ───┤         │
height_items ──┘         │
                         ▼
                    ┌─────────────────┐
                    │ BeginCombo()    │──▶ ポップアップ描画
                    ├─────────────────┤
                    │ ListClipper     │
                    │ + Selectable()  │──▶ アイテム選択
                    ├─────────────────┤
                    │ EndCombo()      │
                    └─────────────────┘
                         │
                         ▼
                    current_item更新 + bool戻り値
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダー | Comboオーバーロード宣言 |
| imgui_widgets.cpp | `imgui_widgets.cpp` | ソース | Combo実装、ヘルパー関数 |
| imgui_internal.h | `imgui_internal.h` | ヘッダー | CalcMaxPopupHeightFromItemCount等 |
