namespace UIWidgets.Menu { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using UIWidgets.Styles; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; /// /// ContextMenu view. /// [RequireComponent(typeof(LayoutGroup))] [RequireComponent(typeof(ContentSizeFitter))] [RequireComponent(typeof(RectTransform))] public partial class ContextMenuView : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IStylable { [SerializeField] MenuItemView defaultItem; /// /// Default item. /// public MenuItemView DefaultItem { get { return defaultItem; } set { if (defaultItem != value) { defaultItem = value; DefaultItemTemplate = new MenuItemTemplate(null, DefaultItem); UpdateEmptyTemplateReferences(); } } } MenuItemTemplate defaultItemTemplate; /// /// Default item template. /// protected MenuItemTemplate DefaultItemTemplate { get { if (defaultItemTemplate == null) { defaultItemTemplate = new MenuItemTemplate(null, DefaultItem); EmptyTemplate.defaultItemTemplate = defaultItemTemplate; } return defaultItemTemplate; } set { if (defaultItemTemplate != value) { SubscribersReset(); defaultItemTemplate = value; UpdateEmptyTemplateReferences(); SubscribersUpdate(); } } } [SerializeField] List specialItems = new List(); /// /// Special items. /// public ReadOnlyCollection SpecialItems { get { return specialItems.AsReadOnly(); } set { if (value == null) { throw new ArgumentNullException("value"); } SubscribersReset(); specialItems.Clear(); specialItems.AddRange(value); UpdateEmptyTemplateReferences(); SubscribersUpdate(); } } /// /// Cache. /// [SerializeField] [HideInInspector] protected List Cache = new List(); /// /// Empty template without nested items templates. /// protected ContextMenuView EmptyTemplate; RectTransform rectTransform; /// /// RectTransform. /// public RectTransform RectTransform { get { if (rectTransform == null) { rectTransform = transform as RectTransform; } return rectTransform; } } /// /// Is pointer over? /// public bool IsPointerOver { get; protected set; } /// /// Subscribers. /// protected readonly List Subscribers = new List(); /// /// Process the start event. /// protected virtual void Start() { Init(); } bool isInited; /// /// Init this instance. /// public virtual void Init() { if (isInited) { return; } gameObject.SetActive(false); defaultItem.gameObject.SetActive(false); for (int i = 0; i < specialItems.Count; i++) { specialItems[i].Template.gameObject.SetActive(false); } isInited = true; } /// /// Subscribe menu instance. /// /// Menu. public void Subscribe(IMenuSubscriber menu) { Subscribers.Add(menu); } /// /// Unsubscribe menu instance. /// /// Menu. public void Unsubscribe(IMenuSubscriber menu) { Subscribers.Remove(menu); } /// /// Send ResetItems event to the subscribers. /// protected void SubscribersReset() { foreach (var s in Subscribers) { ResetItems(s); } } /// /// Send ResetItems event to the subscriber. /// /// Subscriber. protected static void ResetItems(IMenuSubscriber subscriber) { subscriber.ResetItems(); } /// /// Send UpdateItems event to the subscribers. /// protected void SubscribersUpdate() { foreach (var s in Subscribers) { UpdateItems(s); } } /// /// Send UpdateItems event to the subscriber. /// /// Subscriber. protected static void UpdateItems(IMenuSubscriber subscriber) { subscriber.UpdateItems(); } /// /// Return menu to the cache. /// /// Menu. public void Return(ContextMenuView menu) { if (menu == null) { return; } menu.IsPointerOver = false; menu.transform.SetParent(RectTransform, false); menu.gameObject.SetActive(false); Cache.Add(menu); } /// /// Return MenuItem view to the cache. /// /// Item. /// Instance. public void Return(MenuItem item, MenuItemView view) { GetItemTemplate(item).Return(view); } /// /// Get menu. /// /// Menu. public virtual ContextMenuView Instance() { if (EmptyTemplate == null) { CreateEmptyTemplate(); } ContextMenuView menu; if (Cache.Count > 0) { menu = Cache[Cache.Count - 1]; Cache.RemoveAt(Cache.Count - 1); } else { menu = Instantiate(EmptyTemplate); Utilities.FixInstantiated(EmptyTemplate, menu); menu.Init(); } menu.IsPointerOver = false; menu.gameObject.SetActive(true); return menu; } /// /// Create empty template. /// protected virtual void CreateEmptyTemplate() { EmptyTemplate = Instantiate(this); Utilities.FixInstantiated(this, EmptyTemplate); EmptyTemplate.gameObject.SetActive(false); EmptyTemplate.name = string.Format("{0}EmptyTemplate", name); // destroy nested defaultItem if (EmptyTemplate.defaultItem.RectTransform.IsChildOf(EmptyTemplate.RectTransform)) { if (EmptyTemplate.defaultItemTemplate != null) { EmptyTemplate.defaultItemTemplate.Clear(); } EmptyTemplate.defaultItem.transform.SetParent(null, false); Destroy(EmptyTemplate.defaultItem.gameObject); } // destroy nested specialItems for (int i = 0; i < EmptyTemplate.specialItems.Count; i++) { var item = EmptyTemplate.specialItems[i]; if (item.Template.RectTransform.IsChildOf(EmptyTemplate.RectTransform)) { item.Clear(); item.Template.transform.SetParent(null, false); Destroy(item.Template.gameObject); } } EmptyTemplate.Init(); UpdateEmptyTemplateReferences(); } /// /// Update empty template. /// protected virtual void UpdateEmptyTemplateReferences() { if (EmptyTemplate == null) { return; } EmptyTemplate.defaultItem = defaultItem; EmptyTemplate.DefaultItemTemplate = DefaultItemTemplate; EmptyTemplate.specialItems = specialItems; } /// /// Get item instance. /// /// Item. /// Instance. public MenuItemView GetItemView(MenuItem item) { return GetItemTemplate(item).Instance(); } /// /// Get item template. /// /// Item. /// Template. protected MenuItemTemplate GetItemTemplate(MenuItem item) { for (int i = 0; i < SpecialItems.Count; i++) { if (SpecialItems[i].Key == item.Template) { return SpecialItems[i]; } } return DefaultItemTemplate; } /// /// Process the pointer enter event. /// /// Event data. public void OnPointerEnter(PointerEventData eventData) { IsPointerOver = true; } /// /// Process the pointer exit event. /// /// Event data. public void OnPointerExit(PointerEventData eventData) { IsPointerOver = false; } #region IStyleable /// /// Name of the delimiter template. /// protected static readonly string DelimiterName = "-"; /// public bool SetStyle(Style style) { style.ContextMenu.MainBackground.ApplyTo(this); for (int i = 0; i < SpecialItems.Count; i++) { if (UtilitiesCompare.StartsWith(SpecialItems[i].Key, DelimiterName)) { SpecialItems[i].Template.SetDelimiterStyle(style.ContextMenu.DelimiterImage); } else { SpecialItems[i].Template.SetStyle(style); } } DefaultItem.SetStyle(style); return true; } /// public bool GetStyle(Style style) { style.ContextMenu.MainBackground.GetFrom(this); for (int i = 0; i < SpecialItems.Count; i++) { if (UtilitiesCompare.StartsWith(SpecialItems[i].Key, DelimiterName)) { SpecialItems[i].Template.GetDelimiterStyle(style.ContextMenu.DelimiterImage); } else { SpecialItems[i].Template.GetStyle(style); } } DefaultItem.GetStyle(style); return true; } #endregion } }