Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

250 lines
6.4 KiB

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