UI-bibliotheek

Pure renderingbibliotheek voor OSSM-weergaveschermen — tekstpagina's, tekenreeksen, pictogrammen en visuele tests

Overzicht

De lib/ui-bibliotheek is een pure renderinglaag die OSSM-schermen in een U8g2-buffer tekent. Ze heeft geen hardwareafhankelijkheden, geen FreeRTOS en geen mutexen - ze heeft alleen een u8g2_t*-aanwijzer nodig en tekent pixels. Threadveiligheid en weergave-I/O worden afgehandeld door de displayservice.

Deze scheiding betekent dat de bibliotheek native op x86 kan draaien voor geautomatiseerd visueel testen zonder ESP32.

Afhankelijkheden: U8g2, QRCode

Bron: Software/lib/ui/src/

TextPage

TextPage is de primaire structuur voor inhoudgestuurde schermen. Ze omvat helppagina's, foutschermen, updatestatus, WiFi-configuratie, koppelen - alles wat voornamelijk uit tekst bestaat met optionele QR-codes.

struct TextPage {
    const char* title      = nullptr;
    const char* subtitle   = nullptr;
    const char* body       = nullptr;
    const char* bottomText = nullptr;
    const char* qrUrl      = nullptr;
    uint8_t qrVersion      = 3;
    int qrScale            = 2;
    bool centerBody        = false;
    int scrollPercent      = -1;
};

Alle velden zijn optioneel. Stel alleen in wat u nodig heeft.

VeldTypeDoel
titleconst char*Vetgedrukte tekst bovenaan, met een scheidingslijn eronder
subtitleconst char*Middelgrote of vetgedrukte tekst onder de titel; wordt automatisch gesplitst als deze te breed is
bodyconst char*Tekst met automatische regelafbreking; ondersteunt \n als regeleinde
bottomTextconst char*Vastgemaakt aan de onderkant van het scherm (y=62)
qrUrlconst char*QR-code rechtsonder weergegeven; beperkt de tekstbreedte
qrVersionuint8_tQR-versie (standaard 3)
qrScaleintQR-pixelschaal (standaard 2)
centerBodyboolDe hoofdtekst centreren
scrollPercentintScrollindicator weergeven (0–100); -1 om te verbergen

Rendervolgorde

drawTextPage() rendert in deze volgorde:

  1. Het volledige scherm wissen (koptekst + pagina + voettekst)
  2. QR-code — rechterbenedenhoek, verkleint de beschikbare tekstbreedte
  3. Titel — vetgedrukt lettertype, gevolgd door een horizontale scheidingslijn
  4. Ondertitel — probeert eerst het medium lettertype; valt terug naar vet; wordt over twee regels gesplitst als deze nog te breed is
  5. Hoofdtekst — met automatische regelafbreking via drawWrappedText() als er een titel aanwezig is; gecentreerde titelstijl (drawStr::title) als de hoofdtekst het enige veld is
  6. Onderste tekst — vast op y=62
  7. Scrollindicator — schuifbalk aan de rechterkant als scrollPercent >= 0

Gebruik

// Use a predefined page
ui::drawTextPage(&u8g2, ui::pages::helpPage);

// Or build one inline
ui::TextPage page;
page.title = "Custom Title";
page.body = "Some content\nwith line breaks";
page.scrollPercent = 50;
ui::drawTextPage(&u8g2, page);

Voorgedefinieerde pagina's

TextPages.h definieert statische TextPage-instanties in de ui::pages-naamruimte. Deze verwijzen naar tekenreeksen uit Strings.h:

PaginaGebruikte velden
helpPagetitle, body, bottomText, qrUrl
updateCheckingPagebody
noUpdatePagebody, bottomText
updatingPagetitle, body
errorPagetitle
wifiDisconnectedPagetitle, body, bottomText, qrUrl
wifiConnectedPagetitle, body, bottomText
pairingPagetitle, body

Voorbeelddefinitie:

static const TextPage helpPage = {
    .title = helpTitle,
    .body = helpBody,
    .bottomText = helpBottom,
    .qrUrl = helpQr,
};

Tekenreeksen

Alle UI-tekenreeksen bevinden zich in Strings.h onder de naamruimte ui::strings. Ze worden met PROGMEM in flash opgeslagen:

static const char helpTitle[] PROGMEM = "Get Help";
static const char helpBody[] PROGMEM = "On Discord,\nor GitHub";

Progmem.h definieert PROGMEM als een no-op op niet-Arduino-platforms, zodat tekenreeksen zowel op ESP32 als in native testbuilds worden gecompileerd.

Categorieën

CategorieVoorbeelden
BrandingresearchAndDesire, kinkyMakers
Algemene gebruikersinterfaceerror, homing, idle, restart, settings, skip
Menu / modisimplePenetration, strokeEngine, streaming, pairing, update, wifi
Bewegingsbedieningspeed, stroke, sensation, depth, buffer, accel, max
WaarschuwingenspeedWarning, homingTookTooLong, strokeTooShort
HulphelpTitle, helpBody, helpBottom, helpQr
UpdateupdateChecking, noUpdateBody, updatingTitle, updatingBody
WiFiwifiSetup, wifiBody, wifiBottom, wifiQr, wifiConnected
KoppelenpairingTitle, pairingBody
PatronenpatternName0patternName6, patternDesc0patternDesc6

Patroonarrays

Namen en beschrijvingen van Stroke Engine-patronen zijn geïndexeerde arrays:

static const char* const strokeEngineNames[7] = {
    patternName0, patternName1, patternName2,
    patternName3, patternName4, patternName5,
    patternName6,
};

static const char* const strokeEngineDescriptions[7] = {
    patternDesc0, patternDesc1, patternDesc2,
    patternDesc3, patternDesc4, patternDesc5,
    patternDesc6,
};

MenuItems.h wijst de Menu::-enumwaarden toe aan weergavetekenreeksen:

static const char* menuStrings[Menu::NUM_OPTIONS] = {
    ui::strings::simplePenetration, ui::strings::strokeEngine,
    ui::strings::streaming,         ui::strings::pairing,
    ui::strings::update,            ui::strings::wifiSetup,
    ui::strings::helpTitle,         ui::strings::restart,
};

Afbeeldingen en iconen

Pictogrammen (lettertypeglyphs)

Statuspictogrammen gebruiken het pictogramlettertype Siji. Glyphen worden gedefinieerd in DisplayConstants.h:

namespace IconGlyph {
    constexpr uint16_t WIFI_OFF        = 0xe218;
    constexpr uint16_t WIFI_CONNECTING = 0xe219;
    constexpr uint16_t WIFI_CONNECTED  = 0xe21a;
    constexpr uint16_t WIFI_ERROR      = 0xe21b;
    constexpr uint16_t BLE_CONNECTED   = 0xe00b;
    constexpr uint16_t BLE_SMALL       = 0xe0b0;
    constexpr uint16_t EXCLAMATION     = 0xe0b3;
}

drawHeaderIcons() geeft de WiFi- en BLE-status weer in de rechterbovenhoek van het scherm. Foutstatussen leggen extra pixels (uitroeptekens) over het basispictogram heen.

Logo's (XBM-bitmaps)

Logo's zijn PROGMEM XBM byte-arrays in Logos.h:

  • RDLogo — Research & Desire, 57x50 pixels
  • KMLogo — Kinky Makers, 50x50 pixels

Ze worden getekend via de LogoData-structuur en drawLogo():

struct LogoData {
    const char* title;
    const uint8_t* bitmap;
    int w, h, x, y;
};

Hello-animatie

HelloAnimation.h bevat frames met vooraf berekende Y-posities voor de "OSSM"-opstartanimatie. Elk frame specificeert Y-offsets per letter:

struct HelloFrame {
    int heights[4];  // Y position for O, S, S, M
};

drawHelloFrame() rendert een enkel frame. De testsuite voegt alle frames samen tot een GIF.

Andere tekenfuncties

De volledige weergave-API (ui.h):

FunctieDoel
drawTextPage()Render een TextPage-structuur
drawMenu()Scrollbaar menu met selectiemarkering
drawPlayControls()Snelheids-/slag-/sensatiebalken voor bedieningsmodi
drawPreflight()Veiligheidscontrole vóór beweging (snelheidsknop op nul)
drawHeaderIcons()WiFi- en BLE-statuspictogrammen
drawQR()Op zichzelf staande QR-code
drawHelloFrame()Eén frame van de opstartanimatie
drawLogo()XBM-logo met titel

Helpernaamruimten in DrawExtensions.h:

  • drawStr::centered() — horizontaal gecentreerde tekst
  • drawStr::multiLine() — tekst met meerdere regels en automatische regelafbreking, met UTF-8-ondersteuning
  • drawStr::title() — vetgedrukte, gecentreerde tekst op een vaste positie
  • drawShape::scroll() — schuifbalkindicator
  • drawShape::settingBar() — gelabelde verticale balk met vulniveau
  • drawShape::settingBarSmall() — compacte verticale balk (geen label)

Testen en visuele output

De weergavebibliotheek beschikt over native tests die elke schermvariant weergeven en afbeeldingen exporteren voor visuele beoordeling.

Testen uitvoeren

pio test -e test -f test_display

ImageMagick (magick) moet worden geïnstalleerd voor PNG-conversie. Zonder dit worden er nog steeds PBM-bestanden gegenereerd, maar worden PNG's overgeslagen.

Hoe het werkt

  1. Tests creëren een volledig softwarematig U8g2 SSD1306 128x64-display (geen hardware, no-op-I2C)
  2. Elke test roept ui::draw*()-functies op om in de buffer te renderen
  3. savePBM() schrijft de buffer als een PBM P4-bitmap
  4. Nadat alle tests zijn voltooid, converteert ImageMagick PBM naar PNG (omgekeerde kleuren, schaal van 400%)
  5. Hello-animatieframes worden samengevoegd tot een GIF

Uitvoerstructuur

test/test_display/_output/
├── pbm/                        # Raw bitmaps (generated by tests)
│   ├── textpage/
│   │   ├── combos/             # Field combinations (title+body, all fields, etc.)
│   │   ├── scroll/             # Scroll positions (0%, 50%, 100%)
│   │   ├── stress/             # Edge cases (UTF-8, long strings)
│   │   ├── qr/                 # QR code variants
│   │   ├── body/               # Body rendering with/without title
│   │   ├── subtitle/           # Subtitle font sizing
│   │   ├── pages/              # All predefined pages
│   │   └── patterns/           # Stroke engine pattern descriptions
│   ├── header_icons/           # WiFi × BLE status combinations
│   ├── logos/                  # RD logo, KM logo
│   ├── hello/                  # Animation frames
│   ├── menu/                   # Menu rendering variants
│   └── play_controls/          # Preflight, play modes
└── png/                        # Same structure, converted to PNG

Testdekking

TestbestandWat het omvat
test_textpage.cppTextPage-veldcombinaties, stresstests, QR, ondertiteloverloop, indeling van de hoofdtekst
test_pages.cppAlle vooraf gedefinieerde pagina's, beschrijvingen van Stroke Engine-patronen
test_scroll.cppSchuifbalk bij grenswaarden en randgevallen
test_header_icons.cppAlle 20 WiFi × BLE-statuscombinaties
test_logos.cppRD-logo, KM-logo
test_hello.cppAlle frames van de Hello-animatie, GIF-generatie
test_menu.cppMenu met verschillende aantallen items, lange tekst en regelafbreking
test_play_controls.cppBediening voor Preflight, Simple Penetration, Stroke Engine en Streaming

Op deze pagina