ImprovedFileBrowser
Danielbrauer (Talk | contribs) m (→Usage: Cleaned up top of script) |
m (Text replace - "</csharp>" to "</syntaxhighlight>") |
||
(4 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | By Daniel Brauer, inspired by AngryAnt | + | By Daniel Brauer, inspired by AngryAnt's original [[FileBrowser]]. |
== Description == | == Description == | ||
Line 11: | Line 11: | ||
== Component code == | == Component code == | ||
− | <csharp>using UnityEngine; | + | <syntaxhighlight lang="csharp">using UnityEngine; |
using System; | using System; | ||
using System.IO; | using System.IO; | ||
Line 18: | Line 18: | ||
/* | /* | ||
File browser for selecting files or folders at runtime. | File browser for selecting files or folders at runtime. | ||
− | */ | + | */ |
public enum FileBrowserType { | public enum FileBrowserType { | ||
Line 351: | Line 351: | ||
} | } | ||
− | }</csharp> | + | }</syntaxhighlight> |
+ | |||
+ | == Fix: Root Directory == | ||
+ | By Pablo Bollansée (The Oddler) - Unity 3.4.0f5 - Windows 7(x64) | ||
+ | |||
+ | <syntaxhighlight lang="csharp">protected void ReadDirectoryContents() | ||
+ | { | ||
+ | if (m_currentDirectory == "/") | ||
+ | { | ||
+ | //... some code, not importent here | ||
+ | if (SelectionPattern != null) | ||
+ | { | ||
+ | string directoryName = Path.GetDirectoryName(m_currentDirectory); | ||
+ | string[] generation = new string[0]; | ||
+ | if(directoryName != null) | ||
+ | { //This is new: generation should be an empty array for the root directory. | ||
+ | //directoryName will be null if it's a root directory | ||
+ | generation = Directory.GetDirectories( | ||
+ | directoryName, | ||
+ | SelectionPattern ); | ||
+ | } | ||
+ | m_currentDirectoryMatches = Array.IndexOf(generation, m_currentDirectory) >= 0; | ||
+ | } | ||
+ | else | ||
+ | //... | ||
+ | //... </syntaxhighlight> | ||
+ | more info why directotyName is null when it's the root directory see http://msdn.microsoft.com/en-us/library/system.io.path.getdirectoryname.aspx . | ||
== Usage == | == Usage == | ||
Line 357: | Line 383: | ||
Here we have a file path that can be assigned using the file browser. It uses the filter so that only text files are selectable. | Here we have a file path that can be assigned using the file browser. It uses the filter so that only text files are selectable. | ||
− | <csharp>using UnityEngine; | + | <syntaxhighlight lang="csharp">using UnityEngine; |
public class TextFileFinder : MonoBehaviour { | public class TextFileFinder : MonoBehaviour { | ||
Line 401: | Line 427: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
Latest revision as of 20:45, 10 January 2012
By Daniel Brauer, inspired by AngryAnt's original FileBrowser.
Contents |
[edit] Description
Implements a decent file browser GUILayout. This file browser allows you to have the user search for a file or folder, optionally matching a specific pattern. Note: This code uses the ImprovedSelectionList script, and assumes your GUISkin has a "List Item" custom style.
This is how the browser looks using the MetalGUISkin from Extra GUI Skins:
[edit] Component code
using UnityEngine; using System; using System.IO; using System.Collections.Generic; /* File browser for selecting files or folders at runtime. */ public enum FileBrowserType { File, Directory } public class FileBrowser { // Called when the user clicks cancel or select public delegate void FinishedCallback(string path); // Defaults to working directory public string CurrentDirectory { get { return m_currentDirectory; } set { SetNewDirectory(value); SwitchDirectoryNow(); } } protected string m_currentDirectory; // Optional pattern for filtering selectable files/folders. See: // http://msdn.microsoft.com/en-us/library/wz42302f(v=VS.90).aspx // and // http://msdn.microsoft.com/en-us/library/6ff71z1w(v=VS.90).aspx public string SelectionPattern { get { return m_filePattern; } set { m_filePattern = value; ReadDirectoryContents(); } } protected string m_filePattern; // Optional image for directories public Texture2D DirectoryImage { get { return m_directoryImage; } set { m_directoryImage = value; BuildContent(); } } protected Texture2D m_directoryImage; // Optional image for files public Texture2D FileImage { get { return m_fileImage; } set { m_fileImage = value; BuildContent(); } } protected Texture2D m_fileImage; // Browser type. Defaults to File, but can be set to Folder public FileBrowserType BrowserType { get { return m_browserType; } set { m_browserType = value; ReadDirectoryContents(); } } protected FileBrowserType m_browserType; protected string m_newDirectory; protected string[] m_currentDirectoryParts; protected string[] m_files; protected GUIContent[] m_filesWithImages; protected int m_selectedFile; protected string[] m_nonMatchingFiles; protected GUIContent[] m_nonMatchingFilesWithImages; protected int m_selectedNonMatchingDirectory; protected string[] m_directories; protected GUIContent[] m_directoriesWithImages; protected int m_selectedDirectory; protected string[] m_nonMatchingDirectories; protected GUIContent[] m_nonMatchingDirectoriesWithImages; protected bool m_currentDirectoryMatches; protected GUIStyle CentredText { get { if (m_centredText == null) { m_centredText = new GUIStyle(GUI.skin.label); m_centredText.alignment = TextAnchor.MiddleLeft; m_centredText.fixedHeight = GUI.skin.button.fixedHeight; } return m_centredText; } } protected GUIStyle m_centredText; protected string m_name; protected Rect m_screenRect; protected Vector2 m_scrollPosition; protected FinishedCallback m_callback; // Browsers need at least a rect, name and callback public FileBrowser(Rect screenRect, string name, FinishedCallback callback) { m_name = name; m_screenRect = screenRect; m_browserType = FileBrowserType.File; m_callback = callback; SetNewDirectory(Directory.GetCurrentDirectory()); SwitchDirectoryNow(); } protected void SetNewDirectory(string directory) { m_newDirectory = directory; } protected void SwitchDirectoryNow() { if (m_newDirectory == null || m_currentDirectory == m_newDirectory) { return; } m_currentDirectory = m_newDirectory; m_scrollPosition = Vector2.zero; m_selectedDirectory = m_selectedNonMatchingDirectory = m_selectedFile = -1; ReadDirectoryContents(); } protected void ReadDirectoryContents() { if (m_currentDirectory == "/") { m_currentDirectoryParts = new string[] {""}; m_currentDirectoryMatches = false; } else { m_currentDirectoryParts = m_currentDirectory.Split(Path.DirectorySeparatorChar); if (SelectionPattern != null) { string[] generation = Directory.GetDirectories( Path.GetDirectoryName(m_currentDirectory), SelectionPattern ); m_currentDirectoryMatches = Array.IndexOf(generation, m_currentDirectory) >= 0; } else { m_currentDirectoryMatches = false; } } if (BrowserType == FileBrowserType.File || SelectionPattern == null) { m_directories = Directory.GetDirectories(m_currentDirectory); m_nonMatchingDirectories = new string[0]; } else { m_directories = Directory.GetDirectories(m_currentDirectory, SelectionPattern); var nonMatchingDirectories = new List<string>(); foreach (string directoryPath in Directory.GetDirectories(m_currentDirectory)) { if (Array.IndexOf(m_directories, directoryPath) < 0) { nonMatchingDirectories.Add(directoryPath); } } m_nonMatchingDirectories = nonMatchingDirectories.ToArray(); for (int i = 0; i < m_nonMatchingDirectories.Length; ++i) { int lastSeparator = m_nonMatchingDirectories[i].LastIndexOf(Path.DirectorySeparatorChar); m_nonMatchingDirectories[i] = m_nonMatchingDirectories[i].Substring(lastSeparator + 1); } Array.Sort(m_nonMatchingDirectories); } for (int i = 0; i < m_directories.Length; ++i) { m_directories[i] = m_directories[i].Substring(m_directories[i].LastIndexOf(Path.DirectorySeparatorChar) + 1); } if (BrowserType == FileBrowserType.Directory || SelectionPattern == null) { m_files = Directory.GetFiles(m_currentDirectory); m_nonMatchingFiles = new string[0]; } else { m_files = Directory.GetFiles(m_currentDirectory, SelectionPattern); var nonMatchingFiles = new List<string>(); foreach (string filePath in Directory.GetFiles(m_currentDirectory)) { if (Array.IndexOf(m_files, filePath) < 0) { nonMatchingFiles.Add(filePath); } } m_nonMatchingFiles = nonMatchingFiles.ToArray(); for (int i = 0; i < m_nonMatchingFiles.Length; ++i) { m_nonMatchingFiles[i] = Path.GetFileName(m_nonMatchingFiles[i]); } Array.Sort(m_nonMatchingFiles); } for (int i = 0; i < m_files.Length; ++i) { m_files[i] = Path.GetFileName(m_files[i]); } Array.Sort(m_files); BuildContent(); m_newDirectory = null; } protected void BuildContent() { m_directoriesWithImages = new GUIContent[m_directories.Length]; for (int i = 0; i < m_directoriesWithImages.Length; ++i) { m_directoriesWithImages[i] = new GUIContent(m_directories[i], DirectoryImage); } m_nonMatchingDirectoriesWithImages = new GUIContent[m_nonMatchingDirectories.Length]; for (int i = 0; i < m_nonMatchingDirectoriesWithImages.Length; ++i) { m_nonMatchingDirectoriesWithImages[i] = new GUIContent(m_nonMatchingDirectories[i], DirectoryImage); } m_filesWithImages = new GUIContent[m_files.Length]; for (int i = 0; i < m_filesWithImages.Length; ++i) { m_filesWithImages[i] = new GUIContent(m_files[i], FileImage); } m_nonMatchingFilesWithImages = new GUIContent[m_nonMatchingFiles.Length]; for (int i = 0; i < m_nonMatchingFilesWithImages.Length; ++i) { m_nonMatchingFilesWithImages[i] = new GUIContent(m_nonMatchingFiles[i], FileImage); } } public void OnGUI() { GUILayout.BeginArea( m_screenRect, m_name, GUI.skin.window ); GUILayout.BeginHorizontal(); for (int parentIndex = 0; parentIndex < m_currentDirectoryParts.Length; ++parentIndex) { if (parentIndex == m_currentDirectoryParts.Length - 1) { GUILayout.Label(m_currentDirectoryParts[parentIndex], CentredText); } else if (GUILayout.Button(m_currentDirectoryParts[parentIndex])) { string parentDirectoryName = m_currentDirectory; for (int i = m_currentDirectoryParts.Length - 1; i > parentIndex; --i) { parentDirectoryName = Path.GetDirectoryName(parentDirectoryName); } SetNewDirectory(parentDirectoryName); } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); m_scrollPosition = GUILayout.BeginScrollView( m_scrollPosition, false, true, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, GUI.skin.box ); m_selectedDirectory = GUILayoutx.SelectionList( m_selectedDirectory, m_directoriesWithImages, DirectoryDoubleClickCallback ); if (m_selectedDirectory > -1) { m_selectedFile = m_selectedNonMatchingDirectory = -1; } m_selectedNonMatchingDirectory = GUILayoutx.SelectionList( m_selectedNonMatchingDirectory, m_nonMatchingDirectoriesWithImages, NonMatchingDirectoryDoubleClickCallback ); if (m_selectedNonMatchingDirectory > -1) { m_selectedDirectory = m_selectedFile = -1; } GUI.enabled = BrowserType == FileBrowserType.File; m_selectedFile = GUILayoutx.SelectionList( m_selectedFile, m_filesWithImages, FileDoubleClickCallback ); GUI.enabled = true; if (m_selectedFile > -1) { m_selectedDirectory = m_selectedNonMatchingDirectory = -1; } GUI.enabled = false; GUILayoutx.SelectionList( -1, m_nonMatchingFilesWithImages ); GUI.enabled = true; GUILayout.EndScrollView(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Cancel", GUILayout.Width(50))) { m_callback(null); } if (BrowserType == FileBrowserType.File) { GUI.enabled = m_selectedFile > -1; } else { if (SelectionPattern == null) { GUI.enabled = m_selectedDirectory > -1; } else { GUI.enabled = m_selectedDirectory > -1 || ( m_currentDirectoryMatches && m_selectedNonMatchingDirectory == -1 && m_selectedFile == -1 ); } } if (GUILayout.Button("Select", GUILayout.Width(50))) { if (BrowserType == FileBrowserType.File) { m_callback(Path.Combine(m_currentDirectory, m_files[m_selectedFile])); } else { if (m_selectedDirectory > -1) { m_callback(Path.Combine(m_currentDirectory, m_directories[m_selectedDirectory])); } else { m_callback(m_currentDirectory); } } } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.EndArea(); if (Event.current.type == EventType.Repaint) { SwitchDirectoryNow(); } } protected void FileDoubleClickCallback(int i) { if (BrowserType == FileBrowserType.File) { m_callback(Path.Combine(m_currentDirectory, m_files[i])); } } protected void DirectoryDoubleClickCallback(int i) { SetNewDirectory(Path.Combine(m_currentDirectory, m_directories[i])); } protected void NonMatchingDirectoryDoubleClickCallback(int i) { SetNewDirectory(Path.Combine(m_currentDirectory, m_nonMatchingDirectories[i])); } }
[edit] Fix: Root Directory
By Pablo Bollansée (The Oddler) - Unity 3.4.0f5 - Windows 7(x64)
protected void ReadDirectoryContents() { if (m_currentDirectory == "/") { //... some code, not importent here if (SelectionPattern != null) { string directoryName = Path.GetDirectoryName(m_currentDirectory); string[] generation = new string[0]; if(directoryName != null) { //This is new: generation should be an empty array for the root directory. //directoryName will be null if it's a root directory generation = Directory.GetDirectories( directoryName, SelectionPattern ); } m_currentDirectoryMatches = Array.IndexOf(generation, m_currentDirectory) >= 0; } else //... //...
more info why directotyName is null when it's the root directory see http://msdn.microsoft.com/en-us/library/system.io.path.getdirectoryname.aspx .
[edit] Usage
Here we have a file path that can be assigned using the file browser. It uses the filter so that only text files are selectable.
using UnityEngine; public class TextFileFinder : MonoBehaviour { protected string m_textPath; protected FileBrowser m_fileBrowser; [SerializeField] protected Texture2D m_directoryImage, m_fileImage; protected void OnGUI () { if (m_fileBrowser != null) { m_fileBrowser.OnGUI(); } else { OnGUIMain(); } } protected void OnGUIMain() { GUILayout.BeginHorizontal(); GUILayout.Label("Text File", GUILayout.Width(100)); GUILayout.FlexibleSpace(); GUILayout.Label(m_textPath ?? "none selected"); if (GUILayout.Button("...", GUILayout.ExpandWidth(false))) { m_fileBrowser = new FileBrowser( new Rect(100, 100, 600, 500), "Choose Text File", FileSelectedCallback ); m_fileBrowser.SelectionPattern = "*.txt"; m_fileBrowser.DirectoryImage = m_directoryImage; m_fileBrowser.FileImage = m_fileImage; } GUILayout.EndHorizontal(); } protected void FileSelectedCallback(string path) { m_fileBrowser = null; m_textPath = path; } }