diff --git a/.gitmodules b/.gitmodules
index bc21444..c10b07a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "External/edk2"]
path = External/edk2
url = https://github.com/tianocore/edk2.git
+[submodule "External/lvgl"]
+ path = External/lvgl
+ url = https://github.com/lvgl/lvgl.git
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 971d923..88fd351 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,67 @@ this file as both a release log and a lightweight development progress record.
### Added
+- DisplayEngine per-opcode control affordances: each editable FormBrowser
+ statement now shows a distinct, non-semantic cue glyph keyed on its control
+ kind — checkbox box, numeric `+`, one-of/choice `▼`, ordered-list up/down,
+ string caret, date/time segment ticks, and reference/action `▶`. Cues are
+ drawn purely from renderer primitives, so they render identically through the
+ GOP and LVGL backends, and are composited by a post-text overlay
+ (`ModernDisplayDrawStatementRowCue`, called at the end of `DisplayOneMenu`) so
+ the native highlight text background no longer overpaints them. Read-only and
+ grayed/disabled rows intentionally get no cue. edk2 keeps all HII/value/storage
+ ownership; the cue helpers are smoke-guarded against
+ `ConfigAccess`/`RouteConfig`/`ExtractConfig`/`SetVariable`/`HiiGetString`.
+- Unified control-affordance vocabulary across the front-page App and the
+ in-setup DisplayEngine: the per-control cue shapes now live in one shared
+ function, `ModernUiEngineDrawControlCue` (`ModernUiEngineLib`), keyed on
+ `MODERN_UI_VALUE_TYPE` and built from a new shared `ModernUiFillTriangle`
+ renderer primitive plus `ModernUiFillRect`/`ModernUiStrokeRect`. The App value
+ lane (`ModernUiEngineDrawValue`) now paints the matching cue just left of the
+ value box, and the DisplayEngine row overlay maps its row kind to the value
+ type (`ModernDisplayKindToValueType`) and delegates to the same function — so a
+ checkbox/drop-down/numeric/date-time/password/string/ordered-list/action
+ control reads identically in both surfaces. The DisplayEngine's former private
+ `ModernDisplayDrawKindCue`/`ModernDisplayCueTriangle` shape copies are removed.
+- `build-ovmf-x64.sh` gains `MODERN_SETUP_DEMO_DRIVER_SAMPLE=0|1` (default `0`):
+ when `1`, edk2 `DriverSampleDxe` is added to the OVMF overlay (reachable via
+ Device Manager) as a control-rich VFR for exercising the DisplayEngine control
+ affordances. Off by default; never in a shipped overlay.
+- Experimental LVGL renderer-swap mode (`experimental/lvgl-spike` branch only):
+ `MODERN_SETUP_DISPLAY_ENGINE=lvgl` now keeps the existing
+ `ModernDisplayEngineDxe` (all FormBrowser/HII/interaction ownership unchanged)
+ but resolves the `ModernUiRendererLib` class to a new LVGL-backed
+ implementation, `Library/ModernUiLvglRendererLib`. Every primitive composites
+ through LVGL's software draw pipeline into a persistent full-screen XRGB8888
+ shadow canvas, then BLTs only the touched region to GOP: geometry (fills,
+ borders, panels, rows, cards, progress, value boxes, drop-downs) via
+ `lv_draw_rect`, ASCII text via `lv_draw_label` (Montserrat), and non-ASCII
+ (CJK) runs via the firmware HII font composited into the same canvas (LVGL
+ bundles no CJK coverage). The library keeps the exact `ModernUiRenderer.h` API
+ and the original 8 px-cell text-measurement model, so layouts in the display
+ engine and `ModernSetupApp` are unchanged. Verified on OVMF X64: the live UiApp
+ FormBrowser front page renders end-to-end through LVGL. `LvglCoreLib` +
+ `IntrinsicLib` are force-linked only into the lvgl-mode overlay; never in a
+ default overlay. The earlier standalone `LvglDisplayEngineDxe` remains as a
+ separate from-scratch reference and is no longer wired into the OVMF overlay.
+ CJK is handled by compositing the package's embedded bitmap glyphs
+ (`ModernUiGlyphs.c`) into the LVGL canvas, with the firmware HII font as a
+ secondary fallback for code points without an embedded glyph. `lvgl` mode also
+ composes with `MODERN_SETUP_REPLACE_UIAPP=1`: the `ModernSetupApp` front-page
+ shell then renders through the same LVGL pipeline (IntrinsicLib is force-linked
+ into the app component in lvgl mode). Verified on OVMF X64 — both the UiApp
+ FormBrowser front page and the full ModernSetupApp dashboard (zh labels +
+ English values + all chrome) render end-to-end through LVGL.
+- Experimental LVGL rendering-backend spike (`experimental/lvgl-spike` branch only;
+ `Experimental/LvglSpikePkg`, never in a default overlay or `ModernSetupApp`).
+ Pins `External/lvgl` at a tagged v9.5.0-derived baseline and validates that
+ LVGL core + software renderer + its upstream UEFI port build under edk2 GCC on
+ a hard architecture: `LvglSpikeProbe.efi` compiles for LoongArch64 and was run
+ on real LoongArch hardware, drawing an LVGL UI straight to GOP (standalone-app
+ path, not via any DisplayEngine). The ~3-site LoongArch64/RISC-V64 UEFI
+ arch-gate change was contributed upstream and is now in the pinned baseline, so
+ `External/lvgl` is consumed pristine (no local patch, no build-time patching).
+ See `Experimental/LvglSpikePkg/README.md`.
- ModernSetupApp header clock now updates live while the front page is idle. The
app loop arms a one-second periodic timer and waits on it alongside the
keyboard/pointer sources, repainting only the header clock text in place on
diff --git a/Docs/MODULE_BOUNDARIES.md b/Docs/MODULE_BOUNDARIES.md
index 47920d6..c01120f 100644
--- a/Docs/MODULE_BOUNDARIES.md
+++ b/Docs/MODULE_BOUNDARIES.md
@@ -30,6 +30,53 @@ ModernSetupPkg is easiest to maintain when each layer keeps a small, concrete co
| HII bridge | Stay isolated as experimental parser/adapter research | Become the default compatibility path, force writes, treat unsupported opcodes as safe |
| Platform/CI | Build scripts, overlays, QEMU/manual validation, release packaging | Hide behavior changes inside scripts or docs-only PRs |
+## Renderer backends
+
+`ModernUiRendererLib` is a class with two interchangeable implementations selected
+by the build (`MODERN_SETUP_DISPLAY_ENGINE`); both expose the identical
+`Include/ModernUi/ModernUiRenderer.h` API:
+
+- **GOP backend** (`Library/ModernUiRendererLib`) — the default. Draws straight to
+ `EFI_GRAPHICS_OUTPUT_PROTOCOL` (BLT fills, HII-font text, built-in bitmap glyphs).
+- **LVGL backend** (`Library/ModernUiLvglRendererLib`, `=lvgl`, experimental) — every
+ primitive is composited by LVGL's software renderer into a persistent full-screen
+ XRGB8888 **shadow canvas**, then only the touched region is BLT'd to GOP. Geometry
+ uses `lv_draw_rect`; ASCII text uses `lv_draw_label` (Montserrat); non-ASCII (CJK)
+ runs use the package's embedded bitmap glyphs (`ModernUiGlyphs.c`), with the
+ firmware HII font as a secondary fallback (LVGL ships no CJK font).
+
+Both backends share, verbatim, the backend-agnostic surface
+`Library/ModernUiRendererLib/ModernUiRendererCommon.c` (geometry compositions, text
+measurement, themed widgets, the `ModernUiFillTriangle` shape primitive) and the
+glyph table `ModernUiGlyphs.c`. A backend provides only three primitives —
+`ModernUiRendererInit`, `ModernUiFillRect`, `ModernUiDrawText` — declared with the
+shared helpers in `ModernUiRendererInternal.h`. Keep the 8 px-cell /
+fixed-CJK-cell measurement model identical across backends so caller layouts are
+backend-stable.
+
+## Control-affordance vocabulary
+
+The per-control cue shapes (checkbox box, one-of `▼`, ordered-list up/down,
+numeric `+`, date/time segment ticks, password dots, string caret, action `▶`)
+are defined **once**, in `ModernUiEngineDrawControlCue` (`ModernUiEngineLib`),
+keyed on `MODERN_UI_VALUE_TYPE` and built only from renderer primitives
+(`ModernUiFillRect` / `ModernUiStrokeRect` / `ModernUiFillTriangle`). Both
+surfaces that show controls delegate to it, so a given control type reads
+identically in each:
+
+- **Front-page App value lane** — `ModernUiEngineDrawValue` paints the cue just
+ left of the value box.
+- **In-setup DisplayEngine row** — `ModernDisplayDrawStatementRowCue` maps its
+ `MODERN_DISPLAY_FORM_ROW_KIND` to the value type via
+ `ModernDisplayKindToValueType` and draws the cue at the row's right edge,
+ **after** native FormBrowser prints the row text (so it composites on top
+ instead of being overpainted). It classifies already-materialized statement
+ data only and never touches HII/config/storage; read-only and disabled rows
+ get no cue.
+
+Do not add a second copy of these shapes in either consumer — extend the shared
+vocabulary and add the value-type mapping instead.
+
## What not to do
- App code must not parse IFR or write HII varstores. Real setup pages should enter native FormBrowser with `EFI_FORM_BROWSER2_PROTOCOL.SendForm()`.
diff --git a/Experimental/LvglSpikePkg/Include/Library/LvglCoreLib.h b/Experimental/LvglSpikePkg/Include/Library/LvglCoreLib.h
new file mode 100644
index 0000000..1f00545
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Include/Library/LvglCoreLib.h
@@ -0,0 +1,18 @@
+/** @file
+ LvglCoreLib -- convenience umbrella header for the shared LVGL build (core +
+ software renderer + upstream UEFI port). Consumers include this to get the LVGL
+ and lv_uefi APIs. experimental/lvgl-spike only.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef LVGL_CORE_LIB_H_
+#define LVGL_CORE_LIB_H_
+
+#include "lvgl/lvgl.h"
+#include "lvgl/src/drivers/uefi/lv_uefi.h"
+#include "lvgl/src/drivers/uefi/lv_uefi_context.h"
+#include "lvgl/src/drivers/uefi/lv_uefi_display.h"
+
+#endif // LVGL_CORE_LIB_H_
diff --git a/Experimental/LvglSpikePkg/Include/Library/LvglLib.h b/Experimental/LvglSpikePkg/Include/Library/LvglLib.h
new file mode 100644
index 0000000..031dbe7
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Include/Library/LvglLib.h
@@ -0,0 +1,69 @@
+/** @file
+ LvglLib class with APIs from the openssl project
+
+ Copyright (c) 2024, Yang Gang. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __LVGL_LIB_H__
+#define __LVGL_LIB_H__
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4244) // workaround for misc/lv_color.h(355), remove after lvgl update
+#endif
+
+#include
+
+//
+// Custom LVGL key codes for EFI function keys F1-F12.
+// EFI SCAN_F1..F12 (0x000B-0x0016) overlap with LVGL reserved key values,
+// so we remap them to a safe range above 0x0100.
+//
+#define LV_KEY_F1 0x0101U
+#define LV_KEY_F2 0x0102U
+#define LV_KEY_F3 0x0103U
+#define LV_KEY_F4 0x0104U
+#define LV_KEY_F5 0x0105U
+#define LV_KEY_F6 0x0106U
+#define LV_KEY_F7 0x0107U
+#define LV_KEY_F8 0x0108U
+#define LV_KEY_F9 0x0109U
+#define LV_KEY_F10 0x010AU
+#define LV_KEY_F11 0x010BU
+#define LV_KEY_F12 0x010CU
+
+typedef
+VOID
+(EFIAPI *EFI_LVGL_APP_FUNCTION)(
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+UefiLvglInit (
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+UefiLvglDeinit (
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+UefiLvglAppRegister (
+ IN EFI_LVGL_APP_FUNCTION AppRegister
+ );
+
+/**
+ Drain the EFI keyboard buffer and reset the LVGL keypad indev state so that
+ no pending key-press leaks into the next event loop.
+**/
+void
+lv_uefi_keypad_drain (
+ void
+ );
+
+#endif
\ No newline at end of file
diff --git a/Experimental/LvglSpikePkg/Include/LvglTheme.h b/Experimental/LvglSpikePkg/Include/LvglTheme.h
new file mode 100644
index 0000000..0b8f8f8
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Include/LvglTheme.h
@@ -0,0 +1,157 @@
+/** @file
+ LvglTheme.h - User-customizable theme for LvglDisplayEngineDxe.
+
+ Edit the macros in this file and rebuild to restyle the LVGL HII form
+ renderer. All colors, fonts, padding, and radius values used by
+ LvglFormRenderer.c flow through these macros.
+
+ Fonts referenced here must be enabled in LvglPkg/lv_conf.h
+ (LV_FONT_MONTSERRAT_*).
+**/
+
+#ifndef LVGL_THEME_H_
+#define LVGL_THEME_H_
+
+#include
+
+//
+// Background colors (24-bit RGB; passed to lv_color_hex())
+//
+// NovaCore palette: near-black canvas, blue-tinted panels, accent blue.
+//
+#define THEME_COLOR_BG_SCREEN 0x0F141A
+#define THEME_COLOR_BG_PANEL 0x182328
+#define THEME_COLOR_BG_PANEL_ELEV 0x23304A
+#define THEME_COLOR_BG_DIALOG 0x1B2A3A
+#define THEME_COLOR_BG_SEPARATOR 0x2A3A52
+
+//
+// Text colors
+//
+#define THEME_COLOR_TEXT_TITLE 0xFFFFFF
+#define THEME_COLOR_TEXT_PRIMARY 0xEAF2FF
+#define THEME_COLOR_TEXT_SECONDARY 0x9FB0C8
+#define THEME_COLOR_TEXT_DISABLED 0x6A7B92
+#define THEME_COLOR_TEXT_LABEL THEME_COLOR_TEXT_PRIMARY
+#define THEME_COLOR_TEXT_POPUP THEME_COLOR_TEXT_PRIMARY
+
+//
+// Row colors (default vs focused).
+//
+#define THEME_COLOR_ROW_BG THEME_COLOR_BG_PANEL
+#define THEME_COLOR_ROW_TEXT THEME_COLOR_TEXT_PRIMARY
+#define THEME_COLOR_ROW_TEXT_FOCUSED 0xFFFFFF
+#define THEME_COLOR_ROW_TEXT_DISABLED THEME_COLOR_TEXT_DISABLED
+
+//
+// Accent (focus ring + active selection).
+//
+#define THEME_COLOR_ACCENT 0x1A6FD8
+#define THEME_COLOR_ACCENT_HOVER 0x2A85F0
+#define THEME_COLOR_SUCCESS 0x2BC79F
+#define THEME_COLOR_WARNING 0xE9A23B
+#define THEME_COLOR_DANGER 0xE25555
+
+//
+// Accent (subtitle / focus highlight) — LV_PALETTE_* enum value
+//
+#define THEME_ACCENT_PALETTE LV_PALETTE_BLUE
+
+//
+// Fonts — must be enabled in lv_conf.h
+//
+#define THEME_FONT_TITLE (&lv_font_montserrat_20)
+#define THEME_FONT_BODY (&lv_font_montserrat_16)
+#define THEME_FONT_POPUP (&lv_font_montserrat_16)
+
+//
+// Spacing & shape (pixels)
+//
+#define THEME_PAD_SCREEN 16
+#define THEME_PAD_PANEL 8
+#define THEME_PAD_ROW 4
+#define THEME_PAD_ROW_TIGHT 2
+#define THEME_PAD_DIALOG 16
+#define THEME_PAD_DIALOG_ROW_GAP 10
+#define THEME_PAD_DIALOG_COL_GAP 8
+#define THEME_PAD_SCREEN_ROW_GAP 6
+#define THEME_PAD_PANEL_ROW_GAP 4
+#define THEME_PAD_LABEL_TOP 8
+#define THEME_RADIUS 8
+#define THEME_OVERLAY_OPA LV_OPA_50
+
+//
+// Aptio-style chrome (header / subtitle / footer / wallpaper).
+// Used by LvglDisplayEngineDxe/LvglAptioChrome.c.
+//
+#define THEME_COLOR_HEADER_BG_TOP 0x0B1218
+#define THEME_COLOR_HEADER_BG_BOTTOM 0x16263F
+#define THEME_COLOR_HEADER_TEXT 0xFFFFFF
+#define THEME_COLOR_HEADER_DIM 0x9FB0C8
+#define THEME_COLOR_SUBTITLE_BG 0x182328
+#define THEME_COLOR_SUBTITLE_TEXT 0xEAF2FF
+#define THEME_COLOR_FOOTER_BG 0x0B1218
+#define THEME_COLOR_FOOTER_TEXT 0xEAF2FF
+#define THEME_COLOR_FOOTER_DIM 0x6A7B92
+#define THEME_COLOR_HIGHLIGHT_ROW THEME_COLOR_ACCENT
+
+#define THEME_HEADER_HEIGHT 44
+#define THEME_SUBTITLE_HEIGHT 28
+#define THEME_FOOTER_HEIGHT 32
+
+//
+// Chrome — help pane (right column).
+//
+#define THEME_HELPPANE_WIDTH 240
+#define THEME_PAD_HELPPANE_X 14
+#define THEME_PAD_HELPPANE_Y 12
+#define THEME_PAD_HELPPANE_ROW_GAP 8
+
+//
+// Chrome — header / subtitle / content / footer paddings.
+//
+#define THEME_PAD_HEADER_X 16
+#define THEME_PAD_SUBTITLE_X 16
+#define THEME_PAD_CONTENT_LEFT 24
+#define THEME_PAD_CONTENT_RIGHT 16
+#define THEME_PAD_CONTENT_Y 12
+#define THEME_PAD_CONTENT_ROW_GAP 6
+#define THEME_PAD_FOOTER_X 12
+#define THEME_PAD_FOOTER_Y 2
+#define THEME_PAD_FOOTER_COL_GAP 6
+
+//
+// Footer "chip" widgets (one per registered hotkey + nav primitives).
+//
+#define THEME_PAD_CHIP_X 8
+#define THEME_PAD_CHIP_Y 4
+#define THEME_PAD_CHIP_COL_GAP 6
+#define THEME_RADIUS_CHIP 4
+
+//
+// Form rows (StyleRow).
+//
+#define THEME_RADIUS_ROW 4
+#define THEME_PAD_ROW_X 16
+#define THEME_PAD_ROW_Y 10
+#define THEME_BORDER_FOCUS 3
+
+//
+// Generic 1 px separator/border thickness used between panes.
+//
+#define THEME_BORDER_PANE 1
+
+//
+// Confirm/discard dialog card width as a percentage of the screen.
+//
+#define THEME_DIALOG_WIDTH_PCT 50
+
+//
+// Static strings shown in the chrome (no SMBIOS lookup yet).
+//
+#define APTIO_HEADER_TITLE "EDK II Boot Manager"
+#define APTIO_HEADER_VENDOR "UEFI v2.90 | EDK II"
+#define APTIO_FOOTER_NAV_HINTS LV_SYMBOL_UP LV_SYMBOL_DOWN " Select Enter Confirm Esc Exit F9 Defaults F10 Save"
+#define APTIO_FOOTER_SYSINFO "QEMU x86_64 | OVMF"
+
+#endif // LVGL_THEME_H_
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/EscExitHandler.c b/Experimental/LvglSpikePkg/Library/LvglLib/EscExitHandler.c
new file mode 100644
index 0000000..20d9454
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/EscExitHandler.c
@@ -0,0 +1,155 @@
+#include "LvglLibCommon.h"
+#include
+
+
+UINT8 mExitBtnYes = EXIT_BTN_NONE;
+STATIC BOOLEAN mPopUpActive = FALSE;
+VOID *mEscNotifyHandle = NULL;
+
+static lv_group_t *g_default_group = NULL;
+
+void exit_confirm_cb(lv_event_t * e)
+{
+
+ lv_obj_t * btn = lv_event_get_target_obj(e);
+ lv_obj_t * label = lv_obj_get_child(btn, 0);
+ LV_UNUSED(label);
+
+ const char * txt = lv_label_get_text(label);
+
+ if (strcmp(txt, "Yes") == 0) {
+ mExitBtnYes = EXIT_BTN_YES;
+ } else if (strcmp(txt, "No") == 0) {
+ mExitBtnYes = EXIT_BTN_NO;
+ } else {
+ mExitBtnYes = EXIT_BTN_NONE;
+ }
+
+ lv_obj_t * msgbox = lv_event_get_user_data(e);
+
+ lv_group_t *msgbox_group = (lv_group_t *)lv_obj_get_user_data(msgbox);
+
+ lv_indev_t *indev = NULL;
+ for(;;) {
+ indev = lv_indev_get_next(indev);
+ if(!indev) {
+ break;
+ }
+
+ if(lv_indev_get_type(indev) == LV_INDEV_TYPE_KEYPAD) {
+ lv_indev_set_group(indev, g_default_group);
+ }
+ }
+
+ lv_group_del(msgbox_group);
+
+ lv_msgbox_close(msgbox);
+
+ mPopUpActive = false;
+}
+
+
+EFI_STATUS
+EFIAPI
+EscKeyNotifyCallBack (
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if (mPopUpActive) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mPopUpActive = true;
+
+ g_default_group = lv_group_get_default();
+
+ lv_group_t *msgbox_group = lv_group_create();
+
+ lv_obj_t * mbox = lv_msgbox_create(NULL);
+
+ lv_msgbox_add_title(mbox, "Exit?");
+ lv_msgbox_add_text(mbox, "Exit this APP?");
+
+ lv_obj_t * btn_yes = lv_msgbox_add_footer_button(mbox, "Yes");
+ lv_obj_add_event_cb(btn_yes, exit_confirm_cb, LV_EVENT_CLICKED, mbox);
+ lv_group_add_obj(msgbox_group, btn_yes);
+
+ lv_obj_t * btn_no = lv_msgbox_add_footer_button(mbox, "No");
+ lv_obj_add_event_cb(btn_no, exit_confirm_cb, LV_EVENT_CLICKED, mbox);
+ lv_group_add_obj(msgbox_group, btn_no);
+
+ lv_group_focus_obj(btn_yes);
+
+ lv_indev_t *indev = NULL;
+ for(;;) {
+ indev = lv_indev_get_next(indev);
+ if(!indev) {
+ break;
+ }
+
+ if(lv_indev_get_type(indev) == LV_INDEV_TYPE_KEYPAD) {
+ lv_indev_set_group(indev, msgbox_group);
+ }
+ }
+
+ lv_obj_set_user_data(mbox, msgbox_group);
+
+ lv_obj_align(mbox, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t * bg = lv_obj_get_parent(mbox);
+ lv_obj_set_style_bg_opa(bg, LV_OPA_70, 0);
+ lv_obj_set_style_bg_color(bg, lv_palette_main(LV_PALETTE_GREY), 0);
+
+ return EFI_SUCCESS;
+
+}
+
+VOID
+EFIAPI
+LvglUefiEscExitRegister (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;
+ EFI_KEY_DATA KeyData;
+
+ Status = gBS->HandleProtocol(gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID**)&TextInEx);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+
+ ZeroMem(&KeyData, sizeof(KeyData));
+ KeyData.Key.ScanCode = SCAN_ESC;
+ Status = TextInEx->RegisterKeyNotify (
+ TextInEx,
+ &KeyData,
+ EscKeyNotifyCallBack,
+ &mEscNotifyHandle
+ );
+
+}
+
+VOID
+EFIAPI
+LvglUefiEscExitUnregister (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx;
+
+ if (mEscNotifyHandle == NULL) {
+ return;
+ }
+
+ Status = gBS->HandleProtocol(gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID**)&TextInEx);
+ if (EFI_ERROR(Status)) {
+ return;
+ }
+
+ Status = TextInEx->UnregisterKeyNotify (TextInEx, mEscNotifyHandle);
+ if (!EFI_ERROR(Status)) {
+ mEscNotifyHandle = NULL;
+ }
+}
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf b/Experimental/LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf
new file mode 100644
index 0000000..81c00b9
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf
@@ -0,0 +1,499 @@
+## @file
+# LvglCoreLib -- LVGL core + software renderer + upstream UEFI port as an EDK2
+# library class, so multiple modules (the app probe and LvglDisplayEngineDxe)
+# can share one LVGL build. experimental/lvgl-spike only.
+#
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LvglCoreLib
+ FILE_GUID = 6F3B1C0A-2D54-4E19-9A7C-1B8E0D22AB03
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LvglCoreLib
+
+[Sources]
+ lv_conf.h
+ lvgl/src/core/lv_group.c
+ lvgl/src/core/lv_obj.c
+ lvgl/src/core/lv_obj_class.c
+ lvgl/src/core/lv_obj_draw.c
+ lvgl/src/core/lv_obj_event.c
+ lvgl/src/core/lv_obj_id_builtin.c
+ lvgl/src/core/lv_obj_pos.c
+ lvgl/src/core/lv_obj_property.c
+ lvgl/src/core/lv_obj_scroll.c
+ lvgl/src/core/lv_obj_style.c
+ lvgl/src/core/lv_obj_style_gen.c
+ lvgl/src/core/lv_obj_tree.c
+ lvgl/src/core/lv_observer.c
+ lvgl/src/core/lv_refr.c
+ lvgl/src/debugging/monkey/lv_monkey.c
+ lvgl/src/debugging/sysmon/lv_sysmon.c
+ lvgl/src/debugging/test/lv_test_display.c
+ lvgl/src/debugging/test/lv_test_fs.c
+ lvgl/src/debugging/test/lv_test_helpers.c
+ lvgl/src/debugging/test/lv_test_indev.c
+ lvgl/src/debugging/test/lv_test_indev_gesture.c
+ lvgl/src/debugging/test/lv_test_screenshot_compare.c
+ lvgl/src/debugging/vg_lite_tvg/vg_lite_matrix.c
+ lvgl/src/display/lv_display.c
+ lvgl/src/draw/convert/helium/lv_draw_buf_convert_helium.c
+ lvgl/src/draw/convert/lv_draw_buf_convert.c
+ lvgl/src/draw/convert/neon/lv_draw_buf_convert_neon.c
+ lvgl/src/draw/dma2d/lv_draw_dma2d.c
+ lvgl/src/draw/dma2d/lv_draw_dma2d_fill.c
+ lvgl/src/draw/dma2d/lv_draw_dma2d_img.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa_buf.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa_fill.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa_img.c
+ lvgl/src/draw/eve/lv_draw_eve_arc.c
+ lvgl/src/draw/eve/lv_draw_eve.c
+ lvgl/src/draw/eve/lv_draw_eve_fill.c
+ lvgl/src/draw/eve/lv_draw_eve_image.c
+ lvgl/src/draw/eve/lv_draw_eve_letter.c
+ lvgl/src/draw/eve/lv_draw_eve_line.c
+ lvgl/src/draw/eve/lv_draw_eve_ram_g.c
+ lvgl/src/draw/eve/lv_draw_eve_triangle.c
+ lvgl/src/draw/eve/lv_eve.c
+ lvgl/src/draw/lv_draw_3d.c
+ lvgl/src/draw/lv_draw_arc.c
+ lvgl/src/draw/lv_draw_blur.c
+ lvgl/src/draw/lv_draw_buf.c
+ lvgl/src/draw/lv_draw.c
+ lvgl/src/draw/lv_draw_image.c
+ lvgl/src/draw/lv_draw_label.c
+ lvgl/src/draw/lv_draw_line.c
+ lvgl/src/draw/lv_draw_mask.c
+ lvgl/src/draw/lv_draw_rect.c
+ lvgl/src/draw/lv_draw_triangle.c
+ lvgl/src/draw/lv_draw_vector.c
+ lvgl/src/draw/lv_image_decoder.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_3d.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_arc.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_border.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_box_shadow.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_fill.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_grad.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_image.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_label.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_layer.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_line.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_mask_rect.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_triangle.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_vector.c
+ lvgl/src/draw/nanovg/lv_nanovg_fbo_cache.c
+ lvgl/src/draw/nanovg/lv_nanovg_image_cache.c
+ lvgl/src/draw/nanovg/lv_nanovg_utils.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_arc.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_border.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_fill.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_img.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_label.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_layer.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_line.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_stm32_hal.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_triangle.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_utils.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_vector.c
+ lvgl/src/draw/nema_gfx/lv_nema_gfx_path.c
+ lvgl/src/draw/nxp/g2d/lv_draw_buf_g2d.c
+ lvgl/src/draw/nxp/g2d/lv_draw_g2d.c
+ lvgl/src/draw/nxp/g2d/lv_draw_g2d_fill.c
+ lvgl/src/draw/nxp/g2d/lv_draw_g2d_img.c
+ lvgl/src/draw/nxp/g2d/lv_g2d_buf_map.c
+ lvgl/src/draw/nxp/g2d/lv_g2d_utils.c
+ lvgl/src/draw/nxp/pxp/lv_draw_buf_pxp.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp_fill.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp_img.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp_layer.c
+ lvgl/src/draw/nxp/pxp/lv_pxp_cfg.c
+ lvgl/src/draw/nxp/pxp/lv_pxp_osa.c
+ lvgl/src/draw/nxp/pxp/lv_pxp_utils.c
+ lvgl/src/draw/opengles/lv_draw_opengles.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_arc.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_border.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_fill.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_image.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_label.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_line.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_mask_rectangle.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_triangle.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_utils.c
+ lvgl/src/draw/sdl/lv_draw_sdl.c
+ lvgl/src/draw/snapshot/lv_snapshot.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_a8.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_al88.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_argb8888.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_argb8888_premultiplied.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_i1.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_l8.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb565.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb565_swapped.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb888.c
+ lvgl/src/draw/sw/blend/neon/lv_draw_sw_blend_neon_to_rgb565.c
+ lvgl/src/draw/sw/blend/neon/lv_draw_sw_blend_neon_to_rgb888.c
+ lvgl/src/draw/sw/blend/riscv_v/lv_draw_sw_blend_riscv_v_to_rgb888.c
+ lvgl/src/draw/sw/lv_draw_sw_arc.c
+ lvgl/src/draw/sw/lv_draw_sw_blur.c
+ lvgl/src/draw/sw/lv_draw_sw_border.c
+ lvgl/src/draw/sw/lv_draw_sw_box_shadow.c
+ lvgl/src/draw/sw/lv_draw_sw.c
+ lvgl/src/draw/sw/lv_draw_sw_fill.c
+ lvgl/src/draw/sw/lv_draw_sw_grad.c
+ lvgl/src/draw/sw/lv_draw_sw_img.c
+ lvgl/src/draw/sw/lv_draw_sw_letter.c
+ lvgl/src/draw/sw/lv_draw_sw_line.c
+ lvgl/src/draw/sw/lv_draw_sw_mask.c
+ lvgl/src/draw/sw/lv_draw_sw_mask_rect.c
+ lvgl/src/draw/sw/lv_draw_sw_transform.c
+ lvgl/src/draw/sw/lv_draw_sw_triangle.c
+ lvgl/src/draw/sw/lv_draw_sw_utils.c
+ lvgl/src/draw/sw/lv_draw_sw_vector.c
+ lvgl/src/draw/vg_lite/lv_draw_buf_vg_lite.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_arc.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_border.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_box_shadow.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_fill.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_img.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_label.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_layer.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_line.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_mask_rect.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_triangle.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_vector.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_decoder.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_grad.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_math.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_path.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_pending.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_stroke.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_utils.c
+ lvgl/src/drivers/display/drm/lv_linux_drm.c
+ lvgl/src/drivers/display/drm/lv_linux_drm_common.c
+ lvgl/src/drivers/display/drm/lv_linux_drm_egl.c
+ lvgl/src/drivers/display/fb/lv_linux_fbdev.c
+ lvgl/src/drivers/display/ft81x/lv_ft81x.c
+ lvgl/src/drivers/display/ili9341/lv_ili9341.c
+ lvgl/src/drivers/display/lcd/lv_lcd_generic_mipi.c
+ lvgl/src/drivers/display/nv3007/lv_nv3007.c
+ lvgl/src/drivers/display/nxp_elcdif/lv_nxp_elcdif.c
+ lvgl/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.c
+ lvgl/src/drivers/display/st7735/lv_st7735.c
+ lvgl/src/drivers/display/st7789/lv_st7789.c
+ lvgl/src/drivers/display/st7796/lv_st7796.c
+ lvgl/src/drivers/display/st_ltdc/lv_st_ltdc.c
+ lvgl/src/drivers/draw/eve/lv_draw_eve_display.c
+ lvgl/src/drivers/evdev/lv_evdev.c
+ lvgl/src/drivers/libinput/lv_libinput.c
+ lvgl/src/drivers/libinput/lv_xkb.c
+ lvgl/src/drivers/nuttx/lv_nuttx_cache.c
+ lvgl/src/drivers/nuttx/lv_nuttx_entry.c
+ lvgl/src/drivers/nuttx/lv_nuttx_fbdev.c
+ lvgl/src/drivers/nuttx/lv_nuttx_image_cache.c
+ lvgl/src/drivers/nuttx/lv_nuttx_lcd.c
+ lvgl/src/drivers/nuttx/lv_nuttx_libuv.c
+ lvgl/src/drivers/nuttx/lv_nuttx_mouse.c
+ lvgl/src/drivers/nuttx/lv_nuttx_profiler.c
+ lvgl/src/drivers/nuttx/lv_nuttx_touchscreen.c
+ lvgl/src/drivers/opengles/assets/lv_opengles_shader.c
+ lvgl/src/drivers/opengles/glad/src/egl.c
+ lvgl/src/drivers/opengles/glad/src/gl.c
+ lvgl/src/drivers/opengles/glad/src/gles2.c
+ lvgl/src/drivers/opengles/lv_opengles_debug.c
+ lvgl/src/drivers/opengles/lv_opengles_driver.c
+ lvgl/src/drivers/opengles/lv_opengles_egl.c
+ lvgl/src/drivers/opengles/lv_opengles_glfw.c
+ lvgl/src/drivers/opengles/lv_opengles_texture.c
+ lvgl/src/drivers/opengles/opengl_shader/lv_opengl_shader_manager.c
+ lvgl/src/drivers/opengles/opengl_shader/lv_opengl_shader_program.c
+ lvgl/src/drivers/qnx/lv_qnx.c
+ lvgl/src/drivers/sdl/lv_sdl_egl.c
+ lvgl/src/drivers/sdl/lv_sdl_keyboard.c
+ lvgl/src/drivers/sdl/lv_sdl_mouse.c
+ lvgl/src/drivers/sdl/lv_sdl_mousewheel.c
+ lvgl/src/drivers/sdl/lv_sdl_sw.c
+ lvgl/src/drivers/sdl/lv_sdl_texture.c
+ lvgl/src/drivers/sdl/lv_sdl_window.c
+ lvgl/src/drivers/uefi/lv_uefi_context.c
+ lvgl/src/drivers/uefi/lv_uefi_display.c
+ lvgl/src/drivers/uefi/lv_uefi_indev_keyboard.c
+ lvgl/src/drivers/uefi/lv_uefi_indev_pointer.c
+ lvgl/src/drivers/uefi/lv_uefi_indev_touch.c
+ lvgl/src/drivers/uefi/lv_uefi_private.c
+ lvgl/src/drivers/wayland/lv_wayland.c
+ lvgl/src/drivers/wayland/lv_wl_egl_backend.c
+ lvgl/src/drivers/wayland/lv_wl_g2d_backend.c
+ lvgl/src/drivers/wayland/lv_wl_keyboard.c
+ lvgl/src/drivers/wayland/lv_wl_pointer.c
+ lvgl/src/drivers/wayland/lv_wl_seat.c
+ lvgl/src/drivers/wayland/lv_wl_shm_backend.c
+ lvgl/src/drivers/wayland/lv_wl_touch.c
+ lvgl/src/drivers/wayland/lv_wl_window.c
+ lvgl/src/drivers/wayland/lv_wl_xdg_shell.c
+ lvgl/src/drivers/windows/lv_windows_context.c
+ lvgl/src/drivers/windows/lv_windows_display.c
+ lvgl/src/drivers/windows/lv_windows_input.c
+ lvgl/src/drivers/x11/lv_x11_display.c
+ lvgl/src/drivers/x11/lv_x11_input.c
+ lvgl/src/font/binfont_loader/lv_binfont_loader.c
+ lvgl/src/font/fmt_txt/lv_font_fmt_txt.c
+ lvgl/src/font/font_manager/lv_font_manager.c
+ lvgl/src/font/font_manager/lv_font_manager_recycle.c
+ lvgl/src/font/imgfont/lv_imgfont.c
+ lvgl/src/font/lv_font.c
+ lvgl/src/font/lv_font_dejavu_16_persian_hebrew.c
+ lvgl/src/font/lv_font_montserrat_10.c
+ lvgl/src/font/lv_font_montserrat_12.c
+ lvgl/src/font/lv_font_montserrat_14_aligned.c
+ lvgl/src/font/lv_font_montserrat_14.c
+ lvgl/src/font/lv_font_montserrat_16.c
+ lvgl/src/font/lv_font_montserrat_18.c
+ lvgl/src/font/lv_font_montserrat_20.c
+ lvgl/src/font/lv_font_montserrat_22.c
+ lvgl/src/font/lv_font_montserrat_24.c
+ lvgl/src/font/lv_font_montserrat_26.c
+ lvgl/src/font/lv_font_montserrat_28.c
+ lvgl/src/font/lv_font_montserrat_28_compressed.c
+ lvgl/src/font/lv_font_montserrat_30.c
+ lvgl/src/font/lv_font_montserrat_32.c
+ lvgl/src/font/lv_font_montserrat_34.c
+ lvgl/src/font/lv_font_montserrat_36.c
+ lvgl/src/font/lv_font_montserrat_38.c
+ lvgl/src/font/lv_font_montserrat_40.c
+ lvgl/src/font/lv_font_montserrat_42.c
+ lvgl/src/font/lv_font_montserrat_44.c
+ lvgl/src/font/lv_font_montserrat_46.c
+ lvgl/src/font/lv_font_montserrat_48.c
+ lvgl/src/font/lv_font_montserrat_8.c
+ lvgl/src/font/lv_font_source_han_sans_sc_14_cjk.c
+ lvgl/src/font/lv_font_source_han_sans_sc_16_cjk.c
+ lvgl/src/font/lv_font_unscii_16.c
+ lvgl/src/font/lv_font_unscii_8.c
+ lvgl/src/indev/lv_gridnav.c
+ lvgl/src/indev/lv_indev.c
+ lvgl/src/indev/lv_indev_gesture.c
+ lvgl/src/indev/lv_indev_scroll.c
+ lvgl/src/layouts/flex/lv_flex.c
+ lvgl/src/layouts/grid/lv_grid.c
+ lvgl/src/layouts/lv_layout.c
+ lvgl/src/libs/barcode/code128.c
+ lvgl/src/libs/barcode/lv_barcode.c
+ lvgl/src/libs/bin_decoder/lv_bin_decoder.c
+ lvgl/src/libs/bmp/lv_bmp.c
+ lvgl/src/libs/ffmpeg/lv_ffmpeg.c
+ lvgl/src/libs/freetype/lv_freetype.c
+ lvgl/src/libs/freetype/lv_freetype_glyph.c
+ lvgl/src/libs/freetype/lv_freetype_image.c
+ lvgl/src/libs/freetype/lv_freetype_outline.c
+ lvgl/src/libs/freetype/lv_ftsystem.c
+ lvgl/src/libs/frogfs/src/decomp_raw.c
+ lvgl/src/libs/frogfs/src/frogfs.c
+ lvgl/src/libs/fsdrv/lv_fs_cbfs.c
+ lvgl/src/libs/fsdrv/lv_fs_fatfs.c
+ lvgl/src/libs/fsdrv/lv_fs_frogfs.c
+ lvgl/src/libs/fsdrv/lv_fs_littlefs.c
+ lvgl/src/libs/fsdrv/lv_fs_memfs.c
+ lvgl/src/libs/fsdrv/lv_fs_posix.c
+ lvgl/src/libs/fsdrv/lv_fs_stdio.c
+ lvgl/src/libs/fsdrv/lv_fs_uefi.c
+ lvgl/src/libs/fsdrv/lv_fs_win32.c
+ lvgl/src/libs/FT800-FT813/EVE_commands.c
+ lvgl/src/libs/FT800-FT813/EVE_supplemental.c
+ lvgl/src/libs/gif/gif.c
+ lvgl/src/libs/gltf/gltf_environment/lv_gltf_ibl_sampler.c
+ lvgl/src/libs/gltf/gltf_view/assets/chromatic.c
+ lvgl/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c
+ lvgl/src/libs/gltf/math/lv_3dmath.c
+ lvgl/src/libs/gstreamer/lv_gstreamer.c
+ lvgl/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c
+ lvgl/src/libs/libpng/lv_libpng.c
+ lvgl/src/libs/libwebp/lv_libwebp.c
+ lvgl/src/libs/lodepng/lodepng.c
+ lvgl/src/libs/lodepng/lv_lodepng.c
+ lvgl/src/libs/lz4/lz4.c
+ lvgl/src/libs/nanovg/nanovg.c
+ lvgl/src/libs/qrcode/lv_qrcode.c
+ lvgl/src/libs/qrcode/qrcodegen.c
+ lvgl/src/libs/rle/lv_rle.c
+ lvgl/src/libs/rlottie/lv_rlottie.c
+ lvgl/src/libs/svg/lv_svg.c
+ lvgl/src/libs/svg/lv_svg_decoder.c
+ lvgl/src/libs/svg/lv_svg_parser.c
+ lvgl/src/libs/svg/lv_svg_render.c
+ lvgl/src/libs/svg/lv_svg_token.c
+ lvgl/src/libs/tiny_ttf/lv_tiny_ttf.c
+ lvgl/src/libs/tjpgd/lv_tjpgd.c
+ lvgl/src/libs/tjpgd/tjpgd.c
+ lvgl/src/libs/vg_lite_driver/lv_vg_lite_hal/lv_vg_lite_hal.c
+ lvgl/src/libs/vg_lite_driver/lv_vg_lite_hal/vg_lite_os.c
+ lvgl/src/libs/vg_lite_driver/VGLiteKernel/vg_lite_kernel.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_image.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_matrix.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_path.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_stroke.c
+ lvgl/src/lv_init.c
+ lvgl/src/misc/cache/class/lv_cache_lru_ll.c
+ lvgl/src/misc/cache/class/lv_cache_lru_rb.c
+ lvgl/src/misc/cache/class/lv_cache_sc_da.c
+ lvgl/src/misc/cache/instance/lv_image_cache.c
+ lvgl/src/misc/cache/instance/lv_image_header_cache.c
+ lvgl/src/misc/cache/lv_cache.c
+ lvgl/src/misc/cache/lv_cache_entry.c
+ lvgl/src/misc/lv_anim.c
+ lvgl/src/misc/lv_anim_timeline.c
+ lvgl/src/misc/lv_area.c
+ lvgl/src/misc/lv_array.c
+ lvgl/src/misc/lv_async.c
+ lvgl/src/misc/lv_bidi.c
+ lvgl/src/misc/lv_circle_buf.c
+ lvgl/src/misc/lv_color.c
+ lvgl/src/misc/lv_color_op.c
+ lvgl/src/misc/lv_event.c
+ lvgl/src/misc/lv_fs.c
+ lvgl/src/misc/lv_grad.c
+ lvgl/src/misc/lv_iter.c
+ lvgl/src/misc/lv_ll.c
+ lvgl/src/misc/lv_log.c
+ lvgl/src/misc/lv_lru.c
+ lvgl/src/misc/lv_math.c
+ lvgl/src/misc/lv_matrix.c
+ lvgl/src/misc/lv_palette.c
+ lvgl/src/misc/lv_pending.c
+ lvgl/src/misc/lv_profiler_builtin.c
+ lvgl/src/misc/lv_profiler_builtin_posix.c
+ lvgl/src/misc/lv_rb.c
+ lvgl/src/misc/lv_style.c
+ lvgl/src/misc/lv_style_gen.c
+ lvgl/src/misc/lv_templ.c
+ lvgl/src/misc/lv_text_ap.c
+ lvgl/src/misc/lv_text.c
+ lvgl/src/misc/lv_timer.c
+ lvgl/src/misc/lv_tree.c
+ lvgl/src/misc/lv_utils.c
+ lvgl/src/osal/lv_cmsis_rtos2.c
+ lvgl/src/osal/lv_freertos.c
+ lvgl/src/osal/lv_linux.c
+ lvgl/src/osal/lv_mqx.c
+ lvgl/src/osal/lv_os.c
+ lvgl/src/osal/lv_os_none.c
+ lvgl/src/osal/lv_pthread.c
+ lvgl/src/osal/lv_rtthread.c
+ lvgl/src/osal/lv_sdl2.c
+ lvgl/src/osal/lv_windows.c
+ lvgl/src/others/file_explorer/lv_file_explorer.c
+ lvgl/src/others/fragment/lv_fragment.c
+ lvgl/src/others/fragment/lv_fragment_manager.c
+ lvgl/src/others/translation/lv_translation.c
+ lvgl/src/stdlib/builtin/lv_mem_core_builtin.c
+ lvgl/src/stdlib/builtin/lv_sprintf_builtin.c
+ lvgl/src/stdlib/builtin/lv_string_builtin.c
+ lvgl/src/stdlib/builtin/lv_tlsf.c
+ lvgl/src/stdlib/clib/lv_mem_core_clib.c
+ lvgl/src/stdlib/clib/lv_sprintf_clib.c
+ lvgl/src/stdlib/clib/lv_string_clib.c
+ lvgl/src/stdlib/lv_mem.c
+ lvgl/src/stdlib/micropython/lv_mem_core_micropython.c
+ lvgl/src/stdlib/rtthread/lv_mem_core_rtthread.c
+ lvgl/src/stdlib/rtthread/lv_sprintf_rtthread.c
+ lvgl/src/stdlib/rtthread/lv_string_rtthread.c
+ lvgl/src/stdlib/uefi/lv_mem_core_uefi.c
+ lvgl/src/themes/default/lv_theme_default.c
+ lvgl/src/themes/lv_theme.c
+ lvgl/src/themes/mono/lv_theme_mono.c
+ lvgl/src/themes/simple/lv_theme_simple.c
+ lvgl/src/tick/lv_tick.c
+ lvgl/src/widgets/3dtexture/lv_3dtexture.c
+ lvgl/src/widgets/animimage/lv_animimage.c
+ lvgl/src/widgets/arclabel/lv_arclabel.c
+ lvgl/src/widgets/arc/lv_arc.c
+ lvgl/src/widgets/bar/lv_bar.c
+ lvgl/src/widgets/button/lv_button.c
+ lvgl/src/widgets/buttonmatrix/lv_buttonmatrix.c
+ lvgl/src/widgets/calendar/lv_calendar.c
+ lvgl/src/widgets/calendar/lv_calendar_chinese.c
+ lvgl/src/widgets/calendar/lv_calendar_header_arrow.c
+ lvgl/src/widgets/calendar/lv_calendar_header_dropdown.c
+ lvgl/src/widgets/canvas/lv_canvas.c
+ lvgl/src/widgets/chart/lv_chart.c
+ lvgl/src/widgets/checkbox/lv_checkbox.c
+ lvgl/src/widgets/dropdown/lv_dropdown.c
+ lvgl/src/widgets/gif/lv_gif.c
+ lvgl/src/widgets/imagebutton/lv_imagebutton.c
+ lvgl/src/widgets/image/lv_image.c
+ lvgl/src/widgets/ime/lv_ime_pinyin.c
+ lvgl/src/widgets/keyboard/lv_keyboard.c
+ lvgl/src/widgets/label/lv_label.c
+ lvgl/src/widgets/led/lv_led.c
+ lvgl/src/widgets/line/lv_line.c
+ lvgl/src/widgets/list/lv_list.c
+ lvgl/src/widgets/lottie/lv_lottie.c
+ lvgl/src/widgets/menu/lv_menu.c
+ lvgl/src/widgets/msgbox/lv_msgbox.c
+ lvgl/src/widgets/objx_templ/lv_objx_templ.c
+ lvgl/src/widgets/property/lv_animimage_properties.c
+ lvgl/src/widgets/property/lv_arc_properties.c
+ lvgl/src/widgets/property/lv_bar_properties.c
+ lvgl/src/widgets/property/lv_buttonmatrix_properties.c
+ lvgl/src/widgets/property/lv_chart_properties.c
+ lvgl/src/widgets/property/lv_checkbox_properties.c
+ lvgl/src/widgets/property/lv_dropdown_properties.c
+ lvgl/src/widgets/property/lv_image_properties.c
+ lvgl/src/widgets/property/lv_keyboard_properties.c
+ lvgl/src/widgets/property/lv_label_properties.c
+ lvgl/src/widgets/property/lv_led_properties.c
+ lvgl/src/widgets/property/lv_line_properties.c
+ lvgl/src/widgets/property/lv_menu_properties.c
+ lvgl/src/widgets/property/lv_obj_properties.c
+ lvgl/src/widgets/property/lv_roller_properties.c
+ lvgl/src/widgets/property/lv_scale_properties.c
+ lvgl/src/widgets/property/lv_slider_properties.c
+ lvgl/src/widgets/property/lv_span_properties.c
+ lvgl/src/widgets/property/lv_spinbox_properties.c
+ lvgl/src/widgets/property/lv_spinner_properties.c
+ lvgl/src/widgets/property/lv_style_properties.c
+ lvgl/src/widgets/property/lv_switch_properties.c
+ lvgl/src/widgets/property/lv_table_properties.c
+ lvgl/src/widgets/property/lv_tabview_properties.c
+ lvgl/src/widgets/property/lv_textarea_properties.c
+ lvgl/src/widgets/roller/lv_roller.c
+ lvgl/src/widgets/scale/lv_scale.c
+ lvgl/src/widgets/slider/lv_slider.c
+ lvgl/src/widgets/span/lv_span.c
+ lvgl/src/widgets/spinbox/lv_spinbox.c
+ lvgl/src/widgets/spinner/lv_spinner.c
+ lvgl/src/widgets/switch/lv_switch.c
+ lvgl/src/widgets/table/lv_table.c
+ lvgl/src/widgets/tabview/lv_tabview.c
+ lvgl/src/widgets/textarea/lv_textarea.c
+ lvgl/src/widgets/tileview/lv_tileview.c
+ lvgl/src/widgets/win/lv_win.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ LvglSpikePkg/LvglSpikePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ DebugLib
+ PrintLib
+
+[BuildOptions]
+ # See README: LV_CONF_INCLUDE_SIMPLE (symlinked lvgl/), warning relaxers.
+ GCC:*_*_*_CC_FLAGS = -DLV_CONF_INCLUDE_SIMPLE -Wno-error -Wno-format -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-array-bounds -Wno-maybe-uninitialized -Wno-incompatible-pointer-types
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglLib.c b/Experimental/LvglSpikePkg/Library/LvglLib/LvglLib.c
new file mode 100644
index 0000000..52e6550
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglLib.c
@@ -0,0 +1,176 @@
+
+#include "LvglLibCommon.h"
+
+#include
+
+extern UINT8 mExitBtnYes;
+
+BOOLEAN mTickSupport = FALSE;
+STATIC BOOLEAN mUefiLvglInitDone = FALSE;
+
+#if LV_USE_LOG
+static void efi_lv_log_print(lv_log_level_t level, const char * buf)
+{
+ static const int priority[LV_LOG_LEVEL_NUM] = {
+ DEBUG_VERBOSE|DEBUG_INFO|DEBUG_WARN|DEBUG_ERROR, DEBUG_INFO, DEBUG_WARN, DEBUG_ERROR, DEBUG_INFO
+ };
+
+ DebugPrint (priority[level], "[LVGL] %a\n", buf);
+}
+#endif
+
+
+static uint32_t tick_get_cb(void)
+{
+ return (UINT32) DivU64x32 (GetTimeInNanoSecond (GetPerformanceCounter()), 1000 * 1000);
+}
+
+VOID
+EFIAPI
+UefiLvglTickInit (
+ VOID
+ )
+{
+ if (GetPerformanceCounter()) {
+ mTickSupport = TRUE;
+ lv_tick_set_cb(tick_get_cb);
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+UefiLvglInit (
+ VOID
+ )
+{
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_STATUS Status;
+ UINTN Width, Heigth;
+
+ if (mUefiLvglInitDone) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
+ if (EFI_ERROR(Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ lv_init();
+
+#if 0
+ // Need real TimerLib
+ UefiLvglTickInit();
+#endif
+
+#if LV_USE_LOG
+ lv_log_register_print_cb (efi_lv_log_print);
+#endif
+
+ Width = GraphicsOutput->Mode->Info->HorizontalResolution;
+ Heigth = GraphicsOutput->Mode->Info->VerticalResolution;
+
+ lv_disp_t *display = lv_uefi_disp_create (Width, Heigth);
+
+ lv_port_indev_init(display);
+
+ mUefiLvglInitDone = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UefiLvglDeinit (
+ VOID
+ )
+{
+
+ if (!mUefiLvglInitDone) {
+ return EFI_SUCCESS;
+ }
+
+ LvglUefiEscExitUnregister ();
+
+ lv_deinit();
+
+ lv_port_indev_close();
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, 0);
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+
+ mUefiLvglInitDone = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+UefiLvglAppRegister (
+ IN EFI_LVGL_APP_FUNCTION AppRegister
+ )
+{
+ if (!mUefiLvglInitDone) {
+ if (UefiLvglInit() != EFI_SUCCESS) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (AppRegister != NULL) {
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ // call user GUI APP
+ AppRegister();
+
+ LvglUefiEscExitRegister ();
+
+ while (1) {
+ if (mExitBtnYes == EXIT_BTN_YES) {
+ break;
+ }
+
+ lv_timer_handler();
+
+ gBS->Stall (10 * 1000);
+ if (!mTickSupport) {
+ lv_tick_inc(10);
+ }
+ }
+ } else {
+ UefiLvglDeinit();
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+LvglLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ UefiLvglInit ();
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+LvglLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ UefiLvglDeinit();
+
+ return EFI_SUCCESS;
+}
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglLib.inf b/Experimental/LvglSpikePkg/Library/LvglLib/LvglLib.inf
new file mode 100644
index 0000000..89af6be
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglLib.inf
@@ -0,0 +1,543 @@
+## @file
+# LVGL as UEFI Library Class.
+#
+# Copyright (c) 2024, Yang Gang. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LvglLib
+ FILE_GUID = DB82E73C-46EF-4490-9E6E-70E7AE65CCBB
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LvglLib|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = LvglLibConstructor
+ DESTRUCTOR = LvglLibDestructor
+
+[Sources]
+ LvglLib.c
+ LvglUefiPort.h
+ LvglUefiPort.c
+
+ EscExitHandler.c
+ lv_uefi_display.c
+ MouseCursorIcon.c
+ lv_port_indev.c
+ lv_conf.h
+
+# Wrapper header files start #
+ limits.h
+ stdint.h
+ stdio.h
+ stdarg.h
+ stddef.h
+ stdlib.h
+ string.h
+ config.h
+# Wrapper header files end #
+
+# Upstream Lvgl code
+ lvgl/src/lv_init.c
+ lvgl/src/core/lv_group.c
+ lvgl/src/core/lv_obj.c
+ lvgl/src/core/lv_obj_class.c
+ lvgl/src/core/lv_obj_draw.c
+ lvgl/src/core/lv_obj_event.c
+ lvgl/src/core/lv_obj_id_builtin.c
+ lvgl/src/core/lv_obj_pos.c
+ lvgl/src/core/lv_obj_property.c
+ lvgl/src/core/lv_obj_scroll.c
+ lvgl/src/core/lv_obj_style.c
+ lvgl/src/core/lv_obj_style_gen.c
+ lvgl/src/core/lv_obj_tree.c
+ lvgl/src/core/lv_observer.c
+ lvgl/src/core/lv_refr.c
+ lvgl/src/debugging/monkey/lv_monkey.c
+ lvgl/src/debugging/sysmon/lv_sysmon.c
+ lvgl/src/debugging/test/lv_test_display.c
+ lvgl/src/debugging/test/lv_test_fs.c
+ lvgl/src/debugging/test/lv_test_helpers.c
+ lvgl/src/debugging/test/lv_test_indev.c
+ lvgl/src/debugging/test/lv_test_indev_gesture.c
+ lvgl/src/debugging/test/lv_test_screenshot_compare.c
+ lvgl/src/debugging/vg_lite_tvg/vg_lite_matrix.c
+ lvgl/src/display/lv_display.c
+ lvgl/src/draw/lv_draw.c
+ lvgl/src/draw/lv_draw_3d.c
+ lvgl/src/draw/lv_draw_arc.c
+ lvgl/src/draw/lv_draw_blur.c
+ lvgl/src/draw/lv_draw_buf.c
+ lvgl/src/draw/lv_draw_image.c
+ lvgl/src/draw/lv_draw_label.c
+ lvgl/src/draw/lv_draw_line.c
+ lvgl/src/draw/lv_draw_mask.c
+ lvgl/src/draw/lv_draw_rect.c
+ lvgl/src/draw/lv_draw_triangle.c
+ lvgl/src/draw/lv_draw_vector.c
+ lvgl/src/draw/lv_image_decoder.c
+ lvgl/src/draw/convert/lv_draw_buf_convert.c
+ lvgl/src/draw/convert/helium/lv_draw_buf_convert_helium.c
+ lvgl/src/draw/convert/neon/lv_draw_buf_convert_neon.c
+ lvgl/src/draw/dma2d/lv_draw_dma2d.c
+ lvgl/src/draw/dma2d/lv_draw_dma2d_fill.c
+ lvgl/src/draw/dma2d/lv_draw_dma2d_img.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa_buf.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa_fill.c
+ lvgl/src/draw/espressif/ppa/lv_draw_ppa_img.c
+ lvgl/src/draw/eve/lv_draw_eve.c
+ lvgl/src/draw/eve/lv_draw_eve_arc.c
+ lvgl/src/draw/eve/lv_draw_eve_fill.c
+ lvgl/src/draw/eve/lv_draw_eve_image.c
+ lvgl/src/draw/eve/lv_draw_eve_letter.c
+ lvgl/src/draw/eve/lv_draw_eve_line.c
+ lvgl/src/draw/eve/lv_draw_eve_ram_g.c
+ lvgl/src/draw/eve/lv_draw_eve_triangle.c
+ lvgl/src/draw/eve/lv_eve.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_3d.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_arc.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_border.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_box_shadow.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_fill.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_grad.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_image.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_label.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_layer.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_line.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_mask_rect.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_triangle.c
+ lvgl/src/draw/nanovg/lv_draw_nanovg_vector.c
+ lvgl/src/draw/nanovg/lv_nanovg_fbo_cache.c
+ lvgl/src/draw/nanovg/lv_nanovg_image_cache.c
+ lvgl/src/draw/nanovg/lv_nanovg_utils.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_arc.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_border.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_fill.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_img.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_label.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_layer.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_line.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_stm32_hal.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_triangle.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_utils.c
+ lvgl/src/draw/nema_gfx/lv_draw_nema_gfx_vector.c
+ lvgl/src/draw/nema_gfx/lv_nema_gfx_path.c
+ lvgl/src/draw/nxp/g2d/lv_draw_buf_g2d.c
+ lvgl/src/draw/nxp/g2d/lv_draw_g2d.c
+ lvgl/src/draw/nxp/g2d/lv_draw_g2d_fill.c
+ lvgl/src/draw/nxp/g2d/lv_draw_g2d_img.c
+ lvgl/src/draw/nxp/g2d/lv_g2d_buf_map.c
+ lvgl/src/draw/nxp/g2d/lv_g2d_utils.c
+ lvgl/src/draw/nxp/pxp/lv_draw_buf_pxp.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp_fill.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp_img.c
+ lvgl/src/draw/nxp/pxp/lv_draw_pxp_layer.c
+ lvgl/src/draw/nxp/pxp/lv_pxp_cfg.c
+ lvgl/src/draw/nxp/pxp/lv_pxp_osa.c
+ lvgl/src/draw/nxp/pxp/lv_pxp_utils.c
+ lvgl/src/draw/opengles/lv_draw_opengles.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_arc.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_border.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_fill.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_image.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_label.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_line.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_mask_rectangle.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_triangle.c
+ lvgl/src/draw/renesas/dave2d/lv_draw_dave2d_utils.c
+ lvgl/src/draw/sdl/lv_draw_sdl.c
+ lvgl/src/draw/snapshot/lv_snapshot.c
+ lvgl/src/draw/sw/lv_draw_sw.c
+ lvgl/src/draw/sw/lv_draw_sw_arc.c
+ lvgl/src/draw/sw/lv_draw_sw_blur.c
+ lvgl/src/draw/sw/lv_draw_sw_border.c
+ lvgl/src/draw/sw/lv_draw_sw_box_shadow.c
+ lvgl/src/draw/sw/lv_draw_sw_fill.c
+ lvgl/src/draw/sw/lv_draw_sw_grad.c
+ lvgl/src/draw/sw/lv_draw_sw_img.c
+ lvgl/src/draw/sw/lv_draw_sw_letter.c
+ lvgl/src/draw/sw/lv_draw_sw_line.c
+ lvgl/src/draw/sw/lv_draw_sw_mask.c
+ lvgl/src/draw/sw/lv_draw_sw_mask_rect.c
+ lvgl/src/draw/sw/lv_draw_sw_transform.c
+ lvgl/src/draw/sw/lv_draw_sw_triangle.c
+ lvgl/src/draw/sw/lv_draw_sw_utils.c
+ lvgl/src/draw/sw/lv_draw_sw_vector.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_a8.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_al88.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_argb8888.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_argb8888_premultiplied.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_i1.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_l8.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb565.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb565_swapped.c
+ lvgl/src/draw/sw/blend/lv_draw_sw_blend_to_rgb888.c
+ lvgl/src/draw/sw/blend/helium/lv_blend_helium.S
+ lvgl/src/draw/sw/blend/neon/lv_draw_sw_blend_neon_to_rgb565.c
+ lvgl/src/draw/sw/blend/neon/lv_draw_sw_blend_neon_to_rgb888.c
+ lvgl/src/draw/sw/blend/riscv_v/lv_draw_sw_blend_riscv_v_to_rgb888.c
+ lvgl/src/draw/vg_lite/lv_draw_buf_vg_lite.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_arc.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_border.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_box_shadow.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_fill.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_img.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_label.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_layer.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_line.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_mask_rect.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_triangle.c
+ lvgl/src/draw/vg_lite/lv_draw_vg_lite_vector.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_decoder.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_grad.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_math.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_path.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_pending.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_stroke.c
+ lvgl/src/draw/vg_lite/lv_vg_lite_utils.c
+ lvgl/src/drivers/display/drm/lv_linux_drm.c
+ lvgl/src/drivers/display/drm/lv_linux_drm_common.c
+ lvgl/src/drivers/display/drm/lv_linux_drm_egl.c
+ lvgl/src/drivers/display/fb/lv_linux_fbdev.c
+ lvgl/src/drivers/display/ft81x/lv_ft81x.c
+ lvgl/src/drivers/display/ili9341/lv_ili9341.c
+ lvgl/src/drivers/display/lcd/lv_lcd_generic_mipi.c
+ lvgl/src/drivers/display/nv3007/lv_nv3007.c
+ lvgl/src/drivers/display/nxp_elcdif/lv_nxp_elcdif.c
+ lvgl/src/drivers/display/renesas_glcdc/lv_renesas_glcdc.c
+ lvgl/src/drivers/display/st7735/lv_st7735.c
+ lvgl/src/drivers/display/st7789/lv_st7789.c
+ lvgl/src/drivers/display/st7796/lv_st7796.c
+ lvgl/src/drivers/display/st_ltdc/lv_st_ltdc.c
+ lvgl/src/drivers/draw/eve/lv_draw_eve_display.c
+ lvgl/src/drivers/evdev/lv_evdev.c
+ lvgl/src/drivers/libinput/lv_libinput.c
+ lvgl/src/drivers/libinput/lv_xkb.c
+ lvgl/src/drivers/nuttx/lv_nuttx_cache.c
+ lvgl/src/drivers/nuttx/lv_nuttx_entry.c
+ lvgl/src/drivers/nuttx/lv_nuttx_fbdev.c
+ lvgl/src/drivers/nuttx/lv_nuttx_image_cache.c
+ lvgl/src/drivers/nuttx/lv_nuttx_lcd.c
+ lvgl/src/drivers/nuttx/lv_nuttx_libuv.c
+ lvgl/src/drivers/nuttx/lv_nuttx_mouse.c
+ lvgl/src/drivers/nuttx/lv_nuttx_profiler.c
+ lvgl/src/drivers/nuttx/lv_nuttx_touchscreen.c
+ lvgl/src/drivers/opengles/lv_opengles_debug.c
+ lvgl/src/drivers/opengles/lv_opengles_driver.c
+ lvgl/src/drivers/opengles/lv_opengles_egl.c
+ lvgl/src/drivers/opengles/lv_opengles_glfw.c
+ lvgl/src/drivers/opengles/lv_opengles_texture.c
+ lvgl/src/drivers/opengles/assets/lv_opengles_shader.c
+ lvgl/src/drivers/opengles/glad/src/egl.c
+ lvgl/src/drivers/opengles/glad/src/gl.c
+ lvgl/src/drivers/opengles/glad/src/gles2.c
+ lvgl/src/drivers/opengles/opengl_shader/lv_opengl_shader_manager.c
+ lvgl/src/drivers/opengles/opengl_shader/lv_opengl_shader_program.c
+ lvgl/src/drivers/qnx/lv_qnx.c
+ lvgl/src/drivers/sdl/lv_sdl_egl.c
+ lvgl/src/drivers/sdl/lv_sdl_keyboard.c
+ lvgl/src/drivers/sdl/lv_sdl_mouse.c
+ lvgl/src/drivers/sdl/lv_sdl_mousewheel.c
+ lvgl/src/drivers/sdl/lv_sdl_sw.c
+ lvgl/src/drivers/sdl/lv_sdl_texture.c
+ lvgl/src/drivers/sdl/lv_sdl_window.c
+ lvgl/src/drivers/uefi/lv_uefi_context.c
+ lvgl/src/drivers/uefi/lv_uefi_display.c
+ lvgl/src/drivers/uefi/lv_uefi_indev_keyboard.c
+ lvgl/src/drivers/uefi/lv_uefi_indev_pointer.c
+ lvgl/src/drivers/uefi/lv_uefi_indev_touch.c
+ lvgl/src/drivers/uefi/lv_uefi_private.c
+ lvgl/src/drivers/wayland/lv_wayland.c
+ lvgl/src/drivers/wayland/lv_wl_egl_backend.c
+ lvgl/src/drivers/wayland/lv_wl_g2d_backend.c
+ lvgl/src/drivers/wayland/lv_wl_keyboard.c
+ lvgl/src/drivers/wayland/lv_wl_pointer.c
+ lvgl/src/drivers/wayland/lv_wl_seat.c
+ lvgl/src/drivers/wayland/lv_wl_shm_backend.c
+ lvgl/src/drivers/wayland/lv_wl_touch.c
+ lvgl/src/drivers/wayland/lv_wl_window.c
+ lvgl/src/drivers/wayland/lv_wl_xdg_shell.c
+ lvgl/src/drivers/windows/lv_windows_context.c
+ lvgl/src/drivers/windows/lv_windows_display.c
+ lvgl/src/drivers/windows/lv_windows_input.c
+ lvgl/src/drivers/x11/lv_x11_display.c
+ lvgl/src/drivers/x11/lv_x11_input.c
+ lvgl/src/font/lv_font.c
+ lvgl/src/font/lv_font_dejavu_16_persian_hebrew.c
+ lvgl/src/font/lv_font_montserrat_10.c
+ lvgl/src/font/lv_font_montserrat_12.c
+ lvgl/src/font/lv_font_montserrat_14.c
+ lvgl/src/font/lv_font_montserrat_14_aligned.c
+ lvgl/src/font/lv_font_montserrat_16.c
+ lvgl/src/font/lv_font_montserrat_18.c
+ lvgl/src/font/lv_font_montserrat_20.c
+ lvgl/src/font/lv_font_montserrat_22.c
+ lvgl/src/font/lv_font_montserrat_24.c
+ lvgl/src/font/lv_font_montserrat_26.c
+ lvgl/src/font/lv_font_montserrat_28.c
+ lvgl/src/font/lv_font_montserrat_28_compressed.c
+ lvgl/src/font/lv_font_montserrat_30.c
+ lvgl/src/font/lv_font_montserrat_32.c
+ lvgl/src/font/lv_font_montserrat_34.c
+ lvgl/src/font/lv_font_montserrat_36.c
+ lvgl/src/font/lv_font_montserrat_38.c
+ lvgl/src/font/lv_font_montserrat_40.c
+ lvgl/src/font/lv_font_montserrat_42.c
+ lvgl/src/font/lv_font_montserrat_44.c
+ lvgl/src/font/lv_font_montserrat_46.c
+ lvgl/src/font/lv_font_montserrat_48.c
+ lvgl/src/font/lv_font_montserrat_8.c
+ lvgl/src/font/lv_font_source_han_sans_sc_14_cjk.c
+ lvgl/src/font/lv_font_source_han_sans_sc_16_cjk.c
+ lvgl/src/font/lv_font_unscii_16.c
+ lvgl/src/font/lv_font_unscii_8.c
+ lvgl/src/font/binfont_loader/lv_binfont_loader.c
+ lvgl/src/font/fmt_txt/lv_font_fmt_txt.c
+ lvgl/src/font/font_manager/lv_font_manager.c
+ lvgl/src/font/font_manager/lv_font_manager_recycle.c
+ lvgl/src/font/imgfont/lv_imgfont.c
+ lvgl/src/indev/lv_gridnav.c
+ lvgl/src/indev/lv_indev.c
+ lvgl/src/indev/lv_indev_gesture.c
+ lvgl/src/indev/lv_indev_scroll.c
+ lvgl/src/layouts/lv_layout.c
+ lvgl/src/layouts/flex/lv_flex.c
+ lvgl/src/layouts/grid/lv_grid.c
+ lvgl/src/libs/barcode/code128.c
+ lvgl/src/libs/barcode/lv_barcode.c
+ lvgl/src/libs/bin_decoder/lv_bin_decoder.c
+ lvgl/src/libs/bmp/lv_bmp.c
+ lvgl/src/libs/ffmpeg/lv_ffmpeg.c
+ lvgl/src/libs/freetype/lv_freetype.c
+ lvgl/src/libs/freetype/lv_freetype_glyph.c
+ lvgl/src/libs/freetype/lv_freetype_image.c
+ lvgl/src/libs/freetype/lv_freetype_outline.c
+ lvgl/src/libs/freetype/lv_ftsystem.c
+ lvgl/src/libs/frogfs/src/decomp_raw.c
+ lvgl/src/libs/frogfs/src/frogfs.c
+ lvgl/src/libs/fsdrv/lv_fs_cbfs.c
+ lvgl/src/libs/fsdrv/lv_fs_fatfs.c
+ lvgl/src/libs/fsdrv/lv_fs_frogfs.c
+ lvgl/src/libs/fsdrv/lv_fs_littlefs.c
+ lvgl/src/libs/fsdrv/lv_fs_memfs.c
+ lvgl/src/libs/fsdrv/lv_fs_posix.c
+ lvgl/src/libs/fsdrv/lv_fs_stdio.c
+ lvgl/src/libs/fsdrv/lv_fs_uefi.c
+ lvgl/src/libs/fsdrv/lv_fs_win32.c
+ lvgl/src/libs/FT800-FT813/EVE_commands.c
+ lvgl/src/libs/FT800-FT813/EVE_supplemental.c
+ lvgl/src/libs/gif/gif.c
+ lvgl/src/libs/gltf/gltf_environment/lv_gltf_ibl_sampler.c
+ lvgl/src/libs/gltf/gltf_view/assets/chromatic.c
+ lvgl/src/libs/gltf/gltf_view/assets/lv_gltf_view_shader.c
+ lvgl/src/libs/gltf/math/lv_3dmath.c
+ lvgl/src/libs/gstreamer/lv_gstreamer.c
+ lvgl/src/libs/libjpeg_turbo/lv_libjpeg_turbo.c
+ lvgl/src/libs/libpng/lv_libpng.c
+ lvgl/src/libs/libwebp/lv_libwebp.c
+ lvgl/src/libs/lodepng/lodepng.c
+ lvgl/src/libs/lodepng/lv_lodepng.c
+ lvgl/src/libs/lz4/lz4.c
+ lvgl/src/libs/nanovg/nanovg.c
+ lvgl/src/libs/qrcode/lv_qrcode.c
+ lvgl/src/libs/qrcode/qrcodegen.c
+ lvgl/src/libs/rle/lv_rle.c
+ lvgl/src/libs/rlottie/lv_rlottie.c
+ lvgl/src/libs/svg/lv_svg.c
+ lvgl/src/libs/svg/lv_svg_decoder.c
+ lvgl/src/libs/svg/lv_svg_parser.c
+ lvgl/src/libs/svg/lv_svg_render.c
+ lvgl/src/libs/svg/lv_svg_token.c
+ lvgl/src/libs/tiny_ttf/lv_tiny_ttf.c
+ lvgl/src/libs/tjpgd/lv_tjpgd.c
+ lvgl/src/libs/tjpgd/tjpgd.c
+ lvgl/src/libs/vg_lite_driver/lv_vg_lite_hal/lv_vg_lite_hal.c
+ lvgl/src/libs/vg_lite_driver/lv_vg_lite_hal/vg_lite_os.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_image.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_matrix.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_path.c
+ lvgl/src/libs/vg_lite_driver/VGLite/vg_lite_stroke.c
+ lvgl/src/libs/vg_lite_driver/VGLiteKernel/vg_lite_kernel.c
+ lvgl/src/misc/lv_anim.c
+ lvgl/src/misc/lv_anim_timeline.c
+ lvgl/src/misc/lv_area.c
+ lvgl/src/misc/lv_array.c
+ lvgl/src/misc/lv_async.c
+ lvgl/src/misc/lv_bidi.c
+ lvgl/src/misc/lv_circle_buf.c
+ lvgl/src/misc/lv_color.c
+ lvgl/src/misc/lv_color_op.c
+ lvgl/src/misc/lv_event.c
+ lvgl/src/misc/lv_fs.c
+ lvgl/src/misc/lv_grad.c
+ lvgl/src/misc/lv_iter.c
+ lvgl/src/misc/lv_ll.c
+ lvgl/src/misc/lv_log.c
+ lvgl/src/misc/lv_lru.c
+ lvgl/src/misc/lv_math.c
+ lvgl/src/misc/lv_matrix.c
+ lvgl/src/misc/lv_palette.c
+ lvgl/src/misc/lv_pending.c
+ lvgl/src/misc/lv_profiler_builtin.c
+ lvgl/src/misc/lv_profiler_builtin_posix.c
+ lvgl/src/misc/lv_rb.c
+ lvgl/src/misc/lv_style.c
+ lvgl/src/misc/lv_style_gen.c
+ lvgl/src/misc/lv_templ.c
+ lvgl/src/misc/lv_text.c
+ lvgl/src/misc/lv_text_ap.c
+ lvgl/src/misc/lv_timer.c
+ lvgl/src/misc/lv_tree.c
+ lvgl/src/misc/lv_utils.c
+ lvgl/src/misc/cache/lv_cache.c
+ lvgl/src/misc/cache/lv_cache_entry.c
+ lvgl/src/misc/cache/class/lv_cache_lru_ll.c
+ lvgl/src/misc/cache/class/lv_cache_lru_rb.c
+ lvgl/src/misc/cache/class/lv_cache_sc_da.c
+ lvgl/src/misc/cache/instance/lv_image_cache.c
+ lvgl/src/misc/cache/instance/lv_image_header_cache.c
+ lvgl/src/osal/lv_cmsis_rtos2.c
+ lvgl/src/osal/lv_freertos.c
+ lvgl/src/osal/lv_linux.c
+ lvgl/src/osal/lv_mqx.c
+ lvgl/src/osal/lv_os.c
+ lvgl/src/osal/lv_os_none.c
+ lvgl/src/osal/lv_pthread.c
+ lvgl/src/osal/lv_rtthread.c
+ lvgl/src/osal/lv_sdl2.c
+ lvgl/src/osal/lv_windows.c
+ lvgl/src/others/file_explorer/lv_file_explorer.c
+ lvgl/src/others/fragment/lv_fragment.c
+ lvgl/src/others/fragment/lv_fragment_manager.c
+ lvgl/src/others/translation/lv_translation.c
+ lvgl/src/stdlib/lv_mem.c
+ lvgl/src/stdlib/builtin/lv_mem_core_builtin.c
+ lvgl/src/stdlib/builtin/lv_sprintf_builtin.c
+ lvgl/src/stdlib/builtin/lv_string_builtin.c
+ lvgl/src/stdlib/builtin/lv_tlsf.c
+ lvgl/src/stdlib/clib/lv_mem_core_clib.c
+ lvgl/src/stdlib/clib/lv_sprintf_clib.c
+ lvgl/src/stdlib/clib/lv_string_clib.c
+ lvgl/src/stdlib/micropython/lv_mem_core_micropython.c
+ lvgl/src/stdlib/rtthread/lv_mem_core_rtthread.c
+ lvgl/src/stdlib/rtthread/lv_sprintf_rtthread.c
+ lvgl/src/stdlib/rtthread/lv_string_rtthread.c
+ lvgl/src/stdlib/uefi/lv_mem_core_uefi.c
+ lvgl/src/themes/lv_theme.c
+ lvgl/src/themes/default/lv_theme_default.c
+ lvgl/src/themes/mono/lv_theme_mono.c
+ lvgl/src/themes/simple/lv_theme_simple.c
+ lvgl/src/tick/lv_tick.c
+ lvgl/src/widgets/3dtexture/lv_3dtexture.c
+ lvgl/src/widgets/animimage/lv_animimage.c
+ lvgl/src/widgets/arc/lv_arc.c
+ lvgl/src/widgets/arclabel/lv_arclabel.c
+ lvgl/src/widgets/bar/lv_bar.c
+ lvgl/src/widgets/button/lv_button.c
+ lvgl/src/widgets/buttonmatrix/lv_buttonmatrix.c
+ lvgl/src/widgets/calendar/lv_calendar.c
+ lvgl/src/widgets/calendar/lv_calendar_chinese.c
+ lvgl/src/widgets/calendar/lv_calendar_header_arrow.c
+ lvgl/src/widgets/calendar/lv_calendar_header_dropdown.c
+ lvgl/src/widgets/canvas/lv_canvas.c
+ lvgl/src/widgets/chart/lv_chart.c
+ lvgl/src/widgets/checkbox/lv_checkbox.c
+ lvgl/src/widgets/dropdown/lv_dropdown.c
+ lvgl/src/widgets/gif/lv_gif.c
+ lvgl/src/widgets/image/lv_image.c
+ lvgl/src/widgets/imagebutton/lv_imagebutton.c
+ lvgl/src/widgets/ime/lv_ime_pinyin.c
+ lvgl/src/widgets/keyboard/lv_keyboard.c
+ lvgl/src/widgets/label/lv_label.c
+ lvgl/src/widgets/led/lv_led.c
+ lvgl/src/widgets/line/lv_line.c
+ lvgl/src/widgets/list/lv_list.c
+ lvgl/src/widgets/lottie/lv_lottie.c
+ lvgl/src/widgets/menu/lv_menu.c
+ lvgl/src/widgets/msgbox/lv_msgbox.c
+ lvgl/src/widgets/objx_templ/lv_objx_templ.c
+ lvgl/src/widgets/property/lv_animimage_properties.c
+ lvgl/src/widgets/property/lv_arc_properties.c
+ lvgl/src/widgets/property/lv_bar_properties.c
+ lvgl/src/widgets/property/lv_buttonmatrix_properties.c
+ lvgl/src/widgets/property/lv_chart_properties.c
+ lvgl/src/widgets/property/lv_checkbox_properties.c
+ lvgl/src/widgets/property/lv_dropdown_properties.c
+ lvgl/src/widgets/property/lv_image_properties.c
+ lvgl/src/widgets/property/lv_keyboard_properties.c
+ lvgl/src/widgets/property/lv_label_properties.c
+ lvgl/src/widgets/property/lv_led_properties.c
+ lvgl/src/widgets/property/lv_line_properties.c
+ lvgl/src/widgets/property/lv_menu_properties.c
+ lvgl/src/widgets/property/lv_obj_properties.c
+ lvgl/src/widgets/property/lv_roller_properties.c
+ lvgl/src/widgets/property/lv_scale_properties.c
+ lvgl/src/widgets/property/lv_slider_properties.c
+ lvgl/src/widgets/property/lv_span_properties.c
+ lvgl/src/widgets/property/lv_spinbox_properties.c
+ lvgl/src/widgets/property/lv_spinner_properties.c
+ lvgl/src/widgets/property/lv_style_properties.c
+ lvgl/src/widgets/property/lv_switch_properties.c
+ lvgl/src/widgets/property/lv_table_properties.c
+ lvgl/src/widgets/property/lv_tabview_properties.c
+ lvgl/src/widgets/property/lv_textarea_properties.c
+ lvgl/src/widgets/roller/lv_roller.c
+ lvgl/src/widgets/scale/lv_scale.c
+ lvgl/src/widgets/slider/lv_slider.c
+ lvgl/src/widgets/span/lv_span.c
+ lvgl/src/widgets/spinbox/lv_spinbox.c
+ lvgl/src/widgets/spinner/lv_spinner.c
+ lvgl/src/widgets/switch/lv_switch.c
+ lvgl/src/widgets/table/lv_table.c
+ lvgl/src/widgets/tabview/lv_tabview.c
+ lvgl/src/widgets/textarea/lv_textarea.c
+ lvgl/src/widgets/tileview/lv_tileview.c
+ lvgl/src/widgets/win/lv_win.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ LvglSpikePkg/LvglSpikePkg.dec
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ BaseLib
+ TimerLib
+
+[Guids]
+
+[Protocols]
+ gEfiGraphicsOutputProtocolGuid
+ gEfiAbsolutePointerProtocolGuid
+ gEfiSimplePointerProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiSimpleTextInputExProtocolGuid
+
+[BuildOptions]
+
+ # /wd5287: warning C5287: operands are different enum types 'lv_part_t' and 'lv_state_t'; `LV_PART_ANY | LV_STATE_ANY`
+ MSFT:*_*_*_CC_FLAGS = /wd4244 /wd4204 /wd4389 /wd4221 /wd4800 /wd4267 /wd4018 /wd4047 /wd4245 /wd4003 /wd4702 /wd4718 /wd4706 /wd4819 /wd4028 /wd5287
+
+ MSFT:*_*_*_CC_FLAGS = /GL-
+
+ # Spike: keep the probe focused on hard compile/link errors (e.g. soft-float,
+ # arch gates), not on LVGL's many style warnings, so a real XArch blocker is
+ # not masked by -Werror tripping on an unused-variable.
+ GCC:*_*_*_CC_FLAGS = -Wno-format -Wno-error -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-sign-compare -Wno-type-limits -Wno-unused-parameter -Wno-array-bounds -Wno-maybe-uninitialized
\ No newline at end of file
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglLibCommon.h b/Experimental/LvglSpikePkg/Library/LvglLib/LvglLibCommon.h
new file mode 100644
index 0000000..2fe3aac
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglLibCommon.h
@@ -0,0 +1,45 @@
+
+
+#ifndef __LVGL_LIB_COMMON_H__
+#define __LVGL_LIB_COMMON_H__
+
+#include "lvgl/lvgl.h"
+#include "lv_port_indev.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "LvglUefiPort.h"
+
+
+#define EXIT_BTN_NONE 0x0
+#define EXIT_BTN_YES 0x1
+#define EXIT_BTN_NO 0x2
+
+
+lv_display_t * lv_uefi_disp_create(int32_t hor_res, int32_t ver_res);
+
+VOID
+EFIAPI
+LvglUefiEscExitRegister (
+ VOID
+ );
+
+VOID
+EFIAPI
+LvglUefiEscExitUnregister (
+ VOID
+ );
+
+#endif
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.c b/Experimental/LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.c
new file mode 100644
index 0000000..eccd952
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.c
@@ -0,0 +1,133 @@
+/** @file
+ LvglSpikeProbe -- experimental LVGL-on-LoongArch render demo.
+
+ Brings up LVGL's upstream UEFI backend on a GOP display and draws a small demo
+ screen (themed background + title + subtitle + rounded button), then runs the
+ LVGL handler loop holding the frame until ESC is pressed. This both forces the
+ full LVGL closure (core + software renderer + UEFI port, with the
+ LoongArch64/RISC-V64 arch-gate patch) to compile/link AND gives a visible
+ on-hardware result.
+
+ experimental/lvgl-spike only; never ship, never default overlay.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include
+#include
+#include
+#include
+
+#include "lvgl/lvgl.h"
+#include "lvgl/src/drivers/uefi/lv_uefi.h"
+#include "lvgl/src/drivers/uefi/lv_uefi_context.h"
+#include "lvgl/src/drivers/uefi/lv_uefi_display.h"
+
+/**
+ Build the demo UI on the active screen: dark background, a large title, a
+ subtitle line, and a rounded accent button with a centered caption.
+
+ @param[in] Screen The LVGL screen object to populate. Must be non-NULL.
+**/
+STATIC
+VOID
+LvglSpikeBuildUi (
+ IN lv_obj_t *Screen
+ )
+{
+ lv_obj_t *Title;
+ lv_obj_t *Subtitle;
+ lv_obj_t *Button;
+ lv_obj_t *ButtonLabel;
+
+ lv_obj_set_style_bg_color (Screen, lv_color_hex (0x0E1116), LV_PART_MAIN);
+ lv_obj_set_style_bg_opa (Screen, LV_OPA_COVER, LV_PART_MAIN);
+
+ Title = lv_label_create (Screen);
+ lv_label_set_text (Title, "ModernSetupPkg x LVGL");
+ lv_obj_set_style_text_color (Title, lv_color_hex (0xF2C14E), LV_PART_MAIN);
+ lv_obj_set_style_text_font (Title, &lv_font_montserrat_24, LV_PART_MAIN);
+ lv_obj_align (Title, LV_ALIGN_CENTER, 0, -60);
+
+ Subtitle = lv_label_create (Screen);
+ lv_label_set_text (Subtitle, "LVGL v9.5.0 software renderer on LoongArch64 UEFI");
+ lv_obj_set_style_text_color (Subtitle, lv_color_hex (0xB8C0CC), LV_PART_MAIN);
+ lv_obj_align (Subtitle, LV_ALIGN_CENTER, 0, -20);
+
+ Button = lv_button_create (Screen);
+ lv_obj_set_size (Button, 220, 56);
+ lv_obj_align (Button, LV_ALIGN_CENTER, 0, 50);
+ lv_obj_set_style_radius (Button, 12, LV_PART_MAIN);
+ lv_obj_set_style_bg_color (Button, lv_color_hex (0xF2C14E), LV_PART_MAIN);
+
+ ButtonLabel = lv_label_create (Button);
+ lv_label_set_text (ButtonLabel, "Press ESC to exit");
+ lv_obj_set_style_text_color (ButtonLabel, lv_color_hex (0x10141A), LV_PART_MAIN);
+ lv_obj_center (ButtonLabel);
+}
+
+/**
+ Entry point. Initializes the LVGL UEFI backend + core, creates one display on
+ a GOP-backed handle, draws the demo UI, then pumps lv_timer_handler() in a
+ loop (advancing the tick manually) until the user presses ESC. Falls back to a
+ text message on ConOut when no GOP display can be found.
+
+ @param[in] ImageHandle Firmware-allocated image handle.
+ @param[in] SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Always (build/render probe, not a product).
+**/
+EFI_STATUS
+EFIAPI
+LvglSpikeProbeMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ void *DisplayHandle;
+ lv_display_t *Display;
+ EFI_INPUT_KEY Key;
+ EFI_STATUS Status;
+
+ Print (L"LvglSpikeProbe: start\n");
+ lv_uefi_init (ImageHandle, SystemTable);
+ Print (L"LvglSpikeProbe: lv_uefi_init done\n");
+ lv_init ();
+ Print (L"LvglSpikeProbe: lv_init done\n");
+
+ DisplayHandle = lv_uefi_display_get_any ();
+ Print (L"LvglSpikeProbe: display handle = %p\n", DisplayHandle);
+ if (DisplayHandle == NULL) {
+ Print (L"LvglSpikeProbe: no EFI_GRAPHICS_OUTPUT_PROTOCOL display found.\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ Display = lv_uefi_display_create (DisplayHandle);
+ Print (L"LvglSpikeProbe: display created = %p\n", Display);
+ if (Display == NULL) {
+ Print (L"LvglSpikeProbe: lv_uefi_display_create failed.\n");
+ return EFI_DEVICE_ERROR;
+ }
+
+ LvglSpikeBuildUi (lv_screen_active ());
+ Print (L"LvglSpikeProbe: UI built; rendering -- press ESC to exit\n");
+
+ //
+ // Hold the rendered frame; ESC exits. Tick is advanced manually so LVGL
+ // timers/refresh run even if no timestamp tick source is registered.
+ //
+ for ( ; ; ) {
+ lv_timer_handler ();
+ gBS->Stall (10 * 1000);
+ lv_tick_inc (10);
+
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status) && (Key.ScanCode == SCAN_ESC)) {
+ break;
+ }
+ }
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+ return EFI_SUCCESS;
+}
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.inf b/Experimental/LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.inf
new file mode 100644
index 0000000..75f0640
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.inf
@@ -0,0 +1,58 @@
+## @file
+# LvglSpikeProbe -- experimental standalone LVGL-on-GOP render probe.
+#
+# Forces the shared LVGL build (LvglCoreLib) to compile/link and draws a demo
+# UI straight to GOP (NOT via any DisplayEngine). experimental/lvgl-spike only;
+# never ship, never default overlay.
+#
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LvglSpikeProbe
+ FILE_GUID = 7C2A9E14-3B6D-4F08-A1C2-9E5D0B71AA02
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = LvglSpikeProbeMain
+
+[Sources]
+ LvglSpikeProbe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ LvglSpikePkg/LvglSpikePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiBootServicesTableLib
+ UefiLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DebugLib
+ PrintLib
+ TimerLib
+ LvglCoreLib
+
+[Protocols]
+ gEfiGraphicsOutputProtocolGuid
+ gEfiSimplePointerProtocolGuid
+ gEfiAbsolutePointerProtocolGuid
+ gEfiSimpleTextInputExProtocolGuid
+ gEfiSimpleTextInProtocolGuid
+ gEfiEdidActiveProtocolGuid
+ gEfiTimestampProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiDevicePathProtocolGuid
+
+[Guids]
+ gEfiFileInfoGuid
+
+[BuildOptions]
+ # LvglSpikeProbe.c includes , which pulls lv_conf.h via
+ # LV_CONF_INCLUDE_SIMPLE (found in this module's own dir).
+ GCC:*_*_*_CC_FLAGS = -DLV_CONF_INCLUDE_SIMPLE
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglUefiPort.c b/Experimental/LvglSpikePkg/Library/LvglLib/LvglUefiPort.c
new file mode 100644
index 0000000..3c4b568
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglUefiPort.c
@@ -0,0 +1,212 @@
+
+#include "LvglUefiPort.h"
+
+#define LVGL_HEAD_SIGNATURE SIGNATURE_32('l','v','g','l')
+
+typedef struct {
+ UINT32 Signature;
+ UINTN Size;
+} LVGL_HEAD;
+
+#define LVGL_OVERHEAD sizeof(LVGL_HEAD)
+
+void* memset (void *dest, char ch, unsigned int count)
+{
+ return SetMem (dest, count, ch);
+}
+
+
+void *
+malloc (
+ size_t size
+ )
+{
+ LVGL_HEAD *PoolHdr;
+ UINTN NewSize;
+ VOID *Data;
+
+ NewSize = (UINTN)(size) + LVGL_OVERHEAD;
+
+ Data = AllocatePool (NewSize);
+ if (Data != NULL) {
+ PoolHdr = (LVGL_HEAD *)Data;
+ PoolHdr->Signature = LVGL_HEAD_SIGNATURE;
+ PoolHdr->Size = size;
+
+ return (VOID *)(PoolHdr + 1);
+ }
+
+ return NULL;
+}
+
+void *
+realloc (
+ void *ptr,
+ size_t size
+ )
+{
+ LVGL_HEAD *OldPoolHdr;
+ LVGL_HEAD *NewPoolHdr;
+ UINTN OldSize;
+ UINTN NewSize;
+ VOID *Data;
+
+ NewSize = (UINTN)size + LVGL_OVERHEAD;
+ Data = AllocatePool (NewSize);
+ if (Data != NULL) {
+ NewPoolHdr = (LVGL_HEAD *)Data;
+ NewPoolHdr->Signature = LVGL_HEAD_SIGNATURE;
+ NewPoolHdr->Size = size;
+ if (ptr != NULL) {
+ OldPoolHdr = (LVGL_HEAD *)ptr - 1;
+ ASSERT (OldPoolHdr->Signature == LVGL_HEAD_SIGNATURE);
+ OldSize = OldPoolHdr->Size;
+
+ CopyMem ((VOID *)(NewPoolHdr + 1), ptr, MIN (OldSize, size));
+ FreePool ((VOID *)OldPoolHdr);
+ }
+
+ return (VOID *)(NewPoolHdr + 1);
+ }
+
+ return NULL;
+}
+
+void
+free (
+ void *ptr
+ )
+{
+ VOID *EvalOnce;
+ LVGL_HEAD *PoolHdr;
+
+ EvalOnce = ptr;
+ if (EvalOnce == NULL) {
+ return;
+ }
+
+ PoolHdr = (LVGL_HEAD *)EvalOnce - 1;
+ if (PoolHdr->Signature == LVGL_HEAD_SIGNATURE) {
+ FreePool (PoolHdr);
+ } else {
+ FreePool (EvalOnce);
+ }
+}
+
+
+/* Return the absolute value of I. */
+long int
+labs (long int i)
+{
+ return i < 0 ? -i : i;
+}
+
+/* Return the absolute value of I. */
+int
+abs (int i)
+{
+ return i < 0 ? -i : i;
+}
+
+char *strchr(const char *str, int ch)
+{
+ return ScanMem8 (str, AsciiStrSize (str), (UINT8)ch);
+}
+
+
+char *
+strcpy (
+ char *strDest,
+ const char *strSource
+ )
+{
+ AsciiStrCpyS (strDest, AsciiStrnSizeS (strSource, MAX_STRING_SIZE - 1), strSource);
+ return strDest;
+}
+
+char *
+strncpy (
+ char *strDest,
+ const char *strSource,
+ size_t count
+ )
+{
+ UINTN DestMax = MAX_STRING_SIZE;
+
+ if (count < MAX_STRING_SIZE) {
+ DestMax = count + 1;
+ } else {
+ count = MAX_STRING_SIZE-1;
+ }
+
+ AsciiStrnCpyS (strDest, DestMax, strSource, (UINTN)count);
+
+ return strDest;
+}
+
+char *
+strcat (
+ char *strDest,
+ const char *strSource
+ )
+{
+ UINTN DestMax;
+
+ DestMax = AsciiStrnLenS (strDest, MAX_STRING_SIZE) + AsciiStrnSizeS (strSource, MAX_STRING_SIZE);
+
+ if (DestMax > MAX_STRING_SIZE) {
+ DestMax = MAX_STRING_SIZE;
+ }
+
+ AsciiStrCatS (strDest, DestMax, strSource);
+
+ return strDest;
+}
+
+
+char *
+strncat (
+ char *strDest,
+ const char *strSource,
+ size_t count
+ )
+{
+ UINTN DestMax = MAX_STRING_SIZE;
+
+ DestMax = AsciiStrnLenS (strDest, MAX_STRING_SIZE) + AsciiStrnSizeS (strSource, MAX_STRING_SIZE);
+
+ if (DestMax > MAX_STRING_SIZE) {
+ DestMax = MAX_STRING_SIZE;
+ }
+
+ AsciiStrnCatS (strDest, DestMax, strSource, (UINTN)count);
+
+ return strDest;
+}
+
+FILE *
+fopen (
+ const char *filename,
+ const char *mode
+ )
+{
+ return NULL;
+}
+
+int
+fclose (
+ FILE *stream
+ )
+{
+ return EOF;
+}
+
+int
+fscanf (
+ FILE *stream,
+ const char *format,
+ ...
+ )
+{
+ return EOF;
+}
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglUefiPort.h b/Experimental/LvglSpikePkg/Library/LvglLib/LvglUefiPort.h
new file mode 100644
index 0000000..56474c9
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglUefiPort.h
@@ -0,0 +1,164 @@
+
+#ifndef __LVGL_UEFI_PORT_H__
+#define __LVGL_UEFI_PORT_H__
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+typedef INT8 int8_t;
+typedef UINT8 uint8_t;
+typedef INT16 int16_t;
+typedef UINT16 uint16_t;
+typedef INT32 int32_t;
+typedef UINT32 uint32_t;
+typedef INT64 int64_t;
+typedef UINT64 uint64_t;
+typedef INTN intmax_t;
+typedef UINTN uintmax_t;
+typedef INTN intptr_t;
+typedef UINTN uintptr_t;
+typedef UINTN size_t;
+
+typedef INTN ptrdiff_t;
+
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+#define INT8_MAX MAX_INT8
+#define INT16_MAX MAX_INT16
+#define INT32_MAX MAX_INT32
+#define INT64_MAX MAX_INT64
+#define UINT8_MAX MAX_UINT8
+#define UINT16_MAX MAX_UINT16
+#define UINT32_MAX MAX_UINT32
+#define UINT64_MAX MAX_UINT64
+
+#define INT8_MIN MIN_INT8
+#define INT16_MIN MIN_INT16
+#define INT32_MIN MIN_INT32
+#define INT64_MIN MIN_INT64
+#define UINT8_MIN MIN_UINT8
+#define UINT16_MIN MIN_UINT16
+#define UINT32_MIN MIN_UINT32
+#define UINT64_MIN MIN_UINT64
+
+#ifndef offsetof
+#define offsetof OFFSET_OF
+#endif
+
+
+#define calloc(n, s) AllocateZeroPool((n)*(s))
+#define memcpy(dest,source,count) CopyMem(dest,source,(UINTN)(count))
+// #define memset(dest,ch,count) SetMem(dest,(UINTN)(count),(UINT8)(ch))
+#define memchr(buf,ch,count) ScanMem8(buf,(UINTN)(count),(UINT8)ch)
+#define memcmp(buf1,buf2,count) (int)(CompareMem(buf1,buf2,(UINTN)(count)))
+#define memmove(dest,source,count) CopyMem(dest,source,(UINTN)(count))
+
+#define va_init_list(a, b) VA_START(a,b)
+#define va_list VA_LIST
+#define va_arg(a, b) VA_ARG(a,b)
+#define va_end(a) VA_END(a)
+#define va_start VA_START
+#define va_copy VA_COPY
+
+#define FILE VOID
+#define stdout NULL
+#define fprintf(...)
+#define vsnprintf (int)AsciiVSPrint
+
+#define EOF (-1)
+
+char *
+strcpy (
+ char *strDest,
+ const char *strSource
+ );
+
+char *
+strncpy (
+ char *strDest,
+ const char *strSource,
+ size_t count
+ );
+
+char *
+strcat (
+ char *strDest,
+ const char *strSource
+ );
+
+char *
+strncat (
+ char *strDest,
+ const char *strSource,
+ size_t count
+ );
+
+#define MAX_STRING_SIZE 0x1000
+#define strlen(str) (size_t)(AsciiStrnLenS(str,MAX_STRING_SIZE))
+#define strnlen(str, count) (size_t)(AsciiStrnLenS(str, count))
+// #define strcpy(strDest,strSource) AsciiStrCpyS(strDest,MAX_STRING_SIZE,strSource)
+// #define strncpy(strDest,strSource,count) AsciiStrnCpyS(strDest,MAX_STRING_SIZE,strSource,(UINTN)count)
+// #define strcat(strDest,strSource) AsciiStrCatS(strDest,MAX_STRING_SIZE,strSource)
+// #define strncat(strDest,strSource,count) AsciiStrnCatS(strDest,MAX_STRING_SIZE,strSource,(UINTN)count)
+#define strncmp(string1,string2,count) (int)(AsciiStrnCmp(string1,string2,(UINTN)(count)))
+#define strcasecmp(str1,str2) (int)AsciiStriCmp(str1,str2)
+#define strcmp(str1,str2) (int)AsciiStrCmp (str1,str2)
+
+void *
+malloc (
+ size_t size
+ );
+
+void *
+realloc (
+ void *ptr,
+ size_t size
+ );
+
+
+void
+free (
+ void *ptr
+ );
+
+long int labs (long int i);
+
+int abs (int i);
+
+char *strchr(const char *str, int ch);
+
+void* memset (void *dest, char ch, unsigned int count);
+
+FILE *
+fopen (
+ const char *filename,
+ const char *mode
+ );
+
+int
+fclose (
+ FILE *
+ );
+
+int
+fscanf (
+ FILE *stream,
+ const char *format,
+ ...
+ );
+
+#define exit(n) ASSERT(FALSE);
+
+#endif
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/MouseCursorIcon.c b/Experimental/LvglSpikePkg/Library/LvglLib/MouseCursorIcon.c
new file mode 100644
index 0000000..eef5797
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/MouseCursorIcon.c
@@ -0,0 +1,43 @@
+#include "lv_port_indev.h"
+
+// https://github.com/lvgl/lv_web_emscripten/blob/master/mouse_cursor_icon.c
+#ifndef LV_ATTRIBUTE_MEM_ALIGN
+#define LV_ATTRIBUTE_MEM_ALIGN
+#endif
+
+#ifndef LV_ATTRIBUTE_IMG_MOUSE_CURSOR_ICON
+#define LV_ATTRIBUTE_IMG_MOUSE_CURSOR_ICON
+#endif
+
+const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_MOUSE_CURSOR_ICON uint8_t mouse_cursor_icon_map[] = {
+ 0x78, 0x78, 0x78, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x69, 0x69, 0x69, 0xff, 0xed, 0xed, 0xed, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x1b, 0x1b, 0x1b, 0xff, 0x6c, 0x6c, 0x6c, 0xff, 0xec, 0xec, 0xec, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0x16, 0x16, 0x16, 0xff, 0x75, 0x75, 0x75, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xd6, 0xd6, 0xd6, 0xff, 0x13, 0x13, 0x13, 0xff, 0x7f, 0x7f, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xfb, 0xfb, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0xd0, 0xd0, 0xff, 0x11, 0x11, 0x11, 0xff, 0x87, 0x87, 0x87, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xf7, 0xf7, 0xf7, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0xc9, 0xc9, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0x8f, 0x8f, 0x8f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xf4, 0xf4, 0xf4, 0xff, 0xfb, 0xfb, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc3, 0xc3, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0x97, 0x97, 0x97, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf8, 0xf8, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0x9f, 0x9f, 0x9f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xed, 0xed, 0xed, 0xff, 0xf4, 0xf4, 0xf4, 0xff, 0xfb, 0xfb, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb4, 0xb4, 0xb4, 0xff, 0x10, 0x10, 0x10, 0xff, 0xa6, 0xa6, 0xa6, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xe9, 0xe9, 0xe9, 0xff, 0xf1, 0xf1, 0xf1, 0xff, 0xf8, 0xf8, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xff, 0x11, 0x11, 0x11, 0xff, 0xae, 0xae, 0xae, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xe6, 0xe6, 0xe6, 0xff, 0xed, 0xed, 0xed, 0xff, 0xf4, 0xf4, 0xf4, 0xff, 0xfb, 0xfb, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa3, 0xa3, 0xa3, 0xff, 0x13, 0x13, 0x13, 0xff, 0xb4, 0xb4, 0xb4, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xe3, 0xe3, 0xe3, 0xff, 0xea, 0xea, 0xea, 0xff, 0xf1, 0xf1, 0xf1, 0xff, 0xf8, 0xf8, 0xf8, 0xff, 0xfd, 0xfd, 0xfd, 0xff, 0x2d, 0x2d, 0x2d, 0xff, 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0b, 0x0b, 0xff, 0x0b, 0x0b, 0x0b, 0xff, 0x01, 0x01, 0x01, 0xff, 0x13, 0x13, 0x13, 0xff, 0xc5, 0xc5, 0xc5, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xe6, 0xe6, 0xe6, 0xff, 0xd7, 0xd7, 0xd7, 0xff, 0x9c, 0x9c, 0x9c, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x91, 0x91, 0x91, 0xff, 0x2a, 0x2a, 0x2a, 0xff, 0x94, 0x94, 0x94, 0xff, 0xa3, 0xa3, 0xa3, 0xff, 0xa6, 0xa6, 0xa6, 0xff, 0xac, 0xac, 0xac, 0xff, 0xce, 0xce, 0xce, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xcb, 0xcb, 0xcb, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0xeb, 0xeb, 0xeb, 0xff, 0xf5, 0xf5, 0xf5, 0xff, 0x13, 0x13, 0x13, 0xff, 0x98, 0x98, 0x98, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xff, 0x1b, 0x1b, 0x1b, 0xff, 0x4e, 0x4e, 0x4e, 0xff, 0x38, 0x38, 0x38, 0xff, 0x80, 0x80, 0x80, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x81, 0x81, 0x81, 0xff, 0x40, 0x40, 0x40, 0xff, 0xe4, 0xe4, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x19, 0x19, 0x19, 0xff, 0x54, 0x54, 0x54, 0xff, 0xba, 0xba, 0xba, 0xff, 0xb1, 0xb1, 0xb1, 0xff, 0x12, 0x12, 0x12, 0xff, 0xed, 0xed, 0xed, 0xff, 0xef, 0xef, 0xef, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0xb2, 0xb2, 0xb2, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0xff, 0x5d, 0x5d, 0x5d, 0xff, 0xbe, 0xbe, 0xbe, 0xff, 0xed, 0xed, 0xed, 0x54, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0xff, 0x83, 0x83, 0x83, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x40, 0x40, 0x40, 0xff, 0x76, 0x76, 0x76, 0xff, 0xec, 0xec, 0xec, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x81, 0x81, 0x81, 0xff, 0xca, 0xca, 0xca, 0xff, 0xec, 0xec, 0xec, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xbd, 0xbd, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0x45, 0x45, 0x45, 0xff, 0x14, 0x14, 0x14, 0xff, 0x91, 0x91, 0x91, 0xff, 0xf3, 0xf3, 0xf3, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0xb3, 0xb3, 0xff, 0x6f, 0x6f, 0x6f, 0xff, 0x9a, 0x9a, 0x9a, 0xff, 0xd7, 0xd7, 0xd7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xec, 0xec, 0x35, 0xf3, 0xf3, 0xf3, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const lv_img_dsc_t mouse_cursor_icon = {
+ .header.cf = LV_COLOR_FORMAT_ARGB8888,
+ .header.magic = LV_IMAGE_HEADER_MAGIC,
+ .header.w = 13,
+ .header.h = 21,
+ .data_size = 273 * 4,
+ .data = mouse_cursor_icon_map,
+};
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/lv_conf.h b/Experimental/LvglSpikePkg/Library/LvglLib/lv_conf.h
new file mode 100644
index 0000000..0343725
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/lv_conf.h
@@ -0,0 +1,1526 @@
+/**
+ * @file lv_conf.h
+ * Configuration file for v9.5.0
+ */
+
+/*
+ * Copy this file as `lv_conf.h`
+ * 1. simply next to `lvgl` folder
+ * 2. or to any other place and
+ * - define `LV_CONF_INCLUDE_SIMPLE`;
+ * - add the path as an include path.
+ */
+
+/* clang-format off */
+#if 1 /* Set this to "1" to enable content */
+
+#ifndef LV_CONF_H
+#define LV_CONF_H
+
+/* If you need to include anything here, do it inside the `__ASSEMBLY__` guard */
+#if 0 && defined(__ASSEMBLY__)
+#include "my_include.h"
+#endif
+
+/*====================
+ COLOR SETTINGS
+ *====================*/
+
+/** Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) */
+#define LV_COLOR_DEPTH 32
+
+/*=========================
+ STDLIB WRAPPER SETTINGS
+ *=========================*/
+
+/** Possible values
+ * - LV_STDLIB_BUILTIN: LVGL's built in implementation
+ * - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc
+ * - LV_STDLIB_MICROPYTHON: MicroPython implementation
+ * - LV_STDLIB_RTTHREAD: RT-Thread implementation
+ * - LV_STDLIB_CUSTOM: Implement the functions externally
+ */
+#define LV_USE_STDLIB_MALLOC LV_STDLIB_CUSTOM
+
+/** Possible values
+ * - LV_STDLIB_BUILTIN: LVGL's built in implementation
+ * - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc
+ * - LV_STDLIB_MICROPYTHON: MicroPython implementation
+ * - LV_STDLIB_RTTHREAD: RT-Thread implementation
+ * - LV_STDLIB_CUSTOM: Implement the functions externally
+ */
+#define LV_USE_STDLIB_STRING LV_STDLIB_BUILTIN
+
+/** Possible values
+ * - LV_STDLIB_BUILTIN: LVGL's built in implementation
+ * - LV_STDLIB_CLIB: Standard C functions, like malloc, strlen, etc
+ * - LV_STDLIB_MICROPYTHON: MicroPython implementation
+ * - LV_STDLIB_RTTHREAD: RT-Thread implementation
+ * - LV_STDLIB_CUSTOM: Implement the functions externally
+ */
+#define LV_USE_STDLIB_SPRINTF LV_STDLIB_BUILTIN
+
+#define LV_STDINT_INCLUDE
+#define LV_STDDEF_INCLUDE
+#define LV_STDBOOL_INCLUDE
+#define LV_INTTYPES_INCLUDE
+#define LV_LIMITS_INCLUDE
+#define LV_STDARG_INCLUDE
+
+#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN
+ /** Size of memory available for `lv_malloc()` in bytes (>= 2kB) */
+ #define LV_MEM_SIZE (64 * 1024U) /**< [bytes] */
+
+ /** Size of the memory expand for `lv_malloc()` in bytes */
+ #define LV_MEM_POOL_EXPAND_SIZE 0
+
+ /** Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too. */
+ #define LV_MEM_ADR 0 /**< 0: unused*/
+ /* Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc */
+ #if LV_MEM_ADR == 0
+ #undef LV_MEM_POOL_INCLUDE
+ #undef LV_MEM_POOL_ALLOC
+ #endif
+#endif /*LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN*/
+
+/*====================
+ HAL SETTINGS
+ *====================*/
+
+/** Default display refresh, input device read and animation step period. */
+#define LV_DEF_REFR_PERIOD 10 /**< [ms] */
+
+/** Default Dots Per Inch. Used to initialize default sizes such as widgets sized, style paddings.
+ * (Not so important, you can adjust it to modify default sizes and spaces.) */
+#define LV_DPI_DEF 130 /**< [px/inch] */
+
+/*=================
+ * OPERATING SYSTEM
+ *=================*/
+/** Select operating system to use. Possible options:
+ * - LV_OS_NONE
+ * - LV_OS_PTHREAD
+ * - LV_OS_FREERTOS
+ * - LV_OS_CMSIS_RTOS2
+ * - LV_OS_RTTHREAD
+ * - LV_OS_WINDOWS
+ * - LV_OS_MQX
+ * - LV_OS_SDL2
+ * - LV_OS_CUSTOM */
+#define LV_USE_OS LV_OS_NONE
+
+#if LV_USE_OS == LV_OS_CUSTOM
+ #define LV_OS_CUSTOM_INCLUDE
+#endif
+#if LV_USE_OS == LV_OS_FREERTOS
+ /*
+ * Unblocking an RTOS task with a direct notification is 45% faster and uses less RAM
+ * than unblocking a task using an intermediary object such as a binary semaphore.
+ * RTOS task notifications can only be used when there is only one task that can be the recipient of the event.
+ */
+ #define LV_USE_FREERTOS_TASK_NOTIFY 1
+#endif
+
+/*========================
+ * RENDERING CONFIGURATION
+ *========================*/
+
+/** Align stride of all layers and images to this bytes */
+#define LV_DRAW_BUF_STRIDE_ALIGN 1
+
+/** Align start address of draw_buf addresses to this bytes*/
+#define LV_DRAW_BUF_ALIGN 4
+
+/** Using matrix for transformations.
+ * Requirements:
+ * - `LV_USE_MATRIX = 1`.
+ * - Rendering engine needs to support 3x3 matrix transformations. */
+#define LV_DRAW_TRANSFORM_USE_MATRIX 0
+
+/* If a widget has `style_opa < 255` (not `bg_opa`, `text_opa` etc) or not NORMAL blend mode
+ * it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks.
+ * "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers
+ * and can't be drawn in chunks. */
+
+/** The target buffer size for simple layer chunks. */
+#define LV_DRAW_LAYER_SIMPLE_BUF_SIZE (24 * 1024) /**< [bytes]*/
+
+/* Limit the max allocated memory for simple and transformed layers.
+ * It should be at least `LV_DRAW_LAYER_SIMPLE_BUF_SIZE` sized but if transformed layers are also used
+ * it should be enough to store the largest widget too (width x height x 4 area).
+ * Set it to 0 to have no limit. */
+#define LV_DRAW_LAYER_MAX_MEMORY 0 /**< No limit by default [bytes]*/
+
+/** Stack size of drawing thread.
+ * NOTE: If FreeType or ThorVG is enabled, it is recommended to set it to 32KB or more.
+ */
+#define LV_DRAW_THREAD_STACK_SIZE (8 * 1024) /**< [bytes]*/
+
+/** Thread priority of the drawing task.
+ * Higher values mean higher priority.
+ * Can use values from lv_thread_prio_t enum in lv_os.h: LV_THREAD_PRIO_LOWEST,
+ * LV_THREAD_PRIO_LOW, LV_THREAD_PRIO_MID, LV_THREAD_PRIO_HIGH, LV_THREAD_PRIO_HIGHEST
+ * Make sure the priority value aligns with the OS-specific priority levels.
+ * On systems with limited priority levels (e.g., FreeRTOS), a higher value can improve
+ * rendering performance but might cause other tasks to starve. */
+#define LV_DRAW_THREAD_PRIO LV_THREAD_PRIO_HIGH
+
+#define LV_USE_DRAW_SW 1
+#if LV_USE_DRAW_SW == 1
+ /*
+ * Selectively disable color format support in order to reduce code size.
+ * NOTE: some features use certain color formats internally, e.g.
+ * - gradients use RGB888
+ * - bitmaps with transparency may use ARGB8888
+ */
+ #define LV_DRAW_SW_SUPPORT_RGB565 0
+ #define LV_DRAW_SW_SUPPORT_RGB565_SWAPPED 0
+ #define LV_DRAW_SW_SUPPORT_RGB565A8 0
+ #define LV_DRAW_SW_SUPPORT_RGB888 1
+ #define LV_DRAW_SW_SUPPORT_XRGB8888 1
+ #define LV_DRAW_SW_SUPPORT_ARGB8888 1
+ #define LV_DRAW_SW_SUPPORT_ARGB8888_PREMULTIPLIED 0
+ #define LV_DRAW_SW_SUPPORT_L8 0
+ #define LV_DRAW_SW_SUPPORT_AL88 0
+ #define LV_DRAW_SW_SUPPORT_A8 0
+ #define LV_DRAW_SW_SUPPORT_I1 0
+
+ /* The threshold of the luminance to consider a pixel as
+ * active in indexed color format */
+ #define LV_DRAW_SW_I1_LUM_THRESHOLD 127
+
+ /** Set number of draw units.
+ * - > 1 requires operating system to be enabled in `LV_USE_OS`.
+ * - > 1 means multiple threads will render the screen in parallel. */
+ #define LV_DRAW_SW_DRAW_UNIT_CNT 1
+
+ /** Use Arm-2D to accelerate software (sw) rendering. */
+ #define LV_USE_DRAW_ARM2D_SYNC 0
+
+ /** Enable native helium assembly to be compiled. */
+ #define LV_USE_NATIVE_HELIUM_ASM 0
+
+ /**
+ * - 0: Use a simple renderer capable of drawing only simple rectangles with gradient, images, text, and straight lines only.
+ * - 1: Use a complex renderer capable of drawing rounded corners, shadow, skew lines, and arcs too. */
+ #define LV_DRAW_SW_COMPLEX 1
+
+ #if LV_DRAW_SW_COMPLEX == 1
+ /** Allow buffering some shadow calculation.
+ * LV_DRAW_SW_SHADOW_CACHE_SIZE is the maximum shadow size to buffer, where shadow size is
+ * `shadow_width + radius`. Caching has LV_DRAW_SW_SHADOW_CACHE_SIZE^2 RAM cost. */
+ #define LV_DRAW_SW_SHADOW_CACHE_SIZE 0
+
+ /** Set number of maximally-cached circle data.
+ * The circumference of 1/4 circle are saved for anti-aliasing.
+ * `radius * 4` bytes are used per circle (the most often used radiuses are saved).
+ * - 0: disables caching */
+ #define LV_DRAW_SW_CIRCLE_CACHE_SIZE 4
+ #endif
+
+ #define LV_USE_DRAW_SW_ASM LV_DRAW_SW_ASM_NONE
+
+ #if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_CUSTOM
+ #define LV_DRAW_SW_ASM_CUSTOM_INCLUDE ""
+ #endif
+
+ /** Enable drawing complex gradients in software: linear at an angle, radial or conical */
+ #define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 0
+
+#endif
+
+/*Use TSi's aka (Think Silicon) NemaGFX */
+#define LV_USE_NEMA_GFX 0
+
+#if LV_USE_NEMA_GFX
+ /** Select which NemaGFX static library headers to use. Possible options:
+ * - LV_NEMA_LIB_NONE an alias of LV_NEMA_LIB_M33_REVC
+ * - LV_NEMA_LIB_M33_REVC
+ * - LV_NEMA_LIB_M33_NEMAPVG
+ * - LV_NEMA_LIB_M55
+ * - LV_NEMA_LIB_M7
+ * You must also take care to link the correct corresponding static library
+ * in libs/nema_gfx/lib/core/
+ */
+ #define LV_USE_NEMA_LIB LV_NEMA_LIB_NONE
+
+ /** Select which NemaGFX HAL to use. Possible options:
+ * - LV_NEMA_HAL_CUSTOM
+ * - LV_NEMA_HAL_STM32 */
+ #define LV_USE_NEMA_HAL LV_NEMA_HAL_CUSTOM
+ #if LV_USE_NEMA_HAL == LV_NEMA_HAL_STM32
+ #define LV_NEMA_STM32_HAL_INCLUDE
+
+ /** Set it to a value like __attribute__((section("Nemagfx_Memory_Pool_Buffer")))
+ * and define the section in the linker script if you need the GPU memory to
+ * be, e.g. in a region where accesses will not be cached.
+ */
+ #define LV_NEMA_STM32_HAL_ATTRIBUTE_POOL_MEM
+ #endif
+
+ /*Enable Vector Graphics Operations. Available only if NemaVG library is present*/
+ #define LV_USE_NEMA_VG 0
+ #if LV_USE_NEMA_VG
+ /*Define application's resolution used for VG related buffer allocation */
+ #define LV_NEMA_GFX_MAX_RESX 800
+ #define LV_NEMA_GFX_MAX_RESY 600
+ #endif
+#endif
+
+/** Use NXP's PXP on iMX RTxxx platforms. */
+#define LV_USE_PXP 0
+
+#if LV_USE_PXP
+ /** Use PXP for drawing.*/
+ #define LV_USE_DRAW_PXP 1
+
+ /** Use PXP to rotate display.*/
+ #define LV_USE_ROTATE_PXP 0
+
+ #if LV_USE_DRAW_PXP && LV_USE_OS
+ /** Use additional draw thread for PXP processing.*/
+ #define LV_USE_PXP_DRAW_THREAD 1
+ #endif
+
+ /** Enable PXP asserts. */
+ #define LV_USE_PXP_ASSERT 0
+#endif
+
+/** Use NXP's G2D on MPU platforms. */
+#define LV_USE_G2D 0
+
+#if LV_USE_G2D
+ /** Use G2D for drawing. **/
+ #define LV_USE_DRAW_G2D 1
+
+ /** Use G2D to rotate display. **/
+ #define LV_USE_ROTATE_G2D 0
+
+ /** Maximum number of buffers that can be stored for G2D draw unit.
+ * Includes the frame buffers and assets. */
+ #define LV_G2D_HASH_TABLE_SIZE 50
+
+ #if LV_USE_DRAW_G2D && LV_USE_OS
+ /** Use additional draw thread for G2D processing.*/
+ #define LV_USE_G2D_DRAW_THREAD 1
+ #endif
+
+ /** Enable G2D asserts. */
+ #define LV_USE_G2D_ASSERT 0
+#endif
+
+/** Use Renesas Dave2D on RA platforms. */
+#define LV_USE_DRAW_DAVE2D 0
+
+/** Draw using cached SDL textures*/
+#define LV_USE_DRAW_SDL 0
+
+/** Use VG-Lite GPU. */
+#define LV_USE_DRAW_VG_LITE 0
+#if LV_USE_DRAW_VG_LITE
+ /** Enable VG-Lite custom external 'gpu_init()' function */
+ #define LV_VG_LITE_USE_GPU_INIT 0
+
+ /** Enable VG-Lite assert. */
+ #define LV_VG_LITE_USE_ASSERT 0
+
+ /** VG-Lite flush commit trigger threshold. GPU will try to batch these many draw tasks. */
+ #define LV_VG_LITE_FLUSH_MAX_COUNT 8
+
+ /** Enable border to simulate shadow.
+ * NOTE: which usually improves performance,
+ * but does not guarantee the same rendering quality as the software. */
+ #define LV_VG_LITE_USE_BOX_SHADOW 1
+
+ /** VG-Lite gradient maximum cache number.
+ * @note The memory usage of a single gradient image is 4K bytes. */
+ #define LV_VG_LITE_GRAD_CACHE_CNT 32
+
+ /** VG-Lite stroke maximum cache number. */
+ #define LV_VG_LITE_STROKE_CACHE_CNT 32
+
+ /** VG-Lite unaligned bitmap font maximum cache number. */
+ #define LV_VG_LITE_BITMAP_FONT_CACHE_CNT 256
+
+ /** Remove VLC_OP_CLOSE path instruction (Workaround for NXP) **/
+ #define LV_VG_LITE_DISABLE_VLC_OP_CLOSE 0
+
+ /** Disable blit rectangular offset to resolve certain hardware errors. */
+ #define LV_VG_LITE_DISABLE_BLIT_RECT_OFFSET 0
+
+ /** Disable linear gradient extension for some older versions of drivers. */
+ #define LV_VG_LITE_DISABLE_LINEAR_GRADIENT_EXT 0
+
+ /** Maximum path dump print length (in points) */
+ #define LV_VG_LITE_PATH_DUMP_MAX_LEN 1000
+
+ /** Enable usage of the LVGL's built-in vg_lite driver */
+ #define LV_USE_VG_LITE_DRIVER 0
+ #if LV_USE_VG_LITE_DRIVER
+ /** Used to pick the correct GPU series folder valid options are gc255, gc355 and gc555*/
+ #define LV_VG_LITE_HAL_GPU_SERIES gc255
+
+ /** Used to pick the correct GPU revision header it depends on the vendor */
+ #define LV_VG_LITE_HAL_GPU_REVISION 0x40
+
+ /** Base memory address of the GPU IP it depends on SoC,
+ * default value is for NXP based devices */
+ #define LV_VG_LITE_HAL_GPU_BASE_ADDRESS 0x40240000
+ #endif /*LV_USE_VG_LITE_DRIVER*/
+
+ /** Use ThorVG (a software vector library) as VG-Lite driver to allow testing VGLite on PC
+ * Requires: LV_USE_THORVG_INTERNAL or LV_USE_THORVG_EXTERNAL */
+ #define LV_USE_VG_LITE_THORVG 0
+ #if LV_USE_VG_LITE_THORVG
+ /** Enable LVGL's blend mode support */
+ #define LV_VG_LITE_THORVG_LVGL_BLEND_SUPPORT 0
+
+ /** Enable YUV color format support */
+ #define LV_VG_LITE_THORVG_YUV_SUPPORT 0
+
+ /** Enable Linear gradient extension support */
+ #define LV_VG_LITE_THORVG_LINEAR_GRADIENT_EXT_SUPPORT 0
+
+ /** Enable alignment on 16 pixels */
+ #define LV_VG_LITE_THORVG_16PIXELS_ALIGN 1
+
+ /** Buffer address alignment */
+ #define LV_VG_LITE_THORVG_BUF_ADDR_ALIGN 64
+
+ /** Enable multi-thread render */
+ #define LV_VG_LITE_THORVG_THREAD_RENDER 0
+ #endif /*LV_USE_VG_LITE_THORVG*/
+#endif
+
+/** Accelerate blends, fills, etc. with STM32 DMA2D */
+#define LV_USE_DRAW_DMA2D 0
+#if LV_USE_DRAW_DMA2D
+ #define LV_DRAW_DMA2D_HAL_INCLUDE "stm32h7xx_hal.h"
+
+ /* if enabled, the user is required to call `lv_draw_dma2d_transfer_complete_interrupt_handler`
+ * upon receiving the DMA2D global interrupt
+ */
+ #define LV_USE_DRAW_DMA2D_INTERRUPT 0
+#endif
+
+/** Draw using cached OpenGLES textures. Requires LV_USE_OPENGLES */
+#define LV_USE_DRAW_OPENGLES 0
+#if LV_USE_DRAW_OPENGLES
+ #define LV_DRAW_OPENGLES_TEXTURE_CACHE_COUNT 64
+#endif
+
+/** Draw using espressif PPA accelerator */
+#define LV_USE_PPA 0
+#if LV_USE_PPA
+ #define LV_USE_PPA_IMG 0
+ #define LV_PPA_BURST_LENGTH 128
+#endif
+
+/* Use EVE FT81X GPU. */
+#define LV_USE_DRAW_EVE 0
+#if LV_USE_DRAW_EVE
+ /* EVE_GEN value: 2, 3, or 4 */
+ #define LV_DRAW_EVE_EVE_GENERATION 4
+
+ /* The maximum number of bytes to buffer before a single SPI transmission.
+ * Set it to 0 to disable write buffering.
+ */
+ #define LV_DRAW_EVE_WRITE_BUFFER_SIZE 2048
+#endif
+
+/** Use NanoVG Renderer
+ * - Requires LV_USE_NANOVG, LV_USE_MATRIX.
+ */
+#define LV_USE_DRAW_NANOVG 0
+#if LV_USE_DRAW_NANOVG
+ /** Select OpenGL backend for NanoVG:
+ * - LV_NANOVG_BACKEND_GL2: OpenGL 2.0
+ * - LV_NANOVG_BACKEND_GL3: OpenGL 3.0+
+ * - LV_NANOVG_BACKEND_GLES2: OpenGL ES 2.0
+ * - LV_NANOVG_BACKEND_GLES3: OpenGL ES 3.0+
+ */
+ #define LV_NANOVG_BACKEND LV_NANOVG_BACKEND_GLES2
+
+ /** Draw image texture cache count. */
+ #define LV_NANOVG_IMAGE_CACHE_CNT 128
+
+ /** Draw letter texture cache count. */
+ #define LV_NANOVG_LETTER_CACHE_CNT 512
+#endif
+
+/*=======================
+ * FEATURE CONFIGURATION
+ *=======================*/
+
+/*-------------
+ * Logging
+ *-----------*/
+
+/** Enable log module */
+#define LV_USE_LOG 0
+#if LV_USE_LOG
+ /** Set value to one of the following levels of logging detail:
+ * - LV_LOG_LEVEL_TRACE Log detailed information.
+ * - LV_LOG_LEVEL_INFO Log important events.
+ * - LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem.
+ * - LV_LOG_LEVEL_ERROR Log only critical issues, when system may fail.
+ * - LV_LOG_LEVEL_USER Log only custom log messages added by the user.
+ * - LV_LOG_LEVEL_NONE Do not log anything. */
+ #define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
+
+ /** - 1: Print log with 'printf';
+ * - 0: User needs to register a callback with `lv_log_register_print_cb()`. */
+ #define LV_LOG_PRINTF 0
+
+ /** Set callback to print logs.
+ * E.g `my_print`. The prototype should be `void my_print(lv_log_level_t level, const char * buf)`.
+ * Can be overwritten by `lv_log_register_print_cb`. */
+ //#define LV_LOG_PRINT_CB
+
+ /** - 1: Enable printing timestamp;
+ * - 0: Disable printing timestamp. */
+ #define LV_LOG_USE_TIMESTAMP 1
+
+ /** - 1: Print file and line number of the log;
+ * - 0: Do not print file and line number of the log. */
+ #define LV_LOG_USE_FILE_LINE 1
+
+ /* Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs. */
+ #define LV_LOG_TRACE_MEM 1 /**< Enable/disable trace logs in memory operations. */
+ #define LV_LOG_TRACE_TIMER 1 /**< Enable/disable trace logs in timer operations. */
+ #define LV_LOG_TRACE_INDEV 1 /**< Enable/disable trace logs in input device operations. */
+ #define LV_LOG_TRACE_DISP_REFR 1 /**< Enable/disable trace logs in display re-draw operations. */
+ #define LV_LOG_TRACE_EVENT 1 /**< Enable/disable trace logs in event dispatch logic. */
+ #define LV_LOG_TRACE_OBJ_CREATE 1 /**< Enable/disable trace logs in object creation (core `obj` creation plus every widget). */
+ #define LV_LOG_TRACE_LAYOUT 1 /**< Enable/disable trace logs in flex- and grid-layout operations. */
+ #define LV_LOG_TRACE_ANIM 1 /**< Enable/disable trace logs in animation logic. */
+ #define LV_LOG_TRACE_CACHE 1 /**< Enable/disable trace logs in cache operations. */
+#endif /*LV_USE_LOG*/
+
+/*-------------
+ * Asserts
+ *-----------*/
+
+/* Enable assertion failures if an operation fails or invalid data is found.
+ * If LV_USE_LOG is enabled, an error message will be printed on failure. */
+#define LV_USE_ASSERT_NULL 1 /**< Check if the parameter is NULL. (Very fast, recommended) */
+#define LV_USE_ASSERT_MALLOC 1 /**< Checks is the memory is successfully allocated or no. (Very fast, recommended) */
+#define LV_USE_ASSERT_STYLE 0 /**< Check if the styles are properly initialized. (Very fast, recommended) */
+#define LV_USE_ASSERT_MEM_INTEGRITY 0 /**< Check the integrity of `lv_mem` after critical operations. (Slow) */
+#define LV_USE_ASSERT_OBJ 0 /**< Check the object's type and existence (e.g. not deleted). (Slow) */
+
+/** Add a custom handler when assert happens e.g. to restart MCU. */
+#define LV_ASSERT_HANDLER_INCLUDE
+#define LV_ASSERT_HANDLER while(1); /**< Halt by default */
+
+/*-------------
+ * Debug
+ *-----------*/
+
+/** 1: Draw random colored rectangles over the redrawn areas. */
+#define LV_USE_REFR_DEBUG 0
+
+/** 1: Draw a red overlay for ARGB layers and a green overlay for RGB layers*/
+#define LV_USE_LAYER_DEBUG 0
+
+/** 1: Adds the following behaviors for debugging:
+ * - Draw overlays with different colors for each draw_unit's tasks.
+ * - Draw index number of draw unit on white background.
+ * - For layers, draws index number of draw unit on black background. */
+#define LV_USE_PARALLEL_DRAW_DEBUG 0
+
+/*-------------
+ * Others
+ *-----------*/
+
+#define LV_ENABLE_GLOBAL_CUSTOM 0
+#if LV_ENABLE_GLOBAL_CUSTOM
+ /** Header to include for custom 'lv_global' function" */
+ #define LV_GLOBAL_CUSTOM_INCLUDE
+#endif
+
+/** Default cache size in bytes.
+ * Used by image decoders such as `lv_lodepng` to keep the decoded image in memory.
+ * If size is not set to 0, the decoder will fail to decode when the cache is full.
+ * If size is 0, the cache function is not enabled and the decoded memory will be
+ * released immediately after use. */
+#define LV_CACHE_DEF_SIZE 0
+
+/** Default number of image header cache entries. The cache is used to store the headers of images
+ * The main logic is like `LV_CACHE_DEF_SIZE` but for image headers. */
+#define LV_IMAGE_HEADER_CACHE_DEF_CNT 0
+
+/** Number of stops allowed per gradient. Increase this to allow more stops.
+ * This adds (sizeof(lv_color_t) + 1) bytes per additional stop. */
+#define LV_GRADIENT_MAX_STOPS 2
+
+/** Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently.
+ * - 0: round down,
+ * - 64: round up from x.75,
+ * - 128: round up from half,
+ * - 192: round up from x.25,
+ * - 254: round up */
+#define LV_COLOR_MIX_ROUND_OFS 0
+
+/** Add 2 x 32-bit variables to each `lv_obj_t` to speed up getting style properties */
+#define LV_OBJ_STYLE_CACHE 0
+
+/** Add `id` field to `lv_obj_t` */
+#define LV_USE_OBJ_ID 0
+
+/** Enable support widget names*/
+#define LV_USE_OBJ_NAME 0
+
+/** Automatically assign an ID when obj is created */
+#define LV_OBJ_ID_AUTO_ASSIGN LV_USE_OBJ_ID
+
+/** Use builtin obj ID handler functions:
+* - lv_obj_assign_id: Called when a widget is created. Use a separate counter for each widget class as an ID.
+* - lv_obj_id_compare: Compare the ID to decide if it matches with a requested value.
+* - lv_obj_stringify_id: Return string-ified identifier, e.g. "button3".
+* - lv_obj_free_id: Does nothing, as there is no memory allocation for the ID.
+* When disabled these functions needs to be implemented by the user.*/
+#define LV_USE_OBJ_ID_BUILTIN 1
+
+/** Use obj property set/get API. */
+#define LV_USE_OBJ_PROPERTY 0
+
+/** Enable property name support. */
+#define LV_USE_OBJ_PROPERTY_NAME 1
+
+/* Enable the multi-touch gesture recognition feature */
+/* Gesture recognition requires the use of floats */
+#define LV_USE_GESTURE_RECOGNITION 0
+
+/*=====================
+ * COMPILER SETTINGS
+ *====================*/
+
+/** For big endian systems set to 1 */
+#define LV_BIG_ENDIAN_SYSTEM 0
+
+/** Define a custom attribute for `lv_tick_inc` function */
+#define LV_ATTRIBUTE_TICK_INC
+
+/** Define a custom attribute for `lv_timer_handler` function */
+#define LV_ATTRIBUTE_TIMER_HANDLER
+
+/** Define a custom attribute for `lv_display_flush_ready` function */
+#define LV_ATTRIBUTE_FLUSH_READY
+
+/** Align VG_LITE buffers on this number of bytes.
+ * @note vglite_src_buf_aligned() uses this value to validate alignment of passed buffer pointers. */
+#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1
+
+/** Will be added where memory needs to be aligned (with -Os data might not be aligned to boundary by default).
+ * E.g. __attribute__((aligned(4)))*/
+#define LV_ATTRIBUTE_MEM_ALIGN
+
+/** Attribute to mark large constant arrays, for example for font bitmaps */
+#define LV_ATTRIBUTE_LARGE_CONST
+
+/** Compiler prefix for a large array declaration in RAM */
+#define LV_ATTRIBUTE_LARGE_RAM_ARRAY
+
+/** Place performance critical functions into a faster memory (e.g RAM) */
+#define LV_ATTRIBUTE_FAST_MEM
+
+/** Export integer constant to binding. This macro is used with constants in the form of LV_ that
+ * should also appear on LVGL binding API such as MicroPython. */
+#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /**< The default value just prevents GCC warning */
+
+/** Prefix all global extern data with this */
+#define LV_ATTRIBUTE_EXTERN_DATA
+
+/** Use `float` as `lv_value_precise_t` */
+#define LV_USE_FLOAT 0
+
+/** Enable matrix support
+ * - Requires `LV_USE_FLOAT = 1` */
+#define LV_USE_MATRIX 0
+
+/** Include `lvgl_private.h` in `lvgl.h` to access internal data and functions by default */
+#ifndef LV_USE_PRIVATE_API
+ #define LV_USE_PRIVATE_API 1
+#endif
+
+/*==================
+ * FONT USAGE
+ *===================*/
+
+/* Montserrat fonts with ASCII range and some symbols using bpp = 4
+ * https://fonts.google.com/specimen/Montserrat */
+#define LV_FONT_MONTSERRAT_8 0
+#define LV_FONT_MONTSERRAT_10 0
+#define LV_FONT_MONTSERRAT_12 0
+#define LV_FONT_MONTSERRAT_14 1
+#define LV_FONT_MONTSERRAT_16 1
+#define LV_FONT_MONTSERRAT_18 1
+#define LV_FONT_MONTSERRAT_20 1
+#define LV_FONT_MONTSERRAT_22 1
+#define LV_FONT_MONTSERRAT_24 1
+#define LV_FONT_MONTSERRAT_26 0
+#define LV_FONT_MONTSERRAT_28 0
+#define LV_FONT_MONTSERRAT_30 0
+#define LV_FONT_MONTSERRAT_32 0
+#define LV_FONT_MONTSERRAT_34 0
+#define LV_FONT_MONTSERRAT_36 0
+#define LV_FONT_MONTSERRAT_38 0
+#define LV_FONT_MONTSERRAT_40 0
+#define LV_FONT_MONTSERRAT_42 0
+#define LV_FONT_MONTSERRAT_44 0
+#define LV_FONT_MONTSERRAT_46 0
+#define LV_FONT_MONTSERRAT_48 0
+
+/* Demonstrate special features */
+#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /**< bpp = 3 */
+#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /**< Hebrew, Arabic, Persian letters and all their forms */
+#define LV_FONT_SOURCE_HAN_SANS_SC_14_CJK 0 /**< 1338 most common CJK radicals */
+#define LV_FONT_SOURCE_HAN_SANS_SC_16_CJK 0 /**< 1338 most common CJK radicals */
+
+/** Pixel perfect monospaced fonts */
+#define LV_FONT_UNSCII_8 0
+#define LV_FONT_UNSCII_16 0
+
+/** Optionally declare custom fonts here.
+ *
+ * You can use any of these fonts as the default font too and they will be available
+ * globally. Example:
+ *
+ * @code
+ * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)
+ * @endcode
+ */
+#define LV_FONT_CUSTOM_DECLARE
+
+/** Always set a default font */
+#define LV_FONT_DEFAULT &lv_font_montserrat_14
+
+/** Enable handling large font and/or fonts with a lot of characters.
+ * The limit depends on the font size, font face and bpp.
+ * A compiler error will be triggered if a font needs it. */
+#define LV_FONT_FMT_TXT_LARGE 0
+
+/** Enables/disables support for compressed fonts. */
+#define LV_USE_FONT_COMPRESSED 0
+
+/** Enable drawing placeholders when glyph dsc is not found. */
+#define LV_USE_FONT_PLACEHOLDER 1
+
+/*=================
+ * TEXT SETTINGS
+ *=================*/
+
+/**
+ * Select a character encoding for strings.
+ * Your IDE or editor should have the same character encoding.
+ * - LV_TXT_ENC_UTF8
+ * - LV_TXT_ENC_ASCII
+ */
+#define LV_TXT_ENC LV_TXT_ENC_UTF8
+
+/** While rendering text strings, break (wrap) text on these chars. */
+#define LV_TXT_BREAK_CHARS " ,.;:-_)]}"
+
+/** If a word is at least this long, will break wherever "prettiest".
+ * To disable, set to a value <= 0. */
+#define LV_TXT_LINE_BREAK_LONG_LEN 0
+
+/** Minimum number of characters in a long word to put on a line before a break.
+ * Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
+#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
+
+/** Minimum number of characters in a long word to put on a line after a break.
+ * Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
+#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
+
+/** Support bidirectional text. Allows mixing Left-to-Right and Right-to-Left text.
+ * The direction will be processed according to the Unicode Bidirectional Algorithm:
+ * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics */
+#define LV_USE_BIDI 0
+#if LV_USE_BIDI
+ /*Set the default direction. Supported values:
+ *`LV_BASE_DIR_LTR` Left-to-Right
+ *`LV_BASE_DIR_RTL` Right-to-Left
+ *`LV_BASE_DIR_AUTO` detect text base direction*/
+ #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO
+#endif
+
+/** Enable Arabic/Persian processing
+ * In these languages characters should be replaced with another form based on their position in the text */
+#define LV_USE_ARABIC_PERSIAN_CHARS 0
+
+/*The control character to use for signaling text recoloring*/
+#define LV_TXT_COLOR_CMD "#"
+
+/*==================
+ * WIDGETS
+ *================*/
+/* Documentation for widgets can be found here: https://docs.lvgl.io/master/widgets/index.html . */
+
+/** 1: Causes these widgets to be given default values at creation time.
+ * - lv_buttonmatrix_t: Get default maps: {"Btn1", "Btn2", "Btn3", "\n", "Btn4", "Btn5", ""}, else map not set.
+ * - lv_checkbox_t : String label set to "Check box", else set to empty string.
+ * - lv_dropdown_t : Options set to "Option 1", "Option 2", "Option 3", else no values are set.
+ * - lv_roller_t : Options set to "Option 1", "Option 2", "Option 3", "Option 4", "Option 5", else no values are set.
+ * - lv_label_t : Text set to "Text", else empty string.
+ * - lv_arclabel_t : Text set to "Arced Text", else empty string.
+ * */
+#define LV_WIDGETS_HAS_DEFAULT_VALUE 1
+
+#define LV_USE_ANIMIMG 1
+
+#define LV_USE_ARC 1
+
+#define LV_USE_ARCLABEL 1
+
+#define LV_USE_BAR 1
+
+#define LV_USE_BUTTON 1
+
+#define LV_USE_BUTTONMATRIX 1
+
+#define LV_USE_CALENDAR 1
+#if LV_USE_CALENDAR
+ #define LV_CALENDAR_WEEK_STARTS_MONDAY 0
+ #if LV_CALENDAR_WEEK_STARTS_MONDAY
+ #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}
+ #else
+ #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}
+ #endif
+
+ #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
+ #define LV_USE_CALENDAR_HEADER_ARROW 1
+ #define LV_USE_CALENDAR_HEADER_DROPDOWN 1
+ #define LV_USE_CALENDAR_CHINESE 0
+#endif /*LV_USE_CALENDAR*/
+
+#define LV_USE_CANVAS 1
+
+#define LV_USE_CHART 1
+
+#define LV_USE_CHECKBOX 1
+
+#define LV_USE_DROPDOWN 1 /**< Requires: lv_label */
+
+#define LV_USE_IMAGE 1 /**< Requires: lv_label */
+
+#define LV_USE_IMAGEBUTTON 1
+
+#define LV_USE_KEYBOARD 1
+
+#define LV_USE_LABEL 1
+#if LV_USE_LABEL
+ #define LV_LABEL_TEXT_SELECTION 1 /**< Enable selecting text of the label */
+ #define LV_LABEL_LONG_TXT_HINT 1 /**< Store some extra info in labels to speed up drawing of very long text */
+ #define LV_LABEL_WAIT_CHAR_COUNT 3 /**< The count of wait chart */
+#endif
+
+#define LV_USE_LED 1
+
+#define LV_USE_LINE 1
+
+#define LV_USE_LIST 1
+
+#define LV_USE_LOTTIE 0 /**< Requires: lv_canvas, thorvg */
+
+#define LV_USE_MENU 1
+
+#define LV_USE_MSGBOX 1
+
+#define LV_USE_ROLLER 1 /**< Requires: lv_label */
+
+#define LV_USE_SCALE 1
+
+#define LV_USE_SLIDER 1 /**< Requires: lv_bar */
+
+#define LV_USE_SPAN 1
+#if LV_USE_SPAN
+ /** A line of text can contain this maximum number of span descriptors. */
+ #define LV_SPAN_SNIPPET_STACK_SIZE 64
+#endif
+
+#define LV_USE_SPINBOX 1
+
+#define LV_USE_SPINNER 1
+
+#define LV_USE_SWITCH 1
+
+#define LV_USE_TABLE 1
+
+#define LV_USE_TABVIEW 1
+
+#define LV_USE_TEXTAREA 1 /**< Requires: lv_label */
+#if LV_USE_TEXTAREA != 0
+ #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /**< [ms] */
+#endif
+
+#define LV_USE_TILEVIEW 1
+
+#define LV_USE_WIN 1
+
+#define LV_USE_3DTEXTURE 0
+
+/*==================
+ * THEMES
+ *==================*/
+/* Documentation for themes can be found here: https://docs.lvgl.io/master/common-widget-features/styles/styles.html#themes . */
+
+/** A simple, impressive and very complete theme */
+#define LV_USE_THEME_DEFAULT 1
+#if LV_USE_THEME_DEFAULT
+ /** 0: Light mode; 1: Dark mode */
+ #define LV_THEME_DEFAULT_DARK 0
+
+ /** 1: Enable grow on press */
+ #define LV_THEME_DEFAULT_GROW 1
+
+ /** Default transition time in ms. */
+ #define LV_THEME_DEFAULT_TRANSITION_TIME 80
+#endif /*LV_USE_THEME_DEFAULT*/
+
+/** A very simple theme that is a good starting point for a custom theme */
+#define LV_USE_THEME_SIMPLE 1
+
+/** A theme designed for monochrome displays */
+#define LV_USE_THEME_MONO 1
+
+/*==================
+ * LAYOUTS
+ *==================*/
+/* Documentation for layouts can be found here: https://docs.lvgl.io/master/common-widget-features/layouts/index.html . */
+
+/** A layout similar to Flexbox in CSS. */
+#define LV_USE_FLEX 1
+
+/** A layout similar to Grid in CSS. */
+#define LV_USE_GRID 1
+
+/*====================
+ * 3RD PARTS LIBRARIES
+ *====================*/
+/* Documentation for libraries can be found here: https://docs.lvgl.io/master/libs/index.html . */
+
+/* File system interfaces for common APIs */
+
+/** Setting a default driver letter allows skipping the driver prefix in filepaths.
+ * Documentation about how to use the below driver-identifier letters can be found at
+ * https://docs.lvgl.io/master/main-modules/fs.html#lv-fs-identifier-letters . */
+#define LV_FS_DEFAULT_DRIVER_LETTER '\0'
+
+/** API for fopen, fread, etc. */
+#define LV_USE_FS_STDIO 0
+#if LV_USE_FS_STDIO
+ #define LV_FS_STDIO_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+ #define LV_FS_STDIO_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
+ #define LV_FS_STDIO_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */
+#endif
+
+/** API for open, read, etc. */
+#define LV_USE_FS_POSIX 0
+#if LV_USE_FS_POSIX
+ #define LV_FS_POSIX_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+ #define LV_FS_POSIX_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
+ #define LV_FS_POSIX_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */
+#endif
+
+/** API for CreateFile, ReadFile, etc. */
+#define LV_USE_FS_WIN32 0
+#if LV_USE_FS_WIN32
+ #define LV_FS_WIN32_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+ #define LV_FS_WIN32_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
+ #define LV_FS_WIN32_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */
+#endif
+
+/** API for FATFS (needs to be added separately). Uses f_open, f_read, etc. */
+#define LV_USE_FS_FATFS 0
+#if LV_USE_FS_FATFS
+ #define LV_FS_FATFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+ #define LV_FS_FATFS_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
+ #define LV_FS_FATFS_CACHE_SIZE 0 /**< >0 to cache this number of bytes in lv_fs_read() */
+#endif
+
+/** API for memory-mapped file access. */
+#define LV_USE_FS_MEMFS 0
+#if LV_USE_FS_MEMFS
+ #define LV_FS_MEMFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+#endif
+
+/** API for LittleFs. */
+#define LV_USE_FS_LITTLEFS 0
+#if LV_USE_FS_LITTLEFS
+ #define LV_FS_LITTLEFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+ #define LV_FS_LITTLEFS_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
+#endif
+
+/** API for Arduino LittleFs. */
+#define LV_USE_FS_ARDUINO_ESP_LITTLEFS 0
+#if LV_USE_FS_ARDUINO_ESP_LITTLEFS
+ #define LV_FS_ARDUINO_ESP_LITTLEFS_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+ #define LV_FS_ARDUINO_ESP_LITTLEFS_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
+#endif
+
+/** API for Arduino Sd. */
+#define LV_USE_FS_ARDUINO_SD 0
+#if LV_USE_FS_ARDUINO_SD
+ #define LV_FS_ARDUINO_SD_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+ #define LV_FS_ARDUINO_SD_PATH "" /**< Set the working directory. File/directory paths will be appended to it. */
+#endif
+
+/** API for UEFI */
+#define LV_USE_FS_UEFI 0
+#if LV_USE_FS_UEFI
+ #define LV_FS_UEFI_LETTER '\0' /**< Set an upper-case driver-identifier letter for this driver (e.g. 'A'). */
+#endif
+
+#define LV_USE_FS_FROGFS 0
+#if LV_USE_FS_FROGFS
+ #define LV_FS_FROGFS_LETTER '\0'
+#endif
+
+/** LODEPNG decoder library */
+#define LV_USE_LODEPNG 0
+
+/** PNG decoder(libpng) library */
+#define LV_USE_LIBPNG 0
+
+/** BMP decoder library */
+#define LV_USE_BMP 0
+
+/** JPG + split JPG decoder library.
+ * Split JPG is a custom format optimized for embedded systems. */
+#define LV_USE_TJPGD 0
+
+/** libjpeg-turbo decoder library.
+ * - Supports complete JPEG specifications and high-performance JPEG decoding. */
+#define LV_USE_LIBJPEG_TURBO 0
+
+/** WebP decoder library */
+#define LV_USE_LIBWEBP 0
+
+/** GIF decoder library */
+#define LV_USE_GIF 0
+#if LV_USE_GIF
+ /** GIF decoder accelerate */
+ #define LV_GIF_CACHE_DECODE_DATA 0
+#endif
+
+/** GStreamer library */
+#define LV_USE_GSTREAMER 0
+
+/** Decode bin images to RAM */
+#define LV_BIN_DECODER_RAM_LOAD 0
+
+/** RLE decompress library */
+#define LV_USE_RLE 0
+
+/** QR code library */
+#define LV_USE_QRCODE 0
+
+/** Barcode code library */
+#define LV_USE_BARCODE 0
+
+/** FreeType library */
+#define LV_USE_FREETYPE 0
+#if LV_USE_FREETYPE
+ /** Let FreeType use LVGL memory and file porting */
+ #define LV_FREETYPE_USE_LVGL_PORT 0
+
+ /** Cache count of glyphs in FreeType, i.e. number of glyphs that can be cached.
+ * The higher the value, the more memory will be used. */
+ #define LV_FREETYPE_CACHE_FT_GLYPH_CNT 256
+#endif
+
+/** Built-in TTF decoder */
+#define LV_USE_TINY_TTF 0
+#if LV_USE_TINY_TTF
+ /* Enable loading TTF data from files */
+ #define LV_TINY_TTF_FILE_SUPPORT 0
+ #define LV_TINY_TTF_CACHE_GLYPH_CNT 128
+ #define LV_TINY_TTF_CACHE_KERNING_CNT 256
+#endif
+
+/** Rlottie library */
+#define LV_USE_RLOTTIE 0
+
+/** Requires `LV_USE_3DTEXTURE = 1` */
+#define LV_USE_GLTF 0
+
+/** Enable Vector Graphic APIs
+ * Requires `LV_USE_MATRIX = 1`
+ * and a rendering engine supporting vector graphics, e.g.
+ * (LV_USE_DRAW_SW and LV_USE_THORVG) or LV_USE_DRAW_VG_LITE or LV_USE_NEMA_VG. */
+#define LV_USE_VECTOR_GRAPHIC 0
+
+/** Enable ThorVG (vector graphics library) from the src/libs folder.
+ * Requires LV_USE_VECTOR_GRAPHIC */
+#define LV_USE_THORVG_INTERNAL 0
+
+/** Enable ThorVG by assuming that its installed and linked to the project
+ * Requires LV_USE_VECTOR_GRAPHIC */
+#define LV_USE_THORVG_EXTERNAL 0
+
+/** Enable NanoVG (vector graphics library) */
+#define LV_USE_NANOVG 0
+
+/** Use lvgl built-in LZ4 lib */
+#define LV_USE_LZ4_INTERNAL 0
+
+/** Use external LZ4 library */
+#define LV_USE_LZ4_EXTERNAL 0
+
+/*SVG library
+ * - Requires `LV_USE_VECTOR_GRAPHIC = 1` */
+#define LV_USE_SVG 0
+#define LV_USE_SVG_ANIMATION 0
+#define LV_USE_SVG_DEBUG 0
+
+/** FFmpeg library for image decoding and playing videos.
+ * Supports all major image formats so do not enable other image decoder with it. */
+#define LV_USE_FFMPEG 0
+#if LV_USE_FFMPEG
+ /** Dump input information to stderr */
+ #define LV_FFMPEG_DUMP_FORMAT 0
+ /** Use lvgl file path in FFmpeg Player widget
+ * You won't be able to open URLs after enabling this feature.
+ * Note that FFmpeg image decoder will always use lvgl file system. */
+ #define LV_FFMPEG_PLAYER_USE_LV_FS 0
+#endif
+
+/*==================
+ * OTHERS
+ *==================*/
+/* Documentation for several of the below items can be found here: https://docs.lvgl.io/master/auxiliary-modules/index.html . */
+
+/** 1: Enable API to take snapshot for object */
+#define LV_USE_SNAPSHOT 0
+
+/** 1: Enable system monitor component */
+#define LV_USE_SYSMON 0
+#if LV_USE_SYSMON
+ /** Get the idle percentage. E.g. uint32_t my_get_idle(void); */
+ #define LV_SYSMON_GET_IDLE lv_os_get_idle_percent
+ /** 1: Enable usage of lv_os_get_proc_idle_percent.*/
+ #define LV_SYSMON_PROC_IDLE_AVAILABLE 0
+ #if LV_SYSMON_PROC_IDLE_AVAILABLE
+ /** Get the applications idle percentage.
+ * - Requires `LV_USE_OS == LV_OS_PTHREAD` */
+ #define LV_SYSMON_GET_PROC_IDLE lv_os_get_proc_idle_percent
+ #endif
+
+ /** 1: Show CPU usage and FPS count.
+ * - Requires `LV_USE_SYSMON = 1` */
+ #define LV_USE_PERF_MONITOR 1
+ #if LV_USE_PERF_MONITOR
+ #define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT
+
+ /** 0: Displays performance data on the screen; 1: Prints performance data using log. */
+ #define LV_USE_PERF_MONITOR_LOG_MODE 0
+ #endif
+
+ /** 1: Show used memory and memory fragmentation.
+ * - Requires `LV_USE_STDLIB_MALLOC = LV_STDLIB_BUILTIN`
+ * - Requires `LV_USE_SYSMON = 1`*/
+ #define LV_USE_MEM_MONITOR 1
+ #if LV_USE_MEM_MONITOR
+ #define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT
+ #endif
+#endif /*LV_USE_SYSMON*/
+
+/** 1: Enable runtime performance profiler */
+#define LV_USE_PROFILER 0
+#if LV_USE_PROFILER
+ /** 1: Enable the built-in profiler */
+ #define LV_USE_PROFILER_BUILTIN 1
+ #if LV_USE_PROFILER_BUILTIN
+ /** Default profiler trace buffer size */
+ #define LV_PROFILER_BUILTIN_BUF_SIZE (16 * 1024) /**< [bytes] */
+ #define LV_PROFILER_BUILTIN_DEFAULT_ENABLE 1
+ #define LV_USE_PROFILER_BUILTIN_POSIX 0 /**< Enable POSIX profiler port */
+ #endif
+
+ /** Header to include for profiler */
+ #define LV_PROFILER_INCLUDE "lvgl/src/misc/lv_profiler_builtin.h"
+
+ /** Profiler start point function */
+ #define LV_PROFILER_BEGIN LV_PROFILER_BUILTIN_BEGIN
+
+ /** Profiler end point function */
+ #define LV_PROFILER_END LV_PROFILER_BUILTIN_END
+
+ /** Profiler start point function with custom tag */
+ #define LV_PROFILER_BEGIN_TAG LV_PROFILER_BUILTIN_BEGIN_TAG
+
+ /** Profiler end point function with custom tag */
+ #define LV_PROFILER_END_TAG LV_PROFILER_BUILTIN_END_TAG
+
+ /*Enable layout profiler*/
+ #define LV_PROFILER_LAYOUT 1
+
+ /*Enable disp refr profiler*/
+ #define LV_PROFILER_REFR 1
+
+ /*Enable draw profiler*/
+ #define LV_PROFILER_DRAW 1
+
+ /*Enable indev profiler*/
+ #define LV_PROFILER_INDEV 1
+
+ /*Enable decoder profiler*/
+ #define LV_PROFILER_DECODER 1
+
+ /*Enable font profiler*/
+ #define LV_PROFILER_FONT 1
+
+ /*Enable fs profiler*/
+ #define LV_PROFILER_FS 1
+
+ /*Enable style profiler*/
+ #define LV_PROFILER_STYLE 0
+
+ /*Enable timer profiler*/
+ #define LV_PROFILER_TIMER 1
+
+ /*Enable cache profiler*/
+ #define LV_PROFILER_CACHE 1
+
+ /*Enable event profiler*/
+ #define LV_PROFILER_EVENT 1
+#endif
+
+/** 1: Enable Monkey test */
+#define LV_USE_MONKEY 0
+
+/** 1: Enable grid navigation */
+#define LV_USE_GRIDNAV 0
+
+/** 1: Enable `lv_obj` fragment logic */
+#define LV_USE_FRAGMENT 0
+
+/** 1: Support using images as font in label or span widgets */
+#define LV_USE_IMGFONT 0
+
+/** 1: Enable an observer pattern implementation */
+#define LV_USE_OBSERVER 1
+
+/** 1: Enable Pinyin input method
+ * - Requires: lv_keyboard */
+#define LV_USE_IME_PINYIN 0
+#if LV_USE_IME_PINYIN
+ /** 1: Use default thesaurus.
+ * @note If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesaurus. */
+ #define LV_IME_PINYIN_USE_DEFAULT_DICT 1
+ /** Set maximum number of candidate panels that can be displayed.
+ * @note This needs to be adjusted according to size of screen. */
+ #define LV_IME_PINYIN_CAND_TEXT_NUM 6
+
+ /** Use 9-key input (k9). */
+ #define LV_IME_PINYIN_USE_K9_MODE 1
+ #if LV_IME_PINYIN_USE_K9_MODE == 1
+ #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3
+ #endif /*LV_IME_PINYIN_USE_K9_MODE*/
+#endif
+
+/** 1: Enable file explorer.
+ * - Requires: lv_table */
+#define LV_USE_FILE_EXPLORER 0
+#if LV_USE_FILE_EXPLORER
+ /** Maximum length of path */
+ #define LV_FILE_EXPLORER_PATH_MAX_LEN (128)
+ /** Quick access bar, 1:use, 0:do not use.
+ * - Requires: lv_list */
+ #define LV_FILE_EXPLORER_QUICK_ACCESS 1
+#endif
+
+/** 1: Enable Font manager */
+#define LV_USE_FONT_MANAGER 0
+#if LV_USE_FONT_MANAGER
+
+/**Font manager name max length*/
+#define LV_FONT_MANAGER_NAME_MAX_LEN 32
+
+#endif
+
+/** Enable emulated input devices, time emulation, and screenshot compares. */
+#define LV_USE_TEST 0
+#if LV_USE_TEST
+
+/** Enable `lv_test_screenshot_compare`.
+ * Requires lodepng and a few MB of extra RAM. */
+#define LV_USE_TEST_SCREENSHOT_COMPARE 0
+
+#if LV_USE_TEST_SCREENSHOT_COMPARE
+ /** 1: Automatically create missing reference images*/
+ #define LV_TEST_SCREENSHOT_CREATE_REFERENCE_IMAGE 1
+#endif /*LV_USE_TEST_SCREENSHOT_COMPARE*/
+
+#endif /*LV_USE_TEST*/
+
+/** 1: Enable text translation support */
+#define LV_USE_TRANSLATION 0
+
+/*1: Enable color filter style*/
+#define LV_USE_COLOR_FILTER 0
+
+/*==================
+ * DEVICES
+ *==================*/
+
+/** Use SDL to open window on PC and handle mouse and keyboard. */
+#define LV_USE_SDL 0
+#if LV_USE_SDL
+ #define LV_SDL_INCLUDE_PATH
+ #define LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT /**< LV_DISPLAY_RENDER_MODE_DIRECT is recommended for best performance */
+ #define LV_SDL_BUF_COUNT 1 /**< 1 or 2 */
+ #define LV_SDL_ACCELERATED 1 /**< 1: Use hardware acceleration*/
+ #define LV_SDL_FULLSCREEN 0 /**< 1: Make the window full screen by default */
+ #define LV_SDL_DIRECT_EXIT 1 /**< 1: Exit the application when all SDL windows are closed */
+ #define LV_SDL_MOUSEWHEEL_MODE LV_SDL_MOUSEWHEEL_MODE_ENCODER /*LV_SDL_MOUSEWHEEL_MODE_ENCODER/CROWN*/
+#endif
+
+/** Use X11 to open window on Linux desktop and handle mouse and keyboard */
+#define LV_USE_X11 0
+#if LV_USE_X11
+ #define LV_X11_DIRECT_EXIT 1 /**< Exit application when all X11 windows have been closed */
+ #define LV_X11_DOUBLE_BUFFER 1 /**< Use double buffers for rendering */
+ /* Select only 1 of the following render modes (LV_X11_RENDER_MODE_PARTIAL preferred!). */
+ #define LV_X11_RENDER_MODE_PARTIAL 1 /**< Partial render mode (preferred) */
+ #define LV_X11_RENDER_MODE_DIRECT 0 /**< Direct render mode */
+ #define LV_X11_RENDER_MODE_FULL 0 /**< Full render mode */
+#endif
+
+/** Use Wayland to open a window and handle input on Linux or BSD desktops */
+#define LV_USE_WAYLAND 0
+#if LV_USE_WAYLAND
+ #define LV_WAYLAND_DIRECT_EXIT 1 /**< 1: Exit the application when all Wayland windows are closed */
+#endif
+
+/** Driver for /dev/fb */
+#define LV_USE_LINUX_FBDEV 0
+#if LV_USE_LINUX_FBDEV
+ #define LV_LINUX_FBDEV_BSD 0
+ #define LV_LINUX_FBDEV_RENDER_MODE LV_DISPLAY_RENDER_MODE_PARTIAL
+ #define LV_LINUX_FBDEV_BUFFER_COUNT 0
+ #define LV_LINUX_FBDEV_BUFFER_SIZE 60
+ #define LV_LINUX_FBDEV_MMAP 1
+#endif
+
+/** Use Nuttx to open window and handle touchscreen */
+#define LV_USE_NUTTX 0
+
+#if LV_USE_NUTTX
+ #define LV_USE_NUTTX_INDEPENDENT_IMAGE_HEAP 0
+
+ /** Use independent image heap for default draw buffer */
+ #define LV_NUTTX_DEFAULT_DRAW_BUF_USE_INDEPENDENT_IMAGE_HEAP 0
+
+ #define LV_USE_NUTTX_LIBUV 0
+
+ /** Use Nuttx custom init API to open window and handle touchscreen */
+ #define LV_USE_NUTTX_CUSTOM_INIT 0
+
+ /** Driver for /dev/lcd */
+ #define LV_USE_NUTTX_LCD 0
+ #if LV_USE_NUTTX_LCD
+ #define LV_NUTTX_LCD_BUFFER_COUNT 0
+ #define LV_NUTTX_LCD_BUFFER_SIZE 60
+ #endif
+
+ /** Driver for /dev/input */
+ #define LV_USE_NUTTX_TOUCHSCREEN 0
+
+ /** Touchscreen cursor size in pixels(<=0: disable cursor) */
+ #define LV_NUTTX_TOUCHSCREEN_CURSOR_SIZE 0
+
+ /** Driver for /dev/mouse */
+ #define LV_USE_NUTTX_MOUSE 0
+
+ /** Mouse movement step (pixels) */
+ #define LV_USE_NUTTX_MOUSE_MOVE_STEP 1
+
+ /*NuttX trace file and its path*/
+ #define LV_USE_NUTTX_TRACE_FILE 0
+ #if LV_USE_NUTTX_TRACE_FILE
+ #define LV_NUTTX_TRACE_FILE_PATH "/data/lvgl-trace.log"
+ #endif
+
+#endif
+
+/** Driver for /dev/dri/card */
+#define LV_USE_LINUX_DRM 0
+
+#if LV_USE_LINUX_DRM
+
+ /* Use the MESA GBM library to allocate DMA buffers that can be
+ * shared across sub-systems and libraries using the Linux DMA-BUF API.
+ * The GBM library aims to provide a platform independent memory management system
+ * it supports the major GPU vendors - This option requires linking with libgbm */
+ #define LV_USE_LINUX_DRM_GBM_BUFFERS 0
+#endif
+
+/** Interface for TFT_eSPI */
+#define LV_USE_TFT_ESPI 0
+
+/** Interface for Lovyan_GFX */
+#define LV_USE_LOVYAN_GFX 0
+
+#if LV_USE_LOVYAN_GFX
+ #define LV_LGFX_USER_INCLUDE "lv_lgfx_user.hpp"
+
+#endif /*LV_USE_LOVYAN_GFX*/
+
+/** Driver for evdev input devices */
+#define LV_USE_EVDEV 0
+
+/** Driver for libinput input devices */
+#define LV_USE_LIBINPUT 0
+
+#if LV_USE_LIBINPUT
+ #define LV_LIBINPUT_BSD 0
+
+ /** Full keyboard support */
+ #define LV_LIBINPUT_XKB 0
+ #if LV_LIBINPUT_XKB
+ /** "setxkbmap -query" can help find the right values for your keyboard */
+ #define LV_LIBINPUT_XKB_KEY_MAP { .rules = NULL, .model = "pc101", .layout = "us", .variant = NULL, .options = NULL }
+ #endif
+#endif
+
+/* Drivers for LCD devices connected via SPI/parallel port */
+#define LV_USE_ST7735 0
+#define LV_USE_ST7789 0
+#define LV_USE_ST7796 0
+#define LV_USE_ILI9341 0
+#define LV_USE_FT81X 0
+#define LV_USE_NV3007 0
+
+#if (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341 | LV_USE_NV3007)
+ #define LV_USE_GENERIC_MIPI 1
+#else
+ #define LV_USE_GENERIC_MIPI 0
+#endif
+
+/** Driver for Renesas GLCD */
+#define LV_USE_RENESAS_GLCDC 0
+
+/** Driver for ST LTDC */
+#define LV_USE_ST_LTDC 0
+#if LV_USE_ST_LTDC
+ /* Only used for partial. */
+ #define LV_ST_LTDC_USE_DMA2D_FLUSH 0
+#endif
+
+/** Driver for NXP ELCDIF */
+#define LV_USE_NXP_ELCDIF 0
+
+/** LVGL Windows backend */
+#define LV_USE_WINDOWS 0
+
+/** LVGL UEFI backend */
+#define LV_USE_UEFI 1
+#if LV_USE_UEFI
+ #define LV_USE_UEFI_INCLUDE "lv_uefi_edk2.h" /**< Header that hides the actual framework (EDK2, gnu-efi, ...) */
+ #define LV_UEFI_USE_MEMORY_SERVICES 1 /**< Use the memory functions from the boot services table */
+#endif
+
+/** Use a generic OpenGL driver that can be used to embed in other applications or used with GLFW/EGL
+ * - Requires LV_USE_MATRIX.
+ */
+#define LV_USE_OPENGLES 0
+#if LV_USE_OPENGLES
+ #define LV_USE_OPENGLES_DEBUG 1 /**< Enable or disable debug for opengles */
+#endif
+
+/** Use GLFW to open window on PC and handle mouse and keyboard. Requires*/
+#define LV_USE_GLFW 0
+
+
+/** QNX Screen display and input drivers */
+#define LV_USE_QNX 0
+#if LV_USE_QNX
+ #define LV_QNX_BUF_COUNT 1 /**< 1 or 2 */
+#endif
+
+/** Enable or disable for external data and destructor function */
+#define LV_USE_EXT_DATA 0
+
+/*=====================
+* BUILD OPTIONS
+*======================*/
+
+/** Enable examples to be built with the library. */
+#define LV_BUILD_EXAMPLES 1
+
+/** Build the demos */
+#define LV_BUILD_DEMOS 1
+
+/*===================
+ * DEMO USAGE
+ ====================*/
+
+#if LV_BUILD_DEMOS
+ /** Show some widgets. This might be required to increase `LV_MEM_SIZE`. */
+ #define LV_USE_DEMO_WIDGETS 0
+
+ /** Demonstrate usage of encoder and keyboard. */
+ #define LV_USE_DEMO_KEYPAD_AND_ENCODER 1
+
+ /** Benchmark your system */
+ #define LV_USE_DEMO_BENCHMARK 0
+
+ #if LV_USE_DEMO_BENCHMARK
+ /** Use fonts where bitmaps are aligned 16 byte and has Nx16 byte stride */
+ #define LV_DEMO_BENCHMARK_ALIGNED_FONTS 0
+ #endif
+
+ /** Render test for each primitive.
+ * - Requires at least 480x272 display. */
+ #define LV_USE_DEMO_RENDER 0
+
+ /** Stress test for LVGL */
+ #define LV_USE_DEMO_STRESS 0
+
+ /** Music player demo */
+ #define LV_USE_DEMO_MUSIC 0
+ #if LV_USE_DEMO_MUSIC
+ #define LV_DEMO_MUSIC_SQUARE 0
+ #define LV_DEMO_MUSIC_LANDSCAPE 0
+ #define LV_DEMO_MUSIC_ROUND 0
+ #define LV_DEMO_MUSIC_LARGE 0
+ #define LV_DEMO_MUSIC_AUTO_PLAY 0
+ #endif
+
+ /** Vector graphic demo */
+ #define LV_USE_DEMO_VECTOR_GRAPHIC 0
+
+ /** GLTF demo */
+ #define LV_USE_DEMO_GLTF 0
+
+ /*---------------------------
+ * Demos from lvgl/lv_demos
+ ---------------------------*/
+
+ /** Flex layout demo */
+ #define LV_USE_DEMO_FLEX_LAYOUT 0
+
+ /** Smart-phone like multi-language demo */
+ #define LV_USE_DEMO_MULTILANG 0
+
+ /*E-bike demo with Lottie animations (if LV_USE_LOTTIE is enabled)*/
+ #define LV_USE_DEMO_EBIKE 0
+ #if LV_USE_DEMO_EBIKE
+ #define LV_DEMO_EBIKE_PORTRAIT 0 /*0: for 480x270..480x320, 1: for 480x800..720x1280*/
+ #endif
+
+ /** High-resolution demo */
+ #define LV_USE_DEMO_HIGH_RES 0
+
+ /* Smart watch demo */
+ #define LV_USE_DEMO_SMARTWATCH 0
+#endif /* LV_BUILD_DEMOS */
+
+/*--END OF LV_CONF_H--*/
+
+#endif /*LV_CONF_H*/
+
+#endif /*End of "Content enable"*/
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/lv_port_indev.c b/Experimental/LvglSpikePkg/Library/LvglLib/lv_port_indev.c
new file mode 100644
index 0000000..5a8f926
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/lv_port_indev.c
@@ -0,0 +1,567 @@
+/**
+ * @file lv_port_indev.c
+ *
+ */
+
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "lv_port_indev.h"
+
+#include "lvgl/src/indev/lv_indev_private.h"
+
+/*********************
+ * DEFINES
+ *********************/
+
+extern const lv_img_dsc_t mouse_cursor_icon;
+
+typedef struct {
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsPointer;
+ INTN LastCursorX;
+ INTN LastCursorY;
+ UINT64 LastAbsZ;
+ INT32 WheelDelta;
+ UINT32 ActiveButtons;
+ BOOLEAN LeftButton;
+ BOOLEAN RightButton;
+} LVGL_UEFI_MOUSE;
+
+//
+// LVGL treats any non-zero pointer.diff as one full detent and scrolls by
+// scroll_limit (default 10px) per call (lv_indev.c:1638). QEMU usb-mouse can
+// send several wheel reports per perceived host wheel motion, so we ratchet:
+// accumulate raw Z counts and only emit one ±1 detent per N counts.
+// Lower this number = more sensitive. Raise = less sensitive.
+//
+#define LVGL_WHEEL_COUNTS_PER_DETENT 8
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+
+static void mouse_read(lv_indev_t * indev, lv_indev_data_t * data);
+
+static void keypad_read(lv_indev_t * indev, lv_indev_data_t * data);
+
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+lv_indev_t * indev_mouse;
+lv_indev_t * indev_keypad;
+
+LVGL_UEFI_MOUSE mLvglUefiMouse;
+
+//
+// Protocol-install notification: fires when any driver installs
+// EFI_ABSOLUTE_POINTER_PROTOCOL (e.g. when USB mouse binds during BDS
+// ConnectAll). At constructor time USB is not yet enumerated, so the
+// initial lv_uefi_mouse_create() call fails; this callback retries
+// once the pointer protocol actually appears.
+//
+STATIC EFI_EVENT mPointerNotifyEvent = NULL;
+STATIC VOID *mPointerNotifyRegistration = NULL;
+STATIC lv_display_t *mPointerNotifyDisplay = NULL;
+
+/**********************
+ * MACROS
+ **********************/
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+
+static void keypad_read(lv_indev_t * indev_drv, lv_indev_data_t * data)
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ EFI_KEY_DATA KeyData;
+ UINT32 KeyShift;
+
+ data->key = 0;
+
+ Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);
+ Status = TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData);
+ if (!EFI_ERROR (Status)) {
+ switch (KeyData.Key.UnicodeChar) {
+ case CHAR_CARRIAGE_RETURN:
+ data->key = LV_KEY_ENTER;
+ break;
+
+ case CHAR_BACKSPACE:
+ data->key = LV_KEY_BACKSPACE;
+ break;
+
+ case CHAR_TAB:
+ KeyShift = KeyData.KeyState.KeyShiftState;
+ data->key = (KeyShift & EFI_SHIFT_STATE_VALID) && (KeyShift & (EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED)) ? LV_KEY_PREV : LV_KEY_NEXT;
+ break;
+
+ case CHAR_NULL:
+ switch (KeyData.Key.ScanCode) {
+ case SCAN_UP:
+ data->key = LV_KEY_UP;
+ break;
+
+ case SCAN_DOWN:
+ data->key = LV_KEY_DOWN;
+ break;
+
+ case SCAN_RIGHT:
+ data->key = LV_KEY_RIGHT;
+ break;
+
+ case SCAN_LEFT:
+ data->key = LV_KEY_LEFT;
+ break;
+
+ case SCAN_ESC:
+ data->key = LV_KEY_ESC;
+ break;
+
+ case SCAN_DELETE:
+ data->key = LV_KEY_DEL;
+ break;
+
+ case SCAN_PAGE_DOWN:
+ data->key = LV_KEY_NEXT;
+ break;
+
+ case SCAN_PAGE_UP:
+ data->key = LV_KEY_PREV;
+ break;
+
+ case SCAN_HOME:
+ data->key = LV_KEY_HOME;
+ break;
+
+ case SCAN_END:
+ data->key = LV_KEY_END;
+ break;
+
+ case SCAN_F1: data->key = LV_KEY_F1; break;
+ case SCAN_F2: data->key = LV_KEY_F2; break;
+ case SCAN_F3: data->key = LV_KEY_F3; break;
+ case SCAN_F4: data->key = LV_KEY_F4; break;
+ case SCAN_F5: data->key = LV_KEY_F5; break;
+ case SCAN_F6: data->key = LV_KEY_F6; break;
+ case SCAN_F7: data->key = LV_KEY_F7; break;
+ case SCAN_F8: data->key = LV_KEY_F8; break;
+ case SCAN_F9: data->key = LV_KEY_F9; break;
+ case SCAN_F10: data->key = LV_KEY_F10; break;
+ case SCAN_F11: data->key = LV_KEY_F11; break;
+ case SCAN_F12: data->key = LV_KEY_F12; break;
+
+ default:
+ break;
+ }
+ break;
+
+ case CHAR_LINEFEED:
+ break;
+
+ default:
+ data->key = KeyData.Key.UnicodeChar;
+ break;
+ }
+
+ data->state = LV_INDEV_STATE_PRESSED;
+ } else {
+ data->state = LV_INDEV_STATE_RELEASED;
+ }
+
+}
+
+
+lv_indev_t * lv_uefi_keyboard_create(void)
+{
+ lv_indev_t * indev = lv_indev_create();
+ LV_ASSERT_MALLOC(indev);
+ if(indev == NULL) {
+ return NULL;
+ }
+
+ lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
+ lv_indev_set_read_cb(indev, keypad_read);
+
+ return indev;
+}
+
+
+EFI_STATUS
+EFIAPI
+GetXYZ (
+ lv_indev_t * indev_drv
+ )
+{
+ EFI_STATUS Status;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsPointer = NULL;
+ EFI_ABSOLUTE_POINTER_STATE AbsState;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer = NULL;
+ EFI_SIMPLE_POINTER_STATE SimpleState;
+
+ lv_display_t *disp = lv_indev_get_display(indev_drv);
+
+ int32_t hor_res = lv_display_get_horizontal_resolution(disp);
+ int32_t ver_res = lv_display_get_vertical_resolution(disp);
+
+ if (mLvglUefiMouse.AbsPointer != NULL) {
+ AbsPointer = mLvglUefiMouse.AbsPointer;
+ Status = AbsPointer->GetState (AbsPointer, &AbsState);
+ if (!EFI_ERROR (Status)) {
+ mLvglUefiMouse.LastCursorX = (AbsState.CurrentX * hor_res) / (AbsPointer->Mode->AbsoluteMaxX - AbsPointer->Mode->AbsoluteMinX);
+ if (mLvglUefiMouse.LastCursorX > hor_res - 1) {
+ mLvglUefiMouse.LastCursorX = hor_res - 1;
+ }
+ mLvglUefiMouse.LastCursorY = (AbsState.CurrentY * ver_res) / (AbsPointer->Mode->AbsoluteMaxY - AbsPointer->Mode->AbsoluteMinY);
+ if (mLvglUefiMouse.LastCursorY > ver_res - 1) {
+ mLvglUefiMouse.LastCursorY = ver_res - 1;
+ }
+ mLvglUefiMouse.LeftButton = AbsState.ActiveButtons & BIT0;
+
+ mLvglUefiMouse.WheelDelta += (INT32)(AbsState.CurrentZ - mLvglUefiMouse.LastAbsZ);
+ mLvglUefiMouse.LastAbsZ = AbsState.CurrentZ;
+
+ return EFI_SUCCESS;
+ }
+ } else if (mLvglUefiMouse.SimplePointer != NULL) {
+ SimplePointer = mLvglUefiMouse.SimplePointer;
+ Status = SimplePointer->GetState (SimplePointer, &SimpleState);
+ if (!EFI_ERROR (Status)) {
+ mLvglUefiMouse.LastCursorX += (SimpleState.RelativeMovementX * hor_res) / (INT32)(50 * SimplePointer->Mode->ResolutionX);
+ if (mLvglUefiMouse.LastCursorX > hor_res - 1) {
+ mLvglUefiMouse.LastCursorX = hor_res - 1;
+ }
+ if (mLvglUefiMouse.LastCursorX < 0) {
+ mLvglUefiMouse.LastCursorX = 0;
+ }
+ mLvglUefiMouse.LastCursorY += (SimpleState.RelativeMovementY * ver_res) / (INT32)(50 * SimplePointer->Mode->ResolutionY);
+ if (mLvglUefiMouse.LastCursorY > ver_res - 1) {
+ mLvglUefiMouse.LastCursorY = ver_res - 1;
+ }
+ if (mLvglUefiMouse.LastCursorY < 0) {
+ mLvglUefiMouse.LastCursorY = 0;
+ }
+
+ mLvglUefiMouse.LeftButton = SimpleState.LeftButton;
+ mLvglUefiMouse.RightButton = SimpleState.RightButton;
+
+ mLvglUefiMouse.WheelDelta += SimpleState.RelativeMovementZ;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_READY;
+}
+
+
+EFI_STATUS
+EFIAPI
+EfiMouseInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsPointer = NULL;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer = NULL;
+ EFI_HANDLE *HandleBuffer = NULL;
+ UINTN HandleCount, Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN AbsPointerSupport = FALSE;
+ BOOLEAN SimplePointerSupport = FALSE;
+
+ HandleCount = 0;
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiAbsolutePointerProtocolGuid, NULL, &HandleCount, &HandleBuffer);
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
+ if (!EFI_ERROR (Status)) {
+ AbsPointerSupport = TRUE;
+ break;
+ }
+ }
+ if (HandleBuffer!= NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ if (AbsPointerSupport) {
+ goto StartInit;
+ }
+
+ HandleCount = 0;
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimplePointerProtocolGuid, NULL, &HandleCount, &HandleBuffer);
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
+ if (!EFI_ERROR (Status)) {
+ SimplePointerSupport = TRUE;
+ break;
+ }
+ }
+ if (HandleBuffer!= NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ if (!AbsPointerSupport && !SimplePointerSupport) {
+ return EFI_UNSUPPORTED;
+ }
+
+StartInit:
+ DebugPrint (DEBUG_INFO, "EfiMouseInit()\n");
+
+ DebugPrint (DEBUG_INFO, "Abs Pointer: %d\n", AbsPointerSupport);
+ DebugPrint (DEBUG_INFO, "Simple Pointer: %d\n", SimplePointerSupport);
+
+ mLvglUefiMouse.AbsPointer = NULL;
+ mLvglUefiMouse.SimplePointer = NULL;
+ mLvglUefiMouse.LastAbsZ = 0;
+ mLvglUefiMouse.WheelDelta = 0;
+ mLvglUefiMouse.ActiveButtons = 0;
+ mLvglUefiMouse.LeftButton = FALSE;
+ mLvglUefiMouse.RightButton = FALSE;
+
+ if (AbsPointerSupport) {
+ Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiAbsolutePointerProtocolGuid, (VOID **)&AbsPointer);
+ if (!EFI_ERROR (Status) && AbsPointer != NULL) {
+ mLvglUefiMouse.AbsPointer = AbsPointer;
+ }
+ }
+
+ if (SimplePointerSupport && !AbsPointerSupport) {
+ Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimplePointerProtocolGuid, (VOID **)&SimplePointer);
+ if (!EFI_ERROR (Status) && SimplePointer != NULL) {
+ mLvglUefiMouse.SimplePointer = SimplePointer;
+ }
+ }
+
+ return Status;
+}
+
+
+//
+// Scroll amount in pixels per wheel detent. LVGL's built-in
+// indev_proc_pointer_diff path uses indev->scroll_limit (default 10px) but
+// only fires when pointer.last_pressed is set — i.e. after the user has
+// clicked or dragged once. We bypass that by directly scrolling the
+// nearest scrollable ancestor of the obj under the cursor.
+//
+#define LVGL_WHEEL_SCROLL_PIXELS 40
+
+static lv_obj_t * find_scrollable_at_point(lv_display_t * disp, lv_point_t * p)
+{
+ lv_obj_t *screen = lv_display_get_screen_active(disp);
+ if (screen == NULL) return NULL;
+
+ lv_obj_t *hit = lv_indev_search_obj(screen, p);
+ if (hit == NULL) return NULL;
+
+ for (lv_obj_t *o = hit; o != NULL; o = lv_obj_get_parent(o)) {
+ if (lv_obj_has_flag(o, LV_OBJ_FLAG_SCROLLABLE) &&
+ lv_obj_get_scroll_top(o) + lv_obj_get_scroll_bottom(o) > 0)
+ {
+ return o;
+ }
+ }
+ return NULL;
+}
+
+static void mouse_read(lv_indev_t * indev_drv, lv_indev_data_t * data)
+{
+ int wheel_step = 0;
+
+ GetXYZ(indev_drv);
+ data->point.x = mLvglUefiMouse.LastCursorX;
+ data->point.y = mLvglUefiMouse.LastCursorY;
+ if (mLvglUefiMouse.LeftButton) {
+ data->state = LV_INDEV_STATE_PRESSED;
+ } else {
+ data->state = LV_INDEV_STATE_RELEASED;
+ }
+
+ if (mLvglUefiMouse.WheelDelta >= LVGL_WHEEL_COUNTS_PER_DETENT) {
+ wheel_step = 1;
+ mLvglUefiMouse.WheelDelta -= LVGL_WHEEL_COUNTS_PER_DETENT;
+ } else if (mLvglUefiMouse.WheelDelta <= -LVGL_WHEEL_COUNTS_PER_DETENT) {
+ wheel_step = -1;
+ mLvglUefiMouse.WheelDelta += LVGL_WHEEL_COUNTS_PER_DETENT;
+ }
+
+ data->enc_diff = 0;
+
+ if (wheel_step != 0) {
+ lv_display_t *disp = lv_indev_get_display(indev_drv);
+ lv_point_t p = { (int32_t)data->point.x, (int32_t)data->point.y };
+ lv_obj_t *target = find_scrollable_at_point(disp, &p);
+ if (target != NULL) {
+ lv_obj_scroll_by_bounded(
+ target,
+ 0,
+ wheel_step * LVGL_WHEEL_SCROLL_PIXELS,
+ LV_ANIM_OFF
+ );
+ }
+ }
+}
+
+
+void lv_indev_set_cusor_start(lv_indev_t * indev)
+{
+ if(indev == NULL) return;
+
+ lv_display_t *disp = lv_indev_get_display(indev);
+
+ int32_t hor_res = lv_display_get_horizontal_resolution(disp);
+ int32_t ver_res = lv_display_get_vertical_resolution(disp);
+
+ indev->pointer.act_point.x = hor_res / 2;
+ indev->pointer.act_point.y = ver_res / 2;
+ mLvglUefiMouse.LastCursorX = hor_res / 2;
+ mLvglUefiMouse.LastCursorY = ver_res / 2;
+ mLvglUefiMouse.WheelDelta = 0;
+ mLvglUefiMouse.ActiveButtons = 0;
+ mLvglUefiMouse.LeftButton = FALSE;
+ mLvglUefiMouse.RightButton = FALSE;
+}
+
+lv_indev_t * lv_uefi_mouse_create(lv_display_t * disp)
+{
+ //
+ // Idempotent: if a pointer indev already exists, return it.
+ // This lets callers invoke lv_uefi_mouse_create() lazily — e.g. after BDS
+ // has connected USB — without worrying about whether the constructor-time
+ // attempt succeeded.
+ //
+ lv_indev_t * existing = NULL;
+ while ((existing = lv_indev_get_next(existing)) != NULL) {
+ if (lv_indev_get_type(existing) == LV_INDEV_TYPE_POINTER) {
+ return existing;
+ }
+ }
+
+ if (EfiMouseInit() != EFI_SUCCESS) {
+ return NULL;
+ }
+
+ lv_indev_t * indev = lv_indev_create();
+ LV_ASSERT_MALLOC(indev);
+ if(indev == NULL) {
+ return NULL;
+ }
+
+ DebugPrint (DEBUG_INFO, "Create Mouse\n");
+
+ lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
+ lv_indev_set_read_cb(indev, mouse_read);
+ lv_indev_set_display (indev, disp);
+
+ LV_IMG_DECLARE(mouse_cursor_icon);
+ lv_obj_t * mouse_cursor = lv_image_create(lv_screen_active());
+ lv_image_set_src(mouse_cursor, &mouse_cursor_icon);
+ lv_indev_set_cusor_start(indev);
+ lv_indev_set_cursor(indev, mouse_cursor);
+
+ return indev;
+}
+
+STATIC
+VOID
+EFIAPI
+OnPointerProtocolInstalled (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (mPointerNotifyDisplay != NULL) {
+ lv_uefi_mouse_create (mPointerNotifyDisplay);
+ }
+}
+
+void lv_port_indev_init(lv_display_t * disp)
+{
+ lv_uefi_mouse_create(disp);
+
+ lv_uefi_keyboard_create();
+
+ //
+ // If the mouse couldn't be created yet (USB not connected at this point
+ // in boot), register for notification when the pointer protocol shows up.
+ //
+ if (mPointerNotifyEvent == NULL) {
+ EFI_STATUS Status;
+
+ mPointerNotifyDisplay = disp;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ OnPointerProtocolInstalled,
+ NULL,
+ &mPointerNotifyEvent
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->RegisterProtocolNotify (
+ &gEfiAbsolutePointerProtocolGuid,
+ mPointerNotifyEvent,
+ &mPointerNotifyRegistration
+ );
+ }
+ }
+}
+
+void lv_uefi_keypad_drain(void)
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ EFI_KEY_DATA KeyData;
+ lv_indev_t *Indev;
+
+ //
+ // Drain all pending keystrokes from the EFI console.
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&TxtInEx);
+ if (!EFI_ERROR (Status)) {
+ while (!EFI_ERROR (TxtInEx->ReadKeyStrokeEx (TxtInEx, &KeyData))) {
+ }
+ }
+
+ //
+ // Force every keypad indev to RELEASED so LVGL doesn't interpret the
+ // pending ENTER release as a click on the next focused widget.
+ //
+ Indev = NULL;
+ while ((Indev = lv_indev_get_next (Indev)) != NULL) {
+ if (lv_indev_get_type (Indev) == LV_INDEV_TYPE_KEYPAD) {
+ Indev->keypad.last_state = LV_INDEV_STATE_RELEASED;
+ Indev->keypad.last_key = 0;
+ }
+ }
+}
+
+void lv_port_indev_close()
+{
+ if (mPointerNotifyEvent != NULL) {
+ gBS->CloseEvent (mPointerNotifyEvent);
+ mPointerNotifyEvent = NULL;
+ mPointerNotifyRegistration = NULL;
+ mPointerNotifyDisplay = NULL;
+ }
+
+ mLvglUefiMouse.AbsPointer = NULL;
+ mLvglUefiMouse.SimplePointer = NULL;
+ mLvglUefiMouse.LastCursorX = 0;
+ mLvglUefiMouse.LastCursorY = 0;
+ mLvglUefiMouse.LastAbsZ = 0;
+ mLvglUefiMouse.WheelDelta = 0;
+ mLvglUefiMouse.ActiveButtons = 0;
+ mLvglUefiMouse.LeftButton = FALSE;
+ mLvglUefiMouse.RightButton = FALSE;
+}
+
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/lv_port_indev.h b/Experimental/LvglSpikePkg/Library/LvglLib/lv_port_indev.h
new file mode 100644
index 0000000..3b32a61
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/lv_port_indev.h
@@ -0,0 +1,71 @@
+
+/**
+ * @file lv_port_indev.h
+ *
+ */
+
+#ifndef LV_PORT_INDEV_H
+#define LV_PORT_INDEV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ * INCLUDES
+ *********************/
+#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
+#include "lvgl.h"
+#else
+#include "lvgl/lvgl.h"
+#endif
+
+#include "LvglLibCommon.h"
+
+/*********************
+ * DEFINES
+ *********************/
+
+//
+// Custom LVGL key codes for EFI function keys F1-F12.
+// Mirror of the defines in .
+//
+#define LV_KEY_F1 0x0101U
+#define LV_KEY_F2 0x0102U
+#define LV_KEY_F3 0x0103U
+#define LV_KEY_F4 0x0104U
+#define LV_KEY_F5 0x0105U
+#define LV_KEY_F6 0x0106U
+#define LV_KEY_F7 0x0107U
+#define LV_KEY_F8 0x0108U
+#define LV_KEY_F9 0x0109U
+#define LV_KEY_F10 0x010AU
+#define LV_KEY_F11 0x010BU
+#define LV_KEY_F12 0x010CU
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+void lv_port_indev_init(lv_display_t * disp);
+
+void lv_port_indev_close();
+
+/**
+ Drain the EFI keyboard buffer and reset the LVGL keypad indev state so that
+ no pending key-press leaks into the next event loop.
+**/
+void lv_uefi_keypad_drain(void);
+
+/**********************
+ * MACROS
+ **********************/
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*LV_PORT_INDEV_TEMPL_H*/
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/lv_uefi_display.c b/Experimental/LvglSpikePkg/Library/LvglLib/lv_uefi_display.c
new file mode 100644
index 0000000..4f3c841
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/lv_uefi_display.c
@@ -0,0 +1,83 @@
+#include "LvglLibCommon.h"
+
+
+typedef struct {
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *EfiGop;
+ uint8_t *buffer[2];
+} uefi_disp_data_t;
+
+
+static void uefi_disp_delete_evt_cb(lv_event_t * e)
+{
+ lv_display_t * disp = lv_event_get_user_data(e);
+ uefi_disp_data_t * uefi_disp_data = lv_display_get_driver_data(disp);
+
+ free(uefi_disp_data->buffer[0]);
+ free(uefi_disp_data->buffer[1]);
+
+ lv_free(uefi_disp_data);
+}
+
+
+void uefi_disp_flush(lv_display_t * disp, const lv_area_t * area, lv_color32_t * color32_p)
+{
+ UINTN Width, Heigth;
+ uefi_disp_data_t *uefi_disp_data;
+ UINTN Delta;
+
+ uefi_disp_data = lv_display_get_driver_data(disp);
+
+ Width = area->x2 - area->x1 + 1;
+ Heigth = area->y2 - area->y1 + 1;
+ Delta = uefi_disp_data->EfiGop->Mode->Info->HorizontalResolution * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+
+ uefi_disp_data->EfiGop->Blt (
+ uefi_disp_data->EfiGop,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)color32_p,
+ EfiBltBufferToVideo,
+ (UINTN)area->x1,
+ (UINTN)area->y1,
+ (UINTN)area->x1,
+ (UINTN)area->y1,
+ Width,
+ Heigth,
+ Delta
+ );
+
+ lv_display_flush_ready(disp);
+}
+
+
+lv_display_t * lv_uefi_disp_create(int32_t hor_res, int32_t ver_res)
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+
+ Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **) &GraphicsOutput);
+ if (EFI_ERROR(Status)) {
+ return NULL;
+ }
+
+ uefi_disp_data_t * uefi_disp_data = lv_malloc_zeroed(sizeof(uefi_disp_data_t));
+ LV_ASSERT_MALLOC(uefi_disp_data);
+ if(NULL == uefi_disp_data) return NULL;
+
+ uefi_disp_data->EfiGop = GraphicsOutput;
+
+ lv_display_t * disp = lv_display_create(hor_res, ver_res);
+ if(NULL == disp) {
+ lv_free(uefi_disp_data);
+ return NULL;
+ }
+ lv_display_set_driver_data(disp, uefi_disp_data);
+ lv_display_set_flush_cb(disp, (lv_display_flush_cb_t)uefi_disp_flush);
+ lv_display_add_event_cb(disp, uefi_disp_delete_evt_cb, LV_EVENT_DELETE, disp);
+
+ UINTN BufSize = hor_res * ver_res * sizeof (lv_color32_t);
+ uefi_disp_data->buffer[0] = malloc (BufSize);
+ uefi_disp_data->buffer[1] = malloc (BufSize);
+
+ lv_display_set_buffers(disp, uefi_disp_data->buffer[0], uefi_disp_data->buffer[1], BufSize, LV_DISPLAY_RENDER_MODE_DIRECT);
+
+ return disp;
+}
\ No newline at end of file
diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/lvgl b/Experimental/LvglSpikePkg/Library/LvglLib/lvgl
new file mode 120000
index 0000000..a04dfc9
--- /dev/null
+++ b/Experimental/LvglSpikePkg/Library/LvglLib/lvgl
@@ -0,0 +1 @@
+../../../../External/lvgl
\ No newline at end of file
diff --git a/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.c b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.c
new file mode 100644
index 0000000..ed1cb35
--- /dev/null
+++ b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.c
@@ -0,0 +1,76 @@
+/** @file
+ LvglDisplayEngineDxe -- driver glue: initializes the LVGL UEFI backend and
+ installs EDKII_FORM_DISPLAY_ENGINE_PROTOCOL so SetupBrowser drives LVGL instead
+ of the native text-grid DisplayEngineDxe.
+
+ SetupBrowser keeps all IFR/config/callback ownership; this driver only renders.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "LvglDisplayEngineDxe.h"
+#include
+
+typedef struct {
+ EFI_HANDLE Handle;
+ EDKII_FORM_DISPLAY_ENGINE_PROTOCOL FormDisplayProt;
+} LVGL_DISPLAY_ENGINE_PRIVATE;
+
+/**
+ Confirm how to handle changed data when a form session ends. This skeleton
+ never edits varstore data, so it asks SetupBrowser to discard. SetupBrowser
+ still owns the actual decision and any writes.
+
+ @retval BROWSER_ACTION_DISCARD Discard pending changes.
+**/
+STATIC
+UINTN
+EFIAPI
+LvglConfirmDataChange (
+ VOID
+ )
+{
+ return BROWSER_ACTION_DISCARD;
+}
+
+STATIC LVGL_DISPLAY_ENGINE_PRIVATE mPrivate = {
+ NULL,
+ {
+ LvglFormDisplay,
+ LvglExitDisplay,
+ LvglConfirmDataChange
+ }
+};
+
+/**
+ Driver entry point. Caches the image handle / system table for the LVGL UEFI
+ backend, initializes LVGL, and installs the form-display protocol. The LVGL
+ display itself is created lazily on the first form (GOP may not be up yet).
+
+ @param[in] ImageHandle This driver's image handle.
+ @param[in] SystemTable The EFI System Table.
+
+ @retval EFI_SUCCESS The protocol was installed.
+ @retval Others Protocol installation failed.
+**/
+EFI_STATUS
+EFIAPI
+InitializeLvglDisplayEngine (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Must precede lv_init() per the upstream LVGL UEFI backend contract.
+ //
+ lv_uefi_init (ImageHandle, SystemTable);
+ lv_init ();
+
+ return gBS->InstallProtocolInterface (
+ &mPrivate.Handle,
+ &gEdkiiFormDisplayEngineProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivate.FormDisplayProt
+ );
+}
diff --git a/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.h b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.h
new file mode 100644
index 0000000..80094f4
--- /dev/null
+++ b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.h
@@ -0,0 +1,60 @@
+/** @file
+ LvglDisplayEngineDxe -- experimental EDKII_FORM_DISPLAY_ENGINE_PROTOCOL backend
+ that renders native SetupBrowser forms with LVGL instead of edk2's text-grid
+ DisplayEngineDxe.
+
+ BOUNDARY: like every DisplayEngine, this only RENDERS and reports user input.
+ SetupBrowser keeps ownership of IFR parsing, ConfigAccess, callbacks, and
+ varstore writes. This driver never writes HII variables.
+
+ experimental/lvgl-spike only; never a default overlay.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef LVGL_DISPLAY_ENGINE_DXE_H_
+#define LVGL_DISPLAY_ENGINE_DXE_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+/**
+ Render one form with LVGL and block until the user asks to leave it, then
+ report the result to SetupBrowser.
+
+ @param[in] FormData The form (statements, title, HII handle) to show.
+ Must be non-NULL.
+ @param[out] UserInputData Filled with the user's action/selection. Must be
+ non-NULL. For this skeleton: ESC -> Action =
+ BROWSER_ACTION_FORM_EXIT, SelectedStatement = NULL.
+
+ @retval EFI_SUCCESS The form was shown and user input was collected.
+**/
+EFI_STATUS
+EFIAPI
+LvglFormDisplay (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT USER_INPUT *UserInputData
+ );
+
+/**
+ Tear the LVGL display back down and restore the text console after a form
+ session ends.
+**/
+VOID
+EFIAPI
+LvglExitDisplay (
+ VOID
+ );
+
+#endif // LVGL_DISPLAY_ENGINE_DXE_H_
diff --git a/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.inf b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.inf
new file mode 100644
index 0000000..0a049d9
--- /dev/null
+++ b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.inf
@@ -0,0 +1,64 @@
+## @file
+# LvglDisplayEngineDxe -- experimental EDKII_FORM_DISPLAY_ENGINE_PROTOCOL backend
+# that renders native SetupBrowser forms with LVGL. SetupBrowser keeps IFR/config
+# ownership; this only renders. experimental/lvgl-spike only; never default overlay.
+#
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LvglDisplayEngineDxe
+ FILE_GUID = 4D9A7E22-6C13-4B80-9F1E-2A7C5D03AB04
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeLvglDisplayEngine
+
+[Sources]
+ LvglDisplayEngineDxe.c
+ LvglFormRenderer.c
+ LvglDisplayEngineDxe.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ LvglSpikePkg/LvglSpikePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DebugLib
+ PrintLib
+ HiiLib
+ UefiHiiServicesLib
+ LvglCoreLib
+
+[Protocols]
+ gEdkiiFormDisplayEngineProtocolGuid ## PRODUCES
+ gEfiGraphicsOutputProtocolGuid ## CONSUMES
+ gEfiSimplePointerProtocolGuid ## CONSUMES
+ gEfiAbsolutePointerProtocolGuid ## CONSUMES
+ gEfiSimpleTextInputExProtocolGuid ## CONSUMES
+ gEfiSimpleTextInProtocolGuid ## CONSUMES
+ gEfiEdidActiveProtocolGuid ## CONSUMES
+ gEfiTimestampProtocolGuid ## CONSUMES
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiFileInfoGuid
+
+[Depex]
+ TRUE
+
+[BuildOptions]
+ # LvglDisplayEngineDxe.c includes via LvglCoreLib.h, which pulls
+ # lv_conf.h (in Library/LvglLib, on the package include path) via
+ # LV_CONF_INCLUDE_SIMPLE.
+ GCC:*_*_*_CC_FLAGS = -DLV_CONF_INCLUDE_SIMPLE
diff --git a/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglFormRenderer.c b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglFormRenderer.c
new file mode 100644
index 0000000..a24c045
--- /dev/null
+++ b/Experimental/LvglSpikePkg/LvglDisplayEngineDxe/LvglFormRenderer.c
@@ -0,0 +1,229 @@
+/** @file
+ LvglDisplayEngineDxe -- the form renderer. Maps a SetupBrowser
+ FORM_DISPLAY_ENGINE_FORM onto LVGL objects and drives the input loop.
+
+ Skeleton scope (experimental/lvgl-spike, steps 1-2): render the form title and
+ one row per statement (prompt text) as LVGL labels, then hold the frame until
+ ESC. Richer widgets (dropdown/checkbox/spinbox/textarea) and live editing are
+ layered on later; this proves "native form -> LVGL -> GOP" end to end without
+ taking any IFR/config ownership from SetupBrowser.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "LvglDisplayEngineDxe.h"
+
+//
+// One LVGL display, created lazily on the first form (GOP may not be up when the
+// driver loads). NULL until then.
+//
+STATIC lv_display_t *mLvglDisplay = NULL;
+
+/**
+ Convert an HII string (returned as a freshly-allocated CHAR16*) to a pool
+ CHAR8* for LVGL, which consumes UTF-8/ASCII. Non-ASCII code points degrade to
+ '?' -- acceptable for the skeleton. Frees the input CHAR16 buffer.
+
+ @param[in] Unicode HII string to convert. May be NULL.
+
+ @retval Pool-allocated CHAR8 string (caller frees), or NULL. Caller owns it.
+**/
+STATIC
+CHAR8 *
+HiiStringToAscii (
+ IN EFI_STRING Unicode
+ )
+{
+ UINTN Len;
+ CHAR8 *Ascii;
+ UINTN Index;
+
+ if (Unicode == NULL) {
+ return NULL;
+ }
+
+ Len = StrLen (Unicode);
+ Ascii = AllocatePool (Len + 1);
+ if (Ascii != NULL) {
+ for (Index = 0; Index < Len; Index++) {
+ Ascii[Index] = (Unicode[Index] < 0x80) ? (CHAR8)Unicode[Index] : '?';
+ }
+
+ Ascii[Len] = '\0';
+ }
+
+ FreePool (Unicode);
+ return Ascii;
+}
+
+/**
+ Read a statement's prompt string id from its IFR opcode. Question, text, and
+ subtitle opcodes all carry an EFI_IFR_STATEMENT_HEADER immediately after the
+ op header; its first field is the prompt string id. Display-only read; no
+ config semantics are touched.
+
+ @param[in] Statement The statement. Must be non-NULL with a non-NULL OpCode.
+
+ @retval The prompt EFI_STRING_ID, or 0 if none.
+**/
+STATIC
+EFI_STRING_ID
+GetStatementPromptId (
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement
+ )
+{
+ EFI_IFR_STATEMENT_HEADER *Header;
+
+ if ((Statement == NULL) || (Statement->OpCode == NULL)) {
+ return 0;
+ }
+
+ Header = (EFI_IFR_STATEMENT_HEADER *)(Statement->OpCode + 1);
+ return Header->Prompt;
+}
+
+/**
+ Build the LVGL object tree for one form: a title label plus one prompt label
+ per statement, on a themed background.
+
+ @param[in] FormData The form to render. Must be non-NULL.
+**/
+STATIC
+VOID
+LvglBuildForm (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ lv_obj_t *Screen;
+ lv_obj_t *List;
+ lv_obj_t *Title;
+ LIST_ENTRY *Link;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ CHAR8 *Text;
+
+ Screen = lv_screen_active ();
+ lv_obj_clean (Screen);
+ lv_obj_set_style_bg_color (Screen, lv_color_hex (0x0E1116), LV_PART_MAIN);
+ lv_obj_set_style_bg_opa (Screen, LV_OPA_COVER, LV_PART_MAIN);
+
+ //
+ // Title from the form's HII title string id.
+ //
+ Title = lv_label_create (Screen);
+ Text = HiiStringToAscii (HiiGetString (FormData->HiiHandle, FormData->FormTitle, NULL));
+ lv_label_set_text (Title, (Text != NULL) ? Text : "Setup");
+ lv_obj_set_style_text_color (Title, lv_color_hex (0xF2C14E), LV_PART_MAIN);
+ lv_obj_set_style_text_font (Title, &lv_font_montserrat_24, LV_PART_MAIN);
+ lv_obj_align (Title, LV_ALIGN_TOP_MID, 0, 16);
+ if (Text != NULL) {
+ FreePool (Text);
+ }
+
+ //
+ // A scrollable column for the statement rows.
+ //
+ List = lv_obj_create (Screen);
+ lv_obj_set_size (List, lv_pct (90), lv_pct (78));
+ lv_obj_align (List, LV_ALIGN_BOTTOM_MID, 0, -16);
+ lv_obj_set_flex_flow (List, LV_FLEX_FLOW_COLUMN);
+ lv_obj_set_style_bg_opa (List, LV_OPA_TRANSP, LV_PART_MAIN);
+ lv_obj_set_style_border_width (List, 0, LV_PART_MAIN);
+
+ //
+ // One label per statement (prompt text). Display only.
+ //
+ for (Link = GetFirstNode (&FormData->StatementListHead);
+ !IsNull (&FormData->StatementListHead, Link);
+ Link = GetNextNode (&FormData->StatementListHead, Link))
+ {
+ lv_obj_t *Row;
+
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ Text = HiiStringToAscii (HiiGetString (FormData->HiiHandle, GetStatementPromptId (Statement), NULL));
+ if (Text == NULL) {
+ continue;
+ }
+
+ Row = lv_label_create (List);
+ lv_label_set_text (Row, Text);
+ lv_obj_set_style_text_color (Row, lv_color_hex (0xE6EAF0), LV_PART_MAIN);
+ FreePool (Text);
+ }
+}
+
+/**
+ See LvglDisplayEngineDxe.h.
+**/
+EFI_STATUS
+EFIAPI
+LvglFormDisplay (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT USER_INPUT *UserInputData
+ )
+{
+ EFI_INPUT_KEY Key;
+ EFI_STATUS Status;
+ VOID *Handle;
+
+ if ((FormData == NULL) || (UserInputData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (UserInputData, sizeof (USER_INPUT));
+
+ //
+ // Lazily create the LVGL display now that a GOP is expected to be present.
+ //
+ if (mLvglDisplay == NULL) {
+ Handle = lv_uefi_display_get_any ();
+ if (Handle == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mLvglDisplay = lv_uefi_display_create (Handle);
+ if (mLvglDisplay == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ LvglBuildForm (FormData);
+
+ //
+ // Hold the frame; ESC leaves the form. SetupBrowser owns everything else --
+ // we only report the exit action back to it.
+ //
+ for ( ; ; ) {
+ lv_timer_handler ();
+ gBS->Stall (10 * 1000);
+ lv_tick_inc (10);
+
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status) && (Key.ScanCode == SCAN_ESC)) {
+ UserInputData->SelectedStatement = NULL;
+ UserInputData->Action = BROWSER_ACTION_FORM_EXIT;
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ See LvglDisplayEngineDxe.h.
+**/
+VOID
+EFIAPI
+LvglExitDisplay (
+ VOID
+ )
+{
+ if (mLvglDisplay != NULL) {
+ lv_obj_clean (lv_screen_active ());
+ lv_refr_now (mLvglDisplay);
+ }
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, 0);
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+}
diff --git a/Experimental/LvglSpikePkg/LvglSpikeLoongArch.dsc b/Experimental/LvglSpikePkg/LvglSpikeLoongArch.dsc
new file mode 100644
index 0000000..8f02f21
--- /dev/null
+++ b/Experimental/LvglSpikePkg/LvglSpikeLoongArch.dsc
@@ -0,0 +1,53 @@
+## @file
+# Minimal self-contained DSC for the experimental/lvgl-spike LoongArch build.
+# Builds the standalone render probe AND the LvglDisplayEngineDxe backend (LVGL
+# behind EDKII_FORM_DISPLAY_ENGINE_PROTOCOL) for LOONGARCH64. Not a shipped
+# platform; no FD.
+#
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ PLATFORM_NAME = LvglSpike
+ PLATFORM_GUID = 9B2E4D71-0A3C-4F65-8E2D-1C7A6F0B1102
+ PLATFORM_VERSION = 0.01
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/LvglSpike
+ SUPPORTED_ARCHITECTURES = LOONGARCH64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses]
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ LvglCoreLib|LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf
+
+[Components]
+ #
+ # Compiler intrinsics (memcpy/memset/...) that GCC emits for aggregate
+ # copy/zero in LVGL are force-linked per component via NULL|IntrinsicLib.
+ #
+ LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.inf {
+
+ NULL|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+ }
+ LvglSpikePkg/LvglDisplayEngineDxe/LvglDisplayEngineDxe.inf {
+
+ NULL|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+ }
diff --git a/Experimental/LvglSpikePkg/LvglSpikePkg.dec b/Experimental/LvglSpikePkg/LvglSpikePkg.dec
new file mode 100644
index 0000000..cba93ba
--- /dev/null
+++ b/Experimental/LvglSpikePkg/LvglSpikePkg.dec
@@ -0,0 +1,30 @@
+## @file
+# LvglSpikePkg -- experimental evaluation package for an LVGL rendering backend.
+#
+# EXPERIMENTAL / SPIKE ONLY. Exists on experimental/lvgl-spike to answer one
+# question: does LVGL's core + software renderer + upstream UEFI port build (and
+# later render) under edk2 on a hard architecture (LoongArch64), not just X64.
+# It points the LVGL integration at this repo's pinned External/lvgl submodule
+# (LVGL v9.5.0) via a symlink (Library/LvglLib/lvgl). The Aptio-styled chrome
+# from downstream LVGL-UEFI ports is intentionally NOT vendored.
+#
+# Must never appear in a default ModernSetupPkg firmware overlay or ModernSetupApp.
+#
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = LvglSpikePkg
+ PACKAGE_GUID = 0E0B8F2A-4C1D-4E7A-9B3E-7D6A2F11AA01
+ PACKAGE_VERSION = 0.01
+
+[Includes]
+ Include
+ Library/LvglLib
+ Library/LvglLib/lvgl
+
+[LibraryClasses]
+ ## @libraryclass Shared LVGL build (core + SW renderer + UEFI port).
+ LvglCoreLib|Include/Library/LvglCoreLib.h
diff --git a/Experimental/LvglSpikePkg/LvglSpikeRiscV.dsc b/Experimental/LvglSpikePkg/LvglSpikeRiscV.dsc
new file mode 100644
index 0000000..9bcfa9f
--- /dev/null
+++ b/Experimental/LvglSpikePkg/LvglSpikeRiscV.dsc
@@ -0,0 +1,44 @@
+## @file
+# Minimal self-contained DSC for the experimental/lvgl-spike RISC-V build
+# validation. Builds just the LvglSpikeProbe UEFI_APPLICATION (LVGL core +
+# software renderer + upstream UEFI port, with the LoongArch64/RISC-V64
+# arch-gate patch) for RISCV64. Per repo convention RISC-V is build-only
+# (no run/capture helper), so this validates compile+link, not render.
+#
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ PLATFORM_NAME = LvglSpikeRiscV
+ PLATFORM_GUID = 9B2E4D71-0A3C-4F65-8E2D-1C7A6F0B1103
+ PLATFORM_VERSION = 0.01
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/LvglSpikeRiscV
+ SUPPORTED_ARCHITECTURES = RISCV64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses]
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+
+[Components]
+ LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.inf {
+
+ # Force-link the compiler intrinsics (memcpy/memset/memmove/memcmp) GCC
+ # emits for aggregate copy/zero in LVGL, even under -ffreestanding.
+ NULL|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+ }
diff --git a/Experimental/LvglSpikePkg/README.md b/Experimental/LvglSpikePkg/README.md
new file mode 100644
index 0000000..42d5f9b
--- /dev/null
+++ b/Experimental/LvglSpikePkg/README.md
@@ -0,0 +1,103 @@
+# LvglSpikePkg — experimental LVGL rendering-backend evaluation
+
+**Status: experimental spike. Not shipped. Never in a default firmware overlay or
+in `ModernSetupApp`.** Lives only on the `experimental/lvgl-spike` branch.
+
+## Why this exists
+
+To answer one question before considering LVGL as an open-source rendering
+backend for ModernSetupPkg:
+
+> Does LVGL (core + software renderer + its upstream UEFI port) **build and
+> render under edk2 on a hard architecture** — LoongArch64 — not just on X64
+> where downstream LVGL-UEFI ports already work?
+
+This is the single objection that actually gated the "switch backend?" decision:
+the package's entire value is *one* Setup UX across OVMF-X64 / ArmVirt-AArch64 /
+LoongArch64 / RISC-V64. If LVGL could not survive that, the question was moot.
+
+## Result
+
+| Arch | Build (edk2 GCC) | Render | Notes |
+|---|---|---|---|
+| X64 | ✅ (proven upstream by LvglPkg) | ✅ upstream | not re-done here |
+| AArch64 | ✅ already in LVGL's UEFI arch allowlist | — | no patch needed |
+| **LoongArch64** | ✅ **PASS** — 465 objs, `LvglSpikeProbe.efi` PE32+ LoongArch | ✅ **PASS on real hardware** | the crux; see below |
+| RISC-V64 | ⚠️ arch-gate compiles; full build blocked by local toolchain | — (repo is build-only for RISC-V) | environment limit, not LVGL |
+
+**LoongArch64 is the headline:** `LvglSpikeProbe.efi` compiles, links, and was
+run on **real LoongArch silicon**, drawing an LVGL UI (themed background, title,
+rounded button) straight to the GOP framebuffer. Soft-float — the one concern
+that static reading can't settle — is a non-issue: `LV_USE_FLOAT 0` keeps the SW
+renderer integer-only and the whole closure linked cleanly.
+
+### RISC-V64 caveat (environment, not LVGL)
+
+The baseline's RISC-V branch compiles (the `lv_uefi.h` gate passes). The full
+build fails only because the host has `riscv64-linux-gnu-gcc` (a glibc Linux
+cross-compiler) instead of the bare-metal `riscv64-unknown-elf-gcc` edk2 expects:
+LVGL's `#include ` chains into glibc, which then needs
+`gnu/stubs-lp64.h` — absent because edk2 builds RISC-V with soft-float `-mabi=lp64`
+while the installed glibc is `lp64d`. LoongArch avoided this only because its
+glibc ABI happened to match edk2's flags. With a bare-metal RISC-V toolchain (or
+by redirecting LVGL's libc includes to edk2 types) this clears; it is not an
+LVGL problem.
+
+## The upstream contribution (now in the baseline)
+
+LVGL's UEFI port originally hard-`#error`ed on any arch outside
+`{x86_64, i386, aarch64}`. Adding LoongArch64 + RISC-V64 was a small, coherent
+change across exactly three sites:
+
+| File | Role | Change |
+|---|---|---|
+| `src/drivers/uefi/lv_uefi.h` | the `#error` gate + 64-bit size assert | add `__loongarch_lp64` / `__riscv && __riscv_xlen==64` branches (separate, to keep the per-arch `__LV_UEFI_ARCH_*` markers correct) |
+| `src/misc/lv_types.h` | `LV_ARCH_64` fallback list | append both arches (main path already covered via `__UINTPTR_MAX__`) |
+| `tests/makefiles_uefi/efi.h` | CI standalone UEFI test types | fold both LP64 arches into the existing aarch64 type block |
+
+This support has since landed **upstream** and the pinned `External/lvgl` baseline
+is bumped to a commit that includes it. The submodule is consumed **pristine** —
+there is no local patch and no build-time patching. (LVGL stays an unmodified
+upstream submodule.)
+
+## Integration notes learned
+
+- **Memory:** `LV_USE_STDLIB_MALLOC = LV_STDLIB_BUILTIN` gives only a 64 KB static
+ pool — too small for a display draw buffer; LVGL hangs on allocation. Use
+ `LV_STDLIB_CUSTOM` + `LV_UEFI_USE_MEMORY_SERVICES 1` so malloc routes to UEFI
+ `AllocatePool` (`lv_mem_core_uefi.c`).
+- **Headers:** removed LvglPkg's libc-shim headers (`limits.h`, `stdint.h`, …)
+ which shadowed the compiler's freestanding headers (`CHAR_BIT` undeclared).
+- **lv_conf discovery:** `-DLV_CONF_INCLUDE_SIMPLE`, because `lvgl/` is a symlink
+ out to `External/lvgl`, so LVGL's default `"../../lv_conf.h"` escapes the dir.
+- **Render path:** this probe is a standalone UEFI application that draws
+ `lv_draw_sw → EFI_GRAPHICS_OUTPUT_PROTOCOL.Blt()` directly. It does **not** go
+ through HII / FormBrowser / any DisplayEngine — same shape as `ModernSetupApp`,
+ not the DisplayEngine-replacement shape (that would be the separate
+ `LvglDisplayEngineDxe` model, deliberately not vendored here — it carries
+ AMI-"Aptio" branded chrome we must not reuse).
+
+## Build
+
+```sh
+Scripts/bootstrap-edk2.sh # if not already done
+Scripts/build-lvgl-spike-loongarch.sh # -> Build/LvglSpike/.../LvglSpikeProbe.efi
+TARGET=DEBUG Scripts/build-lvgl-spike-riscv.sh # needs a bare-metal riscv64 toolchain
+```
+The pinned `External/lvgl` baseline already carries LoongArch64/RISC-V64 UEFI
+support upstream, so the scripts consume the submodule pristine — no patching.
+
+## Recommendation
+
+The feasibility blocker — "an LVGL backend would break the XArch promise" — is
+**empirically cleared on real LoongArch hardware** with only a ~3-site change
+that is now upstream in LVGL. This does **not** by itself mandate switching; it means the
+decision can now be made on merits (LVGL's widget/text-editing richness and AA
+rendering vs. dependency weight, the boundary/maintenance cost, and the existing
+`ModernUiEngineLib` investment) rather than being blocked on portability.
+
+## Attribution
+
+Builds on LVGL (lvgl/lvgl), LvglPkg (hamitcan99), and the original UEFI port by
+YangGangUEFI — all MIT. See [`REFERENCES.md`](REFERENCES.md) for exactly what is
+used from each and what is deliberately not reused.
diff --git a/Experimental/LvglSpikePkg/REFERENCES.md b/Experimental/LvglSpikePkg/REFERENCES.md
new file mode 100644
index 0000000..fde2aed
--- /dev/null
+++ b/Experimental/LvglSpikePkg/REFERENCES.md
@@ -0,0 +1,46 @@
+# References & attribution — LvglSpikePkg
+
+This experimental package builds on prior open-source work. All third-party code
+used here is MIT-licensed; this file records what we use from each project and
+what we deliberately do **not** reuse. Copyright headers in copied files are kept
+intact, as MIT requires.
+
+## LVGL — https://github.com/lvgl/lvgl
+
+- **License:** MIT.
+- **Use:** vendored directly as the `External/lvgl` git submodule, pinned to a
+ tagged **v9.5.0**-derived baseline that already carries LoongArch64/RISC-V64
+ UEFI support upstream. This is the actual rendering engine (core, software
+ renderer, fonts, widgets, and the upstream UEFI port under
+ `src/drivers/uefi`). The submodule keeps LVGL's own `LICENCE.txt`.
+- **Upstream contribution back:** the LoongArch64 / RISC-V64 arch-gate change
+ was contributed to lvgl/lvgl and is now in the pinned baseline. The submodule
+ is consumed **pristine** — no local patch, no build-time patching; LVGL stays
+ an unmodified upstream submodule.
+
+## LvglPkg — https://github.com/hamitcan99/LvglPkg
+
+- **License:** MIT.
+- **Use:** EDK2-integration reference. The `Library/LvglLib` baseline in this
+ package (the `lv_conf.h`, the INF source-list shape, and the UEFI port glue)
+ was adapted from LvglPkg's `Library/LvglLib`; copied files retain their
+ original `Copyright (c) 2024, Yang Gang` headers. The forthcoming
+ `LvglDisplayEngineDxe` (LVGL behind `EDKII_FORM_DISPLAY_ENGINE_PROTOCOL`,
+ mapping `FORM_DISPLAY_ENGINE_STATEMENT` to LVGL widgets) follows the pattern of
+ LvglPkg's `LvglDisplayEngineDxe` / `LvglFormRenderer.c`.
+- **Deliberately NOT reused:** LvglPkg's `AptioWallpaper.c` / `LvglAptioChrome.*`.
+ "Aptio" is AMI's commercial BIOS brand; per this repo's "no commercial-IBV
+ asset reuse" rule we use original chrome only.
+
+## YangGangUEFI — https://github.com/YangGangUEFI
+
+- **License:** MIT.
+- **Use:** Yang Gang is the original author of the LVGL-on-UEFI port that LvglPkg
+ forked from. Credited here as the origin of the EDK2/LVGL integration approach
+ this spike learns from.
+
+---
+
+*Visual/architectural references are fine; copied artwork, fonts, icons, strings,
+or vendor-branded assets are not. See the package `README.md` for the spike
+findings and `CLAUDE.md` for the boundary rules.*
diff --git a/External/lvgl b/External/lvgl
new file mode 160000
index 0000000..4cdddfe
--- /dev/null
+++ b/External/lvgl
@@ -0,0 +1 @@
+Subproject commit 4cdddfe4ae6aaf08c713d86673f5675875415998
diff --git a/Include/ModernUi/ModernUiEngine.h b/Include/ModernUi/ModernUiEngine.h
index 261b454..367e5cf 100644
--- a/Include/ModernUi/ModernUiEngine.h
+++ b/Include/ModernUi/ModernUiEngine.h
@@ -207,6 +207,38 @@ ModernUiEngineDrawValue (
IN CONST MODERN_UI_THEME *Theme
);
+/**
+ Draw a small non-semantic control-type affordance inside a cue box.
+
+ This is the single shared affordance vocabulary used by both the App value
+ lane and the in-setup DisplayEngine row cue, so a checkbox, drop-down,
+ numeric, date/time, password, string, ordered-list, or action control reads
+ identically in both surfaces. The affordance is composed entirely from
+ renderer fill/stroke/triangle primitives and reflects only the control kind;
+ it never reads or mutates any stored value or HII state.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] CueRect Square pixel box to draw the affordance in. Boxes
+ smaller than 6x6 are ignored.
+ @param[in] Type Control value type selecting the affordance shape.
+ ModernUiValueNone / ModernUiValueText draw nothing.
+ @param[in] CueColor High-contrast mark / stroke color.
+ @param[in] FillColor Subtle inner fill color (checkbox interior).
+
+ @retval EFI_SUCCESS Affordance was drawn (or nothing was needed).
+ @retval EFI_INVALID_PARAMETER Context is NULL.
+ @retval others Status from the first failing renderer primitive.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiEngineDrawControlCue (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT CueRect,
+ IN MODERN_UI_VALUE_TYPE Type,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL CueColor,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColor
+ );
+
/**
Draw a popup surface.
diff --git a/Include/ModernUi/ModernUiRenderer.h b/Include/ModernUi/ModernUiRenderer.h
index bf004c9..52bd828 100644
--- a/Include/ModernUi/ModernUiRenderer.h
+++ b/Include/ModernUi/ModernUiRenderer.h
@@ -31,6 +31,12 @@ typedef struct {
UINTN Height;
} MODERN_UI_RENDER_CONTEXT;
+typedef enum {
+ ModernUiTriDown, ///< Apex points down (drop-down chevron).
+ ModernUiTriUp, ///< Apex points up.
+ ModernUiTriRight ///< Apex points right (navigate / activate arrow).
+} MODERN_UI_TRI_DIR;
+
/**
Blend two GOP colors by percentage weight.
@@ -123,6 +129,31 @@ ModernUiStrokeRect (
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
);
+/**
+ Fill an isosceles triangle inscribed in a rectangle.
+
+ The triangle is built from one-pixel renderer fill spans so it renders
+ identically through the GOP and LVGL backends. Used to compose chevron and
+ arrow control affordances.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Bounding rectangle. Zero width or height is ignored.
+ @param[in] Dir Apex direction (down / up / right).
+ @param[in] Color Fill color.
+
+ @retval EFI_SUCCESS Triangle was drawn (or Rect was empty).
+ @retval EFI_INVALID_PARAMETER Context is NULL.
+ @retval others Status from the first failing fill span.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiFillTriangle (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN MODERN_UI_TRI_DIR Dir,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
+ );
+
/**
Return the expected pixel width for a UCS-2 string.
diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c
index 4002558..3123826 100644
--- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c
+++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c
@@ -54,21 +54,6 @@ ModernDisplayDrawStatementRowAccents (
IN CONST MODERN_UI_THEME *Theme
);
-STATIC
-VOID
-ModernDisplayDrawStatementValueLane (
- IN CONST MODERN_UI_RECT *RowRect,
- IN CONST MODERN_DISPLAY_FORM_ROW *FormRow,
- IN CONST MODERN_UI_THEME *Theme
- );
-
-STATIC
-VOID
-ModernDisplayDrawStatementValueLaneCue (
- IN CONST MODERN_UI_RECT *LaneRect,
- IN CONST MODERN_DISPLAY_FORM_ROW *FormRow,
- IN CONST MODERN_UI_THEME *Theme
- );
STATIC
UINTN
@@ -896,109 +881,47 @@ ModernDisplayFormRowAccentColor (
}
/**
- Draw a subtle editable-value cue inside the value lane.
-
- Native FormBrowser remains responsible for printing the value text. This helper
- only adds a GOP outline, underline, and trailing cap so the existing value area
- reads as an editable chip without changing statement dimensions or wrapping.
-
- @param[in] LaneRect Pixel value-lane rectangle. Must not be NULL.
- @param[in] FormRow Private row model. Must not be NULL.
- @param[in] Theme Theme token table. Must not be NULL.
-**/
-STATIC
-VOID
-ModernDisplayDrawStatementValueLaneCue (
- IN CONST MODERN_UI_RECT *LaneRect,
- IN CONST MODERN_DISPLAY_FORM_ROW *FormRow,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL OutlineColor;
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL AccentColor;
- UINTN CapWidth;
-
- if ((LaneRect == NULL) || (FormRow == NULL) || (Theme == NULL) || (LaneRect->Width < 24) || (LaneRect->Height < 8)) {
- return;
- }
-
- AccentColor = ModernDisplayFormRowAccentColor (FormRow, Theme);
- OutlineColor = ((FormRow->State & ModernDisplayFormRowStateSelected) != 0) ?
- Theme->AccentYellow :
- ModernUiBlendColor (Theme->Border, Theme->BackgroundBlack, 62);
- CapWidth = MIN (4, MAX (2, LaneRect->Width / 24));
-
- ModernUiStrokeRect (&mModernRenderContext, *LaneRect, OutlineColor);
- ModernUiFillRect (
- &mModernRenderContext,
- (MODERN_UI_RECT){ LaneRect->X + 2, LaneRect->Y + LaneRect->Height - 2, LaneRect->Width - 4, 1 },
- ModernUiBlendColor (AccentColor, Theme->BackgroundBlack, 60)
- );
- ModernUiFillRect (
- &mModernRenderContext,
- (MODERN_UI_RECT){ LaneRect->X + LaneRect->Width - CapWidth - 2, LaneRect->Y + 3, CapWidth, LaneRect->Height - 6 },
- ModernUiBlendColor (AccentColor, Theme->BackgroundBlack, 72)
- );
-}
+ Map a DisplayEngine form-row kind to the shared engine control value type.
-/**
- Draw a subtle value lane on highlighted/editable rows.
+ This lets the in-setup DisplayEngine reuse the exact same per-control
+ affordance vocabulary (ModernUiEngineDrawControlCue) that the front-page App
+ value lane uses, so the same control type reads identically in both surfaces.
+ Text-only / subtitle / unknown kinds map to ModernUiValueNone (no cue).
- Native FormBrowser still prints prompt/value text. This helper only paints a
- GOP background hint on the right side of interactive rows so users can
- distinguish the value/edit region from the prompt region.
+ @param[in] Kind DisplayEngine form-row kind.
- @param[in] RowRect Pixel row rectangle. Must not be NULL.
- @param[in] FormRow Private row model. Must not be NULL.
- @param[in] Theme Theme token table. Must not be NULL.
+ @return The matching MODERN_UI_VALUE_TYPE, or ModernUiValueNone when the kind
+ carries no control affordance.
**/
STATIC
-VOID
-ModernDisplayDrawStatementValueLane (
- IN CONST MODERN_UI_RECT *RowRect,
- IN CONST MODERN_DISPLAY_FORM_ROW *FormRow,
- IN CONST MODERN_UI_THEME *Theme
+MODERN_UI_VALUE_TYPE
+ModernDisplayKindToValueType (
+ IN MODERN_DISPLAY_FORM_ROW_KIND Kind
)
{
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL LaneColor;
- MODERN_UI_RECT LaneRect;
- UINTN LaneWidth;
- UINTN LaneX;
- UINTN LaneY;
- UINTN LaneHeight;
-
- if ((RowRect == NULL) || (FormRow == NULL) || (Theme == NULL) || (RowRect->Width < 160) || (RowRect->Height < 12)) {
- return;
- }
-
- if (ModernDisplayFormRowIsTextOnly (FormRow->Kind) || ((FormRow->State & ModernDisplayFormRowStateHighlighted) == 0)) {
- return;
- }
-
- if (((FormRow->State & ModernDisplayFormRowStateDisabled) != 0) || ((FormRow->State & ModernDisplayFormRowStateReadOnly) != 0)) {
- return;
- }
-
- LaneWidth = MIN (MAX (120, RowRect->Width / 3), RowRect->Width - 48);
- LaneX = RowRect->X + MAX (160, RowRect->Width / 2);
- if ((LaneX + LaneWidth + 10) > (RowRect->X + RowRect->Width)) {
- LaneWidth = RowRect->X + RowRect->Width - LaneX - 10;
- }
-
- if (LaneWidth < 64) {
- return;
+ switch (Kind) {
+ case ModernDisplayFormRowCheckbox:
+ return ModernUiValueCheckbox;
+ case ModernDisplayFormRowChoice:
+ return ModernUiValueOneOf;
+ case ModernDisplayFormRowOrderedList:
+ return ModernUiValueOrderedList;
+ case ModernDisplayFormRowNumeric:
+ return ModernUiValueNumeric;
+ case ModernDisplayFormRowDate:
+ case ModernDisplayFormRowTime:
+ return ModernUiValueDateTime;
+ case ModernDisplayFormRowPassword:
+ return ModernUiValuePassword;
+ case ModernDisplayFormRowString:
+ return ModernUiValueString;
+ case ModernDisplayFormRowReference:
+ case ModernDisplayFormRowAction:
+ case ModernDisplayFormRowResetButton:
+ return ModernUiValueAction;
+ default:
+ return ModernUiValueNone;
}
-
- LaneY = RowRect->Y + 4;
- LaneHeight = RowRect->Height - 8;
- LaneColor = ((FormRow->State & ModernDisplayFormRowStateSelected) != 0) ?
- ModernUiBlendColor (Theme->AccentOrange, Theme->BackgroundBlack, 32) :
- ModernUiBlendColor (Theme->SurfaceRaised, Theme->BackgroundBlack, 55);
- LaneRect = (MODERN_UI_RECT){ LaneX, LaneY, LaneWidth, LaneHeight };
-
- ModernUiFillRect (&mModernRenderContext, LaneRect, LaneColor);
- ModernUiFillRect (&mModernRenderContext, (MODERN_UI_RECT){ LaneX, LaneY, 3, LaneHeight }, Theme->AccentYellow);
- ModernDisplayDrawStatementValueLaneCue (&LaneRect, FormRow, Theme);
}
/**
@@ -1123,10 +1046,96 @@ ModernDisplayDrawStatementRow (
}
ModernUiEngineDrawRows (&mModernRenderContext, &RowModel, 1, Theme);
- ModernDisplayDrawStatementValueLane (&RowRect, &FormRow, Theme);
ModernDisplayDrawStatementRowAccents (&RowRect, &FormRow, Theme);
}
+/**
+ Draw a per-opcode control affordance over an already-painted statement row.
+
+ This runs AFTER native FormBrowser has printed the row's prompt/value text
+ (and its highlight background), so the affordance is composited on top rather
+ than being overpainted. It paints only a small non-semantic cue glyph at the
+ row's right edge (clear of the value text) to make each control type read
+ distinctly. It classifies already-materialized statement data and never reads,
+ writes, or owns any HII/FormBrowser value or semantics.
+
+ @param[in] FormData DisplayEngine form that owns Statement. May be NULL.
+ @param[in] Statement Statement to classify. May be NULL (then no cue).
+ @param[in] Column Text-grid column where the row starts.
+ @param[in] Row Text-grid row of the statement.
+ @param[in] Width Text-grid column count of the row.
+ @param[in] Highlight TRUE when the row currently has keyboard highlight.
+ @param[in] Selected TRUE when the row is in edit/selection mode.
+**/
+VOID
+EFIAPI
+ModernDisplayDrawStatementRowCue (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData OPTIONAL,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement OPTIONAL,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN UINTN Width,
+ IN BOOLEAN Highlight,
+ IN BOOLEAN Selected
+ )
+{
+ CONST MODERN_UI_THEME *Theme;
+ UINTN CellWidth;
+ UINTN CellHeight;
+ UINTN X;
+ UINTN Y;
+ UINTN PixelWidth;
+ UINTN CueSide;
+ MODERN_DISPLAY_FORM_ROW FormRow;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL CueColor;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColor;
+
+ if ((Statement == NULL) || (Width == 0) || EFI_ERROR (ModernDisplayEnsureRenderer ())) {
+ return;
+ }
+
+ if (EFI_ERROR (ModernDisplayClassifyStatementForForm (FormData, Statement, Highlight, Selected, &FormRow))) {
+ return;
+ }
+
+ //
+ // Only editable controls get a type affordance; text/subtitle and
+ // disabled/read-only rows do not.
+ //
+ if (ModernDisplayFormRowIsTextOnly (FormRow.Kind) ||
+ ((FormRow.State & (ModernDisplayFormRowStateDisabled | ModernDisplayFormRowStateReadOnly)) != 0))
+ {
+ return;
+ }
+
+ Theme = ModernUiGetTheme ();
+ ModernDisplayGetCellMetrics (&CellWidth, &CellHeight);
+
+ X = Column * CellWidth;
+ Y = Row * CellHeight;
+ PixelWidth = Width * CellWidth;
+ if ((PixelWidth < 48) || (CellHeight < 10)) {
+ return;
+ }
+
+ CueSide = MIN (CellHeight - 6, 14);
+
+ //
+ // High-contrast cue: dark on the bright selected band, bright yellow on the
+ // dark surface. The cue sits at the row's right edge, clear of value text.
+ //
+ CueColor = (Highlight || Selected) ? Theme->BackgroundBlack : Theme->AccentYellow;
+ FillColor = ModernUiBlendColor (Theme->AccentOrange, Theme->BackgroundBlack, 70);
+
+ ModernUiEngineDrawControlCue (
+ &mModernRenderContext,
+ (MODERN_UI_RECT){ X + PixelWidth - CueSide - 8, Y + (CellHeight - CueSide) / 2, CueSide, CueSide },
+ ModernDisplayKindToValueType (FormRow.Kind),
+ CueColor,
+ FillColor
+ );
+}
+
/**
Draw the modern DisplayEngine shell behind the native FormBrowser content.
diff --git a/Library/ModernUiEngineLib/ModernUiEngineLib.c b/Library/ModernUiEngineLib/ModernUiEngineLib.c
index 95da6ae..5ff3874 100644
--- a/Library/ModernUiEngineLib/ModernUiEngineLib.c
+++ b/Library/ModernUiEngineLib/ModernUiEngineLib.c
@@ -962,6 +962,7 @@ ModernUiEngineDrawValue (
)
{
MODERN_UI_RECT Rect;
+ UINTN CueSide;
if ((Context == NULL) || (Value == NULL) || (Theme == NULL)) {
return EFI_INVALID_PARAMETER;
@@ -977,6 +978,25 @@ ModernUiEngineDrawValue (
Rect.Width = MODERN_UI_ROW_VALUE_BOX_WIDTH;
}
+ //
+ // Paint the shared per-type affordance just left of the value lane so a
+ // checkbox, drop-down, numeric, date/time, password, string, ordered-list,
+ // or action control reads the same here as in the in-setup DisplayEngine.
+ // Plain text values carry no affordance.
+ //
+ if ((Value->Type != ModernUiValueText) && (Rect.X > Value->Rect.X)) {
+ CueSide = MIN ((Rect.Height > 6) ? (Rect.Height - 6) : 0, 14);
+ if (CueSide >= 6) {
+ ModernUiEngineDrawControlCue (
+ Context,
+ (MODERN_UI_RECT){ Rect.X - CueSide - 8, Rect.Y + (Rect.Height - CueSide) / 2, CueSide, CueSide },
+ Value->Type,
+ Theme->AccentYellow,
+ ModernUiBlendColor (Theme->AccentOrange, Theme->BackgroundBlack, 70)
+ );
+ }
+ }
+
if ((Value->Type == ModernUiValueOneOf) || (Value->Type == ModernUiValueText)) {
return ModernUiDrawValueBox (Context, Rect, Value->Text, Value->Selected, Theme);
}
@@ -992,6 +1012,126 @@ ModernUiEngineDrawValue (
);
}
+EFI_STATUS
+EFIAPI
+ModernUiEngineDrawControlCue (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT CueRect,
+ IN MODERN_UI_VALUE_TYPE Type,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL CueColor,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColor
+ )
+{
+ UINTN W;
+ UINTN H;
+ UINTN Index;
+ UINTN DotSide;
+ EFI_STATUS Status;
+
+ if (Context == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((CueRect.Width < 6) || (CueRect.Height < 6)) {
+ return EFI_SUCCESS;
+ }
+
+ W = CueRect.Width;
+ H = CueRect.Height;
+ Status = EFI_SUCCESS;
+
+ switch (Type) {
+ case ModernUiValueCheckbox:
+ //
+ // Toggle box: the stored on/off is still shown as value text; this only
+ // marks the row as a checkbox.
+ //
+ Status = ModernUiStrokeRect (Context, CueRect, CueColor);
+ if (!EFI_ERROR (Status)) {
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ CueRect.X + 3, CueRect.Y + 3, W - 6, H - 6 }, FillColor);
+ }
+
+ break;
+
+ case ModernUiValueOneOf:
+ //
+ // Drop-down chevron.
+ //
+ Status = ModernUiFillTriangle (Context, CueRect, ModernUiTriDown, CueColor);
+ break;
+
+ case ModernUiValueOrderedList:
+ //
+ // Up / down reorder chevrons.
+ //
+ Status = ModernUiFillTriangle (Context, (MODERN_UI_RECT){ CueRect.X, CueRect.Y, W, H / 2 - 1 }, ModernUiTriUp, CueColor);
+ if (!EFI_ERROR (Status)) {
+ Status = ModernUiFillTriangle (Context, (MODERN_UI_RECT){ CueRect.X, CueRect.Y + H / 2 + 1, W, H / 2 - 1 }, ModernUiTriDown, CueColor);
+ }
+
+ break;
+
+ case ModernUiValueNumeric:
+ //
+ // Adjust indicator: a plus mark.
+ //
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ CueRect.X + 2, CueRect.Y + H / 2 - 1, W - 4, 2 }, CueColor);
+ if (!EFI_ERROR (Status)) {
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ CueRect.X + W / 2 - 1, CueRect.Y + 2, 2, H - 4 }, CueColor);
+ }
+
+ break;
+
+ case ModernUiValueDateTime:
+ //
+ // Two segment ticks (three-field value).
+ //
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ CueRect.X + W / 3, CueRect.Y + 1, 2, H - 2 }, CueColor);
+ if (!EFI_ERROR (Status)) {
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ CueRect.X + (W * 2) / 3, CueRect.Y + 1, 2, H - 2 }, CueColor);
+ }
+
+ break;
+
+ case ModernUiValuePassword:
+ //
+ // A short row of masked dots.
+ //
+ DotSide = MAX (2, W / 5);
+ for (Index = 0; Index < 3; Index++) {
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ CueRect.X + 2 + Index * (DotSide + 1), CueRect.Y + H / 2 - DotSide / 2, DotSide, DotSide },
+ CueColor
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ break;
+
+ case ModernUiValueString:
+ //
+ // Text caret.
+ //
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ CueRect.X + W / 2, CueRect.Y + 1, 2, H - 2 }, CueColor);
+ break;
+
+ case ModernUiValueAction:
+ //
+ // Navigate / activate arrow.
+ //
+ Status = ModernUiFillTriangle (Context, CueRect, ModernUiTriRight, CueColor);
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
EFI_STATUS
EFIAPI
ModernUiEngineDrawPopup (
diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c
new file mode 100644
index 0000000..2604f74
--- /dev/null
+++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c
@@ -0,0 +1,758 @@
+/** @file
+ LVGL-backed renderer library for ModernSetupPkg (experimental/lvgl-spike).
+
+ This is a drop-in replacement for the hand-rolled GOP rasterizer
+ (Library/ModernUiRendererLib). It implements the identical
+ ModernUiRenderer.h API, but instead of issuing GOP fills and bitmap
+ blits directly, every primitive is composited by LVGL's software draw
+ pipeline:
+
+ - All geometry (fills, borders, panels, rows, cards, progress, value
+ boxes, drop-downs) is drawn with lv_draw_rect.
+ - ASCII text is drawn with lv_draw_label using LVGL's Montserrat font.
+ - Non-ASCII (CJK) runs fall back to the firmware HII font composited
+ into the same buffer, because LVGL ships no bundled CJK coverage.
+
+ The bridge is a persistent full-screen XRGB8888 canvas that acts as a
+ shadow framebuffer. Each primitive renders into the canvas through an
+ LVGL draw layer and then BLTs only its bounding region to the live GOP
+ surface. This keeps the imperative (immediate-mode) renderer contract
+ that ModernDisplayEngineDxe and ModernSetupApp depend on, while routing
+ all actual pixel generation through LVGL.
+
+ SetupBrowser / FormBrowser / HII ownership is unchanged; this library
+ only paints.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ Author: MarsDoge (Dongyan Qian)
+ Open source: https://github.com/MarsDoge/ModernSetupPkg
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include "../ModernUiRendererLib/ModernUiGlyphs.h"
+#include "../ModernUiRendererLib/ModernUiRendererInternal.h"
+
+#define MODERN_UI_TEXT_CELL_HEIGHT MODERN_UI_BUILTIN_GLYPH_HEIGHT
+
+//
+// LVGL bridge state. The library is statically linked into a single
+// consuming module (the display engine or the app), so one shadow canvas
+// per module instance is sufficient. mLvInitDone guards the one-time
+// lv_uefi_init()/lv_init() handshake against repeated ModernUiRendererInit().
+//
+STATIC BOOLEAN mLvInitDone = FALSE;
+STATIC BOOLEAN mLvglReady = FALSE;
+STATIC lv_display_t *mDisplay = NULL;
+STATIC lv_obj_t *mCanvas = NULL;
+STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mCanvasBuf = NULL;
+STATIC VOID *mDispBuf = NULL;
+STATIC UINTN mCanvasW = 0;
+STATIC UINTN mCanvasH = 0;
+STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL *mGop = NULL;
+STATIC EFI_HII_FONT_PROTOCOL *mFont = NULL;
+
+
+/**
+ Convert a GOP BLT pixel to an LVGL color.
+
+ @param[in] Pixel Source GOP pixel. Reserved is ignored.
+
+ @return Equivalent lv_color_t.
+**/
+STATIC
+lv_color_t
+ToLvColor (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Pixel
+ )
+{
+ return lv_color_make (Pixel.Red, Pixel.Green, Pixel.Blue);
+}
+
+
+/**
+ No-op LVGL display flush callback.
+
+ The shadow canvas is composited and BLT'd by this library directly; the
+ bridge display is never refreshed through LVGL's timer pipeline, so this
+ callback only acknowledges completion to satisfy the display contract.
+
+ @param[in] Display LVGL display being flushed.
+ @param[in] Area Flushed area. Unused.
+ @param[in] PxMap Pixel data. Unused.
+**/
+STATIC
+VOID
+LvglBridgeFlush (
+ IN lv_display_t *Display,
+ IN const lv_area_t *Area,
+ IN UINT8 *PxMap
+ )
+{
+ (VOID)Area;
+ (VOID)PxMap;
+ lv_display_flush_ready (Display);
+}
+
+
+/**
+ Push a rectangular region of the shadow canvas to the live GOP surface.
+
+ The region is clipped to the canvas extent. NULL/empty regions and a
+ not-yet-initialized bridge are ignored.
+
+ @param[in] X Left coordinate in canvas/screen pixels.
+ @param[in] Y Top coordinate in canvas/screen pixels.
+ @param[in] Width Region width in pixels.
+ @param[in] Height Region height in pixels.
+**/
+STATIC
+VOID
+BltCanvasRegion (
+ IN UINTN X,
+ IN UINTN Y,
+ IN UINTN Width,
+ IN UINTN Height
+ )
+{
+ if (!mLvglReady || (mGop == NULL) || (mCanvasBuf == NULL)) {
+ return;
+ }
+
+ if ((X >= mCanvasW) || (Y >= mCanvasH) || (Width == 0) || (Height == 0)) {
+ return;
+ }
+
+ if ((X + Width) > mCanvasW) {
+ Width = mCanvasW - X;
+ }
+
+ if ((Y + Height) > mCanvasH) {
+ Height = mCanvasH - Y;
+ }
+
+ mGop->Blt (
+ mGop,
+ mCanvasBuf,
+ EfiBltBufferToVideo,
+ X,
+ Y,
+ X,
+ Y,
+ Width,
+ Height,
+ mCanvasW * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+}
+
+
+/**
+ Initialize a render context and the LVGL shadow-canvas bridge.
+
+ On the first call this performs the one-time LVGL UEFI handshake
+ (lv_uefi_init() must precede lv_init()), then creates a bridge display
+ and a full-screen XRGB8888 canvas sized to the active GOP mode. Later
+ calls reuse the existing bridge and only refresh the cached context.
+
+ @param[out] Context Render context to initialize. Must not be NULL. On
+ success, Width and Height describe the active GOP mode.
+
+ @retval EFI_SUCCESS Context and bridge were initialized.
+ @retval EFI_INVALID_PARAMETER Context is NULL.
+ @retval EFI_NOT_FOUND GOP is unavailable or has no active mode.
+ @retval EFI_OUT_OF_RESOURCES Canvas allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiRendererInit (
+ OUT MODERN_UI_RENDER_CONTEXT *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN CanvasBytes;
+ UINTN DispBytes;
+
+ if (Context == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Context, sizeof (*Context));
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **)&Context->Gop
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateProtocol (
+ &gEfiGraphicsOutputProtocolGuid,
+ NULL,
+ (VOID **)&Context->Gop
+ );
+ }
+
+ if (EFI_ERROR (Status) || (Context->Gop == NULL) || (Context->Gop->Mode == NULL) || (Context->Gop->Mode->Info == NULL)) {
+ DEBUG ((DEBUG_ERROR, "%a: GOP unavailable: %r\n", __func__, Status));
+ return EFI_NOT_FOUND;
+ }
+
+ ModernUiSelectPreferredGopMode (Context->Gop);
+ Context->Width = Context->Gop->Mode->Info->HorizontalResolution;
+ Context->Height = Context->Gop->Mode->Info->VerticalResolution;
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiFontProtocolGuid,
+ NULL,
+ (VOID **)&Context->Font
+ );
+ if (EFI_ERROR (Status)) {
+ Context->Font = NULL;
+ }
+
+ //
+ // One-time LVGL handshake. lv_uefi_init() caches the image handle and
+ // system table for the LVGL UEFI backend and must run before lv_init().
+ //
+ if (!mLvInitDone) {
+ lv_uefi_init (gImageHandle, gST);
+ lv_init ();
+ mLvInitDone = TRUE;
+ }
+
+ //
+ // (Re)build the shadow canvas if it is missing or the mode changed.
+ //
+ if (!mLvglReady || (mCanvasW != Context->Width) || (mCanvasH != Context->Height)) {
+ if (mCanvasBuf != NULL) {
+ FreePool (mCanvasBuf);
+ mCanvasBuf = NULL;
+ }
+
+ if (mDispBuf != NULL) {
+ FreePool (mDispBuf);
+ mDispBuf = NULL;
+ }
+
+ CanvasBytes = Context->Width * Context->Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ mCanvasBuf = AllocateZeroPool (CanvasBytes);
+ if (mCanvasBuf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // The bridge display is never refreshed through LVGL's timer pipeline,
+ // but a small draw buffer keeps the display contract well-formed.
+ //
+ DispBytes = Context->Width * 16 * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ mDispBuf = AllocateZeroPool (DispBytes);
+ if (mDispBuf == NULL) {
+ FreePool (mCanvasBuf);
+ mCanvasBuf = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (mDisplay == NULL) {
+ mDisplay = lv_display_create ((int32_t)Context->Width, (int32_t)Context->Height);
+ if (mDisplay == NULL) {
+ FreePool (mCanvasBuf);
+ FreePool (mDispBuf);
+ mCanvasBuf = NULL;
+ mDispBuf = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ lv_display_set_flush_cb (mDisplay, LvglBridgeFlush);
+ }
+
+ lv_display_set_buffers (
+ mDisplay,
+ mDispBuf,
+ NULL,
+ (uint32_t)DispBytes,
+ LV_DISPLAY_RENDER_MODE_PARTIAL
+ );
+
+ mCanvas = lv_canvas_create (lv_display_get_screen_active (mDisplay));
+ if (mCanvas == NULL) {
+ FreePool (mCanvasBuf);
+ FreePool (mDispBuf);
+ mCanvasBuf = NULL;
+ mDispBuf = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ lv_canvas_set_buffer (
+ mCanvas,
+ mCanvasBuf,
+ (int32_t)Context->Width,
+ (int32_t)Context->Height,
+ LV_COLOR_FORMAT_XRGB8888
+ );
+ }
+
+ mGop = Context->Gop;
+ mFont = Context->Font;
+ mCanvasW = Context->Width;
+ mCanvasH = Context->Height;
+ mLvglReady = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill a rectangle by compositing an opaque lv_draw_rect into the shadow
+ canvas, then BLT the affected region to the GOP surface.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Pixel rectangle. Zero width or height is invalid.
+ @param[in] Color Fill color.
+
+ @retval EFI_SUCCESS Rectangle was filled or clipped outside view.
+ @retval EFI_INVALID_PARAMETER Context is NULL, GOP is unavailable, or Rect is empty.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiFillRect (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
+ )
+{
+ lv_layer_t Layer;
+ lv_draw_rect_dsc_t Dsc;
+ lv_area_t Coords;
+
+ if ((Context == NULL) || (Context->Gop == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mLvglReady || (mCanvas == NULL)) {
+ return EFI_NOT_READY;
+ }
+
+ if ((Rect.X >= mCanvasW) || (Rect.Y >= mCanvasH)) {
+ return EFI_SUCCESS;
+ }
+
+ if ((Rect.X + Rect.Width) > mCanvasW) {
+ Rect.Width = mCanvasW - Rect.X;
+ }
+
+ if ((Rect.Y + Rect.Height) > mCanvasH) {
+ Rect.Height = mCanvasH - Rect.Y;
+ }
+
+ lv_canvas_init_layer (mCanvas, &Layer);
+
+ lv_draw_rect_dsc_init (&Dsc);
+ Dsc.bg_color = ToLvColor (Color);
+ Dsc.bg_opa = LV_OPA_COVER;
+
+ Coords.x1 = (int32_t)Rect.X;
+ Coords.y1 = (int32_t)Rect.Y;
+ Coords.x2 = (int32_t)(Rect.X + Rect.Width - 1);
+ Coords.y2 = (int32_t)(Rect.Y + Rect.Height - 1);
+ lv_draw_rect (&Layer, &Dsc, &Coords);
+
+ lv_canvas_finish_layer (mCanvas, &Layer);
+
+ BltCanvasRegion (Rect.X, Rect.Y, Rect.Width, Rect.Height);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Composite a UCS-2 run through the firmware HII font into the shadow canvas.
+
+ Used for non-ASCII (CJK) runs, which LVGL's bundled Latin fonts do not
+ cover. HII renders into the canvas bitmap (not direct-to-screen) so the
+ run composites with the surrounding LVGL output and is BLT'd in one pass.
+
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] Text Null-terminated UCS-2 run. Must not be NULL.
+ @param[in] PixelWidth Pre-measured run width used for the BLT region.
+ @param[in] Color Text foreground color.
+ @param[in] Background Text background color.
+
+ @retval EFI_SUCCESS Run was rendered.
+ @retval EFI_UNSUPPORTED HII Font protocol is unavailable.
+ @retval EFI_OUT_OF_RESOURCES Temporary allocation failed.
+ @retval others Status from StringToImage().
+**/
+STATIC
+EFI_STATUS
+DrawHiiCanvasRun (
+ IN UINTN X,
+ IN UINTN Y,
+ IN CONST CHAR16 *Text,
+ IN UINTN PixelWidth,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
+ )
+{
+ EFI_IMAGE_OUTPUT *Blt;
+ EFI_FONT_DISPLAY_INFO FontInfo;
+ EFI_STATUS Status;
+
+ if (mFont == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Blt = AllocateZeroPool (sizeof (*Blt));
+ if (Blt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (&FontInfo, sizeof (FontInfo));
+ FontInfo.ForegroundColor = Color;
+ FontInfo.BackgroundColor = Background;
+
+ //
+ // Target the shadow canvas bitmap (Image.Bitmap), NOT the live screen, so
+ // the run blends with the LVGL-drawn pixels already in the canvas.
+ //
+ Blt->Width = (UINT16)mCanvasW;
+ Blt->Height = (UINT16)mCanvasH;
+ Blt->Image.Bitmap = mCanvasBuf;
+
+ Status = mFont->StringToImage (
+ mFont,
+ EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP |
+ EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y |
+ EFI_HII_IGNORE_LINE_BREAK,
+ (EFI_STRING)Text,
+ &FontInfo,
+ &Blt,
+ X,
+ Y,
+ NULL,
+ NULL,
+ NULL
+ );
+ FreePool (Blt);
+
+ BltCanvasRegion (X, Y, PixelWidth, MODERN_UI_TEXT_CELL_HEIGHT);
+ return Status;
+}
+
+
+/**
+ Composite one embedded bitmap glyph into the shadow canvas.
+
+ ModernUiGlyphs.c carries the package's own CJK/icon glyph bitmaps (the
+ alpha coverage the app uses for its localized labels). These are rendered
+ here by alpha-blending each pixel against the canvas-supplied background,
+ then BLT'd. This keeps the original glyph fidelity while everything else
+ goes through LVGL; LVGL ships no CJK font, so this is the primary non-ASCII
+ path and HII is only a fallback for code points without an embedded glyph.
+
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] Glyph Embedded glyph data. Must not be NULL.
+ @param[in] Color Foreground color.
+ @param[in] Background Background color blended under the glyph coverage.
+
+ @retval EFI_SUCCESS Glyph was composited.
+ @retval EFI_INVALID_PARAMETER Glyph is NULL or the bridge is not ready.
+**/
+STATIC
+EFI_STATUS
+DrawBuiltinGlyphCanvas (
+ IN UINTN X,
+ IN UINTN Y,
+ IN CONST MODERN_UI_BUILTIN_GLYPH *Glyph,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
+ )
+{
+ UINTN Row;
+ UINTN Column;
+ UINTN Alpha;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Pixel;
+
+ if ((Glyph == NULL) || !mLvglReady || (mCanvasBuf == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Row = 0; (Row < Glyph->Height) && ((Y + Row) < mCanvasH); Row++) {
+ for (Column = 0; (Column < Glyph->Width) && ((X + Column) < mCanvasW); Column++) {
+ Alpha = Glyph->Bitmap[Row * Glyph->Width + Column];
+ Pixel = &mCanvasBuf[(Y + Row) * mCanvasW + (X + Column)];
+ Pixel->Red = (UINT8)(((UINTN)Background.Red * (255 - Alpha) + (UINTN)Color.Red * Alpha) / 255);
+ Pixel->Green = (UINT8)(((UINTN)Background.Green * (255 - Alpha) + (UINTN)Color.Green * Alpha) / 255);
+ Pixel->Blue = (UINT8)(((UINTN)Background.Blue * (255 - Alpha) + (UINTN)Color.Blue * Alpha) / 255);
+ Pixel->Reserved = 0;
+ }
+ }
+
+ BltCanvasRegion (X, Y, Glyph->Width, Glyph->Height);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Draw an ASCII run with lv_draw_label, on a freshly painted background.
+
+ The run background is filled and the label is drawn in a single LVGL
+ draw layer so both composite into the shadow canvas before one BLT.
+
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] Ascii Null-terminated ASCII (UTF-8 compatible) run.
+ @param[in] PixelWidth Pre-measured run width used for background and BLT.
+ @param[in] Color Text foreground color.
+ @param[in] Background Background color painted behind the run.
+
+ @retval EFI_SUCCESS Run was rendered (or empty width ignored).
+**/
+STATIC
+EFI_STATUS
+DrawLvglAsciiRun (
+ IN UINTN X,
+ IN UINTN Y,
+ IN CONST CHAR8 *Ascii,
+ IN UINTN PixelWidth,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
+ )
+{
+ lv_layer_t Layer;
+ lv_draw_rect_dsc_t RectDsc;
+ lv_draw_label_dsc_t LabelDsc;
+ lv_area_t BgCoords;
+ lv_area_t TextCoords;
+ int32_t BottomY;
+ UINTN BltWidth;
+
+ if ((PixelWidth == 0) || (X >= mCanvasW) || (Y >= mCanvasH)) {
+ return EFI_SUCCESS;
+ }
+
+ if ((X + PixelWidth) > mCanvasW) {
+ PixelWidth = mCanvasW - X;
+ }
+
+ BottomY = (int32_t)(Y + MODERN_UI_TEXT_CELL_HEIGHT - 1);
+ if (BottomY >= (int32_t)mCanvasH) {
+ BottomY = (int32_t)mCanvasH - 1;
+ }
+
+ //
+ // The background is painted at the layout-reserved run width (measured on
+ // the 8 px cell model the callers expect), but the label is clipped to the
+ // canvas right edge so LVGL's variable-width glyphs are not truncated. Any
+ // overshoot into a neighbouring column is repainted by the caller's next
+ // column draw. The BLT covers the wider of the two so glyph overshoot
+ // reaches the screen.
+ //
+ BgCoords.x1 = (int32_t)X;
+ BgCoords.y1 = (int32_t)Y;
+ BgCoords.x2 = (int32_t)(X + PixelWidth - 1);
+ BgCoords.y2 = BottomY;
+
+ TextCoords.x1 = (int32_t)X;
+ TextCoords.y1 = (int32_t)Y;
+ TextCoords.x2 = (int32_t)mCanvasW - 1;
+ TextCoords.y2 = BottomY;
+
+ lv_canvas_init_layer (mCanvas, &Layer);
+
+ lv_draw_rect_dsc_init (&RectDsc);
+ RectDsc.bg_color = ToLvColor (Background);
+ RectDsc.bg_opa = LV_OPA_COVER;
+ lv_draw_rect (&Layer, &RectDsc, &BgCoords);
+
+ lv_draw_label_dsc_init (&LabelDsc);
+ LabelDsc.text = (const char *)Ascii;
+ LabelDsc.font = LV_FONT_DEFAULT;
+ LabelDsc.color = ToLvColor (Color);
+ LabelDsc.opa = LV_OPA_COVER;
+ LabelDsc.align = LV_TEXT_ALIGN_LEFT;
+ lv_draw_label (&Layer, &LabelDsc, &TextCoords);
+
+ lv_canvas_finish_layer (mCanvas, &Layer);
+
+ //
+ // BLT enough width to carry glyph overshoot past the reserved cell width,
+ // bounded by the canvas. ~60% slack covers Montserrat's wider caps.
+ //
+ BltWidth = PixelWidth + (PixelWidth * 3) / 5 + MODERN_UI_ASCII_CELL_WIDTH;
+ if ((X + BltWidth) > mCanvasW) {
+ BltWidth = mCanvasW - X;
+ }
+
+ BltCanvasRegion (X, Y, BltWidth, MODERN_UI_TEXT_CELL_HEIGHT);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Draw UCS-2 text by routing each homogeneous run to the best backend:
+ text-mode graphic glyphs to LVGL rectangles, ASCII to lv_draw_label, and
+ non-ASCII (CJK) to the firmware HII font composited into the canvas.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] Text Null-terminated UCS-2 string. Must not be NULL.
+ @param[in] Color Text foreground color.
+ @param[in] Background Background color.
+
+ @retval EFI_SUCCESS Text was rendered.
+ @retval EFI_INVALID_PARAMETER Context or Text is NULL.
+ @retval others First error from a run backend.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawText (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN UINTN X,
+ IN UINTN Y,
+ IN CONST CHAR16 *Text,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
+ )
+{
+ CHAR16 Run16[MODERN_UI_TEXT_SEGMENT_MAX + 1];
+ CHAR8 Ascii[MODERN_UI_TEXT_SEGMENT_MAX + 1];
+ UINTN Index;
+ UINTN RunLen;
+ UINTN CurrentX;
+ UINTN RunWidth;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ CONST MODERN_UI_BUILTIN_GLYPH *Glyph;
+
+ if ((Context == NULL) || (Context->Gop == NULL) || (Text == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mLvglReady || (mCanvas == NULL)) {
+ return EFI_NOT_READY;
+ }
+
+ CurrentX = X;
+ ReturnStatus = EFI_SUCCESS;
+ Index = 0;
+ while (Text[Index] != L'\0') {
+ //
+ // UEFI text-mode graphic glyph: emit as LVGL rectangles, one cell each.
+ //
+ if (ModernUiIsTextModeGraphicGlyph (Text[Index])) {
+ Status = ModernUiDrawTextModeGraphicGlyph (Context, CurrentX, Y, Text[Index], Color, Background);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+
+ CurrentX += MODERN_UI_GRAPHIC_CELL_WIDTH;
+ Index++;
+ continue;
+ }
+
+ //
+ // Non-ASCII (CJK / icon): prefer the package's embedded bitmap glyph
+ // (LVGL ships no CJK font), accumulating code points without an embedded
+ // glyph into an HII sub-run that is flushed at each glyph boundary.
+ //
+ if (Text[Index] > 0x7F) {
+ RunLen = 0;
+ while ((Text[Index] != L'\0') && (Text[Index] > 0x7F) && !ModernUiIsTextModeGraphicGlyph (Text[Index])) {
+ Glyph = ModernUiFindBuiltinGlyph (Text[Index]);
+ if (Glyph != NULL) {
+ //
+ // Flush any pending HII sub-run before the embedded glyph.
+ //
+ if (RunLen > 0) {
+ Run16[RunLen] = L'\0';
+ RunWidth = ModernUiMeasureText (Run16);
+ Status = DrawHiiCanvasRun (CurrentX, Y, Run16, RunWidth, Color, Background);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+
+ CurrentX += RunWidth;
+ RunLen = 0;
+ }
+
+ Status = DrawBuiltinGlyphCanvas (CurrentX, Y, Glyph, Color, Background);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+
+ CurrentX += Glyph->Advance;
+ Index++;
+ continue;
+ }
+
+ if (RunLen >= MODERN_UI_TEXT_SEGMENT_MAX) {
+ Run16[RunLen] = L'\0';
+ RunWidth = ModernUiMeasureText (Run16);
+ Status = DrawHiiCanvasRun (CurrentX, Y, Run16, RunWidth, Color, Background);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+
+ CurrentX += RunWidth;
+ RunLen = 0;
+ }
+
+ Run16[RunLen++] = Text[Index++];
+ }
+
+ //
+ // Flush the trailing HII sub-run, if any.
+ //
+ if (RunLen > 0) {
+ Run16[RunLen] = L'\0';
+ RunWidth = ModernUiMeasureText (Run16);
+ Status = DrawHiiCanvasRun (CurrentX, Y, Run16, RunWidth, Color, Background);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+
+ CurrentX += RunWidth;
+ }
+
+ continue;
+ }
+
+ //
+ // ASCII run: LVGL lv_draw_label.
+ //
+ RunLen = 0;
+ while ((Text[Index] != L'\0') && (Text[Index] <= 0x7F) &&
+ !ModernUiIsTextModeGraphicGlyph (Text[Index]) && (RunLen < MODERN_UI_TEXT_SEGMENT_MAX))
+ {
+ Run16[RunLen] = Text[Index];
+ Ascii[RunLen] = (CHAR8)Text[Index];
+ RunLen++;
+ Index++;
+ }
+
+ Run16[RunLen] = L'\0';
+ Ascii[RunLen] = '\0';
+ RunWidth = ModernUiMeasureText (Run16);
+ Status = DrawLvglAsciiRun (CurrentX, Y, Ascii, RunWidth, Color, Background);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+
+ CurrentX += RunWidth;
+ }
+
+ return ReturnStatus;
+}
diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf
new file mode 100644
index 0000000..206ed8f
--- /dev/null
+++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf
@@ -0,0 +1,57 @@
+## @file
+# LVGL-backed renderer library for ModernSetupPkg (experimental/lvgl-spike).
+#
+# Drop-in replacement for Library/ModernUiRendererLib: same ModernUiRendererLib
+# class and ModernUiRenderer.h API, but every primitive is composited by LVGL's
+# software draw pipeline (lv_draw_rect / lv_draw_label) into a shadow canvas and
+# BLT'd to GOP. CJK runs fall back to the firmware HII font, which LVGL's bundled
+# Latin fonts do not cover.
+#
+# experimental/lvgl-spike only; selected by MODERN_SETUP_DISPLAY_ENGINE=lvgl.
+# Never wired into a default firmware overlay.
+#
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# Author: MarsDoge (Dongyan Qian)
+# Open source: https://github.com/MarsDoge/ModernSetupPkg
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ModernUiLvglRendererLib
+ FILE_GUID = 7C1E2A94-3D6B-4F12-9A8E-5B0C7D11AE20
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = ModernUiRendererLib|UEFI_APPLICATION DXE_DRIVER
+
+[Sources]
+ ModernUiRendererLib.c
+ # The backend-agnostic renderer surface and glyph table live in the GOP
+ # renderer dir (single source of truth) and are compiled into both renderers.
+ ../ModernUiRendererLib/ModernUiRendererCommon.c
+ ../ModernUiRendererLib/ModernUiGlyphs.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ModernSetupPkg/ModernSetupPkg.dec
+ LvglSpikePkg/LvglSpikePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+ LvglCoreLib
+
+[Protocols]
+ gEfiGraphicsOutputProtocolGuid
+ gEfiHiiFontProtocolGuid
+
+[BuildOptions]
+ # ModernUiRendererLib.c includes , which pulls lv_conf.h (in
+ # LvglSpikePkg/Library/LvglLib, on the package include path) via
+ # LV_CONF_INCLUDE_SIMPLE.
+ GCC:*_*_*_CC_FLAGS = -DLV_CONF_INCLUDE_SIMPLE
diff --git a/Library/ModernUiRendererLib/ModernUiRendererCommon.c b/Library/ModernUiRendererLib/ModernUiRendererCommon.c
new file mode 100644
index 0000000..8509fe5
--- /dev/null
+++ b/Library/ModernUiRendererLib/ModernUiRendererCommon.c
@@ -0,0 +1,1134 @@
+/** @file
+ Backend-agnostic shared renderer surface for ModernSetupPkg.
+
+ This translation unit is compiled verbatim into BOTH renderer libraries (the
+ GOP renderer in Library/ModernUiRendererLib and the LVGL renderer in
+ Library/ModernUiLvglRendererLib). It implements every geometry composition,
+ text-measurement, and themed-widget function of ModernUiRenderer.h on top of
+ the three backend primitives each renderer supplies: ModernUiRendererInit,
+ ModernUiFillRect, and ModernUiDrawText. See ModernUiRendererInternal.h.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ Author: MarsDoge (Dongyan Qian)
+ Open source: https://github.com/MarsDoge/ModernSetupPkg
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include "ModernUiGlyphs.h"
+#include "ModernUiRendererInternal.h"
+
+/**
+ Blend two GOP colors by percentage weight.
+
+ @param[in] Base Base color used when Weight is zero.
+ @param[in] Accent Accent color used when Weight is one hundred.
+ @param[in] Weight Accent weight in percent. Values above 100 are clamped.
+
+ @return Blended color with Reserved cleared.
+**/
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+EFIAPI
+ModernUiBlendColor (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Base,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Accent,
+ IN UINT8 Weight
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Result;
+ UINTN ClampedWeight;
+
+ ClampedWeight = MIN (Weight, 100);
+ Result.Red = (UINT8)(
+ ((UINTN)Base.Red * (100 - ClampedWeight) +
+ (UINTN)Accent.Red * ClampedWeight) / 100
+ );
+ Result.Green = (UINT8)(
+ ((UINTN)Base.Green * (100 - ClampedWeight) +
+ (UINTN)Accent.Green * ClampedWeight) / 100
+ );
+ Result.Blue = (UINT8)(
+ ((UINTN)Base.Blue * (100 - ClampedWeight) +
+ (UINTN)Accent.Blue * ClampedWeight) / 100
+ );
+ Result.Reserved = 0;
+ return Result;
+}
+
+
+/**
+ Select a preferred GOP mode when the active mode is smaller than the target.
+
+ @param[in] Gop Graphics output protocol to inspect. Must not be NULL.
+
+ @retval EFI_SUCCESS Current mode is acceptable or a better mode
+ was selected.
+ @retval EFI_INVALID_PARAMETER Gop or mode data is NULL.
+**/
+EFI_STATUS
+ModernUiSelectPreferredGopMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ UINTN InfoSize;
+ UINT32 Mode;
+ UINT32 BestMode;
+ UINTN BestArea;
+ UINTN Area;
+
+ if ((Gop == NULL) || (Gop->Mode == NULL) || (Gop->Mode->Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Gop->Mode->Info->HorizontalResolution >= MODERN_UI_TARGET_WIDTH) &&
+ (Gop->Mode->Info->VerticalResolution >= MODERN_UI_TARGET_HEIGHT))
+ {
+ return EFI_SUCCESS;
+ }
+
+ BestMode = Gop->Mode->MaxMode;
+ BestArea = MAX_UINTN;
+ for (Mode = 0; Mode < Gop->Mode->MaxMode; Mode++) {
+ Info = NULL;
+ InfoSize = 0;
+ Status = Gop->QueryMode (Gop, Mode, &InfoSize, &Info);
+ if (EFI_ERROR (Status) || (Info == NULL)) {
+ continue;
+ }
+
+ if ((Info->HorizontalResolution >= MODERN_UI_TARGET_WIDTH) &&
+ (Info->VerticalResolution >= MODERN_UI_TARGET_HEIGHT))
+ {
+ Area = (UINTN)Info->HorizontalResolution * (UINTN)Info->VerticalResolution;
+ if (Area < BestArea) {
+ BestArea = Area;
+ BestMode = Mode;
+ }
+ }
+
+ FreePool (Info);
+ }
+
+ if ((BestMode < Gop->Mode->MaxMode) && (BestMode != Gop->Mode->Mode)) {
+ Gop->SetMode (Gop, BestMode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill the full render target with one color.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Color Fill color.
+
+ @retval EFI_SUCCESS The screen was cleared.
+ @retval EFI_INVALID_PARAMETER Context is NULL or invalid.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiClear (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
+ )
+{
+ if (Context == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return ModernUiFillRect (Context, (MODERN_UI_RECT){ 0, 0, Context->Width, Context->Height }, Color);
+}
+
+
+/**
+ Draw a one-pixel rectangle border.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Pixel rectangle to outline.
+ @param[in] Color Border color.
+
+ @retval EFI_SUCCESS Border was drawn.
+ @retval EFI_INVALID_PARAMETER Context is NULL, GOP is unavailable, or Rect is empty.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiStrokeRect (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
+ )
+{
+ EFI_STATUS Status;
+
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y, Rect.Width, 1 }, Color);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y + Rect.Height - 1, Rect.Width, 1 }, Color);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y, 1, Rect.Height }, Color);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X + Rect.Width - 1, Rect.Y, 1, Rect.Height }, Color);
+}
+
+
+/**
+ Fill an isosceles triangle inscribed in a rectangle.
+
+ Built from one-pixel renderer fill spans so the shape renders identically
+ through the GOP and LVGL backends. A failed span aborts and returns its
+ status, leaving the partially drawn triangle in place.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Bounding rectangle. Zero width or height is ignored.
+ @param[in] Dir Apex direction (down / up / right).
+ @param[in] Color Fill color.
+
+ @retval EFI_SUCCESS Triangle was drawn (or Rect was empty).
+ @retval EFI_INVALID_PARAMETER Context is NULL.
+ @retval others Status from the first failing fill span.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiFillTriangle (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN MODERN_UI_TRI_DIR Dir,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
+ )
+{
+ UINTN Index;
+ UINTN Span;
+ UINTN Step;
+ EFI_STATUS Status;
+
+ if (Context == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Rect.Width == 0) || (Rect.Height == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ if (Dir == ModernUiTriRight) {
+ //
+ // Horizontal sweep: each column's height tapers toward the right apex.
+ //
+ for (Index = 0; Index < Rect.Width; Index++) {
+ Span = (Rect.Height * (Rect.Width - Index)) / Rect.Width;
+ if (Span == 0) {
+ Span = 1;
+ }
+
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X + Index, Rect.Y + (Rect.Height - Span) / 2, 1, Span },
+ Color
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Vertical sweep: ModernUiTriUp widens downward, ModernUiTriDown widens up.
+ //
+ for (Index = 0; Index < Rect.Height; Index++) {
+ Step = (Dir == ModernUiTriUp) ? (Index + 1) : (Rect.Height - Index);
+ Span = (Rect.Width * Step) / Rect.Height;
+ if (Span == 0) {
+ Span = 1;
+ }
+
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X + (Rect.Width - Span) / 2, Rect.Y + Index, Span, 1 },
+ Color
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return whether a UCS-2 character is a UEFI text-mode graphics character that
+ should be rendered as a narrow fixed-width shape.
+
+ @param[in] CodePoint UCS-2 code point to classify.
+
+ @retval TRUE CodePoint is a box, arrow, triangle, or checkbox glyph used by
+ edk2 text-mode setup UI.
+ @retval FALSE CodePoint should use normal text or built-in glyph rendering.
+**/
+BOOLEAN
+ModernUiIsTextModeGraphicGlyph (
+ IN CHAR16 CodePoint
+ )
+{
+ return (((CodePoint >= BOXDRAW_HORIZONTAL) && (CodePoint <= BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL)) ||
+ ((CodePoint >= ARROW_LEFT) && (CodePoint <= ARROW_DOWN)) ||
+ (CodePoint == 0x25A0) ||
+ (CodePoint == 0x25A1) ||
+ (CodePoint == 0x25B2) ||
+ (CodePoint == 0x25B6) ||
+ (CodePoint == 0x25BA) ||
+ (CodePoint == 0x25BC) ||
+ (CodePoint == 0x25C0) ||
+ (CodePoint == 0x25C4));
+}
+
+
+/**
+ Draw one UEFI text-mode graphics character as a narrow GOP primitive.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] CodePoint Box, arrow, triangle, or checkbox glyph to render.
+ @param[in] Color Foreground color.
+ @param[in] Background Background fill color.
+
+ @retval EFI_SUCCESS Glyph was rendered.
+ @retval EFI_INVALID_PARAMETER Context is NULL or GOP is unavailable.
+ @retval others Status from fill or stroke primitives.
+**/
+EFI_STATUS
+ModernUiDrawTextModeGraphicGlyph (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN UINTN X,
+ IN UINTN Y,
+ IN CHAR16 CodePoint,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Horizontal;
+ BOOLEAN Vertical;
+ BOOLEAN Left;
+ BOOLEAN Right;
+ BOOLEAN Up;
+ BOOLEAN Down;
+ UINTN Index;
+
+ if ((Context == NULL) || (Context->Gop == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X, Y, MODERN_UI_GRAPHIC_CELL_WIDTH, MODERN_UI_BUILTIN_GLYPH_HEIGHT }, Background);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Horizontal = FALSE;
+ Vertical = FALSE;
+ Left = FALSE;
+ Right = FALSE;
+ Up = FALSE;
+ Down = FALSE;
+
+ switch (CodePoint) {
+ case BOXDRAW_HORIZONTAL:
+ case BOXDRAW_DOUBLE_HORIZONTAL:
+ Left = Right = TRUE;
+ break;
+ case BOXDRAW_VERTICAL:
+ case BOXDRAW_DOUBLE_VERTICAL:
+ Up = Down = TRUE;
+ break;
+ case BOXDRAW_DOWN_RIGHT:
+ case BOXDRAW_DOWN_RIGHT_DOUBLE:
+ case BOXDRAW_DOWN_DOUBLE_RIGHT:
+ case BOXDRAW_DOUBLE_DOWN_RIGHT:
+ Right = Down = TRUE;
+ break;
+ case BOXDRAW_DOWN_LEFT:
+ case BOXDRAW_DOWN_LEFT_DOUBLE:
+ case BOXDRAW_DOWN_DOUBLE_LEFT:
+ case BOXDRAW_DOUBLE_DOWN_LEFT:
+ Left = Down = TRUE;
+ break;
+ case BOXDRAW_UP_RIGHT:
+ case BOXDRAW_UP_RIGHT_DOUBLE:
+ case BOXDRAW_UP_DOUBLE_RIGHT:
+ case BOXDRAW_DOUBLE_UP_RIGHT:
+ Right = Up = TRUE;
+ break;
+ case BOXDRAW_UP_LEFT:
+ case BOXDRAW_UP_LEFT_DOUBLE:
+ case BOXDRAW_UP_DOUBLE_LEFT:
+ case BOXDRAW_DOUBLE_UP_LEFT:
+ Left = Up = TRUE;
+ break;
+ case BOXDRAW_VERTICAL_RIGHT:
+ case BOXDRAW_VERTICAL_RIGHT_DOUBLE:
+ case BOXDRAW_VERTICAL_DOUBLE_RIGHT:
+ case BOXDRAW_DOUBLE_VERTICAL_RIGHT:
+ Up = Down = Right = TRUE;
+ break;
+ case BOXDRAW_VERTICAL_LEFT:
+ case BOXDRAW_VERTICAL_LEFT_DOUBLE:
+ case BOXDRAW_VERTICAL_DOUBLE_LEFT:
+ case BOXDRAW_DOUBLE_VERTICAL_LEFT:
+ Up = Down = Left = TRUE;
+ break;
+ case BOXDRAW_DOWN_HORIZONTAL:
+ case BOXDRAW_DOWN_HORIZONTAL_DOUBLE:
+ case BOXDRAW_DOWN_DOUBLE_HORIZONTAL:
+ case BOXDRAW_DOUBLE_DOWN_HORIZONTAL:
+ Left = Right = Down = TRUE;
+ break;
+ case BOXDRAW_UP_HORIZONTAL:
+ case BOXDRAW_UP_HORIZONTAL_DOUBLE:
+ case BOXDRAW_UP_DOUBLE_HORIZONTAL:
+ case BOXDRAW_DOUBLE_UP_HORIZONTAL:
+ Left = Right = Up = TRUE;
+ break;
+ case BOXDRAW_VERTICAL_HORIZONTAL:
+ case BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE:
+ case BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL:
+ case BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL:
+ Left = Right = Up = Down = TRUE;
+ break;
+ case ARROW_RIGHT:
+ case 0x25B6:
+ case 0x25BA:
+ for (Index = 0; Index < 6; Index++) {
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 2 + Index, Y + 5 + Index, 1, 7 - (Index * 2 > 6 ? 6 : Index * 2) }, Color);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+ case ARROW_LEFT:
+ case 0x25C0:
+ case 0x25C4:
+ for (Index = 0; Index < 6; Index++) {
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 6 - Index, Y + 5 + Index, 1, 7 - (Index * 2 > 6 ? 6 : Index * 2) }, Color);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+ case ARROW_UP:
+ case 0x25B2:
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 3, Y + 5, 2, 8 }, Color);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 2, Y + 6, 4, 2 }, Color);
+ case ARROW_DOWN:
+ case 0x25BC:
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 3, Y + 5, 2, 8 }, Color);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 2, Y + 10, 4, 2 }, Color);
+ case 0x25A0:
+ return ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 1, Y + 6, 6, 6 }, Color);
+ case 0x25A1:
+ return ModernUiStrokeRect (Context, (MODERN_UI_RECT){ X + 1, Y + 6, 6, 6 }, Color);
+ default:
+ break;
+ }
+
+ Horizontal = Left || Right;
+ Vertical = Up || Down;
+ if (Horizontal) {
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){
+ X + (Left ? 0 : MODERN_UI_GRAPHIC_LINE_X),
+ Y + MODERN_UI_GRAPHIC_LINE_Y,
+ (Left && Right) ? MODERN_UI_GRAPHIC_CELL_WIDTH : (MODERN_UI_GRAPHIC_CELL_WIDTH - MODERN_UI_GRAPHIC_LINE_X),
+ 1
+ },
+ Color
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (Vertical) {
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){
+ X + MODERN_UI_GRAPHIC_LINE_X,
+ Y + (Up ? 0 : MODERN_UI_GRAPHIC_LINE_Y),
+ 1,
+ (Up && Down) ? MODERN_UI_BUILTIN_GLYPH_HEIGHT : (MODERN_UI_BUILTIN_GLYPH_HEIGHT - MODERN_UI_GRAPHIC_LINE_Y)
+ },
+ Color
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Return the expected pixel width for a UCS-2 string.
+
+ Built-in CJK glyphs are measured at their bitmap width. Other characters use
+ the renderer's current ASCII cell width.
+
+ @param[in] Text Null-terminated UCS-2 string. Must not be NULL.
+
+ @return Pixel width. NULL input returns 0.
+**/
+UINTN
+EFIAPI
+ModernUiMeasureText (
+ IN CONST CHAR16 *Text
+ )
+{
+ UINTN Index;
+ UINTN Width;
+ CONST MODERN_UI_BUILTIN_GLYPH *Glyph;
+
+ if (Text == NULL) {
+ return 0;
+ }
+
+ Width = 0;
+ for (Index = 0; Text[Index] != L'\0'; Index++) {
+ Glyph = ModernUiFindBuiltinGlyph (Text[Index]);
+ if (ModernUiIsTextModeGraphicGlyph (Text[Index])) {
+ Width += MODERN_UI_GRAPHIC_CELL_WIDTH;
+ } else if (Glyph != NULL) {
+ Width += Glyph->Advance;
+ } else if (Text[Index] > 0x7F) {
+ Width += MODERN_UI_BUILTIN_GLYPH_WIDTH;
+ } else {
+ Width += MODERN_UI_ASCII_CELL_WIDTH;
+ }
+ }
+
+ return Width;
+}
+
+
+/**
+ Format and draw one UCS-2 text line.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] Color Text foreground color.
+ @param[in] Background Text background color.
+ @param[in] Format PrintLib format string. Must not be NULL.
+ @param[in] ... Format arguments consumed according to Format.
+
+ @retval EFI_SUCCESS Text was formatted and rendered.
+ @retval EFI_INVALID_PARAMETER Context or Format is NULL.
+ @retval others Status returned by ModernUiDrawText().
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawTextFormatted (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN UINTN X,
+ IN UINTN Y,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ VA_LIST Marker;
+ CHAR16 Buffer[192];
+
+ if ((Context == NULL) || (Format == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VA_START (Marker, Format);
+ UnicodeVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ return ModernUiDrawText (Context, X, Y, Buffer, Color, Background);
+}
+
+
+/**
+ Draw UCS-2 text constrained to a pixel width.
+
+ The renderer measures mixed ASCII, built-in CJK, and text-mode graphic glyphs
+ and appends "..." when the string must be truncated.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] MaxWidth Maximum text width in pixels.
+ @param[in] Text Null-terminated UCS-2 string. Must not be NULL.
+ @param[in] Color Text foreground color.
+ @param[in] Background Text background color.
+
+ @retval EFI_SUCCESS Text was rendered or empty width was ignored.
+ @retval EFI_INVALID_PARAMETER Context or Text is NULL.
+ @retval EFI_OUT_OF_RESOURCES Temporary truncation buffer allocation failed.
+ @retval others Status returned by ModernUiDrawText().
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawTextFit (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN UINTN X,
+ IN UINTN Y,
+ IN UINTN MaxWidth,
+ IN CONST CHAR16 *Text,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
+ )
+{
+ CHAR16 *Buffer;
+ CHAR16 Character[2];
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN CopyChars;
+ UINTN CurrentWidth;
+ UINTN CharacterWidth;
+ UINTN EllipsisWidth;
+ UINTN TargetWidth;
+ UINTN TextLength;
+
+ if ((Context == NULL) || (Text == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MaxWidth == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (ModernUiMeasureText (Text) <= MaxWidth) {
+ return ModernUiDrawText (Context, X, Y, Text, Color, Background);
+ }
+
+ TextLength = StrLen (Text);
+ Buffer = AllocateZeroPool ((TextLength + 4) * sizeof (CHAR16));
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EllipsisWidth = ModernUiMeasureText (L"...");
+ TargetWidth = (MaxWidth > EllipsisWidth) ? (MaxWidth - EllipsisWidth) : MaxWidth;
+ CopyChars = 0;
+ CurrentWidth = 0;
+ Character[1] = L'\0';
+
+ for (Index = 0; Text[Index] != L'\0'; Index++) {
+ Character[0] = Text[Index];
+ CharacterWidth = ModernUiMeasureText (Character);
+ if ((CurrentWidth + CharacterWidth) > TargetWidth) {
+ break;
+ }
+
+ Buffer[CopyChars++] = Text[Index];
+ CurrentWidth += CharacterWidth;
+ }
+
+ if ((MaxWidth >= EllipsisWidth) && ((CopyChars + 3) < (TextLength + 4))) {
+ Buffer[CopyChars++] = L'.';
+ Buffer[CopyChars++] = L'.';
+ Buffer[CopyChars++] = L'.';
+ }
+
+ Buffer[CopyChars] = L'\0';
+ Status = ModernUiDrawText (Context, X, Y, Buffer, Color, Background);
+ FreePool (Buffer);
+ return Status;
+}
+
+
+/**
+ Draw a themed panel surface and border.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Panel rectangle.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @retval EFI_SUCCESS Panel was drawn.
+ @retval EFI_INVALID_PARAMETER Context or Theme is NULL.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawPanel (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ EFI_STATUS Status;
+
+ if ((Context == NULL) || (Theme == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ModernUiFillRect (Context, Rect, Theme->Surface);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Rect.Width > 2) && (Rect.Height > 2)) {
+ Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X + 1, Rect.Y + 1, Rect.Width - 2, 1 }, Theme->SurfaceRaised);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return ModernUiStrokeRect (Context, Rect, Theme->Border);
+}
+
+
+/**
+ Draw a focus frame only when requested.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Rectangle to outline when HasFocus is TRUE.
+ @param[in] HasFocus TRUE to draw the focus frame.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @retval EFI_SUCCESS Focus frame was drawn or skipped.
+ @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty
+ when HasFocus is TRUE.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawFocusFrame (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN BOOLEAN HasFocus,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ if ((Context == NULL) || (Theme == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!HasFocus) {
+ return EFI_SUCCESS;
+ }
+
+ return ModernUiStrokeRect (Context, Rect, Theme->Accent);
+}
+
+
+/**
+ Draw a compact title/value information card.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Card rectangle. Must be large enough for two text rows.
+ @param[in] Title Card title text. Must not be NULL.
+ @param[in] Value Card value text. Must not be NULL.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @retval EFI_SUCCESS Card was drawn.
+ @retval EFI_INVALID_PARAMETER Context, Title, Value, or Theme is NULL, or
+ Rect is empty.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+ @retval others Status returned by text rendering.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawInfoCard (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN CONST CHAR16 *Title,
+ IN CONST CHAR16 *Value,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ EFI_STATUS Status;
+
+ if ((Context == NULL) || (Title == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ModernUiDrawPanel (Context, Rect, Theme);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiDrawTextFit (Context, Rect.X + 18, Rect.Y + 16, Rect.Width - 36, Title, Theme->MutedText, Theme->Surface);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ModernUiDrawTextFit (Context, Rect.X + 18, Rect.Y + 48, Rect.Width - 36, Value, Theme->Text, Theme->Surface);
+}
+
+
+/**
+ Return the themed background color used by a selectable row.
+
+ @param[in] Selected TRUE when the row is selected.
+ @param[in] Disabled TRUE when the row is visible but disabled or grayed.
+ @param[in] Action TRUE when the row represents an action-like command.
+ @param[in] Subtitle TRUE when the row is a section subtitle.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @return Row background color. NULL Theme returns zero.
+**/
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+EFIAPI
+ModernUiGetSelectableRowBackground (
+ IN BOOLEAN Selected,
+ IN BOOLEAN Disabled,
+ IN BOOLEAN Action,
+ IN BOOLEAN Subtitle,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL RowColor;
+
+ ZeroMem (&RowColor, sizeof (RowColor));
+ if (Theme == NULL) {
+ return RowColor;
+ }
+
+ if (Selected) {
+ RowColor = ModernUiBlendColor (Theme->BackgroundBlack, Theme->SelectedBand, 74);
+ } else if (Action || Subtitle) {
+ RowColor = Theme->SurfaceRaised;
+ } else {
+ RowColor = Theme->Surface;
+ }
+
+ if (Disabled && !Selected) {
+ RowColor = ModernUiBlendColor (Theme->Surface, Theme->Background, 35);
+ }
+
+ return RowColor;
+}
+
+
+/**
+ Draw a themed selectable row surface.
+
+ This is a shared visual primitive for DisplayEngine statement rows and
+ experimental app list rows. It does not own FormBrowser or HII semantics.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Pixel rectangle for the row surface.
+ @param[in] Selected TRUE when the row is selected.
+ @param[in] Disabled TRUE when the row is visible but disabled or grayed.
+ @param[in] Action TRUE when the row represents an action-like command.
+ @param[in] Subtitle TRUE when the row is a section subtitle.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @retval EFI_SUCCESS Row was drawn.
+ @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawSelectableRow (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN BOOLEAN Selected,
+ IN BOOLEAN Disabled,
+ IN BOOLEAN Action,
+ IN BOOLEAN Subtitle,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL RowColor;
+ EFI_STATUS Status;
+
+ if ((Context == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RowColor = ModernUiGetSelectableRowBackground (Selected, Disabled, Action, Subtitle, Theme);
+ Status = ModernUiFillRect (Context, Rect, RowColor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Selected && (Rect.Width > 6) && (Rect.Height > 4)) {
+ if ((Rect.Width > 10) && (Rect.Height > 8)) {
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X + 6, Rect.Y + 3, Rect.Width - 6, Rect.Height - 6 },
+ ModernUiBlendColor (RowColor, Theme->AccentOrange, 18)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X, Rect.Y, Rect.Width, 2 },
+ ModernUiBlendColor (Theme->AccentYellow, Theme->AccentOrange, 45)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X, Rect.Y + Rect.Height - 3, Rect.Width, 2 },
+ ModernUiBlendColor (Theme->AccentOrange, Theme->SelectedBand, 35)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X, Rect.Y + 2, 7, Rect.Height - 4 },
+ Theme->AccentYellow
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Rect.Width > 20) {
+ Status = ModernUiStrokeRect (Context, Rect, Theme->PopupBorder);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X + 8, Rect.Y + 2, Rect.Width - 8, 1 },
+ ModernUiBlendColor (Theme->AccentYellow, Theme->AccentOrange, 45)
+ );
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ if (Subtitle && (Rect.Width > 6)) {
+ return ModernUiFillRect (
+ Context,
+ (MODERN_UI_RECT){ Rect.X, Rect.Y + Rect.Height - 1, Rect.Width, 1 },
+ Theme->Border
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Draw the standard border used around an action/selectable row.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Row rectangle.
+ @param[in] Selected TRUE when the row is selected.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @retval EFI_SUCCESS Row border was drawn.
+ @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawSelectableRowBorder (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN BOOLEAN Selected,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ if ((Context == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return ModernUiStrokeRect (
+ Context,
+ Rect,
+ Selected ? ModernUiBlendColor (Theme->AccentOrange, Theme->Border, 30) : Theme->Border
+ );
+}
+
+
+/**
+ Draw a value selector box with a trailing drop-down marker.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Selector rectangle.
+ @param[in] Value Selected value text. Must not be NULL.
+ @param[in] Selected TRUE when the owning row is selected.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @retval EFI_SUCCESS Selector was drawn.
+ @retval EFI_INVALID_PARAMETER Context, Value, or Theme is NULL, or Rect is
+ empty.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+ @retval others Status returned by text rendering.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawValueBox (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN CONST CHAR16 *Value,
+ IN BOOLEAN Selected,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ EFI_STATUS Status;
+
+ if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ModernUiFillRect (Context, Rect, Selected ? Theme->SelectedBand : Theme->Surface);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiStrokeRect (Context, Rect, Selected ? Theme->PopupBorder : Theme->Border);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiDrawTextFit (
+ Context,
+ Rect.X + 16,
+ Rect.Y + ((Rect.Height > 18) ? ((Rect.Height - 18) / 2) : 0),
+ (Rect.Width > 48) ? (Rect.Width - 48) : Rect.Width,
+ Value,
+ Theme->Text,
+ Selected ? Theme->SelectedBand : Theme->Surface
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ModernUiDrawText (
+ Context,
+ Rect.X + Rect.Width - 26,
+ Rect.Y + ((Rect.Height > 18) ? ((Rect.Height - 18) / 2) : 0),
+ L"v",
+ Theme->AccentYellow,
+ Selected ? Theme->SelectedBand : Theme->Surface
+ );
+}
+
+
+/**
+ Draw a drop-down list frame.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Drop-down rectangle.
+ @param[in] Theme Theme token table. Must not be NULL.
+
+ @retval EFI_SUCCESS Drop-down frame was drawn.
+ @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawDropdownFrame (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN CONST MODERN_UI_THEME *Theme
+ )
+{
+ EFI_STATUS Status;
+
+ if ((Context == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ModernUiFillRect (Context, Rect, Theme->BackgroundBlack);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = ModernUiStrokeRect (Context, Rect, Theme->PopupBorder);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Rect.Width <= 2) || (Rect.Height <= 2)) {
+ return EFI_SUCCESS;
+ }
+
+ return ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X + 1, Rect.Y + 1, Rect.Width - 2, 1 }, Theme->GlowOrange);
+}
+
+
+/**
+ Draw a horizontal progress bar.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] Rect Progress track rectangle.
+ @param[in] Percent Completion percentage. Values above 100 are clamped.
+ @param[in] Track Track color.
+ @param[in] Fill Fill color.
+
+ @retval EFI_SUCCESS Progress bar was drawn.
+ @retval EFI_INVALID_PARAMETER Context is NULL, GOP is unavailable, or Rect is empty.
+ @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+ModernUiDrawProgress (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN MODERN_UI_RECT Rect,
+ IN UINTN Percent,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Track,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill
+ )
+{
+ EFI_STATUS Status;
+ UINTN FillWidth;
+
+ if (Percent > 100) {
+ Percent = 100;
+ }
+
+ Status = ModernUiFillRect (Context, Rect, Track);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FillWidth = (Rect.Width * Percent) / 100;
+ if (FillWidth == 0) {
+ return EFI_SUCCESS;
+ }
+
+ return ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y, FillWidth, Rect.Height }, Fill);
+}
diff --git a/Library/ModernUiRendererLib/ModernUiRendererInternal.h b/Library/ModernUiRendererLib/ModernUiRendererInternal.h
new file mode 100644
index 0000000..2ef7492
--- /dev/null
+++ b/Library/ModernUiRendererLib/ModernUiRendererInternal.h
@@ -0,0 +1,95 @@
+/** @file
+ Private shared declarations for the ModernSetupPkg renderer libraries.
+
+ ModernUiRendererCommon.c implements the backend-agnostic renderer surface
+ (geometry compositions, text measurement, themed widgets) on top of three
+ backend primitives that each renderer provides: ModernUiRendererInit,
+ ModernUiFillRect, and ModernUiDrawText. The GOP renderer
+ (Library/ModernUiRendererLib) and the LVGL renderer
+ (Library/ModernUiLvglRendererLib) share ModernUiRendererCommon.c and
+ ModernUiGlyphs.c verbatim and supply only those three primitives.
+
+ Copyright (c) 2026, MarsDoge. All rights reserved.
+ Author: MarsDoge (Dongyan Qian)
+ Open source: https://github.com/MarsDoge/ModernSetupPkg
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef MODERN_UI_RENDERER_INTERNAL_H_
+#define MODERN_UI_RENDERER_INTERNAL_H_
+
+#include
+#include
+#include
+
+//
+// Fixed text-grid metrics shared by both renderers. The renderer measures and
+// lays out on an 8 px ASCII cell / fixed-width CJK cell model so that callers
+// computing positions from ModernUiMeasureText() are backend-stable.
+//
+#define MODERN_UI_ASCII_CELL_WIDTH 8
+#define MODERN_UI_GRAPHIC_CELL_WIDTH MODERN_UI_ASCII_CELL_WIDTH
+#define MODERN_UI_GRAPHIC_LINE_Y 9
+#define MODERN_UI_GRAPHIC_LINE_X 4
+#define MODERN_UI_TEXT_SEGMENT_MAX 96
+#define MODERN_UI_TARGET_WIDTH 1024
+#define MODERN_UI_TARGET_HEIGHT 768
+
+/**
+ Select a preferred GOP mode when the active mode is smaller than the target.
+
+ @param[in] Gop Graphics output protocol to inspect. Must not be NULL.
+
+ @retval EFI_SUCCESS Current mode is acceptable or a better mode
+ was selected.
+ @retval EFI_INVALID_PARAMETER Gop or mode data is NULL.
+**/
+EFI_STATUS
+ModernUiSelectPreferredGopMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
+ );
+
+/**
+ Return whether a UCS-2 character is a UEFI text-mode graphics character that
+ should be rendered as a narrow fixed-width shape.
+
+ @param[in] CodePoint UCS-2 code point to classify.
+
+ @retval TRUE CodePoint is a box, arrow, triangle, or checkbox glyph used by
+ edk2 text-mode setup UI.
+ @retval FALSE CodePoint should use normal text or built-in glyph rendering.
+**/
+BOOLEAN
+ModernUiIsTextModeGraphicGlyph (
+ IN CHAR16 CodePoint
+ );
+
+/**
+ Draw one UEFI text-mode graphics character as narrow renderer primitives.
+
+ The glyph is composed entirely from ModernUiFillRect/ModernUiStrokeRect, so it
+ renders identically through either backend.
+
+ @param[in] Context Initialized render context. Must not be NULL.
+ @param[in] X Left coordinate in pixels.
+ @param[in] Y Top coordinate in pixels.
+ @param[in] CodePoint Box, arrow, triangle, or checkbox glyph to render.
+ @param[in] Color Foreground color.
+ @param[in] Background Background fill color.
+
+ @retval EFI_SUCCESS Glyph was rendered.
+ @retval EFI_INVALID_PARAMETER Context is NULL or GOP is unavailable.
+ @retval others Status from fill or stroke primitives.
+**/
+EFI_STATUS
+ModernUiDrawTextModeGraphicGlyph (
+ IN MODERN_UI_RENDER_CONTEXT *Context,
+ IN UINTN X,
+ IN UINTN Y,
+ IN CHAR16 CodePoint,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
+ );
+
+#endif // MODERN_UI_RENDERER_INTERNAL_H_
diff --git a/Library/ModernUiRendererLib/ModernUiRendererLib.c b/Library/ModernUiRendererLib/ModernUiRendererLib.c
index 0641372..5f5b4a5 100644
--- a/Library/ModernUiRendererLib/ModernUiRendererLib.c
+++ b/Library/ModernUiRendererLib/ModernUiRendererLib.c
@@ -1,5 +1,10 @@
/** @file
- GOP-backed renderer library for ModernSetupPkg.
+ GOP-backed renderer primitives for ModernSetupPkg.
+
+ Provides the three backend primitives consumed by the shared
+ ModernUiRendererCommon.c: ModernUiRendererInit, ModernUiFillRect, and
+ ModernUiDrawText. All higher-level geometry/text/widget functions live in the
+ shared translation unit.
Copyright (c) 2026, MarsDoge. All rights reserved.
Author: MarsDoge (Dongyan Qian)
@@ -19,114 +24,8 @@
#include
#include "ModernUiGlyphs.h"
+#include "ModernUiRendererInternal.h"
-#define MODERN_UI_ASCII_CELL_WIDTH 8
-#define MODERN_UI_GRAPHIC_CELL_WIDTH MODERN_UI_ASCII_CELL_WIDTH
-#define MODERN_UI_GRAPHIC_LINE_Y 9
-#define MODERN_UI_GRAPHIC_LINE_X 4
-#define MODERN_UI_TEXT_SEGMENT_MAX 96
-#define MODERN_UI_TARGET_WIDTH 1024
-#define MODERN_UI_TARGET_HEIGHT 768
-
-/**
- Blend two GOP colors by percentage weight.
-
- @param[in] Base Base color used when Weight is zero.
- @param[in] Accent Accent color used when Weight is one hundred.
- @param[in] Weight Accent weight in percent. Values above 100 are clamped.
-
- @return Blended color with Reserved cleared.
-**/
-EFI_GRAPHICS_OUTPUT_BLT_PIXEL
-EFIAPI
-ModernUiBlendColor (
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Base,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Accent,
- IN UINT8 Weight
- )
-{
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL Result;
- UINTN ClampedWeight;
-
- ClampedWeight = MIN (Weight, 100);
- Result.Red = (UINT8)(
- ((UINTN)Base.Red * (100 - ClampedWeight) +
- (UINTN)Accent.Red * ClampedWeight) / 100
- );
- Result.Green = (UINT8)(
- ((UINTN)Base.Green * (100 - ClampedWeight) +
- (UINTN)Accent.Green * ClampedWeight) / 100
- );
- Result.Blue = (UINT8)(
- ((UINTN)Base.Blue * (100 - ClampedWeight) +
- (UINTN)Accent.Blue * ClampedWeight) / 100
- );
- Result.Reserved = 0;
- return Result;
-}
-
-/**
- Select a preferred GOP mode when the active mode is smaller than the target.
-
- @param[in] Gop Graphics output protocol to inspect. Must not be NULL.
-
- @retval EFI_SUCCESS Current mode is acceptable or a better mode
- was selected.
- @retval EFI_INVALID_PARAMETER Gop or mode data is NULL.
-**/
-STATIC
-EFI_STATUS
-SelectPreferredGopMode (
- IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
- )
-{
- EFI_STATUS Status;
- EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
- UINTN InfoSize;
- UINT32 Mode;
- UINT32 BestMode;
- UINTN BestArea;
- UINTN Area;
-
- if ((Gop == NULL) || (Gop->Mode == NULL) || (Gop->Mode->Info == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Gop->Mode->Info->HorizontalResolution >= MODERN_UI_TARGET_WIDTH) &&
- (Gop->Mode->Info->VerticalResolution >= MODERN_UI_TARGET_HEIGHT))
- {
- return EFI_SUCCESS;
- }
-
- BestMode = Gop->Mode->MaxMode;
- BestArea = MAX_UINTN;
- for (Mode = 0; Mode < Gop->Mode->MaxMode; Mode++) {
- Info = NULL;
- InfoSize = 0;
- Status = Gop->QueryMode (Gop, Mode, &InfoSize, &Info);
- if (EFI_ERROR (Status) || (Info == NULL)) {
- continue;
- }
-
- if ((Info->HorizontalResolution >= MODERN_UI_TARGET_WIDTH) &&
- (Info->VerticalResolution >= MODERN_UI_TARGET_HEIGHT))
- {
- Area = (UINTN)Info->HorizontalResolution * (UINTN)Info->VerticalResolution;
- if (Area < BestArea) {
- BestArea = Area;
- BestMode = Mode;
- }
- }
-
- FreePool (Info);
- }
-
- if ((BestMode < Gop->Mode->MaxMode) && (BestMode != Gop->Mode->Mode)) {
- Gop->SetMode (Gop, BestMode);
- }
-
- return EFI_SUCCESS;
-}
/**
Initialize a render context from firmware graphics services.
@@ -170,7 +69,7 @@ ModernUiRendererInit (
return EFI_NOT_FOUND;
}
- SelectPreferredGopMode (Context->Gop);
+ ModernUiSelectPreferredGopMode (Context->Gop);
Context->Width = Context->Gop->Mode->Info->HorizontalResolution;
Context->Height = Context->Gop->Mode->Info->VerticalResolution;
@@ -186,6 +85,7 @@ ModernUiRendererInit (
return EFI_SUCCESS;
}
+
/**
Fill a rectangle in the active render target.
@@ -235,68 +135,6 @@ ModernUiFillRect (
);
}
-/**
- Fill the full render target with one color.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Color Fill color.
-
- @retval EFI_SUCCESS The screen was cleared.
- @retval EFI_INVALID_PARAMETER Context is NULL or invalid.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiClear (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
- )
-{
- if (Context == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- return ModernUiFillRect (Context, (MODERN_UI_RECT){ 0, 0, Context->Width, Context->Height }, Color);
-}
-
-/**
- Draw a one-pixel rectangle border.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Pixel rectangle to outline.
- @param[in] Color Border color.
-
- @retval EFI_SUCCESS Border was drawn.
- @retval EFI_INVALID_PARAMETER Context is NULL, GOP is unavailable, or Rect is empty.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiStrokeRect (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color
- )
-{
- EFI_STATUS Status;
-
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y, Rect.Width, 1 }, Color);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y + Rect.Height - 1, Rect.Width, 1 }, Color);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y, 1, Rect.Height }, Color);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X + Rect.Width - 1, Rect.Y, 1, Rect.Height }, Color);
-}
/**
Draw one UCS-2 text run through HII Font.
@@ -367,6 +205,7 @@ DrawHiiText (
return Status;
}
+
/**
Draw one built-in bitmap glyph.
@@ -426,6 +265,7 @@ DrawBuiltinGlyph (
);
}
+
/**
Draw a visible placeholder for a missing non-ASCII glyph.
@@ -458,267 +298,6 @@ DrawMissingGlyph (
return ModernUiStrokeRect (Context, (MODERN_UI_RECT){ X + 2, Y + 2, MODERN_UI_BUILTIN_GLYPH_WIDTH - 4, MODERN_UI_BUILTIN_GLYPH_HEIGHT - 4 }, Color);
}
-/**
- Return whether a UCS-2 character is a UEFI text-mode graphics character that
- should be rendered as a narrow fixed-width shape.
-
- @param[in] CodePoint UCS-2 code point to classify.
-
- @retval TRUE CodePoint is a box, arrow, triangle, or checkbox glyph used by
- edk2 text-mode setup UI.
- @retval FALSE CodePoint should use normal text or built-in glyph rendering.
-**/
-STATIC
-BOOLEAN
-IsTextModeGraphicGlyph (
- IN CHAR16 CodePoint
- )
-{
- return (((CodePoint >= BOXDRAW_HORIZONTAL) && (CodePoint <= BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL)) ||
- ((CodePoint >= ARROW_LEFT) && (CodePoint <= ARROW_DOWN)) ||
- (CodePoint == 0x25A0) ||
- (CodePoint == 0x25A1) ||
- (CodePoint == 0x25B2) ||
- (CodePoint == 0x25B6) ||
- (CodePoint == 0x25BA) ||
- (CodePoint == 0x25BC) ||
- (CodePoint == 0x25C0) ||
- (CodePoint == 0x25C4));
-}
-
-/**
- Draw one UEFI text-mode graphics character as a narrow GOP primitive.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] X Left coordinate in pixels.
- @param[in] Y Top coordinate in pixels.
- @param[in] CodePoint Box, arrow, triangle, or checkbox glyph to render.
- @param[in] Color Foreground color.
- @param[in] Background Background fill color.
-
- @retval EFI_SUCCESS Glyph was rendered.
- @retval EFI_INVALID_PARAMETER Context is NULL or GOP is unavailable.
- @retval others Status from fill or stroke primitives.
-**/
-STATIC
-EFI_STATUS
-DrawTextModeGraphicGlyph (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN UINTN X,
- IN UINTN Y,
- IN CHAR16 CodePoint,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
- )
-{
- EFI_STATUS Status;
- BOOLEAN Horizontal;
- BOOLEAN Vertical;
- BOOLEAN Left;
- BOOLEAN Right;
- BOOLEAN Up;
- BOOLEAN Down;
- UINTN Index;
-
- if ((Context == NULL) || (Context->Gop == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X, Y, MODERN_UI_GRAPHIC_CELL_WIDTH, MODERN_UI_BUILTIN_GLYPH_HEIGHT }, Background);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Horizontal = FALSE;
- Vertical = FALSE;
- Left = FALSE;
- Right = FALSE;
- Up = FALSE;
- Down = FALSE;
-
- switch (CodePoint) {
- case BOXDRAW_HORIZONTAL:
- case BOXDRAW_DOUBLE_HORIZONTAL:
- Left = Right = TRUE;
- break;
- case BOXDRAW_VERTICAL:
- case BOXDRAW_DOUBLE_VERTICAL:
- Up = Down = TRUE;
- break;
- case BOXDRAW_DOWN_RIGHT:
- case BOXDRAW_DOWN_RIGHT_DOUBLE:
- case BOXDRAW_DOWN_DOUBLE_RIGHT:
- case BOXDRAW_DOUBLE_DOWN_RIGHT:
- Right = Down = TRUE;
- break;
- case BOXDRAW_DOWN_LEFT:
- case BOXDRAW_DOWN_LEFT_DOUBLE:
- case BOXDRAW_DOWN_DOUBLE_LEFT:
- case BOXDRAW_DOUBLE_DOWN_LEFT:
- Left = Down = TRUE;
- break;
- case BOXDRAW_UP_RIGHT:
- case BOXDRAW_UP_RIGHT_DOUBLE:
- case BOXDRAW_UP_DOUBLE_RIGHT:
- case BOXDRAW_DOUBLE_UP_RIGHT:
- Right = Up = TRUE;
- break;
- case BOXDRAW_UP_LEFT:
- case BOXDRAW_UP_LEFT_DOUBLE:
- case BOXDRAW_UP_DOUBLE_LEFT:
- case BOXDRAW_DOUBLE_UP_LEFT:
- Left = Up = TRUE;
- break;
- case BOXDRAW_VERTICAL_RIGHT:
- case BOXDRAW_VERTICAL_RIGHT_DOUBLE:
- case BOXDRAW_VERTICAL_DOUBLE_RIGHT:
- case BOXDRAW_DOUBLE_VERTICAL_RIGHT:
- Up = Down = Right = TRUE;
- break;
- case BOXDRAW_VERTICAL_LEFT:
- case BOXDRAW_VERTICAL_LEFT_DOUBLE:
- case BOXDRAW_VERTICAL_DOUBLE_LEFT:
- case BOXDRAW_DOUBLE_VERTICAL_LEFT:
- Up = Down = Left = TRUE;
- break;
- case BOXDRAW_DOWN_HORIZONTAL:
- case BOXDRAW_DOWN_HORIZONTAL_DOUBLE:
- case BOXDRAW_DOWN_DOUBLE_HORIZONTAL:
- case BOXDRAW_DOUBLE_DOWN_HORIZONTAL:
- Left = Right = Down = TRUE;
- break;
- case BOXDRAW_UP_HORIZONTAL:
- case BOXDRAW_UP_HORIZONTAL_DOUBLE:
- case BOXDRAW_UP_DOUBLE_HORIZONTAL:
- case BOXDRAW_DOUBLE_UP_HORIZONTAL:
- Left = Right = Up = TRUE;
- break;
- case BOXDRAW_VERTICAL_HORIZONTAL:
- case BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE:
- case BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL:
- case BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL:
- Left = Right = Up = Down = TRUE;
- break;
- case ARROW_RIGHT:
- case 0x25B6:
- case 0x25BA:
- for (Index = 0; Index < 6; Index++) {
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 2 + Index, Y + 5 + Index, 1, 7 - (Index * 2 > 6 ? 6 : Index * 2) }, Color);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- return EFI_SUCCESS;
- case ARROW_LEFT:
- case 0x25C0:
- case 0x25C4:
- for (Index = 0; Index < 6; Index++) {
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 6 - Index, Y + 5 + Index, 1, 7 - (Index * 2 > 6 ? 6 : Index * 2) }, Color);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- return EFI_SUCCESS;
- case ARROW_UP:
- case 0x25B2:
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 3, Y + 5, 2, 8 }, Color);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 2, Y + 6, 4, 2 }, Color);
- case ARROW_DOWN:
- case 0x25BC:
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 3, Y + 5, 2, 8 }, Color);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 2, Y + 10, 4, 2 }, Color);
- case 0x25A0:
- return ModernUiFillRect (Context, (MODERN_UI_RECT){ X + 1, Y + 6, 6, 6 }, Color);
- case 0x25A1:
- return ModernUiStrokeRect (Context, (MODERN_UI_RECT){ X + 1, Y + 6, 6, 6 }, Color);
- default:
- break;
- }
-
- Horizontal = Left || Right;
- Vertical = Up || Down;
- if (Horizontal) {
- Status = ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){
- X + (Left ? 0 : MODERN_UI_GRAPHIC_LINE_X),
- Y + MODERN_UI_GRAPHIC_LINE_Y,
- (Left && Right) ? MODERN_UI_GRAPHIC_CELL_WIDTH : (MODERN_UI_GRAPHIC_CELL_WIDTH - MODERN_UI_GRAPHIC_LINE_X),
- 1
- },
- Color
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- if (Vertical) {
- Status = ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){
- X + MODERN_UI_GRAPHIC_LINE_X,
- Y + (Up ? 0 : MODERN_UI_GRAPHIC_LINE_Y),
- 1,
- (Up && Down) ? MODERN_UI_BUILTIN_GLYPH_HEIGHT : (MODERN_UI_BUILTIN_GLYPH_HEIGHT - MODERN_UI_GRAPHIC_LINE_Y)
- },
- Color
- );
- }
-
- return Status;
-}
-
-/**
- Return the expected pixel width for a UCS-2 string.
-
- Built-in CJK glyphs are measured at their bitmap width. Other characters use
- the renderer's current ASCII cell width.
-
- @param[in] Text Null-terminated UCS-2 string. Must not be NULL.
-
- @return Pixel width. NULL input returns 0.
-**/
-UINTN
-EFIAPI
-ModernUiMeasureText (
- IN CONST CHAR16 *Text
- )
-{
- UINTN Index;
- UINTN Width;
- CONST MODERN_UI_BUILTIN_GLYPH *Glyph;
-
- if (Text == NULL) {
- return 0;
- }
-
- Width = 0;
- for (Index = 0; Text[Index] != L'\0'; Index++) {
- Glyph = ModernUiFindBuiltinGlyph (Text[Index]);
- if (IsTextModeGraphicGlyph (Text[Index])) {
- Width += MODERN_UI_GRAPHIC_CELL_WIDTH;
- } else if (Glyph != NULL) {
- Width += Glyph->Advance;
- } else if (Text[Index] > 0x7F) {
- Width += MODERN_UI_BUILTIN_GLYPH_WIDTH;
- } else {
- Width += MODERN_UI_ASCII_CELL_WIDTH;
- }
- }
-
- return Width;
-}
/**
Draw UCS-2 text using HII Font and built-in bitmap glyph fallback.
@@ -763,9 +342,9 @@ ModernUiDrawText (
ReturnStatus = EFI_SUCCESS;
for (Index = 0; Text[Index] != L'\0'; ) {
Glyph = ModernUiFindBuiltinGlyph (Text[Index]);
- if ((Glyph != NULL) || IsTextModeGraphicGlyph (Text[Index]) || (Text[Index] > 0x7F)) {
- if (IsTextModeGraphicGlyph (Text[Index])) {
- Status = DrawTextModeGraphicGlyph (Context, CurrentX, Y, Text[Index], Color, Background);
+ if ((Glyph != NULL) || ModernUiIsTextModeGraphicGlyph (Text[Index]) || (Text[Index] > 0x7F)) {
+ if (ModernUiIsTextModeGraphicGlyph (Text[Index])) {
+ Status = ModernUiDrawTextModeGraphicGlyph (Context, CurrentX, Y, Text[Index], Color, Background);
CurrentX += MODERN_UI_GRAPHIC_CELL_WIDTH;
} else if (Glyph != NULL) {
Status = DrawBuiltinGlyph (Context, CurrentX, Y, Glyph, Color, Background);
@@ -800,583 +379,3 @@ ModernUiDrawText (
return ReturnStatus;
}
-
-/**
- Format and draw one UCS-2 text line.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] X Left coordinate in pixels.
- @param[in] Y Top coordinate in pixels.
- @param[in] Color Text foreground color.
- @param[in] Background Text background color.
- @param[in] Format PrintLib format string. Must not be NULL.
- @param[in] ... Format arguments consumed according to Format.
-
- @retval EFI_SUCCESS Text was formatted and rendered.
- @retval EFI_INVALID_PARAMETER Context or Format is NULL.
- @retval others Status returned by ModernUiDrawText().
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawTextFormatted (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN UINTN X,
- IN UINTN Y,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
- IN CONST CHAR16 *Format,
- ...
- )
-{
- VA_LIST Marker;
- CHAR16 Buffer[192];
-
- if ((Context == NULL) || (Format == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- VA_START (Marker, Format);
- UnicodeVSPrint (Buffer, sizeof (Buffer), Format, Marker);
- VA_END (Marker);
-
- return ModernUiDrawText (Context, X, Y, Buffer, Color, Background);
-}
-
-/**
- Draw UCS-2 text constrained to a pixel width.
-
- The renderer measures mixed ASCII, built-in CJK, and text-mode graphic glyphs
- and appends "..." when the string must be truncated.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] X Left coordinate in pixels.
- @param[in] Y Top coordinate in pixels.
- @param[in] MaxWidth Maximum text width in pixels.
- @param[in] Text Null-terminated UCS-2 string. Must not be NULL.
- @param[in] Color Text foreground color.
- @param[in] Background Text background color.
-
- @retval EFI_SUCCESS Text was rendered or empty width was ignored.
- @retval EFI_INVALID_PARAMETER Context or Text is NULL.
- @retval EFI_OUT_OF_RESOURCES Temporary truncation buffer allocation failed.
- @retval others Status returned by ModernUiDrawText().
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawTextFit (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN UINTN X,
- IN UINTN Y,
- IN UINTN MaxWidth,
- IN CONST CHAR16 *Text,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
- )
-{
- CHAR16 *Buffer;
- CHAR16 Character[2];
- EFI_STATUS Status;
- UINTN Index;
- UINTN CopyChars;
- UINTN CurrentWidth;
- UINTN CharacterWidth;
- UINTN EllipsisWidth;
- UINTN TargetWidth;
- UINTN TextLength;
-
- if ((Context == NULL) || (Text == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (MaxWidth == 0) {
- return EFI_SUCCESS;
- }
-
- if (ModernUiMeasureText (Text) <= MaxWidth) {
- return ModernUiDrawText (Context, X, Y, Text, Color, Background);
- }
-
- TextLength = StrLen (Text);
- Buffer = AllocateZeroPool ((TextLength + 4) * sizeof (CHAR16));
- if (Buffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- EllipsisWidth = ModernUiMeasureText (L"...");
- TargetWidth = (MaxWidth > EllipsisWidth) ? (MaxWidth - EllipsisWidth) : MaxWidth;
- CopyChars = 0;
- CurrentWidth = 0;
- Character[1] = L'\0';
-
- for (Index = 0; Text[Index] != L'\0'; Index++) {
- Character[0] = Text[Index];
- CharacterWidth = ModernUiMeasureText (Character);
- if ((CurrentWidth + CharacterWidth) > TargetWidth) {
- break;
- }
-
- Buffer[CopyChars++] = Text[Index];
- CurrentWidth += CharacterWidth;
- }
-
- if ((MaxWidth >= EllipsisWidth) && ((CopyChars + 3) < (TextLength + 4))) {
- Buffer[CopyChars++] = L'.';
- Buffer[CopyChars++] = L'.';
- Buffer[CopyChars++] = L'.';
- }
-
- Buffer[CopyChars] = L'\0';
- Status = ModernUiDrawText (Context, X, Y, Buffer, Color, Background);
- FreePool (Buffer);
- return Status;
-}
-
-/**
- Draw a themed panel surface and border.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Panel rectangle.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @retval EFI_SUCCESS Panel was drawn.
- @retval EFI_INVALID_PARAMETER Context or Theme is NULL.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawPanel (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- EFI_STATUS Status;
-
- if ((Context == NULL) || (Theme == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = ModernUiFillRect (Context, Rect, Theme->Surface);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((Rect.Width > 2) && (Rect.Height > 2)) {
- Status = ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X + 1, Rect.Y + 1, Rect.Width - 2, 1 }, Theme->SurfaceRaised);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- return ModernUiStrokeRect (Context, Rect, Theme->Border);
-}
-
-/**
- Draw a focus frame only when requested.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Rectangle to outline when HasFocus is TRUE.
- @param[in] HasFocus TRUE to draw the focus frame.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @retval EFI_SUCCESS Focus frame was drawn or skipped.
- @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty
- when HasFocus is TRUE.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawFocusFrame (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN BOOLEAN HasFocus,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- if ((Context == NULL) || (Theme == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (!HasFocus) {
- return EFI_SUCCESS;
- }
-
- return ModernUiStrokeRect (Context, Rect, Theme->Accent);
-}
-
-/**
- Draw a compact title/value information card.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Card rectangle. Must be large enough for two text rows.
- @param[in] Title Card title text. Must not be NULL.
- @param[in] Value Card value text. Must not be NULL.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @retval EFI_SUCCESS Card was drawn.
- @retval EFI_INVALID_PARAMETER Context, Title, Value, or Theme is NULL, or
- Rect is empty.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
- @retval others Status returned by text rendering.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawInfoCard (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN CONST CHAR16 *Title,
- IN CONST CHAR16 *Value,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- EFI_STATUS Status;
-
- if ((Context == NULL) || (Title == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = ModernUiDrawPanel (Context, Rect, Theme);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiDrawTextFit (Context, Rect.X + 18, Rect.Y + 16, Rect.Width - 36, Title, Theme->MutedText, Theme->Surface);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return ModernUiDrawTextFit (Context, Rect.X + 18, Rect.Y + 48, Rect.Width - 36, Value, Theme->Text, Theme->Surface);
-}
-
-/**
- Return the themed background color used by a selectable row.
-
- @param[in] Selected TRUE when the row is selected.
- @param[in] Disabled TRUE when the row is visible but disabled or grayed.
- @param[in] Action TRUE when the row represents an action-like command.
- @param[in] Subtitle TRUE when the row is a section subtitle.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @return Row background color. NULL Theme returns zero.
-**/
-EFI_GRAPHICS_OUTPUT_BLT_PIXEL
-EFIAPI
-ModernUiGetSelectableRowBackground (
- IN BOOLEAN Selected,
- IN BOOLEAN Disabled,
- IN BOOLEAN Action,
- IN BOOLEAN Subtitle,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL RowColor;
-
- ZeroMem (&RowColor, sizeof (RowColor));
- if (Theme == NULL) {
- return RowColor;
- }
-
- if (Selected) {
- RowColor = ModernUiBlendColor (Theme->BackgroundBlack, Theme->SelectedBand, 74);
- } else if (Action || Subtitle) {
- RowColor = Theme->SurfaceRaised;
- } else {
- RowColor = Theme->Surface;
- }
-
- if (Disabled && !Selected) {
- RowColor = ModernUiBlendColor (Theme->Surface, Theme->Background, 35);
- }
-
- return RowColor;
-}
-
-/**
- Draw a themed selectable row surface.
-
- This is a shared visual primitive for DisplayEngine statement rows and
- experimental app list rows. It does not own FormBrowser or HII semantics.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Pixel rectangle for the row surface.
- @param[in] Selected TRUE when the row is selected.
- @param[in] Disabled TRUE when the row is visible but disabled or grayed.
- @param[in] Action TRUE when the row represents an action-like command.
- @param[in] Subtitle TRUE when the row is a section subtitle.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @retval EFI_SUCCESS Row was drawn.
- @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawSelectableRow (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN BOOLEAN Selected,
- IN BOOLEAN Disabled,
- IN BOOLEAN Action,
- IN BOOLEAN Subtitle,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL RowColor;
- EFI_STATUS Status;
-
- if ((Context == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- RowColor = ModernUiGetSelectableRowBackground (Selected, Disabled, Action, Subtitle, Theme);
- Status = ModernUiFillRect (Context, Rect, RowColor);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Selected && (Rect.Width > 6) && (Rect.Height > 4)) {
- if ((Rect.Width > 10) && (Rect.Height > 8)) {
- Status = ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){ Rect.X + 6, Rect.Y + 3, Rect.Width - 6, Rect.Height - 6 },
- ModernUiBlendColor (RowColor, Theme->AccentOrange, 18)
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- Status = ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){ Rect.X, Rect.Y, Rect.Width, 2 },
- ModernUiBlendColor (Theme->AccentYellow, Theme->AccentOrange, 45)
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){ Rect.X, Rect.Y + Rect.Height - 3, Rect.Width, 2 },
- ModernUiBlendColor (Theme->AccentOrange, Theme->SelectedBand, 35)
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){ Rect.X, Rect.Y + 2, 7, Rect.Height - 4 },
- Theme->AccentYellow
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Rect.Width > 20) {
- Status = ModernUiStrokeRect (Context, Rect, Theme->PopupBorder);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){ Rect.X + 8, Rect.Y + 2, Rect.Width - 8, 1 },
- ModernUiBlendColor (Theme->AccentYellow, Theme->AccentOrange, 45)
- );
- }
-
- return EFI_SUCCESS;
- }
-
- if (Subtitle && (Rect.Width > 6)) {
- return ModernUiFillRect (
- Context,
- (MODERN_UI_RECT){ Rect.X, Rect.Y + Rect.Height - 1, Rect.Width, 1 },
- Theme->Border
- );
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Draw the standard border used around an action/selectable row.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Row rectangle.
- @param[in] Selected TRUE when the row is selected.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @retval EFI_SUCCESS Row border was drawn.
- @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawSelectableRowBorder (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN BOOLEAN Selected,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- if ((Context == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- return ModernUiStrokeRect (
- Context,
- Rect,
- Selected ? ModernUiBlendColor (Theme->AccentOrange, Theme->Border, 30) : Theme->Border
- );
-}
-
-/**
- Draw a value selector box with a trailing drop-down marker.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Selector rectangle.
- @param[in] Value Selected value text. Must not be NULL.
- @param[in] Selected TRUE when the owning row is selected.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @retval EFI_SUCCESS Selector was drawn.
- @retval EFI_INVALID_PARAMETER Context, Value, or Theme is NULL, or Rect is
- empty.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
- @retval others Status returned by text rendering.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawValueBox (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN CONST CHAR16 *Value,
- IN BOOLEAN Selected,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- EFI_STATUS Status;
-
- if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = ModernUiFillRect (Context, Rect, Selected ? Theme->SelectedBand : Theme->Surface);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiStrokeRect (Context, Rect, Selected ? Theme->PopupBorder : Theme->Border);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiDrawTextFit (
- Context,
- Rect.X + 16,
- Rect.Y + ((Rect.Height > 18) ? ((Rect.Height - 18) / 2) : 0),
- (Rect.Width > 48) ? (Rect.Width - 48) : Rect.Width,
- Value,
- Theme->Text,
- Selected ? Theme->SelectedBand : Theme->Surface
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return ModernUiDrawText (
- Context,
- Rect.X + Rect.Width - 26,
- Rect.Y + ((Rect.Height > 18) ? ((Rect.Height - 18) / 2) : 0),
- L"v",
- Theme->AccentYellow,
- Selected ? Theme->SelectedBand : Theme->Surface
- );
-}
-
-/**
- Draw a drop-down list frame.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Drop-down rectangle.
- @param[in] Theme Theme token table. Must not be NULL.
-
- @retval EFI_SUCCESS Drop-down frame was drawn.
- @retval EFI_INVALID_PARAMETER Context or Theme is NULL, or Rect is empty.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawDropdownFrame (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN CONST MODERN_UI_THEME *Theme
- )
-{
- EFI_STATUS Status;
-
- if ((Context == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = ModernUiFillRect (Context, Rect, Theme->BackgroundBlack);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = ModernUiStrokeRect (Context, Rect, Theme->PopupBorder);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((Rect.Width <= 2) || (Rect.Height <= 2)) {
- return EFI_SUCCESS;
- }
-
- return ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X + 1, Rect.Y + 1, Rect.Width - 2, 1 }, Theme->GlowOrange);
-}
-
-/**
- Draw a horizontal progress bar.
-
- @param[in] Context Initialized render context. Must not be NULL.
- @param[in] Rect Progress track rectangle.
- @param[in] Percent Completion percentage. Values above 100 are clamped.
- @param[in] Track Track color.
- @param[in] Fill Fill color.
-
- @retval EFI_SUCCESS Progress bar was drawn.
- @retval EFI_INVALID_PARAMETER Context is NULL, GOP is unavailable, or Rect is empty.
- @retval EFI_OUT_OF_RESOURCES Temporary BLT allocation failed.
-**/
-EFI_STATUS
-EFIAPI
-ModernUiDrawProgress (
- IN MODERN_UI_RENDER_CONTEXT *Context,
- IN MODERN_UI_RECT Rect,
- IN UINTN Percent,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Track,
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill
- )
-{
- EFI_STATUS Status;
- UINTN FillWidth;
-
- if (Percent > 100) {
- Percent = 100;
- }
-
- Status = ModernUiFillRect (Context, Rect, Track);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- FillWidth = (Rect.Width * Percent) / 100;
- if (FillWidth == 0) {
- return EFI_SUCCESS;
- }
-
- return ModernUiFillRect (Context, (MODERN_UI_RECT){ Rect.X, Rect.Y, FillWidth, Rect.Height }, Fill);
-}
diff --git a/Library/ModernUiRendererLib/ModernUiRendererLib.inf b/Library/ModernUiRendererLib/ModernUiRendererLib.inf
index 469f815..9af3fd2 100644
--- a/Library/ModernUiRendererLib/ModernUiRendererLib.inf
+++ b/Library/ModernUiRendererLib/ModernUiRendererLib.inf
@@ -18,6 +18,7 @@
[Sources]
ModernUiRendererLib.c
+ ModernUiRendererCommon.c
ModernUiGlyphs.c
[Packages]
diff --git a/Scripts/build-loongarchvirt.sh b/Scripts/build-loongarchvirt.sh
index a6c38ce..f6a13e0 100755
--- a/Scripts/build-loongarchvirt.sh
+++ b/Scripts/build-loongarchvirt.sh
@@ -36,6 +36,13 @@ export PATH="/opt/homebrew/bin:${PATH}"
export WORKSPACE
export GCC_LOONGARCH64_PREFIX
ConfigureModernSetupPackagePath
+# Experimental LvglSpikePkg is only consumed by MODERN_SETUP_DISPLAY_ENGINE=lvgl;
+# making it resolvable here is harmless for native/modern.
+AppendPackagePath "${PKG_DIR}/Experimental"
+export PACKAGES_PATH
+
+# LoongArch64/RISC-V64 UEFI support is upstream in the pinned External/lvgl
+# baseline; the submodule is consumed pristine with no local patching.
if [[ ! -d "${WORKSPACE}/MdePkg" || ! -d "${WORKSPACE}/OvmfPkg/LoongArchVirt" ]]; then
echo "WORKSPACE does not look like an edk2 checkout with LoongArchVirt: ${WORKSPACE}" >&2
@@ -71,9 +78,9 @@ if theme_pcd is None:
f"Unsupported MODERN_SETUP_THEME={theme_name!r}; "
"use orange, amber, dark-orange, red, accent-red, dark-red, graphite, or graphite-gold"
)
-if display_engine not in {"modern", "native"}:
+if display_engine not in {"modern", "native", "lvgl"}:
raise SystemExit(
- f"Unsupported MODERN_SETUP_DISPLAY_ENGINE={display_engine!r}; use modern or native"
+ f"Unsupported MODERN_SETUP_DISPLAY_ENGINE={display_engine!r}; use modern, native, or lvgl"
)
if include_app_flag not in {"0", "1", "false", "true", "no", "yes"}:
raise SystemExit(
@@ -86,23 +93,59 @@ if replace_uiapp_flag not in {"0", "1", "false", "true", "no", "yes"}:
replace_uiapp = replace_uiapp_flag in {"1", "true", "yes"}
include_modern_setup_app = (include_app_flag in {"1", "true", "yes"}) or replace_uiapp
-modern_setup_app_component = " ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf"
-modern_setup_app_component_boot_manager_fallback = """ ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf {
-
- GCC:*_*_*_CC_FLAGS = -DMODERN_SETUP_NATIVE_FALLBACK_BOOT_MANAGER_MENU=1
- }"""
+# In lvgl mode the ModernSetupApp shell and the ModernDisplayEngine both pull the
+# LVGL-backed renderer, so they force-link compiler intrinsics (memcpy/memset).
+_app_lvgl_intrinsics = (
+ " \n"
+ " NULL|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\n"
+ if display_engine == "lvgl"
+ else ""
+)
+modern_setup_app_component = (
+ " ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf"
+ if display_engine != "lvgl"
+ else (
+ " ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf {\n"
+ f"{_app_lvgl_intrinsics}"
+ " }"
+ )
+)
+modern_setup_app_component_boot_manager_fallback = (
+ " ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf {\n"
+ " \n"
+ " GCC:*_*_*_CC_FLAGS = -DMODERN_SETUP_NATIVE_FALLBACK_BOOT_MANAGER_MENU=1\n"
+ f"{_app_lvgl_intrinsics}"
+ " }"
+)
modern_setup_app_fdf_inf = "INF ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf"
modern_setup_app_uiapp_fdf_inf = "INF RuleOverride = MODERN_SETUP_UIAPP ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf"
modern_display_component = " ModernSetupPkg/Universal/ModernDisplayEngineDxe/ModernDisplayEngineDxe.inf"
+modern_display_component_lvgl = (
+ " ModernSetupPkg/Universal/ModernDisplayEngineDxe/ModernDisplayEngineDxe.inf {\n"
+ " \n"
+ " NULL|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\n"
+ " }"
+)
modern_display_fdf_inf = "INF ModernSetupPkg/Universal/ModernDisplayEngineDxe/ModernDisplayEngineDxe.inf"
boot_manager_menu_component = " MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf"
boot_manager_menu_fdf_inf = "INF MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf"
driver_sample_component = " MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf"
driver_sample_fdf_inf = "INF MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf"
-library_block = """ ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf
- ModernUiRendererLib|ModernSetupPkg/Library/ModernUiRendererLib/ModernUiRendererLib.inf
- ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf
-"""
+# LVGL core (upstream lvgl sources as a BASE library); resolved only in lvgl mode
+# and consumed transitively through the LVGL renderer library.
+lvgl_library_block = " LvglCoreLib|LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf\n"
+# The renderer library class resolves to the LVGL-backed implementation in lvgl
+# mode and to the hand-rolled GOP rasterizer otherwise (identical API).
+renderer_inf = (
+ "ModernSetupPkg/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf"
+ if display_engine == "lvgl"
+ else "ModernSetupPkg/Library/ModernUiRendererLib/ModernUiRendererLib.inf"
+)
+library_block = (
+ " ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf\n"
+ f" ModernUiRendererLib|{renderer_inf}\n"
+ " ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf\n"
+)
app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUiPlatformDataLib/ModernUiPlatformDataLib.inf
ModernUiBootDataLib|ModernSetupPkg/Library/ModernUiBootDataLib/ModernUiBootDataLib.inf
ModernUiDeviceDataLib|ModernSetupPkg/Library/ModernUiDeviceDataLib/ModernUiDeviceDataLib.inf
@@ -133,8 +176,10 @@ dsc = dsc.replace(
1,
)
if "ModernUiEngineLib|ModernSetupPkg" not in dsc:
- if display_engine == "modern" or include_modern_setup_app:
+ if (display_engine == "modern" or display_engine == "lvgl") or include_modern_setup_app:
dsc = dsc.replace("[LibraryClasses.common]\n", "[LibraryClasses.common]\n" + library_block, 1)
+if display_engine == "lvgl" and "LvglCoreLib|LvglSpikePkg" not in dsc:
+ dsc = dsc.replace("[LibraryClasses.common]\n", "[LibraryClasses.common]\n" + lvgl_library_block, 1)
if include_modern_setup_app and "ModernUiPlatformDataLib|ModernSetupPkg" not in dsc:
dsc = dsc.replace("[LibraryClasses.common]\n", "[LibraryClasses.common]\n" + app_library_block, 1)
if include_modern_setup_app and modern_setup_app_component not in dsc:
@@ -166,7 +211,7 @@ if replace_uiapp:
driver_sample_component + "\n OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf {",
1,
)
-if display_engine == "modern":
+if (display_engine == "modern" or display_engine == "lvgl"):
dsc = dsc.replace(
" CustomizedDisplayLib | MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf",
" CustomizedDisplayLib | ModernSetupPkg/Library/ModernUiCustomizedDisplayLib/ModernUiCustomizedDisplayLib.inf",
@@ -174,7 +219,7 @@ if display_engine == "modern":
)
dsc = dsc.replace(
" MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf",
- modern_display_component,
+ modern_display_component_lvgl if display_engine == "lvgl" else modern_display_component,
1,
)
if enable_driver_sample and driver_sample_component not in dsc:
@@ -183,7 +228,7 @@ if enable_driver_sample and driver_sample_component not in dsc:
driver_sample_component + "\n MdeModulePkg/Application/UiApp/UiApp.inf {",
1,
)
-if display_engine == "modern":
+if (display_engine == "modern" or display_engine == "lvgl"):
dsc += (
"\n[PcdsFixedAtBuild]\n"
f" gModernSetupPkgTokenSpaceGuid.PcdModernSetupTheme|{theme_pcd}\n"
@@ -202,7 +247,7 @@ fdf = fdf.replace(
"!include OvmfPkg/LoongArchVirt/VarStore.fdf.inc",
1,
)
-if display_engine == "modern":
+if (display_engine == "modern" or display_engine == "lvgl"):
fdf = fdf.replace(
"INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf",
modern_display_fdf_inf,
diff --git a/Scripts/build-lvgl-spike-loongarch.sh b/Scripts/build-lvgl-spike-loongarch.sh
new file mode 100755
index 0000000..ea72ea5
--- /dev/null
+++ b/Scripts/build-lvgl-spike-loongarch.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# experimental/lvgl-spike build validation:
+# Compile + link the LVGL core + software renderer + upstream UEFI port (with the
+# LoongArch64/RISC-V64 arch-gate patch in External/lvgl) for LOONGARCH64 under the
+# real edk2 LoongArch GCC toolchain. Builds a single UEFI_APPLICATION module
+# (LvglSpikeProbe) against the stock LoongArchVirtQemu platform DSC -- no FD, no
+# default overlay touched. Answers: does the patch let LVGL build on LoongArch?
+set -euo pipefail
+
+PKG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+# shellcheck disable=SC1091
+source "${PKG_DIR}/Scripts/edk2-workspace.sh"
+WORKSPACE="$(DetectWorkspace)"
+TARGET="${TARGET:-DEBUG}"
+JOBS="${JOBS:-$(nproc 2>/dev/null || echo 4)}"
+
+GCC_LOONGARCH64_PREFIX="${GCC_LOONGARCH64_PREFIX:-}"
+if [[ -z "${GCC_LOONGARCH64_PREFIX}" ]]; then
+ if command -v loongarch64-unknown-linux-gnu-gcc >/dev/null 2>&1; then
+ GCC_LOONGARCH64_PREFIX="loongarch64-unknown-linux-gnu-"
+ elif command -v loongarch64-linux-gnu-gcc >/dev/null 2>&1; then
+ GCC_LOONGARCH64_PREFIX="loongarch64-linux-gnu-"
+ else
+ GCC_LOONGARCH64_PREFIX="loongarch64-unknown-linux-gnu-"
+ fi
+fi
+
+export WORKSPACE
+export GCC_LOONGARCH64_PREFIX
+ConfigureModernSetupPackagePath
+# Make the experimental LvglSpikePkg resolvable as a package.
+AppendPackagePath "${PKG_DIR}/Experimental"
+export PACKAGES_PATH
+
+MODULE="${PKG_DIR}/Experimental/LvglSpikePkg/Library/LvglLib/LvglSpikeProbe.inf"
+PLATFORM_DSC="${PKG_DIR}/Experimental/LvglSpikePkg/LvglSpikeLoongArch.dsc"
+
+# LoongArch64/RISC-V64 UEFI support is upstream in the pinned External/lvgl
+# baseline; the submodule is consumed pristine with no local patching.
+
+if ! command -v "${GCC_LOONGARCH64_PREFIX}gcc" >/dev/null 2>&1; then
+ echo "Missing LoongArch GCC: ${GCC_LOONGARCH64_PREFIX}gcc" >&2
+ exit 1
+fi
+if [[ ! -f "${WORKSPACE}/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc" ]]; then
+ echo "WORKSPACE missing LoongArchVirtQemu platform: ${WORKSPACE}" >&2
+ exit 1
+fi
+
+cd "${WORKSPACE}"
+if [[ ! -x BaseTools/Source/C/bin/VfrCompile ]]; then
+ make -C BaseTools -j"${JOBS}"
+fi
+
+set +u
+# shellcheck disable=SC1091
+source edksetup.sh
+set -u
+
+echo "== Building LvglSpikeProbe (LVGL+UEFI port) for LOONGARCH64, TARGET=${TARGET} =="
+build \
+ -a LOONGARCH64 \
+ -t GCC \
+ -p "${PLATFORM_DSC}" \
+ -b "${TARGET}" \
+ -n "${JOBS}"
+
+echo ""
+echo "OK: LVGL built for LOONGARCH64."
+echo "EFI: ${WORKSPACE}/Build/*/${TARGET}_GCC/LOONGARCH64/LvglSpikeProbe.efi"
diff --git a/Scripts/build-lvgl-spike-riscv.sh b/Scripts/build-lvgl-spike-riscv.sh
new file mode 100755
index 0000000..1d6e1e1
--- /dev/null
+++ b/Scripts/build-lvgl-spike-riscv.sh
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+# Copyright (c) 2026, MarsDoge. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# experimental/lvgl-spike build validation (RISC-V):
+# Compile + link the LVGL core + software renderer + upstream UEFI port (with the
+# LoongArch64/RISC-V64 arch-gate patch) for RISCV64 under the edk2 RISC-V GCC
+# toolchain. Per repo convention RISC-V is build-only (no run/capture helper), so
+# this proves compile+link, not render. Builds one UEFI_APPLICATION; no FD.
+set -euo pipefail
+
+PKG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+# shellcheck disable=SC1091
+source "${PKG_DIR}/Scripts/edk2-workspace.sh"
+WORKSPACE="$(DetectWorkspace)"
+TARGET="${TARGET:-DEBUG}"
+JOBS="${JOBS:-$(nproc 2>/dev/null || echo 4)}"
+
+GCC_RISCV64_PREFIX="${GCC_RISCV64_PREFIX:-}"
+if [[ -z "${GCC_RISCV64_PREFIX}" ]]; then
+ if command -v riscv64-unknown-elf-gcc >/dev/null 2>&1; then
+ GCC_RISCV64_PREFIX="riscv64-unknown-elf-"
+ elif command -v riscv64-linux-gnu-gcc >/dev/null 2>&1; then
+ GCC_RISCV64_PREFIX="riscv64-linux-gnu-"
+ else
+ GCC_RISCV64_PREFIX="riscv64-unknown-elf-"
+ fi
+fi
+
+export WORKSPACE
+export GCC_RISCV64_PREFIX
+ConfigureModernSetupPackagePath
+AppendPackagePath "${PKG_DIR}/Experimental"
+export PACKAGES_PATH
+
+PLATFORM_DSC="${PKG_DIR}/Experimental/LvglSpikePkg/LvglSpikeRiscV.dsc"
+
+# LoongArch64/RISC-V64 UEFI support is upstream in the pinned External/lvgl
+# baseline; the submodule is consumed pristine with no local patching.
+
+if ! command -v "${GCC_RISCV64_PREFIX}gcc" >/dev/null 2>&1; then
+ echo "Missing RISC-V GCC: ${GCC_RISCV64_PREFIX}gcc" >&2
+ exit 1
+fi
+
+cd "${WORKSPACE}"
+if [[ ! -x BaseTools/Source/C/bin/VfrCompile ]]; then
+ make -C BaseTools -j"${JOBS}"
+fi
+
+set +u
+# shellcheck disable=SC1091
+source edksetup.sh
+set -u
+
+echo "== Building LvglSpikeProbe (LVGL+UEFI port) for RISCV64, TARGET=${TARGET} =="
+build \
+ -a RISCV64 \
+ -t GCC \
+ -p "${PLATFORM_DSC}" \
+ -b "${TARGET}" \
+ -n "${JOBS}"
+
+echo ""
+echo "OK: LVGL built for RISCV64."
+echo "EFI: ${WORKSPACE}/Build/LvglSpikeRiscV/${TARGET}_GCC/RISCV64/LvglSpikeProbe.efi"
diff --git a/Scripts/build-ovmf-x64.sh b/Scripts/build-ovmf-x64.sh
index 12b765f..eac2849 100755
--- a/Scripts/build-ovmf-x64.sh
+++ b/Scripts/build-ovmf-x64.sh
@@ -17,11 +17,22 @@ JOBS="${JOBS:-$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
MODERN_SETUP_THEME="${MODERN_SETUP_THEME:-graphite-gold}"
MODERN_SETUP_DISPLAY_ENGINE="${MODERN_SETUP_DISPLAY_ENGINE:-modern}"
MODERN_SETUP_REPLACE_UIAPP="${MODERN_SETUP_REPLACE_UIAPP:-0}"
+# Opt-in control-rich VFR test driver (checkbox/numeric/date/time/string/
+# password/ordered-list), reachable via Device Manager. Used to exercise the
+# DisplayEngine control affordances; off by default.
+MODERN_SETUP_DEMO_DRIVER_SAMPLE="${MODERN_SETUP_DEMO_DRIVER_SAMPLE:-0}"
GENERATE_ONLY="${GENERATE_ONLY:-0}"
OVERLAY_DIR="${WORKSPACE}/Build/ModernSetupPkgOverlay"
export WORKSPACE
ConfigureModernSetupPackagePath
+# Experimental LvglSpikePkg is only consumed by MODERN_SETUP_DISPLAY_ENGINE=lvgl;
+# making it resolvable here is harmless for native/modern.
+AppendPackagePath "${PKG_DIR}/Experimental"
+export PACKAGES_PATH
+
+# LoongArch64/RISC-V64 UEFI support is upstream in the pinned External/lvgl
+# baseline; the submodule is consumed pristine with no local patching.
if [[ ! -d "${WORKSPACE}/MdePkg" || ! -d "${WORKSPACE}/OvmfPkg" ]]; then
echo "WORKSPACE does not look like an edk2 checkout with MdePkg and OvmfPkg: ${WORKSPACE}" >&2
@@ -36,7 +47,7 @@ fi
mkdir -p "${OVERLAY_DIR}"
-python3 - <<'PY' "${WORKSPACE}" "${OVERLAY_DIR}" "${MODERN_SETUP_THEME}" "${MODERN_SETUP_DISPLAY_ENGINE}" "${MODERN_SETUP_REPLACE_UIAPP}"
+python3 - <<'PY' "${WORKSPACE}" "${OVERLAY_DIR}" "${MODERN_SETUP_THEME}" "${MODERN_SETUP_DISPLAY_ENGINE}" "${MODERN_SETUP_REPLACE_UIAPP}" "${MODERN_SETUP_DEMO_DRIVER_SAMPLE}"
from pathlib import Path
import re
import sys
@@ -46,6 +57,7 @@ overlay = Path(sys.argv[2])
theme_name = sys.argv[3].strip().lower()
display_engine = sys.argv[4].strip().lower()
replace_uiapp_flag = sys.argv[5].strip().lower()
+enable_driver_sample = sys.argv[6].strip().lower() in {"1", "true", "yes"}
theme_pcd = {
"orange": "0x00",
"amber": "0x00",
@@ -61,9 +73,9 @@ if theme_pcd is None:
f"Unsupported MODERN_SETUP_THEME={theme_name!r}; "
"use orange, amber, dark-orange, red, accent-red, dark-red, graphite, or graphite-gold"
)
-if display_engine not in {"modern", "native"}:
+if display_engine not in {"modern", "native", "lvgl"}:
raise SystemExit(
- f"Unsupported MODERN_SETUP_DISPLAY_ENGINE={display_engine!r}; use modern or native"
+ f"Unsupported MODERN_SETUP_DISPLAY_ENGINE={display_engine!r}; use modern, native, or lvgl"
)
if replace_uiapp_flag not in {"0", "1", "false", "true", "no", "yes"}:
raise SystemExit(
@@ -71,19 +83,56 @@ if replace_uiapp_flag not in {"0", "1", "false", "true", "no", "yes"}:
)
replace_uiapp = replace_uiapp_flag in {"1", "true", "yes"}
-modern_setup_app_component_boot_manager_fallback = """ ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf {
-
- GCC:*_*_*_CC_FLAGS = -DMODERN_SETUP_NATIVE_FALLBACK_BOOT_MANAGER_MENU=1
- }"""
+# When ModernSetupApp replaces UiApp, in lvgl mode the app shell also renders
+# through the LVGL-backed renderer (resolved via the ModernUiRendererLib class
+# below), so it must force-link IntrinsicLib like the lvgl-mode display engine.
+_app_lvgl_intrinsics = (
+ " \n"
+ " NULL|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\n"
+ if display_engine == "lvgl"
+ else ""
+)
+modern_setup_app_component_boot_manager_fallback = (
+ " ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf {\n"
+ " \n"
+ " GCC:*_*_*_CC_FLAGS = -DMODERN_SETUP_NATIVE_FALLBACK_BOOT_MANAGER_MENU=1\n"
+ f"{_app_lvgl_intrinsics}"
+ " }"
+)
modern_setup_app_uiapp_fdf_inf = "INF RuleOverride = MODERN_SETUP_UIAPP ModernSetupPkg/Application/ModernSetupApp/ModernSetupApp.inf"
+# In lvgl mode the SAME ModernDisplayEngineDxe interaction backend is used as in
+# modern mode; only the renderer library class is swapped to the LVGL-backed
+# implementation (below), and IntrinsicLib is force-linked because the renderer
+# now pulls LVGL's software draw pipeline.
modern_display_component = " ModernSetupPkg/Universal/ModernDisplayEngineDxe/ModernDisplayEngineDxe.inf"
+modern_display_component_lvgl = (
+ " ModernSetupPkg/Universal/ModernDisplayEngineDxe/ModernDisplayEngineDxe.inf {\n"
+ " \n"
+ " NULL|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\n"
+ " }"
+)
modern_display_fdf_inf = "INF ModernSetupPkg/Universal/ModernDisplayEngineDxe/ModernDisplayEngineDxe.inf"
+# LVGL core (the upstream lvgl sources, built as a BASE library) is resolved only
+# in lvgl mode and consumed transitively through the LVGL renderer library.
+lvgl_library_block = " LvglCoreLib|LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf\n"
boot_manager_menu_component = " MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf"
boot_manager_menu_fdf_inf = "INF MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf"
-library_block = """ ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf
- ModernUiRendererLib|ModernSetupPkg/Library/ModernUiRendererLib/ModernUiRendererLib.inf
- ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf
-"""
+# Opt-in control-rich VFR test driver (reachable via Device Manager).
+driver_sample_component = " MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf"
+driver_sample_fdf_inf = "INF MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf"
+# The renderer library class resolves to the LVGL-backed implementation in lvgl
+# mode and to the hand-rolled GOP rasterizer otherwise. Both expose the identical
+# ModernUiRenderer.h API, so ModernUiEngineLib and its consumers are unchanged.
+renderer_inf = (
+ "ModernSetupPkg/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf"
+ if display_engine == "lvgl"
+ else "ModernSetupPkg/Library/ModernUiRendererLib/ModernUiRendererLib.inf"
+)
+library_block = (
+ " ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf\n"
+ f" ModernUiRendererLib|{renderer_inf}\n"
+ " ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf\n"
+)
app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUiPlatformDataLib/ModernUiPlatformDataLib.inf
ModernUiBootDataLib|ModernSetupPkg/Library/ModernUiBootDataLib/ModernUiBootDataLib.inf
ModernUiDeviceDataLib|ModernSetupPkg/Library/ModernUiDeviceDataLib/ModernUiDeviceDataLib.inf
@@ -121,7 +170,7 @@ dsc = replace_regex_once(
r"\1Build/ModernSetupPkgOverlay/OvmfX64ModernSetup.fdf",
"FLASH_DEFINITION",
)
-if display_engine == "modern" or replace_uiapp:
+if (display_engine == "modern" or display_engine == "lvgl") or replace_uiapp:
if "ModernUiEngineLib|ModernSetupPkg" not in dsc:
if "[LibraryClasses.common]\n" in dsc:
dsc = replace_once(dsc, "[LibraryClasses.common]\n", "[LibraryClasses.common]\n" + library_block, "LibraryClasses.common")
@@ -150,7 +199,16 @@ if replace_uiapp:
boot_manager_menu_component + r"\n\1",
"QemuKernelLoaderFsDxe component",
)
-if display_engine == "modern":
+if (display_engine == "modern" or display_engine == "lvgl"):
+ # lvgl mode additionally resolves the LVGL core library, consumed
+ # transitively by the LVGL renderer.
+ if display_engine == "lvgl" and "LvglCoreLib|LvglSpikePkg" not in dsc:
+ if "[LibraryClasses.common]\n" in dsc:
+ dsc = replace_once(dsc, "[LibraryClasses.common]\n", "[LibraryClasses.common]\n" + lvgl_library_block, "LibraryClasses.common for lvgl")
+ elif "[LibraryClasses]\n" in dsc:
+ dsc = replace_once(dsc, "[LibraryClasses]\n", "[LibraryClasses]\n" + lvgl_library_block, "LibraryClasses for lvgl")
+ else:
+ raise SystemExit("Expected LibraryClasses anchor for lvgl")
dsc = replace_regex_once(
dsc,
r"^\s*CustomizedDisplayLib\s*\|\s*MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib\.inf\s*$",
@@ -160,18 +218,25 @@ if display_engine == "modern":
dsc = replace_regex_once(
dsc,
r"^\s*MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe\.inf\s*$",
- modern_display_component,
+ modern_display_component_lvgl if display_engine == "lvgl" else modern_display_component,
"DisplayEngineDxe component",
)
dsc += (
"\n[PcdsFixedAtBuild]\n"
f" gModernSetupPkgTokenSpaceGuid.PcdModernSetupTheme|{theme_pcd}\n"
)
+if enable_driver_sample and driver_sample_component not in dsc:
+ dsc = replace_regex_once(
+ dsc,
+ r"^( MdeModulePkg/Application/UiApp/UiApp\.inf)",
+ driver_sample_component + r"\n\1",
+ "UiApp DSC component anchor for DriverSample",
+ )
(overlay / "OvmfX64ModernSetup.dsc").write_text(dsc)
fdf_path = workspace / "OvmfPkg/OvmfPkgX64.fdf"
fdf = fdf_path.read_text()
-if display_engine == "modern":
+if (display_engine == "modern" or display_engine == "lvgl"):
fdf = replace_regex_once(
fdf,
r"^\s*INF\s+MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe\.inf\s*$",
@@ -200,6 +265,13 @@ if replace_uiapp:
" UI STRING=\"ModernSetupApp\" Optional\n"
" }\n"
)
+if enable_driver_sample and driver_sample_fdf_inf not in fdf:
+ fdf = replace_regex_once(
+ fdf,
+ r"^(\s*INF\s+MdeModulePkg/Application/UiApp/UiApp\.inf\s*)$",
+ driver_sample_fdf_inf + r"\n\1",
+ "UiApp FDF INF anchor for DriverSample",
+ )
(overlay / "OvmfX64ModernSetup.fdf").write_text(fdf)
PY
diff --git a/Tests/Smoke/smoke_validate.py b/Tests/Smoke/smoke_validate.py
index bab30d2..882f601 100755
--- a/Tests/Smoke/smoke_validate.py
+++ b/Tests/Smoke/smoke_validate.py
@@ -67,6 +67,17 @@
"ModernUiHiiBridge.h",
"ModernUiPageAdapter.h",
)
+# The experimental LVGL rendering backend (Experimental/LvglSpikePkg and the
+# LVGL-backed renderer) is selected only by MODERN_SETUP_DISPLAY_ENGINE=lvgl and
+# must never appear in a default (native/modern) generated overlay. These tokens
+# are checked against the *generated* overlays only -- the build scripts
+# themselves legitimately reference them inside the lvgl branch.
+PROHIBITED_DEFAULT_OVERLAY_LVGL_TOKENS = (
+ "LvglCoreLib",
+ "ModernUiLvglRendererLib",
+ "LvglSpikePkg",
+ "LvglDisplayEngineDxe",
+)
PROHIBITED_THEME_ALIAS_TOKENS = (
"\x61\x6f\x72\x75\x73",
"\x61\x73\x75\x73",
@@ -2263,7 +2274,6 @@ def check_phase33_display_form_view_model_boundary(root: Path) -> list[str]:
"ModernDisplayFormRowGetVisualRole",
"MODERN_DISPLAY_FORM_ROW",
"ModernDisplayDrawStatementRowAccents",
- "ModernDisplayDrawStatementValueLane",
):
if token not in row_surface_body:
raise SmokeFailure(f"DisplayEngine row surface must consume the Phase34/36 row model/helper: {token}")
@@ -2280,8 +2290,8 @@ def check_phase33_display_form_view_model_boundary(root: Path) -> list[str]:
"ModernDisplayStatementTextInset",
"ModernDisplayDrawRightRailDivider",
"ModernDisplayPageStatusText",
- "ModernDisplayDrawStatementValueLane",
- "ModernDisplayDrawStatementValueLaneCue",
+ "ModernDisplayKindToValueType",
+ "ModernDisplayDrawStatementRowCue",
"ModernDisplayFooterStatusReservedColumns",
"ModernDisplayPageState",
"ModernDisplayPageStateRebootRequired",
@@ -2310,32 +2320,42 @@ def check_phase33_display_form_view_model_boundary(root: Path) -> list[str]:
if token not in page_chrome_body:
raise SmokeFailure(f"Phase39/40 page chrome must render existing FormBrowser presentation context: {token}")
- value_lane_body = extract_c_function_body(internal_text, "ModernDisplayDrawStatementValueLane")
+ # Per-opcode control affordance: the DisplayEngine reuses the SHARED engine
+ # cue vocabulary (ModernUiEngineDrawControlCue) rather than carrying its own
+ # shape switch. The adapter only maps its row kind to the shared value type;
+ # the affordance shapes themselves live once in ModernUiEngineLib so the App
+ # value lane and the in-setup row read identically.
+ kind_cue_body = extract_c_function_body(internal_text, "ModernDisplayKindToValueType")
for token in (
- "ModernDisplayDrawStatementValueLaneCue",
+ "ModernDisplayFormRowCheckbox",
+ "ModernUiValueCheckbox",
+ "ModernDisplayFormRowNumeric",
+ "ModernUiValueNumeric",
+ "ModernDisplayFormRowOrderedList",
+ "ModernUiValueOrderedList",
+ ):
+ if token not in kind_cue_body:
+ raise SmokeFailure(f"Phase41 control cue kind mapper missing mapping token: {token}")
+
+ # The post-text overlay draws the affordance only on editable rows and only
+ # after native text has been printed; it must classify already-materialized
+ # statement data, delegate to the shared engine cue, and never read/write
+ # HII or storage.
+ row_cue_body = extract_c_function_body(internal_text, "ModernDisplayDrawStatementRowCue")
+ for token in (
+ "ModernDisplayClassifyStatementForForm",
"ModernDisplayFormRowIsTextOnly",
- "ModernDisplayFormRowStateHighlighted",
"ModernDisplayFormRowStateDisabled",
"ModernDisplayFormRowStateReadOnly",
+ "ModernUiEngineDrawControlCue",
+ "ModernDisplayKindToValueType",
):
- if token not in value_lane_body:
- raise SmokeFailure(f"Phase41 value lane polish missing guarded draw token: {token}")
-
- value_lane_cue_body = extract_c_function_body(internal_text, "ModernDisplayDrawStatementValueLaneCue")
- for token in (
- "ModernUiStrokeRect",
- "ModernUiFillRect",
- "ModernUiBlendColor",
- "ModernDisplayFormRowAccentColor",
- "ModernDisplayFormRowStateSelected",
- "Theme->AccentYellow",
- "Theme->Border",
- ):
- if token not in value_lane_cue_body:
- raise SmokeFailure(f"Phase41 value lane cue helper missing presentation token: {token}")
- for token in ("ConfigAccess", "RouteConfig", "ExtractConfig", "SetVariable", "HiiSetBrowserData", "HiiGetString"):
- if token in value_lane_cue_body:
- raise SmokeFailure(f"Phase41 value lane cue helper contains prohibited semantic/storage token: {token}")
+ if token not in row_cue_body:
+ raise SmokeFailure(f"Phase41 control cue overlay missing guarded draw token: {token}")
+ for body in (kind_cue_body, row_cue_body):
+ for token in ("ConfigAccess", "RouteConfig", "ExtractConfig", "SetVariable", "HiiSetBrowserData", "HiiGetString"):
+ if token in body:
+ raise SmokeFailure(f"Phase41 control cue helper contains prohibited semantic/storage token: {token}")
right_help_body = extract_c_function_body(internal_text, "ModernDisplayDrawRightHelpRailContext")
for token in (
@@ -2369,6 +2389,34 @@ def check_phase33_display_form_view_model_boundary(root: Path) -> list[str]:
if token not in engine_text:
raise SmokeFailure(f"Phase36 DisplayEngine footer status chip missing token: {token}")
+ # The shared control-cue vocabulary is the single home for per-type
+ # affordance shapes; both the App value lane and the DisplayEngine row cue
+ # delegate to it, so the shapes are defined exactly once here. It is built
+ # only from renderer primitives and keys on the engine value type.
+ control_cue_body = extract_c_function_body(engine_text, "ModernUiEngineDrawControlCue")
+ for token in (
+ "ModernUiValueCheckbox",
+ "ModernUiValueOneOf",
+ "ModernUiValueOrderedList",
+ "ModernUiValueNumeric",
+ "ModernUiValueDateTime",
+ "ModernUiValuePassword",
+ "ModernUiValueString",
+ "ModernUiValueAction",
+ "ModernUiFillTriangle",
+ "ModernUiStrokeRect",
+ "ModernUiFillRect",
+ ):
+ if token not in control_cue_body:
+ raise SmokeFailure(f"Phase41 shared control cue vocabulary missing affordance token: {token}")
+ # The App value lane must route through the shared cue, not invent its own.
+ draw_value_body = extract_c_function_body(engine_text, "ModernUiEngineDrawValue")
+ if "ModernUiEngineDrawControlCue" not in draw_value_body:
+ raise SmokeFailure("Phase41 App value lane must delegate control affordances to ModernUiEngineDrawControlCue")
+ for token in ("ConfigAccess", "RouteConfig", "ExtractConfig", "SetVariable", "HiiSetBrowserData", "HiiGetString"):
+ if token in control_cue_body:
+ raise SmokeFailure(f"Phase41 shared control cue contains prohibited semantic/storage token: {token}")
+
form_display = root / "Universal" / "ModernDisplayEngineDxe" / "FormDisplay.c"
form_display_text = strip_c_comments(form_display.read_text(encoding="utf-8"))
display_one_menu = extract_c_function_body(form_display_text, "DisplayOneMenu")
@@ -2532,6 +2580,9 @@ def check_overlay_generation(root: Path) -> list[str]:
if not generated_path.exists():
raise SmokeFailure(f"missing generated overlay file: {generated_path}")
assert_not_contains_any(generated_path, PROHIBITED_DEFAULT_OVERLAY_TOKENS)
+ # The LVGL backend is experimental and lvgl-mode only; it must
+ # never leak into a default native/modern overlay.
+ assert_not_contains_any(generated_path, PROHIBITED_DEFAULT_OVERLAY_LVGL_TOKENS)
dsc = workspace / "Build" / "ModernSetupPkgOverlay" / dsc_name
if engine == "modern":
diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.c b/Universal/ModernDisplayEngineDxe/FormDisplay.c
index d589880..8fafe54 100644
--- a/Universal/ModernDisplayEngineDxe/FormDisplay.c
+++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c
@@ -2637,6 +2637,21 @@ DisplayOneMenu (
}
}
+ //
+ // Overlay the per-opcode control affordance AFTER all row text (and its
+ // highlight background) has been printed, so the cue is composited on top
+ // instead of being overpainted by the native text background.
+ //
+ ModernDisplayDrawStatementRowCue (
+ gFormData,
+ Statement,
+ BeginCol,
+ MenuOption->Row,
+ RowWidth,
+ Highlight,
+ (BOOLEAN)(gUserInput->SelectedStatement == Statement)
+ );
+
return EFI_SUCCESS;
}
diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h
index 4024025..317b52a 100644
--- a/Universal/ModernDisplayEngineDxe/FormDisplay.h
+++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h
@@ -101,6 +101,34 @@ ModernDisplayDrawStatementRow (
IN BOOLEAN Selected
);
+/**
+ Draw a per-opcode control affordance over an already-painted statement row.
+
+ Call this AFTER native FormBrowser has printed the row's prompt/value text and
+ highlight background, so the affordance is composited on top instead of being
+ overpainted. It paints only a small non-semantic cue glyph at the row's right
+ edge and never reads, writes, or owns any HII/FormBrowser value or semantics.
+
+ @param[in] FormData DisplayEngine form that owns Statement. May be NULL.
+ @param[in] Statement Statement to classify. May be NULL (then no cue).
+ @param[in] Column Text-grid column where the row starts.
+ @param[in] Row Text-grid row of the statement.
+ @param[in] Width Text-grid column count of the row.
+ @param[in] Highlight TRUE when the row currently has keyboard highlight.
+ @param[in] Selected TRUE when the row is in edit/selection mode.
+**/
+VOID
+EFIAPI
+ModernDisplayDrawStatementRowCue (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData OPTIONAL,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement OPTIONAL,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN UINTN Width,
+ IN BOOLEAN Highlight,
+ IN BOOLEAN Selected
+ );
+
//
// Screen definitions
//