Snippets

Dylan Wolf Unity UI - Submenu Example

Created by Dylan Wolf
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class Submenu : MonoBehaviour {

    [System.NonSerialized]
    public SubmenuItem SelectedItem;
    Selectable firstAvailable;

    public SubmenuItem[] Items;
    GameObject[] objects;

    public Selectable Previous;
    public Selectable Next;

    public Sprite InactiveFrame;
    public Sprite ClearFrame;

    EventSystem evt;

    public enum ButtonDirection
    {
        Horizontal,
        Vertical
    }

    public ButtonDirection Direction;

    private void Start()
    {
        InitChildren();
    }

    bool hasInit = false;
    public void InitChildren()
    {
        if (!hasInit)
        {
            for (int i = 0; i < Items.Length; i++)
            {
                InitChild(Items[i]);
            }
            RewireControls();
            hasInit = true;
        }
    }

    void InitChild(SubmenuItem child)
    {
        Debug.Log("Setting " + child.name + " to " + this.name);
        child.Container = this;
        child.Selectable.SetNavigationType(Navigation.Mode.Explicit);
    }

    void SetNextAndPrevious(Selectable sel, Selectable previous, Selectable nxt)
    {
        if (Direction == ButtonDirection.Horizontal)
            sel.SetLeftAndRight(previous, nxt);
        else
            sel.SetUpAndDown(previous, nxt);
    }

    void SetPrevious(Selectable sel, Selectable prev)
    {
        if (Direction == ButtonDirection.Horizontal)
            sel.SetLeft(prev);
        else
            sel.SetUp(prev);
    }

    void SetNext(Selectable sel, Selectable nxt)
    {
        if (Direction == ButtonDirection.Horizontal)
            sel.SetRight(nxt);
        else
            sel.SetDown(nxt);
    }

    public void RewireControls()
    {
        firstAvailable = null;
        int? lastIndex = null;
        for (int i = 0; i < Items.Length; i++)
        {
            // Set enter/exit navigation
            if (Direction == ButtonDirection.Horizontal)
                Items[i].Selectable.SetUpAndDown(Previous, Next);
            else
                Items[i].Selectable.SetLeftAndRight(Previous, Next);

            // Interactable: set this in order
            if (Items[i].Selectable.IsInteractable())
            {
                // Is first enabled item in the list 
                if (!lastIndex.HasValue)
                {
                    // Clear all the navigation
                    SetNextAndPrevious(Items[i].Selectable, null, null);
                    firstAvailable = Items[i].Selectable;
                }
                else
                {
                    // Set the previous item to the last enabled item
                    SetNextAndPrevious(Items[i].Selectable, Items[lastIndex.Value].Selectable, null);
                    // Reverse the wiring
                    SetNext(Items[lastIndex.Value].Selectable, Items[i].Selectable);
                }
                lastIndex = i;
            }
            // Not interactable: remove this from the order
            else
            {
                // Clear all the navigation
                SetNextAndPrevious(Items[i].Selectable, null, null);
            }
        }

        RewireNextAndPrevious();
    }

    public void SelectItem(SubmenuItem selected)
    {
        SelectedItem = selected;
        RewireNextAndPrevious();
    }

    public void ForceSelection(SubmenuItem selected)
    {
        if (evt == null)
            evt = EventSystem.current;

        evt.SetSelectedGameObject(null);
        evt.SetSelectedGameObject(selected.gameObject);
        //SelectItem(selected);
    }

    Selectable SelectedOrFirst
    {
        get
        {
            return (SelectedItem != null && SelectedItem.Selectable != null) ? SelectedItem.Selectable : firstAvailable;
        }
    }

    public void RewireNextAndPrevious()
    {
        if (Direction == ButtonDirection.Horizontal)
        {
            if (Previous != null)
                Previous.SetDown(SelectedOrFirst);
            if (Next != null)
                Next.SetUp(SelectedOrFirst);
        }
        else
        {
            if (Previous != null)
                Previous.SetRight(SelectedOrFirst);
            if (Next != null)
                Next.SetLeft(SelectedOrFirst);
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class SubmenuItem : MonoBehaviour, ISelectHandler, IDeselectHandler
{
    [System.NonSerialized]
    public Submenu Container;
    public Selectable Selectable { get; private set; }
    public Image ButtonImage { get; private set; }

    public bool IsAvailable => Selectable.interactable;

    public virtual void OnDeselect(BaseEventData eventData)
    {
        ButtonImage.sprite = Container.InactiveFrame;
        eventData.Use();
    }

    public virtual void OnSelect(BaseEventData eventData)
    {
        if (Container.SelectedItem != null)
            Container.SelectedItem.ButtonImage.sprite = Container.ClearFrame;
        Container.SelectItem(this);

        eventData.Use();
    }

    protected virtual void Awake()
    {
        Selectable = GetComponent<Selectable>();
        ButtonImage = GetComponent<Image>();
    }
}

Comments (0)