Skip to content

Commit a234c6b

Browse files
committed
- Added context menu that can be opened in 2 ways: a) right clicking a file on standalone platforms or b) clicking the More Options button located at the top-right corner. Context menu has the following buttons:
- Select All (only when multi selection is enabled and More Options button is clicked) - Deselect All (only when more than 1 items are selected and More Options button is clicked) - New Folder (closed #25) - Delete (only when 1 or more items are selected) - Rename (only when 1 item is selected)
1 parent 13798a1 commit a234c6b

15 files changed

+7601
-2491
lines changed

Plugins/SimpleFileBrowser/Resources/SimpleFileBrowserCanvas.prefab

Lines changed: 6816 additions & 2428 deletions
Large diffs are not rendered by default.

Plugins/SimpleFileBrowser/Scripts/FileBrowser.cs

Lines changed: 326 additions & 61 deletions
Large diffs are not rendered by default.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using UnityEngine;
2+
using UnityEngine.UI;
3+
4+
namespace SimpleFileBrowser
5+
{
6+
public class FileBrowserContextMenu : MonoBehaviour
7+
{
8+
#pragma warning disable 0649
9+
[SerializeField]
10+
private FileBrowser fileBrowser;
11+
12+
[SerializeField]
13+
private RectTransform rectTransform;
14+
15+
[SerializeField]
16+
private Button selectAllButton;
17+
[SerializeField]
18+
private Button deselectAllButton;
19+
[SerializeField]
20+
private Button deleteButton;
21+
[SerializeField]
22+
private Button renameButton;
23+
24+
[SerializeField]
25+
private GameObject selectAllButtonSeparator;
26+
27+
[SerializeField]
28+
private float minDistanceToEdges = 10f;
29+
#pragma warning restore 0649
30+
31+
internal void Show( bool selectAllButtonVisible, bool deselectAllButtonVisible, bool deleteButtonVisible, bool renameButtonVisible, Vector2 position, bool isMoreOptionsMenu )
32+
{
33+
selectAllButton.gameObject.SetActive( selectAllButtonVisible );
34+
deselectAllButton.gameObject.SetActive( deselectAllButtonVisible );
35+
deleteButton.gameObject.SetActive( deleteButtonVisible );
36+
renameButton.gameObject.SetActive( renameButtonVisible );
37+
selectAllButtonSeparator.SetActive( !deselectAllButtonVisible );
38+
39+
rectTransform.anchoredPosition = position;
40+
gameObject.SetActive( true );
41+
42+
if( isMoreOptionsMenu )
43+
rectTransform.pivot = Vector2.one;
44+
else
45+
{
46+
// Find the optimal pivot value
47+
LayoutRebuilder.ForceRebuildLayoutImmediate( rectTransform );
48+
49+
Vector2 size = rectTransform.sizeDelta;
50+
Vector2 canvasSize = fileBrowser.rectTransform.sizeDelta;
51+
52+
// Take canvas' Pivot into consideration
53+
Vector2 positionOffset = canvasSize;
54+
positionOffset.Scale( fileBrowser.rectTransform.pivot );
55+
position += positionOffset;
56+
57+
// Try bottom-right corner first
58+
Vector2 cornerPos = position + new Vector2( size.x + minDistanceToEdges, -size.y - minDistanceToEdges );
59+
if( cornerPos.x <= canvasSize.x && cornerPos.y >= 0f )
60+
rectTransform.pivot = new Vector2( 0f, 1f );
61+
else
62+
{
63+
// Try bottom-left corner
64+
cornerPos = position - new Vector2( size.x + minDistanceToEdges, size.y + minDistanceToEdges );
65+
if( cornerPos.x >= 0f && cornerPos.y >= 0f )
66+
rectTransform.pivot = Vector2.one;
67+
else
68+
{
69+
// Try top-right corner
70+
cornerPos = position + new Vector2( size.x + minDistanceToEdges, size.y + minDistanceToEdges );
71+
if( cornerPos.x <= canvasSize.x && cornerPos.y <= canvasSize.y )
72+
rectTransform.pivot = Vector2.zero;
73+
else
74+
{
75+
// Use top-left corner
76+
rectTransform.pivot = new Vector2( 1f, 0f );
77+
}
78+
}
79+
}
80+
}
81+
}
82+
83+
public void Hide()
84+
{
85+
gameObject.SetActive( false );
86+
}
87+
88+
public void OnSelectAllButtonClicked()
89+
{
90+
Hide();
91+
fileBrowser.SelectAllFiles();
92+
}
93+
94+
public void OnDeselectAllButtonClicked()
95+
{
96+
Hide();
97+
fileBrowser.DeselectAllFiles();
98+
}
99+
100+
public void OnCreateFolderButtonClicked()
101+
{
102+
Hide();
103+
fileBrowser.CreateNewFolder();
104+
}
105+
106+
public void OnDeleteButtonClicked()
107+
{
108+
Hide();
109+
fileBrowser.DeleteSelectedFiles();
110+
}
111+
112+
public void OnRenameButtonClicked()
113+
{
114+
Hide();
115+
fileBrowser.RenameSelectedFile();
116+
}
117+
}
118+
}

Plugins/SimpleFileBrowser/Scripts/FileBrowserContextMenu.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using UnityEngine;
2+
using UnityEngine.UI;
3+
4+
namespace SimpleFileBrowser
5+
{
6+
public class FileBrowserDeleteConfirmationPanel : MonoBehaviour
7+
{
8+
public delegate void OnDeletionConfirmed();
9+
10+
#pragma warning disable 0649
11+
[SerializeField]
12+
private GameObject[] deletedItems;
13+
14+
[SerializeField]
15+
private Image[] deletedItemIcons;
16+
17+
[SerializeField]
18+
private Text[] deletedItemNames;
19+
20+
[SerializeField]
21+
private GameObject deletedItemsRest;
22+
23+
[SerializeField]
24+
private Text deletedItemsRestLabel;
25+
26+
[SerializeField]
27+
private RectTransform yesButtonTransform;
28+
29+
[SerializeField]
30+
private RectTransform noButtonTransform;
31+
32+
[SerializeField]
33+
private float narrowScreenWidth = 380f;
34+
#pragma warning restore 0649
35+
36+
private OnDeletionConfirmed onDeletionConfirmed;
37+
38+
internal void Show( Sprite[] icons, string[] filenames, OnDeletionConfirmed onDeletionConfirmed )
39+
{
40+
this.onDeletionConfirmed = onDeletionConfirmed;
41+
42+
for( int i = 0; i < deletedItems.Length; i++ )
43+
deletedItems[i].SetActive( i < icons.Length );
44+
45+
for( int i = 0; i < deletedItems.Length && i < icons.Length; i++ )
46+
{
47+
deletedItemIcons[i].sprite = icons[i];
48+
deletedItemNames[i].text = filenames[i];
49+
}
50+
51+
if( icons.Length > deletedItems.Length )
52+
{
53+
deletedItemsRestLabel.text = string.Concat( "...and ", ( icons.Length - deletedItems.Length ).ToString(), " other" );
54+
deletedItemsRest.SetActive( true );
55+
}
56+
else
57+
deletedItemsRest.SetActive( false );
58+
59+
gameObject.SetActive( true );
60+
}
61+
62+
// Handles responsive user interface
63+
internal void OnCanvasDimensionsChanged( Vector2 size )
64+
{
65+
if( size.x >= narrowScreenWidth )
66+
{
67+
yesButtonTransform.anchorMin = new Vector2( 0.5f, 0f );
68+
yesButtonTransform.anchorMax = new Vector2( 0.75f, 1f );
69+
noButtonTransform.anchorMin = new Vector2( 0.75f, 0f );
70+
}
71+
else
72+
{
73+
yesButtonTransform.anchorMin = Vector2.zero;
74+
yesButtonTransform.anchorMax = new Vector2( 0.5f, 1f );
75+
noButtonTransform.anchorMin = new Vector2( 0.5f, 0f );
76+
}
77+
}
78+
79+
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
80+
private void LateUpdate()
81+
{
82+
// Handle keyboard shortcuts
83+
if( Input.GetKeyDown( KeyCode.Return ) || Input.GetKeyDown( KeyCode.KeypadEnter ) )
84+
YesButtonClicked();
85+
86+
if( Input.GetKeyDown( KeyCode.Escape ) )
87+
NoButtonClicked();
88+
}
89+
#endif
90+
91+
public void YesButtonClicked()
92+
{
93+
gameObject.SetActive( false );
94+
95+
if( onDeletionConfirmed != null )
96+
onDeletionConfirmed();
97+
}
98+
99+
public void NoButtonClicked()
100+
{
101+
gameObject.SetActive( false );
102+
}
103+
}
104+
}

Plugins/SimpleFileBrowser/Scripts/FileBrowserDeleteConfirmationPanel.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Plugins/SimpleFileBrowser/Scripts/FileBrowserItem.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ private void Update()
8888
#region Pointer Events
8989
public void OnPointerClick( PointerEventData eventData )
9090
{
91+
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
92+
if( eventData.button == PointerEventData.InputButton.Middle )
93+
return;
94+
else if( eventData.button == PointerEventData.InputButton.Right )
95+
{
96+
// First, select the item
97+
if( !isSelected )
98+
{
99+
prevClickTime = 0f;
100+
fileBrowser.OnItemSelected( this, false );
101+
}
102+
103+
// Then, show the context menu
104+
fileBrowser.OnContextMenuTriggered();
105+
return;
106+
}
107+
#endif
108+
91109
if( Time.realtimeSinceStartup - prevClickTime < DOUBLE_CLICK_TIME )
92110
{
93111
prevClickTime = 0f;
@@ -102,11 +120,21 @@ public void OnPointerClick( PointerEventData eventData )
102120

103121
public void OnPointerDown( PointerEventData eventData )
104122
{
123+
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
124+
if( eventData.button != PointerEventData.InputButton.Left )
125+
return;
126+
#endif
127+
105128
pressTime = Time.realtimeSinceStartup;
106129
}
107130

108131
public void OnPointerUp( PointerEventData eventData )
109132
{
133+
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
134+
if( eventData.button != PointerEventData.InputButton.Left )
135+
return;
136+
#endif
137+
110138
if( pressTime == Mathf.Infinity )
111139
{
112140
// We have activated MultiSelectionToggleSelectionMode with this press, processing the click would result in
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using UnityEngine;
2+
using UnityEngine.EventSystems;
3+
using UnityEngine.UI;
4+
5+
namespace SimpleFileBrowser
6+
{
7+
public class FileBrowserRenamedItem : MonoBehaviour
8+
{
9+
public delegate void OnRenameCompleted( string filename );
10+
11+
#pragma warning disable 0649
12+
[SerializeField]
13+
private Image background;
14+
15+
[SerializeField]
16+
private Image icon;
17+
18+
[SerializeField]
19+
private InputField nameInputField;
20+
#pragma warning restore 0649
21+
22+
private OnRenameCompleted onRenameCompleted;
23+
24+
public void Show( string initialFilename, Color backgroundColor, Sprite icon, OnRenameCompleted onRenameCompleted )
25+
{
26+
background.color = backgroundColor;
27+
this.icon.sprite = icon;
28+
this.onRenameCompleted = onRenameCompleted;
29+
30+
transform.SetAsLastSibling();
31+
gameObject.SetActive( true );
32+
33+
nameInputField.text = initialFilename;
34+
nameInputField.ActivateInputField();
35+
}
36+
37+
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WSA || UNITY_WSA_10_0
38+
private void LateUpdate()
39+
{
40+
// Don't allow scrolling with mouse wheel while renaming a file or creating a folder
41+
if( Input.mouseScrollDelta.y != 0f )
42+
nameInputField.DeactivateInputField();
43+
}
44+
#endif
45+
46+
public void OnInputFieldEndEdit( string filename )
47+
{
48+
gameObject.SetActive( false );
49+
50+
// If we don't deselect the InputField manually, FileBrowser's keyboard shortcuts
51+
// no longer work until user clicks on a UI element and thus, deselects the InputField
52+
if( !EventSystem.current.alreadySelecting && EventSystem.current.currentSelectedGameObject == nameInputField.gameObject )
53+
EventSystem.current.SetSelectedGameObject( null );
54+
55+
if( onRenameCompleted != null )
56+
onRenameCompleted( filename );
57+
}
58+
}
59+
}

Plugins/SimpleFileBrowser/Scripts/FileBrowserRenamedItem.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using UnityEngine;
2+
using UnityEngine.UI;
3+
4+
namespace SimpleFileBrowser
5+
{
6+
// Credit: http://answers.unity.com/answers/1157876/view.html
7+
[RequireComponent( typeof( CanvasRenderer ) )]
8+
public class NonDrawingGraphic : Graphic
9+
{
10+
public override void SetMaterialDirty() { return; }
11+
public override void SetVerticesDirty() { return; }
12+
13+
protected override void OnPopulateMesh( VertexHelper vh )
14+
{
15+
vh.Clear();
16+
return;
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)