You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
9.1 KiB
C#

3 weeks ago
using System;
using UnityEngine;
using Sirenix.Utilities;
#if UNITY_EDITOR
using Sirenix.OdinInspector;
using UnityEditor;
using Sirenix.Utilities.Editor;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector.Editor.ValueResolvers;
public class SwitchAttributeDrawer : OdinAttributeDrawer<SwitchAttribute, bool>
{
private const float AnimationSpeedMultiplier = 6f;
private const float SwitchWidth = 28f;
private static readonly int ControlHint = "SwitchControlHint".GetHashCode();
private ValueResolver<Color> backgroundColorOnResolver;
private ValueResolver<Color> backgroundColorOffResolver;
private ValueResolver<Color> switchColorOnResolver;
private ValueResolver<Color> switchColorOffResolver;
private Color backgroundColor;
private Color switchColor;
private float switchPosition;
private Texture whiteTexture;
private bool animating;
private bool hasToggleLeftAttribute;
private string state = "False";
protected override void Initialize()
{
backgroundColorOnResolver = ValueResolver.Get<Color>(Property, Attribute.BackgroundColorOn);
backgroundColorOffResolver = ValueResolver.Get<Color>(Property, Attribute.BackgroundColorOff);
switchColorOnResolver = ValueResolver.Get<Color>(Property, Attribute.SwitchColorOn);
switchColorOffResolver = ValueResolver.Get<Color>(Property, Attribute.SwitchColorOff);
var isOn = ValueEntry.SmartValue;
backgroundColor = isOn ? backgroundColorOnResolver.GetValue() : backgroundColorOffResolver.GetValue();
switchColor = isOn ? switchColorOnResolver.GetValue() : switchColorOffResolver.GetValue();
switchPosition = isOn ? SwitchWidth * 0.5f : 0f;
state = isOn ? "True" : "False";
whiteTexture = Texture2D.whiteTexture;
hasToggleLeftAttribute = Property.Attributes.HasAttribute<ToggleLeftAttribute>();
}
protected override void DrawPropertyLayout(GUIContent label)
{
ValueResolver.DrawErrors(
backgroundColorOnResolver,
backgroundColorOffResolver,
switchColorOnResolver,
switchColorOffResolver);
var backgroundColorOn = backgroundColorOnResolver.GetValue();
var backgroundColorOff = backgroundColorOffResolver.GetValue();
var switchColorOn = switchColorOnResolver.GetValue();
var switchColorOff = switchColorOffResolver.GetValue();
var totalRect = EditorGUILayout.GetControlRect(label != null, EditorGUIUtility.singleLineHeight);
if (label != null && !hasToggleLeftAttribute)
{
totalRect = EditorGUI.PrefixLabel(totalRect, label);
}
var switchBackgroundRect = Attribute.Alignment switch
{
SwitchAlignment.Left => totalRect.AlignLeft(SwitchWidth).AlignCenterY(SwitchWidth * 0.5f),
SwitchAlignment.Right => totalRect.AlignRight(SwitchWidth).AlignCenterY(SwitchWidth * 0.5f),
SwitchAlignment.Center => totalRect.AlignCenterX(SwitchWidth).AlignCenterY(SwitchWidth * 0.5f),
_ => throw new ArgumentException("Invalid enum argument possible values are:\n- SwitchAlignment.Left\n- SwitchAlignment.Right\n- SwitchAlignment.Center")
};
var evt = Event.current;
var isOn = ValueEntry.SmartValue;
var controlID = GUIUtility.GetControlID(ControlHint, FocusType.Keyboard, switchBackgroundRect);
var hasKeyboardFocus = GUIUtility.keyboardControl == controlID;
var targetBackgroundColor = isOn ? backgroundColorOn : backgroundColorOff;
var targetSwitchColor = isOn ? switchColorOn : switchColorOff;
if (ColorHasChanged(targetBackgroundColor, targetSwitchColor))
{
animating = true;
}
if (evt.type == EventType.Layout && animating)
{
backgroundColor = backgroundColor.MoveTowards(
targetBackgroundColor,
GUITimeHelper.LayoutDeltaTime * AnimationSpeedMultiplier);
// EditorTimeHelper.Time.DeltaTime * AnimationSpeedMultiplier);
switchColor = switchColor.MoveTowards(
targetSwitchColor,
GUITimeHelper.LayoutDeltaTime * AnimationSpeedMultiplier);
// EditorTimeHelper.Time.DeltaTime * AnimationSpeedMultiplier);
// GUITimeHelper.LayoutDeltaTime * AnimationSpeedMultiplier);
var targetSwitchPosition = isOn ? SwitchWidth * 0.5f : 0f;
switchPosition = Mathf.MoveTowards(
switchPosition,
targetSwitchPosition,
GUITimeHelper.LayoutDeltaTime * AnimationSpeedMultiplier * SwitchWidth * 0.5f);
// EditorTimeHelper.Time.DeltaTime * AnimationSpeedMultiplier * SwitchWidth * 0.5f);
if (backgroundColor == targetBackgroundColor
&& switchColor == targetSwitchColor
&& switchPosition == targetSwitchPosition)
{
animating = false;
}
GUIHelper.RequestRepaint();
}
else if (evt.OnMouseDown(switchBackgroundRect, 0))
{
GUIUtility.hotControl = controlID;
GUIUtility.keyboardControl = controlID;
}
else if (evt.OnMouseUp(switchBackgroundRect, 0))
{
GUIUtility.hotControl = 0;
GUIUtility.keyboardControl = 0;
ChangeValueTo(!isOn);
}
else if (hasKeyboardFocus && evt.type == EventType.KeyDown)
{
switch (evt.keyCode)
{
case KeyCode.Return:
case KeyCode.Space:
ChangeValueTo(!isOn);
break;
case KeyCode.LeftArrow:
ChangeValueTo(false);
break;
case KeyCode.RightArrow:
ChangeValueTo(true);
break;
}
}
var finalBackgroundColor = hasKeyboardFocus ? Darken(backgroundColor, 1.5f) : backgroundColor;
var borderRadius = Attribute.Rounded ? 99f : 0f;
GUI.DrawTexture(switchBackgroundRect, whiteTexture, ScaleMode.StretchToFill, true, 0f, finalBackgroundColor, 0f, borderRadius);
var finalSwitchColor = hasKeyboardFocus ? Darken(switchColor, 1.5f) : switchColor;
var switchRect = switchBackgroundRect.SetWidth(SwitchWidth * 0.5f).Padding(SwitchWidth * 0.07f).AddX(switchPosition);
GUI.DrawTexture(switchRect, whiteTexture, ScaleMode.StretchToFill, true, 0f, finalSwitchColor, 0f, borderRadius);
if (hasToggleLeftAttribute)
{
EditorGUI.LabelField(totalRect.AddX(SwitchWidth + 4f), label);
}
GUI.Label(totalRect.AddX(SwitchWidth + 4f), state);
}
private void ChangeValueTo(bool newValue)
{
ValueEntry.SmartValue = newValue;
animating = true;
state = newValue ? "True" : "False";
}
private bool ColorHasChanged(Color targetBackgroundColor, Color targetSwitchColor)
=> backgroundColor != targetBackgroundColor || switchColor != targetSwitchColor;
private Color Darken(Color color, float factor)
=> new Color(color.r / factor, color.g / factor, color.b / factor);
}
#endif
public class SwitchAttribute : Attribute
{
private static readonly string DefaultBackgroundColorOn = "@new Color(0.8f, 0.8f, 0.9f)";
private static readonly string DefaultBackgroundColorOff = "@new Color(0f, 0f, 0f)";
private static readonly string DefaultSwitchColorOn = DefaultBackgroundColorOff;
private static readonly string DefaultSwitchColorOff = DefaultBackgroundColorOn;
public string BackgroundColorOn = null;
public string BackgroundColorOff = null;
public string SwitchColorOn = null;
public string SwitchColorOff = null;
public bool Rounded;
public SwitchAlignment Alignment;
public SwitchAttribute(
SwitchAlignment alignment,
string backgroundColorOn = null,
string backgroundColorOff = null,
string switchColorOn = null,
string switchColorOff = null,
bool rounded = true)
{
Alignment = alignment;
Rounded = rounded;
SetColors(backgroundColorOn, backgroundColorOff, switchColorOn, switchColorOff);
}
public SwitchAttribute(
string backgroundColorOn = null,
string backgroundColorOff = null,
string switchColorOn = null,
string switchColorOff = null,
bool rounded = true)
{
Alignment = SwitchAlignment.Left;
Rounded = rounded;
SetColors(backgroundColorOn, backgroundColorOff, switchColorOn, switchColorOff);
}
private void SetColors(
string backgroundColorOn,
string backgroundColorOff,
string switchColorOn,
string switchColorOff)
{
BackgroundColorOn = backgroundColorOn ?? DefaultBackgroundColorOn;
BackgroundColorOff = backgroundColorOff ?? DefaultBackgroundColorOff;
SwitchColorOn = switchColorOn ?? backgroundColorOff ?? DefaultSwitchColorOn;
SwitchColorOff = switchColorOff ?? backgroundColorOn ?? DefaultSwitchColorOff;
}
}
public enum SwitchAlignment
{
Left,
Right,
Center,
}