A game about forced loneliness, made by TACStudios
1using System; 2using Unity.Multiplayer.Center.Analytics; 3using UnityEditor; 4using UnityEngine; 5using UnityEngine.UIElements; 6 7namespace Unity.Multiplayer.Center.Window 8{ 9 // Note: there is a TabView API in UI Toolkit, but only starting from 2023.2 10 internal interface ITabView 11 { 12 /// <summary> 13 /// The name as displayed in the tab button 14 /// Should be serialized. 15 /// </summary> 16 string Name { get; } 17 18 /// <summary> 19 /// The root visual element of the tab view. 20 /// The setter will only be used if the root visual element is null when the tab is created. 21 /// </summary> 22 VisualElement RootVisualElement { get; set; } 23 24 /// <summary> 25 /// Sets the tab view visible or not. 26 /// </summary> 27 /// <param name="visible">If true, visible.</param> 28 void SetVisible(bool visible); 29 30 /// <summary> 31 /// If true the Tab can be selected by the user. 32 /// </summary> 33 bool IsEnabled => true; 34 35 /// <summary> 36 /// Tooltip which will be shown on the Tab Button. 37 /// </summary> 38 string ToolTip => ""; 39 40 /// <summary> 41 /// Refreshes the UI Elements according to latest data. 42 /// If the UI is not created yet, it does it. 43 /// </summary> 44 void Refresh(); 45 46 /// <summary> 47 /// Unregister all events and clear UI Elements 48 /// </summary> 49 void Clear(); 50 51 /// <summary> 52 /// The Multiplayer Center Analytics provider. 53 /// </summary> 54 IMultiplayerCenterAnalytics MultiplayerCenterAnalytics { get; set; } 55 } 56 57 [Serializable] 58 internal class TabGroup 59 { 60 const string k_TabViewName = "tab-view"; 61 const string k_TabZoneName = "tab-zone"; 62 const string k_TabButtonUssClass = "tab-button"; 63 64 // The container for all the tabs 65 const string k_TabsContainerUssClass ="tabs-container"; 66 67 // Gets applied to the root of each tab 68 const string k_TabContentUssClass = "tab-content"; 69 70 [field: SerializeField] 71 public int CurrentTab { get; private set; } = -1; 72 73 public int ViewCount => m_TabViews?.Length ?? 0; 74 75 VisualElement[] m_TabButtons; 76 77 [SerializeReference] 78 ITabView[] m_TabViews; 79 80 public VisualElement Root { get; private set; } 81 82 VisualElement m_MainContainer; 83 84 IMultiplayerCenterAnalytics m_MultiplayerCenterAnalytics; 85 86 internal IMultiplayerCenterAnalytics MultiplayerCenterAnalytics 87 { 88 get => m_MultiplayerCenterAnalytics; 89 set 90 { 91 m_MultiplayerCenterAnalytics = value; 92 foreach (var tabView in m_TabViews) 93 { 94 if(tabView != null) 95 tabView.MultiplayerCenterAnalytics = value; 96 } 97 } 98 } 99 100 public TabGroup(IMultiplayerCenterAnalytics analytics, ITabView[] tabViews, int defaultIndex = 0) 101 { 102 m_TabViews = tabViews; 103 CurrentTab = defaultIndex; 104 MultiplayerCenterAnalytics = analytics; 105 } 106 107 public void SetSelected(int index, bool force = false) 108 { 109 // Select the first tab, if the requested tab is not enabled. 110 // This assumes the first tab is always enabled. 111 if (!m_TabViews[index].IsEnabled) 112 index = 0; 113 114 if (index == CurrentTab && !force) 115 return; 116 117 if (CurrentTab >= 0 && CurrentTab < m_TabViews.Length) 118 { 119 m_TabButtons[CurrentTab].RemoveFromClassList("selected"); 120 m_TabViews[CurrentTab].SetVisible(false); 121 } 122 123 EditorPrefs.SetInt(PlayerSettings.productName + "_MultiplayerCenter_TabIndex", index); 124 CurrentTab = index; 125 m_TabViews[CurrentTab].Refresh(); 126 m_TabButtons[CurrentTab].AddToClassList("selected"); 127 m_TabViews[CurrentTab].SetVisible(true); 128 } 129 130 /// <summary> 131 /// Instantiates the visual elements for all the tabs. 132 /// Use this to create the tabs for the first time the UI is shown or after a domain reload. 133 /// </summary> 134 public void CreateTabs() 135 { 136 Root ??= new VisualElement(); 137 m_MainContainer ??= new VisualElement(); 138 139 if (Root.Q(k_TabZoneName) != null) 140 Root.Q(k_TabZoneName).RemoveFromHierarchy(); 141 142 var tabZone = new VisualElement() {name = k_TabZoneName}; 143 Root.Add(tabZone); 144 Root.name = k_TabViewName; 145 m_TabButtons = new VisualElement[m_TabViews.Length]; 146 for (var i = 0; i < m_TabViews.Length; i++) 147 { 148 var tabView = m_TabViews[i]; 149 var index = i; // copy for closure 150 var tabButton = new Button(() => SetSelected(index)); 151 tabButton.enabledSelf = tabView.IsEnabled; 152 tabButton.tooltip = tabView.ToolTip; 153 tabButton.AddToClassList(k_TabButtonUssClass); 154 tabButton.text = tabView.Name; 155 tabZone.Add(tabButton); 156 m_TabButtons[i] = tabButton; 157 tabView.RootVisualElement ??= new VisualElement(); 158 tabView.RootVisualElement.AddToClassList(k_TabContentUssClass); 159 tabView.RootVisualElement.style.display = DisplayStyle.None; 160 m_MainContainer.Add(m_TabViews[i].RootVisualElement); 161 } 162 163 m_MainContainer.AddToClassList(k_TabsContainerUssClass); 164 Root.Add(m_MainContainer); 165 CurrentTab = EditorPrefs.GetInt(PlayerSettings.productName + "_MultiplayerCenter_TabIndex", 0); 166 } 167 168 static void SetVisible(VisualElement e, bool visible) 169 { 170 e.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None; 171 } 172 173 public void Clear() 174 { 175 if(m_TabViews == null) 176 return; 177 178 foreach (var tabView in m_TabViews) 179 { 180 tabView?.Clear(); 181 } 182 } 183 184 public bool TabsAreValid() 185 { 186 if (m_TabViews == null) 187 return false; 188 189 foreach (var tab in m_TabViews) 190 { 191 if (tab == null) 192 return false; 193 } 194 return true; 195 } 196 } 197}