using System; using System.IO; using UnityEngine; namespace UnityEditor.Recorder { [CustomPropertyDrawer(typeof(FileNameGenerator))] class FileNameGeneratorDrawer : TargetedPropertyDrawer { SerializedProperty m_FileName; SerializedProperty m_Path; static bool s_Dirty = false; private static int padval = 30; static readonly GUIStyle s_PathPreviewStyle = new GUIStyle(GUI.skin.label) { wordWrap = true, stretchHeight = true, stretchWidth = true, padding = new RectOffset(padval, 0, 0, 0), clipping = TextClipping.Overflow }; static readonly GUIStyle s_OpenPathButtonStyle = new GUIStyle("minibutton") { fixedWidth = 30 }; static Texture2D s_OpenPathIcon; protected override void Initialize(SerializedProperty property) { if (s_OpenPathIcon == null) { var iconName = "popout_icon"; if (EditorGUIUtility.isProSkin) iconName = "d_" + iconName; s_OpenPathIcon = UnityHelpers.LoadLocalPackageAsset($"{iconName}.png", true); } base.Initialize(property); m_FileName = property.FindPropertyRelative("m_FileName"); m_Path = property.FindPropertyRelative("m_Path"); } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { Initialize(property); EditorGUI.BeginProperty(position, label, property); position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; const float tagWidth = 88; var txtWidth = position.width - tagWidth - 5; var txtRect = new Rect(position.x, position.y, txtWidth, position.height); var tagRect = new Rect(position.x + txtWidth + 5, position.y, tagWidth, position.height); GUI.SetNextControlName("FileNameField"); m_FileName.stringValue = RecorderEditor.FromRecorderWindow ? EditorGUI.TextField(txtRect, m_FileName.stringValue) : EditorGUI.DelayedTextField(txtRect, m_FileName.stringValue); var editor = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl); if (GUI.GetNameOfFocusedControl().Equals("FileNameField") && Event.current.type == EventType.KeyUp && (Event.current.modifiers == EventModifiers.Control || Event.current.modifiers == EventModifiers.Command)) { if (Event.current.keyCode == KeyCode.C) { Event.current.Use(); editor.Copy(); } else if (Event.current.keyCode == KeyCode.V) { Event.current.Use(); editor.Paste(); m_FileName.stringValue = editor.text; } } GUI.SetNextControlName("FileNameTagPopup"); if (EditorGUI.DropdownButton(tagRect, new GUIContent("+ Wildcards", "Insert a placeholder at the cursor position to include auto-generated text data from your current recording context"), FocusType.Passive)) { GUI.FocusControl("FileNameTagPopup"); var menu = new GenericMenu(); foreach (var w in target.wildcards) { var pattern = w.pattern; menu.AddItem(new GUIContent(w.label), false, () => { m_FileName.stringValue = InsertTag(pattern, m_FileName.stringValue, editor); m_FileName.serializedObject.ApplyModifiedProperties(); s_Dirty = true; }); } menu.DropDown(tagRect); } if (s_Dirty) { s_Dirty = false; GUI.changed = true; } EditorGUI.indentLevel = indent; EditorGUILayout.PropertyField(m_Path); EditorGUI.indentLevel = 0; EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); var path = target.BuildAbsolutePath(null); GUILayoutOption[] op = new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true) }; var r = GUILayoutUtility.GetRect(new GUIContent(path), s_PathPreviewStyle, op); EditorGUI.SelectableLabel(r, path, s_PathPreviewStyle); if (GUILayout.Button(new GUIContent(s_OpenPathIcon, "Open the output location in your file browser"), s_OpenPathButtonStyle)) { try { var fiOutput = new FileInfo(path); var dir = fiOutput.Directory; if (!dir.Exists) dir.Create(); } catch (ArgumentNullException) { // An error occured, most likely because the path was null Debug.LogWarning($"Error opening location {path} in the file browser."); } OpenInFileBrowser.Open(path); } EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); } static string InsertTag(string pattern, string text, TextEditor editor) { if (!string.IsNullOrEmpty(editor.text)) // HACK If editor is not focused on { try { editor.ReplaceSelection(pattern); return editor.text; } catch (Exception) { // ignored } } return text + pattern; } } // Inspired from http://wiki.unity3d.com/index.php/OpenInFileBrowser static class OpenInFileBrowser { static void OpenInOSX(string path, bool openInsideFolder) { var osxPath = path.Replace("\\", "/"); if (!osxPath.StartsWith("\"")) { osxPath = "\"" + osxPath; } if (!osxPath.EndsWith("\"")) { osxPath = osxPath + "\""; } var arguments = (openInsideFolder ? "" : "-R ") + osxPath; System.Diagnostics.Process.Start("open", arguments); } static void OpenInWindows(string path, bool openInsideFolder) { var winPath = path.Replace("/", "\\"); // windows explorer doesn't like forward slashes System.Diagnostics.Process.Start("explorer.exe", (openInsideFolder ? "/root," : "/select,") + winPath); } static void OpenInLinux(string path) { FileInfo fiPath = new FileInfo(path); if (fiPath.Exists) { // xdg-open will open the file with the default file handler, so instead we pass the parent directory // because we want to open a file explorer, not a file _handler_. path = fiPath.DirectoryName; } var linuxPath = path.Replace("\\", "/"); if (!linuxPath.StartsWith("\"")) { linuxPath = "\"" + linuxPath; } if (!linuxPath.EndsWith("\"")) { linuxPath = linuxPath + "\""; } System.Diagnostics.Process.Start("xdg-open", linuxPath); } public static void Open(string path) { if (!File.Exists(path)) path = Path.GetDirectoryName(path); var openInsideFolder = Directory.Exists(path); try { if (Application.platform == RuntimePlatform.WindowsEditor) { OpenInWindows(path, openInsideFolder); } else if (Application.platform == RuntimePlatform.OSXEditor) { OpenInOSX(path, openInsideFolder); } else if (Application.platform == RuntimePlatform.LinuxEditor) { OpenInLinux(path); } } catch (System.ComponentModel.Win32Exception e) { // Safe guard for platform e.HelpLink = ""; // do anything with this variable to silence warning about not using it } } } }