arkham/docs/overview/components.md

3.0 KiB

title subtitle menu_position
Designing Components Overview 1

Component overview

A component in Arkham is a piece of rendering logic that could be reusable, or could be used for organization. They are simple functions that accept a ViewContext reference, alongside any injected objects. See Dependency Injection

A simple component might look like this:

fn seperator(ctx: &mut ViewContext) {
    let width = ctx.size().width;
    let sep_chars = "-".repeat(ctx.size().width);
    ctx.insert(sep_chars);
}

Components with parameters

Reusable components will need the ability to pass parameters into them. This is done by returning the component function from within another function.

fn name_field(name: &str) -> impl Fn(&mut ViewContext) {
    move |ctx:&mut ViewContext| {
        ctx.insert((0,0), "Name:");
        ctx.insert((10,0), name);
    }
}

Understanding component sizing and positioning

When a component is used it is allocated a specific Rect that it can render to. The total dimensions for the component are available in ViewContext::size(). Components are also rendered at a specific position (the upper left corner). Inside a component its coordinates are relative to itself, its upper left corner is (0,0).

Using components

A component can render other components inside them.

In this example we can also see the component positioning and sizing. The first parameter to ViewContext::component is a Rect for the component. This is the position in the parent component it will render its top left corner to and the size the component is allowed to render to.

The first parameter to Rect::new is the Pos for the rect, the coordinates of its top left corner. From the perspective of the field component, the content is inserted at y=0. However, when the component is placed in the container component, its upper left coordinate is specified and the coordinates of the field component become relative to the specified position in the container component.

The second parameter to Rect::new is the Size of the Rect. Its width and height.

fn field(key: &str, value: &str) -> impl Fn(&mut ViewContext) {
    move |ctx: &mut ViewContext| {
        ctx.insert((0,0), format!("{}:", key));
        ctx.insert((10,0), value);
    }
}

fn container(ctx: &mut ViewContext) {
    ctx.component(Rect::new((0,0), (10,1)), field("Name", "Alice")
    ctx.component(Rect::new((0,1), (10,1)), field("Age", "22")
}

The container component will render to the following:

Name:    Alice 
Age:     22

Components as closures

When you need something more complex than ViewContext::insert, but don't want to build a whole separate component. Components can be defined inline using a closure.

fn container(ctx: &mut ViewContext) {
    let size = ctx.size();
    ctx.component(
        Rect::new((0,0), (size.width, size.height /2))
        |ctx: &mut ViewContext| {
            ctx.fill_all(Color::Blue);
        }
    );
}