using UnityEngine;
namespace XericLibrary.Runtime.Blueprint.QuickGraph
{
///
/// QuickGraph 输入交互工具 —— 处理画布平移、缩放。
/// 中键拖拽 = 平移;滚轮 = 缩放。
/// 视图状态读写委托给 ,
/// 输入参数从 读取。
///
[BlueprintTool(phase: ToolPhase.PreUpdate, order: 50)]
[BlueprintTheme("QuickGraph")]
public class QuickGraphInputTool : BlueprintTool
{
// ---------- 配置(从 ToolConfigAssets 读取) ----------
private QuickGraphInputConfig Config
{
get
{
if (ToolConfig is QuickGraphInputConfig external)
return external;
if (_defaultConfig == null)
_defaultConfig = ScriptableObject.CreateInstance();
return _defaultConfig;
}
}
private static QuickGraphInputConfig _defaultConfig;
// ---------- 缓存的 ViewportController 引用 ----------
private BlueprintViewportController _viewport;
private BlueprintViewportController Viewport
{
get
{
if (_viewport == null && Graph != null)
_viewport = BlueprintToolProvider.GetToolByType(Graph);
return _viewport;
}
}
// ---------- 拖拽状态 ----------
private bool _isDragging;
private int _activeDragButton = -1;
private Vector2 senderPanDirection() => GraphInputTool.GetAdapter(Graph)?.PanDirection ?? Vector2.zero;
private float senderZoomAxis() => GraphInputTool.GetAdapter(Graph)?.ZoomAxis ?? 0f;
// ---------- 选择状态 ----------
private BlueprintElementBase _hoveredElement;
public override void OnPointerMove(GraphInputTool sender, Vector2 canvasPoint, Vector2 delta)
{
if (Graph == null || _isDragging) return;
var hit = Graph.HitTest(canvasPoint);
_hoveredElement = hit as BlueprintElementBase;
}
/// 当前悬停的元素(可能为 null)
public BlueprintElementBase HoveredElement => _hoveredElement;
/// 当前选中的元素(委托给 SelectorHandle)。
public BlueprintElementBase SelectedElement =>
BlueprintToolProvider.GetSelector(Graph).PrimarySelection as BlueprintElementBase;
public override void OnConfigChanged()
{
var viewport = Viewport;
if (viewport == null) return;
var cfg = Config;
viewport.MinZoom = cfg.MinZoom;
viewport.MaxZoom = cfg.MaxZoom;
viewport.TargetZoomLevel = Mathf.Clamp(viewport.TargetZoomLevel, cfg.MinZoom, cfg.MaxZoom);
// ViewportController 是 Canvas Pan/Zoom 的唯一提交者;这里只更新 controller 的范围与目标。
Graph?.MarkDirty();
}
public override void OnUpdate(float deltaTime)
{
if (Graph?.Canvas == null) return;
var viewport = Viewport;
if (viewport == null) return;
var cfg = Config;
// ── 同步缩放范围 ──
viewport.MinZoom = cfg.MinZoom;
viewport.MaxZoom = cfg.MaxZoom;
// ── 键盘 Pan ──
viewport.TargetPanOffset += senderPanDirection() * cfg.KeyboardPanSpeed * deltaTime;
// ── 键盘 Zoom ──
float zoomInput = senderZoomAxis();
if (!Mathf.Approximately(zoomInput, 0f))
{
float oldZoom = viewport.TargetZoomLevel;
float zoomDelta = zoomInput / cfg.ZoomDivisor;
viewport.TargetZoomLevel = Mathf.Clamp(
viewport.TargetZoomLevel + zoomDelta,
viewport.MinZoom, viewport.MaxZoom);
ApplyZoomFocus(oldZoom);
}
}
// ===== 鼠标按下 =====
public override void OnPointerDown(GraphInputTool sender, Vector2 canvasPoint, int mouseButton)
{
if (Graph == null) return;
if (mouseButton == 2)
{
_isDragging = true;
_activeDragButton = 2;
}
}
// ===== 鼠标释放 =====
public override void OnPointerUp(GraphInputTool sender, Vector2 canvasPoint, int mouseButton)
{
if (_isDragging && _activeDragButton == mouseButton)
{
_isDragging = false;
_activeDragButton = -1;
}
}
// ===== 拖拽 =====
public override void OnPointerDrag(GraphInputTool sender, Vector2 canvasPoint, Vector2 delta, int mouseButton)
{
var viewport = Viewport;
if (viewport == null) return;
if (mouseButton == 2)
{
// canvas delta 在本帧 Pan 提交后会反向跳变;仅使用 RenderRoot local 平面 delta。
viewport.TargetPanOffset += (sender?.PointerLocalDelta ?? Vector2.zero) * Config.DragPanSpeed;
Graph.MarkDirty();
}
}
// ===== 滚轮 =====
public override void OnScroll(GraphInputTool sender, Vector2 canvasPoint, Vector2 scrollDelta)
{
var viewport = Viewport;
if (viewport == null) return;
float oldZoom = viewport.TargetZoomLevel;
viewport.TargetZoomLevel = Mathf.Clamp(
viewport.TargetZoomLevel + scrollDelta.y / Config.ZoomDivisor,
viewport.MinZoom, viewport.MaxZoom);
if (!Mathf.Approximately(oldZoom, viewport.TargetZoomLevel))
{
viewport.TargetPanOffset += canvasPoint * (oldZoom - viewport.TargetZoomLevel);
Graph.MarkDirty();
}
}
// ===== 快捷键 =====
public override void OnAction(GraphInputTool sender, string actionName)
{
if (Graph?.Canvas == null) return;
switch (actionName)
{
case BlueprintInputConstants.FocusHome:
Viewport?.ResetView();
break;
case BlueprintInputConstants.Undo:
break;
case BlueprintInputConstants.Redo:
break;
case BlueprintInputConstants.NavigateParent:
break;
}
}
// ===== 以鼠标焦点为中心缩放(键盘调用 — 自行读取鼠标位置) =====
private void ApplyZoomFocus(float oldZoom)
{
var viewport = Viewport;
if (viewport == null || Graph?.Canvas == null) return;
Vector2 canvasCursor = Graph.Canvas.ScreenToCanvas(BlueprintUGUIInputManager.MousePosition);
viewport.TargetPanOffset += canvasCursor * (oldZoom - viewport.TargetZoomLevel);
}
}
}