feat(lvgl): real widgets + modern dialogs, CJK chrome, selection polish & OEM branding slot#40
Merged
Merged
Conversation
ReadString's edit caret used gST->ConOut->EnableCursor, which draws straight to the GraphicsConsole framebuffer and is invisible/misplaced behind an off-screen canvas (the LVGL backend). Suppress the native cursor and paint a thin accent caret at the edit cell via a new renderer helper, ModernDisplayDrawTextCaret (declared in FormDisplay.h, implemented in ModernUiCustomizedDisplayLib alongside the row-cue helpers), redrawn each keystroke after the field text so it leaves no trail. This closes the last interaction surface that bypassed the renderer: the LVGL backend now composites the full FormBrowser interaction set (rows, one-of and dialog popups, and input editing) end-to-end, identically on the GOP backend. App-local; no HII/value/storage semantics touched. Validated: OVMF X64 lvgl-mode screendump of the DriverSample string editor showing the caret, GOP + lvgl builds, and smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nly) First IFR-opcode -> LVGL-widget mapping. A new renderer entry point, ModernUiRenderOneOf, abstracts a one-of control: the LVGL backend builds a transient display-only lv_dropdown (rounded box, border, LV_SYMBOL_DOWN arrow), renders it via lv_snapshot_take (enables LV_USE_SNAPSHOT + adds lv_snapshot.c), and alpha-composites the ARGB8888 snapshot over the row background in the shadow canvas; the GOP backend keeps composing the value box from primitives, so there is no GOP regression. ModernUiEngineDrawValue routes one-of values to it (front-page App path); the in-setup DisplayEngine overlays it on the value lane via the new ModernDisplayDrawOneOfWidget, using the option string FormBrowser just printed (NARROW_CHAR/WIDE_CHAR glyph markers stripped). The one-of affordance cue is skipped for these rows since the rendered control carries its own arrow. Display-only: edk2 FormBrowser still owns the selection popup, ConfigAccess, and callbacks. This is the reusable widget pipeline (create -> snapshot -> alpha-composite) for further opcode->widget mappings. Validated: OVMF X64 lvgl + GOP screendumps of the DriverSample VFR form and the App preferences page (one-of renders as a real dropdown on LVGL, a value box on GOP, with clean option text), both builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extends the IFR-opcode -> LVGL-widget mapping beyond one-of to the rest of the value-bearing controls. On the LVGL backend: checkbox -> a checked lv_checkbox; numeric/string/password -> a styled lv_obj field with an lv_label (password masked). All share a new LvglComposeSnapshot helper (lv_snapshot_take + ARGB8888 alpha-composite) and LvglStyleControl/LvglAsciiLabel helpers. Renderer layer gains per-control entry points (ModernUiRenderCheckbox/Numeric/ String/Password) plus an arrow-less ModernUiDrawFieldBox; the GOP backend implements them as themed value/field boxes (no regression). The App path (ModernUiEngineDrawValue) dispatches per value type, and the in-setup DisplayEngine generalizes ModernDisplayDrawOneOfWidget into ModernDisplayDrawValueWidget (opcode-dispatched over the value lane). The affordance cue is skipped for all mapped rows. Date/time and ordered-list keep the cue (no clean single-widget mapping yet); action/reference keep the arrow. Display-only throughout: edk2 FormBrowser still owns selection/editing, ConfigAccess, and callbacks. Validated: OVMF X64 lvgl + GOP screendumps of the DriverSample VFR form (every value control renders as a real widget on LVGL / a themed box on GOP, with clean text), both builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes the IFR-opcode -> LVGL-widget mapping for the remaining value-bearing controls: - ordered-list -> a real list-style lv_obj field (LV_SYMBOL_LIST prefix + the current option order), wired into both the App draw path and the in-setup DisplayEngine overlay; its affordance cue is dropped since the widget carries its own. - date/time -> a segmented field (value spaced around / : - delimiters so month/day/year or H:M:S read as discrete cells) on the app-facing draw path. In the in-setup DisplayEngine date/time deliberately keeps native per-segment rendering + the type cue, because FormBrowser highlights the active segment in place and a full-lane widget overlay would mask that editing feedback. New renderer entry points ModernUiRenderOrderedList / ModernUiRenderDateTime on both backends (GOP draws themed field boxes -- no regression). Display-only throughout: edk2 FormBrowser still owns the reorder popup and segment editing. Validated: OVMF X64 lvgl + GOP (DriverSample) builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ght band When the highlighted statement is the last visible row (e.g. Reset on the front page), the form's 'clean the remain field' loop cleared the rows below the menu while the highlight display attribute was still set. The modern renderer paints cleared rows with the current background, so that empty area was filled with the highlight band color (SelectedBand) -- a large spurious tan block below the menu. Reset the display attribute to the normal field color (GetFieldTextColor, which maps to Theme->Surface) before the clear loop, mirroring the reset already done before the scroll down-arrow. Backend-agnostic; fixes any form whose last visible row is highlighted. Validated: OVMF X64 lvgl + GOP builds clean, smoke PASS, front-page screendump with Reset highlighted shows a dark empty area (no tan block). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…own as ?) FormBrowser builds an ordered-list value by joining options with CHAR_CARRIAGE_RETURN (ProcessOptions.c). That 0x0D passes the >= 0xFFF0 glyph-width marker filter but is < 0x20, so LvglAsciiLabel rendered each separator as '?' (<ATAPI CD>?<IDE HDD>?<PXE>). Add a shared ModernUiNormalizeOrderedListText helper (in the common surface compiled into both backends): strip glyph-width markers, collapse each run of CR/LF into a single ' / ', and drop leading/trailing separators. Both the GOP and LVGL ordered-list renderers normalize the value before drawing, so the box reads '<ATAPI CD> / <IDE HDD> / <PXE>'. Display-only; minimal scope (no multi-row list box). Validated: OVMF X64 lvgl + GOP builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…empty label Two in-setup widget issues found in live testing: 1. Numeric in-place editing and string/password input popups collided with the composited value-lane widget: native FormBrowser's initial editor draw is narrower than (and a different color from) the widget, so the widget box remnant showed beside/under the editor (digits looked invisible on the band; the string popup left the old-value widget peeking out to its left). Add ModernDisplayClearValueLane, called from the edit entry in the form key handler, to repaint the value lane to the plain field background (Theme->Surface, matching what native editing erases to) right before the editor runs. The full form repaint after editing restores the widget. 2. The lv_checkbox widget leaked a stray ']' from the raw '[X]' value text. Render the box indicator with an empty label -- the box conveys the state and the row's left prompt already names the control. Validated: OVMF X64 lvgl + GOP builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per the 'prefer LVGL built-in widgets' direction, replace the hand-composed lv_obj+lv_label field with a real single-line lv_textarea for the string/numeric/password value widgets (one-of already uses lv_dropdown, checkbox uses lv_checkbox). The earlier reason for the lv_obj+label fallback (textarea caret/scroll obscuring short text at row height) is addressed by configuration: - lv_textarea_set_one_line(true) - scrollbar off (LV_SCROLLBAR_MODE_OFF) - caret hidden (LV_PART_CURSOR opacity transparent) -- display-only snapshot - native password masking (lv_textarea_set_password_mode) replaces the manual '*' loop - cursor moved to position 0 so the start of the text shows, not the scrolled end Display-only; edk2 still owns editing. Verified by an OVMF X64 lvgl DriverSample screendump: [0]/[21]/[12]/[16]/[18] fields render cleanly at row height. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an OEM branding watermark slot to the modern DisplayEngine. A new renderer entry point ModernUiDrawOemWatermark composites an original, theme-tinted brand mark (document glyph + "MODERN UEFI SETUP * OPEN SOURCE" + the project URL) into the content-area whitespace, low-opacity, so it fills empty space without fighting the setup text. The asset is 100% original geometry + the project URL -- no IBV/commercial reuse. Assets/Branding/oem-watermark.svg is the scalable design source; Scripts/gen-oem-watermark.py rasterizes it to an A8 coverage map (OemWatermarkData.c/.h). The LVGL backend alpha-blends the A8 map (tinted with the theme muted-text color) directly into the shadow canvas and BLTs the region; the GOP backend is a no-op for now. Because the native FormBrowser repaints the content area after the chrome (rows, the empty-row clear, and the help-string update), drawing the mark at chrome time gets wiped. So the DisplayEngine draws it *after* the statement rows via ModernDisplayDrawOemWatermarkOverlay (invoked at the end of the CfRepaint pass) and confines it to the statement column -- the help/right-rail columns are repainted by later form states and would clip the mark. Display-only throughout: parses no HII, owns no FormBrowser state, no ConfigAccess. Verified by OVMF X64 lvgl screendump of a DriverSample sub-form with content whitespace, plus smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In-setup confirm/error dialogs looked retro and clipped under the modern
renderer:
1. Text truncated with "..." -- the native DisplayEngine sizes popups in
character columns, but the modern proportional font advances wider than a
text-grid cell, so a budget derived from the char count clipped the dialog's
own message ("Load default configurat..."). PrintInternal now grows the text
budget to the measured proportional width when the caller imposes no column
constraint (Width == 0), so unconstrained prints render in full.
2. Dashed-border seam -- the native engine frames popups and multi-string boxes
with Unicode box-drawing glyphs (U+2500..U+257F), which the modern glyph
renderer painted as dashes on top of the panel surface that already supplies
the frame. ModernDisplayCopyPrintable now drops that block in modern mode.
Renderer-layer only: edk2 still owns the dialog control flow, key handling, and
message strings. Verified by OVMF X64 lvgl screendump of the F9 "Load defaults"
confirm dialog, plus smoke.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A living, checklist-style read on how far the engine (GOP "modern" and LVGL "beautiful" lines) and the ModernSetupApp front page are from shipping on real platforms, with ordered remaining work, effort sizing, and the decisions that gate the rest. Complements the existing feature/validation matrices rather than duplicating them; records the LVGL backend graduation, CJK font, memory budget, and hardware-validation thresholds as the real product gates, plus the known watermark-on-dense-form regression and the LvglDisplayEngineDxe cleanup backlog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The watermark was anchored in the content region's bottom whitespace, but on a form whose statement rows fill the content area it tinted faintly over the last rows (a regression from the watermark feature). The DisplayEngine now passes the first empty row (FirstEmptyRow, captured before the empty-row clear loop) to ModernDisplayDrawOemWatermarkOverlay, which confines the mark to the whitespace band from that row down to the content bottom. When the rows reach the content bottom the band collapses below the renderer's minimum-size guard, so the mark is suppressed instead of painting over a statement row. Placement on forms that do have whitespace is unchanged. Verified by OVMF X64 lvgl screendumps: dense DriverSample form (mark suppressed) and short dynamic sub-form (mark still shown in whitespace), plus smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The modern DisplayEngine chrome (header product/mode names and the tab-hint labels) was pinned to English even when the active language is Simplified Chinese, so entering a setup form broke the localization the front-page app already had. Route those labels through ModernUiGetString so the header reads "现代UEFI设置工具 / 高级模式" with tabs "设置分类 / 设备 / 启动 / 安全 / 退出" under the zh-Hans default (PcdModernSetupDefaultLanguage). The CJK glyphs come from the existing embedded Noto Sans CJK SC subset. Labels are a visual hint only -- no change to form navigation, HII GUID binding, callbacks, or storage. To make this linkable from the DisplayEngine: - ModernUiStringLib now declares DXE_DRIVER (was UEFI_APPLICATION only); - it is added to the modern/lvgl DisplayEngine overlay library block (moved out of the app-only block, which is always co-applied) in all four target build scripts, and to the CustomizedDisplayLib LibraryClasses. Verified by an OVMF X64 lvgl screendump of a DriverSample form with the chrome in Chinese, the modern (GOP) build, and smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The highlighted statement row rendered as a flat, muddy SelectedBand band even though ModernDisplayDrawStatementRow already paints a modern row-level selection (inset bar, top/bottom sheen, left accent, framed border) underneath -- the native per-cell text print buried it under a solid fill. The per-cell print path (PrintInternal) now suppresses that flat highlight fill on the single row that just received selection styling, tracked by mModernStyledHighlightRow (set in ModernDisplayDrawStatementRow, cleared when the row de-highlights). The skip is scoped to that exact row, so other EFI_RED-background text -- a highlighted selectable-popup option, which has no row-level styling beneath it -- still fills normally and keeps its highlight. Display-only; no change to navigation, editing, or HII ownership. Applies to both the GOP "modern" and LVGL backends. Verified by OVMF X64 lvgl screendumps: selection at rest, after a highlight move (no stale band on the previous row), and an open one-of popup (highlighted option unchanged), plus the modern build and smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refine the selected row from a busy, muddy treatment (full SelectedBand band + inset blend + top/bottom sheens + framed border + inner highlight line) into a clean, single-intent look: a subtle warm-tinted fill plus one solid 6px left accent stripe. The selection color is sourced once in ModernUiGetSelectableRowBackground (Surface blended ~30% toward AccentYellow instead of BackgroundBlack+SelectedBand at 74%), so the row fill and the per-cell text anti-alias background stay matched and there are no glyph halos. ModernUiDrawSelectableRow's selected branch is reduced to the left accent stripe. Shared visual primitive: applies to both the GOP and LVGL backends and to selectable rows in both the front-page app and the in-setup browser. Verified by OVMF X64 lvgl screendumps (selection clear and clean, text legible), the modern build, and smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "CONTEXT HELP" label rendered as plain muted body text, reading as an oversight next to the gold CPU/Memory/Voltage rail headers. Give it a soft muted-gold accent (AccentYellow blended 50% toward MutedText) so it reads as a styled section header while staying deliberately subdued below the primary telemetry rail in the visual hierarchy. Display-only label color; keeps the MutedText token the right-help-rail smoke guard requires. Verified by an OVMF X64 lvgl screendump and smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ow reset Two issues found in self-review of this branch: 1. ABI mismatch: ModernDisplayDrawOemWatermarkOverlay was declared EFIAPI in FormDisplay.h (and called through that prototype) but defined without EFIAPI. The defining TU does not include FormDisplay.h, so no diagnostic fired. On toolchains where EFIAPI differs from the default (e.g. GCC X64 ms_abi vs SysV), FirstEmptyRow would be read from the wrong register, defeating the watermark whitespace-confinement. Add EFIAPI to the definition to match the declaration and the sibling functions in the file. 2. Stale highlight-row tracking across popups: the per-cell print path skips the highlight fill on the row recorded by ModernDisplayDrawStatementRow. A selectable-option popup prints its highlighted option with an EFI_RED background via PrintStringAt without going through ModernDisplayDrawStatementRow, so if that option shares the recorded grid row its fill was wrongly skipped, leaving the option without a highlight. Add ModernDisplayResetHighlightRowTracking and call it at CreatePopup entry so popup lines are never mistaken for the styled statement row. Verified by OVMF X64 lvgl screendumps: watermark still shown on a short form and suppressed on a dense form (FirstEmptyRow passed correctly), and a one-of option popup with the highlighted option correctly filled, plus smoke. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Advances the LVGL display backend from "cue glyphs over native text" toward real widgets for every value-bearing IFR opcode, then builds out the in-setup experience: modern dialogs, a localized (CJK-capable) chrome, a clean selection treatment, and an original OEM-branding slot. Everything is display-only — edk2 FormBrowser still owns selection, editing, ConfigAccess, callbacks, and variable writes.
MODERN_SETUP_DISPLAY_ENGINE=lvgl|modernselects the LVGL or GOP renderer behind the sameModernDisplayEngineDxe.1. IFR opcode → real LVGL widgets (display-only)
lv_dropdown, checkbox →lv_checkbox, numeric/string/password →lv_textarea(password masked), ordered-list / date-time mapped too. Built as transient display-onlylv_objs →lv_snapshot_take(ARGB8888)→ alpha-composited over the row background in the shadow canvas → BLT. Wired into the in-setup DisplayEngine viaModernDisplayDrawValueWidget, stripping FormBrowser glyph-width markers.ModernDisplayDrawTextCaret) instead of the nativeConOutcursor, so it is themed on both backends.ModernUiRenderOneOf/Checkbox/String/Password/Numeric/OrderedList/DateTimeentry points (themed boxes) — no non-LVGL regression.2. Modern dialogs
3. Localized (CJK) chrome
ModernUiStringLib, so under thezh-Hansdefault the setup header reads 现代UEFI设置工具 / 高级模式 with tabs 设置分类 / 设备 / 启动 / 安全 / 退出, matching the front-page app. CJK glyphs come from the existing embedded Noto Sans CJK SC subset.ModernUiStringLibis nowDXE_DRIVER-usable and wired into the DisplayEngine overlay on all four targets.4. Selection & label polish
ModernUiGetSelectableRowBackground, so the row fill and per-cell text anti-alias background stay matched) plus one solid left-accent stripe — replacing the muddy multi-layer band. The per-cell print path suppresses its flat fill only on the styled row (scoped so highlighted popup options are unaffected).5. OEM branding slot (original art)
ModernUiDrawOemWatermarkcomposites an original, theme-tinted brand mark (document glyph + project URL) into the in-setup content whitespace. 100% original geometry + the project URL — no IBV/commercial reuse: an SVG design source rasterized to an A8 coverage map byScripts/gen-oem-watermark.py. Drawn after the statement rows and confined to the empty band below the last menu row, so it is suppressed on row-filled forms (never tints a statement). LVGL composites it; the GOP backend is a no-op for now.6. Docs
Docs/PRODUCTIZATION_STATUS.md— a living, checklist-style read on how far the engine (GOP/LVGL lines) and the front-page app are from shipping, with effort sizing and the gating decisions (LVGL graduation, CJK coverage strategy, memory budget, hardware validation).Self-review fixes (pre-merge)
A multi-angle review of this branch caught and fixed two real bugs: an EFIAPI/ABI mismatch on
ModernDisplayDrawOemWatermarkOverlay(declaredEFIAPI, defined without it), and a stale highlight-row record across popups that could drop a selectable option's highlight fill. Both fixed and re-verified.Validation
python3 Tests/Smoke/smoke_validate.py— PASS.External/edk2is intentionally untouched (separate baseline work, not part of this branch).🤖 Generated with Claude Code