#if UNITY_EDITOR
|
|
using System;
|
|
using System.Reflection;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
public static class WindowHelper
|
|
{
|
|
private class R_EditorWindow
|
|
{
|
|
private EditorWindow m_instance;
|
|
private System.Type m_type;
|
|
|
|
public R_EditorWindow( EditorWindow instance )
|
|
{
|
|
m_instance = instance;
|
|
m_type = instance.GetType();
|
|
}
|
|
|
|
public object Parent
|
|
{
|
|
get
|
|
{
|
|
var field = m_type.GetField( "m_Parent", BindingFlags.Instance | BindingFlags.NonPublic );
|
|
return field.GetValue( m_instance );
|
|
}
|
|
}
|
|
|
|
public object Docked
|
|
{
|
|
get
|
|
{
|
|
var property = m_type.GetProperty( "docked", BindingFlags.Instance | BindingFlags.NonPublic );
|
|
return property.GetValue( m_instance, null );
|
|
}
|
|
}
|
|
}
|
|
|
|
private class R_DockArea
|
|
{
|
|
private object m_instance;
|
|
private System.Type m_type;
|
|
|
|
public R_DockArea( object instance )
|
|
{
|
|
m_instance = instance;
|
|
m_type = instance.GetType();
|
|
}
|
|
|
|
public object Window
|
|
{
|
|
get
|
|
{
|
|
var property = m_type.GetProperty( "window", BindingFlags.Instance | BindingFlags.Public );
|
|
return property.GetValue( m_instance, null );
|
|
}
|
|
}
|
|
|
|
public object ActualView
|
|
{
|
|
get
|
|
{
|
|
var field = m_type.GetField( "m_ActualView", BindingFlags.Instance | BindingFlags.NonPublic );
|
|
return field.GetValue( m_instance );
|
|
}
|
|
}
|
|
|
|
public object OriginalDragSource
|
|
{
|
|
set
|
|
{
|
|
var field = m_type.GetField( "s_OriginalDragSource", BindingFlags.Static | BindingFlags.NonPublic );
|
|
field.SetValue( null, value );
|
|
}
|
|
}
|
|
|
|
|
|
public void AddTab( EditorWindow pane )
|
|
{
|
|
#if UNITY_2018_3_OR_NEWER
|
|
var method = m_type.GetMethod( "AddTab", BindingFlags.Instance | BindingFlags.Public, null, new System.Type[] { typeof( EditorWindow ), typeof( bool ) }, null );
|
|
method.Invoke( m_instance, new object[] { pane, true } );
|
|
#else
|
|
var method = m_type.GetMethod( "AddTab", BindingFlags.Instance | BindingFlags.Public, null, new System.Type[] { typeof( EditorWindow ) }, null );
|
|
method.Invoke( m_instance, new object[] { pane } );
|
|
#endif
|
|
}
|
|
|
|
public void RemoveTab( EditorWindow pane )
|
|
{
|
|
var method = m_type.GetMethod( "RemoveTab", BindingFlags.Instance | BindingFlags.Public, null, new System.Type[] { typeof( EditorWindow ) }, null );
|
|
method.Invoke( m_instance, new object[] { pane } );
|
|
}
|
|
}
|
|
|
|
private class R_ContainerWindow
|
|
{
|
|
private object m_instance;
|
|
private System.Type m_type;
|
|
|
|
public R_ContainerWindow( object instance )
|
|
{
|
|
m_instance = instance;
|
|
m_type = instance.GetType();
|
|
}
|
|
|
|
public object RootSplitView
|
|
{
|
|
get
|
|
{
|
|
var property = m_type.GetProperty( "rootSplitView", BindingFlags.Instance | BindingFlags.Public );
|
|
return property.GetValue( m_instance, null );
|
|
}
|
|
}
|
|
|
|
public object RootView
|
|
{
|
|
get
|
|
{
|
|
var property = m_type.GetProperty( "rootView", BindingFlags.Instance | BindingFlags.Public );
|
|
return property.GetValue( m_instance, null );
|
|
}
|
|
}
|
|
|
|
public object WindowPtr
|
|
{
|
|
get
|
|
{
|
|
var all = m_type.GetNestedTypes();
|
|
foreach( var item in all )
|
|
{
|
|
Debug.Log( item.Name );
|
|
}
|
|
var property = m_type.GetField( "m_WindowPtr", BindingFlags.Instance | BindingFlags.NonPublic );
|
|
return property.GetValue( m_instance );
|
|
}
|
|
}
|
|
}
|
|
|
|
private class R_SplitView
|
|
{
|
|
private object m_instance;
|
|
private System.Type m_type;
|
|
|
|
public R_SplitView( object instance )
|
|
{
|
|
m_instance = instance;
|
|
m_type = instance.GetType();
|
|
}
|
|
|
|
public object DragOver( EditorWindow child, Vector2 screenPoint )
|
|
{
|
|
var method = m_type.GetMethod( "DragOver", BindingFlags.Instance | BindingFlags.Public );
|
|
return method.Invoke( m_instance, new object[] { child, screenPoint } );
|
|
}
|
|
|
|
public void PerformDrop( EditorWindow child, object dropInfo, Vector2 screenPoint )
|
|
{
|
|
var method = m_type.GetMethod( "PerformDrop", BindingFlags.Instance | BindingFlags.Public );
|
|
method.Invoke( m_instance, new object[] { child, dropInfo, screenPoint } );
|
|
}
|
|
}
|
|
|
|
public enum DockPosition
|
|
{
|
|
Left,
|
|
Top,
|
|
Right,
|
|
Bottom
|
|
}
|
|
|
|
public static bool IsDocked( this EditorWindow wnd )
|
|
{
|
|
var parent = new R_EditorWindow( wnd );
|
|
return (bool)parent.Docked;
|
|
}
|
|
|
|
public static void Undock( this EditorWindow wnd )
|
|
{
|
|
var parent = new R_EditorWindow( wnd );
|
|
var dockArea = new R_DockArea( parent.Parent );
|
|
dockArea.RemoveTab( wnd );
|
|
wnd.Show( true );
|
|
}
|
|
|
|
public static void RemoveTab( this EditorWindow wnd )
|
|
{
|
|
var parent = new R_EditorWindow( wnd );
|
|
var dockArea = new R_DockArea( parent.Parent );
|
|
dockArea.RemoveTab( wnd );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Docks the second window to the first window at the given position
|
|
/// </summary>
|
|
public static void Dock( this EditorWindow wnd, EditorWindow other, DockPosition position )
|
|
{
|
|
var mousePosition = GetFakeMousePosition( wnd, position );
|
|
|
|
var parent = new R_EditorWindow( wnd );
|
|
var child = new R_EditorWindow( other );
|
|
var dockArea = new R_DockArea( parent.Parent );
|
|
var containerWindow = new R_ContainerWindow( dockArea.Window );
|
|
var splitView = new R_SplitView( containerWindow.RootSplitView );
|
|
var dropInfo = splitView.DragOver( other, mousePosition );
|
|
dockArea.OriginalDragSource = child.Parent;
|
|
splitView.PerformDrop( other, dropInfo, mousePosition );
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Adds the the second window as a tab at the end of the first window tab list
|
|
/// </summary>
|
|
/// <param name="existingWindow"></param>
|
|
/// <param name="newWindow"></param>
|
|
public static void AddTab( this EditorWindow existingWindow, EditorWindow newWindow )
|
|
{
|
|
var parent = new R_EditorWindow( existingWindow );
|
|
var child = new R_EditorWindow( newWindow );
|
|
var dockArea = new R_DockArea( parent.Parent );
|
|
dockArea.OriginalDragSource = child.Parent;
|
|
dockArea.AddTab( newWindow );
|
|
}
|
|
|
|
private static Vector2 GetFakeMousePosition( EditorWindow wnd, DockPosition position )
|
|
{
|
|
Vector2 mousePosition = Vector2.zero;
|
|
|
|
// The 20 is required to make the docking work.
|
|
// Smaller values might not work when faking the mouse position.
|
|
switch ( position )
|
|
{
|
|
case DockPosition.Left:
|
|
mousePosition = new Vector2( 20, wnd.position.size.y / 2 );
|
|
break;
|
|
case DockPosition.Top:
|
|
mousePosition = new Vector2( wnd.position.size.x / 2, 20 );
|
|
break;
|
|
case DockPosition.Right:
|
|
mousePosition = new Vector2( wnd.position.size.x - 20, wnd.position.size.y / 2 );
|
|
break;
|
|
case DockPosition.Bottom:
|
|
mousePosition = new Vector2( wnd.position.size.x / 2, wnd.position.size.y - 20 );
|
|
break;
|
|
}
|
|
|
|
return GUIUtility.GUIToScreenPoint( mousePosition );
|
|
}
|
|
}
|
|
#endif
|