@@ -21,7 +21,9 @@ pub use signature::*;
2121pub ( crate ) use godot_convert:: convert_error:: * ;
2222
2323use crate :: builtin:: * ;
24- use crate :: engine:: global;
24+ use crate :: engine:: global:: { self , PropertyHint , PropertyUsageFlags } ;
25+ use crate :: property:: Var ;
26+ use crate :: property:: { Export , PropertyHintInfo } ;
2527use godot_ffi as sys;
2628use registration:: method:: MethodParamOrReturnInfo ;
2729use sys:: { GodotFfi , GodotNullableFfi } ;
@@ -268,15 +270,119 @@ pub trait ArrayElement: GodotType {}
268270#[ derive( Debug , Clone ) ]
269271// Note: is not #[non_exhaustive], so adding fields is a breaking change. Mostly used internally at the moment though.
270272pub struct PropertyInfo {
273+ /// Which type this property has.
274+ ///
275+ /// For objects this should be set to [`VariantType::Object`], and the `class_name` field to the actual name of the class.
276+ ///
277+ /// For [`Variant`] this should be set to [`VariantType::Nil`].
271278 pub variant_type : VariantType ,
279+
280+ /// Which class this property is.
281+ ///
282+ /// This should be set to [`ClassName::none()`] unless the variant type is `Object`. You can use
283+ /// [`GodotClass::class_name()`](crate::obj::GodotClass::class_name()) to get the right name to use here.
272284 pub class_name : ClassName ,
285+
286+ /// The name of this property in Godot.
273287 pub property_name : StringName ,
288+
289+ /// How the property is meant to be edited. See also [`PropertyHint`] in the Godot docs.
290+ ///
291+ /// [`PropertyHint`]: https://docs.godotengine.org/en/latest/classes/class_%40globalscope.html#enum-globalscope-propertyhint
274292 pub hint : global:: PropertyHint ,
293+
294+ /// Extra information passed to Godot for this property, what this means depends on the `hint` value.
275295 pub hint_string : GString ,
296+
297+ /// How this property should be used. See [`PropertyUsageFlags`] in Godot for the meaning.
298+ ///
299+ /// [`PropertyUsageFlags`]: https://docs.godotengine.org/en/latest/classes/class_%40globalscope.html#enum-globalscope-propertyusageflags
276300 pub usage : global:: PropertyUsageFlags ,
277301}
278302
279303impl PropertyInfo {
304+ /// Create a new `PropertyInfo` representing a property named `property_name` with type `T`.
305+ ///
306+ /// This will generate property info equivalent to what a `#[var]` attribute would.
307+ pub fn new_var < T : Var > ( property_name : & str ) -> Self {
308+ <T as GodotConvert >:: Via :: property_info ( property_name) . with_hint_info ( T :: property_hint ( ) )
309+ }
310+
311+ /// Create a new `PropertyInfo` representing an exported property named `property_name` with type `T`.
312+ ///
313+ /// This will generate property info equivalent to what an `#[export]` attribute would.
314+ pub fn new_export < T : Export > ( property_name : & str ) -> Self {
315+ <T as GodotConvert >:: Via :: property_info ( property_name)
316+ . with_hint_info ( T :: default_export_info ( ) )
317+ }
318+
319+ /// Change the `hint` and `hint_string` to be the given `hint_info`.
320+ ///
321+ /// See [`export_info_functions`](crate::property::export_info_functions) for functions that return appropriate `PropertyHintInfo`s for
322+ /// various Godot annotations.
323+ ///
324+ /// # Examples
325+ ///
326+ /// Creating an `@export_range` property.
327+ ///
328+ // TODO: Make this nicer to use.
329+ /// ```no_run
330+ /// use godot::register::property::export_info_functions;
331+ /// use godot::builtin::meta::PropertyInfo;
332+ ///
333+ /// let property = PropertyInfo::new_export::<f64>("my_range_property")
334+ /// .with_hint_info(export_info_functions::export_range(
335+ /// 0.0,
336+ /// 10.0,
337+ /// Some(0.1),
338+ /// false,
339+ /// false,
340+ /// false,
341+ /// false,
342+ /// false,
343+ /// false,
344+ /// ));
345+ /// ```
346+ pub fn with_hint_info ( self , hint_info : PropertyHintInfo ) -> Self {
347+ let PropertyHintInfo { hint, hint_string } = hint_info;
348+
349+ Self {
350+ hint,
351+ hint_string,
352+ ..self
353+ }
354+ }
355+
356+ /// Create a new `PropertyInfo` representing a group in Godot.
357+ ///
358+ /// See [`EditorInspector`](https://docs.godotengine.org/en/latest/classes/class_editorinspector.html#class-editorinspector) in Godot for
359+ /// more information.
360+ pub fn new_group ( group_name : & str , group_prefix : & str ) -> Self {
361+ Self {
362+ variant_type : VariantType :: Nil ,
363+ class_name : ClassName :: none ( ) ,
364+ property_name : group_name. into ( ) ,
365+ hint : PropertyHint :: NONE ,
366+ hint_string : group_prefix. into ( ) ,
367+ usage : PropertyUsageFlags :: GROUP ,
368+ }
369+ }
370+
371+ /// Create a new `PropertyInfo` representing a subgroup in Godot.
372+ ///
373+ /// See [`EditorInspector`](https://docs.godotengine.org/en/latest/classes/class_editorinspector.html#class-editorinspector) in Godot for
374+ /// more information.
375+ pub fn new_subgroup ( subgroup_name : & str , subgroup_prefix : & str ) -> Self {
376+ Self {
377+ variant_type : VariantType :: Nil ,
378+ class_name : ClassName :: none ( ) ,
379+ property_name : subgroup_name. into ( ) ,
380+ hint : PropertyHint :: NONE ,
381+ hint_string : subgroup_prefix. into ( ) ,
382+ usage : PropertyUsageFlags :: SUBGROUP ,
383+ }
384+ }
385+
280386 /// Converts to the FFI type. Keep this object allocated while using that!
281387 pub fn property_sys ( & self ) -> sys:: GDExtensionPropertyInfo {
282388 use crate :: obj:: EngineBitfield as _;
@@ -305,6 +411,40 @@ impl PropertyInfo {
305411 usage : global:: PropertyUsageFlags :: NONE . ord ( ) as u32 ,
306412 }
307413 }
414+
415+ /// Consumes self and turns it into a `sys::GDExtensionPropertyInfo`, should be used together with
416+ /// [`free_owned_property_sys`](Self::free_owned_property_sys).
417+ ///
418+ /// This will leak memory unless used together with `free_owned_property_sys`.
419+ pub ( crate ) fn into_owned_property_sys ( self ) -> sys:: GDExtensionPropertyInfo {
420+ use crate :: obj:: EngineBitfield as _;
421+ use crate :: obj:: EngineEnum as _;
422+
423+ sys:: GDExtensionPropertyInfo {
424+ type_ : self . variant_type . sys ( ) ,
425+ name : self . property_name . into_owned_string_sys ( ) ,
426+ class_name : sys:: SysPtr :: force_mut ( self . class_name . string_sys ( ) ) ,
427+ hint : u32:: try_from ( self . hint . ord ( ) ) . expect ( "hint.ord()" ) ,
428+ hint_string : self . hint_string . into_owned_string_sys ( ) ,
429+ usage : u32:: try_from ( self . usage . ord ( ) ) . expect ( "usage.ord()" ) ,
430+ }
431+ }
432+
433+ /// Properly frees a `sys::GDExtensionPropertyInfo` created by [`into_owned_property_sys`](Self::into_owned_property_sys).
434+ ///
435+ /// # Safety
436+ ///
437+ /// * Must only be used on a struct returned from a call to `into_owned_property_sys`, without modification.
438+ /// * Must not be called more than once on a `sys::GDExtensionPropertyInfo` struct.
439+ pub ( crate ) unsafe fn free_owned_property_sys ( info : sys:: GDExtensionPropertyInfo ) {
440+ // SAFETY: This function was called on a pointer returned from `into_owned_property_sys`, thus both `info.name` and
441+ // `info.hint_string` were created from calls to `into_owned_string_sys` on their respective types.
442+ // Additionally this function isn't called more than once on a struct containing the same `name` or `hint_string` pointers.
443+ unsafe {
444+ let _name = StringName :: from_owned_string_sys ( info. name ) ;
445+ let _hint_string = GString :: from_owned_string_sys ( info. hint_string ) ;
446+ }
447+ }
308448}
309449
310450// ----------------------------------------------------------------------------------------------------------------------------------------------
0 commit comments