Maze / Library /PackageCache /com.unity.inputsystem@1.6.1 /InputSystem /Editor /UITKAssetEditor /StateContainer.cs
| using System; | |
| using System.Linq.Expressions; | |
| using UnityEditor; | |
| using UnityEditor.UIElements; | |
| using UnityEngine.UIElements; | |
| namespace UnityEngine.InputSystem.Editor | |
| { | |
| internal class StateContainer | |
| { | |
| public event Action<InputActionsEditorState> StateChanged; | |
| private readonly VisualElement m_RootVisualElement; | |
| private InputActionsEditorState m_State; | |
| public StateContainer(VisualElement rootVisualElement, InputActionsEditorState initialState) | |
| { | |
| m_RootVisualElement = rootVisualElement; | |
| m_State = initialState; | |
| m_RootVisualElement.TrackSerializedObjectValue(initialState.serializedObject, so => | |
| { | |
| StateChanged?.Invoke(m_State); | |
| }); | |
| rootVisualElement.Bind(initialState.serializedObject); | |
| } | |
| public void Dispatch(Command command) | |
| { | |
| if (command == null) | |
| throw new ArgumentNullException(nameof(command)); | |
| m_State = command(m_State); | |
| // why not just invoke the state changed event immediately you ask? The Dispatch method might have | |
| // been called from inside a UI element event handler and if we raised the event immediately, a view | |
| // might try to redraw itself *during* execution of the event handler. | |
| m_RootVisualElement.schedule.Execute(() => | |
| { | |
| // catch exceptions here or the UIToolkit scheduled event will keep firing forever. | |
| try | |
| { | |
| StateChanged?.Invoke(m_State); | |
| } | |
| catch (Exception e) | |
| { | |
| Debug.LogError(e.Message); | |
| } | |
| }); | |
| } | |
| public void Initialize() | |
| { | |
| StateChanged?.Invoke(m_State); | |
| } | |
| /// <summary> | |
| /// Return a copy of the state. | |
| /// </summary> | |
| /// <remarks> | |
| /// It can sometimes be necessary to get access to the state outside of a state change event, like for example | |
| /// when creating views in response to UI click events. This method is for those times. | |
| /// </remarks> | |
| /// <returns></returns> | |
| public InputActionsEditorState GetState() | |
| { | |
| return m_State; | |
| } | |
| public void Bind<TValue>(Expression<Func<InputActionsEditorState, ReactiveProperty<TValue>>> expr, | |
| Action<InputActionsEditorState> propertyChangedCallback) | |
| { | |
| WhenChanged(expr, propertyChangedCallback); | |
| propertyChangedCallback(m_State); | |
| } | |
| public void Bind(Expression<Func<InputActionsEditorState, SerializedProperty>> expr, | |
| Action<SerializedProperty> serializedPropertyChangedCallback) | |
| { | |
| var propertyGetterFunc = WhenChanged(expr, serializedPropertyChangedCallback); | |
| serializedPropertyChangedCallback(propertyGetterFunc(m_State)); | |
| } | |
| public Func<InputActionsEditorState, ReactiveProperty<TValue>> WhenChanged<TValue>(Expression<Func<InputActionsEditorState, ReactiveProperty<TValue>>> expr, | |
| Action<InputActionsEditorState> propertyChangedCallback) | |
| { | |
| var func = ExpressionUtils.CreateGetter(expr); | |
| if (func == null) | |
| throw new ArgumentException($"Couldn't get property info from expression."); | |
| var prop = func(m_State); | |
| if (prop == null) | |
| throw new InvalidOperationException($"ReactiveProperty {expr} has not been assigned."); | |
| prop.Changed += _ => propertyChangedCallback(m_State); | |
| return func; | |
| } | |
| public Func<InputActionsEditorState, SerializedProperty> WhenChanged(Expression<Func<InputActionsEditorState, SerializedProperty>> expr, | |
| Action<SerializedProperty> serializedPropertyChangedCallback) | |
| { | |
| var serializedPropertyGetter = ExpressionUtils.CreateGetter(expr); | |
| if (serializedPropertyGetter == null) | |
| throw new ArgumentException($"Couldn't get property info from expression."); | |
| var serializedProperty = serializedPropertyGetter(m_State); | |
| if (serializedProperty == null) | |
| throw new InvalidOperationException($"ReactiveProperty {expr} has not been assigned."); | |
| m_RootVisualElement.TrackPropertyValue(serializedProperty, serializedPropertyChangedCallback); | |
| return serializedPropertyGetter; | |
| } | |
| } | |
| } | |