Attribute Macro zng::widget::widget

source ·
#[widget]
Expand description

Expands a struct to a widget struct and macro.

Each widget is a struct and macro pair of the same name that builds a custom widget using WidgetBuilder. Widgets inherit from one other widget and can also inherit multiple mix-ins. Widgets can have intrinsic nodes, default properties and can build to a custom output type.

Properties can be strongly associated with the widget using the #[property(.., widget_impl(Widget))] directive, existing properties can be implemented for the widget using the widget_impl! macro.

§Attribute

The widget attribute must be placed in a struct Name(Parent); declaration, only struct following the exact pattern are allowed, different struct syntaxes will generate a compile error.

The attribute requires one argument, it must be a macro style $crate path to the widget struct, this is used in the generated macro to find the struct during instantiation. The path must be to the public path to the struct, that is, the same path that will be used to import the widget. After the required widget path custom rules for the generated macro can be declared.

use zng::prelude_wgt::*;

/// Minimal widget.
#[widget($crate::Foo)]
pub struct Foo(WidgetBase);

§Inherit

The widget struct field must be the parent widget type. All widgets inherit from another or the WidgetBase, the parent widgets intrinsic properties and nodes are all included in the new widget. The intrinsic properties are included by deref, the new widget will dereference to the parent widget, during widget build auto-deref will select the property methods first, this mechanism even allows for property overrides.

§Intrinsic

The widget struct can define a method widget_intrinsic that includes custom build actions in the WidgetBuilder, this special method will be called once for the widget. The same method is also called for the inherited widgets.

use zng::prelude_wgt::*;

#[widget($crate::Foo)]
pub struct Foo(WidgetBase);

impl Foo {
    fn widget_intrinsic(&mut self) {
        self.widget_builder().push_build_action(|b| {
            // push_intrinsic, capture_var.
        });
    }
}

The example above demonstrates the intrinsic method used to push_build_action. This is the primary mechanism for widgets to define their own behavior that does not depend on properties. Note that the widget inherits from WidgetBase, during instantiation of Foo! the base widget_intrinsic is called first, then the Foo! widget_intrinsic is called.

The method does not need to be pub, and it is not required.

§Build

The widget struct can define a method that builds the final widget instance.

use zng::prelude_wgt::*;

#[widget($crate::Foo)]
pub struct Foo(WidgetBase);

impl Foo {
    /// Custom build.
    pub fn widget_build(&mut self) -> impl UiNode {
        println!("on build!");
        WidgetBase::widget_build(self)
    }
}

The build method must have the same visibility as the widget, and can define its own return type, this is the widget instance type. If the build method is not defined the inherited parent build method is used.

Unlike the intrinsic method, the widget only has one widget_build, if defined it overrides the parent widget_build. Most widgets don’t define their own build, leaving it to be inherited from WidgetBase. The base instance type is an opaque impl UiNode.

Normal widgets must implement UiNode, otherwise they cannot be used as child of other widgets. The widget outer-node also must implement the widget context, to ensure that the widget is correctly placed in the UI tree. Note that you can still use the parent type build implementation, so even if you need to run code on build or define a custom type you don’t need to deref to the parent type to build.

§Defaults

The widget_set! macro can be used inside widget_intrinsic to set properties and when conditions that are applied on the widget by default, if not overridden by derived widgets or the widget instance. During the call to widget_intrinsic the self.importance() value is Importance::WIDGET, after it is changed to Importance::INSTANCE, so just by setting properties in widget_intrinsic they will have less importance allowing for the override mechanism to replace them.

§Impl Properties

The widget_impl! macro can be used inside a impl WgtIdent { } block to strongly associate a property with the widget, and the property attribute has a widget_impl(WgtIdent) directive that also strongly associates a property with the widget.

These two mechanisms can be used to define properties for the widget, the impl properties don’t need to be imported and are always selected over other properties of the same name. They also appear in the widget documentation and can have a distinct visual in IDEs as they are represented by immutable methods while standalone properties are represented by mutable trait methods.

As a general rule only properties that are captured by the widget, or only work with the widget, or have an special meaning in the widget are implemented like this, standalone properties that can be used in any widget are not implemented.

§Generated Macro

The generated widget macro has the same syntax as widget_set!, except that is also starts the widget and builds it at the end.

This widget macro call:

let wgt = Foo! {
    id = "foo";
};

Expands to this:

let wgt = {
    let mut wgt = Foo::widget_new();
    widget_set! {
        &mut wgt;
        id = "foo";
    }
    wgt.widget_build()
};
§Custom Rules

You can declare custom rules for the widget macro, this can be used to declare custom shorthand syntax for the widget.

The custom rules are declared inside braces after the widget path in the widget attribute. The syntax is similar to macro_rules! rules, but the expanded tokens are the direct input of the normal widget expansion.

(<rule>) => { <init> };

The <rule> is any macro pattern rule, the <init> is the normal widget init code that the rule expands to.

Note that custom rules are not inherited, they apply only to the declaring widget macro, inherited widgets must replicate the rules if desired.

Example of a widget that declares a shorthand syntax to implicitly set the id property:

use zng::prelude_wgt::*;

#[widget($crate::Foo {
    ($id:expr) => {
        id = $id;
    };
})]
pub struct Foo(WidgetBase);

let wgt = Foo!("foo");

The macro instance above is equivalent to:

let wgt = Foo! {
    id = "foo";
};
§Limitations

The expanded tokens can only be a recursive input for the same widget macro, you can’t expand to a different widget.

Some rules are intercepted by the default widget rules:

  • $(#[$attr:meta])* $($property:ident)::+ = $($rest:tt)*, blocks all custom $ident = $tt* patterns.
  • $(#[$attr:meta])* when $($rest:tt)*, blocks all custom when $tt* patterns.

Note that the default single property shorthand syntax is not blocked, for example Text!(font_size) will match the custom shorthand rule and try to set the txt with the font_size variable, without the shorthand it would create a widget without txt that sets font_size. So a custom rule $p:expr is only recommended for widgets that have a property of central importance.

§Widget Type

A public associated function widget_type is also generated for the widget, it returns a WidgetType instance that describes the widget type. Note that this is not the widget instance type, only the struct and macro type. If compiled with the "inspector" feature the type is also available in the widget info.

§See Also

See the WidgetBase, WidgetBuilder, WidgetBuilding, NestGroup and Importance for more details.

Expands a struct to a widget and macro.

§Full Documentation

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