Skip to main content

Overview

The lib/ui library is a pure rendering layer that draws OSSM screens into a U8g2 buffer. It has no hardware dependencies, no FreeRTOS, no mutexes — it takes a u8g2_t* pointer and draws pixels. Thread safety and display I/O are handled by the display service. This separation means the library can run on native (x86) for automated visual testing without an ESP32. Dependencies: U8g2, QRCode Source: Software/lib/ui/src/

TextPage

TextPage is the primary struct for content-driven screens. It covers help pages, error screens, update status, WiFi setup, pairing — anything that’s mostly text with optional QR codes.
All fields are optional. Set only what you need.

Rendering order

drawTextPage() renders in this order:
  1. Clear the full screen (header + page + footer)
  2. QR code — bottom-right corner, reduces available text width
  3. Title — bold font, followed by a horizontal separator line
  4. Subtitle — tries medium font first; falls back to bold; splits across two lines if still too wide
  5. Body — word-wrapped with drawWrappedText() if a title is present; centered title-style (drawStr::title) if body is the only field
  6. Bottom text — fixed at y=62
  7. Scroll indicator — right-edge scrollbar if scrollPercent >= 0

Usage

Predefined pages

TextPages.h defines static TextPage instances in the ui::pages namespace. These reference strings from Strings.h: Example definition:

Strings

All UI strings live in Strings.h under the ui::strings namespace. They are stored in flash using PROGMEM:
Progmem.h defines PROGMEM as a no-op on non-Arduino platforms, so strings compile on both ESP32 and native test builds.

Categories

Pattern arrays

Stroke engine pattern names and descriptions are indexed arrays:
MenuItems.h maps Menu:: enum values to display strings:

Images and icons

Icons (font glyphs)

Status icons use the Siji icon font. Glyphs are defined in DisplayConstants.h:
drawHeaderIcons() renders WiFi and BLE status in the top-right corner of the screen. Error states overlay additional pixels (exclamation marks) on the base glyph.

Logos (XBM bitmaps)

Logos are PROGMEM XBM byte arrays in Logos.h:
  • RDLogo — Research & Desire, 57x50 pixels
  • KMLogo — Kinky Makers, 50x50 pixels
They are drawn via the LogoData struct and drawLogo():

Hello animation

HelloAnimation.h contains precomputed Y-position frames for the “OSSM” boot animation. Each frame specifies per-letter Y offsets:
drawHelloFrame() renders a single frame. The test suite stitches all frames into a GIF.

Other draw functions

The full rendering API (ui.h): Helper namespaces in DrawExtensions.h:
  • drawStr::centered() — horizontally centered text
  • drawStr::multiLine() — word-wrapped multi-line text with UTF-8 support
  • drawStr::title() — bold centered text at fixed position
  • drawShape::scroll() — scrollbar indicator
  • drawShape::settingBar() — labeled vertical bar with fill level
  • drawShape::settingBarSmall() — compact vertical bar (no label)

Testing and visual output

The display library has native tests that render every screen variant and export images for visual review.

Running tests

ImageMagick (magick) must be installed for PNG conversion. Without it, PBM files are still generated but PNGs are skipped.

How it works

  1. Tests create a software-only U8g2 SSD1306 128x64 display (no hardware, no-op I2C)
  2. Each test calls ui::draw*() functions to render into the buffer
  3. savePBM() writes the buffer as a PBM P4 bitmap
  4. After all tests complete, ImageMagick converts PBM to PNG (inverted colors, 400% scale)
  5. Hello animation frames are stitched into a GIF

Output structure

Test coverage