Car/Assets/VolumetricLightBeam/Editor/EditorExtensions.cs

335 lines
13 KiB
C#
Raw Normal View History

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
namespace VLB
{
public static class EditorExtensions
{
public static class SD
{
public static GameObject NewBeam() { return new GameObject("Volumetric Light Beam SD", typeof(VolumetricLightBeamSD)); }
public static GameObject NewBeam2D()
{
var gao = new GameObject("Volumetric Light Beam SD (2D)", typeof(VolumetricLightBeamSD));
gao.GetComponent<VolumetricLightBeamSD>().dimensions = Dimensions.Dim2D;
return gao;
}
public static GameObject NewBeamAndDust() { return new GameObject("Volumetric Light Beam SD + Dust", typeof(VolumetricLightBeamSD), typeof(VolumetricDustParticles)); }
public static GameObject NewSpotLightAndBeam()
{
var light = Utils.NewWithComponent<Light>("Spotlight and Beam SD");
light.type = LightType.Spot;
var gao = light.gameObject;
gao.AddComponent<VolumetricLightBeamSD>();
return gao;
}
}
public static class HD
{
public static GameObject NewBeam() { return new GameObject("Volumetric Light Beam HD", typeof(VolumetricLightBeamHD)); }
public static GameObject NewBeam2D() { return new GameObject("Volumetric Light Beam HD (2D)", typeof(VolumetricLightBeamHD2D)); }
public static GameObject NewBeamAndDust() { return new GameObject("Volumetric Light Beam HD + Dust", typeof(VolumetricLightBeamHD), typeof(VolumetricDustParticles)); }
public static GameObject NewSpotLightAndBeam()
{
var light = Utils.NewWithComponent<Light>("Spotlight and Beam HD");
light.type = LightType.Spot;
var gao = light.gameObject;
gao.AddComponent<VolumetricLightBeamHD>().scalable = false;
return gao;
}
}
public static void OnNewGameObjectCreated(GameObject gao, MenuCommand menuCommand)
{
Debug.Assert(gao != null);
Debug.Assert(menuCommand != null);
OnNewGameObjectCreated(gao, menuCommand.context as GameObject);
}
public static void OnNewGameObjectCreated(GameObject gao, GameObject parentGao)
{
Debug.Assert(gao != null);
if (parentGao == null)
{
#if UNITY_2021_2_OR_NEWER
var currentPrefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
#else
var currentPrefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
#endif
if (currentPrefabStage != null)
{
// The user is in prefab mode without any GAO selected in the hierarchy. Get the current prefab root as parent.
parentGao = currentPrefabStage.prefabContentsRoot;
}
}
GameObjectUtility.SetParentAndAlign(gao, parentGao); // Ensure it gets reparented if this was a context click (otherwise does nothing)
Undo.RegisterCreatedObjectUndo(gao, "Create " + gao.name); // Register the creation in the undo system
Selection.activeObject = gao;
}
public static bool CanAddComponentFromEditor<TComp>(VolumetricLightBeamAbstractBase self) where TComp : Component
{
return !Application.isPlaying && self != null && self.GetComponent<TComp>() == null;
}
public static void AddComponentFromEditor<TComp>(VolumetricLightBeamAbstractBase self) where TComp : Component
{
if (CanAddComponentFromEditor<TComp>(self))
{
/*var comp =*/ Undo.AddComponent<TComp>(self.gameObject);
}
}
/// <summary>
/// Add a EditorGUILayout.ToggleLeft which properly handles multi-object editing
/// </summary>
public static void ToggleLeft(this SerializedProperty prop, GUIContent label, params GUILayoutOption[] options)
{
ToggleLeft(prop, label, prop.boolValue, options);
}
public static void ToggleLeft(this SerializedProperty prop, GUIContent label, bool forcedValue, params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
var newValue = EditorGUILayout.ToggleLeft(label, forcedValue, options);
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
prop.boolValue = newValue;
}
public static bool HasAtLeastOneValue(this SerializedProperty prop, bool value)
{
return (prop.boolValue == value) || prop.hasMultipleDifferentValues;
}
public static bool HasAtLeastOnePositiveValue(this SerializedProperty prop)
{
return (prop.floatValue >= 0.0f) || prop.hasMultipleDifferentValues;
}
/// <summary>
/// Create a EditorGUILayout.Slider which properly handles multi-object editing
/// We apply the 'convIn' conversion to the SerializedProperty value before exposing it as a Slider.
/// We apply the 'convOut' conversion to the Slider value to get the SerializedProperty back.
/// </summary>
/// <param name="prop">The value the slider shows.</param>
/// <param name="label">Label in front of the slider.</param>
/// <param name="leftValue">The value at the left end of the slider.</param>
/// <param name="rightValue">The value at the right end of the slider.</param>
/// <param name="convIn">Conversion applied on the SerializedProperty to get the Slider value</param>
/// <param name="convOut">Conversion applied on the Slider value to get the SerializedProperty</param>
public static bool FloatSlider(
this SerializedProperty prop,
GUIContent label,
float leftValue, float rightValue,
System.Func<float, float> convIn,
System.Func<float, float> convOut,
params GUILayoutOption[] options)
{
var floatValue = convIn(prop.floatValue);
EditorGUI.BeginChangeCheck();
{
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
{
floatValue = EditorGUILayout.Slider(label, floatValue, leftValue, rightValue, options);
}
EditorGUI.showMixedValue = false;
}
if (EditorGUI.EndChangeCheck())
{
prop.floatValue = convOut(floatValue);
return true;
}
return false;
}
public static bool FloatSlider(
this SerializedProperty prop,
GUIContent label,
float leftValue, float rightValue,
params GUILayoutOption[] options)
{
var floatValue = prop.floatValue;
EditorGUI.BeginChangeCheck();
{
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
{
floatValue = EditorGUILayout.Slider(label, floatValue, leftValue, rightValue, options);
}
EditorGUI.showMixedValue = false;
}
if (EditorGUI.EndChangeCheck())
{
prop.floatValue = floatValue;
return true;
}
return false;
}
/*
public static void ToggleFromLight(this SerializedProperty prop)
{
ToggleLeft(
prop,
new GUIContent("From Spot", "Get the value from the Light Spot"),
GUILayout.MaxWidth(80.0f));
}
*/
public static void ToggleUseGlobalNoise(this SerializedProperty prop)
{
ToggleLeft(
prop,
new GUIContent("Global", "Get the value from the Global 3D Noise"),
GUILayout.MaxWidth(55.0f));
}
public static void CustomEnum<EnumType>(this SerializedProperty prop, GUIContent content, string[] descriptions = null)
{
if(descriptions == null)
descriptions = System.Enum.GetNames(typeof(EnumType));
Debug.Assert(System.Enum.GetNames(typeof(EnumType)).Length == descriptions.Length, string.Format("Enum '{0}' and the description array don't have the same size", typeof(EnumType)));
int enumValueIndex = prop.enumValueIndex;
EditorGUI.BeginChangeCheck();
{
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
{
#if UNITY_2018_1_OR_NEWER
enumValueIndex = EditorGUILayout.Popup(content, enumValueIndex, descriptions);
#else
enumValueIndex = EditorGUILayout.Popup(content.text, enumValueIndex, descriptions);
#endif
}
EditorGUI.showMixedValue = false;
}
if (EditorGUI.EndChangeCheck())
prop.enumValueIndex = enumValueIndex;
}
public static void CustomMask<EnumType>(this SerializedProperty prop, GUIContent content, string[] descriptions = null)
{
if (descriptions == null)
descriptions = System.Enum.GetNames(typeof(EnumType));
Debug.Assert(System.Enum.GetNames(typeof(EnumType)).Length == descriptions.Length, string.Format("Enum '{0}' and the description array don't have the same size", typeof(EnumType)));
int intValue = prop.intValue;
EditorGUI.BeginChangeCheck();
{
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
{
intValue = EditorGUILayout.MaskField(content, intValue, descriptions);
}
EditorGUI.showMixedValue = false;
}
if (EditorGUI.EndChangeCheck())
prop.intValue = intValue;
}
public static void DrawLineSeparator()
{
DrawLineSeparator(Color.grey, 1, 10);
}
static void DrawLineSeparator(Color color, int thickness = 2, int padding = 10)
{
Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
r.x = 0;
r.width = EditorGUIUtility.currentViewWidth;
r.y += padding / 2;
r.height = thickness;
EditorGUI.DrawRect(r, color);
}
public static bool GlobalToggleButton(ref bool boolean, GUIContent content, string saveString, float maxWidth = 999.0f)
{
EditorGUI.BeginChangeCheck();
boolean = GUILayout.Toggle(boolean, content, EditorStyles.miniButton, GUILayout.MaxWidth(maxWidth));
if (EditorGUI.EndChangeCheck())
{
EditorPrefs.SetBool(saveString, boolean);
SceneView.RepaintAll();
return true;
}
return false;
}
public abstract class EditorGUIWidth : System.IDisposable
{
protected abstract void ApplyWidth(float width);
public EditorGUIWidth(float width) { ApplyWidth(width); }
public void Dispose() { ApplyWidth(0.0f); }
}
public class LabelWidth : EditorGUIWidth
{
public LabelWidth(float width) : base(width) { }
protected override void ApplyWidth(float width) { EditorGUIUtility.labelWidth = width; }
}
public class FieldWidth : EditorGUIWidth
{
public FieldWidth(float width) : base(width) { }
protected override void ApplyWidth(float width) { EditorGUIUtility.fieldWidth = width; }
}
public class ShowMixedValue : System.IDisposable
{
public ShowMixedValue(bool? value) { m_PrevValue = EditorGUI.showMixedValue; EditorGUI.showMixedValue = value ?? false; }
public ShowMixedValue(SerializedProperty prop) : this(prop?.hasMultipleDifferentValues) { }
public void Dispose() { EditorGUI.showMixedValue = m_PrevValue; }
bool m_PrevValue = false;
}
private static ArcHandle ms_ArcHandle = null;
// HANDLES
public static ArcHandle DrawHandleRadius(float radius)
{
if (ms_ArcHandle == null)
ms_ArcHandle = new ArcHandle();
ms_ArcHandle.SetColorWithRadiusHandle(Color.white, 0f);
ms_ArcHandle.angle = 360f;
ms_ArcHandle.angleHandleSizeFunction = null;
ms_ArcHandle.angleHandleColor = Color.clear;
ms_ArcHandle.radius = radius;
ms_ArcHandle.DrawHandle();
return ms_ArcHandle;
}
public static ArcHandle DrawHandleSpotAngle(float angle, float radius)
{
if (ms_ArcHandle == null)
ms_ArcHandle = new ArcHandle();
ms_ArcHandle.angleHandleSizeFunction = ArcHandle.DefaultAngleHandleSizeFunction;
ms_ArcHandle.SetColorWithRadiusHandle(Handles.color, Handles.color.maxColorComponent < 0.5f ? 0.25f : 0.1f);
ms_ArcHandle.angleHandleColor = Handles.color;
ms_ArcHandle.radius = radius;
ms_ArcHandle.angle = angle;
ms_ArcHandle.DrawHandle();
return ms_ArcHandle;
}
}
}
#endif