20 releases (10 breaking)

new 0.11.1 Nov 10, 2024
0.10.1 Oct 20, 2024

#124 in GUI

Download history 828/week @ 2024-09-07 675/week @ 2024-09-14 524/week @ 2024-09-21 219/week @ 2024-09-28 12/week @ 2024-10-05 201/week @ 2024-10-12 187/week @ 2024-10-19 5/week @ 2024-10-26 20/week @ 2024-11-02 204/week @ 2024-11-09

434 downloads per month

MIT license

130KB
3.5K SLoC

Backer

rust crates.io downloads license

A library for straight-forward UI layout.

Dependency free & framework-agnostic. Backer can be used in an index-based layout approach or with inline drawing code.

This library only implements layout & would be most useful along with a GUI library that can do GUI things (like macroquad or egui).

Features ✨

  • Declarative API: The code should look like the structure it defines
  • Minimal interface: No confusing overloads or magic, cascading effects
  • Intuitive constraints: Backer adheres to & smoothly resolves size constraints with an advanced algorithm
  • Performant: Layout can be comfortably recalculated every frame
  • Easy integration & compatibility: Backer should work with just about any UI library with a bit of glue - so it isn't really fine-tuned for any specific UI solution.

This project intends to be a flexible layout tool & not much else.

Preview

Check out the demo site: a mock page showcasing layout capabilities in a realistic interface. Built with egui!

Backer relies on simple rules that can compose to create complex, flexible layouts.

stretched

See some code
    column_spaced(
        10.,
        vec![
            draw_a(ui),
            row_spaced(
                10.,
                vec![
                    draw_b(ui).width(180.).align(Align::Leading),
                    column_spaced(10., vec![draw_a(ui), draw_b(ui), draw_c(ui)]),
                ],
            ),
            draw_c(ui),
        ],
    )
    .pad(10.)

Quick Start

1. Create a Layout struct with your layout function.

use backer::layout::Layout;
use backer::layout::Node;

let layout = Layout::new(my_layout_fn);

fn my_layout_fn(state: &mut MyState) -> Node<MyState> { todo!() }

2. Implement a draw node

For reuse, you can construct your drawable in a function

fn my_drawable(state: &mut MyState) -> Node<MyState> {
  draw(move |area: Area, state: &mut MyState| {
    // The `area` parameter is the space alotted for your view after layout is calculated
    // The `state` parameter is *your* mutable state that you pass when you call layout.
    // This closure should draw UI based on the alotted area or update state so that drawing can be performed later.
  })
}

3. Combine nodes to define & customize your layout

fn my_layout_fn(state: &mut MyState) -> Node<MyState> {
  row(vec![
      my_drawable(state)
  ])
}

4. Draw your layout

// UI libraries generally will expose methods to get the available screen size
// In a real implementation this should use the real screen size!
let available_area = Area {
        x: todo!(),
        y: todo!(),
        width: todo!(),
        height: todo!().
    };
let mut my_state = MyState::new();

let layout = Layout::new(my_layout_fn);
// Perform layout & draw all of your drawable nodes.
layout.draw(available_area, &mut my_state);

Status

The crate is currently usable but new! Breaking changes may be relatively frequent as the crate matures.

Contributions are always welcome 🤗

No runtime deps