UnityGame/Library/PackageCache/com.unity.burst/Editor/LabeledPopup.cs

123 lines
4.6 KiB
C#
Raw Normal View History

2024-10-27 10:53:47 +03:00
using UnityEngine;
using UnityEditor;
namespace Unity.Burst.Editor
{
internal static class LabeledPopup
{
// Because the function given to dropdown menu needs takes its parameter
// in the form of an object, we need someway to wrap the integer into one.
private struct IntegerWrapper
{
public int Value { get; }
public IntegerWrapper(int v)
{
Value = v;
}
}
/// <summary>
/// Enables having several popup menus functioning independently at the same time.
/// </summary>
private class PopperCallBack
{
public static PopperCallBack Instance = null;
/// <summary>
/// Name of the event send when an index have been chosen.
/// </summary>
private const string IndexChangeEventName = "PopperChangingIndex";
private readonly int _controlID;
private int _selectedIdx;
private readonly GUIView _view;
public PopperCallBack(int controlID)
{
_controlID = controlID;
_selectedIdx = -1;
_view = GUIView.current;
}
/// <summary>
/// Tries to get selection chosen by dropdown menu <see cref="controlID"/>.
/// </summary>
/// <param name="controlId">ID of popup menu.</param>
/// <param name="selectedIdx">Current selected index.</param>
/// <returns>
/// Either the selected target, or the <see cref="selectedIdx"/>
/// if none were chosen yet.
/// </returns>
internal static int GetSelectionValue(int controlId, int selectedIdx)
{
var selected = selectedIdx;
// A command event with message IndexChangeEvent will be sent whenever a choice on
// the dropdown menu has been made. So if this is not the case return whatever index was given
var evt = Event.current;
if (evt.type != EventType.ExecuteCommand || evt.commandName != IndexChangeEventName) return selected;
// If this is the popup opened right now: Set the selection idx appropriately
if (Instance != null && controlId == Instance._controlID)
{
selected = Instance._selectedIdx;
Instance = null;
}
return selected;
}
/// <summary>
/// Sets selection on the opened dropdown, and sends an event
/// to the view the popup is within.
/// </summary>
/// <param name="index">Index selected.</param>
internal void SetSelection(object index)
{
_selectedIdx = ((IntegerWrapper)index).Value;
_view.SendEvent(EditorGUIUtility.CommandEvent(IndexChangeEventName));
}
}
/// <summary>
/// Name used for getting a controlID for popup menus.
/// </summary>
private const string LabelControlName = "LabeledPopup";
/// <summary>
/// Create a immediate automatically positioned popup menu.
/// </summary>
/// <param name="index">Current active selection index.</param>
/// <param name="display">Name to display as the button.</param>
/// <param name="options">Display name for the dropdown menu.</param>
/// <returns>The possibly new active selection index.</returns>
public static int Popup(int index, GUIContent display, string[] options)
{
// GetControlRect so space is reserved for the button, and we get a
// position to place the drop down context menu at.
var pos = EditorGUILayout.GetControlRect(false, EditorGUI.kSingleLineHeight,
EditorStyles.popup);
var controlID = GUIUtility.GetControlID(LabelControlName.GetHashCode(), FocusType.Keyboard, pos);
var selected = PopperCallBack.GetSelectionValue(controlID, index);
if (GUI.Button(pos, display, EditorStyles.popup))
{
PopperCallBack.Instance = new PopperCallBack(controlID);
var menu = new GenericMenu();
for (var i = 0; i < options.Length; i++)
{
var size = options[i];
menu.AddItem(EditorGUIUtility.TrTextContent(size), i == index, PopperCallBack.Instance.SetSelection, new IntegerWrapper(i));
}
menu.Popup(pos, index);
}
return selected;
}
}
}