# 機能設計書 20-ペインのリサイズ

## 概要

本ドキュメントは、Windows Terminalにおけるペインの境界を指定方向に移動してサイズを変更する機能（ResizePane アクション）の設計を記述する。

### 本機能の処理概要

ペイン間のセパレーター（境界線）を指定された方向に移動し、隣接するペインのサイズを調整する機能である。二分木構造のペインツリーを再帰的に探索し、フォーカスされたペインに最も近い適切なセパレーターを見つけて、その位置を調整する。

**業務上の目的・背景**：分割されたペインのサイズは初期状態では均等だが、作業内容に応じてペインのサイズを調整したい場合がある。例えば、ログ監視ペインを小さくして、コード編集ペインを広くするといった調整が必要になる。

**機能の利用シーン**：キーバインド（Alt+Shift+矢印キーなど）でペインのサイズを調整する場面で使用される。複数回連続して実行することで段階的にサイズを変更できる。

**主要な処理内容**：
1. ResizePaneアクションの受信とパラメータ（ResizeDirection）の取得
2. ResizeDirection が None の場合は処理をスキップ
3. _ResizePane メソッドの呼び出し
4. ズーム状態の解除
5. Tab::ResizePane から Pane::ResizePane への委譲
6. ペインツリーの再帰的探索で適切なセパレーターを特定
7. _Resize メソッドでセパレーター位置を5%単位で移動
8. GridのRowDefinition/ColumnDefinitionの再計算

**関連システム・外部連携**：外部連携なし。

**権限による制御**：権限による制御なし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | TerminalPage（メイン画面） | 主画面 | _HandleResizePaneによりペイン境界を移動 |

## 機能種別

UI操作 / レイアウト変更

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ResizeDirection | ResizeDirection enum | Yes | リサイズ方向（None, Left, Right, Up, Down） | None の場合は処理スキップ |

### 入力データソース

キーバインドまたはコマンドパレットからのアクション実行によりResizePaneArgsとして渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| セパレーター位置 | float | 更新された分割位置（0.0-1.0の比率） |
| Gridレイアウト | RowDefinition/ColumnDefinition | 更新されたGridの行/列定義 |

### 出力先

ペインのGrid要素のRowDefinition/ColumnDefinition

## 処理フロー

### 処理シーケンス

```
1. _HandleResizePane が呼び出される
   └─ ActionEventArgs から ResizePaneArgs を取得
2. ResizeDirection が None の場合
   └─ Handled(false) を設定して終了
3. _ResizePane(direction) を呼び出し
   ├─ _GetFocusedTabImpl() でフォーカス中のタブを取得
   ├─ _UnZoomIfNeeded() でズーム解除
   └─ tabImpl->ResizePane(direction) を呼び出し
4. Tab::ResizePane(direction)
   └─ _rootPane->ResizePane(direction) を呼び出し
5. Pane::ResizePane(direction) - 再帰的処理
   ├─ leafの場合 → false を返す
   ├─ 子ペインがフォーカスされている場合 → _Resize(direction) を呼び出し
   └─ 子ペインにフォーカスされた子孫がある場合 → 再帰的にResizePane呼び出し
6. Pane::_Resize(direction)
   ├─ 方向とSplitStateの一致を確認
   ├─ 5%単位でセパレーター位置を移動
   ├─ _ClampSplitPosition で位置を制約
   └─ _CreateRowColDefinitions でGridを更新
7. args.Handled(true) を設定
```

### フローチャート

```mermaid
flowchart TD
    A[ResizePane アクション受信] --> B[ResizePaneArgs 取得]
    B --> C{Direction == None?}
    C -->|Yes| D[Handled = false]
    C -->|No| E[_ResizePane 呼び出し]
    E --> F[ズーム解除]
    F --> G[Tab::ResizePane]
    G --> H[Pane::ResizePane - 再帰探索]
    H --> I{leaf ノード?}
    I -->|Yes| J[false 返却]
    I -->|No| K{子がフォーカス?}
    K -->|Yes| L[_Resize 呼び出し]
    K -->|No| M{子孫にフォーカスあり?}
    M -->|Yes| N[子の ResizePane を再帰呼び出し]
    M -->|No| J
    N --> O{リサイズ成功?}
    O -->|No| L
    O -->|Yes| P[true 返却]
    L --> Q{方向とSplit一致?}
    Q -->|No| J
    Q -->|Yes| R[5%単位で位置移動]
    R --> S[_ClampSplitPosition]
    S --> T[_CreateRowColDefinitions]
    T --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-20-01 | Direction None | ResizeDirection が None の場合は処理をスキップする | Direction == None |
| BR-20-02 | 方向一致チェック | セパレーターの方向とリサイズ方向が一致する場合のみリサイズを実行する | DirectionMatchesSplit(direction, _splitState) |
| BR-20-03 | 5%単位移動 | セパレーターは 0.05 (5%) 単位で移動する | 常時 |
| BR-20-04 | 移動方向 | Right / Down 方向の場合は負の方向（-0.05）に移動する | Direction == Right or Down |
| BR-20-05 | 最小サイズ制約 | _ClampSplitPosition により、ペインが消滅しない範囲に位置を制約する | 常時 |
| BR-20-06 | 再帰探索 | フォーカスされたペインに最も近いセパレーターを優先してリサイズする | 常時 |
| BR-20-07 | フォールバック | 子ペインでのリサイズが失敗した場合、親ペインのセパレーターでリサイズを試行する | 子のResizePaneがfalseを返した場合 |

### 計算ロジック

- 移動量: amount = 0.05 (5%)
- 方向補正: Right/Down の場合は amount = -amount
- 新しい分割位置: _desiredSplitPosition = _ClampSplitPosition(changeWidth, _desiredSplitPosition - amount, actualDimension)
- changeWidth: _splitState == SplitState::Vertical の場合 true

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

データベース操作なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| なし | リサイズ不可 | 適切なセパレーターが見つからない場合 | false を返し、処理を終了 |
| なし | Direction None | ResizeDirection が None の場合 | Handled(false) を設定 |

### リトライ仕様

リトライ不要。

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

トランザクション管理なし。

## パフォーマンス要件

リサイズは即座にUI上に反映されること。再帰探索のオーバーヘッドは、ペイン数が少ない（通常数個）ため無視できる。

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

特になし。

## 備考

- ズーム中のペインはリサイズできない（事前にズームが解除される）
- _desiredSplitPosition はユーザーが望む分割位置を保持し、_ClampSplitPosition で実際の表示制約に適用される
- ペインツリーの各ノードのSplitStateがVerticalの場合は左右方向、Horizontalの場合は上下方向のリサイズが可能
- リサイズは root ペインから開始する必要がある（NOTE コメントに記載）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | **47-54行目**: ResizeDirection enum の定義（None, Left, Right, Up, Down） |
| 1-2 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | **233-236行目**: ResizePaneArgs の定義。ResizeDirection プロパティ |
| 1-3 | Pane.h | `src/cascadia/TerminalApp/Pane.h` | **48-53行目**: SplitState enum（None, Horizontal, Vertical）。**112行目**: ResizePane メソッドの宣言 |

**読解のコツ**: ResizeDirection はアクション引数の方向指定（上下左右）、SplitState はペインの分割方向（水平/垂直）。リサイズが可能なのは、方向と分割方向が一致する場合のみ（例：Left/Right方向のリサイズはVertical分割のセパレーターでのみ可能）。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | **490-506行目**: _HandleResizePane の実装。Direction None チェックと _ResizePane 呼び出し |

**主要処理フロー**:
1. **493行目**: ResizePaneArgs を取得
2. **495-498行目**: Direction が None の場合、Handled(false) を設定
3. **502行目**: _ResizePane(direction) を呼び出し
4. **503行目**: args.Handled(true) を設定

#### Step 3: TerminalPage の中継処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | **2789-2796行目**: _ResizePane の実装。タブ取得、ズーム解除、Tab::ResizePane への委譲 |

#### Step 4: Tab の中継処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | **848-855行目**: Tab::ResizePane。root ペインから ResizePane を開始（NOTE: root から呼ぶ必要あり） |

#### Step 5: Pane の再帰的リサイズ処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Pane.cpp | `src/cascadia/TerminalApp/Pane.cpp` | **287-327行目**: Pane::ResizePane。再帰的にフォーカスされたペインに最も近いセパレーターを探索 |
| 5-2 | Pane.cpp | `src/cascadia/TerminalApp/Pane.cpp` | **246-274行目**: Pane::_Resize。実際のセパレーター位置の移動（5%単位）とGrid定義の更新 |

**主要処理フロー**:
- **291-294行目**: leafの場合はfalseを返す
- **300-305行目**: 子ペインがフォーカスされている場合、_Resizeを呼び出す
- **316-324行目**: 子孫にフォーカスがある場合、再帰的にResizePaneを呼び出し、失敗した場合は自身の_Resizeにフォールバック
- **248-251行目**: 方向とSplitStateの一致を確認
- **253-257行目**: 移動量0.05を設定（Right/Downは負方向）
- **268行目**: _ClampSplitPosition で位置を制約
- **271行目**: _CreateRowColDefinitions でGrid定義を更新

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

```
TerminalPage::_HandleResizePane (AppActionHandlers.cpp:490)
    |
    +-- TerminalPage::_ResizePane(direction) (TerminalPage.cpp:2789)
            |
            +-- _GetFocusedTabImpl()
            +-- _UnZoomIfNeeded()
            |
            +-- Tab::ResizePane(direction) (Tab.cpp:848)
                    |
                    +-- Pane::ResizePane(direction) [rootから開始] (Pane.cpp:287)
                            |
                            +-- [再帰探索: フォーカスされたペインのセパレーターを特定]
                            |
                            +-- Pane::_Resize(direction) (Pane.cpp:246)
                                    +-- DirectionMatchesSplit(direction, _splitState)
                                    +-- amount = 0.05 (Right/Down: -0.05)
                                    +-- _ClampSplitPosition()
                                    +-- _CreateRowColDefinitions()
```

### データフロー図

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

ResizePaneArgs         TerminalPage                        Grid レイアウト
(Direction: enum) ---> ::_ResizePane() -----------------> RowDefinition /
                            |                              ColumnDefinition 更新
                            v
                       Tab::ResizePane()
                            |
                            v
                       Pane::ResizePane() [再帰探索]
                            |
                            v
                       Pane::_Resize()
                            |
                       _desiredSplitPosition 更新
                            |
                       _CreateRowColDefinitions()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | _HandleResizePane の実装 |
| TerminalPage.cpp | `src/cascadia/TerminalApp/TerminalPage.cpp` | ソース | _ResizePane の実装 |
| TerminalPage.h | `src/cascadia/TerminalApp/TerminalPage.h` | ヘッダー | _ResizePane の宣言 |
| Tab.cpp | `src/cascadia/TerminalApp/Tab.cpp` | ソース | Tab::ResizePane の実装 |
| Tab.h | `src/cascadia/TerminalApp/Tab.h` | ヘッダー | Tab クラスの宣言 |
| Pane.cpp | `src/cascadia/TerminalApp/Pane.cpp` | ソース | ResizePane / _Resize の実装 |
| Pane.h | `src/cascadia/TerminalApp/Pane.h` | ヘッダー | Pane クラスの宣言 |
| Pane.LayoutSizeNode.cpp | `src/cascadia/TerminalApp/Pane.LayoutSizeNode.cpp` | ソース | レイアウトサイズ計算の補助 |
| ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | IDL | ResizePaneArgs / ResizeDirection の型定義 |
