using UnityEngine; using UnityEditor; using System.Collections.Generic; //----------------------------------------------------------------------------- // Copyright 2015-2022 RenderHeads Ltd. All rights reserved. //----------------------------------------------------------------------------- namespace RenderHeads.Media.AVProVideo.Editor { /// /// Editor for the MediaPlaylist class /// [CustomPropertyDrawer(typeof(MediaPlaylist))] public class MediaPlaylistDrawer : PropertyDrawer { private static readonly GUIContent _guiTextInsert = new GUIContent("Clone"); private static readonly GUIContent _guiTextDelete = new GUIContent("Delete"); private static readonly GUIContent _guiTextUp = new GUIContent("↑"); private static readonly GUIContent _guiTextDown = new GUIContent("↓"); private static GUIStyle _styleButtonFoldout = null; private static GUIStyle _styleHelpBoxNoPad = null; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (_styleButtonFoldout == null) { _styleButtonFoldout = new GUIStyle(EditorStyles.foldout); _styleButtonFoldout.margin = new RectOffset(); _styleButtonFoldout.fontStyle = FontStyle.Bold; _styleButtonFoldout.alignment = TextAnchor.MiddleLeft; } if (_styleHelpBoxNoPad == null) { _styleHelpBoxNoPad = new GUIStyle(EditorStyles.helpBox); _styleHelpBoxNoPad.padding = new RectOffset(); _styleHelpBoxNoPad.overflow = new RectOffset(); _styleHelpBoxNoPad.margin = new RectOffset(); _styleHelpBoxNoPad.margin = new RectOffset(0, 0, 0, 0); _styleHelpBoxNoPad.stretchWidth = false; _styleHelpBoxNoPad.stretchHeight = false; } // Using BeginProperty / EndProperty on the parent property means that // prefab override logic works on the entire property. EditorGUI.BeginProperty(position, label, property); SerializedProperty propItems = property.FindPropertyRelative("_items"); if (propItems.arraySize == 0) { if (GUILayout.Button("Insert Item")) { propItems.InsertArrayElementAtIndex(0); } } int insertIndex = -1; int deleteIndex = -1; for (int i = 0; i < propItems.arraySize; i++) { SerializedProperty propItem = propItems.GetArrayElementAtIndex(i); GUILayout.BeginVertical(_styleHelpBoxNoPad); GUI.backgroundColor = propItem.isExpanded ? Color.yellow : Color.white; GUILayout.Box(GUIContent.none, EditorStyles.miniButton, GUILayout.ExpandWidth(true)); Rect buttonRect = GUILayoutUtility.GetLastRect(); GUI.backgroundColor = Color.white; if (Event.current.type != EventType.Layout) { EditorGUI.indentLevel++; SerializedProperty propName = propItem.FindPropertyRelative("name"); propItem.isExpanded = EditorGUI.Foldout(buttonRect, propItem.isExpanded, "#" + i + ": " + propName.stringValue, true, _styleButtonFoldout); EditorGUI.indentLevel--; } GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button(_guiTextInsert, GUILayout.ExpandWidth(false))) { insertIndex = i; } if (GUILayout.Button(_guiTextDelete, GUILayout.ExpandWidth(false))) { deleteIndex = i; } EditorGUI.BeginDisabledGroup((i - 1) < 0); if (GUILayout.Button(_guiTextUp, GUILayout.ExpandWidth(false))) { propItems.MoveArrayElement(i, i - 1); } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup((i + 1) >= propItems.arraySize); if (GUILayout.Button(_guiTextDown, GUILayout.ExpandWidth(false))) { propItems.MoveArrayElement(i, i + 1); } EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); if (propItem.isExpanded) { EditorGUILayout.PropertyField(propItem); } GUILayout.EndVertical(); GUILayout.Space(8f); } if (insertIndex >= 0) { propItems.InsertArrayElementAtIndex(insertIndex); } else if (deleteIndex >= 0) { propItems.DeleteArrayElementAtIndex(deleteIndex); } EditorGUI.EndProperty(); } } /// /// Editor for the MediaPlaylist.MediaItem class /// [CustomPropertyDrawer(typeof(MediaPlaylist.MediaItem))] public class MediaPlaylistItemDrawer : PropertyDrawer { private static readonly GUIContent _guiTextTransition = new GUIContent("Transition"); private static readonly GUIContent _guiTextOverrideTransition = new GUIContent("Override Transition"); private static readonly GUIContent _guiTextDuration = new GUIContent("Duration"); private static readonly GUIContent _guiTextEasing = new GUIContent("Easing"); public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUILayout.PropertyField(property.FindPropertyRelative("name")); SerializedProperty propSourceType = property.FindPropertyRelative("sourceType"); EditorGUILayout.PropertyField(propSourceType); if (propSourceType.enumValueIndex == 0) { EditorGUILayout.PropertyField(property.FindPropertyRelative("mediaPath")); MediaPathDrawer.ShowBrowseButton(property.FindPropertyRelative("mediaPath")); } else { //EditorGUILayout.PropertyField(property.FindPropertyRelative("texture")); //EditorGUILayout.PropertyField(property.FindPropertyRelative("textureDuration")); } EditorGUILayout.Space(); //EditorGUILayout.PropertyField(property.FindPropertyRelative("stereoPacking")); //EditorGUILayout.PropertyField(property.FindPropertyRelative("alphaPacking")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(property.FindPropertyRelative("loop")); EditorGUILayout.PropertyField(property.FindPropertyRelative("startMode")); SerializedProperty propProgressMode = property.FindPropertyRelative("progressMode"); EditorGUILayout.PropertyField(propProgressMode); if (propProgressMode.enumValueIndex == (int)PlaylistMediaPlayer.ProgressMode.BeforeFinish) { EditorGUILayout.PropertyField(property.FindPropertyRelative("progressTimeSeconds")); } EditorGUILayout.Space(); SerializedProperty propIsOverrideTransition = property.FindPropertyRelative("isOverrideTransition"); EditorGUILayout.PropertyField(propIsOverrideTransition, _guiTextOverrideTransition); if (propIsOverrideTransition.boolValue) { EditorGUI.indentLevel++; SerializedProperty propTransitionMode = property.FindPropertyRelative("overrideTransition"); EditorGUILayout.PropertyField(propTransitionMode, _guiTextTransition); if (propTransitionMode.enumValueIndex != (int)PlaylistMediaPlayer.Transition.None) { EditorGUILayout.PropertyField(property.FindPropertyRelative("overrideTransitionDuration"), _guiTextDuration); EditorGUILayout.PropertyField(property.FindPropertyRelative("overrideTransitionEasing"), _guiTextEasing); } EditorGUI.indentLevel--; } } } /// /// Editor for the PlaylistMediaPlayer component /// [CanEditMultipleObjects] [CustomEditor(typeof(PlaylistMediaPlayer))] public class PlaylistMediaPlayerEditor : UnityEditor.Editor { private SerializedProperty _propPlayerA; private SerializedProperty _propPlayerB; private SerializedProperty _propPlaylist; private SerializedProperty _propPlaylistAutoProgress; private SerializedProperty _propAutoCloseVideo; private SerializedProperty _propPlaylistLoopMode; private SerializedProperty _propPausePreviousOnTransition; private SerializedProperty _propDefaultTransition; private SerializedProperty _propDefaultTransitionDuration; private SerializedProperty _propDefaultTransitionEasing; private SerializedProperty _propAudioVolume; private SerializedProperty _propAudioMuted; private static bool _expandPlaylistItems = false; private static Material _materialIMGUI = null; private static GUIStyle _sectionBoxStyle = null; private const string SettingsPrefix = "AVProVideo-PlaylistMediaPlayerEditor-"; private void OnEnable() { _propPlayerA = this.CheckFindProperty("_playerA"); _propPlayerB = this.CheckFindProperty("_playerB"); _propDefaultTransition = this.CheckFindProperty("_defaultTransition"); _propDefaultTransitionDuration = this.CheckFindProperty("_defaultTransitionDuration"); _propDefaultTransitionEasing = this.CheckFindProperty("_defaultTransitionEasing"); _propPausePreviousOnTransition = this.CheckFindProperty("_pausePreviousOnTransition"); _propPlaylist = this.CheckFindProperty("_playlist"); _propPlaylistAutoProgress = this.CheckFindProperty("_playlistAutoProgress"); _propAutoCloseVideo = this.CheckFindProperty("_autoCloseVideo"); _propPlaylistLoopMode = this.CheckFindProperty("_playlistLoopMode"); _propAudioVolume = this.CheckFindProperty("_playlistAudioVolume"); _propAudioMuted = this.CheckFindProperty("_playlistAudioMuted"); _expandPlaylistItems = EditorPrefs.GetBool(SettingsPrefix + "ExpandPlaylistItems", false); } private void OnDisable() { EditorPrefs.SetBool(SettingsPrefix + "ExpandPlaylistItems", _expandPlaylistItems); if (_materialIMGUI) { DestroyImmediate(_materialIMGUI); _materialIMGUI = null; } } public override bool RequiresConstantRepaint() { PlaylistMediaPlayer media = (this.target) as PlaylistMediaPlayer; return (media.Control != null && media.isActiveAndEnabled); } public override void OnInspectorGUI() { PlaylistMediaPlayer media = (this.target) as PlaylistMediaPlayer; serializedObject.Update(); if (media == null || _propPlayerA == null) { return; } if (_sectionBoxStyle == null) { _sectionBoxStyle = new GUIStyle(GUI.skin.box); _sectionBoxStyle.padding.top = 0; _sectionBoxStyle.padding.bottom = 0; } EditorGUILayout.PropertyField(_propPlayerA); EditorGUILayout.PropertyField(_propPlayerB); EditorGUILayout.Space(); EditorGUILayout.Space(); GUILayout.Label("Audio", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(_propAudioVolume, new GUIContent("Volume")); if (EditorGUI.EndChangeCheck()) { foreach (PlaylistMediaPlayer player in this.targets) { player.AudioVolume = _propAudioVolume.floatValue; } } EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(_propAudioMuted, new GUIContent("Muted")); if (EditorGUI.EndChangeCheck()) { foreach (PlaylistMediaPlayer player in this.targets) { player.AudioMuted = _propAudioMuted.boolValue; } } EditorGUILayout.Space(); EditorGUILayout.Space(); GUILayout.Label("Playlist", EditorStyles.boldLabel); EditorGUILayout.PropertyField(_propPlaylistAutoProgress, new GUIContent("Auto Progress")); EditorGUILayout.PropertyField(_propPlaylistLoopMode, new GUIContent("Loop Mode")); EditorGUILayout.PropertyField(_propAutoCloseVideo); { EditorGUILayout.Space(); EditorGUILayout.Space(); GUI.color = Color.white; GUI.backgroundColor = Color.clear; if (_expandPlaylistItems) { GUI.color = Color.white; GUI.backgroundColor = new Color(0.8f, 0.8f, 0.8f, 0.1f); if (EditorGUIUtility.isProSkin) { GUI.backgroundColor = Color.black; } } GUILayout.BeginVertical(_sectionBoxStyle); GUI.backgroundColor = Color.white; if (GUILayout.Button("Playlist Items", EditorStyles.toolbarButton)) { _expandPlaylistItems = !_expandPlaylistItems; } GUI.color = Color.white; if (_expandPlaylistItems) { EditorGUILayout.PropertyField(_propPlaylist); } GUILayout.EndVertical(); } EditorGUILayout.Space(); EditorGUILayout.Space(); GUILayout.Label("Default Transition", EditorStyles.boldLabel); EditorGUILayout.PropertyField(_propDefaultTransition, new GUIContent("Transition")); EditorGUILayout.PropertyField(_propDefaultTransitionEasing, new GUIContent("Easing")); EditorGUILayout.PropertyField(_propDefaultTransitionDuration, new GUIContent("Duration")); EditorGUILayout.PropertyField(_propPausePreviousOnTransition, new GUIContent("Pause Previous")); EditorGUILayout.Space(); EditorGUILayout.Space(); if (Application.isPlaying) { ITextureProducer textureSource = media.TextureProducer; Texture texture = null; if (textureSource != null) { texture = textureSource.GetTexture(); } if (texture == null) { texture = EditorGUIUtility.whiteTexture; } float ratio = 1f;// (float)texture.width / (float)texture.height; // Reserve rectangle for texture GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); Rect textureRect; if (texture != EditorGUIUtility.whiteTexture) { textureRect = GUILayoutUtility.GetRect(Screen.width / 2, Screen.width / 2, (Screen.width / 2) / ratio, (Screen.width / 2) / ratio); } else { textureRect = GUILayoutUtility.GetRect(1920f / 40f, 1080f / 40f); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); string rateText = "0"; string playerText = string.Empty; if (media.Info != null) { rateText = media.Info.GetVideoDisplayRate().ToString("F2"); playerText = media.Info.GetPlayerDescription(); } EditorGUILayout.LabelField("Display Rate", rateText); EditorGUILayout.LabelField("Using", playerText); // Draw the texture if (Event.current.type == EventType.Repaint) { Matrix4x4 prevMatrix = GUI.matrix; if (textureSource != null && textureSource.RequiresVerticalFlip()) { GUIUtility.ScaleAroundPivot(new Vector2(1f, -1f), new Vector2(0f, textureRect.y + (textureRect.height / 2f))); } GUI.color = Color.gray; EditorGUI.DrawTextureTransparent(textureRect, Texture2D.blackTexture, ScaleMode.StretchToFill); GUI.color = Color.white; if (!GUI.enabled) { GUI.color = Color.grey; GUI.DrawTexture(textureRect, texture, ScaleMode.ScaleToFit, false); GUI.color = Color.white; } else { if (!_materialIMGUI) { _materialIMGUI = VideoRender.CreateResolveMaterial( false ); VideoRender.SetupGammaMaterial(_materialIMGUI, true); } { EditorGUI.DrawPreviewTexture(textureRect, texture, _materialIMGUI, ScaleMode.ScaleToFit); } } GUI.matrix = prevMatrix; } } EditorGUI.BeginDisabledGroup(!(media.Control != null && media.Control.CanPlay() && media.isActiveAndEnabled && !EditorApplication.isPaused)); OnInspectorGUI_PlayControls(media); EditorGUI.EndDisabledGroup(); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUI.BeginDisabledGroup(!Application.isPlaying); GUILayout.Label("Current Item: " + media.PlaylistIndex + " / " + Mathf.Max(0, media.Playlist.Items.Count - 1) ); GUILayout.BeginHorizontal(); EditorGUI.BeginDisabledGroup(!media.CanJumpToItem(media.PlaylistIndex - 1)); if (GUILayout.Button("Prev")) { media.PrevItem(); } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(!media.CanJumpToItem(media.PlaylistIndex + 1)); if (GUILayout.Button("Next")) { media.NextItem(); } EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); serializedObject.ApplyModifiedProperties(); } private void OnInspectorGUI_PlayControls(PlaylistMediaPlayer player) { GUILayout.Space(8.0f); // Slider EditorGUILayout.BeginHorizontal(); bool isPlaying = false; if (player.Control != null) { isPlaying = player.Control.IsPlaying(); } float currentTime = 0f; if (player.Control != null) { currentTime = (float)player.Control.GetCurrentTime(); } float durationTime = 0f; if (player.Info != null) { durationTime = (float)player.Info.GetDuration(); if (float.IsNaN(durationTime)) { durationTime = 0f; } } string timeUsed = Helper.GetTimeString(currentTime, true); GUILayout.Label(timeUsed, GUILayout.ExpandWidth(false)); float newTime = GUILayout.HorizontalSlider(currentTime, 0f, durationTime, GUILayout.ExpandWidth(true)); if (newTime != currentTime && player.Control != null) { player.Control.Seek(newTime); } string timeTotal = "Infinity"; if (!float.IsInfinity(durationTime)) { timeTotal = Helper.GetTimeString(durationTime, true); } GUILayout.Label(timeTotal, GUILayout.ExpandWidth(false)); EditorGUILayout.EndHorizontal(); // Buttons EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Rewind", GUILayout.ExpandWidth(false))) { if (player.Control != null) { player.Control.Rewind(); } } if (!isPlaying) { GUI.color = Color.green; if (GUILayout.Button("Play", GUILayout.ExpandWidth(true))) { player.Play(); } } else { GUI.color = Color.yellow; if (GUILayout.Button("Pause", GUILayout.ExpandWidth(true))) { player.Pause(); } } GUI.color = Color.white; EditorGUILayout.EndHorizontal(); } } }