test
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEditor;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Property drawer for <see cref = "GamepadButton" />
|
||||
/// </summary >
|
||||
[CustomPropertyDrawer(typeof(GamepadButton))]
|
||||
internal class GamepadButtonPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override VisualElement CreatePropertyGUI(SerializedProperty property)
|
||||
{
|
||||
CreateEnumList();
|
||||
return base.CreatePropertyGUI(property);
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
if (m_EnumDisplayNames == null)
|
||||
{
|
||||
CreateEnumList();
|
||||
}
|
||||
|
||||
if (property.propertyType == SerializedPropertyType.Enum)
|
||||
{
|
||||
property.intValue = EditorGUI.Popup(position, label.text, property.intValue, m_EnumDisplayNames);
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void CreateEnumList()
|
||||
{
|
||||
var enumNamesAndValues = new Dictionary<string, int>();
|
||||
var enumDisplayNames = Enum.GetNames(typeof(GamepadButton));
|
||||
var enumValues = Enum.GetValues(typeof(GamepadButton)).Cast<GamepadButton>().ToArray();
|
||||
|
||||
for (var i = 0; i < enumDisplayNames.Length; ++i)
|
||||
{
|
||||
string enumName;
|
||||
switch (enumDisplayNames[i])
|
||||
{
|
||||
case nameof(GamepadButton.Y):
|
||||
case nameof(GamepadButton.Triangle):
|
||||
case nameof(GamepadButton.A):
|
||||
case nameof(GamepadButton.Cross):
|
||||
case nameof(GamepadButton.B):
|
||||
case nameof(GamepadButton.Circle):
|
||||
case nameof(GamepadButton.X):
|
||||
case nameof(GamepadButton.Square):
|
||||
continue;
|
||||
case nameof(GamepadButton.North):
|
||||
enumName = "North, Y, Triangle, X";
|
||||
break;
|
||||
case nameof(GamepadButton.South):
|
||||
enumName = "South, A, Cross, B";
|
||||
break;
|
||||
case nameof(GamepadButton.East):
|
||||
enumName = "East, B, Circle, A";
|
||||
break;
|
||||
case nameof(GamepadButton.West):
|
||||
enumName = "West, X, Square, Y";
|
||||
break;
|
||||
default:
|
||||
enumName = enumDisplayNames[i];
|
||||
break;
|
||||
}
|
||||
enumNamesAndValues.Add(enumName, (int)enumValues.GetValue(i));
|
||||
}
|
||||
var sortedEntries = enumNamesAndValues.OrderBy(x => x.Value);
|
||||
|
||||
m_EnumDisplayNames = sortedEntries.Select(x => x.Key).ToArray();
|
||||
}
|
||||
|
||||
private string[] m_EnumDisplayNames;
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e64ea03a5bf05845977ae0cd2e1dd4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,30 @@
|
||||
// Note: If not UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS we do not use a custom property drawer and
|
||||
// picker for InputActionAsset but rather rely on default (classic) object picker.
|
||||
#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
|
||||
using UnityEditor;
|
||||
using UnityEditor.Search;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer in order to use the "Advanced Picker" from UnityEditor.Search.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(InputActionAsset))]
|
||||
internal sealed class InputActionAssetDrawer : PropertyDrawer
|
||||
{
|
||||
private readonly SearchContext m_Context = UnityEditor.Search.SearchService.CreateContext(new[]
|
||||
{
|
||||
InputActionAssetSearchProviders.CreateInputActionAssetSearchProvider(),
|
||||
InputActionAssetSearchProviders.CreateInputActionAssetSearchProviderForProjectWideActions(),
|
||||
}, string.Empty, SearchConstants.PickerSearchFlags);
|
||||
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
ObjectField.DoObjectField(position, property, typeof(InputActionAsset), label,
|
||||
m_Context, SearchConstants.PickerViewFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e0a885665a44db1adfaf0e3b9e9cda6
|
||||
timeCreated: 1693838957
|
@@ -0,0 +1,123 @@
|
||||
#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Search;
|
||||
using UnityEngine.Search;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
internal static class InputActionAssetSearchProviders
|
||||
{
|
||||
const string k_AssetFolderSearchProviderId = "AssetsInputActionAssetSearchProvider";
|
||||
const string k_ProjectWideActionsSearchProviderId = "ProjectWideInputActionAssetSearchProvider";
|
||||
|
||||
const string k_ProjectWideAssetIdentificationString = " [Project Wide Input Actions]";
|
||||
|
||||
internal static SearchProvider CreateInputActionAssetSearchProvider()
|
||||
{
|
||||
return CreateInputActionAssetSearchProvider(k_AssetFolderSearchProviderId,
|
||||
"Asset Input Action Assets",
|
||||
(obj) => { return obj != null ? AssetDatabase.GetAssetPath(obj) : "Null"; },
|
||||
() => LoadInputActionAssetsFromAssetDatabase(skipProjectWide: true));
|
||||
}
|
||||
|
||||
internal static SearchProvider CreateInputActionAssetSearchProviderForProjectWideActions()
|
||||
{
|
||||
return CreateInputActionAssetSearchProvider(k_ProjectWideActionsSearchProviderId,
|
||||
"Project-Wide Input Action Asset",
|
||||
(obj) => { return obj != null ? AssetDatabase.GetAssetPath(obj) : "Null"; },
|
||||
() => LoadInputActionReferencesFromAsset());
|
||||
}
|
||||
|
||||
private static IEnumerable<Object> LoadInputActionReferencesFromAsset()
|
||||
{
|
||||
var asset = InputSystem.actions;
|
||||
if (asset == null)
|
||||
return Array.Empty<Object>();
|
||||
|
||||
return new List<InputActionAsset>() { asset };
|
||||
}
|
||||
|
||||
private static IEnumerable<Object> LoadInputActionAssetsFromAssetDatabase(bool skipProjectWide)
|
||||
{
|
||||
string[] searchFolders = new string[] { "Assets" };
|
||||
|
||||
var inputActionAssetGUIDs = AssetDatabase.FindAssets($"t:{typeof(InputActionAsset).Name}", searchFolders);
|
||||
|
||||
var inputActionAssetList = new List<InputActionAsset>();
|
||||
foreach (var guid in inputActionAssetGUIDs)
|
||||
{
|
||||
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var assetInputActionAsset = AssetDatabase.LoadAssetAtPath<InputActionAsset>(assetPath);
|
||||
|
||||
if (skipProjectWide)
|
||||
{
|
||||
if (assetInputActionAsset == InputSystem.actions)
|
||||
continue;
|
||||
}
|
||||
|
||||
inputActionAssetList.Add(assetInputActionAsset);
|
||||
}
|
||||
|
||||
return inputActionAssetList;
|
||||
}
|
||||
|
||||
private static SearchProvider CreateInputActionAssetSearchProvider(string id, string displayName,
|
||||
Func<Object, string> createItemFetchDescription, Func<IEnumerable<Object>> fetchAssets)
|
||||
{
|
||||
// We assign description+label in FilteredSearch but also provide a fetchDescription+fetchLabel below.
|
||||
// This is needed to support all zoom-modes for an unknown reason.
|
||||
// Also, fetchLabel/fetchDescription and what is provided to CreateItem is playing different
|
||||
// roles at different zoom levels.
|
||||
var inputActionAssetIcon = InputActionAssetIconLoader.LoadAssetIcon();
|
||||
|
||||
return new SearchProvider(id, displayName)
|
||||
{
|
||||
priority = 25,
|
||||
fetchDescription = FetchLabel,
|
||||
fetchItems = (context, items, provider) => FilteredSearch(context, provider, FetchLabel, createItemFetchDescription,
|
||||
fetchAssets),
|
||||
fetchLabel = FetchLabel,
|
||||
fetchPreview = (item, context, size, options) => inputActionAssetIcon,
|
||||
fetchThumbnail = (item, context) => inputActionAssetIcon,
|
||||
toObject = ToObject,
|
||||
};
|
||||
}
|
||||
|
||||
private static Object ToObject(SearchItem item, Type type)
|
||||
{
|
||||
return item.data as Object;
|
||||
}
|
||||
|
||||
// Custom search function with label matching filtering.
|
||||
private static IEnumerable<SearchItem> FilteredSearch(SearchContext context, SearchProvider provider,
|
||||
Func<Object, string> fetchObjectLabel, Func<Object, string> createItemFetchDescription, Func<IEnumerable<Object>> fetchAssets)
|
||||
{
|
||||
foreach (var asset in fetchAssets())
|
||||
{
|
||||
var label = fetchObjectLabel(asset);
|
||||
Texture2D thumbnail = null; // filled in later
|
||||
|
||||
if (!label.Contains(context.searchText, System.StringComparison.InvariantCultureIgnoreCase))
|
||||
continue; // Ignore due to filtering
|
||||
yield return provider.CreateItem(context, asset.GetInstanceID().ToString(), label, createItemFetchDescription(asset),
|
||||
thumbnail, asset);
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this is overloaded to allow utilizing FetchLabel inside fetchItems to keep label formatting
|
||||
// consistent between CreateItem and additional fetchLabel calls.
|
||||
private static string FetchLabel(Object obj)
|
||||
{
|
||||
// if (obj == InputSystem.actions) return $"{obj.name}{k_ProjectWideAssetIdentificationString}";
|
||||
return obj.name;
|
||||
}
|
||||
|
||||
private static string FetchLabel(SearchItem item, SearchContext context)
|
||||
{
|
||||
return FetchLabel((item.data as Object) !);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15ce6d517ffb81e44bc72545abacdc9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,63 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Property drawer for <see cref="InputAction"/>.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(InputAction))]
|
||||
internal class InputActionDrawer : InputActionDrawerBase
|
||||
{
|
||||
protected override TreeViewItem BuildTree(SerializedProperty property)
|
||||
{
|
||||
return InputActionTreeView.BuildWithJustBindingsFromAction(property);
|
||||
}
|
||||
|
||||
protected override string GetSuffixToRemoveFromPropertyDisplayName()
|
||||
{
|
||||
return " Action";
|
||||
}
|
||||
|
||||
protected override bool IsPropertyAClone(SerializedProperty property)
|
||||
{
|
||||
// When a new item is added to a collection through the inspector, the default behaviour is
|
||||
// to create a clone of the previous item. Here we look at all InputActions that appear before
|
||||
// the current one and compare their Ids to determine if we have a clone. We don't look past
|
||||
// the current item because Unity will be calling this property drawer for each input action
|
||||
// in the collection in turn. If the user just added a new input action, and it's a clone, as
|
||||
// we work our way down the list, we'd end up thinking that an existing input action was a clone
|
||||
// of the newly added one, instead of the other way around. If we do have a clone, we need to
|
||||
// clear out some properties of the InputAction (id, name, and singleton action bindings) and
|
||||
// recreate the tree view.
|
||||
|
||||
if (property?.GetParentProperty() == null || property.GetParentProperty().isArray == false)
|
||||
return false;
|
||||
|
||||
var array = property.GetArrayPropertyFromElement();
|
||||
var index = property.GetIndexOfArrayElement();
|
||||
|
||||
for (var i = 0; i < index; i++)
|
||||
{
|
||||
if (property.FindPropertyRelative(nameof(InputAction.m_Id))?.stringValue ==
|
||||
array.GetArrayElementAtIndex(i)?.FindPropertyRelative(nameof(InputAction.m_Id))?.stringValue)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void ResetProperty(SerializedProperty property)
|
||||
{
|
||||
if (property == null) return;
|
||||
|
||||
property.SetStringValue(nameof(InputAction.m_Id), Guid.NewGuid().ToString());
|
||||
property.SetStringValue(nameof(InputAction.m_Name), "Input Action");
|
||||
property.FindPropertyRelative(nameof(InputAction.m_SingletonActionBindings))?.ClearArray();
|
||||
property.serializedObject?.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2539bd7bca18c47e5a76ad1471ed6829
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,198 @@
|
||||
#if UNITY_EDITOR
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for property drawers that display input actions.
|
||||
/// </summary>
|
||||
internal abstract class InputActionDrawerBase : PropertyDrawer
|
||||
{
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
InitTreeIfNeeded(property);
|
||||
return GetOrCreateViewData(property).TreeView.totalHeight;
|
||||
}
|
||||
|
||||
#if UNITY_2023_2_OR_NEWER
|
||||
[System.Obsolete("CanCacheInspectorGUI has been deprecated and is no longer used.", false)]
|
||||
#endif
|
||||
public override bool CanCacheInspectorGUI(SerializedProperty property)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
InitTreeIfNeeded(property);
|
||||
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
SetNameIfNotSet(property);
|
||||
|
||||
GetOrCreateViewData(property).TreeView.OnGUI(position);
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private void InitTreeIfNeeded(SerializedProperty property)
|
||||
{
|
||||
// NOTE: Unlike InputActionEditorWindow, we do not need to protect against the SerializedObject
|
||||
// changing behind our backs by undo/redo here. Being a PropertyDrawer, we will automatically
|
||||
// get recreated by Unity when it touches our serialized data.
|
||||
|
||||
var viewData = GetOrCreateViewData(property);
|
||||
var propertyIsClone = IsPropertyAClone(property);
|
||||
|
||||
if (!propertyIsClone && viewData.TreeView != null && viewData.TreeView.serializedObject == property.serializedObject)
|
||||
return;
|
||||
|
||||
if (propertyIsClone)
|
||||
ResetProperty(property);
|
||||
|
||||
viewData.TreeView = new InputActionTreeView(property.serializedObject)
|
||||
{
|
||||
onBuildTree = () => BuildTree(property),
|
||||
onDoubleClick = item => OnItemDoubleClicked(item, property),
|
||||
drawActionPropertiesButton = true,
|
||||
title = (GetPropertyTitle(property), property.GetTooltip())
|
||||
};
|
||||
viewData.TreeView.Reload();
|
||||
}
|
||||
|
||||
private void SetNameIfNotSet(SerializedProperty actionProperty)
|
||||
{
|
||||
var nameProperty = actionProperty.FindPropertyRelative("m_Name");
|
||||
if (!string.IsNullOrEmpty(nameProperty.stringValue))
|
||||
return;
|
||||
|
||||
// Special case for InputActionProperty where we want to take the name not from
|
||||
// the m_Action property embedded in it but rather from the InputActionProperty field
|
||||
// itself.
|
||||
var name = actionProperty.displayName;
|
||||
var parent = actionProperty.GetParentProperty();
|
||||
if (parent != null && parent.type == "InputActionProperty")
|
||||
name = parent.displayName;
|
||||
|
||||
var suffix = GetSuffixToRemoveFromPropertyDisplayName();
|
||||
if (name.EndsWith(suffix))
|
||||
name = name.Substring(0, name.Length - suffix.Length);
|
||||
|
||||
// If it's a singleton action, we also need to adjust the InputBinding.action
|
||||
// property values in its binding list.
|
||||
var singleActionBindings = actionProperty.FindPropertyRelative("m_SingletonActionBindings");
|
||||
if (singleActionBindings != null)
|
||||
{
|
||||
var bindingCount = singleActionBindings.arraySize;
|
||||
for (var i = 0; i < bindingCount; ++i)
|
||||
{
|
||||
var binding = singleActionBindings.GetArrayElementAtIndex(i);
|
||||
var actionNameProperty = binding.FindPropertyRelative("m_Action");
|
||||
actionNameProperty.stringValue = name;
|
||||
}
|
||||
}
|
||||
|
||||
nameProperty.stringValue = name;
|
||||
|
||||
actionProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
EditorUtility.SetDirty(actionProperty.serializedObject.targetObject);
|
||||
}
|
||||
|
||||
private static string GetPropertyTitle(SerializedProperty property)
|
||||
{
|
||||
var propertyTitleNumeral = string.Empty;
|
||||
if (property.GetParentProperty() != null && property.GetParentProperty().isArray)
|
||||
propertyTitleNumeral = $" {property.GetIndexOfArrayElement()}";
|
||||
|
||||
if (property.displayName != null &&
|
||||
property.displayName.Length > 0 &&
|
||||
(property.type == nameof(InputAction) || property.type == nameof(InputActionMap)))
|
||||
{
|
||||
return $"{property.displayName}{propertyTitleNumeral}";
|
||||
}
|
||||
|
||||
return property.type == nameof(InputActionMap) ? $"Input Action Map{propertyTitleNumeral}" : $"Input Action{propertyTitleNumeral}";
|
||||
}
|
||||
|
||||
private void OnItemDoubleClicked(ActionTreeItemBase item, SerializedProperty property)
|
||||
{
|
||||
var viewData = GetOrCreateViewData(property);
|
||||
|
||||
// Double-clicking on binding or action item opens property popup.
|
||||
PropertiesViewBase propertyView = null;
|
||||
if (item is BindingTreeItem)
|
||||
{
|
||||
if (viewData.ControlPickerState == null)
|
||||
viewData.ControlPickerState = new InputControlPickerState();
|
||||
propertyView = new InputBindingPropertiesView(item.property,
|
||||
controlPickerState: viewData.ControlPickerState,
|
||||
expectedControlLayout: item.expectedControlLayout,
|
||||
onChange:
|
||||
change => viewData.TreeView.Reload());
|
||||
}
|
||||
else if (item is ActionTreeItem)
|
||||
{
|
||||
propertyView = new InputActionPropertiesView(item.property,
|
||||
onChange: change => viewData.TreeView.Reload());
|
||||
}
|
||||
|
||||
if (propertyView != null)
|
||||
{
|
||||
var rect = new Rect(GUIUtility.GUIToScreenPoint(Event.current.mousePosition), Vector2.zero);
|
||||
PropertiesViewPopup.Show(rect, propertyView);
|
||||
}
|
||||
}
|
||||
|
||||
private InputActionDrawerViewData GetOrCreateViewData(SerializedProperty property)
|
||||
{
|
||||
if (m_PerPropertyViewData == null)
|
||||
m_PerPropertyViewData = new Dictionary<string, InputActionDrawerViewData>();
|
||||
|
||||
if (m_PerPropertyViewData.TryGetValue(property.propertyPath, out var data)) return data;
|
||||
|
||||
data = new InputActionDrawerViewData();
|
||||
m_PerPropertyViewData.Add(property.propertyPath, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
protected abstract TreeViewItem BuildTree(SerializedProperty property);
|
||||
protected abstract string GetSuffixToRemoveFromPropertyDisplayName();
|
||||
protected abstract bool IsPropertyAClone(SerializedProperty property);
|
||||
protected abstract void ResetProperty(SerializedProperty property);
|
||||
|
||||
// Unity creates a single instance of a property drawer to draw multiple instances of the property drawer type,
|
||||
// so we can't store state in the property drawer for each item. We do need that though, because each InputAction
|
||||
// needs to have it's own instance of the InputActionTreeView to correctly draw it's own bindings. So what we do
|
||||
// is keep this array around that stores a tree view instance for each unique property path that the property
|
||||
// drawer encounters. The tree view will be recreated if we detect that the property being drawn has changed.
|
||||
private Dictionary<string, InputActionDrawerViewData> m_PerPropertyViewData;
|
||||
|
||||
internal class PropertiesViewPopup : EditorWindow
|
||||
{
|
||||
public static void Show(Rect btnRect, PropertiesViewBase view)
|
||||
{
|
||||
var window = CreateInstance<PropertiesViewPopup>();
|
||||
window.m_PropertyView = view;
|
||||
window.ShowPopup();
|
||||
window.ShowAsDropDown(btnRect, new Vector2(300, 350));
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
m_PropertyView.OnGUI();
|
||||
}
|
||||
|
||||
private PropertiesViewBase m_PropertyView;
|
||||
}
|
||||
|
||||
private class InputActionDrawerViewData
|
||||
{
|
||||
public InputActionTreeView TreeView;
|
||||
public InputControlPickerState ControlPickerState;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba2c9cc57fa154716b6f077bf9c1c193
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,64 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Property drawer for <see cref="InputActionMap"/>.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(InputActionMap))]
|
||||
internal class InputActionMapDrawer : InputActionDrawerBase
|
||||
{
|
||||
protected override TreeViewItem BuildTree(SerializedProperty property)
|
||||
{
|
||||
return InputActionTreeView.BuildWithJustActionsAndBindingsFromMap(property);
|
||||
}
|
||||
|
||||
protected override string GetSuffixToRemoveFromPropertyDisplayName()
|
||||
{
|
||||
return " Action Map";
|
||||
}
|
||||
|
||||
protected override bool IsPropertyAClone(SerializedProperty property)
|
||||
{
|
||||
// When a new item is added to a collection through the inspector, the default behaviour is
|
||||
// to create a clone of the previous item. Here we look at all InputActionMaps that appear before
|
||||
// the current one and compare their Ids to determine if we have a clone. We don't look past
|
||||
// the current item because Unity will be calling this property drawer for each input action map
|
||||
// in the collection in turn. If the user just added a new input action map, and it's a clone, as
|
||||
// we work our way down the list, we'd end up thinking that an existing input action map was a clone
|
||||
// of the newly added one, instead of the other way around. If we do have a clone, we need to
|
||||
// clear out some properties of the InputActionMap (id, name, input actions, and bindings) and
|
||||
// recreate the tree view.
|
||||
|
||||
if (property?.GetParentProperty() == null || property.GetParentProperty().isArray == false)
|
||||
return false;
|
||||
|
||||
var array = property.GetArrayPropertyFromElement();
|
||||
var index = property.GetIndexOfArrayElement();
|
||||
|
||||
for (var i = 0; i < index; i++)
|
||||
{
|
||||
if (property.FindPropertyRelative(nameof(InputActionMap.m_Id))?.stringValue ==
|
||||
array.GetArrayElementAtIndex(i)?.FindPropertyRelative(nameof(InputActionMap.m_Id))?.stringValue)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void ResetProperty(SerializedProperty property)
|
||||
{
|
||||
if (property == null) return;
|
||||
|
||||
property.SetStringValue(nameof(InputActionMap.m_Id), Guid.NewGuid().ToString());
|
||||
property.SetStringValue(nameof(InputActionMap.m_Name), "Input Action Map");
|
||||
property.FindPropertyRelative(nameof(InputActionMap.m_Actions))?.ClearArray();
|
||||
property.FindPropertyRelative(nameof(InputActionMap.m_Bindings))?.ClearArray();
|
||||
property.serializedObject?.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1ad7c41319cc470d8ae996688c56e79
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,198 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom property drawer for <see cref="InputActionProperty"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Selectively draws the <see cref="InputActionReference"/> and/or the <see cref="InputAction"/>
|
||||
/// underlying the property, based on whether the property is set to use a reference or not.
|
||||
/// The drawer also allows for drawing in different layouts, chosen through Project Settings.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputSettings.InputActionPropertyDrawerMode"/>
|
||||
[CustomPropertyDrawer(typeof(InputActionProperty))]
|
||||
internal class InputActionPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (property == null)
|
||||
throw new System.ArgumentNullException(nameof(property));
|
||||
|
||||
var drawerMode = InputSystem.settings.inputActionPropertyDrawerMode;
|
||||
switch (drawerMode)
|
||||
{
|
||||
case InputSettings.InputActionPropertyDrawerMode.Compact:
|
||||
default:
|
||||
return GetCompactHeight(property);
|
||||
|
||||
case InputSettings.InputActionPropertyDrawerMode.MultilineEffective:
|
||||
case InputSettings.InputActionPropertyDrawerMode.MultilineBoth:
|
||||
return GetMultilineHeight(property, drawerMode == InputSettings.InputActionPropertyDrawerMode.MultilineEffective);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (property == null)
|
||||
throw new System.ArgumentNullException(nameof(property));
|
||||
|
||||
// Using BeginProperty / EndProperty on the parent property means that
|
||||
// prefab override logic works on the entire property.
|
||||
label = EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
var drawerMode = InputSystem.settings.inputActionPropertyDrawerMode;
|
||||
switch (drawerMode)
|
||||
{
|
||||
case InputSettings.InputActionPropertyDrawerMode.Compact:
|
||||
default:
|
||||
DrawCompactGUI(position, property, label);
|
||||
break;
|
||||
|
||||
case InputSettings.InputActionPropertyDrawerMode.MultilineEffective:
|
||||
case InputSettings.InputActionPropertyDrawerMode.MultilineBoth:
|
||||
DrawMultilineGUI(position, property, label, drawerMode == InputSettings.InputActionPropertyDrawerMode.MultilineEffective);
|
||||
break;
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
static float GetCompactHeight(SerializedProperty property)
|
||||
{
|
||||
var useReference = property.FindPropertyRelative("m_UseReference");
|
||||
var effectiveProperty = useReference.boolValue ? property.FindPropertyRelative("m_Reference") : property.FindPropertyRelative("m_Action");
|
||||
return EditorGUI.GetPropertyHeight(effectiveProperty);
|
||||
}
|
||||
|
||||
static float GetMultilineHeight(SerializedProperty property, bool showEffectiveOnly)
|
||||
{
|
||||
var height = 0f;
|
||||
|
||||
// Field label.
|
||||
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
// "Use Reference" toggle.
|
||||
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
// We show either the InputAction property drawer or InputActionReference drawer (default object field).
|
||||
var useReference = property.FindPropertyRelative("m_UseReference");
|
||||
var reference = property.FindPropertyRelative("m_Reference");
|
||||
var action = property.FindPropertyRelative("m_Action");
|
||||
if (showEffectiveOnly)
|
||||
{
|
||||
var effectiveProperty = useReference.boolValue ? reference : action;
|
||||
height += EditorGUI.GetPropertyHeight(effectiveProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
height += EditorGUI.GetPropertyHeight(reference) + EditorGUI.GetPropertyHeight(action);
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
static void DrawCompactGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
position = EditorGUI.PrefixLabel(position, label);
|
||||
|
||||
var useReference = property.FindPropertyRelative("m_UseReference");
|
||||
var effectiveProperty = useReference.boolValue ? property.FindPropertyRelative("m_Reference") : property.FindPropertyRelative("m_Action");
|
||||
|
||||
// Calculate rect for configuration button
|
||||
var buttonRect = position;
|
||||
var popupStyle = Styles.popup;
|
||||
buttonRect.yMin += popupStyle.margin.top + 1f;
|
||||
buttonRect.width = popupStyle.fixedWidth + popupStyle.margin.right;
|
||||
buttonRect.height = EditorGUIUtility.singleLineHeight;
|
||||
position.xMin = buttonRect.xMax;
|
||||
|
||||
// Don't make child fields be indented
|
||||
var indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
|
||||
// Using BeginProperty / EndProperty on the popup button allows the user to
|
||||
// revert prefab overrides to Use Reference by right-clicking the configuration button.
|
||||
EditorGUI.BeginProperty(buttonRect, GUIContent.none, useReference);
|
||||
using (var check = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var newPopupIndex = EditorGUI.Popup(buttonRect, GetCompactPopupIndex(useReference), Contents.compactPopupOptions, popupStyle);
|
||||
if (check.changed)
|
||||
useReference.boolValue = IsUseReference(newPopupIndex);
|
||||
}
|
||||
EditorGUI.EndProperty();
|
||||
|
||||
EditorGUI.PropertyField(position, effectiveProperty, GUIContent.none);
|
||||
|
||||
// Set indent back to what it was
|
||||
EditorGUI.indentLevel = indent;
|
||||
}
|
||||
|
||||
static void DrawMultilineGUI(Rect position, SerializedProperty property, GUIContent label, bool showEffectiveOnly)
|
||||
{
|
||||
const float kIndent = 15f;
|
||||
|
||||
var titleRect = position;
|
||||
titleRect.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
var useReference = property.FindPropertyRelative("m_UseReference");
|
||||
var useReferenceToggleRect = position;
|
||||
useReferenceToggleRect.x += kIndent;
|
||||
useReferenceToggleRect.width -= kIndent;
|
||||
useReferenceToggleRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||
useReferenceToggleRect.height = EditorGUI.GetPropertyHeight(useReference);
|
||||
|
||||
var firstValueRect = position;
|
||||
firstValueRect.x += kIndent;
|
||||
firstValueRect.width -= kIndent;
|
||||
firstValueRect.y += (titleRect.height + useReferenceToggleRect.height) + (EditorGUIUtility.standardVerticalSpacing * 2f);
|
||||
|
||||
var reference = property.FindPropertyRelative("m_Reference");
|
||||
var action = property.FindPropertyRelative("m_Action");
|
||||
|
||||
// Draw the Use Reference toggle.
|
||||
EditorGUI.LabelField(titleRect, label);
|
||||
EditorGUI.PropertyField(useReferenceToggleRect, useReference);
|
||||
|
||||
if (showEffectiveOnly)
|
||||
{
|
||||
// Draw only the Reference or Action underlying the property, whichever is the effective one.
|
||||
var effectiveProperty = useReference.boolValue ? reference : action;
|
||||
firstValueRect.height = EditorGUI.GetPropertyHeight(effectiveProperty);
|
||||
|
||||
EditorGUI.PropertyField(firstValueRect, effectiveProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the Action followed by the Reference.
|
||||
firstValueRect.height = EditorGUI.GetPropertyHeight(action);
|
||||
|
||||
var referenceRect = firstValueRect;
|
||||
referenceRect.y += firstValueRect.height + EditorGUIUtility.standardVerticalSpacing;
|
||||
referenceRect.height = EditorGUI.GetPropertyHeight(reference);
|
||||
|
||||
EditorGUI.PropertyField(firstValueRect, action);
|
||||
EditorGUI.PropertyField(referenceRect, reference);
|
||||
}
|
||||
}
|
||||
|
||||
// 0 == Use Reference, 1 == Use Action
|
||||
// Keep synced with Contents.compactPopupOptions.
|
||||
static int GetCompactPopupIndex(SerializedProperty useReference) => useReference.boolValue ? 0 : 1;
|
||||
static bool IsUseReference(int index) => index == 0;
|
||||
|
||||
static class Contents
|
||||
{
|
||||
static readonly GUIContent s_UseReference = EditorGUIUtility.TrTextContent("Use Reference");
|
||||
static readonly GUIContent s_UseAction = EditorGUIUtility.TrTextContent("Use Action");
|
||||
public static readonly GUIContent[] compactPopupOptions = { s_UseReference, s_UseAction };
|
||||
}
|
||||
|
||||
static class Styles
|
||||
{
|
||||
public static readonly GUIStyle popup = new GUIStyle("PaneOptions") { imagePosition = ImagePosition.ImageOnly };
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 550c4f473d16e49cf9f2e5c45be4490d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,50 @@
|
||||
// Note: If not UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS we do not use a custom property drawer and
|
||||
// picker for InputActionReferences but rather rely on default (classic) object picker.
|
||||
#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
|
||||
using UnityEditor;
|
||||
using UnityEditor.Search;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer in order to use the "Advanced Picker" from UnityEditor.Search.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(InputActionReference))]
|
||||
internal sealed class InputActionReferencePropertyDrawer : PropertyDrawer
|
||||
{
|
||||
private readonly SearchContext m_Context = UnityEditor.Search.SearchService.CreateContext(new[]
|
||||
{
|
||||
InputActionReferenceSearchProviders.CreateInputActionReferenceSearchProviderForAssets(),
|
||||
InputActionReferenceSearchProviders.CreateInputActionReferenceSearchProviderForProjectWideActions(),
|
||||
}, string.Empty, SearchConstants.PickerSearchFlags);
|
||||
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// Sets the property to null if the action is not found in the asset.
|
||||
ValidatePropertyWithDanglingInputActionReferences(property);
|
||||
|
||||
ObjectField.DoObjectField(position, property, typeof(InputActionReference), label,
|
||||
m_Context, SearchConstants.PickerViewFlags);
|
||||
}
|
||||
|
||||
static void ValidatePropertyWithDanglingInputActionReferences(SerializedProperty property)
|
||||
{
|
||||
if (property?.objectReferenceValue is InputActionReference reference)
|
||||
{
|
||||
// Check only if the reference is a project-wide action.
|
||||
if (reference?.asset == InputSystem.actions)
|
||||
{
|
||||
var action = reference?.asset?.FindAction(reference.action.id);
|
||||
if (action is null)
|
||||
{
|
||||
property.objectReferenceValue = null;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30bd04fe045c46918b5fe7bc6efc4ce2
|
||||
timeCreated: 1698143402
|
@@ -0,0 +1,105 @@
|
||||
#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Search;
|
||||
using UnityEngine.Search;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
internal static class SearchConstants
|
||||
{
|
||||
// SearchFlags: these flags are used to customize how search is performed and how search
|
||||
// results are displayed in the advanced object picker.
|
||||
// Note: SearchFlags.Packages is not currently used and hides all results from packages.
|
||||
internal static readonly SearchFlags PickerSearchFlags = SearchFlags.Sorted | SearchFlags.OpenPicker;
|
||||
|
||||
// Search.SearchViewFlags : these flags are used to customize the appearance of the PickerWindow.
|
||||
internal static readonly Search.SearchViewFlags PickerViewFlags = SearchViewFlags.DisableBuilderModeToggle
|
||||
| SearchViewFlags.DisableInspectorPreview
|
||||
| SearchViewFlags.ListView
|
||||
| SearchViewFlags.DisableSavedSearchQuery;
|
||||
}
|
||||
|
||||
internal static class InputActionReferenceSearchProviders
|
||||
{
|
||||
const string k_AssetFolderSearchProviderId = "AssetsInputActionReferenceSearchProvider";
|
||||
const string k_ProjectWideActionsSearchProviderId = "ProjectWideInputActionReferenceSearchProvider";
|
||||
|
||||
// Search provider for InputActionReferences for all assets in the project, without project-wide actions.
|
||||
internal static SearchProvider CreateInputActionReferenceSearchProviderForAssets()
|
||||
{
|
||||
return CreateInputActionReferenceSearchProvider(k_AssetFolderSearchProviderId,
|
||||
"Asset Input Actions",
|
||||
// Show the asset path in the description.
|
||||
(obj) => AssetDatabase.GetAssetPath((obj as InputActionReference).asset),
|
||||
() => InputActionImporter.LoadInputActionReferencesFromAssetDatabase(skipProjectWide: true));
|
||||
}
|
||||
|
||||
// Search provider for InputActionReferences for project-wide actions
|
||||
internal static SearchProvider CreateInputActionReferenceSearchProviderForProjectWideActions()
|
||||
{
|
||||
return CreateInputActionReferenceSearchProvider(k_ProjectWideActionsSearchProviderId,
|
||||
"Project-Wide Input Actions",
|
||||
(obj) => "(Project-Wide Input Actions)",
|
||||
() =>
|
||||
{
|
||||
var asset = InputSystem.actions;
|
||||
if (asset == null)
|
||||
return Array.Empty<Object>();
|
||||
var assetPath = AssetDatabase.GetAssetPath(asset);
|
||||
return InputActionImporter.LoadInputActionReferencesFromAsset(assetPath);
|
||||
});
|
||||
}
|
||||
|
||||
private static SearchProvider CreateInputActionReferenceSearchProvider(string id, string displayName,
|
||||
Func<Object, string> createItemFetchDescription, Func<IEnumerable<Object>> fetchAssets)
|
||||
{
|
||||
// Match icon used for sub-assets from importer for InputActionReferences.
|
||||
// We assign description+label in FilteredSearch but also provide a fetchDescription+fetchLabel below.
|
||||
// This is needed to support all zoom-modes for an unknown reason.
|
||||
// Also, fetchLabel/fetchDescription and what is provided to CreateItem is playing different
|
||||
// roles at different zoom levels.
|
||||
var inputActionReferenceIcon = InputActionAssetIconLoader.LoadActionIcon();
|
||||
|
||||
return new SearchProvider(id, displayName)
|
||||
{
|
||||
priority = 25,
|
||||
fetchDescription = FetchLabel,
|
||||
fetchItems = (context, items, provider) => FilteredSearch(context, provider, FetchLabel, createItemFetchDescription,
|
||||
fetchAssets, "(Project-Wide Input Actions)"),
|
||||
fetchLabel = FetchLabel,
|
||||
fetchPreview = (item, context, size, options) => inputActionReferenceIcon,
|
||||
fetchThumbnail = (item, context) => inputActionReferenceIcon,
|
||||
toObject = (item, type) => item.data as Object,
|
||||
};
|
||||
}
|
||||
|
||||
// Custom search function with label matching filtering.
|
||||
private static IEnumerable<SearchItem> FilteredSearch(SearchContext context, SearchProvider provider,
|
||||
Func<Object, string> fetchObjectLabel, Func<Object, string> createItemFetchDescription, Func<IEnumerable<Object>> fetchAssets, string description)
|
||||
{
|
||||
foreach (var asset in fetchAssets())
|
||||
{
|
||||
var label = fetchObjectLabel(asset);
|
||||
if (!label.Contains(context.searchText, System.StringComparison.InvariantCultureIgnoreCase))
|
||||
continue; // Ignore due to filtering
|
||||
yield return provider.CreateItem(context, asset.GetInstanceID().ToString(), label, createItemFetchDescription(asset),
|
||||
null, asset);
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this is overloaded to allow utilizing FetchLabel inside fetchItems to keep label formatting
|
||||
// consistent between CreateItem and additional fetchLabel calls.
|
||||
private static string FetchLabel(Object obj)
|
||||
{
|
||||
return obj.name;
|
||||
}
|
||||
|
||||
private static string FetchLabel(SearchItem item, SearchContext context)
|
||||
{
|
||||
return FetchLabel((item.data as Object) !);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baaf1bd005134bc6825c06f3510c6643
|
||||
timeCreated: 1698141997
|
@@ -0,0 +1,52 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
|
||||
namespace UnityEngine.InputSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer for string type fields that represent input control paths.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To use this drawer on a property, apply <see cref="InputControlAttribute"/> on it. To constrain
|
||||
/// what type of control is picked, set the <see cref="InputControlAttribute.layout"/> field on the
|
||||
/// attribute.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // A string representing a control path. Constrain it to picking Button-type controls.
|
||||
/// [InputControl(layout = "Button")]
|
||||
/// [SerializeField] private string m_ControlPath;
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
[CustomPropertyDrawer(typeof(InputControlAttribute))]
|
||||
internal sealed class InputControlPathDrawer : PropertyDrawer, IDisposable
|
||||
{
|
||||
private InputControlPickerState m_PickerState;
|
||||
private InputControlPathEditor m_Editor;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_Editor?.Dispose();
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (m_PickerState == null)
|
||||
m_PickerState = new InputControlPickerState();
|
||||
if (m_Editor == null)
|
||||
{
|
||||
m_Editor = new InputControlPathEditor(property, m_PickerState,
|
||||
() => property.serializedObject.ApplyModifiedProperties(),
|
||||
label: label);
|
||||
}
|
||||
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
m_Editor.OnGUI(position, label, property, () => property.serializedObject.ApplyModifiedProperties());
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4075725b42343494dae837a8144df3b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user