RecentMenu.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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;
  57. propMediaPathType.enumValueIndex = (int)mediaPath.PathType;
  58. if (data.propMediaSource != null)
  59. {
  60. data.propMediaSource.enumValueIndex = (int)MediaSource.Path;
  61. }
  62. // Mark as modified
  63. data.propPath.serializedObject.ApplyModifiedProperties();
  64. foreach (Object o in data.propPath.serializedObject.targetObjects)
  65. {
  66. EditorUtility.SetDirty(o);
  67. }
  68. if (data.autoLoadMedia)
  69. {
  70. MediaPlayer mediaPlayer = (MediaPlayer)data.propPath.serializedObject.targetObject;
  71. if (mediaPlayer != null)
  72. {
  73. mediaPlayer.OpenMedia(mediaPlayer.MediaPath, autoPlay:true);
  74. }
  75. }
  76. }
  77. private void Callback_ClearList(object obj)
  78. {
  79. ((List<string>)obj).Clear();
  80. RecentItems.Save();
  81. }
  82. private void Callback_ClearMissingFiles()
  83. {
  84. RecentItems.ClearMissingFiles();
  85. RecentItems.Save();
  86. }
  87. private struct BrowseData
  88. {
  89. public BrowseData(SerializedProperty propPath, SerializedProperty propMediaSource, string extensions, bool autoLoadMedia)
  90. {
  91. this.extensions = extensions;
  92. this.propPath = propPath;
  93. this.propMediaSource = propMediaSource;
  94. this.autoLoadMedia = autoLoadMedia;
  95. }
  96. public bool autoLoadMedia;
  97. public string extensions;
  98. public SerializedProperty propPath;
  99. public SerializedProperty propMediaSource;
  100. }
  101. private void Callback_BrowseMediaReferences(object obj)
  102. {
  103. int controlID = (int)obj;
  104. EditorGUIUtility.ShowObjectPicker<MediaReference>(null, false, "", controlID);
  105. }
  106. private void Callback_Browse(object obj)
  107. {
  108. BrowseData data = (BrowseData)obj;
  109. SerializedProperty propFilePath = data.propPath.FindPropertyRelative("_path");
  110. SerializedProperty propFilePathType = data.propPath.FindPropertyRelative("_pathType");
  111. string startFolder = EditorHelper.GetBrowsableFolder(propFilePath.stringValue, (MediaPathType)propFilePathType.enumValueIndex);
  112. string videoPath = propFilePath.stringValue;
  113. string fullPath = string.Empty;
  114. MediaPath mediaPath = new MediaPath();
  115. if (EditorHelper.OpenMediaFileDialog(startFolder, ref mediaPath, ref fullPath, data.extensions))
  116. {
  117. // Assign to properties
  118. propFilePath.stringValue = mediaPath.Path;
  119. propFilePathType.enumValueIndex = (int)mediaPath.PathType;
  120. if (data.propMediaSource != null) data.propMediaSource.enumValueIndex = (int)MediaSource.Path;
  121. // Mark as modified
  122. data.propPath.serializedObject.ApplyModifiedProperties();
  123. foreach (Object o in data.propPath.serializedObject.targetObjects)
  124. {
  125. EditorUtility.SetDirty(o);
  126. }
  127. if (data.autoLoadMedia)
  128. {
  129. MediaPlayer mediaPlayer = (MediaPlayer)data.propPath.serializedObject.targetObject;
  130. if (mediaPlayer != null)
  131. {
  132. mediaPlayer.OpenMedia(mediaPlayer.MediaPath, autoPlay:true);
  133. }
  134. }
  135. RecentItems.Add(fullPath);
  136. }
  137. }
  138. private void CreateMenu_RecentFiles(GenericMenu menu, List<string> items, string prefix, SerializedProperty propPath, SerializedProperty propMediaSource, bool autoLoadMedia)
  139. {
  140. int missingCount = 0;
  141. for (int i = 0; i < items.Count; i++)
  142. {
  143. string path = items[i];
  144. // Slashes in path must be replaced as they cause the menu to create submenuts
  145. string itemName = ReplaceSlashes(path);
  146. // TODO: shorten if itemName too long
  147. if (System.IO.File.Exists(path))
  148. {
  149. menu.AddItem(new GUIContent(prefix + itemName), false, Callback_Select, new RecentMenuItemData(path, propPath, propMediaSource, autoLoadMedia));
  150. }
  151. else
  152. {
  153. menu.AddDisabledItem(new GUIContent(prefix + itemName));
  154. missingCount++;
  155. }
  156. }
  157. if (items.Count > 0)
  158. {
  159. menu.AddSeparator(prefix + "");
  160. menu.AddItem(new GUIContent(prefix + "Clear"), false, Callback_ClearList, items);
  161. if (missingCount > 0)
  162. {
  163. menu.AddItem(new GUIContent(prefix + "Clear Missing (" + missingCount + ")"), false, Callback_ClearMissingFiles);
  164. }
  165. }
  166. else
  167. {
  168. menu.AddDisabledItem(new GUIContent(prefix + "No recent files yet"));
  169. }
  170. }
  171. private void CreateMenu_RecentUrls(GenericMenu menu, List<string> items, string prefix, SerializedProperty propPath, SerializedProperty propMediaSource, bool autoLoadMedia)
  172. {
  173. for (int i = 0; i < items.Count; i++)
  174. {
  175. string path = items[i];
  176. // Slashes in path must be replaced as they cause the menu to create submenuts
  177. string itemName = ReplaceSlashes(path);
  178. // TODO: shorten if itemName too long
  179. menu.AddItem(new GUIContent(prefix + itemName), false, Callback_Select, new RecentMenuItemData(path, propPath, propMediaSource, autoLoadMedia));
  180. }
  181. if (items.Count > 0)
  182. {
  183. menu.AddSeparator(prefix + "");
  184. menu.AddItem(new GUIContent(prefix + "Clear"), false, Callback_ClearList, items);
  185. }
  186. else
  187. {
  188. menu.AddDisabledItem(new GUIContent(prefix + "No recent URLs yet"));
  189. }
  190. }
  191. private static string ReplaceSlashes(string text)
  192. {
  193. string slashReplacement = "\u2215";
  194. #if UNITY_EDITOR_WIN
  195. // Special replacement for "//" in URLS so they aren't spaced too far apart
  196. text = text.Replace("//", " \u2215 \u2215 ");
  197. // On Windows we have to add extra spaces so it doesn't look squashed together
  198. slashReplacement = " \u2215 ";
  199. #endif
  200. text = text.Replace("/", slashReplacement);//.Replace("\\", slashReplacement);
  201. // Unity will place text after " _" on the right of the menu, so we replace it so this doesn't happen
  202. text = text.Replace(" _", "_");
  203. return text;
  204. }
  205. private static List<string> FindMediaFilesInStreamingAssetsFolder()
  206. {
  207. List<string> files = new List<string>();
  208. if (System.IO.Directory.Exists(Application.streamingAssetsPath))
  209. {
  210. string[] allFiles = System.IO.Directory.GetFiles(Application.streamingAssetsPath, "*", System.IO.SearchOption.AllDirectories);
  211. if (allFiles != null && allFiles.Length > 0)
  212. {
  213. // Filter by type
  214. for (int i = 0; i < allFiles.Length; i++)
  215. {
  216. string file = allFiles[i];
  217. bool remove = false;
  218. if (file.EndsWith(".meta", System.StringComparison.InvariantCultureIgnoreCase))
  219. {
  220. remove = true;
  221. }
  222. #if UNITY_EDITOR_OSX
  223. remove = remove || file.EndsWith(".DS_Store");
  224. #endif
  225. if (!remove)
  226. {
  227. #if UNITY_EDITOR_WIN
  228. // Using Directory.GetFiles returns paths with \ in so correct this to be /
  229. file = file.Replace("\\", "/");
  230. #endif
  231. files.Add(file);
  232. }
  233. }
  234. }
  235. }
  236. return files;
  237. }
  238. private void CreateMenu_StreamingAssets(GenericMenu menu, string prefix, SerializedProperty propPath, SerializedProperty propMediaSource, bool autoLoadMedia)
  239. {
  240. List<string> files = FindMediaFilesInStreamingAssetsFolder();
  241. if (files.Count > 0)
  242. {
  243. for (int i = 0; i < files.Count; i++)
  244. {
  245. string path = files[i];
  246. if (System.IO.File.Exists(path))
  247. {
  248. string itemName = path.Replace(Application.streamingAssetsPath, "");
  249. if (itemName.StartsWith("/") || itemName.StartsWith("\\"))
  250. {
  251. itemName = itemName.Remove(0, 1);
  252. }
  253. itemName = itemName.Replace("\\", "/");
  254. menu.AddItem(new GUIContent(prefix + itemName), false, Callback_Select, new RecentMenuItemData(path, propPath, propMediaSource, autoLoadMedia));
  255. }
  256. }
  257. }
  258. else
  259. {
  260. menu.AddDisabledItem(new GUIContent(prefix + "StreamingAssets folder missing or contains no files"));
  261. }
  262. }
  263. }
  264. }