A game about forced loneliness, made by TACStudios
1using UnityEngine;
2using UnityEditor;
3
4namespace Unity.Burst.Editor
5{
6 internal static class LabeledPopup
7 {
8 // Because the function given to dropdown menu needs takes its parameter
9 // in the form of an object, we need someway to wrap the integer into one.
10 private struct IntegerWrapper
11 {
12 public int Value { get; }
13
14 public IntegerWrapper(int v)
15 {
16 Value = v;
17 }
18 }
19
20 /// <summary>
21 /// Enables having several popup menus functioning independently at the same time.
22 /// </summary>
23 private class PopperCallBack
24 {
25 public static PopperCallBack Instance = null;
26
27 /// <summary>
28 /// Name of the event send when an index have been chosen.
29 /// </summary>
30 private const string IndexChangeEventName = "PopperChangingIndex";
31
32 private readonly int _controlID;
33 private int _selectedIdx;
34 private readonly GUIView _view;
35
36 public PopperCallBack(int controlID)
37 {
38 _controlID = controlID;
39 _selectedIdx = -1;
40 _view = GUIView.current;
41 }
42
43 /// <summary>
44 /// Tries to get selection chosen by dropdown menu <see cref="controlID"/>.
45 /// </summary>
46 /// <param name="controlId">ID of popup menu.</param>
47 /// <param name="selectedIdx">Current selected index.</param>
48 /// <returns>
49 /// Either the selected target, or the <see cref="selectedIdx"/>
50 /// if none were chosen yet.
51 /// </returns>
52 internal static int GetSelectionValue(int controlId, int selectedIdx)
53 {
54 var selected = selectedIdx;
55
56 // A command event with message IndexChangeEvent will be sent whenever a choice on
57 // the dropdown menu has been made. So if this is not the case return whatever index was given
58 var evt = Event.current;
59 if (evt.type != EventType.ExecuteCommand || evt.commandName != IndexChangeEventName) return selected;
60
61 // If this is the popup opened right now: Set the selection idx appropriately
62 if (Instance != null && controlId == Instance._controlID)
63 {
64 selected = Instance._selectedIdx;
65 Instance = null;
66 }
67
68 return selected;
69 }
70
71 /// <summary>
72 /// Sets selection on the opened dropdown, and sends an event
73 /// to the view the popup is within.
74 /// </summary>
75 /// <param name="index">Index selected.</param>
76 internal void SetSelection(object index)
77 {
78 _selectedIdx = ((IntegerWrapper)index).Value;
79 _view.SendEvent(EditorGUIUtility.CommandEvent(IndexChangeEventName));
80 }
81 }
82
83 /// <summary>
84 /// Name used for getting a controlID for popup menus.
85 /// </summary>
86 private const string LabelControlName = "LabeledPopup";
87
88 /// <summary>
89 /// Create a immediate automatically positioned popup menu.
90 /// </summary>
91 /// <param name="index">Current active selection index.</param>
92 /// <param name="display">Name to display as the button.</param>
93 /// <param name="options">Display name for the dropdown menu.</param>
94 /// <returns>The possibly new active selection index.</returns>
95 public static int Popup(int index, GUIContent display, string[] options)
96 {
97 // GetControlRect so space is reserved for the button, and we get a
98 // position to place the drop down context menu at.
99 var pos = EditorGUILayout.GetControlRect(false, EditorGUI.kSingleLineHeight,
100 EditorStyles.popup);
101
102 var controlID = GUIUtility.GetControlID(LabelControlName.GetHashCode(), FocusType.Keyboard, pos);
103
104 var selected = PopperCallBack.GetSelectionValue(controlID, index);
105
106 if (GUI.Button(pos, display, EditorStyles.popup))
107 {
108 PopperCallBack.Instance = new PopperCallBack(controlID);
109
110 var menu = new GenericMenu();
111 for (var i = 0; i < options.Length; i++)
112 {
113 var size = options[i];
114
115 menu.AddItem(EditorGUIUtility.TrTextContent(size), i == index, PopperCallBack.Instance.SetSelection, new IntegerWrapper(i));
116 }
117 menu.Popup(pos, index);
118 }
119
120 return selected;
121 }
122 }
123}