Skip to content
Snippets Groups Projects
DisplayFacts.cs 7.58 KiB
Newer Older
  • Learn to ignore specific revisions
  • using System.Collections.Generic;
    
    BenniHome's avatar
    BenniHome committed
    using UnityEngine;
    
    using System.Linq;
    using UnityEngine.UI;
    
    using MoreLinq;
    using System.ComponentModel;
    using UnityEditor;
    
    using static CommunicationEvents;
    
    BenniHome's avatar
    BenniHome committed
    
    
    public class DisplayFacts : MonoBehaviour, ISerializationCallbackReceiver
    
    BenniHome's avatar
    BenniHome committed
    {
    
        private static DisplayFacts _instance;
        public static DisplayFacts Instance
        {
            get => _instance;
            private set { _instance ??= value; }
        }
    
    
    MaZiFAU's avatar
    MaZiFAU committed
        public static Transform FactscreenContent => Instance.factscreenContent;
        public static GameObject FactSpotPrefab => Instance.factSpotPrefab;
    
    
        //cannot populate static dict while serialization => "singelton"
        public static Dictionary<Type, GameObject> PrefabDictionary { get => Instance._PrefabDictionary; }
        private Dictionary<Type, GameObject> _PrefabDictionary = new();
    
    
        public static Dictionary<string, GameObject> displayedFacts = new();
    
    BenniHome's avatar
    BenniHome committed
    
    
        [SerializeField] private Transform factscreenContent;
    
        [SerializeField] private GameObject factSpotPrefab;
    
    
        private bool sortDescending = false;
    
        private bool showGrouped = false;
    
        private bool showOnlyFavorites = false;
    
        #region ISerializationCallbackReceiver
        [ReadOnly(true), SerializeField]
        private List<string> PrefabtTypeReadonly;
        [SerializeField]
        private List<GameObject> PrefabDataConfig;
    
        public void OnBeforeSerialize()
        {
            PrefabtTypeReadonly = TypeExtensions<Fact>.UAssemblyInheritenceTypes.Select(type => type.ToString()).ToList();
            PrefabtTypeReadonly.Sort(); //for convinience
    
            // if order has changed => do not forget
            var keys = _PrefabDictionary.Keys.Select(type => type.ToString()).ToList();
            var keys_permutation = PrefabtTypeReadonly.Select(type => keys.IndexOf(type)).ToArray();
    
            var vals = _PrefabDictionary.Values.ToArray();
            PrefabDataConfig = new(keys_permutation.Length);
            for (int i = 0; i < keys_permutation.Length; i++)
            {
                GameObject data = keys_permutation[i] < 0
                    ? null
                    : vals[keys_permutation[i]];
    
                if (PrefabDataConfig.Count <= i)
                    PrefabDataConfig.Add(data);
                else
                    PrefabDataConfig[i] = data;
            }
        }
    
        public void OnAfterDeserialize()
        {
            _PrefabDictionary = new();
            for (int i = 0; i != Math.Min(PrefabtTypeReadonly.Count, PrefabDataConfig.Count); i++)
    
                _PrefabDictionary.TryAdd(
                    TypeExtensions<Fact>.UAssemblyInheritenceTypes.FirstOrDefault(type => type.ToString() == PrefabtTypeReadonly[i]),
                    PrefabDataConfig[i]
                );
    
        }
        #endregion ISerializationCallbackReceiver
    
        #region UnityMethods
    
        void Awake()
    
    BenniHome's avatar
    BenniHome committed
        {
    
            Instance = this; //first come, first serve
    
    John Schihada's avatar
    John Schihada committed
    
    
        private void OnEnable()
        {
    
            AddFactEvent.AddListener(AddFact);
    
            RemoveFactEvent.AddListener(RemoveFact);
    
            FactFavorisation.ChangeFavoriteEvent.AddListener(OnFavoriteChange);
    
    BenniHome's avatar
    BenniHome committed
        }
    
    
        private void OnDisable()
        {
            AddFactEvent.RemoveListener(AddFact);
            RemoveFactEvent.RemoveListener(RemoveFact);
            FactFavorisation.ChangeFavoriteEvent.RemoveListener(OnFavoriteChange);
        }
    
        private void RemoveFact(Fact fact)
            => displayedFacts.Remove(fact.Id);
    
        #endregion UnityMethods
    
    BenniHome's avatar
    BenniHome committed
    
    
        public void AddFact(Fact fact)
        {
    
            // index where the new display will be inserted
            int siblingIdx = sortDescending ? 0 : factscreenContent.childCount;
    
                var facts = factscreenContent.GetComponentsInChildren<FactObject>().Select(f => f.Fact).ToList();
    
                if (!sortDescending)
                    siblingIdx = GetIndexInSortedList(fact, facts);
                else
                {
                    facts.Reverse();
                    var _siblingIdx = GetIndexInSortedList(fact, facts);
                    siblingIdx = factscreenContent.childCount - _siblingIdx;
                }
    
    MaZiFAU's avatar
    MaZiFAU committed
            var display = CreateDisplay(fact, factscreenContent);
    
            display.transform.localPosition = Vector3.zero;
    
            displayedFacts.TryAdd(fact.Id, display);
    
    MaZiFAU's avatar
    MaZiFAU committed
            display.transform.parent.gameObject.SetActive(
                !showOnlyFavorites
                || display.GetComponent<FactFavorisation>().IsFavorite
            );
    
            display.transform.parent.transform.SetSiblingIndex(siblingIdx);
    
    MaZiFAU's avatar
    MaZiFAU committed
        public static GameObject CreateDisplay(Fact fact, Transform transform)
        {
            var spot = Instantiate(FactSpotPrefab, transform);
            spot.GetComponent<FactWrapper>().Fact = fact;
    
    MaZiFAU's avatar
    MaZiFAU committed
            return InstantiateDisplay(fact, spot.transform);
    
        }
    
        public static GameObject InstantiateDisplay(Fact fact, Transform transform)
    
            Type fact_type = fact.GetType();
    
            if (fact_type.IsConstructedGenericType)
    
                fact_type = fact_type.GetGenericTypeDefinition();
    
    
            var ret = Instantiate(PrefabDictionary[fact_type], transform);
            ret.GetComponent<FactObject>().Fact = fact;
    
            return ret;
    
    BenniHome's avatar
    BenniHome committed
        }
    
    
        #region Sorting
        #region AscDesc
        public void AscDescChanged(Toggle t)
    
    BenniHome's avatar
    BenniHome committed
        {
    
            sortDescending = !sortDescending;
    
            factscreenContent.gameObject.ForAllChildren(child => child.transform.SetAsFirstSibling());
    
    
        #region Grouping
        public void GroupingChanged(Toggle t)
        {
            showGrouped = t.isOn;
    
    
            var vals = factscreenContent.gameObject.GetDirectChildren();
            var ordered = showGrouped
    
                ? vals.OrderBy(tr => tr.GetComponent<FactObject>().Fact, new FactTypeComparer()).ToList()
                : vals.OrderBy(tr => displayedFacts.Keys.ToList().IndexOf(tr.GetComponent<FactObject>().Fact.Id)).ToList();
    
            if (sortDescending)
                ordered.Reverse();
    
    
            for (int i = 0; i < ordered.Count; i++)
                ordered[i].transform.SetSiblingIndex(i);
        }
    
        private int GetIndexInSortedList(Fact f, List<Fact> toCheck)
        {
            var index = toCheck.BinarySearch(f, new FactTypeComparer());
            if (index < 0) index = ~index;
            return index;
        }
    
        internal class FactTypeComparer : IComparer<Fact>
        {
            /// <summary>
            /// Compare two facts by type and label
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public int Compare(Fact x, Fact y)
            {
                if (x.GetType() == y.GetType()) // same type: compare labels
                    return string.Compare(x.Label, y.Label);
                else // different types: compare type
                    return string.Compare(x.GetType().ToString(), y.GetType().ToString());
            }
        }
        #endregion Grouping
    
        #endregion Sorting
    
        #region Favorites
        public void FavoritesFilterChanged(Toggle t)
        {
            showOnlyFavorites = t.isOn;
    
            if (!showOnlyFavorites) // show all
    
                displayedFacts.Values.ForEach(nFav => nFav.transform.parent.gameObject.SetActive(true));
    
            {   // hide not favorites
                displayedFacts.Values
    
    MaZiFAU's avatar
    MaZiFAU committed
                     .Where(gO => gO != null && !gO.GetComponent<FactFavorisation>().IsFavorite)
    
                     .ForEach(nFav => nFav.transform.parent.gameObject.SetActive(false));
    
            }
        }
    
        private void OnFavoriteChange(Fact changedFact, bool isFavourite)
        {
            if (!showOnlyFavorites)
                return;
    
            var id = changedFact.Id;
            if (displayedFacts.ContainsKey(id))
                displayedFacts[id].transform.parent.gameObject.SetActive(isFavourite);
        }
        #endregion Favorites
    
    
        #endregion Implementation