A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEditor.U2D.Sprites;
5using UnityEditorInternal;
6using UnityEngine;
7using UnityEngine.UIElements;
8
9namespace UnityEditor._2D.Sprite.Editor
10{
11 [RequireSpriteDataProvider(typeof(ISecondaryTextureDataProvider), typeof(ITextureDataProvider))]
12 internal class SpriteSecondaryTexturesModule : SpriteEditorModuleBase
13 {
14 private static class Styles
15 {
16 public static readonly string invalidEntriesWarning = L10n.Tr("Invalid secondary Texture entries (without names or Textures) have been removed.");
17 public static readonly string invalidSourcesWarning = L10n.Tr("Source texture used as secondary Texture. This is invalid and removed.");
18 public static readonly string nameUniquenessWarning = L10n.Tr("Every secondary Texture attached to the Sprite must have a unique name.");
19 public static readonly string builtInNameCollisionWarning = L10n.Tr("The names _MainTex and _AlphaTex are reserved for internal use.");
20 public static readonly GUIContent panelTitle = EditorGUIUtility.TrTextContent("Secondary Textures");
21 public static readonly GUIContent name = EditorGUIUtility.TrTextContent("Name");
22 public static readonly GUIContent texture = EditorGUIUtility.TrTextContent("Texture");
23 public const float textFieldDropDownWidth = 18.0f;
24 }
25
26
27 ReorderableList m_ReorderableList;
28 Vector2 m_ReorderableListScrollPosition;
29 string[] m_SuggestedNames;
30 private IMGUIContainer m_SecondaryTextureInspectorContainer;
31 internal List<SecondarySpriteTexture> secondaryTextureList { get; private set; }
32
33 public override string moduleName
34 {
35 get { return Styles.panelTitle.text; }
36 }
37
38 public override bool ApplyRevert(bool apply)
39 {
40 if (apply)
41 {
42 var spriteAssetPath = "";
43 var secondaryTextureDataProvider = spriteEditor.GetDataProvider<ISecondaryTextureDataProvider>();
44 var spriteDataProvider = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
45 if (spriteDataProvider != null)
46 {
47 var assetImporter = spriteDataProvider.targetObject as AssetImporter;
48 spriteAssetPath = assetImporter != null ? assetImporter.assetPath : spriteAssetPath;
49 }
50
51 // Remove invalid entries.
52 var validEntries = secondaryTextureList.FindAll(x => (x.name != null && x.name != "" && x.texture != null));
53 if (validEntries.Count < secondaryTextureList.Count)
54 Debug.Log(Styles.invalidEntriesWarning);
55
56 // Remove entries with Sprite's source as secondary textures.
57 var finalEntries = validEntries.FindAll(x => (AssetDatabase.GetAssetPath(x.texture) != spriteAssetPath));
58 if (finalEntries.Count < validEntries.Count)
59 Debug.Log(Styles.invalidSourcesWarning);
60
61 secondaryTextureDataProvider.textures = finalEntries.ToArray();
62 }
63
64 return true;
65 }
66
67 public override bool CanBeActivated()
68 {
69 var dataProvider = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
70 return dataProvider != null && dataProvider.spriteImportMode != SpriteImportMode.None;
71 }
72
73 public override void DoPostGUI()
74 {
75 }
76
77 public void SecondaryTextureReorderableListUI()
78 {
79 using (new EditorGUI.DisabledScope(spriteEditor.editingDisabled))
80 {
81 var windowDimension = spriteEditor.windowDimension;
82
83 GUILayout.BeginArea(new Rect(0, 0, 290, 290), Styles.panelTitle, GUI.skin.window);
84 m_ReorderableListScrollPosition = GUILayout.BeginScrollView(m_ReorderableListScrollPosition);
85 m_ReorderableList.DoLayoutList();
86 GUILayout.EndScrollView();
87 GUILayout.EndArea();
88
89 // Deselect the list item if left click outside the panel area.
90 UnityEngine.Event e = UnityEngine.Event.current;
91 if (e.type == EventType.MouseDown && e.button == 0)
92 {
93 m_ReorderableList.index = -1;
94 OnSelectCallback(m_ReorderableList);
95 spriteEditor.RequestRepaint();
96 }
97 }
98 }
99
100 public override void DoMainGUI()
101 {
102 }
103
104 public override void DoToolbarGUI(Rect drawArea)
105 {
106 }
107
108 public override void OnModuleActivate()
109 {
110 var secondaryTextureDataProvider = spriteEditor.GetDataProvider<ISecondaryTextureDataProvider>();
111 secondaryTextureList = secondaryTextureDataProvider.textures == null ? new List<SecondarySpriteTexture>() : secondaryTextureDataProvider.textures.ToList();
112
113 m_ReorderableListScrollPosition = Vector2.zero;
114 m_ReorderableList = new ReorderableList(secondaryTextureList, typeof(SecondarySpriteTexture), false, false, true, true);
115 m_ReorderableList.drawElementCallback = DrawSpriteSecondaryTextureElement;
116 m_ReorderableList.onAddCallback = AddSpriteSecondaryTextureElement;
117 m_ReorderableList.onRemoveCallback = RemoveSpriteSecondaryTextureElement;
118 m_ReorderableList.onCanAddCallback = CanAddSpriteSecondaryTextureElement;
119 m_ReorderableList.elementHeightCallback = (int index) => (EditorGUIUtility.singleLineHeight * 3) + 5;
120 m_ReorderableList.onSelectCallback = OnSelectCallback;
121
122 spriteEditor.selectedSpriteRect = null;
123
124 string suggestedNamesPrefs = EditorPrefs.GetString("SecondarySpriteTexturePropertyNames");
125 if (!string.IsNullOrEmpty(suggestedNamesPrefs))
126 {
127 m_SuggestedNames = suggestedNamesPrefs.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
128
129 for (int i = 0; i < m_SuggestedNames.Length; ++i)
130 m_SuggestedNames[i] = m_SuggestedNames[i].Trim();
131
132 Array.Sort(m_SuggestedNames);
133 }
134 else
135 m_SuggestedNames = null;
136
137 m_SecondaryTextureInspectorContainer = new IMGUIContainer(SecondaryTextureReorderableListUI)
138 {
139 style =
140 {
141 flexGrow = 0,
142 flexBasis = 1,
143 flexShrink = 0,
144 minWidth = 290,
145 minHeight = 290,
146 bottom = 24,
147 right = 24,
148 position = new StyleEnum<Position>(Position.Absolute)
149 },
150 name = "SecondaryTextureInspector"
151 };
152 spriteEditor.GetMainVisualContainer().Add(m_SecondaryTextureInspectorContainer);
153 }
154
155 void OnSelectCallback(ReorderableList list)
156 {
157 // Preview the current selected secondary texture.
158 Texture2D previewTexture = null;
159 int width = 0, height = 0;
160
161 var textureDataProvider = spriteEditor.GetDataProvider<ITextureDataProvider>();
162 if (textureDataProvider != null)
163 {
164 previewTexture = textureDataProvider.previewTexture;
165 textureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
166 }
167
168 if (m_ReorderableList.index >= 0 && m_ReorderableList.index < secondaryTextureList.Count)
169 previewTexture = secondaryTextureList[m_ReorderableList.index].texture;
170
171 if (previewTexture != null)
172 spriteEditor.SetPreviewTexture(previewTexture, width, height);
173 }
174
175 public override void OnModuleDeactivate()
176 {
177 DisplayMainTexture();
178 if (spriteEditor.GetMainVisualContainer().Contains(m_SecondaryTextureInspectorContainer))
179 spriteEditor.GetMainVisualContainer().Remove(m_SecondaryTextureInspectorContainer);
180 }
181
182 void DrawSpriteSecondaryTextureElement(Rect rect, int index, bool isActive, bool isFocused)
183 {
184 bool dataModified = false;
185 float oldLabelWidth = EditorGUIUtility.labelWidth;
186 EditorGUIUtility.labelWidth = 70.0f;
187 SecondarySpriteTexture secondaryTexture = secondaryTextureList[index];
188
189 // "Name" text field
190 EditorGUI.BeginChangeCheck();
191 var r = new Rect(rect.x, rect.y + 5, rect.width - Styles.textFieldDropDownWidth, EditorGUIUtility.singleLineHeight);
192 string newName = EditorGUI.TextField(r, Styles.name, secondaryTexture.name);
193 dataModified = EditorGUI.EndChangeCheck();
194
195 // Suggested names
196 if (m_SuggestedNames != null)
197 {
198 var popupRect = new Rect(r.x + r.width, r.y, Styles.textFieldDropDownWidth, EditorGUIUtility.singleLineHeight);
199 EditorGUI.BeginChangeCheck();
200 int selected = EditorGUI.Popup(popupRect, -1, m_SuggestedNames, EditorStyles.textFieldDropDown);
201 if (EditorGUI.EndChangeCheck())
202 {
203 newName = m_SuggestedNames[selected];
204 dataModified = true;
205 }
206 }
207
208 if (dataModified)
209 {
210 if (!string.IsNullOrEmpty(newName) && newName != secondaryTexture.name && secondaryTextureList.Exists(x => x.name == newName))
211 Debug.LogWarning(Styles.nameUniquenessWarning);
212 else if (newName == "_MainTex" || newName == "_AlphaTex")
213 Debug.LogWarning(Styles.builtInNameCollisionWarning);
214 else
215 secondaryTexture.name = newName;
216 }
217
218 // "Texture" object field
219 EditorGUI.BeginChangeCheck();
220 r.width = rect.width;
221 r.y += EditorGUIUtility.singleLineHeight + 2.0f;
222 secondaryTexture.texture = EditorGUI.ObjectField(r, Styles.texture, secondaryTexture.texture, typeof(Texture2D), false) as Texture2D;
223 dataModified = dataModified || EditorGUI.EndChangeCheck();
224
225 if (dataModified)
226 {
227 secondaryTextureList[index] = secondaryTexture;
228 spriteEditor.SetDataModified();
229 }
230
231 EditorGUIUtility.labelWidth = oldLabelWidth;
232 }
233
234 void AddSpriteSecondaryTextureElement(ReorderableList list)
235 {
236 m_ReorderableListScrollPosition += new Vector2(0.0f, list.elementHeightCallback(0));
237 secondaryTextureList.Add(new SecondarySpriteTexture());
238 spriteEditor.SetDataModified();
239 }
240
241 void RemoveSpriteSecondaryTextureElement(ReorderableList list)
242 {
243 DisplayMainTexture();
244 secondaryTextureList.RemoveAt(list.index);
245 spriteEditor.SetDataModified();
246 }
247
248 bool CanAddSpriteSecondaryTextureElement(ReorderableList list)
249 {
250 return list.count < 8;
251 }
252
253 void DisplayMainTexture()
254 {
255 ITextureDataProvider textureDataProvider = spriteEditor.GetDataProvider<ITextureDataProvider>();
256 if (textureDataProvider != null && textureDataProvider.previewTexture != null)
257 {
258 Texture2D mainTexture = textureDataProvider.previewTexture;
259 int width = 0, height = 0;
260 textureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
261 spriteEditor.SetPreviewTexture(mainTexture, width, height);
262 }
263 }
264 }
265}