using UnityEngine; using UnityEditor; using UnityEditorInternal; using System.Collections; using System.Collections.Generic; namespace TMPro.EditorUtilities { [CustomPropertyDrawer(typeof(TMP_FontWeights))] public class FontWeightDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { SerializedProperty prop_regular = property.FindPropertyRelative("regularTypeface"); SerializedProperty prop_italic = property.FindPropertyRelative("italicTypeface"); float width = position.width; position.width = EditorGUIUtility.labelWidth; EditorGUI.LabelField(position, label); int oldIndent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; // NORMAL FACETYPE if (label.text[0] == '4') GUI.enabled = false; position.x += position.width; position.width = (width - position.width) / 2; EditorGUI.PropertyField(position, prop_regular, GUIContent.none); // ITALIC FACETYPE GUI.enabled = true; position.x += position.width; EditorGUI.PropertyField(position, prop_italic, GUIContent.none); EditorGUI.indentLevel = oldIndent; } } [CustomEditor(typeof(TMP_FontAsset))] public class TMP_FontAssetEditor : Editor { private struct UI_PanelState { public static bool fontSubAssetsPanel = true; public static bool fontWeightPanel = true; public static bool fallbackFontAssetPanel = true; public static bool glyphInfoPanel = false; public static bool kerningInfoPanel = false; } private struct Warning { public bool isEnabled; public double expirationTime; } private int m_CurrentGlyphPage = 0; private int m_CurrentKerningPage = 0; private int m_SelectedGlyphRecord = -1; private int m_SelectedAdjustmentRecord = -1; private string m_dstGlyphID; private const string k_placeholderUnicodeHex = "Unicode Hex ID"; private string m_unicodeHexLabel = k_placeholderUnicodeHex; private Warning m_AddGlyphWarning; private string m_GlyphSearchPattern; private List m_GlyphSearchList; private string m_KerningTableSearchPattern; private List m_KerningTableSearchList; private bool m_isSearchDirty; private const string k_UndoRedo = "UndoRedoPerformed"; private SerializedProperty font_atlas_prop; private SerializedProperty font_material_prop; private SerializedProperty fontWeights_prop; //private SerializedProperty fallbackFontAssets_prop; private ReorderableList m_list; private SerializedProperty font_normalStyle_prop; private SerializedProperty font_normalSpacing_prop; private SerializedProperty font_boldStyle_prop; private SerializedProperty font_boldSpacing_prop; private SerializedProperty font_italicStyle_prop; private SerializedProperty font_tabSize_prop; private SerializedProperty m_fontInfo_prop; private SerializedProperty m_glyphInfoList_prop; private SerializedProperty m_kerningInfo_prop; private KerningTable m_kerningTable; private SerializedProperty m_kerningPairs_prop; private SerializedProperty m_kerningPair_prop; private TMP_FontAsset m_fontAsset; private Material[] m_materialPresets; private bool isAssetDirty = false; private int errorCode; private System.DateTime timeStamp; public void OnEnable() { font_atlas_prop = serializedObject.FindProperty("atlas"); font_material_prop = serializedObject.FindProperty("material"); fontWeights_prop = serializedObject.FindProperty("fontWeights"); m_list = new ReorderableList(serializedObject, serializedObject.FindProperty("fallbackFontAssets"), true, true, true, true); m_list.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { var element = m_list.serializedProperty.GetArrayElementAtIndex(index); rect.y += 2; EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none); }; m_list.drawHeaderCallback = rect => { EditorGUI.LabelField(rect, "Fallback Font Asset List"); }; font_normalStyle_prop = serializedObject.FindProperty("normalStyle"); font_normalSpacing_prop = serializedObject.FindProperty("normalSpacingOffset"); font_boldStyle_prop = serializedObject.FindProperty("boldStyle"); font_boldSpacing_prop = serializedObject.FindProperty("boldSpacing"); font_italicStyle_prop = serializedObject.FindProperty("italicStyle"); font_tabSize_prop = serializedObject.FindProperty("tabSize"); m_fontInfo_prop = serializedObject.FindProperty("m_fontInfo"); m_glyphInfoList_prop = serializedObject.FindProperty("m_glyphInfoList"); m_kerningInfo_prop = serializedObject.FindProperty("m_kerningInfo"); m_kerningPair_prop = serializedObject.FindProperty("m_kerningPair"); m_kerningPairs_prop = m_kerningInfo_prop.FindPropertyRelative("kerningPairs"); m_fontAsset = target as TMP_FontAsset; m_kerningTable = m_fontAsset.kerningInfo; m_materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset); m_GlyphSearchList = new List(); m_KerningTableSearchList = new List(); } public override void OnInspectorGUI() { // Check Warnings //Debug.Log("OnInspectorGUI Called."); Event currentEvent = Event.current; serializedObject.Update(); // TextMeshPro Font Info Panel Rect rect = EditorGUILayout.GetControlRect(); GUI.Label(rect, "Face Info", EditorStyles.boldLabel); rect.x += rect.width - 130f; rect.width = 130f; if (GUI.Button(rect, "Update Atlas Texture")) { TMPro_FontAssetCreatorWindow.ShowFontAtlasCreatorWindow(target as TMP_FontAsset); } EditorGUI.indentLevel = 1; GUI.enabled = false; // Lock UI float labelWidth = EditorGUIUtility.labelWidth; float fieldWidth = EditorGUIUtility.fieldWidth; EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Name"), new GUIContent("Font Source")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("PointSize")); GUI.enabled = true; EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Scale")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("LineHeight")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Ascender")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("CapHeight")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Baseline")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Descender")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Underline"), new GUIContent("Underline Offset")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("strikethrough"), new GUIContent("Strikethrough Offset")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("SuperscriptOffset")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("SubscriptOffset")); SerializedProperty subSize_prop = m_fontInfo_prop.FindPropertyRelative("SubSize"); EditorGUILayout.PropertyField(subSize_prop, new GUIContent("Super / Subscript Size")); subSize_prop.floatValue = Mathf.Clamp(subSize_prop.floatValue, 0.25f, 1f); GUI.enabled = false; //EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Padding")); //GUILayout.label("Atlas Size"); EditorGUI.indentLevel = 1; EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("Padding")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("AtlasWidth"), new GUIContent("Width")); EditorGUILayout.PropertyField(m_fontInfo_prop.FindPropertyRelative("AtlasHeight"), new GUIContent("Height")); GUI.enabled = true; EditorGUILayout.Space(); EditorGUI.indentLevel = 0; UI_PanelState.fontSubAssetsPanel = EditorGUILayout.Foldout(UI_PanelState.fontSubAssetsPanel, new GUIContent("Font Sub-Assets"), true, TMP_UIStyleManager.boldFoldout); if (UI_PanelState.fontSubAssetsPanel) { GUI.enabled = false; EditorGUI.indentLevel = 1; EditorGUILayout.PropertyField(font_atlas_prop, new GUIContent("Font Atlas")); EditorGUILayout.PropertyField(font_material_prop, new GUIContent("Font Material")); GUI.enabled = true; EditorGUILayout.Space(); } string evt_cmd = Event.current.commandName; // Get Current Event CommandName to check for Undo Events // FONT SETTINGS EditorGUI.indentLevel = 0; UI_PanelState.fontWeightPanel = EditorGUILayout.Foldout(UI_PanelState.fontWeightPanel, new GUIContent("Font Weights", "The Font Assets that will be used for different font weights and the settings used to simulate a typeface when no asset is available."), true, TMP_UIStyleManager.boldFoldout); if (UI_PanelState.fontWeightPanel) { EditorGUIUtility.labelWidth *= 0.75f; EditorGUIUtility.fieldWidth *= 0.25f; EditorGUILayout.BeginVertical(); EditorGUI.indentLevel = 1; rect = EditorGUILayout.GetControlRect(true); rect.x += EditorGUIUtility.labelWidth; rect.width = (rect.width - EditorGUIUtility.labelWidth) / 2f; GUI.Label(rect, "Normal Style", EditorStyles.boldLabel); rect.x += rect.width; GUI.Label(rect, "Italic Style", EditorStyles.boldLabel); EditorGUI.indentLevel = 1; //EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(1), new GUIContent("100 - Thin")); //EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(2), new GUIContent("200 - Extra-Light")); //EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(3), new GUIContent("300 - Light")); EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(4), new GUIContent("400 - Regular")); //EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(5), new GUIContent("500 - Medium")); //EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(6), new GUIContent("600 - Demi-Bold")); EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(7), new GUIContent("700 - Bold")); //EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(8), new GUIContent("800 - Heavy")); //EditorGUILayout.PropertyField(fontWeights_prop.GetArrayElementAtIndex(9), new GUIContent("900 - Black")); EditorGUILayout.EndVertical(); EditorGUILayout.Space(); EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(font_normalStyle_prop, new GUIContent("Normal Weight")); font_normalStyle_prop.floatValue = Mathf.Clamp(font_normalStyle_prop.floatValue, -3.0f, 3.0f); if (GUI.changed || evt_cmd == k_UndoRedo) { GUI.changed = false; // Modify the material property on matching material presets. for (int i = 0; i < m_materialPresets.Length; i++) m_materialPresets[i].SetFloat("_WeightNormal", font_normalStyle_prop.floatValue); } EditorGUILayout.PropertyField(font_boldStyle_prop, new GUIContent("Bold Weight")); font_boldStyle_prop.floatValue = Mathf.Clamp(font_boldStyle_prop.floatValue, -3.0f, 3.0f); if (GUI.changed || evt_cmd == k_UndoRedo) { GUI.changed = false; // Modify the material property on matching material presets. for (int i = 0; i < m_materialPresets.Length; i++) m_materialPresets[i].SetFloat("_WeightBold", font_boldStyle_prop.floatValue); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(font_normalSpacing_prop, new GUIContent("Spacing Offset")); font_normalSpacing_prop.floatValue = Mathf.Clamp(font_normalSpacing_prop.floatValue, -100, 100); if (GUI.changed || evt_cmd == k_UndoRedo) { GUI.changed = false; } EditorGUILayout.PropertyField(font_boldSpacing_prop, new GUIContent("Bold Spacing")); font_boldSpacing_prop.floatValue = Mathf.Clamp(font_boldSpacing_prop.floatValue, 0, 100); if (GUI.changed || evt_cmd == k_UndoRedo) { GUI.changed = false; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(font_italicStyle_prop, new GUIContent("Italic Style")); font_italicStyle_prop.intValue = Mathf.Clamp(font_italicStyle_prop.intValue, 15, 60); EditorGUILayout.PropertyField(font_tabSize_prop, new GUIContent("Tab Multiple")); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); EditorGUILayout.Space(); } EditorGUIUtility.labelWidth = 0; EditorGUIUtility.fieldWidth = 0; // FALLBACK FONT ASSETS EditorGUI.indentLevel = 0; UI_PanelState.fallbackFontAssetPanel = EditorGUILayout.Foldout(UI_PanelState.fallbackFontAssetPanel, new GUIContent("Fallback Font Assets", "Select the Font Assets that will be searched and used as fallback when characters are missing from this font asset."), true, TMP_UIStyleManager.boldFoldout); if (UI_PanelState.fallbackFontAssetPanel) { EditorGUIUtility.labelWidth = 120; EditorGUI.indentLevel = 0; m_list.DoLayoutList(); EditorGUILayout.Space(); } // GLYPH INFO TABLE #region Glyph Table EditorGUIUtility.labelWidth = labelWidth; EditorGUIUtility.fieldWidth = fieldWidth; EditorGUI.indentLevel = 0; UI_PanelState.glyphInfoPanel = EditorGUILayout.Foldout(UI_PanelState.glyphInfoPanel, new GUIContent("Glyph Table"), true, TMP_UIStyleManager.boldFoldout); if (UI_PanelState.glyphInfoPanel) { int arraySize = m_glyphInfoList_prop.arraySize; int itemsPerPage = 15; // Display Glyph Management Tools EditorGUILayout.BeginVertical(EditorStyles.helpBox); { // Search Bar implementation #region DISPLAY SEARCH BAR EditorGUILayout.BeginHorizontal(); { EditorGUIUtility.labelWidth = 130f; EditorGUI.BeginChangeCheck(); string searchPattern = EditorGUILayout.TextField("Glyph Search", m_GlyphSearchPattern, "SearchTextField"); if (EditorGUI.EndChangeCheck() || m_isSearchDirty) { if (string.IsNullOrEmpty(searchPattern) == false) { m_GlyphSearchPattern = searchPattern; // Search Glyph Table for potential matches SearchGlyphTable(m_GlyphSearchPattern, ref m_GlyphSearchList); } else m_GlyphSearchPattern = null; m_isSearchDirty = false; } string styleName = string.IsNullOrEmpty(m_GlyphSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; if (GUILayout.Button(GUIContent.none, styleName)) { GUIUtility.keyboardControl = 0; m_GlyphSearchPattern = string.Empty; } } EditorGUILayout.EndHorizontal(); #endregion // Display Page Navigation if (!string.IsNullOrEmpty(m_GlyphSearchPattern)) arraySize = m_GlyphSearchList.Count; DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage); } EditorGUILayout.EndVertical(); // Display Glyph Table Elements if (arraySize > 0) { // Display each GlyphInfo entry using the GlyphInfo property drawer. for (int i = itemsPerPage * m_CurrentGlyphPage; i < arraySize && i < itemsPerPage * (m_CurrentGlyphPage + 1); i++) { // Define the start of the selection region of the element. Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); int elementIndex = i; if (!string.IsNullOrEmpty(m_GlyphSearchPattern)) elementIndex = m_GlyphSearchList[i]; SerializedProperty glyphInfo = m_glyphInfoList_prop.GetArrayElementAtIndex(elementIndex); EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUI.BeginDisabledGroup(i != m_SelectedGlyphRecord); { EditorGUILayout.PropertyField(glyphInfo); } EditorGUI.EndDisabledGroup(); EditorGUILayout.EndVertical(); // Define the end of the selection region of the element. Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); // Check for Item selection Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); if (DoSelectionCheck(selectionArea)) { if (m_SelectedGlyphRecord == i) m_SelectedGlyphRecord = -1; else { m_SelectedGlyphRecord = i; m_AddGlyphWarning.isEnabled = false; m_unicodeHexLabel = k_placeholderUnicodeHex; GUIUtility.keyboardControl = 0; } } // Draw Selection Highlight and Glyph Options if (m_SelectedGlyphRecord == i) { TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); // Draw Glyph management options Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); float optionAreaWidth = controlRect.width * 0.6f; float btnWidth = optionAreaWidth / 3; Rect position = new Rect(controlRect.x + controlRect.width * .4f, controlRect.y, btnWidth, controlRect.height); // Copy Selected Glyph to Target Glyph ID GUI.enabled = !string.IsNullOrEmpty(m_dstGlyphID); if (GUI.Button(position, new GUIContent("Copy to"))) { GUIUtility.keyboardControl = 0; // Convert Hex Value to Decimal int dstGlyphID = TMP_TextUtilities.StringToInt(m_dstGlyphID); //Add new glyph at target Unicode hex id. if (!AddNewGlyph(elementIndex, dstGlyphID)) { m_AddGlyphWarning.isEnabled = true; m_AddGlyphWarning.expirationTime = EditorApplication.timeSinceStartup + 1; } m_dstGlyphID = string.Empty; m_isSearchDirty = true; TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset); } // Target Glyph ID GUI.enabled = true; position.x += btnWidth; GUI.SetNextControlName("GlyphID_Input"); m_dstGlyphID = EditorGUI.TextField(position, m_dstGlyphID); // Placeholder text EditorGUI.LabelField(position, new GUIContent(m_unicodeHexLabel, "The Unicode (Hex) ID of the duplicated Glyph"), TMP_UIStyleManager.label); // Only filter the input when the destination glyph ID text field has focus. if (GUI.GetNameOfFocusedControl() == "GlyphID_Input") { m_unicodeHexLabel = string.Empty; //Filter out unwanted characters. char chr = Event.current.character; if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F')) { Event.current.character = '\0'; } } else m_unicodeHexLabel = k_placeholderUnicodeHex; // Remove Glyph position.x += btnWidth; if (GUI.Button(position, "Remove")) { GUIUtility.keyboardControl = 0; RemoveGlyphFromList(elementIndex); isAssetDirty = true; m_SelectedGlyphRecord = -1; m_isSearchDirty = true; break; } if (m_AddGlyphWarning.isEnabled && EditorApplication.timeSinceStartup < m_AddGlyphWarning.expirationTime) { EditorGUILayout.HelpBox("The Destination Glyph ID already exists", MessageType.Warning); } } } } DisplayPageNavigation(ref m_CurrentGlyphPage, arraySize, itemsPerPage); EditorGUILayout.Space(); } #endregion // KERNING TABLE PANEL #region Kerning Table EditorGUIUtility.labelWidth = labelWidth; EditorGUIUtility.fieldWidth = fieldWidth; EditorGUI.indentLevel = 0; UI_PanelState.kerningInfoPanel = EditorGUILayout.Foldout(UI_PanelState.kerningInfoPanel, new GUIContent("Glyph Adjustment Table"), true, TMP_UIStyleManager.boldFoldout); if (UI_PanelState.kerningInfoPanel) { int arraySize = m_kerningPairs_prop.arraySize; int itemsPerPage = 20; // Display Kerning Pair Management Tools EditorGUILayout.BeginVertical(EditorStyles.helpBox); { // Search Bar implementation #region DISPLAY SEARCH BAR EditorGUILayout.BeginHorizontal(); { EditorGUIUtility.labelWidth = 150f; EditorGUI.BeginChangeCheck(); string searchPattern = EditorGUILayout.TextField("Adjustment Pair Search", m_KerningTableSearchPattern, "SearchTextField"); if (EditorGUI.EndChangeCheck() || m_isSearchDirty) { if (string.IsNullOrEmpty(searchPattern) == false) { m_KerningTableSearchPattern = searchPattern; // Search Glyph Table for potential matches SearchKerningTable(m_KerningTableSearchPattern, ref m_KerningTableSearchList); } else m_KerningTableSearchPattern = null; m_isSearchDirty = false; } string styleName = string.IsNullOrEmpty(m_KerningTableSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton"; if (GUILayout.Button(GUIContent.none, styleName)) { GUIUtility.keyboardControl = 0; m_KerningTableSearchPattern = string.Empty; } } EditorGUILayout.EndHorizontal(); #endregion // Display Page Navigation if (!string.IsNullOrEmpty(m_KerningTableSearchPattern)) arraySize = m_KerningTableSearchList.Count; DisplayPageNavigation(ref m_CurrentKerningPage, arraySize, itemsPerPage); } EditorGUILayout.EndVertical(); //Rect pos; //pos = EditorGUILayout.GetControlRect(false, 20); //pos.x += 5; //EditorGUI.LabelField(pos, "First Glyph", TMP_UIStyleManager.TMP_GUISkin.label); //pos.x += 100; //EditorGUI.LabelField(pos, "Adjustment Values", TMP_UIStyleManager.TMP_GUISkin.label); //pos.x = pos.width / 2 + 5; //EditorGUI.LabelField(pos, "Second Glyph", TMP_UIStyleManager.TMP_GUISkin.label); //pos.x += 100; //EditorGUI.LabelField(pos, "Adjustment Values", TMP_UIStyleManager.TMP_GUISkin.label); if (arraySize > 0) { // Display each GlyphInfo entry using the GlyphInfo property drawer. for (int i = itemsPerPage * m_CurrentKerningPage; i < arraySize && i < itemsPerPage * (m_CurrentKerningPage + 1); i++) { // Define the start of the selection region of the element. Rect elementStartRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); int elementIndex = i; if (!string.IsNullOrEmpty(m_KerningTableSearchPattern)) elementIndex = m_KerningTableSearchList[i]; SerializedProperty kerningInfo = m_kerningPairs_prop.GetArrayElementAtIndex(elementIndex); EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUI.BeginDisabledGroup(i != m_SelectedAdjustmentRecord); { EditorGUILayout.PropertyField(kerningInfo, new GUIContent("Selectable")); } EditorGUI.EndDisabledGroup(); EditorGUILayout.EndVertical(); // Define the end of the selection region of the element. Rect elementEndRegion = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); // Check for Item selection Rect selectionArea = new Rect(elementStartRegion.x, elementStartRegion.y, elementEndRegion.width, elementEndRegion.y - elementStartRegion.y); if (DoSelectionCheck(selectionArea)) { if (m_SelectedAdjustmentRecord == i) { m_SelectedAdjustmentRecord = -1; } else { m_SelectedAdjustmentRecord = i; GUIUtility.keyboardControl = 0; } } // Draw Selection Highlight and Kerning Pair Options if (m_SelectedAdjustmentRecord == i) { TMP_EditorUtility.DrawBox(selectionArea, 2f, new Color32(40, 192, 255, 255)); // Draw Glyph management options Rect controlRect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight * 1f); float optionAreaWidth = controlRect.width; float btnWidth = optionAreaWidth / 4; Rect position = new Rect(controlRect.x + controlRect.width - btnWidth, controlRect.y, btnWidth, controlRect.height); // Remove Kerning pair GUI.enabled = true; if (GUI.Button(position, "Remove")) { GUIUtility.keyboardControl = 0; m_kerningTable.RemoveKerningPair(i); m_fontAsset.ReadFontDefinition(); isAssetDirty = true; m_SelectedAdjustmentRecord = -1; m_isSearchDirty = true; break; } } } } DisplayPageNavigation(ref m_CurrentKerningPage, arraySize, itemsPerPage); GUILayout.Space(5); // Add new kerning pair EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.PropertyField(m_kerningPair_prop); } EditorGUILayout.EndVertical(); if (GUILayout.Button("Add New Kerning Pair")) { int firstGlyph = m_kerningPair_prop.FindPropertyRelative("m_FirstGlyph").intValue; int secondGlyph = m_kerningPair_prop.FindPropertyRelative("m_SecondGlyph").intValue; GlyphValueRecord firstGlyphAdjustments = GetGlyphAdjustments(m_kerningPair_prop.FindPropertyRelative("m_FirstGlyphAdjustments")); GlyphValueRecord secondGlyphAdjustments = GetGlyphAdjustments(m_kerningPair_prop.FindPropertyRelative("m_SecondGlyphAdjustments")); errorCode = m_kerningTable.AddGlyphPairAdjustmentRecord((uint)firstGlyph, firstGlyphAdjustments, (uint)secondGlyph, secondGlyphAdjustments); // Sort Kerning Pairs & Reload Font Asset if new kerning pair was added. if (errorCode != -1) { m_kerningTable.SortKerningPairs(); m_fontAsset.ReadFontDefinition(); serializedObject.ApplyModifiedProperties(); isAssetDirty = true; m_isSearchDirty = true; } else { timeStamp = System.DateTime.Now.AddSeconds(5); } // Clear Add Kerning Pair Panel // TODO } if (errorCode == -1) { GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label("Kerning Pair already exists!", TMP_UIStyleManager.label); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (System.DateTime.Now > timeStamp) errorCode = 0; } } #endregion if (serializedObject.ApplyModifiedProperties() || evt_cmd == k_UndoRedo || isAssetDirty) { TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset); isAssetDirty = false; EditorUtility.SetDirty(target); } // Clear selection if mouse event was not consumed. GUI.enabled = true; if (currentEvent.type == EventType.MouseDown && currentEvent.button == 0) m_SelectedAdjustmentRecord = -1; } void DisplayPageNavigation(ref int currentPage, int arraySize, int itemsPerPage) { Rect pagePos = EditorGUILayout.GetControlRect(false, 20); pagePos.width /= 3; int shiftMultiplier = Event.current.shift ? 10 : 1; // Page + Shift goes 10 page forward // Previous Page GUI.enabled = currentPage > 0; if (GUI.Button(pagePos, "Previous Page")) currentPage -= 1 * shiftMultiplier; // Page Counter GUI.enabled = true; pagePos.x += pagePos.width; int totalPages = (int)(arraySize / (float)itemsPerPage + 0.999f); GUI.Label(pagePos, "Page " + (currentPage + 1) + " / " + totalPages, TMP_UIStyleManager.centeredLabel); // Next Page pagePos.x += pagePos.width; GUI.enabled = itemsPerPage * (currentPage + 1) < arraySize; if (GUI.Button(pagePos, "Next Page")) currentPage += 1 * shiftMultiplier; // Clamp page range currentPage = Mathf.Clamp(currentPage, 0, arraySize / itemsPerPage); GUI.enabled = true; } /// /// /// /// /// bool AddNewGlyph(int srcIndex, int dstGlyphID) { // Make sure Destination Glyph ID doesn't already contain a Glyph if (m_fontAsset.characterDictionary.ContainsKey(dstGlyphID)) return false; // Add new element to glyph list. m_glyphInfoList_prop.arraySize += 1; // Get a reference to the source glyph. SerializedProperty sourceGlyph = m_glyphInfoList_prop.GetArrayElementAtIndex(srcIndex); int dstIndex = m_glyphInfoList_prop.arraySize - 1; // Get a reference to the target / destination glyph. SerializedProperty targetGlyph = m_glyphInfoList_prop.GetArrayElementAtIndex(dstIndex); CopySerializedProperty(sourceGlyph, ref targetGlyph); // Update the ID of the glyph targetGlyph.FindPropertyRelative("id").intValue = dstGlyphID; serializedObject.ApplyModifiedProperties(); m_fontAsset.SortGlyphs(); m_fontAsset.ReadFontDefinition(); return true; } /// /// /// /// void RemoveGlyphFromList(int index) { if (index > m_glyphInfoList_prop.arraySize) return; m_glyphInfoList_prop.DeleteArrayElementAtIndex(index); serializedObject.ApplyModifiedProperties(); m_fontAsset.ReadFontDefinition(); } // Check if any of the Style elements were clicked on. private bool DoSelectionCheck(Rect selectionArea) { Event currentEvent = Event.current; switch (currentEvent.type) { case EventType.MouseDown: if (selectionArea.Contains(currentEvent.mousePosition) && currentEvent.button == 0) { currentEvent.Use(); return true; } break; } return false; } GlyphValueRecord GetGlyphAdjustments (SerializedProperty property) { GlyphValueRecord record; record.xPlacement = property.FindPropertyRelative("xPlacement").floatValue; record.yPlacement = property.FindPropertyRelative("yPlacement").floatValue; record.xAdvance = property.FindPropertyRelative("xAdvance").floatValue; record.yAdvance = property.FindPropertyRelative("yAdvance").floatValue; return record; } /// /// /// /// /// void CopySerializedProperty(SerializedProperty source, ref SerializedProperty target) { // TODO : Should make a generic function which copies each of the properties. target.FindPropertyRelative("id").intValue = source.FindPropertyRelative("id").intValue; target.FindPropertyRelative("x").floatValue = source.FindPropertyRelative("x").floatValue; target.FindPropertyRelative("y").floatValue = source.FindPropertyRelative("y").floatValue; target.FindPropertyRelative("width").floatValue = source.FindPropertyRelative("width").floatValue; target.FindPropertyRelative("height").floatValue = source.FindPropertyRelative("height").floatValue; target.FindPropertyRelative("xOffset").floatValue = source.FindPropertyRelative("xOffset").floatValue; target.FindPropertyRelative("yOffset").floatValue = source.FindPropertyRelative("yOffset").floatValue; target.FindPropertyRelative("xAdvance").floatValue = source.FindPropertyRelative("xAdvance").floatValue; target.FindPropertyRelative("scale").floatValue = source.FindPropertyRelative("scale").floatValue; } /// /// /// /// /// void SearchGlyphTable (string searchPattern, ref List searchResults) { if (searchResults == null) searchResults = new List(); searchResults.Clear(); int arraySize = m_glyphInfoList_prop.arraySize; for (int i = 0; i < arraySize; i++) { SerializedProperty sourceGlyph = m_glyphInfoList_prop.GetArrayElementAtIndex(i); int id = sourceGlyph.FindPropertyRelative("id").intValue; // Check for potential match against a character. if (searchPattern.Length == 1 && id == searchPattern[0]) searchResults.Add(i); // Check for potential match against decimal id if (id.ToString().Contains(searchPattern)) searchResults.Add(i); if (id.ToString("x").Contains(searchPattern)) searchResults.Add(i); if (id.ToString("X").Contains(searchPattern)) searchResults.Add(i); } } void SearchKerningTable(string searchPattern, ref List searchResults) { if (searchResults == null) searchResults = new List(); searchResults.Clear(); int arraySize = m_kerningPairs_prop.arraySize; for (int i = 0; i < arraySize; i++) { SerializedProperty sourceGlyph = m_kerningPairs_prop.GetArrayElementAtIndex(i); int firstGlyph = sourceGlyph.FindPropertyRelative("m_FirstGlyph").intValue; int secondGlyph = sourceGlyph.FindPropertyRelative("m_SecondGlyph").intValue; if (searchPattern.Length == 1) { if (firstGlyph == searchPattern[0]) { searchResults.Add(i); continue; } if (secondGlyph == searchPattern[0]) { searchResults.Add(i); continue; } } if (searchPattern.Length == 2) { if (firstGlyph == searchPattern[0] && secondGlyph == searchPattern[1]) { searchResults.Add(i); continue; } } if (firstGlyph.ToString().Contains(searchPattern)) { searchResults.Add(i); continue; } //if (firstGlyph.ToString("x").Contains(searchPattern)) //{ // searchResults.Add(i); // continue; //} //if (firstGlyph.ToString("X").Contains(searchPattern)) //{ // searchResults.Add(i); // continue; //} if (secondGlyph.ToString().Contains(searchPattern)) { searchResults.Add(i); continue; } //if (secondGlyph.ToString("x").Contains(searchPattern)) //{ // searchResults.Add(i); // continue; //} //if (secondGlyph.ToString("X").Contains(searchPattern)) //{ // searchResults.Add(i); // continue; //} } } } }