351 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
| namespace SRDebugger.UI.Tabs
 | |
| {
 | |
|     using System;
 | |
|     using System.Collections.Generic;
 | |
|     using System.ComponentModel;
 | |
|     using Controls;
 | |
|     using Controls.Data;
 | |
|     using Internal;
 | |
|     using Other;
 | |
|     using Services;
 | |
|     using SRF;
 | |
|     using UnityEngine;
 | |
|     using UnityEngine.UI;
 | |
| 
 | |
|     public class OptionsTabController : SRMonoBehaviourEx
 | |
|     {
 | |
|         private class CategoryInstance
 | |
|         {
 | |
|             public CategoryGroup CategoryGroup { get; private set; }
 | |
|             public readonly List<OptionsControlBase> Options = new List<OptionsControlBase>();
 | |
| 
 | |
|             public CategoryInstance(CategoryGroup group)
 | |
|             {
 | |
|                 CategoryGroup = group;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private readonly List<OptionsControlBase> _controls = new List<OptionsControlBase>();
 | |
|         private readonly List<CategoryInstance> _categories = new List<CategoryInstance>();
 | |
| 
 | |
|         private readonly Dictionary<OptionDefinition, OptionsControlBase> _options =
 | |
|             new Dictionary<OptionDefinition, OptionsControlBase>();
 | |
| 
 | |
|         private bool _queueRefresh;
 | |
|         private bool _selectionModeEnabled;
 | |
|         private Canvas _optionCanvas;
 | |
| 
 | |
|         [RequiredField] public ActionControl ActionControlPrefab;
 | |
| 
 | |
|         [RequiredField] public CategoryGroup CategoryGroupPrefab;
 | |
| 
 | |
|         [RequiredField] public RectTransform ContentContainer;
 | |
| 
 | |
|         [RequiredField] public GameObject NoOptionsNotice;
 | |
| 
 | |
|         [RequiredField] public Toggle PinButton;
 | |
| 
 | |
|         [RequiredField] public GameObject PinPromptSpacer;
 | |
| 
 | |
|         [RequiredField] public GameObject PinPromptText;
 | |
| 
 | |
| 
 | |
|         protected override void Start()
 | |
|         {
 | |
|             base.Start();
 | |
| 
 | |
|             PinButton.onValueChanged.AddListener(SetSelectionModeEnabled);
 | |
| 
 | |
|             PinPromptText.SetActive(false);
 | |
|             //PinPromptSpacer.SetActive(false);
 | |
| 
 | |
|             Populate();
 | |
| 
 | |
|             _optionCanvas = GetComponent<Canvas>();
 | |
| 
 | |
|             Service.Options.OptionsUpdated += OnOptionsUpdated;
 | |
|             Service.Options.OptionsValueUpdated += OnOptionsValueChanged;
 | |
|             Service.PinnedUI.OptionPinStateChanged += OnOptionPinnedStateChanged;
 | |
|         }
 | |
| 
 | |
|         private void OnOptionPinnedStateChanged(OptionDefinition optionDefinition, bool isPinned)
 | |
|         {
 | |
|             if (_options.ContainsKey(optionDefinition))
 | |
|             {
 | |
|                 _options[optionDefinition].IsSelected = isPinned;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void OnOptionsUpdated(object sender, EventArgs eventArgs)
 | |
|         {
 | |
|             Clear();
 | |
|             Populate();
 | |
|         }
 | |
| 
 | |
|         private void OnOptionsValueChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
 | |
|         {
 | |
|             _queueRefresh = true;
 | |
|         }
 | |
| 
 | |
|         protected override void OnEnable()
 | |
|         {
 | |
|             base.OnEnable();
 | |
| 
 | |
|             Service.Panel.VisibilityChanged += PanelOnVisibilityChanged;
 | |
|         }
 | |
| 
 | |
|         protected override void OnDisable()
 | |
|         {
 | |
|             // Always end pinning mode when tabbing away
 | |
|             SetSelectionModeEnabled(false);
 | |
| 
 | |
|             if (Service.Panel != null)
 | |
|             {
 | |
|                 Service.Panel.VisibilityChanged -= PanelOnVisibilityChanged;
 | |
|             }
 | |
| 
 | |
|             base.OnDisable();
 | |
|         }
 | |
| 
 | |
|         protected override void Update()
 | |
|         {
 | |
|             base.Update();
 | |
| 
 | |
|             if (_queueRefresh)
 | |
|             {
 | |
|                 _queueRefresh = false;
 | |
|                 Refresh();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void PanelOnVisibilityChanged(IDebugPanelService debugPanelService, bool b)
 | |
|         {
 | |
|             // Always end pinning mode when panel is closed
 | |
|             if (!b)
 | |
|             {
 | |
|                 SetSelectionModeEnabled(false);
 | |
| 
 | |
|                 // Refresh bindings for all pinned controls
 | |
|                 Refresh();
 | |
|             }
 | |
|             else if (b && CachedGameObject.activeInHierarchy)
 | |
|             {
 | |
|                 // If the panel is visible, and this tab is active (selected), refresh all the data bindings
 | |
|                 Refresh();
 | |
|             }
 | |
| 
 | |
|             if (_optionCanvas != null)
 | |
|             {
 | |
|                 _optionCanvas.enabled = b;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public void SetSelectionModeEnabled(bool isEnabled)
 | |
|         {
 | |
|             if (_selectionModeEnabled == isEnabled)
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             _selectionModeEnabled = isEnabled;
 | |
| 
 | |
|             PinButton.isOn = isEnabled;
 | |
|             PinPromptText.SetActive(isEnabled);
 | |
|             //PinPromptSpacer.SetActive(isEnabled);
 | |
| 
 | |
|             foreach (var kv in _options)
 | |
|             {
 | |
|                 kv.Value.SelectionModeEnabled = isEnabled;
 | |
| 
 | |
|                 // Set IsSelected if entering selection mode.
 | |
|                 if (isEnabled)
 | |
|                 {
 | |
|                     kv.Value.IsSelected = Service.PinnedUI.HasPinned(kv.Key);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             foreach (var cat in _categories)
 | |
|             {
 | |
|                 cat.CategoryGroup.SelectionModeEnabled = isEnabled;
 | |
|             }
 | |
| 
 | |
|             RefreshCategorySelection();
 | |
| 
 | |
|             // Return if entering selection mode
 | |
|             if (isEnabled)
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void Refresh()
 | |
|         {
 | |
|             for (var i = 0; i < _options.Count; i++)
 | |
|             {
 | |
|                 _controls[i].Refresh();
 | |
|                 _controls[i].IsSelected = Service.PinnedUI.HasPinned(_controls[i].Option);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void CommitPinnedOptions()
 | |
|         {
 | |
|             foreach (var kv in _options)
 | |
|             {
 | |
|                 var control = kv.Value;
 | |
| 
 | |
|                 if (control.IsSelected && !Service.PinnedUI.HasPinned(kv.Key))
 | |
|                 {
 | |
|                     Service.PinnedUI.Pin(kv.Key);
 | |
|                 }
 | |
|                 else if (!control.IsSelected && Service.PinnedUI.HasPinned(kv.Key))
 | |
|                 {
 | |
|                     Service.PinnedUI.Unpin(kv.Key);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private bool _isTogglingCategory;
 | |
| 
 | |
|         private void RefreshCategorySelection()
 | |
|         {
 | |
|             _isTogglingCategory = true;
 | |
| 
 | |
|             foreach (var cat in _categories)
 | |
|             {
 | |
|                 var allSelected = true;
 | |
| 
 | |
|                 for (var i = 0; i < cat.Options.Count; i++)
 | |
|                 {
 | |
|                     if (!cat.Options[i].IsSelected)
 | |
|                     {
 | |
|                         allSelected = false;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 cat.CategoryGroup.IsSelected = allSelected;
 | |
|             }
 | |
| 
 | |
|             _isTogglingCategory = false;
 | |
|         }
 | |
| 
 | |
|         private void OnOptionSelectionToggle(bool selected)
 | |
|         {
 | |
|             if (!_isTogglingCategory)
 | |
|             {
 | |
|                 RefreshCategorySelection();
 | |
|                 CommitPinnedOptions();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// When a category mode selection is changed.
 | |
|         /// </summary>
 | |
|         /// <param name="category"></param>
 | |
|         /// <param name="selected"></param>
 | |
|         private void OnCategorySelectionToggle(CategoryInstance category, bool selected)
 | |
|         {
 | |
|             _isTogglingCategory = true;
 | |
| 
 | |
|             for (var i = 0; i < category.Options.Count; i++)
 | |
|             {
 | |
|                 category.Options[i].IsSelected = selected;
 | |
|             }
 | |
| 
 | |
|             _isTogglingCategory = false;
 | |
| 
 | |
|             CommitPinnedOptions();
 | |
|         }
 | |
| 
 | |
|         #region Initialisation
 | |
| 
 | |
|         protected void Populate()
 | |
|         {
 | |
|             var sortedOptions = new Dictionary<string, List<OptionDefinition>>();
 | |
| 
 | |
|             foreach (var option in Service.Options.Options)
 | |
|             {
 | |
|                 // Find a properly list for that category, or create a new one
 | |
|                 List<OptionDefinition> memberList;
 | |
| 
 | |
|                 if (!sortedOptions.TryGetValue(option.Category, out memberList))
 | |
|                 {
 | |
|                     memberList = new List<OptionDefinition>();
 | |
|                     sortedOptions.Add(option.Category, memberList);
 | |
|                 }
 | |
| 
 | |
|                 memberList.Add(option);
 | |
|             }
 | |
| 
 | |
|             var hasCreated = false;
 | |
| 
 | |
|             foreach (var kv in sortedOptions)
 | |
|             {
 | |
|                 if (kv.Value.Count == 0)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 hasCreated = true;
 | |
|                 CreateCategory(kv.Key, kv.Value);
 | |
|             }
 | |
| 
 | |
|             if (hasCreated)
 | |
|             {
 | |
|                 NoOptionsNotice.SetActive(false);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected void CreateCategory(string title, List<OptionDefinition> options)
 | |
|         {
 | |
|             options.Sort((d1, d2) => d1.SortPriority.CompareTo(d2.SortPriority));
 | |
| 
 | |
|             var groupInstance = SRInstantiate.Instantiate(CategoryGroupPrefab);
 | |
|             var categoryInstance = new CategoryInstance(groupInstance);
 | |
| 
 | |
|             _categories.Add(categoryInstance);
 | |
| 
 | |
|             groupInstance.CachedTransform.SetParent(ContentContainer, false);
 | |
|             groupInstance.Header.text = title;
 | |
|             groupInstance.SelectionModeEnabled = false;
 | |
| 
 | |
|             categoryInstance.CategoryGroup.SelectionToggle.onValueChanged.AddListener(
 | |
|                 b => OnCategorySelectionToggle(categoryInstance, b));
 | |
| 
 | |
|             foreach (var option in options)
 | |
|             {
 | |
|                 var control = OptionControlFactory.CreateControl(option, title);
 | |
| 
 | |
|                 if (control == null)
 | |
|                 {
 | |
|                     Debug.LogError("[SRDebugger.OptionsTab] Failed to create option control for {0}".Fmt(option.Name));
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 categoryInstance.Options.Add(control);
 | |
|                 control.CachedTransform.SetParent(groupInstance.Container, false);
 | |
|                 control.IsSelected = Service.PinnedUI.HasPinned(option);
 | |
|                 control.SelectionModeEnabled = false;
 | |
|                 control.SelectionModeToggle.onValueChanged.AddListener(OnOptionSelectionToggle);
 | |
| 
 | |
|                 _options.Add(option, control);
 | |
|                 _controls.Add(control);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void Clear()
 | |
|         {
 | |
|             foreach (var categoryInstance in _categories)
 | |
|             {
 | |
|                 Destroy(categoryInstance.CategoryGroup.gameObject);
 | |
|             }
 | |
| 
 | |
|             _categories.Clear();
 | |
|             _controls.Clear();
 | |
|             _options.Clear();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
|     }
 | |
| }
 |