TMP_SpriteAssetEditor.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. using UnityEngine;
  2. using UnityEngine.TextCore;
  3. using UnityEditor;
  4. using UnityEditorInternal;
  5. using System.Collections.Generic;
  6. namespace TMPro.EditorUtilities
  7. {
  8. [CustomEditor(typeof(TMP_SpriteAsset))]
  9. public class TMP_SpriteAssetEditor : Editor
  10. {
  11. struct UI_PanelState
  12. {
  13. public static bool spriteAssetFaceInfoPanel = true;
  14. public static bool spriteAtlasInfoPanel = true;
  15. public static bool fallbackSpriteAssetPanel = true;
  16. public static bool spriteCharacterTablePanel;
  17. public static bool spriteGlyphTablePanel;
  18. }
  19. private static string[] s_UiStateLabel = new string[] { "<i>(Click to collapse)</i> ", "<i>(Click to expand)</i> " };
  20. int m_moveToIndex;
  21. int m_selectedElement = -1;
  22. int m_CurrentCharacterPage;
  23. int m_CurrentGlyphPage;
  24. const string k_UndoRedo = "UndoRedoPerformed";
  25. string m_CharacterSearchPattern;
  26. List<int> m_CharacterSearchList;
  27. bool m_IsCharacterSearchDirty;
  28. string m_GlyphSearchPattern;
  29. List<int> m_GlyphSearchList;
  30. bool m_IsGlyphSearchDirty;
  31. SerializedProperty m_FaceInfoProperty;
  32. SerializedProperty m_PointSizeProperty;
  33. SerializedProperty m_ScaleProperty;
  34. SerializedProperty m_LineHeightProperty;
  35. SerializedProperty m_AscentLineProperty;
  36. SerializedProperty m_BaselineProperty;
  37. SerializedProperty m_DescentLineProperty;
  38. SerializedProperty m_spriteAtlas_prop;
  39. SerializedProperty m_material_prop;
  40. SerializedProperty m_SpriteCharacterTableProperty;
  41. SerializedProperty m_SpriteGlyphTableProperty;
  42. ReorderableList m_fallbackSpriteAssetList;
  43. TMP_SpriteAsset m_SpriteAsset;
  44. bool isAssetDirty;
  45. float m_xOffset;
  46. float m_yOffset;
  47. float m_xAdvance;
  48. float m_scale;
  49. public void OnEnable()
  50. {
  51. m_SpriteAsset = target as TMP_SpriteAsset;
  52. m_FaceInfoProperty = serializedObject.FindProperty("m_FaceInfo");
  53. m_PointSizeProperty = m_FaceInfoProperty.FindPropertyRelative("m_PointSize");
  54. m_ScaleProperty = m_FaceInfoProperty.FindPropertyRelative("m_Scale");
  55. m_LineHeightProperty = m_FaceInfoProperty.FindPropertyRelative("m_LineHeight");
  56. m_AscentLineProperty = m_FaceInfoProperty.FindPropertyRelative("m_AscentLine");
  57. m_BaselineProperty = m_FaceInfoProperty.FindPropertyRelative("m_Baseline");
  58. m_DescentLineProperty = m_FaceInfoProperty.FindPropertyRelative("m_DescentLine");
  59. m_spriteAtlas_prop = serializedObject.FindProperty("spriteSheet");
  60. m_material_prop = serializedObject.FindProperty("material");
  61. m_SpriteCharacterTableProperty = serializedObject.FindProperty("m_SpriteCharacterTable");
  62. m_SpriteGlyphTableProperty = serializedObject.FindProperty("m_SpriteGlyphTable");
  63. // Fallback TMP Sprite Asset list
  64. m_fallbackSpriteAssetList = new ReorderableList(serializedObject, serializedObject.FindProperty("fallbackSpriteAssets"), true, true, true, true);
  65. m_fallbackSpriteAssetList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
  66. {
  67. var element = m_fallbackSpriteAssetList.serializedProperty.GetArrayElementAtIndex(index);
  68. rect.y += 2;
  69. EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none);
  70. };
  71. m_fallbackSpriteAssetList.drawHeaderCallback = rect =>
  72. {
  73. EditorGUI.LabelField(rect, new GUIContent("Fallback Sprite Asset List", "Select the Sprite Assets that will be searched and used as fallback when a given sprite is missing from this sprite asset."));
  74. };
  75. }
  76. public override void OnInspectorGUI()
  77. {
  78. //Debug.Log("OnInspectorGUI Called.");
  79. Event currentEvent = Event.current;
  80. string evt_cmd = currentEvent.commandName; // Get Current Event CommandName to check for Undo Events
  81. serializedObject.Update();
  82. // TEXTMESHPRO SPRITE INFO PANEL
  83. #region Display Sprite Asset Face Info
  84. Rect rect = EditorGUILayout.GetControlRect(false, 24);
  85. GUI.Label(rect, new GUIContent("<b>Face Info</b> - v" + m_SpriteAsset.version), TMP_UIStyleManager.sectionHeader);
  86. rect.x += rect.width - 132f;
  87. rect.y += 2;
  88. rect.width = 130f;
  89. rect.height = 18f;
  90. if (GUI.Button(rect, new GUIContent("Update Sprite Asset")))
  91. {
  92. TMP_SpriteAssetMenu.UpdateSpriteAsset(m_SpriteAsset);
  93. }
  94. EditorGUI.indentLevel = 1;
  95. EditorGUILayout.PropertyField(m_PointSizeProperty);
  96. EditorGUILayout.PropertyField(m_ScaleProperty);
  97. //EditorGUILayout.PropertyField(m_LineHeightProperty);
  98. EditorGUILayout.PropertyField(m_AscentLineProperty);
  99. EditorGUILayout.PropertyField(m_BaselineProperty);
  100. EditorGUILayout.PropertyField(m_DescentLineProperty);
  101. EditorGUILayout.Space();
  102. #endregion
  103. // ATLAS TEXTURE & MATERIAL
  104. #region Display Atlas Texture and Material
  105. rect = EditorGUILayout.GetControlRect(false, 24);
  106. if (GUI.Button(rect, new GUIContent("<b>Atlas & Material</b>"), TMP_UIStyleManager.sectionHeader))
  107. UI_PanelState.spriteAtlasInfoPanel = !UI_PanelState.spriteAtlasInfoPanel;
  108. GUI.Label(rect, (UI_PanelState.spriteAtlasInfoPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
  109. if (UI_PanelState.spriteAtlasInfoPanel)
  110. {
  111. EditorGUI.BeginChangeCheck();
  112. EditorGUILayout.PropertyField(m_spriteAtlas_prop, new GUIContent("Sprite Atlas"));
  113. if (EditorGUI.EndChangeCheck())
  114. {
  115. // Assign the new sprite atlas texture to the current material
  116. Texture2D tex = m_spriteAtlas_prop.objectReferenceValue as Texture2D;
  117. if (tex != null)
  118. {
  119. Material mat = m_material_prop.objectReferenceValue as Material;
  120. if (mat != null)
  121. mat.mainTexture = tex;
  122. }
  123. }
  124. EditorGUILayout.PropertyField(m_material_prop, new GUIContent("Default Material"));
  125. EditorGUILayout.Space();
  126. }
  127. #endregion
  128. // FALLBACK SPRITE ASSETS
  129. #region Display Sprite Fallbacks
  130. rect = EditorGUILayout.GetControlRect(false, 24);
  131. EditorGUI.indentLevel = 0;
  132. if (GUI.Button(rect, new GUIContent("<b>Fallback Sprite Assets</b>", "Select the Sprite Assets that will be searched and used as fallback when a given sprite is missing from this sprite asset."), TMP_UIStyleManager.sectionHeader))
  133. UI_PanelState.fallbackSpriteAssetPanel = !UI_PanelState.fallbackSpriteAssetPanel;
  134. GUI.Label(rect, (UI_PanelState.fallbackSpriteAssetPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
  135. if (UI_PanelState.fallbackSpriteAssetPanel)
  136. {
  137. m_fallbackSpriteAssetList.DoLayoutList();
  138. EditorGUILayout.Space();
  139. }
  140. #endregion
  141. // SPRITE CHARACTER TABLE
  142. #region Display Sprite Character Table
  143. EditorGUI.indentLevel = 0;
  144. rect = EditorGUILayout.GetControlRect(false, 24);
  145. if (GUI.Button(rect, new GUIContent("<b>Sprite Character Table</b>", "List of sprite characters contained in this sprite asset."), TMP_UIStyleManager.sectionHeader))
  146. UI_PanelState.spriteCharacterTablePanel = !UI_PanelState.spriteCharacterTablePanel;
  147. GUI.Label(rect, (UI_PanelState.spriteCharacterTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
  148. if (UI_PanelState.spriteCharacterTablePanel)
  149. {
  150. int arraySize = m_SpriteCharacterTableProperty.arraySize;
  151. int itemsPerPage = 10;
  152. // Display Glyph Management Tools
  153. EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.ExpandWidth(true));
  154. {
  155. // Search Bar implementation
  156. #region DISPLAY SEARCH BAR
  157. EditorGUILayout.BeginHorizontal();
  158. {
  159. EditorGUIUtility.labelWidth = 110f;
  160. EditorGUI.BeginChangeCheck();
  161. string searchPattern = EditorGUILayout.TextField("Sprite Search", m_CharacterSearchPattern, "SearchTextField");
  162. if (EditorGUI.EndChangeCheck() || m_IsCharacterSearchDirty)
  163. {
  164. if (string.IsNullOrEmpty(searchPattern) == false)
  165. {
  166. //GUIUtility.keyboardControl = 0;
  167. m_CharacterSearchPattern = searchPattern.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim();
  168. // Search Glyph Table for potential matches
  169. SearchCharacterTable(m_CharacterSearchPattern, ref m_CharacterSearchList);
  170. }
  171. else
  172. m_CharacterSearchPattern = null;
  173. m_IsCharacterSearchDirty = false;
  174. }
  175. string styleName = string.IsNullOrEmpty(m_CharacterSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton";
  176. if (GUILayout.Button(GUIContent.none, styleName))
  177. {
  178. GUIUtility.keyboardControl = 0;
  179. m_CharacterSearchPattern = string.Empty;
  180. }
  181. }
  182. EditorGUILayout.EndHorizontal();
  183. #endregion
  184. // Display Page Navigation
  185. if (!string.IsNullOrEmpty(m_CharacterSearchPattern))
  186. arraySize = m_CharacterSearchList.Count;
  187. // Display Page Navigation
  188. DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage);
  189. }
  190. EditorGUILayout.EndVertical();
  191. if (arraySize > 0)
  192. {
  193. // Display each SpriteInfo entry using the SpriteInfo property drawer.
  194. for (int i = itemsPerPage * m_CurrentCharacterPage; i < arraySize && i < itemsPerPage * (m_CurrentCharacterPage + 1); i++)
  195. {
  196. // Define the start of the selection region of the element.
  197. Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true));
  198. int elementIndex = i;
  199. if (!string.IsNullOrEmpty(m_CharacterSearchPattern))
  200. elementIndex = m_CharacterSearchList[i];
  201. SerializedProperty spriteCharacterProperty = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(elementIndex);
  202. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  203. {
  204. EditorGUI.BeginDisabledGroup(i != m_selectedElement);
  205. {
  206. EditorGUILayout.PropertyField(spriteCharacterProperty);
  207. }
  208. EditorGUI.EndDisabledGroup();
  209. }
  210. EditorGUILayout.EndVertical();
  211. // Define the end of the selection region of the element.
  212. Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true));
  213. // Check for Item selection
  214. Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y);
  215. if (DoSelectionCheck(selectionArea))
  216. {
  217. if (m_selectedElement == i)
  218. {
  219. m_selectedElement = -1;
  220. }
  221. else
  222. {
  223. m_selectedElement = i;
  224. GUIUtility.keyboardControl = 0;
  225. }
  226. }
  227. // Draw & Handle Section Area
  228. if (m_selectedElement == i)
  229. {
  230. // Draw selection highlight
  231. TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255));
  232. // Draw options to MoveUp, MoveDown, Add or Remove Sprites
  233. Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f);
  234. controlRect.width /= 8;
  235. // Move sprite up.
  236. bool guiEnabled = GUI.enabled;
  237. if (i == 0) { GUI.enabled = false; }
  238. if (GUI.Button(controlRect, "Up"))
  239. {
  240. SwapCharacterElements(i, i - 1);
  241. }
  242. GUI.enabled = guiEnabled;
  243. // Move sprite down.
  244. controlRect.x += controlRect.width;
  245. if (i == arraySize - 1) { GUI.enabled = false; }
  246. if (GUI.Button(controlRect, "Down"))
  247. {
  248. SwapCharacterElements(i, i + 1);
  249. }
  250. GUI.enabled = guiEnabled;
  251. // Move sprite to new index
  252. controlRect.x += controlRect.width * 2;
  253. //if (i == arraySize - 1) { GUI.enabled = false; }
  254. m_moveToIndex = EditorGUI.IntField(controlRect, m_moveToIndex);
  255. controlRect.x -= controlRect.width;
  256. if (GUI.Button(controlRect, "Goto"))
  257. {
  258. MoveCharacterToIndex(i, m_moveToIndex);
  259. }
  260. //controlRect.x += controlRect.width;
  261. GUI.enabled = guiEnabled;
  262. // Add new Sprite
  263. controlRect.x += controlRect.width * 4;
  264. if (GUI.Button(controlRect, "+"))
  265. {
  266. m_SpriteCharacterTableProperty.arraySize += 1;
  267. int index = m_SpriteCharacterTableProperty.arraySize - 1;
  268. SerializedProperty spriteInfo_prop = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(index);
  269. // Copy properties of the selected element
  270. CopyCharacterSerializedProperty(m_SpriteCharacterTableProperty.GetArrayElementAtIndex(elementIndex), ref spriteInfo_prop);
  271. //spriteInfo_prop.FindPropertyRelative("m_Index").intValue = index;
  272. serializedObject.ApplyModifiedProperties();
  273. m_IsCharacterSearchDirty = true;
  274. }
  275. // Delete selected Sprite
  276. controlRect.x += controlRect.width;
  277. if (m_selectedElement == -1) GUI.enabled = false;
  278. if (GUI.Button(controlRect, "-"))
  279. {
  280. m_SpriteCharacterTableProperty.DeleteArrayElementAtIndex(elementIndex);
  281. m_selectedElement = -1;
  282. serializedObject.ApplyModifiedProperties();
  283. m_IsCharacterSearchDirty = true;
  284. return;
  285. }
  286. }
  287. }
  288. }
  289. DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage);
  290. EditorGUIUtility.labelWidth = 40f;
  291. EditorGUIUtility.fieldWidth = 20f;
  292. GUILayout.Space(5f);
  293. // GLOBAL TOOLS
  294. #region Global Tools
  295. /*
  296. GUI.enabled = true;
  297. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  298. rect = EditorGUILayout.GetControlRect(false, 40);
  299. float width = (rect.width - 75f) / 4;
  300. EditorGUI.LabelField(rect, "Global Offsets & Scale", EditorStyles.boldLabel);
  301. rect.x += 70;
  302. bool old_ChangedState = GUI.changed;
  303. GUI.changed = false;
  304. m_xOffset = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 0, rect.y + 20, width - 5f, 18), new GUIContent("OX:"), m_xOffset);
  305. if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingX", m_xOffset);
  306. m_yOffset = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 1, rect.y + 20, width - 5f, 18), new GUIContent("OY:"), m_yOffset);
  307. if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingY", m_yOffset);
  308. m_xAdvance = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 2, rect.y + 20, width - 5f, 18), new GUIContent("ADV."), m_xAdvance);
  309. if (GUI.changed) UpdateGlobalProperty("m_HorizontalAdvance", m_xAdvance);
  310. m_scale = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 3, rect.y + 20, width - 5f, 18), new GUIContent("SF."), m_scale);
  311. if (GUI.changed) UpdateGlobalProperty("m_Scale", m_scale);
  312. EditorGUILayout.EndVertical();
  313. GUI.changed = old_ChangedState;
  314. */
  315. #endregion
  316. }
  317. #endregion
  318. // SPRITE GLYPH TABLE
  319. #region Display Sprite Glyph Table
  320. EditorGUI.indentLevel = 0;
  321. rect = EditorGUILayout.GetControlRect(false, 24);
  322. if (GUI.Button(rect, new GUIContent("<b>Sprite Glyph Table</b>", "A list of the SpriteGlyphs contained in this sprite asset."), TMP_UIStyleManager.sectionHeader))
  323. UI_PanelState.spriteGlyphTablePanel = !UI_PanelState.spriteGlyphTablePanel;
  324. GUI.Label(rect, (UI_PanelState.spriteGlyphTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
  325. if (UI_PanelState.spriteGlyphTablePanel)
  326. {
  327. int arraySize = m_SpriteGlyphTableProperty.arraySize;
  328. int itemsPerPage = 10;
  329. // Display Glyph Management Tools
  330. EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.ExpandWidth(true));
  331. {
  332. // Search Bar implementation
  333. #region DISPLAY SEARCH BAR
  334. EditorGUILayout.BeginHorizontal();
  335. {
  336. EditorGUIUtility.labelWidth = 110f;
  337. EditorGUI.BeginChangeCheck();
  338. string searchPattern = EditorGUILayout.TextField("Sprite Search", m_GlyphSearchPattern, "SearchTextField");
  339. if (EditorGUI.EndChangeCheck() || m_IsGlyphSearchDirty)
  340. {
  341. if (string.IsNullOrEmpty(searchPattern) == false)
  342. {
  343. //GUIUtility.keyboardControl = 0;
  344. m_GlyphSearchPattern = searchPattern.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim();
  345. // Search Glyph Table for potential matches
  346. SearchCharacterTable(m_GlyphSearchPattern, ref m_GlyphSearchList);
  347. }
  348. else
  349. m_GlyphSearchPattern = null;
  350. m_IsGlyphSearchDirty = false;
  351. }
  352. string styleName = string.IsNullOrEmpty(m_GlyphSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton";
  353. if (GUILayout.Button(GUIContent.none, styleName))
  354. {
  355. GUIUtility.keyboardControl = 0;
  356. m_GlyphSearchPattern = string.Empty;
  357. }
  358. }
  359. EditorGUILayout.EndHorizontal();
  360. #endregion
  361. // Display Page Navigation
  362. if (!string.IsNullOrEmpty(m_GlyphSearchPattern))
  363. arraySize = m_GlyphSearchList.Count;
  364. // Display Page Navigation
  365. DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage);
  366. }
  367. EditorGUILayout.EndVertical();
  368. if (arraySize > 0)
  369. {
  370. // Display each SpriteInfo entry using the SpriteInfo property drawer.
  371. for (int i = itemsPerPage * m_CurrentGlyphPage; i < arraySize && i < itemsPerPage * (m_CurrentGlyphPage + 1); i++)
  372. {
  373. // Define the start of the selection region of the element.
  374. Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true));
  375. int elementIndex = i;
  376. if (!string.IsNullOrEmpty(m_GlyphSearchPattern))
  377. elementIndex = m_GlyphSearchList[i];
  378. SerializedProperty spriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(elementIndex);
  379. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  380. {
  381. EditorGUI.BeginDisabledGroup(i != m_selectedElement);
  382. {
  383. EditorGUILayout.PropertyField(spriteGlyphProperty);
  384. }
  385. EditorGUI.EndDisabledGroup();
  386. }
  387. EditorGUILayout.EndVertical();
  388. // Define the end of the selection region of the element.
  389. Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true));
  390. // Check for Item selection
  391. Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y);
  392. if (DoSelectionCheck(selectionArea))
  393. {
  394. if (m_selectedElement == i)
  395. {
  396. m_selectedElement = -1;
  397. }
  398. else
  399. {
  400. m_selectedElement = i;
  401. GUIUtility.keyboardControl = 0;
  402. }
  403. }
  404. // Draw & Handle Section Area
  405. if (m_selectedElement == i)
  406. {
  407. // Draw selection highlight
  408. TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255));
  409. // Draw options to MoveUp, MoveDown, Add or Remove Sprites
  410. Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f);
  411. controlRect.width /= 8;
  412. // Move sprite up.
  413. bool guiEnabled = GUI.enabled;
  414. if (i == 0) { GUI.enabled = false; }
  415. if (GUI.Button(controlRect, "Up"))
  416. {
  417. SwapGlyphElements(i, i - 1);
  418. }
  419. GUI.enabled = guiEnabled;
  420. // Move sprite down.
  421. controlRect.x += controlRect.width;
  422. if (i == arraySize - 1) { GUI.enabled = false; }
  423. if (GUI.Button(controlRect, "Down"))
  424. {
  425. SwapGlyphElements(i, i + 1);
  426. }
  427. GUI.enabled = guiEnabled;
  428. // Move sprite to new index
  429. controlRect.x += controlRect.width * 2;
  430. //if (i == arraySize - 1) { GUI.enabled = false; }
  431. m_moveToIndex = EditorGUI.IntField(controlRect, m_moveToIndex);
  432. controlRect.x -= controlRect.width;
  433. if (GUI.Button(controlRect, "Goto"))
  434. {
  435. MoveGlyphToIndex(i, m_moveToIndex);
  436. }
  437. //controlRect.x += controlRect.width;
  438. GUI.enabled = guiEnabled;
  439. // Add new Sprite
  440. controlRect.x += controlRect.width * 4;
  441. if (GUI.Button(controlRect, "+"))
  442. {
  443. m_SpriteGlyphTableProperty.arraySize += 1;
  444. int index = m_SpriteGlyphTableProperty.arraySize - 1;
  445. SerializedProperty newSpriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(index);
  446. // Copy properties of the selected element
  447. CopyGlyphSerializedProperty(m_SpriteGlyphTableProperty.GetArrayElementAtIndex(elementIndex), ref newSpriteGlyphProperty);
  448. newSpriteGlyphProperty.FindPropertyRelative("m_Index").intValue = index;
  449. serializedObject.ApplyModifiedProperties();
  450. m_IsGlyphSearchDirty = true;
  451. //m_SpriteAsset.UpdateLookupTables();
  452. }
  453. // Delete selected Sprite
  454. controlRect.x += controlRect.width;
  455. if (m_selectedElement == -1) GUI.enabled = false;
  456. if (GUI.Button(controlRect, "-"))
  457. {
  458. SerializedProperty selectedSpriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(elementIndex);
  459. int selectedGlyphIndex = selectedSpriteGlyphProperty.FindPropertyRelative("m_Index").intValue;
  460. m_SpriteGlyphTableProperty.DeleteArrayElementAtIndex(elementIndex);
  461. // Remove all Sprite Characters referencing this glyph.
  462. for (int j = 0; j < m_SpriteCharacterTableProperty.arraySize; j++)
  463. {
  464. int glyphIndex = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(j).FindPropertyRelative("m_GlyphIndex").intValue;
  465. if (glyphIndex == selectedGlyphIndex)
  466. {
  467. // Remove character
  468. m_SpriteCharacterTableProperty.DeleteArrayElementAtIndex(j);
  469. }
  470. }
  471. m_selectedElement = -1;
  472. serializedObject.ApplyModifiedProperties();
  473. m_IsGlyphSearchDirty = true;
  474. //m_SpriteAsset.UpdateLookupTables();
  475. return;
  476. }
  477. }
  478. }
  479. }
  480. DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage);
  481. EditorGUIUtility.labelWidth = 40f;
  482. EditorGUIUtility.fieldWidth = 20f;
  483. GUILayout.Space(5f);
  484. // GLOBAL TOOLS
  485. #region Global Tools
  486. GUI.enabled = true;
  487. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  488. rect = EditorGUILayout.GetControlRect(false, 40);
  489. float width = (rect.width - 75f) / 4;
  490. EditorGUI.LabelField(rect, "Global Offsets & Scale", EditorStyles.boldLabel);
  491. rect.x += 70;
  492. bool old_ChangedState = GUI.changed;
  493. GUI.changed = false;
  494. m_xOffset = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 0, rect.y + 20, width - 5f, 18), new GUIContent("OX:"), m_xOffset);
  495. if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingX", m_xOffset);
  496. m_yOffset = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 1, rect.y + 20, width - 5f, 18), new GUIContent("OY:"), m_yOffset);
  497. if (GUI.changed) UpdateGlobalProperty("m_HorizontalBearingY", m_yOffset);
  498. m_xAdvance = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 2, rect.y + 20, width - 5f, 18), new GUIContent("ADV."), m_xAdvance);
  499. if (GUI.changed) UpdateGlobalProperty("m_HorizontalAdvance", m_xAdvance);
  500. m_scale = EditorGUI.FloatField(new Rect(rect.x + 5f + width * 3, rect.y + 20, width - 5f, 18), new GUIContent("SF."), m_scale);
  501. if (GUI.changed) UpdateGlobalProperty("m_Scale", m_scale);
  502. EditorGUILayout.EndVertical();
  503. #endregion
  504. GUI.changed = old_ChangedState;
  505. }
  506. #endregion
  507. if (serializedObject.ApplyModifiedProperties() || evt_cmd == k_UndoRedo || isAssetDirty)
  508. {
  509. if (m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty || evt_cmd == k_UndoRedo)
  510. m_SpriteAsset.UpdateLookupTables();
  511. TMPro_EventManager.ON_SPRITE_ASSET_PROPERTY_CHANGED(true, m_SpriteAsset);
  512. isAssetDirty = false;
  513. EditorUtility.SetDirty(target);
  514. }
  515. // Clear selection if mouse event was not consumed.
  516. GUI.enabled = true;
  517. if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0)
  518. m_selectedElement = -1;
  519. }
  520. /// <summary>
  521. ///
  522. /// </summary>
  523. /// <param name="arraySize"></param>
  524. /// <param name="itemsPerPage"></param>
  525. void DisplayPageNavigation(ref int currentPage, int arraySize, int itemsPerPage)
  526. {
  527. Rect pagePos = EditorGUILayout.GetControlRect(false, 20);
  528. pagePos.width /= 3;
  529. int shiftMultiplier = Event.current.shift ? 10 : 1; // Page + Shift goes 10 page forward
  530. // Previous Page
  531. GUI.enabled = currentPage > 0;
  532. if (GUI.Button(pagePos, "Previous Page"))
  533. {
  534. currentPage -= 1 * shiftMultiplier;
  535. //m_isNewPage = true;
  536. }
  537. // Page Counter
  538. GUI.enabled = true;
  539. pagePos.x += pagePos.width;
  540. int totalPages = (int)(arraySize / (float)itemsPerPage + 0.999f);
  541. GUI.Label(pagePos, "Page " + (currentPage + 1) + " / " + totalPages, TMP_UIStyleManager.centeredLabel);
  542. // Next Page
  543. pagePos.x += pagePos.width;
  544. GUI.enabled = itemsPerPage * (currentPage + 1) < arraySize;
  545. if (GUI.Button(pagePos, "Next Page"))
  546. {
  547. currentPage += 1 * shiftMultiplier;
  548. //m_isNewPage = true;
  549. }
  550. // Clamp page range
  551. currentPage = Mathf.Clamp(currentPage, 0, arraySize / itemsPerPage);
  552. GUI.enabled = true;
  553. }
  554. /// <summary>
  555. /// Method to update the properties of all sprites
  556. /// </summary>
  557. /// <param name="property"></param>
  558. /// <param name="value"></param>
  559. void UpdateGlobalProperty(string property, float value)
  560. {
  561. int arraySize = m_SpriteGlyphTableProperty.arraySize;
  562. for (int i = 0; i < arraySize; i++)
  563. {
  564. // Get a reference to the sprite glyph.
  565. SerializedProperty spriteGlyphProperty = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(i);
  566. if (property == "m_Scale")
  567. {
  568. spriteGlyphProperty.FindPropertyRelative(property).floatValue = value;
  569. }
  570. else
  571. {
  572. SerializedProperty glyphMetricsProperty = spriteGlyphProperty.FindPropertyRelative("m_Metrics");
  573. glyphMetricsProperty.FindPropertyRelative(property).floatValue = value;
  574. }
  575. }
  576. GUI.changed = false;
  577. }
  578. // Check if any of the Style elements were clicked on.
  579. private bool DoSelectionCheck(Rect selectionArea)
  580. {
  581. Event currentEvent = Event.current;
  582. switch (currentEvent.type)
  583. {
  584. case EventType.MouseDown:
  585. if (selectionArea.Contains(currentEvent.mousePosition) && currentEvent.button == 0)
  586. {
  587. currentEvent.Use();
  588. return true;
  589. }
  590. break;
  591. }
  592. return false;
  593. }
  594. /// <summary>
  595. /// Swap the sprite item at the currently selected array index to another index.
  596. /// </summary>
  597. /// <param name="selectedIndex">Selected index.</param>
  598. /// <param name="newIndex">New index.</param>
  599. void SwapCharacterElements(int selectedIndex, int newIndex)
  600. {
  601. m_SpriteCharacterTableProperty.MoveArrayElement(selectedIndex, newIndex);
  602. m_selectedElement = newIndex;
  603. m_IsCharacterSearchDirty = true;
  604. m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true;
  605. }
  606. /// <summary>
  607. /// Move Sprite Element at selected index to another index and reorder sprite list.
  608. /// </summary>
  609. /// <param name="selectedIndex"></param>
  610. /// <param name="newIndex"></param>
  611. void MoveCharacterToIndex(int selectedIndex, int newIndex)
  612. {
  613. int arraySize = m_SpriteCharacterTableProperty.arraySize;
  614. if (newIndex >= arraySize)
  615. newIndex = arraySize - 1;
  616. m_SpriteCharacterTableProperty.MoveArrayElement(selectedIndex, newIndex);
  617. m_selectedElement = newIndex;
  618. m_IsCharacterSearchDirty = true;
  619. m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true;
  620. // TODO: Need to handle switching pages if the character or glyph is moved to a different page.
  621. }
  622. /// <summary>
  623. ///
  624. /// </summary>
  625. /// <param name="selectedIndex"></param>
  626. /// <param name="newIndex"></param>
  627. void SwapGlyphElements(int selectedIndex, int newIndex)
  628. {
  629. m_SpriteGlyphTableProperty.MoveArrayElement(selectedIndex, newIndex);
  630. m_selectedElement = newIndex;
  631. m_IsGlyphSearchDirty = true;
  632. m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true;
  633. }
  634. /// <summary>
  635. /// Move Sprite Element at selected index to another index and reorder sprite list.
  636. /// </summary>
  637. /// <param name="selectedIndex"></param>
  638. /// <param name="newIndex"></param>
  639. void MoveGlyphToIndex(int selectedIndex, int newIndex)
  640. {
  641. int arraySize = m_SpriteGlyphTableProperty.arraySize;
  642. if (newIndex >= arraySize)
  643. newIndex = arraySize - 1;
  644. m_SpriteGlyphTableProperty.MoveArrayElement(selectedIndex, newIndex);
  645. m_selectedElement = newIndex;
  646. m_IsGlyphSearchDirty = true;
  647. m_SpriteAsset.m_IsSpriteAssetLookupTablesDirty = true;
  648. // TODO: Need to handle switching pages if the character or glyph is moved to a different page.
  649. }
  650. /// <summary>
  651. ///
  652. /// </summary>
  653. /// <param name="source"></param>
  654. /// <param name="target"></param>
  655. void CopyCharacterSerializedProperty(SerializedProperty source, ref SerializedProperty target)
  656. {
  657. target.FindPropertyRelative("m_Name").stringValue = source.FindPropertyRelative("m_Name").stringValue;
  658. target.FindPropertyRelative("m_HashCode").intValue = source.FindPropertyRelative("m_HashCode").intValue;
  659. target.FindPropertyRelative("m_Unicode").intValue = source.FindPropertyRelative("m_Unicode").intValue;
  660. target.FindPropertyRelative("m_GlyphIndex").intValue = source.FindPropertyRelative("m_GlyphIndex").intValue;
  661. target.FindPropertyRelative("m_Scale").floatValue = source.FindPropertyRelative("m_Scale").floatValue;
  662. }
  663. void CopyGlyphSerializedProperty(SerializedProperty srcGlyph, ref SerializedProperty dstGlyph)
  664. {
  665. // TODO : Should make a generic function which copies each of the properties.
  666. // Index
  667. dstGlyph.FindPropertyRelative("m_Index").intValue = srcGlyph.FindPropertyRelative("m_Index").intValue;
  668. // GlyphMetrics
  669. SerializedProperty srcGlyphMetrics = srcGlyph.FindPropertyRelative("m_Metrics");
  670. SerializedProperty dstGlyphMetrics = dstGlyph.FindPropertyRelative("m_Metrics");
  671. dstGlyphMetrics.FindPropertyRelative("m_Width").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Width").floatValue;
  672. dstGlyphMetrics.FindPropertyRelative("m_Height").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Height").floatValue;
  673. dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue;
  674. dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue;
  675. dstGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue;
  676. // GlyphRect
  677. SerializedProperty srcGlyphRect = srcGlyph.FindPropertyRelative("m_GlyphRect");
  678. SerializedProperty dstGlyphRect = dstGlyph.FindPropertyRelative("m_GlyphRect");
  679. dstGlyphRect.FindPropertyRelative("m_X").intValue = srcGlyphRect.FindPropertyRelative("m_X").intValue;
  680. dstGlyphRect.FindPropertyRelative("m_Y").intValue = srcGlyphRect.FindPropertyRelative("m_Y").intValue;
  681. dstGlyphRect.FindPropertyRelative("m_Width").intValue = srcGlyphRect.FindPropertyRelative("m_Width").intValue;
  682. dstGlyphRect.FindPropertyRelative("m_Height").intValue = srcGlyphRect.FindPropertyRelative("m_Height").intValue;
  683. dstGlyph.FindPropertyRelative("m_Scale").floatValue = srcGlyph.FindPropertyRelative("m_Scale").floatValue;
  684. dstGlyph.FindPropertyRelative("m_AtlasIndex").intValue = srcGlyph.FindPropertyRelative("m_AtlasIndex").intValue;
  685. }
  686. /// <summary>
  687. ///
  688. /// </summary>
  689. /// <param name="searchPattern"></param>
  690. /// <returns></returns>
  691. void SearchCharacterTable(string searchPattern, ref List<int> searchResults)
  692. {
  693. if (searchResults == null) searchResults = new List<int>();
  694. searchResults.Clear();
  695. int arraySize = m_SpriteCharacterTableProperty.arraySize;
  696. for (int i = 0; i < arraySize; i++)
  697. {
  698. SerializedProperty sourceSprite = m_SpriteCharacterTableProperty.GetArrayElementAtIndex(i);
  699. // Check for potential match against array index
  700. if (i.ToString().Contains(searchPattern))
  701. {
  702. searchResults.Add(i);
  703. continue;
  704. }
  705. // Check for potential match against decimal id
  706. int id = sourceSprite.FindPropertyRelative("m_GlyphIndex").intValue;
  707. if (id.ToString().Contains(searchPattern))
  708. {
  709. searchResults.Add(i);
  710. continue;
  711. }
  712. // Check for potential match against name
  713. string name = sourceSprite.FindPropertyRelative("m_Name").stringValue.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim();
  714. if (name.Contains(searchPattern))
  715. {
  716. searchResults.Add(i);
  717. continue;
  718. }
  719. }
  720. }
  721. void SearchGlyphTable(string searchPattern, ref List<int> searchResults)
  722. {
  723. if (searchResults == null) searchResults = new List<int>();
  724. searchResults.Clear();
  725. int arraySize = m_SpriteGlyphTableProperty.arraySize;
  726. for (int i = 0; i < arraySize; i++)
  727. {
  728. SerializedProperty sourceSprite = m_SpriteGlyphTableProperty.GetArrayElementAtIndex(i);
  729. // Check for potential match against array index
  730. if (i.ToString().Contains(searchPattern))
  731. {
  732. searchResults.Add(i);
  733. continue;
  734. }
  735. // Check for potential match against decimal id
  736. int id = sourceSprite.FindPropertyRelative("m_GlyphIndex").intValue;
  737. if (id.ToString().Contains(searchPattern))
  738. {
  739. searchResults.Add(i);
  740. continue;
  741. }
  742. // Check for potential match against name
  743. string name = sourceSprite.FindPropertyRelative("m_Name").stringValue.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim();
  744. if (name.Contains(searchPattern))
  745. {
  746. searchResults.Add(i);
  747. continue;
  748. }
  749. }
  750. }
  751. }
  752. }