Level save + load

This commit is contained in:
2023-06-16 17:08:56 +03:00
parent d9fbd99072
commit 0eb8b1d4ee
132 changed files with 20138 additions and 15 deletions

View File

@@ -0,0 +1,60 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
namespace SimpleFileBrowser
{
// Avoid multiple EventSystems in the scene by activating the embedded EventSystem only if one doesn't already exist in the scene
[DefaultExecutionOrder( 1000 )]
public class EventSystemHandler : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField]
private GameObject embeddedEventSystem;
#pragma warning restore 0649
private void OnEnable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.sceneUnloaded -= OnSceneUnloaded;
SceneManager.sceneUnloaded += OnSceneUnloaded;
ActivateEventSystemIfNeeded();
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneUnloaded -= OnSceneUnloaded;
DeactivateEventSystem();
}
private void OnSceneLoaded( Scene scene, LoadSceneMode mode )
{
#if UNITY_2017_2_OR_NEWER
DeactivateEventSystem();
#endif
ActivateEventSystemIfNeeded();
}
private void OnSceneUnloaded( Scene current )
{
// Deactivate the embedded EventSystem before changing scenes because the new scene might have its own EventSystem
DeactivateEventSystem();
}
private void ActivateEventSystemIfNeeded()
{
if( embeddedEventSystem && !EventSystem.current )
embeddedEventSystem.SetActive( true );
}
private void DeactivateEventSystem()
{
if( embeddedEventSystem )
embeddedEventSystem.SetActive( false );
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0868341868a4a4641b4d272d2fc5f538
timeCreated: 1658741613
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f51dc09bf9e35804ba0f5e76c527025e
timeCreated: 1479416382
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace SimpleFileBrowser
{
public class FileBrowserAccessRestrictedPanel : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField]
private Text messageLabel;
[SerializeField]
private Button okButton;
#pragma warning restore 0649
internal void Show()
{
gameObject.SetActive( true );
}
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
private void LateUpdate()
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( Keyboard.current != null )
#endif
{
// Handle keyboard shortcuts
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( Keyboard.current[Key.Enter].wasPressedThisFrame || Keyboard.current[Key.NumpadEnter].wasPressedThisFrame || Keyboard.current[Key.Escape].wasPressedThisFrame )
#else
if( Input.GetKeyDown( KeyCode.Return ) || Input.GetKeyDown( KeyCode.KeypadEnter ) || Input.GetKeyDown( KeyCode.Escape ) )
#endif
OKButtonClicked();
}
}
#endif
internal void RefreshSkin( UISkin skin )
{
Image background = GetComponentInChildren<Image>();
background.color = skin.PopupPanelsBackgroundColor;
background.sprite = skin.PopupPanelsBackground;
skin.ApplyTo( okButton );
skin.ApplyTo( messageLabel, skin.PopupPanelsTextColor );
}
public void OKButtonClicked()
{
gameObject.SetActive( false );
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 85ea21be7cacb484cb6db0d183d3b2a8
timeCreated: 1603800894
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,142 @@
using UnityEngine;
using UnityEngine.UI;
namespace SimpleFileBrowser
{
public class FileBrowserContextMenu : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField]
private FileBrowser fileBrowser;
[SerializeField]
private RectTransform rectTransform;
[SerializeField]
private Button selectAllButton;
[SerializeField]
private Button deselectAllButton;
[SerializeField]
private Button createFolderButton;
[SerializeField]
private Button deleteButton;
[SerializeField]
private Button renameButton;
[SerializeField]
private GameObject selectAllButtonSeparator;
[SerializeField]
private Text[] allButtonTexts;
[SerializeField]
private Image[] allButtonSeparators;
[SerializeField]
private float minDistanceToEdges = 10f;
#pragma warning restore 0649
internal void Show( bool selectAllButtonVisible, bool deselectAllButtonVisible, bool deleteButtonVisible, bool renameButtonVisible, Vector2 position, bool isMoreOptionsMenu )
{
selectAllButton.gameObject.SetActive( selectAllButtonVisible );
deselectAllButton.gameObject.SetActive( deselectAllButtonVisible );
deleteButton.gameObject.SetActive( deleteButtonVisible );
renameButton.gameObject.SetActive( renameButtonVisible );
selectAllButtonSeparator.SetActive( !deselectAllButtonVisible );
rectTransform.anchoredPosition = position;
gameObject.SetActive( true );
if( isMoreOptionsMenu )
rectTransform.pivot = Vector2.one;
else
{
// Find the optimal pivot value
LayoutRebuilder.ForceRebuildLayoutImmediate( rectTransform );
Vector2 size = rectTransform.sizeDelta;
Vector2 canvasSize = fileBrowser.rectTransform.sizeDelta;
// Take canvas' Pivot into consideration
Vector2 positionOffset = canvasSize;
positionOffset.Scale( fileBrowser.rectTransform.pivot );
position += positionOffset;
// Try bottom-right corner first
Vector2 cornerPos = position + new Vector2( size.x + minDistanceToEdges, -size.y - minDistanceToEdges );
if( cornerPos.x <= canvasSize.x && cornerPos.y >= 0f )
rectTransform.pivot = new Vector2( 0f, 1f );
else
{
// Try bottom-left corner
cornerPos = position - new Vector2( size.x + minDistanceToEdges, size.y + minDistanceToEdges );
if( cornerPos.x >= 0f && cornerPos.y >= 0f )
rectTransform.pivot = Vector2.one;
else
{
// Try top-right corner
cornerPos = position + new Vector2( size.x + minDistanceToEdges, size.y + minDistanceToEdges );
if( cornerPos.x <= canvasSize.x && cornerPos.y <= canvasSize.y )
rectTransform.pivot = Vector2.zero;
else
{
// Use top-left corner
rectTransform.pivot = new Vector2( 1f, 0f );
}
}
}
}
}
internal void Hide()
{
gameObject.SetActive( false );
}
internal void RefreshSkin( UISkin skin )
{
rectTransform.GetComponent<Image>().color = skin.ContextMenuBackgroundColor;
deselectAllButton.image.color = skin.ContextMenuBackgroundColor;
selectAllButton.image.color = skin.ContextMenuBackgroundColor;
createFolderButton.image.color = skin.ContextMenuBackgroundColor;
deleteButton.image.color = skin.ContextMenuBackgroundColor;
renameButton.image.color = skin.ContextMenuBackgroundColor;
for( int i = 0; i < allButtonTexts.Length; i++ )
skin.ApplyTo( allButtonTexts[i], skin.ContextMenuTextColor );
for( int i = 0; i < allButtonSeparators.Length; i++ )
allButtonSeparators[i].color = skin.ContextMenuSeparatorColor;
}
public void OnSelectAllButtonClicked()
{
Hide();
fileBrowser.SelectAllFiles();
}
public void OnDeselectAllButtonClicked()
{
Hide();
fileBrowser.DeselectAllFiles();
}
public void OnCreateFolderButtonClicked()
{
Hide();
fileBrowser.CreateNewFolder();
}
public void OnDeleteButtonClicked()
{
Hide();
fileBrowser.DeleteSelectedFiles();
}
public void OnRenameButtonClicked()
{
Hide();
fileBrowser.RenameSelectedFile();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0d5261bc2717e6143961d30ccb76fb66
timeCreated: 1603793977
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
using UnityEngine;
using UnityEngine.EventSystems;
namespace SimpleFileBrowser
{
public class FileBrowserCursorHandler : MonoBehaviour
#if UNITY_EDITOR || ( !UNITY_ANDROID && !UNITY_IOS )
, IPointerEnterHandler, IPointerExitHandler, IBeginDragHandler, IEndDragHandler
#endif
{
#if UNITY_EDITOR || ( !UNITY_ANDROID && !UNITY_IOS )
#pragma warning disable 0649
[SerializeField]
private Texture2D resizeCursor;
#pragma warning restore 0649
private bool isHovering;
private bool isResizing;
void IPointerEnterHandler.OnPointerEnter( PointerEventData eventData )
{
isHovering = true;
if( !eventData.dragging )
ShowResizeCursor();
}
void IPointerExitHandler.OnPointerExit( PointerEventData eventData )
{
isHovering = false;
if( !isResizing )
ShowDefaultCursor();
}
void IBeginDragHandler.OnBeginDrag( PointerEventData eventData )
{
isResizing = true;
ShowResizeCursor();
}
void IEndDragHandler.OnEndDrag( PointerEventData eventData )
{
isResizing = false;
if( !isHovering )
ShowDefaultCursor();
}
private void ShowDefaultCursor()
{
Cursor.SetCursor( null, Vector2.zero, CursorMode.Auto );
}
private void ShowResizeCursor()
{
Cursor.SetCursor( resizeCursor, new Vector2( resizeCursor.width * 0.5f, resizeCursor.height * 0.5f ), CursorMode.Auto );
}
#endif
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 759524cf7ef37f244bb00cd9724f0349
timeCreated: 1603745549
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,159 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace SimpleFileBrowser
{
public class FileBrowserFileOperationConfirmationPanel : MonoBehaviour
{
public enum OperationType { Delete = 0, Overwrite = 1 };
public delegate void OnOperationConfirmed();
#pragma warning disable 0649
[SerializeField]
private Text[] titleLabels;
[SerializeField]
private GameObject[] targetItems;
[SerializeField]
private Image[] targetItemIcons;
[SerializeField]
private Text[] targetItemNames;
[SerializeField]
private GameObject targetItemsRest;
[SerializeField]
private Text targetItemsRestLabel;
[SerializeField]
private RectTransform yesButtonTransform;
[SerializeField]
private RectTransform noButtonTransform;
[SerializeField]
private float narrowScreenWidth = 380f;
#pragma warning restore 0649
private OnOperationConfirmed onOperationConfirmed;
internal void Show( FileBrowser fileBrowser, List<FileSystemEntry> items, OperationType operationType, OnOperationConfirmed onOperationConfirmed )
{
Show( fileBrowser, items, null, operationType, onOperationConfirmed );
}
internal void Show( FileBrowser fileBrowser, List<FileSystemEntry> items, List<int> selectedItemIndices, OperationType operationType, OnOperationConfirmed onOperationConfirmed )
{
this.onOperationConfirmed = onOperationConfirmed;
int itemCount = ( selectedItemIndices != null ) ? selectedItemIndices.Count : items.Count;
for( int i = 0; i < titleLabels.Length; i++ )
titleLabels[i].gameObject.SetActive( (int) operationType == i );
for( int i = 0; i < targetItems.Length; i++ )
targetItems[i].SetActive( i < itemCount );
for( int i = 0; i < targetItems.Length && i < itemCount; i++ )
{
FileSystemEntry item = items[( selectedItemIndices != null ) ? selectedItemIndices[i] : i];
targetItemIcons[i].sprite = fileBrowser.GetIconForFileEntry( item );
targetItemNames[i].text = item.Name;
}
if( itemCount > targetItems.Length )
{
targetItemsRestLabel.text = string.Concat( "...and ", ( itemCount - targetItems.Length ).ToString(), " other" );
targetItemsRest.SetActive( true );
}
else
targetItemsRest.SetActive( false );
gameObject.SetActive( true );
}
// Handles responsive user interface
internal void OnCanvasDimensionsChanged( Vector2 size )
{
if( size.x >= narrowScreenWidth )
{
yesButtonTransform.anchorMin = new Vector2( 0.5f, 0f );
yesButtonTransform.anchorMax = new Vector2( 0.75f, 1f );
noButtonTransform.anchorMin = new Vector2( 0.75f, 0f );
}
else
{
yesButtonTransform.anchorMin = Vector2.zero;
yesButtonTransform.anchorMax = new Vector2( 0.5f, 1f );
noButtonTransform.anchorMin = new Vector2( 0.5f, 0f );
}
}
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
private void LateUpdate()
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( Keyboard.current != null )
#endif
{
// Handle keyboard shortcuts
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( Keyboard.current[Key.Enter].wasPressedThisFrame || Keyboard.current[Key.NumpadEnter].wasPressedThisFrame )
#else
if( Input.GetKeyDown( KeyCode.Return ) || Input.GetKeyDown( KeyCode.KeypadEnter ) )
#endif
YesButtonClicked();
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( Keyboard.current[Key.Escape].wasPressedThisFrame )
#else
if( Input.GetKeyDown( KeyCode.Escape ) )
#endif
NoButtonClicked();
}
}
#endif
internal void RefreshSkin( UISkin skin )
{
Image background = GetComponentInChildren<Image>();
background.color = skin.PopupPanelsBackgroundColor;
background.sprite = skin.PopupPanelsBackground;
skin.ApplyTo( yesButtonTransform.GetComponent<Button>() );
skin.ApplyTo( noButtonTransform.GetComponent<Button>() );
for( int i = 0; i < titleLabels.Length; i++ )
skin.ApplyTo( titleLabels[i], skin.PopupPanelsTextColor );
skin.ApplyTo( targetItemsRestLabel, skin.PopupPanelsTextColor );
for( int i = 0; i < targetItemNames.Length; i++ )
skin.ApplyTo( targetItemNames[i], skin.PopupPanelsTextColor );
for( int i = 0; i < targetItems.Length; i++ )
targetItems[i].GetComponent<LayoutElement>().preferredHeight = skin.FileHeight;
}
public void YesButtonClicked()
{
gameObject.SetActive( false );
if( onOperationConfirmed != null )
onOperationConfirmed();
}
public void NoButtonClicked()
{
gameObject.SetActive( false );
onOperationConfirmed = null;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 524a683efed82084b9a9c4a3eff23b73
timeCreated: 1658958138
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,543 @@
using System.IO;
using UnityEngine;
namespace SimpleFileBrowser
{
public struct FileSystemEntry
{
public readonly string Path;
public readonly string Name;
public readonly string Extension;
public readonly FileAttributes Attributes;
public bool IsDirectory { get { return ( Attributes & FileAttributes.Directory ) == FileAttributes.Directory; } }
public FileSystemEntry( string path, string name, string extension, bool isDirectory )
{
Path = path;
Name = name;
Extension = extension;
Attributes = isDirectory ? FileAttributes.Directory : FileAttributes.Normal;
}
public FileSystemEntry( FileSystemInfo fileInfo, string extension )
{
Path = fileInfo.FullName;
Name = fileInfo.Name;
Extension = extension;
Attributes = fileInfo.Attributes;
}
}
public static class FileBrowserHelpers
{
#if !UNITY_EDITOR && UNITY_ANDROID
private static AndroidJavaClass m_ajc = null;
public static AndroidJavaClass AJC
{
get
{
if( m_ajc == null )
m_ajc = new AndroidJavaClass( "com.yasirkula.unity.FileBrowser" );
return m_ajc;
}
}
private static AndroidJavaObject m_context = null;
public static AndroidJavaObject Context
{
get
{
if( m_context == null )
{
using( AndroidJavaObject unityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ) )
{
m_context = unityClass.GetStatic<AndroidJavaObject>( "currentActivity" );
}
}
return m_context;
}
}
private static string m_temporaryFilePath = null;
private static string TemporaryFilePath
{
get
{
if( m_temporaryFilePath == null )
{
m_temporaryFilePath = Path.Combine( Application.temporaryCachePath, "tmpFile" );
Directory.CreateDirectory( Application.temporaryCachePath );
}
return m_temporaryFilePath;
}
}
// On Android 10+, filesystem can be accessed via Storage Access Framework only
private static bool? m_shouldUseSAF = null;
public static bool ShouldUseSAF
{
get
{
if( m_shouldUseSAF == null )
m_shouldUseSAF = AJC.CallStatic<bool>( "CheckSAF" );
return m_shouldUseSAF.Value;
}
}
public static bool ShouldUseSAFForPath( string path ) // true: path should be managed with AJC (native helper class for Storage Access Framework), false: path should be managed with System.IO
{
return ShouldUseSAF && ( string.IsNullOrEmpty( path ) || path[0] != '/' );
}
#endif
public static bool FileExists( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<bool>( "SAFEntryExists", Context, path, false );
#endif
return File.Exists( path );
}
public static bool DirectoryExists( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<bool>( "SAFEntryExists", Context, path, true );
else if( ShouldUseSAF ) // Directory.Exists returns true even for inaccessible directories on Android 10+, we need to check if the directory is accessible
{
try
{
Directory.GetFiles( path, "testtesttest" );
return true;
}
catch
{
return false;
}
}
#endif
return Directory.Exists( path );
}
public static bool IsDirectory( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<bool>( "SAFEntryDirectory", Context, path );
#endif
if( Directory.Exists( path ) )
return true;
if( File.Exists( path ) )
return false;
string extension = Path.GetExtension( path );
return extension == null || extension.Length <= 1; // extension includes '.'
}
public static bool IsPathDescendantOfAnother( string path, string parentFolderPath )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<bool>( "IsSAFEntryChildOfAnother", Context, path, parentFolderPath );
#endif
path = Path.GetFullPath( path ).Replace( '\\', '/' );
parentFolderPath = Path.GetFullPath( parentFolderPath ).Replace( '\\', '/' );
if( path == parentFolderPath )
return false;
if( parentFolderPath[parentFolderPath.Length - 1] != '/' )
parentFolderPath += "/";
return path != parentFolderPath && path.StartsWith( parentFolderPath, System.StringComparison.OrdinalIgnoreCase );
}
public static string GetDirectoryName( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<string>( "GetParentDirectory", Context, path );
#endif
return Path.GetDirectoryName( path );
}
public static FileSystemEntry[] GetEntriesInDirectory( string path, bool extractOnlyLastSuffixFromExtensions )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
{
string resultRaw = AJC.CallStatic<string>( "OpenSAFFolder", Context, path );
int separatorIndex = resultRaw.IndexOf( "<>" );
if( separatorIndex <= 0 )
{
Debug.LogError( "Entry count does not exist" );
return null;
}
int entryCount = 0;
for( int i = 0; i < separatorIndex; i++ )
{
char ch = resultRaw[i];
if( ch < '0' && ch > '9' )
{
Debug.LogError( "Couldn't parse entry count" );
return null;
}
entryCount = entryCount * 10 + ( ch - '0' );
}
if( entryCount <= 0 )
return null;
FileSystemEntry[] result = new FileSystemEntry[entryCount];
for( int i = 0; i < entryCount; i++ )
{
separatorIndex += 2;
if( separatorIndex >= resultRaw.Length )
{
Debug.LogError( "Couldn't fetch directory attribute" );
return null;
}
bool isDirectory = resultRaw[separatorIndex] == 'd';
separatorIndex++;
int nextSeparatorIndex = resultRaw.IndexOf( "<>", separatorIndex );
if( nextSeparatorIndex <= 0 )
{
Debug.LogError( "Entry name is empty" );
return null;
}
string entryName = resultRaw.Substring( separatorIndex, nextSeparatorIndex - separatorIndex );
separatorIndex = nextSeparatorIndex + 2;
nextSeparatorIndex = resultRaw.IndexOf( "<>", separatorIndex );
if( nextSeparatorIndex <= 0 )
{
Debug.LogError( "Entry rawUri is empty" );
return null;
}
string rawUri = resultRaw.Substring( separatorIndex, nextSeparatorIndex - separatorIndex );
separatorIndex = nextSeparatorIndex;
result[i] = new FileSystemEntry( rawUri, entryName, isDirectory ? null : FileBrowser.GetExtensionFromFilename( entryName, extractOnlyLastSuffixFromExtensions ), isDirectory );
}
return result;
}
#endif
try
{
FileSystemInfo[] items = new DirectoryInfo( path ).GetFileSystemInfos();
FileSystemEntry[] result = new FileSystemEntry[items.Length];
int index = 0;
for( int i = 0; i < items.Length; i++ )
{
try
{
result[index] = new FileSystemEntry( items[i], FileBrowser.GetExtensionFromFilename( items[i].Name, extractOnlyLastSuffixFromExtensions ) );
index++;
}
catch( System.Exception e )
{
Debug.LogException( e );
}
}
if( result.Length != index )
System.Array.Resize( ref result, index );
return result;
}
catch( System.UnauthorizedAccessException ) { }
catch( System.Exception e )
{
Debug.LogException( e );
}
return null;
}
public static string CreateFileInDirectory( string directoryPath, string filename )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( directoryPath ) )
return AJC.CallStatic<string>( "CreateSAFEntry", Context, directoryPath, false, filename );
#endif
string path = Path.Combine( directoryPath, filename );
using( File.Create( path ) ) { }
return path;
}
public static string CreateFolderInDirectory( string directoryPath, string folderName )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( directoryPath ) )
return AJC.CallStatic<string>( "CreateSAFEntry", Context, directoryPath, true, folderName );
#endif
string path = Path.Combine( directoryPath, folderName );
Directory.CreateDirectory( path );
return path;
}
public static void WriteBytesToFile( string targetPath, byte[] bytes )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( targetPath ) )
{
File.WriteAllBytes( TemporaryFilePath, bytes );
AJC.CallStatic( "WriteToSAFEntry", Context, targetPath, TemporaryFilePath, false );
File.Delete( TemporaryFilePath );
return;
}
#endif
File.WriteAllBytes( targetPath, bytes );
}
public static void WriteTextToFile( string targetPath, string text )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( targetPath ) )
{
File.WriteAllText( TemporaryFilePath, text );
AJC.CallStatic( "WriteToSAFEntry", Context, targetPath, TemporaryFilePath, false );
File.Delete( TemporaryFilePath );
return;
}
#endif
File.WriteAllText( targetPath, text );
}
public static void AppendBytesToFile( string targetPath, byte[] bytes )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( targetPath ) )
{
File.WriteAllBytes( TemporaryFilePath, bytes );
AJC.CallStatic( "WriteToSAFEntry", Context, targetPath, TemporaryFilePath, true );
File.Delete( TemporaryFilePath );
return;
}
#endif
using( var stream = new FileStream( targetPath, FileMode.Append, FileAccess.Write ) )
{
stream.Write( bytes, 0, bytes.Length );
}
}
public static void AppendTextToFile( string targetPath, string text )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( targetPath ) )
{
File.WriteAllText( TemporaryFilePath, text );
AJC.CallStatic( "WriteToSAFEntry", Context, targetPath, TemporaryFilePath, true );
File.Delete( TemporaryFilePath );
return;
}
#endif
File.AppendAllText( targetPath, text );
}
private static void AppendFileToFile( string targetPath, string sourceFileToAppend )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( targetPath ) )
{
AJC.CallStatic( "WriteToSAFEntry", Context, targetPath, sourceFileToAppend, true );
return;
}
#endif
using( Stream input = File.OpenRead( sourceFileToAppend ) )
using( Stream output = new FileStream( targetPath, FileMode.Append, FileAccess.Write ) )
{
byte[] buffer = new byte[4096];
int bytesRead;
while( ( bytesRead = input.Read( buffer, 0, buffer.Length ) ) > 0 )
output.Write( buffer, 0, bytesRead );
}
}
public static byte[] ReadBytesFromFile( string sourcePath )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( sourcePath ) )
{
AJC.CallStatic( "ReadFromSAFEntry", Context, sourcePath, TemporaryFilePath );
byte[] result = File.ReadAllBytes( TemporaryFilePath );
File.Delete( TemporaryFilePath );
return result;
}
#endif
return File.ReadAllBytes( sourcePath );
}
public static string ReadTextFromFile( string sourcePath )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( sourcePath ) )
{
AJC.CallStatic( "ReadFromSAFEntry", Context, sourcePath, TemporaryFilePath );
string result = File.ReadAllText( TemporaryFilePath );
File.Delete( TemporaryFilePath );
return result;
}
#endif
return File.ReadAllText( sourcePath );
}
public static void CopyFile( string sourcePath, string destinationPath )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw file paths are handled on the native-side
{
AJC.CallStatic( "CopyFile", Context, sourcePath, destinationPath, false );
return;
}
#endif
File.Copy( sourcePath, destinationPath, true );
}
public static void CopyDirectory( string sourcePath, string destinationPath )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw directory paths are handled on the native-side
{
AJC.CallStatic( "CopyDirectory", Context, sourcePath, destinationPath, false );
return;
}
#endif
CopyDirectoryRecursively( new DirectoryInfo( sourcePath ), destinationPath );
}
private static void CopyDirectoryRecursively( DirectoryInfo sourceDirectory, string destinationPath )
{
Directory.CreateDirectory( destinationPath );
FileInfo[] files = sourceDirectory.GetFiles();
for( int i = 0; i < files.Length; i++ )
files[i].CopyTo( Path.Combine( destinationPath, files[i].Name ), true );
DirectoryInfo[] subDirectories = sourceDirectory.GetDirectories();
for( int i = 0; i < subDirectories.Length; i++ )
CopyDirectoryRecursively( subDirectories[i], Path.Combine( destinationPath, subDirectories[i].Name ) );
}
public static void MoveFile( string sourcePath, string destinationPath )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw file paths are handled on the native-side
{
AJC.CallStatic( "CopyFile", Context, sourcePath, destinationPath, true );
return;
}
#endif
File.Move( sourcePath, destinationPath );
}
public static void MoveDirectory( string sourcePath, string destinationPath )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAF ) // No need to use ShouldUseSAFForPath because both SAF paths and raw directory paths are handled on the native-side
{
AJC.CallStatic( "CopyDirectory", Context, sourcePath, destinationPath, true );
return;
}
#endif
Directory.Move( sourcePath, destinationPath );
}
public static string RenameFile( string path, string newName )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<string>( "RenameSAFEntry", Context, path, newName );
#endif
string newPath = Path.Combine( Path.GetDirectoryName( path ), newName );
File.Move( path, newPath );
return newPath;
}
public static string RenameDirectory( string path, string newName )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<string>( "RenameSAFEntry", Context, path, newName );
#endif
string newPath = Path.Combine( new DirectoryInfo( path ).Parent.FullName, newName );
Directory.Move( path, newPath );
return newPath;
}
public static void DeleteFile( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
{
AJC.CallStatic<bool>( "DeleteSAFEntry", Context, path );
return;
}
#endif
File.Delete( path );
}
public static void DeleteDirectory( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
{
AJC.CallStatic<bool>( "DeleteSAFEntry", Context, path );
return;
}
#endif
Directory.Delete( path, true );
}
public static string GetFilename( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<string>( "SAFEntryName", Context, path );
#endif
return Path.GetFileName( path );
}
public static long GetFilesize( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
if( ShouldUseSAFForPath( path ) )
return AJC.CallStatic<long>( "SAFEntrySize", Context, path );
#endif
return new FileInfo( path ).Length;
}
public static System.DateTime GetLastModifiedDate( string path )
{
#if !UNITY_EDITOR && UNITY_ANDROID
// Credit: https://stackoverflow.com/a/28504416/2373034
if( ShouldUseSAFForPath( path ) )
return new System.DateTime( 1970, 1, 1, 0, 0, 0 ).AddMilliseconds( AJC.CallStatic<long>( "SAFEntryLastModified", Context, path ) );
#endif
return new FileInfo( path ).LastWriteTime;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2370e7a82ec4087499ebf7efa149e9eb
timeCreated: 1570919647
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,238 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace SimpleFileBrowser
{
public class FileBrowserItem : ListItem, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler
#if UNITY_EDITOR || ( !UNITY_ANDROID && !UNITY_IOS )
, IPointerEnterHandler, IPointerExitHandler
#endif
{
#region Constants
private const float DOUBLE_CLICK_TIME = 0.5f;
private const float TOGGLE_MULTI_SELECTION_HOLD_TIME = 0.5f;
#endregion
#region Variables
protected FileBrowser fileBrowser;
#pragma warning disable 0649
[SerializeField]
private Image background;
[SerializeField]
private Image icon;
public Image Icon { get { return icon; } }
[SerializeField]
private Image multiSelectionToggle;
[SerializeField]
private Text nameText;
#pragma warning restore 0649
#pragma warning disable 0414
private bool isSelected, isHidden;
#pragma warning restore 0414
private UISkin skin;
private float pressTime = Mathf.Infinity;
private float prevClickTime;
#endregion
#region Properties
private RectTransform m_transform;
public RectTransform TransformComponent
{
get
{
if( m_transform == null )
m_transform = (RectTransform) transform;
return m_transform;
}
}
public string Name { get { return nameText.text; } }
public bool IsDirectory { get; private set; }
#endregion
#region Initialization Functions
public void SetFileBrowser( FileBrowser fileBrowser, UISkin skin )
{
this.fileBrowser = fileBrowser;
OnSkinRefreshed( skin, false );
}
public void SetFile( Sprite icon, string name, bool isDirectory )
{
this.icon.sprite = icon;
nameText.text = name;
IsDirectory = isDirectory;
}
#endregion
#region Messages
private void Update()
{
if( fileBrowser.AllowMultiSelection && Time.realtimeSinceStartup - pressTime >= TOGGLE_MULTI_SELECTION_HOLD_TIME )
{
// Item is held for a while
pressTime = Mathf.Infinity;
fileBrowser.OnItemHeld( this );
}
}
#endregion
#region Pointer Events
public void OnPointerClick( PointerEventData eventData )
{
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL || UNITY_WSA || UNITY_WSA_10_0
if( eventData.button == PointerEventData.InputButton.Middle )
return;
else if( eventData.button == PointerEventData.InputButton.Right )
{
// First, select the item
if( !isSelected )
{
prevClickTime = 0f;
fileBrowser.OnItemSelected( this, false );
}
// Then, show the context menu
fileBrowser.OnContextMenuTriggered( eventData.position );
return;
}
#endif
if( Time.realtimeSinceStartup - prevClickTime < DOUBLE_CLICK_TIME )
{
prevClickTime = 0f;
fileBrowser.OnItemSelected( this, true );
}
else
{
prevClickTime = Time.realtimeSinceStartup;
fileBrowser.OnItemSelected( this, false );
}
}
public void OnPointerDown( PointerEventData eventData )
{
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL || UNITY_WSA || UNITY_WSA_10_0
if( eventData.button != PointerEventData.InputButton.Left )
return;
#endif
pressTime = Time.realtimeSinceStartup;
}
public void OnPointerUp( PointerEventData eventData )
{
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL || UNITY_WSA || UNITY_WSA_10_0
if( eventData.button != PointerEventData.InputButton.Left )
return;
#endif
if( pressTime != Mathf.Infinity )
pressTime = Mathf.Infinity;
else if( fileBrowser.MultiSelectionToggleSelectionMode )
{
// We have activated MultiSelectionToggleSelectionMode with this press, processing the click would result in
// deselecting this item since its selected state would be toggled
eventData.eligibleForClick = false;
}
}
#if UNITY_EDITOR || ( !UNITY_ANDROID && !UNITY_IOS )
public void OnPointerEnter( PointerEventData eventData )
{
if( !isSelected )
background.color = skin.FileHoveredBackgroundColor;
}
#endif
#if UNITY_EDITOR || ( !UNITY_ANDROID && !UNITY_IOS )
public void OnPointerExit( PointerEventData eventData )
{
if( !isSelected )
background.color = ( Position % 2 ) == 0 ? skin.FileNormalBackgroundColor : skin.FileAlternatingBackgroundColor;
}
#endif
#endregion
#region Other Events
public void SetSelected( bool isSelected )
{
this.isSelected = isSelected;
background.color = isSelected ? skin.FileSelectedBackgroundColor : ( ( Position % 2 ) == 0 ? skin.FileNormalBackgroundColor : skin.FileAlternatingBackgroundColor );
nameText.color = isSelected ? skin.FileSelectedTextColor : skin.FileNormalTextColor;
if( isHidden )
{
Color c = nameText.color;
c.a = 0.55f;
nameText.color = c;
}
if( multiSelectionToggle ) // Quick links don't have multi-selection toggle
{
// Don't show multi-selection toggle for folders in file selection mode
if( fileBrowser.MultiSelectionToggleSelectionMode && ( !IsDirectory || fileBrowser.PickerMode != FileBrowser.PickMode.Files ) )
{
if( !multiSelectionToggle.gameObject.activeSelf )
{
multiSelectionToggle.gameObject.SetActive( true );
Vector2 shiftAmount = new Vector2( multiSelectionToggle.rectTransform.sizeDelta.x, 0f );
icon.rectTransform.anchoredPosition += shiftAmount;
nameText.rectTransform.anchoredPosition += shiftAmount;
}
multiSelectionToggle.sprite = isSelected ? skin.FileMultiSelectionToggleOnIcon : skin.FileMultiSelectionToggleOffIcon;
}
else if( multiSelectionToggle.gameObject.activeSelf )
{
multiSelectionToggle.gameObject.SetActive( false );
Vector2 shiftAmount = new Vector2( -multiSelectionToggle.rectTransform.sizeDelta.x, 0f );
icon.rectTransform.anchoredPosition += shiftAmount;
nameText.rectTransform.anchoredPosition += shiftAmount;
// Clicking a file shortly after disabling MultiSelectionToggleSelectionMode does nothing, this workaround fixes that issue
prevClickTime = 0f;
}
}
}
public void SetHidden( bool isHidden )
{
this.isHidden = isHidden;
Color c = icon.color;
c.a = isHidden ? 0.5f : 1f;
icon.color = c;
c = nameText.color;
c.a = isHidden ? 0.55f : ( isSelected ? skin.FileSelectedTextColor.a : skin.FileNormalTextColor.a );
nameText.color = c;
}
public void OnSkinRefreshed( UISkin skin, bool isInitialized = true )
{
this.skin = skin;
TransformComponent.sizeDelta = new Vector2( TransformComponent.sizeDelta.x, skin.FileHeight );
skin.ApplyTo( nameText, isSelected ? skin.FileSelectedTextColor : skin.FileNormalTextColor );
icon.rectTransform.sizeDelta = new Vector2( icon.rectTransform.sizeDelta.x, -skin.FileIconsPadding );
if( isInitialized )
SetSelected( isSelected );
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b5f1b2825c50f7b4d9be146ab2137bff
timeCreated: 1479417850
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
using UnityEngine;
using UnityEngine.EventSystems;
namespace SimpleFileBrowser
{
public class FileBrowserMovement : MonoBehaviour
{
#region Variables
#pragma warning disable 0649
private FileBrowser fileBrowser;
private RectTransform canvasTR;
private Camera canvasCam;
[SerializeField]
private RectTransform window;
[SerializeField]
private RecycledListView listView;
#pragma warning restore 0649
private Vector2 initialTouchPos = Vector2.zero;
private Vector2 initialAnchoredPos, initialSizeDelta;
#endregion
#region Initialization Functions
public void Initialize( FileBrowser fileBrowser )
{
this.fileBrowser = fileBrowser;
canvasTR = fileBrowser.GetComponent<RectTransform>();
}
#endregion
#region Pointer Events
public void OnDragStarted( BaseEventData data )
{
PointerEventData pointer = (PointerEventData) data;
canvasCam = pointer.pressEventCamera;
RectTransformUtility.ScreenPointToLocalPointInRectangle( window, pointer.pressPosition, canvasCam, out initialTouchPos );
}
public void OnDrag( BaseEventData data )
{
PointerEventData pointer = (PointerEventData) data;
Vector2 touchPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle( window, pointer.position, canvasCam, out touchPos );
window.anchoredPosition += touchPos - initialTouchPos;
}
public void OnEndDrag( BaseEventData data )
{
fileBrowser.EnsureWindowIsWithinBounds();
}
public void OnResizeStarted( BaseEventData data )
{
PointerEventData pointer = (PointerEventData) data;
canvasCam = pointer.pressEventCamera;
initialAnchoredPos = window.anchoredPosition;
initialSizeDelta = window.sizeDelta;
RectTransformUtility.ScreenPointToLocalPointInRectangle( canvasTR, pointer.pressPosition, canvasCam, out initialTouchPos );
}
public void OnResize( BaseEventData data )
{
PointerEventData pointer = (PointerEventData) data;
Vector2 touchPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle( canvasTR, pointer.position, canvasCam, out touchPos );
Vector2 delta = touchPos - initialTouchPos;
Vector2 newSize = initialSizeDelta + new Vector2( delta.x, -delta.y );
Vector2 canvasSize = canvasTR.sizeDelta;
if( newSize.x < fileBrowser.minWidth ) newSize.x = fileBrowser.minWidth;
if( newSize.y < fileBrowser.minHeight ) newSize.y = fileBrowser.minHeight;
if( newSize.x > canvasSize.x ) newSize.x = canvasSize.x;
if( newSize.y > canvasSize.y ) newSize.y = canvasSize.y;
newSize.x = (int) newSize.x;
newSize.y = (int) newSize.y;
delta = newSize - initialSizeDelta;
window.anchoredPosition = initialAnchoredPos + new Vector2( delta.x * 0.5f, delta.y * -0.5f );
if( window.sizeDelta != newSize )
{
window.sizeDelta = newSize;
fileBrowser.OnWindowDimensionsChanged( newSize );
}
listView.OnViewportDimensionsChanged();
}
public void OnEndResize( BaseEventData data )
{
fileBrowser.EnsureWindowIsWithinBounds();
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 46d41d79fe7c3d44ca846b4f3d81a476
timeCreated: 1479486534
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
using UnityEngine;
namespace SimpleFileBrowser
{
public class FileBrowserQuickLink : FileBrowserItem
{
#region Properties
private string m_targetPath;
public string TargetPath { get { return m_targetPath; } }
#endregion
#region Initialization Functions
public void SetQuickLink( Sprite icon, string name, string targetPath )
{
SetFile( icon, name, true );
m_targetPath = targetPath;
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1f277f5418eabf94cad94208055878af
timeCreated: 1479417850
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,79 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace SimpleFileBrowser
{
public class FileBrowserRenamedItem : MonoBehaviour
{
public delegate void OnRenameCompleted( string filename );
#pragma warning disable 0649
[SerializeField]
private Image background;
[SerializeField]
private Image icon;
[SerializeField]
private InputField nameInputField;
public InputField InputField { get { return nameInputField; } }
#pragma warning restore 0649
private OnRenameCompleted onRenameCompleted;
private RectTransform m_transform;
public RectTransform TransformComponent
{
get
{
if( m_transform == null )
m_transform = (RectTransform) transform;
return m_transform;
}
}
public void Show( string initialFilename, Color backgroundColor, Sprite icon, OnRenameCompleted onRenameCompleted )
{
background.color = backgroundColor;
this.icon.sprite = icon;
this.onRenameCompleted = onRenameCompleted;
transform.SetAsLastSibling();
gameObject.SetActive( true );
nameInputField.text = initialFilename;
nameInputField.ActivateInputField();
}
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
private void LateUpdate()
{
// Don't allow scrolling with mouse wheel while renaming a file or creating a folder
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
if( Mouse.current != null && Mouse.current.scroll.ReadValue().y != 0f )
#else
if( Input.mouseScrollDelta.y != 0f )
#endif
nameInputField.DeactivateInputField();
}
#endif
public void OnInputFieldEndEdit( string filename )
{
gameObject.SetActive( false );
// If we don't deselect the InputField manually, FileBrowser's keyboard shortcuts
// no longer work until user clicks on a UI element and thus, deselects the InputField
if( EventSystem.current && !EventSystem.current.alreadySelecting && EventSystem.current.currentSelectedGameObject == nameInputField.gameObject )
EventSystem.current.SetSelectedGameObject( null );
if( onRenameCompleted != null )
onRenameCompleted( filename );
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c7397ff7ae1ba4c47b6dfd3c84936584
timeCreated: 1603812277
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
using UnityEngine;
using UnityEngine.UI;
namespace SimpleFileBrowser
{
// Credit: http://answers.unity.com/answers/1157876/view.html
[RequireComponent( typeof( CanvasRenderer ) )]
public class NonDrawingGraphic : Graphic
{
public override void SetMaterialDirty() { return; }
public override void SetVerticesDirty() { return; }
protected override void OnPopulateMesh( VertexHelper vh )
{
vh.Clear();
return;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b4fd8cdb8c068dd4bb48c415877496ba
timeCreated: 1603794018
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: dec11495f4b8cef49b7a3b4b06f094c3
folderAsset: yes
timeCreated: 1485706514
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
namespace SimpleFileBrowser
{
public delegate void OnItemClickedHandler( ListItem item );
public interface IListViewAdapter
{
OnItemClickedHandler OnItemClicked { get; set; }
int Count { get; }
float ItemHeight { get; }
ListItem CreateItem();
void SetItemContent( ListItem item );
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 08e51b912648ace4784ebe20fc6cc961
timeCreated: 1485706575
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
using UnityEngine;
namespace SimpleFileBrowser
{
[RequireComponent( typeof( RectTransform ) )]
public class ListItem : MonoBehaviour
{
public object Tag { get; set; }
public int Position { get; set; }
private IListViewAdapter adapter;
internal void SetAdapter( IListViewAdapter listView )
{
this.adapter = listView;
}
public void OnClick()
{
if( adapter.OnItemClicked != null )
adapter.OnItemClicked( this );
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9c3e7249b2cb96446a7ccfbed51aab81
timeCreated: 1485706535
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,252 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace SimpleFileBrowser
{
[RequireComponent( typeof( ScrollRect ) )]
public class RecycledListView : MonoBehaviour
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
, IPointerClickHandler
#endif
{
#pragma warning disable 0649
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
[SerializeField]
private FileBrowser fileBrowser;
#endif
// Cached components
[SerializeField]
private RectTransform viewportTransform;
[SerializeField]
private RectTransform contentTransform;
#pragma warning restore 0649
private float itemHeight, _1OverItemHeight;
private float viewportHeight;
private readonly Dictionary<int, ListItem> items = new Dictionary<int, ListItem>();
private readonly Stack<ListItem> pooledItems = new Stack<ListItem>();
IListViewAdapter adapter = null;
// Current indices of items shown on screen
private int currentTopIndex = -1, currentBottomIndex = -1;
private void Start()
{
viewportHeight = viewportTransform.rect.height;
GetComponent<ScrollRect>().onValueChanged.AddListener( ( pos ) => UpdateItemsInTheList() );
}
public void SetAdapter( IListViewAdapter adapter )
{
this.adapter = adapter;
itemHeight = adapter.ItemHeight;
_1OverItemHeight = 1f / itemHeight;
}
public void OnSkinRefreshed()
{
if( currentTopIndex >= 0 )
{
DestroyItemsBetweenIndices( currentTopIndex, currentBottomIndex );
currentTopIndex = currentBottomIndex = -1;
}
itemHeight = adapter.ItemHeight;
_1OverItemHeight = 1f / itemHeight;
UpdateList();
}
// Update the list
public void UpdateList()
{
float newHeight = Mathf.Max( 1f, adapter.Count * itemHeight );
contentTransform.sizeDelta = new Vector2( 0f, newHeight );
viewportHeight = viewportTransform.rect.height;
UpdateItemsInTheList( true );
}
// Window is resized, update the list
public void OnViewportDimensionsChanged()
{
viewportHeight = viewportTransform.rect.height;
UpdateItemsInTheList();
}
// Calculate the indices of items to show
private void UpdateItemsInTheList( bool updateAllVisibleItems = false )
{
// If there is at least one item to show
if( adapter.Count > 0 )
{
float contentPos = contentTransform.anchoredPosition.y - 1f;
int newTopIndex = (int) ( contentPos * _1OverItemHeight );
int newBottomIndex = (int) ( ( contentPos + viewportHeight + 2f ) * _1OverItemHeight );
if( newTopIndex < 0 )
newTopIndex = 0;
if( newBottomIndex > adapter.Count - 1 )
newBottomIndex = adapter.Count - 1;
if( currentTopIndex == -1 )
{
// There are no active items
updateAllVisibleItems = true;
currentTopIndex = newTopIndex;
currentBottomIndex = newBottomIndex;
CreateItemsBetweenIndices( newTopIndex, newBottomIndex );
}
else
{
// There are some active items
if( newBottomIndex < currentTopIndex || newTopIndex > currentBottomIndex )
{
// If user scrolled a lot such that, none of the items are now within
// the bounds of the scroll view, pool all the previous items and create
// new items for the new list of visible entries
updateAllVisibleItems = true;
DestroyItemsBetweenIndices( currentTopIndex, currentBottomIndex );
CreateItemsBetweenIndices( newTopIndex, newBottomIndex );
}
else
{
// User did not scroll a lot such that, some items are are still within
// the bounds of the scroll view. Don't destroy them but update their content,
// if necessary
if( newTopIndex > currentTopIndex )
{
DestroyItemsBetweenIndices( currentTopIndex, newTopIndex - 1 );
}
if( newBottomIndex < currentBottomIndex )
{
DestroyItemsBetweenIndices( newBottomIndex + 1, currentBottomIndex );
}
if( newTopIndex < currentTopIndex )
{
CreateItemsBetweenIndices( newTopIndex, currentTopIndex - 1 );
// If it is not necessary to update all the items,
// then just update the newly created items. Otherwise,
// wait for the major update
if( !updateAllVisibleItems )
{
UpdateItemContentsBetweenIndices( newTopIndex, currentTopIndex - 1 );
}
}
if( newBottomIndex > currentBottomIndex )
{
CreateItemsBetweenIndices( currentBottomIndex + 1, newBottomIndex );
// If it is not necessary to update all the items,
// then just update the newly created items. Otherwise,
// wait for the major update
if( !updateAllVisibleItems )
{
UpdateItemContentsBetweenIndices( currentBottomIndex + 1, newBottomIndex );
}
}
}
currentTopIndex = newTopIndex;
currentBottomIndex = newBottomIndex;
}
if( updateAllVisibleItems )
{
// Update all the items
UpdateItemContentsBetweenIndices( currentTopIndex, currentBottomIndex );
}
}
else if( currentTopIndex != -1 )
{
// There is nothing to show but some items are still visible; pool them
DestroyItemsBetweenIndices( currentTopIndex, currentBottomIndex );
currentTopIndex = -1;
}
}
private void CreateItemsBetweenIndices( int topIndex, int bottomIndex )
{
for( int i = topIndex; i <= bottomIndex; i++ )
{
CreateItemAtIndex( i );
}
}
// Create (or unpool) an item
private void CreateItemAtIndex( int index )
{
ListItem item;
if( pooledItems.Count > 0 )
{
item = pooledItems.Pop();
item.gameObject.SetActive( true );
}
else
{
item = adapter.CreateItem();
item.transform.SetParent( contentTransform, false );
item.SetAdapter( adapter );
}
// Reposition the item
( (RectTransform) item.transform ).anchoredPosition = new Vector2( 1f, -index * itemHeight );
// To access this item easily in the future, add it to the dictionary
items[index] = item;
}
private void DestroyItemsBetweenIndices( int topIndex, int bottomIndex )
{
for( int i = topIndex; i <= bottomIndex; i++ )
{
ListItem item = items[i];
item.gameObject.SetActive( false );
pooledItems.Push( item );
}
}
private void UpdateItemContentsBetweenIndices( int topIndex, int bottomIndex )
{
for( int i = topIndex; i <= bottomIndex; i++ )
{
ListItem item = items[i];
item.Position = i;
adapter.SetItemContent( item );
}
}
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
// When free space inside ScrollRect is clicked:
// Left click: deselect selected file(s)
// Right click: show context menu
public void OnPointerClick( PointerEventData eventData )
{
if( eventData.button == PointerEventData.InputButton.Left )
fileBrowser.DeselectAllFiles();
else if( eventData.button == PointerEventData.InputButton.Right )
fileBrowser.OnContextMenuTriggered( eventData.position );
}
#endif
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 87ad67b4806678e40a492e337338760b
timeCreated: 1485620000
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,651 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace SimpleFileBrowser
{
[Serializable]
public struct FiletypeIcon
{
public string extension;
public Sprite icon;
}
[CreateAssetMenu( fileName = "UI Skin", menuName = "yasirkula/SimpleFileBrowser/UI Skin", order = 111 )]
public class UISkin : ScriptableObject
{
private int m_version = 0;
public int Version { get { return m_version; } }
[ContextMenu( "Refresh UI" )]
private void Invalidate()
{
m_version = UnityEngine.Random.Range( int.MinValue / 2, int.MaxValue / 2 );
initializedFiletypeIcons = false;
}
#if UNITY_EDITOR
protected virtual void OnValidate()
{
// Refresh all UIs that use this skin
Invalidate();
}
#endif
#pragma warning disable 0649
[Header( "General" )]
[SerializeField]
private Font m_font;
public Font Font
{
get { return m_font; }
set { if( m_font != value ) { m_font = value; m_version++; } }
}
[SerializeField]
private int m_fontSize = 14;
public int FontSize
{
get { return m_fontSize; }
set { if( m_fontSize != value ) { m_fontSize = value; m_version++; } }
}
[Header( "File Browser Window" )]
[SerializeField]
private Color m_windowColor = Color.grey;
public Color WindowColor
{
get { return m_windowColor; }
set { if( m_windowColor != value ) { m_windowColor = value; m_version++; } }
}
[SerializeField]
private Color m_filesListColor = Color.white;
public Color FilesListColor
{
get { return m_filesListColor; }
set { if( m_filesListColor != value ) { m_filesListColor = value; m_version++; } }
}
[SerializeField]
private Color m_filesVerticalSeparatorColor = Color.grey;
public Color FilesVerticalSeparatorColor
{
get { return m_filesVerticalSeparatorColor; }
set { if( m_filesVerticalSeparatorColor != value ) { m_filesVerticalSeparatorColor = value; m_version++; } }
}
[SerializeField]
private Color m_titleBackgroundColor = Color.black;
public Color TitleBackgroundColor
{
get { return m_titleBackgroundColor; }
set { if( m_titleBackgroundColor != value ) { m_titleBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_titleTextColor = Color.white;
public Color TitleTextColor
{
get { return m_titleTextColor; }
set { if( m_titleTextColor != value ) { m_titleTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_windowResizeGizmoColor = Color.black;
public Color WindowResizeGizmoColor
{
get { return m_windowResizeGizmoColor; }
set { if( m_windowResizeGizmoColor != value ) { m_windowResizeGizmoColor = value; m_version++; } }
}
[SerializeField]
private Color m_headerButtonsColor = Color.white;
public Color HeaderButtonsColor
{
get { return m_headerButtonsColor; }
set { if( m_headerButtonsColor != value ) { m_headerButtonsColor = value; m_version++; } }
}
[SerializeField]
private Sprite m_windowResizeGizmo;
public Sprite WindowResizeGizmo
{
get { return m_windowResizeGizmo; }
set { if( m_windowResizeGizmo != value ) { m_windowResizeGizmo = value; m_version++; } }
}
[SerializeField]
private Sprite m_headerBackButton;
public Sprite HeaderBackButton
{
get { return m_headerBackButton; }
set { if( m_headerBackButton != value ) { m_headerBackButton = value; m_version++; } }
}
[SerializeField]
private Sprite m_headerForwardButton;
public Sprite HeaderForwardButton
{
get { return m_headerForwardButton; }
set { if( m_headerForwardButton != value ) { m_headerForwardButton = value; m_version++; } }
}
[SerializeField]
private Sprite m_headerUpButton;
public Sprite HeaderUpButton
{
get { return m_headerUpButton; }
set { if( m_headerUpButton != value ) { m_headerUpButton = value; m_version++; } }
}
[SerializeField]
private Sprite m_headerContextMenuButton;
public Sprite HeaderContextMenuButton
{
get { return m_headerContextMenuButton; }
set { if( m_headerContextMenuButton != value ) { m_headerContextMenuButton = value; m_version++; } }
}
[Header( "Input Fields" )]
[SerializeField]
private Color m_inputFieldNormalBackgroundColor = Color.white;
public Color InputFieldNormalBackgroundColor
{
get { return m_inputFieldNormalBackgroundColor; }
set { if( m_inputFieldNormalBackgroundColor != value ) { m_inputFieldNormalBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_inputFieldInvalidBackgroundColor = Color.red;
public Color InputFieldInvalidBackgroundColor
{
get { return m_inputFieldInvalidBackgroundColor; }
set { if( m_inputFieldInvalidBackgroundColor != value ) { m_inputFieldInvalidBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_inputFieldTextColor = Color.black;
public Color InputFieldTextColor
{
get { return m_inputFieldTextColor; }
set { if( m_inputFieldTextColor != value ) { m_inputFieldTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_inputFieldPlaceholderTextColor = new Color( 0f, 0f, 0f, 0.5f );
public Color InputFieldPlaceholderTextColor
{
get { return m_inputFieldPlaceholderTextColor; }
set { if( m_inputFieldPlaceholderTextColor != value ) { m_inputFieldPlaceholderTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_inputFieldSelectedTextColor = Color.blue;
public Color InputFieldSelectedTextColor
{
get { return m_inputFieldSelectedTextColor; }
set { if( m_inputFieldSelectedTextColor != value ) { m_inputFieldSelectedTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_inputFieldCaretColor = Color.black;
public Color InputFieldCaretColor
{
get { return m_inputFieldCaretColor; }
set { if( m_inputFieldCaretColor != value ) { m_inputFieldCaretColor = value; m_version++; } }
}
[SerializeField]
private Sprite m_inputFieldBackground;
public Sprite InputFieldBackground
{
get { return m_inputFieldBackground; }
set { if( m_inputFieldBackground != value ) { m_inputFieldBackground = value; m_version++; } }
}
[Header( "Buttons" )]
[SerializeField]
private Color m_buttonColor = Color.white;
public Color ButtonColor
{
get { return m_buttonColor; }
set { if( m_buttonColor != value ) { m_buttonColor = value; m_version++; } }
}
[SerializeField]
private Color m_buttonTextColor = Color.black;
public Color ButtonTextColor
{
get { return m_buttonTextColor; }
set { if( m_buttonTextColor != value ) { m_buttonTextColor = value; m_version++; } }
}
[SerializeField]
private Sprite m_buttonBackground;
public Sprite ButtonBackground
{
get { return m_buttonBackground; }
set { if( m_buttonBackground != value ) { m_buttonBackground = value; m_version++; } }
}
[Header( "Dropdowns" )]
[SerializeField]
private Color m_dropdownColor = Color.white;
public Color DropdownColor
{
get { return m_dropdownColor; }
set { if( m_dropdownColor != value ) { m_dropdownColor = value; m_version++; } }
}
[SerializeField]
private Color m_dropdownTextColor = Color.black;
public Color DropdownTextColor
{
get { return m_dropdownTextColor; }
set { if( m_dropdownTextColor != value ) { m_dropdownTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_dropdownArrowColor = Color.black;
public Color DropdownArrowColor
{
get { return m_dropdownArrowColor; }
set { if( m_dropdownArrowColor != value ) { m_dropdownArrowColor = value; m_version++; } }
}
[SerializeField]
private Color m_dropdownCheckmarkColor = Color.black;
public Color DropdownCheckmarkColor
{
get { return m_dropdownCheckmarkColor; }
set { if( m_dropdownCheckmarkColor != value ) { m_dropdownCheckmarkColor = value; m_version++; } }
}
[SerializeField]
private Sprite m_dropdownBackground;
public Sprite DropdownBackground
{
get { return m_dropdownBackground; }
set { if( m_dropdownBackground != value ) { m_dropdownBackground = value; m_version++; } }
}
[SerializeField]
private Sprite m_dropdownArrow;
public Sprite DropdownArrow
{
get { return m_dropdownArrow; }
set { if( m_dropdownArrow != value ) { m_dropdownArrow = value; m_version++; } }
}
[SerializeField]
private Sprite m_dropdownCheckmark;
public Sprite DropdownCheckmark
{
get { return m_dropdownCheckmark; }
set { if( m_dropdownCheckmark != value ) { m_dropdownCheckmark = value; m_version++; } }
}
[Header( "Toggles" )]
[SerializeField]
private Color m_toggleColor = Color.white;
public Color ToggleColor
{
get { return m_toggleColor; }
set { if( m_toggleColor != value ) { m_toggleColor = value; m_version++; } }
}
[SerializeField]
private Color m_toggleTextColor = Color.black;
public Color ToggleTextColor
{
get { return m_toggleTextColor; }
set { if( m_toggleTextColor != value ) { m_toggleTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_toggleCheckmarkColor = Color.black;
public Color ToggleCheckmarkColor
{
get { return m_toggleCheckmarkColor; }
set { if( m_toggleCheckmarkColor != value ) { m_toggleCheckmarkColor = value; m_version++; } }
}
[SerializeField]
private Sprite m_toggleBackground;
public Sprite ToggleBackground
{
get { return m_toggleBackground; }
set { if( m_toggleBackground != value ) { m_toggleBackground = value; m_version++; } }
}
[SerializeField]
private Sprite m_toggleCheckmark;
public Sprite ToggleCheckmark
{
get { return m_toggleCheckmark; }
set { if( m_toggleCheckmark != value ) { m_toggleCheckmark = value; m_version++; } }
}
[Header( "Scrollbars" )]
[SerializeField]
private Color m_scrollbarBackgroundColor = Color.grey;
public Color ScrollbarBackgroundColor
{
get { return m_scrollbarBackgroundColor; }
set { if( m_scrollbarBackgroundColor != value ) { m_scrollbarBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_scrollbarColor = Color.black;
public Color ScrollbarColor
{
get { return m_scrollbarColor; }
set { if( m_scrollbarColor != value ) { m_scrollbarColor = value; m_version++; } }
}
[Header( "Files" )]
[SerializeField]
private float m_fileHeight = 30f;
public float FileHeight
{
get { return m_fileHeight; }
set { if( m_fileHeight != value ) { m_fileHeight = value; m_version++; } }
}
[SerializeField]
private float m_fileIconsPadding = 6f;
public float FileIconsPadding
{
get { return m_fileIconsPadding; }
set { if( m_fileIconsPadding != value ) { m_fileIconsPadding = value; m_version++; } }
}
[SerializeField]
private Color m_fileNormalBackgroundColor = Color.clear;
public Color FileNormalBackgroundColor
{
get { return m_fileNormalBackgroundColor; }
set { if( m_fileNormalBackgroundColor != value ) { m_fileNormalBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_fileAlternatingBackgroundColor = Color.clear;
public Color FileAlternatingBackgroundColor
{
get { return m_fileAlternatingBackgroundColor; }
set { if( m_fileAlternatingBackgroundColor != value ) { m_fileAlternatingBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_fileHoveredBackgroundColor = Color.cyan;
public Color FileHoveredBackgroundColor
{
get { return m_fileHoveredBackgroundColor; }
set { if( m_fileHoveredBackgroundColor != value ) { m_fileHoveredBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_fileSelectedBackgroundColor = Color.blue;
public Color FileSelectedBackgroundColor
{
get { return m_fileSelectedBackgroundColor; }
set { if( m_fileSelectedBackgroundColor != value ) { m_fileSelectedBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_fileNormalTextColor = Color.black;
public Color FileNormalTextColor
{
get { return m_fileNormalTextColor; }
set { if( m_fileNormalTextColor != value ) { m_fileNormalTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_fileSelectedTextColor = Color.black;
public Color FileSelectedTextColor
{
get { return m_fileSelectedTextColor; }
set { if( m_fileSelectedTextColor != value ) { m_fileSelectedTextColor = value; m_version++; } }
}
[Header( "File Icons" )]
[SerializeField]
private Sprite m_folderIcon;
public Sprite FolderIcon
{
get { return m_folderIcon; }
set { if( m_folderIcon != value ) { m_folderIcon = value; m_version++; } }
}
[SerializeField]
private Sprite m_driveIcon;
public Sprite DriveIcon
{
get { return m_driveIcon; }
set { if( m_driveIcon != value ) { m_driveIcon = value; m_version++; } }
}
[SerializeField]
private Sprite m_defaultFileIcon;
public Sprite DefaultFileIcon
{
get { return m_defaultFileIcon; }
set { if( m_defaultFileIcon != value ) { m_defaultFileIcon = value; m_version++; } }
}
[SerializeField]
private FiletypeIcon[] m_filetypeIcons;
public FiletypeIcon[] FiletypeIcons
{
get { return m_filetypeIcons; }
set
{
if( m_filetypeIcons != value )
{
m_filetypeIcons = value;
initializedFiletypeIcons = false;
m_version++;
}
}
}
[NonSerialized] // Never save this value during domain reload (it's sometimes saved even though it's private)
private bool initializedFiletypeIcons = false;
private Dictionary<string, Sprite> filetypeToIcon;
[NonSerialized]
private bool m_allIconExtensionsHaveSingleSuffix = true;
public bool AllIconExtensionsHaveSingleSuffix
{
get
{
if( !initializedFiletypeIcons )
InitializeFiletypeIcons();
return m_allIconExtensionsHaveSingleSuffix;
}
}
[SerializeField]
private Sprite m_fileMultiSelectionToggleOffIcon;
public Sprite FileMultiSelectionToggleOffIcon
{
get { return m_fileMultiSelectionToggleOffIcon; }
set { if( m_fileMultiSelectionToggleOffIcon != value ) { m_fileMultiSelectionToggleOffIcon = value; m_version++; } }
}
[SerializeField]
private Sprite m_fileMultiSelectionToggleOnIcon;
public Sprite FileMultiSelectionToggleOnIcon
{
get { return m_fileMultiSelectionToggleOnIcon; }
set { if( m_fileMultiSelectionToggleOnIcon != value ) { m_fileMultiSelectionToggleOnIcon = value; m_version++; } }
}
[Header( "Context Menu" )]
[SerializeField]
private Color m_contextMenuBackgroundColor = Color.grey;
public Color ContextMenuBackgroundColor
{
get { return m_contextMenuBackgroundColor; }
set { if( m_contextMenuBackgroundColor != value ) { m_contextMenuBackgroundColor = value; m_version++; } }
}
[SerializeField]
private Color m_contextMenuTextColor = Color.black;
public Color ContextMenuTextColor
{
get { return m_contextMenuTextColor; }
set { if( m_contextMenuTextColor != value ) { m_contextMenuTextColor = value; m_version++; } }
}
[SerializeField]
private Color m_contextMenuSeparatorColor = Color.black;
public Color ContextMenuSeparatorColor
{
get { return m_contextMenuSeparatorColor; }
set { if( m_contextMenuSeparatorColor != value ) { m_contextMenuSeparatorColor = value; m_version++; } }
}
[Header( "Popup Panels" )]
[SerializeField, UnityEngine.Serialization.FormerlySerializedAs( "m_deletePanelBackgroundColor" )]
private Color m_popupPanelsBackgroundColor = Color.grey;
public Color PopupPanelsBackgroundColor
{
get { return m_popupPanelsBackgroundColor; }
set { if( m_popupPanelsBackgroundColor != value ) { m_popupPanelsBackgroundColor = value; m_version++; } }
}
[SerializeField, UnityEngine.Serialization.FormerlySerializedAs( "m_deletePanelTextColor" )]
private Color m_popupPanelsTextColor = Color.black;
public Color PopupPanelsTextColor
{
get { return m_popupPanelsTextColor; }
set { if( m_popupPanelsTextColor != value ) { m_popupPanelsTextColor = value; m_version++; } }
}
[SerializeField, UnityEngine.Serialization.FormerlySerializedAs( "m_deletePanelBackground" )]
private Sprite m_popupPanelsBackground;
public Sprite PopupPanelsBackground
{
get { return m_popupPanelsBackground; }
set { if( m_popupPanelsBackground != value ) { m_popupPanelsBackground = value; m_version++; } }
}
#pragma warning restore 0649
public void ApplyTo( Text text, Color textColor )
{
text.color = textColor;
text.font = m_font;
text.fontSize = m_fontSize;
}
public void ApplyTo( InputField inputField )
{
inputField.image.color = m_inputFieldNormalBackgroundColor;
inputField.image.sprite = m_inputFieldBackground;
inputField.selectionColor = m_inputFieldSelectedTextColor;
inputField.caretColor = m_inputFieldCaretColor;
ApplyTo( inputField.textComponent, m_inputFieldTextColor );
if( inputField.placeholder as Text )
ApplyTo( (Text) inputField.placeholder, m_inputFieldPlaceholderTextColor );
}
public void ApplyTo( Button button )
{
button.image.color = m_buttonColor;
button.image.sprite = m_buttonBackground;
ApplyTo( button.GetComponentInChildren<Text>(), m_buttonTextColor );
}
public void ApplyTo( Dropdown dropdown )
{
dropdown.image.color = m_dropdownColor;
dropdown.image.sprite = m_dropdownBackground;
dropdown.template.GetComponent<Image>().color = m_dropdownColor;
Image dropdownArrow = dropdown.transform.Find( "Arrow" ).GetComponent<Image>();
dropdownArrow.color = m_dropdownArrowColor;
dropdownArrow.sprite = m_dropdownArrow;
ApplyTo( dropdown.captionText, m_dropdownTextColor );
ApplyTo( dropdown.itemText, m_dropdownTextColor );
Transform dropdownItem = dropdown.itemText.transform.parent;
dropdownItem.Find( "Item Background" ).GetComponent<Image>().color = m_dropdownColor;
Image dropdownCheckmark = dropdownItem.Find( "Item Checkmark" ).GetComponent<Image>();
dropdownCheckmark.color = m_dropdownCheckmarkColor;
dropdownCheckmark.sprite = m_dropdownCheckmark;
}
public void ApplyTo( Toggle toggle )
{
toggle.image.color = m_toggleColor;
toggle.image.sprite = m_toggleBackground;
toggle.graphic.color = m_toggleCheckmarkColor;
( (Image) toggle.graphic ).sprite = m_toggleCheckmark;
ApplyTo( toggle.GetComponentInChildren<Text>(), m_toggleTextColor );
}
public void ApplyTo( Scrollbar scrollbar )
{
scrollbar.GetComponent<Image>().color = m_scrollbarBackgroundColor;
scrollbar.image.color = m_scrollbarColor;
}
public Sprite GetIconForFileEntry( FileSystemEntry fileInfo, bool extensionMayHaveMultipleSuffixes )
{
if( !initializedFiletypeIcons )
InitializeFiletypeIcons();
Sprite icon;
if( fileInfo.IsDirectory )
return m_folderIcon;
else if( filetypeToIcon.TryGetValue( fileInfo.Extension, out icon ) )
return icon;
else if( extensionMayHaveMultipleSuffixes )
{
for( int i = 0; i < m_filetypeIcons.Length; i++ )
{
if( fileInfo.Extension.EndsWith( m_filetypeIcons[i].extension, StringComparison.Ordinal ) )
{
filetypeToIcon[fileInfo.Extension] = m_filetypeIcons[i].icon;
return m_filetypeIcons[i].icon;
}
}
}
filetypeToIcon[fileInfo.Extension] = m_defaultFileIcon;
return m_defaultFileIcon;
}
private void InitializeFiletypeIcons()
{
initializedFiletypeIcons = true;
if( filetypeToIcon == null )
filetypeToIcon = new Dictionary<string, Sprite>( 128 );
else
filetypeToIcon.Clear();
m_allIconExtensionsHaveSingleSuffix = true;
for( int i = 0; i < m_filetypeIcons.Length; i++ )
{
m_filetypeIcons[i].extension = m_filetypeIcons[i].extension.ToLowerInvariant();
if( m_filetypeIcons[i].extension[0] != '.' )
m_filetypeIcons[i].extension = "." + m_filetypeIcons[i].extension;
filetypeToIcon[m_filetypeIcons[i].extension] = m_filetypeIcons[i].icon;
m_allIconExtensionsHaveSingleSuffix &= ( m_filetypeIcons[i].extension.LastIndexOf( '.' ) == 0 );
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 66bc3ce4885990c40a88f80fe0ad0101
timeCreated: 1634711050
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: