Documented widget syntax.

This commit is contained in:
Samuel Guerra 2023-04-14 17:31:34 -03:00
parent 80e9861757
commit 8cbe116e9a
5 changed files with 322 additions and 386 deletions

View File

@ -6,7 +6,6 @@
- They can be identified with the `P` tag.
Also group in the `unset_property` methods.
* (Re)write property/when syntax docs in `widget_set!`.
* Test widget generated macro in crate that does not depend on zero-ui directly.
* Test all.

View File

@ -1,383 +0,0 @@
///
///
/// Inside the widget module the `properties!` pseudo-macro can used to declare properties of the widget. The properties can
/// be assigned, renamed and exported as widget properties.
///
/// ```
/// # fn main() { }
/// use zero_ui_core::{*, widget_builder::*, widget_instance::*, var::*};
///
/// #[property(CONTEXT)]
/// pub fn bar(child: impl UiNode, val: impl IntoVar<bool>) -> impl UiNode {
/// let _ = val;
/// child
/// }
///
/// #[widget($crate::foo)]
/// pub mod foo {
/// inherit!(super::widget_base::base);
///
/// properties! {
/// /// Baz property docs.
/// pub super::bar as baz = true;
/// // inherited property
/// enabled = false;
/// }
/// }
/// ```
///
/// The example above declares an widget that exports the property `baz`, it is also automatically set to `true` and it also
/// sets the inherited [`WidgetBase`] property `enabled` to `false`.
///
/// The property visibility controls if it is assignable in derived widgets or during widget instantiation, in the example above
/// if `baz` was not `pub` it would be set on the widget but it does not get a `baz` property accessible from outside. Inherited
/// visibility cannot be overridden, the `enabled` property is defined as `pub` in [`WidgetBase`] so it is still `pub` in the
/// widget, even though the value was changed.
///
/// You can also export properties without defining a value, the default assign is not required, the property is only instantiated
/// if it is assigned in the final widget instance, but by exporting the property it is available in the widget macro by name without
/// needing a `use` import.
///
/// ## Unset
///
/// If an inherited property is assigned a value you can *unset* this value by assigning the property with the special value `unset!`.
///
/// ```
/// # fn main() { }
/// use zero_ui_core::{*, widget_builder::*, widget_instance::*, var::*};
/// #
/// # #[property(CONTEXT)]
/// # pub fn baz(child: impl UiNode, val: impl IntoVar<bool>) -> impl UiNode {
/// # let _ = val;
/// # child
/// # }
/// #
/// # #[widget($crate::foo)]
/// # pub mod foo {
/// # inherit!(super::widget_base::base);
/// #
/// # properties! {
/// # pub super::baz = true;
/// # }
/// # }
/// #[widget($crate::bar)]
/// pub mod bar {
/// inherit!(crate::foo);
///
/// properties! {
/// baz = unset!;
/// }
/// }
/// ```
///
/// In the example above the widget `bar` inherits the `foo` widget that defines and sets the `baz` property. Instances of the
/// `bar` property will not include an instance of `baz` because it was `unset!`. Note that this does not remove the property
/// the `bar` widget still exports the `baz` property, it just does not have a default value anymore.
///
/// An `unset!` assign also removes all `when` assigns to the same property, this is unlike normal assigns that just override the
/// *default* value of the property, merged with the `when` assigns.
///
/// ## Multiple Inputs
///
/// Some properties have multiple inputs, you can use a different syntax to assign each input by name or as a comma separated list.
/// In the example below the property `anb` has two inputs `a` and `b`, they are assigned by name in the `named` property and by
/// position in the `unnamed` property. Note that the order of inputs can be swapped in the named init.
///
/// ```
/// # fn main() { }
/// use zero_ui_core::{*, widget_builder::*, widget_instance::*, var::*};
///
/// #[property(CONTEXT)]
/// pub fn anb(child: impl UiNode, a: impl IntoVar<bool>, b: impl IntoVar<bool>) -> impl UiNode {
/// # child
/// }
///
/// #[widget($crate::foo)]
/// pub mod foo {
/// inherit!(super::widget_base::base);
///
/// properties! {
/// pub super::anb as named = {
/// b: false,
/// a: true,
/// };
/// pub super::anb as unnamed = true, false;
/// }
/// }
/// ```
///
/// ## Generics
///
/// Some properties have named generics, the unnamed `impl` generics are inferred, but the named types must be defined using the *turbo-fish*
/// syntax if you want to set a value.
///
/// ```
/// # fn main() { }
/// use zero_ui_core::{*, widget_builder::*, widget_instance::*, var::*};
///
/// #[property(CONTEXT)]
/// pub fn value<T: VarValue>(child: impl UiNode, value: impl IntoVar<T>) -> impl UiNode {
/// # child
/// }
///
/// #[widget($crate::foo)]
/// pub mod foo {
/// inherit!(super::widget_base::base);
///
/// properties! {
/// pub super::value::<bool> = true;
/// }
/// }
/// ```
///
/// Note that the property is not exported with the generics, the generic type must be specified in all other assigns, properties
/// are also only identified by their source and name, so an assign with different type still replaces the value.
///
/// ## Capture Only
///
/// Properties can be *captured* during build using the capture methods of [`WidgetBuilding`], captured properties are not
/// instantiated, the args are redirected to the intrinsic implementation of the widget. Every property can be captured, but
/// some properties are always intrinsic to the widget and cannot have a standalone implementation. You can declare *capture-only*
/// properties using the syntax `pub name(T)`, this expands to a [capture-only](property#capture-only) property that is
/// exported by the widget.
///
/// ```
/// # fn main() { }
/// use zero_ui_core::{*, widget_builder::*, widget_instance::*, var::*};
///
/// #[widget($crate::foo)]
/// pub mod foo {
/// use super::*;
///
/// inherit!(widget_base::base);
///
/// properties! {
/// /// Docs.
/// pub bar(impl IntoVar<bool>) = false;
/// }
///
/// fn include(wgt: &mut WidgetBuilder) {
/// wgt.push_build_action(|wgt| {
/// let bar = wgt.capture_var_or_else::<bool, _>(property_id!(Self::bar), || false);
/// println!("bar: {}", bar.get());
/// });
/// }
/// }
/// ```
///
/// In the example above `bar` expands to:
///
/// ```
/// # fn main() { }
/// # use zero_ui_core::{*, widget_builder::*, widget_instance::*, var::*};
/// #[doc(hidden)]
/// #[property(CONTEXT, capture, default(false))]
/// pub fn __bar__(__child__: impl UiNode, bar: impl IntoVar<bool>) -> impl UiNode {
/// __child__
/// }
/// # macro_rules! demo { () => {
/// properties! {
/// /// Docs.
/// pub __bar__ as bar;
/// }
/// # }}
/// ```
///
/// The capture property is re-exported in the widget, and a build action captures it and prints the value. Usually in
/// a captured variable is used in intrinsic nodes that implement a core feature of the widget.
///
/// This shorthand capture property can only have one unnamed input, the input type can be any of the types allowed in property inputs. If
/// the property is assigned the value is used as the property default and a normal property assign is also inserted.
///
/// ## When
///
/// Conditional property assigns can be setup using `when` blocks. A `when` block has a `bool` expression and multiple property assigns,
/// when the expression is `true` each property has the assigned value, unless it is overridden by a later `when` block.
///
/// ```
/// # fn main() { }
/// # use zero_ui_core::{*, widget_builder::*, widget_instance::*, color::*, var::*};
/// #
/// # #[property(FILL)]
/// # pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
/// # let _ = color;
/// # child
/// # }
/// #
/// # #[property(LAYOUT)]
/// # pub fn is_pressed(child: impl UiNode, state: impl IntoVar<bool>) -> impl UiNode {
/// # let _ = state;
/// # child
/// # }
/// #
/// # #[widget($crate::foo)]
/// # pub mod foo {
/// # use super::*;
/// #
/// # inherit!(widget_base::base);
/// #
/// properties! {
/// background_color = colors::RED;
///
/// when *#is_pressed {
/// background_color = colors::GREEN;
/// }
/// }
/// # }
/// ```
///
/// ### When Condition
///
/// The `when` block defines a condition expression, in the example above this is `*#is_pressed`. The expression can be any Rust expression
/// that results in a [`bool`] value, you can reference properties in it using the `#` token followed by the property name or path and you
/// can reference variables in it using the `#{var}` syntax. If a property or var is reference the `when` block is dynamic, updating all
/// assigned properties when the expression result changes.
///
/// ### Property Reference
///
/// The most common `when` expression reference is a property, in the example above the `is_pressed` property is instantiated for the widget
/// and it's input read-write var controls when the background is set to green. Note that a reference to the value is inserted in the expression
/// so an extra deref `*` is required. A property can also be referenced with a path, `#properties::is_pressed` also works.
///
/// The syntax seen so far is actually a shorthand way to reference the first input of a property, the full syntax is `#is_pressed.0` or
/// `#is_pressed.state`. You can use the extended syntax to reference inputs of properties with out than one input, the input can be
/// reference by tuple-style index or by name. Note that if the value it self is a tuple or `struct` you need to use the extended syntax
/// to reference a member of the value, `#foo.0.0` or `#foo.0.name`. Methods have no ambiguity, `#foo.name()` is the same as `#foo.0.name()`.
///
/// Not all properties can be referenced in `when` conditions, only inputs of type `impl IntoVar<T>` and `impl IntoValue<T>` are
/// allowed, attempting to reference a different kind of input generates a compile error.
///
/// ### Variable Reference
///
/// Other variable can also be referenced, in a widget declaration only context variables due to placement, but in widget instances any locally
/// declared variable can be referenced. Like with properties the variable value is inserted in the expression as a reference so you may need
/// to deref in case the var is a simple [`Copy`] value.
///
/// ```
/// # fn main() { }
/// # use zero_ui_core::{*, widget_builder::*, widget_instance::*, color::*, var::*};
/// #
/// # #[property(FILL)]
/// # pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
/// # let _ = color;
/// # child
/// # }
/// #
/// context_var! {
/// pub static FOO_VAR: Vec<&'static str> = vec![];
/// pub static BAR_VAR: bool = false;
/// }
/// #
/// # #[widget($crate::foo)]
/// # pub mod foo {
/// # use super::*;
/// #
/// # inherit!(widget_base::base);
///
/// properties! {
/// background_color = colors::RED;
///
/// when !*#{BAR_VAR} && #{FOO_VAR}.contains(&"green") {
/// background_color = colors::GREEN;
/// }
/// }
/// # }
/// ```
///
/// ### When Assigns
///
/// Inside the `when` block a list of property assigns is expected, only properties with all inputs of type `impl IntoVar<T>` can ne assigned
/// in `when` blocks, you also cannot `unset!` in when assigns. On instantiation a single instance of the property will be generated, the input
/// vars will track the when expression state and update to the value assigned in the block when it is `true`. When no block is `true` the value
/// assigned to the property outside `when` blocks is used, or the property default value. When more then one block is `true` the *last* one
/// sets the value.
///
/// ### Default Values
///
/// A when assign can be defined by a property without setting a default value, during instantiation if the property declaration has
/// a default value it is used, or if the property was later assigned a value it is used as *default*, if it is not possible to generate
/// a default value the property is not instantiated and the when assign is not used.
///
/// The same apply for properties referenced in the condition expression, note that all `is_state` properties have a default value so
/// it is more rare that a default value is not available. If a condition property cannot be generated the entire when block is ignored.
///
/// # Instantiation
///
/// After the widget macro attribute expands you can still use the module like any other mod, but you can also use it like a macro that
/// accepts property inputs like the `properties!` pseudo-macro, except for the visibility control.
///
/// ```
/// # use zero_ui_core::{*, widget_builder::*, widget_instance::*, color::*, var::*};
/// #
/// # #[property(CONTEXT)]
/// # pub fn bar(child: impl UiNode, val: impl var::IntoVar<bool>) -> impl UiNode {
/// # let _ = val;
/// # child
/// # }
/// #
/// # #[property(LAYOUT)]
/// # pub fn margin(child: impl UiNode, val: impl var::IntoVar<u32>) -> impl UiNode {
/// # let _ = val;
/// # child
/// # }
/// #
/// # #[property(FILL)]
/// # pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
/// # let _ = color;
/// # child
/// # }
/// #
/// # #[property(LAYOUT)]
/// # pub fn is_pressed(child: impl UiNode, state: impl IntoVar<bool>) -> impl UiNode {
/// # let _ = state;
/// # child
/// # }
/// #
/// # #[widget($crate::foo)]
/// # pub mod foo {
/// # inherit!(super::widget_base::base);
/// #
/// # properties! {
/// # /// Baz property docs.
/// # pub super::bar as baz = true;
/// # // inherited property
/// # enabled = false;
/// # }
/// # }
/// # fn main() {
/// # let _scope = app::App::minimal();
/// let wgt = foo! {
/// baz = false;
/// margin = 10;
///
/// when *#is_pressed {
/// background_color = colors::GREEN;
/// }
/// };
/// # }
/// ```
///
/// In the example above the `baz` property is imported from the `foo!` widget, all widget properties are imported inside the
/// widget macro call, and `foo` exported `pub bar as baz`. The value of `baz` is changed for this instance, the instance also
/// gets a new property `margin`, that was not defined in the widget.
///
/// Most of the features of `properties!` can be used in the widget macro, you can `unset!` properties or rename then using the `original as name`
/// syntax. You can also setup `when` conditions, as demonstrated above, the `background_color` is `GREEN` when `is_pressed`, these properties
/// also don't need to be defined in the widget before use, but if they are they are used instead of the contextual imports.
///
/// ## Init Shorthand
///
/// The generated instantiation widget macro also support the *init shorthand* syntax, where the name of a `let` variable defines the property
/// name and value. In the example below the `margin` property is set on the widget with the value of `margin`.
///
/// ```
/// # macro_rules! demo {
/// # () => {
/// let margin = 10;
/// let wgt = foo! {
/// margin;
/// };
/// # };
/// # }
/// ```

View File

@ -3,4 +3,4 @@ use zero_ui::prelude::new_widget::*;
#[widget($crate::Foo)]
pub struct Foo(f32);
fn main() { }
fn main() {}

View File

@ -756,6 +756,8 @@ mod private {
/// }
/// }
/// ```
///
/// This macro has the same syntax as [`widget_set!`], it only changes the importance of property and when defined in it.
#[macro_export]
macro_rules! widget_dft {
(
@ -845,6 +847,324 @@ macro_rules! widget_dft {
///
/// You should use this macro only in contexts where a widget will be build in steps, or in very hot code paths where a widget
/// has many properties and only some will be non-default per instance.
///
///
///
/// # Property Set
///
/// Properties can be assigned using the `property = value;` syntax, this expands to a call to the property method, either
/// directly implemented on the widget or from a trait.
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// id = "test";
/// background_color = colors::BLUE;
/// # }; }
/// ```
///
/// The example above is equivalent to:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let mut wgt = zero_ui_core::widget_base::WidgetBase::start();
/// wgt.id("test");
/// wgt.background_color(colors::BLUE);
/// # }
/// ```
///
/// Note that `id` is an intrinsic property inherited from [`WidgetBase`], but `background_color` is an extension property declared
/// by a [`property`] function. Extension properties require `&mut self` access to the widget, intrinsic properties only require `&self`,
/// this is done so that IDEs that use a different style for mutable methods highlight the properties that are not intrinsic to the widget.
///
/// ## Path Set
///
/// An full or partial path can be used to specify exactly what extension property will be set:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// self::background_color = colors::BLUE;
/// # }; }
/// ```
///
/// In the example above `self::background_color` specify that an extension property that is imported in the `self` module must be set,
/// even if the widget gets an intrinsic `background_color` property the extension property will still be used.
///
/// The example above is equivalent to:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let mut wgt = zero_ui_core::widget_base::WidgetBase::start();
/// self::background_color::background_color(&mut *wgt, colors::BLUE);
/// # }
/// ```
///
/// ## Named Set
///
/// Properties can have multiple parameters, multiple parameters can be set using the struct init syntax:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*, units::*};
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// border = {
/// widths: 1,
/// sides: colors::RED,
/// };
/// # }; }
/// ```
///
/// Note that just like in struct init the parameters don't need to be in order:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*, units::*};
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// border = {
/// sides: colors::RED,
/// widths: 1,
/// };
/// # }; }
/// ```
///
/// Internally each property method has auxiliary methods that validate the member names and construct the property using sorted params, therefore
/// accepting any parameter order. Note each parameter is evaluated in the order they appear, even if they are assigned in a different order after.
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*, units::*};
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// let mut eval_order = vec![];
///
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// border = {
/// sides: {
/// eval_order.push("sides");
/// colors::RED
/// },
/// widths: {
/// eval_order.push("widths");
/// 1
/// },
/// };
/// # };
///
/// assert_eq!(eval_order, vec!["sides", "widths"]);
/// # }
/// ```
///
/// ## Unnamed Set Multiple
///
/// Properties with multiple parameters don't need to be set using the named syntax:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*, units::*};
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// border = 1, colors::RED;
/// # }; }
/// ```
///
/// The example above is equivalent to:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*, units::*};
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let mut wgt = zero_ui_core::widget_base::WidgetBase::start();
/// wgt.border(1, colors::RED);
/// # }
/// ```
///
/// ## Shorthand Set
///
/// Is a variable with the same name as a property is in context the `= name` can be omitted:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// let id = "name";
/// let background_color = colors::BLUE;
/// let widths = 1;
///
/// let wgt = zero_ui_core::widget_base::WidgetBase! {
/// id;
/// self::background_color;
/// border = {
/// widths,
/// sides: colors::RED,
/// };
/// };
/// # }
/// ```
///
/// Note that the shorthand syntax also works for path properties and parameter names.
///
/// The above is equivalent to:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// let id = "name";
/// let background_color = colors::BLUE;
/// let widths = 1;
///
/// let wgt = zero_ui_core::widget_base::WidgetBase! {
/// id = id;
/// self::background_color = background_color;
/// border = {
/// widths: widths,
/// sides: colors::RED,
/// };
/// };
/// # }
/// ```
///
/// # Property Unset
///
/// All properties can be assigned to an special value `unset!`, that *removes* a property, when the widget is build the
/// unset property will not be instantiated:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*, units::*};
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// border = unset!;
/// # }; }
/// ```
///
/// The example above is equivalent to:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*, units::*};
/// # #[property(CONTEXT)] pub fn border(child: impl UiNode, widths: impl IntoVar<SideOffsets>, sides: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # fn main() {
/// # let mut wgt = zero_ui_core::widget_base::WidgetBase::start();
/// wgt.unset_border();
/// # }
/// ```
///
/// Each property method generates an auxiliary `unset_property` method, the unset is registered in the widget builder using the current
/// importance, in [`widget_dft!`] they only unset already inherited default assigns, in [`widget_set!`] it unsets all inherited or
/// previous assigns, see [`WidgetBuilder::push_unset`] for more details.
///
/// # Generic Properties
///
/// Generic properties need a *turbofish* annotation on assign:
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn value<T: VarValue>(child: impl UiNode, value: impl IntoVar<T>) -> impl UiNode { child }
/// #
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// value::<f32> = 1.0;
/// # };}
/// ```
///
/// # When
///
/// Conditional property assigns can be setup using `when` blocks. A `when` block has a `bool` expression and multiple property assigns,
/// when the expression is `true` each property has the assigned value, unless it is overridden by a later `when` block.
///
/// ```
/// # use zero_ui_core::{*, var::*, color::*};
/// # #[property(CONTEXT)] pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode { child }
/// # #[property(EVENT)] pub fn is_pressed(child: impl UiNode, state: impl IntoVar<bool>) -> impl UiNode { child }
/// # fn main() {
/// # let wgt = zero_ui_core::widget_base::WidgetBase! {
/// background_color = colors::RED;
///
/// when *#is_pressed {
/// background_color = colors::GREEN;
/// }
/// # }; }
/// ```
///
/// ## When Condition
///
/// The `when` block defines a condition expression, in the example above this is `*#is_pressed`. The expression can be any Rust expression
/// that results in a [`bool`] value, you can reference properties in it using the `#` token followed by the property name or path and you
/// can reference variables in it using the `#{var}` syntax. If a property or var is reference the `when` block is dynamic, updating all
/// assigned properties when the expression result changes.
///
/// ### Property Reference
///
/// The most common `when` expression reference is a property, in the example above the `is_pressed` property is instantiated for the widget
/// and it's input read-write var controls when the background is set to green. Note that a reference to the value is inserted in the expression
/// so an extra deref `*` is required. A property can also be referenced with a path, `#properties::is_pressed` also works.
///
/// The syntax seen so far is actually a shorthand way to reference the first input of a property, the full syntax is `#is_pressed.0` or
/// `#is_pressed.state`. You can use the extended syntax to reference inputs of properties with out than one input, the input can be
/// reference by tuple-style index or by name. Note that if the value it self is a tuple or `struct` you need to use the extended syntax
/// to reference a member of the value, `#foo.0.0` or `#foo.0.name`. Methods have no ambiguity, `#foo.name()` is the same as `#foo.0.name()`.
///
/// Not all properties can be referenced in `when` conditions, only inputs of type `impl IntoVar<T>` and `impl IntoValue<T>` are
/// allowed, attempting to reference a different kind of input generates a compile error.
///
/// ### Variable Reference
///
/// Other variable can also be referenced, context variables or any locally declared variable can be referenced. Like with properties
/// the variable value is inserted in the expression as a reference so you may need to deref in case the var is a simple [`Copy`] value.
///
/// ```
/// # use zero_ui_core::{*, widget_builder::*, widget_instance::*, color::*, var::*};
/// #
/// # #[property(FILL)]
/// # pub fn background_color(child: impl UiNode, color: impl IntoVar<Rgba>) -> impl UiNode {
/// # let _ = color;
/// # child
/// # }
/// #
/// context_var! {
/// pub static FOO_VAR: Vec<&'static str> = vec![];
/// pub static BAR_VAR: bool = false;
/// }
/// # fn main() {
/// # let wgt = widget_base::WidgetBase! {
/// background_color = colors::RED;
///
/// when !*#{BAR_VAR} && #{FOO_VAR}.contains(&"green") {
/// background_color = colors::GREEN;
/// }
/// # };}
/// ```
///
/// ## When Assigns
///
/// Inside the `when` block a list of property assigns is expected, most properties can be assigned, but `impl IntoValue<T>` properties cannot,
/// you also cannot `unset!` in when assigns, a compile time error happens if the property cannot be when assigned.
///
/// On instantiation a single instance of the property will be generated, the parameters will track the when expression state and update
/// to the value assigned when it is `true`. When no block is `true` the value assigned to the property outside `when` blocks is used, or the property default value. When more then one block is `true` the *last* one sets the value.
///
/// ### Default Values
///
/// A when assign can be defined by a property without setting a default value, during instantiation if the property declaration has
/// a default value it is used, or if the property was later assigned a value it is used as *default*, if it is not possible to generate
/// a default value the property is not instantiated and the when assign is not used.
///
/// The same apply for properties referenced in the condition expression, note that all `is_state` properties have a default value so
/// it is more rare that a default value is not available. If a condition property cannot be generated the entire when block is ignored.
///
/// [`WidgetBase`]: struct@crate::widget_base::WidgetBase
/// [`WidgetBuilder::push_unset`]: crate::widget_builder::WidgetBuilder::push_unset
#[macro_export]
macro_rules! widget_set {
(

View File

@ -3,7 +3,7 @@
use std::mem;
use super::image_properties::{
ImgErrorArgs, ImageFit, ImgLoadingArgs, IMAGE_ALIGN_VAR, IMAGE_CACHE_VAR, IMAGE_CROP_VAR, IMAGE_DOWNSCALE_VAR, IMAGE_ERROR_GEN_VAR,
ImageFit, ImgErrorArgs, ImgLoadingArgs, IMAGE_ALIGN_VAR, IMAGE_CACHE_VAR, IMAGE_CROP_VAR, IMAGE_DOWNSCALE_VAR, IMAGE_ERROR_GEN_VAR,
IMAGE_FIT_VAR, IMAGE_LIMITS_VAR, IMAGE_LOADING_GEN_VAR, IMAGE_OFFSET_VAR, IMAGE_RENDERING_VAR, IMAGE_SCALE_FACTOR_VAR,
IMAGE_SCALE_PPI_VAR, IMAGE_SCALE_VAR,
};