diff --git a/src/Godot.Bindings/Core/Attributes/BindPropertyAttribute.cs b/src/Godot.Bindings/Core/Attributes/BindPropertyAttribute.cs index 851dcc9e..701f4f62 100644 --- a/src/Godot.Bindings/Core/Attributes/BindPropertyAttribute.cs +++ b/src/Godot.Bindings/Core/Attributes/BindPropertyAttribute.cs @@ -15,6 +15,18 @@ public sealed class BindPropertyAttribute : Attribute /// public string? Name { get; init; } + /// + /// Specifies the hint that will be used to register the property. + /// If unspecified it will use the hint calculated from the property type. + /// + public PropertyHint Hint { get; init; } = PropertyHint.None; + + /// + /// Specifies the hint string that will be used to register the property. + /// If unspecified it will use the hint string calculated from the property type. + /// + public string? HintString { get; init; } + /// /// Specifies the marshaller type that will be used to marshal this property. /// If unspecified the default marshaller for the annotated property's type diff --git a/src/Godot.SourceGenerators/BindMethodsWriter.cs b/src/Godot.SourceGenerators/BindMethodsWriter.cs index 24d4e587..fcb7bc2f 100644 --- a/src/Godot.SourceGenerators/BindMethodsWriter.cs +++ b/src/Godot.SourceGenerators/BindMethodsWriter.cs @@ -524,13 +524,13 @@ private static void AppendPropertyInfoObjectInitializer(IndentedStringBuilder sb List lines = []; - if (marshalInfo.Hint != PropertyHint.None) + if (property.HintOverride != PropertyHint.None || marshalInfo.Hint != PropertyHint.None) { - lines.Add($"Hint = {marshalInfo.Hint.FullNameWithGlobal()},"); + lines.Add($"Hint = {(property.HintOverride == PropertyHint.None ? marshalInfo.Hint : property.HintOverride).FullNameWithGlobal()},"); } - if (!string.IsNullOrEmpty(marshalInfo.HintString)) + if (!string.IsNullOrEmpty(property.HintStringOverride) || !string.IsNullOrEmpty(marshalInfo.HintString)) { - lines.Add($"""HintString = "{marshalInfo.HintString}","""); + lines.Add($"""HintString = "{property.HintStringOverride ?? marshalInfo.HintString}","""); } if (marshalInfo.Usage != PropertyUsageFlags.None) { diff --git a/src/Godot.SourceGenerators/SpecCollectors/PropertySpecCollector.cs b/src/Godot.SourceGenerators/SpecCollectors/PropertySpecCollector.cs index a250ac60..43b05226 100644 --- a/src/Godot.SourceGenerators/SpecCollectors/PropertySpecCollector.cs +++ b/src/Godot.SourceGenerators/SpecCollectors/PropertySpecCollector.cs @@ -88,6 +88,8 @@ public static GodotPropertySpec Collect(Compilation compilation, ITypeSymbol ret private static GodotPropertySpec CollectCore(Compilation compilation, string symbolName, ITypeSymbol typeSymbol, AttributeData? attribute, CancellationToken cancellationToken = default) { string? nameOverride = null; + PropertyHint hintOverride = PropertyHint.None; + string? hintStringOverride = null; if (attribute is not null) { @@ -98,6 +100,15 @@ private static GodotPropertySpec CollectCore(Compilation compilation, string sym case "Name": nameOverride = constant.Value as string; break; + case "Hint": + if (constant.Value is long longValue) + { + hintOverride = (PropertyHint)longValue; + } + break; + case "HintString": + hintStringOverride = constant.Value as string; + break; } } } @@ -110,6 +121,8 @@ private static GodotPropertySpec CollectCore(Compilation compilation, string sym FullyQualifiedTypeName = typeSymbol.FullNameWithGlobal(), MarshalInfo = marshalInfo, NameOverride = nameOverride, + HintOverride = hintOverride, + HintStringOverride = hintStringOverride }; } } diff --git a/src/Godot.SourceGenerators/Specs/GodotPropertySpec.cs b/src/Godot.SourceGenerators/Specs/GodotPropertySpec.cs index 28f12a09..8609e03e 100644 --- a/src/Godot.SourceGenerators/Specs/GodotPropertySpec.cs +++ b/src/Godot.SourceGenerators/Specs/GodotPropertySpec.cs @@ -45,6 +45,20 @@ namespace Godot.SourceGenerators; /// public string? NameOverride { get; init; } + /// + /// Hint specified in the [BindProperty] attribute for this property, + /// or PropertyType.None if a hint was not specified. + /// If unspecified the hint of the property will be calculated from the . + /// + public PropertyHint HintOverride { get; init; } + + /// + /// Hint string specified in the [BindProperty] attribute for this property, + /// or if a hint string was not specified. + /// If unspecified the hint string of the property will be calculated from the . + /// + public string? HintStringOverride { get; init; } + /// /// Group information specified in the [PropertyGroup] attribute, /// if the property is annotated to define a group from this property. diff --git a/tests/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NS.NodeWithProperties.generated.cs b/tests/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NS.NodeWithProperties.generated.cs index 4ab5ab9f..1b4888f1 100644 --- a/tests/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NS.NodeWithProperties.generated.cs +++ b/tests/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NS.NodeWithProperties.generated.cs @@ -18,6 +18,8 @@ partial class NodeWithProperties public static global::Godot.StringName @myField { get; } = global::Godot.StringName.CreateStaticFromAscii("myField"u8); public static global::Godot.StringName @myNamedField { get; } = global::Godot.StringName.CreateStaticFromAscii("my_named_field"u8); public static global::Godot.StringName @myFieldWithDefaultValue { get; } = global::Godot.StringName.CreateStaticFromAscii("myFieldWithDefaultValue"u8); + public static global::Godot.StringName @myFieldWithHintOverride { get; } = global::Godot.StringName.CreateStaticFromAscii("myFieldWithHintOverride"u8); + public static global::Godot.StringName @myFieldWithHintStringOverride { get; } = global::Godot.StringName.CreateStaticFromAscii("myFieldWithHintStringOverride"u8); } public new partial class SignalName : global::Godot.Node.SignalName { @@ -99,5 +101,31 @@ internal static void BindMethods(global::Godot.Bridge.ClassRegistrationContext c { __instance.@myFieldWithDefaultValue = value; }); + context.BindProperty(new global::Godot.Bridge.PropertyInfo(PropertyName.@myFieldWithHintOverride, global::Godot.VariantType.Int, global::Godot.Bridge.VariantTypeMetadata.Int32) + { + Hint = global::Godot.PropertyHint.Layers3DPhysics, + Usage = global::Godot.PropertyUsageFlags.Default, + }, + static (NodeWithProperties __instance) => + { + return __instance.@myFieldWithHintOverride; + }, + static (NodeWithProperties __instance, int value) => + { + __instance.@myFieldWithHintOverride = value; + }); + context.BindProperty(new global::Godot.Bridge.PropertyInfo(PropertyName.@myFieldWithHintStringOverride, global::Godot.VariantType.Int, global::Godot.Bridge.VariantTypeMetadata.Int32) + { + HintString = "my_hint_string", + Usage = global::Godot.PropertyUsageFlags.Default, + }, + static (NodeWithProperties __instance) => + { + return __instance.@myFieldWithHintStringOverride; + }, + static (NodeWithProperties __instance, int value) => + { + __instance.@myFieldWithHintStringOverride = value; + }); } } diff --git a/tests/Godot.SourceGenerators.Tests/TestData/Sources/NodeWithProperties.cs b/tests/Godot.SourceGenerators.Tests/TestData/Sources/NodeWithProperties.cs index 3ac4ba92..067b99bd 100644 --- a/tests/Godot.SourceGenerators.Tests/TestData/Sources/NodeWithProperties.cs +++ b/tests/Godot.SourceGenerators.Tests/TestData/Sources/NodeWithProperties.cs @@ -26,4 +26,10 @@ public partial class NodeWithProperties : Node [BindProperty] public int myFieldWithDefaultValue = 42; + + [BindProperty(Hint = PropertyHint.Layers3DPhysics)] + public int myFieldWithHintOverride; + + [BindProperty(HintString = "my_hint_string")] + public int myFieldWithHintStringOverride; }