Добавлен , опубликован
В редакторе Unity порой требуются самые разные контролы. Многие из них уже есть в наборе стандартного класса EditorGUILayout, однако есть и те, которые там найти не получится, но тем не менее - они актуальны и нужны для редакторов.
Сегодня я хотел бы предоставить вам элемент Popup-multibutton - кнопка с подменю. В отличии от стандартного Popup данная кнопка имеет свой заголовок и немного отличается по внешнему виду.
Данный элемент легко модифицировать в кнопку другого стиля, либо кнопку с изображением.
Так же данный пример хорошо иллюстрирует основные принципы создания элементов управления для OnGUI.
код
public static int Popup(string title, string[] values, params GUILayoutOption[] settings)
{
    var style = Styles.MiniPullDown;
    return Popup(new GUIContent(title), values.Select(x => new GUIContent(x)), style, settings);
}

public static int Popup(string title, string[] values, GUIStyle style, params GUILayoutOption[] settings)
{
    return Popup(new GUIContent(title),values.Select(x => new GUIContent(x)), style, settings);
}

public static int Popup(string title, GUIContent[] values, params GUILayoutOption[] settings)
{
    var style = Styles.MiniPullDown;
    return Popup(new GUIContent(title),values.Select(x => new GUIContent(x)), style, settings);
}

public static int Popup(string title, GUIContent[] values, GUIStyle style, params GUILayoutOption[] settings)
{
    return Popup(new GUIContent(title),values.Select(x => new GUIContent(x)), style, settings);
}

public static int Popup(GUIContent title, string[] values, params GUILayoutOption[] settings)
{
    var style = Styles.MiniPullDown;
    return Popup(title, values.Select(x => new GUIContent(x)), style, settings);
}

public static int Popup(GUIContent title, string[] values, GUIStyle style, params GUILayoutOption[] settings)
{
    return Popup(title, values.Select(x => new GUIContent(x)), style, settings);
}

public static int Popup(GUIContent title, GUIContent[] values, params GUILayoutOption[] settings)
{
    var style = Styles.MiniPullDown;
    return Popup(title, values.Select(x => new GUIContent(x)), style, settings);
}

public static int Popup(GUIContent title, GUIContent[] values, GUIStyle style, params GUILayoutOption[] settings)
{
    int selectedId = -1;
    Rect position = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(false, 16f, style, settings));
    var id = GUIUtility.GetControlID("Popup".GetHashCode(), FocusType.Native, position);
    GUI.Box(position, title, style);
    if (Event.current.type == EventType.mouseDown)
    {
        if (position.Contains(Event.current.mousePosition))
        {
            PopupCallbackInfo.instance = new PopupCallbackInfo { controlId = id };
            EditorUtility.DisplayCustomMenu(position, values, -1, PopupCallbackInfo.instance.SetValueDelegate, null);
            Event.current.Use();
        }
    }
    if (PopupCallbackInfo.instance != null && PopupCallbackInfo.instance.change && PopupCallbackInfo.instance.controlId == id)
    {
        selectedId = PopupCallbackInfo.instance.selectedIndex;
        PopupCallbackInfo.instance = null;
    }
    return selectedId;
}

private sealed class PopupCallbackInfo
{
    public int controlId;
    public static PopupCallbackInfo instance;
    public int selectedIndex;
    public bool change = false;
    internal void SetValueDelegate(object userData, string[] options, int selected)
    {
        selectedIndex = selected;
        change = true;
    }
}
Пример использования:
var index = GUILayoutEx.Popup("Paste...", new[] {"As {0}", "As {params}"}); 
У меня в проекте все контролы такого рода хранятся в классе GUILayoutEx - название класса у вас может быть другим.
Сама кнопка будет называться "Paste...". Нажимаемые пункты - "As {0}" и "As {params}".
В index будет попадать число, индекс которого равен индексу нажатой кнопки (отсчет начинается с 0). Если мы ничего не нажали, то в index попадет значение -1.
В результате будет вот такой элемент: