A game about forced loneliness, made by TACStudios
1using System;
2using UnityEngine;
3
4namespace UnityEditor.TestTools.TestRunner.GUI.Controls
5{
6 /// <summary>
7 /// A flag enum content provider to be used with the <see cref="SelectionDropDown" /> control.
8 /// </summary>
9 /// <typeparam name="T">The flag enum type.</typeparam>
10 internal class FlagEnumContentProvider<T> : ISelectionDropDownContentProvider where T : Enum
11 {
12 private readonly Action<T> m_ValueChangedCallback;
13 private readonly T[] m_Values;
14 internal Func<string, string> DisplayNameGenerator = ObjectNames.NicifyVariableName;
15 private T m_CurrentValue;
16
17 /// <summary>
18 /// Creates a new instance of the <see cref="FlagEnumContentProvider{T}" /> class.
19 /// </summary>
20 /// <param name="initialValue">The initial selection value.</param>
21 /// <param name="valueChangedCallback">The callback to be invoked on selection change.</param>
22 /// <exception cref="ArgumentException">
23 /// Thrown if the generic enum parameter type is not integer based
24 /// or if the initial selection value is empty.
25 /// </exception>
26 /// <exception cref="ArgumentNullException">Thrown if the provided change callback is null.</exception>
27 public FlagEnumContentProvider(T initialValue, Action<T> valueChangedCallback)
28 {
29 if (Enum.GetUnderlyingType(typeof(T)) != typeof(int))
30 {
31 throw new ArgumentException("Argument underlying type must be integer.");
32 }
33
34 if ((int)(object)initialValue == 0)
35 {
36 throw new ArgumentException("The initial value must not be an empty set.", nameof(initialValue));
37 }
38
39 if (valueChangedCallback == null)
40 {
41 throw new ArgumentNullException(nameof(valueChangedCallback), "The value change callback must not be null.");
42 }
43
44 m_CurrentValue = initialValue;
45 m_Values = (T[])Enum.GetValues(typeof(T));
46 m_ValueChangedCallback = valueChangedCallback;
47 }
48
49 public int Count => m_Values.Length;
50 public bool IsMultiSelection => true;
51
52 public string GetName(int index)
53 {
54 return ValidateIndexBounds(index) ? DisplayNameGenerator(m_Values[index].ToString()) : string.Empty;
55 }
56
57 public int[] SeparatorIndices => new int[0];
58
59 public bool IsSelected(int index)
60 {
61 return ValidateIndexBounds(index) && IsSet(m_Values[index]);
62 }
63
64 public void SelectItem(int index)
65 {
66 if (!ValidateIndexBounds(index))
67 {
68 return;
69 }
70
71 if (ChangeValue(m_Values[index]))
72 {
73 m_ValueChangedCallback(m_CurrentValue);
74 }
75 }
76
77 private bool ChangeValue(T flag)
78 {
79 var value = flag;
80 var count = GetSetCount();
81
82 if (IsSet(value))
83 {
84 if (count == 1)
85 {
86 return false;
87 }
88
89 m_CurrentValue = FlagEnumUtility.RemoveFlag(m_CurrentValue, flag);
90 return true;
91 }
92
93 m_CurrentValue = FlagEnumUtility.SetFlag(m_CurrentValue, flag);
94 return true;
95 }
96
97 private bool IsSet(T flag)
98 {
99 return FlagEnumUtility.HasFlag(m_CurrentValue, flag);
100 }
101
102 private int GetSetCount()
103 {
104 return BitUtility.GetCardinality((int)(object)m_CurrentValue);
105 }
106
107 private bool ValidateIndexBounds(int index)
108 {
109 if (index < 0 || index >= Count)
110 {
111 Debug.LogError($"Requesting item index {index} from a collection of size {Count}");
112 return false;
113 }
114
115 return true;
116 }
117 }
118}