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
 | 
						|
    }
 | 
						|
}
 |