SanAndreasUnity/Assets/Scripts/Utilities/GUI/FileBrowser.cs
2020-05-31 19:07:22 +02:00

421 lines
No EOL
11 KiB
C#

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;
protected List<string> m_drives = new List<string> ();
// 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() {
// refresh list of drives
try {
m_drives.Clear ();
m_drives.AddRange( Directory.GetLogicalDrives () );
} catch {
}
if (m_currentDirectory == "/") {
m_currentDirectoryParts = new string[] {""};
m_currentDirectoryMatches = false;
} else {
m_currentDirectoryParts = m_currentDirectory.Split(Path.DirectorySeparatorChar);
if (SelectionPattern != null) {
string[] generation = 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 = GetDirectories(m_currentDirectory);
m_nonMatchingDirectories = new string[0];
} else {
m_directories = GetDirectories(m_currentDirectory, SelectionPattern);
var nonMatchingDirectories = new List<string>();
foreach (string directoryPath in 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 = GetFiles(m_currentDirectory);
m_nonMatchingFiles = new string[0];
} else {
m_files = GetFiles(m_currentDirectory, SelectionPattern);
var nonMatchingFiles = new List<string>();
foreach (string filePath in 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;
}
static string[] GetFiles (string path, string searchPattern)
{
try {
return Directory.GetFiles( path, searchPattern );
} catch {
return new string[0];
}
}
static string[] GetFiles (string path)
{
try {
return Directory.GetFiles( path );
} catch {
return new string[0];
}
}
static string[] GetDirectories (string path, string searchPattern)
{
try {
return Directory.GetDirectories( path, searchPattern );
} catch {
return new string[0];
}
}
static string[] GetDirectories (string path)
{
try {
return Directory.GetDirectories( path );
} catch {
return new string[0];
}
}
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
);
// display drives
if (m_drives.Count > 0) {
GUILayout.BeginHorizontal();
foreach (var drive in m_drives) {
if (GUILayout.Button (drive)) {
SetNewDirectory (drive);
}
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal ();
}
// display directory parts
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 = xGUILayout.SelectionList(
m_selectedDirectory,
m_directoriesWithImages,
DirectoryDoubleClickCallback
);
if (m_selectedDirectory > -1) {
m_selectedFile = m_selectedNonMatchingDirectory = -1;
}
m_selectedNonMatchingDirectory = xGUILayout.SelectionList(
m_selectedNonMatchingDirectory,
m_nonMatchingDirectoriesWithImages,
NonMatchingDirectoryDoubleClickCallback
);
if (m_selectedNonMatchingDirectory > -1) {
m_selectedDirectory = m_selectedFile = -1;
}
GUI.enabled = BrowserType == FileBrowserType.File;
m_selectedFile = xGUILayout.SelectionList(
m_selectedFile,
m_filesWithImages,
FileDoubleClickCallback
);
GUI.enabled = true;
if (m_selectedFile > -1) {
m_selectedDirectory = m_selectedNonMatchingDirectory = -1;
}
GUI.enabled = false;
xGUILayout.SelectionList(
-1,
m_nonMatchingFilesWithImages
);
GUI.enabled = true;
GUILayout.EndScrollView();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (SanAndreasUnity.Utilities.GUIUtils.ButtonWithCalculatedSize("Cancel")) {
m_callback(null);
}
if (BrowserType == FileBrowserType.File) {
GUI.enabled = m_selectedFile > -1;
} else {
if (SelectionPattern == null) {
GUI.enabled = true;//m_selectedDirectory > -1;
} else {
GUI.enabled = m_selectedDirectory > -1 ||
(
m_currentDirectoryMatches &&
m_selectedNonMatchingDirectory == -1 &&
m_selectedFile == -1
);
}
}
string selectButtonText = BrowserType == FileBrowserType.File ? "Select" : "Select current folder";
if (SanAndreasUnity.Utilities.GUIUtils.ButtonWithCalculatedSize (selectButtonText)) {
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);
// }
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]));
}
}