123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- #if UNITY_EDITOR
- using UnityEditor;
- using UnityEngine.Events;
- ////TODO: add ability to inspect contents of event traces in a separate window
- namespace UnityEngine.InputSystem.Editor
- {
- /// <summary>
- /// A custom inspector for <see cref="InputRecorder"/>. Adds UI elements to store captures in files, to load them from
- /// there, and to initiate replays from within the editor. It also shows information for when captures or replays are
- /// in progress.
- /// </summary>
- [CustomEditor(typeof(InputRecorder))]
- internal class InputRecorderInspector : UnityEditor.Editor
- {
- protected void OnEnable()
- {
- m_DevicePathProperty = serializedObject.FindProperty("m_DevicePath");
- m_RecordButtonPath = serializedObject.FindProperty("m_RecordButtonPath");
- m_PlayButtonPathProperty = serializedObject.FindProperty("m_PlayButtonPath");
- m_RecordFramesProperty = serializedObject.FindProperty("m_RecordFrames");
- m_RecordStateEventsOnlyProperty = serializedObject.FindProperty("m_RecordStateEventsOnly");
- m_ReplayOnNewDevicesProperty = serializedObject.FindProperty("m_ReplayOnNewDevices");
- m_SimulateTimingOnReplayProperty = serializedObject.FindProperty("m_SimulateOriginalTimingOnReplay");
- m_CaptureMemoryDefaultSizeProperty = serializedObject.FindProperty("m_CaptureMemoryDefaultSize");
- m_CaptureMemoryMaxSizeProperty = serializedObject.FindProperty("m_CaptureMemoryMaxSize");
- m_StartRecordingWhenEnabledProperty = serializedObject.FindProperty("m_StartRecordingWhenEnabled");
- m_AllInput = string.IsNullOrEmpty(m_DevicePathProperty.stringValue);
- m_PlayText = EditorGUIUtility.TrIconContent("PlayButton", "Play the current input capture.");
- m_PauseText = EditorGUIUtility.TrIconContent("PauseButton", "Pause the current input playback.");
- m_ResumeText = EditorGUIUtility.TrIconContent("PauseButton On", "Resume the current input playback.");
- m_StepForwardText = EditorGUIUtility.TrIconContent("d_StepButton", "Play the next input event.");
- m_StepBackwardText = EditorGUIUtility.TrIconContent("d_StepLeftButton", "Play the previous input event.");
- m_StopText = EditorGUIUtility.TrIconContent("PlayButton On", "Stop the current input playback.");
- m_RecordText = EditorGUIUtility.TrIconContent("Animation.Record", "Start recording input.");
- var recorder = (InputRecorder)serializedObject.targetObject;
- m_OnRecordEvent = _ => Repaint();
- recorder.changeEvent.AddListener(m_OnRecordEvent);
- }
- protected void OnDisable()
- {
- var recorder = (InputRecorder)serializedObject.targetObject;
- recorder.changeEvent.RemoveListener(m_OnRecordEvent);
- }
- public override void OnInspectorGUI()
- {
- var recorder = (InputRecorder)serializedObject.targetObject;
- using (var scope = new EditorGUI.ChangeCheckScope())
- {
- var newAllInput = EditorGUILayout.Toggle(m_AllInputText, m_AllInput);
- if (!newAllInput)
- {
- using (new EditorGUI.IndentLevelScope())
- {
- EditorGUILayout.PropertyField(m_DevicePathProperty, m_DeviceText);
- }
- }
- else if (newAllInput != m_AllInput)
- {
- m_DevicePathProperty.stringValue = string.Empty;
- }
- m_AllInput = newAllInput;
- EditorGUILayout.PropertyField(m_RecordFramesProperty);
- EditorGUILayout.PropertyField(m_RecordStateEventsOnlyProperty);
- EditorGUILayout.PropertyField(m_ReplayOnNewDevicesProperty);
- EditorGUILayout.PropertyField(m_SimulateTimingOnReplayProperty);
- EditorGUILayout.PropertyField(m_StartRecordingWhenEnabledProperty, m_RecordWhenEnabledText);
- var defaultSizeInMB = m_CaptureMemoryDefaultSizeProperty.intValue / (1024 * 1024);
- var newDefaultSizeInMB = EditorGUILayout.IntSlider(m_DefaultSizeText, defaultSizeInMB, 1, 100);
- if (newDefaultSizeInMB != defaultSizeInMB)
- m_CaptureMemoryDefaultSizeProperty.intValue = newDefaultSizeInMB * 1024 * 1024;
- var maxSizeInMB = m_CaptureMemoryMaxSizeProperty.intValue / (1024 * 1024);
- var newMaxSizeInMB = maxSizeInMB < newDefaultSizeInMB
- ? newDefaultSizeInMB
- : EditorGUILayout.IntSlider(m_MaxSizeText, maxSizeInMB, 1, 100);
- if (newMaxSizeInMB != maxSizeInMB)
- m_CaptureMemoryMaxSizeProperty.intValue = newMaxSizeInMB * 1024 * 1024;
- EditorGUILayout.PropertyField(m_RecordButtonPath, m_RecordButtonText);
- EditorGUILayout.PropertyField(m_PlayButtonPathProperty, m_PlayButtonText);
- if (scope.changed)
- serializedObject.ApplyModifiedProperties();
- }
- EditorGUILayout.Space();
- using (new EditorGUILayout.HorizontalScope())
- {
- ////TODO: go-to-next and go-to-previous button
- // Play and pause buttons.
- EditorGUI.BeginDisabledGroup(recorder.eventCount == 0 || recorder.captureIsRunning);
- var oldIsPlaying = recorder.replayIsRunning;
- var newIsPlaying = GUILayout.Toggle(oldIsPlaying, !oldIsPlaying ? m_PlayText : m_StopText, EditorStyles.miniButton,
- GUILayout.Width(50));
- if (oldIsPlaying != newIsPlaying)
- {
- if (newIsPlaying)
- recorder.StartReplay();
- else
- recorder.StopReplay();
- }
- if (newIsPlaying && recorder.replay != null && GUILayout.Button(recorder.replay.paused ? m_ResumeText : m_PauseText, EditorStyles.miniButton,
- GUILayout.Width(50)))
- {
- if (recorder.replay.paused)
- recorder.StartReplay();
- else
- recorder.PauseReplay();
- }
- EditorGUI.EndDisabledGroup();
- // Record button.
- EditorGUI.BeginDisabledGroup(recorder.replayIsRunning);
- var oldIsRecording = recorder.captureIsRunning;
- var newIsRecording = GUILayout.Toggle(oldIsRecording, m_RecordText, EditorStyles.miniButton, GUILayout.Width(50));
- if (oldIsRecording != newIsRecording)
- {
- if (newIsRecording)
- recorder.StartCapture();
- else
- recorder.StopCapture();
- }
- EditorGUI.EndDisabledGroup();
- // Load button.
- EditorGUI.BeginDisabledGroup(recorder.replayIsRunning);
- if (GUILayout.Button("Load"))
- {
- var filePath = EditorUtility.OpenFilePanel("Choose Input Event Trace to Load", string.Empty, "inputtrace");
- if (!string.IsNullOrEmpty(filePath))
- recorder.LoadCaptureFromFile(filePath);
- }
- EditorGUI.EndDisabledGroup();
- // Save button.
- EditorGUI.BeginDisabledGroup(recorder.eventCount == 0 || recorder.replayIsRunning);
- if (GUILayout.Button("Save"))
- {
- var filePath = EditorUtility.SaveFilePanel("Choose Where to Save Input Event Trace", string.Empty, $"{recorder.gameObject.name}.inputtrace", "inputtrace");
- if (!string.IsNullOrEmpty(filePath))
- recorder.SaveCaptureToFile(filePath);
- }
- // Clear button.
- if (GUILayout.Button("Clear"))
- {
- recorder.ClearCapture();
- Repaint();
- }
- EditorGUI.EndDisabledGroup();
- }
- ////TODO: allow hotscrubbing
- // Play bar.
- EditorGUILayout.IntSlider(recorder.replayPosition, 0, (int)recorder.eventCount);
- EditorGUILayout.Space();
- using (new EditorGUI.DisabledScope())
- {
- EditorGUILayout.LabelField(m_InfoText, EditorStyles.miniBoldLabel);
- using (new EditorGUI.IndentLevelScope())
- {
- EditorGUILayout.LabelField($"{recorder.eventCount} events", EditorStyles.miniLabel);
- EditorGUILayout.LabelField($"{recorder.totalEventSizeInBytes / 1024} kb captured", EditorStyles.miniLabel);
- EditorGUILayout.LabelField($"{recorder.allocatedSizeInBytes / 1024} kb allocated", EditorStyles.miniLabel);
- if (recorder.capture != null)
- {
- var devices = recorder.capture.deviceInfos;
- if (devices.Count > 0)
- {
- EditorGUILayout.LabelField(m_DevicesText, EditorStyles.miniBoldLabel);
- using (new EditorGUI.IndentLevelScope())
- {
- foreach (var device in devices)
- {
- EditorGUILayout.LabelField(device.layout, EditorStyles.miniLabel);
- }
- }
- }
- }
- }
- }
- }
- private bool m_AllInput;
- private SerializedProperty m_DevicePathProperty;
- private SerializedProperty m_RecordButtonPath;
- private SerializedProperty m_PlayButtonPathProperty;
- private SerializedProperty m_RecordFramesProperty;
- private SerializedProperty m_RecordStateEventsOnlyProperty;
- private SerializedProperty m_ReplayOnNewDevicesProperty;
- private SerializedProperty m_SimulateTimingOnReplayProperty;
- private SerializedProperty m_CaptureMemoryDefaultSizeProperty;
- private SerializedProperty m_CaptureMemoryMaxSizeProperty;
- private SerializedProperty m_StartRecordingWhenEnabledProperty;
- private UnityAction<InputRecorder.Change> m_OnRecordEvent;
- private GUIContent m_RecordButtonText = new GUIContent("Record Button", "If set, this button will start and stop capture in play mode.");
- private GUIContent m_PlayButtonText = new GUIContent("Play Button", "If set, this button will start and stop replay of the current capture in play mode.");
- private GUIContent m_RecordWhenEnabledText = new GUIContent("Capture When Enabled", "If true, recording will start immediately when the component is enabled in play mode.");
- private GUIContent m_DevicesText = new GUIContent("Devices");
- private GUIContent m_AllInputText = new GUIContent("All Input", "Whether to record input from all devices or from just specific devices.");
- private GUIContent m_DeviceText = new GUIContent("Device", "Type of device to record input from.");
- private GUIContent m_InfoText = new GUIContent("Info:");
- private GUIContent m_DefaultSizeText = new GUIContent("Default Size (MB)", "Memory allocate for capture by default. Will automatically grow up to max memory.");
- private GUIContent m_MaxSizeText = new GUIContent("Max Size (MB)", "Maximum memory allocated for capture. Once a capture reaches this limit, new events will start overwriting old ones.");
- private GUIContent m_PlayText;
- private GUIContent m_PauseText;
- private GUIContent m_ResumeText;
- private GUIContent m_StepForwardText;
- private GUIContent m_StepBackwardText;
- private GUIContent m_StopText;
- private GUIContent m_RecordText;
- }
- }
- #endif
|