RecentMenu.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. using UnityEngine;
  2. using UnityEditor;
  3. using System.Collections.Generic;
  4. //-----------------------------------------------------------------------------
  5. // Copyright 2015-2021 RenderHeads Ltd. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. namespace RenderHeads.Media.AVProVideo.Editor
  8. {
  9. /// <summary>
  10. /// </summary>
  11. public class RecentMenu
  12. {
  13. public static void Create(SerializedProperty propPath, SerializedProperty propMediaSource, string fileExtensions, bool autoLoadMedia, int mediaReferencePickerId = -1)
  14. {
  15. RecentItems.Load();
  16. RecentMenu menu = new RecentMenu();
  17. menu.FileBrowseButton(propPath, propMediaSource, fileExtensions, autoLoadMedia, mediaReferencePickerId);
  18. }
  19. private void FileBrowseButton(SerializedProperty propPath, SerializedProperty propMediaSource, string fileExtensions, bool autoLoadMedia, int mediaReferencePickerId = -1)
  20. {
  21. GenericMenu toolsMenu = new GenericMenu();
  22. if (mediaReferencePickerId >= 0)
  23. {
  24. toolsMenu.AddItem(new GUIContent("Media References..."), false, Callback_BrowseMediaReferences, (object)mediaReferencePickerId);
  25. }
  26. toolsMenu.AddItem(new GUIContent("Browse..."), false, Callback_Browse, new BrowseData(propPath, propMediaSource, fileExtensions, autoLoadMedia));
  27. CreateMenu_StreamingAssets(toolsMenu, "StreamingAssets/", propPath, propMediaSource, autoLoadMedia);
  28. CreateMenu_RecentFiles(toolsMenu, RecentItems.Files, "Recent Files/" , propPath, propMediaSource, autoLoadMedia);
  29. CreateMenu_RecentUrls(toolsMenu, RecentItems.Urls, "Recent URLs/", propPath, propMediaSource, autoLoadMedia);
  30. toolsMenu.ShowAsContext();
  31. }
  32. private struct RecentMenuItemData
  33. {
  34. public RecentMenuItemData(string path, SerializedProperty propPath, SerializedProperty propMediaSource, bool autoLoadMedia)
  35. {
  36. this.path = path;
  37. this.propPath = propPath;
  38. this.propMediaSource = propMediaSource;
  39. this.autoLoadMedia = autoLoadMedia;
  40. }
  41. public string path;
  42. public bool autoLoadMedia;
  43. public SerializedProperty propPath;
  44. public SerializedProperty propMediaSource;
  45. }
  46. private void Callback_Select(object obj)
  47. {
  48. RecentMenuItemData data = (RecentMenuItemData)obj;
  49. // Move it to the top of the list
  50. RecentItems.Add(data.path);
  51. // Resolve to relative path
  52. MediaPath mediaPath = EditorHelper.GetMediaPathFromFullPath(data.path);
  53. SerializedProperty propMediaPath = data.propPath.FindPropertyRelative("_path");
  54. SerializedProperty propMediaPathType = data.propPath.FindPropertyRelative("_pathType");
  55. // Assign to properties
  56. propMediaPath.stringValue = mediaPath.Path.Replace("\\", "/");
  57. propMediaPathType.enumValueIndex = (int)mediaPath.PathType;
  58. if (data.propMediaSource != null) data.propMediaSource.enumValueIndex = (int)MediaSource.Path;
  59. // Mark as modified
  60. data.propPath.serializedObject.ApplyModifiedProperties();
  61. foreach (Object o in data.propPath.serializedObject.targetObjects)
  62. {
  63. EditorUtility.SetDirty(o);
  64. }
  65. if (data.autoLoadMedia)
  66. {
  67. MediaPlayer mediaPlayer = (MediaPlayer)data.propPath.serializedObject.targetObject;
  68. if (mediaPlayer != null)
  69. {
  70. mediaPlayer.OpenMedia(mediaPlayer.MediaPath, autoPlay:true);
  71. }
  72. }
  73. }
  74. private void Callback_ClearList(object obj)
  75. {
  76. ((List<string>)obj).Clear();
  77. RecentItems.Save();
  78. }
  79. private void Callback_ClearMissingFiles()
  80. {
  81. RecentItems.ClearMissingFiles();
  82. RecentItems.Save();
  83. }
  84. private struct BrowseData
  85. {
  86. public BrowseData(SerializedProperty propPath, SerializedProperty propMediaSource, string extensions, bool autoLoadMedia)
  87. {
  88. this.extensions = extensions;
  89. this.propPath = propPath;
  90. this.propMediaSource = propMediaSource;
  91. this.autoLoadMedia = autoLoadMedia;
  92. }
  93. public bool autoLoadMedia;
  94. public string extensions;
  95. public SerializedProperty propPath;
  96. public SerializedProperty propMediaSource;
  97. }
  98. private void Callback_BrowseMediaReferences(object obj)
  99. {
  100. int controlID = (int)obj;
  101. EditorGUIUtility.ShowObjectPicker<MediaReference>(null, false, "", controlID);
  102. }
  103. private void Callback_Browse(object obj)
  104. {
  105. BrowseData data = (BrowseData)obj;
  106. SerializedProperty propFilePath = data.propPath.FindPropertyRelative("_path");
  107. SerializedProperty propFilePathType = data.propPath.FindPropertyRelative("_pathType");
  108. string startFolder = EditorHelper.GetBrowsableFolder(propFilePath.stringValue, (MediaPathType)propFilePathType.enumValueIndex);
  109. string videoPath = propFilePath.stringValue;
  110. string fullPath = string.Empty;
  111. MediaPath mediaPath = new MediaPath();
  112. if (EditorHelper.OpenMediaFileDialog(startFolder, ref mediaPath, ref fullPath, data.extensions))
  113. {
  114. // Assign to properties
  115. propFilePath.stringValue = mediaPath.Path.Replace("\\", "/");
  116. propFilePathType.enumValueIndex = (int)mediaPath.PathType;
  117. if (data.propMediaSource != null) data.propMediaSource.enumValueIndex = (int)MediaSource.Path;
  118. // Mark as modified
  119. data.propPath.serializedObject.ApplyModifiedProperties();
  120. foreach (Object o in data.propPath.serializedObject.targetObjects)
  121. {
  122. EditorUtility.SetDirty(o);
  123. }
  124. if (data.autoLoadMedia)
  125. {
  126. MediaPlayer mediaPlayer = (MediaPlayer)data.propPath.serializedObject.targetObject;
  127. if (mediaPlayer != null)
  128. {
  129. mediaPlayer.OpenMedia(mediaPlayer.MediaPath, autoPlay:true);
  130. }
  131. }
  132. RecentItems.Add(fullPath);
  133. }
  134. }
  135. private void CreateMenu_RecentFiles(GenericMenu menu, List<string> items, string prefix, SerializedProperty propPath, SerializedProperty propMediaSource, bool autoLoadMedia)
  136. {
  137. int missingCount = 0;
  138. for (int i = 0; i < items.Count; i++)
  139. {
  140. string path = items[i];
  141. // Slashes in path must be replaced as they cause the menu to create submenuts
  142. string itemName = ReplaceSlashes(path);
  143. // TODO: shorten if itemName too long
  144. if (System.IO.File.Exists(path))
  145. {
  146. menu.AddItem(new GUIContent(prefix + itemName), false, Callback_Select, new RecentMenuItemData(path, propPath, propMediaSource, autoLoadMedia));
  147. }
  148. else
  149. {
  150. menu.AddDisabledItem(new GUIContent(prefix + itemName));
  151. missingCount++;
  152. }
  153. }
  154. if (items.Count > 0)
  155. {
  156. menu.AddSeparator(prefix + "");
  157. menu.AddItem(new GUIContent(prefix + "Clear"), false, Callback_ClearList, items);
  158. if (missingCount > 0)
  159. {
  160. menu.AddItem(new GUIContent(prefix + "Clear Missing (" + missingCount + ")"), false, Callback_ClearMissingFiles);
  161. }
  162. }
  163. else
  164. {
  165. menu.AddDisabledItem(new GUIContent(prefix + "No recent files yet"));
  166. }
  167. }
  168. private void CreateMenu_RecentUrls(GenericMenu menu, List<string> items, string prefix, SerializedProperty propPath, SerializedProperty propMediaSource, bool autoLoadMedia)
  169. {
  170. for (int i = 0; i < items.Count; i++)
  171. {
  172. string path = items[i];
  173. // Slashes in path must be replaced as they cause the menu to create submenuts
  174. string itemName = ReplaceSlashes(path);
  175. // TODO: shorten if itemName too long
  176. menu.AddItem(new GUIContent(prefix + itemName), false, Callback_Select, new RecentMenuItemData(path, propPath, propMediaSource, autoLoadMedia));
  177. }
  178. if (items.Count > 0)
  179. {
  180. menu.AddSeparator(prefix + "");
  181. menu.AddItem(new GUIContent(prefix + "Clear"), false, Callback_ClearList, items);
  182. }
  183. else
  184. {
  185. menu.AddDisabledItem(new GUIContent(prefix + "No recent URLs yet"));
  186. }
  187. }
  188. private static string ReplaceSlashes(string text)
  189. {
  190. string slashReplacement = "\u2215";
  191. #if UNITY_EDITOR_WIN
  192. // Special replacement for "//" in URLS so they aren't spaced too far apart
  193. text = text.Replace("//", " \u2215 \u2215 ");
  194. // On Windows we have to add extra spaces so it doesn't look squashed together
  195. slashReplacement = " \u2215 ";
  196. #endif
  197. text = text.Replace("/", slashReplacement).Replace("\\", slashReplacement);
  198. // Unity will place text after " _" on the right of the menu, so we replace it so this doesn't happen
  199. text = text.Replace(" _", "_");
  200. return text;
  201. }
  202. private static List<string> FindMediaFilesInStreamingAssetsFolder()
  203. {
  204. List<string> files = new List<string>();
  205. if (System.IO.Directory.Exists(Application.streamingAssetsPath))
  206. {
  207. string[] allFiles = System.IO.Directory.GetFiles(Application.streamingAssetsPath, "*", System.IO.SearchOption.AllDirectories);
  208. if (allFiles != null && allFiles.Length > 0)
  209. {
  210. // Filter by type
  211. for (int i = 0; i < allFiles.Length; i++)
  212. {
  213. bool remove = false;
  214. if (allFiles[i].EndsWith(".meta", System.StringComparison.InvariantCultureIgnoreCase))
  215. {
  216. remove = true;
  217. }
  218. #if UNITY_EDITOR_OSX
  219. remove = remove || allFiles[i].EndsWith(".DS_Store");
  220. #endif
  221. if (!remove)
  222. {
  223. files.Add(allFiles[i]);
  224. }
  225. }
  226. }
  227. }
  228. return files;
  229. }
  230. private void CreateMenu_StreamingAssets(GenericMenu menu, string prefix, SerializedProperty propPath, SerializedProperty propMediaSource, bool autoLoadMedia)
  231. {
  232. List<string> files = FindMediaFilesInStreamingAssetsFolder();
  233. if (files.Count > 0)
  234. {
  235. for (int i = 0; i < files.Count; i++)
  236. {
  237. string path = files[i];
  238. if (System.IO.File.Exists(path))
  239. {
  240. string itemName = path.Replace(Application.streamingAssetsPath, "");
  241. if (itemName.StartsWith("/") || itemName.StartsWith("\\"))
  242. {
  243. itemName = itemName.Remove(0, 1);
  244. }
  245. itemName = itemName.Replace("\\", "/");
  246. menu.AddItem(new GUIContent(prefix + itemName), false, Callback_Select, new RecentMenuItemData(path, propPath, propMediaSource, autoLoadMedia));
  247. }
  248. }
  249. }
  250. else
  251. {
  252. menu.AddDisabledItem(new GUIContent(prefix + "StreamingAssets folder missing or contains no files"));
  253. }
  254. }
  255. }
  256. }