Derive Macro glib_macros::Properties

source ·
#[derive(Properties)]
{
    // Attributes available to this derive:
    #[properties]
    #[property]
}
Expand description

This macro enables you to derive object properties in a quick way.

Supported #[property] attributes

AttributeDescriptionDefaultExample
name = "literal"The name of the propertyfield ident where _ (leading and trailing _ are trimmed) is replaced into -#[property(name = "prop-name")]
type = exprThe type of the propertyinferred#[property(type = i32)]
get [= expr]Specify that the property is readable and use PropertyGet::get [or optionally set a custom internal getter]#[property(get)], #[property(get = get_prop)], or [property(get = \|_\| 2)]
set [= expr]Specify that the property is writable and use PropertySet::set [or optionally set a custom internal setter]#[property(set)], #[property(set = set_prop)], or [property(set = \|_, val\| {})]
override_class = exprThe type of class of which to override the property from#[property(override_class = SomeClass)]
override_interface = exprThe type of interface of which to override the property from#[property(override_interface = SomeInterface)]
nullableWhether to use Option<T> in the wrapper’s generated setter#[property(nullable)]
member = identField of the nested type where property is retrieved and set#[property(member = author)]
construct_onlySpecify that the property is construct only. This will not generate a public setter and only allow the property to be set during object construction. The use of a custom internal setter is supported.#[property(get, construct_only)] or #[property(get, set = set_prop, construct_only)]
builder(<required-params>)[.ident]*Used to input required params or add optional Param Spec builder fields#[property(builder(SomeEnum::default()))], #[builder().default_value(1).minimum(0).maximum(5)], etc.
defaultSets the default_value field of the Param Spec builder#[property(default = 1)]
<optional-pspec-builder-fields> = exprUsed to add optional Param Spec builder fields#[property(minimum = 0) , #[property(minimum = 0, maximum = 1)], etc.
<optional-pspec-builder-fields>Used to add optional Param Spec builder fields#[property(explicit_notify)] , #[property(construct_only)], etc.

Using Rust keywords as property names

You might hit a roadblock when declaring properties with this macro because you want to use a name that happens to be a Rust keyword. This may happen with names like loop, which is a pretty common name when creating things like animation handlers. To use those names, you can make use of the raw identifier feature of Rust. Simply prefix the identifier name with r# in the struct declaration. Internally, those r#s are stripped so you can use its expected name in [ObjectExt::property] or within GtkBuilder template files.

Generated wrapper methods

The following methods are generated on the wrapper type specified on #[properties(wrapper_type = ...)]:

  • $property(), when the property is readable
  • set_$property(), when the property is writable and not construct-only
  • connect_$property_notify()
  • notify_$property()

Notice: You can’t reimplement the generated methods on the wrapper type, but you can change their behavior using a custom internal getter/setter.

Internal getters and setters

By default, they are generated for you. However, you can use a custom getter/setter by assigning an expression to get/set #[property] attributes: #[property(get = |_| 2, set)] or #[property(get, set = custom_setter_func)].

Supported types

Every type implementing the trait Property is supported. The type Option<T> is supported as a property only if Option<T> implements ToValueOptional. Optional types also require the nullable attribute: without it, the generated setter on the wrapper type will take T instead of Option<T>, preventing the user from ever calling the setter with a None value. If your type doesn’t support PropertySet, you can’t use the generated setter, but you can always define a custom one.

Adding support for custom types

Types wrapping an existing T: glib::value::ToValue + glib::HasParamSpec

If you have declared a newtype as

struct MyInt(i32);

you can use it as a property by deriving glib::ValueDelegate.

Types with inner mutability

The trait glib::Property must be implemented. The traits PropertyGet and PropertySet should be implemented to enable the Properties macro to generate a default internal getter/setter. If possible, implementing PropertySetNested is preferred over PropertySet, because it enables this macro to access the contained type and provide access to its fields, using the member = $structfield syntax.

Types without glib::HasParamSpec

If you have encountered a type T: glib::value::ToValue, inside the gtk-rs crate, which doesn’t implement HasParamSpec, then it’s a bug and you should report it. If you need to support a ToValue type with a ParamSpec not provided by gtk-rs, then you need to implement glib::HasParamSpec on that type.

Example

use std::cell::RefCell;
use std::marker::PhantomData;
use std::sync::Mutex;
use glib::prelude::*;
use glib::subclass::prelude::*;
use glib_macros::Properties;

#[derive(Default, Clone)]
struct Author {
    name: String,
    nick: String,
}

pub mod imp {
    use glib::{ParamSpec, Value};
    use std::rc::Rc;

    use super::*;

    #[derive(Properties, Default)]
    #[properties(wrapper_type = super::Foo)]
    pub struct Foo {
        #[property(get, set = Self::set_fizz)]
        fizz: RefCell<String>,
        #[property(name = "author-name", get, set, type = String, member = name)]
        #[property(name = "author-nick", get, set, type = String, member = nick)]
        author: RefCell<Author>,
        #[property(get, set, explicit_notify, lax_validation)]
        custom_flags: RefCell<String>,
        #[property(get, set, minimum = 0, maximum = 3)]
        numeric_builder: RefCell<u32>,
        #[property(get, set, builder('c'))]
        builder_with_required_param: RefCell<char>,
        #[property(get, set, nullable)]
        optional: RefCell<Option<String>>,
        #[property(get, set)]
        smart_pointer: Rc<RefCell<String>>,
    }

    impl ObjectImpl for Foo {
        fn properties() -> &'static [ParamSpec] {
            Self::derived_properties()
        }
        fn set_property(&self, id: usize, value: &Value, pspec: &ParamSpec) {
            self.derived_set_property(id, value, pspec)
        }
        fn property(&self, id: usize, pspec: &ParamSpec) -> Value {
            self.derived_property(id, pspec)
        }
    }

    #[glib::object_subclass]
    impl ObjectSubclass for Foo {
        const NAME: &'static str = "MyFoo";
        type Type = super::Foo;
    }

    impl Foo {
        fn set_fizz(&self, value: String) {
            *self.fizz.borrow_mut() = format!("custom set: {}", value);
        }
    }
}

glib::wrapper! {
    pub struct Foo(ObjectSubclass<imp::Foo>);
}

fn main() {
  let myfoo: Foo = glib::object::Object::new();

  myfoo.set_fizz("test value");
  assert_eq!(myfoo.fizz(), "custom set: test value".to_string());
}