Skip to content

Commit

Permalink
Remove Naughty Attributes, and add Easy Buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
Dwarph committed Jan 31, 2023
1 parent a0f20c0 commit 85f6e8d
Show file tree
Hide file tree
Showing 56 changed files with 1,178 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ XR Keyboard is a reusable, physical XR keyboard that is built to be used with Un
## Dependencies

- Ultraleap Unity Plugin (Core & Interaction Engine packages) <https://developer.leapmotion.com/unity>
- NaughtyAttributes <https://github.com/dbrizov/NaughtyAttributes>
- Easy Buttons (included in the project) <https://github.com/madsbangh/EasyButtons>
- TextMeshPro

## Getting Started
Expand Down
8 changes: 8 additions & 0 deletions XR_Keyboard/Assets/XR_Keyboard/Plugins.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions XR_Keyboard/Assets/XR_Keyboard/Plugins/EasyButtons.meta

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.

Loading

0 comments on commit 85f6e8d

Please sign in to comment.