1518 lines
42 KiB
C#
1518 lines
42 KiB
C#
#if UNITY_EDITOR
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEditor.ShortcutManagement;
|
|
using System.Reflection;
|
|
using System.Linq;
|
|
using UnityEngine.UIElements;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEditor.SceneManagement;
|
|
using System.Diagnostics;
|
|
using Type = System.Type;
|
|
using Delegate = System.Delegate;
|
|
using Action = System.Action;
|
|
using static VTabs.Libs.VUtils;
|
|
using static VTabs.Libs.VGUI;
|
|
|
|
|
|
|
|
|
|
namespace VTabs
|
|
{
|
|
public static class VTabs
|
|
{
|
|
|
|
static void UpdateGUIs()
|
|
{
|
|
foreach (var dockArea in allDockAreas)
|
|
if (!guis_byDockArea.ContainsKey(dockArea))
|
|
guis_byDockArea[dockArea] = new VTabsGUI(dockArea);
|
|
|
|
foreach (var dockArea in guis_byDockArea.Keys.ToList().Where(r => !r))
|
|
guis_byDockArea.Remove(dockArea);
|
|
|
|
|
|
|
|
foreach (var gui in guis_byDockArea.Values)
|
|
{
|
|
gui.UpdateScrollAnimation();
|
|
gui.UpdateLockButtonHiding();
|
|
}
|
|
|
|
|
|
// foreach (var dockArea in allDockAreas)
|
|
// // dockArea.GetMemberValue<RectOffset>("m_BorderSize").Log(r => dockArea.name + ": " + r.left);
|
|
// dockArea.GetMemberValue<Rect>("m_TabAreaRect").Log(r => dockArea.name + ": " + r.x);
|
|
|
|
|
|
}
|
|
|
|
public static Dictionary<Object, VTabsGUI> guis_byDockArea = new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void UpdateStyleSheet()
|
|
{
|
|
if (!Application.unityVersion.StartsWith("6000")) return;
|
|
|
|
|
|
void updatePluginFolderPath()
|
|
{
|
|
if (AssetDatabase.LoadAssetAtPath<Object>(pluginFolderPath.CombinePath("VTabs.cs")) is not null) return;
|
|
|
|
|
|
var mainScriptPath = GetScriptPath(nameof(VTabs));
|
|
|
|
ProjectPrefs.SetString("vTabs-plugin-folder-path", mainScriptPath.GetParentPath());
|
|
|
|
}
|
|
|
|
void generate()
|
|
{
|
|
var s = "";
|
|
|
|
void addComment()
|
|
{
|
|
s +=
|
|
@"
|
|
/* This file is generated by vTabs to modify tab style */
|
|
/* Feel free to remove it from version control */
|
|
";
|
|
}
|
|
|
|
void addLargeTabs()
|
|
{
|
|
if (!VTabsMenu.largeTabStyleEnabled) return;
|
|
|
|
s +=
|
|
@"
|
|
/* tab text */
|
|
.dragtab
|
|
{
|
|
padding-left: 10px;
|
|
}
|
|
|
|
/* tab itself */
|
|
.tab
|
|
{
|
|
padding-right: 27px;
|
|
}
|
|
";
|
|
}
|
|
void addNeatTabs()
|
|
{
|
|
if (!VTabsMenu.neatTabStyleEnabled) return;
|
|
|
|
s +=
|
|
@"
|
|
/* tab text */
|
|
.dragtab
|
|
{
|
|
padding-left: 10px;
|
|
}
|
|
|
|
/* tab itself */
|
|
.tab
|
|
{
|
|
padding-right: -1px;
|
|
}
|
|
";
|
|
}
|
|
|
|
void addClassicBackground_dark()
|
|
{
|
|
if (!VTabsMenu.classicBackgroundEnabled) return;
|
|
if (!isDarkTheme) return;
|
|
|
|
s +=
|
|
@"
|
|
/* background */
|
|
.dockarea
|
|
{
|
|
background-color: #262626;
|
|
}
|
|
|
|
/* tab text */
|
|
.dragtab
|
|
{
|
|
color: #dedede;
|
|
}
|
|
|
|
/* top and bottom bars */
|
|
.AppToolbar
|
|
{
|
|
background-color: #181818;
|
|
}
|
|
";
|
|
}
|
|
void addClassicBackground_light()
|
|
{
|
|
if (!VTabsMenu.classicBackgroundEnabled) return;
|
|
if (isDarkTheme) return;
|
|
|
|
s +=
|
|
@"
|
|
/* background */
|
|
.dockarea
|
|
{
|
|
background-color: #a9a9a9;
|
|
}
|
|
|
|
/* top and bottom bars */
|
|
.AppToolbar
|
|
{
|
|
background-color: #888888;
|
|
}
|
|
";
|
|
}
|
|
void addGreyBackground()
|
|
{
|
|
if (!VTabsMenu.greyBackgroundEnabled) return;
|
|
|
|
s +=
|
|
@"
|
|
/* background */
|
|
.dockarea
|
|
{
|
|
background-color: #222222;
|
|
}
|
|
|
|
/* tab text */
|
|
.dragtab
|
|
{
|
|
color: #dedede;
|
|
}
|
|
|
|
/* top and bottom bars */
|
|
.AppToolbar
|
|
{
|
|
background-color: #222222;
|
|
}
|
|
";
|
|
}
|
|
|
|
void save()
|
|
{
|
|
styleSheetPath.EnsureDirExists();
|
|
|
|
System.IO.File.WriteAllText(styleSheetPath, s);
|
|
|
|
AssetDatabase.ImportAsset(styleSheetPath);
|
|
|
|
}
|
|
void addMetadata()
|
|
{
|
|
var importer = AssetImporter.GetAtPath(styleSheetPath);
|
|
|
|
importer.userData = VTabsMenu.tabStyle + " " + VTabsMenu.backgroundStyle + " " + (isDarkTheme ? 1 : 0);
|
|
|
|
importer.Dirty();
|
|
importer.SaveAndReimport();
|
|
|
|
}
|
|
|
|
|
|
addComment();
|
|
|
|
addLargeTabs();
|
|
addNeatTabs();
|
|
|
|
addClassicBackground_dark();
|
|
addClassicBackground_light();
|
|
addGreyBackground();
|
|
|
|
save();
|
|
addMetadata();
|
|
|
|
EditorUtility.RequestScriptReload();
|
|
|
|
}
|
|
void delete()
|
|
{
|
|
System.IO.Directory.Delete(styleSheetsFolderPath, recursive: true);
|
|
|
|
System.IO.File.Delete(styleSheetsFolderPath + ".meta");
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
}
|
|
void update()
|
|
{
|
|
var importer = AssetImporter.GetAtPath(styleSheetPath);
|
|
|
|
if (importer.userData == null || importer.userData.Length != 5) return;
|
|
|
|
|
|
var tabStyle = (int)char.GetNumericValue(importer.userData[0]);
|
|
var backgroundStyle = (int)char.GetNumericValue(importer.userData[2]);
|
|
var wasDarkTheme = (int)char.GetNumericValue(importer.userData[4]) == 1;
|
|
|
|
if (tabStyle != VTabsMenu.tabStyle || backgroundStyle != VTabsMenu.backgroundStyle || isDarkTheme != wasDarkTheme)
|
|
generate();
|
|
|
|
}
|
|
|
|
|
|
updatePluginFolderPath();
|
|
|
|
var hasStyleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>(styleSheetPath) != null;
|
|
var shouldHaveStyleSheet = (VTabsMenu.tabStyle != 0 || VTabsMenu.backgroundStyle != 0) && !VTabsMenu.pluginDisabled;
|
|
|
|
|
|
if (shouldHaveStyleSheet && !hasStyleSheet) generate();
|
|
if (!shouldHaveStyleSheet && hasStyleSheet) delete();
|
|
|
|
if (shouldHaveStyleSheet && hasStyleSheet) update();
|
|
|
|
}
|
|
|
|
static string pluginFolderPath => ProjectPrefs.GetString("vTabs-plugin-folder-path");
|
|
static string styleSheetsFolderPath => pluginFolderPath.CombinePath("StyleSheets");
|
|
static string styleSheetPath => pluginFolderPath.CombinePath("StyleSheets/Extensions/common.uss");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void Shortcuts() // globalEventHandler
|
|
{
|
|
if (!curEvent.isKeyDown) return;
|
|
|
|
void addTab()
|
|
{
|
|
if (curEvent.keyCode != KeyCode.T) return;
|
|
if (curEvent.modifiers != EventModifiers.Control
|
|
&& curEvent.modifiers != EventModifiers.Command) return;
|
|
|
|
if (!VTabsMenu.addTabShortcutEnabled) return;
|
|
|
|
if (EditorWindow.mouseOverWindow.GetDockArea() is not Object dockArea) return;
|
|
if (!guis_byDockArea.TryGetValue(dockArea, out var gui)) return;
|
|
|
|
|
|
VTabsAddTabWindow.Open(dockArea);
|
|
|
|
EditorWindow.mouseOverWindow.Repaint(); // for + button to light up
|
|
|
|
curEvent.Use();
|
|
|
|
}
|
|
void closeTab()
|
|
{
|
|
if (curEvent.keyCode != KeyCode.W) return;
|
|
if (curEvent.modifiers != EventModifiers.Control
|
|
&& curEvent.modifiers != EventModifiers.Command) return;
|
|
|
|
if (!VTabsMenu.closeTabShortcutEnabled) return;
|
|
|
|
if (EditorWindow.mouseOverWindow.GetDockArea() is not Object dockArea) return;
|
|
if (!guis_byDockArea.TryGetValue(dockArea, out var gui)) return;
|
|
|
|
if (gui.tabs.Count == 1) return;
|
|
|
|
|
|
gui.CloseTab(gui.activeTab);
|
|
|
|
curEvent.Use();
|
|
|
|
}
|
|
void reopenTab()
|
|
{
|
|
if (curEvent.keyCode != KeyCode.T) return;
|
|
if (curEvent.modifiers != (EventModifiers.Command | EventModifiers.Shift)
|
|
&& curEvent.modifiers != (EventModifiers.Control | EventModifiers.Shift)) return;
|
|
|
|
if (!VTabsMenu.reopenTabShortcutEnabled) return;
|
|
|
|
if (EditorWindow.mouseOverWindow.GetDockArea() is not Object dockArea) return;
|
|
if (!guis_byDockArea.TryGetValue(dockArea, out var gui)) return;
|
|
|
|
|
|
gui.ReopenClosedTab();
|
|
|
|
curEvent.Use();
|
|
|
|
}
|
|
|
|
addTab();
|
|
closeTab();
|
|
reopenTab();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void UpdateBrowserTitle(EditorWindow browser)
|
|
{
|
|
if (mi_VFavorites_CanBrowserBeWrapped != null && mi_VFavorites_CanBrowserBeWrapped.Invoke(null, new[] { browser }).Equals(false)) return;
|
|
|
|
var isLocked = browser.GetMemberValue<bool>("isLocked");
|
|
var isTitleDefault = browser.titleContent.text == "Project";
|
|
|
|
void setLockedTitle()
|
|
{
|
|
if (!isLocked) return;
|
|
|
|
var isOneColumn = browser.GetMemberValue<int>("m_ViewMode") == 0;
|
|
|
|
var path = isOneColumn ? browser.GetLockedFolderPath_oneColumn() : browser.InvokeMethod<string>("GetActiveFolderPath");
|
|
var guid = path.ToGuid();
|
|
|
|
var name = path.GetFilename();
|
|
var icon = EditorGUIUtility.FindTexture("Project");
|
|
|
|
|
|
void getIconFromVFolders()
|
|
{
|
|
if (mi_VFolders_GetIcon == null) return;
|
|
|
|
if (mi_VFolders_GetIcon.Invoke(null, new[] { guid }) is Texture2D iconFromVFolders)
|
|
icon = iconFromVFolders;
|
|
|
|
}
|
|
|
|
getIconFromVFolders();
|
|
|
|
|
|
browser.titleContent = new GUIContent(name, icon);
|
|
|
|
t_DockArea.GetFieldValue<IDictionary>("s_GUIContents").Clear();
|
|
|
|
}
|
|
void setDefaultTitle()
|
|
{
|
|
if (isLocked) return;
|
|
if (isTitleDefault) return;
|
|
|
|
var name = "Project";
|
|
var icon = EditorGUIUtility.FindTexture("Project@2x");
|
|
|
|
browser.titleContent = new GUIContent(name, icon);
|
|
|
|
t_DockArea.GetFieldValue<IDictionary>("s_GUIContents").Clear();
|
|
|
|
}
|
|
|
|
setLockedTitle();
|
|
setDefaultTitle();
|
|
|
|
}
|
|
|
|
static void UpdatePropertyEditorTitle(EditorWindow propertyEditor)
|
|
{
|
|
var obj = propertyEditor.GetMemberValue<Object>("m_InspectedObject");
|
|
|
|
if (!obj) return;
|
|
|
|
|
|
var name = obj is Component component ? GetComponentName(component) : obj.name;
|
|
var sourceIcon = AssetPreview.GetMiniThumbnail(obj);
|
|
var adjustedIcon = sourceIcon;
|
|
|
|
|
|
void getSourceIconFromVHierarchy()
|
|
{
|
|
if (mi_VHierarchy_GetIcon == null) return;
|
|
if (obj is not GameObject gameObject) return;
|
|
|
|
if (mi_VHierarchy_GetIcon.Invoke(null, new[] { gameObject }) is Texture2D iconFromVHierarchy)
|
|
sourceIcon = iconFromVHierarchy;
|
|
|
|
}
|
|
void getAdjustedIcon()
|
|
{
|
|
if (adjustedObjectIconsBySourceIid.TryGetValue(sourceIcon.GetInstanceID(), out adjustedIcon)) return;
|
|
|
|
|
|
adjustedIcon = new Texture2D(sourceIcon.width, sourceIcon.height, sourceIcon.format, sourceIcon.mipmapCount, false);
|
|
adjustedIcon.hideFlags = HideFlags.DontSave;
|
|
adjustedIcon.SetPropertyValue("pixelsPerPoint", (sourceIcon.width / 16f).RoundToInt());
|
|
|
|
Graphics.CopyTexture(sourceIcon, adjustedIcon);
|
|
|
|
|
|
adjustedObjectIconsBySourceIid[sourceIcon.GetInstanceID()] = adjustedIcon;
|
|
|
|
}
|
|
|
|
|
|
getSourceIconFromVHierarchy();
|
|
getAdjustedIcon();
|
|
|
|
propertyEditor.titleContent = new GUIContent(name, adjustedIcon);
|
|
|
|
propertyEditor.SetMemberValue("m_InspectedObject", null); // prevents further title updates from both internal code and vTabs
|
|
|
|
t_DockArea.GetFieldValue<IDictionary>("s_GUIContents").Clear();
|
|
|
|
}
|
|
|
|
|
|
public static void UpdateTitle(EditorWindow window)
|
|
{
|
|
if (window == null) return;
|
|
|
|
var isPropertyEditor = window.GetType() == t_PropertyEditor;
|
|
var isBrowser = window.GetType() == t_ProjectBrowser;
|
|
|
|
if (!isPropertyEditor && !isBrowser) return;
|
|
|
|
|
|
if (isPropertyEditor)
|
|
UpdatePropertyEditorTitle(window);
|
|
|
|
if (isBrowser)
|
|
if (window.GetPropertyValue<bool>("isLocked"))
|
|
UpdateBrowserTitle(window);
|
|
|
|
}
|
|
|
|
static void UpdateAllBrowserTitles()
|
|
{
|
|
foreach (var r in allBrowsers)
|
|
UpdateBrowserTitle(r);
|
|
}
|
|
static void UpdateAllPropertyEditorTitles()
|
|
{
|
|
foreach (var r in allPropertyEditors)
|
|
UpdatePropertyEditorTitle(r);
|
|
}
|
|
|
|
|
|
static Dictionary<int, Texture2D> adjustedObjectIconsBySourceIid = new Dictionary<int, Texture2D>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void WrappedBrowserOnGUI(EditorWindow browser)
|
|
{
|
|
var headerHeight = 26;
|
|
var footerHeight = 21;
|
|
var breadcrubsYOffset = .5f;
|
|
|
|
var headerRect = browser.position.SetPos(0, 0).SetHeight(headerHeight);
|
|
var footerRect = browser.position.SetPos(0, 0).SetHeightFromBottom(footerHeight);
|
|
var listAreaRect = browser.position.SetPos(0, 0).AddHeight(-footerHeight).AddHeightFromBottom(-headerHeight);
|
|
|
|
var breadcrumbsRect = headerRect.AddHeightFromBottom(-breadcrubsYOffset * 2);
|
|
var topGapRect = headerRect.SetHeight(breadcrubsYOffset * 2);
|
|
|
|
var breadcrumbsTint = isDarkTheme ? Greyscale(0, .05f) : Greyscale(0, .02f);
|
|
var topGapColor = isDarkTheme ? Greyscale(.24f, 1) : Greyscale(.8f, 1);
|
|
|
|
var isOneColumn = browser.GetMemberValue<int>("m_ViewMode") == 0;
|
|
|
|
|
|
void setRootForOneColumn()
|
|
{
|
|
if (!isOneColumn) return;
|
|
if (curEvent.isRepaint) return;
|
|
if (browser.GetMemberValue("m_AssetTree") is not object m_AssetTree) return;
|
|
if (m_AssetTree.GetMemberValue("data") is not object data) return;
|
|
|
|
var m_rootInstanceID = data.GetMemberValue<int>("m_rootInstanceID");
|
|
|
|
void setInitial()
|
|
{
|
|
if (m_rootInstanceID != 0) return;
|
|
|
|
var folderPath = browser.GetLockedFolderPath_oneColumn();
|
|
var folderIid = AssetDatabase.LoadAssetAtPath<Object>(folderPath).GetInstanceID();
|
|
|
|
data.SetMemberValue("m_rootInstanceID", folderIid);
|
|
|
|
m_AssetTree.InvokeMethod("ReloadData");
|
|
|
|
}
|
|
void update()
|
|
{
|
|
if (m_rootInstanceID == 0) return;
|
|
|
|
var folderIid = m_rootInstanceID;
|
|
var folderPath = EditorUtility.InstanceIDToObject(folderIid).GetPath();
|
|
|
|
browser.SetLockedFolderPath_oneColumn(folderPath);
|
|
|
|
browser.GetMemberValue("m_SearchFilter")?.SetMemberValue("m_Folders", new[] { folderPath }); // needed for breadcrumbs to display correctly
|
|
|
|
}
|
|
void reset()
|
|
{
|
|
if (browser.GetMemberValue<bool>("isLocked")) return;
|
|
|
|
data.SetMemberValue("m_rootInstanceID", 0);
|
|
browser.SetLockedFolderPath_oneColumn("Assets");
|
|
|
|
m_AssetTree.InvokeMethod("ReloadData");
|
|
|
|
// returns the browser to normal state on unlock
|
|
|
|
}
|
|
|
|
setInitial();
|
|
update();
|
|
reset();
|
|
|
|
}
|
|
void handleFolderChange()
|
|
{
|
|
if (isOneColumn) return;
|
|
|
|
void onBreadcrumbsClick()
|
|
{
|
|
if (!curEvent.isMouseUp) return;
|
|
if (!breadcrumbsRect.IsHovered()) return;
|
|
|
|
browser.RecordUndo();
|
|
|
|
toCallInGUI += () => UpdateBrowserTitle(browser);
|
|
toCallInGUI += () => browser.Repaint();
|
|
|
|
}
|
|
void onDoubleclick()
|
|
{
|
|
if (!curEvent.isMouseDown) return;
|
|
if (curEvent.clickCount != 2) return;
|
|
|
|
browser.RecordUndo();
|
|
|
|
EditorApplication.delayCall += () => UpdateBrowserTitle(browser);
|
|
EditorApplication.delayCall += () => browser.Repaint();
|
|
|
|
}
|
|
void onUndoRedo()
|
|
{
|
|
if (!curEvent.isKeyDown) return;
|
|
if (!curEvent.holdingCmdOrCtrl) return;
|
|
if (curEvent.keyCode != KeyCode.Z) return;
|
|
|
|
var curFolderGuid = browser.InvokeMethod<string>("GetActiveFolderPath").ToGuid();
|
|
|
|
EditorApplication.delayCall += () =>
|
|
{
|
|
var delayedFolderGuid = browser.InvokeMethod<string>("GetActiveFolderPath").ToGuid();
|
|
|
|
if (delayedFolderGuid == curFolderGuid) return;
|
|
|
|
|
|
var folderIid = AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GUIDToAssetPath(delayedFolderGuid)).GetInstanceID();
|
|
|
|
browser.InvokeMethod("SetFolderSelection", new[] { folderIid }, false);
|
|
|
|
UpdateBrowserTitle(browser);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
onBreadcrumbsClick();
|
|
onDoubleclick();
|
|
onUndoRedo();
|
|
|
|
}
|
|
|
|
void oneColumn()
|
|
{
|
|
if (!isOneColumn) return;
|
|
|
|
|
|
|
|
|
|
if (!browser.InvokeMethod<bool>("Initialized"))
|
|
browser.InvokeMethod("Init");
|
|
|
|
|
|
|
|
var m_TreeViewKeyboardControlID = GUIUtility.GetControlID(FocusType.Keyboard);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
browser.InvokeMethod("OnEvent");
|
|
|
|
if (curEvent.isMouseDown && browser.position.SetPos(0, 0).IsHovered())
|
|
t_ProjectBrowser.SetFieldValue("s_LastInteractedProjectBrowser", browser);
|
|
|
|
|
|
|
|
|
|
// header
|
|
browser.SetFieldValue("m_ListHeaderRect", breadcrumbsRect);
|
|
|
|
if (curEvent.isRepaint)
|
|
browser.InvokeMethod("BreadCrumbBar");
|
|
|
|
breadcrumbsRect.Draw(breadcrumbsTint);
|
|
topGapRect.Draw(topGapColor);
|
|
|
|
breadcrumbsRect.SetHeightFromBottom(1).Draw(Greyscale(.14f));
|
|
|
|
|
|
|
|
|
|
// footer
|
|
browser.SetFieldValue("m_BottomBarRect", footerRect);
|
|
browser.InvokeMethod("BottomBar");
|
|
|
|
|
|
|
|
|
|
// tree
|
|
browser.GetMemberValue("m_AssetTree")?.InvokeMethod("OnGUI", listAreaRect, m_TreeViewKeyboardControlID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
browser.InvokeMethod("HandleCommandEvents");
|
|
|
|
|
|
|
|
}
|
|
void twoColumns()
|
|
{
|
|
if (isOneColumn) return;
|
|
|
|
|
|
|
|
if (!browser.InvokeMethod<bool>("Initialized"))
|
|
browser.InvokeMethod("Init");
|
|
|
|
|
|
|
|
var m_ListKeyboardControlID = GUIUtility.GetControlID(FocusType.Keyboard);
|
|
|
|
var startGridSize = browser.GetFieldValue("m_ListArea")?.GetMemberValue("gridSize");
|
|
|
|
|
|
|
|
|
|
|
|
browser.InvokeMethod("OnEvent");
|
|
|
|
if (curEvent.isMouseDown && browser.position.SetPos(0, 0).IsHovered())
|
|
t_ProjectBrowser.SetFieldValue("s_LastInteractedProjectBrowser", browser);
|
|
|
|
|
|
|
|
|
|
// header
|
|
browser.SetFieldValue("m_ListHeaderRect", breadcrumbsRect);
|
|
|
|
|
|
browser.InvokeMethod("BreadCrumbBar");
|
|
|
|
breadcrumbsRect.Draw(breadcrumbsTint);
|
|
topGapRect.Draw(topGapColor);
|
|
|
|
breadcrumbsRect.SetHeightFromBottom(1).Draw(Greyscale(.14f));
|
|
|
|
|
|
|
|
|
|
// footer
|
|
browser.SetFieldValue("m_BottomBarRect", footerRect);
|
|
browser.InvokeMethod("BottomBar");
|
|
|
|
|
|
|
|
|
|
// list area
|
|
browser.GetFieldValue("m_ListArea").InvokeMethod("OnGUI", listAreaRect, m_ListKeyboardControlID);
|
|
|
|
// block grid size changes when ctrl-shift-scrolling
|
|
if (curEvent.holdingCmdOrCtrl)
|
|
browser.GetFieldValue("m_ListArea").SetMemberValue("gridSize", startGridSize);
|
|
|
|
|
|
|
|
|
|
|
|
browser.SetFieldValue("m_StartGridSize", browser.GetFieldValue("m_ListArea").GetMemberValue("gridSize"));
|
|
|
|
browser.InvokeMethod("HandleContextClickInListArea", listAreaRect);
|
|
browser.InvokeMethod("HandleCommandEvents");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
setRootForOneColumn();
|
|
handleFolderChange();
|
|
|
|
oneColumn();
|
|
twoColumns();
|
|
|
|
}
|
|
|
|
|
|
static void UpdateWrappingForBrowser(EditorWindow browser)
|
|
{
|
|
if (!browser.hasFocus) return;
|
|
if (mi_VFavorites_CanBrowserBeWrapped != null && mi_VFavorites_CanBrowserBeWrapped.Invoke(null, new[] { browser }).Equals(false)) return;
|
|
|
|
var isLocked = browser.GetMemberValue<bool>("isLocked");
|
|
var isWrapped = browser.GetMemberValue("m_Parent").GetMemberValue<Delegate>("m_OnGUI").Method == mi_WrappedBrowserOnGUI;
|
|
|
|
void wrap()
|
|
{
|
|
if (!isLocked) return;
|
|
if (isWrapped) return;
|
|
|
|
var hostView = browser.GetMemberValue("m_Parent");
|
|
|
|
var newDelegate = typeof(VTabs).GetMethod(nameof(WrappedBrowserOnGUI), maxBindingFlags).CreateDelegate(t_EditorWindowDelegate, browser);
|
|
|
|
hostView.SetMemberValue("m_OnGUI", newDelegate);
|
|
|
|
browser.Repaint();
|
|
|
|
|
|
browser.SetMemberValue("useTreeViewSelectionInsteadOfMainSelection", false);
|
|
|
|
}
|
|
void unwrap()
|
|
{
|
|
if (isLocked) return;
|
|
if (!isWrapped) return;
|
|
|
|
var hostView = browser.GetMemberValue("m_Parent");
|
|
|
|
var originalDelegate = hostView.InvokeMethod("CreateDelegate", "OnGUI");
|
|
|
|
hostView.SetMemberValue("m_OnGUI", originalDelegate);
|
|
|
|
browser.Repaint();
|
|
|
|
}
|
|
|
|
wrap();
|
|
unwrap();
|
|
|
|
}
|
|
|
|
static void UpdateWrappingForAllBrowsers()
|
|
{
|
|
foreach (var r in allBrowsers)
|
|
UpdateWrappingForBrowser(r);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void HideTabScrollerButtons()
|
|
{
|
|
void getStyles()
|
|
{
|
|
if (leftScrollerStyle != null && rightScrollerStyle != null) return;
|
|
|
|
if (!guiStylesInitialized) TryInitializeGuiStyles();
|
|
if (!guiStylesInitialized) return;
|
|
|
|
if (typeof(GUISkin).GetFieldValue("current")?.GetFieldValue<Dictionary<string, GUIStyle>>("m_Styles")?.ContainsKey("dragtab scroller prev") != true) return;
|
|
if (typeof(GUISkin).GetFieldValue("current")?.GetFieldValue<Dictionary<string, GUIStyle>>("m_Styles")?.ContainsKey("dragtab scroller next") != true) return;
|
|
|
|
|
|
var t_Styles = typeof(Editor).Assembly.GetType("UnityEditor.DockArea+Styles");
|
|
|
|
leftScrollerStyle = t_Styles.GetFieldValue<GUIStyle>("tabScrollerPrevButton");
|
|
rightScrollerStyle = t_Styles.GetFieldValue<GUIStyle>("tabScrollerNextButton");
|
|
|
|
}
|
|
void createTexture()
|
|
{
|
|
if (clearTexture != null) return;
|
|
|
|
clearTexture = new Texture2D(1, 1);
|
|
clearTexture.hideFlags = HideFlags.DontSave;
|
|
clearTexture.SetPixel(0, 0, Color.clear);
|
|
clearTexture.Apply();
|
|
|
|
}
|
|
void assignTexture()
|
|
{
|
|
if (leftScrollerStyle == null) return;
|
|
if (rightScrollerStyle == null) return;
|
|
|
|
leftScrollerStyle.normal.background = clearTexture;
|
|
rightScrollerStyle.normal.background = clearTexture;
|
|
|
|
}
|
|
|
|
getStyles();
|
|
createTexture();
|
|
assignTexture();
|
|
|
|
}
|
|
|
|
static GUIStyle leftScrollerStyle;
|
|
static GUIStyle rightScrollerStyle;
|
|
|
|
static Texture2D clearTexture;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ClosePropertyEditorsWithNonLoadableObjects()
|
|
{
|
|
foreach (var propertyEditor in allPropertyEditors)
|
|
if (propertyEditor.GetMemberValue<Object>("m_InspectedObject") == null)
|
|
propertyEditor.Close();
|
|
|
|
}
|
|
|
|
static void LoadPropertyEditorInspectedObjects()
|
|
{
|
|
foreach (var propertyEditor in allPropertyEditors)
|
|
propertyEditor.InvokeMethod("LoadPersistedObject");
|
|
|
|
}
|
|
|
|
static void EnsureActiveTabsVisibleOnScroller()
|
|
{
|
|
foreach (var dockArea in allDockAreas)
|
|
{
|
|
if (!guis_byDockArea.TryGetValue(dockArea, out var gui)) continue;
|
|
|
|
|
|
var scrollPos = gui.GetTargetScrollPosition();
|
|
|
|
if (!scrollPos.Approx(0))
|
|
scrollPos += gui.nonZeroTabScrollOffset;
|
|
|
|
|
|
dockArea.SetFieldValue("m_ScrollOffset", scrollPos);
|
|
|
|
}
|
|
}
|
|
|
|
public static void RepaintAllDockAreas()
|
|
{
|
|
foreach (var dockarea in allDockAreas)
|
|
dockarea.InvokeMethod("Repaint");
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[UnityEditor.Callbacks.PostProcessBuild]
|
|
static void OnBuild(BuildTarget _, string __)
|
|
{
|
|
EditorApplication.delayCall += LoadPropertyEditorInspectedObjects;
|
|
EditorApplication.delayCall += UpdateAllPropertyEditorTitles;
|
|
}
|
|
|
|
static void OnDomainReloaded()
|
|
{
|
|
toCallInGUI += UpdateWrappingForAllBrowsers;
|
|
toCallInGUI += UpdateAllBrowserTitles;
|
|
|
|
}
|
|
|
|
static void OnSceneOpened(Scene _, OpenSceneMode __)
|
|
{
|
|
LoadPropertyEditorInspectedObjects();
|
|
ClosePropertyEditorsWithNonLoadableObjects();
|
|
UpdateAllPropertyEditorTitles();
|
|
|
|
}
|
|
|
|
static void OnProjectLoaded()
|
|
{
|
|
toCallInGUI += EnsureActiveTabsVisibleOnScroller;
|
|
|
|
UpdateAllPropertyEditorTitles();
|
|
|
|
}
|
|
|
|
static void OnFocusedWindowChanged()
|
|
{
|
|
if (EditorWindow.focusedWindow?.GetType() == t_ProjectBrowser)
|
|
UpdateWrappingForBrowser(EditorWindow.focusedWindow);
|
|
|
|
}
|
|
|
|
static void OnWindowUnmaximized()
|
|
{
|
|
UpdateAllPropertyEditorTitles();
|
|
UpdateAllBrowserTitles();
|
|
|
|
UpdateWrappingForAllBrowsers();
|
|
|
|
|
|
EnsureActiveTabsVisibleOnScroller();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void CheckIfFocusedWindowChanged()
|
|
{
|
|
if (prevFocusedWindow != EditorWindow.focusedWindow)
|
|
OnFocusedWindowChanged();
|
|
|
|
prevFocusedWindow = EditorWindow.focusedWindow;
|
|
}
|
|
|
|
static EditorWindow prevFocusedWindow;
|
|
|
|
|
|
|
|
static void CheckIfWindowWasUnmaximized()
|
|
{
|
|
var isMaximized = EditorWindow.focusedWindow?.maximized == true;
|
|
|
|
if (!isMaximized && wasMaximized)
|
|
OnWindowUnmaximized();
|
|
|
|
wasMaximized = isMaximized;
|
|
|
|
}
|
|
|
|
static bool wasMaximized;
|
|
|
|
|
|
|
|
static void OnSomeGUI()
|
|
{
|
|
toCallInGUI?.Invoke();
|
|
toCallInGUI = null;
|
|
|
|
CheckIfFocusedWindowChanged();
|
|
|
|
}
|
|
|
|
static void ProjectWindowItemOnGUI(string _, Rect __) => OnSomeGUI();
|
|
static void HierarchyWindowItemOnGUI(int _, Rect __) => OnSomeGUI();
|
|
|
|
static Action toCallInGUI;
|
|
|
|
|
|
|
|
static void DelayCallLoop()
|
|
{
|
|
UpdateAllBrowserTitles();
|
|
UpdateWrappingForAllBrowsers();
|
|
HideTabScrollerButtons();
|
|
|
|
EditorApplication.delayCall -= DelayCallLoop;
|
|
EditorApplication.delayCall += DelayCallLoop;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Update()
|
|
{
|
|
CheckIfFocusedWindowChanged();
|
|
CheckIfWindowWasUnmaximized();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ComponentTabHeaderGUI(Editor editor)
|
|
{
|
|
if (editor.target is not Component component) return;
|
|
|
|
var headerRect = ExpandWidthLabelRect(height: 0).MoveY(-48).SetHeight(50).AddWidthFromMid(8);
|
|
var nameRect = headerRect.MoveX(43).MoveY(5).SetHeight(20).SetXMax(headerRect.xMax - 50);
|
|
var subtextRect = headerRect.MoveX(43).MoveY(22).SetHeight(20);
|
|
|
|
|
|
void hideName()
|
|
{
|
|
var maskRect = headerRect.AddWidthFromRight(-45).AddWidth(-50);
|
|
|
|
var maskColor = Greyscale(isDarkTheme ? .24f : .8f);
|
|
|
|
maskRect.Draw(maskColor);
|
|
|
|
}
|
|
void name()
|
|
{
|
|
SetLabelFontSize(13);
|
|
|
|
GUI.Label(nameRect, GetComponentName(component));
|
|
|
|
ResetLabelStyle();
|
|
|
|
}
|
|
void componentOf()
|
|
{
|
|
SetGUIEnabled(false);
|
|
|
|
GUI.Label(subtextRect, "Component of");
|
|
|
|
ResetGUIEnabled();
|
|
|
|
}
|
|
void goName()
|
|
{
|
|
var goNameRect = subtextRect.MoveX("Component of ".GetLabelWidth() - 3).SetWidth(component.gameObject.name.GetLabelWidth(isBold: true));
|
|
|
|
goNameRect.MarkInteractive();
|
|
|
|
SetGUIEnabled(goNameRect.IsHovered() && !mousePressedOnGoName);
|
|
SetLabelBold();
|
|
|
|
GUI.Label(goNameRect, component.gameObject.name);
|
|
|
|
ResetGUIEnabled();
|
|
ResetLabelStyle();
|
|
|
|
|
|
|
|
if (curEvent.isMouseDown && goNameRect.IsHovered())
|
|
{
|
|
mousePressedOnGoName = true;
|
|
curEvent.Use();
|
|
}
|
|
|
|
if (curEvent.isMouseUp)
|
|
{
|
|
if (mousePressedOnGoName)
|
|
EditorGUIUtility.PingObject(component.gameObject);
|
|
|
|
mousePressedOnGoName = false;
|
|
curEvent.Use();
|
|
}
|
|
|
|
if (curEvent.isMouseLeaveWindow || (!curEvent.isLayout && !goNameRect.Resize(1).IsHovered()))
|
|
mousePressedOnGoName = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
hideName();
|
|
name();
|
|
componentOf();
|
|
goName();
|
|
|
|
Space(-4);
|
|
|
|
}
|
|
|
|
static bool mousePressedOnGoName;
|
|
|
|
static string GetComponentName(Component component)
|
|
{
|
|
if (!component) return "";
|
|
|
|
var name = new GUIContent(EditorGUIUtility.ObjectContent(component, component.GetType())).text;
|
|
|
|
name = name.Substring(name.LastIndexOf('(') + 1);
|
|
name = name.Substring(0, name.Length - 1);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void SetupExtraScrollerSpace()
|
|
{
|
|
|
|
var action = t_WindowAction.GetMethod("CreateWindowMenuItem", maxBindingFlags).Invoke(null, new[] { "vTabs dummy for creating extra space for + button", null, null });
|
|
|
|
|
|
var extraSpaceAmount = 21f;
|
|
|
|
action.SetMemberValue("width", extraSpaceAmount);
|
|
|
|
|
|
var mi_ShouldCreateExtraSpace = typeof(VTabs).GetMethod("ShouldCreateExtraSpace", maxBindingFlags);
|
|
|
|
var funcDelegate = Delegate.CreateDelegate(t_ValidateHandler, mi_ShouldCreateExtraSpace);
|
|
|
|
action.SetMemberValue("validateHandler", funcDelegate);
|
|
|
|
|
|
|
|
|
|
var defaultActions = t_HostView.GetMemberValue<System.Array>("s_windowActions") ?? t_HostView.InvokeMethod<System.Array>("FetchWindowActionFromAttribute");
|
|
|
|
var newActions = System.Array.CreateInstance(t_WindowAction, defaultActions.Length + 1);
|
|
|
|
System.Array.Copy(defaultActions, newActions, defaultActions.Length);
|
|
|
|
newActions.SetValue(action, defaultActions.Length);
|
|
|
|
|
|
t_HostView.SetMemberValue("s_windowActions", newActions);
|
|
|
|
}
|
|
|
|
static bool ShouldCreateExtraSpace(EditorWindow window, object _) => VTabsMenu.addTabButtonEnabled && window == window.GetDockArea().GetTabs()?.Last();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void TryInitializeGuiStyles() => EditorWindow.focusedWindow?.SendEvent(EditorGUIUtility.CommandEvent(""));
|
|
|
|
static bool guiStylesInitialized => typeof(GUI).GetFieldValue("s_Skin") != null;
|
|
|
|
|
|
|
|
|
|
static Object GetDockArea(this EditorWindow window)
|
|
{
|
|
var parent = window?.GetFieldValue<Object>("m_Parent");
|
|
|
|
if (parent?.GetType() == t_DockArea)
|
|
return parent;
|
|
else
|
|
return null;
|
|
|
|
}
|
|
|
|
public static List<EditorWindow> GetTabs(this Object dockArea) => dockArea?.GetFieldValue<List<EditorWindow>>("m_Panes");
|
|
|
|
|
|
|
|
|
|
public static string GetLockedFolderPath_oneColumn(this EditorWindow browser)
|
|
{
|
|
var path = browser.GetMemberValue<string[]>("m_LastFolders")?.FirstOrDefault();
|
|
|
|
if (path == null || path == "Assets")
|
|
path = browser.GetMemberValue("m_SearchFilter")?.GetMemberValue<string[]>("m_Folders")?.FirstOrDefault() ?? "Assets"; // to migrate locked folder paths from 2.0.14
|
|
|
|
return path;
|
|
|
|
// unlike in two column layout, there's no such concept as active folder path in one column
|
|
// so we have to serialize locked folder path in some unused field
|
|
// m_LastFolders appears to work fine for this purpose
|
|
// m_SearchFilter was used before v2.0.15 but could get changed when moving/creating/deleting assets
|
|
|
|
}
|
|
|
|
public static void SetLockedFolderPath_oneColumn(this EditorWindow browser, string folderPath)
|
|
{
|
|
browser.SetMemberValue("m_LastFolders", new[] { folderPath });
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
public class TabInfo
|
|
{
|
|
public TabInfo(EditorWindow window)
|
|
{
|
|
typeName = window.GetType().Name;
|
|
originalDockArea = window.GetDockArea();
|
|
originalTabIndex = window.GetDockArea().GetTabs().IndexOf(window);
|
|
wasFocused = window.hasFocus;
|
|
originalTitle = window.titleContent.text;
|
|
menuItemName = window.titleContent.text.Replace("/", " \u2215 ").Trim(' ');
|
|
|
|
if (isBrowser)
|
|
{
|
|
isLocked = window.GetPropertyValue<bool>("isLocked");
|
|
|
|
|
|
savedGridSize = window.GetFieldValue<int>("m_StartGridSize");
|
|
|
|
isGridSizeSaved = true;
|
|
|
|
|
|
savedLayout = window.GetMemberValue<int>("m_ViewMode");
|
|
|
|
isLayoutSaved = true;
|
|
|
|
|
|
var folderPath = savedLayout == 0 ? window.GetLockedFolderPath_oneColumn() // one column
|
|
: window.InvokeMethod<string>("GetActiveFolderPath"); // two columns
|
|
folderGuid = folderPath.ToGuid();
|
|
|
|
}
|
|
|
|
if (isPropertyEditor)
|
|
globalId = new GlobalID(window.GetMemberValue<string>("m_GlobalObjectId"));
|
|
|
|
}
|
|
public TabInfo(Object lockTo)
|
|
{
|
|
isLocked = true;
|
|
typeName = lockTo is DefaultAsset ? t_ProjectBrowser.Name : t_PropertyEditor.Name;
|
|
|
|
|
|
if (isBrowser)
|
|
folderGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(lockTo));
|
|
|
|
if (isPropertyEditor)
|
|
globalId = lockTo.GetGlobalID();
|
|
|
|
#if UNITY_2021_2_OR_NEWER
|
|
if (isPropertyEditor)
|
|
if (StageUtility.GetCurrentStage() is PrefabStage && globalId.ToString().Contains("00000000000000000000000000000000"))
|
|
lockedPrefabAssetObject = lockTo;
|
|
#endif
|
|
|
|
}
|
|
public TabInfo(string typeName, string menuItemName) { this.typeName = typeName; this.menuItemName = menuItemName; }
|
|
|
|
public string typeName;
|
|
public string menuItemName;
|
|
public object originalDockArea;
|
|
public int originalTabIndex;
|
|
public string originalTitle;
|
|
public bool wasFocused;
|
|
|
|
public bool isBrowser => typeName == t_ProjectBrowser.Name;
|
|
public bool isLocked;
|
|
public string folderGuid = "";
|
|
public int savedGridSize;
|
|
public int savedLayout;
|
|
public bool isGridSizeSaved = false;
|
|
public bool isLayoutSaved = false;
|
|
|
|
public bool isPropertyEditor => typeName == t_PropertyEditor.Name;
|
|
public GlobalID globalId;
|
|
public Object lockedPrefabAssetObject;
|
|
|
|
}
|
|
|
|
[System.Serializable]
|
|
class TabInfoList { public List<TabInfo> list = new List<TabInfo>(); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[InitializeOnLoadMethod]
|
|
static void Init()
|
|
{
|
|
if (VTabsMenu.pluginDisabled) return;
|
|
|
|
|
|
EditorApplication.update -= UpdateGUIs;
|
|
EditorApplication.update += UpdateGUIs;
|
|
|
|
|
|
|
|
// shortcuts
|
|
var globalEventHandler = typeof(EditorApplication).GetFieldValue<EditorApplication.CallbackFunction>("globalEventHandler");
|
|
typeof(EditorApplication).SetFieldValue("globalEventHandler", (globalEventHandler - Shortcuts) + Shortcuts);
|
|
|
|
|
|
// component tabs
|
|
Editor.finishedDefaultHeaderGUI -= ComponentTabHeaderGUI;
|
|
Editor.finishedDefaultHeaderGUI += ComponentTabHeaderGUI;
|
|
|
|
|
|
|
|
|
|
// state change detectors
|
|
var projectWasLoaded = typeof(EditorApplication).GetFieldValue<UnityEngine.Events.UnityAction>("projectWasLoaded");
|
|
typeof(EditorApplication).SetFieldValue("projectWasLoaded", (projectWasLoaded - OnProjectLoaded) + OnProjectLoaded);
|
|
|
|
UnityEditor.SceneManagement.EditorSceneManager.sceneOpened -= OnSceneOpened;
|
|
UnityEditor.SceneManagement.EditorSceneManager.sceneOpened += OnSceneOpened;
|
|
|
|
EditorApplication.projectWindowItemOnGUI -= ProjectWindowItemOnGUI;
|
|
EditorApplication.projectWindowItemOnGUI += ProjectWindowItemOnGUI;
|
|
|
|
EditorApplication.hierarchyWindowItemOnGUI -= HierarchyWindowItemOnGUI;
|
|
EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI;
|
|
|
|
EditorApplication.delayCall -= DelayCallLoop;
|
|
EditorApplication.delayCall += DelayCallLoop;
|
|
|
|
EditorApplication.update -= Update;
|
|
EditorApplication.update += Update;
|
|
|
|
EditorApplication.quitting -= VTabsCache.Save;
|
|
EditorApplication.quitting += VTabsCache.Save;
|
|
|
|
|
|
|
|
// EditorApplication.delayCall += () => VTabsAddTabWindow.UpdateAllEntries();
|
|
|
|
EditorApplication.delayCall += () => UpdateStyleSheet();
|
|
|
|
SetupExtraScrollerSpace();
|
|
|
|
OnDomainReloaded();
|
|
|
|
}
|
|
|
|
|
|
public static IEnumerable<EditorWindow> allBrowsers => _allBrowsers ??= t_ProjectBrowser.GetFieldValue<IList>("s_ProjectBrowsers").Cast<EditorWindow>();
|
|
public static IEnumerable<EditorWindow> _allBrowsers;
|
|
|
|
public static IEnumerable<EditorWindow> allPropertyEditors => Resources.FindObjectsOfTypeAll(t_PropertyEditor).Where(r => r.GetType().BaseType == typeof(EditorWindow)).Cast<EditorWindow>();
|
|
|
|
public static List<EditorWindow> allEditorWindows
|
|
{
|
|
get
|
|
{
|
|
if (typeof(EditorWindow).GetPropertyInfo("activeEditorWindows") == null) // this variable doesn't exist in early 2022.3 versions, even though UnityCsReference repo says it does
|
|
return Resources.FindObjectsOfTypeAll(typeof(EditorWindow)).Cast<EditorWindow>().ToList();
|
|
|
|
return _allEditorWindows ?? typeof(EditorWindow).GetMemberValue<List<EditorWindow>>("activeEditorWindows");
|
|
}
|
|
}
|
|
public static List<EditorWindow> _allEditorWindows;
|
|
|
|
public static IEnumerable<Object> allDockAreas => allEditorWindows.Where(r => r.hasFocus && r.docked && !r.maximized).Select(r => r.GetMemberValue<Object>("m_Parent"));
|
|
|
|
|
|
|
|
public static Type t_DockArea = typeof(Editor).Assembly.GetType("UnityEditor.DockArea");
|
|
public static Type t_PropertyEditor = typeof(Editor).Assembly.GetType("UnityEditor.PropertyEditor");
|
|
public static Type t_ProjectBrowser = typeof(Editor).Assembly.GetType("UnityEditor.ProjectBrowser");
|
|
public static Type t_SceneHierarchyWindow = typeof(Editor).Assembly.GetType("UnityEditor.SceneHierarchyWindow");
|
|
public static Type t_InspectorWindow = typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow");
|
|
public static Type t_WindowAction = typeof(Editor).Assembly.GetType("UnityEditor.WindowAction");
|
|
public static Type t_HostView = typeof(Editor).Assembly.GetType("UnityEditor.HostView");
|
|
public static Type t_EditorWindowDelegate = t_HostView.GetNestedType("EditorWindowDelegate", maxBindingFlags);
|
|
public static Type t_ValidateHandler = t_WindowAction.GetNestedType("ValidateHandler", maxBindingFlags);
|
|
public static Type t_EditorWindowShowButtonDelegate = t_HostView.GetNestedType("EditorWindowShowButtonDelegate", maxBindingFlags);
|
|
|
|
public static Type t_VHierarchy = Type.GetType("VHierarchy.VHierarchy") ?? Type.GetType("VHierarchy.VHierarchy, VHierarchy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
|
|
public static Type t_VFolders = Type.GetType("VFolders.VFolders") ?? Type.GetType("VFolders.VFolders, VFolders, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
|
|
public static Type t_VFavorites = Type.GetType("VFavorites.VFavorites") ?? Type.GetType("VFavorites.VFavorites, VFavorites, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
|
|
|
|
public static MethodInfo mi_WrappedBrowserOnGUI = typeof(VTabs).GetMethod(nameof(WrappedBrowserOnGUI), maxBindingFlags);
|
|
|
|
public static MethodInfo mi_VFolders_GetIcon = t_VFolders?.GetMethod("GetSmallFolderIcon_forVTabs", maxBindingFlags);
|
|
public static MethodInfo mi_VHierarchy_GetIcon = t_VHierarchy?.GetMethod("GetIcon_forVTabs", maxBindingFlags);
|
|
public static MethodInfo mi_VFavorites_BeforeWindowCreated = t_VFavorites?.GetMethod("BeforeWindowCreated_byVTabs", maxBindingFlags);
|
|
public static MethodInfo mi_VFavorites_CanBrowserBeWrapped = t_VFavorites?.GetMethod("CanBrowserBeWrapped_byVTabs", maxBindingFlags);
|
|
|
|
|
|
|
|
|
|
|
|
const string version = "2.1.1";
|
|
|
|
}
|
|
}
|
|
#endif
|