# 機能設計書 143-EndMultiSelect

## 概要

本ドキュメントは、Dear ImGuiライブラリにおけるEndMultiSelect関数の機能設計を記述する。EndMultiSelectはBeginMultiSelectで開始されたマルチセレクションスコープを終了し、最終的な選択リクエストを返却する関数である。

### 本機能の処理概要

EndMultiSelect関数は、マルチセレクトスコープを終了し、スコープ内で発生した選択操作を集約したImGuiMultiSelectIO構造体を返却する。BeginMultiSelectとペアで使用する必要がある。

**業務上の目的・背景**：BeginMultiSelectで開始された選択スコープを正しく終了し、アプリケーションが選択状態を更新するために必要な情報を提供する。スコープ終了時にボックス選択の終了処理、範囲選択の確定、空白クリックによる選択解除などの最終処理を行う。

**機能の利用シーン**：
- マルチセレクト対応ウィジェットのスコープ終了
- 選択リクエストの取得と適用
- ボックス選択操作の完了処理
- 空白クリックによる選択解除の検出

**主要な処理内容**：
1. フォーカススコープのポップ
2. ボックス選択の終了処理（有効時）
3. 空白クリックによる選択クリアの検出
4. ナビゲーションラッピングの適用
5. RangeSrcItem/NavIdItemのリセット判定
6. 更新されたImGuiMultiSelectIO構造体の返却

**関連システム・外部連携**：BeginMultiSelectとペアで使用。アプリケーションはEndMultiSelect後に返却されたリクエストを処理する。

**権限による制御**：ClearOnClickVoidフラグにより空白クリック時の選択解除を制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | Assets Browser | 主機能 | マルチセレクトスコープの終了 |
| 23 | Widgets | 主機能 | マルチセレクトデモのスコープ終了 |

## 機能種別

スコープ終了 / 選択状態確定 / リクエスト返却

## 入力仕様

### 入力パラメータ

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

### 入力データソース

- グローバルコンテキスト（g.CurrentMultiSelect）からの現在のマルチセレクト状態
- スコープ内で蓄積された選択リクエスト
- マウス入力状態（空白クリック検出用）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | ImGuiMultiSelectIO* | 最終的な選択リクエストを含むI/O構造体 |
| Requests | ImVector<ImGuiSelectionRequest> | SetRange等の選択変更リクエスト |

### 出力先

- ImGuiMultiSelectIO構造体（アプリケーションが処理）
- 内部状態のクリーンアップ

## 処理フロー

### 処理シーケンス

```
1. 状態検証
   └─ FocusScopeIdの一致確認（アサーション）
   └─ スタック状態の確認

2. スコープ矩形の計算
   └─ CalcScopeRectでスコープ範囲を取得

3. RangeSrc/NavIdのリセット判定
   └─ パスされていないアイテムのリセット

4. ボックス選択の終了
   └─ BoxSelectフラグ時、EndBoxSelectを呼び出し

5. 空白クリック検出
   └─ ClearOnClickVoidフラグ時、選択クリアリクエスト生成

6. ナビゲーションラッピング
   └─ NavWrapXフラグ時、ラッピング処理

7. スコープのクリーンアップ
   └─ CursorMaxPosの復元
   └─ PopFocusScope
   └─ スタックからのポップ

8. IO返却
   └─ 更新されたms->IOを返却
```

### フローチャート

```mermaid
flowchart TD
    A[EndMultiSelect開始] --> B[状態検証]
    B --> C[スコープ矩形計算]
    C --> D{IsFocused?}
    D -->|Yes| E{RangeSrcPassedBy?}
    D -->|No| F[IOリクエストクリア]
    E -->|No| G[RangeSrcItemリセット]
    E -->|Yes| H{NavIdPassedBy?}
    G --> H
    H -->|No| I[NavIdItemリセット]
    H -->|Yes| J{BoxSelect有効?}
    I --> J
    J -->|Yes| K[EndBoxSelect]
    J -->|No| L{ClearOnClickVoid?}
    K --> L
    L -->|Yes| M{空白クリック?}
    L -->|No| N{NavWrapX?}
    M -->|Yes| O[選択クリアリクエスト]
    M -->|No| N
    O --> N
    N -->|Yes| P[NavMoveRequestTryWrapping]
    N -->|No| Q[スコープクリーンアップ]
    P --> Q
    F --> Q
    Q --> R[PopFocusScope]
    R --> S[return &ms->IO]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-143-01 | ペア呼び出し | BeginMultiSelectと必ずペアで呼び出す | 常時 |
| BR-143-02 | 空白クリック解除 | 空白領域クリックで選択解除 | ClearOnClickVoidフラグあり |
| BR-143-03 | RangeSrcリセット | 未パスのRangeSrcItemはリセット | フォーカス時、アイテム未通過時 |
| BR-143-04 | ナビゲーションラップ | X方向のナビゲーションをラップ | NavWrapXフラグあり |

### 計算ロジック

空白クリック検出条件:
1. ウィンドウがホバーされている
2. ScopeRectフラグ時はスコープ矩形内
3. HoveredId == 0（アイテム上でない）
4. ActiveId == 0
5. マウスリリースされた
6. ドラッグ閾値を超えていない

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

該当なし（ImGuiはインメモリUIライブラリ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | アサーション | FocusScopeIdの不一致 | BeginMultiSelect/EndMultiSelectのペアリングを確認 |
| - | アサーション | スタックの不一致 | ネストされたマルチセレクトの構造を確認 |

### リトライ仕様

該当なし

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

EndMultiSelect呼び出し後、返却されたRequestsをアプリケーションが処理することで選択状態が確定する。

## パフォーマンス要件

- 終了処理は軽量
- ボックス選択終了時に追加の計算が発生
- NavWrapX有効時、ナビゲーション処理の追加コスト

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

内部状態のクリーンアップが正しく行われ、メモリリークを防止。

## 備考

- BeginMultiSelectのBETA状態に準じる
- 返却されたポインタは次のBeginMultiSelect/EndMultiSelect呼び出しまで有効
- 複数フレームにわたってポインタを保持しないこと

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui.h | `imgui.h` | ImGuiMultiSelectIO構造体（3038-3047行目）の読み書き方向を理解 |
| 1-2 | imgui_internal.h | `imgui_internal.h` | ImGuiMultiSelectTempData構造体の一時状態を理解 |

**読解のコツ**: EndMultiSelectでは主にBeginMultiSelectで設定されたデータを読み取り、最終リクエストを生成する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui.h | `imgui.h` | EndMultiSelect関数宣言（774行目） |
| 2-2 | imgui_widgets.cpp | `imgui_widgets.cpp` | EndMultiSelect実装（8013-8090行目） |

**主要処理フロー**:
1. **8019-8021行目**: 状態検証（アサーション）
2. **8023行目**: スコープ矩形の計算
3. **8027-8037行目**: RangeSrcItem/NavIdItemのリセット判定
4. **8039-8040行目**: ボックス選択の終了
5. **8046-8068行目**: 空白クリックによる選択解除
6. **8072-8076行目**: ナビゲーションラッピング
7. **8078-8089行目**: スコープのクリーンアップと返却

#### Step 3: 関連ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui_widgets.cpp | `imgui_widgets.cpp` | CalcScopeRect関数でスコープ範囲計算を理解 |
| 3-2 | imgui_widgets.cpp | `imgui_widgets.cpp` | EndBoxSelect関数でボックス選択終了を理解 |

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

```
EndMultiSelect()
    │
    ├─ CalcScopeRect(ms, window)
    │
    ├─ [if IsFocused && RangeSrcPassedBy==false]
    │     └─ storage->RangeSrcItem = Invalid
    │
    ├─ [if IsFocused && NavIdPassedBy==false]
    │     └─ storage->NavIdItem = Invalid
    │
    ├─ [if BoxSelect] GetBoxSelectState() / EndBoxSelect()
    │
    ├─ [if scope_hovered && HoveredId==0]
    │     ├─ [if BoxSelect] BoxSelectPreStartDrag()
    │     │
    │     └─ [if ClearOnClickVoid && MouseReleased]
    │           └─ MultiSelectAddSetAll(ms, false)
    │
    ├─ [if NavWrapX] NavMoveRequestTryWrapping()
    │
    ├─ PopFocusScope()
    │
    └─ return &ms->IO
```

### データフロー図

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

g.CurrentMultiSelect ─────────┐
                              │
ms->Storage ──────────────────┼──▶ EndMultiSelect() ──────────▶ ImGuiMultiSelectIO*
                              │           │                            │
ms->Flags ────────────────────┤           │                            ├── Requests[]
                              │           │                            │   (SetRange等)
ms->IO.Requests ──────────────┘           │                            │
                                          │                            └── 更新後の状態
g.IO.MousePos ────────────────────────────▶│
                                          │
g.HoveredId ──────────────────────────────▶│
                                          │
g.ActiveId ───────────────────────────────▶├──▶ storage更新
                                          │    (RangeSrc/NavId)
                                          │
                                          └──▶ g.CurrentMultiSelect = NULL
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui.h | `imgui.h` | ヘッダー | 公開API宣言 |
| imgui_widgets.cpp | `imgui_widgets.cpp` | ソース | EndMultiSelect実装 |
| imgui_internal.h | `imgui_internal.h` | ヘッダー | 内部データ構造定義 |
