# 機能設計書 98-RadioButton

## 概要

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

### 本機能の処理概要

RadioButtonは、排他的選択を行うためのラジオボタンウィジェットを作成するUI機能である。複数の選択肢の中から1つだけを選択する場合に使用される。円形のボタンで表現され、選択状態は内側の円で示される。2つのオーバーロードが存在し、ブール値を直接指定する方式と、整数変数と値を比較する方式がある。

**業務上の目的・背景**：GUIアプリケーションにおいて、排他的な選択肢から1つを選ぶ場面は頻繁に発生する。例えば、表示モードの選択（リスト/グリッド/詳細）、ソート順の選択（昇順/降順）、オプションの切り替えなどである。RadioButtonはこれらのニーズに対応し、ユーザーにとって視覚的に明確な選択インターフェースを提供する。

**機能の利用シーン**：設定画面でのオプション選択、表示モードの切り替え、フィルタ条件の選択、エクスポート形式の選択、優先度の設定などで使用される。

**主要な処理内容**：
1. ラジオボタンのサイズを計算する（円形、GetFrameHeight()ベース）
2. ラベルとラジオボタンの全体領域を確定する
3. ButtonBehaviorでクリック状態を判定する
4. 状態に応じた色で円を描画する
5. アクティブ状態の場合は内側の円を描画する
6. 境界線を描画する（スタイル設定による）
7. ラベルテキストを描画する
8. 押下状態（pressed）を戻り値として返す

**関連システム・外部連携**：ImGuiのDrawList描画システムと連携。円の描画にはAddCircleFilled/AddCircleを使用。

**権限による制御**：BeginDisabled/EndDisabledで無効化可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | Long Text | 補助機能 | 表示モードの切り替え |
| 23 | Widgets | 主機能 | ラジオボタンのデモ |

## 機能種別

UIウィジェット / ユーザー入力処理

## 入力仕様

### 入力パラメータ（オーバーロード1：bool版）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | const char* | Yes | ラジオボタンのラベルテキスト | NULL終端文字列 |
| active | bool | Yes | 現在の選択状態（trueで選択中） | - |

### 入力パラメータ（オーバーロード2：int版）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | const char* | Yes | ラジオボタンのラベルテキスト | NULL終端文字列 |
| v | int* | Yes | 現在の選択値を格納する変数へのポインタ | 有効なポインタ |
| v_button | int | Yes | このラジオボタンが表す値 | - |

### 入力データソース

- 呼び出し元からの直接指定
- ImGuiStyleからのスタイル設定値

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pressed | bool | ボタンがクリックされたかどうか |
| *v | int | （int版のみ）更新された選択値 |

### 出力先

- 戻り値として呼び出し元に返却
- ポインタ経由で整数変数を更新（int版のみ）
- ImDrawList（現在のウィンドウの描画リスト）

## 処理フロー

### 処理シーケンス（bool版）

```
1. ウィンドウの取得とスキップチェック
   └─ GetCurrentWindow()で現在のウィンドウを取得
   └─ SkipItemsがtrueの場合はfalseを返す

2. サイズ計算
   └─ square_sz = GetFrameHeight()でラジオボタンサイズを取得
   └─ ラベルサイズを計算
   └─ 全体のバウンディングボックスを作成

3. 中心と半径の計算
   └─ center = check_bb.GetCenter()（ピクセル座標に丸め）
   └─ radius = (square_sz - 1.0f) * 0.5f

4. アイテム登録
   └─ ItemSize()でレイアウト領域を確保
   └─ ItemAdd()で描画リストに追加

5. インタラクション判定
   └─ ButtonBehavior()でhovered/held/pressed状態を取得
   └─ クリック時にMarkItemEdited()を呼び出し

6. 描画
   └─ RenderNavCursor()でナビゲーションカーソルを描画
   └─ AddCircleFilled()で背景円を描画
   └─ active時は内側の円を描画
   └─ FrameBorderSize > 0の場合、境界線を描画
   └─ ラベルを描画

7. ログ出力
   └─ LogEnabled時は"(x)"または"( )"をログに出力

8. 結果返却
   └─ pressed状態を返す
```

### 処理シーケンス（int版）

```
1. bool版のRadioButtonを呼び出し
   └─ RadioButton(label, *v == v_button)

2. クリック時の値更新
   └─ pressed == true の場合、*v = v_button

3. 結果返却
   └─ pressed状態を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始: RadioButton] --> B{int版?}
    B -->|Yes| C[bool版を呼び出し<br/>active = *v == v_button]
    B -->|No| D{SkipItems?}
    C --> E{pressed?}
    E -->|Yes| F[*v = v_button]
    E -->|No| G[return pressed]
    F --> G
    D -->|Yes| H[return false]
    D -->|No| I[サイズ計算]
    I --> J[ItemSize/ItemAdd]
    J --> K{ItemAdd成功?}
    K -->|No| H
    K -->|Yes| L[ButtonBehavior]
    L --> M[背景円描画]
    M --> N{active?}
    N -->|Yes| O[内側の円描画]
    N -->|No| P[境界線描画]
    O --> P
    P --> Q[ラベル描画]
    Q --> G
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-98-01 | 円形サイズ | ラジオボタンはGetFrameHeight()サイズの円形 | 常時 |
| BR-98-02 | 中央配置 | 円の中心はピクセル座標に丸められる | 常時 |
| BR-98-03 | 選択表示 | 選択状態は内側の小さな円で表現 | active == true |
| BR-98-04 | 排他選択 | int版では同じ変数を共有する複数のRadioButtonが排他的に動作 | int版使用時 |

### 計算ロジック

- 円の中心: `center = check_bb.GetCenter()`（IM_ROUND適用）
- 円の半径: `radius = (square_sz - 1.0f) * 0.5f`
- 内側の円の半径: `radius - pad`（padはsquare_sz / 6.0f）

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

データベース操作なし（UI描画のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 早期リターン | window->SkipItems == true | falseを返す |
| - | 早期リターン | ItemAdd失敗 | falseを返す |

### リトライ仕様

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

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

トランザクション管理なし（即時処理）

## パフォーマンス要件

- 単一フレーム内で多数のRadioButtonを描画可能
- 円の描画はセグメント数を自動計算（_CalcCircleAutoSegmentCount）

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

- ポインタ引数のバリデーションは呼び出し元の責任

## 備考

- int版はbool版のラッパーとして実装
- 円のセグメント数は半径に応じて自動計算される
- 境界線はFrameBorderSizeスタイル設定に従う

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui.h | `imgui.h` | 639行目: RadioButton(bool版) API宣言 |
| 1-2 | imgui.h | `imgui.h` | 640行目: RadioButton(int版) API宣言 |

**読解のコツ**: 2つのオーバーロードの関係を理解することが重要。int版はbool版のラッパー。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 1392-1398行目: RadioButton(int版)の実装 |

**主要処理フロー**:
1. **1394行目**: bool版RadioButtonを呼び出し（*v == v_buttonで判定）
2. **1395-1396行目**: pressed時に*v = v_buttonで値を更新

#### Step 3: 内部実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 1337-1389行目: RadioButton(bool版)の実装 |

**主要処理フロー**:
- **1345行目**: GetIDでラベルからID生成
- **1348行目**: GetFrameHeight()でサイズ取得
- **1356-1358行目**: 中心座標と半径の計算
- **1362行目**: ButtonBehavior呼び出し
- **1367-1368行目**: AddCircleFilledで背景円描画
- **1369-1373行目**: active時の内側円描画
- **1375-1379行目**: 境界線描画（FrameBorderSize > 0時）
- **1382-1383行目**: ログ出力
- **1384-1385行目**: ラベル描画

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

```
ImGui::RadioButton(label, v, v_button)  [int版]
    │
    └─ RadioButton(label, *v == v_button)  [bool版]
           │
           ├─ GetCurrentWindow()
           │
           ├─ window->GetID(label)
           │
           ├─ CalcTextSize(label)
           │
           ├─ GetFrameHeight()
           │      └─ 円のサイズを取得
           │
           ├─ ItemSize() / ItemAdd()
           │
           ├─ ButtonBehavior()
           │
           ├─ _CalcCircleAutoSegmentCount()
           │      └─ 円のセグメント数を計算
           │
           ├─ AddCircleFilled()
           │      └─ 背景円を描画
           │
           ├─ AddCircleFilled() [active時]
           │      └─ 内側の円を描画
           │
           ├─ AddCircle() [FrameBorderSize > 0時]
           │      └─ 境界線を描画
           │
           └─ RenderText()
                  └─ ラベル描画
```

### データフロー図

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

label (文字列) ────────────> GetID ─────────────────────────> ImGuiID
                                │
active (bool) または
v, v_button (int) ─────────> 状態判定 ──────────────────────> 選択状態
                                │
                            サイズ計算
                                │
マウス/キーボード状態 ─────> ButtonBehavior ─────────────────> pressed
                                │
                            [int版 + pressed]
                            *v = v_button ──────────────────> *v (更新)
                                │
                            AddCircleFilled ────────────────> DrawList (背景)
                            AddCircleFilled ────────────────> DrawList (内側)
                            AddCircle ──────────────────────> DrawList (境界)
                            RenderText ─────────────────────> DrawList (ラベル)
                                │
                            return pressed ─────────────────> bool (戻り値)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダー | RadioButton APIの宣言 |
| imgui_widgets.cpp | `imgui_widgets.cpp` | ソース | RadioButtonの実装 |
| imgui_draw.cpp | `imgui_draw.cpp` | ソース | AddCircleFilled、AddCircle等の描画関数 |
