-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
namespace EasyButtons.Editor | ||
{ | ||
using System.Reflection; | ||
using JetBrains.Annotations; | ||
using UnityEditor; | ||
using Utils; | ||
using System.Collections.Generic; | ||
|
||
/// <summary> | ||
/// A class that holds information about a button and can draw it in the inspector. | ||
/// </summary> | ||
public abstract class Button | ||
{ | ||
/// <summary> Display name of the button. </summary> | ||
[PublicAPI] public readonly string DisplayName; | ||
|
||
/// <summary> MethodInfo object the button is attached to. </summary> | ||
[PublicAPI] public readonly MethodInfo Method; | ||
|
||
private readonly ButtonSpacing _spacing; | ||
private readonly bool _disabled; | ||
|
||
protected Button(MethodInfo method, ButtonAttribute buttonAttribute) | ||
{ | ||
DisplayName = string.IsNullOrEmpty(buttonAttribute.Name) | ||
? ObjectNames.NicifyVariableName(method.Name) | ||
: buttonAttribute.Name; | ||
|
||
Method = method; | ||
|
||
_spacing = buttonAttribute.Spacing; | ||
|
||
bool inAppropriateMode = EditorApplication.isPlaying | ||
? buttonAttribute.Mode == ButtonMode.EnabledInPlayMode | ||
: buttonAttribute.Mode == ButtonMode.DisabledInPlayMode; | ||
|
||
_disabled = ! (buttonAttribute.Mode == ButtonMode.AlwaysEnabled || inAppropriateMode); | ||
} | ||
|
||
public void Draw(IEnumerable<object> targets) | ||
{ | ||
using (new EditorGUI.DisabledScope(_disabled)) | ||
{ | ||
using (new DrawUtility.VerticalIndent( | ||
_spacing.ContainsFlag(ButtonSpacing.Before), | ||
_spacing.ContainsFlag(ButtonSpacing.After))) | ||
{ | ||
DrawInternal(targets); | ||
} | ||
} | ||
} | ||
|
||
internal static Button Create(MethodInfo method, ButtonAttribute buttonAttribute) | ||
{ | ||
var parameters = method.GetParameters(); | ||
|
||
if (parameters.Length == 0) | ||
{ | ||
return new ButtonWithoutParams(method, buttonAttribute); | ||
} | ||
else | ||
{ | ||
return new ButtonWithParams(method, buttonAttribute, parameters); | ||
} | ||
} | ||
|
||
protected abstract void DrawInternal(IEnumerable<object> targets); | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
namespace EasyButtons.Editor | ||
{ | ||
using System; | ||
using System.Linq; | ||
using System.Reflection; | ||
using UnityEditor; | ||
using UnityEngine; | ||
using Utils; | ||
using Object = UnityEngine.Object; | ||
using System.Collections.Generic; | ||
|
||
internal class ButtonWithParams : Button | ||
{ | ||
private readonly Parameter[] _parameters; | ||
private bool _expanded; | ||
|
||
public ButtonWithParams(MethodInfo method, ButtonAttribute buttonAttribute, ParameterInfo[] parameters) | ||
: base(method, buttonAttribute) | ||
{ | ||
_parameters = parameters.Select(paramInfo => new Parameter(paramInfo)).ToArray(); | ||
_expanded = buttonAttribute.Expanded; | ||
} | ||
|
||
protected override void DrawInternal(IEnumerable<object> targets) | ||
{ | ||
(Rect foldoutRect, Rect buttonRect) = DrawUtility.GetFoldoutAndButtonRects(DisplayName); | ||
|
||
_expanded = DrawUtility.DrawInFoldout(foldoutRect, _expanded, DisplayName, () => | ||
{ | ||
foreach (Parameter param in _parameters) | ||
{ | ||
param.Draw(); | ||
} | ||
}); | ||
|
||
if ( ! GUI.Button(buttonRect, "Invoke")) | ||
return; | ||
|
||
var paramValues = _parameters.Select(param => param.Value).ToArray(); | ||
|
||
foreach (object obj in targets) | ||
{ | ||
Method.Invoke(obj, paramValues); | ||
} | ||
} | ||
|
||
private readonly struct Parameter | ||
{ | ||
private readonly FieldInfo _fieldInfo; | ||
private readonly ScriptableObject _scriptableObj; | ||
private readonly NoScriptFieldEditor _editor; | ||
|
||
public Parameter(ParameterInfo paramInfo) | ||
{ | ||
Type generatedType = ScriptableObjectCache.GetClass(paramInfo.Name, paramInfo.ParameterType); | ||
_scriptableObj = ScriptableObject.CreateInstance(generatedType); | ||
_fieldInfo = generatedType.GetField(paramInfo.Name); | ||
_editor = CreateEditor<NoScriptFieldEditor>(_scriptableObj); | ||
} | ||
|
||
public object Value | ||
{ | ||
get | ||
{ | ||
// Every time modified properties are applied, the "No script asset for ..." warning appears. | ||
// Saving only once before invoking the button minimizes those warnings. | ||
_editor.ApplyModifiedProperties(); | ||
return _fieldInfo.GetValue(_scriptableObj); | ||
} | ||
} | ||
|
||
public void Draw() | ||
{ | ||
_editor.OnInspectorGUI(); | ||
} | ||
|
||
private static TEditor CreateEditor<TEditor>(Object obj) | ||
where TEditor : Editor | ||
{ | ||
return (TEditor) Editor.CreateEditor(obj, typeof(TEditor)); | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
namespace EasyButtons.Editor | ||
{ | ||
using System.Reflection; | ||
using UnityEngine; | ||
using System.Collections.Generic; | ||
|
||
internal class ButtonWithoutParams : Button | ||
{ | ||
public ButtonWithoutParams(MethodInfo method, ButtonAttribute buttonAttribute) | ||
: base(method, buttonAttribute) { } | ||
|
||
protected override void DrawInternal(IEnumerable<object> targets) | ||
{ | ||
if ( ! GUILayout.Button(DisplayName)) | ||
return; | ||
|
||
foreach (object obj in targets) | ||
{ | ||
Method.Invoke(obj, null); | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
namespace EasyButtons.Editor | ||
{ | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using JetBrains.Annotations; | ||
|
||
/// <summary> | ||
/// Helper class that can be used in custom Editors to draw methods marked with the <see cref="ButtonAttribute"/> as buttons. | ||
/// </summary> | ||
public class ButtonsDrawer | ||
{ | ||
/// <summary> | ||
/// A list of buttons that can be drawn for the class. | ||
/// </summary> | ||
[PublicAPI] | ||
public readonly List<Button> Buttons = new List<Button>(); | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="ButtonsDrawer"/> class and fills <see cref="Buttons"/> with | ||
/// methods marked with the <see cref="ButtonAttribute"/>. Recommended to instantiate it in OnEnable to improve | ||
/// performance of the custom editor. | ||
/// </summary> | ||
/// <param name="target">Editor's target.</param> | ||
public ButtonsDrawer(object target) | ||
{ | ||
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; | ||
var methods = target.GetType().GetMethods(flags); | ||
|
||
foreach (MethodInfo method in methods) | ||
{ | ||
var buttonAttribute = method.GetCustomAttribute<ButtonAttribute>(); | ||
|
||
if (buttonAttribute == null) | ||
continue; | ||
|
||
Buttons.Add(Button.Create(method, buttonAttribute)); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Draws all the methods marked with <see cref="ButtonAttribute"/>. | ||
/// </summary> | ||
public void DrawButtons(IEnumerable<object> targets) | ||
{ | ||
foreach (Button button in Buttons) | ||
{ | ||
button.Draw(targets); | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "EasyButtons.Editor", | ||
"rootNamespace": "", | ||
"references": [ | ||
"GUID:f24cf67903b27ae498b3069ecc30cc11" | ||
], | ||
"includePlatforms": [ | ||
"Editor" | ||
], | ||
"excludePlatforms": [], | ||
"allowUnsafeCode": true, | ||
"overrideReferences": false, | ||
"precompiledReferences": [], | ||
"autoReferenced": true, | ||
"defineConstraints": [], | ||
"versionDefines": [], | ||
"noEngineReferences": false | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
namespace EasyButtons.Editor | ||
{ | ||
using System; | ||
using System.Reflection; | ||
using UnityEditor; | ||
using UnityEngine; | ||
|
||
internal class NoScriptFieldEditor : Editor | ||
{ | ||
private static readonly MethodInfo _removeLogEntriesByMode; | ||
private static readonly string[] _propertiesToExclude = { "m_Script" }; | ||
|
||
static NoScriptFieldEditor() | ||
{ | ||
const string logEntryClassName = "UnityEditor.LogEntry"; | ||
const string removeLogMethodName = "RemoveLogEntriesByMode"; | ||
|
||
var editorAssembly = Assembly.GetAssembly(typeof(Editor)); | ||
Type logEntryType = editorAssembly.GetType(logEntryClassName); | ||
_removeLogEntriesByMode = logEntryType.GetMethod(removeLogMethodName, BindingFlags.NonPublic | BindingFlags.Static); | ||
|
||
if (_removeLogEntriesByMode == null) | ||
{ | ||
Debug.LogError($"Could not find the {logEntryClassName}.{removeLogMethodName}() method. " + | ||
"Please submit an issue and specify your Unity version: https://github.com/madsbangh/EasyButtons/issues/new"); | ||
} | ||
} | ||
|
||
public override void OnInspectorGUI() | ||
{ | ||
DrawPropertiesExcluding(serializedObject, _propertiesToExclude); | ||
} | ||
|
||
public void ApplyModifiedProperties() | ||
{ | ||
if ( ! serializedObject.hasModifiedProperties) | ||
return; | ||
|
||
serializedObject.ApplyModifiedPropertiesWithoutUndo(); | ||
RemoveNoScriptWarning(); | ||
} | ||
|
||
private static void RemoveNoScriptWarning() | ||
{ | ||
// The warning doesn't appear in edit mode. | ||
if ( ! Application.isPlaying) | ||
return; | ||
|
||
// The "No Script asset for ..." log has a unique identifier that can be used to remove the warning. | ||
const int noScriptAssetMode = 262144; | ||
_removeLogEntriesByMode?.Invoke(null, new object[] { noScriptAssetMode }); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.