macro_rules! build {
    ( group $ui:expr => $args:tt $then:tt $($rest:tt)* ) => { ... };
    ( process $element:expr , $ui:expr => ( $($args:expr),* ) $then:tt $($rest:tt)* ) => { ... };
    ( $statement:stmt ; $($rest:tt)* ) => { ... };
    () => { ... };
}
Expand description

Convenience macro for pushing and popping groups automatically.

Since it can be quite annoying to have to call Ui::push and Ui::pop manually, this macro aims to solve that by offloading the work to the Rust compiler. It also helps show how groups are nested, further aiding readability.

Syntax

The syntax for using this macro is:

paws::build! {
    group ui => ((800.0, 600.0), Layout::Freeform) { }
    process element, &mut ui => (args) { }
    // or any old statement
}

group

group’s primary use case is for pushing and popping UI groups. A group is transformed like so:

paws::build! {
    group ui => ((300.0, 300.0), Layout::Freeform) {
        println!("hi!");
    }
}
// becomes
ui.push((300.0, 300.0), Layout::Freeform);
{
    println!("hi!");
}
ui.pop();

This module’s examples use a real Ui, but group will work with anything that implements methods called push and pop, so you can even use it with Vec<T> (although that doesn’t mean you should):

let mut stack: Vec<i32> = Vec::new();
paws::build! {
    group stack => (3) {
        assert_eq!(*stack.last().unwrap(), 3);
    }
}

process

process’s primary use case is for user elements that may nest other groups, like panels, menus, windows, etc. Contrary to group, this will call methods called begin and end, as they better signify what is actually done. Here’s an example of how one might implement a window:

use paws::Vector;

// of course, your window will contain actual data like its position, maybe also size, etc.
struct Window;

impl Window {
    // for this example though, the size of the window will be defined by the caller.
    fn begin(&mut self, _ui: &mut Ui<NoRenderer>, _size: impl Into<Vector>, _title: &str) {}
    fn end(&mut self) {}
}

let mut window = Window;
paws::build! {
    process window, &mut ui => ((300.0, 500.0), "Hello, world") {
        // draw stuff inside the window
    }
}

The reason why the element comes before the UI instance is to aid readability. In this case, it’s clear that which element is being processed is more important than the UI instance that’s being used, as there’s usually only one of the latter, while there may be many other elements present.

A process is transformed just like a group, with a few key differences:

paws::build! {
    process window, &mut ui => ((300.0, 500.0), "Hello, world") {
        println!("inside the window!");
    }
}
// becomes
window.begin(&mut ui, (300.0, 500.0), "Hello, world");
{
    println!("inside the window!");
}
window.end();

The first, probably most noticable difference, is that the method names are begin and end, instead of push and pop, as previously mentioned. The second difference is that begin receives the UI instance before all other parameters.