From 1959b3ade3fb2fe7a1286960cfaadf7e5539d1d8 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 20:15:25 -0800 Subject: [PATCH 01/20] Create FontIconSetDefinition --- .../FontIcons/FontIconSetDefinition.cs | 17 +++++++++++++++++ .../FontIcons/FontIconSetDefinition.cs.meta | 11 +++++++++++ 2 files changed, 28 insertions(+) create mode 100644 org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs create mode 100644 org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs.meta diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs new file mode 100644 index 000000000..111153f0b --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs @@ -0,0 +1,17 @@ +// Copyright (c) Mixed Reality Toolkit Contributors +// Licensed under the BSD 3-Clause + +using System.Collections.Generic; +using UnityEngine; + +namespace MixedReality.Toolkit.UX +{ + [CreateAssetMenu(fileName = "FontIconSetDefinition", menuName = "MRTK/UX/Font Icon Set Definition")] + public class FontIconSetDefinition : ScriptableObject + { + [SerializeField] + private string[] iconNames; + + public string[] IconNames => iconNames; + } +} diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs.meta b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs.meta new file mode 100644 index 000000000..d2f677246 --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 073dfa6d3114b214d8a2d2954d572301 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 76a9a1320ba3de8b79b9a4ff0d32fa05a518d166 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 20:15:34 -0800 Subject: [PATCH 02/20] Add MRTK default asset --- .../FontIcons/MRTKFontIconSetDefinition.asset | 96 +++++++++++++++++++ .../MRTKFontIconSetDefinition.asset.meta | 8 ++ 2 files changed, 104 insertions(+) create mode 100644 org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset create mode 100644 org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset.meta diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset b/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset new file mode 100644 index 000000000..c313584b4 --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset @@ -0,0 +1,96 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 073dfa6d3114b214d8a2d2954d572301, type: 3} + m_Name: MRTKFontIconSetDefinition + m_EditorClassIdentifier: + iconNames: + - Wifi + - Bluetooth + - Brightness + - Airplane + - Settings + - People + - Pin + - Bookmark + - Stop Circle + - Add Favorite + - Favorite + - Send + - Search + - Save + - Record Circle + - Question Mark + - Block + - Print + - Power Button + - Play Circle + - Play + - Unpin + - Devices + - Phone + - Person + - Home + - Zoom + - Calendar + - Camera + - Paste + - Phone + - Add + - Mail + - Mute + - Mic Off + - Copy + - Visibility On + - Visibility Off + - Link + - Attach + - Lightbulb + - Movie + - Thumb Up + - Thumb Down + - Thumb Down + - Videocam + - Location On + - Location Off + - Mic + - Undo + - Apps + - Tag + - Arrow Left + - Arrow Right + - Arrow Up + - Arrow Down + - Refresh + - Menu + - More Vertical + - More Horizontal + - Delete + - Chevron Left + - Chevron Right + - Chevron Up + - Chevron Down + - Lock + - Unlock + - Repeat + - Cast + - Clipboard + - Erase + - History + - Notifications + - Notifications Off + - List + - Call + - Call End + - Check + - Edit + - Folder + - Alarm Off diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset.meta b/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset.meta new file mode 100644 index 000000000..d0756e855 --- /dev/null +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e63daff880b56ed439a2e852b6e6993a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: From 616837bb3b4181930a04a70292f3401219e10206 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 21:05:20 -0800 Subject: [PATCH 03/20] Fix race condition where the deserialized value was being read before it was set Now, we pass the font asset in explicitly from the serialization --- .../FontIconSet/FontIconSetInspector.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index f500e5882..a869b6ad5 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -73,8 +73,6 @@ private void OnEnable() /// public override void OnInspectorGUI() { - FontIconSet fontIconSet = (FontIconSet)target; - bool showGlyphIconFoldout = SessionState.GetBool(ShowGlyphIconsFoldoutKey, false); bool showAvailableIcons = SessionState.GetBool(AvailableIconsFoldoutKey, true); bool showSelectedIcons = SessionState.GetBool(SelectedIconsFoldoutKey, true); @@ -103,6 +101,7 @@ public override void OnInspectorGUI() } else { + FontIconSet fontIconSet = (FontIconSet)target; TMP_FontAsset fontAsset = (TMP_FontAsset)iconFontAssetProp.objectReferenceValue; showAvailableIcons = EditorGUILayout.BeginFoldoutHeaderGroup(showAvailableIcons, "Available Icons"); @@ -113,7 +112,7 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("No icons are available in this font. The font may be configured incorrectly.", MessageType.Warning); if (GUILayout.Button("Open Font Editor")) { - Selection.activeObject = fontIconSet.IconFontAsset; + Selection.activeObject = fontAsset; } } else @@ -121,16 +120,16 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("Click an icon to add it to your selected icons.", MessageType.Info); if (GUILayout.Button("Open Font Editor")) { - Selection.activeObject = fontIconSet.IconFontAsset; + Selection.activeObject = fontAsset; } - DrawFontGlyphsGrid(fontIconSet, maxButtonsPerColumn); + DrawFontGlyphsGrid(fontAsset, fontIconSet, maxButtonsPerColumn); } EditorGUILayout.Space(); } - EditorGUILayout.EndFoldoutHeaderGroup(); + showSelectedIcons = EditorGUILayout.BeginFoldoutHeaderGroup(showSelectedIcons, "Selected Icons"); if (showSelectedIcons) { @@ -177,7 +176,6 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("No icons added yet. Click available icons to add.", MessageType.Info); } } - EditorGUILayout.EndFoldoutHeaderGroup(); } } @@ -194,9 +192,21 @@ public override void OnInspectorGUI() /// /// The set of font glyphs to draw. /// The number of buttons per column. + [Obsolete("This method has been removed.")] public void DrawFontGlyphsGrid(FontIconSet fontIconSet, int maxButtonsPerColumn) { TMP_FontAsset fontAsset = fontIconSet.IconFontAsset; + DrawFontGlyphsGrid(fontAsset, fontIconSet, maxButtonsPerColumn); + } + + /// + /// Draw a grid of buttons than can be clicked to select a glyph from a set up glyphs. + /// + /// + /// The set of font glyphs to draw. + /// The number of buttons per column. + private void DrawFontGlyphsGrid(TMP_FontAsset fontAsset, FontIconSet fontIconSet, int maxButtonsPerColumn) + { int column = 0; EditorGUILayout.BeginHorizontal(); for (int i = 0; i < fontAsset.characterTable.Count; i++) From d9594622cc1ed67adc68d9261a2e31a447edcf10 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 21:11:27 -0800 Subject: [PATCH 04/20] Update field naming and general formatting --- .../FontIconSet/FontIconSetInspector.cs | 87 ++++++++----------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index a869b6ad5..1ee69d59a 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -1,4 +1,3 @@ - // Copyright (c) Mixed Reality Toolkit Contributors // Licensed under the BSD 3-Clause @@ -23,19 +22,16 @@ public class FontIconSetInspector : UnityEditor.Editor private const string AvailableIconsFoldoutKey = "MixedRealityToolkit.FontIconSet.ShowAvailableIcons"; private const string SelectedIconsFoldoutKey = "MixedRealityToolkit.FontIconSet.ShowSelectedIcons"; - private const string defaultShaderName = "TextMeshPro/Distance Field SSD"; // Only used for presentation in inspector, not at runtime. - private const int glyphDrawSize = 75; - private const int buttonWidth = 75; - private const int buttonHeight = 90; - private const int maxButtonsPerColumn = 6; - - private static Material fontRenderMaterial; + private const string DefaultShaderName = "TextMeshPro/Distance Field SSD"; // Only used for presentation in inspector, not at runtime. + private const int GlyphDrawSize = 75; + private const int ButtonDimension = 75; + private const int MaxButtonsPerColumn = 6; - private const string noIconFontMessage = "No icon font asset selected. Icon fonts will be unavailable."; - private const string downloadIconFontMessage = "For instructions on how to install the HoloLens icon font asset, click the button below."; - private const string hololensIconFontUrl = "https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/ux-building-blocks/button"; - private const string mdl2IconFontName = "holomdl2"; - private const string textMeshProMenuItem = "Window/TextMeshPro/Font Asset Creator"; + private const string NoIconFontMessage = "No icon font asset selected. Icon fonts will be unavailable."; + private const string DownloadIconFontMessage = "For instructions on how to install the HoloLens icon font asset, click the button below."; + private const string HoloLensIconFontUrl = "https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/ux-building-blocks/button"; + private const string MDL2IconFontName = "holomdl2"; + private const string TextMeshProMenuItem = "Window/TextMeshPro/Font Asset Creator"; private SerializedProperty iconFontAssetProp = null; @@ -88,14 +84,14 @@ public override void OnInspectorGUI() if (iconFontAssetProp.objectReferenceValue == null) { - EditorGUILayout.HelpBox(noIconFontMessage, MessageType.Warning); - if (!CheckIfHololensIconFontExists()) + EditorGUILayout.HelpBox(NoIconFontMessage, MessageType.Warning); + if (!CheckIfHoloLensIconFontExists()) { - EditorGUILayout.HelpBox(downloadIconFontMessage, MessageType.Info); + EditorGUILayout.HelpBox(DownloadIconFontMessage, MessageType.Info); if (GUILayout.Button("View Font Asset Icons Documentation")) { - EditorApplication.ExecuteMenuItem(textMeshProMenuItem); - Application.OpenURL(hololensIconFontUrl); + EditorApplication.ExecuteMenuItem(TextMeshProMenuItem); + Application.OpenURL(HoloLensIconFontUrl); } } } @@ -123,7 +119,7 @@ public override void OnInspectorGUI() Selection.activeObject = fontAsset; } - DrawFontGlyphsGrid(fontAsset, fontIconSet, maxButtonsPerColumn); + DrawFontGlyphsGrid(fontAsset, fontIconSet, MaxButtonsPerColumn); } EditorGUILayout.Space(); @@ -144,13 +140,13 @@ public override void OnInspectorGUI() { using (new EditorGUILayout.HorizontalScope()) { - if (GUILayout.Button(" ", GUILayout.MinHeight(buttonHeight), GUILayout.MaxHeight(buttonHeight), GUILayout.MaxWidth(buttonWidth))) + if (GUILayout.Button(" ", GUILayout.Height(ButtonDimension), GUILayout.MaxWidth(ButtonDimension))) { iconToRemove = iconEntry.Name; } Rect textureRect = GUILayoutUtility.GetLastRect(); - textureRect.width = glyphDrawSize; - textureRect.height = glyphDrawSize; + textureRect.width = GlyphDrawSize; + textureRect.height = GlyphDrawSize; EditorDrawTMPGlyph(textureRect, iconEntry.UnicodeValue, fontAsset); string currentName = iconEntry.Name; @@ -195,14 +191,13 @@ public override void OnInspectorGUI() [Obsolete("This method has been removed.")] public void DrawFontGlyphsGrid(FontIconSet fontIconSet, int maxButtonsPerColumn) { - TMP_FontAsset fontAsset = fontIconSet.IconFontAsset; - DrawFontGlyphsGrid(fontAsset, fontIconSet, maxButtonsPerColumn); + DrawFontGlyphsGrid(fontIconSet.IconFontAsset, fontIconSet, maxButtonsPerColumn); } /// /// Draw a grid of buttons than can be clicked to select a glyph from a set up glyphs. /// - /// + /// The font asset containing the glyphs. /// The set of font glyphs to draw. /// The number of buttons per column. private void DrawFontGlyphsGrid(TMP_FontAsset fontAsset, FontIconSet fontIconSet, int maxButtonsPerColumn) @@ -217,25 +212,23 @@ private void DrawFontGlyphsGrid(TMP_FontAsset fontAsset, FontIconSet fontIconSet EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); } + if (GUILayout.Button(" ", - GUILayout.MinHeight(buttonHeight), - GUILayout.MaxHeight(buttonHeight), - GUILayout.MaxWidth(buttonWidth))) + GUILayout.Height(ButtonDimension), + GUILayout.MaxWidth(ButtonDimension))) { AddIcon(fontIconSet, fontAsset.characterTable[i].unicode); EditorUtility.SetDirty(target); } + Rect textureRect = GUILayoutUtility.GetLastRect(); - textureRect.width = glyphDrawSize; - textureRect.height = glyphDrawSize; + textureRect.width = GlyphDrawSize; + textureRect.height = GlyphDrawSize; EditorDrawTMPGlyph(textureRect, fontAsset, fontAsset.characterTable[i]); - column++; - } - if (column > 0) - { - EditorGUILayout.EndHorizontal(); + column++; } + EditorGUILayout.EndHorizontal(); } private bool AddIcon(FontIconSet fontIconSet, uint unicodeValue) @@ -285,11 +278,11 @@ private void UpdateIconName(FontIconSet fontIconSet, string oldName, string newN } } - private bool CheckIfHololensIconFontExists() + private bool CheckIfHoloLensIconFontExists() { foreach (string guid in AssetDatabase.FindAssets($"t:{typeof(UnityEngine.Font).Name}")) { - if (AssetDatabase.GUIDToAssetPath(guid).Contains(mdl2IconFontName)) + if (AssetDatabase.GUIDToAssetPath(guid).Contains(MDL2IconFontName)) { return true; } @@ -317,7 +310,7 @@ public static void EditorDrawTMPGlyph(Rect glyphRect, TMP_FontAsset fontAsset, T { try { - float iconSizeMultiplier = 0.625f; + const float IconSizeMultiplier = 0.625f; // Get a reference to the Glyph Table int glyphIndex = (int)character.glyphIndex; @@ -335,20 +328,12 @@ public static void EditorDrawTMPGlyph(Rect glyphRect, TMP_FontAsset fontAsset, T { if (fontRenderMaterial == null) { - fontRenderMaterial = new Material(Shader.Find(defaultShaderName)); + fontRenderMaterial = new Material(Shader.Find(DefaultShaderName)); } Material glyphMaterial = fontRenderMaterial; glyphMaterial.mainTexture = atlasTexture; - - if (selected) - { - glyphMaterial.SetColor("_Color", Color.green); - } - else - { - glyphMaterial.SetColor("_Color", Color.white); - } + glyphMaterial.SetColor("_Color", selected ? Color.green : Color.white); int glyphOriginX = glyph.glyphRect.x; int glyphOriginY = glyph.glyphRect.y; @@ -356,13 +341,13 @@ public static void EditorDrawTMPGlyph(Rect glyphRect, TMP_FontAsset fontAsset, T int glyphHeight = glyph.glyphRect.height; float normalizedHeight = fontAsset.faceInfo.ascentLine - fontAsset.faceInfo.descentLine; - float scale = Mathf.Min(glyphRect.width, glyphRect.height) / normalizedHeight * iconSizeMultiplier; + float scale = Mathf.Min(glyphRect.width, glyphRect.height) / normalizedHeight * IconSizeMultiplier; // Compute the normalized texture coordinates Rect texCoords = new Rect((float)glyphOriginX / atlasTexture.width, (float)glyphOriginY / atlasTexture.height, (float)glyphWidth / atlasTexture.width, (float)glyphHeight / atlasTexture.height); - glyphWidth = (int)Mathf.Min(glyphDrawSize, glyphWidth * scale); - glyphHeight = (int)Mathf.Min(glyphDrawSize, glyphHeight * scale); + glyphWidth = (int)Mathf.Min(GlyphDrawSize, glyphWidth * scale); + glyphHeight = (int)Mathf.Min(GlyphDrawSize, glyphHeight * scale); glyphRect.x += (glyphRect.width - glyphWidth) / 2; glyphRect.y += (glyphRect.height - glyphHeight) / 2; From bb5cc5f8dd95220c703743239d1fc5dedb91677a Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 21:12:37 -0800 Subject: [PATCH 05/20] Fix issue where the wrong color param was being set --- .../Editor/Inspectors/FontIconSet/FontIconSetInspector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index 1ee69d59a..a8042a249 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -333,7 +333,7 @@ public static void EditorDrawTMPGlyph(Rect glyphRect, TMP_FontAsset fontAsset, T Material glyphMaterial = fontRenderMaterial; glyphMaterial.mainTexture = atlasTexture; - glyphMaterial.SetColor("_Color", selected ? Color.green : Color.white); + glyphMaterial.SetColor("_FaceColor", selected ? Color.green : Color.white); int glyphOriginX = glyph.glyphRect.x; int glyphOriginY = glyph.glyphRect.y; From 1b278a9eed00fab13440fbde73831b5df5a4810b Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 21:13:59 -0800 Subject: [PATCH 06/20] Disable buttons if the icon has already been added --- .../FontIconSet/FontIconSetInspector.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index a8042a249..b754f7415 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -213,18 +213,21 @@ private void DrawFontGlyphsGrid(TMP_FontAsset fontAsset, FontIconSet fontIconSet EditorGUILayout.BeginHorizontal(); } - if (GUILayout.Button(" ", - GUILayout.Height(ButtonDimension), - GUILayout.MaxWidth(ButtonDimension))) + using (new EditorGUI.DisabledGroupScope(fontIconSet.GlyphIconsByName.ContainsValue(fontAsset.characterTable[i].unicode))) { - AddIcon(fontIconSet, fontAsset.characterTable[i].unicode); - EditorUtility.SetDirty(target); - } + if (GUILayout.Button(" ", + GUILayout.Height(ButtonDimension), + GUILayout.MaxWidth(ButtonDimension))) + { + AddIcon(fontIconSet, fontAsset.characterTable[i].unicode); + EditorUtility.SetDirty(target); + } - Rect textureRect = GUILayoutUtility.GetLastRect(); - textureRect.width = GlyphDrawSize; - textureRect.height = GlyphDrawSize; - EditorDrawTMPGlyph(textureRect, fontAsset, fontAsset.characterTable[i]); + Rect textureRect = GUILayoutUtility.GetLastRect(); + textureRect.width = GlyphDrawSize; + textureRect.height = GlyphDrawSize; + EditorDrawTMPGlyph(textureRect, fontAsset, fontAsset.characterTable[i]); + } column++; } From 7a1a1b48efd37808337d205f1634a04b96fb5556 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 21:17:53 -0800 Subject: [PATCH 07/20] Update to use Foldout instead of BeginFoldoutHeaderGroup We don't need the extra menu stuff provided by BeginFoldoutHeaderGroup --- .../FontIconSet/FontIconSetInspector.cs | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index b754f7415..f6f1eb440 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -75,9 +75,7 @@ public override void OnInspectorGUI() serializedObject.Update(); - showGlyphIconFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(showGlyphIconFoldout, "Font Icons"); - EditorGUILayout.EndFoldoutHeaderGroup(); - + showGlyphIconFoldout = EditorGUILayout.Foldout(showGlyphIconFoldout, "Font Icons"); if (showGlyphIconFoldout) { EditorGUILayout.PropertyField(iconFontAssetProp); @@ -100,7 +98,7 @@ public override void OnInspectorGUI() FontIconSet fontIconSet = (FontIconSet)target; TMP_FontAsset fontAsset = (TMP_FontAsset)iconFontAssetProp.objectReferenceValue; - showAvailableIcons = EditorGUILayout.BeginFoldoutHeaderGroup(showAvailableIcons, "Available Icons"); + showAvailableIcons = EditorGUILayout.Foldout(showAvailableIcons, "Available Icons"); if (showAvailableIcons) { if (fontAsset.characterTable.Count == 0) @@ -124,9 +122,8 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); } - EditorGUILayout.EndFoldoutHeaderGroup(); - showSelectedIcons = EditorGUILayout.BeginFoldoutHeaderGroup(showSelectedIcons, "Selected Icons"); + showSelectedIcons = EditorGUILayout.Foldout(showSelectedIcons, "Selected Icons"); if (showSelectedIcons) { if (fontIconSet.GlyphIconsByName.Count > 0) @@ -172,7 +169,6 @@ public override void OnInspectorGUI() EditorGUILayout.HelpBox("No icons added yet. Click available icons to add.", MessageType.Info); } } - EditorGUILayout.EndFoldoutHeaderGroup(); } } @@ -247,12 +243,9 @@ private bool AddIcon(FontIconSet fontIconSet, uint unicodeValue) private bool RemoveIcon(FontIconSet fontIconSet, string iconName) { bool removed = fontIconSet.RemoveIcon(iconName); - if (removed) + if (removed && FindIconIndexByName(iconName, out int index)) { - if (FindIconIndexByName(iconName, out int index)) - { - iconEntries.RemoveAt(index); - } + iconEntries.RemoveAt(index); } return removed; } @@ -272,12 +265,9 @@ private bool FindIconIndexByName(string iconName, out int outIndex) private void UpdateIconName(FontIconSet fontIconSet, string oldName, string newName) { - if (fontIconSet.UpdateIconName(oldName, newName)) + if (fontIconSet.UpdateIconName(oldName, newName) && FindIconIndexByName(oldName, out int index)) { - if (FindIconIndexByName(oldName, out int index)) - { - iconEntries[index].Name = newName; - } + iconEntries[index].Name = newName; } } From 36d2ed2b66b30c341f3be7c0eb9d531e715d8dad Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 21:22:36 -0800 Subject: [PATCH 08/20] Update FontIconSetInspector.cs --- .../Editor/Inspectors/FontIconSet/FontIconSetInspector.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index f6f1eb440..c63a93de0 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -75,7 +75,7 @@ public override void OnInspectorGUI() serializedObject.Update(); - showGlyphIconFoldout = EditorGUILayout.Foldout(showGlyphIconFoldout, "Font Icons"); + showGlyphIconFoldout = EditorGUILayout.Foldout(showGlyphIconFoldout, "Font Icons", true); if (showGlyphIconFoldout) { EditorGUILayout.PropertyField(iconFontAssetProp); @@ -98,7 +98,7 @@ public override void OnInspectorGUI() FontIconSet fontIconSet = (FontIconSet)target; TMP_FontAsset fontAsset = (TMP_FontAsset)iconFontAssetProp.objectReferenceValue; - showAvailableIcons = EditorGUILayout.Foldout(showAvailableIcons, "Available Icons"); + showAvailableIcons = EditorGUILayout.Foldout(showAvailableIcons, "Available Icons", true); if (showAvailableIcons) { if (fontAsset.characterTable.Count == 0) @@ -123,7 +123,7 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); } - showSelectedIcons = EditorGUILayout.Foldout(showSelectedIcons, "Selected Icons"); + showSelectedIcons = EditorGUILayout.Foldout(showSelectedIcons, "Selected Icons", true); if (showSelectedIcons) { if (fontIconSet.GlyphIconsByName.Count > 0) From 6c6a1a67ac72d045b0a831582857c563e0a3bd80 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Mon, 10 Nov 2025 21:36:19 -0800 Subject: [PATCH 09/20] Update selected icons display for improved flow and usage More icons on screen at once! --- .../FontIconSet/FontIconSetInspector.cs | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index c63a93de0..86a9edb8b 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -130,38 +130,46 @@ public override void OnInspectorGUI() { EditorGUILayout.HelpBox("These icons will appear in the button config helper inspector. Click an icon to remove it from this list.", MessageType.Info); - using (new EditorGUILayout.VerticalScope()) + int column = 0; + string iconToRemove = null; + EditorGUILayout.BeginHorizontal(); + foreach (IconEntry iconEntry in iconEntries) { - string iconToRemove = null; - foreach (IconEntry iconEntry in iconEntries) + if (column >= MaxButtonsPerColumn) { - using (new EditorGUILayout.HorizontalScope()) - { - if (GUILayout.Button(" ", GUILayout.Height(ButtonDimension), GUILayout.MaxWidth(ButtonDimension))) - { - iconToRemove = iconEntry.Name; - } - Rect textureRect = GUILayoutUtility.GetLastRect(); - textureRect.width = GlyphDrawSize; - textureRect.height = GlyphDrawSize; - EditorDrawTMPGlyph(textureRect, iconEntry.UnicodeValue, fontAsset); - - string currentName = iconEntry.Name; - currentName = EditorGUILayout.TextField(currentName); - if (currentName != iconEntry.Name) - { - UpdateIconName(fontIconSet, iconEntry.Name, currentName); - } - EditorGUILayout.Space(); - } - - EditorGUILayout.Space(); + column = 0; + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); } - if (iconToRemove != null) + EditorGUILayout.BeginVertical(GUILayout.Width(ButtonDimension)); + + if (GUILayout.Button(" ", + GUILayout.Height(ButtonDimension), + GUILayout.MaxWidth(ButtonDimension))) + { + iconToRemove = iconEntry.Name; + } + + Rect textureRect = GUILayoutUtility.GetLastRect(); + textureRect.width = GlyphDrawSize; + textureRect.height = GlyphDrawSize; + EditorDrawTMPGlyph(textureRect, iconEntry.UnicodeValue, fontAsset); + + string currentName = EditorGUILayout.TextField(iconEntry.Name); + if (currentName != iconEntry.Name) { - RemoveIcon(fontIconSet, iconToRemove); + UpdateIconName(fontIconSet, iconEntry.Name, currentName); } + EditorGUILayout.EndVertical(); + + column++; + } + EditorGUILayout.EndHorizontal(); + + if (iconToRemove != null) + { + RemoveIcon(fontIconSet, iconToRemove); } } else From 0fc0644e91ac8713a821ff5ad18e3c8a9d0a1a4b Mon Sep 17 00:00:00 2001 From: Kurtis Date: Tue, 11 Nov 2025 11:16:22 -0800 Subject: [PATCH 10/20] Add FontIconSetDefinition to FontIconSet --- .../Inspectors/FontIconSet/FontIconSetInspector.cs | 8 ++++++++ .../FontIcons/FontIconSet.cs | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index 86a9edb8b..1572b8c50 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -34,6 +34,7 @@ public class FontIconSetInspector : UnityEditor.Editor private const string TextMeshProMenuItem = "Window/TextMeshPro/Font Asset Creator"; private SerializedProperty iconFontAssetProp = null; + private SerializedProperty fontIconSetDefinition = null; private class IconEntry { @@ -56,6 +57,7 @@ private void OnEnable() { FontIconSet fontIconSet = (FontIconSet)target; iconFontAssetProp = serializedObject.FindProperty("iconFontAsset"); + fontIconSetDefinition = serializedObject.FindProperty("fontIconSetDefinition"); // Make a list out of dictionary to avoid changing order while editing names foreach (KeyValuePair kv in fontIconSet.GlyphIconsByName) @@ -79,6 +81,7 @@ public override void OnInspectorGUI() if (showGlyphIconFoldout) { EditorGUILayout.PropertyField(iconFontAssetProp); + EditorGUILayout.PropertyField(fontIconSetDefinition); if (iconFontAssetProp.objectReferenceValue == null) { @@ -130,6 +133,11 @@ public override void OnInspectorGUI() { EditorGUILayout.HelpBox("These icons will appear in the button config helper inspector. Click an icon to remove it from this list.", MessageType.Info); + if (fontIconSetDefinition.objectReferenceValue == null) + { + EditorGUILayout.HelpBox("It's recommended to use a Font Icon Set Definition to ensure consistent icon names across icon sets.", MessageType.Warning); + } + int column = 0; string iconToRemove = null; EditorGUILayout.BeginHorizontal(); diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs index 730ad7324..224166c3d 100644 --- a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs @@ -30,8 +30,8 @@ public class FontIconSet : ScriptableObject /// public SerializableDictionary GlyphIconsByName => glyphIconsByName; - [Tooltip("Any TextMeshPro Font Asset that contains the desired icons as glyphs that map to Unicode character values.")] [SerializeField] + [Tooltip("Any TextMeshPro Font Asset that contains the desired icons as glyphs that map to Unicode character values.")] private TMP_FontAsset iconFontAsset = null; /// @@ -39,8 +39,8 @@ public class FontIconSet : ScriptableObject /// public TMP_FontAsset IconFontAsset => iconFontAsset; - [Tooltip("Optional material to use for rendering glyphs in editor.")] [SerializeField] + [Tooltip("Optional material to use for rendering glyphs in editor.")] private Material optionalEditorMaterial; /// @@ -48,6 +48,15 @@ public class FontIconSet : ScriptableObject /// public Material OptionalEditorMaterial => optionalEditorMaterial; + [SerializeField] + [Tooltip("Optional definition to provide consistent icon names.")] + private FontIconSetDefinition fontIconSetDefinition; + + /// + /// Optional definition to provide consistent icon names. + /// + public FontIconSetDefinition FontIconSetDefinition => fontIconSetDefinition; + /// /// Try to get a glyph icon's unicode value by name. /// From dfaf0023433d98c3128a1b4b4332cc13037d6e02 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Tue, 11 Nov 2025 13:30:58 -0800 Subject: [PATCH 11/20] Fix asset not being marked dirty when changed --- .../Inspectors/FontIconSet/FontIconSetInspector.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index 1572b8c50..e0858b5aa 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -34,7 +34,7 @@ public class FontIconSetInspector : UnityEditor.Editor private const string TextMeshProMenuItem = "Window/TextMeshPro/Font Asset Creator"; private SerializedProperty iconFontAssetProp = null; - private SerializedProperty fontIconSetDefinition = null; + private SerializedProperty fontIconSetDefinitionProp = null; private class IconEntry { @@ -57,7 +57,7 @@ private void OnEnable() { FontIconSet fontIconSet = (FontIconSet)target; iconFontAssetProp = serializedObject.FindProperty("iconFontAsset"); - fontIconSetDefinition = serializedObject.FindProperty("fontIconSetDefinition"); + fontIconSetDefinitionProp = serializedObject.FindProperty("fontIconSetDefinition"); // Make a list out of dictionary to avoid changing order while editing names foreach (KeyValuePair kv in fontIconSet.GlyphIconsByName) @@ -81,7 +81,7 @@ public override void OnInspectorGUI() if (showGlyphIconFoldout) { EditorGUILayout.PropertyField(iconFontAssetProp); - EditorGUILayout.PropertyField(fontIconSetDefinition); + EditorGUILayout.PropertyField(fontIconSetDefinitionProp); if (iconFontAssetProp.objectReferenceValue == null) { @@ -133,7 +133,7 @@ public override void OnInspectorGUI() { EditorGUILayout.HelpBox("These icons will appear in the button config helper inspector. Click an icon to remove it from this list.", MessageType.Info); - if (fontIconSetDefinition.objectReferenceValue == null) + if (fontIconSetDefinitionProp.objectReferenceValue == null) { EditorGUILayout.HelpBox("It's recommended to use a Font Icon Set Definition to ensure consistent icon names across icon sets.", MessageType.Warning); } @@ -252,6 +252,7 @@ private bool AddIcon(FontIconSet fontIconSet, uint unicodeValue) if (fontIconSet.AddIcon(name, unicodeValue)) { iconEntries.Add(new IconEntry(name, unicodeValue)); + EditorUtility.SetDirty(fontIconSet); } return true; } @@ -262,6 +263,7 @@ private bool RemoveIcon(FontIconSet fontIconSet, string iconName) if (removed && FindIconIndexByName(iconName, out int index)) { iconEntries.RemoveAt(index); + EditorUtility.SetDirty(fontIconSet); } return removed; } @@ -284,6 +286,7 @@ private void UpdateIconName(FontIconSet fontIconSet, string oldName, string newN if (fontIconSet.UpdateIconName(oldName, newName) && FindIconIndexByName(oldName, out int index)) { iconEntries[index].Name = newName; + EditorUtility.SetDirty(fontIconSet); } } From 909f4e9285dc05fefb336365203e08742b5afa7b Mon Sep 17 00:00:00 2001 From: Kurtis Date: Tue, 11 Nov 2025 15:05:41 -0800 Subject: [PATCH 12/20] Simplify CRUD method implementations --- .../FontIcons/FontIconSet.cs | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs index 224166c3d..0948b64f6 100644 --- a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSet.cs @@ -65,7 +65,6 @@ public class FontIconSet : ScriptableObject /// if icon name found, otherwise . public bool TryGetGlyphIcon(string iconName, out uint unicodeValue) { - unicodeValue = 0; return glyphIconsByName.TryGetValue(iconName, out unicodeValue); } @@ -77,15 +76,7 @@ public bool TryGetGlyphIcon(string iconName, out uint unicodeValue) /// Whether it was able to add this icon. public bool AddIcon(string name, uint unicodeValue) { - if (glyphIconsByName.ContainsValue(unicodeValue)) - { - return false; - } - else - { - glyphIconsByName[name] = unicodeValue; - return true; - } + return !glyphIconsByName.ContainsValue(unicodeValue) && glyphIconsByName.TryAdd(name, unicodeValue); } /// @@ -95,15 +86,7 @@ public bool AddIcon(string name, uint unicodeValue) /// Whether it was able to find the name and remove it. public bool RemoveIcon(string iconName) { - if (glyphIconsByName.ContainsKey(iconName)) - { - glyphIconsByName.Remove(iconName); - return true; - } - else - { - return false; - } + return glyphIconsByName.Remove(iconName); } /// @@ -118,16 +101,7 @@ public bool RemoveIcon(string iconName) /// if it was able to find and update the name. public bool UpdateIconName(string oldName, string newName) { - if (glyphIconsByName.ContainsKey(oldName) && !glyphIconsByName.ContainsKey(newName)) - { - glyphIconsByName[newName] = glyphIconsByName[oldName]; - glyphIconsByName.Remove(oldName); - return true; - } - else - { - return false; - } + return glyphIconsByName.TryGetValue(oldName, out uint unicodeValue) && glyphIconsByName.TryAdd(newName, unicodeValue) && glyphIconsByName.Remove(oldName); } /// From 0d9cd90aa5f5c92131d422137d767dae64fab61e Mon Sep 17 00:00:00 2001 From: Kurtis Date: Tue, 11 Nov 2025 15:22:16 -0800 Subject: [PATCH 13/20] Sort the added symbols by unicode value --- .../FontIconSet/FontIconSetInspector.cs | 72 +++++++------------ 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index e0858b5aa..76b653768 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -36,19 +36,7 @@ public class FontIconSetInspector : UnityEditor.Editor private SerializedProperty iconFontAssetProp = null; private SerializedProperty fontIconSetDefinitionProp = null; - private class IconEntry - { - public string Name; - public uint UnicodeValue; - - public IconEntry(string name, uint unicodeValue) - { - Name = name; - UnicodeValue = unicodeValue; - } - } - - private List iconEntries = new List(); + private SortedList iconEntries = new SortedList(); /// /// A Unity event function that is called when the script component has been enabled. @@ -62,7 +50,7 @@ private void OnEnable() // Make a list out of dictionary to avoid changing order while editing names foreach (KeyValuePair kv in fontIconSet.GlyphIconsByName) { - iconEntries.Add(new IconEntry(kv.Key, kv.Value)); + iconEntries.Add(kv.Value, kv.Key); } } @@ -98,8 +86,8 @@ public override void OnInspectorGUI() } else { - FontIconSet fontIconSet = (FontIconSet)target; - TMP_FontAsset fontAsset = (TMP_FontAsset)iconFontAssetProp.objectReferenceValue; + FontIconSet fontIconSet = target as FontIconSet; + TMP_FontAsset fontAsset = iconFontAssetProp.objectReferenceValue as TMP_FontAsset; showAvailableIcons = EditorGUILayout.Foldout(showAvailableIcons, "Available Icons", true); if (showAvailableIcons) @@ -140,8 +128,9 @@ public override void OnInspectorGUI() int column = 0; string iconToRemove = null; + string iconToRename = null; EditorGUILayout.BeginHorizontal(); - foreach (IconEntry iconEntry in iconEntries) + foreach (KeyValuePair iconEntry in iconEntries) { if (column >= MaxButtonsPerColumn) { @@ -156,18 +145,19 @@ public override void OnInspectorGUI() GUILayout.Height(ButtonDimension), GUILayout.MaxWidth(ButtonDimension))) { - iconToRemove = iconEntry.Name; + iconToRemove = iconEntry.Value; } Rect textureRect = GUILayoutUtility.GetLastRect(); textureRect.width = GlyphDrawSize; textureRect.height = GlyphDrawSize; - EditorDrawTMPGlyph(textureRect, iconEntry.UnicodeValue, fontAsset); + EditorDrawTMPGlyph(textureRect, iconEntry.Key, fontAsset); - string currentName = EditorGUILayout.TextField(iconEntry.Name); - if (currentName != iconEntry.Name) + string currentName = EditorGUILayout.TextField(iconEntry.Value); + if (currentName != iconEntry.Value) { - UpdateIconName(fontIconSet, iconEntry.Name, currentName); + iconToRename = currentName; + iconToRemove = iconEntry.Value; } EditorGUILayout.EndVertical(); @@ -175,7 +165,11 @@ public override void OnInspectorGUI() } EditorGUILayout.EndHorizontal(); - if (iconToRemove != null) + if (iconToRename != null) + { + UpdateIconName(fontIconSet, iconToRemove, iconToRename); + } + else if (iconToRemove != null) { RemoveIcon(fontIconSet, iconToRemove); } @@ -248,51 +242,39 @@ private void DrawFontGlyphsGrid(TMP_FontAsset fontAsset, FontIconSet fontIconSet private bool AddIcon(FontIconSet fontIconSet, uint unicodeValue) { - string name = "Icon " + (iconEntries.Count + 1); + string name = $"Icon {unicodeValue}"; if (fontIconSet.AddIcon(name, unicodeValue)) { - iconEntries.Add(new IconEntry(name, unicodeValue)); + iconEntries.Add(unicodeValue, name); EditorUtility.SetDirty(fontIconSet); + return true; } - return true; + return false; } private bool RemoveIcon(FontIconSet fontIconSet, string iconName) { - bool removed = fontIconSet.RemoveIcon(iconName); - if (removed && FindIconIndexByName(iconName, out int index)) + if (fontIconSet.TryGetGlyphIcon(iconName, out uint unicodeValue) && fontIconSet.RemoveIcon(iconName)) { - iconEntries.RemoveAt(index); + iconEntries.Remove(unicodeValue); EditorUtility.SetDirty(fontIconSet); + return true; } - return removed; - } - - private bool FindIconIndexByName(string iconName, out int outIndex) - { - for (outIndex = 0; outIndex < iconEntries.Count; outIndex++) - { - if (iconEntries[outIndex].Name == iconName) - { - return true; - } - } - outIndex = -1; return false; } private void UpdateIconName(FontIconSet fontIconSet, string oldName, string newName) { - if (fontIconSet.UpdateIconName(oldName, newName) && FindIconIndexByName(oldName, out int index)) + if (fontIconSet.UpdateIconName(oldName, newName) && fontIconSet.TryGetGlyphIcon(newName, out uint unicodeValue)) { - iconEntries[index].Name = newName; + iconEntries[unicodeValue] = newName; EditorUtility.SetDirty(fontIconSet); } } private bool CheckIfHoloLensIconFontExists() { - foreach (string guid in AssetDatabase.FindAssets($"t:{typeof(UnityEngine.Font).Name}")) + foreach (string guid in AssetDatabase.FindAssets($"t:{nameof(Font)}")) { if (AssetDatabase.GUIDToAssetPath(guid).Contains(MDL2IconFontName)) { From 3eaf352b41208cea929469f9b3a4b971692e09f2 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Tue, 11 Nov 2025 15:43:47 -0800 Subject: [PATCH 14/20] Update FontIconSetDefinition.cs --- .../FontIcons/FontIconSetDefinition.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs index 111153f0b..8688d2f8a 100644 --- a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSetDefinition.cs @@ -12,6 +12,9 @@ public class FontIconSetDefinition : ScriptableObject [SerializeField] private string[] iconNames; - public string[] IconNames => iconNames; + /// + /// The list of icon names defined by this asset. + /// + public IReadOnlyList IconNames => iconNames; } } From 4a890c891ddc9da86a5954b6dcaa87daf2530494 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Tue, 11 Nov 2025 15:47:50 -0800 Subject: [PATCH 15/20] Create dropdown for accessing icon set definition names --- .../FontIconSet/FontIconSetInspector.cs | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs index 76b653768..bb53b8f8f 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs @@ -35,8 +35,12 @@ public class FontIconSetInspector : UnityEditor.Editor private SerializedProperty iconFontAssetProp = null; private SerializedProperty fontIconSetDefinitionProp = null; + private bool anyInvalidName = false; private SortedList iconEntries = new SortedList(); + private List validNames = new List(); + private List availableNames = new List(); + private string[] availableNamesArray = Array.Empty(); /// /// A Unity event function that is called when the script component has been enabled. @@ -88,6 +92,7 @@ public override void OnInspectorGUI() { FontIconSet fontIconSet = target as FontIconSet; TMP_FontAsset fontAsset = iconFontAssetProp.objectReferenceValue as TMP_FontAsset; + FontIconSetDefinition setDefinition = fontIconSetDefinitionProp.objectReferenceValue as FontIconSetDefinition; showAvailableIcons = EditorGUILayout.Foldout(showAvailableIcons, "Available Icons", true); if (showAvailableIcons) @@ -125,6 +130,29 @@ public override void OnInspectorGUI() { EditorGUILayout.HelpBox("It's recommended to use a Font Icon Set Definition to ensure consistent icon names across icon sets.", MessageType.Warning); } + else + { + if (anyInvalidName) + { + EditorGUILayout.HelpBox("Icon names highlighted yellow are not present in the selected Font Icon Set Definition and should be updated.", MessageType.Warning); + anyInvalidName = false; + } + + validNames.Clear(); + availableNames.Clear(); + // Reserve space for the current icon's name + availableNames.Add(string.Empty); + foreach (string name in setDefinition.IconNames) + { + validNames.Add(name); + if (!iconEntries.ContainsValue(name)) + { + availableNames.Add(name); + } + } + + availableNamesArray = availableNames.ToArray(); + } int column = 0; string iconToRemove = null; @@ -153,11 +181,37 @@ public override void OnInspectorGUI() textureRect.height = GlyphDrawSize; EditorDrawTMPGlyph(textureRect, iconEntry.Key, fontAsset); - string currentName = EditorGUILayout.TextField(iconEntry.Value); - if (currentName != iconEntry.Value) + if (fontIconSetDefinitionProp.objectReferenceValue != null) { - iconToRename = currentName; - iconToRemove = iconEntry.Value; + // Place the current icon's name in the array + availableNamesArray[0] = iconEntry.Value; + + using (var check = new EditorGUI.ChangeCheckScope()) + { + // If the currently selected name isn't in our icon set map names, highlight the popup + Color oldColor = GUI.backgroundColor; + if (!validNames.Contains(iconEntry.Value)) + { + GUI.backgroundColor = Color.yellow; + anyInvalidName = true; + } + int selected = EditorGUILayout.Popup(string.Empty, 0, availableNamesArray, GUILayout.MaxWidth(ButtonDimension)); + if (check.changed) + { + iconToRename = availableNamesArray[selected]; + iconToRemove = iconEntry.Value; + } + GUI.backgroundColor = oldColor; + } + } + else + { + string currentName = EditorGUILayout.TextField(iconEntry.Value); + if (currentName != iconEntry.Value) + { + iconToRename = currentName; + iconToRemove = iconEntry.Value; + } } EditorGUILayout.EndVertical(); From dd15df7ceb18a97fd22ab41bfe3a6ab0a648c185 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Tue, 11 Nov 2025 15:57:38 -0800 Subject: [PATCH 16/20] Update Selawik-Semibold-MRTKIcons.asset --- .../Fonts/Selawik-Semibold-MRTKIcons.asset | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset b/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset index 843ea507b..8534c6110 100644 --- a/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset +++ b/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset @@ -14,12 +14,8 @@ MonoBehaviour: m_EditorClassIdentifier: glyphIconsByName: entries: - - key: Icon 137 - value: 63518 - key: Icon 136 value: 63357 - - key: Icon 135 - value: 63323 - key: Icon 134 value: 63252 - key: Icon 133 @@ -210,10 +206,6 @@ MonoBehaviour: value: 61810 - key: Icon 40 value: 61801 - - key: Icon 39 - value: 61788 - - key: Icon 38 - value: 61769 - key: Icon 37 value: 61760 - key: Icon 36 @@ -230,8 +222,6 @@ MonoBehaviour: value: 61717 - key: Icon 30 value: 61709 - - key: Icon 29 - value: 61706 - key: Icon 28 value: 60390 - key: Icon 27 @@ -276,8 +266,6 @@ MonoBehaviour: value: 59508 - key: Icon 7 value: 59476 - - key: Icon 6 - value: 59461 - key: Icon 2 value: 59416 - key: Icon 3 @@ -298,5 +286,18 @@ MonoBehaviour: value: 63703 - key: Icon 142 value: 63742 + - key: Thumb Down + value: 63518 + - key: Stop Circle + value: 63323 + - key: Add + value: 61706 + - key: Arrow Down + value: 61769 + - key: Arrow Left + value: 61788 + - key: Call + value: 59461 iconFontAsset: {fileID: 11400000, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} optionalEditorMaterial: {fileID: 0} + fontIconSetDefinition: {fileID: 11400000, guid: e63daff880b56ed439a2e852b6e6993a, type: 2} From ecf172912eb90a3852bea2c312c5590faafb1c83 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Wed, 12 Nov 2025 14:55:04 -0800 Subject: [PATCH 17/20] Add more icon names --- .../FontIcons/MRTKFontIconSetDefinition.asset | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset b/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset index c313584b4..2ac6c526d 100644 --- a/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/MRTKFontIconSetDefinition.asset @@ -94,3 +94,13 @@ MonoBehaviour: - Edit - Folder - Alarm Off + - Warning + - Info + - Error + - Keyboard + - Cancel + - Dialpad + - Photo + - Save As + - Close + - Cut From 9c9c854d463c5e348f1b303e56906111dc82fe4c Mon Sep 17 00:00:00 2001 From: Kurtis Date: Wed, 12 Nov 2025 15:46:57 -0800 Subject: [PATCH 18/20] Add migration path for FontIconSelector --- .../FontIcons/FontIconSelector.cs | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSelector.cs b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSelector.cs index 54e81f646..19fee1a50 100644 --- a/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSelector.cs +++ b/org.mixedrealitytoolkit.uxcore/FontIcons/FontIconSelector.cs @@ -1,7 +1,7 @@ // Copyright (c) Mixed Reality Toolkit Contributors // Licensed under the BSD 3-Clause -using System; +using System.Collections.Generic; using TMPro; using UnityEngine; @@ -11,7 +11,7 @@ namespace MixedReality.Toolkit.UX /// Allows the user to select a specific icon for display via a Unity text component. /// [AddComponentMenu("MRTK/UX/Font Icon Selector")] - public class FontIconSelector : MonoBehaviour + public class FontIconSelector : MonoBehaviour, ISerializationCallbackReceiver { [Tooltip("The FontIconSet that contains the icons available for use.")] [SerializeField] @@ -52,6 +52,11 @@ public string CurrentIconName /// public TMP_Text TextMeshProComponent => textMeshProComponent; + // A temporary variable used to migrate instances of FontIconSelector to use new FontIconSetDefinition names. + // TODO: Remove this after some time to ensure users have successfully migrated. + [SerializeField, HideInInspector] + private bool migratedSuccessfully = false; + /// /// A Unity event function that is called when an enabled script instance is being loaded. /// @@ -83,12 +88,32 @@ private void OnValidate() private void SetIcon(string newIconName) { - if (fontIcons != null && textMeshProComponent != null) + if (fontIcons != null && textMeshProComponent != null && fontIcons.TryGetGlyphIcon(newIconName, out uint unicodeValue)) + { + currentIconName = newIconName; + textMeshProComponent.text = FontIconSet.ConvertUnicodeToHexString(unicodeValue); + } + } + + void ISerializationCallbackReceiver.OnBeforeSerialize() { } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + if (!migratedSuccessfully && fontIcons != null && fontIcons.FontIconSetDefinition != null && textMeshProComponent != null) { - if (fontIcons.TryGetGlyphIcon(newIconName, out uint unicodeValue)) + uint unicodeValue = FontIconSet.ConvertHexStringToUnicode(textMeshProComponent.text); + foreach (KeyValuePair kv in fontIcons.GlyphIconsByName) { - currentIconName = newIconName; - textMeshProComponent.text = FontIconSet.ConvertUnicodeToHexString(unicodeValue); + if (kv.Value == unicodeValue) + { + if (currentIconName != kv.Key) + { + Debug.Log($"[{nameof(FontIconSelector)}] Successfully migrated icon: \"{currentIconName}\" to \"{kv.Key}\"", this); + currentIconName = kv.Key; + migratedSuccessfully = true; + } + break; + } } } } From f22495deaf45fb2ecde4d3db1c859bca51726445 Mon Sep 17 00:00:00 2001 From: Kurtis Date: Wed, 12 Nov 2025 15:47:22 -0800 Subject: [PATCH 19/20] Update FontIconSelectorInspector.cs --- .../FontIconSet/FontIconSelectorInspector.cs | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSelectorInspector.cs b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSelectorInspector.cs index 115528aeb..3a3d83296 100644 --- a/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSelectorInspector.cs +++ b/org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSelectorInspector.cs @@ -1,4 +1,3 @@ - // Copyright (c) Mixed Reality Toolkit Contributors // Licensed under the BSD 3-Clause @@ -13,12 +12,6 @@ namespace MixedReality.Toolkit.Editor [CanEditMultipleObjects] class FontIconSelectorInspector : UnityEditor.Editor { - - private const string defaultShaderName = "TextMeshPro/Distance Field SSD"; - private float fontTileSize = 32; - - private static Material fontRenderMaterial; - private const string noFontIconsMessage = "No IconFontSet profile selected. No icons available."; private const string emptyFontIconSetMessage = "The selected IconFontSet profile has no icons defined. Please edit the IconFontSet."; @@ -29,6 +22,7 @@ class FontIconSelectorInspector : UnityEditor.Editor private GUIStyle currentButtonStyle; private bool initializedStyle = false; + private float fontTileSize = 32; /// /// A Unity event function that is called when the script component has been enabled. @@ -38,7 +32,6 @@ private void OnEnable() fontIconsProp = serializedObject.FindProperty("fontIcons"); currentIconNameProp = serializedObject.FindProperty("currentIconName"); tmProProp = serializedObject.FindProperty("textMeshProComponent"); - } /// @@ -90,7 +83,6 @@ public override void OnInspectorGUI() } private int numColumns = 4; - private Vector2 scrollAmount; public void DrawIconGrid(FontIconSelector fontIconSelector, float tileSize) @@ -101,45 +93,42 @@ public void DrawIconGrid(FontIconSelector fontIconSelector, float tileSize) scrollAmount = EditorGUILayout.BeginScrollView(scrollAmount, GUILayout.MaxHeight(128), GUILayout.MinHeight(64)); EditorGUILayout.BeginHorizontal(); - + foreach (string iconName in fontIconSet.GlyphIconsByName.Keys) { uint unicodeValue = fontIconSet.GlyphIconsByName[iconName]; - bool selected = (iconName == fontIconSelector.CurrentIconName); + if (column >= numColumns) { column = 0; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); } + if (GUILayout.Button(" ", - GUILayout.MinHeight(tileSize), - GUILayout.MaxHeight(tileSize), - GUILayout.MinWidth(tileSize), - GUILayout.MaxWidth(tileSize))) + GUILayout.Height(tileSize), + GUILayout.Width(tileSize))) { - Undo.RecordObjects(new UnityEngine.Object[]{fontIconSelector, fontIconSelector.TextMeshProComponent}, "Changed icon"); + Undo.RecordObjects(new Object[] { fontIconSelector, fontIconSelector.TextMeshProComponent }, "Changed icon"); fontIconSelector.CurrentIconName = iconName; PrefabUtility.RecordPrefabInstancePropertyModifications(fontIconSelector); PrefabUtility.RecordPrefabInstancePropertyModifications(fontIconSelector.TextMeshProComponent); } + Rect textureRect = GUILayoutUtility.GetLastRect(); if (textureRect.yMin + 8 < scrollAmount.y || textureRect.yMax - 8 > scrollAmount.y + 128) { unicodeValue = 0; } - textureRect.width = tileSize; textureRect.height = tileSize; - FontIconSetInspector.EditorDrawTMPGlyph(textureRect, unicodeValue, fontAsset, selected); + FontIconSetInspector.EditorDrawTMPGlyph(textureRect, unicodeValue, fontAsset, iconName == fontIconSelector.CurrentIconName); + column++; } - if (column > 0) - { - EditorGUILayout.EndHorizontal(); - } - + EditorGUILayout.EndHorizontal(); + if (Event.current.type == EventType.Repaint) { float editorWindowWidth = GUILayoutUtility.GetLastRect().width; From c2060c381d7bd9e85fcede6b722b451adb19685d Mon Sep 17 00:00:00 2001 From: Kurtis Date: Wed, 12 Nov 2025 15:51:59 -0800 Subject: [PATCH 20/20] Update Selawik-Semibold-MRTKIcons.asset --- .../Fonts/Selawik-Semibold-MRTKIcons.asset | 318 +++++++++--------- 1 file changed, 158 insertions(+), 160 deletions(-) diff --git a/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset b/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset index 8534c6110..7ecd4089a 100644 --- a/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset +++ b/org.mixedrealitytoolkit.standardassets/Fonts/Selawik-Semibold-MRTKIcons.asset @@ -14,48 +14,8 @@ MonoBehaviour: m_EditorClassIdentifier: glyphIconsByName: entries: - - key: Icon 136 - value: 63357 - - key: Icon 134 - value: 63252 - - key: Icon 133 - value: 63248 - - key: Icon 132 - value: 63146 - - key: Icon 131 - value: 63130 - - key: Icon 130 - value: 63120 - - key: Icon 129 - value: 63104 - - key: Icon 128 - value: 63074 - - key: Icon 127 - value: 63033 - - key: Icon 126 - value: 63022 - - key: Icon 125 - value: 63019 - - key: Icon 124 - value: 62991 - - key: Icon 123 - value: 62984 - - key: Icon 122 - value: 62982 - - key: Icon 121 - value: 62980 - - key: Icon 120 - value: 62978 - - key: Icon 119 - value: 62950 - - key: Icon 118 - value: 62945 - - key: Icon 117 - value: 62910 - key: Icon 116 value: 62893 - - key: Icon 115 - value: 62889 - key: Icon 114 value: 62858 - key: Icon 113 @@ -66,56 +26,22 @@ MonoBehaviour: value: 62828 - key: Icon 110 value: 62822 - - key: Icon 109 - value: 62817 - key: Icon 108 value: 62815 - - key: Icon 107 - value: 62810 - - key: Icon 106 - value: 62807 - - key: Icon 105 - value: 62785 - - key: Icon 104 - value: 62727 - - key: Icon 103 - value: 62713 - - key: Icon 102 - value: 62700 - - key: Icon 101 - value: 62693 - - key: Icon 100 - value: 62679 - - key: Icon 99 - value: 62649 - key: Icon 98 value: 62632 - - key: Icon 97 - value: 62628 - key: Icon 96 value: 62624 - - key: Icon 95 - value: 62601 - - key: Icon 94 - value: 62593 - - key: Icon 93 - value: 62591 - key: Icon 92 value: 62586 - key: Icon 91 value: 62578 - key: Icon 90 value: 62555 - - key: Icon 89 - value: 62489 - key: Icon 88 value: 62476 - - key: Icon 87 - value: 62450 - key: Icon 86 value: 62433 - - key: Icon 85 - value: 62430 - key: Icon 84 value: 62427 - key: Icon 83 @@ -124,24 +50,14 @@ MonoBehaviour: value: 62329 - key: Icon 81 value: 62326 - - key: Icon 80 - value: 62318 - - key: Icon 79 - value: 62314 - - key: Icon 78 - value: 62303 - key: Icon 77 value: 62298 - - key: Icon 76 - value: 62285 - key: Icon 75 value: 62277 - key: Icon 74 value: 62274 - key: Icon 73 value: 62269 - - key: Icon 72 - value: 62267 - key: Icon 71 value: 62240 - key: Icon 70 @@ -160,72 +76,32 @@ MonoBehaviour: value: 62178 - key: Icon 63 value: 62174 - - key: Icon 62 - value: 62166 - - key: Icon 61 - value: 62135 - - key: Icon 60 - value: 62129 - - key: Icon 59 - value: 62123 - - key: Icon 58 - value: 62116 - - key: Icon 57 - value: 62101 - key: Icon 56 value: 62087 - - key: Icon 55 - value: 62061 - key: Icon 54 value: 62059 - - key: Icon 53 - value: 62037 - - key: Icon 52 - value: 62024 - key: Icon 51 value: 61972 - key: Icon 50 value: 61967 - - key: Icon 49 - value: 61942 - key: Icon 48 value: 61923 - - key: Icon 47 - value: 61919 - key: Icon 46 value: 61877 - - key: Icon 45 - value: 61866 - - key: Icon 44 - value: 61852 - key: Icon 43 value: 61835 - - key: Icon 42 - value: 61826 - - key: Icon 41 - value: 61810 - key: Icon 40 value: 61801 - key: Icon 37 value: 61760 - - key: Icon 36 - value: 61758 - - key: Icon 35 - value: 61752 - key: Icon 34 value: 61733 - key: Icon 33 value: 61731 - - key: Icon 32 - value: 61721 - - key: Icon 31 - value: 61717 - key: Icon 30 value: 61709 - key: Icon 28 value: 60390 - - key: Icon 27 - value: 60235 - key: Icon 26 value: 60227 - key: Icon 25 @@ -236,18 +112,8 @@ MonoBehaviour: value: 59532 - key: Icon 22 value: 59531 - - key: Icon 21 - value: 59529 - - key: Icon 20 - value: 59527 - key: Icon 19 value: 59526 - - key: Icon 18 - value: 59525 - - key: Icon 17 - value: 59524 - - key: Icon 16 - value: 59523 - key: Icon 15 value: 59522 - key: Icon 14 @@ -256,48 +122,180 @@ MonoBehaviour: value: 59519 - key: Icon 12 value: 59518 - - key: Icon 11 - value: 59517 - - key: Icon 10 - value: 59512 - - key: Icon 9 - value: 59511 - - key: Icon 8 - value: 59508 - - key: Icon 7 - value: 59476 - key: Icon 2 value: 59416 - key: Icon 3 value: 59440 - - key: Icon 4 - value: 59456 - key: Icon 1 value: 59407 - - key: Icon 5 - value: 59460 - - key: Icon 138 - value: 63520 - - key: Icon 139 - value: 63565 - - key: Icon 140 - value: 63594 - - key: Icon 141 - value: 63703 - key: Icon 142 value: 63742 - - key: Thumb Down - value: 63518 + - key: Add Favorite + value: 63252 + - key: Favorite + value: 63248 + - key: Settings + value: 63146 + - key: Send + value: 63130 + - key: Search + value: 63120 + - key: Save + value: 63104 + - key: Question Mark + value: 63033 + - key: Play + value: 62982 + - key: Play Circle + value: 62984 + - key: Brightness + value: 59456 + - key: Unpin + value: 62980 + - key: Pin + value: 62978 + - key: Devices + value: 62950 + - key: Phone + value: 62945 + - key: Person + value: 62910 + - key: Block + value: 63022 + - key: Print + value: 63019 - key: Stop Circle value: 63323 + - key: Bluetooth + value: 61919 + - key: Calendar + value: 59460 + - key: Record Circle + value: 63074 + - key: Paste + value: 62166 + - key: Camera + value: 62037 - key: Add value: 61706 - - key: Arrow Down - value: 61769 + - key: Home + value: 62593 + - key: Mute + value: 60235 + - key: Power Button + value: 62991 + - key: Link + value: 62693 + - key: Mic Off + value: 62785 + - key: Lightbulb + value: 62679 + - key: People + value: 62889 + - key: Visibility Off + value: 59512 + - key: Movie + value: 62810 + - key: Thumb Up + value: 63518 + - key: Location On + value: 62713 + - key: Refresh + value: 61758 + - key: Location Off + value: 59523 + - key: Thumb Down + value: 63520 + - key: Videocam + value: 63565 + - key: Undo + value: 63703 + - key: Tag + value: 63357 + - key: Menu + value: 62817 + - key: More Vertical + value: 62807 + - key: Mail + value: 62727 + - key: Delete + value: 62285 + - key: Attach + value: 61866 + - key: Chevron Up + value: 62135 + - key: Chevron Right + value: 62129 + - key: Chevron Left + value: 62123 + - key: Chevron Down + value: 62116 + - key: Arrow Up + value: 61852 + - key: Arrow Right + value: 61826 - key: Arrow Left value: 61788 + - key: Arrow Down + value: 61769 + - key: More Horizontal + value: 59529 + - key: Mic + value: 59527 + - key: Apps + value: 59517 + - key: Repeat + value: 61810 + - key: Unlock + value: 59525 + - key: Lock + value: 59524 + - key: Cast + value: 62061 + - key: Visibility On + value: 59511 + - key: Erase + value: 59508 + - key: Clipboard + value: 59476 + - key: History + value: 62591 + - key: Folder + value: 62489 + - key: Edit + value: 62430 + - key: Check + value: 62101 + - key: Call End + value: 62024 + - key: List + value: 61752 - key: Call value: 59461 + - key: Bookmark + value: 61942 + - key: Notifications Off + value: 61721 + - key: Notifications + value: 61717 + - key: Keyboard + value: 62649 + - key: Info + value: 62628 + - key: Warning + value: 63594 + - key: Error + value: 62450 + - key: Photo + value: 62601 + - key: Dialpad + value: 62303 + - key: Close + value: 62314 + - key: Cancel + value: 62318 + - key: Cut + value: 62267 iconFontAsset: {fileID: 11400000, guid: 533bdd8d5c92b52448ee2ecf7bd828a4, type: 2} optionalEditorMaterial: {fileID: 0} fontIconSetDefinition: {fileID: 11400000, guid: e63daff880b56ed439a2e852b6e6993a, type: 2}