diff --git a/Editor/LabelWindow.cs b/Editor/LabelWindow.cs new file mode 100644 index 0000000..cef394c --- /dev/null +++ b/Editor/LabelWindow.cs @@ -0,0 +1,353 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace RotaryHeart.Lib +{ + public class LabelWindow + { + public delegate void SelectCallback(string label, bool added); + public SelectCallback OnSelect; + + object m_AssetLabels; + bool allowMultipleSelection = true; + bool allowCustom; + Dictionary allLabels = new Dictionary(); + + #region Reflection + + #region Fields + + Assembly m_assembly; + + Type m_inputDataType; + Type m_listElementType; + Type m_popupListType; + + FieldInfo m_CloseOnSelection; + FieldInfo m_AllowCustom; + FieldInfo m_OnSelectCallback; + FieldInfo m_MaxCount; + FieldInfo m_SortAlphabetically; + FieldInfo m_EnableAutoCompletion; + + PropertyInfo m_filterScore; + PropertyInfo m_selected; + PropertyInfo m_text; + + MethodInfo m_OnInternalSelectCallback; + MethodInfo m_NewOrMatchingElement; + + #endregion + + #region Properties + + Assembly EditorAssembly + { + get + { + if (m_assembly == null) + { + m_assembly = typeof(Editor).Assembly; + } + + return m_assembly; + } + } + + Type InputDataType + { + get + { + if (m_inputDataType == null) + { + m_inputDataType = EditorAssembly.GetType("UnityEditor.PopupList+InputData"); + } + + return m_inputDataType; + } + } + Type ListElementType + { + get + { + if (m_listElementType == null) + { + m_listElementType = EditorAssembly.GetType("UnityEditor.PopupList+ListElement"); + } + + return m_listElementType; + } + } + Type PopupList + { + get + { + if (m_popupListType == null) + { + m_popupListType = EditorAssembly.GetType("UnityEditor.PopupList"); + } + + return m_popupListType; + } + } + + FieldInfo CloseOnSelection + { + get + { + if (m_CloseOnSelection == null) + { + m_CloseOnSelection = InputDataType.GetField("m_CloseOnSelection"); + } + + return m_CloseOnSelection; + } + } + FieldInfo AllowCustom + { + get + { + if (m_AllowCustom == null) + { + m_AllowCustom = InputDataType.GetField("m_AllowCustom"); + } + + return m_AllowCustom; + } + } + FieldInfo OnSelectCallback + { + get + { + if (m_OnSelectCallback == null) + { + m_OnSelectCallback = InputDataType.GetField("m_OnSelectCallback"); + } + + return m_OnSelectCallback; + } + } + FieldInfo MaxCount + { + get + { + if (m_MaxCount == null) + { + m_MaxCount = InputDataType.GetField("m_MaxCount"); + } + + return m_MaxCount; + } + } + FieldInfo SortAlphabetically + { + get + { + if (m_SortAlphabetically == null) + { + m_SortAlphabetically = InputDataType.GetField("m_SortAlphabetically"); + } + + return m_SortAlphabetically; + } + } + FieldInfo EnableAutoCompletion + { + get + { + if (m_EnableAutoCompletion == null) + { + m_EnableAutoCompletion = InputDataType.GetField("m_EnableAutoCompletion"); + } + + return m_EnableAutoCompletion; + } + } + + PropertyInfo FilterScore + { + get + { + if (m_filterScore == null) + { + m_filterScore = ListElementType.GetProperty("filterScore"); + } + + return m_filterScore; + } + } + PropertyInfo Selected + { + get + { + if (m_selected == null) + { + m_selected = ListElementType.GetProperty("selected"); + } + + return m_selected; + } + } + PropertyInfo Text + { + get + { + if (m_text == null) + { + m_text = ListElementType.GetProperty("text"); + } + + return m_text; + } + } + + MethodInfo OnInternalSelectCallback + { + get + { + if (m_OnInternalSelectCallback == null) + { + m_OnInternalSelectCallback = typeof(LabelWindow).GetMethod("_OnInternalSelectCallback", BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(ListElementType); + } + + return m_OnInternalSelectCallback; + } + } + MethodInfo NewOrMatchingElement + { + get + { + if (m_NewOrMatchingElement == null) + { + m_NewOrMatchingElement = InputDataType.GetMethod("NewOrMatchingElement"); + } + + return m_NewOrMatchingElement; + } + } + + #endregion + + #endregion + + /// + /// Opens the default label window + /// + /// The position where the window is going to be drawn + /// Label array used to populate the list + /// Selected labels + /// Should the default labels be included + /// Should the system allow more than 1 label selected + /// Should the window close on selection + /// Allow custom labels + /// Max label count + /// Should the labels be sorted + /// Should the window show auto completetion + public void OpenLabelWindow(Rect position, string[] labels, string[] selectedLabels, bool populateDefaultLabels = true, bool allowMultipleSelection = true, bool closeOnSelection = false, bool allowCustom = true, int maxCount = 15, bool sortAlphabetically = true, bool enableAutoCompletition = true) + { + if (labels == null) + labels = new string[] { }; + if (selectedLabels == null) + selectedLabels = new string[] { }; + + this.allowMultipleSelection = allowMultipleSelection; + this.allowCustom = allowCustom; + + //Cache the data required + CacheData(labels, selectedLabels, populateDefaultLabels, closeOnSelection, maxCount, sortAlphabetically, enableAutoCompletition); + + //Create a reference of the window + var popupListReference = Activator.CreateInstance(PopupList, new object[] { m_AssetLabels }); + + //Get the correct show method + var showMethod = typeof(PopupWindow).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Where(x => + x.Name.Equals("Show") && x.GetParameters().Length == 4).Single(); + + //Invoke the method with the correct arguments + showMethod.Invoke(null, new object[] { position, popupListReference, null, 6 }); + } + + void CacheData(string[] labels, string[] selectedLabels, bool populateDefaultLabels, bool closeOnSelection, int maxCount, bool sortAlphabetically, bool enableAutoCompletition) + { + //Create instance to the delegate + Delegate action = Delegate.CreateDelegate(OnSelectCallback.FieldType, this, OnInternalSelectCallback); + + //Create instance of data to send to the popup window + m_AssetLabels = Activator.CreateInstance(InputDataType); + + //Assign all the respective values, including the delegate callback + CloseOnSelection.SetValue(m_AssetLabels, closeOnSelection); + AllowCustom.SetValue(m_AssetLabels, true); + OnSelectCallback.SetValue(m_AssetLabels, action); + MaxCount.SetValue(m_AssetLabels, maxCount); + SortAlphabetically.SetValue(m_AssetLabels, sortAlphabetically); + EnableAutoCompletion.SetValue(m_AssetLabels, enableAutoCompletition); + + //Get all the labels available + if (populateDefaultLabels) + { + allLabels = (Dictionary)typeof(AssetDatabase).InvokeMember("GetAllLabels", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, null); + } + + //Include any custom one sent on the array + foreach (var tag in labels) + { + if (string.IsNullOrEmpty(tag)) + continue; + + if (!allLabels.ContainsKey(tag)) + allLabels.Add(tag, 0); + } + + //Asing all the selected values + foreach (var pair in allLabels) + { + var element = NewOrMatchingElement.Invoke(m_AssetLabels, new object[] { pair.Key }); + + if ((float)(FilterScore.GetValue(element, null)) < pair.Value) + { + FilterScore.SetValue(element, pair.Value, null); + } + Selected.SetValue(element, selectedLabels.Any(label => string.Equals(label, pair.Key, StringComparison.OrdinalIgnoreCase)), null); + } + } + + /// + /// Function called by Unity when an element is selected + /// + /// Element data + void _OnInternalSelectCallback(T data) + { + string selectedLabel = Text.GetValue(data, null).ToString(); + + if (!allowCustom && !allLabels.Keys.Any(x => x.ToLower().Equals(selectedLabel.ToLower()))) + return; + + if (!allowMultipleSelection) + { + foreach (var pair in allLabels) + { + if (pair.Key.ToLower().Equals(selectedLabel.ToLower())) + { + continue; + } + + var element = NewOrMatchingElement.Invoke(m_AssetLabels, new object[] { pair.Key }); + + Selected.SetValue(element, false, null); + } + } + + bool currentValue = (bool)(Selected.GetValue(data, null)); + + Selected.SetValue(data, !currentValue, null); + + if (OnSelect != null) + OnSelect.Invoke(selectedLabel, !currentValue); + } + } +} diff --git a/Editor/LabelWindow.cs.meta b/Editor/LabelWindow.cs.meta new file mode 100644 index 0000000..a306047 --- /dev/null +++ b/Editor/LabelWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e6c6148bffd72544931589c0097ad4a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ModifyEditorStyle.cs b/Editor/ModifyEditorStyle.cs index 14aea8c..7edeb25 100644 --- a/Editor/ModifyEditorStyle.cs +++ b/Editor/ModifyEditorStyle.cs @@ -6,6 +6,7 @@ using UnityEditor.SceneManagement; using System; using System.Reflection; +using RotaryHeart.Lib; public class ModifyEditorStyle { @@ -18,91 +19,106 @@ public class ModifyEditorStyle private static bool enable { - get{ - return EditorPrefs.GetBool("ModifyEditorStyle_Enable",true); + get + { + return EditorPrefs.GetBool("ModifyEditorStyle_Enable", true); } - set{ - EditorPrefs.SetBool("ModifyEditorStyle_Enable",value); + set + { + EditorPrefs.SetBool("ModifyEditorStyle_Enable", value); } } private static int fontSize { - get{ - return EditorPrefs.GetInt("ModifyEditorStyle_FontSize",11); + get + { + return EditorPrefs.GetInt("ModifyEditorStyle_FontSize", 11); } - set{ - EditorPrefs.SetInt("ModifyEditorStyle_FontSize",value); + set + { + EditorPrefs.SetInt("ModifyEditorStyle_FontSize", value); } } - private static int smallFontSize + private static int smallFontSize { - get{ - return EditorPrefs.GetInt("ModifyEditorStyle_SmallFontSize",9); + get + { + return EditorPrefs.GetInt("ModifyEditorStyle_SmallFontSize", 9); } - set{ - EditorPrefs.SetInt("ModifyEditorStyle_SmallFontSize",value); + set + { + EditorPrefs.SetInt("ModifyEditorStyle_SmallFontSize", value); } } - private static int bigFontSize + private static int bigFontSize { - get{ - return EditorPrefs.GetInt("ModifyEditorStyle_BigFontSize",12); + get + { + return EditorPrefs.GetInt("ModifyEditorStyle_BigFontSize", 12); } - set{ - EditorPrefs.SetInt("ModifyEditorStyle_BigFontSize",value); + set + { + EditorPrefs.SetInt("ModifyEditorStyle_BigFontSize", value); } } private static int paddingTop { - get{ - return EditorPrefs.GetInt("ModifyEditorStyle_PaddingTop",1); + get + { + return EditorPrefs.GetInt("ModifyEditorStyle_PaddingTop", 1); } - set{ - EditorPrefs.SetInt("ModifyEditorStyle_PaddingTop",value); + set + { + EditorPrefs.SetInt("ModifyEditorStyle_PaddingTop", value); } } private static int paddingBottom { - get{ - return EditorPrefs.GetInt("ModifyEditorStyle_PaddingBottom",2); + get + { + return EditorPrefs.GetInt("ModifyEditorStyle_PaddingBottom", 2); } - set{ - EditorPrefs.SetInt("ModifyEditorStyle_PaddingBottom",value); + set + { + EditorPrefs.SetInt("ModifyEditorStyle_PaddingBottom", value); } } - private static int selected + private static string selected { - get{ - string fontName = EditorPrefs.GetString("ModifyEditorStyle_Selected", defaultFont); - return Array.IndexOf(fonts, fontName); + get + { + return EditorPrefs.GetString("ModifyEditorStyle_Selected", defaultFont); } - set{ - EditorPrefs.SetString("ModifyEditorStyle_Selected", (value < fonts.Length && value >= 0) ? fonts[value] : defaultFont); + set + { + EditorPrefs.SetString("ModifyEditorStyle_Selected", string.IsNullOrEmpty(value) ? defaultFont : value); } } - private static int selectedBold + private static string selectedBold { - get{ - string fontName = EditorPrefs.GetString("ModifyEditorStyle_SelectedBold", defaultFont); - return Array.IndexOf(fonts, fontName); + get + { + return EditorPrefs.GetString("ModifyEditorStyle_SelectedBold", defaultFont); } - set{ - EditorPrefs.SetString("ModifyEditorStyle_SelectedBold", (value < fonts.Length && value >= 0) ? fonts[value] : defaultFont); + set + { + EditorPrefs.SetString("ModifyEditorStyle_SelectedBold", string.IsNullOrEmpty(value) ? defaultFont : value); } } private static string[] _fonts; private static string[] fonts { - get{ - if(_fonts == null) + get + { + if (_fonts == null) { _fonts = Font.GetOSInstalledFontNames(); } @@ -110,7 +126,7 @@ private static string[] fonts } } - private static IEnumerable GUISkinStyles + private static IEnumerable GUISkinStyles { get { @@ -145,7 +161,8 @@ private static IEnumerable EditorStylesGUIStyles private static IEnumerable NeedPadding { - get{ + get + { GUISkin skin = GUI.skin; yield return skin.label; yield return skin.textArea; @@ -243,7 +260,7 @@ private static IEnumerable InternalStyles } } - + #if UNITY_2018_3_OR_NEWER private class ModifyEditorStyleProvider : SettingsProvider { @@ -271,8 +288,39 @@ static void ModifyEditorStylePreference() enable = EditorGUILayout.BeginToggleGroup("Enable", enable); - selected = EditorGUILayout.Popup("Font", selected, fonts); - selectedBold = EditorGUILayout.Popup("Bold Font", selectedBold, fonts); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Font"); + if (EditorGUILayout.DropdownButton(new GUIContent(selected), FocusType.Keyboard)) + { + LabelWindow window = new LabelWindow(); + window.OnSelect = (string value, bool enabled) => + { + if (enabled) + selected = value; + else + selected = null; + }; + window.OpenLabelWindow(new Rect(Event.current.mousePosition, Vector2.one), fonts, new string[] { selected }, false, false, true, false); + } + EditorGUILayout.EndHorizontal(); + + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Bold Font"); + if (EditorGUILayout.DropdownButton(new GUIContent(selectedBold), FocusType.Keyboard)) + { + LabelWindow window = new LabelWindow(); + window.OnSelect = (string value, bool enabled) => + { + if (enabled) + selectedBold = value; + else + selectedBold = null; + }; + window.OpenLabelWindow(new Rect(Event.current.mousePosition, Vector2.one), fonts, new string[] { selectedBold }, false, false, true, false); + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); fontSize = EditorGUILayout.IntField("Font Size", fontSize); smallFontSize = EditorGUILayout.IntField("Small Font Size", smallFontSize); @@ -299,16 +347,14 @@ static void ModifyEditorStylePreference() static void Modify() { - if(!enable) return; + if (!enable) return; - string fontName = selected >= 0 && selected < fonts.Length ? fonts[selected] : defaultFont; - string boldFontName = selectedBold >= 0 && selectedBold < fonts.Length ? fonts[selectedBold] : defaultFont; - normalFont = Font.CreateDynamicFontFromOSFont(fontName, fontSize); - //bigFont = Font.CreateDynamicFontFromOSFont(fontName, bigFontSize); - smallFont = Font.CreateDynamicFontFromOSFont(fontName, smallFontSize); - boldFont = Font.CreateDynamicFontFromOSFont(boldFontName, fontSize); - smallBoldFont = Font.CreateDynamicFontFromOSFont(boldFontName, smallFontSize); + normalFont = Font.CreateDynamicFontFromOSFont(selected, fontSize); + //bigFont = Font.CreateDynamicFontFromOSFont(selected, bigFontSize); + smallFont = Font.CreateDynamicFontFromOSFont(selected, smallFontSize); + boldFont = Font.CreateDynamicFontFromOSFont(selectedBold, fontSize); + smallBoldFont = Font.CreateDynamicFontFromOSFont(selectedBold, smallFontSize); GUISkin skin = GUI.skin; //Debug.Log($"- : {skin.font?.name} {skin.font?.fontSize}"); @@ -349,7 +395,7 @@ static void Modify() foreach (var x in NeedPadding) { - if(x != null) + if (x != null) { //Debug.Log($"{x.name} -> {x.padding}"); var p = x.padding;