UI 자동화를 위해 바인딩 기능 구현
- 유니티 에셋 인증 오류로 meta 재생성
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
#if UNITY_EDITOR
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
#if UNITY_6000_2_OR_NEWER
|
||||
using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem<int>;
|
||||
#endif
|
||||
|
||||
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 Vector2 m_ScrollPos;
|
||||
private void OnGUI()
|
||||
{
|
||||
m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos);
|
||||
m_PropertyView.OnGUI();
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private PropertiesViewBase m_PropertyView;
|
||||
}
|
||||
|
||||
private class InputActionDrawerViewData
|
||||
{
|
||||
public InputActionTreeView TreeView;
|
||||
public InputControlPickerState ControlPickerState;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
||||
Reference in New Issue
Block a user