Skip to content

Commit 2baad66

Browse files
committed
Updates to org.mixedrealitytoolkit.uxcore
1 parent b3c31f9 commit 2baad66

3 files changed

Lines changed: 140 additions & 56 deletions

File tree

org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSelectorInspector.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the BSD 3-Clause
33

44
using MixedReality.Toolkit.UX;
5+
using System.Collections.Generic;
56
using TMPro;
67
using UnityEditor;
78
using UnityEngine;
@@ -116,9 +117,13 @@ public void DrawIconGrid(FontIconSelector fontIconSelector, float tileSize)
116117
scrollAmount = EditorGUILayout.BeginScrollView(scrollAmount, GUILayout.MaxHeight(128), GUILayout.MinHeight(64));
117118
EditorGUILayout.BeginHorizontal();
118119

119-
foreach (string iconName in fontIconSet.GlyphIconsByName.Keys)
120+
List<KeyValuePair<string, uint>> sortedIcons = new List<KeyValuePair<string, uint>>(fontIconSet.GlyphIconsByName);
121+
sortedIcons.Sort((a, b) => a.Key.CompareTo(b.Key));
122+
123+
foreach (KeyValuePair<string, uint> kvp in sortedIcons)
120124
{
121-
uint unicodeValue = fontIconSet.GlyphIconsByName[iconName];
125+
string iconName = kvp.Key;
126+
uint unicodeValue = kvp.Value;
122127

123128
if (column >= numColumns)
124129
{

org.mixedrealitytoolkit.uxcore/Editor/Inspectors/FontIconSet/FontIconSetInspector.cs

Lines changed: 113 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public class FontIconSetInspector : UnityEditor.Editor
3838

3939
private List<KeyValuePair<uint, string>> iconEntries = new List<KeyValuePair<uint, string>>();
4040
private List<string> validNames = new List<string>();
41-
private List<string> availableNames = new List<string>();
4241
private HashSet<uint> selectedUnicodeValues = new HashSet<uint>();
4342
private string[] availableNamesArray = Array.Empty<string>();
4443
private bool requiresUpdate = false;
@@ -104,7 +103,6 @@ private void UpdateIconEntries()
104103
iconEntries.Sort((a, b) => a.Key.CompareTo(b.Key));
105104

106105
validNames.Clear();
107-
availableNames.Clear();
108106

109107
if (fontIconSetDefinitionProp != null)
110108
{
@@ -114,16 +112,18 @@ private void UpdateIconEntries()
114112
foreach (string name in setDefinition.IconNames)
115113
{
116114
validNames.Add(name);
117-
if (!fontIconSet.GlyphIconsByName.ContainsKey(name))
118-
{
119-
availableNames.Add(name);
120-
}
121115
}
116+
availableNamesArray = GetAvailableIconNames(fontIconSet, setDefinition);
117+
}
118+
else
119+
{
120+
availableNamesArray = new string[] { string.Empty };
122121
}
123122
}
124-
availableNames.Sort();
125-
availableNames.Insert(0, string.Empty);
126-
availableNamesArray = availableNames.ToArray();
123+
else
124+
{
125+
availableNamesArray = new string[] { string.Empty };
126+
}
127127

128128
Repaint();
129129
}
@@ -234,20 +234,7 @@ public override void OnInspectorGUI()
234234
}
235235
else
236236
{
237-
bool hasInvalidName = false;
238-
foreach (KeyValuePair<uint, string> entry in iconEntries)
239-
{
240-
if (!validNames.Contains(entry.Value))
241-
{
242-
hasInvalidName = true;
243-
break;
244-
}
245-
}
246-
247-
if (hasInvalidName)
248-
{
249-
EditorGUILayout.HelpBox("Icon names highlighted yellow are not present in the selected Font Icon Set Definition and should be updated.", MessageType.Warning);
250-
}
237+
DrawInvalidIconNameHelpBox(fontIconSet, setDefinition);
251238

252239
// Catch edge cases where the external asset size changes while this inspector is still focused
253240
if (setDefinition.IconNames != null && validNames.Count != setDefinition.IconNames.Count)
@@ -283,24 +270,10 @@ public override void OnInspectorGUI()
283270

284271
if (fontIconSetDefinitionProp.objectReferenceValue != null)
285272
{
286-
// Place the current icon's name in the array
287-
availableNamesArray[0] = iconEntry.Value;
288-
289-
using (var check = new EditorGUI.ChangeCheckScope())
273+
if (DrawIconNamePopup(iconEntry.Value, availableNamesArray, validNames, ButtonDimension, out string newName))
290274
{
291-
// If the currently selected name isn't in our icon set map names, highlight the popup
292-
Color oldColor = GUI.backgroundColor;
293-
if (!validNames.Contains(iconEntry.Value))
294-
{
295-
GUI.backgroundColor = Color.yellow;
296-
}
297-
int selected = EditorGUILayout.Popup(string.Empty, 0, availableNamesArray, GUILayout.MaxWidth(ButtonDimension));
298-
if (check.changed)
299-
{
300-
pendingIconToRenameNew = availableNamesArray[selected];
301-
pendingIconToRenameOld = iconEntry.Value;
302-
}
303-
GUI.backgroundColor = oldColor;
275+
pendingIconToRenameNew = newName;
276+
pendingIconToRenameOld = iconEntry.Value;
304277
}
305278
}
306279
else
@@ -434,6 +407,106 @@ private bool CheckIfHoloLensIconFontExists()
434407
return false;
435408
}
436409

410+
/// <summary>
411+
/// Generates an array of available icon names (those present in the definition but not yet assigned in the icon set),
412+
/// with an empty string at index 0 to act as a placeholder for the currently selected icon name.
413+
/// </summary>
414+
public static string[] GetAvailableIconNames(FontIconSet iconSet, FontIconSetDefinition setDefinition)
415+
{
416+
if (iconSet == null || setDefinition == null || setDefinition.IconNames == null)
417+
{
418+
return null;
419+
}
420+
421+
List<string> availableNames = new List<string>();
422+
foreach (string name in setDefinition.IconNames)
423+
{
424+
if (!iconSet.GlyphIconsByName.ContainsKey(name))
425+
{
426+
availableNames.Add(name);
427+
}
428+
}
429+
availableNames.Sort();
430+
availableNames.Insert(0, string.Empty);
431+
return availableNames.ToArray();
432+
}
433+
434+
/// <summary>
435+
/// Draws a warning HelpBox if the provided <see cref="FontIconSet"/> contains assigned icon names that are not present in the <see cref="FontIconSetDefinition"/>.
436+
/// </summary>
437+
public static void DrawInvalidIconNameHelpBox(FontIconSet iconSet, FontIconSetDefinition setDefinition)
438+
{
439+
if (iconSet == null || setDefinition == null || setDefinition.IconNames == null)
440+
{
441+
return;
442+
}
443+
444+
foreach (string assignedName in iconSet.GlyphIconsByName.Keys)
445+
{
446+
bool isNameValid = false;
447+
foreach (string validName in setDefinition.IconNames)
448+
{
449+
if (validName == assignedName)
450+
{
451+
isNameValid = true;
452+
break;
453+
}
454+
}
455+
456+
if (!isNameValid)
457+
{
458+
EditorGUILayout.HelpBox("Icon names highlighted yellow are not present in the selected Font Icon Set Definition and should be updated.", MessageType.Warning);
459+
return;
460+
}
461+
}
462+
}
463+
464+
/// <summary>
465+
/// Draws a popup for renaming an icon, highlighting it yellow if the name is invalid/missing from the definition.
466+
/// </summary>
467+
public static bool DrawIconNamePopup(string currentName, string[] availableNamesArray, IEnumerable<string> validNames, float maxWidth, out string newName)
468+
{
469+
newName = currentName;
470+
if (availableNamesArray == null || availableNamesArray.Length == 0)
471+
{
472+
return false;
473+
}
474+
475+
availableNamesArray[0] = currentName;
476+
477+
bool changed = false;
478+
using (var check = new EditorGUI.ChangeCheckScope())
479+
{
480+
Color oldColor = GUI.backgroundColor;
481+
482+
bool isNameValid = false;
483+
foreach (string validName in validNames)
484+
{
485+
if (validName == currentName)
486+
{
487+
isNameValid = true;
488+
break;
489+
}
490+
}
491+
492+
if (!isNameValid)
493+
{
494+
GUI.backgroundColor = Color.yellow;
495+
}
496+
497+
int selected = EditorGUILayout.Popup(string.Empty, 0, availableNamesArray, GUILayout.MaxWidth(maxWidth));
498+
if (check.changed)
499+
{
500+
newName = availableNamesArray[selected];
501+
changed = true;
502+
}
503+
504+
GUI.backgroundColor = oldColor;
505+
}
506+
507+
return changed;
508+
}
509+
437510
/// <summary>
438511
/// Draws a Text Mesh Pro glyph in the supplied <see cref="Rect"/>.
439512
/// </summary>

org.mixedrealitytoolkit.uxcore/Theming/ThemeBinding.cs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class ThemeBinding : MonoBehaviour
1818

1919
[SerializeReference, InterfaceSelector]
2020
[Tooltip("The list of bound theme entries.")]
21-
private IBinder[] binders;
21+
private IBinder[] binders = System.Array.Empty<IBinder>();
2222

2323
protected void OnEnable()
2424
{
@@ -28,28 +28,34 @@ protected void OnEnable()
2828
return;
2929
}
3030

31-
foreach (IBinder binder in binders)
31+
if (binders != null)
3232
{
33-
if (binder == null)
33+
foreach (IBinder binder in binders)
3434
{
35-
Debug.LogWarning($"{nameof(ThemeBinding)} on '{gameObject.name}' has a null binder entry.", this);
36-
continue;
35+
if (binder == null)
36+
{
37+
Debug.LogWarning($"{nameof(ThemeBinding)} on '{gameObject.name}' has a null binder entry.", this);
38+
continue;
39+
}
40+
41+
if (string.IsNullOrWhiteSpace(binder.ThemeDefinitionItemName))
42+
{
43+
Debug.LogWarning($"{nameof(ThemeBinding)} on '{gameObject.name}' has a {binder.GetType().Name} with no theme item assigned.", this);
44+
}
45+
46+
binder.Subscribe(themeDataSource);
3747
}
38-
39-
if (string.IsNullOrWhiteSpace(binder.ThemeDefinitionItemName))
40-
{
41-
Debug.LogWarning($"{nameof(ThemeBinding)} on '{gameObject.name}' has a {binder.GetType().Name} with no theme item assigned.", this);
42-
}
43-
44-
binder.Subscribe(themeDataSource);
4548
}
4649
}
4750

4851
protected void OnDisable()
4952
{
50-
foreach (IBinder binder in binders)
53+
if (binders != null)
5154
{
52-
binder?.Unsubscribe(themeDataSource);
55+
foreach (IBinder binder in binders)
56+
{
57+
binder?.Unsubscribe(themeDataSource);
58+
}
5359
}
5460
}
5561
#endif

0 commit comments

Comments
 (0)