WindowHelper.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #if UNITY_EDITOR
  2. using System;
  3. using System.Reflection;
  4. using UnityEditor;
  5. using UnityEngine;
  6. namespace AmplifyShaderEditor
  7. {
  8. public static class WindowHelper
  9. {
  10. private class R_EditorWindow
  11. {
  12. private EditorWindow m_instance;
  13. private System.Type m_type;
  14. public R_EditorWindow( EditorWindow instance )
  15. {
  16. m_instance = instance;
  17. m_type = instance.GetType();
  18. }
  19. public object Parent
  20. {
  21. get
  22. {
  23. var field = m_type.GetField( "m_Parent", BindingFlags.Instance | BindingFlags.NonPublic );
  24. return field.GetValue( m_instance );
  25. }
  26. }
  27. public object Docked
  28. {
  29. get
  30. {
  31. var property = m_type.GetProperty( "docked", BindingFlags.Instance | BindingFlags.NonPublic );
  32. return property.GetValue( m_instance, null );
  33. }
  34. }
  35. }
  36. private class R_DockArea
  37. {
  38. private object m_instance;
  39. private System.Type m_type;
  40. public R_DockArea( object instance )
  41. {
  42. m_instance = instance;
  43. m_type = instance.GetType();
  44. }
  45. public object Window
  46. {
  47. get
  48. {
  49. var property = m_type.GetProperty( "window", BindingFlags.Instance | BindingFlags.Public );
  50. return property.GetValue( m_instance, null );
  51. }
  52. }
  53. public object ActualView
  54. {
  55. get
  56. {
  57. var field = m_type.GetField( "m_ActualView", BindingFlags.Instance | BindingFlags.NonPublic );
  58. return field.GetValue( m_instance );
  59. }
  60. }
  61. public object OriginalDragSource
  62. {
  63. set
  64. {
  65. var field = m_type.GetField( "s_OriginalDragSource", BindingFlags.Static | BindingFlags.NonPublic );
  66. field.SetValue( null, value );
  67. }
  68. }
  69. public void AddTab( EditorWindow pane )
  70. {
  71. var method = m_type.GetMethod( "AddTab", BindingFlags.Instance | BindingFlags.Public, null, new System.Type[] { typeof( EditorWindow ), typeof( bool ) }, null );
  72. if( method != null )
  73. method.Invoke( m_instance, new object[] { pane, true } );
  74. }
  75. public void RemoveTab( EditorWindow pane )
  76. {
  77. if( !pane.maximized )
  78. {
  79. var method = m_type.GetMethod( "RemoveTab", BindingFlags.Instance | BindingFlags.Public, null, new System.Type[] { typeof( EditorWindow ) }, null );
  80. if( method != null )
  81. method.Invoke( m_instance, new object[] { pane } );
  82. }
  83. }
  84. }
  85. private class R_ContainerWindow
  86. {
  87. private object m_instance;
  88. private System.Type m_type;
  89. public R_ContainerWindow( object instance )
  90. {
  91. m_instance = instance;
  92. m_type = instance.GetType();
  93. }
  94. public object RootSplitView
  95. {
  96. get
  97. {
  98. var property = m_type.GetProperty( "rootSplitView", BindingFlags.Instance | BindingFlags.Public );
  99. return property.GetValue( m_instance, null );
  100. }
  101. }
  102. public object RootView
  103. {
  104. get
  105. {
  106. var property = m_type.GetProperty( "rootView", BindingFlags.Instance | BindingFlags.Public );
  107. return property.GetValue( m_instance, null );
  108. }
  109. }
  110. public object WindowPtr
  111. {
  112. get
  113. {
  114. var all = m_type.GetNestedTypes();
  115. foreach( var item in all )
  116. {
  117. Debug.Log( item.Name );
  118. }
  119. var property = m_type.GetField( "m_WindowPtr", BindingFlags.Instance | BindingFlags.NonPublic );
  120. return property.GetValue( m_instance );
  121. }
  122. }
  123. }
  124. private class R_SplitView
  125. {
  126. private object m_instance;
  127. private System.Type m_type;
  128. public R_SplitView( object instance )
  129. {
  130. m_instance = instance;
  131. m_type = instance.GetType();
  132. }
  133. public object DragOver( EditorWindow child, Vector2 screenPoint )
  134. {
  135. var method = m_type.GetMethod( "DragOver", BindingFlags.Instance | BindingFlags.Public );
  136. return method.Invoke( m_instance, new object[] { child, screenPoint } );
  137. }
  138. public void PerformDrop( EditorWindow child, object dropInfo, Vector2 screenPoint )
  139. {
  140. var method = m_type.GetMethod( "PerformDrop", BindingFlags.Instance | BindingFlags.Public );
  141. method.Invoke( m_instance, new object[] { child, dropInfo, screenPoint } );
  142. }
  143. }
  144. public enum DockPosition
  145. {
  146. Left,
  147. Top,
  148. Right,
  149. Bottom
  150. }
  151. public static bool IsDocked( this EditorWindow wnd )
  152. {
  153. #if UNITY_2020_2_OR_NEWER
  154. return wnd.docked;
  155. #else
  156. var parent = new R_EditorWindow( wnd );
  157. return (bool)parent.Docked;
  158. #endif
  159. }
  160. public static void Undock( this EditorWindow wnd )
  161. {
  162. var parent = new R_EditorWindow( wnd );
  163. var dockArea = new R_DockArea( parent.Parent );
  164. dockArea.RemoveTab( wnd );
  165. wnd.Show( true );
  166. }
  167. public static void RemoveTab( this EditorWindow wnd )
  168. {
  169. var parent = new R_EditorWindow( wnd );
  170. var dockArea = new R_DockArea( parent.Parent );
  171. dockArea.RemoveTab( wnd );
  172. }
  173. /// <summary>
  174. /// Docks the second window to the first window at the given position
  175. /// </summary>
  176. public static void Dock( this EditorWindow wnd, EditorWindow other, DockPosition position )
  177. {
  178. var mousePosition = GetFakeMousePosition( wnd, position );
  179. var parent = new R_EditorWindow( wnd );
  180. var child = new R_EditorWindow( other );
  181. var dockArea = new R_DockArea( parent.Parent );
  182. var containerWindow = new R_ContainerWindow( dockArea.Window );
  183. var splitView = new R_SplitView( containerWindow.RootSplitView );
  184. var dropInfo = splitView.DragOver( other, mousePosition );
  185. dockArea.OriginalDragSource = child.Parent;
  186. splitView.PerformDrop( other, dropInfo, mousePosition );
  187. }
  188. /// <summary>
  189. /// Adds the the second window as a tab at the end of the first window tab list
  190. /// </summary>
  191. /// <param name="existingWindow"></param>
  192. /// <param name="newWindow"></param>
  193. public static void AddTab( this EditorWindow existingWindow, EditorWindow newWindow )
  194. {
  195. var parent = new R_EditorWindow( existingWindow );
  196. var child = new R_EditorWindow( newWindow );
  197. var dockArea = new R_DockArea( parent.Parent );
  198. dockArea.OriginalDragSource = child.Parent;
  199. dockArea.AddTab( newWindow );
  200. }
  201. private static Vector2 GetFakeMousePosition( EditorWindow wnd, DockPosition position )
  202. {
  203. Vector2 mousePosition = Vector2.zero;
  204. // The 20 is required to make the docking work.
  205. // Smaller values might not work when faking the mouse position.
  206. switch ( position )
  207. {
  208. case DockPosition.Left:
  209. mousePosition = new Vector2( 20, wnd.position.size.y / 2 );
  210. break;
  211. case DockPosition.Top:
  212. mousePosition = new Vector2( wnd.position.size.x / 2, 20 );
  213. break;
  214. case DockPosition.Right:
  215. mousePosition = new Vector2( wnd.position.size.x - 20, wnd.position.size.y / 2 );
  216. break;
  217. case DockPosition.Bottom:
  218. mousePosition = new Vector2( wnd.position.size.x / 2, wnd.position.size.y - 20 );
  219. break;
  220. }
  221. return GUIUtility.GUIToScreenPoint( mousePosition );
  222. }
  223. }
  224. }
  225. #endif