A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.IO;
4using UnityEditor.EditorTools;
5using UnityEditorInternal;
6using UnityEngine;
7using Object = UnityEngine.Object;
8
9namespace UnityEditor.Tilemaps
10{
11 internal class TilemapEditorToolPreferences : ScriptableSingleton<TilemapEditorToolPreferences>
12 {
13 private static readonly string s_LibraryFolderPath = "Library/GridBrush";
14 private static readonly string s_AssetPath = FileUtil.CombinePaths(s_LibraryFolderPath, "TilemapEditorToolPreferences.asset");
15
16 internal class TilemapEditorToolProperties
17 {
18 public static readonly string defaultToolsEditorPref = "TilemapEditorTool.DefaultTools";
19
20 public static readonly GUIContent defaultToolsLabel = EditorGUIUtility.TrTextContent("Default Tile Palette Tools");
21 public static readonly GUIContent addLabel = EditorGUIUtility.TrTextContent("<<", "Add to Defaults");
22 public static readonly GUIContent removeLabel = EditorGUIUtility.TrTextContent(">>", "Remove from Defaults");
23 public static readonly GUIContent saveLabel = EditorGUIUtility.TrTextContent("Save", "Save Defaults");
24 public static readonly GUIContent revertLabel = EditorGUIUtility.TrTextContent("Revert", "Revert Changes");
25 public static readonly GUIContent resetLabel = EditorGUIUtility.TrTextContent("Reset", "Reset Defaults");
26 }
27
28 internal static void PreferencesGUI()
29 {
30 using (new SettingsWindow.GUIScope())
31 {
32 instance.DoPreferencesGUI();
33 }
34 }
35
36 internal static EditorTool[] CreateDefaultTilePaletteEditorTools()
37 {
38 return instance.CreateDefaultTilemapEditorTools();
39 }
40
41 internal static event Action tilemapEditorToolsChanged;
42
43 private ReorderableList m_DefaultTypes;
44 private ReorderableList m_OtherTypes;
45 private bool m_Changed;
46
47 private HashSet<Type> m_AllTilemapEditorToolTypes;
48 private List<DefaultTilemapEditorTool> m_DefaultTilemapEditorToolTypes;
49 private List<DefaultTilemapEditorTool> m_OtherTilemapEditorToolTypes;
50
51 private static EditorTool[] s_DefaultTilemapEditorTools;
52
53 private void OnEnable()
54 {
55 m_DefaultTilemapEditorToolTypes = new List<DefaultTilemapEditorTool>();
56 m_OtherTilemapEditorToolTypes = new List<DefaultTilemapEditorTool>();
57
58 LoadDefaultEditorToolTypes();
59
60 m_DefaultTypes = new ReorderableList(m_DefaultTilemapEditorToolTypes, typeof(DefaultTilemapEditorTool), true, false, false, false);
61 m_DefaultTypes.drawElementCallback = OnDrawDefaultElement;
62 m_DefaultTypes.onReorderCallback = OnReorderDefaultElement;
63
64 m_OtherTypes = new ReorderableList(m_OtherTilemapEditorToolTypes, typeof(DefaultTilemapEditorTool), true, false, false, false);
65 m_OtherTypes.drawElementCallback = OnDrawOtherElement;
66
67 m_Changed = false;
68 }
69
70 private void InitializeAllTilemapEditorToolTypes()
71 {
72 m_AllTilemapEditorToolTypes = new HashSet<Type>();
73 foreach (var tilemapEditorToolType in TypeCache.GetTypesDerivedFrom(typeof(TilemapEditorTool)))
74 {
75 if (tilemapEditorToolType.IsAbstract)
76 continue;
77 m_AllTilemapEditorToolTypes.Add(tilemapEditorToolType);
78 }
79 }
80
81 private void LoadDefaultEditorToolTypes()
82 {
83 InitializeAllTilemapEditorToolTypes();
84
85 m_DefaultTilemapEditorToolTypes.Clear();
86 m_OtherTilemapEditorToolTypes.Clear();
87
88 var defaultTools = LoadTilemapEditorToolPreferencesAsset();
89 if (defaultTools == null || defaultTools.Count == 0)
90 {
91 foreach (var type in TilemapEditorTool.s_DefaultToolTypes)
92 {
93 m_DefaultTilemapEditorToolTypes.Add(new DefaultTilemapEditorTool { fullTypeName = type.FullName, tilemapEditorToolType = type });
94 }
95 }
96 else
97 {
98 foreach (var defaultTool in defaultTools)
99 {
100 if (!String.IsNullOrWhiteSpace(defaultTool.fullTypeName))
101 {
102 Type toolType = null;
103 foreach (var type in m_AllTilemapEditorToolTypes)
104 {
105 if (type.FullName == defaultTool.fullTypeName)
106 {
107 toolType = type;
108 break;
109 }
110 }
111 m_DefaultTilemapEditorToolTypes.Add(new DefaultTilemapEditorTool { fullTypeName = defaultTool.fullTypeName, tilemapEditorToolType = toolType });
112 }
113 }
114 }
115
116 HashSet<Type> otherTypes = new HashSet<Type>(m_AllTilemapEditorToolTypes);
117 foreach (var defaultType in m_DefaultTilemapEditorToolTypes)
118 {
119 if (defaultType.tilemapEditorToolType != null)
120 otherTypes.Remove(defaultType.tilemapEditorToolType);
121 }
122
123 foreach (var otherType in otherTypes)
124 {
125 m_OtherTilemapEditorToolTypes.Add(new DefaultTilemapEditorTool
126 {fullTypeName = otherType.FullName, tilemapEditorToolType = otherType});
127 }
128 }
129
130 private EditorTool[] CreateDefaultTilemapEditorTools()
131 {
132 if (m_DefaultTilemapEditorToolTypes == null)
133 LoadDefaultEditorToolTypes();
134
135 // Create Tools based on the user's preferences
136 List<EditorTool> editorTools = new List<EditorTool>();
137 foreach (var defaultTool in m_DefaultTilemapEditorToolTypes)
138 {
139 if (defaultTool.tilemapEditorToolType != null)
140 {
141 var tool = ScriptableObject.CreateInstance(defaultTool.tilemapEditorToolType) as EditorTool;
142 if (tool != null)
143 editorTools.Add(tool);
144 }
145 }
146
147 // Ensure that there are always tools for the Tile Palette
148 if (editorTools.Count == 0)
149 {
150 foreach (var defaultToolType in TilemapEditorTool.s_DefaultToolTypes)
151 {
152 editorTools.Add(ScriptableObject.CreateInstance(defaultToolType) as EditorTool);
153 }
154 }
155
156 s_DefaultTilemapEditorTools = editorTools.ToArray();
157 return s_DefaultTilemapEditorTools;
158 }
159
160 internal void UpdateTilemapEditorToolsChange()
161 {
162 tilemapEditorToolsChanged?.Invoke();
163 }
164
165 private void OnDrawDefaultElement(Rect rect, int i, bool isactive, bool isfocused)
166 {
167 if (i < 0 || i >= m_DefaultTilemapEditorToolTypes.Count)
168 return;
169
170 var type = m_DefaultTilemapEditorToolTypes[i];
171 DoDrawElement(rect, type);
172 }
173
174 private void OnDrawOtherElement(Rect rect, int i, bool isactive, bool isfocused)
175 {
176 if (i < 0 || i >= m_OtherTilemapEditorToolTypes.Count)
177 return;
178
179 var type = m_OtherTilemapEditorToolTypes[i];
180 DoDrawElement(rect, type);
181 }
182
183 private void DoDrawElement(Rect rect, DefaultTilemapEditorTool defaultType)
184 {
185 if (defaultType.tilemapEditorToolType == null)
186 {
187 EditorGUI.LabelField(rect, GUIContent.Temp(String.Format("[{0}] {1}", "Invalid", defaultType.fullTypeName)));
188 }
189 else
190 {
191 if (defaultType.toolInstance == null)
192 defaultType.toolInstance = (TilemapEditorTool)ScriptableObject.CreateInstance(defaultType.tilemapEditorToolType);
193 if (defaultType.toolInstance != null && defaultType.toolInstance.toolbarIcon != null)
194 {
195 EditorGUI.LabelField(rect, defaultType.toolInstance.toolbarIcon);
196 var size = GUI.skin.label.CalcSize(defaultType.toolInstance.toolbarIcon);
197 rect.xMin += size.x;
198 }
199 EditorGUI.LabelField(rect, GUIContent.Temp(defaultType.tilemapEditorToolType.Name, defaultType.tilemapEditorToolType.FullName));
200 }
201 }
202
203 private void OnReorderDefaultElement(ReorderableList list)
204 {
205 m_Changed = true;
206 }
207
208 private void DoPreferencesGUI()
209 {
210 if (m_DefaultTypes == null)
211 LoadDefaultEditorToolTypes();
212
213 EditorGUILayout.LabelField(TilemapEditorToolProperties.defaultToolsLabel);
214
215 EditorGUILayout.BeginHorizontal();
216
217 m_DefaultTypes.DoLayoutList();
218
219 EditorGUILayout.BeginVertical(GUILayout.Width(100));
220 if (GUILayout.Button(TilemapEditorToolProperties.addLabel))
221 {
222 var otherIndex = m_OtherTypes.index;
223 if (0 <= otherIndex && otherIndex < m_OtherTilemapEditorToolTypes.Count)
224 {
225 var otherType = m_OtherTilemapEditorToolTypes[otherIndex];
226 var defaultIndex = m_DefaultTypes.index;
227 m_DefaultTilemapEditorToolTypes.Insert(defaultIndex + 1, otherType);
228 m_OtherTilemapEditorToolTypes.RemoveAt(otherIndex);
229
230 m_DefaultTypes.index = defaultIndex + 1;
231 m_OtherTypes.index = -1;
232
233 m_Changed = true;
234 }
235 }
236 if (GUILayout.Button(TilemapEditorToolProperties.removeLabel))
237 {
238 var defaultIndex = m_DefaultTypes.index;
239 if (0 <= defaultIndex && defaultIndex < m_DefaultTilemapEditorToolTypes.Count)
240 {
241 var defaultType = m_DefaultTilemapEditorToolTypes[defaultIndex];
242 if (defaultType.tilemapEditorToolType != null)
243 {
244 var otherIndex = m_OtherTypes.index;
245 m_OtherTilemapEditorToolTypes.Insert(otherIndex + 1, defaultType);
246 m_OtherTypes.index = otherIndex + 1;
247 }
248 m_DefaultTilemapEditorToolTypes.RemoveAt(defaultIndex);
249 m_DefaultTypes.index = -1;
250
251 m_Changed = true;
252 }
253 }
254
255 EditorGUILayout.EndVertical();
256
257 m_OtherTypes.DoLayoutList();
258
259 EditorGUILayout.EndHorizontal();
260
261 EditorGUILayout.BeginHorizontal();
262 using (new EditorGUI.DisabledScope(!m_Changed))
263 {
264 if (GUILayout.Button(TilemapEditorToolProperties.saveLabel))
265 {
266 SaveTilemapEditorToolPreferences(m_DefaultTilemapEditorToolTypes);
267 m_Changed = false;
268 GridPaintingState.RepaintGridPaintPaletteWindow();
269 }
270 if (GUILayout.Button(TilemapEditorToolProperties.revertLabel))
271 {
272 LoadDefaultEditorToolTypes();
273 m_DefaultTypes.index = -1;
274 m_OtherTypes.index = -1;
275 m_Changed = false;
276 }
277 }
278 if (GUILayout.Button(TilemapEditorToolProperties.resetLabel))
279 {
280 ResetTilemapEditorToolPreferences();
281 m_DefaultTypes.index = -1;
282 m_OtherTypes.index = -1;
283 m_Changed = false;
284 GridPaintingState.RepaintGridPaintPaletteWindow();
285 }
286 EditorGUILayout.EndHorizontal();
287 }
288
289 internal void SaveTilemapEditorToolPreferences(List<DefaultTilemapEditorTool> defaultTools)
290 {
291 SaveTilemapEditorToolPreferencesAsset(defaultTools);
292 ClearExistingDefaultTilemapEditorTools();
293 LoadDefaultEditorToolTypes();
294 DeactivateToolIfNotInDefault();
295 UpdateTilemapEditorToolsChange();
296 }
297
298 internal void ResetTilemapEditorToolPreferences()
299 {
300 DeleteTilemapEditorToolPreferencesAsset();
301 ClearExistingDefaultTilemapEditorTools();
302 LoadDefaultEditorToolTypes();
303 DeactivateToolIfNotInDefault();
304 UpdateTilemapEditorToolsChange();
305 }
306
307 private static void DeleteTilemapEditorToolPreferencesAsset()
308 {
309 if (File.Exists(s_AssetPath))
310 {
311 FileUtil.DeleteFileOrDirectory(s_AssetPath);
312 }
313 }
314
315 private static void SaveTilemapEditorToolPreferencesAsset(List<DefaultTilemapEditorTool> defaultTools)
316 {
317 if (defaultTools == null)
318 return;
319
320 foreach (var defaultTool in defaultTools)
321 {
322 if (defaultTool.tilemapEditorToolType != null &&
323 !(defaultTool.tilemapEditorToolType.IsSubclassOf(typeof(TilemapEditorTool))))
324 {
325 return;
326 }
327 }
328
329 if (!Directory.Exists(s_LibraryFolderPath))
330 {
331 Directory.CreateDirectory(s_LibraryFolderPath);
332 }
333
334 var saveAsset = ScriptableObject.CreateInstance<TilemapEditorToolPreferencesAsset>();
335 saveAsset.m_UserDefaultTools = defaultTools;
336 InternalEditorUtility.SaveToSerializedFileAndForget(new Object[] { saveAsset }, s_AssetPath, true);
337 }
338
339 private static void ClearExistingDefaultTilemapEditorTools()
340 {
341 if (s_DefaultTilemapEditorTools == null)
342 return;
343
344 for (int i = 0; i < s_DefaultTilemapEditorTools.Length; ++i)
345 {
346 s_DefaultTilemapEditorTools[i] = null;
347 }
348 }
349
350 private List<DefaultTilemapEditorTool> LoadTilemapEditorToolPreferencesAsset()
351 {
352 if (!File.Exists(s_AssetPath))
353 return null;
354
355 var serializedObjects = InternalEditorUtility.LoadSerializedFileAndForget(s_AssetPath);
356 if (serializedObjects != null && serializedObjects.Length > 0)
357 {
358 var defaultTools = serializedObjects[0] as TilemapEditorToolPreferencesAsset;
359 if (defaultTools != null)
360 return defaultTools.m_UserDefaultTools;
361 }
362 return null;
363 }
364
365 private void DeactivateToolIfNotInDefault()
366 {
367 var activeToolType = ToolManager.activeToolType;
368 if (activeToolType == null ||
369 !activeToolType.IsSubclassOf(typeof(TilemapEditorTool)))
370 {
371 return;
372 }
373
374 if (s_DefaultTilemapEditorTools == null || s_DefaultTilemapEditorTools[0] == null)
375 CreateDefaultTilemapEditorTools();
376
377 foreach (var defaultToolType in s_DefaultTilemapEditorTools)
378 {
379 if (activeToolType == defaultToolType.GetType())
380 return;
381 }
382
383 ToolManager.SetActiveTool(typeof(ViewModeTool));
384 }
385 }
386}