-
MaZiFAU authored
ListFact: +Intrduction, needed for lists on MMT server side +Incomplete +-> see SOMDocManager.MMT_OMS_URI.FactRef Bug Fix: +Fact Ordering was broken +ScrollFactContainer marked as IsSet wrongly +Angle Hint showed up with 0° HotFix; +Game Crash when Scrolls not loaded +-> patched with guard clausel (pls find better way)
MaZiFAU authoredListFact: +Intrduction, needed for lists on MMT server side +Incomplete +-> see SOMDocManager.MMT_OMS_URI.FactRef Bug Fix: +Fact Ordering was broken +ScrollFactContainer marked as IsSet wrongly +Angle Hint showed up with 0° HotFix; +Game Crash when Scrolls not loaded +-> patched with guard clausel (pls find better way)
DisplayFacts.cs 9.15 KiB
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
using UnityEngine.UI;
using MoreLinq;
using System.ComponentModel;
using UnityEditor;
using static CommunicationEvents;
public class DisplayFacts : MonoBehaviour, ISerializationCallbackReceiver
{
private static DisplayFacts _instance;
public static DisplayFacts Instance
{
get => _instance;
private set { _instance ??= value; }
}
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();
[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++)
// if (PrefabDataConfig[i] != null)
_PrefabDictionary.TryAdd(
TypeExtensions<Fact>.UAssemblyInheritenceTypes.FirstOrDefault(type => type.ToString() == PrefabtTypeReadonly[i]),
PrefabDataConfig[i]
);
}
#endregion ISerializationCallbackReceiver
#region UnityMethods
void Awake()
{
Instance = this; //first come, first serve
}
private void OnEnable()
{
AddFactEvent.AddListener(AddFact);
RemoveFactEvent.AddListener(RemoveFact);
FactFavorisation.ChangeFavoriteEvent.AddListener(OnFavoriteChange);
}
private void OnDisable()
{
AddFactEvent.RemoveListener(AddFact);
RemoveFactEvent.RemoveListener(RemoveFact);
FactFavorisation.ChangeFavoriteEvent.RemoveListener(OnFavoriteChange);
}
private void RemoveFact(Fact fact)
=> displayedFacts.Remove(fact.Id);
#endregion UnityMethods
#region Implementation
public void AddFact(Fact fact)
{
// index where the new display will be inserted
int siblingIdx = sortDescending ? 0 : factscreenContent.childCount;
if (showGrouped)
{
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;
}
}
// create display
var display = CreateDisplay(fact, factscreenContent);
display.transform.localPosition = Vector3.zero;
displayedFacts.TryAdd(fact.Id, display);
display.transform.parent.gameObject.SetActive(
!showOnlyFavorites
|| display.GetComponent<FactFavorisation>().IsFavorite
);
display.transform.parent.transform.SetSiblingIndex(siblingIdx);
}
public static GameObject CreateDisplay(Fact fact, Transform transform)
{
var spot = Instantiate(FactSpotPrefab, transform);
spot.GetComponent<FactWrapper>().Fact = fact;
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;
}
#region Sorting
#region AscDesc
public void AscDescChanged(Toggle t)
{
sortDescending = !sortDescending; // t.isOn
factscreenContent.gameObject.ForAllChildren(child => child.transform.SetAsFirstSibling());
}
#endregion AscDesc
#region Grouping
public void GroupingChanged(Toggle t)
{
showGrouped = t.isOn;
var vals = factscreenContent.gameObject.GetDirectChildren();
var ordered = showGrouped
? vals.OrderBy(tr => tr.GetComponent<FactWrapper>().Fact, new FactTypeComparer()).ToList()
: vals.OrderBy(tr =>
displayedFacts.Keys.ToList()
.IndexOf(
tr.GetComponent<FactWrapper>().URI
)).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;
}
private 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)
{
int ret, index_x;
#pragma warning disable CS0642 // Möglicherweise falsche leere Anweisung
if (0 != (ret = (index_x = TypeRank.IndexOf(x.GetType())) - TypeRank.IndexOf(y.GetType()))) ;
else
if (index_x < 0) // Types not in List and same
if (0 != (ret = x.DependentFactIds.Length - y.DependentFactIds.Length)) ;
else
if (0 != (ret = string.Compare(x.GetType().ToString(), y.GetType().ToString()))) ;
else;
else if (true) // keep auto format // Types in List and same
if (0 != (ret = x.DependentFactIds.Zip(y.DependentFactIds, (x, y) => string.Compare(x, y)).Aggregate(0, (r1, r2) => r1 + r2))) ;
else
if (0 != (ret = string.Compare(x.Label, y.Label))) ;
#pragma warning restore CS0642 // Möglicherweise falsche leere Anweisung
return ret;
}
private List<Type> TypeRank = new()
{
typeof(PointFact),
typeof(OnLineFact),
typeof(LineFact),
typeof(RayFact),
typeof(ParallelLineFact),
typeof(RightAngleFact),
typeof(AngleFact),
typeof(CircleFact),
typeof(RadiusFact),
typeof(AreaCircleFact),
typeof(EqualCirclesFact),
typeof(UnEqualCirclesFact),
typeof(OnCircleFact),
typeof(AngleCircleLineFact),
typeof(OrthogonalCircleLineFact),
typeof(CylinderVolumeFact),
typeof(ConeVolumeFact),
typeof(TruncatedConeVolumeFact),
typeof(FunctionFact),
typeof(FunctionCallFact),
typeof(AttachedPositionFunction),
typeof(TestFact),
};
}
#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));
else
{ // hide not favorites
displayedFacts.Values
.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;
if (displayedFacts.TryGetValue(changedFact.Id, out GameObject display))
display.transform.parent.gameObject.SetActive(isFavourite);
}
#endregion Favorites
#endregion Implementation
}