123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- namespace UnityEditor.SettingsManagement
- {
- static class SettingsGUIStyles
- {
- const string k_SettingsGearIcon = "Packages/" + UserSettings.packageName + "/Content/Options.png";
- static bool s_Initialized;
- public static GUIStyle s_SettingsGizmo;
- public static GUIStyle s_SettingsArea;
- public static GUIStyle s_IndentedSettingBlock;
- static void Init()
- {
- if (s_Initialized)
- return;
- s_Initialized = true;
- s_SettingsGizmo = new GUIStyle()
- {
- normal = new GUIStyleState()
- {
- background = AssetDatabase.LoadAssetAtPath<Texture2D>(k_SettingsGearIcon)
- },
- fixedWidth = 14,
- fixedHeight = 14,
- padding = new RectOffset(0, 0, 0, 0),
- margin = new RectOffset(4, 4, 4, 4),
- imagePosition = ImagePosition.ImageOnly
- };
- s_SettingsArea = new GUIStyle()
- {
- margin = new RectOffset(6, 6, 0, 0)
- };
- s_IndentedSettingBlock = new GUIStyle()
- {
- padding = new RectOffset(16, 0, 0, 0)
- };
- }
- public static GUIStyle settingsGizmo
- {
- get
- {
- Init();
- return s_SettingsGizmo;
- }
- }
- public static GUIStyle settingsArea
- {
- get
- {
- Init();
- return s_SettingsArea;
- }
- }
- public static GUIStyle indentedSettingBlock
- {
- get
- {
- Init();
- return s_IndentedSettingBlock;
- }
- }
- }
- /// <summary>
- /// Extension methods for GUILayout that also implement settings-specific functionality.
- /// </summary>
- public static class SettingsGUILayout
- {
- /// <inheritdoc />
- /// <summary>
- /// Create an indented GUI section.
- /// </summary>
- public class IndentedGroup : IDisposable
- {
- bool m_IsDisposed;
- /// <summary>
- /// Create an indented GUI section.
- /// </summary>
- public IndentedGroup()
- {
- EditorGUIUtility.labelWidth -= SettingsGUIStyles.indentedSettingBlock.padding.left - 4;
- GUILayout.BeginVertical(SettingsGUIStyles.indentedSettingBlock);
- }
- /// <summary>
- /// Create an indented GUI section with a header.
- /// </summary>
- public IndentedGroup(string label)
- {
- GUILayout.Label(label);
- EditorGUIUtility.labelWidth -= SettingsGUIStyles.indentedSettingBlock.padding.left - 4;
- GUILayout.BeginVertical(SettingsGUIStyles.indentedSettingBlock);
- }
- /// <inheritdoc />
- /// <summary>
- /// Revert the GUI indent back to it's original value.
- /// </summary>
- public void Dispose()
- {
- if (m_IsDisposed)
- return;
- m_IsDisposed = true;
- GUILayout.EndVertical();
- EditorGUIUtility.labelWidth += SettingsGUIStyles.indentedSettingBlock.padding.left - 4;
- }
- }
- internal static HashSet<string> s_Keywords = null;
- internal static bool MatchSearchGroups(string searchContext, string label)
- {
- if (s_Keywords != null)
- {
- foreach (var keyword in label.Split(' '))
- s_Keywords.Add(keyword);
- }
- if (searchContext == null)
- return true;
- var ctx = searchContext.Trim();
- if (string.IsNullOrEmpty(ctx))
- return true;
- var split = searchContext.Split(' ');
- return split.Any(x => !string.IsNullOrEmpty(x) && label.IndexOf(x, StringComparison.InvariantCultureIgnoreCase) > -1);
- }
- internal static bool DebugModeFilter(IUserSetting pref)
- {
- if (!EditorPrefs.GetBool("DeveloperMode", false))
- return true;
- if (pref.scope == SettingsScope.Project && UserSettingsProvider.showProjectSettings)
- return true;
- if (pref.scope == SettingsScope.User && UserSettingsProvider.showUserSettings)
- return true;
- return false;
- }
- /// <summary>
- /// A slider that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="min">The value at the left end of the slider.</param>
- /// <param name="max">The value at the right end of the slider.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SearchableSlider(GUIContent label, float value, float min, float max, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label.text))
- return value;
- return EditorGUILayout.Slider(label, value, min, max);
- }
- /// <summary>
- /// A slider that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="min">The value at the left end of the slider.</param>
- /// <param name="max">The value at the right end of the slider.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SearchableSlider(string label, float value, float min, float max, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label))
- return value;
- return EditorGUILayout.Slider(label, value, min, max);
- }
- /// <summary>
- /// A float field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SearchableFloatField(GUIContent label, float value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label.text))
- return value;
- return EditorGUILayout.FloatField(label, value);
- }
- /// <summary>
- /// A float field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SearchableFloatField(string label, float value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label))
- return value;
- return EditorGUILayout.FloatField(label, value);
- }
- /// <summary>
- /// An int field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static int SearchableIntField(GUIContent label, int value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label.text))
- return value;
- return EditorGUILayout.IntField(label, value);
- }
- /// <summary>
- /// An int field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static int SearchableIntField(string label, int value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label))
- return value;
- return EditorGUILayout.IntField(label, value);
- }
- /// <summary>
- /// An toggle field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static bool SearchableToggle(GUIContent label, bool value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label.text))
- return value;
- return EditorGUILayout.Toggle(label, value);
- }
- /// <summary>
- /// An toggle field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static bool SearchableToggle(string label, bool value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label))
- return value;
- return EditorGUILayout.Toggle(label, value);
- }
- /// <summary>
- /// An text field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static string SearchableTextField(GUIContent label, string value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label.text))
- return value;
- return EditorGUILayout.TextField(label, value);
- }
- /// <summary>
- /// An text field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static string SearchableTextField(string label, string value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label))
- return value;
- return EditorGUILayout.TextField(label, value);
- }
- /// <summary>
- /// An color field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static Color SearchableColorField(GUIContent label, Color value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label.text))
- return value;
- return EditorGUILayout.ColorField(label, value);
- }
- /// <summary>
- /// An color field that implements search filtering.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static Color SearchableColorField(string label, Color value, string searchContext)
- {
- if (!MatchSearchGroups(searchContext, label))
- return value;
- return EditorGUILayout.ColorField(label, value);
- }
- /// <summary>
- /// A slider that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="min">The value at the left end of the slider.</param>
- /// <param name="max">The value at the right end of the slider.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SettingsSlider(GUIContent label, UserSetting<float> value, float min, float max, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label.text))
- return value;
- var res = EditorGUILayout.Slider(label, value, min, max);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A slider that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="min">The value at the left end of the slider.</param>
- /// <param name="max">The value at the right end of the slider.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SettingsSlider(string label, UserSetting<float> value, float min, float max, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label))
- return value;
- var res = EditorGUILayout.Slider(label, value, min, max);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A slider that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="min">The value at the left end of the slider.</param>
- /// <param name="max">The value at the right end of the slider.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static int SettingsSlider(GUIContent label, UserSetting<int> value, int min, int max, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label.text))
- return value;
- var res = EditorGUILayout.IntSlider(label, value, min, max);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A slider that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="min">The value at the left end of the slider.</param>
- /// <param name="max">The value at the right end of the slider.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static int SettingsSlider(string label, UserSetting<int> value, int min, int max, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label))
- return value;
- var res = EditorGUILayout.IntSlider(label, value, min, max);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A float field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SettingsFloatField(GUIContent label, UserSetting<float> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label.text))
- return value;
- var res = EditorGUILayout.FloatField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A float field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static float SettingsFloatField(string label, UserSetting<float> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label))
- return value;
- var res = EditorGUILayout.FloatField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// An integer field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static int SettingsIntField(GUIContent label, UserSetting<int> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label.text))
- return value;
- var res = EditorGUILayout.IntField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// An integer field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static int SettingsIntField(string label, UserSetting<int> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label))
- return value;
- var res = EditorGUILayout.IntField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A boolean toggle field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static bool SettingsToggle(GUIContent label, UserSetting<bool> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label.text))
- return value;
- var res = EditorGUILayout.Toggle(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A boolean toggle field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static bool SettingsToggle(string label, UserSetting<bool> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label))
- return value;
- var res = EditorGUILayout.Toggle(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A text field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static string SettingsTextField(GUIContent label, UserSetting<string> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label.text))
- return value;
- var res = EditorGUILayout.TextField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A text field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static string SettingsTextField(string label, UserSetting<string> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label))
- return value;
- var res = EditorGUILayout.TextField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A color field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static Color SettingsColorField(GUIContent label, UserSetting<Color> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label.text))
- return value;
- var res = EditorGUILayout.ColorField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// A color field that implements search filtering and context menu reset.
- /// </summary>
- /// <param name="label">Label in front of the value field.</param>
- /// <param name="value">The value to edit.</param>
- /// <param name="searchContext">A string representing the current search query. Empty or null strings are to be treated as matching any value.</param>
- /// <returns>The value that has been set by the user.</returns>
- public static Color SettingsColorField(string label, UserSetting<Color> value, string searchContext)
- {
- if (!DebugModeFilter(value) || !MatchSearchGroups(searchContext, label))
- return value;
- var res = EditorGUILayout.ColorField(label, value);
- DoResetContextMenuForLastRect(value);
- return res;
- }
- /// <summary>
- /// Using the last automatically layoutted rect, implement a context click menu for a user setting.
- /// </summary>
- /// <param name="setting">The target setting for the reset context menu.</param>
- public static void DoResetContextMenuForLastRect(IUserSetting setting)
- {
- DoResetContextMenu(GUILayoutUtility.GetLastRect(), setting);
- }
- static void DoResetContextMenu(Rect rect, IUserSetting pref)
- {
- var evt = Event.current;
- if (evt.type == EventType.ContextClick && rect.Contains(evt.mousePosition))
- {
- var menu = new GenericMenu();
- menu.AddItem(new GUIContent("Reset [" + pref.scope + "] " + pref.key), false, () =>
- {
- pref.Reset(true);
- });
- menu.ShowAsContext();
- }
- }
- }
- }
|