# 通知設計書 80-NOTIFICATION_DRAG_BEGIN

## 概要

本ドキュメントは、Godot Engineにおける`NOTIFICATION_DRAG_BEGIN`通知の設計仕様を記載する。この通知はドラッグ操作が開始された際にViewport内のすべてのノードに送信され、ドラッグ&ドロップ機能の実装に使用される。

### 本通知の処理概要

この通知は、ユーザーがGUI上でドラッグ操作を開始した際に、Viewport内のすべてのノード（ドラッグ元だけでなく）に伝播して送信される。Controlノードの`_get_drag_data()`メソッドでドラッグデータが提供されるか、`force_drag()`メソッドが呼び出された時にドラッグが開始される。

**業務上の目的・背景**：ゲームやアプリケーションUIにおいて、ドラッグ&ドロップ機能は頻繁に使用される。アイテムの移動、ファイルのドロップ、リストの並び替えなど、多くのインタラクションパターンがある。この通知により、ドラッグ操作の開始をViewport全体に通知し、必要なビジュアルフィードバックや処理の準備を行うことができる。

**通知の送信タイミング**：以下のイベントで通知が送信される：
- マウスドラッグでControlノードの`_get_drag_data()`がデータを返した時
- `Control.force_drag()`が呼び出された時
- ドラッグ操作が正式に開始されたと判断された時（ドラッグ試行後）

**通知の受信者**：Viewportのセクションルートノードとそのすべての子孫ノード。SubViewportContainerの子でないSubViewportは除外される。

**通知内容の概要**：通知自体にはパラメータは含まれないが、ドラッグデータは`Viewport.gui_get_drag_data()`で取得可能。

**期待されるアクション**：受信したノードは以下のような処理を行う：
1. ドラッグ開始のビジュアルフィードバック表示
2. ドロップターゲットの強調表示準備
3. ドラッグ関連のUI状態の更新

## 通知種別

アプリ内通知（エンジン内部通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 通知定数 | `NOTIFICATION_DRAG_BEGIN` |
| 通知値 | 21 |
| 送信方式 | 同期（propagate） |
| 優先度 | 高（ユーザーインタラクション） |
| リトライ | なし |

### 送信先決定ロジック

通知は`Viewport::_propagate_drag_notification()`メソッドで以下のルールに従って伝播される：
1. 指定されたノードに通知を送信
2. すべての子ノードに対して再帰的に処理
3. SubViewportContainerの子でないSubViewportは除外

## 通知テンプレート

### 通知定義

```cpp
// node.h
NOTIFICATION_DRAG_BEGIN = 21,
```

### 処理テンプレート（GDScript）

```gdscript
func _notification(what):
    if what == NOTIFICATION_DRAG_BEGIN:
        print("ドラッグ開始")
        var drag_data = get_viewport().gui_get_drag_data()
        if drag_data:
            _highlight_drop_zones()

func _notification(what):
    if what == NOTIFICATION_DRAG_END:
        print("ドラッグ終了")
        _unhighlight_drop_zones()
```

### 処理テンプレート（C++）

```cpp
void MyControl::_notification(int p_notification) {
    switch (p_notification) {
        case NOTIFICATION_DRAG_BEGIN: {
            Variant drag_data = get_viewport()->gui_get_drag_data();
            if (drag_data.get_type() != Variant::NIL) {
                _show_drop_indicator();
            }
        } break;
        case NOTIFICATION_DRAG_END: {
            _hide_drop_indicator();
        } break;
    }
}
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| drag_data | ドラッグ中のデータ | `Viewport.gui_get_drag_data()` | No（取得は任意） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| マウス操作 | ドラッグ検出 | _get_drag_data()がデータを返す | GUIドラッグ開始 |
| API呼び出し | force_drag() | gui.global_draggingがtrue | 強制ドラッグ開始 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| gui.dragging == false | ドラッグが実際に開始されていない |
| SubViewport（非埋め込み） | SubViewportContainerの子でないSubViewport |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[マウスドラッグ検出] --> B{drag_attemptedフラグ}
    B -->|未試行| C[_get_drag_data呼び出し]
    C --> D{ドラッグデータあり?}
    D -->|Yes| E[gui.dragging = true]
    D -->|No| F[ドラッグなしで続行]
    E --> G[_propagate_drag_notification]
    G --> H[セクションルートからノードへ通知]
    H --> I{SubViewport?}
    I -->|Yes, 非埋め込み| J[スキップ]
    I -->|No| K[notification DRAG_BEGIN送信]
    K --> L[子ノードへ再帰]
    L --> M[終了]
    J --> L
    F --> M
```

## データベース参照・更新仕様

該当なし（本通知はエンジン内部のGUIシステムで処理され、データベースは使用しない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 特になし | - | - |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（ユーザーアクションに連動） |

### 配信時間帯

制限なし

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

- ドラッグデータにはユーザーが提供した任意のデータが含まれる可能性があるため、受信側での検証が推奨
- クロスウィンドウドラッグの場合、異なるセキュリティコンテキストからのデータに注意

## 備考

- `NOTIFICATION_DRAG_END`（値22）とペアで使用される
- ドラッグ成功/失敗は`Viewport.gui_is_drag_successful()`で確認可能
- ドラッグプレビューは`Control._make_custom_tooltip()`と同様に`set_drag_preview()`で設定可能
- 公式ドキュメントでは「すべてのノードが受信する」と明記

---

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

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

### 推奨読解順序

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

ViewportのGUI状態構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | node.h | `scene/main/node.h` | NOTIFICATION_DRAG_BEGIN定数（値21） |
| 1-2 | viewport.h | `scene/main/viewport.h` | gui構造体、dragging、drag_dataメンバ |

**読解のコツ**: `gui.dragging`フラグがドラッグ状態を示し、`gui.drag_data`がドラッグ中のデータを保持する。

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

通知の発火元を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | viewport.cpp | `scene/main/viewport.cpp` | _propagate_drag_notification()メソッド（行1333-1343） |

**主要処理フロー**:
1. **行1335**: `p_node->notification(p_what)`で通知送信
2. **行1336**: `is_svc`チェック（SubViewportContainer判定）
3. **行1337-1341**: 子ノードへの再帰（SubViewportを条件付きでスキップ）

#### Step 3: ドラッグ開始処理を理解する

ドラッグ開始のトリガーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | viewport.cpp | `scene/main/viewport.cpp` | GUI入力処理内のドラッグ検出（行2063-2066） |
| 3-2 | viewport.cpp | `scene/main/viewport.cpp` | force_drag()内の通知（行2482） |

**主要処理フロー**:
- **行2063-2066**: `gui.dragging`がtrueの場合に`_propagate_drag_notification(section_root, NOTIFICATION_DRAG_BEGIN)`
- **行2482**: `force_drag()`内でも同様の通知

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

```
マウスドラッグ入力
    │
    └─ Viewport::_gui_input_event()
           │
           ├─ ドラッグ検出処理
           │      ├─ Control::_get_drag_data()呼び出し
           │      └─ gui.dragging = true
           │
           └─ Viewport::_propagate_drag_notification(section_root, NOTIFICATION_DRAG_BEGIN)
                  │
                  ├─ p_node->notification(NOTIFICATION_DRAG_BEGIN)
                  │
                  └─ 子ノードへの再帰
                         ├─ SubViewport（非埋め込み）→ スキップ
                         └─ その他 → 通知送信
```

### データフロー図

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

マウスドラッグ   ───▶ _gui_input_event()   ───▶ NOTIFICATION_DRAG
                          │                    _BEGIN送信
                          ▼                         │
                    _get_drag_data()                ▼
                          │                   すべてのノードへ
                          ▼                   通知伝播
                    gui.dragging = true            │
                          │                        ▼
                          ▼                   gui_get_drag_data()
                    _propagate_drag            でデータ取得可能
                    _notification()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| node.h | `scene/main/node.h` | ヘッダ | 通知定数定義 |
| viewport.h | `scene/main/viewport.h` | ヘッダ | Viewportクラス、GUI構造体定義 |
| viewport.cpp | `scene/main/viewport.cpp` | ソース | _propagate_drag_notification()実装、GUI入力処理 |
| control.cpp | `scene/gui/control.cpp` | ソース | _get_drag_data()仮想メソッド |
| Node.xml | `doc/classes/Node.xml` | ドキュメント | 公式ドキュメント定義（行1200-1204） |
