Attribute Macro zng::widget::property

source ·
#[property]
Expand description

Expands a function to a widget property.

Property functions take one UiNode child input and one or more other inputs and produces an UiNode that implements the property feature.

The attribute expansion does not modify the function, it can still be used as a function directly. Some properties are implemented by calling other property functions to generate a derived effect.

The attribute expansion generates a hidden trait of the same name and visibility, the trait is implemented for widget builders, the widget macros use this to set the property. Because it has the same name it is imported together with the property function, in practice this only matters in doc links where you must use the fn@ disambiguator.

§Attribute

The property attribute has one required argument and three optional.

§Nest Group

The first argument is the property NestGroup. The group defines the overall nest position of the property, for example, LAYOUT properties always wrap FILL properties. This is important as widgets are open and any combination of properties may end-up instantiated in the same widget.

use zng::prelude_wgt::*;

#[property(LAYOUT)]
pub fn align(child: impl UiNode, align: impl IntoVar<Align>) -> impl UiNode {
    // ..
}

The nest group can be tweaked, by adding or subtracting integers, in the example bellow both properties are in the SIZE group, but size is always inside max_size.

use zng::prelude_wgt::*;

#[property(SIZE+1)]
pub fn size(child: impl UiNode, size: impl IntoVar<Size>) -> impl UiNode {
    // ..
}

#[property(SIZE)]
pub fn max_size(child: impl UiNode, size: impl IntoVar<Size>) -> impl UiNode {
    // ..
}
§Default

The next argument is an optional default(args..). It defines the value to use when the property must be instantiated and no value was provided. The defaults should cause the property to behave as if it is not set, as the default value will be used in widgets that only set the property in when blocks.

use zng::prelude_wgt::*;

#[property(FILL, default(rgba(0, 0, 0, 0)))]
pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
    // ..
}

In the example above the background_color defines a transparent color as the default, so if the background color is only set in a when block if will only be visible when it is active.

For properties with multiple inputs the default args may be defined in a comma separated list of params, default(dft0, ..).

§Impl For

The last argument is an optional impl(<widget-type>), it strongly associates the property with a widget, users can set this property on the widget without needing to import the property.

Note that this makes the property have priority over all others of the same name, only a derived widget can override with another strongly associated property.

Note that you can also use the widget_impl! in widget declarations to implement existing properties for a widget.

§Capture

After the nest group and before default the , capture, value indicates that the property is capture-only. This flag changes how the property must be declared, the first argument is a property input and the function can have only one input, no return type is allowed and the function body must be empty, unused input warnings are suppressed by the expanded code.

Capture-only properties must be captured by a widget and implemented as part of the widget’s intrinsics, the reason for a property function is purely to define the property signature and metadata, the capture-only property function can also be used to set a property dynamically, such as in a style widget that is applied on the actual widget that captures the property.

A documentation sections explaining capture-only properties is generated for the property, it is also tagged differently in the functions list.

use zng::prelude_wgt::*;

/// Children property, must be captured by panel widgets.
#[property(CONTEXT, capture)]
pub fn children(children: impl UiNodeList) { }

§Args

The property function requires at least two args, the first is the child node and the other(s) the input values. The number and type of inputs is validated at compile time, the types are limited and are identified and validated by their token name, so you cannot use renamed types.

§Child

The first function arg must be of type impl UiNode, it represents the child node and the property node must delegate to it so that the UI tree functions correctly. The type must be an impl generic, a full path to UiNode is allowed, but no import renames as the proc-macro attribute can only use tokens to identify the type.

§Inputs

The second arg and optional other args define the property inputs. When a property is assigned in a widget only these inputs are defined by the user, the child arg is provided by the widget builder. Property inputs are limited, and must be identifiable by their token name alone. The types are validated at compile time, they must be declared using impl generics, a full path to the generic traits is allowed, but no import renames.

§Input Types

These are the allowed input types:

§impl IntoVar<T>

The most common type, accepts any value that can be converted IntoVar<T>, usually the property defines the T, but it can be generic. The property node must respond to var updates. The input kind is InputKind::Var. No auto-default is generated for this type, property implementation should provide a default value that causes the property to behave as if it was not set.

The input can be read in when expressions and can be assigned in when blocks.

§impl IntoValue<T>

Accepts any value that can be converted IntoValue<T> that does not change, usually the property defines the T, but it can be generic. The input kind is InputKind::Value. No auto-default is generated for this type.

The input can be read in when expressions, but cannot be assigned in when blocks.

§impl UiNode

This input accepts another UiNode, the implementation must handle it like it handles the child node, delegating all methods. The input kind is InputKind::UiNode. The NilUiNode is used as the default value if no other is provided.

The input cannot be read in when expressions, but can be assigned in when blocks.

§impl UiNodeList

This input accepts an UiNodeList, the implementation must handle it like it handles the child node, delegating all methods. The input kind is InputKind::UiNodeList. An empty list is used as the default value if no other is provided.

The input cannot be read in when expressions, but can be assigned in when blocks.

§impl WidgetHandler<A>

This input accepts any WidgetHandler<A> for the argument type A, usually the property defines the A, but it can be generic. The input kind is InputKind::WidgetHandler. A no-op handler is used for the default if no other is provided.

Event handler properties usually have the on_ name prefix. You can use the event_property! macro to generate standard event properties.

The input cannot be read in when expressions, but can be assigned in when blocks.

§Getter Properties

Most properties with var inputs are setters, that is the inputs affect the widget. Some properties can be getters, detecting widget state and setting it on the input variable. These properties are usually named with a prefix that indicates their input is actually for getting state, the prefixes is_ and has_ mark a property with a single bool input that reads a widget state, the prefix get_ and actual_ marks a property that reads a non-boolean state from the widget.

Getter properties are configured with a default read-write variable, so that they can be used in when expressions directly, for example, when *#is_pressed, the is_pressed property has a default(var(false)), so it automatically initializes with a read-write variable that is used in the when condition. The property attribute generates defaults automatically based on the prefix, the default is var(T::default()), this can be overwritten just by setting the default, it is not possible to declare a getter property without default.

Note that if a property is used in when condition without being set and without default value the when block is discarded on widget build. If you are implementing a getter property that is not named using the prefixes listed above you must set default(var(T::default()).

§Generics

Apart from the impl generics of inputs and child, there is some support for named generic types, only one named generic is allowed for inputs impl IntoVar<T>, impl IntoValue<T> and impl WidgetHandler<A>.

§Output

The property output type must be any type that implements UiNode, usually an opaque type impl UiNode is used. The property node can be anything, as long as it delegates to the child node, see match_node or ui_node about implementing a node.

Some common property patterns have helper functions, for example, to setup a context var you can use the with_context_var function.

§More Details

See property_id! and property_args! for more details about what kind of meta-code is generated for properties.

Expands a function to a widget property.

§Full Documentation

Read the documentation in the zng::widget::property page.