XPUI Framework
Write an e-Paper screen once, and run it wherever an e-Paper panel is. A screen is
a plain Rust struct that says what it looks like and how it changes, and the
same code runs on a bare-metal microcontroller board, hosted inside a C++ e-Paper
firmware, and in a desktop simulator on your laptop. You find out a screen is
right before any device is on the desk, and the framework asks nothing of your
firmware: no dependencies, no build script, no_std.
- One screen, every panel. Describe a screen with stacks, lists, sliders, toggles and dialogs; a backend paints it through whatever the device has. The gallery runs the same screens on eight boards, and the simulator puts them in a window, inside the device's own body.
- Tested on a laptop, not on a device. The
testingfeature is a fake host that records every draw call, soupdateandbodyare ordinary code in an ordinarycargo test. Every gallery screen is also compared, pixel for pixel, against golden images of each board's panel. - Buttons and touch, handled for you. A screen tags its controls with its own messages; focus, key repeat, value editing and dialogs that capture input are the framework's job, so a button-only reader and a touch panel behave alike.
- Built for e-Paper's limits. 1-bit panels, a few hundred KB of RAM, no GPU, and a refresh that takes a second: nothing allocates per frame, and a screen repaints only when something changed.
Under the hood, you describe what a screen looks like and xpui measures it,
routes input to it and paints it through five small traits a backend
implements. The framework names no product and no drawing library, which is
what lets the same screen move between devices, and every test run on a laptop.
Every document in this repository is listed in docs/README.md.
Using it
Section titled “Using it”[dependencies]xpui = { git = "https://github.com/XPUI-Framework/xpui-framework", branch = "main" }
[dev-dependencies]# The fake host: a backend that records every draw call instead of painting,# so a screen can be tested with no window and no device.xpui = { git = "https://github.com/XPUI-Framework/xpui-framework", branch = "main", features = ["testing"] }Nothing is on crates.io yet, which is why the dependency above is a git URL. A
screen is a struct that says what it looks like and how it changes:
use xpui::{vstack, NavigationScreen, Screen, Stepper, Text, View};
struct Brightness { level: i32, /// Built when the value changes rather than when the screen is described. label: String,}
/// Everything this screen can be told.#[derive(Clone, Copy)]enum Msg { Set(i32), // an absolute value, from dragging the track Step(i32), // a nudge of -1 or +1, from the end glyphs}
impl Screen for Brightness { type Message = Msg;
fn title(&self) -> Option<&'static str> { Some("Brightness") }
fn body(&self) -> impl View<Msg> { NavigationScreen::new(vstack![12; Text::new(&self.label), Stepper::new(self.level) .on_change(Msg::Set) .on_step(Msg::Step), ]) }
fn update(&mut self, message: Msg) { self.level = match message { Msg::Set(level) => level.clamp(0, 100), Msg::Step(delta) => (self.level + delta).clamp(0, 100), }; // Formatted here, not in `body`. `body` runs on every paint and every // frame carrying input; `update` runs when the value actually changes. self.label = format!("Brightness {}%", self.level); }}That is a working screen: a header, a label and a stepper that answers a
finger on the track, the − and + glyphs, and the hardware buttons, with no
coordinate, hit-test or redraw call written. It cannot reach a panel yet —
xpui has no idea one exists — so a
backend connects it to
something that can paint. alloc is required; std is used only by the
testing module.
Checking it
Section titled “Checking it”./build-and-test.shThe checks themselves are in xtask/ — this repository's own list,
in Rust, holding nothing it does not run. ./build-and-test.sh fix formats
in place first. Format, clippy on the host and two bare-metal architectures,
the tests, every documented snippet compiled, every public item documented,
and every link and command in the prose resolved. How a change is reviewed
is in docs/contributing.md.
Where it sits
Section titled “Where it sits”Every arrow is a dependency in a Cargo.toml, and they all point inward
toward xpui, which depends on nothing at all. That is the rule the
organisation is arranged around: a backend can be written without the framework
knowing it exists, and a firmware reaches whatever it needs directly rather
than through whoever happens to sit above it.