ReadmeEditor.cs
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using UnityEditor; 5 using System; 6 using System.IO; 7 using System.Reflection; 8 9 [CustomEditor(typeof(Readme))] 10 [InitializeOnLoad] 11 public class ReadmeEditor : Editor 12 { 13 static string s_ShowedReadmeSessionStateName = "ReadmeEditor.showedReadme"; 14 15 static string s_ReadmeSourceDirectory = "Assets/TutorialInfo"; 16 17 const float k_Space = 16f; 18 19 static ReadmeEditor() 20 { 21 EditorApplication.delayCall += SelectReadmeAutomatically; 22 } 23 24 static void RemoveTutorial() 25 { 26 if (EditorUtility.DisplayDialog("Remove Readme Assets", 27 28 $"All contents under {s_ReadmeSourceDirectory} will be removed, are you sure you want to proceed?", 29 "Proceed", 30 "Cancel")) 31 { 32 if (Directory.Exists(s_ReadmeSourceDirectory)) 33 { 34 FileUtil.DeleteFileOrDirectory(s_ReadmeSourceDirectory); 35 FileUtil.DeleteFileOrDirectory(s_ReadmeSourceDirectory + ".meta"); 36 } 37 else 38 { 39 Debug.Log($"Could not find the Readme folder at {s_ReadmeSourceDirectory}"); 40 } 41 42 var readmeAsset = SelectReadme(); 43 if (readmeAsset != null) 44 { 45 var path = AssetDatabase.GetAssetPath(readmeAsset); 46 FileUtil.DeleteFileOrDirectory(path + ".meta"); 47 FileUtil.DeleteFileOrDirectory(path); 48 } 49 50 AssetDatabase.Refresh(); 51 } 52 } 53 54 static void SelectReadmeAutomatically() 55 { 56 if (!SessionState.GetBool(s_ShowedReadmeSessionStateName, false)) 57 { 58 var readme = SelectReadme(); 59 SessionState.SetBool(s_ShowedReadmeSessionStateName, true); 60 61 if (readme && !readme.loadedLayout) 62 { 63 LoadLayout(); 64 readme.loadedLayout = true; 65 } 66 } 67 } 68 69 static void LoadLayout() 70 { 71 var assembly = typeof(EditorApplication).Assembly; 72 var windowLayoutType = assembly.GetType("UnityEditor.WindowLayout", true); 73 var method = windowLayoutType.GetMethod("LoadWindowLayout", BindingFlags.Public | BindingFlags.Static); 74 method.Invoke(null, new object[] { Path.Combine(Application.dataPath, "TutorialInfo/Layout.wlt"), false }); 75 } 76 77 static Readme SelectReadme() 78 { 79 var ids = AssetDatabase.FindAssets("Readme t:Readme"); 80 if (ids.Length == 1) 81 { 82 var readmeObject = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(ids[0])); 83 84 Selection.objects = new UnityEngine.Object[] { readmeObject }; 85 86 return (Readme)readmeObject; 87 } 88 else 89 { 90 Debug.Log("Couldn't find a readme"); 91 return null; 92 } 93 } 94 95 protected override void OnHeaderGUI() 96 { 97 var readme = (Readme)target; 98 Init(); 99 100 var iconWidth = Mathf.Min(EditorGUIUtility.currentViewWidth / 3f - 20f, 128f); 101 102 GUILayout.BeginHorizontal("In BigTitle"); 103 { 104 if (readme.icon != null) 105 { 106 GUILayout.Space(k_Space); 107 GUILayout.Label(readme.icon, GUILayout.Width(iconWidth), GUILayout.Height(iconWidth)); 108 } 109 GUILayout.Space(k_Space); 110 GUILayout.BeginVertical(); 111 { 112 113 GUILayout.FlexibleSpace(); 114 GUILayout.Label(readme.title, TitleStyle); 115 GUILayout.FlexibleSpace(); 116 } 117 GUILayout.EndVertical(); 118 GUILayout.FlexibleSpace(); 119 } 120 GUILayout.EndHorizontal(); 121 } 122 123 public override void OnInspectorGUI() 124 { 125 var readme = (Readme)target; 126 Init(); 127 128 foreach (var section in readme.sections) 129 { 130 if (!string.IsNullOrEmpty(section.heading)) 131 { 132 GUILayout.Label(section.heading, HeadingStyle); 133 } 134 135 if (!string.IsNullOrEmpty(section.text)) 136 { 137 GUILayout.Label(section.text, BodyStyle); 138 } 139 140 if (!string.IsNullOrEmpty(section.linkText)) 141 { 142 if (LinkLabel(new GUIContent(section.linkText))) 143 { 144 Application.OpenURL(section.url); 145 } 146 } 147 148 GUILayout.Space(k_Space); 149 } 150 151 if (GUILayout.Button("Remove Readme Assets", ButtonStyle)) 152 { 153 RemoveTutorial(); 154 } 155 } 156 157 bool m_Initialized; 158 159 GUIStyle LinkStyle 160 { 161 get { return m_LinkStyle; } 162 } 163 164 [SerializeField] 165 GUIStyle m_LinkStyle; 166 167 GUIStyle TitleStyle 168 { 169 get { return m_TitleStyle; } 170 } 171 172 [SerializeField] 173 GUIStyle m_TitleStyle; 174 175 GUIStyle HeadingStyle 176 { 177 get { return m_HeadingStyle; } 178 } 179 180 [SerializeField] 181 GUIStyle m_HeadingStyle; 182 183 GUIStyle BodyStyle 184 { 185 get { return m_BodyStyle; } 186 } 187 188 [SerializeField] 189 GUIStyle m_BodyStyle; 190 191 GUIStyle ButtonStyle 192 { 193 get { return m_ButtonStyle; } 194 } 195 196 [SerializeField] 197 GUIStyle m_ButtonStyle; 198 199 void Init() 200 { 201 if (m_Initialized) 202 return; 203 m_BodyStyle = new GUIStyle(EditorStyles.label); 204 m_BodyStyle.wordWrap = true; 205 m_BodyStyle.fontSize = 14; 206 m_BodyStyle.richText = true; 207 208 m_TitleStyle = new GUIStyle(m_BodyStyle); 209 m_TitleStyle.fontSize = 26; 210 211 m_HeadingStyle = new GUIStyle(m_BodyStyle); 212 m_HeadingStyle.fontStyle = FontStyle.Bold; 213 m_HeadingStyle.fontSize = 18; 214 215 m_LinkStyle = new GUIStyle(m_BodyStyle); 216 m_LinkStyle.wordWrap = false; 217 218 // Match selection color which works nicely for both light and dark skins 219 m_LinkStyle.normal.textColor = new Color(0x00 / 255f, 0x78 / 255f, 0xDA / 255f, 1f); 220 m_LinkStyle.stretchWidth = false; 221 222 m_ButtonStyle = new GUIStyle(EditorStyles.miniButton); 223 m_ButtonStyle.fontStyle = FontStyle.Bold; 224 225 m_Initialized = true; 226 } 227 228 bool LinkLabel(GUIContent label, params GUILayoutOption[] options) 229 { 230 var position = GUILayoutUtility.GetRect(label, LinkStyle, options); 231 232 Handles.BeginGUI(); 233 Handles.color = LinkStyle.normal.textColor; 234 Handles.DrawLine(new Vector3(position.xMin, position.yMax), new Vector3(position.xMax, position.yMax)); 235 Handles.color = Color.white; 236 Handles.EndGUI(); 237 238 EditorGUIUtility.AddCursorRect(position, MouseCursor.Link); 239 240 return GUI.Button(position, label, LinkStyle); 241 } 242 }