using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using UnityEngine.TextCore;
using UnityEngine.TextCore.LowLevel;
using UnityEditor.TextCore.LowLevel;
namespace TMPro.EditorUtilities
{
[CustomPropertyDrawer(typeof(TMP_FontWeightPair))]
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 TYPEFACE
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 TYPEFACE
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 faceInfoPanel = true;
public static bool generationSettingsPanel = true;
public static bool fontAtlasInfoPanel = true;
public static bool fontWeightPanel = true;
public static bool fallbackFontAssetPanel = true;
public static bool glyphTablePanel = false;
public static bool characterTablePanel = false;
public static bool fontFeatureTablePanel = false;
}
private struct AtlasSettings
{
public GlyphRenderMode glyphRenderMode;
public int pointSize;
public int padding;
public int atlasWidth;
public int atlasHeight;
}
///
/// Material used to display SDF glyphs in the Character and Glyph tables.
///
internal static Material internalSDFMaterial
{
get
{
if (s_InternalSDFMaterial == null)
{
Shader shader = Shader.Find("Hidden/TMP/Internal/Editor/Distance Field SSD");
if (shader != null)
s_InternalSDFMaterial = new Material(shader);
}
return s_InternalSDFMaterial;
}
}
static Material s_InternalSDFMaterial;
///
/// Material used to display Bitmap glyphs in the Character and Glyph tables.
///
internal static Material internalBitmapMaterial
{
get
{
if (s_InternalBitmapMaterial == null)
{
Shader shader = Shader.Find("Hidden/Internal-GUITextureClipText");
if (shader != null)
s_InternalBitmapMaterial = new Material(shader);
}
return s_InternalBitmapMaterial;
}
}
static Material s_InternalBitmapMaterial;
private static string[] s_UiStateLabel = new string[] { "(Click to collapse) ", "(Click to expand) " };
private GUIContent[] m_AtlasResolutionLabels = { new GUIContent("8"), new GUIContent("16"), new GUIContent("32"), new GUIContent("64"), new GUIContent("128"), new GUIContent("256"), new GUIContent("512"), new GUIContent("1024"), new GUIContent("2048"), new GUIContent("4096"), new GUIContent("8192") };
private int[] m_AtlasResolutions = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
private struct Warning
{
public bool isEnabled;
public double expirationTime;
}
private int m_CurrentGlyphPage = 0;
private int m_CurrentCharacterPage = 0;
private int m_CurrentKerningPage = 0;
private int m_SelectedGlyphRecord = -1;
private int m_SelectedCharacterRecord = -1;
private int m_SelectedAdjustmentRecord = -1;
private string m_dstGlyphID;
private string m_dstUnicode;
private const string k_placeholderUnicodeHex = "New Unicode (Hex)";
private string m_unicodeHexLabel = k_placeholderUnicodeHex;
private const string k_placeholderGlyphID = "New Glyph ID";
private string m_GlyphIDLabel = k_placeholderGlyphID;
private Warning m_AddGlyphWarning;
private Warning m_AddCharacterWarning;
private bool m_DisplayDestructiveChangeWarning;
private AtlasSettings m_AtlasSettings;
private bool m_MaterialPresetsRequireUpdate;
private string m_GlyphSearchPattern;
private List m_GlyphSearchList;
private string m_CharacterSearchPattern;
private List m_CharacterSearchList;
private string m_KerningTableSearchPattern;
private List m_KerningTableSearchList;
private bool m_isSearchDirty;
private const string k_UndoRedo = "UndoRedoPerformed";
private SerializedProperty m_AtlasPopulationMode_prop;
private SerializedProperty font_atlas_prop;
private SerializedProperty font_material_prop;
private SerializedProperty m_AtlasRenderMode_prop;
private SerializedProperty m_SamplingPointSize_prop;
private SerializedProperty m_AtlasPadding_prop;
private SerializedProperty m_AtlasWidth_prop;
private SerializedProperty m_AtlasHeight_prop;
private SerializedProperty m_IsMultiAtlasTexturesEnabled_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_FaceInfo_prop;
private SerializedProperty m_GlyphTable_prop;
private SerializedProperty m_CharacterTable_prop;
private TMP_FontFeatureTable m_FontFeatureTable;
private SerializedProperty m_FontFeatureTable_prop;
private SerializedProperty m_GlyphPairAdjustmentRecords_prop;
private TMP_SerializedPropertyHolder m_SerializedPropertyHolder;
private SerializedProperty m_EmptyGlyphPairAdjustmentRecord_prop;
private TMP_FontAsset m_fontAsset;
private Material[] m_materialPresets;
private bool isAssetDirty = false;
private int errorCode;
private System.DateTime timeStamp;
public void OnEnable()
{
m_FaceInfo_prop = serializedObject.FindProperty("m_FaceInfo");
font_atlas_prop = serializedObject.FindProperty("m_AtlasTextures").GetArrayElementAtIndex(0);
font_material_prop = serializedObject.FindProperty("material");
m_AtlasPopulationMode_prop = serializedObject.FindProperty("m_AtlasPopulationMode");
m_AtlasRenderMode_prop = serializedObject.FindProperty("m_AtlasRenderMode");
m_SamplingPointSize_prop = m_FaceInfo_prop.FindPropertyRelative("m_PointSize");
m_AtlasPadding_prop = serializedObject.FindProperty("m_AtlasPadding");
m_AtlasWidth_prop = serializedObject.FindProperty("m_AtlasWidth");
m_AtlasHeight_prop = serializedObject.FindProperty("m_AtlasHeight");
m_IsMultiAtlasTexturesEnabled_prop = serializedObject.FindProperty("m_IsMultiAtlasTexturesEnabled");
fontWeights_prop = serializedObject.FindProperty("m_FontWeightTable");
m_list = new ReorderableList(serializedObject, serializedObject.FindProperty("m_FallbackFontAssetTable"), 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 List");
};
// Clean up fallback list in the event if contains null elements.
CleanFallbackFontAssetTable();
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_CharacterTable_prop = serializedObject.FindProperty("m_CharacterTable");
m_GlyphTable_prop = serializedObject.FindProperty("m_GlyphTable");
m_FontFeatureTable_prop = serializedObject.FindProperty("m_FontFeatureTable");
m_GlyphPairAdjustmentRecords_prop = m_FontFeatureTable_prop.FindPropertyRelative("m_GlyphPairAdjustmentRecords");
m_fontAsset = target as TMP_FontAsset;
m_FontFeatureTable = m_fontAsset.fontFeatureTable;
// Upgrade Font Feature Table if necessary
if (m_fontAsset.m_KerningTable != null && m_fontAsset.m_KerningTable.kerningPairs != null && m_fontAsset.m_KerningTable.kerningPairs.Count > 0)
m_fontAsset.ReadFontAssetDefinition();
// Create serialized object to allow us to use a serialized property of an empty kerning pair.
m_SerializedPropertyHolder = CreateInstance();
m_SerializedPropertyHolder.fontAsset = m_fontAsset;
SerializedObject internalSerializedObject = new SerializedObject(m_SerializedPropertyHolder);
m_EmptyGlyphPairAdjustmentRecord_prop = internalSerializedObject.FindProperty("glyphPairAdjustmentRecord");
m_materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset);
m_GlyphSearchList = new List();
m_KerningTableSearchList = new List();
// Sort Font Asset Tables
m_fontAsset.SortAllTables();
}
public void OnDisable()
{
// Revert changes if user closes or changes selection without having made a choice.
if (m_DisplayDestructiveChangeWarning)
{
m_DisplayDestructiveChangeWarning = false;
RestoreAtlasGenerationSettings();
GUIUtility.keyboardControl = 0;
serializedObject.ApplyModifiedProperties();
}
}
public override void OnInspectorGUI()
{
//Debug.Log("OnInspectorGUI Called.");
Event currentEvent = Event.current;
serializedObject.Update();
Rect rect = EditorGUILayout.GetControlRect(false, 24);
float labelWidth = EditorGUIUtility.labelWidth;
float fieldWidth = EditorGUIUtility.fieldWidth;
// FACE INFO PANEL
#region Face info
GUI.Label(rect, new GUIContent("Face Info - v" + m_fontAsset.version), TMP_UIStyleManager.sectionHeader);
rect.x += rect.width - 132f;
rect.y += 2;
rect.width = 130f;
rect.height = 18f;
if (GUI.Button(rect, new GUIContent("Update Atlas Texture")))
{
TMPro_FontAssetCreatorWindow.ShowFontAtlasCreatorWindow(target as TMP_FontAsset);
}
EditorGUI.indentLevel = 1;
GUI.enabled = false; // Lock UI
// TODO : Consider creating a property drawer for these.
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_FamilyName"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_StyleName"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_PointSize"));
GUI.enabled = true;
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_Scale"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_LineHeight"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_AscentLine"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_CapLine"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_MeanLine"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_Baseline"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_DescentLine"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_UnderlineOffset"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_UnderlineThickness"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_StrikethroughOffset"));
//EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("strikethroughThickness"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SuperscriptOffset"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SuperscriptSize"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SubscriptOffset"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_SubscriptSize"));
EditorGUILayout.PropertyField(m_FaceInfo_prop.FindPropertyRelative("m_TabWidth"));
// TODO : Add clamping for some of these values.
//subSize_prop.floatValue = Mathf.Clamp(subSize_prop.floatValue, 0.25f, 1f);
EditorGUILayout.Space();
#endregion
// GENERATION SETTINGS
#region Generation Settings
rect = EditorGUILayout.GetControlRect(false, 24);
if (GUI.Button(rect, new GUIContent("Generation Settings"), TMP_UIStyleManager.sectionHeader))
UI_PanelState.generationSettingsPanel = !UI_PanelState.generationSettingsPanel;
GUI.Label(rect, (UI_PanelState.generationSettingsPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
if (UI_PanelState.generationSettingsPanel)
{
EditorGUI.indentLevel = 1;
EditorGUI.BeginChangeCheck();
Font sourceFont = (Font)EditorGUILayout.ObjectField("Source Font File", m_fontAsset.m_SourceFontFile_EditorRef, typeof(Font), false);
if (EditorGUI.EndChangeCheck())
{
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(sourceFont));
m_fontAsset.m_SourceFontFileGUID = guid;
m_fontAsset.m_SourceFontFile_EditorRef = sourceFont;
}
EditorGUI.BeginDisabledGroup(sourceFont == null);
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_AtlasPopulationMode_prop, new GUIContent("Atlas Population Mode"));
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
bool isDatabaseRefreshRequired = false;
if (m_AtlasPopulationMode_prop.intValue == 0)
{
m_fontAsset.sourceFontFile = null;
//Set atlas textures to non readable.
for (int i = 0; i < m_fontAsset.atlasTextures.Length; i++)
{
Texture2D tex = m_fontAsset.atlasTextures[i];
if (tex != null && tex.isReadable)
FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, false);
}
Debug.Log("Atlas Population mode set to [Static].");
}
else if (m_AtlasPopulationMode_prop.intValue == 1)
{
if (m_fontAsset.m_SourceFontFile_EditorRef.dynamic == false)
{
Debug.LogWarning("Please set the [" + m_fontAsset.name + "] font to dynamic mode as this is required for Dynamic SDF support.", m_fontAsset.m_SourceFontFile_EditorRef);
m_AtlasPopulationMode_prop.intValue = 0;
serializedObject.ApplyModifiedProperties();
}
else
{
m_fontAsset.sourceFontFile = m_fontAsset.m_SourceFontFile_EditorRef;
// Set atlas textures to non readable.
for (int i = 0; i < m_fontAsset.atlasTextures.Length; i++)
{
Texture2D tex = m_fontAsset.atlasTextures[i];
if (tex != null && tex.isReadable == false)
FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, true);
}
Debug.Log("Atlas Population mode set to [Dynamic].");
}
}
if (isDatabaseRefreshRequired)
AssetDatabase.Refresh();
serializedObject.Update();
isAssetDirty = true;
}
// Save state of atlas settings
if (m_DisplayDestructiveChangeWarning == false)
{
SavedAtlasGenerationSettings();
//Undo.RegisterCompleteObjectUndo(m_fontAsset, "Font Asset Changes");
}
EditorGUI.BeginDisabledGroup(m_AtlasPopulationMode_prop.intValue == (int)AtlasPopulationMode.Static);
{
EditorGUI.BeginChangeCheck();
// TODO: Switch shaders depending on GlyphRenderMode.
EditorGUILayout.PropertyField(m_AtlasRenderMode_prop);
EditorGUILayout.PropertyField(m_SamplingPointSize_prop, new GUIContent("Sampling Point Size"));
if (EditorGUI.EndChangeCheck())
{
m_DisplayDestructiveChangeWarning = true;
}
// Changes to these properties require updating Material Presets for this font asset.
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_AtlasPadding_prop, new GUIContent("Padding"));
EditorGUILayout.IntPopup(m_AtlasWidth_prop, m_AtlasResolutionLabels, m_AtlasResolutions, new GUIContent("Atlas Width"));
EditorGUILayout.IntPopup(m_AtlasHeight_prop, m_AtlasResolutionLabels, m_AtlasResolutions, new GUIContent("Atlas Height"));
EditorGUILayout.PropertyField(m_IsMultiAtlasTexturesEnabled_prop, new GUIContent("Multi Atlas Textures", "Determines if the font asset will store glyphs in multiple atlas textures."));
if (EditorGUI.EndChangeCheck())
{
m_MaterialPresetsRequireUpdate = true;
m_DisplayDestructiveChangeWarning = true;
}
if (m_DisplayDestructiveChangeWarning)
{
// These changes are destructive on the font asset
rect = EditorGUILayout.GetControlRect(false, 60);
rect.x += 15;
rect.width -= 15;
EditorGUI.HelpBox(rect, "Changing these settings will clear the font asset's character, glyph and texture data.", MessageType.Warning);
if (GUI.Button(new Rect(rect.width - 140, rect.y + 36, 80, 18), new GUIContent("Apply")))
{
m_DisplayDestructiveChangeWarning = false;
// Update face info is sampling point size was changed.
if (m_AtlasSettings.pointSize != m_SamplingPointSize_prop.intValue)
{
FontEngine.LoadFontFace(m_fontAsset.sourceFontFile, m_SamplingPointSize_prop.intValue);
m_fontAsset.faceInfo = FontEngine.GetFaceInfo();
}
// Update material
m_fontAsset.material.SetFloat(ShaderUtilities.ID_TextureWidth, m_AtlasWidth_prop.intValue);
m_fontAsset.material.SetFloat(ShaderUtilities.ID_TextureHeight, m_AtlasHeight_prop.intValue);
m_fontAsset.material.SetFloat(ShaderUtilities.ID_GradientScale, m_AtlasPadding_prop.intValue + 1);
// Update material presets if any of the relevant properties have been changed.
if (m_MaterialPresetsRequireUpdate)
{
m_MaterialPresetsRequireUpdate = false;
Material[] materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset);
for (int i = 0; i < materialPresets.Length; i++)
{
Material mat = materialPresets[i];
mat.SetFloat(ShaderUtilities.ID_TextureWidth, m_AtlasWidth_prop.intValue);
mat.SetFloat(ShaderUtilities.ID_TextureHeight, m_AtlasHeight_prop.intValue);
mat.SetFloat(ShaderUtilities.ID_GradientScale, m_AtlasPadding_prop.intValue + 1);
}
}
m_fontAsset.UpdateFontAssetData();
GUIUtility.keyboardControl = 0;
isAssetDirty = true;
// Update Font Asset Creation Settings to reflect new changes.
UpdateFontAssetCreationSettings();
// TODO: Clear undo buffers.
//Undo.ClearUndo(m_fontAsset);
}
if (GUI.Button(new Rect(rect.width - 56, rect.y + 36, 80, 18), new GUIContent("Revert")))
{
m_DisplayDestructiveChangeWarning = false;
RestoreAtlasGenerationSettings();
GUIUtility.keyboardControl = 0;
// TODO: Clear undo buffers.
//Undo.ClearUndo(m_fontAsset);
}
}
}
EditorGUI.EndDisabledGroup();
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space();
}
#endregion
// ATLAS & MATERIAL PANEL
#region Atlas & Material
rect = EditorGUILayout.GetControlRect(false, 24);
if (GUI.Button(rect, new GUIContent("Atlas & Material"), TMP_UIStyleManager.sectionHeader))
UI_PanelState.fontAtlasInfoPanel = !UI_PanelState.fontAtlasInfoPanel;
GUI.Label(rect, (UI_PanelState.fontAtlasInfoPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
if (UI_PanelState.fontAtlasInfoPanel)
{
EditorGUI.indentLevel = 1;
GUI.enabled = false;
EditorGUILayout.PropertyField(font_atlas_prop, new GUIContent("Font Atlas"));
EditorGUILayout.PropertyField(font_material_prop, new GUIContent("Font Material"));
GUI.enabled = true;
EditorGUILayout.Space();
}
#endregion
string evt_cmd = Event.current.commandName; // Get Current Event CommandName to check for Undo Events
// FONT WEIGHT PANEL
#region Font Weights
rect = EditorGUILayout.GetControlRect(false, 24);
if (GUI.Button(rect, 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."), TMP_UIStyleManager.sectionHeader))
UI_PanelState.fontWeightPanel = !UI_PanelState.fontWeightPanel;
GUI.Label(rect, (UI_PanelState.fontWeightPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
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, "Regular Typeface", EditorStyles.label);
rect.x += rect.width;
GUI.Label(rect, "Italic Typeface", EditorStyles.label);
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 - Semi-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;
#endregion
// FALLBACK FONT ASSETS
#region Fallback Font Asset
rect = EditorGUILayout.GetControlRect(false, 24);
EditorGUI.indentLevel = 0;
if (GUI.Button(rect, 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."), TMP_UIStyleManager.sectionHeader))
UI_PanelState.fallbackFontAssetPanel = !UI_PanelState.fallbackFontAssetPanel;
GUI.Label(rect, (UI_PanelState.fallbackFontAssetPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
if (UI_PanelState.fallbackFontAssetPanel)
{
EditorGUIUtility.labelWidth = 120;
EditorGUI.indentLevel = 0;
m_list.DoLayoutList();
EditorGUILayout.Space();
}
#endregion
// CHARACTER TABLE TABLE
#region Character Table
EditorGUIUtility.labelWidth = labelWidth;
EditorGUIUtility.fieldWidth = fieldWidth;
EditorGUI.indentLevel = 0;
rect = EditorGUILayout.GetControlRect(false, 24);
int characterCount = m_fontAsset.characterTable.Count;
if (GUI.Button(rect, new GUIContent("Character Table [" + characterCount + "]" + (rect.width > 320 ? " Characters" : ""), "List of characters contained in this font asset."), TMP_UIStyleManager.sectionHeader))
UI_PanelState.characterTablePanel = !UI_PanelState.characterTablePanel;
GUI.Label(rect, (UI_PanelState.characterTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
if (UI_PanelState.characterTablePanel)
{
int arraySize = m_CharacterTable_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("Character Search", m_CharacterSearchPattern, "SearchTextField");
if (EditorGUI.EndChangeCheck() || m_isSearchDirty)
{
if (string.IsNullOrEmpty(searchPattern) == false)
{
m_CharacterSearchPattern = searchPattern;
// Search Character Table for potential matches
SearchCharacterTable (m_CharacterSearchPattern, ref m_CharacterSearchList);
}
else
m_CharacterSearchPattern = null;
m_isSearchDirty = false;
}
string styleName = string.IsNullOrEmpty(m_CharacterSearchPattern) ? "SearchCancelButtonEmpty" : "SearchCancelButton";
if (GUILayout.Button(GUIContent.none, styleName))
{
GUIUtility.keyboardControl = 0;
m_CharacterSearchPattern = string.Empty;
}
}
EditorGUILayout.EndHorizontal();
#endregion
// Display Page Navigation
if (!string.IsNullOrEmpty(m_CharacterSearchPattern))
arraySize = m_CharacterSearchList.Count;
DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage);
}
EditorGUILayout.EndVertical();
// Display Character Table Elements
if (arraySize > 0)
{
// Display each character entry using the CharacterPropertyDrawer.
for (int i = itemsPerPage * m_CurrentCharacterPage; i < arraySize && i < itemsPerPage * (m_CurrentCharacterPage + 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_CharacterSearchPattern))
elementIndex = m_CharacterSearchList[i];
SerializedProperty characterProperty = m_CharacterTable_prop.GetArrayElementAtIndex(elementIndex);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUI.BeginDisabledGroup(i != m_SelectedCharacterRecord);
{
EditorGUILayout.PropertyField(characterProperty);
}
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_SelectedCharacterRecord == i)
m_SelectedCharacterRecord = -1;
else
{
m_SelectedCharacterRecord = i;
m_AddCharacterWarning.isEnabled = false;
m_unicodeHexLabel = k_placeholderUnicodeHex;
GUIUtility.keyboardControl = 0;
}
}
// Draw Selection Highlight and Glyph Options
if (m_SelectedCharacterRecord == 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_dstUnicode);
if (GUI.Button(position, new GUIContent("Copy to")))
{
GUIUtility.keyboardControl = 0;
// Convert Hex Value to Decimal
int dstGlyphID = TMP_TextUtilities.StringHexToInt(m_dstUnicode);
//Add new glyph at target Unicode hex id.
if (!AddNewCharacter(elementIndex, dstGlyphID))
{
m_AddCharacterWarning.isEnabled = true;
m_AddCharacterWarning.expirationTime = EditorApplication.timeSinceStartup + 1;
}
m_dstUnicode = 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("CharacterID_Input");
m_dstUnicode = EditorGUI.TextField(position, m_dstUnicode);
// Placeholder text
EditorGUI.LabelField(position, new GUIContent(m_unicodeHexLabel, "The Unicode (Hex) ID of the duplicated Character"), TMP_UIStyleManager.label);
// Only filter the input when the destination glyph ID text field has focus.
if (GUI.GetNameOfFocusedControl() == "CharacterID_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;
//m_dstUnicode = string.Empty;
}
// Remove Glyph
position.x += btnWidth;
if (GUI.Button(position, "Remove"))
{
GUIUtility.keyboardControl = 0;
RemoveCharacterFromList(elementIndex);
isAssetDirty = true;
m_SelectedCharacterRecord = -1;
m_isSearchDirty = true;
break;
}
if (m_AddCharacterWarning.isEnabled && EditorApplication.timeSinceStartup < m_AddCharacterWarning.expirationTime)
{
EditorGUILayout.HelpBox("The Destination Character ID already exists", MessageType.Warning);
}
}
}
}
DisplayPageNavigation(ref m_CurrentCharacterPage, arraySize, itemsPerPage);
EditorGUILayout.Space();
}
#endregion
// GLYPH TABLE
#region Glyph Table
EditorGUIUtility.labelWidth = labelWidth;
EditorGUIUtility.fieldWidth = fieldWidth;
EditorGUI.indentLevel = 0;
rect = EditorGUILayout.GetControlRect(false, 24);
GUIStyle glyphPanelStyle = new GUIStyle(EditorStyles.helpBox);
int glyphCount = m_fontAsset.glyphTable.Count;
if (GUI.Button(rect, new GUIContent("Glyph Table [" + glyphCount + "]" + (rect.width > 275 ? " Glyphs" : ""), "List of glyphs contained in this font asset."), TMP_UIStyleManager.sectionHeader))
UI_PanelState.glyphTablePanel = !UI_PanelState.glyphTablePanel;
GUI.Label(rect, (UI_PanelState.glyphTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
if (UI_PanelState.glyphTablePanel)
{
int arraySize = m_GlyphTable_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 glyphProperty = m_GlyphTable_prop.GetArrayElementAtIndex(elementIndex);
EditorGUILayout.BeginVertical(glyphPanelStyle);
using (new EditorGUI.DisabledScope(i != m_SelectedGlyphRecord))
{
EditorGUILayout.PropertyField(glyphProperty);
}
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;
int dstGlyphID;
// Convert Hex Value to Decimal
int.TryParse(m_dstGlyphID, out 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_GlyphIDLabel, "The Glyph 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_GlyphIDLabel = string.Empty;
//Filter out unwanted characters.
char chr = Event.current.character;
if ((chr < '0' || chr > '9'))
{
Event.current.character = '\0';
}
}
else
{
m_GlyphIDLabel = k_placeholderGlyphID;
//m_dstGlyphID = string.Empty;
}
// 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
// FONT FEATURE TABLE
#region Font Feature Table
EditorGUIUtility.labelWidth = labelWidth;
EditorGUIUtility.fieldWidth = fieldWidth;
EditorGUI.indentLevel = 0;
rect = EditorGUILayout.GetControlRect(false, 24);
int adjustmentPairCount = m_fontAsset.fontFeatureTable.glyphPairAdjustmentRecords.Count;
if (GUI.Button(rect, new GUIContent("Glyph Adjustment Table [" + adjustmentPairCount + "]" + (rect.width > 340 ? " Records" : ""), "List of glyph adjustment / advanced kerning pairs."), TMP_UIStyleManager.sectionHeader))
UI_PanelState.fontFeatureTablePanel = !UI_PanelState.fontFeatureTablePanel;
GUI.Label(rect, (UI_PanelState.fontFeatureTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel);
if (UI_PanelState.fontFeatureTablePanel)
{
int arraySize = m_GlyphPairAdjustmentRecords_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();
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 pairAdjustmentRecordProperty = m_GlyphPairAdjustmentRecords_prop.GetArrayElementAtIndex(elementIndex);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
using (new EditorGUI.DisabledScope(i != m_SelectedAdjustmentRecord))
{
EditorGUILayout.PropertyField(pairAdjustmentRecordProperty, new GUIContent("Selectable"));
}
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;
RemoveAdjustmentPairFromList(i);
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_EmptyGlyphPairAdjustmentRecord_prop);
}
EditorGUILayout.EndVertical();
if (GUILayout.Button("Add New Glyph Adjustment Record"))
{
SerializedProperty firstAdjustmentRecordProperty = m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_FirstAdjustmentRecord");
SerializedProperty secondAdjustmentRecordProperty = m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_SecondAdjustmentRecord");
uint firstGlyphIndex = (uint)firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue;
uint secondGlyphIndex = (uint)secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue;
TMP_GlyphValueRecord firstValueRecord = GetValueRecord(firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord"));
TMP_GlyphValueRecord secondValueRecord = GetValueRecord(secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord"));
errorCode = -1;
uint pairKey = secondGlyphIndex << 16 | firstGlyphIndex;
if (m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.ContainsKey(pairKey) == false)
{
TMP_GlyphPairAdjustmentRecord adjustmentRecord = new TMP_GlyphPairAdjustmentRecord(new TMP_GlyphAdjustmentRecord(firstGlyphIndex, firstValueRecord), new TMP_GlyphAdjustmentRecord(secondGlyphIndex, secondValueRecord));
m_FontFeatureTable.m_GlyphPairAdjustmentRecords.Add(adjustmentRecord);
m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.Add(pairKey, adjustmentRecord);
errorCode = 0;
}
// Add glyphs and characters
TMP_Character character;
uint firstCharacter = m_SerializedPropertyHolder.firstCharacter;
if (!m_fontAsset.characterLookupTable.ContainsKey(firstCharacter))
m_fontAsset.TryAddCharacterInternal(firstCharacter, out character);
uint secondCharacter = m_SerializedPropertyHolder.secondCharacter;
if (!m_fontAsset.characterLookupTable.ContainsKey(secondCharacter))
m_fontAsset.TryAddCharacterInternal(secondCharacter, out character);
// Sort Kerning Pairs & Reload Font Asset if new kerning pair was added.
if (errorCode != -1)
{
m_FontFeatureTable.SortGlyphPairAdjustmentRecords();
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)
{
// Delay callback until user has decided to Apply or Revert the changes.
if (m_DisplayDestructiveChangeWarning == false)
TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, m_fontAsset);
if (m_fontAsset.IsFontAssetLookupTablesDirty || evt_cmd == k_UndoRedo)
m_fontAsset.ReadFontAssetDefinition();
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 CleanFallbackFontAssetTable()
{
SerializedProperty m_FallbackFontAsseTable = serializedObject.FindProperty("m_FallbackFontAssetTable");
bool isListDirty = false;
int elementCount = m_FallbackFontAsseTable.arraySize;
for (int i = 0; i < elementCount; i++)
{
SerializedProperty element = m_FallbackFontAsseTable.GetArrayElementAtIndex(i);
if (element.objectReferenceValue == null)
{
m_FallbackFontAsseTable.DeleteArrayElementAtIndex(i);
elementCount -= 1;
i -= 1;
isListDirty = true;
}
}
if (isListDirty)
{
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
}
}
void SavedAtlasGenerationSettings()
{
m_AtlasSettings.glyphRenderMode = (GlyphRenderMode)m_AtlasRenderMode_prop.intValue;
m_AtlasSettings.pointSize = m_SamplingPointSize_prop.intValue;
m_AtlasSettings.padding = m_AtlasPadding_prop.intValue;
m_AtlasSettings.atlasWidth = m_AtlasWidth_prop.intValue;
m_AtlasSettings.atlasHeight = m_AtlasHeight_prop.intValue;
}
void RestoreAtlasGenerationSettings()
{
m_AtlasRenderMode_prop.intValue = (int)m_AtlasSettings.glyphRenderMode;
m_SamplingPointSize_prop.intValue = m_AtlasSettings.pointSize;
m_AtlasPadding_prop.intValue = m_AtlasSettings.padding;
m_AtlasWidth_prop.intValue = m_AtlasSettings.atlasWidth;
m_AtlasHeight_prop.intValue = m_AtlasSettings.atlasHeight;
}
void UpdateFontAssetCreationSettings()
{
m_fontAsset.m_CreationSettings.pointSize = m_SamplingPointSize_prop.intValue;
m_fontAsset.m_CreationSettings.renderMode = m_AtlasRenderMode_prop.intValue;
m_fontAsset.m_CreationSettings.padding = m_AtlasPadding_prop.intValue;
m_fontAsset.m_CreationSettings.atlasWidth = m_AtlasWidth_prop.intValue;
m_fontAsset.m_CreationSettings.atlasHeight = m_AtlasHeight_prop.intValue;
}
void UpdateCharacterData(SerializedProperty property, int index)
{
TMP_Character character = m_fontAsset.characterTable[index];
character.unicode = (uint)property.FindPropertyRelative("m_Unicode").intValue;
character.scale = property.FindPropertyRelative("m_Scale").floatValue;
SerializedProperty glyphProperty = property.FindPropertyRelative("m_Glyph");
character.glyph.index = (uint)glyphProperty.FindPropertyRelative("m_Index").intValue;
SerializedProperty glyphRectProperty = glyphProperty.FindPropertyRelative("m_GlyphRect");
character.glyph.glyphRect = new GlyphRect(glyphRectProperty.FindPropertyRelative("m_X").intValue, glyphRectProperty.FindPropertyRelative("m_Y").intValue, glyphRectProperty.FindPropertyRelative("m_Width").intValue, glyphRectProperty.FindPropertyRelative("m_Height").intValue);
SerializedProperty glyphMetricsProperty = glyphProperty.FindPropertyRelative("m_Metrics");
character.glyph.metrics = new GlyphMetrics(glyphMetricsProperty.FindPropertyRelative("m_Width").floatValue, glyphMetricsProperty.FindPropertyRelative("m_Height").floatValue, glyphMetricsProperty.FindPropertyRelative("m_HorizontalBearingX").floatValue, glyphMetricsProperty.FindPropertyRelative("m_HorizontalBearingY").floatValue, glyphMetricsProperty.FindPropertyRelative("m_HorizontalAdvance").floatValue);
character.glyph.scale = glyphProperty.FindPropertyRelative("m_Scale").floatValue;
character.glyph.atlasIndex = glyphProperty.FindPropertyRelative("m_AtlasIndex").intValue;
}
void UpdateGlyphData(SerializedProperty property, int index)
{
Glyph glyph = m_fontAsset.glyphTable[index];
glyph.index = (uint)property.FindPropertyRelative("m_Index").intValue;
SerializedProperty glyphRect = property.FindPropertyRelative("m_GlyphRect");
glyph.glyphRect = new GlyphRect(glyphRect.FindPropertyRelative("m_X").intValue, glyphRect.FindPropertyRelative("m_Y").intValue, glyphRect.FindPropertyRelative("m_Width").intValue, glyphRect.FindPropertyRelative("m_Height").intValue);
SerializedProperty glyphMetrics = property.FindPropertyRelative("m_Metrics");
glyph.metrics = new GlyphMetrics(glyphMetrics.FindPropertyRelative("m_Width").floatValue, glyphMetrics.FindPropertyRelative("m_Height").floatValue, glyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue, glyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue, glyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue);
glyph.scale = property.FindPropertyRelative("m_Scale").floatValue;
}
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.glyphLookupTable.ContainsKey((uint)dstGlyphID))
return false;
// Add new element to glyph list.
m_GlyphTable_prop.arraySize += 1;
// Get a reference to the source glyph.
SerializedProperty sourceGlyph = m_GlyphTable_prop.GetArrayElementAtIndex(srcIndex);
int dstIndex = m_GlyphTable_prop.arraySize - 1;
// Get a reference to the target / destination glyph.
SerializedProperty targetGlyph = m_GlyphTable_prop.GetArrayElementAtIndex(dstIndex);
CopyGlyphSerializedProperty(sourceGlyph, ref targetGlyph);
// Update the ID of the glyph
targetGlyph.FindPropertyRelative("m_Index").intValue = dstGlyphID;
serializedObject.ApplyModifiedProperties();
m_fontAsset.SortGlyphTable();
m_fontAsset.ReadFontAssetDefinition();
return true;
}
///
///
///
///
void RemoveGlyphFromList(int index)
{
if (index > m_GlyphTable_prop.arraySize)
return;
int targetGlyphIndex = m_GlyphTable_prop.GetArrayElementAtIndex(index).FindPropertyRelative("m_Index").intValue;
m_GlyphTable_prop.DeleteArrayElementAtIndex(index);
// Remove all characters referencing this glyph.
for (int i = 0; i < m_CharacterTable_prop.arraySize; i++)
{
int glyphIndex = m_CharacterTable_prop.GetArrayElementAtIndex(i).FindPropertyRelative("m_GlyphIndex").intValue;
if (glyphIndex == targetGlyphIndex)
{
// Remove character
m_CharacterTable_prop.DeleteArrayElementAtIndex(i);
}
}
serializedObject.ApplyModifiedProperties();
m_fontAsset.ReadFontAssetDefinition();
}
bool AddNewCharacter(int srcIndex, int dstGlyphID)
{
// Make sure Destination Glyph ID doesn't already contain a Glyph
if (m_fontAsset.characterLookupTable.ContainsKey((uint)dstGlyphID))
return false;
// Add new element to glyph list.
m_CharacterTable_prop.arraySize += 1;
// Get a reference to the source glyph.
SerializedProperty sourceCharacter = m_CharacterTable_prop.GetArrayElementAtIndex(srcIndex);
int dstIndex = m_CharacterTable_prop.arraySize - 1;
// Get a reference to the target / destination glyph.
SerializedProperty targetCharacter = m_CharacterTable_prop.GetArrayElementAtIndex(dstIndex);
CopyCharacterSerializedProperty(sourceCharacter, ref targetCharacter);
// Update the ID of the glyph
targetCharacter.FindPropertyRelative("m_Unicode").intValue = dstGlyphID;
serializedObject.ApplyModifiedProperties();
m_fontAsset.SortCharacterTable();
m_fontAsset.ReadFontAssetDefinition();
return true;
}
void RemoveCharacterFromList(int index)
{
if (index > m_CharacterTable_prop.arraySize)
return;
m_CharacterTable_prop.DeleteArrayElementAtIndex(index);
serializedObject.ApplyModifiedProperties();
m_fontAsset.ReadFontAssetDefinition();
}
// 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;
}
TMP_GlyphValueRecord GetValueRecord(SerializedProperty property)
{
TMP_GlyphValueRecord record = new TMP_GlyphValueRecord();
record.xPlacement = property.FindPropertyRelative("m_XPlacement").floatValue;
record.yPlacement = property.FindPropertyRelative("m_YPlacement").floatValue;
record.xAdvance = property.FindPropertyRelative("m_XAdvance").floatValue;
record.yAdvance = property.FindPropertyRelative("m_YAdvance").floatValue;
return record;
}
void RemoveAdjustmentPairFromList(int index)
{
if (index > m_GlyphPairAdjustmentRecords_prop.arraySize)
return;
m_GlyphPairAdjustmentRecords_prop.DeleteArrayElementAtIndex(index);
serializedObject.ApplyModifiedProperties();
m_fontAsset.ReadFontAssetDefinition();
}
///
///
///
///
///
void CopyGlyphSerializedProperty(SerializedProperty srcGlyph, ref SerializedProperty dstGlyph)
{
// TODO : Should make a generic function which copies each of the properties.
dstGlyph.FindPropertyRelative("m_Index").intValue = srcGlyph.FindPropertyRelative("m_Index").intValue;
// Glyph -> GlyphMetrics
SerializedProperty srcGlyphMetrics = srcGlyph.FindPropertyRelative("m_Metrics");
SerializedProperty dstGlyphMetrics = dstGlyph.FindPropertyRelative("m_Metrics");
dstGlyphMetrics.FindPropertyRelative("m_Width").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Width").floatValue;
dstGlyphMetrics.FindPropertyRelative("m_Height").floatValue = srcGlyphMetrics.FindPropertyRelative("m_Height").floatValue;
dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingX").floatValue;
dstGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalBearingY").floatValue;
dstGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue = srcGlyphMetrics.FindPropertyRelative("m_HorizontalAdvance").floatValue;
// Glyph -> GlyphRect
SerializedProperty srcGlyphRect = srcGlyph.FindPropertyRelative("m_GlyphRect");
SerializedProperty dstGlyphRect = dstGlyph.FindPropertyRelative("m_GlyphRect");
dstGlyphRect.FindPropertyRelative("m_X").intValue = srcGlyphRect.FindPropertyRelative("m_X").intValue;
dstGlyphRect.FindPropertyRelative("m_Y").intValue = srcGlyphRect.FindPropertyRelative("m_Y").intValue;
dstGlyphRect.FindPropertyRelative("m_Width").intValue = srcGlyphRect.FindPropertyRelative("m_Width").intValue;
dstGlyphRect.FindPropertyRelative("m_Height").intValue = srcGlyphRect.FindPropertyRelative("m_Height").intValue;
dstGlyph.FindPropertyRelative("m_Scale").floatValue = srcGlyph.FindPropertyRelative("m_Scale").floatValue;
dstGlyph.FindPropertyRelative("m_AtlasIndex").intValue = srcGlyph.FindPropertyRelative("m_AtlasIndex").intValue;
}
void CopyCharacterSerializedProperty(SerializedProperty source, ref SerializedProperty target)
{
// TODO : Should make a generic function which copies each of the properties.
int unicode = source.FindPropertyRelative("m_Unicode").intValue;
target.FindPropertyRelative("m_Unicode").intValue = unicode;
int srcGlyphIndex = source.FindPropertyRelative("m_GlyphIndex").intValue;
target.FindPropertyRelative("m_GlyphIndex").intValue = srcGlyphIndex;
target.FindPropertyRelative("m_Scale").floatValue = source.FindPropertyRelative("m_Scale").floatValue;
}
///
///
///
///
///
void SearchGlyphTable (string searchPattern, ref List searchResults)
{
if (searchResults == null) searchResults = new List();
searchResults.Clear();
int arraySize = m_GlyphTable_prop.arraySize;
for (int i = 0; i < arraySize; i++)
{
SerializedProperty sourceGlyph = m_GlyphTable_prop.GetArrayElementAtIndex(i);
int id = sourceGlyph.FindPropertyRelative("m_Index").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 SearchCharacterTable(string searchPattern, ref List searchResults)
{
if (searchResults == null) searchResults = new List();
searchResults.Clear();
int arraySize = m_CharacterTable_prop.arraySize;
for (int i = 0; i < arraySize; i++)
{
SerializedProperty sourceCharacter = m_CharacterTable_prop.GetArrayElementAtIndex(i);
int id = sourceCharacter.FindPropertyRelative("m_Unicode").intValue;
// Check for potential match against a character.
if (searchPattern.Length == 1 && id == searchPattern[0])
searchResults.Add(i);
else if (id.ToString("x").Contains(searchPattern))
searchResults.Add(i);
else if (id.ToString("X").Contains(searchPattern))
searchResults.Add(i);
// Check for potential match against decimal id
//if (id.ToString().Contains(searchPattern))
// searchResults.Add(i);
}
}
void SearchKerningTable(string searchPattern, ref List searchResults)
{
if (searchResults == null) searchResults = new List();
searchResults.Clear();
// Lookup glyph index of potential characters contained in the search pattern.
uint firstGlyphIndex = 0;
TMP_Character firstCharacterSearch;
if (searchPattern.Length > 0 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[0], out firstCharacterSearch))
firstGlyphIndex = firstCharacterSearch.glyphIndex;
uint secondGlyphIndex = 0;
TMP_Character secondCharacterSearch;
if (searchPattern.Length > 1 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[1], out secondCharacterSearch))
secondGlyphIndex = secondCharacterSearch.glyphIndex;
int arraySize = m_GlyphPairAdjustmentRecords_prop.arraySize;
for (int i = 0; i < arraySize; i++)
{
SerializedProperty record = m_GlyphPairAdjustmentRecords_prop.GetArrayElementAtIndex(i);
SerializedProperty firstAdjustmentRecord = record.FindPropertyRelative("m_FirstAdjustmentRecord");
SerializedProperty secondAdjustmentRecord = record.FindPropertyRelative("m_SecondAdjustmentRecord");
int firstGlyph = firstAdjustmentRecord.FindPropertyRelative("m_GlyphIndex").intValue;
int secondGlyph = secondAdjustmentRecord.FindPropertyRelative("m_GlyphIndex").intValue;
if (firstGlyphIndex == firstGlyph && secondGlyphIndex == secondGlyph)
searchResults.Add(i);
else if (searchPattern.Length == 1 && (firstGlyphIndex == firstGlyph || firstGlyphIndex == secondGlyph))
searchResults.Add(i);
else if (firstGlyph.ToString().Contains(searchPattern))
searchResults.Add(i);
else if (secondGlyph.ToString().Contains(searchPattern))
searchResults.Add(i);
}
}
}
}