A game about forced loneliness, made by TACStudios
1using System;
2using System.Reflection;
3
4using UnityEditor;
5using UnityEngine;
6
7namespace Unity.PlasticSCM.Editor.UI
8{
9 internal static class RunModal
10 {
11 static RunModal()
12 {
13 InitializeInfo();
14 }
15
16 internal static bool IsAvailable()
17 {
18 return mShowWithModeMethod != null
19 && mCreateSavedGUIState != null
20 && mApplyAndForgetMethod != null
21 && mParentField != null
22 && mParentWindowProp != null
23 && mMakeModalMethod != null;
24 }
25
26 internal static void Dialog(EditorWindow window)
27 {
28 ShowAsUtility(window);
29
30 object savedGUIState = CreateSavedGUIState();
31 PushDispatcherContext(window);
32
33 MakeModal(window);
34
35 PopDispatcherContext(window);
36 ApplySavedGUIState(savedGUIState);
37 }
38
39 static void MakeModal(EditorWindow window)
40 {
41 // MakeModal(m_Parent.window);
42 var hostView = mParentField.GetValue(window);
43 var parentWindow = mParentWindowProp.GetValue(hostView, null);
44
45 mMakeModalMethod.Invoke(
46 mMakeModalMethod.IsStatic ? null : window,
47 new object[] { parentWindow });
48 }
49
50 static void ShowAsUtility(EditorWindow window)
51 {
52 // ShowWithMode(ShowMode.Utility);
53 mShowWithModeMethod.Invoke(window, new object[] { 2 });
54 }
55
56 static object CreateSavedGUIState()
57 {
58 // SavedGUIState guiState = SavedGUIState.Create();
59 return mCreateSavedGUIState.Invoke(null, null);
60 }
61
62 static void ApplySavedGUIState(object savedGUIState)
63 {
64 // guiState.ApplyAndForget();
65 mApplyAndForgetMethod.Invoke(savedGUIState, null);
66 }
67
68 static void PopDispatcherContext(EditorWindow window)
69 {
70 //UnityEngine.UIElements.EventDispatcher.editorDispatcher.PopDispatcherContext();
71
72 object editorDispatcher = mEditorDispatcherProp2020.GetValue(null);
73 mPopContextMethod2020.Invoke(editorDispatcher, null);
74 }
75
76 static void PushDispatcherContext(EditorWindow window)
77 {
78 //UnityEngine.UIElements.EventDispatcher.editorDispatcher.PushDispatcherContext();
79
80 object editorDispatcher = mEditorDispatcherProp2020.GetValue(null);
81 mPushContextMethod2020.Invoke(editorDispatcher, null);
82 }
83
84 static object GetDispatcher(EditorWindow window)
85 {
86 object dispatcher = null;
87 if (MayHaveDispatcher())
88 {
89 var parent = mParentField.GetValue(window);
90 if (parent != null)
91 {
92 var visualTree = mVisualTreeProp.GetValue(parent, null);
93 if (visualTree != null)
94 {
95 var panel = mPanelProp.GetValue(visualTree, null);
96 if (panel != null)
97 {
98 dispatcher = mDispatcherProp.GetValue(panel, null);
99 }
100 }
101 }
102 }
103
104 return dispatcher;
105 }
106
107 static bool MayHaveDispatcher()
108 {
109 return mDispatcherType != null
110 && mPushContextMethod != null
111 && mPopContextMethod != null;
112 }
113
114 static void InitializeInfo()
115 {
116 var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static;
117 mMakeModalMethod = BuildMakeModalMethodInfo(flags);
118 mShowWithModeMethod = typeof(EditorWindow).GetMethod("ShowWithMode", flags);
119 mParentField = typeof(EditorWindow).GetField("m_Parent", flags);
120 var hostViewType = mParentField.FieldType;
121 mParentWindowProp = hostViewType.GetProperty("window", flags);
122
123 var savedGUIStateType = typeof(EditorWindow).Assembly.GetType("UnityEditor.SavedGUIState");
124 mCreateSavedGUIState = savedGUIStateType.GetMethod("Create", flags);
125 mApplyAndForgetMethod = savedGUIStateType.GetMethod("ApplyAndForget", flags);
126
127 mEditorDispatcherProp2020 = typeof(UnityEngine.UIElements.EventDispatcher).GetProperty("editorDispatcher", flags);
128 mPushContextMethod2020 = mEditorDispatcherProp2020.PropertyType.GetMethod("PushDispatcherContext", flags);
129 mPopContextMethod2020 = mEditorDispatcherProp2020.PropertyType.GetMethod("PopDispatcherContext", flags);
130
131 flags = BindingFlags.NonPublic
132 | BindingFlags.Instance
133 | BindingFlags.Public;
134
135 mParentField = typeof(EditorWindow).GetField("m_Parent", flags);
136 if (mParentField != null)
137 hostViewType = mParentField.FieldType;
138 if (hostViewType != null)
139 mVisualTreeProp = hostViewType.GetProperty("visualTree");
140 if (mVisualTreeProp != null)
141 {
142 var visualTreeType = mVisualTreeProp.PropertyType;
143 if (visualTreeType != null)
144 {
145 mPanelProp = visualTreeType.GetProperty("panel");
146 if (mPanelProp != null)
147 {
148 var panelType = mPanelProp.PropertyType;
149 if (panelType != null)
150 {
151 mDispatcherProp = panelType.GetProperty("dispatcher");
152 if (mDispatcherProp != null)
153 {
154 mDispatcherType = mDispatcherProp.PropertyType;
155 if (mDispatcherType != null)
156 {
157 mPushContextMethod = mDispatcherType.GetMethod("PushDispatcherContext", flags);
158 mPopContextMethod = mDispatcherType.GetMethod("PopDispatcherContext", flags);
159 }
160 }
161 }
162 }
163 }
164 }
165 }
166
167 static MethodInfo BuildMakeModalMethodInfo(BindingFlags flags)
168 {
169 return typeof(EditorWindow).GetMethod("Internal_MakeModal", flags);
170 }
171
172 static FieldInfo mParentField;
173 static PropertyInfo mParentWindowProp;
174 static MethodInfo mMakeModalMethod;
175 static MethodInfo mShowWithModeMethod;
176 static MethodInfo mCreateSavedGUIState;
177 static MethodInfo mApplyAndForgetMethod;
178 static PropertyInfo mVisualTreeProp;
179 static Type mDispatcherType;
180 static MethodInfo mPushContextMethod;
181 static MethodInfo mPopContextMethod;
182 static PropertyInfo mPanelProp;
183 static PropertyInfo mDispatcherProp;
184
185 static PropertyInfo mEditorDispatcherProp2020;
186 static MethodInfo mPushContextMethod2020;
187 static MethodInfo mPopContextMethod2020;
188
189 // // How ContainerWindows are visualized. Used with ContainerWindow.Show
190 // internal enum ShowMode
191 // {
192 // // Show as a normal window with max, min & close buttons.
193 // NormalWindow = 0,
194 // // Used for a popup menu. On mac this means light shadow and no titlebar.
195 // PopupMenu = 1,
196 // // Utility window - floats above the app. Disappears when app loses focus.
197 // Utility = 2,
198 // // Window has no shadow or decorations. Used internally for dragging stuff around.
199 // NoShadow = 3,
200 // // The Unity main window. On mac, this is the same as NormalWindow, except window doesn't have a close button.
201 // MainWindow = 4,
202 // // Aux windows. The ones that close the moment you move the mouse out of them.
203 // AuxWindow = 5,
204 // // Like PopupMenu, but without keyboard focus
205 // cm-help.es.txtTooltip = 6
206 // }
207 }
208}