TMP_CharacterPropertyDrawer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. using UnityEngine;
  2. using UnityEngine.TextCore;
  3. using UnityEngine.TextCore.LowLevel;
  4. using UnityEditor;
  5. using System.Collections;
  6. namespace TMPro.EditorUtilities
  7. {
  8. [CustomPropertyDrawer(typeof(TMP_Character))]
  9. public class TMP_CharacterPropertyDrawer : PropertyDrawer
  10. {
  11. //[SerializeField]
  12. //static Material s_InternalSDFMaterial;
  13. //[SerializeField]
  14. //static Material s_InternalBitmapMaterial;
  15. int m_GlyphSelectedForEditing = -1;
  16. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  17. {
  18. SerializedProperty prop_Unicode = property.FindPropertyRelative("m_Unicode");
  19. SerializedProperty prop_GlyphIndex = property.FindPropertyRelative("m_GlyphIndex");
  20. SerializedProperty prop_Scale = property.FindPropertyRelative("m_Scale");
  21. GUIStyle style = new GUIStyle(EditorStyles.label);
  22. style.richText = true;
  23. EditorGUIUtility.labelWidth = 40f;
  24. EditorGUIUtility.fieldWidth = 50;
  25. Rect rect = new Rect(position.x + 50, position.y, position.width, 49);
  26. // Display non-editable fields
  27. if (GUI.enabled == false)
  28. {
  29. int unicode = prop_Unicode.intValue;
  30. EditorGUI.LabelField(new Rect(rect.x, rect.y, 120f, 18), new GUIContent("Unicode: <color=#FFFF80>0x" + unicode.ToString("X") + "</color>"), style);
  31. EditorGUI.LabelField(new Rect(rect.x + 115, rect.y, 120f, 18), unicode <= 0xFFFF ? new GUIContent("UTF16: <color=#FFFF80>\\u" + unicode.ToString("X4") + "</color>") : new GUIContent("UTF32: <color=#FFFF80>\\U" + unicode.ToString("X8") + "</color>"), style);
  32. EditorGUI.LabelField(new Rect(rect.x, rect.y + 18, 120, 18), new GUIContent("Glyph ID: <color=#FFFF80>" + prop_GlyphIndex.intValue + "</color>"), style);
  33. EditorGUI.LabelField(new Rect(rect.x, rect.y + 36, 80, 18), new GUIContent("Scale: <color=#FFFF80>" + prop_Scale.floatValue + "</color>"), style);
  34. // Draw Glyph (if exists)
  35. DrawGlyph(position, property);
  36. }
  37. else // Display editable fields
  38. {
  39. EditorGUIUtility.labelWidth = 55f;
  40. GUI.SetNextControlName("Unicode Input");
  41. EditorGUI.BeginChangeCheck();
  42. string unicode = EditorGUI.TextField(new Rect(rect.x, rect.y, 120, 18), "Unicode:", prop_Unicode.intValue.ToString("X"));
  43. if (GUI.GetNameOfFocusedControl() == "Unicode Input")
  44. {
  45. //Filter out unwanted characters.
  46. char chr = Event.current.character;
  47. if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F'))
  48. {
  49. Event.current.character = '\0';
  50. }
  51. }
  52. if (EditorGUI.EndChangeCheck())
  53. {
  54. // Update Unicode value
  55. prop_Unicode.intValue = TMP_TextUtilities.StringHexToInt(unicode);
  56. }
  57. // Cache current glyph index in case it needs to be restored if the new glyph index is invalid.
  58. int currentGlyphIndex = prop_GlyphIndex.intValue;
  59. EditorGUIUtility.labelWidth = 59f;
  60. EditorGUI.BeginChangeCheck();
  61. EditorGUI.DelayedIntField(new Rect(rect.x, rect.y + 18, 100, 18), prop_GlyphIndex, new GUIContent("Glyph ID:"));
  62. if (EditorGUI.EndChangeCheck())
  63. {
  64. // Get a reference to the font asset
  65. TMP_FontAsset fontAsset = property.serializedObject.targetObject as TMP_FontAsset;
  66. // Make sure new glyph index is valid.
  67. int elementIndex = fontAsset.glyphTable.FindIndex(item => item.index == prop_GlyphIndex.intValue);
  68. if (elementIndex == -1)
  69. prop_GlyphIndex.intValue = currentGlyphIndex;
  70. else
  71. fontAsset.m_IsFontAssetLookupTablesDirty = true;
  72. }
  73. int glyphIndex = prop_GlyphIndex.intValue;
  74. // Reset glyph selection if new character has been selected.
  75. if (GUI.enabled && m_GlyphSelectedForEditing != glyphIndex)
  76. m_GlyphSelectedForEditing = -1;
  77. // Display button to edit the glyph data.
  78. if (GUI.Button(new Rect(rect.x + 120, rect.y + 18, 75, 18), new GUIContent("Edit Glyph")))
  79. {
  80. if (m_GlyphSelectedForEditing == -1)
  81. m_GlyphSelectedForEditing = glyphIndex;
  82. else
  83. m_GlyphSelectedForEditing = -1;
  84. // Button clicks should not result in potential change.
  85. GUI.changed = false;
  86. }
  87. // Show the glyph property drawer if selected
  88. if (glyphIndex == m_GlyphSelectedForEditing && GUI.enabled)
  89. {
  90. // Get a reference to the font asset
  91. TMP_FontAsset fontAsset = property.serializedObject.targetObject as TMP_FontAsset;
  92. if (fontAsset != null)
  93. {
  94. // Get the index of the glyph in the font asset glyph table.
  95. int elementIndex = fontAsset.glyphTable.FindIndex(item => item.index == glyphIndex);
  96. if (elementIndex != -1)
  97. {
  98. SerializedProperty prop_GlyphTable = property.serializedObject.FindProperty("m_GlyphTable");
  99. SerializedProperty prop_Glyph = prop_GlyphTable.GetArrayElementAtIndex(elementIndex);
  100. SerializedProperty prop_GlyphMetrics = prop_Glyph.FindPropertyRelative("m_Metrics");
  101. SerializedProperty prop_GlyphRect = prop_Glyph.FindPropertyRelative("m_GlyphRect");
  102. Rect newRect = EditorGUILayout.GetControlRect(false, 115);
  103. EditorGUI.DrawRect(new Rect(newRect.x + 52, newRect.y - 20, newRect.width - 52, newRect.height - 5), new Color(0.1f, 0.1f, 0.1f, 0.45f));
  104. EditorGUI.DrawRect(new Rect(newRect.x + 53, newRect.y - 19, newRect.width - 54, newRect.height - 7), new Color(0.3f, 0.3f, 0.3f, 0.8f));
  105. // Display GlyphRect
  106. newRect.x += 55;
  107. newRect.y -= 18;
  108. newRect.width += 5;
  109. EditorGUI.PropertyField(newRect, prop_GlyphRect);
  110. // Display GlyphMetrics
  111. newRect.y += 45;
  112. EditorGUI.PropertyField(newRect, prop_GlyphMetrics);
  113. rect.y += 120;
  114. }
  115. }
  116. }
  117. EditorGUIUtility.labelWidth = 39f;
  118. EditorGUI.PropertyField(new Rect(rect.x, rect.y + 36, 80, 18), prop_Scale, new GUIContent("Scale:"));
  119. // Draw Glyph (if exists)
  120. DrawGlyph(position, property);
  121. }
  122. }
  123. public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  124. {
  125. return 58;
  126. }
  127. void DrawGlyph(Rect position, SerializedProperty property)
  128. {
  129. // Get a reference to the atlas texture
  130. TMP_FontAsset fontAsset = property.serializedObject.targetObject as TMP_FontAsset;
  131. if (fontAsset == null)
  132. return;
  133. // Get a reference to the Glyph Table
  134. SerializedProperty prop_GlyphTable = property.serializedObject.FindProperty("m_GlyphTable");
  135. int glyphIndex = property.FindPropertyRelative("m_GlyphIndex").intValue;
  136. int elementIndex = fontAsset.glyphTable.FindIndex(item => item.index == glyphIndex);
  137. // Return if we can't find the glyph
  138. if (elementIndex == -1)
  139. return;
  140. SerializedProperty prop_Glyph = prop_GlyphTable.GetArrayElementAtIndex(elementIndex);
  141. // Get reference to atlas texture.
  142. int atlasIndex = prop_Glyph.FindPropertyRelative("m_AtlasIndex").intValue;
  143. Texture2D atlasTexture = fontAsset.atlasTextures.Length > atlasIndex ? fontAsset.atlasTextures[atlasIndex] : null;
  144. if (atlasTexture == null)
  145. return;
  146. Material mat;
  147. if (((GlyphRasterModes)fontAsset.atlasRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP)
  148. {
  149. mat = TMP_FontAssetEditor.internalBitmapMaterial;
  150. if (mat == null)
  151. return;
  152. mat.mainTexture = atlasTexture;
  153. mat.SetColor("_Color", Color.white);
  154. }
  155. else
  156. {
  157. mat = TMP_FontAssetEditor.internalSDFMaterial;
  158. if (mat == null)
  159. return;
  160. mat.mainTexture = atlasTexture;
  161. mat.SetFloat(ShaderUtilities.ID_GradientScale, fontAsset.atlasPadding + 1);
  162. }
  163. // Draw glyph
  164. Rect glyphDrawPosition = new Rect(position.x, position.y, 48, 58);
  165. SerializedProperty prop_GlyphRect = prop_Glyph.FindPropertyRelative("m_GlyphRect");
  166. int glyphOriginX = prop_GlyphRect.FindPropertyRelative("m_X").intValue;
  167. int glyphOriginY = prop_GlyphRect.FindPropertyRelative("m_Y").intValue;
  168. int glyphWidth = prop_GlyphRect.FindPropertyRelative("m_Width").intValue;
  169. int glyphHeight = prop_GlyphRect.FindPropertyRelative("m_Height").intValue;
  170. float normalizedHeight = fontAsset.faceInfo.ascentLine - fontAsset.faceInfo.descentLine;
  171. float scale = glyphDrawPosition.width / normalizedHeight;
  172. // Compute the normalized texture coordinates
  173. Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height);
  174. if (Event.current.type == EventType.Repaint)
  175. {
  176. glyphDrawPosition.x += (glyphDrawPosition.width - glyphWidth * scale) / 2;
  177. glyphDrawPosition.y += (glyphDrawPosition.height - glyphHeight * scale) / 2;
  178. glyphDrawPosition.width = glyphWidth * scale;
  179. glyphDrawPosition.height = glyphHeight * scale;
  180. // Could switch to using the default material of the font asset which would require passing scale to the shader.
  181. Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat);
  182. }
  183. }
  184. }
  185. }