using System; using UnityEngine; using UnityEngine.UIElements; namespace UnityEditor.Rendering { public partial class RenderGraphViewer { class PanManipulator : MouseManipulator { public const string k_ContentPanClassName = "content-pan"; // Minimum distance the mouse must be dragged to be considered a drag action const float k_MinDragDistance = 5.0f; Vector2 m_PanStartPosition; Vector2 m_OriginalScrollOffset; ScrollView m_TargetScrollView; RenderGraphViewer m_Viewer; // Whether drag action is currently active public bool dragActive { get; private set; } // Whether a new drag action can be started public bool canStartDragging { get; set; } = true; public PanManipulator(RenderGraphViewer viewer) { m_Viewer = viewer; dragActive = false; activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse }); activators.Add(new ManipulatorActivationFilter { button = MouseButton.MiddleMouse }); } protected override void RegisterCallbacksOnTarget() { m_TargetScrollView = target as ScrollView; if (m_TargetScrollView == null) throw new InvalidOperationException( $"{nameof(RenderGraphViewer)}.{nameof(PanManipulator)} can only be added to a {nameof(ScrollView)}"); target.RegisterCallback(OnMouseDown); target.RegisterCallback(OnMouseMove); target.RegisterCallback(OnMouseUp); target.RegisterCallback(OnMouseCaptureOutEvent); } protected override void UnregisterCallbacksFromTarget() { target.UnregisterCallback(OnMouseDown); target.UnregisterCallback(OnMouseMove); target.UnregisterCallback(OnMouseUp); target.UnregisterCallback(OnMouseCaptureOutEvent); } void OnMouseDown(MouseDownEvent e) { if (dragActive) { e.StopImmediatePropagation(); return; } if (!canStartDragging || !CanStartManipulation(e)) return; m_PanStartPosition = e.localMousePosition; m_OriginalScrollOffset = m_TargetScrollView.scrollOffset; dragActive = true; target.CaptureMouse(); target.AddToClassList(k_ContentPanClassName); e.StopImmediatePropagation(); } Vector2 Diff(Vector2 localMousePosition) { return localMousePosition - m_PanStartPosition; } protected void OnMouseMove(MouseMoveEvent e) { if (!dragActive) return; // Subtract the diff because we want view content to pan in the opposite direction of the movement m_TargetScrollView.scrollOffset = m_OriginalScrollOffset - Diff(e.localMousePosition); e.StopPropagation(); } protected void OnMouseUp(MouseUpEvent e) { if (!dragActive || !CanStopManipulation(e)) return; StopManipulation(); e.StopPropagation(); // If it was just a click, treat it as a deselect if (Diff(e.localMousePosition).magnitude < k_MinDragDistance) { m_Viewer.DeselectPass(); } } protected void OnMouseCaptureOutEvent(MouseCaptureOutEvent evt) { if (!dragActive) return; StopManipulation(); } void StopManipulation() { dragActive = false; target.ReleaseMouse(); target.RemoveFromClassList(k_ContentPanClassName); } } } }