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
Attribute | Description | Default | Example |
---|---|---|---|
name = "literal" | The name of the property | field ident where _ (leading and trailing _ are trimmed) is replaced into - | #[property(name = "prop-name")] |
type = expr | The type of the property | inferred | #[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 = expr | The type of class of which to override the property from | #[property(override_class = SomeClass)] | |
override_interface = expr | The type of interface of which to override the property from | #[property(override_interface = SomeInterface)] | |
nullable | Whether to use Option<T> in the wrapper’s generated setter | #[property(nullable)] | |
member = ident | Field of the nested type where property is retrieved and set | #[property(member = author)] | |
construct_only | Specify 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. | |
default | Sets the default_value field of the Param Spec builder | #[property(default = 1)] | |
<optional-pspec-builder-fields> = expr | Used 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 readableset_$property()
, when the property is writable and not construct-onlyconnect_$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());
}