using System; using System.Collections.Generic; using UnityEditor; using UnityEditor.Timeline; using UnityEngine; using UnityEngine.Timeline; using UnityEngine.UIElements; #if !UNITY_2020_2_OR_NEWER using L10n = UnityEditor.Timeline.L10n; #endif /// /// Store the editor preferences for Timeline. /// [FilePath("TimelinePreferences.asset", FilePathAttribute.Location.PreferencesFolder)] public class TimelinePreferences : ScriptableSingleton { /// /// The time unit used by the Timeline Editor when displaying time values. /// [SerializeField] public TimeFormat timeFormat; /// /// Define the time unit for the timeline window. /// true : frame unit. /// false : timecode unit. /// [NonSerialized, Obsolete("timeUnitInFrame is deprecated. Use timeFormat instead", false)] public bool timeUnitInFrame; /// /// Draw the waveforms for all audio clips. /// [SerializeField] public bool showAudioWaveform = true; /// /// Allow the users to hear audio while scrubbing on audio clip. /// [SerializeField] bool m_AudioScrubbing; /// /// Enables audio scrubbing when moving the playhead. /// public bool audioScrubbing { get { return m_AudioScrubbing; } set { if (m_AudioScrubbing != value) { m_AudioScrubbing = value; TimelinePlayable.muteAudioScrubbing = !value; TimelineEditor.Refresh(RefreshReason.ContentsModified); } } } /// /// Enable Snap to Frame to manipulate clips and align them on frames. /// [SerializeField] public bool snapToFrame = true; #if TIMELINE_FRAMEACCURATE [SerializeField] bool m_PlaybackLockedToFrame; #endif /// /// Enable Timelines to be evaluated on frame during editor preview. /// public bool playbackLockedToFrame { get { #if TIMELINE_FRAMEACCURATE return m_PlaybackLockedToFrame; #else Debug.LogWarning($"PlaybackLockedToFrame is not available for this Unity version"); return false; #endif } set { #if TIMELINE_FRAMEACCURATE m_PlaybackLockedToFrame = value; TimelineEditor.RefreshPreviewPlay(); #else Debug.LogWarning($"PlaybackLockedToFrame is not available for this Unity version"); #endif } } /// /// Enable the ability to snap clips on the edge of another clip. /// [SerializeField] public bool edgeSnap = true; /// /// Behavior of the timeline window during playback. /// [SerializeField] public PlaybackScrollMode playbackScrollMode = PlaybackScrollMode.None; void OnDisable() { Save(); } /// /// Save the timeline preferences settings file. /// public void Save() { Save(true); } internal SerializedObject GetSerializedObject() { return new SerializedObject(this); } } class TimelinePreferencesProvider : SettingsProvider { SerializedObject m_SerializedObject; SerializedProperty m_ShowAudioWaveform; SerializedProperty m_TimeFormat; SerializedProperty m_SnapToFrame; SerializedProperty m_EdgeSnap; SerializedProperty m_PlaybackScrollMode; SerializedProperty m_PlaybackLockedToFrame; internal class Styles { public static readonly GUIContent TimeUnitLabel = L10n.TextContent("Time Unit", "Define the time unit for the timeline window (Frames, Timecode or Seconds)."); public static readonly GUIContent ShowAudioWaveformLabel = L10n.TextContent("Show Audio Waveforms", "Draw the waveforms for all audio clips."); public static readonly GUIContent AudioScrubbingLabel = L10n.TextContent("Allow Audio Scrubbing", "Allow the users to hear audio while scrubbing on audio clip."); public static readonly GUIContent SnapToFrameLabel = L10n.TextContent("Snap To Frame", "Enable Snap to Frame to manipulate clips and align them on frames."); public static readonly GUIContent EdgeSnapLabel = L10n.TextContent("Edge Snap", "Enable the ability to snap clips on the edge of another clip."); public static readonly GUIContent PlaybackScrollModeLabel = L10n.TextContent("Playback Scrolling Mode", "Define scrolling behavior during playback."); public static readonly GUIContent EditorSettingLabel = L10n.TextContent("Timeline Editor Settings", ""); #if TIMELINE_FRAMEACCURATE public static readonly GUIContent PlaybackLockedToFrame = L10n.TextContent("Playback Locked To Frame", "Enable Frame Accurate Preview."); #endif } public TimelinePreferencesProvider(string path, SettingsScope scopes, IEnumerable keywords = null) : base(path, scopes, keywords) { } public override void OnActivate(string searchContext, VisualElement rootElement) { TimelinePreferences.instance.Save(); m_SerializedObject = TimelinePreferences.instance.GetSerializedObject(); m_ShowAudioWaveform = m_SerializedObject.FindProperty("showAudioWaveform"); m_TimeFormat = m_SerializedObject.FindProperty("timeFormat"); m_SnapToFrame = m_SerializedObject.FindProperty("snapToFrame"); m_EdgeSnap = m_SerializedObject.FindProperty("edgeSnap"); m_PlaybackScrollMode = m_SerializedObject.FindProperty("playbackScrollMode"); #if TIMELINE_FRAMEACCURATE m_PlaybackLockedToFrame = m_SerializedObject.FindProperty("m_PlaybackLockedToFrame"); #endif } public override void OnGUI(string searchContext) { m_SerializedObject.Update(); EditorGUI.BeginChangeCheck(); using (new SettingsWindow.GUIScope()) { EditorGUILayout.LabelField(Styles.EditorSettingLabel, EditorStyles.boldLabel); m_TimeFormat.enumValueIndex = EditorGUILayout.Popup(Styles.TimeUnitLabel, m_TimeFormat.enumValueIndex, m_TimeFormat.enumDisplayNames); m_PlaybackScrollMode.enumValueIndex = EditorGUILayout.Popup(Styles.PlaybackScrollModeLabel, m_PlaybackScrollMode.enumValueIndex, m_PlaybackScrollMode.enumNames); m_ShowAudioWaveform.boolValue = EditorGUILayout.Toggle(Styles.ShowAudioWaveformLabel, m_ShowAudioWaveform.boolValue); TimelinePreferences.instance.audioScrubbing = EditorGUILayout.Toggle(Styles.AudioScrubbingLabel, TimelinePreferences.instance.audioScrubbing); m_SnapToFrame.boolValue = EditorGUILayout.Toggle(Styles.SnapToFrameLabel, m_SnapToFrame.boolValue); m_EdgeSnap.boolValue = EditorGUILayout.Toggle(Styles.EdgeSnapLabel, m_EdgeSnap.boolValue); #if TIMELINE_FRAMEACCURATE m_PlaybackLockedToFrame.boolValue = EditorGUILayout.Toggle(Styles.PlaybackLockedToFrame, m_PlaybackLockedToFrame.boolValue); #endif } if (EditorGUI.EndChangeCheck()) { m_SerializedObject.ApplyModifiedProperties(); TimelinePreferences.instance.Save(); TimelineEditor.Refresh(RefreshReason.WindowNeedsRedraw); TimelineEditor.RefreshPreviewPlay(); } } [SettingsProvider] public static SettingsProvider CreateTimelineProjectSettingProvider() { var provider = new TimelinePreferencesProvider("Preferences/Timeline", SettingsScope.User, GetSearchKeywordsFromGUIContentProperties()); return provider; } }