using System; namespace UnityEditor.Rendering { /// Used in editor drawer part to store the state of expandable areas. /// An enum to use to describe the state. public abstract class ExpandedStateBase where TState : struct, IConvertible { /// Accessor to the expended state of this specific mask. /// The filtering mask /// True: All flagged area are expended public abstract bool GetExpandedAreas(TState mask); /// Setter to the expended state. /// The filtering mask /// The expended state to set public abstract void SetExpandedAreas(TState mask, bool value); /// Utility to set all states to true public abstract void ExpandAll(); /// Utility to set all states to false public abstract void CollapseAll(); /// Get or set the state given the mask. /// The filtering mask /// True: All flagged area are expended public bool this[TState mask] { get => GetExpandedAreas(mask); set => SetExpandedAreas(mask, value); } } /// Used in editor drawer part to store the state of expandable areas using EditorPrefBoolFlags. /// An enum to use to describe the state. /// A type given to automatically compute the key. public class ExpandedState : ExpandedStateBase where TState : struct, IConvertible { /// /// The variable which stores the state of expandable areas. /// protected internal EditorPrefBoolFlags m_State; /// /// Constructor will create the key to store in the EditorPref the state given generic type passed. /// The key will be formated as such prefix:TTarget:TState:UI_State. /// /// If key did not exist, it will be created with this value for initialization. /// [Optional] Prefix scope of the key (Default is CoreRP) /// [Optional] Postfix used to differentiate between different keys (Default is UI_State) public ExpandedState(TState defaultValue, string prefix = "CoreRP", string stateId = "UI_State") { string key = $"{prefix}:{typeof(TTarget).Name}:{typeof(TState).Name}:{stateId}"; m_State = new EditorPrefBoolFlags(key); //register key if not already there if (!EditorPrefs.HasKey(key)) { EditorPrefs.SetInt(key, (int)(object)defaultValue); } } /// public override bool GetExpandedAreas(TState mask) { return m_State.HasFlag(mask); } /// public override void SetExpandedAreas(TState mask, bool value) { m_State.SetFlag(mask, value); } /// public override void ExpandAll() { m_State.rawValue = uint.MaxValue; } /// public override void CollapseAll() { m_State.rawValue = 0u; } } /// Used in editor drawer part to store the state of expandable areas using EditorPrefBoolFlags for a list of elements. /// A type given to automatically compute the key. public class ExpandedStateList : ExpandedState { /// /// Constructor will create the key to store in the EditorPref the state given generic type passed. /// The key will be formated as such prefix:TTarget:TState:UI_State. /// /// [Optional] Prefix scope of the key (Default is CoreRP) public ExpandedStateList(string prefix = "CoreRP") : base(default(int), prefix, "UI_State_List") { } /// /// Swap flag between src index and dst index. /// /// src index to swap. /// dst index to swap. public void SwapFlags(int srcIndex, int dstIndex) { int srcFlag = 1 << srcIndex; int dstFlag = 1 << dstIndex; bool srcVal = GetExpandedAreas(srcFlag); SetExpandedAreas(srcFlag, GetExpandedAreas(dstFlag)); SetExpandedAreas(dstFlag, srcVal); } /// Removes a flag at a given index which causes the following flags' index to decrease by one. /// The index of the flag to be removed. public void RemoveFlagAtIndex(int index) { m_State.rawValue = RightShiftOnceFromIndexToMSB(index, m_State.rawValue); } /// Utility to logical right shift every bit from the index flag to MSB resulting in the index flag being shifted out.<\summary> /// Right shift every bit greater or equal to the index. /// Value to make the operations on. /// The right shift value after the given index. internal static uint RightShiftOnceFromIndexToMSB(int index, uint value) { // Example of each operation: // 1011 1001 - Value uint indexBit = 1u << index; // 0000 1000 - Index bit uint remainArea = indexBit - 1u; // 0000 0111 uint remainBits = remainArea & value; // 0000 0001 uint movedBits = (~remainArea - indexBit & value) >> 1; // 1111 1000 // 1111 0000 // 1011 0000 // 0101 1000 return movedBits | remainBits; // 0101 1001 - Result } } }