feat(menu): add a graphical boot menu (#106)

* feat(menu): add a graphical boot menu

Adds the graphical menu style, selected with menu-style = "graphical" or
--menu-style=graphical. It draws to the graphics output with the existing
framebuffer, using a built-in 8x8 font, and takes input from the keyboard
and from relative or absolute pointers. The Sprout logo is drawn in the
bottom right corner. If there is no graphics output, the simple menu is
used, which still falls back to the basic menu.

The logo is converted from assets/logo-small.png to raw pixels by the build
crate, which adds the png crate as a build-time dependency only.

The default menu style is still simple. Pointer input is untested, as
OVMF has no mouse driver.

* fix(build): only build the logo conversion on the host

CI builds the whole workspace for the UEFI target, which also builds the
build crate for UEFI. The png dependency pulls in simd-adler32, which
crashes LLVM on that target. The logo conversion only runs in build
scripts on the host, so png and the conversion are now left out when
targeting UEFI.
This commit is contained in:
alex authored and GitHub committed 2026-10-03 17:01:48 -07:00
1 parent 96b6c6f86a
commit 5e8fe7c783
14 files changed
+1035 -8

No files matched your search

+21
View File
@@ -31,6 +31,27 @@ impl Framebuffer {
})
}
/// The width of the framebuffer in pixels.
pub fn width(&self) -> usize {
self.width
}
/// The height of the framebuffer in pixels.
pub fn height(&self) -> usize {
self.height
}
/// Fill the rectangle at `x` and `y` of `width` and `height` with `color`.
/// The parts of the rectangle outside of the framebuffer are not drawn.
pub fn fill_rect(&mut self, x: usize, y: usize, width: usize, height: usize, color: BltPixel) {
let end_x = x.saturating_add(width).min(self.width);
let end_y = y.saturating_add(height).min(self.height);
for row in y..end_y {
// The row is in bounds, so its range is within the pixels.
self.pixels[row * self.width + x..row * self.width + end_x].fill(color);
}
}
/// Mutably acquires a pixel of the framebuffer at the specified `x` and `y` coordinate.
pub fn pixel(&mut self, x: usize, y: usize) -> Option<&mut BltPixel> {
// Verify that the coordinates are within the bounds of the framebuffer.