A game about forced loneliness, made by TACStudios
at master 182 lines 6.8 kB view raw
1using System; 2using UnityEngine; 3using UnityEditor.Experimental.GraphView; 4using UnityEngine.UIElements; 5using UnityEngine.UIElements.StyleSheets; 6 7namespace UnityEditor.ShaderGraph.Drawing 8{ 9 class WindowDraggable : MouseManipulator 10 { 11 bool m_Active; 12 13 WindowDockingLayout m_WindowDockingLayout; 14 15 Vector2 m_LocalMosueOffset; 16 17 VisualElement m_Handle; 18 GraphView m_GraphView; 19 20 public Action OnDragFinished; 21 22 public WindowDraggable(VisualElement handle = null, VisualElement container = null) 23 { 24 m_Handle = handle; 25 m_Active = false; 26 m_WindowDockingLayout = new WindowDockingLayout(); 27 28 if (container != null) 29 container.RegisterCallback<GeometryChangedEvent>(OnParentGeometryChanged); 30 } 31 32 protected override void RegisterCallbacksOnTarget() 33 { 34 if (m_Handle == null) 35 m_Handle = target; 36 m_Handle.RegisterCallback(new EventCallback<MouseDownEvent>(OnMouseDown), TrickleDownEnum.NoTrickleDown); 37 m_Handle.RegisterCallback(new EventCallback<MouseMoveEvent>(OnMouseMove), TrickleDownEnum.NoTrickleDown); 38 m_Handle.RegisterCallback(new EventCallback<MouseUpEvent>(OnMouseUp), TrickleDownEnum.NoTrickleDown); 39 target.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged); 40 } 41 42 protected override void UnregisterCallbacksFromTarget() 43 { 44 m_Handle.UnregisterCallback(new EventCallback<MouseDownEvent>(OnMouseDown), TrickleDownEnum.NoTrickleDown); 45 m_Handle.UnregisterCallback(new EventCallback<MouseMoveEvent>(OnMouseMove), TrickleDownEnum.NoTrickleDown); 46 m_Handle.UnregisterCallback(new EventCallback<MouseUpEvent>(OnMouseUp), TrickleDownEnum.NoTrickleDown); 47 target.UnregisterCallback<GeometryChangedEvent>(OnGeometryChanged); 48 if (m_GraphView != null) 49 m_GraphView.UnregisterCallback<GeometryChangedEvent>(OnGeometryChanged); 50 } 51 52 void OnMouseDown(MouseDownEvent evt) 53 { 54 m_Active = true; 55 56 VisualElement parent = target.parent; 57 while (parent != null && !(parent is GraphView)) 58 parent = parent.parent; 59 m_GraphView = parent as GraphView; 60 61 if (m_GraphView != null) 62 m_GraphView.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged); 63 64 // m_LocalMouseOffset is offset from the target element's (0, 0) to the 65 // to the mouse position. 66 m_LocalMosueOffset = m_Handle.WorldToLocal(evt.mousePosition); 67 68 m_Handle.CaptureMouse(); 69 evt.StopImmediatePropagation(); 70 } 71 72 void OnMouseMove(MouseMoveEvent evt) 73 { 74 if (m_Active) 75 { 76 // The mouse position of is corrected according to the offset within the target 77 // element (m_LocalWorldOffset) to set the position relative to the mouse position 78 // when the dragging started. 79 Vector2 position = target.parent.WorldToLocal(evt.mousePosition) - m_LocalMosueOffset; 80 81 // Make sure that the object remains in the parent window 82 position.x = Mathf.Clamp(position.x, 0f, target.parent.layout.width - target.layout.width); 83 position.y = Mathf.Clamp(position.y, 0f, target.parent.layout.height - target.layout.height); 84 85 // While moving, use only the left and top position properties, 86 // while keeping the others NaN to not affect layout. 87 target.style.left = position.x; 88 target.style.top = position.y; 89 target.style.right = float.NaN; 90 target.style.bottom = float.NaN; 91 } 92 } 93 94 void OnMouseUp(MouseUpEvent evt) 95 { 96 bool emitDragFinishedEvent = m_Active; 97 98 m_Active = false; 99 100 if (m_Handle.HasMouseCapture()) 101 { 102 m_Handle.ReleaseMouse(); 103 } 104 105 evt.StopImmediatePropagation(); 106 107 // Recalculate which corner to dock to 108 m_WindowDockingLayout.CalculateDockingCornerAndOffset(target.layout, target.parent.layout); 109 m_WindowDockingLayout.ClampToParentWindow(); 110 111 // Use the docking results to figure which of left/right and top/bottom needs to be set. 112 m_WindowDockingLayout.ApplyPosition(target); 113 114 // Signal that the dragging has finished. 115 if (emitDragFinishedEvent && OnDragFinished != null) 116 OnDragFinished(); 117 } 118 119 void OnGeometryChanged(GeometryChangedEvent geometryChangedEvent) 120 { 121 // Make the target clamp to the border of the window if the 122 // parent window becomes too small to contain it. 123 if (target.parent.layout.width < target.layout.width) 124 { 125 if (m_WindowDockingLayout.dockingLeft) 126 { 127 target.style.left = 0f; 128 target.style.right = float.NaN; 129 } 130 else 131 { 132 target.style.left = float.NaN; 133 target.style.right = 0f; 134 } 135 } 136 137 if (target.parent.layout.height < target.layout.height) 138 { 139 if (m_WindowDockingLayout.dockingTop) 140 { 141 target.style.top = 0f; 142 target.style.bottom = float.NaN; 143 } 144 else 145 { 146 target.style.top = float.NaN; 147 target.style.bottom = 0f; 148 } 149 } 150 } 151 152 void OnParentGeometryChanged(GeometryChangedEvent geometryChangedEvent) 153 { 154 // Check if the parent window can no longer contain the target window. 155 // If the window is out of bounds, make one edge clamp to the border of the 156 // parent window. 157 if (target.layout.xMin < 0f) 158 { 159 target.style.left = 0f; 160 target.style.right = float.NaN; 161 } 162 163 if (target.layout.xMax > geometryChangedEvent.newRect.width) 164 { 165 target.style.left = float.NaN; 166 target.style.right = 0f; 167 } 168 169 if (target.layout.yMax > geometryChangedEvent.newRect.height) 170 { 171 target.style.top = float.NaN; 172 target.style.bottom = 0f; 173 } 174 175 if (target.layout.yMin < 0f) 176 { 177 target.style.top = 0f; 178 target.style.bottom = float.NaN; 179 } 180 } 181 } 182}