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