ImprovedFileBrowser

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Added back link to AngryAnt's original file browser, so they now link to each other.)
m (Component code: Added a space so the block comment is correctly copy-pastable)
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 {

Revision as of 18:35, 25 July 2011

By Daniel Brauer, inspired by AngryAnt's original FileBrowser.

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:

ImprovedFileBrowser.png

Component code

<csharp>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])); }

}</csharp>

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.

<csharp>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; } } </csharp>

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox