OptionsTabController.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. using System.Linq;
  2. namespace SRDebugger.UI.Tabs
  3. {
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel;
  7. using Controls;
  8. using Controls.Data;
  9. using Internal;
  10. using Other;
  11. using Services;
  12. using SRF;
  13. using UnityEngine;
  14. using UnityEngine.UI;
  15. public class OptionsTabController : SRMonoBehaviourEx
  16. {
  17. private class CategoryInstance
  18. {
  19. public CategoryGroup CategoryGroup { get; private set; }
  20. public readonly List<OptionsControlBase> Options = new List<OptionsControlBase>();
  21. public CategoryInstance(CategoryGroup group)
  22. {
  23. CategoryGroup = group;
  24. }
  25. }
  26. private readonly List<OptionsControlBase> _controls = new List<OptionsControlBase>();
  27. private readonly List<CategoryInstance> _categories = new List<CategoryInstance>();
  28. private readonly Dictionary<OptionDefinition, OptionsControlBase> _options =
  29. new Dictionary<OptionDefinition, OptionsControlBase>();
  30. private bool _queueRefresh;
  31. private bool _selectionModeEnabled;
  32. private Canvas _optionCanvas;
  33. [RequiredField] public ActionControl ActionControlPrefab;
  34. [RequiredField] public CategoryGroup CategoryGroupPrefab;
  35. [RequiredField] public RectTransform ContentContainer;
  36. [RequiredField] public GameObject NoOptionsNotice;
  37. [RequiredField] public Toggle PinButton;
  38. [RequiredField] public GameObject PinPromptSpacer;
  39. [RequiredField] public GameObject PinPromptText;
  40. protected override void Start()
  41. {
  42. base.Start();
  43. PinButton.onValueChanged.AddListener(SetSelectionModeEnabled);
  44. PinPromptText.SetActive(false);
  45. //PinPromptSpacer.SetActive(false);
  46. Populate();
  47. _optionCanvas = GetComponent<Canvas>();
  48. Service.Options.OptionsUpdated += OnOptionsUpdated;
  49. Service.PinnedUI.OptionPinStateChanged += OnOptionPinnedStateChanged;
  50. }
  51. protected override void OnDestroy()
  52. {
  53. if (Service.Options != null)
  54. {
  55. Service.Options.OptionsUpdated -= OnOptionsUpdated;
  56. }
  57. if (Service.PinnedUI != null)
  58. {
  59. Service.PinnedUI.OptionPinStateChanged -= OnOptionPinnedStateChanged;
  60. }
  61. base.OnDestroy();
  62. }
  63. private void OnOptionPinnedStateChanged(OptionDefinition optionDefinition, bool isPinned)
  64. {
  65. if (_options.ContainsKey(optionDefinition))
  66. {
  67. _options[optionDefinition].IsSelected = isPinned;
  68. }
  69. }
  70. private void OnOptionsUpdated(object sender, EventArgs eventArgs)
  71. {
  72. Clear();
  73. Populate();
  74. }
  75. protected override void OnEnable()
  76. {
  77. base.OnEnable();
  78. Service.Panel.VisibilityChanged += PanelOnVisibilityChanged;
  79. }
  80. protected override void OnDisable()
  81. {
  82. // Always end pinning mode when tabbing away
  83. SetSelectionModeEnabled(false);
  84. if (Service.Panel != null)
  85. {
  86. Service.Panel.VisibilityChanged -= PanelOnVisibilityChanged;
  87. }
  88. base.OnDisable();
  89. }
  90. protected override void Update()
  91. {
  92. base.Update();
  93. if (_queueRefresh)
  94. {
  95. _queueRefresh = false;
  96. Refresh();
  97. }
  98. }
  99. private void PanelOnVisibilityChanged(IDebugPanelService debugPanelService, bool b)
  100. {
  101. // Always end pinning mode when panel is closed
  102. if (!b)
  103. {
  104. SetSelectionModeEnabled(false);
  105. // Refresh bindings for all pinned controls
  106. Refresh();
  107. }
  108. else if (b && CachedGameObject.activeInHierarchy)
  109. {
  110. // If the panel is visible, and this tab is active (selected), refresh all the data bindings
  111. Refresh();
  112. }
  113. if (_optionCanvas != null)
  114. {
  115. _optionCanvas.enabled = b;
  116. }
  117. }
  118. public void SetSelectionModeEnabled(bool isEnabled)
  119. {
  120. if (_selectionModeEnabled == isEnabled)
  121. {
  122. return;
  123. }
  124. _selectionModeEnabled = isEnabled;
  125. PinButton.isOn = isEnabled;
  126. PinPromptText.SetActive(isEnabled);
  127. //PinPromptSpacer.SetActive(isEnabled);
  128. foreach (var kv in _options)
  129. {
  130. kv.Value.SelectionModeEnabled = isEnabled;
  131. // Set IsSelected if entering selection mode.
  132. if (isEnabled)
  133. {
  134. kv.Value.IsSelected = Service.PinnedUI.HasPinned(kv.Key);
  135. }
  136. }
  137. foreach (var cat in _categories)
  138. {
  139. cat.CategoryGroup.SelectionModeEnabled = isEnabled;
  140. }
  141. RefreshCategorySelection();
  142. // Return if entering selection mode
  143. if (isEnabled)
  144. {
  145. return;
  146. }
  147. }
  148. private void Refresh()
  149. {
  150. for (var i = 0; i < _options.Count; i++)
  151. {
  152. _controls[i].Refresh();
  153. _controls[i].SelectionModeEnabled = _selectionModeEnabled;
  154. _controls[i].IsSelected = Service.PinnedUI.HasPinned(_controls[i].Option);
  155. }
  156. }
  157. private void CommitPinnedOptions()
  158. {
  159. foreach (var kv in _options)
  160. {
  161. var control = kv.Value;
  162. if (control.IsSelected && !Service.PinnedUI.HasPinned(kv.Key))
  163. {
  164. Service.PinnedUI.Pin(kv.Key);
  165. }
  166. else if (!control.IsSelected && Service.PinnedUI.HasPinned(kv.Key))
  167. {
  168. Service.PinnedUI.Unpin(kv.Key);
  169. }
  170. }
  171. }
  172. private bool _isTogglingCategory;
  173. private void RefreshCategorySelection()
  174. {
  175. _isTogglingCategory = true;
  176. foreach (var cat in _categories)
  177. {
  178. var allSelected = true;
  179. for (var i = 0; i < cat.Options.Count; i++)
  180. {
  181. if (!cat.Options[i].IsSelected)
  182. {
  183. allSelected = false;
  184. break;
  185. }
  186. }
  187. cat.CategoryGroup.IsSelected = allSelected;
  188. }
  189. _isTogglingCategory = false;
  190. }
  191. private void OnOptionSelectionToggle(bool selected)
  192. {
  193. if (!_isTogglingCategory)
  194. {
  195. RefreshCategorySelection();
  196. CommitPinnedOptions();
  197. }
  198. }
  199. /// <summary>
  200. /// When a category mode selection is changed.
  201. /// </summary>
  202. /// <param name="category"></param>
  203. /// <param name="selected"></param>
  204. private void OnCategorySelectionToggle(CategoryInstance category, bool selected)
  205. {
  206. _isTogglingCategory = true;
  207. for (var i = 0; i < category.Options.Count; i++)
  208. {
  209. category.Options[i].IsSelected = selected;
  210. }
  211. _isTogglingCategory = false;
  212. CommitPinnedOptions();
  213. }
  214. #region Initialisation
  215. protected void Populate()
  216. {
  217. var sortedOptions = new Dictionary<string, List<OptionDefinition>>();
  218. foreach (var option in Service.Options.Options)
  219. {
  220. if (!OptionControlFactory.CanCreateControl(option))
  221. {
  222. if (option.IsProperty)
  223. {
  224. Debug.LogError("[SRDebugger.OptionsTab] Unsupported property type: {0} (on property {1})".Fmt(option.Property.PropertyType, option.Property));
  225. }
  226. else
  227. {
  228. Debug.LogError("[SRDebugger.OptionsTab] Unsupported method signature: {0}".Fmt(option.Name));
  229. }
  230. continue;
  231. }
  232. // Find a properly list for that category, or create a new one
  233. List<OptionDefinition> memberList;
  234. if (!sortedOptions.TryGetValue(option.Category, out memberList))
  235. {
  236. memberList = new List<OptionDefinition>();
  237. sortedOptions.Add(option.Category, memberList);
  238. }
  239. memberList.Add(option);
  240. }
  241. var hasCreated = false;
  242. foreach (var kv in sortedOptions.OrderBy(p => p.Key))
  243. {
  244. if (kv.Value.Count == 0)
  245. {
  246. continue;
  247. }
  248. hasCreated = true;
  249. CreateCategory(kv.Key, kv.Value);
  250. }
  251. if (hasCreated)
  252. {
  253. NoOptionsNotice.SetActive(false);
  254. }
  255. RefreshCategorySelection();
  256. }
  257. protected void CreateCategory(string title, List<OptionDefinition> options)
  258. {
  259. options.Sort((d1, d2) => d1.SortPriority.CompareTo(d2.SortPriority));
  260. var groupInstance = SRInstantiate.Instantiate(CategoryGroupPrefab);
  261. var categoryInstance = new CategoryInstance(groupInstance);
  262. _categories.Add(categoryInstance);
  263. groupInstance.CachedTransform.SetParent(ContentContainer, false);
  264. groupInstance.Header.text = title;
  265. groupInstance.SelectionModeEnabled = _selectionModeEnabled;
  266. categoryInstance.CategoryGroup.SelectionToggle.onValueChanged.AddListener(
  267. b => OnCategorySelectionToggle(categoryInstance, b));
  268. foreach (var option in options)
  269. {
  270. var control = OptionControlFactory.CreateControl(option, title);
  271. if (control == null)
  272. {
  273. Debug.LogError("[SRDebugger.OptionsTab] Failed to create option control for {0}".Fmt(option.Name));
  274. continue;
  275. }
  276. categoryInstance.Options.Add(control);
  277. control.CachedTransform.SetParent(groupInstance.Container, false);
  278. control.IsSelected = Service.PinnedUI.HasPinned(option);
  279. control.SelectionModeEnabled = _selectionModeEnabled;
  280. control.SelectionModeToggle.onValueChanged.AddListener(OnOptionSelectionToggle);
  281. _options.Add(option, control);
  282. _controls.Add(control);
  283. }
  284. }
  285. void Clear()
  286. {
  287. foreach (var categoryInstance in _categories)
  288. {
  289. Destroy(categoryInstance.CategoryGroup.gameObject);
  290. }
  291. _categories.Clear();
  292. _controls.Clear();
  293. _options.Clear();
  294. }
  295. #endregion
  296. }
  297. }