update 0.6.3.7
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using XericLibrary.Runtime.Blueprint.Render;
|
||||
|
||||
namespace XericLibrary.Runtime.Blueprint
|
||||
{
|
||||
@@ -9,14 +8,13 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
/// 蓝图框选工具 —— 鼠标左键在空白区域拖拽,绘制矩形选框,
|
||||
/// 释放时计算框选范围内所有元素的交集并输出统计日志。
|
||||
/// <para>选框 UGUI Image 默认渲染在所有层之上(SetAsLastSibling)。</para>
|
||||
/// <para>框选结果保存在 <see cref="SelectedElements"/> 中供其他工具读取。</para>
|
||||
/// <para>框选结果通过 <see cref="BlueprintToolProvider.GetSelector"/>(Graph).<see cref="SelectorHandle.CurrentSelection"/> 读取。</para>
|
||||
/// <para>
|
||||
/// 选框仅在拖拽距离超过 <c>QuickGraphInputConfig.BoxSelectThreshold</c> 后才显示,
|
||||
/// 选框仅在拖拽距离超过 <see cref="BoxSelectThreshold"/> 后才显示,
|
||||
/// 避免误触显示闪烁。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[BlueprintTool(phase: ToolPhase.PreUpdate, order: 60)]
|
||||
[BlueprintTheme("QuickGraph")]
|
||||
public class BlueprintBoxSelectTool : BlueprintTool
|
||||
{
|
||||
// ---------- 状态 ----------
|
||||
@@ -34,30 +32,12 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
|
||||
// ---------- 配置 ----------
|
||||
|
||||
private QuickGraphInputConfig _boxConfig;
|
||||
|
||||
private QuickGraphInputConfig BoxConfig
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_boxConfig == null && Graph != null)
|
||||
{
|
||||
foreach (var c in Graph.ConfigAssets)
|
||||
{
|
||||
if (c is QuickGraphInputConfig qc) { _boxConfig = qc; break; }
|
||||
}
|
||||
if (_boxConfig == null)
|
||||
{
|
||||
_boxConfig = ScriptableObject.CreateInstance<QuickGraphInputConfig>();
|
||||
}
|
||||
}
|
||||
return _boxConfig;
|
||||
}
|
||||
}
|
||||
/// <summary>框选拖拽触发阈值(画布单位)。拖拽距离超过此值后才显示选框并开始框选。</summary>
|
||||
public float BoxSelectThreshold = 10f;
|
||||
|
||||
// ---------- 结果 ----------
|
||||
|
||||
/// <summary>结果:通过 Provider.CurrentSelectElements 读取框选结果。</summary>
|
||||
/// <summary>结果:通过 Provider.Selector.CurrentSelection 读取框选结果。</summary>
|
||||
|
||||
// ===== 鼠标按下 =====
|
||||
|
||||
@@ -85,7 +65,7 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
_dragEndCanvas = canvasPoint;
|
||||
|
||||
// 检查拖拽距离是否超过阈值
|
||||
float threshold = BoxConfig.BoxSelectThreshold;
|
||||
float threshold = BoxSelectThreshold;
|
||||
float dragDist = Vector2.Distance(_dragStartCanvas, _dragEndCanvas);
|
||||
|
||||
if (!_boxVisible && dragDist > threshold)
|
||||
@@ -183,7 +163,7 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
UpdateSelectionBox();
|
||||
|
||||
// 计算选框内的元素(画布坐标空间)
|
||||
BlueprintToolProvider.CurrentSelectElements.Clear();
|
||||
var selectList = new System.Collections.Generic.List<IBlueprintElement>();
|
||||
var min = new Vector2(
|
||||
Mathf.Min(_dragStartCanvas.x, _dragEndCanvas.x),
|
||||
Mathf.Min(_dragStartCanvas.y, _dragEndCanvas.y));
|
||||
@@ -192,14 +172,11 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
Mathf.Max(_dragStartCanvas.y, _dragEndCanvas.y));
|
||||
var selectRect = new Rect(min, max - min);
|
||||
|
||||
foreach (var element in Graph.Elements)
|
||||
{
|
||||
if (element == null) continue;
|
||||
if (element.BoundingBox.Overlaps(selectRect))
|
||||
{
|
||||
BlueprintToolProvider.CurrentSelectElements.Add(element);
|
||||
}
|
||||
}
|
||||
var selector = BlueprintToolProvider.GetSelector(Graph);
|
||||
selector.RectHitTest(Graph, selectRect, selectList);
|
||||
|
||||
// 通过当前 Graph 的 SelectorHandle 提交多选
|
||||
selector.CommitMultiSelection(selectList);
|
||||
|
||||
// 销毁选框
|
||||
DestroySelectionBox();
|
||||
@@ -207,12 +184,14 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
|
||||
private void SelectAtPoint(Vector2 canvasPoint)
|
||||
{
|
||||
BlueprintToolProvider.CurrentSelectElements.Clear();
|
||||
if (Graph == null) return;
|
||||
|
||||
var hit = Graph.HitTest(canvasPoint);
|
||||
var selector = BlueprintToolProvider.GetSelector(Graph);
|
||||
var hit = selector.HitTest(Graph, canvasPoint);
|
||||
if (hit != null)
|
||||
BlueprintToolProvider.CurrentSelectElements.Add(hit);
|
||||
selector.CommitSelection(hit);
|
||||
else
|
||||
selector.SwapToHistory();
|
||||
}
|
||||
|
||||
private void DestroySelectionBox()
|
||||
|
||||
@@ -10,12 +10,12 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
/// 通过 <c>KfsStyle</c> + <c>KeyFlippingStampSheet</c> 状态机驱动拖拽识别。
|
||||
/// </summary>
|
||||
[BlueprintTool(phase: ToolPhase.PreUpdate, order: 1)]
|
||||
[BlueprintTheme("QuickGraph")]
|
||||
public class BlueprintInputTool_InputManager : BlueprintInputTool_UGUI
|
||||
{
|
||||
// ===== 三键的 sheet 状态表 =====
|
||||
private readonly MacroKey.KeyFlippingStampSheet[] _sheets = new MacroKey.KeyFlippingStampSheet[3];
|
||||
private readonly Vector2[] _lastCanvasPos = new Vector2[3];
|
||||
private readonly Vector2[] _lastLocalPos = new Vector2[3];
|
||||
|
||||
// ===== 快捷键轮询常量 =====
|
||||
private static readonly KeyCode[] s_modifierKeys = new[]
|
||||
@@ -76,16 +76,16 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
}
|
||||
|
||||
// 键盘 Pan / Zoom
|
||||
GraphInputTool.LastPanDirection = Vector2.zero;
|
||||
PanDirection = Vector2.zero;
|
||||
float x = 0f, y = 0f;
|
||||
if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W)) y += 1f;
|
||||
if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S)) y -= 1f;
|
||||
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A)) x -= 1f;
|
||||
if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D)) x += 1f;
|
||||
GraphInputTool.LastPanDirection = new Vector2(x, y);
|
||||
GraphInputTool.LastZoomAxis = 0f;
|
||||
if (Input.GetKey(KeyCode.Equals) || Input.GetKey(KeyCode.KeypadPlus)) GraphInputTool.LastZoomAxis = 1f;
|
||||
if (Input.GetKey(KeyCode.Minus) || Input.GetKey(KeyCode.KeypadMinus)) GraphInputTool.LastZoomAxis = -1f;
|
||||
PanDirection = new Vector2(x, y);
|
||||
ZoomAxis = 0f;
|
||||
if (Input.GetKey(KeyCode.Equals) || Input.GetKey(KeyCode.KeypadPlus)) ZoomAxis = 1f;
|
||||
if (Input.GetKey(KeyCode.Minus) || Input.GetKey(KeyCode.KeypadMinus)) ZoomAxis = -1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -104,6 +104,7 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
{
|
||||
var pt = canvas.ScreenToCanvas(Input.mousePosition);
|
||||
_lastCanvasPos[button] = pt;
|
||||
_lastLocalPos[button] = canvas.ScreenToLocal(Input.mousePosition);
|
||||
BlueprintToolProvider.DispatchPointerDown(Graph, this, pt, button);
|
||||
}
|
||||
|
||||
@@ -111,10 +112,13 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
if (sheet.IsDragging)
|
||||
{
|
||||
var current = canvas.ScreenToCanvas(Input.mousePosition);
|
||||
var currentLocal = canvas.ScreenToLocal(Input.mousePosition);
|
||||
var delta = current - _lastCanvasPos[button];
|
||||
PointerLocalDelta = currentLocal - _lastLocalPos[button];
|
||||
_lastCanvasPos[button] = current;
|
||||
_lastLocalPos[button] = currentLocal;
|
||||
|
||||
if (delta.sqrMagnitude > 0.0001f)
|
||||
if (delta.sqrMagnitude > 0.0001f || PointerLocalDelta.sqrMagnitude > 0.0001f)
|
||||
{
|
||||
BlueprintToolProvider.DispatchPointerDrag(Graph, this, current, delta, button);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
/// 不再依赖 <c>BlueprintInputManager</c> 管理器。
|
||||
/// </summary>
|
||||
[BlueprintTool(phase: ToolPhase.PreUpdate, order: 1)]
|
||||
[BlueprintTheme("QuickGraph")]
|
||||
public class BlueprintInputTool_InputSystem : BlueprintInputTool_UGUI
|
||||
{
|
||||
private InputActionAsset _inputActionAsset;
|
||||
@@ -47,10 +46,10 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
public override void OnInitialize()
|
||||
{
|
||||
// 创建回调委托(确保 Bind/Unbind 使用同一引用)
|
||||
_panHandler = ctx => GraphInputTool.LastPanDirection = ctx.ReadValue<Vector2>();
|
||||
_panCanceled = _ => GraphInputTool.LastPanDirection = Vector2.zero;
|
||||
_zoomHandler = ctx => GraphInputTool.LastZoomAxis = ctx.ReadValue<float>();
|
||||
_zoomCanceled = _ => GraphInputTool.LastZoomAxis = 0f;
|
||||
_panHandler = ctx => PanDirection = ctx.ReadValue<Vector2>();
|
||||
_panCanceled = _ => PanDirection = Vector2.zero;
|
||||
_zoomHandler = ctx => ZoomAxis = ctx.ReadValue<float>();
|
||||
_zoomCanceled = _ => ZoomAxis = 0f;
|
||||
_homeHandler = _ => DispatchShortcut(BlueprintInputConstants.FocusHome);
|
||||
_undoHandler = _ => DispatchShortcut(BlueprintInputConstants.Undo);
|
||||
_redoHandler = _ => DispatchShortcut(BlueprintInputConstants.Redo);
|
||||
|
||||
@@ -23,8 +23,11 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
|
||||
private const string BackgroundGoName = "__Bp_GridBackground";
|
||||
|
||||
// 上一帧的鼠标画布坐标(用于计算 PointerMove delta)
|
||||
// 上一帧坐标:普通交互使用 canvas delta,中键平移使用不受 Pan/Zoom 影响的 local delta。
|
||||
private Vector2 _lastCanvasPos;
|
||||
private Vector2 _lastLocalPos;
|
||||
private Vector2 _dragStartCanvasPos;
|
||||
private Vector2 _dragStartLocalPos;
|
||||
|
||||
/// <summary>
|
||||
/// 是否通过 EventTrigger 处理鼠标按键/拖拽/滚轮事件。
|
||||
@@ -37,6 +40,7 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
|
||||
public override void OnInitialize()
|
||||
{
|
||||
GraphInputTool.RegisterAdapter(Graph, this);
|
||||
TryBindEventTrigger();
|
||||
}
|
||||
|
||||
@@ -62,18 +66,17 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
return;
|
||||
}
|
||||
|
||||
var canvasPt = Graph.Canvas != null
|
||||
? Graph.Canvas.ScreenToCanvas(BlueprintUGUIInputManager.MousePosition)
|
||||
: Vector2.zero;
|
||||
var canvasPt = Graph.Canvas.ScreenToCanvas(BlueprintUGUIInputManager.MousePosition);
|
||||
var localPt = Graph.Canvas.ScreenToLocal(BlueprintUGUIInputManager.MousePosition);
|
||||
PointerLocalDelta = localPt - _lastLocalPos;
|
||||
UpdateCursorContext(canvasPt);
|
||||
|
||||
// ── 每帧分发 PointerMove ──
|
||||
var delta = canvasPt - _lastCanvasPos;
|
||||
if (delta.sqrMagnitude > 0.0001f || _lastCanvasPos == Vector2.zero)
|
||||
{
|
||||
BlueprintToolProvider.DispatchPointerMove(Graph, this, canvasPt, delta);
|
||||
}
|
||||
_lastCanvasPos = canvasPt;
|
||||
_lastLocalPos = localPt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -97,6 +100,7 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
GraphInputTool.UnregisterAdapter(Graph, this);
|
||||
UnbindEventTrigger();
|
||||
}
|
||||
|
||||
@@ -237,13 +241,13 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 _dragStartPos;
|
||||
private bool _hadDragThisClick;
|
||||
|
||||
private void OnBeginDragEvent(BaseEventData data)
|
||||
{
|
||||
if (!(data is PointerEventData pData)) return;
|
||||
_dragStartPos = PointerCanvasPos(pData);
|
||||
_dragStartCanvasPos = PointerCanvasPos(pData);
|
||||
_dragStartLocalPos = Graph.Canvas.ScreenToLocal(pData.position);
|
||||
_hadDragThisClick = true;
|
||||
}
|
||||
|
||||
@@ -251,10 +255,13 @@ namespace XericLibrary.Runtime.Blueprint
|
||||
{
|
||||
if (!(data is PointerEventData pData)) return;
|
||||
var current = PointerCanvasPos(pData);
|
||||
var delta = current - _dragStartPos;
|
||||
_dragStartPos = current;
|
||||
var currentLocal = Graph.Canvas.ScreenToLocal(pData.position);
|
||||
var canvasDelta = current - _dragStartCanvasPos;
|
||||
PointerLocalDelta = currentLocal - _dragStartLocalPos;
|
||||
_dragStartCanvasPos = current;
|
||||
_dragStartLocalPos = currentLocal;
|
||||
UpdateCursorContext(current);
|
||||
BlueprintToolProvider.DispatchPointerDrag(Graph, this, current, delta, (int)pData.button);
|
||||
BlueprintToolProvider.DispatchPointerDrag(Graph, this, current, canvasDelta, (int)pData.button);
|
||||
}
|
||||
|
||||
private void OnEndDragEvent(BaseEventData data)
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace XericLibrary.Runtime.Blueprint
|
||||
{
|
||||
/// <summary>
|
||||
/// 蓝图视口控制器 —— 管理视图状态(Pan/Zoom/范围),提供外部 API 供工具和外部代码读写。
|
||||
/// <para>
|
||||
/// 在 <c>ToolPhase.PreUpdate, order: 40</c> 执行,每帧直接将目标值写入 <see cref="IBlueprintCanvas"/>,
|
||||
/// 不做插值平滑。输入工具通过写入 <see cref="TargetPanOffset"/> / <see cref="TargetZoomLevel"/>
|
||||
/// 来驱动视图,外部代码可通过 <c>BlueprintToolProvider.GetTool<BlueprintViewportController>(graph)</c>
|
||||
/// 获取实例直接控制视图。
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 此工具为通用基础工具(无主题限定),对所有蓝图主题可见。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[BlueprintTool(phase: ToolPhase.PreUpdate, order: 40)]
|
||||
public class BlueprintViewportController : BlueprintTool
|
||||
{
|
||||
// ── 目标值(由输入工具或外部代码写入) ──
|
||||
|
||||
/// <summary>目标平移偏移量。外部代码直接设置此值即可控制视图平移。</summary>
|
||||
public Vector2 TargetPanOffset = Vector2.zero;
|
||||
|
||||
/// <summary>目标缩放级别。外部代码直接设置此值即可控制视图缩放。</summary>
|
||||
public float TargetZoomLevel = 1f;
|
||||
|
||||
/// <summary>最小缩放限制。</summary>
|
||||
public float MinZoom = 0.1f;
|
||||
|
||||
/// <summary>最大缩放限制。</summary>
|
||||
public float MaxZoom = 3f;
|
||||
|
||||
// ── 帧间脏检测 ──
|
||||
|
||||
private Vector2 _prevPanOffset;
|
||||
private float _prevZoomLevel;
|
||||
private bool _initialized;
|
||||
|
||||
public override void OnUpdate(float deltaTime)
|
||||
{
|
||||
if (Graph?.Canvas == null) return;
|
||||
|
||||
var canvas = Graph.Canvas;
|
||||
|
||||
// 首次同步
|
||||
if (!_initialized)
|
||||
{
|
||||
TargetPanOffset = canvas.PanOffset;
|
||||
TargetZoomLevel = canvas.ZoomLevel;
|
||||
_prevPanOffset = TargetPanOffset;
|
||||
_prevZoomLevel = TargetZoomLevel;
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
// 同步范围到 Canvas
|
||||
canvas.MinZoom = MinZoom;
|
||||
canvas.MaxZoom = MaxZoom;
|
||||
|
||||
// 钳制目标值
|
||||
TargetZoomLevel = Mathf.Clamp(TargetZoomLevel, MinZoom, MaxZoom);
|
||||
|
||||
// 直接写入 Canvas(无插值)
|
||||
canvas.PanOffset = TargetPanOffset;
|
||||
canvas.ZoomLevel = TargetZoomLevel;
|
||||
|
||||
// 标记脏
|
||||
if (TargetPanOffset != _prevPanOffset || !Mathf.Approximately(TargetZoomLevel, _prevZoomLevel))
|
||||
{
|
||||
Graph.MarkDirty();
|
||||
_prevPanOffset = TargetPanOffset;
|
||||
_prevZoomLevel = TargetZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 公共 API
|
||||
// ====================================================================
|
||||
|
||||
/// <summary>重置视图到原点,缩放归 1。</summary>
|
||||
public void ResetView()
|
||||
{
|
||||
TargetPanOffset = Vector2.zero;
|
||||
TargetZoomLevel = 1f;
|
||||
Graph?.MarkDirty();
|
||||
}
|
||||
|
||||
/// <summary>聚焦到某个画布坐标点。</summary>
|
||||
public void FocusOn(Vector2 canvasCenter, float zoom = 1f)
|
||||
{
|
||||
TargetZoomLevel = Mathf.Clamp(zoom, MinZoom, MaxZoom);
|
||||
if (Graph?.Canvas != null)
|
||||
{
|
||||
// local = canvas * zoom + pan;令目标画布点落在实际 viewport 的 RenderRoot local 中心。
|
||||
TargetPanOffset = Graph.Canvas.GetViewportLocalRect().center - canvasCenter * TargetZoomLevel;
|
||||
}
|
||||
else TargetPanOffset = -canvasCenter * TargetZoomLevel;
|
||||
Graph?.MarkDirty();
|
||||
}
|
||||
|
||||
/// <summary>聚焦到一组元素的包围盒区域。</summary>
|
||||
public void FocusOnElements(System.Collections.Generic.IReadOnlyList<IBlueprintElement> elements, float padding = 100f)
|
||||
{
|
||||
if (elements == null || elements.Count == 0) return;
|
||||
if (Graph?.Canvas == null) return;
|
||||
|
||||
// 计算所有元素的包围盒
|
||||
Rect bounds = elements[0].BoundingBox;
|
||||
for (int i = 1; i < elements.Count; i++)
|
||||
{
|
||||
var b = elements[i].BoundingBox;
|
||||
bounds.xMin = Mathf.Min(bounds.xMin, b.xMin);
|
||||
bounds.yMin = Mathf.Min(bounds.yMin, b.yMin);
|
||||
bounds.xMax = Mathf.Max(bounds.xMax, b.xMax);
|
||||
bounds.yMax = Mathf.Max(bounds.yMax, b.yMax);
|
||||
}
|
||||
|
||||
bounds.xMin -= padding;
|
||||
bounds.yMin -= padding;
|
||||
bounds.xMax += padding;
|
||||
bounds.yMax += padding;
|
||||
|
||||
// 以实际 viewport 的 RenderRoot local 尺寸适配;再复用 FocusOn 的统一公式。
|
||||
var viewportLocal = Graph.Canvas.GetViewportLocalRect();
|
||||
float zoomX = bounds.width > 0.0001f ? viewportLocal.width / bounds.width : MaxZoom;
|
||||
float zoomY = bounds.height > 0.0001f ? viewportLocal.height / bounds.height : MaxZoom;
|
||||
float zoom = Mathf.Clamp(Mathf.Min(zoomX, zoomY), MinZoom, MaxZoom);
|
||||
FocusOn(bounds.center, zoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fe1086d7e9750541a9a5de047e05ce6
|
||||
guid: f4bb7dd4bbd0e6e4fac82161405eca13
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,221 +0,0 @@
|
||||
using UnityEngine;
|
||||
using XericLibrary.Runtime.Blueprint.Render;
|
||||
|
||||
namespace XericLibrary.Runtime.Blueprint
|
||||
{
|
||||
/// <summary>
|
||||
/// QuickGraph 输入交互工具 —— 处理画布平移、缩放和节点选择。
|
||||
/// <para>中键拖拽 = 平移;左键点击 = 选择;滚轮 = 缩放。</para>
|
||||
/// <para>快捷键(新输入系统):方向键 = 平移,Ctrl+± = 缩放,Ctrl+H = 归位。</para>
|
||||
/// </summary>
|
||||
[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<QuickGraphInputConfig>();
|
||||
return _defaultConfig;
|
||||
}
|
||||
}
|
||||
private static QuickGraphInputConfig _defaultConfig;
|
||||
|
||||
// ---------- 视图状态 ----------
|
||||
private Vector2 _targetPanOffset;
|
||||
private float _targetZoomLevel = 1f;
|
||||
private bool _viewInitialized;
|
||||
|
||||
// 用于检测帧间变化
|
||||
private Vector2 _prevPanOffset;
|
||||
private float _prevZoomLevel;
|
||||
|
||||
// ---------- 拖拽状态 ----------
|
||||
private bool _isDragging;
|
||||
private int _activeDragButton = -1;
|
||||
private Vector2 _dragStartPan;
|
||||
|
||||
// ---------- 选择状态 ----------
|
||||
private BlueprintElementBase _hoveredElement;
|
||||
private BlueprintElementBase _selectedElement;
|
||||
|
||||
// ===== 更新(平滑插值 + 键盘轮询) =====
|
||||
|
||||
public override void OnUpdate(float deltaTime)
|
||||
{
|
||||
if (Graph?.Canvas == null) return;
|
||||
|
||||
var cfg = Config;
|
||||
var canvas = Graph.Canvas;
|
||||
|
||||
// ── 同步缩放范围 ──
|
||||
canvas.MinZoom = cfg.MinZoom;
|
||||
canvas.MaxZoom = cfg.MaxZoom;
|
||||
|
||||
if (!_viewInitialized)
|
||||
{
|
||||
_targetPanOffset = canvas.PanOffset;
|
||||
_targetZoomLevel = canvas.ZoomLevel;
|
||||
_prevPanOffset = _targetPanOffset;
|
||||
_prevZoomLevel = _targetZoomLevel;
|
||||
_viewInitialized = true;
|
||||
}
|
||||
|
||||
// ── 键盘 Pan ──
|
||||
_targetPanOffset += GraphInputTool.LastPanDirection
|
||||
* cfg.KeyboardPanSpeed * deltaTime;
|
||||
|
||||
// ── 键盘 / 滚轮 Zoom ──
|
||||
float zoomInput = GraphInputTool.LastZoomAxis;
|
||||
if (!Mathf.Approximately(zoomInput, 0f))
|
||||
{
|
||||
float oldZoom = _targetZoomLevel;
|
||||
float zoomDelta = zoomInput / cfg.ZoomDivisor;
|
||||
_targetZoomLevel = Mathf.Clamp(
|
||||
_targetZoomLevel + zoomDelta,
|
||||
canvas.MinZoom, canvas.MaxZoom);
|
||||
ApplyZoomFocus(ref _targetPanOffset, _targetZoomLevel, oldZoom);
|
||||
GraphInputTool.LastZoomAxis = 0f;
|
||||
}
|
||||
|
||||
// ── 平滑插值到目标值 ──
|
||||
canvas.PanOffset = Vector2.Lerp(
|
||||
canvas.PanOffset, _targetPanOffset, cfg.PanLerpSpeed * deltaTime);
|
||||
canvas.ZoomLevel = Mathf.Lerp(
|
||||
canvas.ZoomLevel, _targetZoomLevel, cfg.ZoomLerpSpeed * deltaTime);
|
||||
|
||||
// ── 标记脏 ──
|
||||
if (canvas.PanOffset != _prevPanOffset || !Mathf.Approximately(canvas.ZoomLevel, _prevZoomLevel))
|
||||
{
|
||||
Graph.MarkDirty();
|
||||
_prevPanOffset = canvas.PanOffset;
|
||||
_prevZoomLevel = canvas.ZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 鼠标移动 =====
|
||||
|
||||
public override void OnPointerMove(GraphInputTool sender, Vector2 canvasPoint, Vector2 delta)
|
||||
{
|
||||
if (Graph == null || _isDragging) return;
|
||||
|
||||
var hit = Graph.HitTest(canvasPoint);
|
||||
_hoveredElement = hit as BlueprintElementBase;
|
||||
}
|
||||
|
||||
// ===== 鼠标按下 =====
|
||||
|
||||
public override void OnPointerDown(GraphInputTool sender, Vector2 canvasPoint, int mouseButton)
|
||||
{
|
||||
if (Graph == null) return;
|
||||
|
||||
if (mouseButton == 2)
|
||||
{
|
||||
_isDragging = true;
|
||||
_activeDragButton = 2;
|
||||
_dragStartPan = _targetPanOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 鼠标释放 =====
|
||||
|
||||
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)
|
||||
{
|
||||
if (Graph?.Canvas == null) return;
|
||||
|
||||
if (mouseButton == 2)
|
||||
{
|
||||
_targetPanOffset += delta * Config.DragPanSpeed;
|
||||
Graph.MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 滚轮 =====
|
||||
|
||||
public override void OnScroll(GraphInputTool sender, Vector2 canvasPoint, Vector2 scrollDelta)
|
||||
{
|
||||
if (Graph == null) return;
|
||||
|
||||
float oldZoom = _targetZoomLevel;
|
||||
|
||||
_targetZoomLevel = Mathf.Clamp(
|
||||
_targetZoomLevel + scrollDelta.y / Config.ZoomDivisor,
|
||||
Graph.Canvas.MinZoom, Graph.Canvas.MaxZoom);
|
||||
|
||||
if (!Mathf.Approximately(oldZoom, _targetZoomLevel))
|
||||
{
|
||||
_targetPanOffset += canvasPoint * (oldZoom - _targetZoomLevel);
|
||||
Graph.MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 快捷键 =====
|
||||
|
||||
public override void OnAction(GraphInputTool sender, string actionName)
|
||||
{
|
||||
if (Graph?.Canvas == null) return;
|
||||
|
||||
switch (actionName)
|
||||
{
|
||||
case BlueprintInputConstants.FocusHome:
|
||||
ResetView();
|
||||
break;
|
||||
case BlueprintInputConstants.Undo:
|
||||
break;
|
||||
case BlueprintInputConstants.Redo:
|
||||
break;
|
||||
case BlueprintInputConstants.NavigateParent:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 辅助 =====
|
||||
|
||||
public void ResetView()
|
||||
{
|
||||
_targetPanOffset = Vector2.zero;
|
||||
_targetZoomLevel = 1f;
|
||||
Graph?.MarkDirty();
|
||||
}
|
||||
|
||||
private void SelectElement(BlueprintElementBase element)
|
||||
{
|
||||
_selectedElement = element;
|
||||
}
|
||||
|
||||
/// <summary>当前悬停的元素(可能为 null)</summary>
|
||||
public BlueprintElementBase HoveredElement => _hoveredElement;
|
||||
|
||||
/// <summary>当前选中的元素(可能为 null)</summary>
|
||||
public BlueprintElementBase SelectedElement => _selectedElement;
|
||||
|
||||
// ===== 以鼠标焦点为中心缩放(键盘调用 — 自行读取鼠标位置) =====
|
||||
|
||||
private void ApplyZoomFocus(ref Vector2 panOffset, float newZoom, float oldZoom)
|
||||
{
|
||||
if (Graph?.Canvas == null) return;
|
||||
|
||||
// 通过 BlueprintUGUIInputManager 获取统一鼠标位置(已被 BlueprintInputReceiver 每帧刷新)
|
||||
Vector2 canvasCursor = Graph.Canvas.ScreenToCanvas(BlueprintUGUIInputManager.MousePosition);
|
||||
panOffset += canvasCursor * (oldZoom - newZoom);
|
||||
}
|
||||
|
||||
// =====(旧 ZoomFocusAdjust 已删除 — 替代为 ApplyZoomFocus,OnScroll 直接内联 canvasPoint 计算)=====
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user