# 機能設計書 108-DragFloatRange2

## 概要

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

### 本機能の処理概要

`DragFloatRange2`関数は、最小値と最大値の範囲を同時に編集できるドラッグスライダーウィジェットを作成する関数である。2つの連動したドラッグスライダーを横に並べて表示し、範囲の開始点と終了点を個別に調整できる。最小値が最大値を超えないように、またその逆も同様に、相互に制約が課される。

**業務上の目的・背景**：アプリケーションでは、価格帯、時間範囲、パラメータの有効範囲など、2つの値で範囲を定義するケースが頻繁に発生する。単純な2つのDragFloatでは、最小値が最大値を超えてしまう不整合が起きやすい。DragFloatRange2は、この問題を自動的に防ぎながら、直感的な範囲編集を可能にする。特にパーティクルシステムの寿命範囲、オーディオのフェードイン/アウト時間、物理シミュレーションのパラメータ範囲設定などで有用である。

**機能の利用シーン**：
- パーティクルシステムの寿命・サイズ範囲設定
- オーディオのフェード時間設定
- フィルタリングの値範囲指定
- アニメーションのキーフレーム範囲選択
- 物理パラメータの有効範囲設定
- 価格・数量の範囲フィルター

**主要な処理内容**：
1. ラベルからIDを生成しグループを開始
2. 2つの要素の幅を計算（PushMultiItemsWidths）
3. 最小値スライダーを描画（制約: 全体の最小値〜現在の最大値）
4. SameLineで横に並べる
5. 最大値スライダーを描画（制約: 現在の最小値〜全体の最大値）
6. ラベルを表示
7. グループを終了して戻り値を返す

**関連システム・外部連携**：
- DragScalar: 単一要素のドラッグ処理
- スタイルシステム: ItemInnerSpacing

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 23 | Widgets | 主機能 | 範囲ドラッグスライダーのデモ |

## 機能種別

ウィジェット描画処理 / 入力処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | const char* | Yes | ウィジェットのラベル | NULL不可 |
| v_current_min | float* | Yes | 現在の最小値へのポインタ | 有効なポインタ |
| v_current_max | float* | Yes | 現在の最大値へのポインタ | 有効なポインタ |
| v_speed | float | No | ドラッグ速度係数（デフォルト: 1.0f） | 正の値推奨 |
| v_min | float | No | 全体の最小値（デフォルト: 0.0f） | v_min >= v_maxで無制限 |
| v_max | float | No | 全体の最大値（デフォルト: 0.0f） | v_min >= v_maxで無制限 |
| format | const char* | No | 最小値の表示フォーマット（デフォルト: "%.3f"） | printf形式 |
| format_max | const char* | No | 最大値の表示フォーマット（デフォルト: format使用） | printf形式 |
| flags | ImGuiSliderFlags | No | スライダーフラグ（デフォルト: 0） | 有効なフラグ |

### 入力データソース

- ユーザー指定のパラメータ（関数引数）
- マウス入力（各要素へのドラッグ）
- キーボード入力（Ctrl、テキスト入力モード時）
- ImGuiスタイル設定（ItemInnerSpacing）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | bool | いずれかの値が変更された場合true |
| v_current_min | float* | 変更後の最小値（変更時に更新） |
| v_current_max | float* | 変更後の最大値（変更時に更新） |

### 出力先

- v_current_min, v_current_maxパラメータ（値の更新）
- ImDrawList（描画コマンドリスト）

## 処理フロー

### 処理シーケンス

```
1. 前処理
   └─ ウィンドウスキップ確認
2. グループ・ID設定
   └─ PushID(label), BeginGroup
3. 幅計算
   └─ PushMultiItemsWidths(2, CalcItemWidth())
4. 最小値スライダー制約計算
   └─ min_min = (v_min >= v_max) ? -FLT_MAX : v_min
   └─ min_max = (v_min >= v_max) ? *v_current_max : min(v_max, *v_current_max)
5. 最小値スライダー描画
   └─ DragScalar("##min", ..., min_min, min_max)
   └─ min_min == min_max なら ReadOnly フラグ追加
6. 幅ポップ、SameLine
7. 最大値スライダー制約計算
   └─ max_min = (v_min >= v_max) ? *v_current_min : max(v_min, *v_current_min)
   └─ max_max = (v_min >= v_max) ? FLT_MAX : v_max
8. 最大値スライダー描画
   └─ DragScalar("##max", ..., max_min, max_max)
9. ラベル表示
   └─ TextEx(label)
10. グループ終了
    └─ EndGroup, PopID
11. 戻り値を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{SkipItems?}
    B -->|Yes| C[return false]
    B -->|No| D[PushID, BeginGroup]
    D --> E[PushMultiItemsWidths 2]
    E --> F[min制約計算]
    F --> G{min_min == min_max?}
    G -->|Yes| H[ReadOnlyフラグ追加]
    G -->|No| I[DragScalar ##min]
    H --> I
    I --> J[PopItemWidth, SameLine]
    J --> K[max制約計算]
    K --> L{max_min == max_max?}
    L -->|Yes| M[ReadOnlyフラグ追加]
    L -->|No| N[DragScalar ##max]
    M --> N
    N --> O[PopItemWidth, SameLine]
    O --> P[TextEx label]
    P --> Q[EndGroup, PopID]
    Q --> R[return value_changed]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-108-1 | 最小値制約 | 最小値スライダーは現在の最大値を超えられない | 常時 |
| BR-108-2 | 最大値制約 | 最大値スライダーは現在の最小値を下回れない | 常時 |
| BR-108-3 | 無制限モード | v_min >= v_maxの場合、全体範囲を-FLT_MAX〜FLT_MAXに | 常時 |
| BR-108-4 | ReadOnly判定 | 制約範囲が0の場合、ReadOnlyフラグを追加 | 制約一致時 |
| BR-108-5 | フォーマット継承 | format_maxがNULLの場合、formatを使用 | 常時 |

### 計算ロジック

最小値スライダー制約:
```cpp
// 無制限モード（v_min >= v_max）の場合
min_min = -FLT_MAX
min_max = *v_current_max

// 制限モードの場合
min_min = v_min
min_max = ImMin(v_max, *v_current_max)
```

最大値スライダー制約:
```cpp
// 無制限モード（v_min >= v_max）の場合
max_min = *v_current_min
max_max = FLT_MAX

// 制限モードの場合
max_min = ImMax(v_min, *v_current_min)
max_max = v_max
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 描画スキップ | window->SkipItemsがtrue | falseを返して終了 |

### リトライ仕様

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

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

該当なし

## パフォーマンス要件

- 単一フレーム内で複数呼び出し可能
- 2つのDragScalarが順次処理される

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

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

## 備考

- AlwaysClampフラグの使用を推奨（手動入力時も範囲制約を維持）
- 最小値と最大値のフォーマットを別々に指定可能
- 範囲が狭くなると自動的にReadOnlyになる

---

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

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

### 推奨読解順序

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

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

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

**主要処理フロー**:
1. **2848-2850行目**: ウィンドウスキップ確認
2. **2853-2855行目**: PushID, BeginGroup, PushMultiItemsWidths
3. **2857-2860行目**: 最小値スライダー制約計算と描画
4. **2864-2867行目**: 最大値スライダー制約計算と描画
5. **2871-2873行目**: ラベル表示、EndGroup, PopID

#### Step 2: 制約計算を理解する

最小値・最大値の相互制約を追跡する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | 2857-2860行目: 最小値制約計算 |
| 2-2 | imgui_widgets.cpp | `imgui_widgets.cpp` | 2864-2867行目: 最大値制約計算 |

**読解のコツ**:
- v_min >= v_maxの条件は「無制限モード」の判定
- min_maxは「最小値スライダーの上限」= 現在の最大値
- max_minは「最大値スライダーの下限」= 現在の最小値

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

```
ImGui::DragFloatRange2()
    │
    ├─ GetCurrentWindow()
    ├─ PushID(label)
    ├─ BeginGroup()
    ├─ PushMultiItemsWidths(2, width)
    │
    ├─ 最小値制約計算
    │      ├─ min_min = (無制限) ? -FLT_MAX : v_min
    │      └─ min_max = (無制限) ? *v_current_max : min(v_max, *v_current_max)
    │
    ├─ DragScalar("##min", ...)
    │      └─ 最小値を編集
    │
    ├─ PopItemWidth()
    ├─ SameLine()
    │
    ├─ 最大値制約計算
    │      ├─ max_min = (無制限) ? *v_current_min : max(v_min, *v_current_min)
    │      └─ max_max = (無制限) ? FLT_MAX : v_max
    │
    ├─ DragScalar("##max", ...)
    │      └─ 最大値を編集
    │
    ├─ PopItemWidth()
    ├─ SameLine()
    ├─ TextEx(label)
    ├─ EndGroup()
    └─ PopID()
```

### データフロー図

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

label           ───┐
v_current_min   ───┼──▶ DragFloatRange2()
v_current_max   ───┤           │
v_speed         ───┤           ▼
v_min/v_max     ───┤    ┌─────────────┐
format          ───┤    │ 制約計算     │
format_max      ───┤    │ min ← max   │
flags           ───┘    │ max → min   │
                        └─────────────┘
                               │
                    ┌──────────┴──────────┐
                    ▼                     ▼
             DragScalar(min)        DragScalar(max)
                    │                     │
                    ▼                     ▼
             v_current_min更新      v_current_max更新
                    │                     │
                    └──────────┬──────────┘
                               ▼
                        bool戻り値
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダー | DragFloatRange2宣言 |
| imgui_widgets.cpp | `imgui_widgets.cpp` | ソース | DragFloatRange2実装 |
| imgui_internal.h | `imgui_internal.h` | ヘッダー | DragScalar, PushMultiItemsWidths等 |
