暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

StateContainer.cs 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
  2. using System;
  3. using System.Linq.Expressions;
  4. using UnityEditor;
  5. using UnityEditor.UIElements;
  6. using UnityEngine.UIElements;
  7. namespace UnityEngine.InputSystem.Editor
  8. {
  9. internal class StateContainer
  10. {
  11. public event Action<InputActionsEditorState> StateChanged;
  12. private VisualElement m_RootVisualElement;
  13. private InputActionsEditorState m_State;
  14. public StateContainer(InputActionsEditorState initialState)
  15. {
  16. m_State = initialState;
  17. }
  18. public void Dispatch(Command command)
  19. {
  20. if (command == null)
  21. throw new ArgumentNullException(nameof(command));
  22. m_State = command(m_State);
  23. // why not just invoke the state changed event immediately you ask? The Dispatch method might have
  24. // been called from inside a UI element event handler and if we raised the event immediately, a view
  25. // might try to redraw itself *during* execution of the event handler.
  26. m_RootVisualElement.schedule.Execute(() =>
  27. {
  28. // catch exceptions here or the UIToolkit scheduled event will keep firing forever.
  29. try
  30. {
  31. StateChanged?.Invoke(m_State);
  32. }
  33. catch (Exception e)
  34. {
  35. Debug.LogException(e);
  36. }
  37. });
  38. }
  39. public void Initialize(VisualElement rootVisualElement)
  40. {
  41. // We need to use a root element for the TrackSerializedObjectValue that is destroyed with the view.
  42. // Using a root element from the settings window would not enable the tracking callback to be destroyed or garbage collected.
  43. m_RootVisualElement = rootVisualElement;
  44. m_RootVisualElement.Unbind();
  45. m_RootVisualElement.TrackSerializedObjectValue(m_State.serializedObject, so =>
  46. {
  47. StateChanged?.Invoke(m_State);
  48. });
  49. StateChanged?.Invoke(m_State);
  50. rootVisualElement.Bind(m_State.serializedObject);
  51. }
  52. /// <summary>
  53. /// Return a copy of the state.
  54. /// </summary>
  55. /// <remarks>
  56. /// It can sometimes be necessary to get access to the state outside of a state change event, like for example
  57. /// when creating views in response to UI click events. This method is for those times.
  58. /// </remarks>
  59. /// <returns></returns>
  60. public InputActionsEditorState GetState()
  61. {
  62. return m_State;
  63. }
  64. public void Bind<TValue>(Expression<Func<InputActionsEditorState, ReactiveProperty<TValue>>> expr,
  65. Action<InputActionsEditorState> propertyChangedCallback)
  66. {
  67. WhenChanged(expr, propertyChangedCallback);
  68. propertyChangedCallback(m_State);
  69. }
  70. public void Bind(Expression<Func<InputActionsEditorState, SerializedProperty>> expr,
  71. Action<SerializedProperty> serializedPropertyChangedCallback)
  72. {
  73. var propertyGetterFunc = WhenChanged(expr, serializedPropertyChangedCallback);
  74. serializedPropertyChangedCallback(propertyGetterFunc(m_State));
  75. }
  76. public Func<InputActionsEditorState, ReactiveProperty<TValue>> WhenChanged<TValue>(Expression<Func<InputActionsEditorState, ReactiveProperty<TValue>>> expr,
  77. Action<InputActionsEditorState> propertyChangedCallback)
  78. {
  79. var func = ExpressionUtils.CreateGetter(expr);
  80. if (func == null)
  81. throw new ArgumentException($"Couldn't get property info from expression.");
  82. var prop = func(m_State);
  83. if (prop == null)
  84. throw new InvalidOperationException($"ReactiveProperty {expr} has not been assigned.");
  85. prop.Changed += _ => propertyChangedCallback(m_State);
  86. return func;
  87. }
  88. public Func<InputActionsEditorState, SerializedProperty> WhenChanged(Expression<Func<InputActionsEditorState, SerializedProperty>> expr,
  89. Action<SerializedProperty> serializedPropertyChangedCallback)
  90. {
  91. var serializedPropertyGetter = ExpressionUtils.CreateGetter(expr);
  92. if (serializedPropertyGetter == null)
  93. throw new ArgumentException($"Couldn't get property info from expression.");
  94. var serializedProperty = serializedPropertyGetter(m_State);
  95. if (serializedProperty == null)
  96. throw new InvalidOperationException($"ReactiveProperty {expr} has not been assigned.");
  97. m_RootVisualElement.TrackPropertyValue(serializedProperty, serializedPropertyChangedCallback);
  98. return serializedPropertyGetter;
  99. }
  100. }
  101. }
  102. #endif