Add ButtonAttribute to display methods in editor properties panel

#1917
This commit is contained in:
Wojtek Figat
2024-12-06 16:10:50 +01:00
parent 1088a71e69
commit b6d2a3683c
8 changed files with 122 additions and 0 deletions

View File

@@ -112,6 +112,12 @@ namespace FlaxEditor.Content
throw new TargetException("Missing Visual Script asset.");
_type.Asset.SetScriptInstanceParameterValue(_parameter.Name, (Object)obj, value);
}
/// <inheritdoc />
public object Invoke(object obj, object[] parameters)
{
throw new NotSupportedException();
}
}
sealed class VisualScriptMethodInfo : IScriptMemberInfo
@@ -240,6 +246,14 @@ namespace FlaxEditor.Content
{
throw new NotSupportedException();
}
/// <inheritdoc />
public object Invoke(object obj, object[] parameters)
{
if (!_type.Asset)
throw new TargetException("Missing Visual Script asset.");
return _type.Asset.InvokeMethod(_index, obj, parameters);
}
}
/// <summary>

View File

@@ -127,12 +127,41 @@ namespace FlaxEditor.CustomEditors
_isSetBlocked = true;
Initialize(layout);
ShowButtons();
Refresh();
_isSetBlocked = false;
CurrentCustomEditor = prev;
}
private void ShowButtons()
{
var values = Values;
if (values == null || values.HasDifferentTypes)
return;
var type = TypeUtils.GetObjectType(values[0]);
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var method in methods)
{
if (!method.HasAttribute(typeof(ButtonAttribute)) ||
method.ParametersCount != 0)
continue;
var attribute = method.GetAttribute<ButtonAttribute>();
var text = string.IsNullOrEmpty(attribute.Text) ? Utilities.Utils.GetPropertyNameUI(method.Name) : attribute.Text;
var tooltip = string.IsNullOrEmpty(attribute.Tooltip) ? Editor.Instance.CodeDocs.GetTooltip(method) : attribute.Tooltip;
var button = _layout.Button(text, tooltip);
button.Button.Tag = method;
button.Button.ButtonClicked += OnButtonClicked;
}
}
private void OnButtonClicked(Button button)
{
var method = (ScriptMemberInfo)button.Tag;
var obj = method.IsStatic ? null : Values[0];
method.Invoke(obj);
}
internal static CustomEditor CurrentCustomEditor;
internal void OnChildCreated(CustomEditor child)

View File

@@ -293,6 +293,14 @@ namespace FlaxEditor.Scripting
/// <param name="obj">The object whose member value will be modified.</param>
/// <param name="value">The new member value.</param>
void SetValue(object obj, object value);
/// <summary>
/// Invokes the method on a specific object (null if static) using the provided parameters.
/// </summary>
/// <param name="obj">The instance of the object to invoke its method. Use null for static methods.</param>
/// <param name="parameters">List of parameters to provide.</param>
/// <returns>The value returned by the method.</returns>
object Invoke(object obj, object[] parameters);
}
/// <summary>

View File

@@ -691,6 +691,23 @@ namespace FlaxEditor.Scripting
else
_custom.SetValue(obj, value);
}
/// <summary>
/// Invokes the method on a specific object (null if static) using the provided parameters.
/// </summary>
/// <param name="obj">The instance of the object to invoke its method. Use null for static methods.</param>
/// <param name="parameters">List of parameters to provide.</param>
/// <returns>The value returned by the method.</returns>
public object Invoke(object obj = null, object[] parameters = null)
{
if (parameters == null)
parameters = Array.Empty<object>();
if (_managed is MethodInfo methodInfo)
return methodInfo.Invoke(obj, parameters);
if (_managed != null)
throw new NotSupportedException();
return _custom.Invoke(obj, parameters);
}
}
/// <summary>

View File

@@ -39,6 +39,7 @@ namespace FlaxEditor.Surface
typeof(TooltipAttribute),
typeof(HideInEditorAttribute),
typeof(NoAnimateAttribute),
typeof(ButtonAttribute),
};
/// <summary>

View File

@@ -2263,6 +2263,14 @@ void VisualScript::GetMethodSignature(int32 index, String& name, byte& flags, St
}
}
Variant VisualScript::InvokeMethod(int32 index, const Variant& instance, Span<Variant> parameters) const
{
auto& method = _methods[index];
Variant result;
VisualScriptingModule.InvokeMethod((void*)&method, instance, parameters, result);
return result;
}
Span<byte> VisualScript::GetMetaData(int32 typeID)
{
auto meta = Graph.Meta.GetEntry(typeID);

View File

@@ -267,6 +267,9 @@ public:
// Gets the signature data of the method.
API_FUNCTION() void GetMethodSignature(int32 index, API_PARAM(Out) String& name, API_PARAM(Out) byte& flags, API_PARAM(Out) String& returnTypeName, API_PARAM(Out) Array<String>& paramNames, API_PARAM(Out) Array<String>& paramTypeNames, API_PARAM(Out) Array<bool>& paramOuts);
// Invokes the method.
API_FUNCTION() Variant InvokeMethod(int32 index, const Variant& instance, Span<Variant> parameters) const;
// Gets the metadata of the script surface.
API_FUNCTION() Span<byte> GetMetaData(int32 typeID);

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
namespace FlaxEngine
{
/// <summary>
/// Displays the method in the properties panel where user can click and invoke this method.
/// </summary>
/// <remarks>Supported on both static and member methods that are parameterless.</remarks>
[AttributeUsage(AttributeTargets.Method)]
public sealed class ButtonAttribute : Attribute
{
/// <summary>
/// The button text. Empty value will use method name (auto-formatted).
/// </summary>
public string Text;
/// <summary>
/// The button tooltip text. Empty value will use method documentation.
/// </summary>
public string Tooltip;
/// <summary>
/// Initializes a new instance of the <see cref="ButtonAttribute"/> class.
/// </summary>
public ButtonAttribute()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ButtonAttribute"/> class.
/// </summary>
/// <param name="text">The button text.</param>
/// <param name="tooltip">The button tooltip.</param>
public ButtonAttribute(string text, string tooltip = null)
{
Text = text;
Tooltip = tooltip;
}
}
}