| Crates.io | matte |
| lib.rs | matte |
| version | 0.3.1 |
| created_at | 2025-03-12 16:54:02.172591+00 |
| updated_at | 2025-03-23 00:43:58.767885+00 |
| description | Minimalist and allocation free GUI Layout |
| homepage | |
| repository | https://github.com/DoctorWhoof/matte |
| max_upload_size | |
| id | 1590075 |
| size | 496,172 |
A minimalist immediate mode, no_std and no allocations layout library for rectangular elements (Frames), intended for games, embedded systems, and other constrained environments. Matte does not perform any rendering, it simply lays out nested rectangles (Frames) with margins and gaps between children.
While easy to use, Matte's approach is very limited and can't create complex layouts! There are a few key functions to work with:
For instance, repeatedly pushing a new Frame from the same edge is analogous to using a "Row" or "Column" in a more complex GUI library.
It does not have any knowledge of fancy things like rendering and input. Instead, it provides you with closures that are aware of their parent Frame's rectangle and available space, and you do the rendering and input yourself.
It also does not know in advance the size of the children, so you may need to do the math yourself within the closure before adding children, although this is planned to be easier in the future. You can use the [Frame::cursor()] method to check the available space after margin is applied, or [Frame::rect()] to get the closure's rectangle.
To evenly divide a frame into columns and rows, you can use the [Frame::divide_width()] and [Frame::divide_height()] functions to obtain the desired width and height of each child frame taking gaps and margin into account.

Three examples are provided:
use matte::{Frame, Rect, Fitting, Edge::*, Align::*};
fn main() {
// Create a root frame
let mut root = Frame::new(Rect {
x: 0,
y: 0,
w: 800,
h: 600,
});
// Optionally set fitting mode to automatically scale elements
root.fitting = Fitting::Scale;
// Add a header at the top
root.push_edge(Top, 100, |header| {
// Add a logo to the left of the header
header.push_edge(Left, 200, |logo| {
// You can acquire this rectangle using logo.rect(),
// and draw it with your favorite graphics crate.
});
// Add navigation buttons to the right
header.push_edge(Right, 200, |nav| {
// Navigation content
for _ in 0..10 {
nav.push_edge(Top, 40, |button| {
// This "button" is a smaller rect within nav, stacked from the top
})
}
});
});
// Add a sidebar with specific width
root.push_edge(Left, 200, |sidebar| {
// Sidebar content
});
// Add a centered element with specific dimensions (will scale if needed)
root.push_size(Center, 300, 200, |centered_element| {
// Centered content that will scale to fit if necessary
});
// Main content area (fill remaining space)
root.fill(|content| {
// Place an element at specific coordinates with automatic scaling
content.place(LeftTop, 50, 50, 400, 300, |placed_element| {
// Element content that scales to fit available space
});
});
}
no_stdset_margin() and set_gap()divide_width() and divide_height()Relaxed: Allows overflowAggressive: Removes elements that exceed boundariesClamp: Resizes elements to fit available spaceScale: Scales elements to fit while preserving aspect ratioplace()set_scale()