macro_rules! build_ui {
    (@preset entity) => { ... };
    (@preset $anything_else:ident) => { ... };
    (@preset $node:ident {$($styles:tt)*}) => { ... };
    (@child_list list: (if ($predicate:expr) { $( $if_true:tt )* } else { $( $if_false:tt )* } $(,)?),
        cmds: $cmds:expr, prefix: ($( $prefix:tt )*),
    ) => { ... };
    (@child_list list: (if ($predicate:expr) { $( $if_true:tt )* } $(,)?),
        cmds: $cmds:expr, prefix: ($( $prefix:tt )*),
    ) => { ... };
    (@child_list list: (
            if ($predicate:expr) { $( $if_true:tt )* } else { $( $if_false:tt )* }
            , $( $tail:tt )+
        ),
        cmds: $cmds:expr, prefix: ($( $prefix:tt )*),
    ) => { ... };
    (@child_list list: (if ($predicate:expr) { $( $if_true:tt )* } , $( $tail:tt )+),
        cmds: $cmds:expr, prefix: ($( $prefix:tt )*),
    ) => { ... };
    (@child_list list: ($preset:ident $( { $($syl:tt)* } )? $( [ $($bc:tt)* ] )? $( ( $( $c:tt )* ) )? $(,)?),
        cmds: $cmds:expr, prefix: ($( $prefix:tt )*),
    ) => { ... };
    (@child_list list: (
            $preset:ident $( { $($syl:tt)* } )? $( [ $($bc:tt)* ] )? $( ( $( $c:tt )* ) )?
            , $( $tail:tt )+
        ),
        cmds: $cmds:expr, prefix: ($( $prefix:tt )*),
    ) => { ... };
    (#[cmd($cmds:expr)] id ( $id:expr )) => { ... };
    (#[cmd($cmds:expr)] $preset:ident
        $( {$($styles:tt)*} )? // {..} style modifiers
        $( [$($bundles:expr),* ; $($components:expr),*] )? // [..] components
        $( ( $( $children_list:tt )* ) )?
    ) => { ... };
}
Expand description

Define a bevy UI and spawns it using cmd

Syntax

use bevy::prelude::*;
let commands: Commands;
let my_id: Entity;
build_ui! {
    // The bevy `Commands`
    #[cmd(commands)]
    // The "preset" is an identifier, see doc
    $entity
        // Style modifiers. Supposing $entity is a `NodeBundle`, does:
        // $entity.style = style!{ flex_whatever: Whatever }
        // Leads to a compilation error if $entity doesn't have a `style`
        // field
        { flex_whatever: Whatever }
        // Additional components and bundles. Translates to
        // $entity.insert_bundle(bundle1).insert_bundle(bundle2).insert(comp1).insert(comp2)
        // If you don't care for bundles or comp, just leave the left or
        // right of the ; blank
        [bundle1, bundl2 ;comp1, comp2]
        // Children entities, may have {..}, [..;..] and (..)
        (
            entity[ButtonBundle](square),
            id(my_id)
        )
}

The $entity in the macro may be one of the following:

  • id(Entity): inserts a pre-existing entity as child of containing entity
  • $ident: where $ident is the name of a local variable of type T: ComponentBundle. Spawn the bundle as base to insert extra components to. Useful to not repeat yourself.
  • entity: spawn an empty bundle as base to insert extra components to.

Example

build_ui! {
    #[cmd(commands)]
    vertical{size:size!(100 pct, 100 pct)}(
        horizontal{justify_content: FlexStart, flex_basis: unit!(10 pct)}(
            tab_square[;focus], tab_square[;focus], tab_square[;focus],
        ),
        column_box(
            column[;red](
                vertical(select_square, select_square),
                horizontal{flex_wrap: Wrap}[gray](
                    square[;focus], square[;focus], square[;focus], square[;focus],
                    square[;focus], square[;focus], square[;focus], square[;focus],
                    square[;focus], square[;focus], square[;focus], square[;focus],
                ),
                horizontal{flex_wrap: Wrap}[gray](
                    square[;focus], square[;focus], square[;focus], square[;focus],
                    square[;focus], square[;focus], square[;focus], square[;focus],
                ),
            ),
        ),
    )
}
// Basically becomes
commands.spawn_bundle(NodeBundle {
    style: Style { size: size!(100 pct, 100 pct), .. vertical.style },
    .. vertical
})
  .with_children(|cmds| {
    cmds.spawn_bundle(NodeBundle {
        style: Style {justify_content: FlexStart, flex_basis: unit!(10 pct), .. horizontal.style },
        .. horizontal
    })
      .with_children(|cmds| {
        cmds.spawn_bundle(tab_square).insert(focus);
        cmds.spawn_bundle(tab_square).insert(focus);
        cmds.spawn_bundle(tab_square).insert(focus);
      });
    cmds.spawn_bundle(column_box)
      .with_children(|cmds| {
        cmds.spawn_bundle(column).insert(red)
          .with_children(|cmds| {
            vertical.with_children(|cmds| {
              cmds.spawn_bundle(select_square);
              cmds.spawn_bundle(select_square);
            });
            cmds.spawn_bundle(NodeBundle {
                style: Style {flex_wrap: Wrap, ..horizontal.style},
                .. horizontal
            }).insert(gray)
              .with_children(|cmds| {
                for _ in 0..12 {
                  cmds.spawn_bundle(square).insert(focus);
                }
              });
            cmds.spawn_bundle(NodeBundle {
                style: Style {flex_wrap: Wrap, ..horizontal.style},
                .. horizontal
            }).insert(gray)
              .with_children(|cmds| {
                for _ in 0..8 {
                  cmds.spawn_bundle(square).insert(focus);
                }
              });
          });
      });
  });